Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
expression_dirichlet_vector.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!
36 use num_types, only : rp
37 use bc, only : bc_t
38 use coefs, only : coef_t
44 use json_module, only : json_file
45 use json_utils, only : json_get
46 use time_state, only : time_state_t
47 use utils, only : neko_error
48 use, intrinsic :: iso_c_binding, only : c_ptr, c_null_ptr
49 implicit none
50 private
51
56 type, public, extends(bc_t) :: expression_dirichlet_vector_t
58 type(expression_t) :: expr(3)
60 real(kind=rp), allocatable :: gx(:)
61 real(kind=rp), allocatable :: gy(:)
62 real(kind=rp), allocatable :: gz(:)
64 real(kind=rp), allocatable :: xm(:)
65 real(kind=rp), allocatable :: ym(:)
66 real(kind=rp), allocatable :: zm(:)
68 type(c_ptr) :: gx_d = c_null_ptr
69 type(c_ptr) :: gy_d = c_null_ptr
70 type(c_ptr) :: gz_d = c_null_ptr
71 contains
73 procedure, pass(this) :: init => expression_dirichlet_vector_init
75 procedure, pass(this) :: init_from_components => &
78 procedure, pass(this) :: free => expression_dirichlet_vector_free
80 procedure, pass(this) :: finalize => expression_dirichlet_vector_finalize
82 procedure, pass(this) :: apply_scalar => &
85 procedure, pass(this) :: apply_vector => &
88 procedure, pass(this) :: apply_scalar_dev => &
91 procedure, pass(this) :: apply_vector_dev => &
94 procedure, pass(this) :: update => expression_dirichlet_vector_update
96
97contains
98
102 subroutine expression_dirichlet_vector_init(this, coef, json)
103 class(expression_dirichlet_vector_t), intent(inout), target :: this
104 type(coef_t), target, intent(in) :: coef
105 type(json_file), intent(inout) :: json
106 character(len=NEKO_EXPR_LEN), allocatable :: str(:)
107
108 call json_get(json, "value", str, filler = '')
109
110 if (size(str) .ne. 3) then
111 call neko_error("An expression velocity boundary condition takes " // &
112 "exactly three expressions, one per component")
113 end if
114
115 call this%init_from_components(coef, str(1), str(2), str(3))
116 if (allocated(str)) deallocate(str)
117
119
126 str_x, str_y, str_z)
127 class(expression_dirichlet_vector_t), intent(inout), target :: this
128 type(coef_t), target, intent(in) :: coef
129 character(len=*), intent(in) :: str_x
130 character(len=*), intent(in) :: str_y
131 character(len=*), intent(in) :: str_z
132
133 call this%free()
134 call this%init_base(coef)
135
136 if (len_trim(str_x) .eq. 0 .or. len_trim(str_y) .eq. 0 .or. &
137 len_trim(str_z) .eq. 0) then
138 call neko_error("An expression boundary condition needs a non-empty " &
139 // "expression for every component")
140 end if
141
142 call this%expr(1)%init(str_x)
143 call this%expr(2)%init(str_y)
144 call this%expr(3)%init(str_z)
145
147
150 class(expression_dirichlet_vector_t), target, intent(inout) :: this
151 integer :: i
152
153 call this%free_base()
154
155 do i = 1, 3
156 call this%expr(i)%free()
157 end do
158
159 if (allocated(this%gx)) then
160 if (neko_bcknd_device .eq. 1) then
161 call device_unmap(this%gx, this%gx_d)
162 end if
163 deallocate(this%gx)
164 end if
165
166 if (allocated(this%gy)) then
167 if (neko_bcknd_device .eq. 1) then
168 call device_unmap(this%gy, this%gy_d)
169 end if
170 deallocate(this%gy)
171 end if
172
173 if (allocated(this%gz)) then
174 if (neko_bcknd_device .eq. 1) then
175 call device_unmap(this%gz, this%gz_d)
176 end if
177 deallocate(this%gz)
178 end if
179
180 if (allocated(this%xm)) deallocate(this%xm)
181 if (allocated(this%ym)) deallocate(this%ym)
182 if (allocated(this%zm)) deallocate(this%zm)
183
185
190 class(expression_dirichlet_vector_t), target, intent(inout) :: this
191 integer :: m
192
193 call this%finalize_base()
194
195 m = this%msk(0)
196 if (m .eq. 0) return
197
198 allocate(this%xm(m), this%ym(m), this%zm(m))
199 allocate(this%gx(m), this%gy(m), this%gz(m))
200 call expression_mask_coords(this, this%xm, this%ym, this%zm)
201 this%gx = 0.0_rp
202 this%gy = 0.0_rp
203 this%gz = 0.0_rp
204
205 if (neko_bcknd_device .eq. 1) then
206 call device_map(this%gx, this%gx_d, m)
207 call device_map(this%gy, this%gy_d, m)
208 call device_map(this%gz, this%gz_d, m)
209 end if
210
211 if (.not. this%expr(1)%time_dependent) then
212 call this%expr(1)%eval(this%gx, m, this%xm, this%ym, this%zm)
213 call expression_check_finite(this%expr(1)%src, this%gx, m, &
214 "boundary condition")
215 end if
216 if (.not. this%expr(2)%time_dependent) then
217 call this%expr(2)%eval(this%gy, m, this%xm, this%ym, this%zm)
218 call expression_check_finite(this%expr(2)%src, this%gy, m, &
219 "boundary condition")
220 end if
221 if (.not. this%expr(3)%time_dependent) then
222 call this%expr(3)%eval(this%gz, m, this%xm, this%ym, this%zm)
223 call expression_check_finite(this%expr(3)%src, this%gz, m, &
224 "boundary condition")
225 end if
226
227 if (neko_bcknd_device .eq. 1) then
228 call device_memcpy(this%gx, this%gx_d, m, host_to_device, sync = .false.)
229 call device_memcpy(this%gy, this%gy_d, m, host_to_device, sync = .false.)
230 call device_memcpy(this%gz, this%gz_d, m, host_to_device, sync = .true.)
231 end if
232
234
242 subroutine expression_dirichlet_vector_update(this, time, strm)
243 class(expression_dirichlet_vector_t), intent(inout) :: this
244 type(time_state_t), intent(in), optional :: time
245 type(c_ptr), intent(inout), optional :: strm
246 integer :: m
247
248 if (.not. (this%expr(1)%time_dependent .or. &
249 this%expr(2)%time_dependent .or. &
250 this%expr(3)%time_dependent)) return
251 if (this%updated) return
252
253 if (.not. present(time)) then
254 call neko_error("A boundary condition expression depends on time, " // &
255 "but the solver did not provide a time state")
256 end if
257
258 m = this%msk(0)
259
260 if (this%expr(1)%time_dependent) then
261 call this%expr(1)%eval(this%gx, m, this%xm, this%ym, this%zm, &
262 time%t, time%dt)
263 call expression_check_finite(this%expr(1)%src, this%gx, m, &
264 "boundary condition")
265 end if
266 if (this%expr(2)%time_dependent) then
267 call this%expr(2)%eval(this%gy, m, this%xm, this%ym, this%zm, &
268 time%t, time%dt)
269 call expression_check_finite(this%expr(2)%src, this%gy, m, &
270 "boundary condition")
271 end if
272 if (this%expr(3)%time_dependent) then
273 call this%expr(3)%eval(this%gz, m, this%xm, this%ym, this%zm, &
274 time%t, time%dt)
275 call expression_check_finite(this%expr(3)%src, this%gz, m, &
276 "boundary condition")
277 end if
278
279 if (neko_bcknd_device .eq. 1) then
280 ! The three copies go on the same stream, so waiting for the last one
281 ! covers all of them. Synchronous on purpose, see
282 ! expression_dirichlet_update.
283 call device_memcpy(this%gx, this%gx_d, m, host_to_device, &
284 sync = .false., strm = strm)
285 call device_memcpy(this%gy, this%gy_d, m, host_to_device, &
286 sync = .false., strm = strm)
287 call device_memcpy(this%gz, this%gz_d, m, host_to_device, &
288 sync = .true., strm = strm)
289 end if
290
291 this%updated = .true.
292
294
300 subroutine expression_dirichlet_vector_apply_scalar(this, x, n, time, strong)
301 class(expression_dirichlet_vector_t), intent(inout) :: this
302 integer, intent(in) :: n
303 real(kind=rp), intent(inout), dimension(n) :: x
304 type(time_state_t), intent(in), optional :: time
305 logical, intent(in), optional :: strong
307
314 strong, strm)
315 class(expression_dirichlet_vector_t), intent(inout), target :: this
316 type(c_ptr), intent(inout) :: x_d
317 type(time_state_t), intent(in), optional :: time
318 logical, intent(in), optional :: strong
319 type(c_ptr), intent(inout) :: strm
321
329 subroutine expression_dirichlet_vector_apply_vector(this, x, y, z, n, &
330 time, strong)
331 class(expression_dirichlet_vector_t), intent(inout) :: this
332 integer, intent(in) :: n
333 real(kind=rp), intent(inout), dimension(n) :: x
334 real(kind=rp), intent(inout), dimension(n) :: y
335 real(kind=rp), intent(inout), dimension(n) :: z
336 type(time_state_t), intent(in), optional :: time
337 logical, intent(in), optional :: strong
338 integer :: i, m, k
339 logical :: strong_
340
341 if (present(strong)) then
342 strong_ = strong
343 else
344 strong_ = .true.
345 end if
346
347 m = this%msk(0)
348 if (.not. strong_ .or. m .eq. 0) return
349
350 ! The bc list applies the host conditions from inside an OpenMP parallel
351 ! region, and evaluating an expression mutates the shared evaluation stack
352 ! of `expr`, so only one thread may run the update. The implicit barrier of
353 ! `single` also makes the values visible to every thread before the loop
354 ! below.
355 !$omp single
356 call this%update(time)
357 !$omp end single
358
359 !$omp do
360 do i = 1, m
361 k = this%msk(i)
362 x(k) = this%gx(i)
363 y(k) = this%gy(i)
364 z(k) = this%gz(i)
365 end do
366 !$omp end do
367
369
378 z_d, time, strong, strm)
379 class(expression_dirichlet_vector_t), intent(inout), target :: this
380 type(c_ptr), intent(inout) :: x_d
381 type(c_ptr), intent(inout) :: y_d
382 type(c_ptr), intent(inout) :: z_d
383 type(time_state_t), intent(in), optional :: time
384 logical, intent(in), optional :: strong
385 type(c_ptr), intent(inout) :: strm
386 integer :: m
387 logical :: strong_
388
389 if (present(strong)) then
390 strong_ = strong
391 else
392 strong_ = .true.
393 end if
394
395 m = this%msk(0)
396 if (.not. strong_ .or. m .eq. 0) return
397
398 call this%update(time, strm)
399
400 call device_inhom_dirichlet_apply_vector(this%msk_d, x_d, y_d, z_d, &
401 this%gx_d, this%gy_d, this%gz_d, m, strm)
402
404
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
Retrieves a parameter by name or throws an error.
Defines a boundary condition.
Definition bc.f90:34
Coefficients.
Definition coef.f90:34
Device backend wrappers for inhomogeneous Dirichlet boundary conditions.
subroutine device_inhom_dirichlet_apply_vector(msk, x, y, z, bla_x, bla_y, bla_z, m, strm)
Apply an inhomogeneous Dirichlet condition to a vector field on the device.
Device abstraction, common interface for various accelerators.
Definition device.F90:34
integer, parameter, public host_to_device
Definition device.F90:48
Defines a vector valued Dirichlet condition prescribed by mathematical expressions.
subroutine expression_dirichlet_vector_update(this, time, strm)
Bring the values up to date with the current time.
subroutine expression_dirichlet_vector_apply_vector_dev(this, x_d, y_d, z_d, time, strong, strm)
Apply the condition to a vector field (device version).
subroutine expression_dirichlet_vector_apply_scalar(this, x, n, time, strong)
(No-op) Apply scalar.
subroutine expression_dirichlet_vector_apply_vector(this, x, y, z, n, time, strong)
Apply the condition to a vector field.
subroutine expression_dirichlet_vector_init(this, coef, json)
Constructor from JSON.
subroutine expression_dirichlet_vector_free(this)
Destructor.
subroutine expression_dirichlet_vector_apply_scalar_dev(this, x_d, time, strong, strm)
(No-op) Apply scalar (device version).
subroutine expression_dirichlet_vector_init_from_components(this, coef, str_x, str_y, str_z)
Constructor from components.
subroutine expression_dirichlet_vector_finalize(this)
Finalize.
Defines a Dirichlet condition prescribed by a mathematical expression.
subroutine, public expression_mask_coords(bc, xm, ym, zm)
Tabulate the coordinates of the points of the mask of a boundary condition.
Evaluation of mathematical expressions given as strings in the case file.
subroutine, public expression_check_finite(str, res, n, usage)
Abort if an expression did not evaluate to a finite value everywhere.
integer, parameter, public neko_expr_len
Maximum length of an expression string read from the case file.
Utilities for retrieving parameters from the case files.
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
Module with things related to the simulation time.
Utilities.
Definition utils.f90:35
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
A compiled mathematical expression.
Vector valued Dirichlet condition, with one mathematical expression per component,...
A struct that contains all info about the time, expand as needed.