Neko 1.99.9
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-2025, 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!
36 use num_types, only : rp, dp, xp
38 use space, only : space_t
39 use stack, only : stack_i4_t
40 use dofmap, only : dofmap_t
41 use logger, only : neko_log, log_size
43 use json_module, only : json_file
44 use utils, only : neko_error
54 use el_finder, only : el_finder_t
55 use pe_finder, only : pe_finder_t
56 use comm, only : neko_comm
57 use mpi_f08, only : mpi_sum, mpi_comm, mpi_comm_rank, &
58 mpi_comm_size, mpi_wtime, mpi_allreduce, mpi_in_place, mpi_integer, &
59 mpi_min, mpi_barrier, mpi_reduce_scatter_block, mpi_alltoall, &
60 mpi_isend, mpi_irecv
62 use vector, only : vector_t
64 use matrix, only : matrix_t
65 use math, only : copy, neko_eps
66 use mask, only : mask_t
67 use structs, only : array_ptr_t
68 use, intrinsic :: iso_c_binding, only : c_ptr, c_null_ptr, c_associated
69 implicit none
70 private
71
72 integer, public, parameter :: glob_map_size = 4096
73 real(kind=dp), public, parameter :: glob_interp_tol = neko_eps*1e3_dp
74 real(kind=dp), public, parameter :: glob_interp_pad = 1e-2_dp
75
81 real(kind=dp) :: tolerance = glob_interp_tol
83 real(kind=dp) :: padding = glob_interp_pad
85
87 type, public :: global_interpolation_t
89 type(vector_t) :: x
91 type(vector_t) :: y
93 type(vector_t) :: z
95 integer :: gdim
97 integer :: nelv
99 integer :: glb_nelv
101 type(mpi_comm) :: comm
103 integer :: pe_rank
105 integer :: pe_size
107 type(space_t) :: xh
110 integer :: n_points
112 real(kind=rp), allocatable :: xyz(:,:)
114 real(kind=rp), allocatable :: rst(:,:)
116 integer, allocatable :: pe_owner(:)
118 type(stack_i4_t), allocatable :: points_at_pe(:)
121 integer, allocatable :: el_owner0(:)
122 type(c_ptr) :: el_owner0_d = c_null_ptr
123
125 integer :: n_points_local
126 integer, allocatable :: el_owner0_local(:)
127 type(c_ptr) :: el_owner0_local_d = c_null_ptr
128 real(kind=rp), allocatable :: rst_local(:,:)
129 real(kind=rp), allocatable :: xyz_local(:,:)
131 type(local_interpolator_t) :: local_interp
134 logical :: all_points_local = .false.
136 real(kind=dp) :: tolerance = glob_interp_tol
138 real(kind=dp) :: padding = glob_interp_pad
139
143 integer, allocatable :: n_points_pe(:)
144 integer, allocatable :: n_points_offset_pe(:)
147 integer, allocatable :: n_points_pe_local(:)
148 integer, allocatable :: n_points_offset_pe_local(:)
151 class(pe_finder_t), allocatable :: pe_finder
153 class(el_finder_t), allocatable :: el_finder
155 type(legendre_rst_finder_t) :: rst_finder
160 type(vector_t) :: temp_local, temp
161 integer :: n_dof = -1
162 type(vector_t) :: masked_field
163
164 contains
167 procedure, pass(this) :: init_json_xyz => &
171 procedure, pass(this) :: init_json_dof => &
175 procedure, pass(this) :: init_xyz => global_interpolation_init_xyz
177 procedure, pass(this) :: init_dof => global_interpolation_init_dof
179 procedure, pass(this) :: free => global_interpolation_free
181 procedure, pass(this) :: free_points => global_interpolation_free_points
182 procedure, pass(this) :: free_points_local => &
184 procedure, pass(this) :: find_points_and_redist => &
189 procedure, pass(this) :: find_points_coords => &
191 procedure, pass(this) :: find_points_coords1d => &
194 procedure, pass(this) :: check_points => &
196 procedure, pass(this) :: find_points_xyz => global_interpolation_find_xyz
197 generic :: find_points => find_points_xyz, find_points_coords, &
198 find_points_coords1d
200 procedure, pass(this) :: evaluate => global_interpolation_evaluate
201 procedure, pass(this) :: evaluate_masked => &
203 procedure, pass(this) :: init_redist_comm => &
205
207 generic :: init => init_dof, init_xyz, init_json_xyz, init_json_dof
208
210
211contains
212
226 subroutine global_interpolation_init_json_xyz(this, x, y, z, gdim, nelv, Xh, &
227 params_subdict, comm)
228 class(global_interpolation_t), target, intent(inout) :: this
229 real(kind=rp), intent(in) :: x(:)
230 real(kind=rp), intent(in) :: y(:)
231 real(kind=rp), intent(in) :: z(:)
232 integer, intent(in) :: gdim
233 integer, intent(in) :: nelv
234 type(space_t), intent(in) :: Xh
235 type(json_file), intent(inout) :: params_subdict
236 type(mpi_comm), intent(in), optional :: comm
237
238 real(kind=dp) :: tol, pad
239
240 call json_get_or_lookup_or_default(params_subdict, 'tolerance', &
241 tol, glob_interp_tol)
242 call json_get_or_lookup_or_default(params_subdict, 'padding', &
243 pad, glob_interp_pad)
244
245 call this%init_xyz(x, y, z, gdim, nelv, xh, comm = comm, tol = tol, &
246 pad = pad)
247
249
257 subroutine global_interpolation_init_json_dof(this, dof, params_subdict, &
258 comm, mask)
259 class(global_interpolation_t), target, intent(inout) :: this
260 type(dofmap_t) :: dof
261 type(json_file), intent(inout) :: params_subdict
262 type(mpi_comm), optional, intent(in) :: comm
263 type(mask_t), intent(in), optional :: mask
264
265 real(kind=dp) :: tol, pad
266
267 call json_get_or_lookup_or_default(params_subdict, 'tolerance', &
268 tol, glob_interp_tol)
269 call json_get_or_lookup_or_default(params_subdict, 'padding', &
270 pad, glob_interp_pad)
271
272 call this%init_dof(dof, comm = comm, tol = tol, pad = pad, mask = mask)
273
275
282 subroutine global_interpolation_init_dof(this, dof, comm, tol, pad, mask)
283 class(global_interpolation_t), target, intent(inout) :: this
284 type(dofmap_t) :: dof
285 type(mpi_comm), optional, intent(in) :: comm
286 real(kind=dp), optional :: tol
287 real(kind=dp), optional :: pad
288 type(mask_t), intent(in), optional :: mask
289
290 integer :: temp_nelv
291
292 ! Store the number of dofs
293 this%n_dof = dof%size()
294 ! NOTE: Passing dof%x%x(:,1,1,1), etc in init_xyz passes down the entire
295 ! dof%x array and not a slice. It is done this way for
296 ! to get the right dimension (see global_interpolation_init_xyz).
297 if (.not. present(mask)) then
298 call this%init_xyz(dof%x%x(:,1,1,1), dof%y%x(:,1,1,1), dof%z%x(:,1,1,1), &
299 dof%msh%gdim, dof%msh%nelv, dof%Xh, comm = comm, &
300 tol = tol, pad = pad)
301 else
302
303 ! Verify that the mask size is compatible with the dofmap
304 temp_nelv = mask%size() / (dof%Xh%lx*dof%Xh%ly*dof%Xh%lz)
305 if (mod(mask%size(), dof%Xh%lx*dof%Xh%ly*dof%Xh%lz) /= 0) then
306 call neko_error("Mask size must be a multiple of the number of" // &
307 " elements in the mesh.")
308 end if
309 ! Initialize with the masked coordinates
310 call this%init_xyz(dof%x%x(mask%get(),1,1,1), dof%y%x(mask%get(),1,1,1), &
311 dof%z%x(mask%get(),1,1,1), dof%msh%gdim, temp_nelv, dof%Xh, &
312 comm = comm, tol = tol, pad = pad)
313 ! Initialize a helper field with the size of the mask, after
314 ! init_xyz since that frees the object
315 call this%masked_field%init(mask%size())
316 end if
317
318 end subroutine global_interpolation_init_dof
319
330 subroutine global_interpolation_init_xyz(this, x, y, z, gdim, nelv, Xh, &
331 comm, tol, pad)
332 class(global_interpolation_t), target, intent(inout) :: this
333 real(kind=rp), intent(in) :: x(:)
334 real(kind=rp), intent(in) :: y(:)
335 real(kind=rp), intent(in) :: z(:)
336 integer, intent(in) :: gdim
337 integer, intent(in) :: nelv
338 type(space_t), intent(in) :: Xh
339 type(mpi_comm), intent(in), optional :: comm
340 real(kind=dp), intent(in), optional :: tol
341 real(kind=dp), intent(in), optional :: pad
342
343 integer :: lx, ly, lz, ierr, i, n
344 character(len=8000) :: log_buf
345 !real(kind=dp) :: padding ! <-- note that this padding is in dp
346 real(kind=rp) :: time1, time_start
347 character(len=255) :: mode_str
348 integer :: boxdim, envvar_len
349
350 call neko_log%section('Global Interpolation')
351 call neko_log%message('Initializing global interpolation')
352
353 call this%free()
354
355 ! Set communicator
356 if (present(comm)) then
357 this%comm = comm
358 else
359 this%comm = neko_comm
360 end if
361
362 ! Set point search parameters
363 this%padding = glob_interp_pad
364 if (present(pad)) this%padding = pad
365
366 this%tolerance = glob_interp_tol
367 if (present(tol)) this%tolerance = tol
368
369 write(log_buf, '(A,E15.7)') &
370 'Tolerance: ', this%tolerance
371 call neko_log%message(log_buf)
372 write(log_buf, '(A,E15.7)') &
373 'Padding : ', this%padding
374 call neko_log%message(log_buf)
375
376 time_start = mpi_wtime()
377 call mpi_barrier(this%comm)
378
379 call mpi_comm_rank(this%comm, this%pe_rank, ierr)
380 call mpi_comm_size(this%comm, this%pe_size, ierr)
381
382 this%gdim = gdim
383 this%nelv = nelv
384
385 call mpi_allreduce(nelv, this%glb_nelv, 1, mpi_integer, &
386 mpi_sum, this%comm, ierr)
387 lx = xh%lx
388 ly = xh%ly
389 lz = xh%lz
390 n = nelv * lx*ly*lz
391 call this%x%init(n)
392 call this%y%init(n)
393 call this%z%init(n)
394 call copy(this%x%x, x, n)
395 call this%x%copy_from(host_to_device,.false.)
396 call copy(this%y%x, y, n)
397 call this%y%copy_from(host_to_device,.false.)
398 call copy(this%z%x, z, n)
399 call this%z%copy_from(host_to_device,.false.)
400 call this%Xh%init(xh%t, lx, ly, lz)
401
402 ! Initialize n_dof if it was not started with a dof-based constructor
403 if (this%n_dof == -1) then
404 this%n_dof = n
405 end if
406
407
408 call get_environment_variable("NEKO_GLOBAL_INTERP_EL_FINDER", &
409 mode_str, envvar_len)
410
411 if (envvar_len .gt. 0) then
412 if (mode_str(1:envvar_len) == 'AABB') then
413 allocate(aabb_el_finder_t :: this%el_finder)
414 end if
415 end if
416 call get_environment_variable("NEKO_GLOBAL_INTERP_PE_FINDER", &
417 mode_str, envvar_len)
418
419 if (envvar_len .gt. 0) then
420 if (mode_str(1:envvar_len) == 'AABB') then
421 allocate(aabb_pe_finder_t :: this%pe_finder)
422 end if
423 end if
424
425 if (.not. allocated(this%el_finder)) then
426 allocate(cartesian_el_finder_t :: this%el_finder)
427 end if
428 if (.not. allocated(this%pe_finder)) then
429 allocate(cartesian_pe_finder_t :: this%pe_finder)
430 end if
431 select type (el_find => this%el_finder)
432 type is (aabb_el_finder_t)
433 call neko_log%message('Using AABB element finder')
434 call el_find%init(x, y, z, nelv, xh, this%padding)
435 type is (cartesian_el_finder_t)
436 call neko_log%message('Using Cartesian element finder')
437 boxdim = max(lx*int(real(nelv, xp)**(1.0_xp / 3.0_xp)), 2)
438 boxdim = min(boxdim, 300)
439 call el_find%init(x, y, z, nelv, xh, boxdim, this%padding)
440 class default
441 call neko_error('Unknown element finder type')
442 end select
443
444 select type (pe_find => this%pe_finder)
445 type is (aabb_pe_finder_t)
446 call neko_log%message('Using AABB PE finder')
447 call pe_find%init(this%x%x, this%y%x, this%z%x, &
448 nelv, xh, this%comm, this%padding)
449 type is (cartesian_pe_finder_t)
450 call neko_log%message('Using Cartesian PE finder')
451 boxdim = lx*int(real(this%glb_nelv, xp)**(1.0_xp / 3.0_xp))
452 boxdim = max(boxdim, 32)
453 boxdim = min(boxdim, &
454 int(8.0_xp*(30000.0_xp * this%pe_size)**(1.0_xp / 3.0_xp)))
455 call pe_find%init(this%x%x, this%y%x, this%z%x, &
456 nelv, xh, this%comm, boxdim, this%padding)
457 class default
458 call neko_error('Unknown PE finder type')
459 end select
460
461 call this%rst_finder%init(this%x%x, this%y%x, this%z%x, nelv, xh, &
462 this%tolerance)
463 if (allocated(this%n_points_pe)) deallocate(this%n_points_pe)
464 if (allocated(this%n_points_pe_local)) deallocate(this%n_points_pe_local)
465 if (allocated(this%n_points_offset_pe_local)) &
466 deallocate(this%n_points_offset_pe_local)
467 if (allocated(this%n_points_offset_pe)) deallocate(this%n_points_offset_pe)
468 allocate(this%n_points_pe(0:(this%pe_size-1)))
469 allocate(this%n_points_offset_pe(0:(this%pe_size-1)))
470 allocate(this%n_points_pe_local(0:(this%pe_size-1)))
471 allocate(this%n_points_offset_pe_local(0:(this%pe_size-1)))
472 allocate(this%points_at_pe(0:(this%pe_size-1)))
473 do i = 0, this%pe_size-1
474 call this%points_at_pe(i)%init()
475 end do
476 call mpi_barrier(this%comm)
477 time1 = mpi_wtime()
478 write(log_buf, '(A,E15.7)') &
479 'Global interpolation initialized (s):', time1-time_start
480 call neko_log%message(log_buf)
481 call neko_log%end_section()
482 end subroutine global_interpolation_init_xyz
483
484
487 class(global_interpolation_t), target, intent(inout) :: this
488 integer :: i
489
490 call this%x%free()
491 call this%y%free()
492 call this%z%free()
493 call this%Xh%free()
494
495 this%nelv = 0
496 this%gdim = 0
497
498 call this%free_points()
499 call this%free_points_local()
500 call this%local_interp%free()
501 if (allocated(this%el_finder)) then
502 call this%el_finder%free()
503 deallocate(this%el_finder)
504 end if
505 if (allocated(this%pe_finder)) then
506 call this%pe_finder%free()
507 deallocate(this%pe_finder)
508 end if
509 call this%rst_finder%free()
510
511 call this%temp_local%free()
512 call this%temp%free()
513 call this%masked_field%free()
514 if (allocated(this%points_at_pe)) then
515 do i = 0, this%pe_size-1
516 call this%points_at_pe(i)%free()
517 end do
518 deallocate(this%points_at_pe)
519 end if
520 if (allocated(this%n_points_pe)) deallocate(this%n_points_pe)
521 if (allocated(this%n_points_pe_local)) deallocate(this%n_points_pe_local)
522 if (allocated(this%n_points_offset_pe_local)) &
523 deallocate(this%n_points_offset_pe_local)
524 if (allocated(this%n_points_offset_pe)) deallocate(this%n_points_offset_pe)
525
526
527
528 end subroutine global_interpolation_free
529
532 class(global_interpolation_t), target, intent(inout) :: this
533
534 this%n_points = 0
535 this%all_points_local = .false.
536
537 if (allocated(this%xyz)) deallocate(this%xyz)
538 if (allocated(this%rst)) deallocate(this%rst)
539 if (allocated(this%pe_owner)) deallocate(this%pe_owner)
540 if (allocated(this%el_owner0)) then
541 if (neko_bcknd_device .eq. 1) then
542 call device_unmap(this%el_owner0, this%el_owner0_d)
543 end if
544 deallocate(this%el_owner0)
545 end if
546
547 call this%glb_intrp_comm%free()
548
549
551
552
554 class(global_interpolation_t), target, intent(inout) :: this
555
556 this%n_points_local = 0
557 this%all_points_local = .false.
558
559 if (allocated(this%xyz_local)) deallocate(this%xyz_local)
560 if (allocated(this%rst_local)) deallocate(this%rst_local)
561 if (allocated(this%el_owner0_local)) then
562 if (neko_bcknd_device .eq. 1) then
563 call device_unmap(this%el_owner0_local, this%el_owner0_local_d)
564 end if
565 deallocate(this%el_owner0_local)
566 end if
567
569
570
573 class(global_interpolation_t), target, intent(inout) :: this
574 character(len=8000) :: log_buf
575 type(vector_t) :: x_t
576 type(vector_t) :: y_t
577 type(vector_t) :: z_t
578 type(matrix_t) :: rst_local_cand
579 type(vector_t) :: resx
580 type(vector_t) :: resy
581 type(vector_t) :: resz
582 type(c_ptr) :: el_cands_d
583 type(matrix_t) :: res
584 integer :: i, j, stupid_intent
585 type(stack_i4_t), target :: all_el_candidates
586 integer, allocatable :: n_el_cands(:)
587 integer, contiguous, pointer :: el_cands(:), point_ids(:), send_recv(:)
588 real(kind=rp), allocatable :: res_results(:,:)
589 real(kind=rp), allocatable :: rst_results(:,:)
590 integer, allocatable :: el_owner_results(:)
591 integer :: ierr, ii, n_point_cand, n_glb_point_cand, point_id, rank
592 real(kind=rp) :: time1, time2, time_start
593 !Temp stuff for glb_intrp_comm
594 type(stack_i4_t) :: send_pe, recv_pe
595 type(glb_intrp_comm_t) :: glb_intrp_find, glb_intrp_find_back
596 type(stack_i4_t) :: send_pe_find, recv_pe_find
597
598 el_cands_d = c_null_ptr
599 call neko_log%section('Global Interpolation')
600 call glb_intrp_find%init_dofs(this%pe_size)
601 call send_pe_find%init()
602 call recv_pe_find%init()
603 call mpi_barrier(this%comm)
604 time_start = mpi_wtime()
605 write(log_buf, '(A)') 'Global interpolation, finding points'
606 call neko_log%message(log_buf)
607 ! Find pe candidates that the points i want may be at
608 ! Add number to n_points_pe_local
609 !Working arrays
610 this%n_points_pe = 0
611 call this%pe_finder%find_batch(this%xyz, this%n_points, &
612 this%points_at_pe, this%n_points_pe)
613 call mpi_barrier(this%comm)
614 time1 = mpi_wtime()
615 write(log_buf, '(A,E15.7)') &
616 'Found PE candidates time since start of findpts (s):', &
617 time1 - time_start
618 call neko_log%message(log_buf)
619
620 !Send number of points I want to candidates
621 ! n_points_local -> how many points might be at this rank
622 ! n_points_pe_local -> how many points local on this rank that other pes
623 ! might want
624 this%n_points_pe_local = 0
625 this%n_points_local = 0
626 call mpi_reduce_scatter_block(this%n_points_pe, this%n_points_local, &
627 1, mpi_integer, mpi_sum, this%comm, ierr)
628 call mpi_alltoall(this%n_points_pe, 1, mpi_integer,&
629 this%n_points_pe_local, 1, mpi_integer, this%comm, ierr)
630
631 !Set up offset arrays
632 this%n_points_offset_pe_local(0) = 0
633 this%n_points_offset_pe(0) = 0
634 do i = 1, (this%pe_size - 1)
635 this%n_points_offset_pe_local(i) = this%n_points_pe_local(i-1)&
636 + this%n_points_offset_pe_local(i-1)
637 this%n_points_offset_pe(i) = this%n_points_pe(i-1)&
638 + this%n_points_offset_pe(i-1)
639 end do
640 do i = 0, (this%pe_size-1)
641 if (this%n_points_pe(i) .gt. 0) then
642 call send_pe_find%push(i)
643 point_ids => this%points_at_pe(i)%array()
644 do j = 1, this%n_points_pe(i)
645 call glb_intrp_find%send_dof(i)%push(3*(point_ids(j)-1)+1)
646 call glb_intrp_find%send_dof(i)%push(3*(point_ids(j)-1)+2)
647 call glb_intrp_find%send_dof(i)%push(3*(point_ids(j)-1)+3)
648 end do
649 end if
650 if (this%n_points_pe_local(i) .gt. 0) then
651 call recv_pe_find%push(i)
652 do j = 1, this%n_points_pe_local(i)
653 call glb_intrp_find%recv_dof(i)%push(3*(j + &
654 this%n_points_offset_pe_local(i) - 1) + 1)
655 call glb_intrp_find%recv_dof(i)%push(3*(j + &
656 this%n_points_offset_pe_local(i) - 1) + 2)
657 call glb_intrp_find%recv_dof(i)%push(3*(j + &
658 this%n_points_offset_pe_local(i) - 1) + 3)
659 end do
660 end if
661 end do
662
663
664
665 call glb_intrp_find%init(send_pe_find, recv_pe_find, this%comm)
666
667 call glb_intrp_find_back%init_dofs(this%pe_size)
668 ii = 0
669 do i = 0, (this%pe_size-1)
670 send_recv => glb_intrp_find%recv_dof(i)%array()
671 do j = 1, glb_intrp_find%recv_dof(i)%size()
672 call glb_intrp_find_back%send_dof(i)%push(send_recv(j))
673 end do
674 send_recv => glb_intrp_find%send_dof(i)%array()
675 do j = 1, glb_intrp_find%send_dof(i)%size()
676 ii = ii + 1
677 call glb_intrp_find_back%recv_dof(i)%push(ii)
678 end do
679 end do
680
681 call glb_intrp_find_back%init(recv_pe_find, send_pe_find, this%comm)
682
683
684 if (allocated(this%xyz_local)) then
685 deallocate(this%xyz_local)
686 end if
687 allocate(this%xyz_local(3, this%n_points_local))
688 call glb_intrp_find%sendrecv(this%xyz, this%xyz_local, this%n_points*3, &
689 this%n_points_local*3)
690
691 call mpi_barrier(this%comm)
692 time1 = mpi_wtime()
693 write(log_buf, '(A,E15.7)') &
694 'Sent to points to PE candidates, time since start of ' &
695 // 'find_points (s):', time1 - time_start
696 call neko_log%message(log_buf)
697
698 !Okay, now we need to find the rst...
699 call all_el_candidates%init()
700
701 if (allocated(n_el_cands)) then
702 deallocate(n_el_cands)
703 end if
704
705 allocate(n_el_cands(this%n_points_local))
707 call this%el_finder%find_batch(this%xyz_local, this%n_points_local, &
708 all_el_candidates, n_el_cands)
709
710 n_point_cand = all_el_candidates%size()
711 if (n_point_cand .gt. 1e8) then
712 print *, 'Warning, many point candidates on rank', this%pe_rank, &
713 'cands:', n_point_cand, &
714 'Consider increasing number of ranks'
715 end if
716 call x_t%init(n_point_cand)
717 call y_t%init(n_point_cand)
718 call z_t%init(n_point_cand)
719 ii = 0
721 do i = 1 , this%n_points_local
722 do j = 1, n_el_cands(i)
723 ii = ii + 1
724 x_t%x(ii) = this%xyz_local(1,i)
725 y_t%x(ii) = this%xyz_local(2,i)
726 z_t%x(ii) = this%xyz_local(3,i)
727 end do
728 end do
729
730 call mpi_barrier(this%comm)
731 time1 = mpi_wtime()
732 write(log_buf, '(A,E15.7)') &
733 'Element candidates found, now time for finding rst, time ' // &
734 'since start of find_points (s):', time1 - time_start
735 call neko_log%message(log_buf)
736 call rst_local_cand%init(3, n_point_cand)
737 call resx%init(n_point_cand)
738 call resy%init(n_point_cand)
739 call resz%init(n_point_cand)
740
741 ! Find rst within all element candidates for target xyz (x_t, y_t, z_t)
742 call mpi_barrier(this%comm)
743 time1 = mpi_wtime()
744 el_cands => all_el_candidates%array()
745 if (neko_bcknd_device .eq. 1) then
746 call x_t%copy_from(host_to_device,.false.)
747
748 call y_t%copy_from(host_to_device,.false.)
749
750 call z_t%copy_from(host_to_device,.false.)
751 call device_map(el_cands, el_cands_d, n_point_cand)
752 call device_memcpy(el_cands, el_cands_d, n_point_cand, &
753 host_to_device, .true.)
754 end if
755
756 call this%rst_finder%find(rst_local_cand, &
757 x_t, y_t, z_t, &
758 el_cands, n_point_cand, &
759 resx, resy, resz)
760 if (neko_bcknd_device .eq. 1) then
761 call rst_local_cand%copy_from(device_to_host,.false.)
762 call resx%copy_from(device_to_host,.false.)
763 call resy%copy_from(device_to_host,.false.)
764 call resz%copy_from(device_to_host,.true.)
765 call device_unmap(el_cands, el_cands_d)
766 end if
767 call mpi_barrier(this%comm)
768
769 time2 = mpi_wtime()
770 write(log_buf, '(A,E15.7)') &
771 'Found rst with Newton iteration, time (s):', time2-time1
772 call neko_log%message(log_buf)
773
774 write(log_buf, '(A)') &
775 'Checking validity of points and choosing best candidates.'
776 call neko_log%message(log_buf)
777 call mpi_barrier(this%comm, ierr)
778
779 if (allocated(this%rst_local)) deallocate(this%rst_local)
780 if (allocated(this%el_owner0_local)) deallocate(this%el_owner0_local)
781 allocate(this%rst_local(3, this%n_points_local))
782 allocate(this%el_owner0_local(this%n_points_local))
783 ! Choose the best candidate at this rank
784 ii = 0
785 do i = 1 , this%n_points_local
786 this%xyz_local(1,i) = 10.0
787 this%xyz_local(2,i) = 10.0
788 this%xyz_local(3,i) = 10.0
789 this%rst_local(1,i) = 10.0
790 this%rst_local(2,i) = 10.0
791 this%rst_local(3,i) = 10.0
792 this%el_owner0_local(i) = -1
793 do j = 1, n_el_cands(i)
794 ii = ii + 1
795 if (rst_cmp(this%rst_local(:, i), rst_local_cand%x(:, ii), &
796 this%xyz_local(:, i), [resx%x(ii), resy%x(ii), resz%x(ii)], &
797 this%padding)) then
798 this%rst_local(1, i) = rst_local_cand%x(1, ii)
799 this%rst_local(2, i) = rst_local_cand%x(2, ii)
800
801 this%rst_local(3, i) = rst_local_cand%x(3, ii)
802 this%xyz_local(1,i) = resx%x(ii)
803 this%xyz_local(2,i) = resy%x(ii)
804 this%xyz_local(3,i) = resz%x(ii)
805 this%el_owner0_local(i) = el_cands(ii)
806 end if
807 ! if (this%pe_rank .eq. 0) print *,i, this%rst_local(:,i), &
808 ! this%xyz_local(:,i), this%el_owner0_local(i)
809 end do
810 end do
811 call res%init(3, this%n_points)
812 n_glb_point_cand = sum(this%n_points_pe)
813 if (allocated(rst_results)) deallocate(rst_results)
814 if (allocated(res_results)) deallocate(res_results)
815 if (allocated(el_owner_results)) deallocate(el_owner_results)
816 allocate(rst_results(3, n_glb_point_cand))
817 allocate(res_results(3, n_glb_point_cand))
818 allocate(el_owner_results(n_glb_point_cand))
819 res = 1e2_rp
820 this%rst = 1e2
821 this%pe_owner = -1
822 this%el_owner0 = -1
823 call glb_intrp_find_back%sendrecv(this%xyz_local, res_results, &
824 this%n_points_local*3, n_glb_point_cand*3)
825 call glb_intrp_find_back%sendrecv(this%rst_local, rst_results, &
826 this%n_points_local*3, n_glb_point_cand*3)
827 do i = 1, size(glb_intrp_find_back%send_pe)
828 rank = glb_intrp_find_back%send_pe(i)
829 call mpi_isend(this%el_owner0_local( &
830 this%n_points_offset_pe_local(rank) + 1), &
831 this%n_points_pe_local(rank), &
832 mpi_integer, rank, 0, &
833 this%comm, glb_intrp_find_back%send_buf(i)%request, ierr)
834 glb_intrp_find_back%send_buf(i)%flag = .false.
835 end do
836 do i = 1, size(glb_intrp_find_back%recv_pe)
837 rank = glb_intrp_find_back%recv_pe(i)
838 call mpi_irecv(el_owner_results(this%n_points_offset_pe(rank)+1),&
839 this%n_points_pe(rank), &
840 mpi_integer, rank, 0, &
841 this%comm, glb_intrp_find_back%recv_buf(i)%request, ierr)
842 glb_intrp_find_back%recv_buf(i)%flag = .false.
843 end do
844 call glb_intrp_find_back%nbwait_no_op()
845 ii = 0
846 do i = 1, size(glb_intrp_find_back%recv_pe)
847 point_ids => this%points_at_pe(glb_intrp_find_back%recv_pe(i))%array()
848 do j = 1, this%n_points_pe(glb_intrp_find_back%recv_pe(i))
849 point_id = point_ids(j)
850 ii = ii + 1
851 if (rst_cmp(this%rst(:, point_id), rst_results(:, ii), &
852 res%x(:, point_id), res_results(:, ii), this%padding) .or. &
853 this%pe_owner(point_ids(j)) .eq. -1 ) then
854 this%rst(:, point_ids(j)) = rst_results(:, ii)
855 res%x(:, point_ids(j)) = res_results(:, ii)
856 this%pe_owner(point_ids(j)) = glb_intrp_find_back%recv_pe(i)
857 this%el_owner0(point_ids(j)) = el_owner_results(ii)
858 end if
859 ! if (this%pe_rank .eq. 0) print *,point_id, &
860 !this%rst(:,point_ids(j)),res%x(:,point_ids(j)),
861 ! this%el_owner0(point_ids(j))
862 end do
863 end do
864
865 !OK, now I know the correct rst values of the points I want We now
866 !send the correct rsts to the correct rank (so a point only
867 !belongs to one rank)
868 do i = 0, this%pe_size-1
869 call this%points_at_pe(i)%clear()
870 this%n_points_pe(i) = 0
871 end do
872
873 do i = 1, this%n_points
874 stupid_intent = i
875 if (this%pe_owner(i) .eq. -1 .or. this%el_owner0(i) .eq. -1) then
876 print *, 'No owning rank found for',&
877 ' point ', stupid_intent, ' with coords', this%xyz(:,i), &
878 ' Interpolation will always yield 0.0. Try increase padding.'
879 else
880 call this%points_at_pe(this%pe_owner(i))%push(stupid_intent)
881 this%n_points_pe(this%pe_owner(i)) = &
882 this%n_points_pe(this%pe_owner(i)) + 1
883 end if
884 end do
885 call mpi_reduce_scatter_block(this%n_points_pe, this%n_points_local, 1, &
886 mpi_integer, mpi_sum, this%comm, ierr)
887 call mpi_alltoall(this%n_points_pe, 1, mpi_integer, &
888 this%n_points_pe_local, 1, mpi_integer, this%comm, ierr)
889 this%n_points_offset_pe_local(0) = 0
890 this%n_points_offset_pe(0) = 0
891 do i = 1, (this%pe_size - 1)
892 this%n_points_offset_pe_local(i) = this%n_points_pe_local(i-1)&
893 + this%n_points_offset_pe_local(i-1)
894 this%n_points_offset_pe(i) = this%n_points_pe(i-1)&
895 + this%n_points_offset_pe(i-1)
896 end do
897 call send_pe_find%free()
898 call recv_pe_find%free()
899 call glb_intrp_find%free()
900 call send_pe_find%init()
901 call recv_pe_find%init()
902 call glb_intrp_find%init_dofs(this%pe_size)
903 !setup comm to send xyz and rst to chosen ranks
904 do i = 0, (this%pe_size-1)
905 if (this%n_points_pe(i) .gt. 0) then
906 call send_pe_find%push(i)
907 point_ids => this%points_at_pe(i)%array()
908 do j = 1, this%n_points_pe(i)
909 call glb_intrp_find%send_dof(i)%push(3*(point_ids(j) - 1) + 1)
910 call glb_intrp_find%send_dof(i)%push(3*(point_ids(j) - 1) + 2)
911 call glb_intrp_find%send_dof(i)%push(3*(point_ids(j) - 1) + 3)
912 end do
913 end if
914 if (this%n_points_pe_local(i) .gt. 0) then
915 call recv_pe_find%push(i)
916 do j = 1, this%n_points_pe_local(i)
917 call glb_intrp_find%recv_dof(i)%push(3*(j + &
918 this%n_points_offset_pe_local(i) - 1) + 1)
919 call glb_intrp_find%recv_dof(i)%push(3*(j + &
920 this%n_points_offset_pe_local(i) - 1) + 2)
921 call glb_intrp_find%recv_dof(i)%push(3*(j + &
922 this%n_points_offset_pe_local(i) - 1) + 3)
923 end do
924 end if
925 end do
926
927
928 call glb_intrp_find%init(send_pe_find, recv_pe_find, this%comm)
929 call glb_intrp_find%sendrecv(this%xyz, this%xyz_local, this%n_points*3, &
930 this%n_points_local*3)
931 call glb_intrp_find%sendrecv(this%rst, this%rst_local, this%n_points*3, &
932 this%n_points_local*3)
933 ii = 0
934 do i = 1, size(glb_intrp_find%send_pe)
935 rank = glb_intrp_find%send_pe(i)
936 point_ids => this%points_at_pe(rank)%array()
937 do j = 1, this%n_points_pe(rank)
938 ii = ii + 1
939 el_owner_results(ii) = this%el_owner0(point_ids(j))
940 end do
941 call mpi_isend(el_owner_results(this%n_points_offset_pe(rank) + 1),&
942 this%n_points_pe(rank), &
943 mpi_integer, rank, 0, &
944 this%comm, glb_intrp_find%send_buf(i)%request, ierr)
945 glb_intrp_find%send_buf(i)%flag = .false.
946 end do
947 do i = 1, size(glb_intrp_find%recv_pe)
948 rank = glb_intrp_find%recv_pe(i)
949 call mpi_irecv(this%el_owner0_local( &
950 this%n_points_offset_pe_local(rank) + 1), &
951 this%n_points_pe_local(rank), &
952 mpi_integer, rank, 0, &
953 this%comm, glb_intrp_find%recv_buf(i)%request, ierr)
954 glb_intrp_find%recv_buf(i)%flag = .false.
955 end do
956 call glb_intrp_find%nbwait_no_op()
957
958 call glb_intrp_find%free()
959
960 !Set up final way of doing communication
961 call send_pe%init()
962 call recv_pe%init()
963 call this%glb_intrp_comm%init_dofs(this%pe_size)
964 do i = 0, (this%pe_size-1)
965 if (this%n_points_pe(i) .gt. 0) then
966 call recv_pe%push(i)
967 point_ids => this%points_at_pe(i)%array()
968 do j = 1, this%n_points_pe(i)
969 call this%glb_intrp_comm%recv_dof(i)%push(point_ids(j))
970 end do
971 end if
972 if (this%n_points_pe_local(i) .gt. 0) then
973 call send_pe%push(i)
974 do j = 1, this%n_points_pe_local(i)
975 call this%glb_intrp_comm%send_dof(i)%push(j + &
976 this%n_points_offset_pe_local(i))
977 end do
978 end if
979 end do
980 call this%glb_intrp_comm%init(send_pe, recv_pe, this%comm)
981
982 !Initialize working arrays for evaluation
983 call this%temp_local%init(this%n_points_local)
984 call this%temp%init(this%n_points)
985
986 !Initialize interpolator for local interpolation
987 call this%local_interp%init(this%Xh, this%rst_local, &
988 this%n_points_local)
989
990
991 if (neko_bcknd_device .eq. 1) then
992 call device_memcpy(this%el_owner0, this%el_owner0_d, &
993 this%n_points, host_to_device, sync = .true.)
994 call device_map(this%el_owner0_local, this%el_owner0_local_d, &
995 this%n_points_local)
996 call device_memcpy(this%el_owner0_local, this%el_owner0_local_d, &
997 this%n_points_local, host_to_device, sync = .true.)
998 end if
999
1000 call this%check_points(this%x%x, this%y%x, this%z%x)
1001
1002 !Free stuff
1003 call send_pe%free()
1004 call recv_pe%free()
1005 call glb_intrp_find_back%free()
1006 call send_pe_find%free()
1007 call recv_pe_find%free()
1008 call x_t%free()
1009 call y_t%free()
1010 call z_t%free()
1011 call rst_local_cand%free()
1012 call resx%free()
1013 call resy%free()
1014 call resz%free()
1015 call res%free()
1016 call all_el_candidates%free()
1017
1018 if (allocated(n_el_cands)) deallocate(n_el_cands)
1019 if (allocated(rst_results)) deallocate(rst_results)
1020 if (allocated(res_results)) deallocate(res_results)
1021 if (allocated(el_owner_results)) deallocate(el_owner_results)
1022 call mpi_barrier(this%comm, ierr)
1023 time2 = mpi_wtime()
1024 write(log_buf, '(A,E15.7)') 'Global interpolation find points ' // &
1025 'done, time (s):', time2-time_start
1026 call neko_log%message(log_buf)
1027 call neko_log%end_section()
1028 call neko_log%newline()
1030
1034 subroutine global_interpolation_check_points(this, x, y, z)
1035 class(global_interpolation_t), target, intent(inout) :: this
1036 real(kind=rp), intent(inout) :: x(:)
1037 real(kind=rp), intent(inout) :: y(:)
1038 real(kind=rp), intent(inout) :: z(:)
1039 integer :: i, j
1040 character(len=8000) :: log_buf
1041 real(kind=rp) :: xdiff, ydiff, zdiff
1042 logical :: isdiff
1043 type(vector_t) :: x_check, y_check, z_check
1044
1045 call x_check%init(this%n_points)
1046 call y_check%init(this%n_points)
1047 call z_check%init(this%n_points)
1048 call this%evaluate(x_check%x, x, on_host = .true.)
1049 call this%evaluate(y_check%x, y, on_host = .true.)
1050 call this%evaluate(z_check%x, z, on_host = .true.)
1051 write(log_buf, '(A)') 'Checking validity of points.'
1052 call neko_log%message(log_buf)
1053 j = 0
1054 do i = 1 , this%n_points
1055 ! Check validity of points
1056 isdiff = .false.
1057 xdiff = x_check%x(i)-this%xyz(1,i)
1058 ydiff = y_check%x(i)-this%xyz(2,i)
1059 zdiff = z_check%x(i)-this%xyz(3,i)
1060 isdiff = norm2(real([xdiff, ydiff, zdiff], xp)) > this%tolerance
1061 if (isdiff) then
1062 write(*, *) 'Point ', i, 'at rank ', this%pe_rank, &
1063 'with coordinates: ', &
1064 this%xyz(1, i), this%xyz(2, i), this%xyz(3, i), &
1065 'Differ from interpolated coords: ', &
1066 x_check%x(i), y_check%x(i), z_check%x(i), &
1067 'Actual difference: ', &
1068 xdiff, ydiff, zdiff, norm2(real([xdiff, ydiff, zdiff], xp)), &
1069 'Process, element: ', &
1070 this%pe_owner(i), this%el_owner0(i)+1, &
1071 'Calculated rst: ', &
1072 this%rst(1,i), this%rst(2,i), this%rst(3,i)
1073 j = j + 1
1074 end if
1075 end do
1076 call x_check%free()
1077 call y_check%free()
1078 call z_check%free()
1079
1081
1089 subroutine global_interpolation_find_coords(this, x, y, z, n_points)
1090 class(global_interpolation_t), intent(inout) :: this
1091 integer :: n_points
1092 !!Perhaps this should be kind dp
1093 !!this is to get around that x,y,z often is 4 dimensional...
1094 !!Should maybe add interface for 1d aswell
1095 real(kind=rp) :: x(n_points,1,1,1)
1096 real(kind=rp) :: y(n_points,1,1,1)
1097 real(kind=rp) :: z(n_points,1,1,1)
1098 integer :: i
1099
1100 call this%free_points()
1101 call this%free_points_local()
1102
1103 this%n_points = n_points
1104
1106
1107 !Deepcopy of coordinates
1108 do i = 1, n_points
1109 this%xyz(1, i) = x(i,1,1,1)
1110 this%xyz(2, i) = y(i,1,1,1)
1111 this%xyz(3, i) = z(i,1,1,1)
1112 end do
1113
1115
1124 subroutine global_interpolation_find_coords1d(this, x, y, z, n_points)
1125 class(global_interpolation_t), intent(inout) :: this
1126 integer :: n_points
1127 real(kind=rp) :: x(n_points)
1128 real(kind=rp) :: y(n_points)
1129 real(kind=rp) :: z(n_points)
1130 integer :: i
1131
1132 call this%free_points()
1133 call this%free_points_local()
1134
1135 this%n_points = n_points
1136
1138
1139 !Deepcopy of coordinates
1140 do i = 1, n_points
1141 this%xyz(1, i) = x(i)
1142 this%xyz(2, i) = y(i)
1143 this%xyz(3, i) = z(i)
1144 end do
1145
1147
1149
1150
1152 class(global_interpolation_t) :: this
1153
1154 if (allocated(this%xyz)) deallocate(this%xyz)
1155 if (allocated(this%rst)) deallocate(this%rst)
1156 if (allocated(this%pe_owner)) deallocate(this%pe_owner)
1157 if (allocated(this%el_owner0)) deallocate(this%el_owner0)
1158
1159 allocate(this%pe_owner(this%n_points))
1160 allocate(this%el_owner0(this%n_points))
1161 allocate(this%xyz(3, this%n_points))
1162 allocate(this%rst(3, this%n_points))
1163 if (neko_bcknd_device .eq. 1) then
1164 call device_map(this%el_owner0, this%el_owner0_d, this%n_points)
1165 end if
1166
1168
1175 subroutine global_interpolation_find_xyz(this, xyz, n_points)
1176 class(global_interpolation_t), intent(inout) :: this
1177 integer, intent(in) :: n_points
1178 !!Perhaps this should be kind dp
1179 real(kind=rp), intent(inout) :: xyz(3, n_points)
1180
1181
1182 call this%free_points()
1183 call this%free_points_local()
1184
1185 this%n_points = n_points
1186
1188
1190 call copy(this%xyz, xyz, 3 * n_points)
1191
1193
1194 end subroutine global_interpolation_find_xyz
1195
1204 subroutine global_interpolation_find_and_redist(this, xyz, n_points)
1205 class(global_interpolation_t), intent(inout) :: this
1206 integer, intent(inout) :: n_points
1207 !!Perhaps this should be kind dp
1208 real(kind=rp), allocatable, intent(inout) :: xyz(:,:)
1209
1210
1211 call this%free_points()
1212 call this%free_points_local()
1213
1214
1215 this%n_points = n_points
1217
1219 call copy(this%xyz, xyz, 3 * n_points)
1220
1222 call this%free_points()
1223 this%n_points = this%n_points_local
1224 n_points = this%n_points_local
1226 if (allocated(xyz)) then
1227 deallocate(xyz)
1228 end if
1229 allocate(xyz(3, n_points))
1230
1231 call copy(xyz, this%xyz_local, 3*n_points)
1232 call copy(this%rst, this%rst_local, 3*n_points)
1233 call copy(this%xyz, this%xyz_local, 3*n_points)
1234 this%pe_owner = this%pe_rank
1235 this%el_owner0 = this%el_owner0_local
1236 if (neko_bcknd_device .eq. 1) then
1237 call device_memcpy(this%el_owner0, this%el_owner0_d, &
1238 this%n_points, host_to_device, sync = .true.)
1239 end if
1240 this%all_points_local = .true.
1241
1243
1247 subroutine global_interpolation_init_redist_comm(this, redist_comm)
1248 class(global_interpolation_t), intent(inout) :: this
1249 type(glb_intrp_comm_t), intent(inout) :: redist_comm
1250 type(stack_i4_t) :: send_pe
1251 type(stack_i4_t) :: recv_pe
1252 integer, pointer :: point_ids(:) => null()
1253 integer :: rank
1254 integer :: i
1255
1256 call send_pe%init()
1257 call recv_pe%init()
1258 call redist_comm%init_dofs(this%pe_size)
1259
1260 do rank = 0, this%pe_size - 1
1261 if (this%n_points_pe(rank) .gt. 0) then
1262 call send_pe%push(rank)
1263 point_ids => this%points_at_pe(rank)%array()
1264 do i = 1, this%n_points_pe(rank)
1265 call redist_comm%send_dof(rank)%push(point_ids(i))
1266 end do
1267 end if
1268 if (this%n_points_pe_local(rank) .gt. 0) then
1269 call recv_pe%push(rank)
1270 do i = 1, this%n_points_pe_local(rank)
1271 call redist_comm%recv_dof(rank)%push( &
1272 this%n_points_offset_pe_local(rank) + i)
1273 end do
1274 end if
1275 end do
1276
1277 call redist_comm%init(send_pe, recv_pe, this%comm)
1278 nullify(point_ids)
1279 call send_pe%free()
1280 call recv_pe%free()
1282
1289 subroutine global_interpolation_evaluate_masked(this, interp_values, &
1290 field, mask, on_host)
1291 class(global_interpolation_t), target, intent(inout) :: this
1292 real(kind=rp), intent(inout), target :: interp_values(this%n_points)
1293 real(kind=rp), intent(inout), target :: field(this%n_dof)
1294 type(mask_t), intent(in) :: mask
1295 logical, intent(in) :: on_host
1296
1297 call vector_masked_gather_copy(this%masked_field, field, mask, this%n_dof)
1298 call this%evaluate(interp_values, this%masked_field%x, on_host)
1299
1301
1306 subroutine global_interpolation_evaluate(this, interp_values, field, on_host)
1307 class(global_interpolation_t), target, intent(inout) :: this
1308 real(kind=rp), intent(inout), target :: interp_values(this%n_points)
1309 real(kind=rp), intent(inout), target :: field(this%nelv*this%Xh%lxyz)
1310 logical, intent(in) :: on_host
1311 type(c_ptr) :: interp_d
1312
1313 if (.not. this%all_points_local) then
1314 call this%local_interp%evaluate(this%temp_local%x, &
1315 this%el_owner0_local, field, this%nelv, on_host)
1316 if (neko_bcknd_device .eq. 1 .and. .not. on_host) then
1317 call device_memcpy(this%temp_local%x, this%temp_local%x_d, &
1318 this%n_points_local, device_to_host, .true.)
1319 end if
1320 interp_values = 0.0_rp
1321 call this%glb_intrp_comm%sendrecv(this%temp_local%x, interp_values, &
1322 this%n_points_local, this%n_points)
1323 if (neko_bcknd_device .eq. 1 .and. .not. on_host .and. &
1324 this%n_points .gt. 0) then
1325 interp_d = device_get_ptr(interp_values)
1326 call device_memcpy(interp_values, interp_d, &
1327 this%n_points, host_to_device, .false.)
1328 end if
1329 else
1330 call this%local_interp%evaluate(interp_values, this%el_owner0_local, &
1331 field, this%nelv, on_host)
1332 end if
1333
1334 end subroutine global_interpolation_evaluate
1335
1336
1347 function rst_cmp(rst1, rst2, res1, res2, tol) result(rst2_better)
1348 real(kind=rp) :: rst1(3), res1(3)
1349 real(kind=rp) :: rst2(3), res2(3)
1350 real(kind=dp) :: tol
1351 logical :: rst2_better
1352 !If rst1 is invalid and rst2 is valid, take rst2
1353 ! If both invalidl, take smallest residual
1354 if (abs(rst1(1)) .gt. 1.0_xp+tol .or. &
1355 abs(rst1(2)) .gt. 1.0_xp+tol .or. &
1356 abs(rst1(3)) .gt. 1.0_xp+tol) then
1357 if (abs(rst2(1)) .le. 1.0_xp+tol .and. &
1358 abs(rst2(2)) .le. 1.0_xp+tol .and. &
1359 abs(rst2(3)) .le. 1.0_xp+tol) then
1360 rst2_better = .true.
1361 else
1362 rst2_better = (norm2(real(res2, xp)) .lt. norm2(real(res1, xp)))
1363 end if
1364 else
1366 rst2_better = (norm2(real(res2, xp)) .lt. norm2(real(res1, xp)) .and. &
1367 abs(rst2(1)) .le. 1.0_xp+tol .and. &
1368 abs(rst2(2)) .le. 1.0_xp+tol .and. &
1369 abs(rst2(3)) .le. 1.0_xp+tol)
1370 end if
1371 end function rst_cmp
1372
1373end module global_interpolation
double real
Return the device pointer for an associated Fortran array.
Definition device.F90:113
Map a Fortran array to a device (allocate and associate)
Definition device.F90:83
Copy data between host and device (or device and device)
Definition device.F90:72
Unmap a Fortran array from a device (deassociate and free)
Definition device.F90:89
Implements aabb_pe_finder given a dofmap.
integer, parameter, public glob_map_size
Minimum number of total boxes in the aabb tree.
Implements cartesian_pe_finder given a dofmap.
Definition comm.F90:1
integer, public pe_size
MPI size of communicator.
Definition comm.F90:62
integer, public pe_rank
MPI rank.
Definition comm.F90:59
type(mpi_comm), public neko_comm
MPI communicator.
Definition comm.F90:46
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
Defines a mapping of the degrees of freedom.
Definition dofmap.f90:35
Defines a field.
Definition field.f90:34
Defines global interpolation communication Based on the MPI based gather-scatter kernel.
Implements global_interpolation given a dofmap.
subroutine global_interpolation_free(this)
Destructor.
subroutine global_interpolation_find_coords1d(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_init_json_dof(this, dof, params_subdict, comm, mask)
Initialize the global interpolation object on a dofmap.
subroutine global_interpolation_free_points(this)
Destructor for point arrays.
real(kind=dp), parameter, public glob_interp_tol
subroutine global_interpolation_init_point_arrays(this)
subroutine global_interpolation_init_redist_comm(this, redist_comm)
Build a communicator that redistributes point-wise payloads from the original point ordering to the l...
subroutine global_interpolation_evaluate(this, interp_values, field, on_host)
Evalute the interpolated value in the points given a field.
subroutine global_interpolation_free_points_local(this)
subroutine global_interpolation_init_dof(this, dof, comm, tol, pad, mask)
Initialize the global interpolation object on a dofmap.
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...
logical function rst_cmp(rst1, rst2, res1, res2, tol)
Compares two sets of rst coordinates and checks whether rst2 is better than rst1 given a tolerance re...
real(kind=dp), parameter, public glob_interp_pad
subroutine global_interpolation_init_xyz(this, x, y, z, gdim, nelv, xh, comm, tol, pad)
Initialize the global interpolation object on a set of coordinates.
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_init_json_xyz(this, x, y, z, gdim, nelv, xh, params_subdict, comm)
Initialize the global interpolation object on a set of coordinates, with configuration parameters giv...
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_check_points(this, x, y, z)
Check the points for validity This is used to check that the points are valid and that the interpolat...
subroutine global_interpolation_evaluate_masked(this, interp_values, field, mask, on_host)
Evaluate the interpolated value in a masked field.
Utilities for retrieving parameters from the case files.
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:92
integer, parameter, public log_size
Definition log.f90:46
Object for handling masks in Neko.
Definition mask.f90:34
Definition math.f90:60
subroutine, public copy(a, b, n)
Copy a vector .
Definition math.f90:295
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
Implements pe_finder given a dofmap.
Definition pe_finder.f90:35
Defines a function space.
Definition space.f90:34
Implements a dynamic stack ADT.
Definition stack.f90:49
Defines structs that are used... Dont know if we should keep it though.
Definition structs.f90:2
Utilities.
Definition utils.f90:35
subroutine, public vector_masked_gather_copy(a, b, mask, n)
Gather a vector to reduced contigous array .
Defines a vector.
Definition vector.f90:34
Implements global interpolation for arbitrary points in the domain.
Implements global interpolation for arbitrary points in the domain.
Implements global interpolation for arbitrary points in the domain.
Base type for element finder providing element candidates for a given point in the domain.
Definition el_finder.f90:43
Global interpolation communication method.
Implements the settings helper data container for global interpolation.
Implements global interpolation for arbitrary points in the domain.
Type to compute local element (rst) coordinates for a gives set points in physical (xyz) space on a S...
Interpolation on a set of points with known rst coordinates in elements local to this process....
Type for consistently handling masks in Neko. This type encapsulates the mask array and its associate...
Definition mask.f90:51
Implements global interpolation for arbitrary points in the domain.
Definition pe_finder.f90:44
The function space for the SEM solution fields.
Definition space.f90:64
Integer based stack.
Definition stack.f90:77
Pointer to array.
Definition structs.f90:14
#define max(a, b)
Definition tensor.cu:40