Neko 1.99.2
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, 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
46 use math, only : glmin, glmax
47 use comm, only : pe_rank
49 use file, only : file_t
50 use, intrinsic :: iso_c_binding, only : c_ptr, c_null_ptr, c_associated
53 use json_utils, only : json_get
54 implicit none
55 private
56
58 type, abstract, public :: wall_model_t
60 type(coef_t), pointer :: coef => null()
62 type(dofmap_t), pointer :: dof => null()
64 type(field_t), pointer :: mu => null()
66 type(field_t), pointer :: rho => null()
70 character(len=:), allocatable :: scheme_name
72 integer, pointer :: msk(:) => null()
73 type(c_ptr) :: msk_d = c_null_ptr
75 integer, pointer :: facet(:) => null()
77 type(vector_t) :: tau_x
79 type(vector_t) :: tau_y
81 type(vector_t) :: tau_z
83 type(vector_t) :: n_x
85 type(vector_t) :: n_y
87 type(vector_t) :: n_z
89 integer, allocatable :: ind_r(:)
90 type(c_ptr) :: ind_r_d = c_null_ptr
92 integer, allocatable :: ind_s(:)
93 type(c_ptr) :: ind_s_d = c_null_ptr
95 integer, allocatable :: ind_t(:)
96 type(c_ptr) :: ind_t_d = c_null_ptr
98 integer, allocatable :: ind_e(:)
99 type(c_ptr) :: ind_e_d = c_null_ptr
101 type(vector_t) :: h
103 integer :: h_index = 0
105 integer :: n_nodes = 0
107 type(field_t), pointer :: tau_field => null()
108 contains
110 procedure, pass(this) :: init_base => wall_model_init_base
112 procedure, pass(this) :: partial_init_base => wall_model_partial_init_base
114 procedure, pass(this) :: finalize_base => wall_model_finalize_base
116 procedure, pass(this) :: free_base => wall_model_free_base
118 procedure, pass(this) :: compute_mag_field => wall_model_compute_mag_field
120 procedure(wall_model_init), pass(this), deferred :: init
128 procedure(wall_model_partial_init), pass(this), deferred :: partial_init
130 procedure(wall_model_finalize), pass(this), deferred :: finalize
132 procedure(wall_model_free), pass(this), deferred :: free
134 procedure(wall_model_compute), pass(this), deferred :: compute
136 procedure, pass(this) :: find_points => wall_model_find_points
137 end type wall_model_t
138
139 abstract interface
140
143 subroutine wall_model_compute(this, t, tstep)
144 import wall_model_t, rp
145 class(wall_model_t), intent(inout) :: this
146 real(kind=rp), intent(in) :: t
147 integer, intent(in) :: tstep
148 end subroutine wall_model_compute
149 end interface
150
151 abstract interface
152
160 subroutine wall_model_init(this, scheme_name, coef, msk, facet, &
161 h_index, json)
162 import wall_model_t, json_file, dofmap_t, coef_t, rp
163 class(wall_model_t), intent(inout) :: this
164 character(len=*), intent(in) :: scheme_name
165 type(coef_t), intent(in) :: coef
166 integer, intent(in) :: msk(:)
167 integer, intent(in) :: facet(:)
168 integer, intent(in) :: h_index
169 type(json_file), intent(inout) :: json
170 end subroutine wall_model_init
171 end interface
172
173 abstract interface
174
178 subroutine wall_model_partial_init(this, coef, json)
179 import wall_model_t, json_file, dofmap_t, coef_t, rp
180 class(wall_model_t), intent(inout) :: this
181 type(coef_t), intent(in) :: coef
182 type(json_file), intent(inout) :: json
183 end subroutine wall_model_partial_init
184 end interface
185
186 abstract interface
187
190 subroutine wall_model_finalize(this, msk, facet)
191 import wall_model_t
192 class(wall_model_t), intent(inout) :: this
193 integer, intent(in) :: msk(:)
194 integer, intent(in) :: facet(:)
195 end subroutine wall_model_finalize
196 end interface
197
198 abstract interface
199
200 subroutine wall_model_free(this)
201 import wall_model_t
202 class(wall_model_t), intent(inout) :: this
203 end subroutine wall_model_free
204 end interface
205
206 interface
207
216 module subroutine wall_model_factory(object, scheme_name, coef, msk, &
217 facet, json)
218 class(wall_model_t), allocatable, intent(inout) :: object
219 character(len=*), intent(in) :: scheme_name
220 type(coef_t), intent(in) :: coef
221 integer, intent(in) :: msk(:)
222 integer, intent(in) :: facet(:)
223 type(json_file), intent(inout) :: json
224 end subroutine wall_model_factory
225 end interface
226
227 interface
228
231 module subroutine wall_model_allocator(object, type_name)
232 class(wall_model_t), allocatable, intent(inout) :: object
233 character(len=:), allocatable, intent(in) :: type_name
234 end subroutine wall_model_allocator
235 end interface
236
237 !
238 ! Machinery for injecting user-defined types
239 !
240
244 abstract interface
245 subroutine wall_model_allocate(obj)
246 import wall_model_t
247 class(wall_model_t), allocatable, intent(inout) :: obj
248 end subroutine wall_model_allocate
249 end interface
250
251 interface
252
253 module subroutine register_wall_model(type_name, allocator)
254 character(len=*), intent(in) :: type_name
255 procedure(wall_model_allocate), pointer, intent(in) :: allocator
256 end subroutine register_wall_model
257 end interface
258
259 ! A name-allocator pair for user-defined types. A helper type to define a
260 ! registry of custom allocators.
261 type allocator_entry
262 character(len=20) :: type_name
263 procedure(wall_model_allocate), pointer, nopass :: allocator
264 end type allocator_entry
265
267 type(allocator_entry), allocatable :: wall_model_registry(:)
268
270 integer :: wall_model_registry_size = 0
271
272 public :: wall_model_factory, wall_model_allocator, register_wall_model, &
273 wall_model_allocate
274
275contains
282 subroutine wall_model_init_base(this, scheme_name, coef, msk, facet, index)
283 class(wall_model_t), intent(inout) :: this
284 type(coef_t), target, intent(in) :: coef
285 integer, target, intent(in) :: msk(0:)
286 integer, target, intent(in) :: facet(0:)
287 character(len=*) :: scheme_name
288 integer, intent(in) :: index
289
290 call this%free_base
291
292 this%coef => coef
293 this%dof => coef%dof
294 this%h_index = index
295 this%scheme_name = trim(scheme_name)
296 this%mu => neko_registry%get_field_by_name(this%scheme_name // "_mu")
297 this%rho => neko_registry%get_field_by_name(this%scheme_name // &
298 "_rho")
299
300 call neko_registry%add_field(this%dof, "tau", &
301 ignore_existing = .true.)
302 this%tau_field => neko_registry%get_field("tau")
303
304 call this%finalize_base(msk, facet)
305 end subroutine wall_model_init_base
306
311 subroutine wall_model_partial_init_base(this, coef, json)
312 class(wall_model_t), intent(inout) :: this
313 type(coef_t), target, intent(in) :: coef
314 type(json_file), intent(inout) :: json
315
316 call this%free_base()
317
318 this%coef => coef
319 this%dof => coef%dof
320 call json_get(json, "h_index", this%h_index)
321 call json_get(json, "scheme_name", this%scheme_name)
322
323 this%mu => neko_registry%get_field_by_name(this%scheme_name // "_mu")
324 this%rho => neko_registry%get_field_by_name(this%scheme_name // &
325 "_rho")
326
327 call neko_registry%add_field(this%dof, "tau", &
328 ignore_existing = .true.)
329 this%tau_field => neko_registry%get_field("tau")
330 end subroutine wall_model_partial_init_base
331
332 subroutine wall_model_finalize_base(this, msk, facet)
333 class(wall_model_t), intent(inout) :: this
334 integer, target, intent(in) :: msk(0:)
335 integer, target, intent(in) :: facet(:)
336
337 this%msk(0:msk(0)) => msk
338 if (neko_bcknd_device .eq. 1) this%msk_d = device_get_ptr(msk)
339 this%facet(0:msk(0)) => facet
340
341 call this%tau_x%init(this%msk(0))
342 call this%tau_y%init(this%msk(0))
343 call this%tau_z%init(this%msk(0))
344
345 allocate(this%ind_r(this%msk(0)))
346 allocate(this%ind_s(this%msk(0)))
347 allocate(this%ind_t(this%msk(0)))
348 allocate(this%ind_e(this%msk(0)))
349
350 call this%h%init(this%msk(0))
351 call this%n_x%init(this%msk(0))
352 call this%n_y%init(this%msk(0))
353 call this%n_z%init(this%msk(0))
354
355 call this%find_points()
356
357 ! Initialize pointers for device
358 if (neko_bcknd_device .eq. 1) then
359 call device_map(this%ind_r, this%ind_r_d, this%n_nodes)
360 call device_map(this%ind_s, this%ind_s_d, this%n_nodes)
361 call device_map(this%ind_t, this%ind_t_d, this%n_nodes)
362 call device_map(this%ind_e, this%ind_e_d, this%n_nodes)
363 call device_memcpy(this%ind_r, this%ind_r_d, this%n_nodes, &
364 host_to_device, sync = .false.)
365 call device_memcpy(this%ind_s, this%ind_s_d, this%n_nodes, &
366 host_to_device, sync = .false.)
367 call device_memcpy(this%ind_t, this%ind_t_d, this%n_nodes, &
368 host_to_device, sync = .false.)
369 call device_memcpy(this%ind_e, this%ind_e_d, this%n_nodes, &
370 host_to_device, sync = .false.)
371 end if
372
373 end subroutine wall_model_finalize_base
374
376 subroutine wall_model_free_base(this)
377 class(wall_model_t), intent(inout) :: this
378
379 nullify(this%coef)
380 nullify(this%msk)
381 nullify(this%facet)
382 nullify(this%tau_field)
383 nullify(this%mu)
384 nullify(this%rho)
385
386 call this%tau_x%free()
387 call this%tau_y%free()
388 call this%tau_z%free()
389
390 if (allocated(this%ind_r)) then
391 deallocate(this%ind_r)
392 end if
393 if (allocated(this%ind_s)) then
394 deallocate(this%ind_s)
395 end if
396 if (allocated(this%ind_t)) then
397 deallocate(this%ind_t)
398 end if
399 if (allocated(this%ind_e)) then
400 deallocate(this%ind_e)
401 end if
402
403 if (c_associated(this%msk_d)) then
404 call device_free(this%msk_d)
405 end if
406 if (c_associated(this%ind_r_d)) then
407 call device_free(this%ind_r_d)
408 end if
409 if (c_associated(this%ind_s_d)) then
410 call device_free(this%ind_s_d)
411 end if
412 if (c_associated(this%ind_t_d)) then
413 call device_free(this%ind_t_d)
414 end if
415 if (c_associated(this%ind_e_d)) then
416 call device_free(this%ind_e_d)
417 end if
418
419 if (allocated(this%scheme_name)) then
420 deallocate(this%scheme_name)
421 end if
422
423
424 call this%h%free()
425 call this%n_x%free()
426 call this%n_y%free()
427 call this%n_z%free()
428
429 nullify(this%dof)
430 end subroutine wall_model_free_base
431
433 subroutine wall_model_find_points(this)
434 class(wall_model_t), intent(inout) :: this
435 integer :: n_nodes, fid, idx(4), i, linear
436 real(kind=rp) :: normal(3), p(3), x, y, z, xw, yw, zw, magp
437 real(kind=rp) :: hmin, hmax
438 type(field_t), pointer :: h_field
439 type(file_t) :: h_file
440 character(len=LOG_SIZE), allocatable :: log_msg
441
442 n_nodes = this%msk(0)
443 this%n_nodes = n_nodes
444
445 call neko_registry%add_field(this%coef%dof, "sampling_height", &
446 ignore_existing=.true.)
447
448 h_field => neko_registry%get_field_by_name("sampling_height")
449
450 do i = 1, n_nodes
451 linear = this%msk(i)
452 fid = this%facet(i)
453 idx = nonlinear_index(linear, this%coef%Xh%lx, this%coef%Xh%ly,&
454 this%coef%Xh%lz)
455 normal = this%coef%get_normal(idx(1), idx(2), idx(3), idx(4), fid)
456
457 this%n_x%x(i) = normal(1)
458 this%n_y%x(i) = normal(2)
459 this%n_z%x(i) = normal(3)
460
461 ! inward normal
462 normal = -normal
463
464 select case (fid)
465 case (1)
466 this%ind_r(i) = idx(1) + this%h_index
467 this%ind_s(i) = idx(2)
468 this%ind_t(i) = idx(3)
469 case (2)
470 this%ind_r(i) = idx(1) - this%h_index
471 this%ind_s(i) = idx(2)
472 this%ind_t(i) = idx(3)
473 case (3)
474 this%ind_r(i) = idx(1)
475 this%ind_s(i) = idx(2) + this%h_index
476 this%ind_t(i) = idx(3)
477 case (4)
478 this%ind_r(i) = idx(1)
479 this%ind_s(i) = idx(2) - this%h_index
480 this%ind_t(i) = idx(3)
481 case (5)
482 this%ind_r(i) = idx(1)
483 this%ind_s(i) = idx(2)
484 this%ind_t(i) = idx(3) + this%h_index
485 case (6)
486 this%ind_r(i) = idx(1)
487 this%ind_s(i) = idx(2)
488 this%ind_t(i) = idx(3) - this%h_index
489 case default
490 call neko_error("The face index is not correct ")
491 end select
492 this%ind_e(i) = idx(4)
493
494 ! Location of the wall node
495 xw = this%dof%x(idx(1), idx(2), idx(3), idx(4))
496 yw = this%dof%y(idx(1), idx(2), idx(3), idx(4))
497 zw = this%dof%z(idx(1), idx(2), idx(3), idx(4))
498
499 ! Location of the sampling point
500 x = this%dof%x(this%ind_r(i), this%ind_s(i), this%ind_t(i), &
501 this%ind_e(i))
502 y = this%dof%y(this%ind_r(i), this%ind_s(i), this%ind_t(i), &
503 this%ind_e(i))
504 z = this%dof%z(this%ind_r(i), this%ind_s(i), this%ind_t(i), &
505 this%ind_e(i))
506
507 ! Vector from the sampling point to the wall
508 p(1) = x - xw
509 p(2) = y - yw
510 p(3) = z - zw
511
512 ! Total distance to the sampling point
513 magp = sqrt(p(1)**2 + p(2)**2 + p(3)**2)
514
515 ! Project on the normal direction to get h
516 this%h%x(i) = p(1)*normal(1) + p(2)*normal(2) + p(3)*normal(3)
517
518 h_field%x(linear,1,1,1) = this%h%x(i)
519
520 ! Look at how much the total distance distance from the normal and warn
521 ! if significant
522 if ((this%h%x(i) - magp) / magp > 0.1) then
523 write(log_msg,*) "Significant misalignment between wall normal and"
524 call neko_log%message(log_msg, neko_log_debug)
525 write(log_msg,*) "sampling point direction at wall node", xw, yw, zw
526 call neko_log%message(log_msg, neko_log_debug)
527 end if
528 end do
529
530! hmin = glmin(this%h%x, n_nodes)
531! hmax = glmax(this%h%x, n_nodes)
532! if (pe_rank .eq. 0) then
533! write(*, "(A, F10.4, F10.4)") " h min / max:", hmin, hmax
534! end if
535
536 if (neko_bcknd_device .eq. 1) then
537 call device_memcpy(this%h%x, this%h%x_d, n_nodes, host_to_device,&
538 sync = .false.)
539 call device_memcpy(this%n_x%x, this%n_x%x_d, n_nodes, host_to_device, &
540 sync = .false.)
541 call device_memcpy(this%n_y%x, this%n_y%x_d, n_nodes, host_to_device, &
542 sync = .false.)
543 call device_memcpy(this%n_z%x, this%n_z%x_d, n_nodes, host_to_device, &
544 sync = .true.)
545 end if
546
547 ! Each wall_model bc will do a write unfortunately... But very helpful
548 ! for setup debugging.
549 call h_file%init("sampling_height.fld")
550 call h_file%write(h_field)
551 end subroutine wall_model_find_points
552
554 class(wall_model_t), intent(inout) :: this
555 integer :: i, m
556 real(kind=rp) :: magtau
557
558 m = this%msk(0)
559 if (m > 0) then
560 if (neko_bcknd_device .eq. 1) then
561 call wall_model_compute_mag_field_device(this%tau_x%x_d, &
562 this%tau_y%x_d, &
563 this%tau_z%x_d, &
564 this%tau_field%x_d, &
565 this%msk_d, m)
566 else
567 do i = 1, m
568 magtau = sqrt(this%tau_x%x(i)**2 + &
569 this%tau_y%x(i)**2 + &
570 this%tau_z%x(i)**2)
571 this%tau_field%x(this%msk(i),1,1,1) = magtau
572 end do
573 end if
574 end if
575
576 end subroutine wall_model_compute_mag_field
577
578end 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:101
Map a Fortran array to a device (allocate and associate)
Definition device.F90:77
Copy data between host and device (or device and device)
Definition device.F90:71
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
Definition comm.F90:1
integer, public pe_rank
MPI rank.
Definition comm.F90:56
Device abstraction, common interface for various accelerators.
Definition device.F90:34
integer, parameter, public host_to_device
Definition device.F90:47
subroutine, public device_free(x_d)
Deallocate memory on the device.
Definition device.F90:219
Defines a mapping of the degrees of freedom.
Definition dofmap.f90:35
Defines a field.
Definition field.f90:34
Module for file I/O operations.
Definition file.f90:34
Utilities for retrieving parameters from the case files.
Logging routines.
Definition log.f90:34
integer, parameter, public neko_log_debug
Debug log level.
Definition log.f90:84
type(log_t), public neko_log
Global log stream.
Definition log.f90:76
integer, parameter, public log_size
Definition log.f90:46
Definition math.f90:60
real(kind=rp) function, public glmax(a, n)
Max of a vector of length n.
Definition math.f90:516
real(kind=rp) function, public glmin(a, n)
Min of a vector of length n.
Definition math.f90:546
Build configurations.
integer, parameter neko_bcknd_device
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Defines a registry for storing solution fields.
Definition registry.f90:34
type(registry_t), target, public neko_registry
Global field registry.
Definition registry.f90:128
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_finalize_base(this, msk, facet)
subroutine wall_model_init_base(this, scheme_name, coef, msk, facet, index)
Constructor for the wall_model_t (base) class.
subroutine wall_model_partial_init_base(this, coef, json)
Partial initialization based on JSON, prior to knowing the mask and facets.
subroutine wall_model_find_points(this)
Find sampling points based on the requested index.
subroutine wall_model_free_base(this)
Destructor for the wall_model_t (base) class.
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:56
A wrapper around a polymorphic generic_file_t that handles its init. This is essentially a factory fo...
Definition file.f90:55
Base abstract type for wall-stress models for wall-modelled LES.