Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
overset_interface.f90
Go to the documentation of this file.
1! Copyright (c) 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!
35 use comm, only : neko_global_comm
37 use registry, only : neko_registry
38 use num_types, only : rp
39 use coefs, only : coef_t
42 use mask, only : mask_t
43 use bc, only : bc_t, bc_dirichlet
44 use field_list, only : field_list_t
45 use math, only : masked_copy_0, copy
47 use vector, only : vector_t
49 use vector_list, only : vector_list_t
52 use device, only : device_to_host
56 use stack, only : stack_i4_t
57 use json_module, only : json_file
59 use field, only : field_t
60 use logger, only : neko_log, log_size
62 use mpi_f08, only : mpi_allreduce, mpi_integer, mpi_sum
63 use, intrinsic :: iso_c_binding, only : c_ptr
64 use time_state, only : time_state_t
65 implicit none
66 private
67
69 type, public, extends(bc_t) :: overset_interface_t
71 type(field_dirichlet_t) :: bc_s
75 character(len=:), allocatable :: field_name
77 type(global_interpolation_t) :: interface_interpolator
79 type(mask_t) :: interface_dof_mask
80 type(mask_t) :: domain_element_mask
82 type(vector_t) :: x_dof, y_dof, z_dof
83 type(vector_t) :: x_interface_dof, y_interface_dof, z_interface_dof
85 type(vector_t) :: s_interface
86 type(vector_series_t) :: s_interface_lag
87 integer :: iextm_order = 1
88 integer :: last_tstep = -1
89 type(vector_list_t) :: interface_dof, interface_field
91 type(global_interpolation_settings_t) :: interpolation_settings
92 integer :: n_int_tot = 0
93 logical :: find_interface = .false.
94 logical :: setup = .false.
95 logical :: log = .false.
96
99 procedure(morph_overset_interface), nopass, pointer :: &
100 morph_interface => null()
101
102 contains
104 procedure, pass(this) :: init => overset_interface_init
106 procedure, pass(this) :: init_from_components => &
109 procedure, pass(this) :: free => overset_interface_free
111 procedure, pass(this) :: finalize => overset_interface_finalize
113 procedure, pass(this) :: apply_scalar => overset_interface_apply_scalar
115 procedure, pass(this) :: apply_vector => overset_interface_apply_vector
117 procedure, pass(this) :: apply_vector_dev => &
120 procedure, pass(this) :: apply_scalar_dev => &
122 procedure, pass(this) :: update => overset_interface_update
123
125 procedure, pass(this), private :: build_masks_ => build_masks_
127 procedure, pass(this), private :: gather_interface_dofs_ => &
130 procedure, pass(this), private :: setup_interpolator_ => &
133 procedure, pass(this), private :: log_interface_error_ => &
135 end type overset_interface_t
136
137 abstract interface
138
153 subroutine morph_overset_interface(interface_dof, interface_field, &
154 interface_mask, time, bc_name, &
155 find_interface)
157 type(vector_list_t), intent(inout) :: interface_dof
158 type(vector_list_t), intent(inout) :: interface_field
159 type(mask_t), intent(in) :: interface_mask
160 type(time_state_t), intent(in) :: time
161 character(len=*), intent(in) :: bc_name
162 logical, intent(inout) :: find_interface
163 end subroutine morph_overset_interface
164 end interface
165
167
168contains
169
173 subroutine overset_interface_init(this, coef, json)
174 class(overset_interface_t), intent(inout), target :: this
175 type(coef_t), target, intent(in) :: coef
176 type(json_file), intent(inout) :: json
177 character(len=:), allocatable :: field_name
178 real(kind=rp) :: tol, pad
179 logical :: log
180
181 call json_get(json, "field_name", field_name)
182 call json_get_or_default(json, "interpolation.tolerance", tol, -1.0_rp)
183 call json_get_or_default(json, "interpolation.padding", pad, -1.0_rp)
184 call json_get_or_default(json, "order", this%iextm_order, 1)
185 if (this%iextm_order .lt. 1 .or. this%iextm_order .gt. 3) then
186 call neko_error("The order of the IEXTm time scheme must be 1 to 3.")
187 end if
188 call json_get_or_default(json, "log", log, .false.)
189
190 call this%init_from_components(coef, field_name, tol, pad, log)
191 if (allocated(field_name)) deallocate(field_name)
192
193 end subroutine overset_interface_init
194
197 subroutine overset_interface_init_from_components(this, coef, field_name, &
198 tol, pad, log)
199 class(overset_interface_t), intent(inout), target :: this
200 type(coef_t), intent(in) :: coef
201 character(len=*), intent(in) :: field_name
202 real(kind=rp), intent(in), optional :: tol, pad
203 logical, intent(in), optional :: log
204 character(len=256) :: log_buf
205
206 call this%init_base(coef)
207 this%bc_type = bc_dirichlet
208
209 if (present(tol)) then
210 if (tol .gt. 0.0_rp) then
211 this%interpolation_settings%tolerance = tol
212 end if
213 end if
214
215 if (present(pad)) then
216 if (pad .gt. 0.0_rp) then
217 this%interpolation_settings%padding = pad
218 end if
219 end if
220
221 if (present(log)) then
222 this%log = log
223 end if
224
225 this%field_name = field_name
226 write (log_buf, '(A,A)') "Coupling overset interface for: ", &
227 trim(this%field_name)
228 call neko_log%message(log_buf)
229
230 call this%bc_s%init_from_components(coef, this%field_name)
231 call this%field_list%init(1)
232 call this%field_list%assign_to_field(1, this%bc_s%field_bc)
233
234 call this%x_dof%init(this%dof%size(), 'x')
235 call this%y_dof%init(this%dof%size(), 'y')
236 call this%z_dof%init(this%dof%size(), 'z')
237
238 if (neko_bcknd_device .eq. 1) then
239 call device_copy(this%x_dof%x_d, this%dof%x_d, this%dof%size())
240 call device_copy(this%y_dof%x_d, this%dof%y_d, this%dof%size())
241 call device_copy(this%z_dof%x_d, this%dof%z_d, this%dof%size())
242
243 call this%x_dof%copy_from(device_to_host, sync = .false.)
244 call this%y_dof%copy_from(device_to_host, sync = .false.)
245 call this%z_dof%copy_from(device_to_host, sync = .true.)
246 else
247 call copy(this%x_dof%x, this%dof%x, this%dof%size())
248 call copy(this%y_dof%x, this%dof%y, this%dof%size())
249 call copy(this%z_dof%x, this%dof%z, this%dof%size())
250 end if
251
253
255 subroutine overset_interface_free(this)
256 class(overset_interface_t), target, intent(inout) :: this
257
258 call this%bc_s%free()
259 call this%field_list%free()
260 call this%interface_dof%free()
261 call this%interface_field%free()
262
263 call this%x_dof%free()
264 call this%y_dof%free()
265 call this%z_dof%free()
266
267 call this%x_interface_dof%free()
268 call this%y_interface_dof%free()
269 call this%z_interface_dof%free()
270 call this%s_interface%free()
271 call this%s_interface_lag%free()
272
273 if (allocated(this%field_name)) then
274 deallocate(this%field_name)
275 end if
276
277 call this%interface_interpolator%free()
278
279 call this%interface_dof_mask%free()
280 call this%domain_element_mask%free()
281
282 call this%free_base()
283 end subroutine overset_interface_free
284
289 subroutine overset_interface_apply_scalar(this, x, n, time, strong)
290 class(overset_interface_t), intent(inout) :: this
291 integer, intent(in) :: n
292 real(kind=rp), intent(inout), dimension(n) :: x
293 type(time_state_t), intent(in), optional :: time
294 logical, intent(in), optional :: strong
295 logical :: strong_
296
297 if (present(strong)) then
298 strong_ = strong
299 else
300 strong_ = .true.
301 end if
302
303 if (strong_) then
304 if (.not. this%updated) then
305 call this%update(time)
306 this%updated = .true.
307 end if
308
309 call masked_copy_0(x, this%bc_s%field_bc%x, this%msk, n, this%msk(0))
310 end if
311
312 end subroutine overset_interface_apply_scalar
313
318 subroutine overset_interface_apply_scalar_dev(this, x_d, time, strong, strm)
319 class(overset_interface_t), intent(inout), target :: this
320 type(c_ptr), intent(inout) :: x_d
321 type(time_state_t), intent(in), optional :: time
322 logical, intent(in), optional :: strong
323 type(c_ptr), intent(inout) :: strm
324 logical :: strong_
325
326 if (present(strong)) then
327 strong_ = strong
328 else
329 strong_ = .true.
330 end if
331
332 if (strong_) then
333 if (.not. this%updated) then
334 call this%update(time)
335 this%updated = .true.
336 end if
337
338 if (this%msk(0) .gt. 0) then
339 call device_masked_copy_0(x_d, this%bc_s%field_bc%x_d, &
340 this%bc_s%msk_d, this%bc_s%dof%size(), this%msk(0), strm)
341 end if
342 end if
343
345
347 subroutine overset_interface_apply_vector(this, x, y, z, n, time, strong)
348 class(overset_interface_t), intent(inout) :: this
349 integer, intent(in) :: n
350 real(kind=rp), intent(inout), dimension(n) :: x
351 real(kind=rp), intent(inout), dimension(n) :: y
352 real(kind=rp), intent(inout), dimension(n) :: z
353 type(time_state_t), intent(in), optional :: time
354 logical, intent(in), optional :: strong
355
356 call neko_error("overset_interface cannot apply vector BCs.&
357 & Use overset_interface_vector instead!")
358
359 end subroutine overset_interface_apply_vector
360
362 subroutine overset_interface_apply_vector_dev(this, x_d, y_d, z_d, time, &
363 strong, strm)
364 class(overset_interface_t), intent(inout), target :: this
365 type(c_ptr), intent(inout) :: x_d
366 type(c_ptr), intent(inout) :: y_d
367 type(c_ptr), intent(inout) :: z_d
368 type(time_state_t), intent(in), optional :: time
369 logical, intent(in), optional :: strong
370 type(c_ptr), intent(inout) :: strm
371
372 call neko_error("overset_interface cannot apply vector BCs.&
373 & Use overset_interface_vector instead!")
374
376
379 class(overset_interface_t), target, intent(inout) :: this
380
381 call this%finalize_base()
382
383 call this%bc_s%mark_facets(this%marked_facet)
384 call this%bc_s%finalize()
385
386 call this%build_masks_()
387
388 call this%x_interface_dof%init(this%interface_dof_mask%size(), &
389 'x_interface')
390 call this%y_interface_dof%init(this%interface_dof_mask%size(), &
391 'y_interface')
392 call this%z_interface_dof%init(this%interface_dof_mask%size(), &
393 'z_interface')
394 call this%gather_interface_dofs_()
395
396 call this%setup_interpolator_()
397
398 call this%s_interface%init(this%interface_dof_mask%size(), 's_interface')
399
400 call this%interface_dof%init(3)
401 call this%interface_dof%assign_to_vector(1, this%x_interface_dof)
402 call this%interface_dof%assign_to_vector(2, this%y_interface_dof)
403 call this%interface_dof%assign_to_vector(3, this%z_interface_dof)
404
405 call this%interface_field%init(1)
406 call this%interface_field%assign_to_vector(1, this%s_interface)
407
408 call this%s_interface_lag%init(this%s_interface, this%iextm_order)
409
410 call mpi_allreduce(this%s_interface%size(), this%n_int_tot, 1, mpi_integer, &
411 mpi_sum, neko_global_comm)
412
413 end subroutine overset_interface_finalize
414
416 subroutine overset_interface_update(this, time)
417 class(overset_interface_t), intent(inout) :: this
418 type(time_state_t), intent(in) :: time
419 type(field_t), pointer :: s
420 type(iextm_time_scheme_t) :: time_scheme
421 integer :: nhist, ihist
422 real(kind=rp) :: iextm_coeffs(4)
423
425 call this%morph_interface(this%interface_dof, this%interface_field, &
426 this%interface_dof_mask, time, this%name, &
427 this%find_interface)
428
430 if (this%find_interface) then
431
432 ! sync
433 call this%x_interface_dof%copy_from(device_to_host, sync = .false.)
434 call this%y_interface_dof%copy_from(device_to_host, sync = .false.)
435 call this%z_interface_dof%copy_from(device_to_host, sync = .true.)
436
437 call this%interface_interpolator%find_points(this%x_interface_dof%x, &
438 this%y_interface_dof%x, this%z_interface_dof%x, &
439 this%x_interface_dof%size())
440 this%find_interface = .false.
441
442 end if
443
444 s => neko_registry%get_field(trim(this%field_name))
445
446 call this%interface_interpolator%evaluate_masked(this%s_interface%x, s%x, &
447 this%domain_element_mask, .false.)
448
449 if (this%log) then
450 call this%log_interface_error_(s)
451 end if
452
453 if (time%tstep .ne. this%last_tstep) then
454 this%last_tstep = time%tstep
455
456 call this%s_interface_lag%update()
457
458 nhist = min(time%tstep, this%iextm_order)
459 call time_scheme%compute_coeffs(iextm_coeffs, &
460 real(time%dtlag, kind=rp), nhist)
461
462 call vector_cmult2(this%s_interface, this%s_interface_lag%lv(1), &
463 iextm_coeffs(1))
464 do ihist = 2, nhist
465 call vector_add2s2(this%s_interface, this%s_interface_lag%lv(ihist), &
466 iextm_coeffs(ihist))
467 end do
468 end if
469
470 call vector_masked_scatter_copy(this%bc_s%field_bc%x(:,1,1,1), &
471 this%s_interface, this%interface_dof_mask, this%bc_s%dof%size())
472
473 nullify(s)
474
475 end subroutine overset_interface_update
476
478 subroutine log_interface_error_(this, s)
479 class(overset_interface_t), intent(inout) :: this
480 type(field_t), pointer, intent(in) :: s
481 real(kind=rp) :: s_int_norm
482 type(vector_t), pointer :: error
483 integer :: ind(1)
484 logical :: clear_scratch = .false.
485 character(len=256) :: log_buf
486
487 call neko_scratch_registry%request_vector(error, ind(1), this%s_interface%size(), &
488 clear_scratch)
489 call vector_masked_gather_copy(error, s%x(:,1,1,1), this%interface_dof_mask, &
490 this%dof%size())
491 call vector_add2s2(error, this%s_interface, -1.0_rp)
492 s_int_norm = sqrt(vector_glsc2(error, error)) / sqrt(real(this%n_int_tot, kind=rp))
493 call neko_scratch_registry%relinquish(ind)
494
495 write(log_buf, '(A12,A3,A10,1x,E15.7)') 'Interface BC', ' | ', &
496 'L2 Error: ', s_int_norm
497 call neko_log%message(log_buf)
498
499 end subroutine log_interface_error_
500
501 !===================
502 ! Helper subroutines
503 !===================
504
506 subroutine build_masks_(this)
507 class(overset_interface_t), intent(inout) :: this
508 type(mask_t) :: temp_mask
509 logical, allocatable :: found(:)
510 integer :: i, j, k, e, nelems
511 integer :: lx, ly, lz
512 integer :: nonlinear_idx(4), linear_idx
513 type(stack_i4_t) :: idx_stack
514
515 call this%interface_dof_mask%init(this%msk(1:this%msk(0)), this%msk(0))
516
517 lx = this%Xh%lx
518 ly = this%Xh%ly
519 lz = this%Xh%lz
520
521 allocate(found(this%msh%nelv))
522 found = .false.
523
524 do i = 1, this%msk(0)
525 linear_idx = this%msk(i)
526 nonlinear_idx = nonlinear_index(linear_idx, lx, ly, lz)
527 found(nonlinear_idx(4)) = .true.
528 end do
529
530 nelems = 0
531 call idx_stack%init()
532 do e = 1, this%msh%nelv
533 if (found(e)) then
534 nelems = nelems + 1
535 do k = 1, this%Xh%lz
536 do j = 1, this%Xh%ly
537 do i = 1, this%Xh%lx
538 linear_idx = linear_index(i, j, k, e, lx, ly, lz)
539 call idx_stack%push(linear_idx)
540 end do
541 end do
542 end do
543 end if
544 end do
545
546 deallocate(found)
547
548 call temp_mask%init(idx_stack%array(), idx_stack%size())
549 call idx_stack%free()
550
551 call this%domain_element_mask%invert_mask(temp_mask, this%dof%size())
552 call temp_mask%free()
553
554 end subroutine build_masks_
555
557 subroutine gather_interface_dofs_(this)
558 class(overset_interface_t), intent(inout) :: this
559
560 call vector_masked_gather_copy(this%x_interface_dof, this%dof%x(:,1,1,1), &
561 this%interface_dof_mask, this%dof%size())
562 call vector_masked_gather_copy(this%y_interface_dof, this%dof%y(:,1,1,1), &
563 this%interface_dof_mask, this%dof%size())
564 call vector_masked_gather_copy(this%z_interface_dof, this%dof%z(:,1,1,1), &
565 this%interface_dof_mask, this%dof%size())
566
567 call this%x_interface_dof%copy_from(device_to_host, sync = .false.)
568 call this%y_interface_dof%copy_from(device_to_host, sync = .false.)
569 call this%z_interface_dof%copy_from(device_to_host, sync = .true.)
570
571 end subroutine gather_interface_dofs_
572
574 subroutine setup_interpolator_(this)
575 class(overset_interface_t), intent(inout) :: this
576
577 call this%interface_interpolator%init(this%dof, &
579 tol = this%interpolation_settings%tolerance, &
580 pad = this%interpolation_settings%padding, &
581 mask = this%domain_element_mask)
582
583 call this%interface_interpolator%find_points(this%x_interface_dof%x, &
584 this%y_interface_dof%x, this%z_interface_dof%x, &
585 this%x_interface_dof%size())
586
587 end subroutine setup_interpolator_
588
589end module overset_interface
__inline__ __device__ void nonlinear_index(const int idx, const int lx, int *index)
Definition bc_utils.h:44
double real
Retrieves a parameter by name or assigns a provided default value. In the latter case also adds the m...
Retrieves a parameter by name or throws an error.
User callback for overset-interface morphing and boundary-value updates.
Defines a boundary condition.
Definition bc.f90:34
integer, parameter, public bc_dirichlet
Supported boundary condition types. The values are set in order of precedence for global resolution....
Definition bc.f90:66
Coefficients.
Definition coef.f90:34
Definition comm.F90:1
type(mpi_comm), public neko_global_comm
Definition comm.F90:47
subroutine, public device_copy(a_d, b_d, n, strm)
Copy a vector .
subroutine, public device_masked_copy_0(a_d, b_d, mask_d, n, n_mask, strm)
Copy a masked vector .
Device abstraction, common interface for various accelerators.
Definition device.F90:34
integer, parameter, public device_to_host
Definition device.F90:48
Defines user dirichlet condition for a scalar field.
Defines a field.
Definition field.f90:34
Implements global_interpolation given a dofmap.
Utilities for retrieving parameters from the case files.
Logging routines.
Definition log.f90:34
type(log_t), public neko_log
Global log stream.
Definition log.f90:80
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:294
subroutine, public masked_copy_0(a, b, mask, n, n_mask)
Copy a masked vector .
Definition math.f90:315
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
Defines overset interface scalar boundary conditions.
subroutine overset_interface_finalize(this)
Finalize by building the mask arrays and preparing interpolation data.
subroutine overset_interface_update(this, time)
Update values at the overset interface.
subroutine overset_interface_apply_scalar(this, x, n, time, strong)
Apply scalar.
subroutine gather_interface_dofs_(this)
Gather interface dofs.
subroutine overset_interface_apply_vector(this, x, y, z, n, time, strong)
(No-op) Apply vector.
subroutine overset_interface_free(this)
Destructor.
subroutine overset_interface_apply_scalar_dev(this, x_d, time, strong, strm)
Apply scalar (device).
subroutine log_interface_error_(this, s)
Log interface RMSE for the scalar field.
subroutine overset_interface_init(this, coef, json)
Constructor.
subroutine setup_interpolator_(this)
Set up the global interpolator.
subroutine build_masks_(this)
Build masks.
subroutine overset_interface_apply_vector_dev(this, x_d, y_d, z_d, time, strong, strm)
(No-op) Apply vector (device).
subroutine overset_interface_init_from_components(this, coef, field_name, tol, pad, log)
Constructor from components.
Defines a registry for storing solution fields.
Definition registry.f90:34
type(registry_t), target, public neko_registry
Global field registry.
Definition registry.f90:144
Defines a registry for storing and requesting temporary objects This can be used when you have a func...
type(scratch_registry_t), target, public neko_scratch_registry
Global scratch registry.
Implements a dynamic stack ADT.
Definition stack.f90:49
Base class for time integration schemes.
Module with things related to the simulation time.
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:289
subroutine, public vector_masked_gather_copy(a, b, mask, n)
Gather a vector to reduced contigous array .
real(kind=rp) function, public vector_glsc2(a, b, n)
subroutine, public vector_add2s2(a, b, c1, n)
Vector addition with scalar multiplication (multiplication on second argument)
subroutine, public vector_masked_scatter_copy(a, b, mask, n)
Scatter a contiguous vector into an array .
subroutine, public vector_cmult2(a, b, c, n)
Multiplication by constant c .
Contains the vector_series_t type.
Defines a vector.
Definition vector.f90:34
Base type for a boundary condition.
Definition bc.f90:72
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:93
User defined dirichlet condition, for which the user can work with an entire field....
field_list_t, To be able to group fields together
Implements the settings helper data container for global interpolation.
Implements global interpolation for arbitrary points in the domain.
Explicit interface extrapolation scheme for overset grids.
Type for consistently handling masks in Neko. This type encapsulates the mask array and its associate...
Definition mask.f90:51
Overset interface BC for a scalar field.
Integer based stack.
Definition stack.f90:77
A struct that contains all info about the time, expand as needed.
vector_list_t, To be able to group vectors together
Stores a series (sequence) of vectors, logically connected to a base vector, and arranged according t...