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 real(kind=rp) :: area
178 logical :: strong_
179
180 if (present(strong)) then
181 strong_ = strong
182 else
183 strong_ = .true.
184 end if
185
186 m = this%facet_node_msk(0)
187 if (.not. strong_) then
188 !$omp do
189 do i = 1, m
190 k = this%facet_node_msk(i)
191 facet = this%facet(i)
192 idx = nonlinear_index(k, this%coef%Xh%lx, this%coef%Xh%lx, &
193 this%coef%Xh%lx)
194 area = 0.0_rp
195 select case (facet)
196 case (1,2)
197 area = this%coef%area(idx(2), idx(3), facet, idx(4))
198 case (3,4)
199 area = this%coef%area(idx(1), idx(3), facet, idx(4))
200 case (5,6)
201 area = this%coef%area(idx(1), idx(2), facet, idx(4))
202 end select
203 !$omp atomic
204 x(k) = x(k) + this%flux(1)%x(i) * area
205 end do
206 !$omp end do
207 end if
208 end subroutine neumann_apply_scalar
209
212 subroutine neumann_apply_vector(this, x, y, z, n, time, strong)
213 class(neumann_t), intent(inout) :: this
214 integer, intent(in) :: n
215 real(kind=rp), intent(inout), dimension(n) :: x
216 real(kind=rp), intent(inout), dimension(n) :: y
217 real(kind=rp), intent(inout), dimension(n) :: z
218 type(time_state_t), intent(in), optional :: time
219 logical, intent(in), optional :: strong
220 integer :: i, m, k, facet
221 ! Store non-linear index
222 integer :: idx(4)
223 real(kind=rp) :: area
224 logical :: strong_
225
226 if (present(strong)) then
227 strong_ = strong
228 else
229 strong_ = .true.
230 end if
231
232 m = this%facet_node_msk(0)
233 if (.not. strong_) then
234 !$omp do
235 do i = 1, m
236 k = this%facet_node_msk(i)
237 facet = this%facet(i)
238 idx = nonlinear_index(k, this%coef%Xh%lx, this%coef%Xh%lx, &
239 this%coef%Xh%lx)
240 area = 0.0_rp
241 select case (facet)
242 case (1,2)
243 area = this%coef%area(idx(2), idx(3), facet, idx(4))
244 case (3,4)
245 area = this%coef%area(idx(1), idx(3), facet, idx(4))
246 case (5,6)
247 area = this%coef%area(idx(1), idx(2), facet, idx(4))
248 end select
249 !$omp atomic
250 x(k) = x(k) + this%flux(1)%x(i) * area
251 !$omp atomic
252 y(k) = y(k) + this%flux(2)%x(i) * area
253 !$omp atomic
254 z(k) = z(k) + this%flux(3)%x(i) * area
255 end do
256 !$omp end do
257 end if
258 end subroutine neumann_apply_vector
259
262 subroutine neumann_apply_scalar_dev(this, x_d, time, strong, strm)
263 class(neumann_t), intent(inout), target :: this
264 type(c_ptr), intent(inout) :: x_d
265 type(time_state_t), intent(in), optional :: time
266 logical, intent(in), optional :: strong
267 type(c_ptr), intent(inout) :: strm
268 logical :: strong_
269
270 if (present(strong)) then
271 strong_ = strong
272 else
273 strong_ = .true.
274 end if
275
276 if (.not. this%uniform_0 .and. this%facet_node_msk(0) .gt. 0 .and. &
277 .not. strong_) then
278 call device_neumann_apply_scalar(this%facet_node_msk_d, &
279 this%facet_d, x_d, &
280 this%flux(1)%x_d, this%coef%area_d, this%coef%Xh%lx, &
281 size(this%facet_node_msk), strm)
282 end if
283 end subroutine neumann_apply_scalar_dev
284
287 subroutine neumann_apply_vector_dev(this, x_d, y_d, z_d, &
288 time, strong, strm)
289 class(neumann_t), intent(inout), target :: this
290 type(c_ptr), intent(inout) :: x_d
291 type(c_ptr), intent(inout) :: y_d
292 type(c_ptr), intent(inout) :: z_d
293 type(time_state_t), intent(in), optional :: time
294 logical, intent(in), optional :: strong
295 type(c_ptr), intent(inout) :: strm
296 logical :: strong_
297
298 if (present(strong)) then
299 strong_ = strong
300 else
301 strong_ = .true.
302 end if
303
304 if (.not. this%uniform_0 .and. this%facet_node_msk(0) .gt. 0 .and. &
305 .not. strong_) then
306 call device_neumann_apply_vector(this%facet_node_msk_d, this%facet_d, &
307 x_d, y_d, z_d, &
308 this%flux(1)%x_d, this%flux(2)%x_d, this%flux(3)%x_d, &
309 this%coef%area_d, this%coef%Xh%lx, &
310 size(this%facet_node_msk), strm)
311 end if
312
313 end subroutine neumann_apply_vector_dev
314
316 subroutine neumann_free(this)
317 class(neumann_t), target, intent(inout) :: this
318 integer :: i
319
320 if (allocated(this%flux)) then
321 do i = 1, size(this%flux)
322 call this%flux(i)%free()
323 end do
324 deallocate(this%flux)
325 end if
326
327 if (allocated(this%init_flux_)) then
328 deallocate(this%init_flux_)
329 end if
330
331 call this%free_base()
332
333 end subroutine neumann_free
334
336 subroutine neumann_finalize(this)
337 class(neumann_t), target, intent(inout) :: this
338 integer :: i
339
340 call this%finalize_base()
341
342 ! Allocate flux vectors and assign to initial constant values
343 do i = 1, size(this%init_flux_)
344 call this%flux(i)%init(this%facet_node_msk(0))
345 this%flux(i) = this%init_flux_(i)
346 end do
347
348 this%uniform_0 = .true.
349
350 do i = 1, size(this%init_flux_)
351 this%uniform_0 = abscmp(this%init_flux_(i), 0.0_rp) .and. this%uniform_0
352 end do
353 end subroutine neumann_finalize
354
358 subroutine neumann_set_flux_scalar(this, flux, comp)
359 class(neumann_t), intent(inout) :: this
360 real(kind=rp), intent(in) :: flux
361 integer, intent(in) :: comp
362
363 if (size(this%flux) .lt. comp) then
364 call neko_error("Component index out of bounds in " // &
365 "neumann_set_flux_scalar")
366 end if
367
368 this%flux(comp) = flux
369 ! If we were uniform zero before, and this comp is set to zero, we are still
370 ! uniform zero
371 this%uniform_0 = abscmp(flux, 0.0_rp) .and. this%uniform_0
372
373 end subroutine neumann_set_flux_scalar
374
378 subroutine neumann_set_flux_array(this, flux, comp)
379 class(neumann_t), intent(inout) :: this
380 type(vector_t), intent(in) :: flux
381 integer, intent(in) :: comp
382 integer :: i
383
384 if (size(this%flux) .lt. comp) then
385 call neko_error("Component index out of bounds in " // &
386 "neuman_set_flux_array")
387 end if
388
389 this%flux(comp) = flux
390
391 ! Once a flux is set explicitly, we no longer assume it is uniform zero.
392 this%uniform_0 = .false.
393
394 end subroutine neumann_set_flux_array
395end 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:70
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:601
subroutine, public copy(a, b, n)
Copy a vector .
Definition math.f90:295
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:359
subroutine neumann_set_flux_array(this, flux, comp)
Set a flux component using a vector_t of values.
Definition neumann.f90:379
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:289
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:213
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:263
subroutine neumann_free(this)
Destructor.
Definition neumann.f90:317
subroutine neumann_finalize(this)
Finalize by setting the flux.
Definition neumann.f90:337
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:73
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:135
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.