Neko 1.1.2
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
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
208 if (present(tol)) then
209 if (tol .gt. 0.0_rp) then
210 this%interpolation_settings%tolerance = tol
211 end if
212 end if
213
214 if (present(pad)) then
215 if (pad .gt. 0.0_rp) then
216 this%interpolation_settings%padding = pad
217 end if
218 end if
219
220 if (present(log)) then
221 this%log = log
222 end if
223
224 this%field_name = field_name
225 write (log_buf, '(A,A)') "Coupling overset interface for: ", &
226 trim(this%field_name)
227 call neko_log%message(log_buf)
228
229 call this%bc_s%init_from_components(coef, this%field_name)
230 call this%field_list%init(1)
231 call this%field_list%assign_to_field(1, this%bc_s%field_bc)
232
233 call this%x_dof%init(this%dof%size(), 'x')
234 call this%y_dof%init(this%dof%size(), 'y')
235 call this%z_dof%init(this%dof%size(), 'z')
236
237 if (neko_bcknd_device .eq. 1) then
238 call device_copy(this%x_dof%x_d, this%dof%x_d, this%dof%size())
239 call device_copy(this%y_dof%x_d, this%dof%y_d, this%dof%size())
240 call device_copy(this%z_dof%x_d, this%dof%z_d, this%dof%size())
241
242 call this%x_dof%copy_from(device_to_host, sync = .false.)
243 call this%y_dof%copy_from(device_to_host, sync = .false.)
244 call this%z_dof%copy_from(device_to_host, sync = .true.)
245 else
246 call copy(this%x_dof%x, this%dof%x, this%dof%size())
247 call copy(this%y_dof%x, this%dof%y, this%dof%size())
248 call copy(this%z_dof%x, this%dof%z, this%dof%size())
249 end if
250
252
254 subroutine overset_interface_free(this)
255 class(overset_interface_t), target, intent(inout) :: this
256
257 call this%bc_s%free()
258 call this%field_list%free()
259 call this%interface_dof%free()
260 call this%interface_field%free()
261
262 call this%x_dof%free()
263 call this%y_dof%free()
264 call this%z_dof%free()
265
266 call this%x_interface_dof%free()
267 call this%y_interface_dof%free()
268 call this%z_interface_dof%free()
269 call this%s_interface%free()
270 call this%s_interface_lag%free()
271
272 if (allocated(this%field_name)) then
273 deallocate(this%field_name)
274 end if
275
276 call this%interface_interpolator%free()
277
278 call this%interface_dof_mask%free()
279 call this%domain_element_mask%free()
280
281 call this%free_base()
282 end subroutine overset_interface_free
283
288 subroutine overset_interface_apply_scalar(this, x, n, time, strong)
289 class(overset_interface_t), intent(inout) :: this
290 integer, intent(in) :: n
291 real(kind=rp), intent(inout), dimension(n) :: x
292 type(time_state_t), intent(in), optional :: time
293 logical, intent(in), optional :: strong
294 logical :: strong_
295
296 if (present(strong)) then
297 strong_ = strong
298 else
299 strong_ = .true.
300 end if
301
302 if (strong_) then
303 !$omp single
304 if (.not. this%updated) then
305 call this%update(time)
306 this%updated = .true.
307 end if
308 !$omp end single
309
310 call masked_copy_0(x, this%bc_s%field_bc%x, this%msk, n, this%msk(0))
311 end if
312
313 end subroutine overset_interface_apply_scalar
314
319 subroutine overset_interface_apply_scalar_dev(this, x_d, time, strong, strm)
320 class(overset_interface_t), intent(inout), target :: this
321 type(c_ptr), intent(inout) :: x_d
322 type(time_state_t), intent(in), optional :: time
323 logical, intent(in), optional :: strong
324 type(c_ptr), intent(inout) :: strm
325 logical :: strong_
326
327 if (present(strong)) then
328 strong_ = strong
329 else
330 strong_ = .true.
331 end if
332
333 if (strong_) then
334 !$omp single
335 if (.not. this%updated) then
336 call this%update(time)
337 this%updated = .true.
338 end if
339 !$omp end single
340
341 if (this%msk(0) .gt. 0) then
342 call device_masked_copy_0(x_d, this%bc_s%field_bc%x_d, &
343 this%bc_s%msk_d, this%bc_s%dof%size(), this%msk(0), strm)
344 end if
345 end if
346
348
350 subroutine overset_interface_apply_vector(this, x, y, z, n, time, strong)
351 class(overset_interface_t), intent(inout) :: this
352 integer, intent(in) :: n
353 real(kind=rp), intent(inout), dimension(n) :: x
354 real(kind=rp), intent(inout), dimension(n) :: y
355 real(kind=rp), intent(inout), dimension(n) :: z
356 type(time_state_t), intent(in), optional :: time
357 logical, intent(in), optional :: strong
358
359 call neko_error("overset_interface cannot apply vector BCs.&
360 & Use overset_interface_vector instead!")
361
362 end subroutine overset_interface_apply_vector
363
365 subroutine overset_interface_apply_vector_dev(this, x_d, y_d, z_d, time, &
366 strong, strm)
367 class(overset_interface_t), intent(inout), target :: this
368 type(c_ptr), intent(inout) :: x_d
369 type(c_ptr), intent(inout) :: y_d
370 type(c_ptr), intent(inout) :: z_d
371 type(time_state_t), intent(in), optional :: time
372 logical, intent(in), optional :: strong
373 type(c_ptr), intent(inout) :: strm
374
375 call neko_error("overset_interface cannot apply vector BCs.&
376 & Use overset_interface_vector instead!")
377
379
381 subroutine overset_interface_finalize(this, only_facets)
382 class(overset_interface_t), target, intent(inout) :: this
383 logical, optional, intent(in) :: only_facets
384 logical :: only_facets_
385
386 if (present(only_facets)) then
387 only_facets_ = only_facets
388 else
389 only_facets_ = .false.
390 end if
391
392 call this%finalize_base(only_facets_)
393
394 call this%bc_s%mark_facets(this%marked_facet)
395 call this%bc_s%finalize(only_facets_)
396
397 call this%build_masks_()
398
399 call this%x_interface_dof%init(this%interface_dof_mask%size(), &
400 'x_interface')
401 call this%y_interface_dof%init(this%interface_dof_mask%size(), &
402 'y_interface')
403 call this%z_interface_dof%init(this%interface_dof_mask%size(), &
404 'z_interface')
405 call this%gather_interface_dofs_()
406
407 call this%setup_interpolator_()
408
409 call this%s_interface%init(this%interface_dof_mask%size(), 's_interface')
410
411 call this%interface_dof%init(3)
412 call this%interface_dof%assign_to_vector(1, this%x_interface_dof)
413 call this%interface_dof%assign_to_vector(2, this%y_interface_dof)
414 call this%interface_dof%assign_to_vector(3, this%z_interface_dof)
415
416 call this%interface_field%init(1)
417 call this%interface_field%assign_to_vector(1, this%s_interface)
418
419 call this%s_interface_lag%init(this%s_interface, this%iextm_order)
420
421 call mpi_allreduce(this%s_interface%size(), this%n_int_tot, 1, mpi_integer, &
422 mpi_sum, neko_global_comm)
423
424 end subroutine overset_interface_finalize
425
427 subroutine overset_interface_update(this, time)
428 class(overset_interface_t), intent(inout) :: this
429 type(time_state_t), intent(in) :: time
430 type(field_t), pointer :: s
431 type(iextm_time_scheme_t) :: time_scheme
432 integer :: nhist, ihist
433 real(kind=rp) :: iextm_coeffs(4)
434
436 call this%morph_interface(this%interface_dof, this%interface_field, &
437 this%interface_dof_mask, time, this%name, &
438 this%find_interface)
439
441 if (this%find_interface) then
442
443 ! sync
444 call this%x_interface_dof%copy_from(device_to_host, sync = .false.)
445 call this%y_interface_dof%copy_from(device_to_host, sync = .false.)
446 call this%z_interface_dof%copy_from(device_to_host, sync = .true.)
447
448 call this%interface_interpolator%find_points(this%x_interface_dof%x, &
449 this%y_interface_dof%x, this%z_interface_dof%x, &
450 this%x_interface_dof%size())
451 this%find_interface = .false.
452
453 end if
454
455 s => neko_registry%get_field(trim(this%field_name))
456
457 call this%interface_interpolator%evaluate_masked(this%s_interface%x, s%x, &
458 this%domain_element_mask, .false.)
459
460 if (this%log) then
461 call this%log_interface_error_(s)
462 end if
463
464 if (time%tstep .ne. this%last_tstep) then
465 this%last_tstep = time%tstep
466
467 call this%s_interface_lag%update()
468
469 nhist = min(time%tstep, this%iextm_order)
470 call time_scheme%compute_coeffs(iextm_coeffs, time%dtlag, nhist)
471
472 call vector_cmult2(this%s_interface, this%s_interface_lag%lv(1), &
473 iextm_coeffs(1))
474 do ihist = 2, nhist
475 call vector_add2s2(this%s_interface, this%s_interface_lag%lv(ihist), &
476 iextm_coeffs(ihist))
477 end do
478 end if
479
480 call vector_masked_scatter_copy(this%bc_s%field_bc%x(:,1,1,1), &
481 this%s_interface, this%interface_dof_mask, this%bc_s%dof%size())
482
483 nullify(s)
484
485 end subroutine overset_interface_update
486
488 subroutine log_interface_error_(this, s)
489 class(overset_interface_t), intent(inout) :: this
490 type(field_t), pointer, intent(in) :: s
491 real(kind=rp) :: s_int_norm
492 type(vector_t), pointer :: error
493 integer :: ind(1)
494 logical :: clear_scratch = .false.
495 character(len=256) :: log_buf
496
497 call neko_scratch_registry%request_vector(error, ind(1), this%s_interface%size(), &
498 clear_scratch)
499 call vector_masked_gather_copy(error, s%x(:,1,1,1), this%interface_dof_mask, &
500 this%dof%size())
501 call vector_add2s2(error, this%s_interface, -1.0_rp)
502 s_int_norm = sqrt(vector_glsc2(error, error)) / sqrt(real(this%n_int_tot, kind=rp))
503 call neko_scratch_registry%relinquish(ind)
504
505 write(log_buf, '(A12,A3,A10,1x,E15.7)') 'Interface BC', ' | ', &
506 'L2 Error: ', s_int_norm
507 call neko_log%message(log_buf)
508
509 end subroutine log_interface_error_
510
511 !===================
512 ! Helper subroutines
513 !===================
514
516 subroutine build_masks_(this)
517 class(overset_interface_t), intent(inout) :: this
518 type(mask_t) :: temp_mask
519 logical, allocatable :: found(:)
520 integer :: i, j, k, e, nelems
521 integer :: lx, ly, lz
522 integer :: nonlinear_idx(4), linear_idx
523 type(stack_i4_t) :: idx_stack
524
525 call this%interface_dof_mask%init(this%msk(1:this%msk(0)), this%msk(0))
526
527 lx = this%Xh%lx
528 ly = this%Xh%ly
529 lz = this%Xh%lz
530
531 allocate(found(this%msh%nelv))
532 found = .false.
533
534 do i = 1, this%msk(0)
535 linear_idx = this%msk(i)
536 nonlinear_idx = nonlinear_index(linear_idx, lx, ly, lz)
537 found(nonlinear_idx(4)) = .true.
538 end do
539
540 nelems = 0
541 call idx_stack%init()
542 do e = 1, this%msh%nelv
543 if (found(e)) then
544 nelems = nelems + 1
545 do k = 1, this%Xh%lz
546 do j = 1, this%Xh%ly
547 do i = 1, this%Xh%lx
548 linear_idx = linear_index(i, j, k, e, lx, ly, lz)
549 call idx_stack%push(linear_idx)
550 end do
551 end do
552 end do
553 end if
554 end do
555
556 deallocate(found)
557
558 call temp_mask%init(idx_stack%array(), idx_stack%size())
559 call idx_stack%free()
560
561 call this%domain_element_mask%invert_mask(temp_mask, this%dof%size())
562 call temp_mask%free()
563
564 end subroutine build_masks_
565
567 subroutine gather_interface_dofs_(this)
568 class(overset_interface_t), intent(inout) :: this
569
570 call vector_masked_gather_copy(this%x_interface_dof, this%dof%x(:,1,1,1), &
571 this%interface_dof_mask, this%dof%size())
572 call vector_masked_gather_copy(this%y_interface_dof, this%dof%y(:,1,1,1), &
573 this%interface_dof_mask, this%dof%size())
574 call vector_masked_gather_copy(this%z_interface_dof, this%dof%z(:,1,1,1), &
575 this%interface_dof_mask, this%dof%size())
576
577 call this%x_interface_dof%copy_from(device_to_host, sync = .false.)
578 call this%y_interface_dof%copy_from(device_to_host, sync = .false.)
579 call this%z_interface_dof%copy_from(device_to_host, sync = .true.)
580
581 end subroutine gather_interface_dofs_
582
584 subroutine setup_interpolator_(this)
585 class(overset_interface_t), intent(inout) :: this
586
587 call this%interface_interpolator%init(this%dof, &
589 tol = this%interpolation_settings%tolerance, &
590 pad = this%interpolation_settings%padding, &
591 mask = this%domain_element_mask)
592
593 call this%interface_interpolator%find_points(this%x_interface_dof%x, &
594 this%y_interface_dof%x, this%z_interface_dof%x, &
595 this%x_interface_dof%size())
596
597 end subroutine setup_interpolator_
598
599end 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
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:291
subroutine, public masked_copy_0(a, b, mask, n, n_mask)
Copy a masked vector .
Definition math.f90:312
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Defines overset interface scalar boundary conditions.
subroutine overset_interface_finalize(this, only_facets)
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:62
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:63
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...