Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
neumann.f90
Go to the documentation of this file.
1! Copyright (c) 2024-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 neumann
35 use num_types, only : rp
36 use bc, only : bc_t, bc_neumann
37 use, intrinsic :: iso_c_binding, only : c_ptr, c_null_ptr
39 use coefs, only : coef_t
40 use json_module, only : json_file
42 use math, only : cfill, copy, abscmp
43 use vector, only : vector_t
49 use time_state, only : time_state_t
50 implicit none
51 private
52
60 type, public, extends(bc_t) :: neumann_t
63 type(vector_t), allocatable :: flux(:)
68 real(kind=rp), allocatable, private :: init_flux_(:)
71 logical :: uniform_0 = .false.
72 contains
73 procedure, pass(this) :: apply_scalar => neumann_apply_scalar
74 procedure, pass(this) :: apply_vector => neumann_apply_vector
75 procedure, pass(this) :: apply_scalar_dev => neumann_apply_scalar_dev
76 procedure, pass(this) :: apply_vector_dev => neumann_apply_vector_dev
78 procedure, pass(this) :: init => neumann_init
80 procedure, pass(this) :: neumann_init_from_components_array
82 procedure, pass(this) :: neumann_init_from_components_single
83 generic :: init_from_components => &
87 procedure, pass(this) :: set_flux_scalar => neumann_set_flux_scalar
89 procedure, pass(this) :: set_flux_array => neumann_set_flux_array
91 generic :: set_flux => set_flux_scalar, set_flux_array
93 procedure, pass(this) :: free => neumann_free
95 procedure, pass(this) :: finalize => neumann_finalize
96 end type neumann_t
97
98contains
99
103 subroutine neumann_init(this, coef, json)
104 class(neumann_t), intent(inout), target :: this
105 type(coef_t), target, intent(in) :: coef
106 type(json_file), intent(inout) :: json
107 real(kind=rp) :: flux
108 logical :: found
109
110 call this%init_base(coef)
111
112 ! Try to read array from json
113 call json%get("flux", this%init_flux_, found)
114
115 ! If we haven't found an array, try to read a single value
116 if (.not. found) then
117 call json_get_or_lookup(json, "flux", flux)
118 allocate(this%init_flux_(1))
119 this%init_flux_(1) = flux
120 end if
121
122 if ((size(this%init_flux_) .ne. 1) &
123 .and. (size(this%init_flux_) .ne. 3)) then
124 call neko_error("Neumann BC flux must be a scalar or a 3-component" // &
125 " vector.")
126 end if
127
128 allocate(this%flux(size(this%init_flux_)))
129 this%bc_type = bc_neumann
130 end subroutine neumann_init
131
135 subroutine neumann_init_from_components_array(this, coef, flux)
136 class(neumann_t), intent(inout), target :: this
137 type(coef_t), intent(in) :: coef
138 real(kind=rp), intent(in) :: flux(3)
139
140 call this%init_base(coef)
141 this%init_flux_ = flux
142
143 if ((size(this%init_flux_) .ne. 3)) then
144 call neko_error("Neumann BC flux must be a scalar or a 3-component" // &
145 " vector.")
146 end if
147 allocate(this%flux(size(this%init_flux_)))
148 this%bc_type = bc_neumann
150
154 subroutine neumann_init_from_components_single(this, coef, flux)
155 class(neumann_t), intent(inout), target :: this
156 type(coef_t), intent(in) :: coef
157 real(kind=rp), intent(in) :: flux
158
159 call this%init_base(coef)
160 allocate(this%init_flux_(1))
161 this%init_flux_(1) = flux
162 allocate(this%flux(size(this%init_flux_)))
163 this%bc_type = bc_neumann
165
168 subroutine neumann_apply_scalar(this, x, n, time, strong)
169 class(neumann_t), intent(inout) :: this
170 integer, intent(in) :: n
171 real(kind=rp), intent(inout), dimension(n) :: x
172 type(time_state_t), intent(in), optional :: time
173 logical, intent(in), optional :: strong
174 integer :: i, m, k, facet
175 ! Store non-linear index
176 integer :: idx(4)
177 logical :: strong_
178
179 if (present(strong)) then
180 strong_ = strong
181 else
182 strong_ = .true.
183 end if
184
185 m = this%facet_node_msk(0)
186 if (.not. strong_) then
187 !$omp do
188 do i = 1, m
189 k = this%facet_node_msk(i)
190 facet = this%facet(i)
191 idx = nonlinear_index(k, this%coef%Xh%lx, this%coef%Xh%lx, &
192 this%coef%Xh%lx)
193 select case (facet)
194 case (1,2)
195 x(k) = x(k) + &
196 this%flux(1)%x(i) * &
197 this%coef%area(idx(2), idx(3), facet, idx(4))
198 case (3,4)
199 x(k) = x(k) + &
200 this%flux(1)%x(i) * &
201 this%coef%area(idx(1), idx(3), facet, idx(4))
202 case (5,6)
203 x(k) = x(k) + &
204 this%flux(1)%x(i) * &
205 this%coef%area(idx(1), idx(2), facet, idx(4))
206 end select
207 end do
208 !$omp end do
209 end if
210 end subroutine neumann_apply_scalar
211
214 subroutine neumann_apply_vector(this, x, y, z, n, time, strong)
215 class(neumann_t), intent(inout) :: this
216 integer, intent(in) :: n
217 real(kind=rp), intent(inout), dimension(n) :: x
218 real(kind=rp), intent(inout), dimension(n) :: y
219 real(kind=rp), intent(inout), dimension(n) :: z
220 type(time_state_t), intent(in), optional :: time
221 logical, intent(in), optional :: strong
222 integer :: i, m, k, facet
223 ! Store non-linear index
224 integer :: idx(4)
225 logical :: strong_
226
227 if (present(strong)) then
228 strong_ = strong
229 else
230 strong_ = .true.
231 end if
232
233 m = this%facet_node_msk(0)
234 if (.not. strong_) then
235 !$omp parallel do private(k, facet, idx)
236 do i = 1, m
237 k = this%facet_node_msk(i)
238 facet = this%facet(i)
239 idx = nonlinear_index(k, this%coef%Xh%lx, this%coef%Xh%lx, &
240 this%coef%Xh%lx)
241 select case (facet)
242 case (1,2)
243 x(k) = x(k) + &
244 this%flux(1)%x(i) * &
245 this%coef%area(idx(2), idx(3), facet, idx(4))
246 y(k) = y(k) + &
247 this%flux(2)%x(i) * &
248 this%coef%area(idx(2), idx(3), facet, idx(4))
249 z(k) = z(k) + &
250 this%flux(3)%x(i) * &
251 this%coef%area(idx(2), idx(3), facet, idx(4))
252 case (3,4)
253 x(k) = x(k) + &
254 this%flux(1)%x(i) * &
255 this%coef%area(idx(1), idx(3), facet, idx(4))
256 y(k) = y(k) + &
257 this%flux(2)%x(i) * &
258 this%coef%area(idx(1), idx(3), facet, idx(4))
259 z(k) = z(k) + &
260 this%flux(3)%x(i) * &
261 this%coef%area(idx(1), idx(3), facet, idx(4))
262 case (5,6)
263 x(k) = x(k) + &
264 this%flux(1)%x(i) * &
265 this%coef%area(idx(1), idx(2), facet, idx(4))
266 y(k) = y(k) + &
267 this%flux(2)%x(i) * &
268 this%coef%area(idx(1), idx(2), facet, idx(4))
269 z(k) = z(k) + &
270 this%flux(3)%x(i) * &
271 this%coef%area(idx(1), idx(2), facet, idx(4))
272 end select
273 end do
274 !$omp end parallel do
275 end if
276 end subroutine neumann_apply_vector
277
280 subroutine neumann_apply_scalar_dev(this, x_d, time, strong, strm)
281 class(neumann_t), intent(inout), target :: this
282 type(c_ptr), intent(inout) :: x_d
283 type(time_state_t), intent(in), optional :: time
284 logical, intent(in), optional :: strong
285 type(c_ptr), intent(inout) :: strm
286 logical :: strong_
287
288 if (present(strong)) then
289 strong_ = strong
290 else
291 strong_ = .true.
292 end if
293
294 if (.not. this%uniform_0 .and. this%facet_node_msk(0) .gt. 0 .and. &
295 .not. strong_) then
296 call device_neumann_apply_scalar(this%facet_node_msk_d, &
297 this%facet_d, x_d, &
298 this%flux(1)%x_d, this%coef%area_d, this%coef%Xh%lx, &
299 size(this%facet_node_msk), strm)
300 end if
301 end subroutine neumann_apply_scalar_dev
302
305 subroutine neumann_apply_vector_dev(this, x_d, y_d, z_d, &
306 time, strong, strm)
307 class(neumann_t), intent(inout), target :: this
308 type(c_ptr), intent(inout) :: x_d
309 type(c_ptr), intent(inout) :: y_d
310 type(c_ptr), intent(inout) :: z_d
311 type(time_state_t), intent(in), optional :: time
312 logical, intent(in), optional :: strong
313 type(c_ptr), intent(inout) :: strm
314 logical :: strong_
315
316 if (present(strong)) then
317 strong_ = strong
318 else
319 strong_ = .true.
320 end if
321
322 if (.not. this%uniform_0 .and. this%facet_node_msk(0) .gt. 0 .and. &
323 .not. strong_) then
324 call device_neumann_apply_vector(this%facet_node_msk_d, this%facet_d, &
325 x_d, y_d, z_d, &
326 this%flux(1)%x_d, this%flux(2)%x_d, this%flux(3)%x_d, &
327 this%coef%area_d, this%coef%Xh%lx, &
328 size(this%facet_node_msk), strm)
329 end if
330
331 end subroutine neumann_apply_vector_dev
332
334 subroutine neumann_free(this)
335 class(neumann_t), target, intent(inout) :: this
336 integer :: i
337
338 if (allocated(this%flux)) then
339 do i = 1, size(this%flux)
340 call this%flux(i)%free()
341 end do
342 deallocate(this%flux)
343 end if
344
345 if (allocated(this%init_flux_)) then
346 deallocate(this%init_flux_)
347 end if
348
349 call this%free_base()
350
351 end subroutine neumann_free
352
354 subroutine neumann_finalize(this)
355 class(neumann_t), target, intent(inout) :: this
356 integer :: i
357
358 call this%finalize_base()
359
360 ! Allocate flux vectors and assign to initial constant values
361 do i = 1, size(this%init_flux_)
362 call this%flux(i)%init(this%facet_node_msk(0))
363 this%flux(i) = this%init_flux_(i)
364 end do
365
366 this%uniform_0 = .true.
367
368 do i = 1, size(this%init_flux_)
369 this%uniform_0 = abscmp(this%init_flux_(i), 0.0_rp) .and. this%uniform_0
370 end do
371 end subroutine neumann_finalize
372
376 subroutine neumann_set_flux_scalar(this, flux, comp)
377 class(neumann_t), intent(inout) :: this
378 real(kind=rp), intent(in) :: flux
379 integer, intent(in) :: comp
380
381 if (size(this%flux) .lt. comp) then
382 call neko_error("Component index out of bounds in " // &
383 "neumann_set_flux_scalar")
384 end if
385
386 this%flux(comp) = flux
387 ! If we were uniform zero before, and this comp is set to zero, we are still
388 ! uniform zero
389 this%uniform_0 = abscmp(flux, 0.0_rp) .and. this%uniform_0
390
391 end subroutine neumann_set_flux_scalar
392
396 subroutine neumann_set_flux_array(this, flux, comp)
397 class(neumann_t), intent(inout) :: this
398 type(vector_t), intent(in) :: flux
399 integer, intent(in) :: comp
400 integer :: i
401
402 if (size(this%flux) .lt. comp) then
403 call neko_error("Component index out of bounds in " // &
404 "neuman_set_flux_array")
405 end if
406
407 this%flux(comp) = flux
408
409 ! Once a flux is set explicitly, we no longer assume it is uniform zero.
410 this%uniform_0 = .false.
411
412 end subroutine neumann_set_flux_array
413end module neumann
__inline__ __device__ void nonlinear_index(const int idx, const int lx, int *index)
Definition bc_utils.h:44
Copy data between host and device (or device and device)
Definition device.F90:72
Defines a boundary condition.
Definition bc.f90:34
integer, parameter, public bc_neumann
Definition bc.f90:69
Coefficients.
Definition coef.f90:34
subroutine, public device_copy(a_d, b_d, n, strm)
Copy a vector .
subroutine, public device_cfill(a_d, c, n, strm)
Set all elements to a constant c .
subroutine, public device_neumann_apply_scalar(msk, facet, x, flux, area, lx, m, strm)
subroutine, public device_neumann_apply_vector(msk, facet, x, y, z, flux_x, flux_y, flux_z, area, lx, m, strm)
Device abstraction, common interface for various accelerators.
Definition device.F90:34
integer, parameter, public device_to_host
Definition device.F90:48
Utilities for retrieving parameters from the case files.
Definition math.f90:60
subroutine, public cfill(a, c, n)
Set all elements to a constant c .
Definition math.f90:600
subroutine, public copy(a, b, n)
Copy a vector .
Definition math.f90:294
Build configurations.
integer, parameter neko_bcknd_device
Defines a Neumann boundary condition.
Definition neumann.f90:34
subroutine neumann_init_from_components_array(this, coef, flux)
Constructor from components, using a flux array for vector components.
Definition neumann.f90:136
subroutine neumann_set_flux_scalar(this, flux, comp)
Set the flux using a scalar.
Definition neumann.f90:377
subroutine neumann_set_flux_array(this, flux, comp)
Set a flux component using a vector_t of values.
Definition neumann.f90:397
subroutine neumann_apply_vector_dev(this, x_d, y_d, z_d, time, strong, strm)
Boundary condition apply for a generic Neumann condition to vectors x, y and z (device version)
Definition neumann.f90:307
subroutine neumann_init_from_components_single(this, coef, flux)
Constructor from components, using an signle flux.
Definition neumann.f90:155
subroutine neumann_init(this, coef, json)
Constructor.
Definition neumann.f90:104
subroutine neumann_apply_vector(this, x, y, z, n, time, strong)
Boundary condition apply for a generic Neumann condition to vectors x, y and z.
Definition neumann.f90:215
subroutine neumann_apply_scalar(this, x, n, time, strong)
Boundary condition apply for a generic Neumann condition to a vector x.
Definition neumann.f90:169
subroutine neumann_apply_scalar_dev(this, x_d, time, strong, strm)
Boundary condition apply for a generic Neumann condition to a vector x (device version)
Definition neumann.f90:281
subroutine neumann_free(this)
Destructor.
Definition neumann.f90:335
subroutine neumann_finalize(this)
Finalize by setting the flux.
Definition neumann.f90:355
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
Defines a vector.
Definition vector.f90:34
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 Neumann boundary condition. Sets the flux of the field to the chosen values.
Definition neumann.f90:60
A struct that contains all info about the time, expand as needed.