ADflow  v1.0
ADflow is a finite volume RANS solver tailored for gradient-based aerodynamic design optimization.
initializeFlow.F90
Go to the documentation of this file.
2 
3  use constants, only: inttype, realtype, maxstringlen
4 
5  implicit none
6  save
7 
8 contains
9 
10  subroutine referencestate
11  !
12  ! The original version has been nuked since the computations are
13  ! no longer necessary when calling from python
14  ! This is the most compliclated routine in all of ADflow. It is
15  ! stupidly complicated. This is most likely the reason your
16  ! derivatives are wrong. You don't understand this routine
17  ! and its effects.
18  ! This routine *requries* the following as input:
19  ! Mach, pInfDim, TInfDim, rhoInfDim, rGasDim (machCoef non-SA
20  ! turbulence only)
21  ! Optionally, pRef, rhoRef and Tref are used if they are
22  ! are non-negative. This only happens when you want the equations
23  ! normalized by values other than the freestream
24  ! * This routine computes as output:
25  ! * muInfDim, (unused anywhere in code)
26  ! pRef, rhoRef, Tref, muRef, timeRef ('dimensional' reference)
27  ! pInf, pInfCorr, rhoInf, uInf, rGas, muInf, gammaInf and wInf
28  ! (Non-dimensionalized values used in actual computations)
29  !
30  use constants
31  use paramturb
32  use inputphysics, only: equations, mach, machcoef, &
36  muinfdim, &
39  nw, nwf, kpresent, winf
40  use flowutils, only: computegamma, etot
41  use turbutils, only: sanuknowneddyratio
42  implicit none
43 
44  integer(kind=intType) :: sps, nn, mm, ierr
45  real(kind=realtype) :: gm1, ratio
46  real(kind=realtype) :: nuinf, ktmp, uinf2
47  real(kind=realtype) :: vinf, zinf, tmp1(1), tmp2(1)
48 
49  ! Compute the dimensional viscosity from Sutherland's law
51  * ((tsuthdim + ssuthdim) / (tinfdim + ssuthdim)) &
52  * ((tinfdim / tsuthdim)**1.5_realtype)
53 
54  ! Set the reference values. They *COULD* be different from the
55  ! free-stream values for an internal flow simulation. For now,
56  ! we just use the actual free stream values.
57  pref = pinfdim
58  tref = tinfdim
60 
61  ! Compute the value of muRef, such that the nonDimensional
62  ! equations are identical to the dimensional ones.
63  ! Note that in the non-dimensionalization of muRef there is
64  ! a reference length. However this reference length is 1.0
65  ! in this code, because the coordinates are converted to
66  ! meters.
67 
68  muref = sqrt(pref * rhoref)
69 
70  ! Compute timeRef for a correct nonDimensionalization of the
71  ! unsteady equations. Some story as for the reference viscosity
72  ! concerning the reference length.
73 
74  timeref = sqrt(rhoref / pref)
75  href = pref / rhoref
76  uref = sqrt(href)
77 
78  ! Compute the nonDimensional pressure, density, velocity,
79  ! viscosity and gas constant.
80 
81  pinf = pinfdim / pref
83  uinf = mach * sqrt(gammainf * pinf / rhoinf)
84  rgas = rgasdim * rhoref * tref / pref
85  muinf = muinfdim / muref
86  tmp1(1) = tinfdim
87  call computegamma(tmp1, tmp2, 1)
88  gammainf = tmp2(1)
89 
90  ! ----------------------------------------
91  ! Compute the final wInf
92  ! ----------------------------------------
93 
94  ! Allocate the memory for wInf if necessary
95 #ifndef USE_TAPENADE
96  if (allocated(winf)) deallocate (winf)
97  allocate (winf(nw), stat=ierr)
98 #endif
99 
100  ! zero out the winf first
101  winf(:) = zero
102 
103  ! Set the reference value of the flow variables, except the total
104  ! energy. This will be computed at the end of this routine.
105 
106  winf(irho) = rhoinf
107  winf(ivx) = uinf * veldirfreestream(1)
108  winf(ivy) = uinf * veldirfreestream(2)
109  winf(ivz) = uinf * veldirfreestream(3)
110 
111  ! Compute the velocity squared based on MachCoef. This gives a
112  ! better indication of the 'speed' of the flow so the turubulence
113  ! intensity ration is more meaningful especially for moving
114  ! geometries. (Not used in SA model)
115 
116  uinf2 = machcoef * machcoef * gammainf * pinf / rhoinf
117 
118  ! Set the turbulent variables if transport variables are to be
119  ! solved. We should be checking for RANS equations here,
120  ! however, this code is included in block res. The issue is
121  ! that for frozen turbulence (or ANK jacobian) we call the
122  ! block_res with equationType set to Laminar even though we are
123  ! actually solving the rans equations. The issue is that, the
124  ! freestream turb variables will be changed to zero, thus
125  ! changing the solution. Insteady we check if nw > nwf which
126  ! will accomplish the same thing.
127 
128  if (nw > nwf) then
129 
130  nuinf = muinf / rhoinf
131 
132  select case (turbmodel)
133 
135 
137 
138  !=============================================================
139 
141 
142  winf(itu1) = 1.5_realtype * uinf2 * turbintensityinf**2
143  winf(itu2) = winf(itu1) / (eddyvisinfratio * nuinf)
144 
145  !=============================================================
146 
147  case (ktau)
148 
149  winf(itu1) = 1.5_realtype * uinf2 * turbintensityinf**2
150  winf(itu2) = eddyvisinfratio * nuinf / winf(itu1)
151 
152  !=============================================================
153 
154  case (v2f)
155 
156  winf(itu1) = 1.5_realtype * uinf2 * turbintensityinf**2
157  winf(itu2) = 0.09_realtype * winf(itu1)**2 &
158  / (eddyvisinfratio * nuinf)
159  winf(itu3) = 0.666666_realtype * winf(itu1)
160  winf(itu4) = 0.0_realtype
161 
162  end select
163 
164  end if
165 
166  ! Set the value of pInfCorr. In case a k-equation is present
167  ! add 2/3 times rho*k.
168 
169  pinfcorr = pinf
170  if (kpresent) pinfcorr = pinf + two * third * rhoinf * winf(itu1)
171 
172  ! Compute the free stream total energy.
173 
174  ktmp = zero
175  if (kpresent) ktmp = winf(itu1)
176  vinf = zero
177  zinf = zero
178  call etot(rhoinf, uinf, vinf, zinf, pinfcorr, ktmp, &
179  winf(irhoe), kpresent)
180 
181  end subroutine referencestate
182 
183  ! ----------------------------------------------------------------------
184  ! |
185  ! No Tapenade Routine below this line |
186  ! |
187  ! ----------------------------------------------------------------------
188 
189 #ifndef USE_TAPENADE
190  subroutine infchangecorrection(oldWinf, correctionTol, correctionType)
191  ! Adjust the flow states to a change in wInf
192  use constants
193  use blockpointers, only: il, jl, kl, w, ndom, d2wall
194  use flowvarrefstate, only: winf, nwf, nw
195  use inputphysics, only: equations
197  use haloexchange, only: whalo2
198  use flowutils, only: adjustinflowangle
199  use oversetdata, only: oversetpresent
200  use iteration, only: currentlevel
202  use bcroutines, only: applyallbc_block
204  use communication, only: myid
205  implicit none
206 
207  real(kind=realtype), intent(in), dimension(nwf) :: oldwinf
208  real(kind=realtype), intent(in) :: correctiontol
209  character*(*), intent(in) :: correctionType
210  integer(kind=intType) :: sps, nn, i, j, k, l
211  real(kind=realtype) :: deltawinf(nwf)
212 
213  ! variables for rotation update
214  real(kind=realtype), dimension(3) :: vec1, vec2, vcell
215  real(kind=realtype), dimension(3, 3) :: rotmat
216  real(kind=realtype) :: mag1, mag2
217 
218  ! Make sure we have the updated wInf
219  call adjustinflowangle()
220  call referencestate
221 
222  ! first check if the state changed enough to warrant a correction. This tolerance
223  ! can be adjusted from python. Default is 1e-12.
224  deltawinf = winf(1:nwf) - oldwinf(1:nwf)
225 
226  if (mynorm2(deltawinf) < correctiontol) then
227  ! The change deltaWinf is so small, (or zero) don't do the
228  ! update and just return. This will save some time when the
229  ! solver is called with the same AP conditions multiple times,
230  ! such as during a GS AS solution
231  return
232  end if
233 
234  ! The state changed enough so we will run a correction update.
235  ! Check which correction type we are using
236  if (correctiontype .eq. "offset") then
237 
238  ! Loop over all the blocks, adding the offset between the old and new Winf
239  do sps = 1, ntimeintervalsspectral
240  do nn = 1, ndom
241  call setpointers(nn, 1_inttype, sps)
242  do k = 2, kl
243  do j = 2, jl
244  do i = 2, il
245  do l = 1, nwf
246  w(i, j, k, l) = w(i, j, k, l) + deltawinf(l)
247  end do
248  end do
249  end do
250  end do
251  call applyallbc_block(.true.)
252  end do
253  end do
254 
255  else if (correctiontype .eq. "rotate") then
256 
257  ! Rotate the flow velocities by the rotation change in Winf.
258  ! We also scale the velocity magnitudes based on the magnitude change.
259  ! vec1 is the old free stream velocity vector, vec2 is the new one.
260  vec1 = oldwinf(ivx:ivz)
261  vec2 = winf(ivx:ivz)
262 
263  ! get the general rotation matrix
264  call getrotmatrix(vec1, vec2, rotmat)
265 
266  ! Compute the magnitude of vec1 and vec2 so that we can adjust the magnitude of the velocity
267  mag1 = mynorm2(vec1)
268  mag2 = mynorm2(vec2)
269 
270  ! Loop over all the blocks, rotate each cell's velocity
271  do sps = 1, ntimeintervalsspectral
272  do nn = 1, ndom
273  call setpointers(nn, 1_inttype, sps)
274  do k = 2, kl
275  do j = 2, jl
276  do i = 2, il
277  ! pick out the cell velocity
278  vcell = w(i, j, k, ivx:ivz)
279  ! rotate and put back
280  w(i, j, k, ivx:ivz) = matmul(rotmat, vcell)
281  ! scale the magnitudes
282  w(i, j, k, ivx:ivz) = w(i, j, k, ivx:ivz) * mag2 / mag1
283  ! we also add the offset to the density and energy
284  w(i, j, k, irho) = w(i, j, k, irho) + deltawinf(irho)
285  w(i, j, k, irhoe) = w(i, j, k, irhoe) + deltawinf(irhoe)
286  end do
287  end do
288  end do
289  call applyallbc_block(.true.)
290  end do
291  end do
292 
293  end if
294 
295  ! Exchange values
296  call whalo2(currentlevel, 1_inttype, nw, .true., .true., .true.)
297 
298  ! Need to re-apply the BCs. The reason is that BC halos behind
299  ! interpolated cells need to be recomputed with their new
300  ! interpolated values from actual compute cells. Only needed for
301  ! overset.
302  if (oversetpresent) then
303  do sps = 1, ntimeintervalsspectral
304  do nn = 1, ndom
305  call setpointers(nn, 1, sps)
306  if (equations == ransequations) then
307  call bcturbtreatment
308  call applyallturbbcthisblock(.true.)
309  end if
310  call applyallbc_block(.true.)
311  end do
312  end do
313  end if
314 
315  end subroutine infchangecorrection
316 
317  ! Section out the BCdata setup so that it can by called from python when needed
319  ! sets the prescribed boundary data from the CGNS arrays
320 
321  use constants
322  use iteration, only: groundlevel
324  implicit none
325 
326  ! Allocate the memory for the prescribed boundary data at the
327  ! boundary faces and determine the data for both the fine grid.
328 
329  groundlevel = 1
330 
331  ! Determine the reference state.
332  call referencestate
333 
334  call setbcdatafinegrid(.true.)
335 
336  ! Determine the prescribed data on the coarse grid levels
337  ! by interpolation.
338 #ifndef USE_TAPENADE
340 #endif
341 
342  end subroutine updatebcdataalllevels
343 
344  subroutine initflow
345  !
346  ! initFlow allocates the
347  ! memory for and initializes the flow variables. In case a
348  ! restart is performed the owned variables are read from the
349  ! previous solution file(s).
350  !
351  use constants
352  use block, only: flowdoms
354  use variablereading, only: halosread
355 
356  implicit none
357  !
358  ! Local variables.
359  !
360  integer :: ierr
361 
362  integer(kind=intType) :: sps, level, nLevels
363 
364  ! Determine the number of multigrid levels.
365 
366  nlevels = ubound(flowdoms, 2)
367 
368  ! As some boundary conditions can be treated in multiple ways,
369  ! some memory allocated must be released again.
370 
371  call releaseextramembcs
372 
373  ! Determine for the time spectral mode the matrices for the
374  ! time derivatives.
376 
377  ! Loop over the number of spectral solutions to allocate
378  ! the memory for the w-variables and p on the fine grid.
379  do sps = 1, ntimeintervalsspectral
380  call allocmemflovarpart1(sps, 1_inttype)
381  end do
382 
383  ! Allocate the memory for the solution variables on the coarse
384  ! grid levels and the memory for the dependent flow variables,
385  ! residuals, etc, on all multigrid levels.
386  do sps = 1, ntimeintervalsspectral
387  call allocmemflovarpart2(sps, 1_inttype)
388 
389  do level = 2, nlevels
390  call allocmemflovarpart1(sps, level)
391  call allocmemflovarpart2(sps, level)
392  end do
393  end do
394 
395  ! Initialize free stream field
396  call initflowfield
397 
398  ! Initialize the dependent flow variables and the halo values.
399 
401 
402  end subroutine initflow
403 
404  subroutine allocmemflovarpart1(sps, level)
405  !
406  ! allocMemFlovarPart1 allocates the memory for the flow
407  ! variables w and p for all the blocks on the given multigrid
408  ! level and spectral solution sps.
409  !
410  use constants
411  use block, only: flowdoms, ndom
412  use flowvarrefstate, only: nw, nwf, nt1, nt2
416  use iteration, only: noldlevels
417  use utils, only: terminate
418  implicit none
419  !
420  ! Subroutine arguments.
421  !
422  integer(kind=intType), intent(in) :: sps, level
423  !
424  ! Local variables.
425  !
426  integer :: ierr
427 
428  integer(kind=intType) :: nn
429  integer(kind=intType) :: il, jl, kl, ie, je, ke, ib, jb, kb
430 
431  ! Loop over the domains.
432 
433  domains: do nn = 1, ndom
434 
435  ! Store some dimensions a bit easier.
436 
437  il = flowdoms(nn, level, sps)%il
438  jl = flowdoms(nn, level, sps)%jl
439  kl = flowdoms(nn, level, sps)%kl
440 
441  ie = flowdoms(nn, level, sps)%ie
442  je = flowdoms(nn, level, sps)%je
443  ke = flowdoms(nn, level, sps)%ke
444 
445  ib = flowdoms(nn, level, sps)%ib
446  jb = flowdoms(nn, level, sps)%jb
447  kb = flowdoms(nn, level, sps)%kb
448 
449  ! Allocate the memory for the independent variables.
450  ! Memory is allocated for the turbulent variables (if any) if
451  ! the current level is smaller or equal to the multigrid start
452  ! level or if the turbulent transport equations are solved in
453  ! a coupled manner.
454 
455  if (level <= mgstartlevel .or. turbtreatment == coupled) then
456  allocate (flowdoms(nn, level, sps)%w(0:ib, 0:jb, 0:kb, 1:nw), &
457  stat=ierr)
458  else
459  allocate (flowdoms(nn, level, sps)%w(0:ib, 0:jb, 0:kb, 1:nwf), &
460  stat=ierr)
461  end if
462  if (ierr /= 0) &
463  call terminate("allocMemFlovarPart1", &
464  "Memory allocation failure for w")
465 
466  ! Alloc mem for nodal gradients
467  allocate (flowdoms(nn, level, sps)%ux(il, jl, kl), stat=ierr)
468  allocate (flowdoms(nn, level, sps)%uy(il, jl, kl), stat=ierr)
469  allocate (flowdoms(nn, level, sps)%uz(il, jl, kl), stat=ierr)
470 
471  allocate (flowdoms(nn, level, sps)%vx(il, jl, kl), stat=ierr)
472  allocate (flowdoms(nn, level, sps)%vy(il, jl, kl), stat=ierr)
473  allocate (flowdoms(nn, level, sps)%vz(il, jl, kl), stat=ierr)
474 
475  allocate (flowdoms(nn, level, sps)%wx(il, jl, kl), stat=ierr)
476  allocate (flowdoms(nn, level, sps)%wy(il, jl, kl), stat=ierr)
477  allocate (flowdoms(nn, level, sps)%wz(il, jl, kl), stat=ierr)
478 
479  allocate (flowdoms(nn, level, sps)%qx(il, jl, kl), stat=ierr)
480  allocate (flowdoms(nn, level, sps)%qy(il, jl, kl), stat=ierr)
481  allocate (flowdoms(nn, level, sps)%qz(il, jl, kl), stat=ierr)
482 
483  ! Allocate memory for the pressure.
484  allocate (flowdoms(nn, level, sps)%p(0:ib, 0:jb, 0:kb), stat=ierr)
485  if (ierr /= 0) &
486  call terminate("allocMemFlovarPart1", &
487  "Memory allocation failure for p")
488 
489  ! Allocate memory for the speed of sound squared
490  allocate (flowdoms(nn, level, sps)%aa(0:ib, 0:jb, 0:kb), stat=ierr)
491  if (ierr /= 0) &
492  call terminate("allocMemFlovarPart1", &
493  "Memory allocation failure for p")
494 
495  ! The eddy viscosity for eddy viscosity models.
496  ! Although a dependent variable, it is allocated on all grid
497  ! levels, because the eddy viscosity might be frozen in the
498  ! multigrid.
499 
500  ! Always allocate rev due to reverse mode AD- Peter Lyu. Also
501  ! zero so that it doesn't affect laminar cases.
502  allocate (flowdoms(nn, level, sps)%rev(0:ib, 0:jb, 0:kb), &
503  stat=ierr)
504  flowdoms(nn, level, sps)%rev = zero
505  if (ierr /= 0) &
506  call terminate("allocMemFlovarPart1", &
507  "Memory allocation failure for rev")
508  !endif
509 
510  ! If this is the finest grid some more memory must be allocated.
511 
512  fineleveltest: if (level == 1) then
513 
514  ! Allocate the memory for gamma and initialize it to
515  ! the constant gamma value.
516 
517  allocate (flowdoms(nn, level, sps)%gamma(0:ib, 0:jb, 0:kb), &
518  stat=ierr)
519  if (ierr /= 0) &
520  call terminate("allocMemFlovarPart1", &
521  "Memory allocation failure for gamma.")
522 
523  flowdoms(nn, level, sps)%gamma = gammaconstant
524 
525  ! The laminar viscosity for viscous computations.
526  ! Always allocate rlv due to reverse mode - Peter Lyu
527  !if( viscous ) then
528  allocate (flowdoms(nn, level, sps)%rlv(0:ib, 0:jb, 0:kb), &
529  stat=ierr)
530  if (ierr /= 0) &
531  call terminate("allocMemFlovarPart1", &
532  "Memory allocation failure for rlv")
533  !endif
534 
535  ! The state vectors in the past for unsteady computations.
536 
537  if (equationmode == unsteady .and. &
538  timeintegrationscheme == bdf) then
539  allocate ( &
540  flowdoms(nn, level, sps)%wOld(noldlevels, 2:il, 2:jl, 2:kl, nw), &
541  stat=ierr)
542  if (ierr /= 0) &
543  call terminate("allocMemFlovarPart1", &
544  "Memory allocation failure for wOld")
545 
546  ! Initialize wOld to zero, such that it is initialized.
547  ! The actual values do not matter.
548 
549  flowdoms(nn, level, sps)%wOld = zero
550 
551  ! Added by HDN
552  else if (equationmode == unsteady .and. &
553  timeintegrationscheme == md) then
554  allocate ( &
555  flowdoms(nn, level, sps)%wOld(noldlevels, 2:il, 2:jl, 2:kl, nw), &
556  stat=ierr)
557  if (ierr /= 0) &
558  call terminate("allocMemFlovarPart1", &
559  "Memory allocation failure for wOld")
560 
561  flowdoms(nn, level, sps)%wOld = zero
562  end if
563 
564  ! If this is the 1st spectral solution (note that we are
565  ! already on the finest grid) and the rans equations are
566  ! solved, allocate the memory for the arrays used for the
567  ! implicit boundary condition treatment. Normally this should
568  ! only be allocated for RANS but the derivative calcs require
569  ! these be allocated.
570 
571  sps1ranstest: if (sps == 1) then
572  allocate (flowdoms(nn, level, sps)%bmti1(je, ke, nt1:nt2, nt1:nt2), &
573  flowdoms(nn, level, sps)%bmti2(je, ke, nt1:nt2, nt1:nt2), &
574  flowdoms(nn, level, sps)%bmtj1(ie, ke, nt1:nt2, nt1:nt2), &
575  flowdoms(nn, level, sps)%bmtj2(ie, ke, nt1:nt2, nt1:nt2), &
576  flowdoms(nn, level, sps)%bmtk1(ie, je, nt1:nt2, nt1:nt2), &
577  flowdoms(nn, level, sps)%bmtk2(ie, je, nt1:nt2, nt1:nt2), &
578  flowdoms(nn, level, sps)%bvti1(je, ke, nt1:nt2), &
579  flowdoms(nn, level, sps)%bvti2(je, ke, nt1:nt2), &
580  flowdoms(nn, level, sps)%bvtj1(ie, ke, nt1:nt2), &
581  flowdoms(nn, level, sps)%bvtj2(ie, ke, nt1:nt2), &
582  flowdoms(nn, level, sps)%bvtk1(ie, je, nt1:nt2), &
583  flowdoms(nn, level, sps)%bvtk2(ie, je, nt1:nt2), &
584  stat=ierr)
585  if (ierr /= 0) &
586  call terminate("allocMemFlovarPart1", &
587  "Memory allocation failure for bmti1, etc")
588 
589  end if sps1ranstest
590  end if fineleveltest
591 
592  end do domains
593 
594  end subroutine allocmemflovarpart1
595 
596  ! ==================================================================
597 
598  subroutine allocmemflovarpart2(sps, level)
599  !
600  ! AllocMemFlovarPart2 allocates the memory for the dependent
601  ! flow variables and iteration variables for all the blocks on
602  ! the given multigrid level and spectral solution sps. Some
603  ! variables are only allocated on the coarser grids, e.g. the
604  ! multigrid forcing terms and the state vector upon entrance on
605  ! the mg level. Other variables are only allocated on the finest
606  ! mesh. These are typically dependent variables like laminar
607  ! viscosity, or residuals, time step, etc. Exceptions are
608  ! pressure and eddy viscosity. Although these are dependent
609  ! variables, they are allocated on all grid levels.
610  !
611  use block
612  use constants
613  use flowvarrefstate
614  use inputphysics
616  use inputiteration
617  use inputunsteady
618  use iteration
619  use utils, only: terminate
620  implicit none
621  !
622  ! Subroutine arguments.
623  !
624  integer(kind=intType), intent(in) :: sps, level
625  !
626  ! Local variables.
627  !
628  integer :: ierr
629 
630  integer(kind=intType) :: nn, mm
631  integer(kind=intType) :: il, jl, kl, ie, je, ke, ib, jb, kb
632 
633  ! Loop over the domains.
634 
635  domains: do nn = 1, ndom
636 
637  ! Store some dimensions a bit easier.
638 
639  il = flowdoms(nn, level, sps)%il
640  jl = flowdoms(nn, level, sps)%jl
641  kl = flowdoms(nn, level, sps)%kl
642 
643  ie = flowdoms(nn, level, sps)%ie
644  je = flowdoms(nn, level, sps)%je
645  ke = flowdoms(nn, level, sps)%ke
646 
647  ib = flowdoms(nn, level, sps)%ib
648  jb = flowdoms(nn, level, sps)%jb
649  kb = flowdoms(nn, level, sps)%kb
650 
651  ! Block is moving. Allocate the memory for s, sFaceI,
652  ! sFaceJ and sFaceK.
653 
654  allocate (flowdoms(nn, level, sps)%s(ie, je, ke, 3), &
655  flowdoms(nn, level, sps)%sFaceI(0:ie, je, ke), &
656  flowdoms(nn, level, sps)%sFaceJ(ie, 0:je, ke), &
657  flowdoms(nn, level, sps)%sFaceK(ie, je, 0:ke), stat=ierr)
658  if (ierr /= 0) &
659  call terminate("allocMemFlovarPart2", &
660  "Memory allocation failure for s, &
661  &sFaceI, sFaceJ and sFaceK.")
662 
663  ! Extra face velocities for ALE
664  if (equationmode == unsteady .and. useale) then
665  allocate ( &
666  flowdoms(nn, level, sps)%sVeloIALE(0:ie, je, ke, 3), &
667  flowdoms(nn, level, sps)%sVeloJALE(ie, 0:je, ke, 3), &
668  flowdoms(nn, level, sps)%sVeloKALE(ie, je, 0:ke, 3), &
669  flowdoms(nn, level, sps)%sFaceIALE(0:nalesteps, 0:ie, je, ke), &
670  flowdoms(nn, level, sps)%sFaceJALE(0:nalesteps, ie, 0:je, ke), &
671  flowdoms(nn, level, sps)%sFaceKALE(0:nalesteps, ie, je, 0:ke), stat=ierr)
672  if (ierr /= 0) &
673  call terminate("allocMemFlovarPart2", &
674  "Memory allocation failure for &
675  &sVeloIALE, sVeloJALE and sVeloKALE; &
676  &sFaceIALE, sFaceJALE and sFaceKALE.")
677  end if
678 
679  ! Test if we are on the finest mesh.
680 
681  fineleveltest: if (level == 1) then
682 
683  ! Allocate the memory that must always be allocated.
684 
685  allocate ( &
686  flowdoms(nn, level, sps)%dw(0:ib, 0:jb, 0:kb, 1:nw), &
687  flowdoms(nn, level, sps)%fw(0:ib, 0:jb, 0:kb, 1:nwf), &
688  flowdoms(nn, level, sps)%dtl(1:ie, 1:je, 1:ke), &
689  flowdoms(nn, level, sps)%radI(1:ie, 1:je, 1:ke), &
690  flowdoms(nn, level, sps)%radJ(1:ie, 1:je, 1:ke), &
691  flowdoms(nn, level, sps)%radK(1:ie, 1:je, 1:ke), &
692  flowdoms(nn, level, sps)%scratch(0:ib, 0:jb, 0:kb, 10), &
693  flowdoms(nn, level, sps)%shockSensor(0:ib, 0:jb, 0:kb), &
694  stat=ierr)
695  if (ierr /= 0) &
696  call terminate("allocMemFlovarPart2", &
697  "Memory allocation failure for dw, fw, dwOld, fwOld, &
698  &gamma, dtl and the spectral radii.")
699 
700  ! Initialize dw and fw to zero.
701 
702  flowdoms(nn, level, sps)%dw = zero
703  flowdoms(nn, level, sps)%fw = zero
704 
705  ! Extra variables for ALE
706  if (equationmode == unsteady .and. useale) then
707  allocate ( &
708  flowdoms(nn, level, sps)%dwALE(0:nalesteps, 0:ib, 0:jb, 0:kb, 1:nw), &
709  flowdoms(nn, level, sps)%fwALE(0:nalesteps, 0:ib, 0:jb, 0:kb, 1:nwf), &
710  stat=ierr)
711  if (ierr /= 0) &
712  call terminate("allocMemFlovarPart2", &
713  "Memory allocation failure for dwALE, fwALE.")
714 
715  flowdoms(nn, level, sps)%dwALE = zero
716  flowdoms(nn, level, sps)%fwALE = zero
717  end if
718 
719  ! Allocate the memory for the zeroth runge kutta stage
720  allocate (flowdoms(nn, level, sps)%wn(2:il, 2:jl, 2:kl, 1:nwf), &
721  flowdoms(nn, level, sps)%pn(2:il, 2:jl, 2:kl), stat=ierr)
722  if (ierr /= 0) &
723  call terminate("allocMemFlovarPart2", &
724  "Memory allocation failure for wn and pn")
725 
726  ! For unsteady mode using Runge-Kutta schemes allocate the
727  ! memory for dwOldRK.
728 
729  if (equationmode == unsteady .and. &
731 
732  mm = nrkstagesunsteady - 1
733  allocate (flowdoms(nn, level, sps)%dwOldRK(mm, il, jl, kl, nw), &
734  stat=ierr)
735  if (ierr /= 0) &
736  call terminate("allocMemFlovarPart2", &
737  "Memory allocation failure for dwOldRK.")
738  end if
739 
740  else fineleveltest
741 
742  ! Coarser level. Allocate the memory for the multigrid
743  ! forcing term and the state variables upon entry.
744 
745  allocate (flowdoms(nn, level, sps)%p1(1:ie, 1:je, 1:ke), &
746  flowdoms(nn, level, sps)%w1(1:ie, 1:je, 1:ke, 1:nwf), &
747  flowdoms(nn, level, sps)%wr(2:il, 2:jl, 2:kl, 1:nwf), &
748  stat=ierr)
749  if (ierr /= 0) &
750  call terminate("allocMemFlovarPart2", &
751  "Memory allocation failure for p1, w1 &
752  &and wr")
753 
754  ! Initialize w1 and p1 to zero, just that they
755  ! are initialized.
756 
757  flowdoms(nn, level, sps)%p1 = zero
758  flowdoms(nn, level, sps)%w1 = zero
759 
760  end if fineleveltest
761 
762  end do domains
763 
764  end subroutine allocmemflovarpart2
765 
766  subroutine allocrestartfiles(nFiles)
767  !
768  ! Allocate memory for the restartfles *
769  ! The array is populated from Python using setRestartFiles
770  ! If memeory has been allocated for the array there exist at
771  ! least one element in the array.
772  !
773  use constants
774  use inputio, only: restartfiles
775  use utils, only: terminate
776  implicit none
777  !
778  ! Subroutine argument.
779  !
780  integer(kind=intType) :: nFiles
781  !
782  ! Local variables.
783  !
784  integer :: ierr
785 
786  if (allocated(restartfiles)) then
787  deallocate (restartfiles)
788  end if
789 
790  allocate (restartfiles(nfiles), stat=ierr)
791  if (ierr /= 0) &
792  call terminate("allocRestartFiles", &
793  "Memory allocation failure for restartFiles")
794 
795  ! Zero Array with empty strings
796  restartfiles = ""
797 
798  end subroutine allocrestartfiles
799 
801  !
802  ! copySpectralSolution copies the solution of the 1st spectral
803  ! solution to all spectral solutions. This typically occurs when
804  ! a for the spectral mode a restart is made from a steady or an
805  ! unsteady solution. Possible rotation effects are taken into
806  ! account for the velocity components.
807  !
808  use constants
809  use block, only: flowdoms, ndom
810  use flowvarrefstate, only: nw
812  use iomodule, only: iovar
813  use monitor, only: timeunsteadyrestart
814  use section, only: sections, nsections
815  use utils, only: rotmatrixrigidbody
816  implicit none
817  !
818  ! Local variables.
819  !
820  integer(kind=intType) :: sps, spsm1, mm, nn, i, j, k, l
821 
822  real(kind=realtype) :: dt, tnew, told, tmp
823  real(kind=realtype) :: theta, costheta, sintheta
824 
825  real(kind=realtype), dimension(3) :: rotpoint, uu
826  real(kind=realtype), dimension(3) :: xt, yt, zt
827  real(kind=realtype), dimension(3, 3) :: rotmat
828 
829  real(kind=realtype), dimension(nSections, 3, 3) :: rotmatsec
830 
831  ! Determine the rotation matrix from one spectral solution to the
832  ! other for every section.
833 
834  sectionloop: do nn = 1, nsections
835 
836  ! Test if the section is rotating.
837 
838  testrotating: if (sections(nn)%rotating) then
839 
840  ! Section is rotating. Determine the angle between the
841  ! spectral solutions and its sine and cosine.
842 
843  i = sections(nn)%nSlices * ntimeintervalsspectral
844  theta = two * pi / real(i, realtype)
845  costheta = cos(theta)
846  sintheta = sin(theta)
847 
848  ! Transform to a frame where the xt-axis points in the
849  ! direction of the rotation vector.
850 
851  xt(1) = sections(nn)%rotAxis(1)
852  xt(2) = sections(nn)%rotAxis(2)
853  xt(3) = sections(nn)%rotAxis(3)
854 
855  ! Construct the yt axis. It does not matter exactly as long
856  ! as it is normal to xt.
857 
858  if (abs(xt(2)) < 0.707107_realtype) then
859  yt(1) = zero
860  yt(2) = one
861  yt(3) = zero
862  else
863  yt(1) = zero
864  yt(2) = zero
865  yt(3) = one
866  end if
867 
868  ! Make sure that yt is normal to xt.
869 
870  tmp = xt(1) * yt(1) + xt(2) * yt(2) + xt(3) * yt(3)
871  yt(1) = yt(1) - tmp * xt(1)
872  yt(2) = yt(2) - tmp * xt(2)
873  yt(3) = yt(3) - tmp * xt(3)
874 
875  ! And create a unit vector.
876 
877  tmp = one / sqrt(yt(1)**2 + yt(2)**2 + yt(3)**2)
878  yt(1) = tmp * yt(1)
879  yt(2) = tmp * yt(2)
880  yt(3) = tmp * yt(3)
881 
882  ! Create the vector zt by taking the cross product xt*yt.
883 
884  zt(1) = xt(2) * yt(3) - xt(3) * yt(2)
885  zt(2) = xt(3) * yt(1) - xt(1) * yt(3)
886  zt(3) = xt(1) * yt(2) - xt(2) * yt(1)
887 
888  ! The rotation matrix in the xt,yt,zt frame is given by
889  !
890  ! R = | 1 0 0 |
891  ! | 0 cos(theta) -sin(theta) |
892  ! | 0 sin(theta) cos(theta) |
893  !
894  ! The rotation matrix in the standard cartesian frame is then
895  ! given by t * r * t^t, where the colums of the transformation
896  ! matrix t are the unit vectors xt,yt,zt. One can easily check
897  ! this by checking rotation around the y- and z-axis. The
898  ! result of this is the expression below.
899 
900  rotmatsec(nn, 1, 1) = xt(1) * xt(1) &
901  + costheta * (yt(1) * yt(1) + zt(1) * zt(1))
902  rotmatsec(nn, 1, 2) = xt(1) * xt(2) &
903  + costheta * (yt(1) * yt(2) + zt(1) * zt(2)) &
904  - sintheta * (yt(1) * zt(2) - yt(2) * zt(1))
905  rotmatsec(nn, 1, 3) = xt(1) * xt(3) &
906  + costheta * (yt(1) * yt(3) + zt(1) * zt(3)) &
907  - sintheta * (yt(1) * zt(3) - yt(3) * zt(1))
908 
909  rotmatsec(nn, 2, 1) = xt(1) * xt(2) &
910  + costheta * (yt(1) * yt(2) + zt(1) * zt(2)) &
911  + sintheta * (yt(1) * zt(2) - yt(2) * zt(1))
912  rotmatsec(nn, 2, 2) = xt(2) * xt(2) &
913  + costheta * (yt(2) * yt(2) + zt(2) * zt(2))
914  rotmatsec(nn, 2, 3) = xt(2) * xt(3) &
915  + costheta * (yt(2) * yt(3) + zt(2) * zt(3)) &
916  - sintheta * (yt(2) * zt(3) - yt(3) * zt(2))
917 
918  rotmatsec(nn, 3, 1) = xt(1) * xt(3) &
919  + costheta * (yt(1) * yt(3) + zt(1) * zt(3)) &
920  + sintheta * (yt(1) * zt(3) - yt(3) * zt(1))
921  rotmatsec(nn, 3, 2) = xt(2) * xt(3) &
922  + costheta * (yt(2) * yt(3) + zt(2) * zt(3)) &
923  + sintheta * (yt(2) * zt(3) - yt(3) * zt(2))
924  rotmatsec(nn, 3, 3) = xt(3) * xt(3) &
925  + costheta * (yt(3) * yt(3) + zt(3) * zt(3))
926 
927  else testrotating
928 
929  ! Section is not rotating. Set the rotation matrix to the
930  ! identity matrix.
931 
932  rotmatsec(nn, 1, 1) = one
933  rotmatsec(nn, 1, 2) = zero
934  rotmatsec(nn, 1, 3) = zero
935 
936  rotmatsec(nn, 2, 1) = zero
937  rotmatsec(nn, 2, 2) = one
938  rotmatsec(nn, 2, 3) = zero
939 
940  rotmatsec(nn, 3, 1) = zero
941  rotmatsec(nn, 3, 2) = zero
942  rotmatsec(nn, 3, 3) = one
943 
944  end if testrotating
945 
946  end do sectionloop
947 
948  ! Initialize told to timeUnsteadyRestart. This takes the
949  ! possibility into account that the spectral mode is restarted
950  ! from an unsteady computation. Although not likely this
951  ! possibility is allowed and should therefore be taken into
952  ! account. Anyway told corresponds to the time of the 1st
953  ! spectral solution. Also determine the time step between the
954  ! spectral solutions. Both told and dt are only used to determine
955  ! the rigid body motion and if these are specified it is assumed
956  ! that there is only one section present in the grid.
957 
958  told = timeunsteadyrestart
959  dt = sections(1)%timePeriod &
960  / real(ntimeintervalsspectral, realtype)
961 
962  ! Loop over the number of spectral modes, starting at 2.
963 
964  spectralloop: do sps = 2, ntimeintervalsspectral
965 
966  ! Determine the corresponding time for this spectral solution
967  ! and store sps - 1 a bit easier.
968 
969  tnew = told + dt
970  spsm1 = sps - 1
971 
972  ! Determine the rotation matrix and rotation point between the
973  ! told and tnew for the rigid body rotation of the entire mesh.
974  ! The rotation point is not needed for the transformation of the
975  ! velocities, but rotMatrixRigidBody happens to compute it.
976 
977  call rotmatrixrigidbody(tnew, told, rotmat, rotpoint)
978 
979  ! Loop over the local number of blocks.
980 
981  domains: do nn = 1, ndom
982 
983  ! Store the section ID of this block a bit easier in mm.
984 
985  mm = flowdoms(nn, 1, 1)%sectionId
986 
987  ! Loop over the owned cells of this block. As the number of
988  ! cells is identical for all spectral solutions, it does not
989  ! matter which mode is taken for the upper dimensions.
990 
991  do k = 2, flowdoms(nn, 1, 1)%kl
992  do j = 2, flowdoms(nn, 1, 1)%jl
993  do i = 2, flowdoms(nn, 1, 1)%il
994 
995  ! Step 1. Copy the solution variables w from
996  ! the previous spectral solution.
997 
998  do l = 1, nw
999  iovar(nn, sps)%w(i, j, k, l) = iovar(nn, spsm1)%w(i, j, k, l)
1000  end do
1001 
1002  ! Step 2. Apply the rigid body motion rotation matrix
1003  ! to the velocity. Use uu as a temporary storage.
1004 
1005  uu(1) = rotmat(1, 1) * iovar(nn, sps)%w(i, j, k, ivx) &
1006  + rotmat(1, 2) * iovar(nn, sps)%w(i, j, k, ivy) &
1007  + rotmat(1, 3) * iovar(nn, sps)%w(i, j, k, ivz)
1008 
1009  uu(2) = rotmat(2, 1) * iovar(nn, sps)%w(i, j, k, ivx) &
1010  + rotmat(2, 2) * iovar(nn, sps)%w(i, j, k, ivy) &
1011  + rotmat(2, 3) * iovar(nn, sps)%w(i, j, k, ivz)
1012 
1013  uu(3) = rotmat(3, 1) * iovar(nn, sps)%w(i, j, k, ivx) &
1014  + rotmat(3, 2) * iovar(nn, sps)%w(i, j, k, ivy) &
1015  + rotmat(3, 3) * iovar(nn, sps)%w(i, j, k, ivz)
1016 
1017  ! Step 3. Apply the rotation matrix of the section to
1018  ! the velocity.
1019 
1020  iovar(nn, sps)%w(i, j, k, ivx) = rotmatsec(mm, 1, 1) * uu(1) &
1021  + rotmatsec(mm, 1, 2) * uu(2) &
1022  + rotmatsec(mm, 1, 3) * uu(3)
1023 
1024  iovar(nn, sps)%w(i, j, k, ivy) = rotmatsec(mm, 2, 1) * uu(1) &
1025  + rotmatsec(mm, 2, 2) * uu(2) &
1026  + rotmatsec(mm, 2, 3) * uu(3)
1027 
1028  iovar(nn, sps)%w(i, j, k, ivz) = rotmatsec(mm, 3, 1) * uu(1) &
1029  + rotmatsec(mm, 3, 2) * uu(2) &
1030  + rotmatsec(mm, 3, 3) * uu(3)
1031  end do
1032  end do
1033  end do
1034 
1035  end do domains
1036 
1037  ! Set told to tnew for the next spectral solution.
1038 
1039  told = tnew
1040 
1041  end do spectralloop
1042 
1043  end subroutine copyspectralsolution
1044 
1046  !
1047  ! determineSolFileNames determines the number and names of the
1048  ! files that contain the solutions. For steady computations only
1049  ! one file must be present. For unsteady the situation is a
1050  ! little more complicated. It is attempted to read as many
1051  ! solutions as needed for a consistent restart. If not possible
1052  ! as many as possible solutions are read. For an unsteady
1053  ! computation the order will be reduced; for time spectral mode
1054  ! the solution will be interpolated.
1055  !
1056  use constants
1057  use communication, only: myid
1058  use inputio, only: restartfiles
1059  use inputphysics, only: equationmode
1063  use utils, only: terminate
1064  implicit none
1065  !
1066  ! Local variables
1067  !
1068  integer :: ierr
1069 
1070  integer(kind=intType) :: ii, nn
1071 
1072  character(len=7) :: integerString
1073  character(len=maxStringLen) :: tmpName
1074 
1075  ! Initialize copySpectral and interpolSpectral to .false.
1076 
1077  copyspectral = .false.
1078  interpolspectral = .false.
1079 
1080  ! Determine the desired number of files to be read. This depends
1081  ! on the equation mode we have to solve for. Also set the
1082  ! corresponding file names.
1083 
1084  select case (equationmode)
1085 
1086  case (steady)
1087 
1088  ! Steady computation. Only one solution needs to be read.
1089  ! In case a list of restart files were provided in the python
1090  ! script, we force a read from only the first solution file.
1091 
1092  nsolsread = 1
1093  allocate (solfiles(nsolsread), stat=ierr)
1094  if (ierr /= 0) &
1095  call terminate("determineSolFileNames", &
1096  "Memory allocation failure for solFiles")
1097 
1098  solfiles(1) = restartfiles(1)
1099 
1100  ! Check if the files can be opened, exit if that fails.
1101  call checksolfilenames()
1102 
1103  !===============================================================
1104 
1105  case (unsteady)
1106 
1107  ! Unsteady computation. For a consistent restart nOldLevels
1108  ! solutions must be read. All restart files are provided explicitly
1109  ! from python script.
1110  call setsolfilenames()
1111 
1112  ! Check if the files can be opened, exit if that fails.
1113  call checksolfilenames()
1114 
1115  ! Set nOldSolAvail to nSolsRead and check if a consistent
1116  ! restart can be made. If not, processor 0 prints a warning.
1117 
1119  if (myid == 0 .and. noldsolavail < noldlevels) then
1120 
1121  print "(a)", "#"
1122  print "(a)", "# Warning"
1123  print "(a)", "# Not enough data found for a consistent &
1124  &time accurate restart."
1125  print "(a)", "# Order is reduced in the first time steps &
1126  &until enough data is available again."
1127  print "(a)", "#"
1128 
1129  end if
1130 
1131  ! Set the logicals oldSolWritten, such that nothing is
1132  ! overwritten when solution files are dumped for this
1133  ! computation.
1134 
1135  ii = min(nsolsread, noldlevels - 1)
1136  do nn = 1, ii
1137  oldsolwritten(nn) = .true.
1138  end do
1139 
1140  !===============================================================
1141 
1142  case (timespectral)
1143 
1144  ! Time spectral computation. For a consistent restart
1145  ! nTimeIntervalsSpectral solutions must be read. First
1146  ! determine the the restart files.
1147  call setsolfilenames()
1148 
1149  ! Check if the files can be opened, exit if that fails.
1150  call checksolfilenames()
1151 
1152  ! Check whether or not the spectral solution must be copied
1153  ! or interpolated.
1154 
1155  if (nsolsread == 1) then
1156  copyspectral = .true.
1157  else if (nsolsread /= ntimeintervalsspectral) then
1158  interpolspectral = .true.
1159  end if
1160 
1161  end select
1162 
1163  end subroutine determinesolfilenames
1164 
1165  subroutine setsolfilenames
1166  !
1167  ! setSolFileNames allocates and set the solution files that
1168  ! will be read and loaded in the restart
1169  !
1170  use communication
1171  use inputio
1172  use utils, only: terminate
1173  use variablereading, only: solfiles, nsolsread
1174  implicit none
1175  !
1176  ! Local variables
1177  !
1178  integer :: ierr
1179  integer(kind=intType) :: nn
1180 
1181  ! The length of the array provided gives the number of nSolsRead.
1182  nsolsread = SIZE(restartfiles, 1)
1183 
1184  ! Allocate the memory for the file names and set them.
1185  allocate (solfiles(nsolsread), stat=ierr)
1186  if (ierr /= 0) &
1187  call terminate("determineSolFileNames", &
1188  "Memory allocation failure for solFiles")
1189 
1190  do nn = 1, nsolsread
1191  solfiles(nn) = restartfiles(nn)
1192  end do
1193 
1194  end subroutine setsolfilenames
1195 
1197  !
1198  ! checkSolFileNames will check if the provided restart files
1199  ! are readable on disk. If not readable return fail, if readable
1200  ! message will be printed to let the user know that restart file
1201  ! will be tried to read.
1202  !
1203  use communication
1204  use utils, only: terminate
1205  use variablereading, only: solfiles, nsolsread
1206  use commonformats, only: strings
1207  implicit none
1208  !
1209  ! Local variables
1210  !
1211  integer :: ierr
1212  character(len=maxStringLen) :: errorMessage
1213  integer(kind=intType) :: nn
1214 
1215  do nn = 1, nsolsread
1216  open (unit=21, file=solfiles(nn), status="old", iostat=ierr)
1217  if (ierr /= 0) then
1218  write (errormessage, *) "Restart file ", trim(solfiles(nn)), &
1219  " could not be opened for reading"
1220  call terminate("checkSolFileNames", errormessage)
1221  exit
1222  end if
1223  close (unit=21)
1224 
1225  if (myid == 0) then
1226  print "(a)", "#"
1227  write (*, strings) "# Found restart file: ", trim(solfiles(nn))
1228  print "(a)", "#"
1229  end if
1230  end do
1231 
1232  end subroutine checksolfilenames
1233 
1234  subroutine initdepvarandhalos(halosRead)
1235  !
1236  ! InitDepvarAndHalos computes the dependent flow variables,
1237  ! like viscosities, and initializes the halo cells by applying
1238  ! the boundary conditions and exchanging the internal halo's.
1239  ! This is all done on the start level grid.
1240  !
1241  use blockpointers
1242  use flowvarrefstate
1243  use inputio
1244  use inputiteration
1245  use inputphysics
1246  use inputtimespectral
1247  use iteration
1248  use monitor
1249  use section
1250  use utils, only: setpointers
1251  use haloexchange, only: whalo2
1252  use turbutils, only: computeeddyviscosity
1253  use turbbcroutines, only: applyallturbbc
1256  use flowutils, only: computelamviscosity
1257  use bcroutines, only: applyallbc
1258  use residuals, only: residual
1259  implicit none
1260  !
1261  ! Subroutine arguments.
1262  !
1263  logical, intent(in) :: halosRead
1264  !
1265  ! Local variables.
1266  !
1267  integer(kind=intType) :: nn, mm
1268  real(kind=realtype) :: relaxbleedsor
1269 
1270  real(kind=realtype), dimension(nSections) :: t
1271 
1272  logical :: initBleeds
1273 
1274  ! Set the logical whether or not to initialize the prescribed
1275  ! data for the bleed regions. If the halos were read the bleeds
1276  ! have been initialized already and nothing needs to be done.
1277 
1278  if (halosread) then
1279  initbleeds = .false.
1280  else
1281  initbleeds = .true.
1282  end if
1283 
1284  ! Compute the face velocities and for viscous walls the slip
1285  ! velocities. This is done for all the mesh levels.
1286 
1287  currentlevel = 1
1288  groundlevel = 1
1289 
1290  do mm = 1, ntimeintervalsspectral
1291 
1292  ! Compute the time, which corresponds to this spectral solution.
1293  ! For steady and unsteady mode this is simply the restart time;
1294  ! for the spectral mode the periodic time must be taken into
1295  ! account, which can be different for every section.
1296 
1298 
1299  if (equationmode == timespectral) then
1300  do nn = 1, nsections
1301  t(nn) = t(nn) + (mm - 1) * sections(nn)%timePeriod &
1302  / real(ntimeintervalsspectral, realtype)
1303  end do
1304  end if
1305  call gridvelocitiesfinelevel(.false., t, mm)
1307  call normalvelocitiesalllevels(mm)
1308 
1309  call slipvelocitiesfinelevel(.false., t, mm)
1311 
1312  end do
1313 
1314  ! Loop over the number of spectral solutions and blocks
1315  ! to compute the laminar viscosity.
1316 
1317  do mm = 1, ntimeintervalsspectral
1318  do nn = 1, ndom
1319  call setpointers(nn, mgstartlevel, mm)
1320  call computelamviscosity(.false.)
1321  end do
1322  end do
1323 
1324  ! Exchange the solution on the multigrid start level.
1325  ! It is possible that the halo values are needed for the boundary
1326  ! conditions. Viscosities are not exchanged.
1327 
1328  call whalo2(mgstartlevel, 1_inttype, nw, .true., .true., &
1329  .false.)
1330 
1331  ! Apply all flow boundary conditions to be sure that the halo's
1332  ! contain the correct values. These might be needed to compute
1333  ! the eddy-viscosity. Also the data for the outflow bleeds
1334  ! is determined.
1335 
1338 
1339  call applyallbc(.true.)
1340 
1341  ! Loop over the number of spectral solutions and blocks
1342  ! to compute the eddy viscosities.
1343 
1344  do mm = 1, ntimeintervalsspectral
1345  do nn = 1, ndom
1346 
1347  ! Set the pointers for this block.
1348 
1349  call setpointers(nn, mgstartlevel, mm)
1350 
1351  ! Compute the eddy viscosity for rans computations using
1352  ! an eddy viscosity model.
1353 
1354  call computeeddyviscosity(.false.)
1355 
1356  ! In case of a rans computation and no restart, initialize
1357  ! the turbulent variables a bit better for some turbulence
1358  ! models.
1359 
1360  ! if(equations == RANSEquations .and. (.not. restart)) then
1361  !
1362  ! select case (turbModel)
1363  !
1364  ! case (komegaWilcox, komegaModified, menterSST)
1365  ! call initKOmega(0_intType)
1366  ! call computeEddyViscosity
1367  !
1368  ! end select
1369  !
1370  ! endif
1371 
1372  end do
1373  end do
1374 
1375  ! Exchange the laminar and eddy viscosities.
1376 
1377  call whalo2(mgstartlevel, 1_inttype, 0_inttype, .false., &
1378  .false., .true.)
1379 
1380  if (equations == ransequations) then
1381  call applyallturbbc(.true.)
1382  end if
1383  call applyallbc(.true.)
1384 
1385  ! Exchange the solution for the second time to be sure that all
1386  ! halo's are initialized correctly. As this is the initialization
1387  ! phase, this is not critical.
1388 
1389  call whalo2(mgstartlevel, 1_inttype, nw, .true., .true., &
1390  .true.)
1391 
1392  end subroutine initdepvarandhalos
1393 
1394  subroutine initflowrestart
1395  !
1396  ! initFlowRestart loads restart information from the restart
1397  ! file into the state variables.
1398  !
1399  use constants
1400  use iomodule, only: iovar
1402  halosread
1403  use utils, only: terminate
1404  implicit none
1405  !
1406  ! Local variables.
1407  !
1408  integer(kind=intType) :: ierr
1409 
1410  ! Initialize halosRead to .false. This will be overwritten
1411  ! if halo values are read during the restart.
1412 
1413  halosread = .false.
1414 
1415  ! Determine the number and names of the solution files and
1416  ! determine the contents of IOVar, the data structure to
1417  ! generalize the IO.
1418 
1420  call setiovar
1421 
1422  ! Determine the format of the files and read them.
1423  ! Note that halosRead is possibly overwritten in the
1424  ! folloing select case statement below
1425 
1426  call readrestartfile()
1427 
1428  ! Copy or interpolate the spectral solution, if needed.
1429 
1432 
1433  ! Release the memory of the file names and IOVar.
1434 
1435  deallocate (solfiles, iovar, stat=ierr)
1436  if (ierr /= 0) &
1437  call terminate("initFlow", &
1438  "Deallocation failure for solFiles and IOVar")
1439 
1440  ! At the moment the pressure is stored at the location of the
1441  ! total energy. Copy the pressure to its own arrays and
1442  ! compute the total energy.
1443 
1445 
1446  ! Initialize the halo cells if a restart is performed and the
1447  ! entire flow field if this is not the case.
1448 
1450 
1451  ! Initialize the dependent flow variables and the halo values.
1453 
1454  end subroutine initflowrestart
1455 
1456  subroutine initflowfield
1457  !
1458  ! initFlowfield initializes the flow field to a uniform flow on
1459  ! the start level grid. Exception may be some turbulence
1460  ! variables, which are initialized a bit smarter.
1461  !
1462  use constants
1463  use communication, only: myid
1464  use inputiteration, only: ncycles, nsgstartup
1465  use inputphysics, only: equationmode
1466  use inputunsteady, only: ntimestepsfine
1467  use iteration, only: noldsolavail
1470  implicit none
1471  !
1472  ! Local variables.
1473  !
1474  integer(kind=intType) :: nn
1475 
1476  ! Initialize nTimeStepsRestart to 0 (no restart
1477  ! is performed) and allocate the memory for the arrays to store
1478  ! convergence history. This allocation is only to be done by
1479  ! processor 0. For an unsteady computation the entire convergence
1480  ! history is stored and the values after every time step is
1481  ! stored in a separate array.
1482 
1483  ntimestepsrestart = 0
1485 
1486  nn = nsgstartup + ncycles
1487  if (equationmode == unsteady) nn = ntimestepsfine * nn
1488  if (myid == 0) call allocconvarrays(nn)
1489  if (equationmode == unsteady .and. myid == 0) &
1491 
1492  ! Set nOldSolAvail to 1, to indicate that an unsteady
1493  ! computation should be started with a lower order
1494  ! time integration scheme, because not enough states
1495  ! in the past are available.
1496 
1497  noldsolavail = 1
1498 
1499  ! Initialize the flow field to uniform flow.
1500 
1501  call setuniformflow
1502 
1503  end subroutine initflowfield
1504 
1505  subroutine initializehalos(halosRead)
1506  !
1507  ! initializeHalos sets the flow variables in the halo cells
1508  ! using a constant extrapolation. If the halos are read only the
1509  ! second halos are initialized, otherwise both.
1510  !
1511  use constants
1512  use blockpointers, only: ndom, w, p, rlv, ib, jb, kb, &
1513  il, ie, jl, je, kl, ke, rev
1514  use flowvarrefstate, only: viscous, nw, eddymodel, muinf
1515  use inputiteration, only: mgstartlevel
1516  use inputphysics, only: eddyvisinfratio
1518  use utils, only: setpointers
1519  implicit none
1520  !
1521  ! Subroutine arguments.
1522  !
1523  logical, intent(in) :: halosRead
1524  !
1525  ! Local variables.
1526  !
1527  integer(kind=intType) :: nn, mm, i, j, k, l
1528  integer(kind=intType) :: jj, kk
1529 
1530  ! Loop over the number of spectral solutions and blocks.
1531 
1532  spectralloop: do mm = 1, ntimeintervalsspectral
1533  domains: do nn = 1, ndom
1534 
1535  ! Set the pointers for this block.
1536 
1537  call setpointers(nn, mgstartlevel, mm)
1538 
1539  ! Determine the situation we are dealing with.
1540 
1541  testhalosread: if (halosread) then
1542 
1543  ! The first layer of halo cells have been read. Initialize
1544  ! the second layer from the first layer.
1545 
1546  ! Halo cells in the i-direction.
1547 
1548  do k = 0, kb
1549  kk = max(1_inttype, min(k, ke))
1550  do j = 0, jb
1551  jj = max(1_inttype, min(j, je))
1552 
1553  do l = 1, nw
1554  w(0, j, k, l) = w(1, jj, kk, l)
1555  w(ib, j, k, l) = w(ie, jj, kk, l)
1556  end do
1557 
1558  p(0, j, k) = p(1, jj, kk)
1559  p(ib, j, k) = p(ie, jj, kk)
1560 
1561  end do
1562  end do
1563 
1564  ! Halo cells in j-direction. Note that the i-halo's have
1565  ! already been set.
1566 
1567  do k = 0, kb
1568  kk = max(1_inttype, min(k, ke))
1569  do i = 1, ie
1570 
1571  do l = 1, nw
1572  w(i, 0, k, l) = w(i, 1, kk, l)
1573  w(i, jb, k, l) = w(i, je, kk, l)
1574  end do
1575 
1576  p(i, 0, k) = p(i, 1, kk)
1577  p(i, jb, k) = p(i, je, kk)
1578 
1579  end do
1580  end do
1581 
1582  ! Halo cells in k-direction. Note that the halo's in both
1583  ! i and j direction have already been set.
1584 
1585  do j = 1, je
1586  do i = 1, ie
1587 
1588  do l = 1, nw
1589  w(i, j, 0, l) = w(i, j, 1, l)
1590  w(i, j, kb, l) = w(i, j, ke, l)
1591  end do
1592 
1593  p(i, j, 0) = p(i, j, 1)
1594  p(i, j, kb) = p(i, j, ke)
1595 
1596  end do
1597  end do
1598 
1599  else testhalosread
1600 
1601  ! No halo cells have been read. Initialize both layers
1602  ! using the internal value.
1603 
1604  ! Halo cells in the i-direction.
1605 
1606  do k = 0, kb
1607  kk = max(2_inttype, min(k, kl))
1608  do j = 0, jb
1609  jj = max(2_inttype, min(j, jl))
1610 
1611  do l = 1, nw
1612  w(0, j, k, l) = w(2, jj, kk, l)
1613  w(1, j, k, l) = w(2, jj, kk, l)
1614  w(ie, j, k, l) = w(il, jj, kk, l)
1615  w(ib, j, k, l) = w(il, jj, kk, l)
1616  end do
1617 
1618  p(0, j, k) = p(2, jj, kk)
1619  p(1, j, k) = p(2, jj, kk)
1620  p(ie, j, k) = p(il, jj, kk)
1621  p(ib, j, k) = p(il, jj, kk)
1622 
1623  end do
1624  end do
1625 
1626  ! Halo cells in j-direction. Note that the i-halo's have
1627  ! already been set.
1628 
1629  do k = 0, kb
1630  kk = max(2_inttype, min(k, kl))
1631  do i = 2, il
1632 
1633  do l = 1, nw
1634  w(i, 0, k, l) = w(i, 2, kk, l)
1635  w(i, 1, k, l) = w(i, 2, kk, l)
1636  w(i, je, k, l) = w(i, jl, kk, l)
1637  w(i, jb, k, l) = w(i, jl, kk, l)
1638  end do
1639 
1640  p(i, 0, k) = p(i, 2, kk)
1641  p(i, 1, k) = p(i, 2, kk)
1642  p(i, je, k) = p(i, jl, kk)
1643  p(i, jb, k) = p(i, jl, kk)
1644 
1645  end do
1646  end do
1647 
1648  ! Halo cells in k-direction. Note that the halo's in both
1649  ! i and j direction have already been set.
1650 
1651  do j = 2, jl
1652  do i = 2, il
1653 
1654  do l = 1, nw
1655  w(i, j, 0, l) = w(i, j, 2, l)
1656  w(i, j, 1, l) = w(i, j, 2, l)
1657  w(i, j, ke, l) = w(i, j, kl, l)
1658  w(i, j, kb, l) = w(i, j, kl, l)
1659  end do
1660 
1661  p(i, j, 0) = p(i, j, 2)
1662  p(i, j, 1) = p(i, j, 2)
1663  p(i, j, ke) = p(i, j, kl)
1664  p(i, j, kb) = p(i, j, kl)
1665 
1666  end do
1667  end do
1668 
1669  end if testhalosread
1670 
1671  ! Initialize the laminar and eddy viscosity, if appropriate,
1672  ! such that no uninitialized memory is present.
1673  ! As the viscosities are dependent variables their values
1674  ! are not read during a restart.
1675 
1676  if (viscous) rlv = muinf
1678 
1679  end do domains
1680  end do spectralloop
1681 
1682  end subroutine initializehalos
1684  !
1685  ! interpolateSpectralSolution uses a spectral interpolation to
1686  ! determine the initialization of the flow solution.
1687  ! The solution is interpolated from the solution read, which
1688  ! contains a different number of time instances and is stored in
1689  ! IOVar()%w. This variable can be found in IOModule.
1690  !
1691  use constants
1692  use blockpointers, only: w, il, jl, kl, ndom, sectionid
1693  use flowvarrefstate, only: nw
1695  use iomodule, only: iovar
1696  use section, only: sections, nsections
1698  use variablereading, only: nsolsread
1699  implicit none
1700  !
1701  ! Local variables.
1702  !
1703  integer :: ierr
1704 
1705  integer(kind=intType) :: jj, nn, ll, sps, i, j, k, l
1706 
1707  real(kind=realtype) :: t
1708 
1709  real(kind=realtype), dimension(nSolsRead) :: alpscal
1710  real(kind=realtype), dimension(nSections, nSolsRead, 3, 3) :: alpmat
1711 
1712  ! Loop over the number of spectral solutions to be interpolated.
1713 
1714  spectralloop: do sps = 1, ntimeintervalsspectral
1715 
1716  ! Determine the ratio of the time of this solution and the
1717  ! periodic time.
1718 
1719  nn = sps - 1
1720  t = real(nn, realtype) / real(ntimeintervalsspectral, realtype)
1721 
1722  ! Determine the interpolation coefficients for both the scalar
1723  ! and the vector quantities.
1724 
1725  call spectralinterpolcoef(nsolsread, t, alpscal, alpmat)
1726 
1727  ! Loop over the local number of blocks.
1728 
1729  domains: do nn = 1, ndom
1730 
1731  ! Set the pointers for this block to the finest grid level.
1732 
1733  call setpointers(nn, 1_inttype, sps)
1734 
1735  ! Loop over the number of variables to be interpolated.
1736 
1737  varloop: do l = 1, nw
1738 
1739  ! Check if this is a velocity variable.
1740 
1741  veltest: if (l == ivx .or. l == ivy .or. l == ivz) then
1742 
1743  ! Velocity variable. Set ll, which is the row in the
1744  ! matrix coefficients.
1745 
1746  select case (l)
1747  case (ivx)
1748  ll = 1
1749  case (ivy)
1750  ll = 2
1751  case (ivz)
1752  ll = 3
1753  end select
1754 
1755  ! Loop over the owned cells to interpolate the variable.
1756 
1757  do k = 2, kl
1758  do j = 2, jl
1759  do i = 2, il
1760 
1761  ! Initialization to zero and loop over the number of
1762  ! spectral solutions used in the interpolation and
1763  ! update the variable accordingly. Note that for the
1764  ! vector variables the matrix coefficients must be
1765  ! used; these matrices can be different for the
1766  ! sections present in the grid.
1767 
1768  w(i, j, k, l) = zero
1769  do jj = 1, nsolsread
1770  w(i, j, k, l) = w(i, j, k, l) &
1771  + alpmat(sectionid, jj, ll, 1) &
1772  * iovar(nn, jj)%w(i, j, k, ivx) &
1773  + alpmat(sectionid, jj, ll, 2) &
1774  * iovar(nn, jj)%w(i, j, k, ivy) &
1775  + alpmat(sectionid, jj, ll, 3) &
1776  * iovar(nn, jj)%w(i, j, k, ivz)
1777  end do
1778 
1779  end do
1780  end do
1781  end do
1782 
1783  else veltest
1784 
1785  ! Scalar variable.
1786  ! Loop over the owned cells to interpolate the variable.
1787 
1788  do k = 2, kl
1789  do j = 2, jl
1790  do i = 2, il
1791 
1792  ! Initialization to zero and loop over the number of
1793  ! spectral solutions used in the interpolation and
1794  ! update the variable accordingly.
1795 
1796  w(i, j, k, l) = zero
1797  do jj = 1, nsolsread
1798  w(i, j, k, l) = w(i, j, k, l) &
1799  + alpscal(jj) * iovar(nn, jj)%w(i, j, k, l)
1800  end do
1801 
1802  end do
1803  end do
1804  end do
1805 
1806  end if veltest
1807 
1808  end do varloop
1809 
1810  end do domains
1811 
1812  end do spectralloop
1813 
1814  ! Release the memory of w of IOVar.
1815 
1816  do sps = 1, nsolsread
1817  do nn = 1, ndom
1818  deallocate (iovar(nn, sps)%w, stat=ierr)
1819  if (ierr /= 0) &
1820  call terminate("interpolateSpectralSolution", &
1821  "Deallocation failure for w.")
1822  end do
1823  end do
1824 
1825  end subroutine interpolatespectralsolution
1826 
1828  !
1829  ! releaseExtraMemBCs releases the extra memory allocated in
1830  ! allocMemBcdata. This additional memory was allocated, such
1831  ! that alternative boundary condition treatments can be handled
1832  ! in setBCDataFineGrid.
1833  !
1834  use constants
1835  use blockpointers, only: flowdoms, ndom, bctype, bcdata, nbocos
1837  use utils, only: setpointers, terminate
1838  implicit none
1839  !
1840  ! Local variables.
1841  !
1842  integer :: ierr
1843 
1844  integer(kind=intType) :: mm, nn, sps, level, nLevels, ii
1845 
1846  ! Determine the number of multigrid levels.
1847 
1848  nlevels = ubound(flowdoms, 2)
1849 
1850  ! Loop over the number of multigrid level, spectral solutions
1851  ! and local blocks.
1852 
1853  levelloop: do level = 1, nlevels
1854  spectralloop: do sps = 1, ntimeintervalsspectral
1855  domainsloop: do nn = 1, ndom
1856 
1857  ! Have the pointers in blockPointers point to the
1858  ! current block to make everything more readable.
1859 
1860  call setpointers(nn, level, sps)
1861 
1862  ! Loop over the number of boundary subfaces for this block.
1863 
1864  bocoloop: do mm = 1, nbocos
1865 
1866  ! Determine the boundary condition we are having here.
1867 
1868  inflowtype:select case(bctype(mm))
1869 
1870  case (subsonicinflow)
1871 
1872  ! Subsonic inflow. Determine the boundary condition
1873  ! treatment and release the accordingly. Note that
1874  ! the boundary condition treatment of the finest mesh
1875  ! must be used, because this data is not available yet
1876  ! on the coarse grid.
1877 
1878  ii = &
1879  flowdoms(nn, 1, sps)%BCData(mm)%subsonicInletTreatment
1880 
1881  select case (ii)
1882 
1883  case (totalconditions)
1884 
1885  ! Total conditions used. Release the memory for
1886  ! the density and velocities and nullify their
1887  ! pointers.
1888 
1889  deallocate (bcdata(mm)%rho, bcdata(mm)%velx, &
1890  bcdata(mm)%vely, bcdata(mm)%velz, &
1891  stat=ierr)
1892  if (ierr /= 0) &
1893  call terminate("releaseExtraMemBCs", &
1894  "Deallocation failure for rho, &
1895  &velx, vely and velz")
1896 
1897  nullify (bcdata(mm)%rho)
1898  nullify (bcdata(mm)%velx)
1899  nullify (bcdata(mm)%vely)
1900  nullify (bcdata(mm)%velz)
1901  !===================================================
1902 
1903  case (massflow)
1904 
1905  ! Full velocity vector and density prescribed at
1906  ! inlet boundaries. Release the memory for the
1907  ! total conditions and flow directions and nullify
1908  ! their pointers.
1909 
1910  deallocate (bcdata(mm)%ptInlet, &
1911  bcdata(mm)%ttInlet, &
1912  bcdata(mm)%htInlet, &
1913  bcdata(mm)%flowXdirInlet, &
1914  bcdata(mm)%flowYdirInlet, &
1915  bcdata(mm)%flowZdirInlet, stat=ierr)
1916  if (ierr /= 0) &
1917  call terminate("releaseExtraMemBCs", &
1918  "Deallocation failure for the &
1919  &total conditions.")
1920 
1921  nullify (bcdata(mm)%ptInlet)
1922  nullify (bcdata(mm)%ttInlet)
1923  nullify (bcdata(mm)%htInlet)
1924  nullify (bcdata(mm)%flowXdirInlet)
1925  nullify (bcdata(mm)%flowYdirInlet)
1926  nullify (bcdata(mm)%flowZdirInlet)
1927 
1928  end select
1929 
1930  end select inflowtype
1931 
1932  end do bocoloop
1933  end do domainsloop
1934  end do spectralloop
1935  end do levelloop
1936 
1937  end subroutine releaseextramembcs
1938 
1939  subroutine setiovar
1940  !
1941  ! setIOVar allocates the memory for the derived data type IOVar,
1942  ! which is simplifies the reading. If an interpolation must be
1943  ! performed for the time spectral method also the solution of
1944  ! this IO type is allocated. For all other cases the pointers of
1945  ! IOVar are set the the appropriate entries of flowDoms, with
1946  ! possible offset due to the usage of pointers.
1947  !
1948  use constants
1949  use block, only: flowdoms, ndom
1950  use flowvarrefstate, only: nw
1951  use inputphysics, only: equationmode
1952  use iomodule, only: iovar
1953  use utils, only: terminate
1955  implicit none
1956  !
1957  ! Local variables.
1958  !
1959  integer :: ierr
1960 
1961  integer(kind=intType) :: nn, mm, il, jl, kl
1962 
1963  ! Allocate the memory for IOVar.
1964 
1965  allocate (iovar(ndom, nsolsread), stat=ierr)
1966  if (ierr /= 0) &
1967  call terminate("setIOVar", &
1968  "Memory allocation failure for solRead")
1969 
1970  ! Determine the equation mode we are solving and set the pointers
1971  ! of coorRead accordingly, or even allocate the memory, if needed.
1972 
1973  select case (equationmode)
1974 
1975  case (steady)
1976 
1977  ! Steady computation. Only one solution needs to be read.
1978  ! Loop over the number of blocks and set the pointers.
1979  ! No pointer offset is needed.
1980 
1981  do nn = 1, ndom
1982  iovar(nn, 1)%pointerOffset = 0
1983  iovar(nn, 1)%w => flowdoms(nn, 1, 1)%w(1:, 1:, 1:, :)
1984  end do
1985 
1986  !===============================================================
1987 
1988  case (unsteady)
1989 
1990  ! Unsteady computation. The first solution should be stored in
1991  ! w. For the others the pointers point to wOld. As the
1992  ! starting indices of wOld are 2, a pointer shift takes place
1993  ! here. I know this is a pain in the butt, but that's what
1994  ! we have to live with.
1995 
1996  do nn = 1, ndom
1997  iovar(nn, 1)%pointerOffset = 0
1998  iovar(nn, 1)%w => flowdoms(nn, 1, 1)%w(1:, 1:, 1:, :)
1999 
2000  do mm = 2, nsolsread
2001  iovar(nn, mm)%pointerOffset = -1
2002  iovar(nn, mm)%w => flowdoms(nn, 1, 1)%wOld(mm - 1, 2:, 2:, 2:, :)
2003  end do
2004  end do
2005 
2006  !===============================================================
2007 
2008  case (timespectral)
2009 
2010  ! Time spectral mode. A further check is required.
2011 
2012  testallocsolread: if (interpolspectral) then
2013 
2014  ! A restart is performed using a different number of time
2015  ! instances than the previous computation. Consequently the
2016  ! solutions will be interpolated later on. Hence some
2017  ! additional storage is required for the solutions and thus
2018  ! the w variables of IOVar are allocated. No halo data is
2019  ! needed here. No pointer offset either due to the explicit
2020  ! allocation.
2021 
2022  do nn = 1, ndom
2023  il = flowdoms(nn, 1, 1)%il
2024  jl = flowdoms(nn, 1, 1)%jl
2025  kl = flowdoms(nn, 1, 1)%kl
2026 
2027  do mm = 1, nsolsread
2028  iovar(nn, mm)%pointerOffset = 0
2029 
2030  allocate (iovar(nn, mm)%w(2:il, 2:jl, 2:kl, nw), stat=ierr)
2031  if (ierr /= 0) &
2032  call terminate("setIOVar", &
2033  "Memory allocation failure for w")
2034  end do
2035 
2036  end do
2037 
2038  else testallocsolread
2039 
2040  ! A restart is made using either 1 solution or the correct
2041  ! number of solution instances. In both cases simply set
2042  ! the pointers of IOVar. No pointer offset is needed.
2043 
2044  do nn = 1, ndom
2045  do mm = 1, nsolsread
2046  iovar(nn, mm)%pointerOffset = 0
2047  iovar(nn, mm)%w => flowdoms(nn, 1, mm)%w(1:, 1:, 1:, :)
2048  end do
2049  end do
2050 
2051  end if testallocsolread
2052 
2053  end select
2054 
2055  end subroutine setiovar
2056 
2057  subroutine setpressureandcomputeenergy(halosRead)
2058  !
2059  ! Due to the usage of the variable IOVar, which generalizes the
2060  ! IO and leads to reuse of code, currently the pressure is
2061  ! stored at the position of rhoE. In this routine that data is
2062  ! copied to the pressure array and the total energy is computed.
2063  ! Note that this routine is only called when a restart is done.
2064  !
2065  use constants
2066  use blockpointers, only: ndom, p, w, il, jl, kl
2067  use flowvarrefstate, only: kpresent
2069  use utils, only: setpointers
2070  use flowutils, only: computeetotblock
2071  implicit none
2072  !
2073  ! Subroutine arguments.
2074  !
2075  logical, intent(in) :: halosRead
2076  !
2077  ! Local variables.
2078  !
2079  integer(kind=intType) :: sps, nn, nHalo
2080  integer(kind=intType) :: i, j, k
2081  integer(kind=intType) :: iBeg, iEnd, jBeg, jEnd, kBeg, kEnd
2082 
2083  ! Set the value of nHalo, depending whether or not the halo cells
2084  ! have been read from the restart file.
2085 
2086  nhalo = 0
2087  if (halosread) nhalo = 1
2088 
2089  ! Loop over the number of time instances and the local blocks.
2090  ! As this routine is only called when a restart is performed,
2091  ! the MG start level is the finest level.
2092 
2093  do sps = 1, ntimeintervalsspectral
2094  do nn = 1, ndom
2095 
2096  ! Set the pointers to the correct block. As this routine is
2097  ! only called when a restart is performed, the MG start level
2098  ! is the finest level.
2099 
2100  call setpointers(nn, 1_inttype, sps)
2101 
2102  ! Determine the range for which the pressure must be computed.
2103 
2104  ibeg = 2 - nhalo; jbeg = 2 - nhalo; kbeg = 2 - nhalo
2105  iend = il + nhalo; jend = jl + nhalo; kend = kl + nhalo
2106 
2107  ! Copy the pressure for the required cells.
2108 
2109  do k = kbeg, kend
2110  do j = jbeg, jend
2111  do i = ibeg, iend
2112  p(i, j, k) = w(i, j, k, irhoe)
2113  end do
2114  end do
2115  end do
2116 
2117  ! Compute the total energy as well.
2118 
2119  call computeetotblock(ibeg, iend, jbeg, jend, kbeg, kend, kpresent)
2120  end do
2121  end do
2122 
2123  end subroutine setpressureandcomputeenergy
2124  subroutine setrestartfiles(fileName, i)
2125  !
2126  ! Populates the restartfiles
2127  ! The array is populated from Python using setRestartFiles
2128  !
2129  use constants
2130  use inputio, only: restartfiles
2131  implicit none
2132  !
2133  ! Subroutine argument.
2134  !
2135  character(len=*), intent(inout) :: fileName
2136  integer(kind=intType) :: i
2137 
2138  restartfiles(i) = filename
2139 
2140  end subroutine setrestartfiles
2141 
2142  subroutine setuniformflow
2143  !
2144  ! setUniformFlow set the flow variables of all local blocks on
2145  ! the start level to the uniform flow field.
2146  !
2147  use constants
2148  use blockpointers, only: w, dw, fw, flowdoms, ib, jb, kb, &
2149  rev, rlv, ndom, bcdata, p
2150  use communication
2151  use flowvarrefstate, only: eddymodel, viscous, muinf, nw, nwf, &
2152  pinfcorr, winf
2153  use inputiteration, only: mgstartlevel
2156  use utils, only: setpointers
2157  implicit none
2158  !
2159  ! Local variables.
2160  !
2161  integer :: ierr
2162 
2163  integer(kind=intType) :: nn, mm, i, j, k, l
2164 
2165  real(kind=realtype) :: tmp
2166 
2167  real(kind=realtype), dimension(3) :: dirloc, dirglob
2168 
2169  ! Loop over the number of spectral solutions and blocks.
2170  spectralloop: do mm = 1, ntimeintervalsspectral
2171  domains: do nn = 1, ndom
2172 
2173  ! Set the pointers for this block.
2174 
2175  call setpointers(nn, mgstartlevel, mm)
2176 
2177  ! Set the w-variables to the ones of the uniform flow field.
2178  do l = 1, nw
2179  do k = 0, kb
2180  do j = 0, jb
2181  do i = 0, ib
2182  w(i, j, k, l) = winf(l)
2183  dw(i, j, k, l) = zero
2184  end do
2185  end do
2186  end do
2187  end do
2188  !set this here for a reinitialize flow to eliminate possible NAN's
2189  do l = 1, nwf
2190  do k = 0, kb
2191  do j = 0, jb
2192  do i = 0, ib
2193  fw(i, j, k, l) = zero
2194  end do
2195  end do
2196  end do
2197  end do
2198 
2199  ! Set the pressure.
2200 
2201  p = pinfcorr
2202 
2203  ! Initialize the laminar and eddy viscosity, if appropriate,
2204  ! such that no uninitialized memory is present.
2205 
2206  if (viscous) rlv = muinf
2208 
2209  end do domains
2210  end do spectralloop
2211 
2212  ! Correct for the time spectral method in combination with an
2213  ! internal flow computation the velocity direction.
2214  ! It is possible that the prescribed direction is different
2215  ! for every time instance.
2216 
2217  testcorrection: if (equationmode == timespectral .and. &
2218  flowtype == internalflow) then
2219 
2220  ! Loop over the number of spectral solutions.
2221 
2222  spectralloopcorr: do mm = 1, ntimeintervalsspectral
2223 
2224  ! Initialize the local direction to zero. In the loop
2225  ! below this direction will be accumulated.
2226 
2227  dirloc = zero
2228 
2229  ! Loop over the number of blocks and determine the average
2230  ! velocity direction prescribed at the inlets.
2231 
2232  domainloop1: do nn = 1, ndom
2233 
2234  ! Set the pointer for the BCData to make the code more
2235  ! readable.
2236 
2237  bcdata => flowdoms(nn, mgstartlevel, mm)%BCData
2238 
2239  ! Loop over the number of boundary subfaces and update
2240  ! the local prescribed velocity direction.
2241 
2242  do l = 1, flowdoms(nn, mgstartlevel, mm)%nBocos
2243  call velmagnanddirectionsubface(tmp, dirloc, bcdata, l)
2244  end do
2245  end do domainloop1
2246 
2247  ! Determine the sum of dirLoc and create a unit vector
2248  ! for the global direction.
2249 
2250  call mpi_allreduce(dirloc, dirglob, 3, adflow_real, mpi_sum, &
2251  adflow_comm_world, ierr)
2252 
2253  tmp = one / max(eps, sqrt(dirglob(1)**2 &
2254  + dirglob(2)**2 &
2255  + dirglob(3)**2))
2256  dirglob(1) = tmp * dirglob(1)
2257  dirglob(2) = tmp * dirglob(2)
2258  dirglob(3) = tmp * dirglob(3)
2259 
2260  ! Loop again over the local domains and correct the
2261  ! velocity direction.
2262 
2263  domainsloop2: do nn = 1, ndom
2264 
2265  ! Set the pointers for this block.
2266 
2267  call setpointers(nn, mgstartlevel, mm)
2268 
2269  do k = 0, kb
2270  do j = 0, jb
2271  do i = 0, ib
2272  tmp = sqrt(w(i, j, k, ivx)**2 &
2273  + w(i, j, k, ivy)**2 &
2274  + w(i, j, k, ivz)**2)
2275  w(i, j, k, ivx) = tmp * dirglob(1)
2276  w(i, j, k, ivy) = tmp * dirglob(2)
2277  w(i, j, k, ivz) = tmp * dirglob(3)
2278  end do
2279  end do
2280  end do
2281 
2282  end do domainsloop2
2283  end do spectralloopcorr
2284 
2285  end if testcorrection
2286 
2287  end subroutine setuniformflow
2288 
2289  !=================================================================
2290 
2291  subroutine velmagnanddirectionsubface(vmag, dir, BCData, mm)
2292  !
2293  ! VelMagnAndDirectionSubface determines the maximum value
2294  ! of the magnitude of the velocity as well as the sum of the
2295  ! flow directions for the currently active subface.
2296  !
2297  use constants
2298  use block
2299  implicit none
2300  !
2301  ! Subroutine arguments.
2302  !
2303  integer(kind=intType), intent(in) :: mm
2304 
2305  real(kind=realtype), intent(out) :: vmag
2306  real(kind=realtype), dimension(3), intent(inout) :: dir
2307 
2308  type(bcdatatype), dimension(:), pointer :: bcdata
2309  !
2310  ! Local variables.
2311  !
2312  integer(kind=intType) :: i, j
2313  real(kind=realtype) :: vel
2314 
2315  ! Initialize vmag to -1.0.
2316 
2317  vmag = -one
2318 
2319  ! Check if the velocity is prescribed.
2320 
2321  if (associated(bcdata(mm)%velx) .and. &
2322  associated(bcdata(mm)%vely) .and. &
2323  associated(bcdata(mm)%velz)) then
2324 
2325  ! Loop over the owned faces of the subface. As the cell range
2326  ! may contain halo values, the nodal range is used.
2327 
2328  do j = (bcdata(mm)%jnBeg + 1), bcdata(mm)%jnEnd
2329  do i = (bcdata(mm)%inBeg + 1), bcdata(mm)%inEnd
2330 
2331  ! Compute the magnitude of the velocity and compare it
2332  ! with the current maximum. Store the maximum of the two.
2333 
2334  vel = sqrt(bcdata(mm)%velx(i, j)**2 &
2335  + bcdata(mm)%vely(i, j)**2 &
2336  + bcdata(mm)%velz(i, j)**2)
2337  vmag = max(vmag, vel)
2338 
2339  ! Compute the unit vector of the velocity and add it to dir.
2340 
2341  vel = one / max(eps, vel)
2342  dir(1) = dir(1) + vel * bcdata(mm)%velx(i, j)
2343  dir(2) = dir(2) + vel * bcdata(mm)%vely(i, j)
2344  dir(3) = dir(3) + vel * bcdata(mm)%velz(i, j)
2345 
2346  end do
2347  end do
2348  end if
2349 
2350  ! Check if the velocity direction is prescribed.
2351 
2352  if (associated(bcdata(mm)%flowXdirInlet) .and. &
2353  associated(bcdata(mm)%flowYdirInlet) .and. &
2354  associated(bcdata(mm)%flowZdirInlet)) then
2355 
2356  ! Add the unit vectors to dir by looping over the owned
2357  ! faces of the subfaces. Again the nodal range must be
2358  ! used for this.
2359 
2360  do j = (bcdata(mm)%jnBeg + 1), bcdata(mm)%jnEnd
2361  do i = (bcdata(mm)%inBeg + 1), bcdata(mm)%inEnd
2362 
2363  dir(1) = dir(1) + bcdata(mm)%flowXdirInlet(i, j)
2364  dir(2) = dir(2) + bcdata(mm)%flowYdirInlet(i, j)
2365  dir(3) = dir(3) + bcdata(mm)%flowZdirInlet(i, j)
2366 
2367  end do
2368  end do
2369 
2370  end if
2371 
2372  end subroutine velmagnanddirectionsubface
2373  subroutine timespectralcoef(coefSpectral, matrixCoefSpectral, &
2374  diagMatCoefSpectral)
2375  !
2376  ! timeSpectralCoef computes the time integration coefficients
2377  ! for the time spectral method. As it is possible that sections
2378  ! have different periodic times these coefficients are
2379  ! determined for all the sections. For vector quantities, such
2380  ! as momentum, these coefficients can also be different due to
2381  ! rotation and the fact that only a part of the wheel is
2382  ! simulated.
2383  !
2384  use constants
2385  use flowvarrefstate, only: timeref
2387  use section, only: nsections, sections
2388  implicit none
2389  !
2390  ! Subroutine arguments.
2391  !
2392  real(kind=realtype), &
2393  dimension(nSections, nTimeIntervalsSpectral - 1), &
2394  intent(out) :: coefspectral
2395  real(kind=realtype), &
2396  dimension(nSections, nTimeIntervalsSpectral - 1, 3, 3), &
2397  intent(out) :: matrixcoefspectral
2398  real(kind=realtype), dimension(nSections, 3, 3), &
2399  intent(out) :: diagmatcoefspectral
2400  !
2401  ! Local variables.
2402  !
2403  integer(kind=intType) :: pp, nn, mm, ii, i, j, ntot
2404  real(kind=realtype) :: coef, dangle, angle, fact, slicesfact
2405 
2406  real(kind=realtype), dimension(3, 3) :: rotmat, tmp
2407 
2408  ! Loop over the number of sections.
2409 
2410  sectionloop: do mm = 1, nsections
2411 
2412  ! Initialize dAngle (smallest angle in the cotangent function)
2413  ! and coef, which is the multiplication factor in front of the
2414  ! cotangent/cosecant function. Coef is a combination of the 1/2
2415  ! and the 2*pi/timePeriod
2416 
2417  dangle = pi / real(ntimeintervalsspectral, realtype)
2418  coef = pi * timeref / sections(mm)%timePeriod
2419 
2420  ! Computation of the scalar coefficients.
2421 
2422  scalarloop: do nn = 1, (ntimeintervalsspectral - 1)
2423 
2424  angle = nn * dangle
2425 
2426  ! The coefficient for an odd and even number of time
2427  ! instances are different; the former is 1/sin, the
2428  ! latter cos/sin or 1/tan.
2429 
2430  coefspectral(mm, nn) = coef / sin(angle)
2431 
2432  if (mod(ntimeintervalsspectral, 2_inttype) == 0) &
2433  coefspectral(mm, nn) = coefspectral(mm, nn) * cos(angle)
2434 
2435  ! Negate coef for the next spectral coefficient.
2436 
2437  coef = -coef
2438 
2439  end do scalarloop
2440 
2441  ! Initialize dAngle to the smallest angle in the cotangent
2442  ! or cosecant function. Now this angle is for the entire wheel,
2443  ! i.e. the number of slices must be taken into account.
2444 
2445  ntot = ntimeintervalsspectral * sections(mm)%nSlices
2446  dangle = pi / real(ntot, realtype)
2447 
2448  ! Initialize the rotation matrix to the unity matrix.
2449 
2450  rotmat(1, 1) = one; rotmat(1, 2) = zero; rotmat(1, 3) = zero
2451  rotmat(2, 1) = zero; rotmat(2, 2) = one; rotmat(2, 3) = zero
2452  rotmat(3, 1) = zero; rotmat(3, 2) = zero; rotmat(3, 3) = one
2453 
2454  ! Loop over the number of spectral coefficient to initialize the
2455  ! matrix coefficients; this is basically pp == 0 in the loop
2456  ! over the number slices. Use is made of the fact that the
2457  ! rotation matrix is the identity for pp == 0.
2458  ! coef changes sign at every time instance
2459 
2460  slicesfact = one / real(sections(mm)%nSlices, realtype)
2461  fact = one
2462 
2463  do nn = 1, (ntimeintervalsspectral - 1)
2464 
2465  ! Determine the scalar coefficient. This value depends now
2466  ! whether the total number of time instances in the wheel is
2467  ! odd or even.
2468 
2469  angle = nn * dangle
2470  coef = one / sin(angle)
2471 
2472  if (mod(ntot, 2_inttype) == 0) &
2473  coef = coef * cos(angle)
2474 
2475  coef = coef * fact * slicesfact
2476 
2477  ! The first part of matrixCoefSpectral is a diagonal matrix,
2478  ! because this indicates the contribution of the current
2479  ! slice to the time derivative.
2480 
2481  matrixcoefspectral(mm, nn, 1, 1) = coef
2482  matrixcoefspectral(mm, nn, 1, 2) = zero
2483  matrixcoefspectral(mm, nn, 1, 3) = zero
2484 
2485  matrixcoefspectral(mm, nn, 2, 1) = zero
2486  matrixcoefspectral(mm, nn, 2, 2) = coef
2487  matrixcoefspectral(mm, nn, 2, 3) = zero
2488 
2489  matrixcoefspectral(mm, nn, 3, 1) = zero
2490  matrixcoefspectral(mm, nn, 3, 2) = zero
2491  matrixcoefspectral(mm, nn, 3, 3) = coef
2492 
2493  fact = -fact
2494 
2495  end do
2496 
2497  ! Initialize diagMatCoefSpectral to zero, because the
2498  ! starting index in the loop over the number of slices -1 is
2499  ! 1, i.e. the slice where the actual computation takes places
2500  ! does not contribute to diagMatCoefSpectral.
2501 
2502  do j = 1, 3
2503  do i = 1, 3
2504  diagmatcoefspectral(mm, i, j) = zero
2505  end do
2506  end do
2507 
2508  ! Loop over the additional slices which complete an entire
2509  ! revolution. To be able to compute the coefficients a bit
2510  ! easier the loop runs from 1 to nSlices-1 and not from
2511  ! 2 to nSlices.
2512 
2513  slicesloop: do pp = 1, (sections(mm)%nSlices - 1)
2514 
2515  ! Compute the rotation matrix for this slice. This is the
2516  ! old one multiplied by the transformation matrix going from
2517  ! one slices to the next. Use tmp as temporary storage.
2518 
2519  do j = 1, 3
2520  do i = 1, 3
2521  tmp(i, j) = rotmatrixspectral(mm, i, 1) * rotmat(1, j) &
2522  + rotmatrixspectral(mm, i, 2) * rotmat(2, j) &
2523  + rotmatrixspectral(mm, i, 3) * rotmat(3, j)
2524  end do
2525  end do
2526 
2527  rotmat = tmp
2528 
2529  slicesfact = one / real(sections(mm)%nSlices, realtype)
2530 
2531  ! Loop over the number of spectral coefficients and update
2532  ! matrixCoefSpectral. The multiplication with (-1)**nn
2533  ! takes place here too.
2534 
2535  ! Multiply also by the term (-1)**(pN+1)
2536 
2537  fact = one
2538  if (mod(pp * ntimeintervalsspectral, 2_inttype) /= 0) &
2539  fact = -one
2540  slicesfact = fact * slicesfact
2541 
2542  fact = one
2543  ii = pp * ntimeintervalsspectral
2544  do nn = 1, (ntimeintervalsspectral - 1)
2545 
2546  ! Compute the coefficient multiplying the rotation matrix.
2547  ! Again make a distinction between an odd and an even
2548  ! number of time instances for the entire wheel.
2549 
2550  angle = (nn + ii) * dangle
2551  coef = one / sin(angle)
2552 
2553  if (mod(ntot, 2_inttype) == 0) &
2554  coef = coef * cos(angle)
2555 
2556  coef = coef * fact * slicesfact
2557 
2558  ! Update matrixCoefSpectral.
2559 
2560  do j = 1, 3
2561  do i = 1, 3
2562  matrixcoefspectral(mm, nn, i, j) = &
2563  matrixcoefspectral(mm, nn, i, j) + coef * rotmat(i, j)
2564  end do
2565  end do
2566 
2567  fact = -fact
2568 
2569  end do
2570 
2571  ! Update diagMatCoefSpectral. Also here the distinction
2572  ! between odd and even number of time instances.
2573 
2574  angle = ii * dangle
2575  coef = one / sin(angle)
2576 
2577  if (mod(ntot, 2_inttype) == 0) &
2578  coef = coef * cos(angle)
2579 
2580  coef = coef * slicesfact
2581 
2582  do j = 1, 3
2583  do i = 1, 3
2584  diagmatcoefspectral(mm, i, j) = &
2585  diagmatcoefspectral(mm, i, j) - coef * rotmat(i, j)
2586  end do
2587  end do
2588 
2589  end do slicesloop
2590 
2591  ! The matrix coefficients must be multiplied by the leading
2592  ! coefficient, which depends on the actual periodic time.
2593 
2594  coef = pi * timeref / sections(mm)%timePeriod
2595 
2596  do j = 1, 3
2597  do i = 1, 3
2598  diagmatcoefspectral(mm, i, j) = &
2599  coef * diagmatcoefspectral(mm, i, j)
2600  end do
2601  end do
2602 
2603  do nn = 1, (ntimeintervalsspectral - 1)
2604 
2605  do j = 1, 3
2606  do i = 1, 3
2607  matrixcoefspectral(mm, nn, i, j) = &
2608  coef * matrixcoefspectral(mm, nn, i, j)
2609  end do
2610  end do
2611 
2612  end do
2613 
2614  end do sectionloop
2615 
2616  end subroutine timespectralcoef
2617 
2619  !
2620  ! timeSpectralMatrices computes the matrices for the time
2621  ! derivative of the time spectral method for all sections. For
2622  ! scalar quantities these matrices only differ if sections have
2623  ! different periodic times. For vector quantities, such as
2624  ! momentum, these matrices can be different depending on whether
2625  ! the section is rotating or not and the number of slices
2626  ! present.
2627  !
2628  use constants
2629  use inputphysics, only: equationmode
2632  use section, only: nsections
2633  use utils, only: terminate
2634  implicit none
2635  !
2636  ! Local variables.
2637  !
2638  integer :: ierr
2639 
2640  integer(kind=intType) :: nn, mm, ll, kk, ii
2641  integer(kind=intType) :: i, j
2642 
2643  real(kind=realtype), dimension(3, 3) :: tmpmat
2644 
2645  real(kind=realtype), dimension(:, :), allocatable :: coefspectral
2646  real(kind=realtype), dimension(:, :, :, :), allocatable :: &
2647  matrixcoefspectral
2648  real(kind=realtype), dimension(:, :, :), allocatable :: &
2649  diagmatcoefspectral
2650  !
2651  ! This routine is only used for the spectral solutions. Return
2652  ! immediately if a different mode is solved.
2653 
2654  if (equationmode /= timespectral) return
2655 
2656  ! Allocate the memory for the matrices as well as the help
2657  ! variables needed to construct these matrices.
2658 
2659  !added to allow second call in mdUpdateRoutines
2660  if (allocated(dscalar)) deallocate (dscalar)
2661  if (allocated(dvector)) deallocate (dvector)
2662 
2664  mm = 3 * nn
2665  kk = nn - 1
2666 
2667  allocate (dscalar(nsections, nn, nn), &
2668  dvector(nsections, mm, mm), &
2669  coefspectral(nsections, kk), &
2670  matrixcoefspectral(nsections, kk, 3, 3), &
2671  diagmatcoefspectral(nsections, 3, 3), stat=ierr)
2672  if (ierr /= 0) &
2673  call terminate("timeSpectralMatrices", &
2674  "Memory allocation failure for the matrices of &
2675  &the spectral time derivatives.")
2676 
2677  ! Determine the help variables needed to construct the
2678  ! actual matrices.
2679 
2680  call timespectralcoef(coefspectral, matrixcoefspectral, &
2681  diagmatcoefspectral)
2682  !
2683  ! Determine the time derivative matrices for the sections.
2684  !
2685  ! Loop over the number of sections.
2686 
2687  sectionloop: do ii = 1, nsections
2688  !
2689  ! Matrix for scalar quantities.
2690  !
2691  ! Loop over the number of rows.
2692 
2693  do nn = 1, ntimeintervalsspectral
2694 
2695  ! Set the diagonal element to zero, i.e. there is no
2696  ! contribution to the own time derivative.
2697 
2698  dscalar(ii, nn, nn) = zero
2699 
2700  ! Loop over the rest of the columns.
2701 
2702  do mm = 1, (ntimeintervalsspectral - 1)
2703 
2704  ! Determine the corresponding column index.
2705 
2706  ll = nn + mm
2707  if (ll > ntimeintervalsspectral) &
2708  ll = ll - ntimeintervalsspectral
2709 
2710  ! Store the corresponding coefficient in dscalar.
2711 
2712  dscalar(ii, nn, ll) = coefspectral(ii, mm)
2713 
2714  end do
2715  end do
2716  !
2717  ! Matrices for vector quantities.
2718  !
2719  ! Loop over the number of time intervals; the number of rows
2720  ! is 3 times this number.
2721 
2722  rowloop: do nn = 1, ntimeintervalsspectral
2723 
2724  ! Initialize the diagonal block to diagMatCoefSpectral,
2725  ! the additional diagonal entry needed for the rotational
2726  ! periodicity.
2727 
2728  kk = 3 * (nn - 1)
2729  do j = 1, 3
2730  do i = 1, 3
2731  dvector(ii, kk + i, kk + j) = diagmatcoefspectral(ii, i, j)
2732  end do
2733  end do
2734 
2735  ! Loop over the other time intervals, which contribute to
2736  ! the time derivative.
2737 
2738  columnloop: do mm = 1, (ntimeintervalsspectral - 1)
2739 
2740  ! Determine the corresponding column index and check the
2741  ! situation we are having here.
2742 
2743  ll = nn + mm
2744  if (ll > ntimeintervalsspectral) then
2745 
2746  ! Index is outside the range and a shift must be applied.
2747 
2748  ll = ll - ntimeintervalsspectral
2749 
2750  ! The vector must be rotated. This effect is incorporated
2751  ! directly in the matrix of time derivatives.
2752 
2753  do j = 1, 3
2754  do i = 1, 3
2755  tmpmat(i, j) = matrixcoefspectral(ii, mm, i, 1) &
2756  * rotmatrixspectral(ii, 1, j) &
2757  + matrixcoefspectral(ii, mm, i, 2) &
2758  * rotmatrixspectral(ii, 2, j) &
2759  + matrixcoefspectral(ii, mm, i, 3) &
2760  * rotmatrixspectral(ii, 3, j)
2761  end do
2762  end do
2763 
2764  else
2765 
2766  ! Index is in the range. Copy the matrix coefficient
2767  ! into tmpMat.
2768 
2769  do j = 1, 3
2770  do i = 1, 3
2771  tmpmat(i, j) = matrixcoefspectral(ii, mm, i, j)
2772  end do
2773  end do
2774 
2775  end if
2776 
2777  ! Determine the offset for the column index and store
2778  ! this submatrix in the correct place of dvector.
2779 
2780  ll = 3 * (ll - 1)
2781  do j = 1, 3
2782  do i = 1, 3
2783  dvector(ii, kk + i, ll + j) = tmpmat(i, j)
2784  end do
2785  end do
2786 
2787  end do columnloop
2788  end do rowloop
2789  end do sectionloop
2790 
2791  ! Release the memory of the help variables needed to construct
2792  ! the matrices of the time derivatives.
2793 
2794  deallocate (coefspectral, matrixcoefspectral, &
2795  diagmatcoefspectral, stat=ierr)
2796  if (ierr /= 0) &
2797  call terminate("timeSpectralMatrices", &
2798  "Deallocation failure for the help variables.")
2799 
2800  end subroutine timespectralmatrices
2801 
2802  subroutine readrestartfile()
2803  !
2804  ! readRestartFile reads the fine grid solution(s) from the
2805  ! restart file(s). If the restart file(s) do not correspond to
2806  ! the current mesh, the solution(s) are interpolated onto this
2807  ! mesh. It is also allowed to change boundary conditions, e.g.
2808  ! an alpha and/or Mach sweep is possible. Furthermore there is
2809  ! some support when starting from a different turbulence model,
2810  ! although this should be used with care.
2811  !
2812  use constants
2813  use cgnsgrid
2814  use su_cgns
2815  use variablereading ! Full import since we need basically everything
2816  use blockpointers, only: ibegor, jbegor, kbegor, il, jl, kl, ndom, &
2817  nbkglobal, nx, ny, nz
2819  use inputphysics, only: equationmode
2822  use utils, only: terminate, setpointers
2823  use sorting, only: bsearchstrings
2824  use commonformats, only: strings, stringint1
2825  implicit none
2826  !
2827  ! Local variables.
2828  !
2829  integer :: nzones, celldim, physdim, ierr, nsols
2830 
2831  integer(cgsize_t), dimension(9) :: sizes
2832  integer, dimension(9) :: rindsizes
2833  integer, dimension(nSolsRead) :: fileids
2834 
2835  integer(kind=intType) :: ii, jj, nn
2836  integer(kind=intType) :: ntypemismatch
2837  integer(kind=intType) :: nhimin, nhjmin, nhkmin
2838  integer(kind=intType) :: nhimax, nhjmax, nhkmax
2839 
2840  character(len=7) :: integerstring
2841  character(len=maxCGNSNameLen) :: cgnsname
2842  character(len=2*maxStringLen) :: errormessage
2843 
2844  ! Initialize halosRead to .true. This will be overwritten if
2845  ! there is at least one block present for which the halo data
2846  ! cannot be read.
2847 
2848  halosread = .true.
2849 
2850  ! Initialize nTypeMismatch to 0.
2851 
2852  ntypemismatch = 0
2853 
2854  ! Loop over the number of files to be read and open them.
2855 
2856  fileopenloop: do solid = 1, nsolsread
2857 
2858  ! Open the restart file for reading.
2859 
2860  call cg_open_f(solfiles(solid), mode_read, cgnsind, ierr)
2861  if (ierr /= all_ok) then
2862  write (errormessage, *) "File ", trim(solfiles(solid)), &
2863  " could not be opened for reading"
2864  call terminate("readRestartFile", errormessage)
2865  end if
2866 
2867  fileids(solid) = cgnsind
2868 
2869  ! Determine the number of bases in the cgns file.
2870  ! This must be at least 1.
2871 
2872  call cg_nbases_f(cgnsind, cgnsbase, ierr)
2873  if (ierr /= all_ok) &
2874  call terminate("readRestartFile", &
2875  "Something wrong when calling cg_nbases_f")
2876 
2877  if (cgnsbase < 1) then
2878  write (errormessage, *) "CGNS file ", trim(solfiles(solid)), &
2879  " does not contain a base"
2880  call terminate("readRestartFile", errormessage)
2881  end if
2882 
2883  ! Only data from the first base is read. Information from
2884  ! higher bases is ignored.
2885 
2886  cgnsbase = 1
2887 
2888  ! Read the cell and physical dimensions as well as the name for
2889  ! this base.
2890 
2891  call cg_base_read_f(cgnsind, cgnsbase, cgnsname, celldim, &
2892  physdim, ierr)
2893  if (ierr /= all_ok) &
2894  call terminate("readRestartFile", &
2895  "Something wrong when calling cg_base_read_f")
2896 
2897  ! Check the cell and physical dimensions. Both must be 3 for
2898  ! this code to work.
2899 
2900  if (celldim /= 3 .or. physdim /= 3) then
2901  write (errormessage, stringint1) "Both the number of cell and physical dimensions should be 3, not ", &
2902  celldim, " and ", physdim
2903  call terminate("readRestartFile", errormessage)
2904  end if
2905 
2906  end do fileopenloop
2907 
2908  ! Broadcast nTimeStepsRestart and timeUnsteadyRestart to all
2909  ! processors. These values are needed to perform a consistent
2910  ! unsteady restart.
2911 
2912  call mpi_bcast(ntimestepsrestart, 1, adflow_integer, 0, &
2913  adflow_comm_world, ierr)
2914  call mpi_bcast(timeunsteadyrestart, 1, adflow_real, 0, &
2915  adflow_comm_world, ierr)
2916 
2917  ! Get the scaling factors for density, pressure and velocity
2918  ! by reading the reference state.
2919 
2920  call scalefactors(fileids)
2921 
2922  ! Loop over the number of files to be read and read the solution.
2923 
2924  solloop: do solid = 1, nsolsread
2925 
2926  ! Store the file index a bit easier and set the base to 1.
2927 
2928  cgnsind = fileids(solid)
2929  cgnsbase = 1
2930 
2931  ! Determine the number of zones (blocks) in the restart file
2932  ! and check if this is identical to the number in the grid file.
2933 
2934  call cg_nzones_f(cgnsind, cgnsbase, nzones, ierr)
2935  if (ierr /= all_ok) &
2936  call terminate("readRestartFile", &
2937  "Something wrong when calling cg_nzones_f")
2938 
2939  if (nzones /= cgnsndom) &
2940  call terminate("readRestartFile", &
2941  "Number of blocks in grid file and restart &
2942  &file differ")
2943 
2944  ! Create a sorted version of the zone names of the restart file
2945  ! and store its corresponding zone numbers in zoneNumbers.
2946 
2948 
2949  ! Loop over the number of blocks stored on this processor.
2950 
2951  domains: do nn = 1, ndom
2952 
2953  ! Set the pointers for this block. Make sure that the
2954  ! correct data is set.
2955 
2956  ii = min(solid, ntimeintervalsspectral)
2957  call setpointers(nn, 1_inttype, ii)
2958 
2959  ! Store the zone name of the original grid a bit easier.
2960 
2961  cgnsname = cgnsdoms(nbkglobal)%zoneName
2962 
2963  ! Search in the sorted zone names of the restart file for
2964  ! cgnsName. The name must be found; otherwise the restart
2965  ! is pointless. If found, the zone number is set accordingly.
2966 
2967  jj = bsearchstrings(cgnsname, zonenames)
2968  if (jj == 0) then
2969  write (errormessage, *) "Zone name ", trim(cgnsname), &
2970  " not found in restart file ", &
2971  trim(solfiles(solid))
2972  call terminate("readRestartFile", errormessage)
2973  else
2974  jj = zonenumbers(jj)
2975  end if
2976 
2977  cgnszone = jj
2978 
2979  ! Determine the dimensions of the zone and check if these are
2980  ! identical to the dimensions of the block in the grid file.
2981 
2982  call cg_zone_read_f(cgnsind, cgnsbase, cgnszone, &
2983  cgnsname, sizes, ierr)
2984  if (ierr /= all_ok) &
2985  call terminate("readRestartFile", &
2986  "Something wrong when calling &
2987  &cg_zone_read_f")
2988 
2989  if (cgnsdoms(nbkglobal)%il /= sizes(1) .or. &
2990  cgnsdoms(nbkglobal)%jl /= sizes(2) .or. &
2991  cgnsdoms(nbkglobal)%kl /= sizes(3)) &
2992  call terminate("readRestartFile", &
2993  "Corresponding zones in restart file and &
2994  &grid file have different dimensions")
2995 
2996  ! Determine the number of flow solutions in this zone and
2997  ! check if there is a solution stored.
2998 
2999  call cg_nsols_f(cgnsind, cgnsbase, cgnszone, nsols, ierr)
3000  if (ierr /= all_ok) &
3001  call terminate("readRestartFile", &
3002  "Something wrong when calling cg_nsols_f")
3003 
3004  if (nsols == 0) &
3005  call terminate("readRestartFile", &
3006  "No solution present in restart file")
3007 
3008  ! Check for multiple solutions. A distinction is needed for
3009  ! overset cases because there will be an extra solution node
3010  ! for the nodal iblanks.
3011 
3012  if ((nsols > 1) .or. nsols > 2) &
3013  call terminate("readRestartFile", &
3014  "Multiple solutions present in restart file")
3015 
3016  ! Determine the location of the solution variables. A loop is
3017  ! done over the solution nodes which is either 1 or 2. In the
3018  ! latter case, pick the node not named "Nodal Blanks".
3019 
3020  do cgnssol = 1, nsols
3021  call cg_sol_info_f(cgnsind, cgnsbase, cgnszone, cgnssol, &
3022  cgnsname, location, ierr)
3023  if (ierr /= all_ok) &
3024  call terminate("readRestartFile", &
3025  "Something wrong when calling &
3026  &cg_sol_info_f")
3027 
3028  if (trim(cgnsname) /= "Nodal Blanks") exit
3029  end do
3030 
3031  ! Determine the rind info.
3032 
3033  call cg_goto_f(cgnsind, cgnsbase, ierr, "Zone_t", &
3034  cgnszone, "FlowSolution_t", cgnssol, "end")
3035  if (ierr /= all_ok) &
3036  call terminate("readRestartFile", &
3037  "Something wrong when calling cg_goto_f")
3038 
3039  call cg_rind_read_f(rindsizes, ierr)
3040  if (ierr /= all_ok) &
3041  call terminate("readRestartFile", &
3042  "Something wrong when calling &
3043  &cg_rind_read_f")
3044 
3045  ! Check if halo's are present. If not, set halosRead to .false.
3046  ! This only needs to be done if this is not an older state for
3047  ! an unsteady computation.
3048 
3049  if (solid == 1 .or. equationmode == timespectral) then
3050  if (rindsizes(1) == 0 .or. rindsizes(2) == 0 .or. rindsizes(3) == 0 .or. &
3051  rindsizes(4) == 0 .or. rindsizes(5) == 0 .or. rindsizes(6) == 0) &
3052  halosread = .false.
3053  end if
3054 
3055  ! Initialize the number of halo cells to read to 0.
3056 
3057  nhimin = 0; nhjmin = 0; nhkmin = 0
3058  nhimax = 0; nhjmax = 0; nhkmax = 0
3059 
3060  ! Determine the range which must be read. A few things must be
3061  ! taken into account: - in iBegor, iEndor, etc. The nodal
3062  ! range is stored. As in CGNS the cell
3063  ! range start at 1, 1 must be subtracted
3064  ! from the upper bound.
3065  ! - the rind info must be taken into
3066  ! account, because only the upper bound
3067  ! is changed in cgns; the lower bound
3068  ! remains 1.
3069  ! - in case the solution is stored in the
3070  ! vertices one extra variable in each
3071  ! direction is read. An averaging will
3072  ! take place to obtain cell centered
3073  ! values.
3074  ! Also when vertex data is present, set halosRead to .false.,
3075  ! because it is not possible to determine the halos.
3076 
3077  if (location == cellcenter) then
3078 
3079  ! Correct the number of halo cells to be read.
3080  ! Only if this is not an older state in time for an
3081  ! unsteady computation.
3082 
3083  if (solid == 1 .or. equationmode == timespectral) then
3084  if (rindsizes(1) > 0) nhimin = 1; if (rindsizes(2) > 0) nhimax = 1
3085  if (rindsizes(3) > 0) nhjmin = 1; if (rindsizes(4) > 0) nhjmax = 1
3086  if (rindsizes(5) > 0) nhkmin = 1; if (rindsizes(6) > 0) nhkmax = 1
3087  end if
3088 
3089  ! Set the cell range to be read from the CGNS file.
3090 
3091  rangemin(1) = ibegor - nhimin
3092  rangemin(2) = jbegor - nhjmin
3093  rangemin(3) = kbegor - nhkmin
3094 
3095  rangemax(1) = rangemin(1) + nx - 1 + nhimin + nhimax
3096  rangemax(2) = rangemin(2) + ny - 1 + nhjmin + nhjmax
3097  rangemax(3) = rangemin(3) + nz - 1 + nhkmin + nhkmax
3098 
3099  else if (location == vertex) then
3100 
3101  ! Set the nodal range such that enough info is present
3102  ! to average the nodal data to create the cell centered
3103  ! data in the owned cells. No halo cells will be
3104  ! initialized.
3105 
3106  halosread = .false.
3107 
3108  rangemin(1) = ibegor
3109  rangemin(2) = jbegor
3110  rangemin(3) = kbegor
3111 
3112  rangemax(1) = rangemin(1) + nx
3113  rangemax(2) = rangemin(2) + ny
3114  rangemax(3) = rangemin(3) + nz
3115  else
3116  call terminate("readRestartFile", &
3117  "Only CellCenter or Vertex data allowed in &
3118  &restart file")
3119  end if
3120 
3121  ! Allocate the memory for buffer, needed to store the variable
3122  ! to be read, and bufferVertex in case the solution is stored
3123  ! in the vertices.
3124 
3125  allocate (buffer(2 - nhimin:il + nhimax, &
3126  2 - nhjmin:jl + nhjmax, &
3127  2 - nhkmin:kl + nhkmax), stat=ierr)
3128  if (ierr /= 0) &
3129  call terminate("readRestartFile", &
3130  "Memory allocation failure for buffer")
3131 
3132  if (location == vertex) then
3133  allocate (buffervertex(1:il, 1:jl, 1:kl), stat=ierr)
3134  if (ierr /= 0) &
3135  call terminate("readRestartFile", &
3136  "Memory allocation failure for bufferVertex")
3137  end if
3138 
3139  ! Create a sorted version of the variable names and store the
3140  ! corresponding type in varTypes.
3141 
3142  call getsortedvarnumbers
3143 
3144  ! Read the density and the turbulence variables.
3145 
3146  call readdensity(ntypemismatch)
3147  call readturbvar(ntypemismatch)
3148 
3149  ! Read the other variables, depending on the situation.
3150 
3151  testprim: if (solid == 1 .or. equationmode == timespectral) then
3152 
3153  ! Either the first solution or time spectral mode. Read
3154  ! the primitive variables from the restart file.
3155 
3156  call readxvelocity(ntypemismatch)
3157  call readyvelocity(ntypemismatch)
3158  call readzvelocity(ntypemismatch)
3159  call readpressure(ntypemismatch)
3160 
3161  else testprim
3162 
3163  ! Old solution in unsteady mode. Read the conservative
3164  ! variables.
3165 
3166  call readxmomentum(ntypemismatch)
3167  call readymomentum(ntypemismatch)
3168  call readzmomentum(ntypemismatch)
3169  call readenergy(ntypemismatch)
3170 
3171  end if testprim
3172 
3173  ! Release the memory of buffer, varNames and varTypes.
3174 
3175  deallocate (buffer, varnames, vartypes, stat=ierr)
3176  if (ierr /= 0) &
3177  call terminate("readRestartFile", &
3178  "Deallocation error for buffer, varNames &
3179  &and varTypes.")
3180 
3181  ! In case bufferVertex is allocated, release it.
3182 
3183  if (location == vertex) then
3184  deallocate (buffervertex, stat=ierr)
3185  if (ierr /= 0) &
3186  call terminate("readRestartFile", &
3187  "Deallocation error for bufferVertex")
3188  end if
3189 
3190  end do domains
3191 
3192  ! Release the memory of zoneNames and zoneNumbers.
3193 
3194  deallocate (zonenames, zonenumbers, stat=ierr)
3195  if (ierr /= 0) &
3196  call terminate("readRestartFile", &
3197  "Deallocation failure for zoneNames &
3198  &and zoneNumbers.")
3199 
3200  ! Close the cgns solution file.
3201 
3202  call cg_close_f(cgnsind, ierr)
3203  if (ierr /= all_ok) &
3204  call terminate("readRestartFile", &
3205  "Something wrong when calling cg_close_f")
3206 
3207  end do solloop
3208 
3209  ! Determine the global sum of nTypeMismatch; the result only
3210  ! needs to be known on processor 0. Use ii as the global buffer
3211  ! to store the result. If a type mismatch occured,
3212  ! print a warning.
3213 
3214  call mpi_reduce(ntypemismatch, ii, 1, adflow_integer, &
3215  mpi_sum, 0, adflow_comm_world, ierr)
3216  if (myid == 0 .and. ii > 0) then
3217 
3218  write (integerstring, "(i6)") ii
3219  integerstring = adjustl(integerstring)
3220 
3221  print "(a)", "#"
3222  print "(a)", "# Warning"
3223  print strings, "# ", trim(integerstring), " type mismatches occured when reading the solution of the blocks"
3224  print "(a)", "#"
3225  end if
3226 
3227  end subroutine readrestartfile
3228 
3230  !
3231  ! getSortedZoneNumbers reads the names of the zones of the
3232  ! cgns file given by cgnsInd and cgnsBase. Afterwards the
3233  ! zonenames are sorted in increasing order, such that a binary
3234  ! search algorithm can be employed. The original zone numbers
3235  ! are stored in zoneNumbers.
3236  ! If the zone contains a link to a zone containing the
3237  ! coordinates the name of the linked zone is taken.
3238  !
3239 
3240  use constants
3241  use cgnsgrid, only: cgnsndom
3242  use su_cgns
3244  use sorting, only: qsortstrings, bsearchstrings
3245  use utils, only: terminate
3246  use commonformats, only: strings
3247  implicit none
3248  !
3249  ! Local variables.
3250  !
3251  integer :: ierr
3252  integer :: zone, zonetype, ncoords, pathlength
3253  integer :: pos
3254 
3255  integer(kind=cgsize_t), dimension(9) :: sizesblock
3256 
3257  integer(kind=intType) :: nn, ii
3258 
3259  character(len=maxStringLen) :: errormessage, linkpath
3260  character(len=maxCGNSNameLen), dimension(cgnsNdom) :: tmpnames
3261 
3262  logical :: namefound
3263 
3264  character(len=7) :: int1string, int2string
3265 
3266  ! Allocate the memory for zoneNames and zoneNumbers.
3267 
3268  allocate (zonenames(cgnsndom), zonenumbers(cgnsndom), stat=ierr)
3269  if (ierr /= 0) &
3270  call terminate("getSortedZoneNumbers", &
3271  "Memory allocation failure for zoneNames &
3272  &and zoneNumbers")
3273 
3274  ! Loop over the number of zones in the file.
3275 
3276  cgnsdomains: do nn = 1, cgnsndom
3277 
3278  ! Initialize nameFound to .false.
3279 
3280  namefound = .false.
3281 
3282  ! Check if the zone is structured.
3283 
3284  zone = nn
3285  call cg_zone_type_f(cgnsind, cgnsbase, zone, zonetype, ierr)
3286  if (ierr /= all_ok) &
3287  call terminate("getSortedZoneNumbers", &
3288  "Something wrong when calling cg_zone_type_f")
3289 
3290  if (zonetype /= structured) then
3291 
3292  write (int1string, "(i7)") cgnsbase
3293  int1string = adjustl(int1string)
3294  write (int2string, "(i7)") zone
3295  int2string = adjustl(int2string)
3296 
3297  write (errormessage, strings) "Base ", trim(int1string), ": Zone ", trim(int2string), &
3298  " of the cgns restart file is not structured"
3299  call terminate("getSortedZoneNumbers", errormessage)
3300 
3301  end if
3302 
3303  ! Determine the number of grid coordinates of this zone.
3304 
3305  call cg_ncoords_f(cgnsind, cgnsbase, zone, ncoords, ierr)
3306  if (ierr /= all_ok) &
3307  call terminate("getSortedZoneNumbers", &
3308  "Something wrong when calling cg_ncoords_f")
3309 
3310  ! If ncoords == 3, there are coordinates present. Then check if
3311  ! it is a link. If so, take the zone name of the link.
3312 
3313  if (ncoords == 3) then
3314 
3315  ! Go to the coordinates node.
3316 
3317  call cg_goto_f(cgnsind, cgnsbase, ierr, "Zone_t", zone, &
3318  "GridCoordinates_t", 1, "end")
3319  if (ierr /= all_ok) &
3320  call terminate("getSortedZoneNumbers", &
3321  "Something wrong when calling cg_goto_f")
3322 
3323  ! Check if this node is a link.
3324 
3325  call cg_is_link_f(pathlength, ierr)
3326  if (ierr /= all_ok) &
3327  call terminate("getSortedZoneNumbers", &
3328  "Something wrong when calling cg_is_link_f")
3329 
3330  if (pathlength > 0) then
3331 
3332  ! Determine the name of the linkPath.
3333 
3334  call cg_link_read_f(errormessage, linkpath, ierr)
3335  if (ierr /= all_ok) &
3336  call terminate("getSortedZoneNumbers", &
3337  "Something wrong when calling &
3338  &cg_link_read_f")
3339 
3340  ! Find the zone name.
3341  ! Find, starting from the back, the forward slash.
3342 
3343  pos = index(linkpath, "/", .true.)
3344  if (pos > 0) then
3345  linkpath = linkpath(:pos - 1)
3346 
3347  ! Find the next forward slash from the back and
3348  ! remove the leading part from the path name.
3349 
3350  pos = index(linkpath, "/", .true.)
3351  if (pos > 0) linkpath = linkpath(pos + 1:)
3352  end if
3353 
3354  ! Create the zone name and set nameFound to .true..
3355 
3356  linkpath = adjustl(linkpath)
3357  zonenames(nn) = trim(linkpath)
3358  namefound = .true.
3359 
3360  end if
3361  end if
3362 
3363  ! If no name was yet found set it to the name of the
3364  ! current zone.
3365 
3366  if (.not. namefound) then
3367  call cg_zone_read_f(cgnsind, cgnsbase, zone, &
3368  zonenames(nn), sizesblock, ierr)
3369  if (ierr /= all_ok) &
3370  call terminate("getSortedZoneNumbers", &
3371  "Something wrong when calling &
3372  &cg_zone_read_f")
3373  end if
3374 
3375  end do cgnsdomains
3376 
3377  ! Set tmpNames to zoneNames and sort the latter
3378  ! in increasing order.
3379 
3380  do nn = 1, cgnsndom
3381  tmpnames(nn) = zonenames(nn)
3382  end do
3383 
3384  ! Sort zoneNames in increasing order.
3385 
3387 
3388  ! Initialize zoneNumbers to -1. This serves as a check during
3389  ! the search.
3390 
3391  do nn = 1, cgnsndom
3392  zonenumbers(nn) = -1
3393  end do
3394 
3395  ! Find the original zone numbers for the sorted zone names.
3396 
3397  do nn = 1, cgnsndom
3398  ii = bsearchstrings(tmpnames(nn), zonenames)
3399 
3400  ! Check if the zone number is not already taken. If this is the
3401  ! case, this means that two identical zone names are present.
3402 
3403  if (zonenumbers(ii) /= -1) &
3404  call terminate("getSortedZoneNumbers", &
3405  "Error occurs only when two identical zone &
3406  &names are present")
3407 
3408  ! And set the zone number.
3409 
3410  zonenumbers(ii) = nn
3411  end do
3412 
3413  end subroutine getsortedzonenumbers
3414 
3416  !
3417  ! getSortedVarNumbers reads the names of variables stored in
3418  ! the given solution node of the cgns file, indicated by
3419  ! cgnsInd, cgnsBase and cgnsZone. Afterwards the variable
3420  ! names are sorted in increasing order, such that they can be
3421  ! used in a binary search. Their original variable number and
3422  ! type is stored.
3423  !
3424  use constants
3425  use su_cgns
3428  use sorting, only: qsortstrings, bsearchstrings
3429  use utils, only: terminate
3430  implicit none
3431  !
3432  ! Local variables.
3433  !
3434  integer :: i, ierr
3435  integer, dimension(:), allocatable :: tmptypes
3436 
3437  integer(kind=intType) :: nn, ii
3438 
3439  integer(kind=intType), dimension(:), allocatable :: varnumbers
3440 
3441  character(len=maxCGNSNameLen), allocatable, dimension(:) :: &
3442  tmpnames
3443 
3444  ! Determine the number of solution variables stored.
3445 
3446  call cg_nfields_f(cgnsind, cgnsbase, cgnszone, cgnssol, &
3447  nvar, ierr)
3448  if (ierr /= all_ok) &
3449  call terminate("getSortedVarNumbers", &
3450  "Something wrong when calling cg_nfield_f")
3451 
3452  ! Allocate the memory for varnames, vartypes and varnumber
3453 
3454  allocate (varnames(nvar), vartypes(nvar), varnumbers(nvar), &
3455  stat=ierr)
3456  if (ierr /= 0) &
3457  call terminate("getSortedVarNumbers", &
3458  "Memory allocation failure for varNames, etc.")
3459 
3460  ! Loop over the number of variables and store their names and
3461  ! types.
3462 
3463  do i = 1, nvar
3464  call cg_field_info_f(cgnsind, cgnsbase, cgnszone, cgnssol, &
3465  i, vartypes(i), varnames(i), ierr)
3466  if (ierr /= 0) &
3467  call terminate("getSortedVarNumbers", &
3468  "Something wrong when calling cg_field_info_f")
3469  end do
3470 
3471  ! Allocate the memory for tmpTypes and tmpNames and initialize
3472  ! their values.
3473 
3474  allocate (tmptypes(nvar), tmpnames(nvar), stat=ierr)
3475  if (ierr /= 0) &
3476  call terminate("getSortedVarNumbers", &
3477  "Memory allocation failure for tmp variables")
3478 
3479  do i = 1, nvar
3480  tmptypes(i) = vartypes(i)
3481  tmpnames(i) = varnames(i)
3482  end do
3483 
3484  ! Sort varNames in increasing order.
3485 
3486  nn = nvar
3487  call qsortstrings(varnames, nn)
3488 
3489  ! Initialize varNumbers to -1. This serves as a check during
3490  ! the search.
3491 
3492  do i = 1, nvar
3493  varnumbers(i) = -1
3494  end do
3495 
3496  ! Find the original types and numbers for the just sorted
3497  ! variable names.
3498 
3499  do i = 1, nvar
3500  ii = bsearchstrings(tmpnames(i), varnames)
3501 
3502  ! Check if the variable number is not already taken. If this is
3503  ! the case, this means that two identical var names are present.
3504 
3505  if (varnumbers(ii) /= -1) &
3506  call terminate("getSortedVarNumbers", &
3507  "Error occurs only when two identical &
3508  &variable names are present")
3509 
3510  ! And set the variable number and type.
3511 
3512  varnumbers(ii) = i
3513  vartypes(ii) = tmptypes(i)
3514  end do
3515 
3516  ! Release the memory of varNumbers, tmpNames and tmpTypes.
3517 
3518  deallocate (varnumbers, tmptypes, tmpnames, stat=ierr)
3519  if (ierr /= 0) &
3520  call terminate("getSortedVarNumbers", &
3521  "Deallocation error for tmp variables")
3522 
3523  end subroutine getsortedvarnumbers
3524 #endif
3525 end module initializeflow
Definition: BCData.F90:1
subroutine setbcdatacoarsegrid
Definition: BCData.F90:3091
subroutine setbcdatafinegrid(initializationPart)
Definition: BCData.F90:2623
subroutine applyallbc_block(secondHalo)
Definition: BCRoutines.F90:58
subroutine applyallbc(secondHalo)
Definition: BCRoutines.F90:16
Definition: block.F90:1
integer(kind=inttype) ndom
Definition: block.F90:761
type(blocktype), dimension(:, :, :), allocatable, target flowdoms
Definition: block.F90:771
integer(kind=inttype) jl
integer(kind=inttype) kbegor
integer(kind=inttype) nx
real(kind=realtype), dimension(:, :, :), pointer p
integer(kind=inttype) ny
integer(kind=inttype) ie
real(kind=realtype), dimension(:, :, :, :), pointer w
real(kind=realtype), dimension(:, :, :), pointer d2wall
integer(kind=inttype) nbkglobal
integer(kind=inttype) jb
integer(kind=inttype) kb
real(kind=realtype), dimension(:, :, :), pointer rlv
integer(kind=inttype) ibegor
integer(kind=inttype) nbocos
integer(kind=inttype) sectionid
integer(kind=inttype) jbegor
real(kind=realtype), dimension(:, :, :), pointer rev
integer(kind=inttype), dimension(:), pointer bctype
real(kind=realtype), dimension(:, :, :, :), pointer dw
integer(kind=inttype) ib
real(kind=realtype), dimension(:, :, :, :), pointer fw
integer(kind=inttype) nz
integer(kind=inttype) je
integer(kind=inttype) ke
integer(kind=inttype) kl
integer(kind=inttype) il
type(cgnsblockinfotype), dimension(:), allocatable cgnsdoms
Definition: cgnsGrid.F90:495
integer(kind=inttype) cgnsndom
Definition: cgnsGrid.F90:491
character(len=maxstringlen) strings
character(len=maxstringlen) stringint1
integer adflow_comm_world
integer(kind=inttype), parameter spalartallmarasedwards
Definition: constants.F90:128
integer(kind=inttype), parameter spalartallmaras
Definition: constants.F90:128
real(kind=realtype), parameter zero
Definition: constants.F90:71
integer(kind=inttype), parameter coupled
Definition: constants.F90:207
integer, parameter itu3
Definition: constants.F90:43
real(kind=realtype), parameter third
Definition: constants.F90:81
real(kind=realtype), parameter pi
Definition: constants.F90:22
integer, parameter itu2
Definition: constants.F90:42
real(kind=realtype), parameter eps
Definition: constants.F90:23
integer(kind=inttype), parameter ktau
Definition: constants.F90:128
integer(kind=inttype), parameter md
Definition: constants.F90:189
integer, parameter itu1
Definition: constants.F90:40
integer, parameter irho
Definition: constants.F90:34
integer(kind=inttype), parameter komegawilcox
Definition: constants.F90:128
integer(kind=inttype), parameter timespectral
Definition: constants.F90:115
integer(kind=inttype), parameter komegamodified
Definition: constants.F90:128
integer, parameter ivx
Definition: constants.F90:35
integer(kind=inttype), parameter unsteady
Definition: constants.F90:115
integer, parameter irhoe
Definition: constants.F90:38
integer(kind=inttype), parameter bdf
Definition: constants.F90:189
integer(kind=inttype), parameter totalconditions
Definition: constants.F90:235
real(kind=realtype), parameter one
Definition: constants.F90:72
integer, parameter maxstringlen
Definition: constants.F90:16
integer(kind=inttype), parameter steady
Definition: constants.F90:115
integer, parameter ivz
Definition: constants.F90:37
real(kind=realtype), parameter two
Definition: constants.F90:73
integer, parameter itu4
Definition: constants.F90:44
integer(kind=inttype), parameter explicitrk
Definition: constants.F90:189
integer(kind=inttype), parameter massflow
Definition: constants.F90:235
integer(kind=inttype), parameter mentersst
Definition: constants.F90:128
integer(kind=inttype), parameter subsonicinflow
Definition: constants.F90:265
integer, parameter ivy
Definition: constants.F90:36
integer(kind=inttype), parameter ransequations
Definition: constants.F90:110
integer(kind=inttype), parameter internalflow
Definition: constants.F90:120
integer(kind=inttype), parameter v2f
Definition: constants.F90:128
subroutine computelamviscosity(includeHalos)
Definition: flowUtils.F90:1202
subroutine adjustinflowangle()
Definition: flowUtils.F90:1326
subroutine computeetotblock(iStart, iEnd, jStart, jEnd, kStart, kEnd, correctForK)
Definition: flowUtils.F90:553
subroutine computegamma(T, gamma, mm)
Definition: flowUtils.F90:56
subroutine etot(rho, u, v, w, p, k, etotal, correctForK)
Definition: flowUtils.F90:675
real(kind=realtype) rhoinfdim
real(kind=realtype) muinfdim
real(kind=realtype) gammainf
real(kind=realtype) href
integer(kind=inttype) nt1
real(kind=realtype) uinf
real(kind=realtype) pinfdim
real(kind=realtype) pinfcorr
real(kind=realtype) pinf
real(kind=realtype) rgas
real(kind=realtype) uref
real(kind=realtype) muref
real(kind=realtype) tinfdim
real(kind=realtype) rhoref
integer(kind=inttype) nwf
real(kind=realtype), dimension(:), allocatable winf
real(kind=realtype) muinf
real(kind=realtype) tref
integer(kind=inttype) nw
real(kind=realtype) rhoinf
real(kind=realtype) pref
real(kind=realtype) timeref
integer(kind=inttype) nt2
subroutine whalo2(level, start, end, commPressure, commGamma, commViscous)
subroutine allocmemflovarpart2(sps, level)
subroutine infchangecorrection(oldWinf, correctionTol, correctionType)
subroutine getsortedvarnumbers
subroutine updatebcdataalllevels
subroutine setpressureandcomputeenergy(halosRead)
subroutine allocmemflovarpart1(sps, level)
subroutine determinesolfilenames
subroutine velmagnanddirectionsubface(vmag, dir, BCData, mm)
subroutine setrestartfiles(fileName, i)
subroutine initdepvarandhalos(halosRead)
subroutine setsolfilenames
subroutine interpolatespectralsolution
subroutine copyspectralsolution
subroutine setuniformflow
subroutine initflow
subroutine checksolfilenames
subroutine getsortedzonenumbers
subroutine timespectralcoef(coefSpectral, matrixCoefSpectral, diagMatCoefSpectral)
subroutine initializehalos(halosRead)
subroutine timespectralmatrices
subroutine referencestate
subroutine releaseextramembcs
subroutine initflowrestart
subroutine allocrestartfiles(nFiles)
subroutine readrestartfile()
subroutine initflowfield
character(len=maxstringlen), dimension(:), allocatable restartfiles
Definition: inputParam.F90:161
integer(kind=inttype) ncycles
Definition: inputParam.F90:262
integer(kind=inttype) mgstartlevel
Definition: inputParam.F90:270
integer(kind=inttype) turbtreatment
Definition: inputParam.F90:269
integer(kind=inttype) nsgstartup
Definition: inputParam.F90:264
real(kind=realtype) ssuthdim
Definition: inputParam.F90:604
real(kind=realtype) turbintensityinf
Definition: inputParam.F90:597
real(kind=realtype) gammaconstant
Definition: inputParam.F90:595
real(kind=realtype) eddyvisinfratio
Definition: inputParam.F90:597
integer(kind=inttype) equations
Definition: inputParam.F90:583
integer(kind=inttype) equationmode
Definition: inputParam.F90:583
real(kind=realtype) tsuthdim
Definition: inputParam.F90:604
integer(kind=inttype) turbmodel
Definition: inputParam.F90:584
real(kind=realtype) machcoef
Definition: inputParam.F90:593
integer(kind=inttype) flowtype
Definition: inputParam.F90:583
real(kind=realtype) mach
Definition: inputParam.F90:593
real(kind=realtype) rgasdim
Definition: inputParam.F90:595
real(kind=realtype), dimension(3) veldirfreestream
Definition: inputParam.F90:599
real(kind=realtype) musuthdim
Definition: inputParam.F90:604
real(kind=realtype), dimension(:, :, :), allocatable dvector
Definition: inputParam.F90:660
real(kind=realtype), dimension(:, :, :), allocatable rotmatrixspectral
Definition: inputParam.F90:695
integer(kind=inttype) ntimeintervalsspectral
Definition: inputParam.F90:645
real(kind=realtype), dimension(:, :, :), allocatable dscalar
Definition: inputParam.F90:659
logical useale
Definition: inputParam.F90:754
integer(kind=inttype) nrkstagesunsteady
Definition: inputParam.F90:742
integer(kind=inttype) timeintegrationscheme
Definition: inputParam.F90:719
integer(kind=inttype) ntimestepsfine
Definition: inputParam.F90:731
type(iotype), dimension(:, :), allocatable iovar
Definition: IOModule.f90:49
integer(kind=inttype) noldlevels
Definition: iteration.f90:79
integer(kind=inttype) currentlevel
Definition: iteration.f90:18
integer(kind=inttype) groundlevel
Definition: iteration.f90:18
integer(kind=inttype) nalesteps
Definition: iteration.f90:107
logical, dimension(:), allocatable oldsolwritten
Definition: iteration.f90:123
integer(kind=inttype) noldsolavail
Definition: iteration.f90:79
real(kind=realtype) timeunsteadyrestart
Definition: monitor.f90:98
integer(kind=inttype) ntimestepsrestart
Definition: monitor.f90:97
logical oversetpresent
Definition: overset.F90:373
subroutine residual
Definition: residuals.F90:1029
integer(kind=inttype) nsections
Definition: section.f90:44
type(sectiontype), dimension(:), allocatable sections
Definition: section.f90:46
subroutine gridvelocitiescoarselevels(sps)
subroutine slipvelocitiesfinelevel(useOldCoor, t, sps)
subroutine slipvelocitiescoarselevels(sps)
subroutine normalvelocitiesalllevels(sps)
subroutine gridvelocitiesfinelevel(useOldCoor, t, sps)
integer(kind=inttype) function bsearchstrings(key, base)
Definition: sorting.F90:812
subroutine qsortstrings(arr, nn)
Definition: sorting.F90:525
subroutine bcturbtreatment
subroutine applyallturbbc(secondHalo)
subroutine applyallturbbcthisblock(secondHalo)
real(kind=realtype) function sanuknowneddyratio(eddyRatio, nuLam)
Definition: turbUtils.F90:334
subroutine computeeddyviscosity(includeHalos)
Definition: turbUtils.F90:581
Definition: utils.F90:1
subroutine alloctimearrays(nTimeTot)
Definition: utils.F90:5886
subroutine rotmatrixrigidbody(tNew, tOld, rotationMatrix, rotationPoint)
Definition: utils.F90:614
real(kind=realtype) function mynorm2(x)
Definition: utils.F90:1697
subroutine spectralinterpolcoef(nsps, t, alpScal, alpMat)
Definition: utils.F90:3668
subroutine setpointers(nn, mm, ll)
Definition: utils.F90:3237
subroutine allocconvarrays(nIterTot)
Definition: utils.F90:5830
subroutine getrotmatrix(vec1, vec2, rotMat)
Definition: utils.F90:6592
subroutine terminate(routineName, errorMessage)
Definition: utils.F90:502
real(kind=cgnsrealtype), dimension(:, :, :), allocatable buffer
subroutine readymomentum(nTypeMismatch)
integer(kind=inttype) nsolsread
subroutine readyvelocity(nTypeMismatch)
integer(kind=inttype) solid
subroutine readturbvar(nTypeMismatch)
integer, dimension(:), allocatable vartypes
subroutine readzvelocity(nTypeMismatch)
integer(kind=inttype), dimension(:), allocatable zonenumbers
real(kind=cgnsrealtype), dimension(:, :, :), allocatable buffervertex
subroutine readdensity(nTypeMismatch)
subroutine readzmomentum(nTypeMismatch)
character(len=maxstringlen), dimension(:), allocatable solfiles
subroutine readxvelocity(nTypeMismatch)
subroutine readpressure(nTypeMismatch)
subroutine readenergy(nTypeMismatch)
character(len=maxcgnsnamelen), dimension(:), allocatable zonenames
subroutine readxmomentum(nTypeMismatch)
integer(kind=cgsize_t), dimension(3) rangemax
character(len=maxcgnsnamelen), dimension(:), allocatable varnames
integer(kind=cgsize_t), dimension(3) rangemin
subroutine scalefactors(fileIDs)