Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
non_normal_aligned.f90
Go to the documentation of this file.
1! Copyright (c) 2020-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!
35 use json_module, only : json_file
37 use dirichlet, only : dirichlet_t
40 use num_types, only : rp, dp
41 use tuple, only : tuple_i4_t
42 use coefs, only : coef_t
45 use utils, only : neko_error
46 use vector, only : vector_t
49 use field, only : field_t
51 use time_state, only : time_state_t
52 use, intrinsic :: iso_c_binding, only : c_ptr
53 implicit none
54 private
55
61 type, public, extends(bc_t) :: non_normal_aligned_t
63 type(dirichlet_t) :: bc_x
64 type(dirichlet_t) :: bc_y
65 type(dirichlet_t) :: bc_z
67 type(vector_t) :: value_x
68 type(vector_t) :: value_y
69 type(vector_t) :: value_z
71 real(kind=rp), private :: constant_value(3) = 0.0_rp
72
75 logical, private :: use_constant_value = .true.
76 logical, private :: read_values_from_field = .false.
77 logical, private :: field_interpolate = .false.
78 character(len=:), allocatable, private :: field_file_name
79 character(len=:), allocatable, private :: field_mesh_file_name
80 real(kind=dp), private :: field_interp_tolerance = glob_interp_tol
81 real(kind=dp), private :: field_interp_padding = glob_interp_pad
82 contains
84 procedure, pass(this) :: apply_scalar => non_normal_aligned_apply_scalar
86 procedure, pass(this) :: apply_vector => non_normal_aligned_apply_vector
88 procedure, pass(this) :: apply_scalar_dev => &
91 procedure, pass(this) :: apply_vector_dev => &
94 procedure, pass(this) :: init => non_normal_aligned_init
96 procedure, pass(this) :: init_from_components => &
99 procedure, pass(this) :: set_values => non_normal_aligned_set_values
101 procedure, pass(this) :: free => non_normal_aligned_free
103 procedure, pass(this) :: finalize => non_normal_aligned_finalize
105 procedure, pass(this) :: get_normal_axis => &
107 end type non_normal_aligned_t
108
109contains
110
114 subroutine non_normal_aligned_init(this, coef, json)
115 class(non_normal_aligned_t), target, intent(inout) :: this
116 type(coef_t), target, intent(in) :: coef
117 type(json_file), intent(inout) :: json
118 real(kind=rp), allocatable :: value(:)
119 real(kind=rp) :: value_3(3)
120 logical :: found_file_name, found_value
121
122 call json%info("file_name", found = found_file_name)
123 call json%info("value", found = found_value)
124
125 if (found_file_name .and. found_value) then
126 call neko_error("non_normal_aligned accepts either 'file_name' or " // &
127 "'value', but not both.")
128 end if
129
130 if (found_file_name) then
131 call this%free()
132 call this%init_base(coef)
133 call this%bc_x%init_from_components(coef, 0.0_rp)
134 call this%bc_y%init_from_components(coef, 0.0_rp)
135 call this%bc_z%init_from_components(coef, 0.0_rp)
136 call json_get(json, "file_name", this%field_file_name)
137 call json_get_or_default(json, "interpolate", this%field_interpolate, &
138 .false.)
139 call json_get_or_default(json, "mesh_file_name", &
140 this%field_mesh_file_name, "none")
141 call json_get_or_default(json, "interpolation.tolerance", &
142 this%field_interp_tolerance, glob_interp_tol)
143 call json_get_or_default(json, "interpolation.padding", &
144 this%field_interp_padding, glob_interp_pad)
145 this%read_values_from_field = .true.
146 this%use_constant_value = .false.
147 this%bc_type = bc_mixed_constrains_tangent
148 else
149 value_3 = 0.0_rp
150 call json_get_or_lookup(json, "value", value)
151 if (size(value) .ne. 3) then
152 call neko_error("The non_normal boundary condition requires a " // &
153 "3-component value vector.")
154 end if
155 value_3 = value
156
157 call this%init_from_components(coef, value_3)
158 end if
159 end subroutine non_normal_aligned_init
160
164 subroutine non_normal_aligned_init_from_components(this, coef, value)
165 class(non_normal_aligned_t), target, intent(inout) :: this
166 type(coef_t), target, intent(in) :: coef
167 real(kind=rp), intent(in) :: value(3)
168
169 call this%free()
170 call this%init_base(coef)
171 call this%bc_x%init_from_components(coef, 0.0_rp)
172 call this%bc_y%init_from_components(coef, 0.0_rp)
173 call this%bc_z%init_from_components(coef, 0.0_rp)
174 this%constant_value = value
175 this%use_constant_value = .true.
176 this%bc_type = bc_mixed_constrains_tangent
178
186 subroutine non_normal_aligned_set_values(this, value_x, value_y, value_z)
187 class(non_normal_aligned_t), intent(inout) :: this
188 type(vector_t), intent(in) :: value_x
189 type(vector_t), intent(in) :: value_y
190 type(vector_t), intent(in) :: value_z
191
192 if (.not. allocated(this%bc_x%msk) .or. .not. allocated(this%bc_y%msk) &
193 .or. .not. allocated(this%bc_z%msk)) then
194 call neko_error("non_normal_aligned_set_values requires finalized " // &
195 "nested boundary-condition masks.")
196 end if
197
198 if (value_x%size() .ne. this%bc_x%msk(0) .or. &
199 value_y%size() .ne. this%bc_y%msk(0) .or. &
200 value_z%size() .ne. this%bc_z%msk(0)) then
201 call neko_error("non_normal_aligned_set_values requires compact " // &
202 "component vectors matching bc_x, bc_y and bc_z mask sizes.")
203 end if
204
205 call this%value_x%free()
206 call this%value_y%free()
207 call this%value_z%free()
208 this%value_x = value_x
209 this%value_y = value_y
210 this%value_z = value_z
211 this%read_values_from_field = .false.
212 this%use_constant_value = .false.
213 end subroutine non_normal_aligned_set_values
214
220 subroutine non_normal_aligned_apply_scalar(this, x, n, time, strong)
221 class(non_normal_aligned_t), intent(inout) :: this
222 integer, intent(in) :: n
223 real(kind=rp), intent(inout), dimension(n) :: x
224 type(time_state_t), intent(in), optional :: time
225 logical, intent(in), optional :: strong
227
238 subroutine non_normal_aligned_apply_vector(this, x, y, z, n, time, strong)
239 class(non_normal_aligned_t), intent(inout) :: this
240 integer, intent(in) :: n
241 real(kind=rp), intent(inout), dimension(n) :: x
242 real(kind=rp), intent(inout), dimension(n) :: y
243 real(kind=rp), intent(inout), dimension(n) :: z
244 type(time_state_t), intent(in), optional :: time
245 logical, intent(in), optional :: strong
246 logical :: strong_
247 integer :: i
248
249 if (present(strong)) then
250 strong_ = strong
251 else
252 strong_ = .true.
253 end if
254
255 ! The local coordinates are aligned with the global axes, so the nested
256 ! Dirichlet conditions only provide the masks. The prescribed values are
257 ! stored compactly in the same order as each nested mask.
258 if (strong_) then
259 do i = 1, this%bc_x%msk(0)
260 x(this%bc_x%msk(i)) = this%value_x%x(i)
261 end do
262 do i = 1, this%bc_y%msk(0)
263 y(this%bc_y%msk(i)) = this%value_y%x(i)
264 end do
265 do i = 1, this%bc_z%msk(0)
266 z(this%bc_z%msk(i)) = this%value_z%x(i)
267 end do
268 end if
270
276 subroutine non_normal_aligned_apply_scalar_dev(this, x_d, time, strong, strm)
277 class(non_normal_aligned_t), intent(inout), target :: this
278 type(c_ptr), intent(inout) :: x_d
279 type(time_state_t), intent(in), optional :: time
280 logical, intent(in), optional :: strong
281 type(c_ptr), intent(inout) :: strm
283
293 subroutine non_normal_aligned_apply_vector_dev(this, x_d, y_d, z_d, &
294 time, strong, strm)
295 class(non_normal_aligned_t), intent(inout), target :: this
296 type(c_ptr), intent(inout) :: x_d
297 type(c_ptr), intent(inout) :: y_d
298 type(c_ptr), intent(inout) :: z_d
299 type(time_state_t), intent(in), optional :: time
300 logical, intent(in), optional :: strong
301 type(c_ptr), intent(inout) :: strm
302 logical :: strong_
303
304 if (present(strong)) then
305 strong_ = strong
306 else
307 strong_ = .true.
308 end if
309
310 if (strong_) then
311 if (this%bc_x%msk(0) .gt. 0) then
312 call device_inhom_dirichlet_apply_scalar(this%bc_x%msk_d, x_d, &
313 this%value_x%x_d, this%bc_x%msk(0), strm)
314 end if
315 if (this%bc_y%msk(0) .gt. 0) then
316 call device_inhom_dirichlet_apply_scalar(this%bc_y%msk_d, y_d, &
317 this%value_y%x_d, this%bc_y%msk(0), strm)
318 end if
319 if (this%bc_z%msk(0) .gt. 0) then
320 call device_inhom_dirichlet_apply_scalar(this%bc_z%msk_d, z_d, &
321 this%value_z%x_d, this%bc_z%msk(0), strm)
322 end if
323 end if
325
332 subroutine non_normal_aligned_get_normal_axis(this, sx, sy, sz, facet, el)
333 class(non_normal_aligned_t), target, intent(inout) :: this
334 real(kind=rp), intent(out) :: sx, sy, sz
335 integer, intent(in) :: facet
336 integer, intent(in) :: el
337 integer :: j, l
338
339 associate(c => this%coef, nx => this%coef%nx, ny => this%coef%ny, &
340 nz => this%coef%nz)
341 sx = 0.0_rp
342 sy = 0.0_rp
343 sz = 0.0_rp
344 select case (facet)
345 case (1, 2)
346 do l = 2, c%Xh%lx - 1
347 do j = 2, c%Xh%lx -1
348 sx = sx + abs(abs(nx(l, j, facet, el)) - 1.0_rp)
349 sy = sy + abs(abs(ny(l, j, facet, el)) - 1.0_rp)
350 sz = sz + abs(abs(nz(l, j, facet, el)) - 1.0_rp)
351 end do
352 end do
353 case (3, 4)
354 do l = 2, c%Xh%lx - 1
355 do j = 2, c%Xh%lx - 1
356 sx = sx + abs(abs(nx(l, j, facet, el)) - 1.0_rp)
357 sy = sy + abs(abs(ny(l, j, facet, el)) - 1.0_rp)
358 sz = sz + abs(abs(nz(l, j, facet, el)) - 1.0_rp)
359 end do
360 end do
361 case (5, 6)
362 do l = 2, c%Xh%lx - 1
363 do j = 2, c%Xh%lx - 1
364 sx = sx + abs(abs(nx(l, j, facet, el)) - 1.0_rp)
365 sy = sy + abs(abs(ny(l, j, facet, el)) - 1.0_rp)
366 sz = sz + abs(abs(nz(l, j, facet, el)) - 1.0_rp)
367 end do
368 end do
369 end select
370 sx = sx / (c%Xh%lx - 2)**2
371 sy = sy / (c%Xh%lx - 2)**2
372 sz = sz / (c%Xh%lx - 2)**2
373 end associate
375
381 class(non_normal_aligned_t), target, intent(inout) :: this
382 integer :: i
383 integer :: scratch_idx(3)
384 type(tuple_i4_t), pointer :: bfp(:)
385 real(kind=rp) :: sx, sy, sz
386 real(kind=rp), parameter :: tol = 1d-3
387 type(tuple_i4_t) :: bc_facet
388 integer :: facet, el
389 type(field_t), pointer :: value_x_field, value_y_field, value_z_field
390 associate(c => this%coef, nx => this%coef%nx, ny => this%coef%ny, &
391 nz => this%coef%nz)
392 bfp => this%marked_facet%array()
393 do i = 1, this%marked_facet%size()
394 bc_facet = bfp(i)
395 facet = bc_facet%x(1)
396 el = bc_facet%x(2)
397 call this%get_normal_axis(sx, sy, sz, facet, el)
398
399 if (sx .lt. tol) then
400 call this%bc_y%mark_facet(facet, el)
401 call this%bc_z%mark_facet(facet, el)
402 end if
403
404 if (sy .lt. tol) then
405 call this%bc_x%mark_facet(facet, el)
406 call this%bc_z%mark_facet(facet, el)
407 end if
408
409 if (sz .lt. tol) then
410 call this%bc_y%mark_facet(facet, el)
411 call this%bc_x%mark_facet(facet, el)
412 end if
413 end do
414 end associate
415 call this%bc_x%finalize()
416 call this%bc_y%finalize()
417 call this%bc_z%finalize()
418
419 call this%value_x%init(this%bc_x%msk(0), 'non_normal_aligned_x')
420 call this%value_y%init(this%bc_y%msk(0), 'non_normal_aligned_y')
421 call this%value_z%init(this%bc_z%msk(0), 'non_normal_aligned_z')
422
423 if (this%use_constant_value) then
424 this%value_x = this%constant_value(1)
425 this%value_y = this%constant_value(2)
426 this%value_z = this%constant_value(3)
427 else if (this%read_values_from_field) then
428 call neko_scratch_registry%request_field(value_x_field, scratch_idx(1), &
429 .true.)
430 call neko_scratch_registry%request_field(value_y_field, scratch_idx(2), &
431 .true.)
432 call neko_scratch_registry%request_field(value_z_field, scratch_idx(3), &
433 .true.)
434
435 if (trim(this%field_mesh_file_name) .eq. "none") then
436 call import_fields(this%field_file_name, &
437 u = value_x_field, v = value_y_field, w = value_z_field, &
438 interpolate = this%field_interpolate, &
439 tolerance = this%field_interp_tolerance, &
440 padding = this%field_interp_padding)
441 else
442 call import_fields(this%field_file_name, this%field_mesh_file_name, &
443 u = value_x_field, v = value_y_field, w = value_z_field, &
444 interpolate = this%field_interpolate, &
445 tolerance = this%field_interp_tolerance, &
446 padding = this%field_interp_padding)
447 end if
448
449 call vector_masked_gather_copy_0(this%value_x, &
450 value_x_field%x(:,1,1,1), this%bc_x%msk, value_x_field%size(), &
451 this%bc_x%msk(0))
452 call vector_masked_gather_copy_0(this%value_y, &
453 value_y_field%x(:,1,1,1), this%bc_y%msk, value_y_field%size(), &
454 this%bc_y%msk(0))
455 call vector_masked_gather_copy_0(this%value_z, &
456 value_z_field%x(:,1,1,1), this%bc_z%msk, value_z_field%size(), &
457 this%bc_z%msk(0))
458 call neko_scratch_registry%relinquish_field(scratch_idx)
459 end if
460
461 call this%finalize_base()
462 end subroutine non_normal_aligned_finalize
463
465 subroutine non_normal_aligned_free(this)
466 class(non_normal_aligned_t), target, intent(inout) :: this
467
468 call this%bc_x%free()
469 call this%bc_y%free()
470 call this%bc_z%free()
471 call this%value_x%free()
472 call this%value_y%free()
473 call this%value_z%free()
474
475 if (allocated(this%field_file_name)) then
476 deallocate(this%field_file_name)
477 end if
478 if (allocated(this%field_mesh_file_name)) then
479 deallocate(this%field_mesh_file_name)
480 end if
481
482 this%field_interpolate = .false.
483 this%field_interp_tolerance = glob_interp_tol
484 this%field_interp_padding = glob_interp_pad
485 this%read_values_from_field = .false.
486 call this%free_base()
487 end subroutine non_normal_aligned_free
488end module non_normal_aligned
Retrieves a parameter by name or assigns a provided default value. In the latter case also adds the m...
Retrieves a parameter by name or throws an error.
Defines a boundary condition.
Definition bc.f90:34
integer, parameter, public bc_mixed_constrains_tangent
Definition bc.f90:68
Coefficients.
Definition coef.f90:34
Device backend wrappers for inhomogeneous Dirichlet boundary conditions.
subroutine device_inhom_dirichlet_apply_scalar(msk, x, bla_x, m, strm)
Apply an inhomogeneous Dirichlet condition to a scalar field on the device.
Defines a dirichlet boundary condition.
Definition dirichlet.f90:34
Defines a field.
Definition field.f90:34
Implements global_interpolation given a dofmap.
real(kind=dp), parameter, public glob_interp_tol
real(kind=dp), parameter, public glob_interp_pad
Importation of fields from fld files.
Utilities for retrieving parameters from the case files.
Implements non_normal_aligned_t.
subroutine non_normal_aligned_free(this)
Free the boundary condition and its nested storage.
subroutine non_normal_aligned_set_values(this, value_x, value_y, value_z)
Set inhomogeneous prescribed global vector components.
subroutine non_normal_aligned_apply_scalar_dev(this, x_d, time, strong, strm)
No-op scalar application on the device.
subroutine non_normal_aligned_apply_vector(this, x, y, z, n, time, strong)
Apply the tangential components of the prescribed vector on the CPU.
subroutine non_normal_aligned_get_normal_axis(this, sx, sy, sz, facet, el)
Estimate which global axis is normal to a marked facet.
subroutine non_normal_aligned_init_from_components(this, coef, value)
Construct the boundary condition from a uniform global vector.
subroutine non_normal_aligned_apply_vector_dev(this, x_d, y_d, z_d, time, strong, strm)
Apply the tangential components of the prescribed vector on the device.
subroutine non_normal_aligned_init(this, coef, json)
Construct the boundary condition from JSON.
subroutine non_normal_aligned_finalize(this)
Finalize the boundary condition.
subroutine non_normal_aligned_apply_scalar(this, x, n, time, strong)
No-op scalar application.
integer, parameter, public dp
Definition num_types.f90:10
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:14
Defines a registry for storing and requesting temporary objects This can be used when you have a func...
type(scratch_registry_t), target, public neko_scratch_registry
Global scratch registry.
Module with things related to the simulation time.
Implements a n-tuple.
Definition tuple.f90:41
Utilities.
Definition utils.f90:35
subroutine, public vector_masked_gather_copy_0(a, b, mask, n, n_mask)
Gather a vector to reduced contigous array .
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
Generic Dirichlet boundary condition on .
Definition dirichlet.f90:49
Axis-aligned mixed Dirichlet condition in the non-normal direction.
A struct that contains all info about the time, expand as needed.
Integer based 2-tuple.
Definition tuple.f90:58