47  use json_module, 
only : json_file, json_value, json_core
 
   56  use, 
intrinsic :: iso_c_binding
 
   60  use mpi_f08, 
only : mpi_allreduce, mpi_integer, mpi_sum, mpi_double_precision, &
 
   61       mpi_gatherv, mpi_gather, mpi_exscan
 
   67     real(kind=
rp) :: start_time
 
   69     integer :: n_fields = 0
 
   72     integer :: n_global_probes
 
   74     integer :: n_probes_offset
 
   76     real(kind=
rp), 
allocatable :: xyz(:,:)
 
   78     real(kind=
rp), 
allocatable :: out_values(:,:)
 
   79     type(c_ptr), 
allocatable :: out_values_d(:)
 
   80     real(kind=
rp), 
allocatable :: out_vals_trsp(:,:)
 
   82     integer :: n_local_probes
 
   85     character(len=20), 
allocatable :: which_fields(:)
 
   87     integer, 
allocatable :: n_local_probes_tot_offset(:)
 
   88     integer, 
allocatable :: n_local_probes_tot(:)
 
   91     real(kind=
rp), 
allocatable :: global_output_values(:,:)
 
   99     procedure, pass(this) :: init_from_components => &
 
 
  130    class(
probes_t), 
intent(inout), 
target :: this
 
  131    type(json_file), 
intent(inout) :: json
 
  132    class(
case_t), 
intent(inout), 
target :: case
 
  133    character(len=:), 
allocatable :: output_file
 
  134    character(len=:), 
allocatable :: input_file
 
  138    character(len=:), 
allocatable :: point_type
 
  139    type(json_value), 
pointer :: json_point_list
 
  140    type(json_file) :: json_point
 
  141    type(json_core) :: core
 
  142    integer :: idx, n_point_children
 
  146    call this%init_base(json, 
case)
 
  149    call json%info(
'fields', n_children = this%n_fields)
 
  150    call json_get(json, 
'fields', this%which_fields)
 
  151    call json_get(json, 
'output_file', output_file)
 
  154    call this%sampled_fields%init(this%n_fields)
 
  155    do i = 1, this%n_fields
 
  157       call this%sampled_fields%assign(i, &
 
  162    this%n_local_probes = 0
 
  163    this%n_global_probes = 0
 
  166    if (json%valid_path(
'points_file')) 
then 
  169       call json_get(json, 
'points_file', input_file)
 
  174            this%n_global_probes, input_file)
 
  178    call json%get(
'points', json_point_list)
 
  179    call json%info(
'points', n_children = n_point_children)
 
  181    do idx = 1, n_point_children
 
  185       select case (point_type)
 
  188          call this%read_file(json_point)
 
  190          call this%read_point(json_point)
 
  192          call this%read_line(json_point)
 
  194          call neko_error(
'Plane probes not implemented yet.')
 
  196          call this%read_circle(json_point)
 
  198          call this%read_point_zone(json_point, 
case%fluid%dm_Xh)
 
  200          call json_point%print()
 
  203          call neko_error(
'Unknown region type ' // point_type)
 
  207    call mpi_allreduce(this%n_local_probes, this%n_global_probes, 1, &
 
  211    call this%init_from_components(
case%fluid%dm_Xh, output_file)
 
 
  223    class(
probes_t), 
intent(inout) :: this
 
  224    type(json_file), 
intent(inout) :: json
 
  225    character(len=:), 
allocatable :: input_file
 
  226    real(kind=
rp), 
dimension(:,:), 
allocatable :: point_list
 
  228    integer :: n_local, n_global
 
  232    call json_get(json, 
'file_name', input_file)
 
  236    call this%add_points(point_list)
 
 
  244    class(
probes_t), 
intent(inout) :: this
 
  245    type(json_file), 
intent(inout) :: json
 
  247    real(kind=
rp), 
dimension(:,:), 
allocatable :: point_list
 
  248    real(kind=
rp), 
dimension(:), 
allocatable :: rp_list_reader
 
  252    call json_get(json, 
'coordinates', rp_list_reader)
 
  254    if (mod(
size(rp_list_reader), 3) /= 0) 
then 
  255       call neko_error(
'Invalid number of coordinates.')
 
  259    allocate(point_list(3, 
size(rp_list_reader)/3))
 
  260    point_list = reshape(rp_list_reader, [3, 
size(rp_list_reader)/3])
 
  262    call this%add_points(point_list)
 
 
  269    class(
probes_t), 
intent(inout) :: this
 
  270    type(json_file), 
intent(inout) :: json
 
  272    real(kind=
rp), 
dimension(:,:), 
allocatable :: point_list
 
  273    real(kind=
rp), 
dimension(:), 
allocatable :: start, 
end 
  274    real(kind=
rp), 
dimension(3) :: direction
 
  277    integer :: n_points, i
 
  283    call json_get(json, 
"amount", n_points)
 
  286    if (
size(start) /= 3 .or. 
size(
end) /= 3) then
 
  287       call neko_error(
'Invalid start or end coordinates.')
 
  291    allocate(point_list(3, n_points))
 
  294    direction = 
end - start
 
  296       t = 
real(i - 1, kind = rp) / 
real(n_points - 1, kind = rp)
 
  297       point_list(:, i) = start + direction * t
 
  300    call this%add_points(point_list)
 
 
  313    class(
probes_t), 
intent(inout) :: this
 
  314    type(json_file), 
intent(inout) :: json
 
  316    real(kind=rp), 
dimension(:,:), 
allocatable :: point_list
 
  317    real(kind=rp), 
dimension(:), 
allocatable :: center, normal
 
  318    real(kind=rp) :: radius
 
  319    real(kind=rp) :: angle
 
  320    integer :: n_points, i
 
  321    character(len=:), 
allocatable :: axis
 
  323    real(kind=rp), 
dimension(3) :: zero_line, cross_line, temp
 
  327    if (pe_rank .ne. 0) 
return 
  328    call json_get(json, 
"center", center)
 
  329    call json_get(json, 
"normal", normal)
 
  330    call json_get(json, 
"radius", radius)
 
  331    call json_get(json, 
"amount", n_points)
 
  332    call json_get(json, 
"axis", axis)
 
  335    if (
size(center) /= 3 .or. 
size(normal) /= 3) 
then 
  336       call neko_error(
'Invalid center or normal coordinates.')
 
  338    if (axis /= 
'x' .and. axis /= 
'y' .and. axis /= 
'z') 
then 
  339       call neko_error(
'Invalid axis.')
 
  341    if (radius <= 0) 
then 
  342       call neko_error(
'Invalid radius.')
 
  344    if (n_points <= 0) 
then 
  345       call neko_error(
'Invalid number of points.')
 
  349    normal = normal / norm2(normal)
 
  352    if (axis .eq. 
'x') zero_line = [1.0, 0.0, 0.0]
 
  353    if (axis .eq. 
'y') zero_line = [0.0, 1.0, 0.0]
 
  354    if (axis .eq. 
'z') zero_line = [0.0, 0.0, 1.0]
 
  356    if (1.0_rp - dot_product(zero_line, normal) .le. 1e-6) 
then 
  357       call neko_error(
'Invalid axis and normal.')
 
  360    zero_line = zero_line - dot_product(zero_line, normal) * normal
 
  361    zero_line = zero_line / norm2(zero_line)
 
  363    cross_line(1) = normal(2) * zero_line(3) - normal(3) * zero_line(2)
 
  364    cross_line(2) = normal(3) * zero_line(1) - normal(1) * zero_line(3)
 
  365    cross_line(3) = normal(1) * zero_line(2) - normal(2) * zero_line(1)
 
  368    allocate(point_list(3, n_points))
 
  370    pi = 4.0_rp * atan(1.0_rp)
 
  374       angle = 2.0_rp * pi * 
real(i - 1, kind = rp) / 
real(n_points, kind = rp)
 
  375       temp = cos(angle) * zero_line + sin(angle) * cross_line
 
  377       point_list(:, i) = center + radius * temp
 
  380    call this%add_points(point_list)
 
 
  389    class(
probes_t), 
intent(inout) :: this
 
  390    type(json_file), 
intent(inout) :: json
 
  391    type(dofmap_t), 
intent(in) :: dof
 
  393    real(kind=rp), 
dimension(:,:), 
allocatable :: point_list
 
  394    character(len=:), 
allocatable :: point_zone_name
 
  395    class(point_zone_t), 
pointer :: zone
 
  396    integer :: i, idx, lx, nlindex(4)
 
  397    real(kind=rp) :: x, y, z
 
  400    if (pe_rank .ne. 0) 
return 
  402    call json_get(json, 
"name", point_zone_name)
 
  403    zone => neko_point_zone_registry%get_point_zone(point_zone_name)
 
  406    allocate(point_list(3, zone%size))
 
  410       idx = zone%mask%get(i)
 
  413       x = dof%x(nlindex(1), nlindex(2), nlindex(3), nlindex(4))
 
  414       y = dof%y(nlindex(1), nlindex(2), nlindex(3), nlindex(4))
 
  415       z = dof%z(nlindex(1), nlindex(2), nlindex(3), nlindex(4))
 
  417       point_list(:, i) = [x, y, z]
 
  420    call this%add_points(point_list)
 
 
  430    class(
probes_t), 
intent(inout) :: this
 
  431    real(kind=rp), 
dimension(:,:), 
intent(in) :: new_points
 
  433    real(kind=rp), 
dimension(:,:), 
allocatable :: temp
 
  434    integer :: n_old, n_new
 
  437    n_old = this%n_local_probes
 
  438    n_new = 
size(new_points, 2)
 
  441    if (
allocated(this%xyz)) 
then 
  442       call move_alloc(this%xyz, temp)
 
  446    allocate(this%xyz(3, n_old + n_new))
 
  447    if (
allocated(temp)) 
then 
  448       this%xyz(:, 1:n_old) = temp
 
  450    this%xyz(:, n_old+1:n_old+n_new) = new_points
 
  452    this%n_local_probes = this%n_local_probes + n_new
 
 
  462    class(
probes_t), 
intent(inout) :: this
 
  463    type(dofmap_t), 
intent(in) :: dof
 
  464    character(len=:), 
allocatable, 
intent(inout) :: output_file
 
  465    character(len=1024) :: header_line
 
  466    real(kind=rp), 
allocatable :: global_output_coords(:,:)
 
  468    type(matrix_t) :: mat_coords
 
  471    call this%global_interp%init(dof)
 
  474    call this%global_interp%find_points_and_redist(this%xyz, &
 
  478    allocate(this%out_values(this%n_local_probes, this%n_fields))
 
  479    allocate(this%out_values_d(this%n_fields))
 
  480    allocate(this%out_vals_trsp(this%n_fields, this%n_local_probes))
 
  482    if (neko_bcknd_device .eq. 1) 
then 
  483       do i = 1, this%n_fields
 
  484          this%out_values_d(i) = c_null_ptr
 
  485          call device_map(this%out_values(:,i), this%out_values_d(i), &
 
  491    call this%fout%init(trim(output_file))
 
  493    select type (ft => this%fout%file_type)
 
  499       write(header_line, 
'(I0,A,I0)') this%n_global_probes, 
",", this%n_fields
 
  500       do i = 1, this%n_fields
 
  501          header_line = trim(header_line) // 
"," // trim(this%which_fields(i))
 
  503       call this%fout%set_header(header_line)
 
  508       allocate(this%n_local_probes_tot(pe_size))
 
  509       allocate(this%n_local_probes_tot_offset(pe_size))
 
  510       call this%setup_offset()
 
  511       if (pe_rank .eq. 0) 
then 
  512          allocate(global_output_coords(3, this%n_global_probes))
 
  513          call this%mat_out%init(this%n_global_probes, this%n_fields)
 
  514          allocate(this%global_output_values(this%n_fields, &
 
  515               this%n_global_probes))
 
  516          call mat_coords%init(this%n_global_probes,3)
 
  518       call mpi_gatherv(this%xyz, 3*this%n_local_probes, &
 
  519            mpi_real_precision, global_output_coords, &
 
  520            3*this%n_local_probes_tot, &
 
  521            3*this%n_local_probes_tot_offset, &
 
  522            mpi_real_precision, 0, neko_comm, ierr)
 
  523       if (pe_rank .eq. 0) 
then 
  524          call trsp(mat_coords%x, this%n_global_probes, &
 
  525               global_output_coords, 3)
 
  527          call this%fout%write(mat_coords)
 
  530       call neko_error(
"Invalid data. Expected csv_file_t.")
 
 
  537    class(
probes_t), 
intent(inout) :: this
 
  539    if (
allocated(this%xyz)) 
then 
  543    if (
allocated(this%out_values)) 
then 
  544       deallocate(this%out_values)
 
  547    if (
allocated(this%out_vals_trsp)) 
then 
  548       deallocate(this%out_vals_trsp)
 
  551    call this%sampled_fields%free()
 
  553    if (
allocated(this%n_local_probes_tot)) 
then 
  554       deallocate(this%n_local_probes_tot)
 
  557    if (
allocated(this%n_local_probes_tot_offset)) 
then 
  558       deallocate(this%n_local_probes_tot_offset)
 
  561    if (
allocated(this%global_output_values)) 
then 
  562       deallocate(this%global_output_values)
 
  565    call this%global_interp%free()
 
 
  572    character(len=LOG_SIZE) :: log_buf 
 
  576    call neko_log%section(
'Probes')
 
  577    write(log_buf, 
'(A,I6)') 
"Number of probes: ", this%n_global_probes
 
  578    call neko_log%message(log_buf)
 
  580    call neko_log%message(
"xyz-coordinates:", lvl = neko_log_debug)
 
  581    do i = 1, this%n_local_probes
 
  582       write(log_buf, 
'("(",F10.6,",",F10.6,",",F10.6,")")') this%xyz(:,i)
 
  583       call neko_log%message(log_buf, lvl = neko_log_debug)
 
  587    write(log_buf, 
'(A,I6)') 
"Number of fields: ", this%n_fields
 
  588    call neko_log%message(log_buf)
 
  589    do i = 1, this%n_fields
 
  590       write(log_buf, 
'(A,I6,A,A)') &
 
  591            "Field: ", i, 
" ", trim(this%which_fields(i))
 
  592       call neko_log%message(log_buf, lvl = neko_log_debug)
 
  594    call neko_log%end_section()
 
  595    call neko_log%newline()
 
 
  603    character(len=LOG_SIZE) :: log_buf 
 
  606    do i = 1, this%n_local_probes
 
  607       write (log_buf, *) pe_rank, 
"/", this%global_interp%pe_owner(i), &
 
  608            "/" , this%global_interp%el_owner0(i)
 
  609       call neko_log%message(log_buf)
 
  610       write(log_buf, 
'(A5,"(",F10.6,",",F10.6,",",F10.6,")")') &
 
  611            "rst: ", this%global_interp%rst(:,i)
 
  612       call neko_log%message(log_buf)
 
 
  620    this%n_local_probes_tot = 0
 
  621    this%n_local_probes_tot_offset = 0
 
  622    this%n_probes_offset = 0
 
  623    call mpi_gather(this%n_local_probes, 1, mpi_integer, &
 
  624         this%n_local_probes_tot, 1, mpi_integer, &
 
  627    call mpi_exscan(this%n_local_probes, this%n_probes_offset, 1, &
 
  628         mpi_integer, mpi_sum, neko_comm, ierr)
 
  629    call mpi_gather(this%n_probes_offset, 1, mpi_integer, &
 
  630         this%n_local_probes_tot_offset, 1, mpi_integer, &
 
 
  642    class(
probes_t), 
intent(inout) :: this
 
  643    type(time_state_t), 
intent(in) :: time
 
  645    logical :: do_interp_on_host = .false.
 
  648    if (time%t .lt. this%start_time) 
return 
  651    do i = 1, this%n_fields
 
  652       call this%global_interp%evaluate(this%out_values(:,i), &
 
  653            this%sampled_fields%items(i)%ptr%x, &
 
  657    if (neko_bcknd_device .eq. 1) 
then 
  658       do i = 1, this%n_fields
 
  659          call device_memcpy(this%out_values(:,i), this%out_values_d(i), &
 
  660               this%n_local_probes, device_to_host, sync = .true.)
 
  664    if (this%output_controller%check(time)) 
then 
  667       if (this%seq_io) 
then 
  668          call trsp(this%out_vals_trsp, this%n_fields, &
 
  669               this%out_values, this%n_local_probes)
 
  670          call mpi_gatherv(this%out_vals_trsp, &
 
  671               this%n_fields*this%n_local_probes, &
 
  672               mpi_real_precision, this%global_output_values, &
 
  673               this%n_fields*this%n_local_probes_tot, &
 
  674               this%n_fields*this%n_local_probes_tot_offset, &
 
  675               mpi_real_precision, 0, neko_comm, ierr)
 
  676          if (pe_rank .eq. 0) 
then 
  677             call trsp(this%mat_out%x, this%n_global_probes, &
 
  678                  this%global_output_values, this%n_fields)
 
  679             call this%fout%write(this%mat_out, time%t)
 
  682          call neko_error(
'probes sim comp, parallel io need implementation')
 
  686       call this%output_controller%register_execution()
 
 
  695    class(
probes_t), 
intent(inout) :: this
 
  696    character(len=:), 
allocatable :: points_file
 
  697    real(kind=rp), 
allocatable :: xyz(:,:)
 
  698    integer, 
intent(inout) :: n_local_probes, n_global_probes
 
  701    type(file_t) :: file_in
 
  703    call file_in%init(trim(points_file))
 
  705    select type (ft => file_in%file_type)
 
  710       call neko_error(
"Invalid data. Expected csv_file_t.")
 
  714    call file_free(file_in)
 
 
  724    type(csv_file_t), 
intent(inout) :: f
 
  725    real(kind=rp), 
allocatable :: xyz(:,:)
 
  726    integer, 
intent(inout) :: n_local_probes, n_global_probes
 
  727    type(matrix_t) :: mat_in, mat_in2
 
  730    n_lines = f%count_lines()
 
  733    n_global_probes = n_lines
 
  736    if (pe_rank .eq. 0) 
then 
  737       n_local_probes = n_global_probes
 
  738       allocate(xyz(3, n_local_probes))
 
  739       call mat_in%init(n_global_probes,3)
 
  740       call mat_in2%init(3, n_global_probes)
 
  742       call trsp(xyz, 3, mat_in%x, n_global_probes)
 
  745       allocate(xyz(3, n_local_probes))
 
 
__inline__ __device__ void nonlinear_index(const int idx, const int lx, int *index)
 
Map a Fortran array to a device (allocate and associate)
 
Copy data between host and device (or device and device)
 
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 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
 
Defines a mapping of the degrees of freedom.
 
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.
 
subroutine file_free(this)
File operation destructor.
 
Implements global_interpolation given a dofmap.
 
Utilities for retrieving parameters from the case files.
 
integer, parameter, public neko_log_debug
Debug log level.
 
type(log_t), public neko_log
Global log stream.
 
integer, parameter, public log_size
 
integer, parameter neko_bcknd_device
 
integer, parameter, public rp
Global precision used in computations.
 
type(point_zone_registry_t), target, public neko_point_zone_registry
Global point_zone registry.
 
subroutine read_point_zone(this, json, dof)
Construct a list of points from a point zone.
 
subroutine read_circle(this, json)
Construct a list of points from a circle.
 
subroutine add_points(this, new_points)
Append a new list of points to the exsiting list.
 
subroutine probes_evaluate_and_write(this, time)
Interpolate each probe from its r,s,t coordinates.
 
subroutine read_line(this, json)
Construct a list of points from a line.
 
subroutine probes_init_from_components(this, dof, output_file)
Initialize without json things.
 
subroutine read_probe_locations(this, xyz, n_local_probes, n_global_probes, points_file)
Initialize the physical coordinates from a csv input file.
 
subroutine read_point(this, json)
Read a list of points from the json file.
 
subroutine probes_show(this)
Print current probe status, with number of probes and coordinates.
 
subroutine probes_free(this)
Destructor.
 
subroutine probes_debug(this)
Show the status of processor/element owner and error code for each point.
 
subroutine probes_setup_offset(this)
Setup offset for rank 0.
 
subroutine read_file(this, json)
Read a list of points from a csv file.
 
subroutine read_xyz_from_csv(xyz, n_local_probes, n_global_probes, f)
Read and initialize the number of probes from a csv input file.
 
subroutine probes_init_from_json(this, json, case)
Constructor from json.
 
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 .
 
Module with things related to the simulation time.
 
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...
 
Implements global interpolation for arbitrary points in the domain.
 
Base abstract type for point zones.
 
Base abstract class for simulation components.
 
A struct that contains all info about the time, expand as needed.