Neko 0.9.99
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
global_interpolation.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!
39 use num_types, only: rp
40 use space, only: space_t
41 use dofmap, only: dofmap_t
42 use mesh, only: mesh_t
43 use logger, only: neko_log, log_size
44 use utils, only: neko_error, neko_warning
46 use comm
47 use math, only: copy
49 use structs, only: array_ptr_t
50 use, intrinsic :: iso_c_binding
51 implicit none
52 private
54 type, public :: global_interpolation_t
56 type(array_ptr_t) :: x
58 type(array_ptr_t) :: y
60 type(array_ptr_t) :: z
62 integer :: gdim
64 integer :: nelv
66 type(space_t), pointer :: xh
68 type(local_interpolator_t) :: local_interp
70 logical :: all_points_local = .false.
71 !! Gslib handle.
72 !! @note: Remove when we remove gslib.
73 integer :: gs_handle
74 logical :: gs_init = .false.
77 integer :: n_points
80 real(kind=rp), allocatable :: xyz(:,:)
82 integer, allocatable :: proc_owner(:)
84 integer, allocatable :: el_owner(:)
85 type(c_ptr) :: el_owner_d = c_null_ptr
88 real(kind=rp), allocatable :: rst(:,:)
91 real(kind=rp), allocatable :: dist2(:)
93 integer, allocatable :: error_code(:)
95 real(kind=rp) :: tol = 5d-13
96 contains
98 procedure, pass(this) :: init_xyz => global_interpolation_init_xyz
99 procedure, pass(this) :: init_dof => global_interpolation_init_dof
101 procedure, pass(this) :: free => global_interpolation_free
103 procedure, pass(this) :: free_points => global_interpolation_free_points
104 procedure, pass(this) :: find_points_and_redist => &
109 procedure, pass(this) :: find_points_coords => &
111 procedure, pass(this) :: find_points_xyz => global_interpolation_find_xyz
112 generic :: find_points => find_points_xyz, find_points_coords
114 procedure, pass(this) :: evaluate => global_interpolation_evaluate
115
117 generic :: init => init_dof, init_xyz
118
120
121contains
122
126 subroutine global_interpolation_init_dof(this, dof, tol)
127 class(global_interpolation_t), intent(inout) :: this
128 type(dofmap_t), target :: dof
129 real(kind=rp), optional :: tol
130
131 ! NOTE: Passing dof%x(:,1,1,1), etc in init_xyz passes down the entire
132 ! dof%x array and not a slice. It is done this way for
133 ! this%x%ptr to point to dof%x (see global_interpolation_init_xyz).
134 call this%init_xyz(dof%x(:,1,1,1), dof%y(:,1,1,1), dof%z(:,1,1,1), &
135 dof%msh%gdim, dof%msh%nelv, dof%Xh, tol = tol)
136
137 end subroutine global_interpolation_init_dof
138
148 subroutine global_interpolation_init_xyz(this, x, y, z, gdim, nelv, Xh, tol)
149 class(global_interpolation_t), intent(inout) :: this
150 real(kind=rp), intent(in), target :: x(:)
151 real(kind=rp), intent(in), target :: y(:)
152 real(kind=rp), intent(in), target :: z(:)
153 integer, intent(in) :: gdim
154 integer, intent(in) :: nelv
155 type(space_t), intent(in), target :: Xh
156 real(kind=rp), intent(in), optional :: tol
157 integer :: lx, ly, lz, max_pts_per_iter
158
159#ifdef HAVE_GSLIB
160
161 this%x%ptr => x
162 this%y%ptr => y
163 this%z%ptr => z
164 this%gdim = gdim
165 this%nelv = nelv
166 this%Xh => xh
167 if (present(tol)) this%tol = tol
168
169 ! Number of points to iterate on simultaneosuly
170 max_pts_per_iter = 128
171 lx = xh%lx
172 ly = xh%ly
173 lz = xh%lz
174
175 call fgslib_findpts_setup(this%gs_handle, &
177 this%gdim, &
178 this%x%ptr, this%y%ptr, this%z%ptr, & ! Physical nodal values
179 lx, ly, lz, nelv, & ! Mesh dimensions
180 2*lx, 2*ly, 2*lz, & ! Mesh size for bounding box computation
181 0.01, & ! relative size to expand bounding boxes by
182 lx*ly*lz*nelv, lx*ly*lz*nelv, & ! local/global hash mesh sizes
183 max_pts_per_iter, this%tol)
184 this%gs_init = .true.
185#else
186 call neko_error('Neko needs to be built with GSLIB support')
187#endif
188
189 end subroutine global_interpolation_init_xyz
190
191
194 class(global_interpolation_t), intent(inout) :: this
195
196 nullify(this%x%ptr)
197 nullify(this%y%ptr)
198 nullify(this%z%ptr)
199 nullify(this%Xh)
200
201 this%nelv = 0
202 this%gdim = 0
203
204 call this%free_points()
205
206#ifdef HAVE_GSLIB
207 if (this%gs_init) then
208 call fgslib_findpts_free(this%gs_handle)
209 this%gs_init = .false.
210 end if
211#endif
212
213 end subroutine global_interpolation_free
214
217 class(global_interpolation_t), intent(inout) :: this
218
219 this%n_points = 0
220 this%all_points_local = .false.
221
222 if (allocated(this%xyz)) deallocate(this%xyz)
223 if (allocated(this%rst)) deallocate(this%rst)
224 if (allocated(this%proc_owner)) deallocate(this%proc_owner)
225 if (allocated(this%el_owner)) deallocate(this%el_owner)
226 if (allocated(this%dist2)) deallocate(this%dist2)
227 if (allocated(this%error_code)) deallocate(this%error_code)
228
229 if (c_associated(this%el_owner_d)) then
230 call device_free(this%el_owner_d)
231 end if
232
234
237 class(global_interpolation_t), intent(inout) :: this
238 !!Perhaps this should be kind dp
239 real(kind=rp) :: xdiff, ydiff, zdiff
240 character(len=8000) :: log_buf
241 real(kind=rp), allocatable :: x_check(:)
242 real(kind=rp), allocatable :: y_check(:)
243 real(kind=rp), allocatable :: z_check(:)
244 logical :: isdiff
245 integer :: i
246
247
248#ifdef HAVE_GSLIB
249
250 ! gslib find points, which element they belong, to process etc.
251 call fgslib_findpts(this%gs_handle, &
252 this%error_code, 1, &
253 this%proc_owner, 1, &
254 this%el_owner, 1, &
255 this%rst, this%gdim, &
256 this%dist2, 1, &
257 this%xyz(1,1), this%gdim, &
258 this%xyz(2,1), this%gdim, &
259 this%xyz(3,1), this%gdim, this%n_points)
260
261 do i = 1 , this%n_points
262
263 !
264 ! Check validity of points
265 !
266 if (this%error_code(i) .eq. 1) then
267 if (this%dist2(i) .gt. this%tol) then
268 write(*,*) 'Point with coords: ',&
269 this%xyz(1,i),&
270 this%xyz(2,i),&
271 this%xyz(3,i),&
272 'Did not converge to tol. Absolute differences squared: ',&
273 this%dist2(i), 'PE rank', pe_rank
274 end if
275 end if
276
277 if (this%error_code(i) .eq. 2) &
278 write(*,*) 'Point with coords: ',&
279 this%xyz(1,i), this%xyz(2,i), this%xyz(3,i),&
280 'Outside the mesh!',&
281 ' Interpolation on these points will return 0.0. dist2: ', &
282 this%dist2(i),&
283 'el_owner, rst coords, pe: ',&
284 this%el_owner(i), this%rst(1,i), this%rst(2,i), &
285 this%rst(3,i), pe_rank
286
287 end do
288
289 allocate(x_check(this%n_points))
290 allocate(y_check(this%n_points))
291 allocate(z_check(this%n_points))
292
293 call fgslib_findpts_eval(this%gs_handle, x_check, &
294 1, this%error_code, 1, &
295 this%proc_owner, 1, this%el_owner, 1, &
296 this%rst, this%gdim, &
297 this%n_points, this%x%ptr)
298
299 call fgslib_findpts_eval(this%gs_handle, y_check, &
300 1, this%error_code, 1, &
301 this%proc_owner, 1, this%el_owner, 1, &
302 this%rst, this%gdim, &
303 this%n_points, this%y%ptr)
304
305 call fgslib_findpts_eval(this%gs_handle, z_check, &
306 1, this%error_code, 1, &
307 this%proc_owner, 1, this%el_owner, 1, &
308 this%rst, this%gdim, &
309 this%n_points, this%z%ptr)
310
311 do i = 1 , this%n_points
312
313 !
314 ! Check validity of points
315 !
316 isdiff = .false.
317 xdiff = (x_check(i)-this%xyz(1,i))**2
318 if ( xdiff .gt. this%tol) isdiff = .true.
319 ydiff = (y_check(i)-this%xyz(2,i))**2
320 if ( ydiff .gt. this%tol) isdiff = .true.
321 zdiff = (z_check(i)-this%xyz(3,i))**2
322 if ( zdiff .gt. this%tol) isdiff = .true.
323
324 if (isdiff) then
325 write(*,*) 'Points with coords: ', &
326 this%xyz(1, i), this%xyz(2, i), this%xyz(3, i), &
327 'Differ from interpolated coords: ', &
328 x_check(i), y_check(i), z_check(i), &
329 'Distance squared: ', &
330 xdiff, ydiff, zdiff
331 end if
332
333 end do
334
335 deallocate(x_check)
336 deallocate(y_check)
337 deallocate(z_check)
338
339 if (neko_bcknd_device .eq. 1) then
340 call device_memcpy(this%el_owner, this%el_owner_d, &
341 this%n_points, host_to_device, sync = .true.)
342 end if
343#else
344 call neko_error('Neko needs to be built with GSLIB support')
345#endif
347
360 subroutine global_interpolation_find_coords(this, x, y, z, n_points)
361 class(global_interpolation_t), intent(inout) :: this
362 integer :: n_points
363 !!Perhaps this should be kind dp
364 !!this is to get around that x,y,z often is 4 dimensional...
365 !!Should maybe add interface for 1d aswell
366 real(kind=rp) :: x(n_points,1,1,1)
367 real(kind=rp) :: y(n_points,1,1,1)
368 real(kind=rp) :: z(n_points,1,1,1)
369 integer :: i
370
371 call this%free_points()
372
373 this%n_points = n_points
374
376
377 do i = 1, n_points
378 this%xyz(1, i) = x(i,1,1,1)
379 this%xyz(2, i) = y(i,1,1,1)
380 this%xyz(3, i) = z(i,1,1,1)
381 end do
382
384
386
388 class(global_interpolation_t) :: this
389
390 allocate(this%xyz(3, this%n_points))
391 allocate(this%rst(3, this%n_points))
392 allocate(this%proc_owner(this%n_points))
393 allocate(this%el_owner(this%n_points))
394 allocate(this%dist2(this%n_points))
395 allocate(this%error_code(this%n_points))
396
397 if (neko_bcknd_device .eq. 1) &
398 call device_map(this%el_owner, this%el_owner_d, this%n_points)
399
401
412 subroutine global_interpolation_find_xyz(this, xyz, n_points)
413 class(global_interpolation_t), intent(inout) :: this
414 integer, intent(in) :: n_points
415 !!Perhaps this should be kind dp
416 real(kind=rp), intent(inout) :: xyz(3, n_points)
417
418
419 call this%free_points()
420
421 this%n_points = n_points
422
424
426 call copy(this%xyz, xyz, 3 * n_points)
427
429
430 end subroutine global_interpolation_find_xyz
431
443 subroutine global_interpolation_find_and_redist(this, xyz, n_points)
444 class(global_interpolation_t), intent(inout) :: this
445 integer, intent(inout) :: n_points
446 !!Perhaps this should be kind dp
447 real(kind=rp), allocatable, intent(inout) :: xyz(:,:)
448 integer :: i
449
450
451 call this%free_points()
452
453 this%n_points = n_points
455
457 call copy(this%xyz, xyz, 3 * n_points)
458
463
464 do i = 1, this%n_points
465 if (this%proc_owner(i) .ne. pe_rank) then
466 write(*,*) 'Redistribution failed on rank: ', pe_rank, &
467 'for point with coord: ', &
468 this%xyz(1, i), this%xyz(2, i), this%xyz(3, i)
469 exit
470 end if
471 end do
472
473 n_points = this%n_points
474 if (allocated(xyz)) then
475 deallocate(xyz)
476 end if
477 allocate(xyz(3, n_points))
478 call copy(xyz, this%xyz, 3*n_points)
479
480 call this%local_interp%init(this%Xh, this%rst(1,:),&
481 this%rst(2,:), this%rst(3,:), n_points)
482 this%all_points_local = .true.
483
484
486
488 class(global_interpolation_t), intent(inout) :: this
489 integer, allocatable :: n_points_per_pe(:)
490 integer, allocatable :: n_points_from_pe(:)
491 integer, allocatable :: n_point_offset_from_pe(:)
492 real(kind=rp), allocatable :: xyz_send_to_pe(:,:)
493 real(kind=rp), allocatable :: new_xyz(:,:)
494 integer :: i, j, k, ierr, n_new_points, max_n_points_to_send
495
496 n_new_points = 0
497
498 allocate(n_points_per_pe(0:(pe_size-1)))
499 allocate(n_points_from_pe(0:(pe_size-1)))
500 n_points_per_pe = 0
501 n_points_from_pe = 0
503 do i = 1, this%n_points
504 n_points_per_pe(this%proc_owner(i)) = &
505 n_points_per_pe(this%proc_owner(i)) + 1
506 end do
509 do i = 0, (pe_size - 1)
510 call mpi_reduce(n_points_per_pe(i), n_new_points, 1, mpi_integer, &
511 mpi_sum, i, neko_comm, ierr)
512 call mpi_gather(n_points_per_pe(i), 1, mpi_integer,&
513 n_points_from_pe, 1, mpi_integer, i, neko_comm, ierr)
514 end do
515
516 allocate(n_point_offset_from_pe(0:(pe_size-1)))
517 n_point_offset_from_pe(0) = 0
518 do i = 1, (pe_size - 1)
519 n_point_offset_from_pe(i) = n_points_from_pe(i-1)&
520 + n_point_offset_from_pe(i-1)
521 end do
522
523 allocate(new_xyz(3, n_new_points))
524 max_n_points_to_send = maxval(n_points_per_pe)
525 allocate(xyz_send_to_pe(3, max_n_points_to_send))
526 do i = 0, (pe_size - 1)
528 k = 0
529 do j = 1, this%n_points
530 if (this%proc_owner(j) .eq. i) then
531 k = k + 1
532 xyz_send_to_pe(:,k) = this%xyz(:,j)
533 end if
534 end do
535 if (k .ne. n_points_per_pe(i)) then
536 write(*,*) 'PE: ', pe_rank, ' has k= ', k, &
537 'points for PE:', i,' but should have: ', &
538 n_points_per_pe(i)
539 call neko_error('Error in redistribution of points')
540 end if
541 call mpi_gatherv(xyz_send_to_pe,3*n_points_per_pe(i), &
542 mpi_double_precision, new_xyz,3*n_points_from_pe, &
543 3*n_point_offset_from_pe, &
544 mpi_double_precision, i, neko_comm, ierr)
545
546 end do
547
548 call this%free_points()
549
550 this%n_points = n_new_points
552 call copy(this%xyz, new_xyz, 3 * n_new_points)
553
554 deallocate(n_point_offset_from_pe)
555 deallocate(n_points_from_pe)
556 deallocate(n_points_per_pe)
557 deallocate(xyz_send_to_pe)
558
559 end subroutine global_interpolation_redist
560
561
562
566 subroutine global_interpolation_evaluate(this, interp_values, field)
567 class(global_interpolation_t), intent(inout) :: this
568 real(kind=rp), intent(inout) :: interp_values(this%n_points)
569 real(kind=rp), intent(inout) :: field(this%nelv*this%Xh%lxyz)
570
571
572#ifdef HAVE_GSLIB
573 if (.not. this%all_points_local) then
574 call fgslib_findpts_eval(this%gs_handle, interp_values, &
575 1, this%error_code, 1, &
576 this%proc_owner, 1, this%el_owner, 1, &
577 this%rst, this%gdim, &
578 this%n_points, field)
579 else
580 if (this%n_points .gt. 0) &
581 call this%local_interp%evaluate(interp_values, this%el_owner, &
582 field, this%nelv)
583 end if
584#else
585 call neko_error('Neko needs to be built with GSLIB support')
586#endif
587
588 end subroutine global_interpolation_evaluate
589
590end module global_interpolation
Definition comm.F90:1
integer pe_rank
MPI rank.
Definition comm.F90:28
type(mpi_comm) neko_comm
MPI communicator.
Definition comm.F90:16
integer pe_size
MPI size of communicator.
Definition comm.F90:31
Defines a mapping of the degrees of freedom.
Definition dofmap.f90:35
Defines a field.
Definition field.f90:34
Implements global_interpolation given a dofmap.
subroutine global_interpolation_free(this)
Destructor.
subroutine global_interpolation_free_points(this)
Destructor for point arrays.
subroutine global_interpolation_init_point_arrays(this)
subroutine global_interpolation_init_xyz(this, x, y, z, gdim, nelv, xh, tol)
Initialize the global interpolation object on a set of coordinates.
subroutine global_interpolation_find_coords(this, x, y, z, n_points)
Finds the corresponding r,s,t coordinates in the correct global element as well as which process that...
subroutine global_interpolation_evaluate(this, interp_values, field)
Evalute the interpolated value in the points given a field on the dofmap.
subroutine global_interpolation_init_dof(this, dof, tol)
Initialize the global interpolation object on a dofmap.
subroutine global_interpolation_find_xyz(this, xyz, n_points)
Finds the corresponding r,s,t coordinates in the correct global element as well as which process that...
subroutine global_interpolation_find_and_redist(this, xyz, n_points)
Finds the corresponding r,s,t coordinates and redistributes the points to the owning rank in the corr...
subroutine global_interpolation_find_common(this)
Common routine for finding the points.
subroutine global_interpolation_redist(this)
Routines to obtain interpolated values on a set of points with known rst coordinates in elements loca...
Logging routines.
Definition log.f90:34
type(log_t), public neko_log
Global log stream.
Definition log.f90:65
integer, parameter, public log_size
Definition log.f90:42
Definition math.f90:60
subroutine, public copy(a, b, n)
Copy a vector .
Definition math.f90:238
Defines a mesh.
Definition mesh.f90:34
MPI derived types.
Definition mpi_types.f90:34
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Defines a function space.
Definition space.f90:34
Defines structs that are used... Dont know if we should keep it though.
Definition structs.f90:2
Utilities.
Definition utils.f90:35
subroutine, public neko_warning(warning_msg)
Reports a warning to standard output.
Definition utils.f90:266
Implements global interpolation for arbitrary points in the domain.
Interpolation on a set of points with known rst coordinates in elements local to this process....
The function space for the SEM solution fields.
Definition space.f90:62
Pointer to array.
Definition structs.f90:14