Neko 1.99.5
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 if (.not. this%updated) then
304 call this%update(time)
305 this%updated = .true.
306 end if
307
308 call masked_copy_0(x, this%bc_s%field_bc%x, this%msk, n, this%msk(0))
309 end if
310
311 end subroutine overset_interface_apply_scalar
312
317 subroutine overset_interface_apply_scalar_dev(this, x_d, time, strong, strm)
318 class(overset_interface_t), intent(inout), target :: this
319 type(c_ptr), intent(inout) :: x_d
320 type(time_state_t), intent(in), optional :: time
321 logical, intent(in), optional :: strong
322 type(c_ptr), intent(inout) :: strm
323 logical :: strong_
324
325 if (present(strong)) then
326 strong_ = strong
327 else
328 strong_ = .true.
329 end if
330
331 if (strong_) then
332 if (.not. this%updated) then
333 call this%update(time)
334 this%updated = .true.
335 end if
336
337 if (this%msk(0) .gt. 0) then
338 call device_masked_copy_0(x_d, this%bc_s%field_bc%x_d, &
339 this%bc_s%msk_d, this%bc_s%dof%size(), this%msk(0), strm)
340 end if
341 end if
342
344
346 subroutine overset_interface_apply_vector(this, x, y, z, n, time, strong)
347 class(overset_interface_t), intent(inout) :: this
348 integer, intent(in) :: n
349 real(kind=rp), intent(inout), dimension(n) :: x
350 real(kind=rp), intent(inout), dimension(n) :: y
351 real(kind=rp), intent(inout), dimension(n) :: z
352 type(time_state_t), intent(in), optional :: time
353 logical, intent(in), optional :: strong
354
355 call neko_error("overset_interface cannot apply vector BCs.&
356 & Use overset_interface_vector instead!")
357
358 end subroutine overset_interface_apply_vector
359
361 subroutine overset_interface_apply_vector_dev(this, x_d, y_d, z_d, time, &
362 strong, strm)
363 class(overset_interface_t), intent(inout), target :: this
364 type(c_ptr), intent(inout) :: x_d
365 type(c_ptr), intent(inout) :: y_d
366 type(c_ptr), intent(inout) :: z_d
367 type(time_state_t), intent(in), optional :: time
368 logical, intent(in), optional :: strong
369 type(c_ptr), intent(inout) :: strm
370
371 call neko_error("overset_interface cannot apply vector BCs.&
372 & Use overset_interface_vector instead!")
373
375
377 subroutine overset_interface_finalize(this, only_facets)
378 class(overset_interface_t), target, intent(inout) :: this
379 logical, optional, intent(in) :: only_facets
380 logical :: only_facets_
381
382 if (present(only_facets)) then
383 only_facets_ = only_facets
384 else
385 only_facets_ = .false.
386 end if
387
388 call this%finalize_base(only_facets_)
389
390 call this%bc_s%mark_facets(this%marked_facet)
391 call this%bc_s%finalize(only_facets_)
392
393 call this%build_masks_()
394
395 call this%x_interface_dof%init(this%interface_dof_mask%size(), &
396 'x_interface')
397 call this%y_interface_dof%init(this%interface_dof_mask%size(), &
398 'y_interface')
399 call this%z_interface_dof%init(this%interface_dof_mask%size(), &
400 'z_interface')
401 call this%gather_interface_dofs_()
402
403 call this%setup_interpolator_()
404
405 call this%s_interface%init(this%interface_dof_mask%size(), 's_interface')
406
407 call this%interface_dof%init(3)
408 call this%interface_dof%assign_to_vector(1, this%x_interface_dof)
409 call this%interface_dof%assign_to_vector(2, this%y_interface_dof)
410 call this%interface_dof%assign_to_vector(3, this%z_interface_dof)
411
412 call this%interface_field%init(1)
413 call this%interface_field%assign_to_vector(1, this%s_interface)
414
415 call this%s_interface_lag%init(this%s_interface, this%iextm_order)
416
417 call mpi_allreduce(this%s_interface%size(), this%n_int_tot, 1, mpi_integer, &
418 mpi_sum, neko_global_comm)
419
420 end subroutine overset_interface_finalize
421
423 subroutine overset_interface_update(this, time)
424 class(overset_interface_t), intent(inout) :: this
425 type(time_state_t), intent(in) :: time
426 type(field_t), pointer :: s
427 type(iextm_time_scheme_t) :: time_scheme
428 integer :: nhist, ihist
429 real(kind=rp) :: iextm_coeffs(4)
430
432 call this%morph_interface(this%interface_dof, this%interface_field, &
433 this%interface_dof_mask, time, this%name, &
434 this%find_interface)
435
437 if (this%find_interface) then
438
439 ! sync
440 call this%x_interface_dof%copy_from(device_to_host, sync = .false.)
441 call this%y_interface_dof%copy_from(device_to_host, sync = .false.)
442 call this%z_interface_dof%copy_from(device_to_host, sync = .true.)
443
444 call this%interface_interpolator%find_points(this%x_interface_dof%x, &
445 this%y_interface_dof%x, this%z_interface_dof%x, &
446 this%x_interface_dof%size())
447 this%find_interface = .false.
448
449 end if
450
451 s => neko_registry%get_field(trim(this%field_name))
452
453 call this%interface_interpolator%evaluate_masked(this%s_interface%x, s%x, &
454 this%domain_element_mask, .false.)
455
456 if (this%log) then
457 call this%log_interface_error_(s)
458 end if
459
460 if (time%tstep .ne. this%last_tstep) then
461 this%last_tstep = time%tstep
462
463 call this%s_interface_lag%update()
464
465 nhist = min(time%tstep, this%iextm_order)
466 call time_scheme%compute_coeffs(iextm_coeffs, time%dtlag, nhist)
467
468 call vector_cmult2(this%s_interface, this%s_interface_lag%lv(1), &
469 iextm_coeffs(1))
470 do ihist = 2, nhist
471 call vector_add2s2(this%s_interface, this%s_interface_lag%lv(ihist), &
472 iextm_coeffs(ihist))
473 end do
474 end if
475
476 call vector_masked_scatter_copy(this%bc_s%field_bc%x(:,1,1,1), &
477 this%s_interface, this%interface_dof_mask, this%bc_s%dof%size())
478
479 nullify(s)
480
481 end subroutine overset_interface_update
482
484 subroutine log_interface_error_(this, s)
485 class(overset_interface_t), intent(inout) :: this
486 type(field_t), pointer, intent(in) :: s
487 real(kind=rp) :: s_int_norm
488 type(vector_t), pointer :: error
489 integer :: ind(1)
490 logical :: clear_scratch = .false.
491 character(len=256) :: log_buf
492
493 call neko_scratch_registry%request_vector(error, ind(1), this%s_interface%size(), &
494 clear_scratch)
495 call vector_masked_gather_copy(error, s%x(:,1,1,1), this%interface_dof_mask, &
496 this%dof%size())
497 call vector_add2s2(error, this%s_interface, -1.0_rp)
498 s_int_norm = sqrt(vector_glsc2(error, error)) / sqrt(real(this%n_int_tot, kind=rp))
499 call neko_scratch_registry%relinquish(ind)
500
501 write(log_buf, '(A12,A3,A10,1x,E15.7)') 'Interface BC', ' | ', &
502 'L2 Error: ', s_int_norm
503 call neko_log%message(log_buf)
504
505 end subroutine log_interface_error_
506
507 !===================
508 ! Helper subroutines
509 !===================
510
512 subroutine build_masks_(this)
513 class(overset_interface_t), intent(inout) :: this
514 type(mask_t) :: temp_mask
515 logical, allocatable :: found(:)
516 integer :: i, j, k, e, nelems
517 integer :: lx, ly, lz
518 integer :: nonlinear_idx(4), linear_idx
519 type(stack_i4_t) :: idx_stack
520
521 call this%interface_dof_mask%init(this%msk(1:this%msk(0)), this%msk(0))
522
523 lx = this%Xh%lx
524 ly = this%Xh%ly
525 lz = this%Xh%lz
526
527 allocate(found(this%msh%nelv))
528 found = .false.
529
530 do i = 1, this%msk(0)
531 linear_idx = this%msk(i)
532 nonlinear_idx = nonlinear_index(linear_idx, lx, ly, lz)
533 found(nonlinear_idx(4)) = .true.
534 end do
535
536 nelems = 0
537 call idx_stack%init()
538 do e = 1, this%msh%nelv
539 if (found(e)) then
540 nelems = nelems + 1
541 do k = 1, this%Xh%lz
542 do j = 1, this%Xh%ly
543 do i = 1, this%Xh%lx
544 linear_idx = linear_index(i, j, k, e, lx, ly, lz)
545 call idx_stack%push(linear_idx)
546 end do
547 end do
548 end do
549 end if
550 end do
551
552 deallocate(found)
553
554 call temp_mask%init(idx_stack%array(), idx_stack%size())
555 call idx_stack%free()
556
557 call this%domain_element_mask%invert_mask(temp_mask, this%dof%size())
558 call temp_mask%free()
559
560 end subroutine build_masks_
561
563 subroutine gather_interface_dofs_(this)
564 class(overset_interface_t), intent(inout) :: this
565
566 call vector_masked_gather_copy(this%x_interface_dof, this%dof%x(:,1,1,1), &
567 this%interface_dof_mask, this%dof%size())
568 call vector_masked_gather_copy(this%y_interface_dof, this%dof%y(:,1,1,1), &
569 this%interface_dof_mask, this%dof%size())
570 call vector_masked_gather_copy(this%z_interface_dof, this%dof%z(:,1,1,1), &
571 this%interface_dof_mask, this%dof%size())
572
573 call this%x_interface_dof%copy_from(device_to_host, sync = .false.)
574 call this%y_interface_dof%copy_from(device_to_host, sync = .false.)
575 call this%z_interface_dof%copy_from(device_to_host, sync = .true.)
576
577 end subroutine gather_interface_dofs_
578
580 subroutine setup_interpolator_(this)
581 class(overset_interface_t), intent(inout) :: this
582
583 call this%interface_interpolator%init(this%dof, &
585 tol = this%interpolation_settings%tolerance, &
586 pad = this%interpolation_settings%padding, &
587 mask = this%domain_element_mask)
588
589 call this%interface_interpolator%find_points(this%x_interface_dof%x, &
590 this%y_interface_dof%x, this%z_interface_dof%x, &
591 this%x_interface_dof%size())
592
593 end subroutine setup_interpolator_
594
595end 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:46
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:62
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...