Neko  0.8.1
A portable framework for high-order spectral element flow simulations
probes.F90
Go to the documentation of this file.
1 ! Copyright (c) 2020-2023, 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 !
37 module probes
38  use num_types, only: rp
39  use matrix, only: matrix_t
40  use logger, only: neko_log, log_size
41  use utils, only: neko_error
42  use field_list, only: field_list_t
45  use dofmap, only: dofmap_t
46  use json_module, only : json_file
47  use json_utils, only : json_get
49  use tensor, only: trsp
50  use comm
51  use device
52  use file
53  use csv_file
54  use case
55  use device
56  use, intrinsic :: iso_c_binding
57  implicit none
58  private
59 
60  type, public, extends(simulation_component_t) :: probes_t
62  integer :: n_fields = 0
63  type(global_interpolation_t) :: global_interp
65  integer :: n_global_probes
67  integer :: n_probes_offset
69  real(kind=rp), allocatable :: xyz(:,:)
71  real(kind=rp), allocatable :: out_values(:,:)
72  type(c_ptr), allocatable :: out_values_d(:)
73  real(kind=rp), allocatable :: out_vals_trsp(:,:)
75  integer :: n_local_probes
77  type(field_list_t) :: sampled_fields
78  character(len=20), allocatable :: which_fields(:)
80  integer, allocatable :: n_local_probes_tot_offset(:)
81  integer, allocatable :: n_local_probes_tot(:)
83  logical :: seq_io
84  real(kind=rp), allocatable :: global_output_values(:,:)
86  type(file_t) :: fout
87  type(matrix_t) :: mat_out
88  contains
90  procedure, pass(this) :: init => probes_init_from_json
91  ! Actual constructor
92  procedure, pass(this) :: init_from_attributes => &
95  procedure, pass(this) :: free => probes_free
97  procedure, pass(this) :: setup_offset => probes_setup_offset
99  procedure, pass(this) :: compute_ => probes_evaluate_and_write
100 
101  end type probes_t
102 
103 contains
104 
106  subroutine probes_init_from_json(this, json, case)
107  class(probes_t), intent(inout) :: this
108  type(json_file), intent(inout) :: json
109  class(case_t), intent(inout), target :: case
110  real(kind=rp), allocatable :: xyz(:,:)
111  character(len=:), allocatable :: output_file
112  character(len=:), allocatable :: points_file
113  integer :: i, n_local_probes, n_global_probes
114  call this%free()
115 
116  call this%init_base(json, case)
117 
119  call json%info('fields', n_children=this%n_fields)
120  call json_get(json, 'fields', this%which_fields)
123  call json_get(json, 'points_file', points_file)
124  call json_get(json, 'output_file', output_file)
125 
126  allocate(this%sampled_fields%fields(this%n_fields))
127  do i = 1, this%n_fields
128  this%sampled_fields%fields(i)%f => neko_field_registry%get_field(&
129  trim(this%which_fields(i)))
130  end do
134  call read_probe_locations(this, this%xyz, this%n_local_probes, &
135  this%n_global_probes, points_file)
136  call probes_show(this)
137  call this%init_from_attributes(case%fluid%dm_Xh, output_file)
138  if(allocated(xyz)) deallocate(xyz)
139 
140  end subroutine probes_init_from_json
141 
142 
146  subroutine probes_init_from_attributes(this, dof, output_file)
147  class(probes_t), intent(inout) :: this
148  type(dofmap_t), intent(in) :: dof
149  character(len=:), allocatable, intent(inout) :: output_file
150  character(len=1024) :: header_line
151  real(kind=rp), allocatable :: global_output_coords(:,:)
152  integer :: i, ierr
153  type(matrix_t) :: mat_coords
154 
155 
156 
158  call this%global_interp%init(dof)
159 
161  call this%global_interp%find_points_and_redist(this%xyz, this%n_local_probes)
162 
164  allocate(this%out_values(this%n_local_probes,this%n_fields))
165  allocate(this%out_values_d(this%n_fields))
166  allocate(this%out_vals_trsp(this%n_fields,this%n_local_probes))
167 
168  if (neko_bcknd_device .eq. 1) then
169  do i = 1, this%n_fields
170  this%out_values_d(i) = c_null_ptr
171  call device_map(this%out_values(:,i), this%out_values_d(i),&
172  this%n_local_probes)
173  end do
174  end if
175 
176 
177 
179  this%fout = file_t(trim(output_file))
180 
181  select type(ft => this%fout%file_type)
182  type is (csv_file_t)
183 
184  ! Build the header
185  write(header_line, '(I0,A,I0)') this%n_global_probes, ",", this%n_fields
186  do i = 1, this%n_fields
187  header_line = trim(header_line) // "," // trim(this%which_fields(i))
188  end do
189  call this%fout%set_header(header_line)
190 
194  allocate(this%n_local_probes_tot(pe_size))
195  allocate(this%n_local_probes_tot_offset(pe_size))
196  call this%setup_offset()
197  if (pe_rank .eq. 0) then
198  allocate(global_output_coords(3,&
199  this%n_global_probes))
200  call this%mat_out%init(this%n_global_probes, this%n_fields)
201  allocate(this%global_output_values(this%n_fields,&
202  this%n_global_probes))
203  call mat_coords%init(this%n_global_probes,3)
204  end if
205  call mpi_gatherv(this%xyz, 3*this%n_local_probes,&
206  mpi_double_precision, global_output_coords,&
207  3*this%n_local_probes_tot,&
208  3*this%n_local_probes_tot_offset,&
209  mpi_double_precision, 0, neko_comm, ierr)
210  if (pe_rank .eq. 0) then
211  call trsp(mat_coords%x, this%n_global_probes,&
212  global_output_coords, 3)
213  !! Write the data to the file
214  call this%fout%write(mat_coords)
215  end if
216  class default
217  call neko_error("Invalid data. Expected csv_file_t.")
218  end select
219 
220  end subroutine probes_init_from_attributes
221 
223  subroutine probes_free(this)
224  class(probes_t), intent(inout) :: this
225 
226  if (allocated(this%xyz)) then
227  deallocate(this%xyz)
228  end if
229 
230  if (allocated(this%out_values)) then
231  deallocate(this%out_values)
232  end if
233 
234  if (allocated(this%out_vals_trsp)) then
235  deallocate(this%out_vals_trsp)
236  end if
237 
238  if (allocated(this%sampled_fields%fields)) then
239  deallocate(this%sampled_fields%fields)
240  end if
241 
242  if (allocated(this%n_local_probes_tot)) then
243  deallocate(this%n_local_probes_tot)
244  end if
245 
246  if (allocated(this%n_local_probes_tot_offset)) then
247  deallocate(this%n_local_probes_tot_offset)
248  end if
249 
250  if (allocated(this%global_output_values)) then
251  deallocate(this%global_output_values)
252  end if
253 
254  call this%global_interp%free()
255 
256  end subroutine probes_free
257 
259  subroutine probes_show(this)
260  class(probes_t), intent(in) :: this
261  character(len=LOG_SIZE) :: log_buf ! For logging status
262  integer :: i
263 
264  ! Probes summary
265  call neko_log%section('Probes')
266  write(log_buf, '(A,I6)') "Number of probes: ", this%n_global_probes
267  call neko_log%message(log_buf)
268  call neko_log%message("xyz-coordinates:")
269  do i=1,this%n_local_probes
270  write(log_buf, '("(",F10.6,",",F10.6,",",F10.6,")")') this%xyz(:,i)
271  call neko_log%message(log_buf)
272  end do
273  ! Field summary
274  write(log_buf, '(A,I6)') "Number of fields: ", this%n_fields
275  call neko_log%message(log_buf)
276  do i=1,this%n_fields
277  write(log_buf, '(A,I6, A ,A)') "Field: ", i, " ", trim(this%which_fields(i))
278  call neko_log%message(log_buf)
279  end do
280  call neko_log%end_section()
281  call neko_log%newline()
282 
283  end subroutine probes_show
284 
286  subroutine probes_debug(this)
287  class(probes_t) :: this
288 
289  character(len=LOG_SIZE) :: log_buf ! For logging status
290  integer :: i
291 
292  do i = 1, this%n_local_probes
293  write (log_buf, *) pe_rank, "/", this%global_interp%proc_owner(i), "/" ,&
294  this%global_interp%el_owner(i), "/",this%global_interp%error_code(i)
295  call neko_log%message(log_buf)
296  write(log_buf, '(A5,"(",F10.6,",",F10.6,",",F10.6,")")') "rst: ", this%global_interp%rst(:,i)
297  call neko_log%message(log_buf)
298  end do
299  end subroutine probes_debug
300 
302  subroutine probes_setup_offset(this)
303  class(probes_t) :: this
304  integer :: ierr
305  this%n_local_probes_tot = 0
306  this%n_local_probes_tot_offset = 0
307  this%n_probes_offset = 0
308  call mpi_gather(this%n_local_probes, 1, mpi_integer,&
309  this%n_local_probes_tot, 1, mpi_integer,&
310  0, neko_comm, ierr)
311 
312  call mpi_exscan(this%n_local_probes, this%n_probes_offset, 1, &
313  mpi_integer, mpi_sum, neko_comm, ierr)
314  call mpi_gather(this%n_probes_offset, 1, mpi_integer,&
315  this%n_local_probes_tot_offset, 1, mpi_integer,&
316  0, neko_comm, ierr)
317 
318 
319 
320  end subroutine probes_setup_offset
321 
326  subroutine probes_evaluate_and_write(this, t, tstep)
327  class(probes_t), intent(inout) :: this
328  real(kind=rp), intent(in) :: t
329  integer, intent(in) :: tstep
330  real(kind=rp), allocatable :: tmp(:,:)
331  integer :: i, ierr, lx
332  integer :: size_outfields
333 
335 
336 
337  do i = 1,this%n_fields
338  call this%global_interp%evaluate(this%out_values(:,i), &
339  this%sampled_fields%fields(i)%f%x)
340  end do
341 
342  if (neko_bcknd_device .eq. 1) then
343  do i = 1, this%n_fields
344  call device_memcpy(this%out_values(:,i),this%out_values_d(i),&
345  this%n_local_probes, device_to_host, sync=.true.)
346  end do
347  end if
348 
349  if (this%output_controller%check(t, tstep)) then
350  ! Gather all values to rank 0
351  ! If io is only done at root
352  if (this%seq_io) then
353  call trsp(this%out_vals_trsp, this%n_fields, &
354  this%out_values,this%n_local_probes)
355  call mpi_gatherv(this%out_vals_trsp, this%n_fields*this%n_local_probes,&
356  mpi_double_precision, this%global_output_values,&
357  this%n_fields*this%n_local_probes_tot,&
358  this%n_fields*this%n_local_probes_tot_offset,&
359  mpi_double_precision, 0, neko_comm, ierr)
360  if (pe_rank .eq. 0) then
361  call trsp(this%mat_out%x, this%n_global_probes, &
362  this%global_output_values, this%n_fields)
363  call this%fout%write(this%mat_out, t)
364  end if
365  else
366  call neko_error('probes sim comp, parallel io need implementation')
367  end if
368 
369  !! Register the execution of the activity
370  call this%output_controller%register_execution()
371  end if
372 
373  end subroutine probes_evaluate_and_write
374 
377  subroutine read_probe_locations(this, xyz, n_local_probes, n_global_probes, points_file)
378  class(probes_t), intent(inout) :: this
379  character(len=:), allocatable :: points_file
380  real(kind=rp), allocatable :: xyz(:,:)
381  integer, intent(inout) :: n_local_probes, n_global_probes
382 
384  type(file_t) :: file_in
385  integer :: ierr, file_unit, n_lines
386 
387  file_in = file_t(trim(points_file))
389  select type(ft => file_in%file_type)
390  type is (csv_file_t)
391  call read_xyz_from_csv(this, xyz, n_local_probes, n_global_probes, ft)
392  this%seq_io = .true.
393  class default
394  call neko_error("Invalid data. Expected csv_file_t.")
395  end select
396 
398  call file_free(file_in)
399 
400  end subroutine read_probe_locations
401 
407  subroutine read_xyz_from_csv(this, xyz, n_local_probes, n_global_probes, f)
408  class(probes_t), intent(inout) :: this
409  type(csv_file_t), intent(inout) :: f
410  real(kind=rp), allocatable :: xyz(:,:)
411  integer, intent(inout) :: n_local_probes, n_global_probes
412  type(matrix_t) :: mat_in, mat_in2
413  integer :: ierr, file_unit, n_lines
414 
415  if (pe_rank .eq. 0) n_lines = f%count_lines()
416  call mpi_bcast(n_lines, 1, mpi_integer, 0, neko_comm, ierr)
417 
418  ! Update the number of probes
419  n_global_probes = n_lines
420  this%n_global_probes = n_lines
421 
422  ! Initialize the temporal array
423  if (pe_rank .eq. 0) then
424  this%n_local_probes = this%n_global_probes
425  n_local_probes = n_global_probes
426  allocate(xyz(3,this%n_local_probes))
427  call mat_in%init(this%n_global_probes,3)
428  call mat_in2%init(3,this%n_global_probes)
429  call f%read(mat_in)
430  call trsp(xyz, 3, mat_in%x, this%n_global_probes)
431  else
432  n_local_probes = 0
433  this%n_local_probes = 0
434  allocate(xyz(3,this%n_local_probes))
435  end if
436 
437  end subroutine read_xyz_from_csv
438 end module probes
Map a Fortran array to a device (allocate and associate)
Definition: device.F90:57
Copy data between host and device (or device and device)
Definition: device.F90:51
Retrieves a parameter by name or throws an error.
Definition: json_utils.f90:44
Defines a simulation case.
Definition: case.f90:34
Definition: comm.F90:1
integer pe_rank
MPI rank.
Definition: comm.F90:26
type(mpi_comm) neko_comm
MPI communicator.
Definition: comm.F90:16
integer pe_size
MPI size of communicator.
Definition: comm.F90:29
File format for .csv files, used for any read/write operations involving floating point data.
Definition: csv_file.f90:35
Device abstraction, common interface for various accelerators.
Definition: device.F90:34
integer, parameter, public device_to_host
Definition: device.F90:47
Defines a mapping of the degrees of freedom.
Definition: dofmap.f90:35
Defines a registry for storing solution fields.
type(field_registry_t), target, public neko_field_registry
Global field registry.
Module for file I/O operations.
Definition: file.f90:34
subroutine file_free(this)
File operation destructor.
Definition: file.f90:131
Implements global_interpolation given a dofmap.
Utilities for retrieving parameters from the case files.
Definition: json_utils.f90:34
Logging routines.
Definition: log.f90:34
type(log_t), public neko_log
Global log stream.
Definition: log.f90:61
integer, parameter, public log_size
Definition: log.f90:40
Defines a matrix.
Definition: matrix.f90:34
integer, parameter, public rp
Global precision used in computations.
Definition: num_types.f90:12
Implements probes.
Definition: probes.F90:37
subroutine read_xyz_from_csv(this, xyz, n_local_probes, n_global_probes, f)
Read and initialize the number of probes from a csv input file.
Definition: probes.F90:408
subroutine probes_init_from_attributes(this, dof, output_file)
Initialize without json things.
Definition: probes.F90:147
subroutine read_probe_locations(this, xyz, n_local_probes, n_global_probes, points_file)
Initialize the physical coordinates from a csv input file.
Definition: probes.F90:378
subroutine probes_show(this)
Print current probe status, with number of probes and coordinates.
Definition: probes.F90:260
subroutine probes_free(this)
Destructor.
Definition: probes.F90:224
subroutine probes_debug(this)
Show the status of processor/element owner and error code for each point.
Definition: probes.F90:287
subroutine probes_setup_offset(this)
Setup offset for rank 0.
Definition: probes.F90:303
subroutine probes_evaluate_and_write(this, t, tstep)
Interpolate each probe from its r,s,t coordinates.
Definition: probes.F90:327
subroutine probes_init_from_json(this, json, case)
Constructor from json.
Definition: probes.F90:107
Simulation components are objects that encapsulate functionality that can be fit to a particular comp...
Tensor operations.
Definition: tensor.f90:61
subroutine, public trsp(a, lda, b, ldb)
Transpose of a rectangular tensor .
Definition: tensor.f90:121
Utilities.
Definition: utils.f90:35
field_list_t, To be able to group fields together
Definition: field_list.f90:7
A wrapper around a polymorphic generic_file_t that handles its init. This is essentially a factory fo...
Definition: file.f90:53
Implements global interpolation for arbitrary points in the domain.
Base abstract class for simulation components.