Neko 1.99.1
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
cartesian_el_finder.f90
Go to the documentation of this file.
1! Copyright (c) 2020-2023, The Neko Authors
2! All rights reserved.
3!
4! Redistribution and use in source and binary forms, with or without
5! modification, are permitted provided that the following conditions
6! are met:
7!
8! * Redistributions of source code must retain the above copyright
9! notice, this list of conditions and the following disclaimer.
10!
11! * Redistributions in binary form must reproduce the above
12! copyright notice, this list of conditions and the following
13! disclaimer in the documentation and/or other materials provided
14! with the distribution.
15!
16! * Neither the name of the authors nor the names of its
17! contributors may be used to endorse or promote products derived
18! from this software without specific prior written permission.
19!
20! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21! "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22! LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23! FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24! COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25! INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26! BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27! LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29! LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30! ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31! POSSIBILITY OF SUCH DAMAGE.
32!
33
35 use num_types, only : rp, xp, dp
37 use el_finder, only : el_finder_t
38 use space, only : space_t
39 use stack, only : stack_i4_t
40 use tuple, only : tuple_i4_t
41 use point, only : point_t
42 use htable, only : htable_i4_t
43 use utils, only : linear_index, neko_error
44 use mpi_f08, only : mpi_wtime
45 use tensor_cpu, only : tnsr3d_cpu
46 use fast3d, only : setup_intp
47 implicit none
48 private
49
50
51 type, public, extends(el_finder_t) :: cartesian_el_finder_t
53 type(stack_i4_t), allocatable :: el_map(:)
54 integer :: n_boxes, nel
55 real(kind=xp) :: max_x, min_x
56 real(kind=xp) :: max_y, min_y
57 real(kind=xp) :: max_z, min_z
58 real(kind=xp) :: x_res, y_res, z_res
59 real(kind=xp) :: padding
60 contains
61 procedure, pass(this) :: init => cartesian_el_finder_init
62 procedure, pass(this) :: free => cartesian_el_finder_free
63 procedure, pass(this) :: find => cartesian_el_finder_find_candidates
64 procedure, pass(this) :: find_batch => &
66 procedure, pass(this) :: compute_idx => cartesian_el_finder_compute_idx
67 procedure, pass(this) :: compute_3idx => &
70
71contains
72
73 subroutine cartesian_el_finder_init(this, x, y, z, nel, Xh, n_boxes, padding)
74 class(cartesian_el_finder_t), intent(inout) :: this
75 type(space_t), intent(in) :: Xh
76 real(kind=rp), intent(in), target :: x(:), y(:), z(:)
77 integer, intent(in) :: nel
78 integer, intent(in) :: n_boxes
79 real(kind=dp), intent(in) :: padding
80 type(htable_i4_t) :: marked_box
81 integer :: i, j, k, e
82 integer :: el_npts, el_x_npts, el_y_npts, el_z_npts
83 real(kind=rp) :: el_x(xh%lxyz), el_y(xh%lxyz), el_z(xh%lxyz)
84 integer :: lxyz
85 integer :: el_idx
86 integer :: htable_data
87 real(kind=rp) :: center_x, center_y, center_z, r_res
88 integer :: current_size
89 real(kind=rp) :: time_start, time_end
90 integer :: min_id(3), max_id(3)
91 integer :: lin_idx, lx2
92 integer :: i2, j2, k2
93 real(kind=rp) :: min_bb_x, max_bb_x
94 real(kind=rp) :: min_bb_y, max_bb_y
95 real(kind=rp) :: min_bb_z, max_bb_z
96
97 call this%free()
98 ! Ensure n_boxes is within a reasonable range
99 if (n_boxes > 0 .and. n_boxes <= 1000) then
100 allocate(this%el_map(n_boxes**3))
101 else
102 call neko_error("Cartesian el finder, n_boxes is too large or negative")
103 end if
104 do i = 1, n_boxes**3
105 call this%el_map(i)%init()
106 end do
107
108 current_size = 0
109 this%padding = padding
110 this%max_x = maxval(x(1:nel*xh%lxyz))
111 this%min_x = minval(x(1:nel*xh%lxyz))
112 this%max_y = maxval(y(1:nel*xh%lxyz))
113 this%min_y = minval(y(1:nel*xh%lxyz))
114 this%max_z = maxval(z(1:nel*xh%lxyz))
115 this%min_z = minval(z(1:nel*xh%lxyz))
116
117 center_x = (this%max_x + this%min_x) / 2.0_xp
118 center_y = (this%max_y + this%min_y) / 2.0_xp
119 center_z = (this%max_z + this%min_z) / 2.0_xp
120
121 this%max_x = this%max_x - center_x
122 this%max_y = this%max_y - center_y
123 this%max_z = this%max_z - center_z
124 this%min_x = this%min_x - center_x
125 this%min_y = this%min_y - center_y
126 this%min_z = this%min_z - center_z
127 this%max_x = this%max_x * (1.0_xp + this%padding) + center_x
128 this%max_y = this%max_y * (1.0_xp + this%padding) + center_y
129 this%max_z = this%max_z * (1.0_xp + this%padding) + center_z
130 this%min_x = this%min_x * (1.0_xp + this%padding) + center_x
131 this%min_y = this%min_y * (1.0_xp + this%padding) + center_y
132 this%min_z = this%min_z * (1.0_xp + this%padding) + center_z
133
134
135
136 !Resulting resolution
137 this%x_res = (this%max_x - this%min_x) / real(n_boxes, xp)
138 this%y_res = (this%max_y - this%min_y) / real(n_boxes, xp)
139 this%z_res = (this%max_z - this%min_z) / real(n_boxes, xp)
140
141 this%nel = nel
142 this%n_boxes = n_boxes
143 call marked_box%init(nel)
144 lxyz = xh%lxyz
145
146 do e = 1, nel
147 call marked_box%clear()
148
149 !move it to do scaling
150 lx2 = xh%lx/2
151 if (mod(xh%lx,2) .eq. 0) then
152 lin_idx = linear_index(lx2,lx2,lx2, e, xh%lx, xh%lx, xh%lx)
153 center_x = x(lin_idx)
154 center_y = y(lin_idx)
155 center_z = z(lin_idx)
156 else
157 center_x = 0d0
158 center_y = 0d0
159 center_z = 0d0
160 do i = lx2, lx2 + 1
161 do j = lx2, lx2 + 1
162 do k = lx2, lx2 + 1
163 lin_idx = linear_index(i,j,k,e, xh%lx, xh%lx, xh%lx)
164 center_x = center_x + x(lin_idx)
165 center_y = center_y + y(lin_idx)
166 center_z = center_z + z(lin_idx)
167 end do
168 end do
169 end do
170 center_x = center_x / 8.0_xp
171 center_y = center_y / 8.0_xp
172 center_z = center_z / 8.0_xp
173 end if
174
175 ! Scaling the element coordinates with padding
176 ! for bounding box computations
177
178 el_x = x((e-1)*lxyz+1:e*lxyz) - center_x
179 el_y = y((e-1)*lxyz+1:e*lxyz) - center_y
180 el_z = z((e-1)*lxyz+1:e*lxyz) - center_z
181 el_x = el_x * (1.0_rp + padding) + center_x
182 el_y = el_y * (1.0_rp + padding) + center_y
183 el_z = el_z * (1.0_rp + padding) + center_z
184 !Padded and ready
185
186 ! Now we go through the bounding boxes of all subboxes in the element
187 do i = 1, xh%lx - 1
188 do j = 1, xh%ly - 1
189 do k = 1, xh%lz - 1
190 lin_idx = linear_index(i, j, k, 1, xh%lx, xh%lx, xh%lx)
191 max_bb_x = el_x(lin_idx)
192 min_bb_x = el_x(lin_idx)
193 max_bb_y = el_y(lin_idx)
194 min_bb_y = el_y(lin_idx)
195 max_bb_z = el_z(lin_idx)
196 min_bb_z = el_z(lin_idx)
197 do i2 = 0, 1
198 do j2 = 0, 1
199 do k2 = 0, 1
200 lin_idx = linear_index(i+i2,j+j2,k+k2, &
201 1, xh%lx, xh%lx, xh%lx)
202 max_bb_x = max(max_bb_x, el_x(lin_idx))
203 min_bb_x = min(min_bb_x, el_x(lin_idx))
204 max_bb_y = max(max_bb_y, el_y(lin_idx))
205 min_bb_y = min(min_bb_y, el_y(lin_idx))
206 max_bb_z = max(max_bb_z, el_z(lin_idx))
207 min_bb_z = min(min_bb_z, el_z(lin_idx))
208 end do
209 end do
210 end do
211
212
213 min_id = this%compute_3idx(min_bb_x, min_bb_y, min_bb_z)
214 max_id = this%compute_3idx(max_bb_x, max_bb_y, max_bb_z)
215 do i2 = min_id(1), max_id(1)
216 do j2 = min_id(2), max_id(2)
217 do k2 = min_id(3), max_id(3)
218 if (i2 .ge. 1 .and. i2 .le. this%n_boxes .and. &
219 j2 .ge. 1 .and. j2 .le. this%n_boxes .and. &
220 k2 .ge. 1 .and. k2 .le. this%n_boxes) then
221 el_idx = linear_index(i2, j2, k2, 1, &
222 this%n_boxes, this%n_boxes, this%n_boxes)
223 if (marked_box%get(el_idx,htable_data) .ne. 0)then
224 call marked_box%set(el_idx, htable_data)
225 call this%el_map(el_idx)%push(e)
226 end if
227 end if
228 end do
229 end do
230 end do
231 end do
232 end do
233 end do
234 end do
235 call marked_box%free()
236 !print *, "Time for cartesian_el_finder_init: ", MPI_Wtime() - time_start
237 end subroutine cartesian_el_finder_init
238
240 class(cartesian_el_finder_t), intent(inout) :: this
241 integer :: i
242
243 if (allocated(this%el_map)) then
244 do i = 1, size(this%el_map)
245 call this%el_map(i)%free()
246 end do
247 deallocate(this%el_map)
248 end if
249 end subroutine cartesian_el_finder_free
250
251 function cartesian_el_finder_compute_idx(this, x, y, z) result(idx)
252 class(cartesian_el_finder_t), intent(in) :: this
253 real(kind=rp), intent(in) :: x, y, z
254 integer :: idx
255 integer :: ids(3)
256
257 ids = this%compute_3idx(x, y, z)
258 idx = linear_index(ids(1), ids(2), ids(3), 1, &
259 this%n_boxes, this%n_boxes, this%n_boxes)
260
262
263 function cartesian_el_finder_compute_xyz_idxs(this, x, y, z) result(idxs)
264 class(cartesian_el_finder_t), intent(in) :: this
265 real(kind=rp), intent(in) :: x, y, z
266 integer :: idxs(3)
267 integer :: x_id, y_id, z_id
268
269 x_id = int(real(x - this%min_x,xp) / this%x_res)
270 y_id = int(real(y - this%min_y,xp) / this%y_res)
271 z_id = int(real(z - this%min_z,xp) / this%z_res)
272 if (x_id .eq. -1) then
273 x_id = 0
274 end if
275 if (x_id .eq. this%n_boxes) then
276 x_id = this%n_boxes - 1
277 end if
278 if (y_id .eq. -1) then
279 y_id = 0
280 end if
281 if (y_id .eq. this%n_boxes) then
282 y_id = this%n_boxes - 1
283 end if
284 if (z_id .eq. -1) then
285 z_id = 0
286 end if
287 if (z_id .eq. this%n_boxes) then
288 z_id = this%n_boxes - 1
289 end if
290 x_id = x_id + 1
291 y_id = y_id + 1
292 z_id = z_id + 1
293
294 idxs(1) = x_id
295 idxs(2) = y_id
296 idxs(3) = z_id
298
299 subroutine cartesian_el_finder_find_candidates(this, my_point, el_candidates)
300 class(cartesian_el_finder_t), intent(inout) :: this
301 type(point_t), intent(in) :: my_point
302 type(stack_i4_t), intent(inout) :: el_candidates
303 integer :: idx, i, adjusted_index
304 integer, pointer :: el_cands(:)
305
306 call el_candidates%clear()
307 idx = this%compute_idx(real(my_point%x(1),rp), &
308 real(my_point%x(2), rp), real(my_point%x(3), rp))
309 el_cands => this%el_map(idx)%array()
310 do i = 1, this%el_map(idx)%size()
311 adjusted_index = el_cands(i) - 1
312 call el_candidates%push(adjusted_index)
313 end do
315
316 ! In order to get more cache hits
317 subroutine cartesian_el_finder_find_candidates_batch(this, points, n_points, &
318 all_el_candidates, n_el_cands)
319 class(cartesian_el_finder_t), intent(inout) :: this
320 integer, intent(in) :: n_points
321 real(kind=rp), intent(in) :: points(3,n_points)
322 type(stack_i4_t), intent(inout) :: all_el_candidates
323 integer, intent(inout) :: n_el_cands(n_points)
324 integer :: i, j, adjusted_index
325 integer :: idx3(3), idx
326 integer, pointer :: el_cands(:)
327
328 call all_el_candidates%clear()
329 n_el_cands = 0
330
331 do i = 1, n_points
332 idx3 = this%compute_3idx(real(points(1,i), rp), &
333 real(points(2,i), rp), real(points(3,i), rp))
334 if (idx3(1) .ge. 1 .and. idx3(1) .le. this%n_boxes .and. &
335 idx3(2) .ge. 1 .and. idx3(2) .le. this%n_boxes .and. &
336 idx3(3) .ge. 1 .and. idx3(3) .le. this%n_boxes) then
337 idx = this%compute_idx(real(points(1,i), rp), &
338 real(points(2,i), rp), real(points(3,i), rp))
339 el_cands => this%el_map(idx)%array()
340 do j = 1, this%el_map(idx)%size()
341 adjusted_index = el_cands(j) - 1 ! Adjusting for zero-based indexing
342 call all_el_candidates%push(adjusted_index)
343 end do
344 n_el_cands(i) = this%el_map(idx)%size()
345 end if
346 end do
347
349
350end module cartesian_el_finder
double real
subroutine cartesian_el_finder_find_candidates(this, my_point, el_candidates)
subroutine cartesian_el_finder_find_candidates_batch(this, points, n_points, all_el_candidates, n_el_cands)
integer function, dimension(3) cartesian_el_finder_compute_xyz_idxs(this, x, y, z)
subroutine cartesian_el_finder_init(this, x, y, z, nel, xh, n_boxes, padding)
integer function cartesian_el_finder_compute_idx(this, x, y, z)
subroutine cartesian_el_finder_free(this)
Fast diagonalization methods from NEKTON.
Definition fast3d.f90:61
subroutine, public setup_intp(jh, jht, z_to, z_from, n_to, n_from, derivative)
Compute interpolation weights for points z_to using values at points z_from.
Definition fast3d.f90:244
Implements a hash table ADT.
Definition htable.f90:36
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public i2
Definition num_types.f90:5
integer, parameter, public xp
Definition num_types.f90:14
integer, parameter, public dp
Definition num_types.f90:9
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Implements a point.
Definition point.f90:35
Defines a function space.
Definition space.f90:34
Implements a dynamic stack ADT.
Definition stack.f90:35
subroutine, public tnsr3d_cpu(v, nv, u, nu, a, bt, ct, nelv)
Implements a n-tuple.
Definition tuple.f90:34
Utilities.
Definition utils.f90:35
pure integer function, public linear_index(i, j, k, l, lx, ly, lz)
Compute the address of a (i,j,k,l) array with sizes (1:lx, 1:ly, 1:lz, :)
Definition utils.f90:237
Base type for element finder providing element candidates for a given point in the domain.
Definition el_finder.f90:43
Integer based hash table.
Definition htable.f90:82
A point in with coordinates .
Definition point.f90:43
The function space for the SEM solution fields.
Definition space.f90:63
Integer based stack.
Definition stack.f90:63
Integer based 2-tuple.
Definition tuple.f90:51
#define max(a, b)
Definition tensor.cu:40