37 use json_module,
only : json_file
61 use mpi_f08,
only : mpi_allreduce, mpi_gather, mpi_gatherv, mpi_exscan, &
73 type(
coef_t),
pointer :: coef => null()
77 integer,
allocatable :: zone_indices(:)
81 character(len=NEKO_VARNAME_LEN),
allocatable :: col_names(:)
85 integer :: n_local = 0
87 integer :: n_global = 0
91 real(kind=
rp),
allocatable :: local_buffer(:,:)
93 real(kind=
rp),
allocatable :: local_buffer_t(:,:)
95 real(kind=
rp),
allocatable :: global_buffer(:,:)
97 integer,
allocatable :: recvcounts(:)
99 integer,
allocatable :: displs(:)
100 integer,
allocatable :: recvcounts_c(:), displs_c(:)
108 real(kind=
rp) :: start_time = 0.0_rp
110 logical :: mesh_has_changed = .false.
112 logical :: geometry_in_data = .false.
114 logical :: output_normals = .false.
116 logical :: output_area = .false.
119 logical :: append_out = .true.
123 generic :: init_from_components => &
124 init_from_controllers, init_from_controllers_properties
125 procedure, pass(this) :: init_from_controllers => &
127 procedure, pass(this) :: init_from_controllers_properties => &
129 procedure,
private, pass(this) :: init_common => &
136 procedure,
private, pass(this) :: gather_column => &
147 type(json_file),
intent(inout) :: json
148 class(
case_t),
intent(inout),
target :: case
149 character(len=:),
allocatable :: name, output_filename
150 character(len=NEKO_VARNAME_LEN),
allocatable :: fields(:)
151 integer,
allocatable :: zone_indices(:)
152 real(kind=
rp) :: start_time
153 logical :: output_normals
154 logical :: output_area
155 logical :: append_out
156 logical :: user_set_compute
162 user_set_compute = json%valid_path(
"compute_control") .or. &
163 json%valid_path(
"compute_value")
165 call this%init_base(json,
case)
167 if (user_set_compute)
then
168 call neko_warning(
"boundary_data_writer: 'compute_control' and " // &
169 "'compute_value' are ignored. Use 'output_control' and " // &
170 "'output_value' to set how often the data is written.")
172 call this%compute_controller%init(
case%time%start_time, &
173 case%time%end_time,
"tsteps", 1.0_rp)
175 call json_get(json,
"zone_indices", zone_indices)
176 call json_get(json,
"output_filename", output_filename)
182 call json_get(json,
"fields", fields)
184 call this%init_common(name,
case%fluid%c_Xh, zone_indices, fields, &
185 output_filename, output_normals, output_area, append_out, &
206 order, preprocess_controller, compute_controller, output_controller, &
207 coef, zone_indices, fields, output_filename, output_normals, &
208 output_area, append_out, start_time)
210 character(len=*),
intent(in) :: name
211 class(
case_t),
intent(inout),
target :: case
212 integer,
intent(in) :: order
216 type(
coef_t),
intent(inout),
target :: coef
217 integer,
intent(in) :: zone_indices(:)
218 character(len=*),
intent(in) :: fields(:)
219 character(len=*),
intent(in) :: output_filename
220 logical,
intent(in) :: output_normals
221 logical,
intent(in) :: output_area
222 logical,
intent(in) :: append_out
223 real(kind=
rp),
intent(in) :: start_time
227 call this%init_base_from_components(
case, order, preprocess_controller, &
229 call this%init_common(name, coef, zone_indices, fields, &
230 output_filename, output_normals, output_area, append_out, start_time)
254 name, case, order, preprocess_control, preprocess_value, &
255 compute_control, compute_value, output_control, output_value, coef, &
256 zone_indices, fields, output_filename, output_normals, output_area, &
257 append_out, start_time)
259 character(len=*),
intent(in) :: name
260 class(
case_t),
intent(inout),
target :: case
261 integer,
intent(in) :: order
262 character(len=*),
intent(in) :: preprocess_control
263 real(kind=
rp),
intent(in) :: preprocess_value
264 character(len=*),
intent(in) :: compute_control
265 real(kind=
rp),
intent(in) :: compute_value
266 character(len=*),
intent(in) :: output_control
267 real(kind=
rp),
intent(in) :: output_value
268 type(
coef_t),
intent(inout),
target :: coef
269 integer,
intent(in) :: zone_indices(:)
270 character(len=*),
intent(in) :: fields(:)
271 character(len=*),
intent(in) :: output_filename
272 logical,
intent(in) :: output_normals
273 logical,
intent(in) :: output_area
274 logical,
intent(in) :: append_out
275 real(kind=
rp),
intent(in) :: start_time
279 call this%init_base_from_components(
case, order, preprocess_control, &
280 preprocess_value, compute_control, compute_value, output_control, &
282 call this%init_common(name, coef, zone_indices, fields, &
283 output_filename, output_normals, output_area, append_out, start_time)
298 fields, output_filename, output_normals, output_area, append_out, &
301 character(len=*),
intent(in) :: name
302 type(
coef_t),
intent(inout),
target :: coef
303 integer,
intent(in) :: zone_indices(:)
304 character(len=*),
intent(in) :: fields(:)
305 character(len=*),
intent(in) :: output_filename
306 logical,
intent(in) :: output_normals
307 logical,
intent(in) :: output_area
308 logical,
intent(in) :: append_out
309 real(kind=
rp),
intent(in) :: start_time
310 character(len=LOG_SIZE) :: log_buf
311 character(len=80) :: suffix
312 integer :: i, col, ierr, offset, n_geom
313 logical :: ale_enabled
317 this%start_time = start_time
318 this%output_normals = output_normals
319 this%output_area = output_area
320 this%append_out = append_out
323 allocate(this%zone_indices(
size(zone_indices)))
324 this%zone_indices = zone_indices
327 if (
size(fields) .eq. 0)
then
328 call neko_error(
"boundary_data_writer requires at least one entry " // &
332 call this%fields%init(
size(fields))
333 do i = 1,
size(fields)
334 this%fields%items(i)%ptr => &
338 ale_enabled = .false.
340 if (
neko_ale%active) ale_enabled = .true.
344 this%mesh_has_changed = .false.
345 if (ale_enabled)
then
346 this%mesh_has_changed = .true.
351 this%geometry_in_data = this%mesh_has_changed
354 call this%bdata%init(this%coef, this%zone_indices)
356 this%n_local = this%bdata%n_local
357 this%n_global = this%bdata%n_global
359 call this%work%init(this%n_local)
373 if (this%geometry_in_data)
then
375 if (this%output_normals) n_geom = n_geom + 3
376 if (this%output_area) n_geom = n_geom + 1
379 this%n_cols = n_geom + this%fields%size()
381 allocate(this%col_names(this%n_cols))
383 if (this%geometry_in_data)
then
385 this%col_names(col) =
"x"
387 this%col_names(col) =
"y"
389 this%col_names(col) =
"z"
390 if (this%output_normals)
then
392 this%col_names(col) =
"n_x"
394 this%col_names(col) =
"n_y"
396 this%col_names(col) =
"n_z"
398 if (this%output_area)
then
400 this%col_names(col) =
"area"
403 do i = 1, this%fields%size()
405 this%col_names(col) = trim(fields(i))
408 allocate(this%local_buffer(this%n_local, this%n_cols))
409 this%local_buffer = 0.0_rp
412 allocate(this%local_buffer_t(this%n_cols, this%n_local))
413 this%local_buffer_t = 0.0_rp
416 allocate(this%recvcounts(
pe_size))
421 call mpi_gather(this%n_local, 1, mpi_integer, this%recvcounts, 1, &
425 call mpi_exscan(this%n_local, offset, 1, mpi_integer, mpi_sum, &
429 call mpi_gather(offset, 1, mpi_integer, this%displs, 1, mpi_integer, &
432 allocate(this%recvcounts_c(
pe_size))
433 allocate(this%displs_c(
pe_size))
434 this%recvcounts_c = this%recvcounts * this%n_cols
435 this%displs_c = this%displs * this%n_cols
438 allocate(this%global_buffer(
max(1, this%n_cols),
max(1, this%n_global)))
440 allocate(this%global_buffer(1, 1))
442 this%global_buffer = 0.0_rp
446 if (trim(suffix) .ne.
"csv" .and. trim(suffix) .ne.
"h5" .and. &
447 trim(suffix) .ne.
"hdf5")
then
448 call neko_error(
"boundary_data_writer: output_filename must end in " // &
449 "'.csv', '.h5' or '.hdf5'")
452 call this%fout%init(this%case%output_directory // trim(output_filename))
455 if (this%output_normals) n_geom = n_geom + 3
456 if (this%output_area) n_geom = n_geom + 1
458 select type (ft => this%fout%file_type)
465 call neko_error(
"boundary_data_writer: expected csv_file_t or " // &
470 call neko_log%section(
"Boundary data writer")
471 write(log_buf,
'(A,A)')
"Name: ", trim(this%name)
473 write(log_buf,
'(A,*(I0,:,", "))')
"Zone indices: ", this%zone_indices
475 write(log_buf,
'(A,I0)')
"Global number of masked points: ", this%n_global
477 write(log_buf,
'(A,A)')
"Output file: ", trim(output_filename)
480 do i = 1, this%n_cols
481 write(log_buf,
'(A,A)')
" ", trim(this%col_names(i))
484 write(log_buf,
'(A,L1)')
"Moving mesh: ", this%mesh_has_changed
496 character(len=*),
intent(in) :: output_filename
497 integer,
intent(in) :: n_geom
498 character(len=1024) :: header_line
499 character(len=NEKO_FNAME_LEN) :: mesh_filename
502 integer :: i, suffix_pos
505 do i = 1, this%n_cols
506 header_line = trim(header_line) //
"," // trim(this%col_names(i))
508 call this%fout%set_header(trim(header_line))
511 call this%mat_out%init(this%n_global, this%n_cols)
513 call this%mat_out%init(1, 1)
522 header_line =
"x,y,z"
523 if (this%output_normals) header_line = &
524 trim(header_line) //
",n_x,n_y,n_z"
525 if (this%output_area) header_line = trim(header_line) //
",area"
527 mesh_filename = this%case%output_directory // &
528 trim(output_filename)
530 if (this%geometry_in_data)
then
531 mesh_filename = trim(mesh_filename(1:suffix_pos-1)) // &
532 "_initial_mesh" // trim(mesh_filename(suffix_pos:))
534 mesh_filename = trim(mesh_filename(1:suffix_pos-1)) //
"_mesh" // &
535 trim(mesh_filename(suffix_pos:))
538 call fmesh%init(trim(mesh_filename), &
539 header = trim(header_line), overwrite = .true.)
540 call fmesh%write(mat_geom)
553 integer,
intent(in) :: n_geom
556 logical :: attr_exist
558 call ft%set_overwrite(.not. this%append_out)
560 call this%vec_out%init(
max(0, this%n_local),
"value")
563 call ft%set_active_group(
"boundary_data")
567 call ft%read_attribute(
"NSteps", out_int, attr_exist)
569 this%output_controller%nexecutions = out_int
571 out_int = this%n_global
572 call ft%write_attribute(
"NPoints", out_int)
574 if (this%geometry_in_data)
then
575 mat_geom%name =
"initial_coordinates"
577 mat_geom%name =
"coordinates"
579 call ft%write_dataset(mat_geom)
590 call this%bdata%free()
592 call this%work%free()
593 call this%vec_out%free()
594 call this%mat_out%free()
596 call this%fields%free()
597 call this%fout%free()
599 if (
allocated(this%zone_indices))
deallocate(this%zone_indices)
600 if (
allocated(this%col_names))
deallocate(this%col_names)
601 if (
allocated(this%local_buffer))
deallocate(this%local_buffer)
602 if (
allocated(this%local_buffer_t))
deallocate(this%local_buffer_t)
603 if (
allocated(this%global_buffer))
deallocate(this%global_buffer)
604 if (
allocated(this%recvcounts))
deallocate(this%recvcounts)
605 if (
allocated(this%displs))
deallocate(this%displs)
606 if (
allocated(this%recvcounts_c))
deallocate(this%recvcounts_c)
607 if (
allocated(this%displs_c))
deallocate(this%displs_c)
611 call this%free_base()
622 integer,
intent(in) :: col
624 if (this%n_local .le. 0)
return
626 call this%bdata%get(f, this%work)
632 call copy(this%local_buffer(:, col), this%work%x, this%n_local)
641 integer :: i, col, n_rows, out_int
642 character(len=80) :: group_name
643 real(kind=
rp) :: time_
646 if (time%t .lt. this%start_time)
then
647 call this%output_controller%set_counter(time)
650 if (.not. this%output_controller%check(time))
return
653 if (this%mesh_has_changed)
then
654 call this%bdata%update_geometry()
669 if (this%geometry_in_data)
then
670 call copy(this%local_buffer(:, col + 1), this%bdata%x%x, this%n_local)
671 call copy(this%local_buffer(:, col + 2), this%bdata%y%x, this%n_local)
672 call copy(this%local_buffer(:, col + 3), this%bdata%z%x, this%n_local)
675 if (this%output_normals)
then
676 call copy(this%local_buffer(:, col + 1), this%bdata%n_x%x, &
678 call copy(this%local_buffer(:, col + 2), this%bdata%n_y%x, &
680 call copy(this%local_buffer(:, col + 3), this%bdata%n_z%x, &
685 if (this%output_area)
then
686 call copy(this%local_buffer(:, col + 1), this%bdata%area%x, &
692 do i = 1, this%fields%size()
694 call this%gather_column(this%fields%items(i)%ptr, col)
698 select type (ft => this%fout%file_type)
702 n_rows = this%n_global
706 this%mat_out%x(i, 1:this%n_cols) = &
707 this%global_buffer(1:this%n_cols, i)
709 call this%fout%write(this%mat_out, time%t)
713 out_int = this%output_controller%nexecutions + 1
716 call ft%set_active_group(
"boundary_data")
717 call ft%write_attribute(
"NSteps", out_int)
719 if (.not. this%append_out)
then
720 write(group_name,
'(A,I0)')
"boundary_data/Step_", out_int
721 call ft%set_active_group(trim(group_name))
724 do i = 1, this%n_cols
725 call copy(this%vec_out%x, this%local_buffer(:, i), &
727 this%vec_out%name = trim(this%col_names(i))
728 call ft%write_dataset(this%vec_out)
731 if (this%append_out)
then
734 call vec_time%init(1,
"time")
735 vec_time%x(1) = time%t
737 call vec_time%init(0,
"time")
739 call ft%write_dataset(vec_time)
744 call ft%write_attribute(
"time", time_)
750 call this%output_controller%register_execution()
759 call trsp(this%local_buffer_t, this%n_cols, this%local_buffer, this%n_local)
761 call mpi_gatherv(this%local_buffer_t, this%n_local * this%n_cols, &
772 type(
matrix_t),
intent(inout) :: mat
773 integer,
intent(in) :: n_geom
776 call mat%init(n_geom,
max(0, this%n_local),
"coordinates")
778 do i = 1, this%n_local
779 mat%x(1, i) = this%bdata%x%x(i)
780 mat%x(2, i) = this%bdata%y%x(i)
781 mat%x(3, i) = this%bdata%z%x(i)
783 if (this%output_normals)
then
784 mat%x(4, i) = this%bdata%n_x%x(i)
785 mat%x(5, i) = this%bdata%n_y%x(i)
786 mat%x(6, i) = this%bdata%n_z%x(i)
789 if (this%output_area) mat%x(k + 1, i) = this%bdata%area%x(i)
799 type(
matrix_t),
intent(inout) :: mat
800 integer,
intent(in) :: n_geom
801 real(kind=
rp),
allocatable :: sendbuf(:,:), recvbuf(:,:)
802 integer,
allocatable :: counts(:), disp(:)
803 integer :: i, k, ierr
805 allocate(sendbuf(n_geom, this%n_local))
808 do i = 1, this%n_local
809 sendbuf(1, i) = this%bdata%x%x(i)
810 sendbuf(2, i) = this%bdata%y%x(i)
811 sendbuf(3, i) = this%bdata%z%x(i)
813 if (this%output_normals)
then
814 sendbuf(4, i) = this%bdata%n_x%x(i)
815 sendbuf(5, i) = this%bdata%n_y%x(i)
816 sendbuf(6, i) = this%bdata%n_z%x(i)
819 if (this%output_area) sendbuf(k + 1, i) = this%bdata%area%x(i)
823 allocate(recvbuf(n_geom, this%n_global))
825 allocate(recvbuf(n_geom, 1))
830 counts = this%recvcounts * n_geom
831 disp = this%displs * n_geom
837 call mat%init(this%n_global, n_geom)
838 do i = 1, this%n_global
839 mat%x(i, 1:n_geom) = recvbuf(1:n_geom, i)
845 deallocate(sendbuf, recvbuf, counts, disp)
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.
ALE Manager: Handles Mesh Motion.
type(ale_manager_t), pointer, public neko_ale
Implements the boundary_data_writer_t type.
subroutine boundary_data_writer_init_from_json(this, json, case)
Constructor from json.
subroutine boundary_data_writer_compute(this, time)
Sample the boundary and write.
subroutine boundary_data_writer_local_geometry(this, mat, n_geom)
Collect the reference geometry of the local points into a matrix.
subroutine boundary_data_writer_gather_column(this, f, col)
Gather a field at the masked points into a column of the local buffer.
subroutine boundary_data_writer_setup_output_hdf5(this, ft, n_geom)
Set up an HDF5 output.
subroutine boundary_data_writer_free(this)
Destructor.
subroutine boundary_data_writer_gather_to_root(this)
Gather the local sample buffer onto rank zero.
subroutine boundary_data_writer_init_from_controllers_properties(this, name, case, order, preprocess_control, preprocess_value, compute_control, compute_value, output_control, output_value, coef, zone_indices, fields, output_filename, output_normals, output_area, append_out, start_time)
Constructor from components, passing properties to the time_based_controller components in the base t...
subroutine boundary_data_writer_gather_geometry(this, mat, n_geom)
Gather the reference geometry of all points onto rank zero.
subroutine boundary_data_writer_init_common(this, name, coef, zone_indices, fields, output_filename, output_normals, output_area, append_out, start_time)
Common part of all constructors.
subroutine boundary_data_writer_setup_output_csv(this, output_filename, n_geom)
Set up a CSV output.
subroutine boundary_data_writer_init_from_controllers(this, name, case, order, preprocess_controller, compute_controller, output_controller, coef, zone_indices, fields, output_filename, output_normals, output_area, append_out, start_time)
Constructor from components, passing controllers.
Implements the boundary_data_t type.
Defines a simulation case.
type(mpi_datatype), public mpi_real_precision
MPI type for working precision of REAL types.
integer, public pe_size
MPI size of communicator.
integer, public pe_rank
MPI rank.
type(mpi_comm), public neko_comm
MPI communicator.
File format for .csv files, used for any read/write operations involving floating point data.
Device abstraction, common interface for various accelerators.
integer, parameter, public device_to_host
Module for file I/O operations.
Utilities for retrieving parameters from the case files.
type(log_t), public neko_log
Global log stream.
integer, parameter, public log_size
subroutine, public copy(a, b, n)
Copy a vector .
integer, parameter neko_bcknd_device
integer, parameter, public rp
Global precision used in computations.
Implements output_controller_t
Defines a registry for storing solution fields.
type(registry_t), target, public neko_registry
Global field registry.
Simulation components are objects that encapsulate functionality that can be fit to a particular comp...
subroutine compute_(this, time)
Dummy compute function.
subroutine, public trsp(a, lda, b, ldb)
Transpose of a rectangular tensor .
Contains the time_based_controller_t type.
Module with things related to the simulation time.
integer, parameter, public neko_fname_len
subroutine, public neko_warning(warning_msg)
Reports a warning to standard output.
subroutine, public filename_suffix(fname, suffix)
Extract a filename's suffix.
integer, parameter, public neko_varname_len
pure integer function, public filename_suffix_pos(fname)
Find position (in the string) of a filename's suffix.
Collects data on the boundary points of one or more labelled zones and perform some bounary operation...
A simulation component that writes registry fields sampled on labelled boundary zones....
Coefficients defined on a given (mesh, ) tuple. Arrays use indices (i,j,k,e): element e,...
field_list_t, To be able to group fields together
A wrapper around a polymorphic generic_file_t that handles its init. This is essentially a factory fo...
Interface for HDF5 files.
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.