ADflow  v1.0
ADflow is a finite volume RANS solver tailored for gradient-based aerodynamic design optimization.
adtSearch.F90
Go to the documentation of this file.
1 module adtsearch
2  !
3  ! Module which contains the subroutines for the global search.
4  !
5  use constants
7  use adtutils, only: adtterminate
8  use adtdata
9  implicit none
10 
11  !=================================================================
12 
13 contains
14 
15  !===============================================================
16 
17  subroutine containmentsearch(nCoor, coor, &
18  adtID, procID, &
19  elementType, elementID, &
20  uvw, nInterpol, &
21  arrDonor, arrInterpol)
22  !
23  ! This routine attempts for every coordinate to find the
24  ! element in the given ADT, which contains that coordinate.
25  ! If no element is found the corresponding entry in procID is
26  ! set to -1 to indicate failure.
27  ! Subroutine intent(in) arguments.
28  ! --------------------------------
29  ! nCoor: Number of coordinates for which the element must
30  ! be determined.
31  ! coor: The coordinates of these points.
32  ! adtID: The ADT to be searched.
33  ! nInterpol: Number of variables to be interpolated.
34  ! arrDonor: Array with the donor data; needed to obtain the
35  ! interpolated data.
36  ! Subroutine intent(out) arguments.
37  ! ---------------------------------
38  ! procID: The ID of the processor in the group of the ADT
39  ! where the element containing the point is
40  ! stored. If no element is found for a given
41  ! point the corresponding entry in procID is set
42  ! to -1 to indicate failure. Remember that the
43  ! processor ID's start at 0 and not at 1.
44  ! elementType: The type of element which contains the point.
45  ! elementID: The entry in the connectivity of this element
46  ! which contains the point.
47  ! uvw: The parametric coordinates of the point in the
48  ! transformed element; this transformation is
49  ! such that every element is transformed into a
50  ! standard element in parametric space. The u, v
51  ! and w coordinates can be used to determine the
52  ! actual interpolation weights.
53  ! arrInterpol: Array with the interpolated data.
54  !
55  implicit none
56  !
57  ! Subroutine arguments.
58  !
59  integer(kind=intType), intent(in) :: nCoor, nInterpol
60  character(len=*), intent(in) :: adtID
61 
62  real(kind=realtype), dimension(:, :), intent(in) :: coor
63  real(kind=realtype), dimension(:, :), intent(in) :: arrdonor
64 
65  integer, dimension(:), intent(out) :: procID
66  integer(kind=intType), dimension(:), intent(out) :: elementID
67 
68  integer(kind=adtElementType), dimension(:), intent(out) :: &
69  elementType
70  real(kind=realtype), dimension(:, :), intent(out) :: uvw
71  real(kind=realtype), dimension(:, :), intent(out) :: arrinterpol
72  !
73  ! Local variables.
74  !
75  integer :: ierr
76 
77  type(adttype), pointer :: ADT
78 
79  integer(kind=intType) :: jj, nAlloc
80 
81  real(kind=realtype), dimension(1) :: dummy
82 
83  ! Determine the index in the array ADTs, which stores the given
84  ! ID. As the number of trees stored is limited, a linear search
85  ! algorithm is okay.
86 
87  nalloc = ubound(adts, 1)
88  do jj = 1, nalloc
89  if (adtid == adts(jj)%adtID) exit
90  end do
91 
92  ! Check if the ADT to be searched exists. If not stop.
93  ! Note that adtTerminate is not called. The reason is that the
94  ! processor ID is not known.
95 
96  if (jj > nalloc) stop "ADT to be searched does not exist."
97 
98  ! Set pointer to the ADT we will be working with
99 
100  adt => adts(jj)
101 
102  ! Check if the ADT corresponds to a volume grid. If not terminate.
103 
104  if (adt%adtType /= adtvolumeadt) then
105  if (adt%myID == 0) &
106  call adtterminate(adt, "containmentSearch", &
107  "ADT does not contain a volume mesh.")
108  call mpi_barrier(adt%comm, ierr)
109  end if
110 
111  ! Initialize the search, i.e. determine the number of
112  ! coordinates to be searched in each of the local ADT's.
113 
114  call initsearch(ncoor, coor, dummy, adt, .true.)
115 
116  ! Perform the actual search.
117 
118  call search(ncoor, coor, procid, elementtype, &
119  elementid, uvw, dummy, adt, &
120  .true., ninterpol, arrdonor, arrinterpol)
121 
122  end subroutine containmentsearch
123 
124  subroutine failsafesearch(nCoor, coor, &
125  adtID, procID, &
126  elementType, elementID, &
127  uvw, dist2, &
128  nInterpol, arrDonor, &
129  arrInterpol)
130  !
131  ! This routine attempts for every coordinate to find the
132  ! element in the given ADT, which contains that coordinate.
133  ! If no element is found a minimum distance search is
134  ! performed, such that always an interpolation can be
135  ! performed. To indicate that the element does not contain the
136  ! point the element ID is negated.
137  ! Subroutine intent(in) arguments.
138  ! --------------------------------
139  ! nCoor: Number of coordinates for which the element must be
140  ! determined.
141  ! coor: The coordinates of these points.
142  ! adtID: The ADT to be searched.
143  ! nInterpol: Number of variables to be interpolated.
144  ! arrDonor: Array with the donor data; needed to obtain the
145  ! interpolated data.
146  ! Subroutine intent(out) arguments.
147  ! ---------------------------------
148  ! procID: The ID of the processor in the group of the ADT
149  ! where the element containing the point is
150  ! stored. If no element is found for a given
151  ! point the corresponding entry in procID is set
152  ! to -1 to indicate failure. Remember that the
153  ! processor ID's start at 0 and not at 1.
154  ! elementType: The type of element which contains the point.
155  ! elementID: The entry in the connectivity of this element
156  ! which contains the point. The ID is negative if
157  ! the coordinate is outside the element, i.e. if
158  ! a minimum distance search had to be used.
159  ! uvw: The parametric coordinates of the point in the
160  ! transformed element; this transformation is
161  ! such that every element is transformed into a
162  ! standard element in parametric space. The u, v
163  ! and w coordinates can be used to determine the
164  ! actual interpolation weights.
165  ! arrInterpol: Array with the interpolated data.
166  ! Subroutine intent(inout) arguments.
167  ! -----------------------------------
168  ! dist2: Minimum distance squared of the coordinates to the
169  ! elements of the ADT. On input it should be
170  ! initialized by the calling program, possibly to a
171  ! large value. In this way it is possible to handle
172  ! periodic problems as efficiently as possible.
173  !
174  implicit none
175  !
176  ! Subroutine arguments.
177  !
178  integer(kind=intType), intent(in) :: nCoor, nInterpol
179  character(len=*), intent(in) :: adtID
180 
181  real(kind=realtype), dimension(:, :), intent(in) :: coor
182  real(kind=realtype), dimension(:, :), intent(in) :: arrdonor
183 
184  integer, dimension(:), intent(out) :: procID
185  integer(kind=intType), dimension(:), intent(out) :: elementID
186 
187  integer(kind=adtElementType), dimension(:), intent(out) :: &
188  elementType
189 
190  real(kind=realtype), dimension(:, :), intent(out) :: uvw
191  real(kind=realtype), dimension(:, :), intent(out) :: arrinterpol
192 
193  real(kind=realtype), dimension(:), intent(inout) :: dist2
194  !
195  ! Local variables.
196  !
197  integer :: ierr
198  integer, dimension(:), allocatable :: tmpProcID
199 
200  type(adttype), pointer :: ADT
201 
202  integer(kind=intType) :: i, j, ii, jj, nAlloc, nFail
203  integer(kind=intType), dimension(:), allocatable :: tmpElementID
204  integer(kind=intType), dimension(:), allocatable :: coorIDs
205 
206  integer(kind=adtElementType), dimension(:), allocatable :: &
207  tmpElementType
208 
209  real(kind=realtype), dimension(1) :: dummy
210 
211  real(kind=realtype), dimension(:), allocatable :: tmpdist2
212  real(kind=realtype), dimension(:, :), allocatable :: tmpcoor
213  real(kind=realtype), dimension(:, :), allocatable :: tmpuvw
214  real(kind=realtype), dimension(:, :), allocatable :: tmparrint
215 
216  ! Determine the index in the array ADTs, which stores the given
217  ! ID. As the number of trees stored is limited, a linear search
218  ! algorithm is okay.
219 
220  nalloc = ubound(adts, 1)
221  do jj = 1, nalloc
222  if (adtid == adts(jj)%adtID) exit
223  end do
224 
225  ! Check if the ADT to be searched exists. If not stop.
226  ! Note that adtTerminate is not called. The reason is that the
227  ! processor ID is not known.
228 
229  if (jj > nalloc) stop "ADT to be searched does not exist."
230 
231  ! Set pointer to the ADT we will be working with
232  adt => adts(jj)
233 
234  ! Check if the ADT corresponds to a volume grid.
235  ! If not terminate.
236 
237  if (adt%adtType /= adtvolumeadt) then
238  if (adt%myID == 0) &
239  call adtterminate(adt, "failSafeSearch", &
240  "ADT does not contain a volume mesh.")
241  call mpi_barrier(adt%comm, ierr)
242  end if
243 
244  ! Perform the containment search.
245 
246  call initsearch(ncoor, coor, dummy, adt, .true.)
247 
248  call search(ncoor, coor, procid, elementtype, &
249  elementid, uvw, dummy, adt, &
250  .true., ninterpol, arrdonor, arrinterpol)
251 
252  ! Determine the number of coordinates for which the containment
253  ! search failed. Set for the other coordinates the distance to
254  ! zero.
255 
256  nfail = 0
257  do i = 1, ncoor
258  if (procid(i) == -1) then
259  nfail = nfail + 1
260  else
261  dist2(i) = zero
262  end if
263  end do
264 
265  ! Determine the global sum of nFail, which is stored in ii.
266 
267  call mpi_allreduce(nfail, ii, 1, adflow_integer, mpi_max, &
268  adt%comm, ierr)
269 
270  ! Return if ii == 0, because the minimum distance search
271  ! is not needed.
272 
273  if (ii == 0) return
274 
275  ! Allocate the memory for the arrays needed for the minimum
276  ! distance search.
277 
278  allocate (tmpcoor(3, nfail), tmpprocid(nfail), &
279  tmpelementtype(nfail), tmpelementid(nfail), &
280  tmpuvw(3, nfail), tmpdist2(nfail), &
281  coorids(nfail), tmparrint(ninterpol, nfail), &
282  stat=ierr)
283  if (ierr /= 0) &
284  call adtterminate(adt, "failSafeSearch", &
285  "Memory allocation failure for the arrays &
286  &for the minimum distance search.")
287 
288  ! Store the information needed for minimum distance search in
289  ! the arrays tmpCoor, tmpDist2 and coorIDs.
290 
291  ii = 0
292  do i = 1, ncoor
293  if (procid(i) == -1) then
294  ii = ii + 1
295 
296  tmpcoor(1, ii) = coor(1, i)
297  tmpcoor(2, ii) = coor(2, i)
298  tmpcoor(3, ii) = coor(3, i)
299  tmpdist2(ii) = dist2(i)
300  coorids(ii) = i
301  end if
302  end do
303 
304  ! Perform the minimum distance search for the coordinates for
305  ! which the containment search failed.
306 
307  call initsearch(nfail, tmpcoor, tmpdist2, adt, .false.)
308 
309  call search(nfail, tmpcoor, tmpprocid, tmpelementtype, &
310  tmpelementid, tmpuvw, tmpdist2, adt, &
311  .false., ninterpol, arrdonor, tmparrint)
312 
313  ! Copy for the successful searches the data into the arrays to
314  ! be returned by this subroutine. Note that the element IDs are
315  ! negated to indicate that the coordinate is outside the element.
316 
317  do i = 1, nfail
318  if (tmpprocid(i) /= -1) then
319  ii = coorids(i)
320 
321  procid(ii) = tmpprocid(i)
322  elementtype(ii) = tmpelementtype(i)
323  elementid(ii) = -tmpelementid(i)
324  uvw(1, ii) = tmpuvw(1, i)
325  uvw(2, ii) = tmpuvw(2, i)
326  uvw(3, ii) = tmpuvw(3, i)
327  dist2(ii) = tmpdist2(i)
328 
329  do j = 1, ninterpol
330  arrinterpol(j, ii) = tmparrint(j, i)
331  end do
332  end if
333  end do
334 
335  ! Release the memory used in the minimum distance search.
336 
337  deallocate (tmpcoor, tmpprocid, tmpelementtype, tmpelementid, &
338  tmpuvw, tmpdist2, coorids, tmparrint, &
339  stat=ierr)
340  if (ierr /= 0) &
341  call adtterminate(adt, "failSafeSearch", &
342  "Deallocation failure for the arrays &
343  &for the minimum distance search.")
344 
345  end subroutine failsafesearch
346 
347  subroutine initsearch(nCoor, coor, dist2, ADT, containmentSearch)
348  !
349  ! This routine performs the initialization tasks before the
350  ! actual search takes place. It determines the number and the
351  ! ID's of the coordinates every local tree may have to
352  ! interpolate. From this info this routine also determines the
353  ! number of rounds needed in the actual algorithm to avoid a
354  ! memory bottleneck.
355  ! Subroutine intent(in) arguments.
356  ! --------------------------------
357  ! nCoor: Number of local coordinates for which the
358  ! element must be determined.
359  ! coor: The coordinates of these points.
360  ! ADT: ADT type whose ADT must be searched
361  ! containmentSearch: Whether or not a containment search must
362  ! be performed. If not a minimum distance
363  ! search algorithm is used, which is more
364  ! expensive.
365  ! Subroutine intent(inout) arguments.
366  ! -----------------------------------
367  ! dist2: Guaranteed minimum distance squared of the
368  ! coordinates to the elements of the ADT. This array
369  ! should be initialized by the calling routine,
370  ! possibly to a large value. It is only used for a
371  ! minimum distance search.
372  !
373  implicit none
374  !
375  ! Subroutine arguments.
376  !
377  type(adttype), intent(inout) :: adt
378  integer(kind=intType), intent(in) :: ncoor
379 
380  real(kind=realtype), dimension(:, :), intent(in) :: coor
381  real(kind=realtype), dimension(:), intent(inout) :: dist2
382 
383  logical, intent(in) :: containmentsearch
384  !
385  ! Local variables.
386  !
387  integer :: ierr, nrootleaves, comm, nprocs, myid
388  integer :: myentryinrootprocs
389 
390  integer, dimension(:), pointer :: rootleavesprocs
391 
392  integer(kind=intType) :: i, j, k, mm, nn
393 
394  integer(kind=intType), dimension(:), allocatable :: ncoorperproc
395  integer(kind=intType), dimension(:), allocatable :: ncoorfromproc
396 
397  real(kind=realtype) :: d1, d2, dx, dy, dz
398 
399  real(kind=realtype), dimension(:, :, :), pointer :: rootbboxes
400 
401  ! Set some pointers to make the code more readable.
402 
403  nrootleaves = adt%nRootLeaves
404  myentryinrootprocs = adt%myEntryInRootProcs
405  rootleavesprocs => adt%rootLeavesProcs
406  rootbboxes => adt%rootBBoxes
407 
408  comm = adt%comm
409  nprocs = adt%nProcs
410  myid = adt%myID
411 
412  ! Determine the global maximum of nCoor. This number will serve
413  ! as an upper bound for the number of points to be searched
414  ! during a round.
415 
416  call mpi_allreduce(ncoor, ncoormax, 1, adflow_integer, mpi_max, &
417  comm, ierr)
419  !
420  ! Determine for every root leaf the local coordinates, which
421  ! should be searched in the corresponding ADT. The criterion
422  ! for a containment search is of course different from a
423  ! minimum distance search and therefore a distinction must be
424  ! made between the two methods.
425  !
426  ! Allocate the memory for nCoorPerRootLeaf and mCoorPerRootLeaf.
427  ! Initially the latter is a copy of the former, but its data
428  ! will change in the outer loop in the iterative algorithm, see
429  ! adtSearch. The numbering starts at 0, because these arrays
430  ! will be cumulative storage format arrays.
431 
432  allocate (ncoorperrootleaf(0:nprocs), &
433  mcoorperrootleaf(0:nprocs), stat=ierr)
434  if (ierr /= 0) &
435  call adtterminate(adt, "initSearch", &
436  "Memory allocation failure for &
437  &nCoorPerRootLeaf and mCoorPerRootLeaf.")
438 
439  ! Determine for a minimum distance search the guaranteed minimum
440  ! distance squared to each of the root leaves and store the
441  ! absolute minimum.
442 
443  testmindistance: if (.not. containmentsearch) then
444 
445  do j = 1, nrootleaves
446  do i = 1, ncoor
447  d1 = abs(coor(1, i) - rootbboxes(1, 1, j))
448  d2 = abs(coor(1, i) - rootbboxes(1, 2, j))
449  dx = max(d1, d2)
450 
451  d1 = abs(coor(2, i) - rootbboxes(2, 1, j))
452  d2 = abs(coor(2, i) - rootbboxes(2, 2, j))
453  dy = max(d1, d2)
454 
455  d1 = abs(coor(3, i) - rootbboxes(3, 1, j))
456  d2 = abs(coor(3, i) - rootbboxes(3, 2, j))
457  dz = max(d1, d2)
458 
459  d2 = dx * dx + dy * dy + dz * dz
460  dist2(i) = min(dist2(i), d2)
461  end do
462  end do
463 
464  end if testmindistance
465 
466  ! Determine the local number of coordinates to be searched in
467  ! each of the local trees, i.e. the array nCoorPerRootLeaf. Note
468  ! that the processor storing the ADT stores this number rather
469  ! than the root leaf. Furthermore nCoorPerRootLeaf is stored in
470  ! cumulative storage format and therefore an outer loop over the
471  ! number of root leaves is the most logical thing to do.
472 
473  ncoorperrootleaf(0) = 0
474  mm = 0
475 
476  loop1rootleaves: do j = 1, nrootleaves
477 
478  ! Determine the next processor which stores a tree; initialize
479  ! in the same loop nCoorPerRootLeaf of the processors in
480  ! between. The counter mm contains the entry in
481  ! nCoorPerRootLeaf where the number is stored. Remember that
482  ! the processor ID's start at 0.
483 
484  do k = (mm + 1), (rootleavesprocs(j) + 1)
486  end do
487 
488  mm = rootleavesprocs(j) + 1
489 
490  ! Make a distinction between a containment and a
491  ! minimum distance search.
492 
493  test1containment: if (containmentsearch) then
494 
495  ! Containment search. Loop over the local number of
496  ! coordinates and check if the coordinates are within the
497  ! bounding box of the current root leaf. If so, update
498  ! the counter.
499 
500  do i = 1, ncoor
501  if (coor(1, i) >= rootbboxes(1, 1, j) .and. &
502  coor(1, i) <= rootbboxes(1, 2, j) .and. &
503  coor(2, i) >= rootbboxes(2, 1, j) .and. &
504  coor(2, i) <= rootbboxes(2, 2, j) .and. &
505  coor(3, i) >= rootbboxes(3, 1, j) .and. &
506  coor(3, i) <= rootbboxes(3, 2, j)) &
507  ncoorperrootleaf(mm) = ncoorperrootleaf(mm) + 1
508  end do
509 
510  else test1containment
511 
512  ! Minimum distance search. Loop over the local number of
513  ! coordinates and determine the possible minimum distance
514  ! squared to the bounding box of the current root leaf.
515  ! If less than the currently stored guaranteed minimum
516  ! distance squared, update the counter.
517 
518  do i = 1, ncoor
519  if (coor(1, i) < rootbboxes(1, 1, j)) then
520  dx = coor(1, i) - rootbboxes(1, 1, j)
521  else if (coor(1, i) > rootbboxes(1, 2, j)) then
522  dx = coor(1, i) - rootbboxes(1, 2, j)
523  else
524  dx = zero
525  end if
526 
527  if (coor(2, i) < rootbboxes(2, 1, j)) then
528  dy = coor(2, i) - rootbboxes(2, 1, j)
529  else if (coor(2, i) > rootbboxes(2, 2, j)) then
530  dy = coor(2, i) - rootbboxes(2, 2, j)
531  else
532  dy = zero
533  end if
534 
535  if (coor(3, i) < rootbboxes(3, 1, j)) then
536  dz = coor(3, i) - rootbboxes(3, 1, j)
537  else if (coor(3, i) > rootbboxes(3, 2, j)) then
538  dz = coor(3, i) - rootbboxes(3, 2, j)
539  else
540  dz = zero
541  end if
542 
543  d2 = dx * dx + dy * dy + dz * dz
544  if (d2 < dist2(i)) &
545  ncoorperrootleaf(mm) = ncoorperrootleaf(mm) + 1
546 
547  end do
548 
549  end if test1containment
550 
551  end do loop1rootleaves
552 
553  ! Fill the rest of the array nCoorPerRootLeaf.
554 
555  do k = (mm + 1), nprocs
557  end do
558 
559  ! Copy nCoorPerRootLeaf to mCoorPerRootLeaf.
560 
561  do j = 0, nprocs
563  end do
564 
565  ! Allocate the memory for coorPerRootLeaf.
566 
567  nn = ncoorperrootleaf(nprocs)
568  allocate (coorperrootleaf(nn), stat=ierr)
569  if (ierr /= 0) &
570  call adtterminate(adt, "initSearch", &
571  "Memory allocation failure for &
572  &coorPerRootLeaf.")
573 
574  ! Repeat the loop over the number of root leaves, but now store
575  ! the ID's of the local coordinates.
576 
577  nn = 0
578  loop2rootleaves: do j = 1, nrootleaves
579 
580  ! Make a distinction between a containment and a
581  ! minimum distance search.
582 
583  test2containment: if (containmentsearch) then
584 
585  ! Containment search. Store the nodes which are within the
586  ! bounding box of the root leaf.
587 
588  do i = 1, ncoor
589  if (coor(1, i) >= rootbboxes(1, 1, j) .and. &
590  coor(1, i) <= rootbboxes(1, 2, j) .and. &
591  coor(2, i) >= rootbboxes(2, 1, j) .and. &
592  coor(2, i) <= rootbboxes(2, 2, j) .and. &
593  coor(3, i) >= rootbboxes(3, 1, j) .and. &
594  coor(3, i) <= rootbboxes(3, 2, j)) then
595  nn = nn + 1
596  coorperrootleaf(nn) = i
597  end if
598  end do
599 
600  else test2containment
601 
602  ! Minimum distance search. Store the nodes which have a
603  ! smaller possible minimum distance squared than the
604  ! currently stored value.
605 
606  do i = 1, ncoor
607  if (coor(1, i) < rootbboxes(1, 1, j)) then
608  dx = coor(1, i) - rootbboxes(1, 1, j)
609  else if (coor(1, i) > rootbboxes(1, 2, j)) then
610  dx = coor(1, i) - rootbboxes(1, 2, j)
611  else
612  dx = zero
613  end if
614 
615  if (coor(2, i) < rootbboxes(2, 1, j)) then
616  dy = coor(2, i) - rootbboxes(2, 1, j)
617  else if (coor(2, i) > rootbboxes(2, 2, j)) then
618  dy = coor(2, i) - rootbboxes(2, 2, j)
619  else
620  dy = zero
621  end if
622 
623  if (coor(3, i) < rootbboxes(3, 1, j)) then
624  dz = coor(3, i) - rootbboxes(3, 1, j)
625  else if (coor(3, i) > rootbboxes(3, 2, j)) then
626  dz = coor(3, i) - rootbboxes(3, 2, j)
627  else
628  dz = zero
629  end if
630 
631  d2 = dx * dx + dy * dy + dz * dz
632  if (d2 < dist2(i)) then
633  nn = nn + 1
634  coorperrootleaf(nn) = i
635  end if
636  end do
637 
638  end if test2containment
639 
640  end do loop2rootleaves
641  !
642  ! Determine for every tree the number of coordinates from
643  ! other processors it should search and from that information
644  ! the number of rounds in the outer loop of the search
645  ! algorithm in search.
646  !
647  ! Allocate the memory for some help arrays.
648 
649  allocate (procrecv(nprocs - 1), ncoorprocrecv(nprocs - 1), &
650  ncoorperproc(0:nprocs - 1), ncoorfromproc(0:nprocs - 1), &
651  stat=ierr)
652  if (ierr /= 0) &
653  call adtterminate(adt, "initSearch", &
654  "Memory allocation failure for help arrays.")
655 
656  ! Determine the number of coordinates I want to be searched in
657  ! the trees of other processors. Store the number I have to
658  ! search in my own tree and set it to 0 afterwards; the local
659  ! interpolations are handled differently.
660 
661  do i = 0, (nprocs - 1)
662  ncoorperproc(i) = ncoorperrootleaf(i + 1) - ncoorperrootleaf(i)
663  end do
664 
665  nlocalinterpol = ncoorperproc(myid)
666  ncoorperproc(myid) = 0
667 
668  ! Communicate these numbers to the other processors.
669 
670  call mpi_alltoall(ncoorperproc, 1, adflow_integer, &
671  ncoorfromproc, 1, adflow_integer, comm, ierr)
672 
673  ! Determine the total number of coordinates I have to interpolate
674  ! and the processor ID's I will receive coordinates from.
675 
676  nn = 0
677  nprocrecv = 0
678 
679  do i = 0, (nprocs - 1)
680  if (ncoorfromproc(i) > 0) then
681  nprocrecv = nprocrecv + 1
682  procrecv(nprocrecv) = i
683  nn = nn + ncoorfromproc(i)
684  end if
685  end do
686 
687  ! Determine the number of rounds in the outer loop of the
688  ! interpolation algorithm.
689 
690  i = real(nn, realtype) / real(ncoormax, realtype)
691  if (i * ncoormax < nn) i = i + 1
692  i = max(i, 1_inttype)
693 
694  call mpi_allreduce(i, nrounds, 1, adflow_integer, mpi_max, &
695  comm, ierr)
696 
697  ! Modify the sequence of procRecv, such that number of
698  ! coordinates sent from processors during a certain round
699  ! is more balanced.
700 
701  nn = max(nrootleaves, 1_inttype)
702  j = (real(myentryinrootprocs, realtype) / real(nn, realtype)) &
703  * nprocrecv
704 
705  do i = 1, nprocrecv
706  j = j + 1
707  if (j > nprocrecv) j = 1
708 
709  nn = procrecv(i)
710  procrecv(i) = procrecv(j)
711  procrecv(j) = nn
712  end do
713 
714  ! Store the number of coordinates to be received in
715  ! nCoorProcRecv.
716 
717  do i = 1, nprocrecv
718  ncoorprocrecv(i) = ncoorfromproc(procrecv(i))
719  end do
720 
721  ! Release the memory of the local help arrays.
722 
723  deallocate (ncoorperproc, ncoorfromproc, stat=ierr)
724  if (ierr /= 0) &
725  call adtterminate(adt, "initSearch", &
726  "Deallocation failure for nCoorPerProc and &
727  &nCoorFromProc")
728 
729  end subroutine initsearch
730 
731  subroutine mindistancesearch(nCoor, coor, &
732  adtID, procID, &
733  elementType, elementID, &
734  uvw, dist2, &
735  nInterpol, arrDonor, &
736  arrInterpol)
737  !
738  ! This routine attempts for every coordinate to find the
739  ! element in the given ADT which minimizes the distance to
740  ! this point.
741  ! Subroutine intent(in) arguments.
742  ! --------------------------------
743  ! nCoor: Number of coordinates for which the element must be
744  ! determined.
745  ! coor: The coordinates of these points.
746  ! adtID: The ADT to be searched.
747  ! nInterpol: Number of variables to be interpolated.
748  ! arrDonor: Array with the donor data; needed to obtain the
749  ! interpolated data.
750  ! Subroutine intent(out) arguments.
751  ! ---------------------------------
752  ! procID: The ID of the processor in the group of the ADT
753  ! where the element containing the point is
754  ! stored. If no element is found for a given
755  ! point the corresponding entry in procID is set
756  ! to -1 to indicate failure. Remember that the
757  ! processor ID's start at 0 and not at 1.
758  ! elementType: The type of element which contains the point.
759  ! elementID: The entry in the connectivity of this element
760  ! which contains the point. The ID is negative if
761  ! the coordinate is outside the element.
762  ! uvw: The parametric coordinates of the point in the
763  ! transformed element; this transformation is
764  ! such that every element is transformed into a
765  ! standard element in parametric space. The u, v
766  ! and w coordinates can be used to determine the
767  ! actual interpolation weights. If the tree
768  ! corresponds to a surface mesh the third entry
769  ! of this array will not be filled.
770  ! arrInterpol: Array with the interpolated data.
771  ! Subroutine intent(inout) arguments.
772  ! -----------------------------------
773  ! dist2: Minimum distance squared of the coordinates to the
774  ! elements of the ADT. On input it should be
775  ! initialized by the calling program, possibly to a
776  ! large value. In this way it is possible to handle
777  ! periodic problems as efficiently as possible.
778  !
779  implicit none
780  !
781  ! Subroutine arguments.
782  !
783  integer(kind=intType), intent(in) :: ncoor, ninterpol
784  character(len=*), intent(in) :: adtid
785 
786  real(kind=realtype), dimension(:, :), intent(in) :: coor
787  real(kind=realtype), dimension(:, :), intent(in) :: arrdonor
788 
789  integer, dimension(:), intent(out) :: procid
790  integer(kind=intType), dimension(:), intent(out) :: elementid
791 
792  integer(kind=adtElementType), dimension(:), intent(out) :: &
793  elementtype
794 
795  real(kind=realtype), dimension(:, :), intent(out) :: uvw
796  real(kind=realtype), dimension(:, :), intent(out) :: arrinterpol
797 
798  real(kind=realtype), dimension(:), intent(inout) :: dist2
799  !
800  ! Local variables.
801  !
802  integer(kind=intType) :: jj, nalloc
803 
804  type(adttype), pointer :: ADT
805 
806  ! Determine the index in the array ADTs, which stores the given
807  ! ID. As the number of trees stored is limited, a linear search
808  ! algorithm is okay.
809 
810  nalloc = ubound(adts, 1)
811  do jj = 1, nalloc
812  if (adtid == adts(jj)%adtID) exit
813  end do
814 
815  ! Check if the ADT to be searched exists. If not stop.
816  ! Note that adtTerminate is not called. The reason is that the
817  ! processor ID is not known.
818 
819  if (jj > nalloc) stop "ADT to be searched does not exist."
820 
821  ! Set pointer to the ADT we will be working with
822 
823  adt => adts(jj)
824 
825  ! Initialize the search, i.e. determine the number of
826  ! coordinates to be searched in each of the local ADT's.
827 
828  call initsearch(ncoor, coor, dist2, adt, .false.)
829 
830  ! Perform the actual search.
831 
832  call search(ncoor, coor, procid, elementtype, &
833  elementid, uvw, dist2, adt, &
834  .false., ninterpol, arrdonor, arrinterpol)
835 
836  ! Negate the elementID if the coordinate is outside the element,
837  ! i.e. if the distance is larger than zero.
838 
839  do jj = 1, ncoor
840  if (dist2(jj) > zero) elementid(jj) = -elementid(jj)
841  end do
842 
843  end subroutine mindistancesearch
844 
845  subroutine search(nCoor, coor, procID, &
846  elementType, elementID, uvw, &
847  dist2, ADT, containmentSearch, &
848  nInterpol, arrDonor, arrInterpol)
849  !
850  ! This routine implements the parallel part of the search
851  ! algorithm and calls the appropriate local tree searches.
852  ! Subroutine intent(in) arguments.
853  ! --------------------------------
854  ! nCoor: Number of local coordinates for which the
855  ! element must be determined.
856  ! coor: The coordinates of these points.
857  ! ADT: ADT type whose ADT must be searched
858  ! containmentSearch: Whether or not a containment search must
859  ! be performed. If not a minimum distance
860  ! search algorithm is used, which is more
861  ! expensive.
862  ! nInterpol: Number of variables to be interpolated.
863  ! arrDonor: Array with the donor data; needed to
864  ! obtain the interpolated data.
865  ! Subroutine intent(inout) arguments.
866  ! -----------------------------------
867  ! dist2: Minimum distance squared of the coordinates to the
868  ! elements of the ADT. On input it contains the
869  ! guarenteed distance squared to one of the root
870  ! leaves. On output it contains the distance squared to
871  ! the nearest element of the global tree. It is only
872  ! used for a minimum distance search.
873  ! Subroutine intent(out) arguments.
874  ! ---------------------------------
875  ! procID: The ID of the processor in the group of the ADT
876  ! where the element containing the point is
877  ! stored.
878  ! elementType: The type of element which contains the point or
879  ! minimizes the distance to the point.
880  ! elementID: The entry in the connectivity of this element.
881  ! uvw: The parametric coordinates of (the projection
882  ! of) the point in the transformed element; this
883  ! transformation is such that every element is
884  ! transformed into a standard element in
885  ! parametric space. The u, v and w coordinates
886  ! can be used to determine the actual
887  ! interpolation weights.
888  ! arrInterpol: Array with the interpolated data.
889  !
890  implicit none
891  !
892  ! Subroutine arguments.
893  !
894  type(adttype), intent(inout) :: ADT
895  integer(kind=intType), intent(in) :: nCoor
896  integer(kind=intType), intent(in) :: nInterpol
897 
898  real(kind=realtype), dimension(:, :), intent(in) :: coor
899  real(kind=realtype), dimension(:), intent(inout) :: dist2
900 
901  real(kind=realtype), dimension(:, :), intent(in) :: arrdonor
902 
903  integer, dimension(:), intent(out) :: procID
904  integer(kind=intType), dimension(:), intent(out) :: elementID
905 
906  integer(kind=adtElementType), dimension(:), intent(out) :: &
907  elementType
908 
909  real(kind=realtype), dimension(:, :), intent(out) :: uvw
910  real(kind=realtype), dimension(:, :), intent(out) :: arrinterpol
911 
912  logical, intent(in) :: containmentSearch
913  !
914  ! Local variables.
915  !
916  integer :: ierr
917  integer :: comm, nProcs, myID
918  integer :: nProcRecvCur, nProcSendCur, nVarCoor, nVarUVW
919  integer :: startProcRecv, procCur, sizeMessage
920 
921  integer, dimension(mpi_status_size) :: mpiStatus
922 
923  integer, dimension(:), allocatable :: procSendCur
924  integer, dimension(:), allocatable :: sendRequest
925  integer, dimension(:, :), allocatable :: sendRecvRequest
926 
927  integer(kind=intType) :: i, j, k, k1, l, m, ii, mm, nn
928  integer(kind=intType) :: nLocalInterpolRound
929  integer(kind=intType) :: iStartLocal, iEndLocal, nCoorRecv
930 
931  integer(kind=intType), dimension(:), allocatable :: nCoorPerProc
932  integer(kind=intType), dimension(:), allocatable :: nCoorFromProc
933 
934  integer(kind=intType), dimension(:, :), allocatable :: intRecv
935  integer(kind=intType), dimension(:, :), allocatable :: intBuf
936 
937  real(kind=realtype), dimension(:, :), allocatable :: coorbuf
938  real(kind=realtype), dimension(:, :), allocatable :: coorrecv
939  real(kind=realtype), dimension(:, :), allocatable :: uvwrecv
940  real(kind=realtype), dimension(:, :), allocatable :: uvwbuf
941 
942  logical, dimension(:), allocatable :: coorRequested
943 
944  ! Some abbreviations to make the code more readable.
945 
946  comm = adt%comm
947  nprocs = adt%nProcs
948  myid = adt%myID
949 
950  ! Determine the number of variables stored in the coordinate
951  ! buffers. For a minimum distance search also the distance
952  ! squared is stored, i.e. 4 variables instead of 3.
953 
954  if (containmentsearch) then
955  nvarcoor = 3
956  else
957  nvarcoor = 4
958  end if
959 
960  ! And the size of the uvw buffers. These contain nVarCoor plus
961  ! the number of variables to be interpolated.
962 
963  nvaruvw = nvarcoor + max(ninterpol, 0_inttype)
964 
965  ! Initialize procID to -1, which indicates failure.
966 
967  do i = 1, ncoor
968  procid(i) = -1
969  end do
970 
971  ! Allocate the memory for some help arrays used in the search
972  ! algorithm.
973 
974  nn = ncoorperrootleaf(nprocs)
975  allocate (procsendcur(nprocs - 1), sendrequest(nprocs - 1), &
976  ncoorperproc(0:nprocs - 1), ncoorfromproc(0:nprocs - 1), &
977  sendrecvrequest(2, nprocs - 1), coorrequested(nn), &
978  stat=ierr)
979  if (ierr /= 0) &
980  call adtterminate(adt, "search", &
981  "Memory allocation failure for help arrays.")
982 
983  ! Initialize coorRequested to .false. This indicates that
984  ! the corresponding entry in coorPerRootLeaf has not been
985  ! requested for interpolation.
986 
987  do j = 1, nn
988  coorrequested(j) = .false.
989  end do
990 
991  ! Initialize the starting position in the array procRecv to 1.
992  ! This variable indicates the starting position in procRecv for
993  ! the current round. Also initializes nCoorFromProc to 0.
994 
995  startprocrecv = 1
996 
997  do i = 0, (nprocs - 1)
998  ncoorfromproc(i) = 0
999  end do
1000 
1001  ! Determine the number of local interpolations per round and
1002  ! initialize the iStartLocal and iEndLocal, the start and end
1003  ! indices for the local interpolation of the current round.
1004 
1005  nn = nlocalinterpol / nrounds
1006  if (nn * nrounds < nlocalinterpol) nn = nn + 1
1007  nlocalinterpolround = nn
1008 
1009  istartlocal = 0
1010  iendlocal = nlocalinterpolround
1011  !
1012  ! Iterative algorithm to determine the elements containing the
1013  ! coordinates or the elements which minimize the distance. The
1014  ! algorithm consists of a synchronous outer loop over the
1015  ! number of times the inner loop should be executed. This
1016  ! inner loop is asynchronous and performs the actual ADT
1017  ! search. The outer loop is present to avoid that too much
1018  ! data is communicated to a single processor at once such that
1019  ! a memory bottleneck occurs.
1020  !
1021  outerloop: do mm = 1, nrounds
1022 
1023  ! Determine the processors I want data from in this round
1024  ! as well as the number of coordinates from these nodes.
1025 
1026  nprocrecvcur = 0
1027  ncoorrecv = 0
1028 
1029  do i = startprocrecv, nprocrecv
1030 
1031  ! Exit the loop if the maximum number of nodes has been
1032  ! reached.
1033 
1034  if (ncoorrecv == ncoormax) exit
1035 
1036  ! Update the number of processors from which I will receive
1037  ! data during this round.
1038 
1039  nprocrecvcur = nprocrecvcur + 1
1040 
1041  ! Determine the amount I can receive from this processor.
1042  ! If the upper limit is exceeded cut it off.
1043 
1044  j = ncoorprocrecv(i)
1045  if ((ncoorrecv + j) > ncoormax) j = ncoormax - ncoorrecv
1046  ncoorrecv = ncoorrecv + j
1047 
1048  ! Store the amount j in the appropriate place of
1049  ! nCoorFromProc and determine the number of nodes to be
1050  ! sent to this processor in the next round (possibly 0).
1051 
1052  ncoorfromproc(procrecv(i)) = j
1053  ncoorprocrecv(i) = ncoorprocrecv(i) - j
1054 
1055  ! Exit the loop if still some data should be received from
1056  ! this processor in a next round. The difference between this
1057  ! exit and the one in the beginning of the do loop is that
1058  ! here the counter i is not update yet and therefore
1059  ! startProcRecv will be set correctly for the next round.
1060 
1061  if (ncoorprocrecv(i) > 0) exit
1062  end do
1063 
1064  ! Do an all to all communication such that every processor
1065  ! knows the amount of data it should send to other processors.
1066 
1067  call mpi_alltoall(ncoorfromproc, 1, adflow_integer, &
1068  ncoorperproc, 1, adflow_integer, comm, ierr)
1069 
1070  ! Set the non-zero entries of nCoorFromProc to zero again
1071  ! for the next round.
1072 
1073  nn = min(i, nprocrecv)
1074  do j = startprocrecv, nn
1075  ncoorfromproc(procrecv(j)) = 0
1076  end do
1077 
1078  ! Set the starting index for the next round.
1079 
1080  startprocrecv = i
1081 
1082  ! Determine the number of messages I have to send, the
1083  ! corresponding processors and the total number of points to
1084  ! be sent.
1085 
1086  nprocsendcur = 0
1087  nn = 0
1088 
1089  do i = 0, (nprocs - 1)
1090  if (ncoorperproc(i) > 0) then
1091  nprocsendcur = nprocsendcur + 1
1092  procsendcur(nprocsendcur) = i
1093  nn = nn + ncoorperproc(i)
1094  end if
1095  end do
1096 
1097  ! Allocate the memory for the send buffer of the coordinates
1098  ! and possibly the minimum distance squared.
1099 
1100  allocate (coorbuf(nvarcoor, nn), stat=ierr)
1101  if (ierr /= 0) &
1102  call adtterminate(adt, "search", &
1103  "Memory allocation failure for coorBuf.")
1104 
1105  ! Send the coordinates to the appropriate processors.
1106  ! Initialize the counter k in the coordinate buffer to 0.
1107 
1108  k = 0
1109  sendcoorloop: do i = 1, nprocsendcur
1110 
1111  ! Store the processor ID and the starting entry in
1112  ! coorPerRootLeaf a bit easier and initialize k1 to k.
1113 
1114  proccur = procsendcur(i)
1115  nn = mcoorperrootleaf(proccur)
1116  k1 = k
1117 
1118  ! Loop to fill to buffer to this processor.
1119  ! A distinction is made between a containment search and a
1120  ! minimum distance search. In the former case a coordinate is
1121  ! only sent if it has not been interpolated yet; in the
1122  ! latter case it is sent if the distance is larger than zero.
1123  ! For a minimum distance search also the current distance
1124  ! squared is stored.
1125 
1126  test1containment: if (containmentsearch) then
1127 
1128  ! Containment search. Store the coordinates of the points
1129  ! to be searched in coorBuf. Note that the counter j is
1130  ! updated inside the loop. This is done to be able to send
1131  ! the maximum number of coordinates possible.
1132 
1133  j = 0
1134  do
1135  ! Exit the loop if the maximum number or if the last
1136  ! coordinate for this processor has been reached.
1137 
1138  if (j == ncoorperproc(proccur) .or. &
1139  nn == ncoorperrootleaf(proccur + 1)) exit
1140 
1141  ! Update the counter nn and check if this coordinate
1142  ! still needs to be interpolated.
1143 
1144  nn = nn + 1
1145  l = coorperrootleaf(nn)
1146 
1147  if (procid(l) == -1) then
1148 
1149  ! Coordinate needs to be interpolated. Update the
1150  ! counters j and k and copy the coordinate in the
1151  ! send buffer.
1152 
1153  j = j + 1
1154  k = k + 1
1155  coorbuf(1, k) = coor(1, l)
1156  coorbuf(2, k) = coor(2, l)
1157  coorbuf(3, k) = coor(3, l)
1158 
1159  ! Set the entry in coorRequested to .true. to indicate
1160  ! that a request was sent.
1161 
1162  coorrequested(nn) = .true.
1163 
1164  end if
1165  end do
1166 
1167  else test1containment
1168 
1169  ! Minimum distance search. Even if an earlier minimum
1170  ! distance was found, it is possible that an even smaller
1171  ! distance can be found. Therefore only points with a
1172  ! minimum distance squared of zero will not be sent. Both
1173  ! the coordinates and the current minimum distance squared
1174  ! is sent. Again the counter j is updated inside the loop.
1175 
1176  j = 0
1177  do
1178  ! Exit the loop if the maximum number or if the last
1179  ! coordinate for this processor has been reached.
1180 
1181  if (j == ncoorperproc(proccur) .or. &
1182  nn == ncoorperrootleaf(proccur + 1)) exit
1183 
1184  ! Update the counter nn and check if this coordinate still
1185  ! needs to be interpolated.
1186 
1187  nn = nn + 1
1188  l = coorperrootleaf(nn)
1189 
1190  if (dist2(l) > zero) then
1191 
1192  ! Coordinate needs to be interpolated. Update the
1193  ! counters j and k and store the coordinates and the
1194  ! distance squared in the send buffer.
1195 
1196  j = j + 1
1197  k = k + 1
1198  coorbuf(1, k) = coor(1, l)
1199  coorbuf(2, k) = coor(2, l)
1200  coorbuf(3, k) = coor(3, l)
1201  coorbuf(4, k) = dist2(l)
1202 
1203  ! Set the entry in coorRequested to .true. to indicate
1204  ! that a request was sent.
1205 
1206  coorrequested(nn) = .true.
1207 
1208  end if
1209  end do
1210 
1211  end if test1containment
1212 
1213  ! Determine the size of the message and send it.
1214  ! Use nonblocking sends to avoid deadlock.
1215 
1216  sizemessage = nvarcoor * (k - k1)
1217  call mpi_isend(coorbuf(1, k1 + 1), sizemessage, adflow_real, &
1218  proccur, proccur, comm, &
1219  sendrequest(i), ierr)
1220 
1221  end do sendcoorloop
1222  !
1223  ! Perform the local interpolations. This is done here to
1224  ! have an overlap between communication and computation.
1225  !
1226  ! Determine the local number to be interpolated in this round.
1227 
1228  nn = iendlocal - istartlocal
1229 
1230  ! Allocate the memory for the coorRecv, the integers for
1231  ! storing the processor ID, element type and element ID, and
1232  ! uvwRecv. This memory is also used for the local
1233  ! interpolation, which explains the max test for intRecv and
1234  ! uvwRecv. The coordinates are different, because they will be
1235  ! released after each received message.
1236 
1237  i = max(nn, ncoorrecv)
1238  allocate (coorrecv(nvarcoor, nn), intrecv(3, i), &
1239  uvwrecv(nvaruvw, i), stat=ierr)
1240  if (ierr /= 0) &
1241  call adtterminate(adt, "search", &
1242  "Memory allocation failure for &
1243  &recv arrays")
1244 
1245  ! Initialize the counters i and j, which are used to fill the
1246  ! buffer coorRecv.
1247 
1248  j = 0
1249  i = mcoorperrootleaf(myid)
1250 
1251  ! Make a distinction between a containment and a minimum
1252  ! distance search.
1253 
1254  test2containment: if (containmentsearch) then
1255 
1256  ! Containment search. Copy the local coordinates to be
1257  ! searched in coorRecv. As it is possible that in an earlier
1258  ! round the coordinate has already been found, only take
1259  ! coordinates whose element has not been found yet.
1260 
1261  do
1262  ! Exit the loop if the maximum number or if the last
1263  ! coordinate of the local interpolation has been reached.
1264 
1265  if (j == nn .or. i == ncoorperrootleaf(myid + 1)) exit
1266 
1267  ! Update the counter i and check if the corresponding
1268  ! coordinate still needs to be interpolated. If so, store it
1269  ! in coorRecv and set the corresponding entry in
1270  ! coorRequested to .true.
1271 
1272  i = i + 1
1273  l = coorperrootleaf(i)
1274 
1275  if (procid(l) == -1) then
1276  j = j + 1
1277 
1278  coorrecv(1, j) = coor(1, l)
1279  coorrecv(2, j) = coor(2, l)
1280  coorrecv(3, j) = coor(3, l)
1281 
1282  coorrequested(i) = .true.
1283  end if
1284  end do
1285 
1286  ! Perform the local interpolations. Note that j contains the
1287  ! actual number of coordinates to be searched.
1288 
1289  nn = j
1290  call containmenttreesearch(adt, coorrecv, intrecv, &
1291  uvwrecv, arrdonor, nn, &
1292  ninterpol)
1293 
1294  ! Store the interpolation data at the correct location in
1295  ! the corresponding arrays.
1296 
1297  i = mcoorperrootleaf(myid)
1298  do j = 1, nn
1299 
1300  ! Determine the coordinate entry, which corresponds to the
1301  ! counter j. Remember that in the calls to search routines
1302  ! only nodes are given which were not interpolated.
1303 
1304  do
1305  i = i + 1
1306  if (coorrequested(i)) exit
1307  end do
1308  l = coorperrootleaf(i)
1309 
1310  ! Copy the data if an actual element was found.
1311 
1312  if (intrecv(1, j) >= 0) then
1313  procid(l) = intrecv(1, j)
1314  elementtype(l) = intrecv(2, j)
1315  elementid(l) = intrecv(3, j)
1316  uvw(1, l) = uvwrecv(1, j)
1317  uvw(2, l) = uvwrecv(2, j)
1318  uvw(3, l) = uvwrecv(3, j)
1319 
1320  do m = 1, ninterpol
1321  arrinterpol(m, l) = uvwrecv(m + nvarcoor, j)
1322  end do
1323  end if
1324 
1325  end do
1326 
1327  else test2containment
1328 
1329  ! Minimum distance search. Store the local coordinates and
1330  ! distance in coorRecv for the coordinates with non-zero
1331  ! distance.
1332 
1333  do
1334  ! Exit the loop if the maximum number or if the last
1335  ! coordinate of the local interpolation has been reached.
1336 
1337  if (j == nn .or. i == ncoorperrootleaf(myid + 1)) exit
1338 
1339  ! Update the counter i and check if the corresponding
1340  ! coordinate still needs to be interpolated. If so, store
1341  ! its coordinates and distance squared in coorRecv and set
1342  ! the corresponding entry in coorRequested to .true.
1343 
1344  i = i + 1
1345  l = coorperrootleaf(i)
1346 
1347  if (dist2(l) > zero) then
1348  j = j + 1
1349 
1350  coorrecv(1, j) = coor(1, l)
1351  coorrecv(2, j) = coor(2, l)
1352  coorrecv(3, j) = coor(3, l)
1353  coorrecv(4, j) = dist2(l)
1354 
1355  coorrequested(i) = .true.
1356  end if
1357  end do
1358 
1359  ! Perform the local interpolations. Note that j contains the
1360  ! actual number of coordinates to be searched.
1361 
1362  nn = j
1363  call mindistancetreesearch(adt, coorrecv, intrecv, &
1364  uvwrecv, arrdonor, nn, &
1365  ninterpol)
1366 
1367  ! Store the interpolation data at the correct location in
1368  ! the corresponding arrays.
1369 
1370  i = mcoorperrootleaf(myid)
1371 
1372  do j = 1, nn
1373 
1374  ! Determine the next coordinate entry, whose request was
1375  ! sent to be interpolated. Remember that it is possible
1376  ! that some nodes were not sent to be interpolated (if
1377  ! their distance squared is zero already).
1378 
1379  do
1380  i = i + 1
1381  if (coorrequested(i)) exit
1382  end do
1383  l = coorperrootleaf(i)
1384 
1385  ! Copy the data if an actual element was found and if
1386  ! the corresponding distance squared is less than the
1387  ! currently stored value.
1388 
1389  if (intrecv(1, j) >= 0 .and. uvwrecv(4, j) < dist2(l)) then
1390 
1391  procid(l) = intrecv(1, j)
1392  elementtype(l) = intrecv(2, j)
1393  elementid(l) = intrecv(3, j)
1394  uvw(1, l) = uvwrecv(1, j)
1395  uvw(2, l) = uvwrecv(2, j)
1396  uvw(3, l) = uvwrecv(3, j)
1397  dist2(l) = uvwrecv(4, j)
1398 
1399  do m = 1, ninterpol
1400  arrinterpol(m, l) = uvwrecv(m + nvarcoor, j)
1401  end do
1402  end if
1403 
1404  end do
1405 
1406  end if test2containment
1407 
1408  ! The buffer coorRecv is not needed anymore.
1409  ! Release the memory.
1410 
1411  deallocate (coorrecv, stat=ierr)
1412  if (ierr /= 0) &
1413  call adtterminate(adt, "search", &
1414  "Deallocation failure for coorRecv.")
1415 
1416  ! Set iStartLocal and iEndLocal for the next round.
1417  ! Also update mCoorPerRootLeaf(myID).
1418 
1419  istartlocal = iendlocal
1420  iendlocal = iendlocal + nlocalinterpolround
1421  iendlocal = max(iendlocal, nlocalinterpol)
1422 
1423  mcoorperrootleaf(myid) = i
1424  !
1425  ! Perform the interpolations from the other processors.
1426  ! Their coordinates are received in an arbitrary sequence
1427  ! using blocking receives and the interpolated data is sent
1428  ! back using nonblocking sends.
1429  !
1430  ! Loop over the number of messages I will receive. The counter
1431  ! ii contains the current starting position for the buffers
1432  ! to be sent back to the requesting processors.
1433 
1434  ii = 1
1435  recvsendloop: do i = 1, nprocrecvcur
1436 
1437  ! Block until a message arrives and find the source and size
1438  ! of the message.
1439 
1440  call mpi_probe(mpi_any_source, myid, comm, mpistatus, ierr)
1441 
1442  proccur = mpistatus(mpi_source)
1443  call mpi_get_count(mpistatus, adflow_real, sizemessage, ierr)
1444 
1445  ! Check in debug mode that the message is of correct size.
1446 
1447  if (debug) then
1448  if (sizemessage == mpi_undefined .or. &
1449  mod(sizemessage, nvarcoor) /= 0) &
1450  call adtterminate(adt, "search", &
1451  "Unexpected size of message")
1452  end if
1453 
1454  ! Allocate the memory for the coordinates to be received and
1455  ! receive them using a blocking receive; the message has
1456  ! already arrived.
1457 
1458  nn = sizemessage / nvarcoor
1459  allocate (coorrecv(nvarcoor, nn), stat=ierr)
1460  if (ierr /= 0) &
1461  call adtterminate(adt, "search", &
1462  "Memory allocation failure for &
1463  &coorRecv.")
1464 
1465  call mpi_recv(coorrecv, sizemessage, adflow_real, proccur, &
1466  myid, comm, mpistatus, ierr)
1467 
1468  ! Search the corresponding elements in the local tree and
1469  ! release coorRecv afterwards.
1470 
1471  if (containmentsearch) then
1472  call containmenttreesearch(adt, coorrecv, &
1473  intrecv(:, ii:), uvwrecv(:, ii:), &
1474  arrdonor, nn, &
1475  ninterpol)
1476  else
1477  call mindistancetreesearch(adt, coorrecv, &
1478  intrecv(:, ii:), uvwrecv(:, ii:), &
1479  arrdonor, nn, &
1480  ninterpol)
1481  end if
1482 
1483  deallocate (coorrecv, stat=ierr)
1484  if (ierr /= 0) &
1485  call adtterminate(adt, "search", &
1486  "Deallocation failure for coorRecv.")
1487 
1488  ! Send the integer and the floating point information back to
1489  ! the requesting processor.
1490 
1491  sizemessage = 3 * nn
1492  call mpi_isend(intrecv(1, ii), sizemessage, adflow_integer, &
1493  proccur, proccur + 1, comm, &
1494  sendrecvrequest(1, i), ierr)
1495 
1496  sizemessage = nvaruvw * nn
1497  call mpi_isend(uvwrecv(1, ii), sizemessage, adflow_real, &
1498  proccur, proccur + 2, comm, &
1499  sendrecvrequest(2, i), ierr)
1500 
1501  ! Update the counter ii for the next message.
1502 
1503  ii = ii + nn
1504 
1505  end do recvsendloop
1506 
1507  ! Complete the nonblocking coordinate sends and release the
1508  ! memory of coorBuf.
1509 
1510  do i = 1, nprocsendcur
1511  call mpi_waitany(nprocsendcur, sendrequest, sizemessage, &
1512  mpistatus, ierr)
1513  end do
1514 
1515  deallocate (coorbuf, stat=ierr)
1516  if (ierr /= 0) &
1517  call adtterminate(adt, "search", &
1518  "Deallocation failure for coorBuf.")
1519 
1520  ! Loop over the number of processors to which I sent requests.
1521  ! Now it is time to receive the information they interpolated.
1522  ! The sequence of receiving messages is arbitrary.
1523 
1524  recvloop: do ii = 1, nprocsendcur
1525 
1526  ! Block until an integer message arrives. These messages have
1527  ! tags of myID+1. Also determine the sending processor and
1528  ! the size of the message.
1529 
1530  call mpi_probe(mpi_any_source, myid + 1, comm, mpistatus, ierr)
1531 
1532  proccur = mpistatus(mpi_source)
1533  call mpi_get_count(mpistatus, adflow_integer, sizemessage, ierr)
1534 
1535  ! Check in debug mode that the message is of correct size.
1536 
1537  if (debug) then
1538  if (sizemessage == mpi_undefined .or. &
1539  mod(sizemessage, 3) /= 0) &
1540  call adtterminate(adt, "search", &
1541  "Unexpected size of message")
1542  end if
1543 
1544  ! Allocate the memory for the integer and uvw buffers, such
1545  ! that the messages can be received.
1546 
1547  nn = sizemessage / 3
1548  allocate (intbuf(3, nn), uvwbuf(nvaruvw, nn), stat=ierr)
1549  if (ierr /= 0) &
1550  call adtterminate(adt, "search", &
1551  "Memory allocation failure for intBuf &
1552  &and uvwBuf.")
1553 
1554  call mpi_recv(intbuf, sizemessage, adflow_integer, proccur, &
1555  myid + 1, comm, mpistatus, ierr)
1556 
1557  sizemessage = nvaruvw * nn
1558  call mpi_recv(uvwbuf, sizemessage, adflow_real, proccur, &
1559  myid + 2, comm, mpistatus, ierr)
1560 
1561  ! Store the interpolation data at the correct location in the
1562  ! corresponding arrays. A distinction must be made between
1563  ! containment search and minimum distance search, because for
1564  ! the latter it is possible that a better candidate is
1565  ! already stored.
1566 
1567  i = mcoorperrootleaf(proccur)
1568 
1569  test3containment: if (containmentsearch) then
1570 
1571  ! Containment search. Loop over the number of points
1572  ! requested on the other processor.
1573 
1574  do j = 1, nn
1575 
1576  ! Determine the next coordinate entry, whose request was
1577  ! sent to be interpolated. Remember that only nodes are
1578  ! sent which were not interpolated.
1579 
1580  do
1581  i = i + 1
1582  if (coorrequested(i)) exit
1583  end do
1584 
1585  ! Copy the data if an actual element was found.
1586 
1587  if (intbuf(1, j) >= 0) then
1588  l = coorperrootleaf(i)
1589 
1590  procid(l) = intbuf(1, j)
1591  elementtype(l) = intbuf(2, j)
1592  elementid(l) = intbuf(3, j)
1593  uvw(1, l) = uvwbuf(1, j)
1594  uvw(2, l) = uvwbuf(2, j)
1595  uvw(3, l) = uvwbuf(3, j)
1596 
1597  do m = 1, ninterpol
1598  arrinterpol(m, l) = uvwbuf(m + nvarcoor, j)
1599  end do
1600  end if
1601 
1602  end do
1603 
1604  else test3containment
1605 
1606  ! Minimum distance search. Loop over the number of points
1607  ! requested on the other processor.
1608 
1609  do j = 1, nn
1610 
1611  ! Determine the next coordinate entry, whose request was
1612  ! sent to be interpolated. Remember that it is possible
1613  ! that some nodes were not sent to be interpolated (if
1614  ! their distance squared is zero already).
1615 
1616  do
1617  i = i + 1
1618  if (coorrequested(i)) exit
1619  end do
1620 
1621  ! Copy the data if an actual element was found and if
1622  ! the corresponding distance squared is less than the
1623  ! currently stored value.
1624 
1625  l = coorperrootleaf(i)
1626  if (intbuf(1, j) >= 0 .and. uvwbuf(4, j) < dist2(l)) then
1627 
1628  procid(l) = intbuf(1, j)
1629  elementtype(l) = intbuf(2, j)
1630  elementid(l) = intbuf(3, j)
1631  uvw(1, l) = uvwbuf(1, j)
1632  uvw(2, l) = uvwbuf(2, j)
1633  uvw(3, l) = uvwbuf(3, j)
1634  dist2(l) = uvwbuf(4, j)
1635 
1636  do m = 1, ninterpol
1637  arrinterpol(m, l) = uvwbuf(m + nvarcoor, j)
1638  end do
1639  end if
1640 
1641  end do
1642 
1643  end if test3containment
1644 
1645  ! Update mCoorPerRootLeaf(procCur) for the next round and
1646  ! release the memory of intBuf and uvwBuf.
1647 
1648  mcoorperrootleaf(proccur) = i
1649 
1650  deallocate (intbuf, uvwbuf, stat=ierr)
1651  if (ierr /= 0) &
1652  call adtterminate(adt, "search", &
1653  "Deallocation failure for intBuf &
1654  &and uvwBuf.")
1655  end do recvloop
1656 
1657  ! Complete the nonblocking sends of the interpolated data.
1658 
1659  !nProcRecvCur = 2*nProcRecvCur
1660  do i = 1, nprocrecvcur
1661  call mpi_waitany(nprocrecvcur, sendrecvrequest(1, :), sizemessage, &
1662  mpistatus, ierr)
1663  call mpi_waitany(nprocrecvcur, sendrecvrequest(2, :), sizemessage, &
1664  mpistatus, ierr)
1665  end do
1666 
1667  ! Release the memory of the buffers used in the nonblocking
1668  ! sends of the interpolated data.
1669 
1670  deallocate (intrecv, uvwrecv, stat=ierr)
1671  if (ierr /= 0) &
1672  call adtterminate(adt, "search", &
1673  "Deallocation failure for intRecv and &
1674  &uvwRecv")
1675 
1676  ! Synchronize the processors, because wild cards have been
1677  ! used in the communication.
1678 
1679  call mpi_barrier(comm, ierr)
1680 
1681  end do outerloop
1682 
1683  ! Release the memory of the help arrays allocated in this
1684  ! routine.
1685 
1686  deallocate (procsendcur, sendrequest, ncoorperproc, &
1687  ncoorfromproc, sendrecvrequest, coorrequested, &
1688  stat=ierr)
1689  if (ierr /= 0) &
1690  call adtterminate(adt, "search", &
1691  "Deallocation failure for help arrays.")
1692 
1693  ! Release the memory of the help arrays stored in the module
1694  ! adtData.
1695 
1696  deallocate (procrecv, ncoorprocrecv, ncoorperrootleaf, &
1697  mcoorperrootleaf, coorperrootleaf, stat=ierr)
1698  if (ierr /= 0) &
1699  call adtterminate(adt, "search", &
1700  "Deallocation failure for help arrays &
1701  &stored in the module adtData.")
1702 
1703  end subroutine search
1704 
1705 end module adtsearch
integer(kind=inttype) nrounds
Definition: adtData.F90:184
integer nprocrecv
Definition: adtData.F90:181
integer(kind=inttype) ncoormax
Definition: adtData.F90:183
integer, dimension(:), allocatable procrecv
Definition: adtData.F90:198
integer(kind=inttype), dimension(:), allocatable ncoorprocrecv
Definition: adtData.F90:200
integer(kind=inttype), dimension(:), allocatable coorperrootleaf
Definition: adtData.F90:203
integer(kind=inttype) nlocalinterpol
Definition: adtData.F90:185
type(adttype), dimension(:), allocatable, target adts
Definition: adtData.F90:170
integer(kind=inttype), dimension(:), allocatable ncoorperrootleaf
Definition: adtData.F90:201
integer(kind=inttype), dimension(:), allocatable mcoorperrootleaf
Definition: adtData.F90:202
subroutine containmenttreesearch(ADT, coor, intInfo, uvw, arrDonor, nCoor, nInterpol)
subroutine mindistancetreesearch(ADT, coor, intInfo, uvw, arrDonor, nCoor, nInterpol)
subroutine initsearch(nCoor, coor, dist2, ADT, containmentSearch)
Definition: adtSearch.F90:348
subroutine containmentsearch(nCoor, coor, adtID, procID, elementType, elementID, uvw, nInterpol, arrDonor, arrInterpol)
Definition: adtSearch.F90:22
subroutine search(nCoor, coor, procID, elementType, elementID, uvw, dist2, ADT, containmentSearch, nInterpol, arrDonor, arrInterpol)
Definition: adtSearch.F90:849
subroutine mindistancesearch(nCoor, coor, adtID, procID, elementType, elementID, uvw, dist2, nInterpol, arrDonor, arrInterpol)
Definition: adtSearch.F90:737
subroutine failsafesearch(nCoor, coor, adtID, procID, elementType, elementID, uvw, dist2, nInterpol, arrDonor, arrInterpol)
Definition: adtSearch.F90:130
subroutine adtterminate(ADT, routineName, errorMessage)
Definition: adtUtils.F90:29
real(kind=realtype), parameter zero
Definition: constants.F90:71
integer, parameter adtvolumeadt
Definition: constants.F90:246
integer(kind=inttype), parameter ncoormaxlowerlimit
Definition: constants.F90:247