Neko 1.99.3
A portable framework for high-order spectral element flow simulations
Loading...
Searching...
No Matches
boundary_flux.f90
Go to the documentation of this file.
1! Copyright (c) 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!
35 use num_types, only : rp
36 use json_module, only : json_file
38 use registry, only : neko_registry
39 use field, only : field_t
40 use case, only : case_t
42 use time_state, only : time_state_t
43 use coefs, only : coef_t
44 use neumann, only : neumann_t
45 use logger, only : neko_log, log_size
46 use utils, only : neko_error
47 use file, only : file_t
48 use vector, only : vector_t
52 use drag_torque, only : setup_normals
55 implicit none
56 private
57
60 type, public, extends(simulation_component_t) :: boundary_flux_t
62 type(field_t), pointer :: u => null()
64 type(field_t), pointer :: v => null()
66 type(field_t), pointer :: w => null()
68 type(coef_t), pointer :: coef => null()
70 type(neumann_t) :: bc
72 integer, allocatable :: zone_indices(:)
74 character(len=80), allocatable :: field_names(:)
76 logical :: log = .true.
78 logical :: csv_output_enabled = .false.
80 type(file_t) :: csv_output
82 type(vector_t) :: csv_row
84 type(vector_t) :: n1
86 type(vector_t) :: n2
88 type(vector_t) :: n3
90 type(vector_t) :: surface_u
92 type(vector_t) :: surface_v
94 type(vector_t) :: surface_w
96 real(kind=rp) :: flux = 0.0_rp
97 contains
99 procedure, pass(this) :: init => boundary_flux_init_from_json
101 generic :: init_from_components => &
102 init_from_controllers, init_from_controllers_properties
104 procedure, pass(this) :: init_from_controllers => &
107 procedure, pass(this) :: init_from_controllers_properties => &
110 procedure, private, pass(this) :: init_common => &
113 procedure, pass(this) :: free => boundary_flux_free
115 procedure, pass(this) :: compute_ => boundary_flux_compute
116 end type boundary_flux_t
117
118contains
119
123 subroutine boundary_flux_init_from_json(this, json, case)
124 class(boundary_flux_t), intent(inout), target :: this
125 type(json_file), intent(inout) :: json
126 class(case_t), intent(inout), target :: case
127 character(len=:), allocatable :: name
128 integer, allocatable :: zone_indices(:)
129 character(len=80), allocatable :: field_names(:)
130 logical :: log
131 character(len=:), allocatable :: output_filename
132
133 call this%free()
134
135 call json_get_or_default(json, "name", name, "boundary_flux")
136 call json_get_or_default(json, "log", log, .true.)
137 call this%init_base(json, case)
138
139 call json_get(json, "zone_indices", zone_indices)
140 call json_get(json, "field_names", field_names)
141
142 if (json%valid_path("output_filename")) then
143 call json_get(json, "output_filename", output_filename)
144 call this%init_common(name, case%fluid%c_Xh, zone_indices, &
145 field_names, log, output_filename)
146 else
147 call this%init_common(name, case%fluid%c_Xh, zone_indices, &
148 field_names, log)
149 end if
150 end subroutine boundary_flux_init_from_json
151
159 subroutine boundary_flux_init_common(this, name, coef, zone_indices, &
160 field_names, log, output_filename)
161 class(boundary_flux_t), intent(inout) :: this
162 character(len=*), intent(in) :: name
163 type(coef_t), intent(inout), target :: coef
164 integer, intent(in) :: zone_indices(:)
165 character(len=*), intent(in) :: field_names(:)
166 logical, intent(in) :: log
167 character(len=*), intent(in), optional :: output_filename
168 character(len=LOG_SIZE) :: log_buf
169 integer :: i
170 integer :: n_pts
171
172 this%name = name
173 this%log = log
174 this%csv_output_enabled = .false.
175 this%flux = 0.0_rp
176
177 this%coef => coef
178
179 if (size(zone_indices) .eq. 0) then
180 call neko_error("boundary_flux requires at least one zone index")
181 end if
182
183 if (size(field_names) .ne. 3) then
184 call neko_error("boundary_flux requires exactly three field names")
185 end if
186
187 allocate(this%zone_indices(size(zone_indices)))
188 this%zone_indices = zone_indices
189 allocate(this%field_names(size(field_names)))
190 this%field_names = field_names
191
192 this%u => neko_registry%get_field_by_name(trim(this%field_names(1)))
193 this%v => neko_registry%get_field_by_name(trim(this%field_names(2)))
194 this%w => neko_registry%get_field_by_name(trim(this%field_names(3)))
195
196 call this%bc%init_from_components(this%coef, 0.0_rp)
197 this%bc%zone_indices = this%zone_indices
198 do i = 1, size(this%zone_indices)
199 call this%bc%mark_zone(this%bc%msh%labeled_zones(this%zone_indices(i)))
200 end do
201 call this%bc%finalize()
202
203 n_pts = this%bc%msk(0)
204 if (n_pts .gt. 0) then
205 call this%n1%init(n_pts)
206 call this%n2%init(n_pts)
207 call this%n3%init(n_pts)
208 call this%surface_u%init(n_pts)
209 call this%surface_v%init(n_pts)
210 call this%surface_w%init(n_pts)
211 call setup_normals(this%coef, this%bc%msk, this%bc%facet, &
212 this%n1%x, this%n2%x, this%n3%x, n_pts)
213 call vector_cmult(this%n1, -1.0_rp, n_pts)
214 call vector_cmult(this%n2, -1.0_rp, n_pts)
215 call vector_cmult(this%n3, -1.0_rp, n_pts)
216 if (neko_bcknd_device .eq. 1) then
217 call device_memcpy(this%n1%x, this%n1%x_d, n_pts, &
218 host_to_device, .false.)
219 call device_memcpy(this%n2%x, this%n2%x_d, n_pts, &
220 host_to_device, .false.)
221 call device_memcpy(this%n3%x, this%n3%x_d, n_pts, &
222 host_to_device, .true.)
223 end if
224 end if
225
226 if (present(output_filename)) then
227 call this%csv_output%init(trim(output_filename), &
228 header = "tstep,time,flux", overwrite = .true.)
229 call this%csv_row%init(3)
230 this%csv_output_enabled = .true.
231 end if
232
233 call neko_log%section("Boundary flux")
234 write(log_buf, '(A,A)') "Name: ", trim(this%name)
235 call neko_log%message(log_buf)
236 write(log_buf, '(A,A,", ",A,", ",A)') "Fields: ", &
237 trim(this%field_names(1)), trim(this%field_names(2)), &
238 trim(this%field_names(3))
239 call neko_log%message(log_buf)
240 write(log_buf, '(A,*(I0,:,", "))') "Zone indices: ", this%zone_indices
241 call neko_log%message(log_buf)
242 write(log_buf, '(A,I0)') "Marked boundary quadrature points: ", &
243 this%bc%msk(0)
244 call neko_log%message(log_buf)
245 call neko_log%end_section()
246 end subroutine boundary_flux_init_common
247
259 subroutine boundary_flux_init_from_controllers(this, name, case, order, &
260 preprocess_controller, compute_controller, output_controller, &
261 zone_indices, field_names, log, output_filename)
262 class(boundary_flux_t), intent(inout) :: this
263 character(len=*), intent(in) :: name
264 class(case_t), intent(inout), target :: case
265 integer, intent(in) :: order
266 type(time_based_controller_t), intent(in) :: preprocess_controller
267 type(time_based_controller_t), intent(in) :: compute_controller
268 type(time_based_controller_t), intent(in) :: output_controller
269 integer, intent(in) :: zone_indices(:)
270 character(len=*), intent(in) :: field_names(:)
271 logical, intent(in), optional :: log
272 character(len=*), intent(in), optional :: output_filename
273 logical :: log_enabled
274
275 call this%free()
276
277 log_enabled = .true.
278 if (present(log)) log_enabled = log
279
280 call this%init_base_from_components(case, order, preprocess_controller, &
281 compute_controller, output_controller)
282
283 if (present(output_filename)) then
284 call this%init_common(name, case%fluid%c_Xh, zone_indices, &
285 field_names, log_enabled, output_filename)
286 else
287 call this%init_common(name, case%fluid%c_Xh, zone_indices, &
288 field_names, log_enabled)
289 end if
291
307 order, preprocess_control, preprocess_value, compute_control, &
308 compute_value, output_control, output_value, zone_indices, field_names, &
309 log, output_filename)
310 class(boundary_flux_t), intent(inout) :: this
311 character(len=*), intent(in) :: name
312 class(case_t), intent(inout), target :: case
313 integer, intent(in) :: order
314 character(len=*), intent(in) :: preprocess_control
315 real(kind=rp), intent(in) :: preprocess_value
316 character(len=*), intent(in) :: compute_control
317 real(kind=rp), intent(in) :: compute_value
318 character(len=*), intent(in) :: output_control
319 real(kind=rp), intent(in) :: output_value
320 integer, intent(in) :: zone_indices(:)
321 character(len=*), intent(in) :: field_names(:)
322 logical, intent(in), optional :: log
323 character(len=*), intent(in), optional :: output_filename
324 logical :: log_enabled
325
326 call this%free()
327
328 log_enabled = .true.
329 if (present(log)) log_enabled = log
330
331 call this%init_base_from_components(case, order, preprocess_control, &
332 preprocess_value, compute_control, compute_value, output_control, &
333 output_value)
334
335 if (present(output_filename)) then
336 call this%init_common(name, case%fluid%c_Xh, zone_indices, &
337 field_names, log_enabled, output_filename)
338 else
339 call this%init_common(name, case%fluid%c_Xh, zone_indices, &
340 field_names, log_enabled)
341 end if
343
345 subroutine boundary_flux_free(this)
346 class(boundary_flux_t), intent(inout) :: this
347
348 call this%bc%free()
349 call this%csv_output%free()
350 call this%csv_row%free()
351 call this%n1%free()
352 call this%n2%free()
353 call this%n3%free()
354 call this%surface_u%free()
355 call this%surface_v%free()
356 call this%surface_w%free()
357 if (allocated(this%zone_indices)) deallocate(this%zone_indices)
358 if (allocated(this%field_names)) deallocate(this%field_names)
359
360 nullify(this%u)
361 nullify(this%v)
362 nullify(this%w)
363 nullify(this%coef)
364
365 call this%free_base()
366 end subroutine boundary_flux_free
367
370 subroutine boundary_flux_compute(this, time)
371 class(boundary_flux_t), intent(inout) :: this
372 type(time_state_t), intent(in) :: time
373 integer :: n_pts
374 character(len=18) :: value_buf
375 character(len=12) :: step_str
376 character(len=:), allocatable :: header_line, value_line
377
378 n_pts = this%bc%msk(0)
379 this%flux = 0.0_rp
380
381 call vector_masked_gather_copy_0(this%surface_u, this%u%x, &
382 this%bc%msk, this%u%size(), n_pts)
383 call vector_masked_gather_copy_0(this%surface_v, this%v%x, &
384 this%bc%msk, this%v%size(), n_pts)
385 call vector_masked_gather_copy_0(this%surface_w, this%w%x, &
386 this%bc%msk, this%w%size(), n_pts)
387
388 this%flux = vector_glsc2(this%surface_u, this%n1, n_pts) + &
389 vector_glsc2(this%surface_v, this%n2, n_pts) + &
390 vector_glsc2(this%surface_w, this%n3, n_pts)
391
392 if (this%log) then
393 call neko_log%section(trim(this%name))
394
395 header_line = repeat(' ', 12) // ' |' // left_pad('Flux:', 18)
396 write(step_str, '(I12)') time%tstep
397 step_str = adjustl(step_str)
398 write(value_buf, '(ES18.9)') this%flux
399 value_line = step_str // ' |' // value_buf
400
401 call neko_log%message(header_line)
402 call neko_log%message(value_line)
403 call neko_log%end_section()
404 end if
405
406 if (this%csv_output_enabled) then
407 if (this%output_controller%check(time)) then
408 this%csv_row%x(1) = real(time%tstep, rp)
409 this%csv_row%x(2) = time%t
410 this%csv_row%x(3) = this%flux
411 call this%csv_output%write(this%csv_row)
412 call this%output_controller%register_execution()
413 end if
414 end if
415 end subroutine boundary_flux_compute
416
420 pure function left_pad(text, width) result(padded)
421 character(len=*), intent(in) :: text
422 integer, intent(in) :: width
423 character(len=:), allocatable :: padded
424 integer :: pad_width
425
426 pad_width = max(0, width - len_trim(text))
427 padded = repeat(' ', pad_width) // trim(text)
428 end function left_pad
429
430end module boundary_flux
double real
Copy data between host and device (or device and device)
Definition device.F90:71
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
Implements boundary_flux_t.
subroutine boundary_flux_init_common(this, name, coef, zone_indices, field_names, log, output_filename)
Common constructor shared by all public constructors.
subroutine boundary_flux_init_from_controllers(this, name, case, order, preprocess_controller, compute_controller, output_controller, zone_indices, field_names, log, output_filename)
Construct from explicit time-based controllers.
subroutine boundary_flux_compute(this, time)
Compute and optionally output the total boundary flux.
subroutine boundary_flux_init_from_json(this, json, case)
Construct from JSON.
subroutine boundary_flux_init_from_controllers_properties(this, name, case, order, preprocess_control, preprocess_value, compute_control, compute_value, output_control, output_value, zone_indices, field_names, log, output_filename)
Construct from time-based controller properties.
subroutine boundary_flux_free(this)
Free all resources owned by the component.
pure character(len=:) function, allocatable left_pad(text, width)
Left-pad a string to a fixed width.
Defines a simulation case.
Definition case.f90:34
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:47
subroutine, public setup_normals(coef, mask, facets, n1, n2, n3, n_pts)
Computes the normals for a given set of boundary points accessed by the mask.
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
type(log_t), public neko_log
Global log stream.
Definition log.f90:80
integer, parameter, public log_size
Definition log.f90:46
Build configurations.
integer, parameter neko_bcknd_device
Defines a Neumann boundary condition.
Definition neumann.f90:34
integer, parameter, public rp
Global precision used in computations.
Definition num_types.f90:12
Implements output_controller_t
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
Simulation components are objects that encapsulate functionality that can be fit to a particular comp...
subroutine compute_(this, time)
Dummy compute function.
Contains the time_based_controller_t type.
Module with things related to the simulation time.
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 .
subroutine, public vector_cmult(a, c, n)
Multiplication by constant c .
real(kind=rp) function, public vector_glsc2(a, b, n)
Defines a vector.
Definition vector.f90:34
A simulation component for total vector flux through labelled zones.
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
Definition coef.f90:63
A wrapper around a polymorphic generic_file_t that handles its init. This is essentially a factory fo...
Definition file.f90:56
A Neumann boundary condition. Sets the flux of the field to the chosen values.
Definition neumann.f90:60
Base abstract class for simulation components.
A utility type for determining whether an action should be executed based on the current time value....
A struct that contains all info about the time, expand as needed.
#define max(a, b)
Definition tensor.cu:40