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, bc_dirichlet
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 this%bc_type = bc_dirichlet
136
137 if (len_trim(str_x) .eq. 0 .or. len_trim(str_y) .eq. 0 .or. &
138 len_trim(str_z) .eq. 0) then
139 call neko_error("An expression boundary condition needs a non-empty " &
140 // "expression for every component")
141 end if
142
143 call this%expr(1)%init(str_x)
144 call this%expr(2)%init(str_y)
145 call this%expr(3)%init(str_z)
146
148
151 class(expression_dirichlet_vector_t), target, intent(inout) :: this
152 integer :: i
153
154 call this%free_base()
155
156 do i = 1, 3
157 call this%expr(i)%free()
158 end do
159
160 if (allocated(this%gx)) then
161 if (neko_bcknd_device .eq. 1) then
162 call device_unmap(this%gx, this%gx_d)
163 end if
164 deallocate(this%gx)
165 end if
166
167 if (allocated(this%gy)) then
168 if (neko_bcknd_device .eq. 1) then
169 call device_unmap(this%gy, this%gy_d)
170 end if
171 deallocate(this%gy)
172 end if
173
174 if (allocated(this%gz)) then
175 if (neko_bcknd_device .eq. 1) then
176 call device_unmap(this%gz, this%gz_d)
177 end if
178 deallocate(this%gz)
179 end if
180
181 if (allocated(this%xm)) deallocate(this%xm)
182 if (allocated(this%ym)) deallocate(this%ym)
183 if (allocated(this%zm)) deallocate(this%zm)
184
186
191 class(expression_dirichlet_vector_t), target, intent(inout) :: this
192 integer :: m
193
194 call this%finalize_base()
195
196 m = this%msk(0)
197 if (m .eq. 0) return
198
199 allocate(this%xm(m), this%ym(m), this%zm(m))
200 allocate(this%gx(m), this%gy(m), this%gz(m))
201 call expression_mask_coords(this, this%xm, this%ym, this%zm)
202 this%gx = 0.0_rp
203 this%gy = 0.0_rp
204 this%gz = 0.0_rp
205
206 if (neko_bcknd_device .eq. 1) then
207 call device_map(this%gx, this%gx_d, m)
208 call device_map(this%gy, this%gy_d, m)
209 call device_map(this%gz, this%gz_d, m)
210 end if
211
212 if (.not. this%expr(1)%time_dependent) then
213 call this%expr(1)%eval(this%gx, m, this%xm, this%ym, this%zm)
214 call expression_check_finite(this%expr(1)%src, this%gx, m, &
215 "boundary condition")
216 end if
217 if (.not. this%expr(2)%time_dependent) then
218 call this%expr(2)%eval(this%gy, m, this%xm, this%ym, this%zm)
219 call expression_check_finite(this%expr(2)%src, this%gy, m, &
220 "boundary condition")
221 end if
222 if (.not. this%expr(3)%time_dependent) then
223 call this%expr(3)%eval(this%gz, m, this%xm, this%ym, this%zm)
224 call expression_check_finite(this%expr(3)%src, this%gz, m, &
225 "boundary condition")
226 end if
227
228 if (neko_bcknd_device .eq. 1) then
229 call device_memcpy(this%gx, this%gx_d, m, host_to_device, sync = .false.)
230 call device_memcpy(this%gy, this%gy_d, m, host_to_device, sync = .false.)
231 call device_memcpy(this%gz, this%gz_d, m, host_to_device, sync = .true.)
232 end if
233
235
243 subroutine expression_dirichlet_vector_update(this, time, strm)
244 class(expression_dirichlet_vector_t), intent(inout) :: this
245 type(time_state_t), intent(in), optional :: time
246 type(c_ptr), intent(inout), optional :: strm
247 integer :: m
248
249 if (.not. (this%expr(1)%time_dependent .or. &
250 this%expr(2)%time_dependent .or. &
251 this%expr(3)%time_dependent)) return
252 if (this%updated) return
253
254 if (.not. present(time)) then
255 call neko_error("A boundary condition expression depends on time, " // &
256 "but the solver did not provide a time state")
257 end if
258
259 m = this%msk(0)
260
261 if (this%expr(1)%time_dependent) then
262 call this%expr(1)%eval(this%gx, m, this%xm, this%ym, this%zm, &
263 time%t, time%dt)
264 call expression_check_finite(this%expr(1)%src, this%gx, m, &
265 "boundary condition")
266 end if
267 if (this%expr(2)%time_dependent) then
268 call this%expr(2)%eval(this%gy, m, this%xm, this%ym, this%zm, &
269 time%t, time%dt)
270 call expression_check_finite(this%expr(2)%src, this%gy, m, &
271 "boundary condition")
272 end if
273 if (this%expr(3)%time_dependent) then
274 call this%expr(3)%eval(this%gz, m, this%xm, this%ym, this%zm, &
275 time%t, time%dt)
276 call expression_check_finite(this%expr(3)%src, this%gz, m, &
277 "boundary condition")
278 end if
279
280 if (neko_bcknd_device .eq. 1) then
281 ! The three copies go on the same stream, so waiting for the last one
282 ! covers all of them. Synchronous on purpose, see
283 ! expression_dirichlet_update.
284 call device_memcpy(this%gx, this%gx_d, m, host_to_device, &
285 sync = .false., strm = strm)
286 call device_memcpy(this%gy, this%gy_d, m, host_to_device, &
287 sync = .false., strm = strm)
288 call device_memcpy(this%gz, this%gz_d, m, host_to_device, &
289 sync = .true., strm = strm)
290 end if
291
292 this%updated = .true.
293
295
301 subroutine expression_dirichlet_vector_apply_scalar(this, x, n, time, strong)
302 class(expression_dirichlet_vector_t), intent(inout) :: this
303 integer, intent(in) :: n
304 real(kind=rp), intent(inout), dimension(n) :: x
305 type(time_state_t), intent(in), optional :: time
306 logical, intent(in), optional :: strong
308
315 strong, strm)
316 class(expression_dirichlet_vector_t), intent(inout), target :: this
317 type(c_ptr), intent(inout) :: x_d
318 type(time_state_t), intent(in), optional :: time
319 logical, intent(in), optional :: strong
320 type(c_ptr), intent(inout) :: strm
322
330 subroutine expression_dirichlet_vector_apply_vector(this, x, y, z, n, &
331 time, strong)
332 class(expression_dirichlet_vector_t), intent(inout) :: this
333 integer, intent(in) :: n
334 real(kind=rp), intent(inout), dimension(n) :: x
335 real(kind=rp), intent(inout), dimension(n) :: y
336 real(kind=rp), intent(inout), dimension(n) :: z
337 type(time_state_t), intent(in), optional :: time
338 logical, intent(in), optional :: strong
339 integer :: i, m, k
340 logical :: strong_
341
342 if (present(strong)) then
343 strong_ = strong
344 else
345 strong_ = .true.
346 end if
347
348 m = this%msk(0)
349 if (.not. strong_ .or. m .eq. 0) return
350
351 ! The bc list applies the host conditions from inside an OpenMP parallel
352 ! region, and evaluating an expression mutates the shared evaluation stack
353 ! of `expr`, so only one thread may run the update. The implicit barrier of
354 ! `single` also makes the values visible to every thread before the loop
355 ! below.
356 !$omp single
357 call this%update(time)
358 !$omp end single
359
360 !$omp do
361 do i = 1, m
362 k = this%msk(i)
363 x(k) = this%gx(i)
364 y(k) = this%gy(i)
365 z(k) = this%gz(i)
366 end do
367 !$omp end do
368
370
379 z_d, time, strong, strm)
380 class(expression_dirichlet_vector_t), intent(inout), target :: this
381 type(c_ptr), intent(inout) :: x_d
382 type(c_ptr), intent(inout) :: y_d
383 type(c_ptr), intent(inout) :: z_d
384 type(time_state_t), intent(in), optional :: time
385 logical, intent(in), optional :: strong
386 type(c_ptr), intent(inout) :: strm
387 integer :: m
388 logical :: strong_
389
390 if (present(strong)) then
391 strong_ = strong
392 else
393 strong_ = .true.
394 end if
395
396 m = this%msk(0)
397 if (.not. strong_ .or. m .eq. 0) return
398
399 call this%update(time, strm)
400
401 call device_inhom_dirichlet_apply_vector(this%msk_d, x_d, y_d, z_d, &
402 this%gx_d, this%gy_d, this%gz_d, m, strm)
403
405
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
integer, parameter, public bc_dirichlet
Supported boundary condition types. The values are set in order of precedence for global resolution....
Definition bc.f90:67
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:73
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:135
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.