Neko 1.1.2
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
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 this%strong = .false.
112
113 ! Try to read array from json
114 call json%get("flux", this%init_flux_, found)
115
116 ! If we haven't found an array, try to read a single value
117 if (.not. found) then
118 call json_get_or_lookup(json, "flux", flux)
119 allocate(this%init_flux_(1))
120 this%init_flux_(1) = flux
121 end if
122
123 if ((size(this%init_flux_) .ne. 1) &
124 .and. (size(this%init_flux_) .ne. 3)) then
125 call neko_error("Neumann BC flux must be a scalar or a 3-component" // &
126 " vector.")
127 end if
128
129 allocate(this%flux(size(this%init_flux_)))
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_)))
149
153 subroutine neumann_init_from_components_single(this, coef, flux)
154 class(neumann_t), intent(inout), target :: this
155 type(coef_t), intent(in) :: coef
156 real(kind=rp), intent(in) :: flux
157
158 call this%init_base(coef)
159 allocate(this%init_flux_(1))
160 this%init_flux_(1) = flux
161 allocate(this%flux(size(this%init_flux_)))
163
166 subroutine neumann_apply_scalar(this, x, n, time, strong)
167 class(neumann_t), intent(inout) :: this
168 integer, intent(in) :: n
169 real(kind=rp), intent(inout), dimension(n) :: x
170 type(time_state_t), intent(in), optional :: time
171 logical, intent(in), optional :: strong
172 integer :: i, m, k, facet
173 ! Store non-linear index
174 integer :: idx(4)
175 real(kind=rp) :: area
176 logical :: strong_
177
178 if (present(strong)) then
179 strong_ = strong
180 else
181 strong_ = .true.
182 end if
183
184 m = this%msk(0)
185 if (.not. strong_) then
186 !$omp do
187 do i = 1,m
188 k = this%msk(i)
189 facet = this%facet(i)
190 idx = nonlinear_index(k, this%coef%Xh%lx, this%coef%Xh%lx, &
191 this%coef%Xh%lx)
192 area = 0.0_rp
193 select case (facet)
194 case (1,2)
195 area = this%coef%area(idx(2), idx(3), facet, idx(4))
196 case (3,4)
197 area = this%coef%area(idx(1), idx(3), facet, idx(4))
198 case (5,6)
199 area = this%coef%area(idx(1), idx(2), facet, idx(4))
200 end select
201 !$omp atomic
202 x(k) = x(k) + this%flux(1)%x(i) * area
203 end do
204 !$omp end do
205 end if
206 end subroutine neumann_apply_scalar
207
210 subroutine neumann_apply_vector(this, x, y, z, n, time, strong)
211 class(neumann_t), intent(inout) :: this
212 integer, intent(in) :: n
213 real(kind=rp), intent(inout), dimension(n) :: x
214 real(kind=rp), intent(inout), dimension(n) :: y
215 real(kind=rp), intent(inout), dimension(n) :: z
216 type(time_state_t), intent(in), optional :: time
217 logical, intent(in), optional :: strong
218 integer :: i, m, k, facet
219 ! Store non-linear index
220 integer :: idx(4)
221 real(kind=rp) :: area
222 logical :: strong_
223
224 if (present(strong)) then
225 strong_ = strong
226 else
227 strong_ = .true.
228 end if
229
230 m = this%msk(0)
231 if (.not. strong_) then
232 !$omp do
233 do i = 1, m
234 k = this%msk(i)
235 facet = this%facet(i)
236 idx = nonlinear_index(k, this%coef%Xh%lx, this%coef%Xh%lx, &
237 this%coef%Xh%lx)
238 area = 0.0_rp
239 select case (facet)
240 case (1,2)
241 area = this%coef%area(idx(2), idx(3), facet, idx(4))
242 case (3,4)
243 area = this%coef%area(idx(1), idx(3), facet, idx(4))
244 case (5,6)
245 area = this%coef%area(idx(1), idx(2), facet, idx(4))
246 end select
247 !$omp atomic
248 x(k) = x(k) + this%flux(1)%x(i) * area
249 !$omp atomic
250 y(k) = y(k) + this%flux(2)%x(i) * area
251 !$omp atomic
252 z(k) = z(k) + this%flux(3)%x(i) * area
253 end do
254 !$omp end do
255 end if
256 end subroutine neumann_apply_vector
257
260 subroutine neumann_apply_scalar_dev(this, x_d, time, strong, strm)
261 class(neumann_t), intent(inout), target :: this
262 type(c_ptr), intent(inout) :: x_d
263 type(time_state_t), intent(in), optional :: time
264 logical, intent(in), optional :: strong
265 type(c_ptr), intent(inout) :: strm
266 logical :: strong_
267
268 if (present(strong)) then
269 strong_ = strong
270 else
271 strong_ = .true.
272 end if
273
274 if (.not. this%uniform_0 .and. this%msk(0) .gt. 0 .and. &
275 .not. strong_) then
276 call device_neumann_apply_scalar(this%msk_d, this%facet_d, x_d, &
277 this%flux(1)%x_d, this%coef%area_d, this%coef%Xh%lx, &
278 size(this%msk), strm)
279 end if
280 end subroutine neumann_apply_scalar_dev
281
284 subroutine neumann_apply_vector_dev(this, x_d, y_d, z_d, &
285 time, strong, strm)
286 class(neumann_t), intent(inout), target :: this
287 type(c_ptr), intent(inout) :: x_d
288 type(c_ptr), intent(inout) :: y_d
289 type(c_ptr), intent(inout) :: z_d
290 type(time_state_t), intent(in), optional :: time
291 logical, intent(in), optional :: strong
292 type(c_ptr), intent(inout) :: strm
293 logical :: strong_
294
295 if (present(strong)) then
296 strong_ = strong
297 else
298 strong_ = .true.
299 end if
300
301 if (.not. this%uniform_0 .and. this%msk(0) .gt. 0 .and. &
302 .not. strong_) then
303 call device_neumann_apply_vector(this%msk_d, this%facet_d, &
304 x_d, y_d, z_d, &
305 this%flux(1)%x_d, this%flux(2)%x_d, this%flux(3)%x_d, &
306 this%coef%area_d, this%coef%Xh%lx, &
307 size(this%msk), strm)
308 end if
309
310 end subroutine neumann_apply_vector_dev
311
313 subroutine neumann_free(this)
314 class(neumann_t), target, intent(inout) :: this
315 integer :: i
316
317 if (allocated(this%flux)) then
318 do i = 1, size(this%flux)
319 call this%flux(i)%free()
320 end do
321 deallocate(this%flux)
322 end if
323
324 if (allocated(this%init_flux_)) then
325 deallocate(this%init_flux_)
326 end if
327
328 call this%free_base()
329
330 end subroutine neumann_free
331
333 subroutine neumann_finalize(this, only_facets)
334 class(neumann_t), target, intent(inout) :: this
335 logical, optional, intent(in) :: only_facets
336 integer :: i
337
338 if (present(only_facets)) then
339 if (.not. only_facets) then
340 call neko_error("For neumann_t, only_facets has to be true.")
341 end if
342 end if
343
344 call this%finalize_base(.true.)
345
346 ! Allocate flux vectors and assign to initial constant values
347 do i = 1, size(this%init_flux_)
348 call this%flux(i)%init(this%msk(0))
349 this%flux(i) = this%init_flux_(i)
350 end do
351
352 this%uniform_0 = .true.
353
354 do i = 1, size(this%init_flux_)
355 this%uniform_0 = abscmp(this%init_flux_(i), 0.0_rp) .and. this%uniform_0
356 end do
357 end subroutine neumann_finalize
358
362 subroutine neumann_set_flux_scalar(this, flux, comp)
363 class(neumann_t), intent(inout) :: this
364 real(kind=rp), intent(in) :: flux
365 integer, intent(in) :: comp
366
367 if (size(this%flux) .lt. comp) then
368 call neko_error("Component index out of bounds in " // &
369 "neumann_set_flux_scalar")
370 end if
371
372 this%flux(comp) = flux
373 ! If we were uniform zero before, and this comp is set to zero, we are still
374 ! uniform zero
375 this%uniform_0 = abscmp(flux, 0.0_rp) .and. this%uniform_0
376
377 end subroutine neumann_set_flux_scalar
378
382 subroutine neumann_set_flux_array(this, flux, comp)
383 class(neumann_t), intent(inout) :: this
384 type(vector_t), intent(in) :: flux
385 integer, intent(in) :: comp
386 integer :: i
387
388 if (size(this%flux) .lt. comp) then
389 call neko_error("Component index out of bounds in " // &
390 "neuman_set_flux_array")
391 end if
392
393 this%flux(comp) = flux
394
395 ! Once a flux is set explicitly, we no longer assume it is uniform zero.
396 this%uniform_0 = .false.
397
398 end subroutine neumann_set_flux_array
399end 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
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:597
subroutine, public copy(a, b, n)
Copy a vector .
Definition math.f90:291
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:363
subroutine neumann_set_flux_array(this, flux, comp)
Set a flux component using a vector_t of values.
Definition neumann.f90:383
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:286
subroutine neumann_finalize(this, only_facets)
Finalize by setting the flux.
Definition neumann.f90:334
subroutine neumann_init_from_components_single(this, coef, flux)
Constructor from components, using an signle flux.
Definition neumann.f90:154
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:211
subroutine neumann_apply_scalar(this, x, n, time, strong)
Boundary condition apply for a generic Neumann condition to a vector x.
Definition neumann.f90:167
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:261
subroutine neumann_free(this)
Destructor.
Definition neumann.f90:314
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
Defines a vector.
Definition vector.f90:34
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 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.