FrontISTR  5.9.0
Large-scale structural analysis program with finit element method
fstr_EIG_tridiag.f90
Go to the documentation of this file.
1 !-------------------------------------------------------------------------------
2 ! Copyright (c) 2019 FrontISTR Commons
3 ! This software is released under the MIT License, see LICENSE.txt
4 !-------------------------------------------------------------------------------
8  use hecmw
9 
10  implicit none
11 
12  public
13 
15  real(kind=kreal), pointer :: q(:) => null()
16  end type fstr_eigen_vec
17 
19  real(kind=kreal), allocatable :: alpha(:)
20  real(kind=kreal), allocatable :: beta(:)
21  end type fstr_tri_diag
22 
23 contains
24 
25  subroutine tridiag(hecMESH, hecMAT, fstrEIG, Q, Tri, iter, is_converge)
26  use hecmw
27  use m_fstr
29  implicit none
30  type(hecmwst_local_mesh) :: hecmesh
31  type(hecmwst_matrix) :: hecMAT
32  type(fstr_eigen) :: fstrEIG
33  type(fstr_tri_diag) :: Tri
34  type(fstr_eigen_vec), pointer :: Q(:)
35 
36  integer(kind=kint), intent(in) :: iter
37  integer(kind=kint) :: N, NP, NDOF, NNDOF, NPNDOF
38  integer(kind=kint) :: i, j, k, in, jn, kn, nget
39  integer(kind=kint) :: iter2, ierr, maxiter
40  real(kind=kreal) :: resid, chk, vmax, sigma, tolerance
41  real(kind=kreal), allocatable :: alpha(:), beta(:), temp(:)
42  real(kind=kreal), allocatable :: l(:,:)
43 
44  integer(kind=kint), allocatable :: iparm(:)
45  real(kind=kreal), pointer :: eigvec(:,:)
46  real(kind=kreal), pointer :: eigval(:)
47  logical :: is_converge
48 
49  n = hecmat%N
50  np = hecmat%NP
51  ndof = hecmesh%n_dof
52  nndof = n *ndof
53  npndof = np*ndof
54  eigval => fstreig%eigval
55  eigvec => fstreig%eigvec
56  nget = fstreig%nget
57  maxiter = fstreig%maxiter
58  tolerance = fstreig%tolerance
59 
60  allocate( iparm(maxiter) )
61  allocate( temp(maxiter) )
62  allocate( alpha(iter) )
63  allocate( beta(iter) )
64  allocate( l(iter, iter) )
65 
66  do j=1, iter
67  do i = 1,iter
68  l(i,j) = 0.0d0
69  enddo
70  enddo
71 
72  do i=1, iter
73  alpha(i) = tri%alpha(i)
74  l(i,i) = 1.0d0
75  enddo
76 
77  beta(1) = 0.0d0
78  do i=2, iter
79  beta(i) = tri%beta(i)
80  enddo
81 
82  call ql_decomposition(iter, iter, alpha, beta, l, ierr)
83 
84  sigma = 0.0d0
85  if(fstreig%is_free) sigma = fstreig%sigma
86  do i = 1, iter
87  if(alpha(i) /= 0.0d0)then
88  eigval(i) = 1.0d0/alpha(i) - sigma
89  else
90  ! A zero Ritz value stands for an infinite eigenvalue. evsort orders by
91  ! magnitude, so the sentinel keeps such a mode out of the requested set.
92  eigval(i) = huge(0.0d0)
93  endif
94  enddo
95 
96  ! The lowest modes are the largest Ritz values, so the convergence check has to
97  ! pick them through iparm rather than take the leading entries of alpha.
98  call evsort(eigval, iparm, iter)
99 
100  is_converge = .true.
101  chk = 0.0d0
102  ! Two extra modes absorb the reordering of modes sitting on the boundary of the requested set.
103  do i = 1, min(nget+2, iter)
104  in = iparm(i)
105  if (dabs(alpha(in)) > 0.0d0) then
106  ! Divide by the eigenvalue of the mode itself.
107  resid = dabs(tri%beta(iter+1)*l(iter,in))/dabs(alpha(in))
108  chk = max(chk, resid)
109  if(tolerance < resid) is_converge = .false.
110  else
111  is_converge = .false.
112  endif
113  enddo
114  if(myrank == 0) write(*,"(i8,1pe12.5)")iter, chk
115 
116  if(iter < nget) is_converge = .false.
117 
118  if(iter == maxiter-1 .and. .not. is_converge)then
119  if(myrank == 0)then
120  write(*,*) '### WARNING: eigen analysis stopped at maxiter without convergence.'
121  write(ilog,*) '### WARNING: eigen analysis stopped at maxiter without convergence.'
122  endif
123  ! Only iter Ritz pairs exist. Reporting more would print entries of eigval and
124  ! eigvec that no iteration has ever written.
125  if(iter < nget) fstreig%nget = iter
126  is_converge = .true.
127  endif
128 
129  if(is_converge)then
130  temp = eigval
131 
132  eigvec = 0.0d0
133  do k=1, iter
134  in = iparm(k)
135  eigval(k) = temp(in)
136  do j=1, iter
137  do i=1, npndof
138  eigvec(i, k) = eigvec(i, k) + q(j)%q(i) * l(j, in)
139  enddo
140  enddo
141  enddo
142 
143  do j=1, iter
144  chk = 0.0d0
145  vmax = 0.0d0
146  do i = 1, nndof
147  chk = max(chk, dabs(eigvec(i,j)))
148  vmax = max(vmax, eigvec(i,j))
149  enddo
150  call hecmw_allreduce_r1(hecmesh, chk, hecmw_max)
151  call hecmw_allreduce_r1(hecmesh, vmax, hecmw_max)
152  if(chk /= 0.0d0)then
153  ! The largest component becomes +1. A tie between +a and -a goes to the
154  ! positive one so that serial and parallel runs pick the same sign.
155  if(vmax /= chk) chk = -chk
156  chk = 1.0d0/chk
157  do i = 1, nndof
158  eigvec(i,j) = eigvec(i,j) * chk
159  enddo
160  endif
161  enddo
162  endif
163 
164  deallocate(iparm)
165  deallocate(temp)
166  deallocate(alpha)
167  deallocate(beta)
168  deallocate(l)
169  end subroutine tridiag
170 
171  !======================================================================!
172  ! Description !
173  !======================================================================!
183  !
184  !on input
185  !
186  !nm must be set to the row dimension of two-dimensional
187  !array parameters as declared in the calling program
188  !dimension statement.
189  !
190  !is the order of the matrix.
191  !
192  !contains the diagonal elements of the input matrix.
193  !
194  !contains the subdiagonal elements of the input matrix
195  !in its last n-1 positions. e(1) is arbitrary.
196  !
197  !contains the transformation matrix produced in the
198  !reduction by tred2, if performed. if the eigenvectors
199  !of the tridiagonal matrix are desired, z must contain
200  !the identity matrix.
201  !
202  !on output
203  !
204  !d
205  !contains the eigenvalues in the order produced by the ql sweeps,
206  !which is not sorted. ordering is left to the caller. if an
207  !error exit is made, the eigenvalues are correct for indices
208  !1,2,...,ierror-1.
209  !-----------------------------------------------------
210  !e
211  !has been destroyed.
212  !
213  !z
214  !contains orthonormal eigenvectors of the symmetric
215  !tridiagonal (or full) matrix. if an error exit is made,
216  !z contains the eigenvectors associated with the stored
217  !eigenvalues.
218  !-----------------------------------------------------
219  !ierror is set to
220  ! zero for normal return,
221  ! j if the j-th eigenvalue has not been
222  ! determined after 30 iterations.
223  !
224  !calls a2b2 for dsqrt(a*a + b*b) .
225  !=======================================================================
226 
227  !call QL_decomposition(iter, iter, alpha, beta, L, ierr)
228  subroutine ql_decomposition(nm, n, d, e, z, ierror)
229  use hecmw
230  implicit none
231  integer(kind=kint) :: i, j, k, l, m, n, ii, l1, l2, nm, mml, ierror
232  real(kind=kreal) :: d(n), e(n), z(nm, n)
233  real(kind=kreal) :: c, c2, c3, dl1, el1, f, g, h, p, r, s, s2, tst1, tst2
234 
235  ierror = 0
236  if (n .eq. 1) go to 1001
237 
238  do i = 2, n
239  e(i-1) = e(i)
240  enddo
241 
242  f = 0.0d0
243  tst1 = 0.0d0
244  e(n) = 0.0d0
245 
246  do 240 l = 1, n
247  j = 0
248  h = dabs(d(l)) + dabs(e(l))
249  if (tst1 .lt. h) tst1 = h
250  ! .......... look for small sub-diagonal element ..........
251  bb:do m = l, n
252  tst2 = tst1 + dabs(e(m))
253  if (tst2 .eq. tst1) exit bb
254  ! .......... e(n) is always zero, so there is no exit
255  ! through the bottom of the loop ..........
256  enddo bb
257 
258  if (m .eq. l) go to 220
259 
260  130 if (j .eq. 30) go to 1000
261  j = j + 1
262  ! .......... form shift ..........
263  l1 = l + 1
264  l2 = l1 + 1
265  g = d(l)
266  p = (d(l1) - g) / (2.0d0 * e(l))
267  r = a2b2(p,1.0d0)
268  d(l) = e(l) / (p + dsign(r,p))
269  d(l1) = e(l) * (p + dsign(r,p))
270  dl1 = d(l1)
271  h = g - d(l)
272  if (l2 .gt. n) go to 145
273 
274  do i = l2, n
275  d(i) = d(i) - h
276  enddo
277 
278  145 f = f + h
279  ! .......... ql transformation ..........
280  p = d(m)
281  c = 1.0d0
282  c2 = c
283  el1 = e(l1)
284  s = 0.0d0
285  s2 = 0.0d0
286  c3 = 0.0d0
287  mml = m - l
288  ! .......... for i=m-1 step -1 until l do -- ..........
289  do ii = 1, mml
290  c3 = c2
291  c2 = c
292  s2 = s
293  i = m - ii
294  g = c * e(i)
295  h = c * p
296  r = a2b2(p,e(i))
297  e(i+1) = s * r
298  s = e(i) / r
299  c = p / r
300  p = c * d(i) - s * g
301  d(i+1) = h + s * (c * g + s * d(i))
302  ! .......... form vector ..........
303  do k = 1, n
304  h = z(k,i+1)
305  z(k,i+1) = s * z(k,i) + c * h
306  z(k,i) = c * z(k,i) - s * h
307  enddo
308  enddo
309 
310  p = -s * s2 * c3 * el1 * e(l) / dl1
311  e(l) = s * p
312  d(l) = c * p
313  tst2 = tst1 + dabs(e(l))
314  if (tst2 .gt. tst1) go to 130
315  220 d(l) = d(l) + f
316  240 continue
317 
318  go to 1001
319  ! .......... set error -- no convergence to an
320  ! eigenvalue after 30 iterations ..........
321  1000 ierror = l
322  1001 return
323  end subroutine ql_decomposition
324 
325  function a2b2(a,b)
326  use hecmw
327  implicit none
328 
329  real(kind=kreal) :: a2b2
330  real(kind=kreal) :: a, b
331  real(kind=kreal) :: p, q, r, s, t, u
332 
333  p = dmax1(dabs(a), dabs(b))
334  if (p /= 0.0d0) then
335  r = (dmin1(dabs(a),dabs(b))/p) ** 2
336  do
337  t = 4.0d0 + r
338  if (t == 4.0d0) exit
339  s = r/t
340  u = 1.0d0 + 2.0d0*s
341  p = u * p
342  q = s/u
343  r = q * q * r
344  end do
345  end if
346  a2b2 = p
347  return
348 
349  end function a2b2
350 
351 end module m_fstr_eig_tridiag
Definition: hecmw.f90:6
subroutine evsort(EIG, NEW, NEIG)
Sort eigenvalues.
This module provides a subroutine to find the eigenvalues and eigenvectors of a symmetric tridiagonal...
subroutine tridiag(hecMESH, hecMAT, fstrEIG, Q, Tri, iter, is_converge)
subroutine ql_decomposition(nm, n, d, e, z, ierror)
This subroutine has been adapted from the eispack routine tql2, which is a translation of the algol p...
real(kind=kreal) function a2b2(a, b)
This module defines common data and basic structures for analysis.
Definition: m_fstr.F90:15
integer(kind=kint) myrank
PARALLEL EXECUTION.
Definition: m_fstr.F90:103
integer(kind=kint), parameter ilog
FILE HANDLER.
Definition: m_fstr.F90:114
Package of data used by Lanczos eigenvalue solver.
Definition: m_fstr.F90:632