Nek5000
SEM for Incompressible NS
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
navier4.F90
Go to the documentation of this file.
1 !-----------------------------------------------------------------------
14 !-----------------------------------------------------------------------
15 module helmholtz
16  use kinds, only : dp
17  implicit none
18 
19 
21  private :: projh, gensh, hconj, updrhsh, hmhzpf
22 
26  real(DP), allocatable :: projectors(:,:) !>
27  integer :: n_max !>
28  integer :: n_sav !>
29  integer :: next !>
30  real(DP) :: dt !>
31 
33  real(DP), allocatable :: h_red(:,:)
34  end type approx_space
35 
36 contains
37 
41 subroutine init_approx_space(apx, n_max, ntot)
42  use kinds, only : dp
43  implicit none
44  type(approx_space), intent(out) :: apx
45  integer, intent(in) :: n_max, ntot
46  apx%n_max = n_max
47  apx%n_sav = 0
48  apx%next = 0
49  allocate(apx%projectors(ntot, 0:n_max), apx%H_red(n_max, n_max))
50  apx%projectors = 0._dp
51  apx%H_red = 0._dp
52  apx%dt = 0._dp
53 end subroutine init_approx_space
54 
62 subroutine projh(r,h1,h2,bi,vml,vmk, apx, wl,ws,name4)
63  use kinds, only : dp, qp
64  use size_m, only : nx1, ny1, nz1, nelv, nid
65  use geom, only : voltm1, volvm1
66  use tstep, only : istep, ifield, nelfld
67  use parallel, only : nid
68  use ctimer, only : nproj, tproj, proj_flop, proj_mop
69  use ctimer, only : dnekclock
70  implicit none
71 
72  real(DP), intent(inout) :: r(*) !>
73  real(DP), intent(in) :: h1(*) !>
74  real(DP), intent(in) :: h2(*) !>
75  real(DP), intent(in) :: vml(*) !>
76  real(DP), intent(in) :: vmk(*) !>
77  real(DP), intent(in) :: bi(*) !>
78  real(DP), intent(out) :: wl(*) !>
79  real(DP), intent(out) :: ws(*) !>
80  type(approx_space), intent(inout) :: apx !>
81  character(4), intent(in) :: name4 !>
82 
83  integer :: nel, ntot, i, j, n10
84  real(DP) :: vol, alpha1, alpha2, ratio
85  real(DP), external :: glsc23
86  real(DP), allocatable :: evecs(:,:), ev(:)
87  integer :: ierr
88  real(DP), parameter :: one = 1._dp, zero = 0._dp
89  real(DP) :: etime
90  real(QP) :: qsum
91 
92  nproj = nproj + 1
93  etime = dnekclock()
94 
95  if (apx%n_sav == 0) then
96  apx%projectors(:,0) = 0._dp
97  return
98  endif
99 
100  nel =nelfld(ifield)
101  ntot=nx1*ny1*nz1*nel
102 
103  vol = voltm1
104  if (nel == nelv) vol = volvm1
105 
106  ! Diag to see how much reduction in the residual is attained.
107  alpha1 = glsc23(r,bi,vml,ntot)
108  if (alpha1 > 0) alpha1 = sqrt(alpha1/vol)
109 
110  ! Update approximation space if dt has changed
111  etime = etime - dnekclock()
112  call updrhsh(apx,h1,h2,vml,vmk,ws)
113  etime = etime + dnekclock()
114 
116  ! Orthogonalize the approximation space
117  if (10 * apx%n_sav + 100 > ntot) write(*,*) "wl isn't big enough to be dsyev's work"
118  allocate(evecs(apx%n_sav, apx%n_sav), ev(apx%n_sav))
119  evecs = apx%H_red(1:apx%n_sav,1:apx%n_sav)
120  call dsyev('V', 'U', apx%n_sav, &
121  evecs, apx%n_sav, &
122  ev, &
123  wl, ntot, ierr)
124  if (nid == 0 .and. ierr /= 0) write(*,*) "DSYEV failed", ierr
125 
126  ! Compute overlap of residual and (non-orthogonal) projectors
127  proj_flop = proj_flop + ntot
128  proj_mop = proj_mop + 3*ntot
129  wl(1:ntot) = r(1:ntot) * vml(1:ntot)
130 #if 0
131  do i = 1, apx%n_sav
132  !ws(i) = glsc3(wl, approx(:,i,1), vml, ntot)
133  ws(i) = glsc2(wl, apx%projectors(:,i), ntot)
134  enddo
135 #else
136  proj_flop = proj_flop + (2*ntot-1)*apx%n_sav
137  proj_mop = proj_mop + apx%n_sav * (ntot+1)
138  call dgemv('T', ntot, apx%n_sav, &
139  one, apx%projectors(:,1:apx%n_sav), ntot, &
140  wl, 1, &
141  zero, ws, 1)
142  call gop(ws, ws(1+apx%n_sav), '+ ', apx%n_sav)
143 #endif
144 
145  ! Mix the overlaps to get the orthogonal projection
146  ! and take the inverse by dividing by \lambda
147  ! \todo sort the sums for more precision
148 
149  do i = 1, apx%n_sav
150  qsum = 0._qp
151  do j = 1, apx%n_sav
152  qsum = qsum + evecs(j,i) * ws(j)
153  enddo
154  enddo
155  do i = 1, apx%n_sav
156  qsum = 0._qp
157  do j = 1, apx%n_sav
158  qsum = qsum + evecs(j,i) * ws(j)
159  enddo
160  ev(i) = qsum / ev(i)
161  enddo
162 
163  ! Compute the weights for the approximate solution
164  do i = 1, apx%n_sav
165  qsum = 0._qp
166  do j = 1, apx%n_sav
167  qsum = qsum + evecs(i,j) * ev(j)
168  enddo
169  ws(i) = qsum
170  enddo
171 
172  ! Expand the approximate solution wrt (non-orth.) projectors
173  proj_flop = proj_flop + ntot*(2*apx%n_sav-1)
174  proj_mop = proj_mop + (apx%n_sav+1) * ntot
175  call dgemv('N', ntot, apx%n_sav, &
176  one, apx%projectors(:,1:apx%n_sav), ntot, &
177  ws, 1, &
178  zero, apx%projectors(:,0), 1)
179 
180  ! Compute the new residual explicitly
181  ! This fixes any numerical precision issues in the previous sections
182  etime = etime - dnekclock()
183  call axhelm(wl,apx%projectors(:,0),h1,h2,1,1)
184  etime = etime + dnekclock()
185  proj_flop = proj_flop + ntot
186  proj_mop = proj_mop + 2*ntot
187  wl(1:ntot) = wl(1:ntot) * vmk(1:ntot)
188  call dssum(wl)
189  proj_flop = proj_flop + ntot
190  proj_mop = proj_mop + 2*ntot
191  r(1:ntot) = r(1:ntot) - wl(1:ntot)
192 
193 
194  !...............................................................
195  ! Recompute the norm of the residual to show how much its shrunk
196  alpha2 = glsc23(r,bi,vml,ntot)
197  if (alpha2 > 0) alpha2 = sqrt(alpha2/vol)
198  ratio = alpha1/alpha2
199 
200  tproj = tproj + (dnekclock() - etime)
201  n10=min(10,apx%n_sav)
202 
203  if (nid == 0) write(6,10) istep,name4,alpha1,alpha2,ratio,apx%n_sav
204  10 format(4x,i7,4x,a4,' alph1n',1p3e12.4,i6)
205 
206  if (nid == 0) write(6,11) istep,name4,apx%n_sav,(ev(i),i=1,n10)
207  11 format(4x,i7,4x,a4,' halpha',i6,10(1p10e12.4,/,17x))
208 
209  return
210 end subroutine projh
211 
212 !-----------------------------------------------------------------------
215 subroutine gensh(v1,h1,h2,vml,vmk,apx,ws)
216  use kinds, only : dp
217  use mesh, only : niterhm
218  implicit none
219 
220  REAL(DP), intent(inout) :: V1 (*) !>
221  REAL(DP), intent(in) :: H1 (*) !>
222  REAL(DP), intent(in) :: H2 (*) !>
223  REAL(DP), intent(in) :: vmk(*) !>
224  REAL(DP), intent(in) :: vml(*) !>
225  real(DP), intent(out) :: ws(:) !>
226  type(approx_space), intent(inout) :: apx !>
227 
228  integer :: ntot
229  real(DP) :: norm
230  real(DP), external :: dnrm2
231  ntot = size(apx%projectors,1)
232 
233  ! Reconstruct solution
234  v1(1:ntot) = v1(1:ntot) + apx%projectors(:,0)
235 
236  ! If the new vector is in the space already, don't re-add it.
237  if (niterhm < 1) return
238 
239  ! Add the solution to the approximation space
240  apx%n_sav = min(apx%n_sav + 1, apx%n_max)
241  apx%next = mod(apx%next, apx%n_max) + 1
242  call copy(apx%projectors(:,apx%next),v1,ntot)
243  call hconj(apx,apx%next,h1,h2,vml,vmk,ws)
244 
245  return
246 end subroutine gensh
247 
248 !-----------------------------------------------------------------------
250 subroutine hconj(apx,k,h1,h2,vml,vmk,ws)
251  use kinds, only : dp
252  use ctimer, only : nhconj, thconj, hconj_flop, hconj_mop, dnekclock
253  implicit none
254 
255  type(approx_space), intent(inout) :: apx !>
256  integer, intent(in) :: k !>
257  real(DP), intent(in) :: h1(*) !>
258  real(DP), intent(in) :: h2(*) !>
259  real(DP), intent(in) :: vml(*) !>
260  real(DP), intent(in) :: vmk(*) !>
261  real(DP), intent(out) :: ws(*) !>
262 
263  integer :: i, ntot
264  real(DP), parameter :: one = 1._dp, zero = 0._dp
265  real(DP) :: etime
266 
267  ntot= size(apx%projectors, 1)
268  hconj_flop = hconj_flop + apx%n_sav*(2*ntot-1)
269  hconj_mop = hconj_mop + apx%n_sav * (ntot +1)
270  hconj_flop = hconj_flop + ntot
271  hconj_mop = hconj_flop + 3*ntot
272  hconj_flop = hconj_flop + ntot
273  hconj_mop = hconj_flop + 3*ntot
274  nhconj = nhconj + 1
275 
276  ! Compute H| projectors(:,k) >
277  call axhelm(apx%projectors(:,0),apx%projectors(:,k),h1,h2,1,1)
278  etime = dnekclock()
279  apx%projectors(:,0) = apx%projectors(:,0) * vmk(1:ntot)
280  call dssum(apx%projectors(:,0))
281  apx%projectors(:,0) = apx%projectors(:,0) * vml(1:ntot)
282 
283  ! Compute < projectors(:,i) | H | projectors(:,k) > for i \in [1,n_sav]
284  call dgemv('T', ntot, apx%n_sav, &
285  one, apx%projectors(1,1), ntot, &
286  apx%projectors(1,0), 1, &
287  zero, apx%H_red(1,k), 1)
288  call gop(apx%H_red(:,k), ws, '+ ', apx%n_sav)
289 
290  ! Re-symmetrize
291  do i = 1, apx%n_sav
292  apx%H_red(k,i) = apx%H_red(i,k)
293  enddo
294  thconj = thconj + (dnekclock() - etime)
295 
296  return
297 end subroutine hconj
298 
299 !-----------------------------------------------------------------------
301 subroutine updrhsh(apx,h1,h2,vml,vmk,ws)
302  use kinds, only : dp
303  use input, only : ifvarp, iflomach
304  use tstep, only : dt, ifield
305  implicit none
306 
307  type(approx_space), intent(inout) :: apx !>
308  real(DP), intent(in) :: h1(*) !>
309  real(DP), intent(in) :: h2(*) !>
310  real(DP), intent(in) :: vml(*) !>
311  real(DP), intent(in) :: vmk(*) !>
312  real(DP), intent(out) :: ws(*) !>
313 
314  logical :: ifupdate
315  logical, save :: ifnewdt = .false.
316  integer :: n_sav, k
317 
318  ! First, we have to decide if the dt has changed.
319  ifupdate = .false.
320  if (dt /= apx%dt) then
321  apx%dt = dt
322  ifnewdt = .true.
323  ifupdate = .true.
324  elseif (ifnewdt) then
325  ifnewdt = .false.
326  endif
327  if (ifvarp(ifield)) ifupdate = .true.
328  if (iflomach) ifupdate = .true.
329 
330  ! If it has, recompute apx%H_red column by column
331  if (ifupdate) then
332  n_sav = apx%n_sav
333  ! Loops over columns to update
334  do k=1,n_sav
335  apx%n_sav = k
336  call hconj(apx, apx%n_sav, h1,h2,vml,vmk,ws)
337  enddo
338  endif
339 
340  return
341 end subroutine updrhsh
342 
343 !-----------------------------------------------------------------------
344 subroutine hmhzpf(name,u,r,h1,h2,mask,mult,imesh,tli,maxit,isd,bi)
345  use kinds, only : dp
346  use size_m, only : lx1, ly1, lz1
347  use size_m, only : nx1, ny1, nz1, nelv, nelt, ndim
348  use ctimer, only : etime1, dnekclock, thmhz
349  use fdmh1, only : kfldfdm
350  use input, only : param
351  implicit none
352 
353  CHARACTER(4) :: NAME
354  REAL(DP), intent(out) :: U (lx1,ly1,lz1,1) !>
355  REAL(DP), intent(in) :: R (lx1,ly1,lz1,1) !>
356  REAL(DP), intent(in) :: H1 (lx1,ly1,lz1,1) !>
357  REAL(DP), intent(in) :: H2 (lx1,ly1,lz1,1) !>
358  REAL(DP), intent(in) :: MASK (lx1,ly1,lz1,1) !>
359  REAL(DP), intent(in) :: MULT (lx1,ly1,lz1,1) !>
360  REAL(DP), intent(in) :: bi (lx1,ly1,lz1,1) !>
361  real(DP) :: tli
362  integer :: imesh, maxit, isd
363 
364  integer :: ntot
365  real(DP) :: tol
366 
367  etime1=dnekclock()
368 
369  IF (imesh == 1) ntot = nx1*ny1*nz1*nelv
370  IF (imesh == 2) ntot = nx1*ny1*nz1*nelt
371 
372  tol = tli
373  if (param(22) /= 0) tol = abs(param(22))
374  CALL chktcg1(tol,r,h1,h2,mask,mult,imesh,isd)
375 
376 
377 ! Set flags for overlapping Schwarz preconditioner (pff 11/12/98)
378 
379  kfldfdm = -1
380 ! if (name.eq.'TEMP') kfldfdm = 0
381 ! if (name.eq.'VELX') kfldfdm = 1
382 ! if (name.eq.'VELY') kfldfdm = 2
383 ! if (name.eq.'VELZ') kfldfdm = 3
384  if (name == 'PRES') kfldfdm = ndim+1
385 
386  call cggo &
387  (u,r,h1,h2,mask,mult,imesh,tol,maxit,isd,bi,name)
388  thmhz=thmhz+(dnekclock()-etime1)
389 
390 
391  return
392 end subroutine hmhzpf
393 
394 !-----------------------------------------------------------------------
396 subroutine hsolve(name,u,r,h1,h2,vmk,vml,imsh,tol,maxit,isd &
397  ,apx,bi)
398  use kinds, only : dp
399  use size_m, only : lx1, ly1, lz1, lelv
400  use input, only : param
401  use string, only : capit
402  use tstep, only : ifield, nelfld, istep
403  implicit none
404 
405  CHARACTER(4), intent(in) :: NAME !>
406  REAL(DP), intent(out) :: U (lx1,ly1,lz1,lelv) !>
407  REAL(DP), intent(inout) :: R (lx1,ly1,lz1,lelv) !>
408  REAL(DP), intent(in) :: H1 (lx1,ly1,lz1,lelv) !>
409  REAL(DP), intent(in) :: H2 (lx1,ly1,lz1,lelv) !>
410  REAL(DP), intent(in) :: vmk (lx1,ly1,lz1,lelv) !>
411  REAL(DP), intent(in) :: vml (lx1,ly1,lz1,lelv) !>
412  integer, intent(in) :: imsh !>
413  real(DP), intent(in) :: tol !>
414  integer, intent(in) :: maxit !>
415  integer, intent(in) :: isd !>
416  type(approx_space), intent(inout) :: apx !>
417  REAL(DP), intent(in) :: bi (lx1,ly1,lz1,*) !>
418 
419  real(DP), allocatable :: w1(:)
420  real(DP), allocatable :: w2(:)
421 
422  logical :: ifstdh
423  character(4) :: cname
424  integer :: nel
425  real(DP) :: rinit
426  real(DP), external :: glsc23
427 
428 
429  call chcopy(cname,name,4)
430  call capit(cname,4)
431 
432  ! figure out if we're projecting or not
433  ifstdh = .true.
434  ! Is this a pressure solve?
435  if (cname == 'PRES') then
436  if (param(95) /= 0 .AND. istep > param(95) .and. param(93) > 0) then
437  ifstdh = .false.
438  endif
439  ! Is this a velocity solve?
440  elseif (cname == 'VELX' .or. cname == 'VELY' .or. cname == 'VELZ') then
441  if (param(94) /= 0 .AND. istep > param(94) .and. param(92) > 0) then
442  ifstdh = .false.
443  endif
444  endif
445 
446 
447  if (ifstdh) then
448 
449  call hmholtz(name,u,r,h1,h2,vmk,vml,imsh,tol,maxit,isd)
450 
451  else
452 
453  nel = nelfld(ifield)
454 
455  call dssum(r)
456  r(:,:,:,1:nel) = r(:,:,:,1:nel) * vmk(:,:,:,1:nel)
457 
458  allocate(w2(2+2*apx%n_max))
459  allocate(w1(lx1*ly1*lz1*lelv))
460  call projh(r,h1,h2,bi,vml,vmk,apx,w1,w2,name)
461  deallocate(w1)
462 
463  call hmhzpf(name,u,r,h1,h2,vmk,vml,imsh,tol,maxit,isd,bi)
464  call gensh(u,h1,h2,vml,vmk,apx,w2)
465 
466  endif
467 
468 
469  return
470 end subroutine hsolve
471 !-----------------------------------------------------------------------
472 
473 end module helmholtz
subroutine, private updrhsh(apx, h1, h2, vml, vmk, ws)
Recompute H_red if dt has changed.
Definition: navier4.F90:301
subroutine dssum(u)
Direct stiffness sum.
Definition: dssum.F90:54
cleaned
Definition: tstep_mod.F90:2
Input parameters from preprocessors.
Definition: input_mod.F90:11
Type to hold the approximation space. Should not be modified outside this module, so more of a handle...
Definition: navier4.F90:25
subroutine, private hmhzpf(name, u, r, h1, h2, mask, mult, imesh, tli, maxit, isd, bi)
Definition: navier4.F90:344
subroutine axhelm(au, u, helm1, helm2, imesh, isd)
Compute the (Helmholtz) matrix-vector product, AU = helm1*[A]u + helm2*[B]u, for NEL elements...
Definition: hmholtz.F90:79
subroutine, public hsolve(name, u, r, h1, h2, vmk, vml, imsh, tol, maxit, isd, apx, bi)
Either std. Helmholtz solve, or a projection + Helmholtz solve.
Definition: navier4.F90:396
cleaned
Definition: mesh_mod.F90:2
real(dp) function dnekclock()
Definition: ctimer_mod.F90:103
real(dp) function glsc2(x, y, n)
Perform inner-product in double precision.
Definition: math.F90:210
subroutine copy(a, b, n)
Definition: math.F90:52
subroutine chktcg1(tol, res, h1, h2, mask, mult, imesh, isd)
Check that the tolerances are not too small for the CG-solver. Important when calling the CG-solver (...
Definition: hmholtz.F90:637
cleaned
Definition: parallel_mod.F90:2
subroutine, public init_approx_space(apx, n_max, ntot)
Initialize approximation space object.
Definition: navier4.F90:41
subroutine capit(lettrs, n)
Capitalizes string of length n.
Definition: string_mod.F90:161
subroutine, private projh(r, h1, h2, bi, vml, vmk, apx, wl, ws, name4)
Project out the part of the residual in the approx space.
Definition: navier4.F90:62
Geometry arrays.
Definition: geom_mod.F90:2
subroutine, private gensh(v1, h1, h2, vml, vmk, apx, ws)
Reconstruct the solution to the original problem by adding back the approximate solution, add solution to approximation space.
Definition: navier4.F90:215
subroutine gop(x, w, op, n)
Global vector commutative operation.
Definition: comm_mpi.F90:104
subroutine cggo(x, f, h1, h2, mask, mult, imsh, tin, maxit, isd, binv, name)
Solve the Helmholtz equation, H*U = RHS, using preconditioned conjugate gradient iteration. Preconditioner: diag(H).
Definition: hmholtz.F90:744
subroutine chcopy(a, b, n)
Definition: math.F90:63
subroutine, private hconj(apx, k, h1, h2, vml, vmk, ws)
Update the k-th row/column of H_red.
Definition: navier4.F90:250
subroutine hmholtz(name, u, rhs, h1, h2, mask, mult, imsh, tli, maxit, isd)
Definition: hmholtz.F90:2