ADflow  v1.0
ADflow is a finite volume RANS solver tailored for gradient-based aerodynamic design optimization.
wallSearch.F90
Go to the documentation of this file.
2 contains
3  subroutine wallsearch(aSurf, bSurf)
4 
5  use constants
7  use inputoverset, only: nearwalldist
10  use adtutils, only: stack
11  use utils, only: mynorm2
12  implicit none
13 
14  ! Input/Output
15  type(oversetwall), intent(inout) :: aSurf, bSurf
16 
17  ! Working Varaibles
18  integer(kind=intType) :: i, jj, k, iElem, maxLevels, nNeighbours, nOtherElem, iOther, otherElem
19  integer(kind=intType) :: nInterpol, elemID, intInfo(3), factor, jelem, otherElems(4)
20  real(kind=realtype) :: uvw(5), xx(4), dist, q1(3, 4), q2(3, 4), delta, radius1, radius2
21 
22  ! Variables we have to pass the ADT search routine
23  integer(kind=intType), dimension(:), pointer :: frontLeaves
24  integer(kind=intType), dimension(:), pointer :: frontLeavesNew
25  type(adtbboxtargettype), dimension(:), pointer :: BB
26  real(kind=realtype), dimension(3, 2) :: dummy
27  integer(kind=intType), dimension(:), allocatable :: tmpCellArr
28  integer(kind=intType), dimension(:), allocatable :: tmpNodeElem
29  integer(kind=intType), dimension(:), allocatable :: mask
30  type(adtleaftype), dimension(:), pointer :: ADTree
31 
32  logical :: overlapped
33 
34  if (asurf%nCells == 0 .or. bsurf%nCells == 0) then
35  ! Either block doesn't have walls, so there is nothing do but just
36  ! return.
37  return
38  end if
39 
40  if (clusterareas(bsurf%cluster) < clusterareas(asurf%cluster)) then
41  ! B is smaller so we don't need to do anything
42  return
43  else if (clusterareas(bsurf%cluster) == clusterareas(asurf%cluster)) then
44  ! If the areas are *exactly* equal (which can happen when we have
45  ! replicated grids) cut by the cluster index.
46 
47  if (bsurf%cluster < asurf%cluster) then
48  return
49  end if
50  end if
51  ninterpol = 0
52  ! Allocate the (pointer) memory that may be resized as necessary for
53  ! the singlePoint search routine.
54  allocate (bb(10), frontleaves(25), frontleavesnew(25), stack(100))
55 
56  ! Basically what we are doing it looping all of our bSurf NODES. We
57  ! use a special "surface containment search". Essentially all we are
58  ! looking for is if a point it inside of of an actual element
59  ! BBox. If it isn't inside any BBox then we know it it can't
60  ! overlap. This is essentialy fast cull of the majority of panels so
61  ! we can later just focus on the ones that may actually overlap.
62  ! node as being blanked
63 
64  ! Start with a max 10 layers (each with an unreduced 8 cells)
65  maxlevels = 1
66  allocate (tmpcellarr(3 * 3), mask(asurf%nCells), tmpnodeelem(bsurf%nNodes))
67  tmpnodeelem(:) = 0
68  mask = 0
69  adtree => asurf%ADT%ADTree
70 
71  do i = 1, bsurf%nNodes
72 
73  xx(1:3) = bsurf%x(:, i)
74  xx(4) = large
75 
76  ! Just check if it is inside the root bounding box..ie the full
77  ! bounding box of the surface. This is would appear conservative,
78  ! but isn't good enough. We need to expand by nearWallDist since
79  ! it is possible a overlap occurs right at the edge of the
80  ! bounding box.
81  if (xx(1) >= adtree(1)%xMin(1) - nearwalldist .and. &
82  xx(1) <= adtree(1)%xMax(4) + nearwalldist .and. &
83  xx(2) >= adtree(1)%xMin(2) - nearwalldist .and. &
84  xx(2) <= adtree(1)%xMax(5) + nearwalldist .and. &
85  xx(3) >= adtree(1)%xMin(3) - nearwalldist .and. &
86  xx(3) <= adtree(1)%xMax(6) + nearwalldist) then
87 
88  ! Now find the closest element on the other mesh for this
89  ! node. This is the regular (expensive) closest point search
90 
91  call mindistancetreesearchsinglepoint(asurf%ADT, xx, intinfo, uvw, &
92  dummy, ninterpol, bb, frontleaves, frontleavesnew)
93  elemid = intinfo(3)
94  tmpnodeelem(i) = elemid
95  end if
96  end do
97 
98  ! Loop over the cells now since this is eventually want we need to blank out:
99  cellloop: do i = 1, bsurf%nCells
100 
101  ! Extract out the elems found on the other mesh for the 4 nodes
102  ! on my element. There could be none, 1 or up to 4 other elements.
103 
104  notherelem = 0
105  do jj = 1, 4
106  otherelem = tmpnodeelem(bsurf%conn(jj, i))
107  if (otherelem /= 0) then
108  notherelem = notherelem + 1
109  otherelems(notherelem) = otherelem
110  end if
111  end do
112 
113  ! Get the coordinates of my quad
114  do jj = 1, 4
115  q1(:, jj) = bsurf%x(:, bsurf%conn(jj, i))
116  end do
117 
118  do iother = 1, notherelem
119 
120  elemid = otherelems(iother)
121 
122  ! Get coordinates of the other (found) quad
123  do jj = 1, 4
124  q2(:, jj) = asurf%x(:, asurf%conn(jj, elemid))
125  end do
126 
127  ! Do a quick check of the cell itself. If it overlaps,
128  ! we're done and don't need to deal with neighbor cells at
129  ! all.
130  call quadoverlap(q1, q2, overlapped)
131  if (overlapped) then
132  bsurf%iBlank(bsurf%cellPtr(i)) = -2
133 
134  ! No need to do anything else
135  cycle cellloop
136  end if
137 
138  ! Otherwise, we need to do more work.
139  radius1 = getcellradius(q1)
140  radius2 = getcellradius(q2)
141 
142  ! We technically only should only need to add 1 here, but
143  ! to be safer, we'll have at least two layers to check.
144  factor = int(radius1 / radius2) + 2
145 
146  if (factor > maxlevels) then
147  deallocate (tmpcellarr)
148  maxlevels = factor
149  allocate (tmpcellarr((1 + 2 * maxlevels)**2))
150  end if
151 
152  ! This is where it gets interesing: We can determine the
153  ! number of recursive radiating layers we need to check
154  ! based on the relative size of the the two quads.
155 
156  ! Now for the fun part: Recursion!
157  nneighbours = 0
158  call getneighbourcells(asurf, mask, elemid, factor, tmpcellarr, nneighbours)
159 
160  ! Now just blindly check them until we run out of find an overlapped one:
161 
162  do ielem = 1, nneighbours
163  elemid = tmpcellarr(ielem)
164 
165  ! Return the mask for this elem back to 0
166  mask(elemid) = 0
167 
168  ! Get coordinates of the other quad
169  do jj = 1, 4
170  q2(:, jj) = asurf%x(:, asurf%conn(jj, elemid))
171  end do
172 
173  ! Do the actual overlap calc for the found cell:
174  call quadoverlap(q1, q2, overlapped)
175 
176  if (overlapped) then
177  bsurf%iBlank(bsurf%cellPtr(i)) = -2
178 
179  ! No need to do anything else, but we we do need to
180  ! flip all the mask elements back for the next
181  ! iteration of cellLoop
182 
183  do jelem = ielem + 1, nneighbours
184  mask(tmpcellarr(jelem)) = 0
185  end do
186 
187  cycle cellloop
188 
189  end if
190  end do
191  end do
192  end do cellloop
193 
194  deallocate (bb, frontleaves, frontleavesnew, stack, tmpcellarr, mask)
195 
196  end subroutine wallsearch
197 
198  recursive subroutine getneighbourcells(aSurf, mask, baseElemID, layers, elemList, nElemFound)
199 
200  ! This routine recursively assembles a list all neighbours within
201  ! "layers" of the the baseELemID. The elemList is sorted such that
202  ! there are no duplicates:
203 
204  use constants
205  use oversetdata, only: oversetwall
206  implicit none
207 
208  ! Input/Output
209  type(oversetwall), intent(inout) :: asurf
210  integer(kind=intType), intent(inout), dimension(:) :: mask, elemlist
211  integer(kind=intType), intent(in) :: baseelemid, layers
212  integer(kind=intType), intent(inout) :: nelemfound
213 
214  ! Working
215  integer(kind=intType) :: i, inode, icell, curelem
216 
217  ! The recusive chain ends when layers == 0
218  if (layers == 0) then
219  return
220  end if
221 
222  ! Loop over the nodes of the given quad:
223  do i = 1, 4
224  inode = asurf%conn(i, baseelemid)
225 
226  ! Loop over the (up to 4) cells surrounding this node use the
227  ! node->elem (nte) array
228  do icell = 1, 4
229  curelem = asurf%nte(icell, inode)
230  if (curelem /= 0) then
231  ! This is a real cell:
232 
233  if (mask(curelem) /= baseelemid .and. mask(curelem) == 0) then
234  ! we know we don't need to add the baseElemID and if its
235  ! already in the mask we don't have to do anything either
236 
237  nelemfound = nelemfound + 1
238  elemlist(nelemfound) = curelem
239  mask(curelem) = 1
240  ! Now recursively call again, with the baseElement of curElem and 1 fewer levels
241  call getneighbourcells(asurf, mask, curelem, layers - 1, elemlist, nelemfound)
242  end if
243  end if
244  end do
245  end do
246  end subroutine getneighbourcells
247 
248  subroutine quadoverlap(q1, q2, overlapped)
249  ! Given two quad in *3D* determine if they overlap using the
250  ! separation axis theorem after projecting onto the plane defined by
251  ! the cell normal. Check both normals from each quad.
252 
253  use constants
254  use utils, only: mynorm2, cross_prod
255 
256  implicit none
257 
258  ! input/output
259  real(kind=realtype), dimension(3, 4), intent(in) :: q1, q2
260  logical, intent(out) :: overlapped
261 
262  ! Working
263  integer(kind=intType) :: ii, jj
264  real(kind=realtype), dimension(2, 4) :: qq1, qq2
265  real(kind=realtype), dimension(3) :: axis1, axis2, n1, n2, normal, v1, v2, c1, c2
266  real(kind=realtype) :: e1, e2
267  ! Check distance between cell centers
268  c1 = zero
269  c2 = zero
270  do ii = 1, 4
271  c1 = c1 + fourth * q1(:, ii)
272  c2 = c2 + fourth * q2(:, ii)
273  end do
274 
275  ! Get get max distance between center and node:
276  e1 = zero
277  e2 = zero
278  do ii = 1, 4
279  e1 = max(e1, mynorm2(c1 - q1(:, ii)))
280  e2 = max(e2, mynorm2(c2 - q2(:, ii)))
281  end do
282 
283  ! Check if distance between cell center sid beyond the threshold
284  if (mynorm2(c1 - c2) .ge. (e1 + e2)) then
285  overlapped = .false.
286  return
287  end if
288 
289  ! The two quads *may* be overlapped. We have to do it hard way.
290 
291  ! Normal of first quad
292  v1 = q1(:, 3) - q1(:, 1)
293  v2 = q1(:, 4) - q1(:, 2)
294  call cross_prod(v1, v2, n1)
295  n1 = n1 / mynorm2(n1)
296 
297  ! Normal of second quad
298  v1 = q2(:, 3) - q2(:, 1)
299  v2 = q2(:, 4) - q2(:, 2)
300  call cross_prod(v1, v2, n2)
301  n2 = n2 / mynorm2(n2)
302 
303  ! f the normals are not in the same direction, must be a thin
304  ! surface.
305  if (dot_product(n1, n2) < zero) then
306  overlapped = .false.
307  return
308  end if
309 
310  do ii = 1, 2
311  if (ii == 1) then
312  normal = n1
313  axis1 = q1(:, 2) - q1(:, 1)
314  else
315  normal = n2
316  axis1 = q2(:, 2) - q2(:, 1)
317  end if
318 
319  ! Project axis1 onto the plane and normalize
320  axis1 = axis1 - dot_product(axis1, normal) * normal
321  axis1 = axis1 / mynorm2(axis1)
322 
323  ! Axis 2 is now the normal cross axis1
324  call cross_prod(normal, axis1, axis2)
325  axis2 = axis2 / mynorm2(axis2)
326 
327  do jj = 1, 4
328  qq1(1, jj) = dot_product(axis1, q1(:, jj))
329  qq1(2, jj) = dot_product(axis2, q1(:, jj))
330 
331  qq2(1, jj) = dot_product(axis1, q2(:, jj))
332  qq2(2, jj) = dot_product(axis2, q2(:, jj))
333  end do
334  call quadoverlap2d(qq1, qq2, overlapped)
335 
336  if (overlapped) then
337  return
338  end if
339  end do
340 
341  end subroutine quadoverlap
342 
343  subroutine quadoverlap2d(q1, q2, overlapped)
344  ! Given two quad in *2D* determine if they overlap using the
345  ! separation axis theorem
346 
347  use constants
348  implicit none
349 
350  ! input/output
351  real(kind=realtype), dimension(2, 4), intent(in) :: q1, q2
352  logical, intent(out) :: overlapped
353 
354  ! Working
355  real(kind=realtype), dimension(4) :: tmp1, tmp2
356  integer(kind=intType) :: ii, jj, kk, jjp1
357  real(kind=realtype), dimension(2) :: axis, p0
358  real(kind=realtype) :: min1, max1, min2, max2
359  overlapped = .true.
360  tmp1 = zero
361  tmp2 = zero
362  quadloop: do ii = 1, 2 ! Loop over the two quads
363  edgeloop: do jj = 1, 4 ! Loop over the edges of each quad
364  jjp1 = mod(jj, 4) + 1
365 
366  if (ii == 1) then
367  axis = q1(:, jjp1) - q1(:, jj)
368  p0 = q1(:, jj)
369  else
370  axis = q2(:, jjp1) - q2(:, jj)
371  p0 = q2(:, jj)
372  end if
373 
374  ! Take the axis normal
375  axis = (/axis(2), -axis(1)/)
376 
377  ! Take the dot products
378  do kk = 1, 4
379  tmp1(kk) = dot_product(axis, q1(:, kk) - p0)
380  tmp2(kk) = dot_product(axis, q2(:, kk) - p0)
381  end do
382 
383  min1 = minval(tmp1)
384  max1 = maxval(tmp1)
385 
386  min2 = minval(tmp2)
387  max2 = maxval(tmp2)
388 
389  if (max1 < min2 .or. max2 < min1) then
390  overlapped = .false.
391  ! We can just jump right out since we know they cannot
392  ! overlap.
393  exit quadloop
394  end if
395  end do edgeloop
396  end do quadloop
397  end subroutine quadoverlap2d
398 
399  function getcellradius(q)
400 
401  use constants
402  use utils, only: mynorm2
403  implicit none
404  ! Input
405  real(kind=realtype), dimension(3, 4) :: q
406  real(kind=realtype) :: getcellradius
407 
408  ! Working
409  real(kind=realtype) :: c(3)
410  integer(kind=intType) :: ii
411 
412  c = zero
413  do ii = 1, 4
414  c = c + fourth * q(:, ii)
415  end do
416 
418  do ii = 1, 4
419  getcellradius = max(getcellradius, mynorm2(c - q(:, ii)))
420  end do
421 
422  end function getcellradius
423 
424 end module wallsearches
subroutine mindistancetreesearchsinglepoint(ADT, coor, intInfo, uvw, arrDonor, nInterpol, BB, frontLeaves, frontLeavesNew)
integer(kind=inttype), dimension(:), pointer stack
Definition: adtUtils.F90:20
real(kind=realtype), parameter zero
Definition: constants.F90:71
real(kind=realtype), parameter fourth
Definition: constants.F90:82
real(kind=realtype), parameter large
Definition: constants.F90:24
real(kind=realtype) nearwalldist
Definition: inputParam.F90:883
real(kind=realtype), dimension(:), allocatable clusterareas
Definition: overset.F90:368
Definition: utils.F90:1
subroutine cross_prod(a, b, c)
Definition: utils.F90:1721
real(kind=realtype) function mynorm2(x)
Definition: utils.F90:1697
subroutine wallsearch(aSurf, bSurf)
Definition: wallSearch.F90:4
recursive subroutine getneighbourcells(aSurf, mask, baseElemID, layers, elemList, nElemFound)
Definition: wallSearch.F90:199
subroutine quadoverlap(q1, q2, overlapped)
Definition: wallSearch.F90:249
subroutine quadoverlap2d(q1, q2, overlapped)
Definition: wallSearch.F90:344
real(kind=realtype) function getcellradius(q)
Definition: wallSearch.F90:400