Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
legendre_rst_finder.f90
Go to the documentation of this file.
1! Copyright (c) 2020-2026, 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, dp, xp
38 use space, only: space_t
39 use utils, only: neko_error, neko_warning
40 use vector, only: vector_t
41 use matrix, only: matrix_t
42 use math, only: neko_eps, matinv39
45 use, intrinsic :: iso_c_binding, only: c_ptr, c_null_ptr
48 use device_math, only: device_vlsc3
49 implicit none
50 private
51
54 type, public :: legendre_rst_finder_t
55 type(vector_t) :: x_hat, y_hat, z_hat
56 type(space_t), pointer :: xh => null()
57 integer :: nelv = 0
58 real(kind=rp) :: tol = neko_eps
59 integer :: max_iter = 10
60 contains
61 procedure, pass(this) :: init => legendre_rst_finder_init
62 procedure, pass(this) :: free => legendre_rst_finder_free
63 procedure, pass(this) :: find => legendre_rst_finder_find
65
66contains
67
68 subroutine legendre_rst_finder_init(this, x, y, z, nelv, Xh, tol, max_iter)
69 class(legendre_rst_finder_t), intent(inout) :: this
70 type(space_t), target, intent(in) :: Xh
71 integer, intent(in) :: nelv
72 real(kind=rp), intent(in), dimension(nelv*Xh%lxyz) :: x, y, z
73 real(kind=dp), intent(in), optional :: tol
74 integer, intent(in), optional :: max_iter
75
76 call this%free()
77
78 if (present(tol)) then
79 if (tol < neko_eps) then
80 call neko_error('Tolerance for the Legendre finder is too small')
81 end if
82 this%tol = tol
83
84 else
85 this%tol = neko_eps
86 end if
87 if (present(max_iter)) then
88 if (max_iter < 1) then
89 call neko_error('Max iterations for the Legendre finder is too small')
90 end if
91 this%max_iter = max_iter
92 else
93 this%max_iter = 10
94 end if
95
96 this%Xh => xh
97 this%nelv = nelv
98
99 call this%x_hat%init(nelv*xh%lxyz)
100 call this%y_hat%init(nelv*xh%lxyz)
101 call this%z_hat%init(nelv*xh%lxyz)
102
103 call tnsr3d_cpu(this%x_hat%x, xh%lx, x, &
104 xh%lx, xh%vinv, &
105 xh%vinvt, xh%vinvt, nelv)
106 call tnsr3d_cpu(this%y_hat%x, xh%lx, y, &
107 xh%lx, xh%vinv, &
108 xh%vinvt, xh%vinvt, nelv)
109 call tnsr3d_cpu(this%z_hat%x, xh%lx, z, &
110 xh%lx, xh%vinv, &
111 xh%vinvt, xh%vinvt, nelv)
112
114 call this%x_hat%copy_from(host_to_device, .false.)
115 call this%y_hat%copy_from(host_to_device, .false.)
116 call this%z_hat%copy_from(host_to_device, .false.)
117
118 end subroutine legendre_rst_finder_init
119
121 class(legendre_rst_finder_t), intent(inout) :: this
122
123 call this%x_hat%free()
124 call this%y_hat%free()
125 call this%z_hat%free()
126
127 this%Xh => null()
128
129 end subroutine legendre_rst_finder_free
130
146 subroutine legendre_rst_finder_find(this, rst_local_cand, x_t, y_t, z_t, &
147 el_cands, n_point_cand, resx, resy, resz)
148 class(legendre_rst_finder_t), intent(inout) :: this
149 type(matrix_t), intent(inout) :: rst_local_cand
150 type(vector_t), intent(in) :: x_t, y_t, z_t
151 integer, intent(in) :: n_point_cand
152 integer, intent(inout) :: el_cands(:)
153 type(vector_t), intent(inout) :: resx, resy, resz
154 type(c_ptr) :: el_cands_d = c_null_ptr
155
157 if (n_point_cand .lt. 1) return
158
159 rst_local_cand = 0.0_rp
160
161 if (neko_bcknd_device .eq. 1) then
162 el_cands_d = device_get_ptr(el_cands)
163 call find_rst_legendre_device(this, rst_local_cand%x_d, &
164 x_t%x_d, y_t%x_d, z_t%x_d, &
165 el_cands_d, n_point_cand, &
166 resx%x_d, resy%x_d, resz%x_d)
167
168 else
169 call find_rst_legendre_cpu(this, rst_local_cand%x, x_t%x, y_t%x, z_t%x, &
170 el_cands, n_point_cand, &
171 resx%x, resy%x, resz%x)
172
173 end if
174
175 end subroutine legendre_rst_finder_find
176
183 subroutine find_rst_legendre_device(this, rst, pt_x, pt_y, pt_z, &
184 el_list, n_pts, resx, resy, resz)
185 type(legendre_rst_finder_t), intent(inout) :: this
186 type(c_ptr), intent(inout) :: rst
187 type(c_ptr), intent(in) :: pt_x, pt_y, pt_z
188 type(c_ptr), intent(in) :: el_list
189 type(c_ptr), intent(inout) :: resx, resy, resz
190 integer, intent(in) :: n_pts
191 type(vector_t) :: conv_pts
192 integer :: iter
193 logical :: converged
194 real(kind=rp) :: conv_sum
195
196 if (n_pts .eq. 0) return
197
198 call conv_pts%init(n_pts)
199
200 conv_pts = 1.0_rp
201
202 iter = 0
203 converged = .false.
204 !Iterate until found, not heavily optimized
205 do while (.not. converged)
206 iter = iter + 1
207 call device_find_rst_legendre(rst, pt_x, pt_y, pt_z, &
208 this%x_hat%x_d, this%y_hat%x_d, this%z_hat%x_d, &
209 resx, resy, resz, &
210 this%Xh%lx,el_list, n_pts, this%tol, &
211 conv_pts%x_d)
212 !This can be made more approriate... avoid memcpy at least
213 conv_sum = device_vlsc3(conv_pts%x_d,conv_pts%x_d,conv_pts%x_d,n_pts)
214 converged = conv_sum .lt. 0.5
215 !print *, conv_sum
216 if( iter .ge. this%max_iter) converged = .true.
217 end do
218
219 call conv_pts%free()
220 end subroutine find_rst_legendre_device
221
228 subroutine find_rst_legendre_cpu(this, rst, pt_x, pt_y, pt_z, &
229 el_list, n_pts, resx, resy, resz)
230 type(legendre_rst_finder_t), intent(inout) :: this
231 integer, intent(in) :: n_pts
232 real(kind=rp), intent(inout) :: rst(3, n_pts)
233 real(kind=rp), intent(in) :: pt_x(n_pts)
234 real(kind=rp), intent(in) :: pt_y(n_pts)
235 real(kind=rp), intent(in) :: pt_z(n_pts)
236 real(kind=rp), intent(inout) :: resx(n_pts)
237 real(kind=rp), intent(inout) :: resy(n_pts)
238 real(kind=rp), intent(inout) :: resz(n_pts)
239 integer, intent(in) :: el_list(n_pts)
240 real(kind=rp) :: r_legendre(1, this%Xh%lx)
241 real(kind=rp) :: s_legendre(this%Xh%lx, 1)
242 real(kind=rp) :: t_legendre(this%Xh%lx, 1)
243 real(kind=rp) :: dr_legendre(1, this%Xh%lx)
244 real(kind=rp) :: ds_legendre(this%Xh%lx, 1)
245 real(kind=rp) :: dt_legendre(this%Xh%lx, 1)
246 real(kind=rp) :: jac(3,3)
247 real(kind=xp) :: rst_d(3), jacinv(3,3)
248 real(kind=rp), dimension(this%Xh%lx * this%Xh%lx * this%Xh%lx) :: x_hat
249 real(kind=rp), dimension(this%Xh%lx * this%Xh%lx * this%Xh%lx) :: y_hat
250 real(kind=rp), dimension(this%Xh%lx * this%Xh%lx * this%Xh%lx) :: z_hat
251 integer :: conv_pts
252 logical :: converged
253 integer :: i, j, e, iter, lx, ih
254
255
256
257 lx = this%Xh%lx
258 if (n_pts .lt. 1) return
259
260 rst = 0.0_rp
261 ! If performance critical we should do multiple points at the time
262 ! Currently we do one point at the time
263 do i = 1, n_pts
264 iter = 0
265 converged = .false.
266 do while (.not. converged)
267 iter = iter + 1
268 ! Compute legendre polynomials in this rst coordinate
269 r_legendre(1, 1) = 1.0
270 r_legendre(1, 2) = rst(1,i)
271 s_legendre(1, 1) = 1.0
272 s_legendre(2, 1) = rst(2,i)
273 t_legendre(1, 1) = 1.0
274 t_legendre(2, 1) = rst(3,i)
275 dr_legendre(1, 1) = 0.0
276 dr_legendre(1, 2) = 1.0
277 ds_legendre(1, 1) = 0.0
278 ds_legendre(2, 1) = 1.0
279 dt_legendre(1, 1) = 0.0
280 dt_legendre(2, 1) = 1.0
281 do j = 2, lx-1
282 r_legendre(1, j+1) = ((2.0_xp*(j-1.0_xp)+1.0_xp) * rst(1,i) &
283 * r_legendre(1, j) - (j-1.0_xp) &
284 * r_legendre(1, j-1)) / (real(j,xp))
285 s_legendre(j+1, 1) = ((2.0_xp*(j-1.0_xp)+1.0_xp) * rst(2,i) &
286 * s_legendre(j, 1) - (j-1.0_xp) &
287 * s_legendre(j-1, 1))/(real(j,xp))
288 t_legendre(j+1, 1) = ((2.0_xp*(j-1.0_xp)+1.0_xp) * rst(3,i) &
289 * t_legendre(j, 1) - (j-1.0_xp) &
290 * t_legendre(j-1, 1))/(real(j,xp))
291 dr_legendre(1, j+1) = ((j-1.0_xp)+1.0_xp) * r_legendre(1, j) &
292 + rst(1,i)*dr_legendre(1, j)
293 ds_legendre(j+1, 1) = ((j-1.0_xp)+1.0_xp) * s_legendre(j, 1) &
294 + rst(2,i)*ds_legendre(j, 1)
295 dt_legendre(j+1, 1) = ((j-1.0_xp)+1.0_xp) * t_legendre(j, 1) &
296 + rst(3,i)*dt_legendre(j, 1)
297 end do
298 e = (el_list(i))*this%Xh%lxyz + 1
299
300 ! Pull the element data to a static array instead of a slice
301 do ih = 0, lx*lx*lx - 1
302 x_hat(ih + 1) = this%x_hat%x(e + ih)
303 y_hat(ih + 1) = this%y_hat%x(e + ih)
304 z_hat(ih + 1) = this%z_hat%x(e + ih)
305 end do
306
307 ! Compute the current xyz value
308 call tnsr3d_el_cpu(resx(i), 1, x_hat, lx, &
309 r_legendre, s_legendre, t_legendre)
310 call tnsr3d_el_cpu(resy(i), 1, y_hat, lx, &
311 r_legendre, s_legendre, t_legendre)
312 call tnsr3d_el_cpu(resz(i), 1, z_hat, lx, &
313 r_legendre, s_legendre, t_legendre)
314 ! This should in principle be merged into some larger kernel
315 ! Compute the jacobian
316 call tnsr3d_el_cpu(jac(1,1), 1, x_hat, lx, &
317 dr_legendre, s_legendre, t_legendre)
318 call tnsr3d_el_cpu(jac(1,2), 1, y_hat, lx, &
319 dr_legendre, s_legendre, t_legendre)
320 call tnsr3d_el_cpu(jac(1,3), 1, z_hat, lx, &
321 dr_legendre, s_legendre, t_legendre)
322 call tnsr3d_el_cpu(jac(2,1), 1, x_hat, lx, &
323 r_legendre, ds_legendre, t_legendre)
324 call tnsr3d_el_cpu(jac(2,2), 1, y_hat, lx, &
325 r_legendre, ds_legendre, t_legendre)
326 call tnsr3d_el_cpu(jac(2,3), 1, z_hat, lx, &
327 r_legendre, ds_legendre, t_legendre)
328 call tnsr3d_el_cpu(jac(3,1), 1, x_hat, lx, &
329 r_legendre, s_legendre, dt_legendre)
330 call tnsr3d_el_cpu(jac(3,2), 1, y_hat, lx, &
331 r_legendre, s_legendre, dt_legendre)
332 call tnsr3d_el_cpu(jac(3,3), 1, z_hat, lx, &
333 r_legendre, s_legendre, dt_legendre)
334 resx(i) = pt_x(i) - resx(i)
335 resy(i) = pt_y(i) - resy(i)
336 resz(i) = pt_z(i) - resz(i)
337 ! Jacobian inverse
338 jacinv = matinv39(jac(1,1), jac(1,2), jac(1,3),&
339 jac(2,1), jac(2,2), jac(2,3),&
340 jac(3,1), jac(3,2), jac(3,3))
341 ! Update direction
342 rst_d(1) = (resx(i)*jacinv(1,1) &
343 + jacinv(2,1)*resy(i) &
344 + jacinv(3,1)*resz(i))
345 rst_d(2) = (resx(i)*jacinv(1,2) &
346 + jacinv(2,2)*resy(i) &
347 + jacinv(3,2)*resz(i))
348 rst_d(3) = (resx(i)*jacinv(1,3) &
349 + jacinv(2,3)*resy(i) &
350 + jacinv(3,3)*resz(i))
351
352 conv_pts = 0
353 if (norm2(real(rst_d,xp)) .le. this%tol) then
354 conv_pts = 1
355 end if
356 if (norm2(real(rst_d,xp)) .gt. 4.0) then
357 conv_pts = 1
358 end if
359 ! Update rst coordinates
360 rst(1,i) = rst(1,i) + rst_d(1)
361 rst(2,i) = rst(2,i) + rst_d(2)
362 rst(3,i) = rst(3,i) + rst_d(3)
363
364 converged = conv_pts .eq. 1
365 if (iter .ge. this%max_iter) converged = .true.
366 end do
367 end do
368 end subroutine find_rst_legendre_cpu
369end module legendre_rst_finder
double real
Return the device pointer for an associated Fortran array.
Definition device.F90:113
Copy data between host and device (or device and device)
Definition device.F90:72
subroutine, public device_find_rst_legendre(rst_d, pt_x_d, pt_y_d, pt_z_d, x_hat_d, y_hat_d, z_hat_d, resx_d, resy_d, resz_d, lx, el_ids_d, n_pts, tol, conv_pts_d)
real(kind=rp) function, public device_vlsc3(u_d, v_d, w_d, n, strm)
Compute multiplication sum .
Device abstraction, common interface for various accelerators.
Definition device.F90:34
integer, parameter, public host_to_device
Definition device.F90:48
subroutine, public device_free(x_d)
Deallocate memory on the device.
Definition device.F90:243
integer, parameter, public device_to_host
Definition device.F90:48
subroutine, public device_alloc(x_d, s)
Allocate memory on the device.
Definition device.F90:212
type(c_ptr), bind(C), public glb_cmd_queue
Global command queue.
Definition device.F90:52
subroutine find_rst_legendre_device(this, rst, pt_x, pt_y, pt_z, el_list, n_pts, resx, resy, resz)
Using the Legendre polynomials to find the rst coordinates on GPU.
subroutine legendre_rst_finder_init(this, x, y, z, nelv, xh, tol, max_iter)
subroutine legendre_rst_finder_find(this, rst_local_cand, x_t, y_t, z_t, el_cands, n_point_cand, resx, resy, resz)
Given a set of element candidates containing the given points and computes the local RST coordinates ...
subroutine find_rst_legendre_cpu(this, rst, pt_x, pt_y, pt_z, el_list, n_pts, resx, resy, resz)
Using the Legendre polynomials to find the rst coordinates.
subroutine legendre_rst_finder_free(this)
Definition math.f90:60
real(rp) function, dimension(3, 3), public matinv39(a11, a12, a13, a21, a22, a23, a31, a32, a33)
Definition math.f90:1821
real(kind=rp), parameter, public neko_eps
Machine epsilon .
Definition math.f90:70
Defines a matrix.
Definition matrix.f90:34
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public xp
Definition num_types.f90:16
integer, parameter, public dp
Definition num_types.f90:10
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
Defines a function space.
Definition space.f90:34
subroutine, public tnsr3d_cpu(v, nv, u, nu, a, bt, ct, nelv)
Three-dimensional tensor product over a list of elements.
subroutine, public tnsr3d_el_cpu(v, nv, u, nu, a, bt, ct)
Three-dimensional tensor product on a single element.
Utilities.
Definition utils.f90:35
subroutine, public neko_warning(warning_msg)
Reports a warning to standard output.
Definition utils.f90:452
Defines a vector.
Definition vector.f90:34
Type to compute local element (rst) coordinates for a gives set points in physical (xyz) space on a S...
The function space for the SEM solution fields.
Definition space.f90:64