Neko 1.99.7
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 subroutine expression_dirichlet_vector_finalize(this, only_facets)
191 class(expression_dirichlet_vector_t), target, intent(inout) :: this
192 logical, optional, intent(in) :: only_facets
193 logical :: only_facets_
194 integer :: m
195
196 if (present(only_facets)) then
197 only_facets_ = only_facets
198 else
199 only_facets_ = .false.
200 end if
201
202 call this%finalize_base(only_facets_)
203
204 m = this%msk(0)
205 if (m .eq. 0) return
206
207 allocate(this%xm(m), this%ym(m), this%zm(m))
208 allocate(this%gx(m), this%gy(m), this%gz(m))
209 call expression_mask_coords(this, this%xm, this%ym, this%zm)
210 this%gx = 0.0_rp
211 this%gy = 0.0_rp
212 this%gz = 0.0_rp
213
214 if (neko_bcknd_device .eq. 1) then
215 call device_map(this%gx, this%gx_d, m)
216 call device_map(this%gy, this%gy_d, m)
217 call device_map(this%gz, this%gz_d, m)
218 end if
219
220 if (.not. this%expr(1)%time_dependent) then
221 call this%expr(1)%eval(this%gx, m, this%xm, this%ym, this%zm)
222 call expression_check_finite(this%expr(1)%src, this%gx, m, &
223 "boundary condition")
224 end if
225 if (.not. this%expr(2)%time_dependent) then
226 call this%expr(2)%eval(this%gy, m, this%xm, this%ym, this%zm)
227 call expression_check_finite(this%expr(2)%src, this%gy, m, &
228 "boundary condition")
229 end if
230 if (.not. this%expr(3)%time_dependent) then
231 call this%expr(3)%eval(this%gz, m, this%xm, this%ym, this%zm)
232 call expression_check_finite(this%expr(3)%src, this%gz, m, &
233 "boundary condition")
234 end if
235
236 if (neko_bcknd_device .eq. 1) then
237 call device_memcpy(this%gx, this%gx_d, m, host_to_device, sync = .false.)
238 call device_memcpy(this%gy, this%gy_d, m, host_to_device, sync = .false.)
239 call device_memcpy(this%gz, this%gz_d, m, host_to_device, sync = .true.)
240 end if
241
243
251 subroutine expression_dirichlet_vector_update(this, time, strm)
252 class(expression_dirichlet_vector_t), intent(inout) :: this
253 type(time_state_t), intent(in), optional :: time
254 type(c_ptr), intent(inout), optional :: strm
255 integer :: m
256
257 if (.not. (this%expr(1)%time_dependent .or. &
258 this%expr(2)%time_dependent .or. &
259 this%expr(3)%time_dependent)) return
260 if (this%updated) return
261
262 if (.not. present(time)) then
263 call neko_error("A boundary condition expression depends on time, " // &
264 "but the solver did not provide a time state")
265 end if
266
267 m = this%msk(0)
268
269 if (this%expr(1)%time_dependent) then
270 call this%expr(1)%eval(this%gx, m, this%xm, this%ym, this%zm, &
271 time%t, time%dt)
272 call expression_check_finite(this%expr(1)%src, this%gx, m, &
273 "boundary condition")
274 end if
275 if (this%expr(2)%time_dependent) then
276 call this%expr(2)%eval(this%gy, m, this%xm, this%ym, this%zm, &
277 time%t, time%dt)
278 call expression_check_finite(this%expr(2)%src, this%gy, m, &
279 "boundary condition")
280 end if
281 if (this%expr(3)%time_dependent) then
282 call this%expr(3)%eval(this%gz, m, this%xm, this%ym, this%zm, &
283 time%t, time%dt)
284 call expression_check_finite(this%expr(3)%src, this%gz, m, &
285 "boundary condition")
286 end if
287
288 if (neko_bcknd_device .eq. 1) then
289 ! The three copies go on the same stream, so waiting for the last one
290 ! covers all of them. Synchronous on purpose, see
291 ! expression_dirichlet_update.
292 call device_memcpy(this%gx, this%gx_d, m, host_to_device, &
293 sync = .false., strm = strm)
294 call device_memcpy(this%gy, this%gy_d, m, host_to_device, &
295 sync = .false., strm = strm)
296 call device_memcpy(this%gz, this%gz_d, m, host_to_device, &
297 sync = .true., strm = strm)
298 end if
299
300 this%updated = .true.
301
303
309 subroutine expression_dirichlet_vector_apply_scalar(this, x, n, time, strong)
310 class(expression_dirichlet_vector_t), intent(inout) :: this
311 integer, intent(in) :: n
312 real(kind=rp), intent(inout), dimension(n) :: x
313 type(time_state_t), intent(in), optional :: time
314 logical, intent(in), optional :: strong
316
323 strong, strm)
324 class(expression_dirichlet_vector_t), intent(inout), target :: this
325 type(c_ptr), intent(inout) :: x_d
326 type(time_state_t), intent(in), optional :: time
327 logical, intent(in), optional :: strong
328 type(c_ptr), intent(inout) :: strm
330
338 subroutine expression_dirichlet_vector_apply_vector(this, x, y, z, n, &
339 time, strong)
340 class(expression_dirichlet_vector_t), intent(inout) :: this
341 integer, intent(in) :: n
342 real(kind=rp), intent(inout), dimension(n) :: x
343 real(kind=rp), intent(inout), dimension(n) :: y
344 real(kind=rp), intent(inout), dimension(n) :: z
345 type(time_state_t), intent(in), optional :: time
346 logical, intent(in), optional :: strong
347 integer :: i, m, k
348 logical :: strong_
349
350 if (present(strong)) then
351 strong_ = strong
352 else
353 strong_ = .true.
354 end if
355
356 m = this%msk(0)
357 if (.not. strong_ .or. m .eq. 0) return
358
359 ! The bc list applies the host conditions from inside an OpenMP parallel
360 ! region, and evaluating an expression mutates the shared evaluation stack
361 ! of `expr`, so only one thread may run the update. The implicit barrier of
362 ! `single` also makes the values visible to every thread before the loop
363 ! below.
364 !$omp single
365 call this%update(time)
366 !$omp end single
367
368 !$omp do
369 do i = 1, m
370 k = this%msk(i)
371 x(k) = this%gx(i)
372 y(k) = this%gy(i)
373 z(k) = this%gz(i)
374 end do
375 !$omp end do
376
378
387 z_d, time, strong, strm)
388 class(expression_dirichlet_vector_t), intent(inout), target :: this
389 type(c_ptr), intent(inout) :: x_d
390 type(c_ptr), intent(inout) :: y_d
391 type(c_ptr), intent(inout) :: z_d
392 type(time_state_t), intent(in), optional :: time
393 logical, intent(in), optional :: strong
394 type(c_ptr), intent(inout) :: strm
395 integer :: m
396 logical :: strong_
397
398 if (present(strong)) then
399 strong_ = strong
400 else
401 strong_ = .true.
402 end if
403
404 m = this%msk(0)
405 if (.not. strong_ .or. m .eq. 0) return
406
407 call this%update(time, strm)
408
409 call device_inhom_dirichlet_apply_vector(this%msk_d, x_d, y_d, z_d, &
410 this%gx_d, this%gy_d, this%gz_d, m, strm)
411
413
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
subroutine device_inhom_dirichlet_apply_vector(msk, x, y, z, bla_x, bla_y, bla_z, m, strm)
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_finalize(this, only_facets)
Finalize.
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.
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:12
Module with things related to the simulation time.
Utilities.
Definition utils.f90:35
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 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.