Neko 1.99.7
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
bc.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!
34module bc
36 use num_types, only : rp
37 use device, only : host_to_device, device_memcpy, &
39 use iso_c_binding, only : c_associated
40 use dofmap, only : dofmap_t
41 use coefs, only : coef_t
42 use space, only : space_t
44 use facet_zone, only : facet_zone_t
45 use stack, only : stack_i4t2_t
46 use tuple, only : tuple_i4_t
47 use field, only : field_t
48 use gs_ops, only : gs_op_add
49 use math, only : relcmp
51 use logger, only : neko_log, log_size
52 use, intrinsic :: iso_c_binding, only : c_ptr, c_null_ptr
53 use json_module, only : json_file
54 use time_state, only : time_state_t
55 use field, only : field_t
56 use file, only : file_t
57
58 implicit none
59 private
60
62 type, public, abstract :: bc_t
64 integer, allocatable :: msk(:)
66 integer, allocatable :: facet(:)
68 type(dofmap_t), pointer :: dof => null()
70 type(coef_t), pointer :: coef => null()
72 type(mesh_t), pointer :: msh => null()
74 type(space_t), pointer :: xh => null()
76 type(stack_i4t2_t) :: marked_facet
78 type(c_ptr) :: msk_d = c_null_ptr
80 type(c_ptr) :: facet_d = c_null_ptr
85 logical :: strong = .true.
88 logical :: updated = .false.
89 !!> Name of the bc
90 character(len=:), allocatable :: name
91 !!> Zone indices where the bc is applied
92 integer, allocatable :: zone_indices(:)
93 contains
95 procedure, pass(this) :: init_base => bc_init_base
97 procedure, pass(this) :: free_base => bc_free_base
99 procedure, pass(this) :: mark_facet => bc_mark_facet
101 procedure, pass(this) :: mark_facets => bc_mark_facets
103 procedure, pass(this) :: mark_zone => bc_mark_zone
106 procedure, pass(this) :: finalize_base => bc_finalize_base
107
110 procedure, pass(this) :: apply_scalar_generic => bc_apply_scalar_generic
113 procedure, pass(this) :: apply_vector_generic => bc_apply_vector_generic
115 procedure, pass(this) :: debug_mask_ => bc_debug_mask
117 procedure(bc_apply_scalar), pass(this), deferred :: apply_scalar
119 procedure(bc_apply_vector), pass(this), deferred :: apply_vector
121 procedure(bc_apply_scalar_dev), pass(this), deferred :: apply_scalar_dev
123 procedure(bc_apply_vector_dev), pass(this), deferred :: apply_vector_dev
125 procedure(bc_destructor), pass(this), deferred :: free
127 procedure(bc_constructor), pass(this), deferred :: init
129 procedure(bc_finalize), pass(this), deferred :: finalize
130 end type bc_t
131
133 type, public :: bc_ptr_t
134 class(bc_t), pointer :: ptr => null()
135 end type bc_ptr_t
136
137 ! Helper type to have an array of polymorphic bc_t objects.
138 type, public :: bc_alloc_t
139 class(bc_t), allocatable :: obj
140 end type bc_alloc_t
141
142
143 abstract interface
144
145 subroutine bc_constructor(this, coef, json)
146 import :: bc_t, coef_t, json_file
147 class(bc_t), intent(inout), target :: this
148 type(coef_t), target, intent(in) :: coef
149 type(json_file), intent(inout) :: json
150 end subroutine bc_constructor
151 end interface
152
153 abstract interface
154
155 subroutine bc_destructor(this)
156 import :: bc_t
157 class(bc_t), intent(inout), target :: this
158 end subroutine bc_destructor
159 end interface
160
161 abstract interface
162
163 subroutine bc_finalize(this, only_facets)
164 import :: bc_t
165 class(bc_t), intent(inout), target :: this
166 logical, optional, intent(in) :: only_facets
167 end subroutine bc_finalize
168 end interface
169
170 abstract interface
171
176 subroutine bc_apply_scalar(this, x, n, time, strong)
177 import :: bc_t, time_state_t
178 import :: rp
179 class(bc_t), intent(inout) :: this
180 integer, intent(in) :: n
181 real(kind=rp), intent(inout), dimension(n) :: x
182 type(time_state_t), intent(in), optional :: time
183 logical, intent(in), optional :: strong
184 end subroutine bc_apply_scalar
185 end interface
186
187 abstract interface
188
196 subroutine bc_apply_vector(this, x, y, z, n, time, strong)
197 import :: bc_t, time_state_t
198 import :: rp
199 class(bc_t), intent(inout) :: this
200 integer, intent(in) :: n
201 real(kind=rp), intent(inout), dimension(n) :: x
202 real(kind=rp), intent(inout), dimension(n) :: y
203 real(kind=rp), intent(inout), dimension(n) :: z
204 type(time_state_t), intent(in), optional :: time
205 logical, intent(in), optional :: strong
206 end subroutine bc_apply_vector
207 end interface
208
209 abstract interface
210
215 subroutine bc_apply_scalar_dev(this, x_d, time, strong, strm)
216 import :: c_ptr
217 import :: bc_t, time_state_t
218 import :: rp
219 class(bc_t), intent(inout), target :: this
220 type(c_ptr), intent(inout) :: x_d
221 type(time_state_t), intent(in), optional :: time
222 logical, intent(in), optional :: strong
223 type(c_ptr), intent(inout) :: strm
224 end subroutine bc_apply_scalar_dev
225 end interface
226
227 abstract interface
228
235 subroutine bc_apply_vector_dev(this, x_d, y_d, z_d, time, strong, strm)
236 import :: c_ptr, bc_t, time_state_t
237 import :: rp
238 class(bc_t), intent(inout), target :: this
239 type(c_ptr), intent(inout) :: x_d
240 type(c_ptr), intent(inout) :: y_d
241 type(c_ptr), intent(inout) :: z_d
242 type(time_state_t), intent(in), optional :: time
243 logical, intent(in), optional :: strong
244 type(c_ptr), intent(inout) :: strm
245 end subroutine bc_apply_vector_dev
246 end interface
247
248contains
249
252 subroutine bc_init_base(this, coef)
253 class(bc_t), intent(inout) :: this
254 type(coef_t), target, intent(in) :: coef
255
256 call this%free_base
257
258 this%dof => coef%dof
259 this%coef => coef
260 this%Xh => this%dof%Xh
261 this%msh => this%dof%msh
262
263 call this%marked_facet%init()
264
265 end subroutine bc_init_base
266
268 subroutine bc_free_base(this)
269 class(bc_t), intent(inout) :: this
270
271 call this%marked_facet%free()
272
273 nullify(this%Xh)
274 nullify(this%msh)
275 nullify(this%dof)
276 nullify(this%coef)
277
278 if (allocated(this%msk)) then
279 if (neko_bcknd_device .eq. 1) then
280 call device_unmap(this%msk, this%msk_d)
281 end if
282 deallocate(this%msk)
283 end if
284
285 if (allocated(this%facet)) then
286 if (neko_bcknd_device .eq. 1) then
287 call device_unmap(this%facet, this%facet_d)
288 end if
289 deallocate(this%facet)
290 end if
291
292 if (allocated(this%name)) then
293 deallocate(this%name)
294 end if
295
296 if (allocated(this%zone_indices)) then
297 deallocate(this%zone_indices)
298 end if
299
300 ! Back to the state of a freshly declared bc, so that a condition which is
301 ! reinitialised does not inherit an `updated` from its previous life and
302 ! skip its first update.
303 this%updated = .false.
304
305 end subroutine bc_free_base
306
315 subroutine bc_apply_vector_generic(this, x, y, z, time, strong, strm)
316 class(bc_t), intent(inout) :: this
317 type(field_t), intent(inout) :: x
318 type(field_t), intent(inout) :: y
319 type(field_t), intent(inout) :: z
320 type(time_state_t), intent(in), optional :: time
321 logical, intent(in), optional :: strong
322 type(c_ptr), intent(inout), optional :: strm
323 type(c_ptr) :: strm_
324 integer :: n
325 character(len=256) :: msg
326
327 ! Get the size of the fields
328 n = x%size()
329
330 ! Ensure all fields are the same size
331 if (y%size() .ne. n .or. z%size() .ne. n) then
332 msg = "Fields x, y, z must have the same size in " // &
333 "bc_list_apply_vector_field"
334 call neko_error(trim(msg))
335 end if
336
337 if (neko_bcknd_device .eq. 1) then
338
339 if (present(strm)) then
340 strm_ = strm
341 else
342 strm_ = glb_cmd_queue
343 end if
344
345 call this%apply_vector_dev(x%x_d, y%x_d, z%x_d, time = time, &
346 strong = strong, strm = strm_)
347 else
348 call this%apply_vector(x%x, y%x, z%x, n, time = time, strong = strong)
349 end if
350
351 end subroutine bc_apply_vector_generic
352
359 subroutine bc_apply_scalar_generic(this, x, time, strong, strm)
360 class(bc_t), intent(inout) :: this
361 type(field_t), intent(inout) :: x
362 type(time_state_t), intent(in), optional :: time
363 logical, intent(in), optional :: strong
364 type(c_ptr), intent(inout), optional :: strm
365 type(c_ptr) :: strm_
366 integer :: n
367
368 ! Get the size of the field
369 n = x%size()
370
371 if (neko_bcknd_device .eq. 1) then
372
373 if (present(strm)) then
374 strm_ = strm
375 else
376 strm_ = glb_cmd_queue
377 end if
378
379 call this%apply_scalar_dev(x%x_d, time = time, strong = strong, &
380 strm = strm_)
381 else
382 call this%apply_scalar(x%x, n, time = time)
383 end if
384
385 end subroutine bc_apply_scalar_generic
386
390 subroutine bc_mark_facet(this, facet, el)
391 class(bc_t), intent(inout) :: this
392 integer, intent(in) :: facet
393 integer, intent(in) :: el
394 type(tuple_i4_t) :: t
395
396 t%x = [facet, el]
397 call this%marked_facet%push(t)
398
399 end subroutine bc_mark_facet
400
403 subroutine bc_mark_facets(this, facet_list)
404 class(bc_t), intent(inout) :: this
405 type(stack_i4t2_t), intent(inout) :: facet_list
406 type(tuple_i4_t), pointer :: fp(:)
407 integer :: i
408
409 fp => facet_list%array()
410 do i = 1, facet_list%size()
411 call this%marked_facet%push(fp(i))
412 end do
413
414 end subroutine bc_mark_facets
415
418 subroutine bc_mark_zone(this, bc_zone)
419 class(bc_t), intent(inout) :: this
420 class(facet_zone_t), intent(in) :: bc_zone
421 integer :: i
422 do i = 1, bc_zone%size
423 call this%marked_facet%push(bc_zone%facet_el(i))
424 end do
425 end subroutine bc_mark_zone
426
434 subroutine bc_finalize_base(this, only_facets)
435 class(bc_t), target, intent(inout) :: this
436 logical, optional, intent(in) :: only_facets
437 type(tuple_i4_t), pointer :: bfp(:)
438 type(tuple_i4_t) :: bc_facet
439 type(field_t) :: test_field
440 integer :: facet_size, facet, el
441 logical :: only_facet = .false.
442 integer :: i, j, k, l, msk_c
443 integer :: lx, ly, lz, n
444 character(len=LOG_SIZE) :: log_buf
445 lx = this%Xh%lx
446 ly = this%Xh%ly
447 lz = this%Xh%lz
448 if ( present(only_facets)) then
449 only_facet = only_facets
450 else
451 only_facet = .false.
452 end if
454
455 ! Note we assume that lx = ly = lz
456 facet_size = lx**2
457 allocate(this%msk(0:facet_size * this%marked_facet%size()))
458 allocate(this%facet(0:facet_size * this%marked_facet%size()))
459
460 msk_c = 0
461 bfp => this%marked_facet%array()
462
463 ! Loop through each (facet, element) id tuple
464 ! Then loop over all the nodes of the face and compute their linear index
465 ! This index goes into this%msk, whereas the corresponding face id goes into
466 ! this%facet
467 do i = 1, this%marked_facet%size()
468 bc_facet = bfp(i)
469 facet = bc_facet%x(1)
470 el = bc_facet%x(2)
471 select case (facet)
472 case (1)
473 do l = 1, lz
474 do k = 1, ly
475 msk_c = msk_c + 1
476 this%msk(msk_c) = linear_index(1, k, l, el, lx, ly, lz)
477 this%facet(msk_c) = 1
478 end do
479 end do
480 case (2)
481 do l = 1, lz
482 do k = 1, ly
483 msk_c = msk_c + 1
484 this%msk(msk_c) = linear_index(lx, k, l, el, lx, ly, lz)
485 this%facet(msk_c) = 2
486 end do
487 end do
488 case (3)
489 do l = 1, lz
490 do j = 1, lx
491 msk_c = msk_c + 1
492 this%msk(msk_c) = linear_index(j, 1, l, el, lx, ly, lz)
493 this%facet(msk_c) = 3
494 end do
495 end do
496 case (4)
497 do l = 1, lz
498 do j = 1, lx
499 msk_c = msk_c + 1
500 this%msk(msk_c) = linear_index(j, ly, l, el, lx, ly, lz)
501 this%facet(msk_c) = 4
502 end do
503 end do
504 case (5)
505 do k = 1, ly
506 do j = 1, lx
507 msk_c = msk_c + 1
508 this%msk(msk_c) = linear_index(j, k, 1, el, lx, ly, lz)
509 this%facet(msk_c) = 5
510 end do
511 end do
512 case (6)
513 do k = 1, ly
514 do j = 1, lx
515 msk_c = msk_c + 1
516 this%msk(msk_c) = linear_index(j, k, lz, el, lx, ly, lz)
517 this%facet(msk_c) = 6
518 end do
519 end do
520 end select
521 end do
522 this%facet(0) = msk_c
523 if (neko_bcknd_device .eq. 1) then
524 !Observe the facet_mask is junk if only_facet is false
525 n = msk_c + 1
526 call device_map(this%facet, this%facet_d, n)
527 call device_memcpy(this%facet, this%facet_d, n, &
528 host_to_device, sync = .true.)
529 end if
530 if ( .not. only_facet) then
531 !Makes check for points not on facet that should have bc applied
532 call test_field%init(this%dof)
533
534 n = test_field%size()
535 test_field%x = 0.0_rp
536 !Apply this bc once
537 do i = 1, msk_c
538 test_field%x(this%msk(i),1,1,1) = 1.0
539 end do
540 if (neko_bcknd_device .eq. 1) then
541 call device_memcpy(test_field%x, test_field%x_d, n, &
542 host_to_device, sync = .true.)
543 end if
544 !Check if some point that was not zeroed was zeroed on another element
545 call this%coef%gs_h%op(test_field, gs_op_add)
546 if (neko_bcknd_device .eq. 1) then
547 call device_memcpy(test_field%x, test_field%x_d, n, &
548 device_to_host, sync = .true.)
549 end if
550 msk_c = 0
551 do i = 1, this%dof%size()
552 if (test_field%x(i,1,1,1) .gt. 0.5) then
553 msk_c = msk_c + 1
554 end if
555 end do
556 !Allocate new mask
557 deallocate(this%msk)
558 allocate(this%msk(0:msk_c))
559 j = 1
560 do i = 1, this%dof%size()
561 if (test_field%x(i,1,1,1) .gt. 0.5) then
562 this%msk(j) = i
563 j = j + 1
564 end if
565 end do
566
567 call test_field%free()
568 end if
569
570 this%msk(0) = msk_c
571
572 if (neko_bcknd_device .eq. 1) then
573 n = msk_c + 1
574 call device_map(this%msk, this%msk_d, n)
575 call device_memcpy(this%msk, this%msk_d, n, &
576 host_to_device, sync = .true.)
577 end if
578
579 if (.not. allocated(this%name)) then
580! gives plenty of empty info lines during AMR restart
581! this%name = ""
582 else
583 write(log_buf, '(A,A)') 'BC assigned name : ', trim(this%name)
584 call neko_log%message(log_buf)
585 end if
586
587! causes trouble for AMR restart
588! if (.not. allocated(this%zone_indices)) then
589! allocate(this%zone_indices(1))
590! this%zone_indices(1) = -1
591! end if
592
593 end subroutine bc_finalize_base
594
598 subroutine bc_debug_mask(this, file_name)
599 class(bc_t), intent(inout) :: this
600 character(len=*), intent(in) :: file_name
601 type(field_t) :: bdry_field
602 integer:: i, m, k
603 type(file_t) :: dump_file
604
605 call bdry_field%init(this%coef%dof, 'bdry')
606 m = this%msk(0)
607 do i = 1, m
608 k = this%msk(i)
609 bdry_field%x(k,1,1,1) = 1.0_rp
610 end do
611 call dump_file%init(file_name)
612 call dump_file%write(bdry_field)
613
614 end subroutine bc_debug_mask
615end module bc
Apply the boundary condition to a scalar field on the device.
Definition bc.f90:215
Apply the boundary condition to a scalar field.
Definition bc.f90:176
Apply the boundary condition to a vector field on the device.
Definition bc.f90:235
Apply the boundary condition to a vector field.
Definition bc.f90:196
Constructor.
Definition bc.f90:145
Destructor.
Definition bc.f90:155
Finalize by building the mask and facet arrays.
Definition bc.f90:163
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
Defines a boundary condition.
Definition bc.f90:34
subroutine bc_mark_zone(this, bc_zone)
Mark all facets from a zone.
Definition bc.f90:419
subroutine bc_free_base(this)
Destructor for the base type, bc_t.
Definition bc.f90:269
subroutine bc_init_base(this, coef)
Constructor.
Definition bc.f90:253
subroutine bc_apply_scalar_generic(this, x, time, strong, strm)
Apply the boundary condition to a scalar field. Dispatches to the CPU or the device version.
Definition bc.f90:360
subroutine bc_finalize_base(this, only_facets)
Finalize the construction of the bc by populting the msk and facet arrays.
Definition bc.f90:435
subroutine bc_apply_vector_generic(this, x, y, z, time, strong, strm)
Apply the boundary condition to a vector field. Dispatches to the CPU or the device version.
Definition bc.f90:316
subroutine bc_debug_mask(this, file_name)
Write a field showing the mask of the bc.
Definition bc.f90:599
subroutine bc_mark_facet(this, facet, el)
Mark facet on element el as part of the boundary condition.
Definition bc.f90:391
subroutine bc_mark_facets(this, facet_list)
Mark all facets from a (facet, el) tuple list.
Definition bc.f90:404
Coefficients.
Definition coef.f90:34
Device abstraction, common interface for various accelerators.
Definition device.F90:34
integer, parameter, public host_to_device
Definition device.F90:48
integer, parameter, public device_to_host
Definition device.F90:48
type(c_ptr), bind(C), public glb_cmd_queue
Global command queue.
Definition device.F90:52
Defines a mapping of the degrees of freedom.
Definition dofmap.f90:35
Defines a zone as a subset of facets in a mesh.
Defines a field.
Definition field.f90:34
Module for file I/O operations.
Definition file.f90:34
Defines Gather-scatter operations.
Definition gs_ops.f90:34
integer, parameter, public gs_op_add
Definition gs_ops.f90:36
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
Definition math.f90:60
Defines a mesh.
Definition mesh.f90:34
integer, parameter, public neko_msh_max_zlbls
Max num. zone labels.
Definition mesh.f90:65
integer, parameter, public neko_msh_max_zlbl_len
Max length of a zone label.
Definition mesh.f90:67
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Defines a function space.
Definition space.f90:34
Implements a dynamic stack ADT.
Definition stack.f90:49
Module with things related to the simulation time.
Implements a n-tuple.
Definition tuple.f90:41
Utilities.
Definition utils.f90:35
character(len=100) function, dimension(:), allocatable, public split_string(string, delimiter)
Split a string based on delimiter (tokenizer) OBS: very hacky, this should really be improved,...
Definition utils.f90:251
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
Pointer to a `bc_t`.
Definition bc.f90:133
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
A wrapper around a polymorphic generic_file_t that handles its init. This is essentially a factory fo...
Definition file.f90:56
The function space for the SEM solution fields.
Definition space.f90:64
Integer 2-tuple based stack.
Definition stack.f90:98
A struct that contains all info about the time, expand as needed.
Integer based 2-tuple.
Definition tuple.f90:58