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, this%n2, this%n3, 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 end if
217
218 if (present(output_filename)) then
219 call this%csv_output%init(trim(output_filename), &
220 header = "tstep,time,flux", overwrite = .true.)
221 call this%csv_row%init(3)
222 this%csv_output_enabled = .true.
223 end if
224
225 call neko_log%section("Boundary flux")
226 write(log_buf, '(A,A)') "Name: ", trim(this%name)
227 call neko_log%message(log_buf)
228 write(log_buf, '(A,A,", ",A,", ",A)') "Fields: ", &
229 trim(this%field_names(1)), trim(this%field_names(2)), &
230 trim(this%field_names(3))
231 call neko_log%message(log_buf)
232 write(log_buf, '(A,*(I0,:,", "))') "Zone indices: ", this%zone_indices
233 call neko_log%message(log_buf)
234 write(log_buf, '(A,I0)') "Marked boundary quadrature points: ", &
235 this%bc%msk(0)
236 call neko_log%message(log_buf)
237 call neko_log%end_section()
238 end subroutine boundary_flux_init_common
239
251 subroutine boundary_flux_init_from_controllers(this, name, case, order, &
252 preprocess_controller, compute_controller, output_controller, &
253 zone_indices, field_names, log, output_filename)
254 class(boundary_flux_t), intent(inout) :: this
255 character(len=*), intent(in) :: name
256 class(case_t), intent(inout), target :: case
257 integer, intent(in) :: order
258 type(time_based_controller_t), intent(in) :: preprocess_controller
259 type(time_based_controller_t), intent(in) :: compute_controller
260 type(time_based_controller_t), intent(in) :: output_controller
261 integer, intent(in) :: zone_indices(:)
262 character(len=*), intent(in) :: field_names(:)
263 logical, intent(in), optional :: log
264 character(len=*), intent(in), optional :: output_filename
265 logical :: log_enabled
266
267 call this%free()
268
269 log_enabled = .true.
270 if (present(log)) log_enabled = log
271
272 call this%init_base_from_components(case, order, preprocess_controller, &
273 compute_controller, output_controller)
274
275 if (present(output_filename)) then
276 call this%init_common(name, case%fluid%c_Xh, zone_indices, &
277 field_names, log_enabled, output_filename)
278 else
279 call this%init_common(name, case%fluid%c_Xh, zone_indices, &
280 field_names, log_enabled)
281 end if
283
299 order, preprocess_control, preprocess_value, compute_control, &
300 compute_value, output_control, output_value, zone_indices, field_names, &
301 log, output_filename)
302 class(boundary_flux_t), intent(inout) :: this
303 character(len=*), intent(in) :: name
304 class(case_t), intent(inout), target :: case
305 integer, intent(in) :: order
306 character(len=*), intent(in) :: preprocess_control
307 real(kind=rp), intent(in) :: preprocess_value
308 character(len=*), intent(in) :: compute_control
309 real(kind=rp), intent(in) :: compute_value
310 character(len=*), intent(in) :: output_control
311 real(kind=rp), intent(in) :: output_value
312 integer, intent(in) :: zone_indices(:)
313 character(len=*), intent(in) :: field_names(:)
314 logical, intent(in), optional :: log
315 character(len=*), intent(in), optional :: output_filename
316 logical :: log_enabled
317
318 call this%free()
319
320 log_enabled = .true.
321 if (present(log)) log_enabled = log
322
323 call this%init_base_from_components(case, order, preprocess_control, &
324 preprocess_value, compute_control, compute_value, output_control, &
325 output_value)
326
327 if (present(output_filename)) then
328 call this%init_common(name, case%fluid%c_Xh, zone_indices, &
329 field_names, log_enabled, output_filename)
330 else
331 call this%init_common(name, case%fluid%c_Xh, zone_indices, &
332 field_names, log_enabled)
333 end if
335
337 subroutine boundary_flux_free(this)
338 class(boundary_flux_t), intent(inout) :: this
339
340 call this%bc%free()
341 call this%csv_output%free()
342 call this%csv_row%free()
343 call this%n1%free()
344 call this%n2%free()
345 call this%n3%free()
346 call this%surface_u%free()
347 call this%surface_v%free()
348 call this%surface_w%free()
349 if (allocated(this%zone_indices)) deallocate(this%zone_indices)
350 if (allocated(this%field_names)) deallocate(this%field_names)
351
352 nullify(this%u)
353 nullify(this%v)
354 nullify(this%w)
355 nullify(this%coef)
356
357 call this%free_base()
358 end subroutine boundary_flux_free
359
362 subroutine boundary_flux_compute(this, time)
363 class(boundary_flux_t), intent(inout) :: this
364 type(time_state_t), intent(in) :: time
365 integer :: n_pts
366 character(len=18) :: value_buf
367 character(len=12) :: step_str
368 character(len=:), allocatable :: header_line, value_line
369
370 n_pts = this%bc%msk(0)
371 this%flux = 0.0_rp
372
373 call vector_masked_gather_copy_0(this%surface_u, this%u%x, &
374 this%bc%msk, this%u%size(), n_pts)
375 call vector_masked_gather_copy_0(this%surface_v, this%v%x, &
376 this%bc%msk, this%v%size(), n_pts)
377 call vector_masked_gather_copy_0(this%surface_w, this%w%x, &
378 this%bc%msk, this%w%size(), n_pts)
379
380 this%flux = vector_glsc2(this%surface_u, this%n1, n_pts) + &
381 vector_glsc2(this%surface_v, this%n2, n_pts) + &
382 vector_glsc2(this%surface_w, this%n3, n_pts)
383
384 if (this%log) then
385 call neko_log%section(trim(this%name))
386
387 header_line = repeat(' ', 12) // ' |' // left_pad('Flux:', 18)
388 write(step_str, '(I12)') time%tstep
389 step_str = adjustl(step_str)
390 write(value_buf, '(ES18.9)') this%flux
391 value_line = step_str // ' |' // value_buf
392
393 call neko_log%message(header_line)
394 call neko_log%message(value_line)
395 call neko_log%end_section()
396 end if
397
398 if (this%csv_output_enabled) then
399 if (this%output_controller%check(time)) then
400 this%csv_row%x(1) = real(time%tstep, rp)
401 this%csv_row%x(2) = time%t
402 this%csv_row%x(3) = this%flux
403 call this%csv_output%write(this%csv_row)
404 call this%output_controller%register_execution()
405 end if
406 end if
407 end subroutine boundary_flux_compute
408
412 pure function left_pad(text, width) result(padded)
413 character(len=*), intent(in) :: text
414 integer, intent(in) :: width
415 character(len=:), allocatable :: padded
416 integer :: pad_width
417
418 pad_width = max(0, width - len_trim(text))
419 padded = repeat(' ', pad_width) // trim(text)
420 end function left_pad
421
422end module boundary_flux
double real
Copy data between host and device (or device and device)
Definition device.F90:72
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:48
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