ADflow  v1.0
ADflow is a finite volume RANS solver tailored for gradient-based aerodynamic design optimization.
partitioning.F90
Go to the documentation of this file.
2 
3 contains
4 
5  subroutine partitionandreadgrid(partitionOnly)
6  !
7  ! partitionAndReadGrid determines the partitioning of the
8  ! multiblock grid over the processors and reads the grid of the
9  ! blocks (or block parts) assigned to this processor. Other
10  ! preprocessing activities, such as the proper setup of the halo
11  ! communication structure, creation of coarse grids and wall
12  ! distance computation, are performed in the preprocessing
13  ! library.
14  !
15  use constants
16  use iomodule, only: iovar
17  use partitionmod, only: fileids, gridfiles
18  use utils, only: terminate
19  use loadbalance, only: loadbalancegrid
22  implicit none
23 
24  logical, intent(in) :: partitionOnly
25  !
26  ! Local variables
27  !
28  integer :: ierr
29 
30  ! Determine the number of grid files that must be read,
31  ! as well as the corresponding file names.
32 
34 
35  ! Read the number of blocks and the block sizes of the grid stored
36  ! in the cgns grid file. This info is stored on all processors
37 
38  call readblocksizes
40 
41  ! Determine the grid sections.
43 
44  ! If we are just doing a partition test, return
45  if (partitiononly) then
46  return
47  end if
48 
49  ! Determine the number of blocks to be stored on this processor
50  ! and the relation to the original grid. Remember that blocks
51  ! can be split for load balancing reasons.
52 
53  call loadbalancegrid
54 
55  ! Initialize the iblank array for the fine grid domains
56 
58 
59  ! Allocate the coordinates of the fine grid level and the
60  ! derived data type used to read them.
61 
63 
64  ! Read the grid of the blocks (block parts) to be stored
65  ! on this processor.
66 
67  call readgrid
68 
69  ! Determine for the time spectral mode the time of one period,
70  ! the rotation matrices for the velocity components and
71  ! create the fine grid coordinates of all time spectral locations.
72 
76 
77  ! Release the memory of fileIDs, gridFiles and IOVar.
78  ! They are not needed anymore.
79 
80  deallocate (fileids, gridfiles, iovar, stat=ierr)
81  if (ierr /= 0) &
82  call terminate("partitionAndReadGrid", &
83  "Deallocation failure for fileIDs, gridFiles &
84  &and IOVar")
85 
86  ! Check if for all faces on the block boundaries either a
87  ! physical boundary condition or a connectivity has been
88  ! specified and check if the 1 to 1 subfaces match.
89 
90  call checkfaces
92 
93  end subroutine partitionandreadgrid
94 
96  !
97  ! determineGridFileNames determines the number and names of the
98  ! files that contain the grids. For steady computations only one
99  ! file must be present no matter if a restart is performed or
100  ! not. For unsteady the situation is a little more complicated.
101  ! If no restart is performed only one file must be present. If a
102  ! restart is performed in unsteady or time spectral mode and a
103  ! rigid body motion is prescribed again only one grid file is
104  ! required; however for a consistent restart with deforming
105  ! meshes the grids in the past must be read as well. If this is
106  ! not possible only a first order restart can be made in
107  ! unsteady mode and some kind of interpolation is used for the
108  ! time spectral method.
109  !
110  use constants
112  use inputio, only: gridfile
113  use inputphysics, only: equationmode
115  use inputunsteady, only: noldgridread
119  use utils, only: terminate
120  implicit none
121  !
122  ! Local variables
123  !
124  integer :: ierr
125 
126  integer(kind=intType) :: ii, nn, restartID
127 
128  character(len=7) :: integerString
129  character(len=maxStringLen) :: tmpName
130 
131  ! Initialization of nOldGridRead and interpolSpectral.
132 
133  noldgridread = 1
134  interpolspectral = .true.
135 
136  ! Determine the desired number of files from which grids at
137  ! certain time levels should be read. This depends on the
138  ! equation mode we have to solve for. Also set the corresponding
139  ! file names.
140 
141  select case (equationmode)
142 
143  case (steady)
144 
145  ! Steady computation. Only one grid needs to be read.
146 
147  ngridsread = 1
148  allocate (fileids(ngridsread), &
149  gridfiles(ngridsread), stat=ierr)
150  if (ierr /= 0) &
151  call terminate("determineGridFileNames", &
152  "Memory allocation failure for fileIDs &
153  &and gridFiles")
154 
155  gridfiles(1) = gridfile
156 
157  !===============================================================
158 
159  case (unsteady)
160 
161  ! Unsteady computation. A further check is required.
162  ! EJ: replaced boolean variable restart with .false. for now
163  ! Need to refactor this code as well with ALE restart
164 
165  testmultipleunsteady: if (deforming_grid .and. .false.) then
166 
167  ! A restart is made with deforming meshes. For a consistent
168  ! restart nOldLevels grids must be read. First determine
169  ! the prefix of the grid file and the time step number
170  ! from which a restart should be made.
171 
172  ii = len_trim(gridfile)
173  do
174  if (gridfile(ii:ii) < "0" .or. gridfile(ii:ii) > "9") exit
175  ii = ii - 1
176  end do
177 
178  ! If the last characters of the file name do not contain a
179  ! number, the grid file does not come from a previous
180  ! unsteady deforming mesh computation and therefore only
181  ! one grid will be read.
182 
183  if (ii == len_trim(gridfile)) then
184 
185  ngridsread = 1
186  allocate (fileids(ngridsread), &
187  gridfiles(ngridsread), stat=ierr)
188  if (ierr /= 0) &
189  call terminate("determineGridFileNames", &
190  "Memory allocation failure for fileIDs &
191  &and gridFiles")
192 
193  gridfiles(1) = gridfile
194 
195  else
196 
197  ! Read the integer number from the last characters
198  ! of the grid file.
199 
200  read (gridfile(ii + 1:), *) restartid
201 
202  ! Allocate the memory for the file names and set them.
203 
205  allocate (fileids(ngridsread), &
206  gridfiles(ngridsread), stat=ierr)
207  if (ierr /= 0) &
208  call terminate("determineGridFileNames", &
209  "Memory allocation failure for fileIDs &
210  &and gridFiles")
211 
212  do nn = 1, ngridsread
213  write (integerstring, "(i6)") restartid - nn + 1
214  integerstring = adjustl(integerstring)
215  gridfiles(nn) = gridfile(:ii)//trim(integerstring)
216  end do
217 
218  end if
219 
220  else testmultipleunsteady
221 
222  ! The computation either starts from scratch or an unsteady
223  ! restart for a rigid grid (possibly moving) is made. In
224  ! all cases only one grid file is needed.
225 
226  ngridsread = 1
227  allocate (fileids(ngridsread), &
228  gridfiles(ngridsread), stat=ierr)
229  if (ierr /= 0) &
230  call terminate("determineGridFileNames", &
231  "Memory allocation failure for fileIDs &
232  &and gridFiles")
233 
234  gridfiles(1) = gridfile
235 
236  end if testmultipleunsteady
237 
238  ! Check if the files can be opened.
239 
240  do nn = 1, ngridsread
241  open (unit=21, file=gridfiles(nn), status="old", iostat=ierr)
242  if (ierr /= 0) exit
243  close (unit=21)
244  end do
245 
246  ! Possibly correct nGridsRead and set nOldGridRead.
247  ! If nOldGridRead == 0, i.e. not a valid grid is found,
248  ! print an error message and terminate.
249 
250  ngridsread = nn - 1
252 
253  if (noldgridread == 0) then
254  if (myid == 0) &
255  call terminate("determineGridFileNames", &
256  "Grid file(s) could not be opened")
257  call mpi_barrier(adflow_comm_world, ierr)
258  end if
259 
260  !===============================================================
261 
262  case (timespectral)
263 
264  ! Time spectral computation. A further check is required.
265  ! EJ: replaced boolean variable restart with .false. for now
266  ! Need to refactor this code as well with ALE restart
267 
268  testmultiplets: if (deforming_grid .and. .false.) then
269 
270  ! A restart is made with deforming meshes. For a consistent
271  ! restart multiple grids must be read. First determine the
272  ! the prefix of the grid file from which a restart should
273  ! be made.
274 
275  ii = len_trim(gridfile)
276  do
277  if (gridfile(ii:ii) < "0" .or. gridfile(ii:ii) > "9") exit
278  ii = ii - 1
279  end do
280 
281  ! If the last characters of the file name do not contain a
282  ! number, the grid file does not come from a previous
283  ! time spectral deforming mesh computation and therefore
284  ! only one grid will be read.
285 
286  if (ii == len_trim(gridfile)) then
287 
288  ngridsread = 1
289  allocate (fileids(ngridsread), &
290  gridfiles(ngridsread), stat=ierr)
291  if (ierr /= 0) &
292  call terminate("determineGridFileNames", &
293  "Memory allocation failure for fileIDs &
294  &and gridFiles")
295 
296  gridfiles(1) = gridfile
297 
298  else
299 
300  ! Loop to find out how many time instances were used in
301  ! the previous computation from which a restart is made.
302 
303  nn = 0
304  do
305  nn = nn + 1
306  write (integerstring, "(i6)") nn
307  integerstring = adjustl(integerstring)
308  tmpname = gridfile(:ii)//trim(integerstring)
309 
310  open (unit=21, file=tmpname, status="old", iostat=ierr)
311  if (ierr /= 0) exit
312  close (unit=21)
313  end do
314 
315  nn = nn - 1
316 
317  ! Take care of the exceptional situation that nn == 0.
318  ! This happens when the restart file ends at with an
319  ! integer, but does not correspond to a time spectral
320  ! solution. Allocate the memory.
321 
322  ngridsread = max(nn, 1_inttype)
323  allocate (fileids(ngridsread), &
324  gridfiles(ngridsread), stat=ierr)
325  if (ierr /= 0) &
326  call terminate("determineGridFileNames", &
327  "Memory allocation failure for fileIDs &
328  &and gridFiles")
329 
330  if (nn == 0) then
331  gridfiles(1) = gridfile
332  else
333  do nn = 1, ngridsread
334  write (integerstring, "(i6)") nn
335  integerstring = adjustl(integerstring)
336  gridfiles(nn) = gridfile(:ii)//trim(integerstring)
337  end do
338  end if
339 
340  ! Check whether or not the coordinates must be interpolated,
341  ! i.e. check if nGridsRead == nTimeIntervalsSpectral.
342 
344  interpolspectral = .false.
345 
346  end if
347 
348  else testmultiplets
349 
350  ! The computation either starts from scratch or a
351  ! restart for a rigid grid (possibly moving) is made. In
352  ! all cases only one grid file is needed.
353 
354  ngridsread = 1
355  allocate (fileids(ngridsread), &
356  gridfiles(ngridsread), stat=ierr)
357  if (ierr /= 0) &
358  call terminate("determineGridFileNames", &
359  "Memory allocation failure for fileIDs &
360  &and gridFiles")
361 
362  gridfiles(1) = gridfile
363 
364  end if testmultiplets
365 
366  end select
367 
368  end subroutine determinegridfilenames
369 
371  !
372  ! determineNeighborIDs determines for every internal block
373  ! boundary the block ID of the neighbor. In the cgns file only
374  ! the zone name is stored, but the ID's are more useful
375  ! internally.
376  ! Although for this case a quadratic search algorithm is not too
377  ! bad (number of blocks are O(1000) maximum), I don't like the
378  ! idea of having a quadratic loop in the code. That's why a
379  ! O(n log(n)) algorithm is used here.
380  !
381  use constants
382  use cgnsgrid, only: cgnsdoms, cgnsndom
383  use utils, only: terminate
385  implicit none
386  !
387  ! Local variables
388  !
389  character(len=maxCGNSNameLen), dimension(cgnsNDom) :: zoneNames
390 
391  integer(kind=intType), dimension(cgnsNDom) :: zoneNumbers
392 
393  integer(kind=intType) :: i, j, k, ii
394  !
395  ! Copy the zone name from the derived data type into zoneNames.
396 
397  do i = 1, cgnsndom
398  zonenames(i) = cgnsdoms(i)%zoneName
399  end do
400 
401  ! Sort zoneNames in increasing order.
402 
403  call qsortstrings(zonenames, cgnsndom)
404 
405  ! Initialize zoneNumbers to -1. This serves as a check during
406  ! the search.
407 
408  zonenumbers = -1
409 
410  ! Find the original zone ids for the sorted zone names.
411 
412  do i = 1, cgnsndom
413  ii = bsearchstrings(cgnsdoms(i)%zoneName, zonenames)
414 
415  ! Check if the zone number is not already taken. If this is the
416  ! case, this means that the grid file contains two identical
417  ! zone names.
418 
419  if (zonenumbers(ii) /= -1) &
420  call terminate("determineNeighborIDs", &
421  "Error occurs only when two identical zone &
422  &names are present")
423 
424  ! And set the zone number.
425 
426  zonenumbers(ii) = i
427  end do
428 
429  ! Loop over the blocks and its connectivities to find out the
430  ! neighbors.
431 
432  domains: do i = 1, cgnsndom
433 
434  ! The 1-to-1 connectivities.
435 
436  do j = 1, cgnsdoms(i)%n1to1
437 
438  ! Determine the neighbor ID for this internal block boundary.
439 
440  ii = bsearchstrings(cgnsdoms(i)%conn1to1(j)%donorName, zonenames)
441  if (ii == 0) &
442  call terminate("determineNeighborIDs", &
443  "donor name not found in sorted zone names")
444 
445  cgnsdoms(i)%conn1to1(j)%donorBlock = zonenumbers(ii)
446 
447  end do
448 
449  ! The non-matching abutting connectivities.
450 
451  do j = 1, cgnsdoms(i)%nNonMatchAbutting
452 
453  ! Determine the neighbor ID's for this subface.
454 
455  do k = 1, cgnsdoms(i)%connNonMatchAbutting(j)%nDonorBlocks
456 
457  ii = bsearchstrings( &
458  cgnsdoms(i)%connNonMatchAbutting(j)%donorNames(k), zonenames)
459  if (ii == 0) &
460  call terminate("determineNeighborIDs", &
461  "donor name not found in sorted zone names")
462 
463  cgnsdoms(i)%connNonMatchAbutting(j)%donorBlocks(k) = &
464  zonenumbers(ii)
465  end do
466  end do
467 
468  end do domains
469 
470  end subroutine determineneighborids
471 
473  !
474  ! DetermineInterfaceIDs determines more information for both the
475  ! sliding mesh and domain interfaces with other codes, which are
476  ! both specified as user defined boundary conditions in CGNS. In
477  ! particular the number of sliding mesh interfaces and their
478  ! pairings, and number of interfaces with other codes are
479  ! determined.
480  ! There are some parts in the coupler API routines where
481  ! the family-specified domain interfaces are implicitly assumed.
482  ! Therefore, it is recommended for the time being that all the
483  ! domain interfaces should be family-specified.
484  !
485  use constants
486  use cgnsgrid, only: cgnsdoms, cgnsndom, cgnsfamilies, &
490  use iteration, only: standalonemode
491  use utils, only: terminate
493  use commonformats, only: stringspace
494 
495  implicit none
496  !
497  ! Local variables.
498  !
499  integer :: ierr
500 
501  integer(kind=intType) :: ii, jj, mm, nn
502  integer(kind=intType) :: nSlidingFam, nSlidingBC, nSliding
503  integer(kind=intType) :: nDomainFam, nDomainBC
504 
505  integer(kind=intType), dimension(:), allocatable :: famSlidingID
506  integer(kind=intType), dimension(:, :), allocatable :: bcSlidingID
507  integer(kind=intType), dimension(:), allocatable :: orID
508 
509  character(len=maxStringLen) :: errorMessage
510 
511  character(len=maxCGNSNameLen), dimension(:), allocatable :: &
512  namesSliding
513  character(len=maxCGNSNameLen), dimension(:), allocatable :: &
514  namesSorted
515 
516  logical :: validInterface
517  !
518  ! Count the total number of each type of user-defined BC that
519  ! needs to be treated here. Note that if a BC is specified by the
520  ! the family it is not counted, such that BCs making up a user-
521  ! defined family are only counted once.
522 
523  nslidingfam = 0
524  nslidingbc = 0
525  ndomainfam = 0
526  ndomainbc = 0
527 
528  do nn = 1, cgnsnfamilies
529 
530  select case (cgnsfamilies(nn)%BCType)
531  case (slidinginterface)
532  nslidingfam = nslidingfam + 1
536  ndomainfam = ndomainfam + 1
537  end select
538 
539  end do
540 
541  do nn = 1, cgnsndom
542  do mm = 1, cgnsdoms(nn)%nBocos
543  if (cgnsdoms(nn)%bocoInfo(mm)%actualFace .and. &
544  cgnsdoms(nn)%bocoInfo(mm)%familyID == 0) then
545 
546  select case (cgnsdoms(nn)%bocoInfo(mm)%BCType)
547  case (slidinginterface)
548  nslidingbc = nslidingbc + 1
552  ndomainbc = ndomainbc + 1
553  end select
554 
555  end if
556  end do
557  end do
558 
559  ! Domain interfaces are only allowed when the code is run in a
560  ! multi-disciplinary environment. Check this.
561 
562  cgnsndomaininterfaces = ndomainfam + ndomainbc
563 
564  if (standalonemode .and. cgnsndomaininterfaces > 0) then
565  if (myid == 0) &
566  call terminate("determineInterfaceIDs", &
567  "Domain interfaces are not allowed in &
568  &stand alone mode.")
569  call mpi_barrier(adflow_comm_world, ierr)
570  end if
571 
572  ! The number of sliding mesh interfaces must be even, because each
573  ! sliding interface should have two sides. Check this.
574 
575  nsliding = nslidingfam + nslidingbc
576  if (mod(nsliding, 2) == 1) then
577  if (myid == 0) &
578  call terminate("determineInterfaceIDs", &
579  "Odd number of sliding mesh families found")
580  call mpi_barrier(adflow_comm_world, ierr)
581  end if
582 
583  ! Allocate memory to store the names and IDs for the interfaces.
584 
585  allocate (famidsdomaininterfaces(ndomainfam), &
586  bcidsdomaininterfaces(2, ndomainbc), &
587  namessliding(nsliding), namessorted(nsliding), &
588  orid(nsliding), famslidingid(nslidingfam), &
589  bcslidingid(2, nslidingbc), stat=ierr)
590  if (ierr /= 0) &
591  call terminate("determineInterfaceIDs", &
592  "Memory allocation failure for names, IDs")
593 
594  ! Loop back over the families again and store the names and
595  ! IDs this time around. Note the ID is just the index of the
596  ! corresponding family.
597 
598  ii = 0
599  jj = 0
600 
601  do nn = 1, cgnsnfamilies
602 
603  select case (cgnsfamilies(nn)%BCType)
604  case (slidinginterface)
605  ii = ii + 1
606  namessliding(ii) = cgnsfamilies(nn)%familyName
607  famslidingid(ii) = nn
611  jj = jj + 1
612  famidsdomaininterfaces(jj) = nn
613  end select
614 
615  end do
616 
617  ! Loop back over the boundary conditions again and store the
618  ! names and IDs this time around. Note the ID has two parts:
619  ! the domain and the index of the BC info in that domain.
620 
621  jj = 0
622 
623  do nn = 1, cgnsndom
624  do mm = 1, cgnsdoms(nn)%nBocos
625  if (cgnsdoms(nn)%bocoInfo(mm)%actualFace .and. &
626  cgnsdoms(nn)%bocoInfo(mm)%familyID == 0) then
627 
628  select case (cgnsdoms(nn)%bocoInfo(mm)%BCType)
629  case (slidinginterface)
630  ii = ii + 1
631  namessliding(ii) = cgnsdoms(nn)%bocoInfo(mm)%bocoName
632  bcslidingid(:, ii - nslidingfam) = (/nn, mm/)
636  jj = jj + 1
637  bcidsdomaininterfaces(:, jj) = (/nn, mm/)
638  end select
639 
640  end if
641  end do
642  end do
643 
644  ! Initialize orID to -1, which serves as a check later on, and
645  ! copy the names of the sliding mesh families in namesSorted.
646 
647  do ii = 1, nsliding
648  orid(ii) = -1
649  namessorted(ii) = namessliding(ii)
650  end do
651 
652  ! Sort the names of the sliding mesh families in increasing
653  ! order and find the corresponding entry in namesSliding.
654 
655  call qsortstrings(namessorted, nsliding)
656 
657  do ii = 1, nsliding
658 
659  ! Search the sorted strings.
660 
661  mm = bsearchstrings(namessliding(ii), namessorted)
662 
663  if (orid(mm) /= -1) then
664 
665  ! Family name occurs more than once. This is not allowed.
666 
667  write (errormessage, stringspace) "Family name", trim(namessliding(ii)), "occurs more than once."
668  if (myid == 0) &
669  call terminate("determineInterfaceIDs", errormessage)
670  call mpi_barrier(adflow_comm_world, ierr)
671 
672  end if
673 
674  ! Store the entry in orID.
675 
676  orid(mm) = ii
677 
678  end do
679 
680  ! Set the number of sliding mesh interfaces and allocate the
681  ! memory for famIDsSliding.
682 
683  cgnsnsliding = nsliding / 2
684  allocate (famidssliding(cgnsnsliding, 2), stat=ierr)
685  if (ierr /= 0) &
686  call terminate("determineInterfaceIDs", &
687  "Memory allocation failure for famIDsSliding")
688 
689  ! Check if the sorted family names indeed form a
690  ! sliding mesh interface.
691 
692  do ii = 1, cgnsnsliding
693 
694  ! Store the entries in namesSorted, which should form a sliding
695  ! interface, a bit easier.
696 
697  nn = 2 * ii
698  mm = nn - 1
699 
700  ! Store the original values in famIDsSliding.
701 
702  jj = orid(nn) / 2
703 
704  famidssliding(jj, 1) = famslidingid(orid(mm))
705  famidssliding(jj, 2) = famslidingid(orid(nn))
706 
707  ! Check if the names form a valid sliding interface.
708 
709  validinterface = .true.
710  if (len_trim(namessorted(nn)) /= len_trim(namessorted(mm))) &
711  validinterface = .false.
712 
713  jj = len_trim(namessorted(nn)) - 2
714  if (jj <= 0) then
715  validinterface = .false.
716  else if (namessorted(nn) (:jj) /= namessorted(mm) (:jj)) then
717  validinterface = .false.
718  end if
719 
720  ! Print an error message and exit if the two families do not
721  ! form a valid sliding interface.
722 
723  if (.not. validinterface) then
724  write (errormessage, stringspace) "Family names", trim(namessliding(nn)), "and", &
725  trim(namessliding(mm)), "do not form a valid sliding mesh interface"
726  if (myid == 0) &
727  call terminate("determineInterfaceIDs", errormessage)
728  call mpi_barrier(adflow_comm_world, ierr)
729  end if
730 
731  ! The two names form a valid sliding interface. Store the
732  ! sliding interface ID for the original family or BC. Note that
733  ! one gets a positive ID and the other one a negative ID.
734  ! In this way a distinction is made between the two sides.
735 
736  if (orid(mm) > nslidingfam) then
737  jj = bcslidingid(2, orid(mm))
738  mm = bcslidingid(1, orid(mm))
739  cgnsdoms(mm)%bocoInfo(jj)%slidingID = -ii
740  else
741  mm = famslidingid(orid(mm))
742  cgnsfamilies(mm)%slidingID = -ii
743  end if
744 
745  if (orid(nn) > nslidingfam) then
746  jj = bcslidingid(2, orid(nn))
747  nn = bcslidingid(1, orid(nn))
748  cgnsdoms(nn)%bocoInfo(jj)%slidingID = ii
749  else
750  nn = famslidingid(orid(nn))
751  cgnsfamilies(nn)%slidingID = ii
752  end if
753 
754  end do
755 
756  ! Loop over all the boundary conditions again, this time
757  ! copying the sliding interface IDs for those BCs that
758  ! were part of a sliding family.
759 
760  do nn = 1, cgnsndom
761  do mm = 1, cgnsdoms(nn)%nBocos
762  if (cgnsdoms(nn)%bocoInfo(mm)%actualFace .and. &
763  cgnsdoms(nn)%bocoInfo(mm)%familyID > 0 .and. &
764  cgnsdoms(nn)%bocoInfo(mm)%BCType == slidinginterface) then
765 
766  cgnsdoms(nn)%bocoInfo(mm)%slidingID = &
767  cgnsfamilies(cgnsdoms(nn)%bocoInfo(mm)%familyID)%slidingID
768 
769  end if
770  end do
771  end do
772 
773  ! Deallocate the memory used to determine the sliding IDs.
774 
775  deallocate (namessliding, namessorted, orid, &
776  famslidingid, bcslidingid, stat=ierr)
777  if (ierr /= 0) &
778  call terminate("determineInterfaceIDs", &
779  "Deallocation failure for names, IDs")
780 
781  end subroutine determineinterfaceids
782 
784  !
785  ! InitFineGridIblank allocates the fine grid iblank array and
786  ! initializes the values for the holes, boundary, and halos. The
787  ! holes read into the cgns domains are distributed amongst its
788  ! sublocks in the form of iblanks. That is, we do not store a
789  ! list of indices for the holes of the flow domains as done in
790  ! the CGNS. The number of holes in each domain are also counted.
791  !
792  use constants
793  use block, only: ndom, flowdoms
794  use utils, only: terminate
796  implicit none
797  !
798  ! Local variables.
799  !
800  integer :: ierr
801 
802  integer(kind=intType) :: i, j, k, l, m, n, cgnsId, sps
803 
804  ! Loop over the local blocks.
805  spectralloop: do sps = 1, ntimeintervalsspectral
806  domains: do n = 1, ndom
807 
808  ! Allocate memory for the iblank array of this block.
809 
810  i = flowdoms(n, 1, sps)%ib
811  j = flowdoms(n, 1, sps)%jb
812  k = flowdoms(n, 1, sps)%kb
813  allocate (flowdoms(n, 1, sps)%iblank(0:i, 0:j, 0:k), &
814  flowdoms(n, 1, sps)%forcedRecv(0:i, 0:j, 0:k), &
815  flowdoms(n, 1, sps)%status(0:i, 0:j, 0:k), &
816  stat=ierr)
817  if (ierr /= 0) &
818  call terminate("initFineGridIblank", &
819  "Memory allocation failure for iblank")
820 
821  ! Initialize iblank to 1 everywhere, and the number of holes
822  ! for this domain to 0.
823 
824  flowdoms(n, 1, sps)%iblank = 1
825  flowdoms(n, 1, sps)%forcedRecv = 0
826  flowdoms(n, 1, sps)%status = 0
827  end do domains
828  end do spectralloop
829 
830  end subroutine initfinegridiblank
831 
833  !
834  ! timePeriodSpectral determines the time of one period for the
835  ! time spectral method. It is possible that sections have
836  ! different periodic times.
837  !
838  use constants
846  use section, only: sections, nsections
847  use utils, only: terminate
848  implicit none
849  !
850  ! Local parameter.
851  !
852  real(kind=realtype), parameter :: tol = 1.e-5_realtype
853  !
854  ! Local variables.
855  !
856  integer :: ierr
857  integer(kind=intType) :: nn
858 
859  real(kind=realtype) :: tt, omega
860  real(kind=realtype) :: timeperiod
861 
862  logical :: timeDetermined
863 
864  ! This routine is only used for the spectral solutions. Return
865  ! immediately if a different mode is solved.
866 
867  if (equationmode /= timespectral) return
868 
869  ! First check if a rotational frequency has been specified.
870  ! Only for external flows.
871 
872  timedetermined = .false.
873 
874  externaltest: if (flowtype == externalflow) then
875 
876  ! X-rotation.
877 
878  if (degreefourxrot > 0) then
879  timeperiod = two * pi / omegafourxrot
880  timedetermined = .true.
881  end if
882 
883  ! Y-rotation.
884 
885  if (degreefouryrot > 0) then
886  tt = two * pi / omegafouryrot
887 
888  ! Check if a time period was already determined. If so, try
889  ! to determine a common time. Otherwise just copy the data.
890 
891  if (timedetermined) then
892  timeperiod = commontimespectral(timeperiod, tt)
893  else
894  timeperiod = tt
895  timedetermined = .true.
896  end if
897  end if
898 
899  ! Z-rotation.
900 
901  if (degreefourzrot > 0) then
902  tt = two * pi / omegafourzrot
903 
904  ! Check if a time period was already determined. If so, try
905  ! to determine a common time. Otherwise just copy the data.
906 
907  if (timedetermined) then
908  timeperiod = commontimespectral(timeperiod, tt)
909  else
910  timeperiod = tt
911  timedetermined = .true.
912  end if
913  end if
914 
915  ! Alpha
916  !print *,'degreeFourAlpha',degreefouralpha,omegafouralpha,sincoeffouralpha
917  if (degreefouralpha > 0) then
918  tt = two * pi / omegafouralpha
919  !print *,'timePeriod',tt
920  ! Check if a time period was already determined. If so, try
921  ! to determine a common time. Otherwise just copy the data.
922 
923  if (timedetermined) then
924  timeperiod = commontimespectral(timeperiod, tt)
925  else
926  timeperiod = tt
927  timedetermined = .true.
928  end if
929  end if
930 
931  ! Beta
932 
933  if (degreefourbeta > 0) then
934  tt = two * pi / omegafourbeta
935 
936  ! Check if a time period was already determined. If so, try
937  ! to determine a common time. Otherwise just copy the data.
938 
939  if (timedetermined) then
940  timeperiod = commontimespectral(timeperiod, tt)
941  else
942  timeperiod = tt
943  timedetermined = .true.
944  end if
945  end if
946 
947  ! Mach
948 
949  if (degreefourmach > 0) then
950  tt = two * pi / omegafourmach
951 
952  ! Check if a time period was already determined. If so, try
953  ! to determine a common time. Otherwise just copy the data.
954 
955  if (timedetermined) then
956  timeperiod = commontimespectral(timeperiod, tt)
957  else
958  timeperiod = tt
959  timedetermined = .true.
960  end if
961  end if
962 
963  ! aeroelastic case
964  if (omegafourier > 0) then
965  tt = two * pi / omegafourier
966 
967  ! Check if a time period was already determined. If so, try
968  ! to determine a common time. Otherwise just copy the data.
969 
970  if (timedetermined) then
971  timeperiod = commontimespectral(timeperiod, tt)
972  else
973  timeperiod = tt
974  timedetermined = .true.
975  end if
976  end if
977 
978 !!$ ! Altitude.
979 !!$
980 !!$ if(degreeFourAltitude > 0) then
981 !!$ tt = two*pi/omegaFourAltitude
982 !!$
983 !!$ ! Check if a time period was already determined. If so, try
984 !!$ ! to determine a common time. Otherwise just copy the data.
985 !!$
986 !!$ if( timeDetermined ) then
987 !!$ timePeriod = commonTimeSpectral(timePeriod, tt)
988 !!$ else
989 !!$ timePeriod = tt
990 !!$ timeDetermined = .true.
991 !!$ endif
992 !!$ endif
993 
994  end if externaltest
995 
996  ! If it was possible to determine the time, copy it to the
997  ! sections and return.
998 
999  if (timedetermined) then
1000  do nn = 1, nsections
1001  sections(nn)%timePeriod = timeperiod / sections(nn)%nSlices
1002  !print *,'sectionTimePeriod',sections(nn)%timePeriod,nn
1003  end do
1004  return
1005  end if
1006 
1007  ! Try to determine the periodic time via the rotation rate of the
1008  ! sections and its number of slices.
1009 
1010  sectionloop: do nn = 1, nsections
1011 
1012  ! Test if the section is rotating, because only for rotating
1013  ! sections the periodic time can be determined.
1014 
1015  testrotating: if (sections(nn)%rotating) then
1016 
1017  ! Determine the magnitude of the rotation rate and the
1018  ! corresponding periodic time period.
1019 
1020  omega = sqrt(sections(nn)%rotRate(1)**2 &
1021  + sections(nn)%rotRate(2)**2 &
1022  + sections(nn)%rotRate(3)**2)
1023 
1024  tt = two * pi / omega
1025 
1026  ! If a time period was already determined, check if this is
1027  ! identical to tt. If not print an error message and exit.
1028 
1029  if (timedetermined) then
1030 
1031  tt = abs(tt - timeperiod) / timeperiod
1032  if (tt > tol) then
1033  if (myid == 0) &
1034  call terminate("timePeriodSpectral", &
1035  "Rotational frequencies of the rotating &
1036  &sections are not identical.")
1037  call mpi_barrier(adflow_comm_world, ierr)
1038  end if
1039 
1040  else
1041 
1042  ! Just copy the data.
1043 
1044  timeperiod = tt
1045  timedetermined = .true.
1046 
1047  end if
1048 
1049  end if testrotating
1050  end do sectionloop
1051 
1052  ! Divide the periodic time by the number of slices to get the
1053  ! characteristic time for every section.
1054 
1055  do nn = 1, nsections
1056  sections(nn)%timePeriod = timeperiod / sections(nn)%nSlices
1057  end do
1058 
1059  ! Return if it was possible to determine the time.
1060 
1061  if (timedetermined) return
1062 
1063  ! Periodic time could not be determined. Print an error
1064  ! message and exit.
1065 
1066  if (myid == 0) &
1067  call terminate("timePeriodSpectral", &
1068  "Not possible to determine the periodic time &
1069  &for the time spectral method")
1070  call mpi_barrier(adflow_comm_world, ierr)
1071 
1072  end subroutine timeperiodspectral
1073 
1074  function commontimespectral(t1, t2)
1075  !
1076  ! The function commonTimeSpectral determines the smallest
1077  ! possible common time between t1 and t2, such that
1078  ! tcommon = n1*t1 = n2*t2 and n1, n2 integers.
1079  !
1080  use communication
1081  use utils, only: terminate
1082  implicit none
1083  !
1084  ! Function definition
1085  !
1086  real(kind=realtype) :: commontimespectral
1087  !
1088  ! Function arguments.
1089  !
1090  real(kind=realtype), intent(in) :: t1, t2
1091  !
1092  ! Local parameters.
1093  !
1094  integer(kind=intType), parameter :: nmax = 100
1095  real(kind=realtype), parameter :: tol = 1.e-5_realtype
1096  !
1097  ! Local variables.
1098  !
1099  integer :: ierr
1100  integer(kind=intType) :: n1, n2
1101  real(kind=realtype) :: tt1, tt2, tt, ratio
1102 
1103  ! Store the largest time in tt1 and the smallest in tt2 and
1104  ! compute the ratio tt1/tt2, which is >= 1
1105 
1106  tt1 = max(t1, t2)
1107  tt2 = min(t1, t2)
1108  ratio = tt1 / tt2
1109 
1110  ! Loop to find the smallest integer values of n1 and n2, such
1111  ! that n1*tt1 = n2*tt2. Note that due to the previous definition
1112  ! n2 >= n1.
1113 
1114  do n1 = 1, nmax
1115  tt = n1 * ratio
1116  n2 = nint(tt)
1117  tt = abs(tt - n2)
1118  if (tt <= tol) exit
1119  end do
1120 
1121  ! Check if a common time was found
1122 
1123  if (n1 > nmax) then
1124  if (myid == 0) &
1125  call terminate("commonTimeSpectral", &
1126  "No common time periodic time found. &
1127  &Problem may not be periodic")
1128  call mpi_barrier(adflow_comm_world, ierr)
1129  end if
1130 
1131  ! Set the common time.
1132 
1133  commontimespectral = n1 * tt1
1134 
1135  end function commontimespectral
1137  !
1138  ! timeRotMatricesSpectral determines the rotation matrices
1139  ! used in the time derivatives for the velocity components in
1140  ! the time spectral method. These matrices are the identity
1141  ! matrices for non-rotating sections and something different for
1142  ! rotating sections. Therefore the rotation matrices are stored
1143  ! for every section.
1144  !
1145  use constants
1146  use inputphysics, only: equationmode
1148  use section, only: sections, nsections
1149  use utils, only: terminate
1150  implicit none
1151  !
1152  ! Local variables.
1153  !
1154  integer :: ierr
1155 
1156  integer(kind=intType) :: nn
1157  real(kind=realtype) :: tmp, theta, costheta, sintheta
1158 
1159  real(kind=realtype), dimension(3) :: xt, yt, zt
1160 
1161  ! This routine is only used for the spectral solutions. Return
1162  ! immediately if a different mode is solved.
1163 
1164  if (equationmode /= timespectral) return
1165 
1166  ! Allocate the memory for rotMatrixSpectral, which will store
1167  ! the rotation matrices for all the sections.
1168 
1169  if (allocated(rotmatrixspectral)) deallocate (rotmatrixspectral)
1170  allocate (rotmatrixspectral(nsections, 3, 3), stat=ierr)
1171 
1172  if (ierr /= 0) &
1173  call terminate("timeRotMatricesSpectral", &
1174  "Memory allocation failure for &
1175  &rotMatrixSpectral")
1176 
1177  ! Loop over the number of sections.
1178 
1179  sectionloop: do nn = 1, nsections
1180 
1181  ! Test if the rotation matrix is the unity matrix. This is the
1182  ! case if this section is not rotating or if the number of
1183  ! slices is only 1, i.e. the true physical model is computed.
1184 
1185  testunity: if (.not. sections(nn)%rotating .or. &
1186  sections(nn)%nSlices == 1) then
1187 
1188  ! Set the rotation matrix to the unity matrix.
1189 
1190  rotmatrixspectral(nn, 1, 1) = one
1191  rotmatrixspectral(nn, 1, 2) = zero
1192  rotmatrixspectral(nn, 1, 3) = zero
1193 
1194  rotmatrixspectral(nn, 2, 1) = zero
1195  rotmatrixspectral(nn, 2, 2) = one
1196  rotmatrixspectral(nn, 2, 3) = zero
1197 
1198  rotmatrixspectral(nn, 3, 1) = zero
1199  rotmatrixspectral(nn, 3, 2) = zero
1200  rotmatrixspectral(nn, 3, 3) = one
1201 
1202  else testunity
1203 
1204  ! Section is rotating and only a part of the physical problem
1205  ! is modelled. Consequently a rotation matrix is present for
1206  ! the velocity components.
1207 
1208  ! First transform to a frame where the xt-axis points in the
1209  ! direction of the rotation vector.
1210 
1211  xt(1) = sections(nn)%rotAxis(1)
1212  xt(2) = sections(nn)%rotAxis(2)
1213  xt(3) = sections(nn)%rotAxis(3)
1214 
1215  ! Construct the yt axis. It does not matter exactly as long
1216  ! as it is normal to xt.
1217 
1218  if (abs(xt(2)) < 0.707107_realtype) then
1219  yt(1) = zero
1220  yt(2) = one
1221  yt(3) = zero
1222  else
1223  yt(1) = zero
1224  yt(2) = zero
1225  yt(3) = one
1226  end if
1227 
1228  ! Make sure that yt is normal to xt.
1229 
1230  tmp = xt(1) * yt(1) + xt(2) * yt(2) + xt(3) * yt(3)
1231  yt(1) = yt(1) - tmp * xt(1)
1232  yt(2) = yt(2) - tmp * xt(2)
1233  yt(3) = yt(3) - tmp * xt(3)
1234 
1235  ! And create a unit vector.
1236 
1237  tmp = one / sqrt(yt(1)**2 + yt(2)**2 + yt(3)**2)
1238  yt(1) = tmp * yt(1)
1239  yt(2) = tmp * yt(2)
1240  yt(3) = tmp * yt(3)
1241 
1242  ! Create the vector zt by taking the cross product xt*yt.
1243 
1244  zt(1) = xt(2) * yt(3) - xt(3) * yt(2)
1245  zt(2) = xt(3) * yt(1) - xt(1) * yt(3)
1246  zt(3) = xt(1) * yt(2) - xt(2) * yt(1)
1247 
1248  ! Compute the periodic angle theta and its sine and cosine.
1249 
1250  theta = two * pi / real(sections(nn)%nSlices, realtype)
1251  costheta = cos(theta)
1252  sintheta = sin(theta)
1253 
1254  ! The rotation matrix in the xt,yt,zt frame is given by
1255  !
1256  ! R = | 1 0 0 |
1257  ! | 0 cos(theta) -sin(theta) |
1258  ! | 0 sin(theta) cos(theta) |
1259  !
1260  ! The rotation matrix in the standard cartesian frame is then
1261  ! given by t * r * t^t, where the colums of the transformation
1262  ! matrix t are the unit vectors xt,yt,zt. One can easily check
1263  ! this by checking rotation around the y- and z-axis. The
1264  ! result of this is the expression below.
1265 
1266  rotmatrixspectral(nn, 1, 1) = xt(1) * xt(1) &
1267  + costheta * (yt(1) * yt(1) + zt(1) * zt(1))
1268  rotmatrixspectral(nn, 1, 2) = xt(1) * xt(2) &
1269  + costheta * (yt(1) * yt(2) + zt(1) * zt(2)) &
1270  - sintheta * (yt(1) * zt(2) - yt(2) * zt(1))
1271  rotmatrixspectral(nn, 1, 3) = xt(1) * xt(3) &
1272  + costheta * (yt(1) * yt(3) + zt(1) * zt(3)) &
1273  - sintheta * (yt(1) * zt(3) - yt(3) * zt(1))
1274 
1275  rotmatrixspectral(nn, 2, 1) = xt(1) * xt(2) &
1276  + costheta * (yt(1) * yt(2) + zt(1) * zt(2)) &
1277  + sintheta * (yt(1) * zt(2) - yt(2) * zt(1))
1278  rotmatrixspectral(nn, 2, 2) = xt(2) * xt(2) &
1279  + costheta * (yt(2) * yt(2) + zt(2) * zt(2))
1280  rotmatrixspectral(nn, 2, 3) = xt(2) * xt(3) &
1281  + costheta * (yt(2) * yt(3) + zt(2) * zt(3)) &
1282  - sintheta * (yt(2) * zt(3) - yt(3) * zt(2))
1283 
1284  rotmatrixspectral(nn, 3, 1) = xt(1) * xt(3) &
1285  + costheta * (yt(1) * yt(3) + zt(1) * zt(3)) &
1286  + sintheta * (yt(1) * zt(3) - yt(3) * zt(1))
1287  rotmatrixspectral(nn, 3, 2) = xt(2) * xt(3) &
1288  + costheta * (yt(2) * yt(3) + zt(2) * zt(3)) &
1289  + sintheta * (yt(2) * zt(3) - yt(3) * zt(2))
1290  rotmatrixspectral(nn, 3, 3) = xt(3) * xt(3) &
1291  + costheta * (yt(3) * yt(3) + zt(3) * zt(3))
1292 
1293  end if testunity
1294 
1295  end do sectionloop
1296 
1297  end subroutine timerotmatricesspectral
1298 
1300  !
1301  ! fineGridSpectralCoor computes the coordinates of all but
1302  ! the first spectral solution from the known coordinates of the
1303  ! first time instance.
1304  !
1305  use constants
1306  use block, only: flowdoms, ndom
1307  use inputphysics, only: equationmode
1309  use iomodule, only: iovar
1310  use iteration, only: currentlevel
1311  use monitor, only: timeunsteady
1312  use section, only: nsections, sections
1314  use utils, only: terminate
1315  implicit none
1316  !
1317  ! Local variables.
1318  !
1319  integer :: ierr
1320 
1321  integer(kind=intType) :: nn, ll, i, j, k
1322  integer(kind=intType) :: il, jl, kl
1323 
1324  real(kind=realtype), dimension(nSections) :: dt, t
1325 
1326  ! This routine is only used for the spectral solutions. Return
1327  ! immediately if a different mode is solved.
1328 
1329  if (equationmode /= timespectral) return
1330 
1331  ! Also return immediately if all coordinates were already read
1332  ! from the grid file.
1333 
1334  if (.not. interpolspectral) return
1335  !
1336  ! Step 1. Perform a rigid body motion of the coordinates of the
1337  ! 1st time instance to the other instances.
1338  !
1339  ! Set currentLevel to 1, such that updateCoorFineMesh
1340  ! updates the coordinates of the correct level.
1341 
1342  currentlevel = 1
1343 
1344  ! Determine the delta t for every section. Remember it is possible
1345  ! that every section has a different periodic time.
1346 
1347  do nn = 1, nsections
1348  dt(nn) = sections(nn)%timePeriod &
1349  / real(ntimeintervalsspectral, realtype)
1350  end do
1351 
1352  ! Loop over the number of spectral solutions, starting at 2,
1353  ! because the first is already known.
1354 
1355  timeunsteady = zero
1356  spectralloop: do ll = 2, ntimeintervalsspectral
1357 
1358  ! Set the owned coordinates to the coordinates of the first
1359  ! solution such that updateCoorFineMesh can modify them.
1360 
1361  do nn = 1, ndom
1362 
1363  do k = 1, flowdoms(nn, 1, 1)%kl
1364  do j = 1, flowdoms(nn, 1, 1)%jl
1365  do i = 1, flowdoms(nn, 1, 1)%il
1366  flowdoms(nn, 1, ll)%x(i, j, k, 1) = flowdoms(nn, 1, 1)%x(i, j, k, 1)
1367  flowdoms(nn, 1, ll)%x(i, j, k, 2) = flowdoms(nn, 1, 1)%x(i, j, k, 2)
1368  flowdoms(nn, 1, ll)%x(i, j, k, 3) = flowdoms(nn, 1, 1)%x(i, j, k, 3)
1369  end do
1370  end do
1371  end do
1372 
1373  end do
1374 
1375  ! Compute the corresponding times for this spectral solution
1376  ! and call updateCoorFineMesh to determine the coordinates.
1377 
1378  do nn = 1, nsections
1379  t(nn) = (ll - 1) * dt(nn)
1380  end do
1381 
1382  call updatecoorfinemesh(t, ll)
1383 
1384  end do spectralloop
1385 
1386  ! Return if only one grid has been read.
1387 
1388  if (ngridsread == 1) return
1389  !
1390  ! Step 2. Multiple grids have been read, but the number is not
1391  ! equal to the number of time instances used in the
1392  ! computation. As multiple grids have been read this
1393  ! means that a time spectral computation on a deforming
1394  ! mesh is performed. Therefore the deformations,
1395  ! relative to the first grid, must be interpolated.
1396  !
1397  ! First allocate the memory of IOVar(..,1)%w.
1398  ! This will serve as temporary storage for the coordinates of
1399  ! the 1st spectral instance, because those will be used in the
1400  ! call to updateCoorFineMesh. In this way this routine can be
1401  ! used without modification.
1402 
1403  do nn = 1, ndom
1404 
1405  kl = flowdoms(nn, 1, 1)%kl
1406  jl = flowdoms(nn, 1, 1)%jl
1407  il = flowdoms(nn, 1, 1)%il
1408 
1409  allocate (iovar(nn, 1)%w(il, jl, kl, 3), stat=ierr)
1410  if (ierr /= 0) &
1411  call terminate("fineGridSpectralCoor", &
1412  "Memory allocation failure for &
1413  &IOVar(nn,1)%w")
1414 
1415  do k = 1, kl
1416  do j = 1, jl
1417  do i = 1, il
1418  iovar(nn, 1)%w(i, j, k, 1) = flowdoms(nn, 1, 1)%x(i, j, k, 1)
1419  iovar(nn, 1)%w(i, j, k, 2) = flowdoms(nn, 1, 1)%x(i, j, k, 2)
1420  iovar(nn, 1)%w(i, j, k, 3) = flowdoms(nn, 1, 1)%x(i, j, k, 3)
1421  end do
1422  end do
1423  end do
1424 
1425  end do
1426 
1427  ! Determine the delta t for every section. Remember it is possible
1428  ! that every section has a different periodic time.
1429 
1430  do nn = 1, nsections
1431  dt(nn) = sections(nn)%timePeriod &
1432  / real(ngridsread, realtype)
1433  end do
1434 
1435  ! Loop over the number of spectral solutions read, starting at
1436  ! 2, and determine the displacements relative to the rigid body
1437  ! motion of the grid of the 1st time instance.
1438 
1439  timeunsteady = zero
1440  spectralloopread: do ll = 2, ngridsread
1441 
1442  ! Compute the corresponding times for this spectral solution
1443  ! and call updateCoorFineMesh to determine the coordinates.
1444 
1445  do nn = 1, nsections
1446  t(nn) = (ll - 1) * dt(nn)
1447  end do
1448 
1449  call updatecoorfinemesh(t, 1_inttype)
1450 
1451  ! Determine the relative displacements for this time instance
1452  ! and initialize flowDoms(nn,1,1) for the next round.
1453 
1454  do nn = 1, ndom
1455 
1456  do k = 1, flowdoms(nn, 1, 1)%kl
1457  do j = 1, flowdoms(nn, 1, 1)%jl
1458  do i = 1, flowdoms(nn, 1, 1)%il
1459  iovar(nn, ll)%w(i, j, k, 1) = iovar(nn, ll)%w(i, j, k, 1) &
1460  - flowdoms(nn, 1, 1)%x(i, j, k, 1)
1461  iovar(nn, ll)%w(i, j, k, 2) = iovar(nn, ll)%w(i, j, k, 2) &
1462  - flowdoms(nn, 1, 1)%x(i, j, k, 2)
1463  iovar(nn, ll)%w(i, j, k, 3) = iovar(nn, ll)%w(i, j, k, 3) &
1464  - flowdoms(nn, 1, 1)%x(i, j, k, 3)
1465 
1466  flowdoms(nn, 1, 1)%x(i, j, k, 1) = iovar(nn, 1)%w(i, j, k, 1)
1467  flowdoms(nn, 1, 1)%x(i, j, k, 2) = iovar(nn, 1)%w(i, j, k, 2)
1468  flowdoms(nn, 1, 1)%x(i, j, k, 3) = iovar(nn, 1)%w(i, j, k, 3)
1469  end do
1470  end do
1471  end do
1472 
1473  end do
1474 
1475  end do spectralloopread
1476 
1477  ! The coordinates of IOVar now contain the relative
1478  ! displacements compared to the rigid body motion of the first
1479  ! time instance, except for the first time instance.
1480  ! Set these to zero.
1481 
1482  do nn = 1, ndom
1483  iovar(nn, 1)%w = zero
1484  end do
1485 
1486  ! Interpolate the displacements and add them to the currently
1487  ! stored coordinates.
1488 
1489  call terminate("fineGridSpectralCoor", &
1490  "Arti should do this interpolation stuff")
1491 
1492  ! Release the memory of the variable w in IOVar.
1493 
1494  do nn = 1, ndom
1495  do ll = 1, ngridsread
1496  deallocate (iovar(nn, ll)%w, stat=ierr)
1497  if (ierr /= 0) &
1498  call terminate("fineGridSpectralCoor", &
1499  "Deallocation failure for IOVar%w")
1500  end do
1501  end do
1502 
1503  end subroutine finegridspectralcoor
1504  subroutine updatecoorfinemesh(dtAdvance, sps)
1505  !
1506  ! updateCoorFineMesh updates the coordinates of the
1507  ! moving parts of the current finest mesh by the given amount of
1508  ! time, possibly different per section. In unsteady mode all the
1509  ! times will be equal, but in time spectral mode they can be
1510  ! different.
1511  ! This routine is called in the full mg cycle to put the fine
1512  ! mesh to the position previously calculated on the coarser
1513  ! grid levels, in the unsteady time loop to advance the
1514  ! coordinates only one time step and in the partitioning part
1515  ! of the spectral mode to compute the coordinates of the given
1516  ! spectral solution sps. As it is used in the full MG cycle,
1517  ! currentLevel points to the correct grid level and not
1518  ! ground level.
1519  !
1520  use constants
1521  use block
1522  use blockpointers
1523  use flowvarrefstate
1524  use cgnsgrid
1525  use inputmotion
1526  use iteration
1527  use monitor
1529  implicit none
1530  !
1531  ! Subroutine arguments.
1532  !
1533  integer(kind=intType), intent(in) :: sps
1534 
1535  real(kind=realtype), dimension(*), intent(in) :: dtadvance
1536  !
1537  ! Local variables.
1538  !
1539  integer(kind=intType) :: i, j, k, nn
1540 
1541  real(kind=realtype) :: displx, disply, displz
1542  real(kind=realtype) :: tnew, told
1543  real(kind=realtype) :: anglex, angley, anglez, dx, dy, dz
1544  real(kind=realtype) :: xix, xiy, xiz, etax, etay, etaz
1545  real(kind=realtype) :: zetax, zetay, zetaz, xp, yp, zp, t
1546  real(kind=realtype) :: phi, cosphi, sinphi, eta, zeta
1547 
1548  real(kind=realtype), dimension(3) :: rotationpoint
1549  real(kind=realtype), dimension(3, 3) :: rotationmatrix
1550 
1551  ! Compute the displacements due to the rigid motion of the mesh.
1552 
1553  displx = zero
1554  disply = zero
1555  displz = zero
1556 
1557  ! Determine the time values of the old and new time level.
1558  ! It is assumed that the rigid body rotation of the mesh is only
1559  ! used when only 1 section is present.
1560 
1562  told = tnew - dtadvance(1)
1563 
1564  ! Compute the rotation matrix of the rigid body rotation as
1565  ! well as the rotation point; the latter may vary in time due
1566  ! to rigid body translation.
1567 
1568  call rotmatrixrigidbody(tnew, told, rotationmatrix, rotationpoint)
1569 
1570  ! Loop over the number of local blocks.
1571 
1572  blockloop: do nn = 1, ndom
1573 
1574  ! Set the pointers for this block on the current level.
1575  ! Note that currentLevel must be used and not groundLevel,
1576  ! because groundLevel is 1 level too coarse when this routine
1577  ! is called in the full mg cycle.
1578 
1579  call setpointers(nn, currentlevel, sps)
1580  !
1581  ! The rigid body motion of the entire mesh.
1582  !
1583  ! First the rotation.
1584 
1585  do k = 1, kl
1586  do j = 1, jl
1587  do i = 1, il
1588 
1589  ! Determine the vector relative to the rotation point.
1590 
1591  xp = x(i, j, k, 1) - rotationpoint(1)
1592  yp = x(i, j, k, 2) - rotationpoint(2)
1593  zp = x(i, j, k, 3) - rotationpoint(3)
1594 
1595  ! Apply the transformation matrix to the vector (xp,yp,zp)
1596  ! and set the new coordinates.
1597 
1598  x(i, j, k, 1) = rotationmatrix(1, 1) * xp &
1599  + rotationmatrix(1, 2) * yp &
1600  + rotationmatrix(1, 3) * zp + rotationpoint(1)
1601  x(i, j, k, 2) = rotationmatrix(2, 1) * xp &
1602  + rotationmatrix(2, 2) * yp &
1603  + rotationmatrix(2, 3) * zp + rotationpoint(2)
1604  x(i, j, k, 3) = rotationmatrix(3, 1) * xp &
1605  + rotationmatrix(3, 2) * yp &
1606  + rotationmatrix(3, 3) * zp + rotationpoint(3)
1607  end do
1608  end do
1609  end do
1610 
1611  ! Add the translation.
1612 
1613  do k = 1, kl
1614  do j = 1, jl
1615  do i = 1, il
1616  x(i, j, k, 1) = x(i, j, k, 1) + displx
1617  x(i, j, k, 2) = x(i, j, k, 2) + disply
1618  x(i, j, k, 3) = x(i, j, k, 3) + displz
1619  end do
1620  end do
1621  end do
1622 
1623  !
1624  ! Determine whether the corresponding cgns block is a rotating
1625  ! block. If it is, apply the rotation.
1626  ! Note that now the section ID of the block is taken into
1627  ! account to allow for different periodic times per section.
1628  !
1629  if (cgnsdoms(nbkglobal)%rotatingFrameSpecified) then
1630 
1631  ! Compute the rotation angles.
1632 
1633  anglex = dtadvance(sectionid) * cgnsdoms(nbkglobal)%rotRate(1)
1634  angley = dtadvance(sectionid) * cgnsdoms(nbkglobal)%rotRate(2)
1635  anglez = dtadvance(sectionid) * cgnsdoms(nbkglobal)%rotRate(3)
1636 
1637  ! Compute the unit vector in the direction of the rotation
1638  ! axis, which will be called the xi-direction.
1639 
1640  t = one / max(eps, sqrt(anglex**2 + angley**2 + anglez**2))
1641  xix = t * anglex
1642  xiy = t * angley
1643  xiz = t * anglez
1644 
1645  ! Determine the rotation angle in xi-direction and its sine
1646  ! and cosine. Due to the definition of the xi-direction this
1647  ! angle will always be positive.
1648 
1649  phi = xix * anglex + xiy * angley + xiz * anglez
1650  cosphi = cos(phi)
1651  sinphi = sin(phi)
1652 
1653  ! Loop over the owned coordinates of this block.
1654 
1655  do k = 1, kl
1656  do j = 1, jl
1657  do i = 1, il
1658 
1659  ! Compute the vector relative to center of rotation.
1660 
1661  dx = x(i, j, k, 1) - cgnsdoms(nbkglobal)%rotCenter(1)
1662  dy = x(i, j, k, 2) - cgnsdoms(nbkglobal)%rotCenter(2)
1663  dz = x(i, j, k, 3) - cgnsdoms(nbkglobal)%rotCenter(3)
1664 
1665  ! Compute the coordinates of the point p, which is the
1666  ! closest point on the rotation axis.
1667 
1668  t = dx * xix + dy * xiy + dz * xiz
1669  xp = cgnsdoms(nbkglobal)%rotCenter(1) + t * xix
1670  yp = cgnsdoms(nbkglobal)%rotCenter(2) + t * xiy
1671  zp = cgnsdoms(nbkglobal)%rotCenter(3) + t * xiz
1672 
1673  ! Determine the unit vector in eta direction, which
1674  ! is defined from point p to the current point.
1675 
1676  etax = x(i, j, k, 1) - xp
1677  etay = x(i, j, k, 2) - yp
1678  etaz = x(i, j, k, 3) - zp
1679 
1680  eta = sqrt(etax**2 + etay**2 + etaz**2)
1681  t = one / max(eps, eta)
1682 
1683  etax = t * etax
1684  etay = t * etay
1685  etaz = t * etaz
1686 
1687  ! Determine the unit vector in zeta-direction. This is
1688  ! the cross product of the unit vectors in xi and in
1689  ! eta-direction.
1690 
1691  zetax = xiy * etaz - xiz * etay
1692  zetay = xiz * etax - xix * etaz
1693  zetaz = xix * etay - xiy * etax
1694 
1695  ! Compute the new eta and zeta coordinates.
1696 
1697  zeta = eta * sinphi
1698  eta = eta * cosphi
1699 
1700  ! Compute the new cartesian coordinates.
1701 
1702  x(i, j, k, 1) = xp + eta * etax + zeta * zetax
1703  x(i, j, k, 2) = yp + eta * etay + zeta * zetay
1704  x(i, j, k, 3) = zp + eta * etaz + zeta * zetaz
1705 
1706  end do
1707  end do
1708  end do
1709 
1710  end if
1711 
1712  end do blockloop
1713 
1714  end subroutine updatecoorfinemesh
1716  !
1717  ! allocCoorFineGrid allocates the memory for all the coordinates
1718  ! of all local blocks. Also the memory for the derived data type
1719  ! used for the reading is allocated. If an interpolation must be
1720  ! performed for the time spectral method the variables of this
1721  ! IO type are allocated as well. For all other cases the pointer
1722  ! of the variables are set to the appropriate entry in flowDoms.
1723  !
1724  use constants
1725  use block, only: ndom, flowdoms
1726  use inputphysics, only: equationmode
1728  use iomodule, only: iovar
1729  use iteration, only: noldlevels, deforming_grid
1731  use utils, only: terminate
1732  implicit none
1733  !
1734  ! Local variables.
1735  !
1736  integer :: ierr
1737 
1738  integer(kind=intType) :: nn, mm
1739  integer(kind=intType) :: il, jl, kl, ie, je, ke
1740 
1741  ! Loop over the local blocks and allocate the memory for the
1742  ! coordinates.
1743 
1744  blockloop: do nn = 1, ndom
1745 
1746  ! Some abbreviations of the block dimensions.
1747 
1748  il = flowdoms(nn, 1, 1)%il
1749  jl = flowdoms(nn, 1, 1)%jl
1750  kl = flowdoms(nn, 1, 1)%kl
1751 
1752  ie = flowdoms(nn, 1, 1)%ie
1753  je = flowdoms(nn, 1, 1)%je
1754  ke = flowdoms(nn, 1, 1)%ke
1755 
1756  ! Loop over the number of spectral modes and allocate the
1757  ! memory of the coordinates, single halo's included. The halo
1758  ! values will be initialized in the preprocessing part.
1759 
1760  do mm = 1, ntimeintervalsspectral
1761  allocate (flowdoms(nn, 1, mm)%x(0:ie, 0:je, 0:ke, 3), stat=ierr)
1762  if (ierr /= 0) &
1763  call terminate("allocCoorFineGrid", &
1764  "Memory allocation failure for flowDoms%x")
1765 
1766  flowdoms(nn, 1, mm)%x = 0.0
1767 
1768  !allocate xInit for all time spectral intervals for mesh warping
1769 
1770  if (ierr /= 0) &
1771  call terminate("allocCoorFineGrid", &
1772  "Memory allocation failure for flowDoms%xInit")
1773  !flowDoms(nn,1,mm)%xInit=0.0
1774  !for the first grid also allocate xPlus and xMinus for the
1775  !mesh warping verification...
1776  end do
1777 
1778  ! For a time accurate computation on deforming meshes, allocate
1779  ! the memory for the old coordinates. As this is not the time
1780  ! spectral mode, the third index of flowDoms is always 1.
1781 
1782  if (deforming_grid .and. equationmode == unsteady) then
1783 
1784  allocate (flowdoms(nn, 1, 1)%xOld(noldlevels, 0:ie, 0:je, 0:ke, 3), &
1785  stat=ierr)
1786  if (ierr /= 0) &
1787  call terminate("allocCoorFineGrid", &
1788  "Memory allocation failure for xOld")
1789  end if
1790 
1791  ! Added by HDN
1792  if (deforming_grid .and. equationmode == unsteady) then
1793 
1794  allocate (flowdoms(nn, 1, 1)%xALE(0:ie, 0:je, 0:ke, 3), &
1795  stat=ierr)
1796  if (ierr /= 0) &
1797  call terminate("allocCoorFineGrid", &
1798  "Memory allocation failure for xALE")
1799  end if
1800 
1801  end do blockloop
1802 
1803  ! Allocate the memory for IOVar.
1804 
1805  allocate (iovar(ndom, ngridsread), stat=ierr)
1806  if (ierr /= 0) &
1807  call terminate("allocCoorFineGrid", &
1808  "Memory allocation failure for IOVar")
1809 
1810  ! Determine the equation mode we are solving and set the pointers
1811  ! of IOVar accordingly, or even allocate the memory, if needed.
1812 
1813  select case (equationmode)
1814 
1815  case (steady)
1816 
1817  ! Steady computation. Only one grid needs to be read.
1818  ! Loop over the number of blocks and set the pointer.
1819  ! No pointer offsets are needed for the coordinates.
1820 
1821  do nn = 1, ndom
1822  iovar(nn, 1)%pointerOffset = 0
1823  iovar(nn, 1)%w => flowdoms(nn, 1, 1)%x(1:, 1:, 1:, :)
1824  end do
1825 
1826  !===============================================================
1827 
1828  case (unsteady)
1829 
1830  ! Unsteady computation. The first set of coordinates should
1831  ! be stored in x, other sets (if present) in xOld.
1832  ! No pointer offsets are needed for the coordinates.
1833 
1834  do nn = 1, ndom
1835  iovar(nn, 1)%pointerOffset = 0
1836  iovar(nn, 1)%w => flowdoms(nn, 1, 1)%x(1:, 1:, 1:, :)
1837 
1838  do mm = 2, ngridsread
1839  iovar(nn, mm)%pointerOffset = 0
1840  iovar(nn, mm)%w => flowdoms(nn, 1, 1)%xOld(mm - 1, 1:, 1:, 1:, :)
1841  end do
1842  end do
1843 
1844  !===============================================================
1845 
1846  case (timespectral)
1847 
1848  ! Time spectral mode. A further check is required.
1849 
1850  testallociovar: if (interpolspectral .and. &
1851  ngridsread > 1) then
1852 
1853  ! A restart is performed for a deforming mesh using a
1854  ! different number of time instances than the previous
1855  ! computation. Consequently the coordinates, or better
1856  ! the deformations, will be interpolated later on. Hence
1857  ! some additional storage is required for the coordinates
1858  ! to be read and thus the memory for the variables w of
1859  ! IOVar is allocated. No halo data is needed here.
1860  ! Note that for the 1st time instance the pointer is set
1861  ! to the coordinates of flowDoms, because these are not
1862  ! interpolated. Only the higher time instances are
1863  ! interpolated. No pointer offsets are needed for the
1864  ! coordinates.
1865 
1866  do nn = 1, ndom
1867  il = flowdoms(nn, 1, 1)%il
1868  jl = flowdoms(nn, 1, 1)%jl
1869  kl = flowdoms(nn, 1, 1)%kl
1870 
1871  iovar(nn, 1)%pointerOffset = 0
1872  iovar(nn, 1)%w => flowdoms(nn, 1, 1)%x(1:, 1:, 1:, :)
1873 
1874  do mm = 2, ngridsread
1875  iovar(nn, mm)%pointerOffset = 0
1876  allocate (iovar(nn, mm)%w(il, jl, kl, 3), stat=ierr)
1877  if (ierr /= 0) &
1878  call terminate("allocCoorFineGrid", &
1879  "Memory allocation failure for &
1880  &IOVar%w")
1881  end do
1882  end do
1883 
1884  else testallociovar
1885 
1886  ! One of the following options is true.
1887  ! - The computation starts from scratch.
1888  ! - A restart is performed using a rigid grid, possibly
1889  ! moving. The number of time instances does not have
1890  ! to be the same.
1891  ! - A restart with a deforming mesh is performed with the
1892  ! same number of time instances.
1893  !
1894  ! In all these situations the pointers of IOVar are
1895  ! simply set to the coordinates of flowDoms.
1896 
1897  do nn = 1, ndom
1898  do mm = 1, ngridsread
1899  iovar(nn, mm)%pointerOffset = 0
1900  iovar(nn, mm)%w => flowdoms(nn, 1, mm)%x(1:, 1:, 1:, :)
1901  end do
1902  end do
1903 
1904  end if testallociovar
1905 
1906  end select
1907 
1908  end subroutine alloccoorfinegrid
1909  subroutine checkpartitioning(np, load_inbalance, face_inbalance)
1910 
1911  ! This subroutine runs the load balancing and partitioning algorithm
1912  ! to determine what the load balancing will be for a given number of
1913  ! procs np. The output is load_inbalance and face_inbalance.
1914 
1915  use constants
1916  use communication, only: nproc
1917  use partitionmod, only: ubvec
1918  use loadbalance, only: blockdistribution
1919  implicit none
1920 
1921  integer(kind=intType), intent(in) :: np
1922  integer(kind=intType) :: nproc_save
1923  real(kind=realtype), intent(out) :: load_inbalance, face_inbalance
1924 
1925  ! Note: This file follows mostly partitionAndReadGrid. See
1926  ! partitionAndReadGrid.f90 for more infromation
1927 
1928  ! Trick it into thinking we have np processors:
1929  nproc_save = nproc
1930  nproc = np
1931 
1932  call blockdistribution
1933 
1934  ! Restore the number of procs
1935  nproc = nproc_save
1936 
1937  ! Extract the inbalance info:
1938  load_inbalance = ubvec(1)
1939  face_inbalance = ubvec(2)
1940 
1941  end subroutine checkpartitioning
1942 
1944  !
1945  ! determineSections determines the number of sections, i.e.
1946  ! grid parts between sliding mesh interfaces, present in the
1947  ! entire grid.
1948  !
1949  use constants
1950  use block
1951  use cgnsgrid
1952  use communication
1953  use inputtimespectral
1954  use section
1955  use su_cgns
1957  use utils, only: terminate
1958  implicit none
1959  !
1960  ! Local parameter, threshold for allowed angle difference between
1961  ! the theoretical and true value, 0.1 degrees.
1962  !
1963  real(kind=realtype), parameter :: threshold = 0.1_realtype
1964  !
1965  ! Local variables.
1966  !
1967  integer :: ierr
1968 
1969  integer(kind=intType) :: nn, mm, ii, jj
1970  integer(kind=intType) :: nLevel, nSlices, slideID
1971  integer(kind=intType), dimension(cgnsNDom) :: sectionID, sorted
1972  integer(kind=intType), dimension(cgnsNsliding, 2) :: secSliding
1973 
1974  real(kind=realtype) :: costheta, cosphi, cospsi
1975  real(kind=realtype) :: sintheta, sinphi, sinpsi
1976  real(kind=realtype) :: r11, r12, r13, r21, r22, r23
1977  real(kind=realtype) :: r31, r32, r33
1978  real(kind=realtype) :: d1, d2, a1, a0, lamr, lami, angle, dangle
1979 
1980  logical :: situationChanged
1981 
1982  ! Initialize sectionID to the cgns block number.
1983 
1984  do nn = 1, cgnsndom
1985  sectionid(nn) = nn
1986  end do
1987 
1988  ! Loop to determine the highest cgns block id in every section.
1989 
1990  loophighestblock: do
1991 
1992  ! Initialize situationChanged to .false.
1993 
1994  situationchanged = .false.
1995 
1996  ! Loop over the internal block faces of the blocks.
1997 
1998  do nn = 1, cgnsndom
1999 
2000  ! First the 1 to 1 block connectivities.
2001 
2002  do mm = 1, cgnsdoms(nn)%n1to1
2003 
2004  ! Store the neighboring block a bit easier and change the
2005  ! value of sectionID if the neighboring block has a
2006  ! higher value. In that case situationChanged is .true.
2007 
2008  ii = cgnsdoms(nn)%conn1to1(mm)%donorBlock
2009  if (sectionid(ii) > sectionid(nn)) then
2010  sectionid(nn) = sectionid(ii)
2011  situationchanged = .true.
2012  end if
2013 
2014  end do
2015 
2016  ! No general connectivities yet.
2017 
2018  end do
2019 
2020  ! Criterion to exit the loop.
2021 
2022  if (.not. situationchanged) exit
2023 
2024  end do loophighestblock
2025 
2026  ! Copy sectionID in sorted and sort sorted in increasing order.
2027 
2028  do nn = 1, cgnsndom
2029  sorted(nn) = sectionid(nn)
2030  end do
2031 
2032  call qsortintegers(sorted, cgnsndom)
2033 
2034  ! Determine the number of sections. Note there is at least one
2035  ! section, because there is at least one block in the grid.
2036 
2037  nsections = 1
2038  do nn = 2, cgnsndom
2039  if (sorted(nn) > sorted(nsections)) then
2040  nsections = nsections + 1
2041  sorted(nsections) = sorted(nn)
2042  end if
2043  end do
2044 
2045  ! Determine the sections to which the owned blocks belong.
2046 
2047  nlevel = ubound(flowdoms, 2)
2048  do nn = 1, ndom
2049 
2050  ! Determine the corresponding cgns block id and search its
2051  ! section id in sorted.
2052 
2053  mm = flowdoms(nn, 1, 1)%cgnsBlockID
2054  mm = bsearchintegers(sectionid(mm), sorted)
2055 
2056  if (debug) then
2057  if (mm == 0) call terminate("determineSections", &
2058  "Entry not found in sorted.")
2059  end if
2060 
2061  ! Set the section id for all grid levels for all spectral
2062  ! time intervals.
2063 
2064  do jj = 1, ntimeintervalsspectral
2065  do ii = 1, nlevel
2066  flowdoms(nn, ii, jj)%sectionID = mm
2067  end do
2068  end do
2069 
2070  end do
2071 
2072  ! Allocate the memory for sections.
2073 
2074  allocate (sections(nsections), stat=ierr)
2075  if (ierr /= 0) &
2076  call terminate("determineSections", &
2077  "Memory allocation failure for sections.")
2078 
2079  ! Initialize the number of slices for each of the sections to 1,
2080  ! periodic and rotating to .false. and rotCenter, rotAxis
2081  ! and rotRate to zero.
2082 
2083  do nn = 1, nsections
2084  sections(nn)%nSlices = 1
2085  sections(nn)%periodic = .false.
2086  sections(nn)%rotating = .false.
2087  sections(nn)%rotCenter = zero
2088  sections(nn)%rotAxis = zero
2089  sections(nn)%rotRate = zero
2090  end do
2091 
2092  ! Determine the number of slices and the periodic transformation
2093  ! for the sections.
2094 
2095  loopcgnsdom: do nn = 1, cgnsndom
2096 
2097  ! Search for the corresponding section.
2098 
2099  ii = bsearchintegers(sectionid(nn), sorted(1:nsections))
2100  if (debug) then
2101  if (ii == 0) call terminate("determineSections", &
2102  "Entry not found in sorted.")
2103  end if
2104 
2105  ! It is assumed that periodic info is correct. So if this
2106  ! section has already been treated, there is no need to do
2107  ! it again.
2108 
2109  if (sections(ii)%periodic) cycle
2110 
2111  ! Loop over the 1 to 1 subfaces of the cgns block and try to
2112  ! find a periodic one.
2113 
2114  do mm = 1, cgnsdoms(nn)%n1to1
2115  if (cgnsdoms(nn)%conn1to1(mm)%periodic) exit
2116  end do
2117 
2118  ! Continue with the next block if this block does not have
2119  ! periodic subfaces.
2120 
2121  if (mm > cgnsdoms(nn)%n1to1) cycle
2122 
2123  ! Subface mm is a periodic one. Set periodic to .true.
2124 
2125  sections(ii)%periodic = .true.
2126 
2127  ! Set the rotation axis of the section to the rotation
2128  ! angles of the periodic transformation. This may be
2129  ! overwritten later on using the rotation rate, but for
2130  ! some cases this is the only rotation information present.
2131 
2132  sections(ii)%rotAxis = cgnsdoms(nn)%conn1to1(mm)%rotationAngles
2133 
2134  ! Construct the rotation matrix, where it is assumed that the
2135  ! sequence of rotation is first rotation around the x-axis,
2136  ! followed by rotation around the y-axis and finally rotation
2137  ! around the z-axis.
2138 
2139  costheta = cos(cgnsdoms(nn)%conn1to1(mm)%rotationAngles(1))
2140  sintheta = sin(cgnsdoms(nn)%conn1to1(mm)%rotationAngles(1))
2141 
2142  cosphi = cos(cgnsdoms(nn)%conn1to1(mm)%rotationAngles(2))
2143  sinphi = sin(cgnsdoms(nn)%conn1to1(mm)%rotationAngles(2))
2144 
2145  cospsi = cos(cgnsdoms(nn)%conn1to1(mm)%rotationAngles(3))
2146  sinpsi = sin(cgnsdoms(nn)%conn1to1(mm)%rotationAngles(3))
2147 
2148  r11 = cosphi * cospsi
2149  r21 = cosphi * sinpsi
2150  r31 = -sinphi
2151 
2152  r12 = sintheta * sinphi * cospsi - costheta * sinpsi
2153  r22 = sintheta * sinphi * sinpsi + costheta * cospsi
2154  r32 = sintheta * cosphi
2155 
2156  r13 = costheta * sinphi * cospsi + sintheta * sinpsi
2157  r23 = costheta * sinphi * sinpsi - sintheta * cospsi
2158  r33 = costheta * cosphi
2159 
2160  ! Store the rotation matrix, rotation center and translation
2161  ! vector for this section.
2162 
2163  sections(ii)%rotCenter = &
2164  cgnsdoms(nn)%conn1to1(mm)%rotationCenter
2165  sections(ii)%translation = &
2166  cgnsdoms(nn)%conn1to1(mm)%translation
2167 
2168  sections(ii)%rotMatrix(1, 1) = r11
2169  sections(ii)%rotMatrix(2, 1) = r21
2170  sections(ii)%rotMatrix(3, 1) = r31
2171 
2172  sections(ii)%rotMatrix(1, 2) = r12
2173  sections(ii)%rotMatrix(2, 2) = r22
2174  sections(ii)%rotMatrix(3, 2) = r32
2175 
2176  sections(ii)%rotMatrix(1, 3) = r13
2177  sections(ii)%rotMatrix(2, 3) = r23
2178  sections(ii)%rotMatrix(3, 3) = r33
2179 
2180  ! Determine the coefficients of lambda and lambda^2 of the
2181  ! characteristic polynomial.
2182 
2183  d2 = -r11 - r22 - r33
2184  d1 = r11 * r22 + r11 * r33 + r22 * r33 - r12 * r21 - r13 * r31 - r23 * r32
2185 
2186  ! Make use of the fact that one eigenvalue of the transformation
2187  ! matrix is 1 and determine the coefficients of the quadratic
2188  ! equation for the other two eigenvalues.
2189 
2190  a1 = d2 + one
2191  a0 = a1 + d1
2192 
2193  ! Determine the real and imaginary part of the two eigenvalues.
2194  ! Neglect the factor 1/2 here.
2195 
2196  lamr = -a1
2197  lami = sqrt(abs(a1 * a1 - four * a0))
2198 
2199  ! Determine the angle in the imaginary plane. Due to the
2200  ! positive definition of lami, this angle will be between
2201  ! 0 and pi. Take care of the exceptional case that the angle
2202  ! is zero.
2203 
2204  angle = atan2(lami, lamr)
2205  if (angle == zero) angle = two * pi
2206 
2207  ! Determine the number of slices.
2208 
2209  nslices = nint(two * pi / angle)
2210 
2211  ! Determine the angle difference in degrees between
2212  ! nSlices*angle and a complete rotation. If this is larger than
2213  ! the threshold processor 0 will print an error message and exit.
2214 
2215  dangle = abs(180.0_realtype * (two * pi - nslices * angle) / pi)
2216 
2217  if (dangle >= threshold) then
2218  if (myid == 0) &
2219  call terminate("determineSections", &
2220  "Periodic angle not a integer divide of &
2221  &360 degrees")
2222  call mpi_barrier(adflow_comm_world, ierr)
2223  end if
2224 
2225  ! Set the number of slices for this section.
2226 
2227  sections(ii)%nSlices = nslices
2228 
2229  end do loopcgnsdom
2230 
2231  ! Again loop over the number of block of the original mesh,
2232  ! but now determine whether or not the section is rotating.
2233 
2234  do nn = 1, cgnsndom
2235 
2236  ! If the block is rotating, copy that information to
2237  ! the corresponding section. If the section is not
2238  ! periodic, also set the rotation center.
2239 
2240  if (cgnsdoms(nn)%rotatingFrameSpecified) then
2241 
2242  ii = bsearchintegers(sectionid(nn), sorted(1:nsections))
2243  sections(ii)%rotating = .true.
2244  sections(ii)%rotAxis = cgnsdoms(nn)%rotRate
2245  sections(ii)%rotRate = cgnsdoms(nn)%rotRate
2246 
2247  if (.not. sections(ii)%periodic) &
2248  sections(ii)%rotCenter = cgnsdoms(nn)%rotCenter
2249 
2250  end if
2251  end do
2252 
2253  ! Determine the two sections for every sliding mesh
2254  ! interface.
2255 
2256  secsliding = 0
2257  do nn = 1, cgnsndom
2258  do mm = 1, cgnsdoms(nn)%nBocos
2259  if (cgnsdoms(nn)%bocoInfo(mm)%actualFace .and. &
2260  cgnsdoms(nn)%bocoInfo(mm)%BCType == slidinginterface) then
2261 
2262  ! Boundary face is part of a sliding mesh interface.
2263  ! Determine the ID of the interface.
2264 
2265  slideid = abs(cgnsdoms(nn)%bocoInfo(mm)%slidingID)
2266 
2267  ! Determine the section to which this block belongs and
2268  ! store its id for this sliding interface.
2269 
2270  ii = bsearchintegers(sectionid(nn), sorted(1:nsections))
2271  if (secsliding(slideid, 1) == 0) then
2272  secsliding(slideid, 1) = ii
2273  else if (secsliding(slideid, 1) /= ii) then
2274  secsliding(slideid, 2) = ii
2275  end if
2276 
2277  end if
2278  end do
2279  end do
2280 
2281  ! Loop over the sliding mesh interfaces to set the rotation axis
2282  ! for non-rotating sections.
2283 
2284  do ii = 1, cgnsnsliding
2285 
2286  ! Store the two sections id's a bit easier.
2287 
2288  mm = secsliding(ii, 1)
2289  nn = secsliding(ii, 2)
2290 
2291  ! Print an error message if both sections are not rotating.
2292 
2293  if ((.not. sections(mm)%rotating) .and. &
2294  (.not. sections(nn)%rotating)) then
2295  if (myid == 0) &
2296  call terminate("determineSections", &
2297  "Encountered sliding interface between &
2298  &two non-rotating sections")
2299  call mpi_barrier(adflow_comm_world, ierr)
2300  end if
2301 
2302  ! Set the rotation axis if section mm is not rotating.
2303  ! If it is not periodic also set the rotation point.
2304 
2305  if (.not. sections(mm)%rotating) then
2306  sections(mm)%rotAxis = sections(nn)%rotAxis
2307  if (.not. sections(mm)%periodic) &
2308  sections(mm)%rotCenter = sections(nn)%rotCenter
2309  end if
2310 
2311  ! Idem for section nn.
2312 
2313  if (.not. sections(nn)%rotating) then
2314  sections(nn)%rotAxis = sections(mm)%rotAxis
2315  if (.not. sections(nn)%periodic) &
2316  sections(nn)%rotCenter = sections(mm)%rotCenter
2317  end if
2318 
2319  end do
2320 
2321  ! Determine the unit rotation axis for the sections.
2322 
2323  do nn = 1, nsections
2324  d1 = one / max(eps, sqrt(sections(nn)%rotAxis(1)**2 &
2325  + sections(nn)%rotAxis(2)**2 &
2326  + sections(nn)%rotAxis(3)**2))
2327 
2328  sections(nn)%rotAxis(1) = d1 * sections(nn)%rotAxis(1)
2329  sections(nn)%rotAxis(2) = d1 * sections(nn)%rotAxis(2)
2330  sections(nn)%rotAxis(3) = d1 * sections(nn)%rotAxis(3)
2331  end do
2332 
2333  end subroutine determinesections
2334 
2335 end module partitioning
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) nbkglobal
integer(kind=inttype) sectionid
real(kind=realtype), dimension(:, :, :, :), pointer x
integer(kind=inttype) kl
integer(kind=inttype) il
type(cgnsblockinfotype), dimension(:), allocatable cgnsdoms
Definition: cgnsGrid.F90:495
integer(kind=inttype), dimension(:, :), allocatable famidssliding
Definition: cgnsGrid.F90:512
integer(kind=inttype) cgnsndomaininterfaces
Definition: cgnsGrid.F90:517
integer(kind=inttype), dimension(:, :), allocatable bcidsdomaininterfaces
Definition: cgnsGrid.F90:523
type(cgnsfamilytype), dimension(:), allocatable cgnsfamilies
Definition: cgnsGrid.F90:504
integer(kind=inttype) cgnsnfamilies
Definition: cgnsGrid.F90:500
integer(kind=inttype) cgnsnsliding
Definition: cgnsGrid.F90:508
integer(kind=inttype), dimension(:), allocatable famidsdomaininterfaces
Definition: cgnsGrid.F90:521
integer(kind=inttype) cgnsndom
Definition: cgnsGrid.F90:491
character(len=maxstringlen) stringspace
integer adflow_comm_world
integer(kind=inttype), parameter domaininterfacep
Definition: constants.F90:279
integer(kind=inttype), parameter slidinginterface
Definition: constants.F90:275
real(kind=realtype), parameter zero
Definition: constants.F90:71
integer(kind=inttype), parameter domaininterfacerhouvw
Definition: constants.F90:278
integer(kind=inttype), parameter domaininterfacerho
Definition: constants.F90:280
real(kind=realtype), parameter four
Definition: constants.F90:75
real(kind=realtype), parameter pi
Definition: constants.F90:22
real(kind=realtype), parameter eps
Definition: constants.F90:23
integer(kind=inttype), parameter timespectral
Definition: constants.F90:115
integer(kind=inttype), parameter unsteady
Definition: constants.F90:115
real(kind=realtype), parameter one
Definition: constants.F90:72
integer(kind=inttype), parameter domaininterfacetotal
Definition: constants.F90:281
integer(kind=inttype), parameter steady
Definition: constants.F90:115
real(kind=realtype), parameter two
Definition: constants.F90:73
integer(kind=inttype), parameter domaininterfaceall
Definition: constants.F90:277
integer(kind=inttype), parameter externalflow
Definition: constants.F90:120
subroutine check1to1subfaces
subroutine checkfaces
Definition: gridChecking.F90:4
character(len=maxstringlen) gridfile
Definition: inputParam.F90:158
integer(kind=inttype) degreefouryrot
Definition: inputParam.F90:354
integer(kind=inttype) degreefourmach
Definition: inputParam.F90:459
real(kind=realtype) omegafouralpha
Definition: inputParam.F90:404
integer(kind=inttype) degreefourxrot
Definition: inputParam.F90:353
real(kind=realtype) omegafouryrot
Definition: inputParam.F90:363
real(kind=realtype) omegafourzrot
Definition: inputParam.F90:364
real(kind=realtype) omegafourxrot
Definition: inputParam.F90:362
real(kind=realtype) omegafourbeta
Definition: inputParam.F90:434
real(kind=realtype) omegafourmach
Definition: inputParam.F90:464
integer(kind=inttype) degreefourbeta
Definition: inputParam.F90:429
integer(kind=inttype) degreefourzrot
Definition: inputParam.F90:355
integer(kind=inttype) degreefouralpha
Definition: inputParam.F90:399
integer(kind=inttype) equationmode
Definition: inputParam.F90:583
integer(kind=inttype) flowtype
Definition: inputParam.F90:583
real(kind=realtype), dimension(:, :, :), allocatable rotmatrixspectral
Definition: inputParam.F90:695
integer(kind=inttype) ntimeintervalsspectral
Definition: inputParam.F90:645
real(kind=realtype) omegafourier
Definition: inputParam.F90:699
integer(kind=inttype) noldgridread
Definition: inputParam.F90:751
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
logical standalonemode
Definition: iteration.f90:69
logical deforming_grid
Definition: iteration.f90:69
subroutine loadbalancegrid
Definition: loadBalance.F90:6
subroutine blockdistribution
real(kind=realtype) timeunsteady
Definition: monitor.f90:98
real(kind=realtype) timeunsteadyrestart
Definition: monitor.f90:98
subroutine determineneighborids
subroutine determineinterfaceids
subroutine timeperiodspectral
subroutine checkpartitioning(np, load_inbalance, face_inbalance)
subroutine updatecoorfinemesh(dtAdvance, sps)
subroutine initfinegridiblank
subroutine partitionandreadgrid(partitionOnly)
Definition: partitioning.F90:6
subroutine determinegridfilenames
subroutine determinesections
subroutine timerotmatricesspectral
subroutine alloccoorfinegrid
real(kind=realtype) function commontimespectral(t1, t2)
subroutine finegridspectralcoor
integer(kind=inttype) ngridsread
character(len=maxstringlen), dimension(:), allocatable gridfiles
logical interpolspectral
integer, dimension(:), allocatable fileids
real, dimension(2) ubvec
subroutine readblocksizes
Definition: readCGNSGrid.F90:6
subroutine readgrid
integer(kind=inttype) nsections
Definition: section.f90:44
type(sectiontype), dimension(:), allocatable sections
Definition: section.f90:46
integer(kind=inttype) function bsearchstrings(key, base)
Definition: sorting.F90:812
subroutine qsortstrings(arr, nn)
Definition: sorting.F90:525
subroutine qsortintegers(arr, nn)
Definition: sorting.F90:101
integer(kind=inttype) function bsearchintegers(key, base)
Definition: sorting.F90:18
Definition: utils.F90:1
subroutine rotmatrixrigidbody(tNew, tOld, rotationMatrix, rotationPoint)
Definition: utils.F90:614
subroutine setpointers(nn, mm, ll)
Definition: utils.F90:3237
subroutine terminate(routineName, errorMessage)
Definition: utils.F90:502