Neko 1.99.9
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
wall_model.f90
Go to the documentation of this file.
1! Copyright (c) 2024-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!
33!
36 use num_types, only : rp
37 use field, only : field_t
38 use json_module, only : json_file
39 use registry, only : neko_registry
40 use dofmap, only : dofmap_t
41 use coefs, only : coef_t
44 use vector, only : vector_t
48 use user_intf, only : user_t
49 use, intrinsic :: iso_c_binding, only : c_ptr, c_null_ptr
50 use device, only : device_get_ptr
53 implicit none
54 private
55
57 type, abstract, public :: wall_model_t
59 type(coef_t), pointer :: coef => null()
61 type(dofmap_t), pointer :: dof => null()
63 type(field_t), pointer :: mu => null()
65 type(field_t), pointer :: rho => null()
69 character(len=:), allocatable :: scheme_name
71 integer, pointer :: msk(:) => null()
72 type(c_ptr) :: msk_d = c_null_ptr
74 integer, pointer :: facet(:) => null()
76 type(vector_t) :: tau_x
78 type(vector_t) :: tau_y
80 type(vector_t) :: tau_z
82 type(vector_t) :: n_x
84 type(vector_t) :: n_y
86 type(vector_t) :: n_z
88 class(wall_sampler_t), allocatable :: sampler
90 integer :: n_nodes = 0
92 type(field_t), pointer :: tau_field => null()
93 contains
95 procedure, pass(this) :: init_base => wall_model_init_base
97 procedure, pass(this) :: partial_init_base => wall_model_partial_init_base
99 procedure, pass(this) :: finalize_base => wall_model_finalize_base
101 procedure, pass(this) :: free_base => wall_model_free_base
103 procedure, pass(this) :: compute_mag_field => wall_model_compute_mag_field
105 procedure(wall_model_init), pass(this), deferred :: init
111 procedure(wall_model_partial_init), pass(this), deferred :: partial_init
113 procedure(wall_model_finalize), pass(this), deferred :: finalize
115 procedure(wall_model_free), pass(this), deferred :: free
117 procedure(wall_model_compute), pass(this), deferred :: compute
119 procedure, pass(this) :: setup_geometry => wall_model_setup_geometry
121 procedure, pass(this) :: validate_single_sample => &
123 end type wall_model_t
124
125 abstract interface
126
129 subroutine wall_model_compute(this, t, tstep)
130 import wall_model_t, rp
131 class(wall_model_t), intent(inout) :: this
132 real(kind=rp), intent(in) :: t
133 integer, intent(in) :: tstep
134 end subroutine wall_model_compute
135 end interface
136
137 abstract interface
138
145 subroutine wall_model_init(this, scheme_name, coef, msk, facet, &
146 json)
147 import wall_model_t, json_file, dofmap_t, coef_t, rp
148 class(wall_model_t), intent(inout) :: this
149 character(len=*), intent(in) :: scheme_name
150 type(coef_t), intent(in) :: coef
151 integer, intent(in) :: msk(:)
152 integer, intent(in) :: facet(:)
153 type(json_file), intent(inout) :: json
154 end subroutine wall_model_init
155 end interface
156
157 abstract interface
158
163 subroutine wall_model_partial_init(this, coef, scheme_name, json)
164 import wall_model_t, json_file, dofmap_t, coef_t, rp, user_t
165 class(wall_model_t), intent(inout) :: this
166 type(coef_t), intent(in) :: coef
167 character(len=*), intent(in) :: scheme_name
168 type(json_file), intent(inout) :: json
169 end subroutine wall_model_partial_init
170 end interface
171
172 abstract interface
173
176 subroutine wall_model_finalize(this, msk, facet, bc_name, user)
177 import wall_model_t, user_t
178 class(wall_model_t), intent(inout) :: this
179 integer, intent(in) :: msk(:)
180 integer, intent(in) :: facet(:)
181 character(len=*), optional, intent(in) :: bc_name
182 type(user_t), target, optional, intent(in) :: user
183 end subroutine wall_model_finalize
184 end interface
185
186 abstract interface
187
188 subroutine wall_model_free(this)
189 import wall_model_t
190 class(wall_model_t), intent(inout) :: this
191 end subroutine wall_model_free
192 end interface
193
194 interface
195
203 module subroutine wall_model_factory(object, scheme_name, coef, msk, &
204 facet, json)
205 class(wall_model_t), allocatable, intent(inout) :: object
206 character(len=*), intent(in) :: scheme_name
207 type(coef_t), intent(in) :: coef
208 integer, intent(in) :: msk(:)
209 integer, intent(in) :: facet(:)
210 type(json_file), intent(inout) :: json
211 end subroutine wall_model_factory
212 end interface
213
214 interface
215
218 module subroutine wall_model_allocator(object, type_name)
219 class(wall_model_t), allocatable, intent(inout) :: object
220 character(len=:), allocatable, intent(in) :: type_name
221 end subroutine wall_model_allocator
222 end interface
223
224 !
225 ! Machinery for injecting user-defined types
226 !
227
231 abstract interface
232 subroutine wall_model_allocate(obj)
233 import wall_model_t
234 class(wall_model_t), allocatable, intent(inout) :: obj
235 end subroutine wall_model_allocate
236 end interface
237
238 interface
239
240 module subroutine register_wall_model(type_name, allocator)
241 character(len=*), intent(in) :: type_name
242 procedure(wall_model_allocate), pointer, intent(in) :: allocator
243 end subroutine register_wall_model
244 end interface
245
246 ! A name-allocator pair for user-defined types. A helper type to define a
247 ! registry of custom allocators.
248 type allocator_entry
249 character(len=20) :: type_name
250 procedure(wall_model_allocate), pointer, nopass :: allocator
251 end type allocator_entry
252
254 type(allocator_entry), allocatable :: wall_model_registry(:)
255
257 integer :: wall_model_registry_size = 0
258
259 public :: wall_model_factory, wall_model_allocator, register_wall_model, &
260 wall_model_allocate
261
262contains
269 subroutine wall_model_init_base(this, scheme_name, coef, msk, facet, sampler)
270 class(wall_model_t), intent(inout) :: this
271 type(coef_t), target, intent(in) :: coef
272 integer, target, intent(in) :: msk(0:)
273 integer, target, intent(in) :: facet(0:)
274 character(len=*) :: scheme_name
275 class(wall_sampler_t), allocatable, intent(inout) :: sampler
276
277 call this%free_base
278
279 this%coef => coef
280 this%dof => coef%dof
281 if (.not. allocated(sampler)) then
282 call neko_error('Wall model sampler has not been initialized')
283 end if
284 call move_alloc(sampler, this%sampler)
285 this%scheme_name = trim(scheme_name)
286 this%mu => neko_registry%get_field_by_name(this%scheme_name // "_mu")
287 this%rho => neko_registry%get_field_by_name(this%scheme_name // &
288 "_rho")
289
290 call neko_registry%add_field(this%dof, "tau", &
291 ignore_existing = .true.)
292 this%tau_field => neko_registry%get_field("tau")
293
294 call this%finalize_base(msk, facet)
295 end subroutine wall_model_init_base
296
301 subroutine wall_model_partial_init_base(this, coef, scheme_name, json)
302 class(wall_model_t), intent(inout) :: this
303 type(coef_t), target, intent(in) :: coef
304 character(len=*), intent(in) :: scheme_name
305 type(json_file), intent(inout) :: json
306
307 call this%free_base()
308
309 this%coef => coef
310 this%dof => coef%dof
311 call wall_sampler_factory(this%sampler, json)
312 this%scheme_name = trim(scheme_name)
313
314 this%mu => neko_registry%get_field_by_name(this%scheme_name // "_mu")
315 this%rho => neko_registry%get_field_by_name(this%scheme_name // &
316 "_rho")
317
318 call neko_registry%add_field(this%dof, "tau", &
319 ignore_existing = .true.)
320 this%tau_field => neko_registry%get_field("tau")
321 end subroutine wall_model_partial_init_base
322
323 subroutine wall_model_finalize_base(this, msk, facet, bc_name, user)
324 class(wall_model_t), intent(inout) :: this
325 integer, target, intent(in) :: msk(0:)
326 integer, target, intent(in) :: facet(:)
327 character(len=*), optional, intent(in) :: bc_name
328 type(user_t), target, optional, intent(in) :: user
329
330 this%msk(0:msk(0)) => msk
331 if (neko_bcknd_device .eq. 1) this%msk_d = device_get_ptr(msk)
332 this%facet(0:msk(0)) => facet
333
334 call this%tau_x%init(this%msk(0))
335 call this%tau_y%init(this%msk(0))
336 call this%tau_z%init(this%msk(0))
337
338 call this%n_x%init(this%msk(0))
339 call this%n_y%init(this%msk(0))
340 call this%n_z%init(this%msk(0))
341
342 call this%setup_geometry()
343 if (.not. allocated(this%sampler)) then
344 call neko_error('Wall model sampler has not been initialized')
345 end if
346 if (present(bc_name)) then
347 if (present(user)) then
348 call this%sampler%finalize(this%coef, this%msk, this%facet, &
349 this%n_x, this%n_y, this%n_z, bc_name, user)
350 else
351 call this%sampler%finalize(this%coef, this%msk, this%facet, &
352 this%n_x, this%n_y, this%n_z, bc_name)
353 end if
354 else
355 if (this%sampler%user_values) then
356 call neko_error('Wall model user sampler has no boundary context')
357 end if
358 call this%sampler%finalize(this%coef, this%msk, this%facet, &
359 this%n_x, this%n_y, this%n_z)
360 end if
361
362 end subroutine wall_model_finalize_base
363
365 subroutine wall_model_free_base(this)
366 class(wall_model_t), intent(inout) :: this
367
368 nullify(this%coef)
369 nullify(this%msk)
370 nullify(this%facet)
371 nullify(this%tau_field)
372 nullify(this%mu)
373 nullify(this%rho)
374 this%msk_d = c_null_ptr
375
376 call this%tau_x%free()
377 call this%tau_y%free()
378 call this%tau_z%free()
379
380 if (allocated(this%sampler)) then
381 call this%sampler%free()
382 deallocate(this%sampler)
383 end if
384
385 if (allocated(this%scheme_name)) then
386 deallocate(this%scheme_name)
387 end if
388
389 call this%n_x%free()
390 call this%n_y%free()
391 call this%n_z%free()
392
393 nullify(this%dof)
394 end subroutine wall_model_free_base
395
397 subroutine wall_model_setup_geometry(this)
398 class(wall_model_t), intent(inout) :: this
399 integer :: n_nodes, fid, idx(4), i, linear
400 real(kind=rp) :: normal(3)
401
402 call this%coef%require_facets('wall_model')
403
404 n_nodes = this%msk(0)
405 this%n_nodes = n_nodes
406
407 do i = 1, n_nodes
408 linear = this%msk(i)
409 fid = this%facet(i)
410 idx = nonlinear_index(linear, this%coef%Xh%lx, this%coef%Xh%ly,&
411 this%coef%Xh%lz)
412 normal = this%coef%get_normal(idx(1), idx(2), idx(3), idx(4), fid)
413
414 this%n_x%x(i) = normal(1)
415 this%n_y%x(i) = normal(2)
416 this%n_z%x(i) = normal(3)
417
418 end do
419
420 if (neko_bcknd_device .eq. 1) then
421 call device_memcpy(this%n_x%x, this%n_x%x_d, n_nodes, host_to_device, &
422 sync = .false.)
423 call device_memcpy(this%n_y%x, this%n_y%x_d, n_nodes, host_to_device, &
424 sync = .false.)
425 call device_memcpy(this%n_z%x, this%n_z%x_d, n_nodes, host_to_device, &
426 sync = .true.)
427 end if
428
429 end subroutine wall_model_setup_geometry
430
431 subroutine wall_model_validate_single_sample(this)
432 class(wall_model_t), intent(inout) :: this
433
434 if (this%sampler%n_samples /= 1) then
435 call neko_error('This wall model requires exactly one sample per node')
436 end if
437 end subroutine wall_model_validate_single_sample
438
440 class(wall_model_t), intent(inout) :: this
441 integer :: i, m
442 real(kind=rp) :: magtau
443
444 m = this%msk(0)
445 if (m > 0) then
446 if (neko_bcknd_device .eq. 1) then
447 call wall_model_compute_mag_field_device(this%tau_x%x_d, &
448 this%tau_y%x_d, &
449 this%tau_z%x_d, &
450 this%tau_field%x_d, &
451 this%msk_d, m)
452 else
453 do i = 1, m
454 magtau = sqrt(this%tau_x%x(i)**2 + &
455 this%tau_y%x(i)**2 + &
456 this%tau_z%x(i)**2)
457 this%tau_field%x(this%msk(i),1,1,1) = magtau
458 end do
459 end if
460 end if
461
462 end subroutine wall_model_compute_mag_field
463
464end module wall_model
__inline__ __device__ void nonlinear_index(const int idx, const int lx, int *index)
Definition bc_utils.h:44
__global__ void wall_model_compute_mag_field(const T *__restrict__ tau_x_d, const T *__restrict__ tau_y_d, const T *__restrict__ tau_z_d, T *__restrict__ tau_field_d, const int *__restrict__ msk_d, const int m)
Return the device pointer for an associated Fortran array.
Definition device.F90:113
Copy data between host and device (or device and device)
Definition device.F90:72
Retrieves a parameter by name or throws an error.
Compute wall shear stress.
Finilzation of partial construction, similar to bc_t
Common constructor.
Partial constructor from JSON, meant to work as the first stage of initialization before the finalize...
Coefficients.
Definition coef.f90:34
Device abstraction, common interface for various accelerators.
Definition device.F90:34
integer, parameter, public host_to_device
Definition device.F90:48
Defines a mapping of the degrees of freedom.
Definition dofmap.f90:35
Defines a field.
Definition field.f90:34
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:14
Defines a registry for storing solution fields.
Definition registry.f90:34
type(registry_t), target, public neko_registry
Global field registry.
Definition registry.f90:144
Interfaces for user interaction with NEKO.
Definition user_intf.f90:34
Utilities.
Definition utils.f90:35
Defines a vector.
Definition vector.f90:34
Implements the device kernel for the wall_model_t type.
subroutine, public wall_model_compute_mag_field_device(tau_x_d, tau_y_d, tau_z_d, tau_field_d, msk_d, m)
Compute the wall shear stress's magnitude on device.
Implements wall_model_t.
subroutine wall_model_partial_init_base(this, coef, scheme_name, json)
Partial initialization based on JSON, prior to knowing the mask and facets.
subroutine wall_model_init_base(this, scheme_name, coef, msk, facet, sampler)
Constructor for the wall_model_t (base) class.
subroutine wall_model_setup_geometry(this)
Build wall-node normals independently of the sampling strategy.
subroutine wall_model_free_base(this)
Destructor for the wall_model_t (base) class.
subroutine wall_model_validate_single_sample(this)
subroutine wall_model_finalize_base(this, msk, facet, bc_name, user)
Factory for wall-model samplers.
subroutine, public wall_sampler_factory(object, json)
Wall sampler factory.
Defines the abstract interface for wall-model field samplers.
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:93
A type collecting all the overridable user routines and flag to suppress type injection from custom m...
Base abstract type for wall-stress models for wall-modelled LES.
Base type for sampling solution fields at points associated with wall nodes. Samples belonging to one...