184 const std::string& directory_path,
190 : directory_path_( directory_path )
191 , distributed_domain_( distributed_domain )
192 , coords_shell_device_( coords_shell_device )
193 , coords_radii_device_( coords_radii_device )
194 , output_type_points_( output_type_points )
195 , output_type_connectivity_( output_type_connectivity )
197 if ( coords_shell_device.extent( 0 ) != coords_radii_device.extent( 0 ) )
199 Kokkos::abort(
"XDMF: Number of subdomains of shell and radii coords does not match." );
212 template <
typename InputScalarDataType >
217 if ( first_write_happened_ )
219 Kokkos::abort(
"XDMF::add(): Cannot add data after write() has been called." );
222 check_extents( data );
224 if ( is_label_taken( data.label() ) )
226 Kokkos::abort( (
"Cannot add data with label '" + data.label() +
227 "' - data with identical label has been added previously." )
231 if constexpr ( std::is_same_v< InputScalarDataType, double > )
233 device_data_views_scalar_double_.push_back( { data, output_type } );
235 else if constexpr ( std::is_same_v< InputScalarDataType, float > )
237 device_data_views_scalar_float_.push_back( { data, output_type } );
241 Kokkos::abort(
"XDMF::add(): Grid data type not supported (yet)." );
248 template <
typename InputScalarDataType,
int VecDim >
253 if ( first_write_happened_ )
255 Kokkos::abort(
"XDMF::add(): Cannot add data after write() has been called." );
258 check_extents( data );
260 if ( is_label_taken( data.label() ) )
262 Kokkos::abort( (
"Cannot add data with label '" + data.label() +
263 "' - data with identical label has been added previously." )
267 if constexpr ( std::is_same_v< InputScalarDataType, double > )
269 device_data_views_vec_double_.push_back( { data, output_type } );
271 else if constexpr ( std::is_same_v< InputScalarDataType, float > )
273 device_data_views_vec_float_.push_back( { data, output_type } );
277 Kokkos::abort(
"XDMF::add(): Grid data type not supported (yet)." );
297 const auto geometry_file_base =
"geometry.bin";
298 const auto topology_file_base =
"topology.bin";
300 const auto readme_file_path = directory_path_ +
"/README.md";
302 const auto geometry_file_path = directory_path_ +
"/" + geometry_file_base;
303 const auto topology_file_path = directory_path_ +
"/" + topology_file_base;
305 const auto step_file_path = directory_path_ +
"/step_" + std::to_string( write_counter_ ) +
".xmf";
307 const int num_subdomains = coords_shell_device_.extent( 0 );
308 const int nodes_x = coords_shell_device_.extent( 1 );
309 const int nodes_y = coords_shell_device_.extent( 2 );
310 const int nodes_r = coords_radii_device_.extent( 1 );
312 const auto number_of_nodes_local = num_subdomains * nodes_x * nodes_y * nodes_r;
313 const auto number_of_elements_local = num_subdomains * ( nodes_x - 1 ) * ( nodes_y - 1 ) * ( nodes_r - 1 ) * 2;
315 if ( !first_write_happened_ )
319 int num_nodes_elements_subdomains_global[3] = {
320 number_of_nodes_local, number_of_elements_local, num_subdomains };
321 MPI_Allreduce( MPI_IN_PLACE, &num_nodes_elements_subdomains_global, 3, MPI_INT, MPI_SUM, MPI_COMM_WORLD );
322 number_of_nodes_global_ = num_nodes_elements_subdomains_global[0];
323 number_of_elements_global_ = num_nodes_elements_subdomains_global[1];
324 number_of_subdomains_global_ = num_nodes_elements_subdomains_global[2];
334 int local_values[3] = { number_of_nodes_local, number_of_elements_local, num_subdomains };
337 MPI_Scan( &local_values, &offsets, 3, MPI_INT, MPI_SUM, MPI_COMM_WORLD );
340 number_of_nodes_offset_ = offsets[0] - local_values[0];
341 number_of_elements_offset_ = offsets[1] - local_values[1];
342 number_of_subdomains_offset_ = offsets[2] - local_values[2];
352 std::ofstream readme_stream( readme_file_path );
354 <<
"# This directory contains the output of the XDMF writer (for visualization and checkpointing).\n";
355 readme_stream <<
"\n";
356 readme_stream <<
"Overview:\n";
357 readme_stream <<
"- `geometry.bin`: cartesian node coordinates\n";
358 readme_stream <<
"- `topology.bin`: connectivity/topology/elements (whatever you want to call it)\n";
359 readme_stream <<
"- `checkpoint_metadata.bin`: metadata for checkpointing\n";
361 <<
"- `step_*.xmf`: xmf file (open this with Paraview for visualization) for each write() step\n";
362 readme_stream <<
"- `<some_name>_*.bin`: binary grid data (per write() step)\n";
363 readme_stream.close();
370 std::stringstream geometry_stream;
371 switch ( output_type_points_ )
374 write_geometry_binary_data< float >( geometry_stream );
377 write_geometry_binary_data< double >( geometry_stream );
380 Kokkos::abort(
"XDMF: Unknown output type for geometry." );
385 MPI_COMM_WORLD, geometry_file_path.c_str(), MPI_MODE_CREATE | MPI_MODE_RDWR, MPI_INFO_NULL, &fh );
388 MPI_Offset disp = number_of_nodes_offset_ * 3 *
static_cast< int >( output_type_points_ );
389 MPI_File_set_view( fh, disp, MPI_CHAR, MPI_CHAR,
"native", MPI_INFO_NULL );
391 std::string geom_str = geometry_stream.str();
395 fh, geom_str.data(),
static_cast< int >( geom_str.size() ), MPI_CHAR, MPI_STATUS_IGNORE );
398 MPI_File_close( &fh );
403 std::stringstream topology_stream;
404 switch ( output_type_connectivity_ )
407 write_topology_binary_data< int32_t >( topology_stream, number_of_nodes_offset_ );
410 write_topology_binary_data< int64_t >( topology_stream, number_of_nodes_offset_ );
413 Kokkos::abort(
"XDMF: Unknown output type for topology." );
418 MPI_COMM_WORLD, topology_file_path.c_str(), MPI_MODE_CREATE | MPI_MODE_RDWR, MPI_INFO_NULL, &fh );
421 MPI_Offset disp = 6 * number_of_elements_offset_ *
static_cast< int >( output_type_connectivity_ );
422 MPI_File_set_view( fh, disp, MPI_CHAR, MPI_CHAR,
"native", MPI_INFO_NULL );
424 std::string topo_str = topology_stream.str();
428 fh, topo_str.data(),
static_cast< int >( topo_str.size() ), MPI_CHAR, MPI_STATUS_IGNORE );
431 MPI_File_close( &fh );
436 write_checkpoint_metadata();
442 auto xml = XML(
"Xdmf", { {
"Version",
"2.0" } } );
443 auto domain = XML(
"Domain" );
444 auto grid = XML(
"Grid", { {
"Name",
"Grid" }, {
"GridType",
"Uniform" } } );
447 XML(
"Geometry", { {
"Type",
"XYZ" } } )
450 { {
"Format",
"Binary" },
451 {
"DataType",
"Float" },
452 {
"Precision", std::to_string(
static_cast< int >( output_type_points_ ) ) },
453 {
"Endian",
"Little" },
454 {
"Dimensions", std::to_string( number_of_nodes_global_ ) +
" " + std::to_string( 3 ) } },
455 geometry_file_base ) );
457 grid.add_child( geometry );
461 { {
"Type",
"Wedge" }, {
"NumberOfElements", std::to_string( number_of_elements_global_ ) } } )
464 { {
"Format",
"Binary" },
465 {
"DataType",
"Int" },
466 {
"Precision", std::to_string(
static_cast< int >( output_type_connectivity_ ) ) },
467 {
"Endian",
"Little" },
468 {
"Dimensions", std::to_string( number_of_elements_global_ * 6 ) } },
469 topology_file_base ) );
471 grid.add_child( topology );
475 for (
const auto& [data, output_type] : device_data_views_scalar_float_ )
477 const auto attribute = write_scalar_attribute_file( data, output_type );
478 grid.add_child( attribute );
481 for (
const auto& [data, output_type] : device_data_views_scalar_double_ )
483 const auto attribute = write_scalar_attribute_file( data, output_type );
484 grid.add_child( attribute );
487 for (
const auto& [data, output_type] : device_data_views_vec_float_ )
489 const auto attribute = write_vec_attribute_file( data, output_type );
490 grid.add_child( attribute );
493 for (
const auto& [data, output_type] : device_data_views_vec_double_ )
495 const auto attribute = write_vec_attribute_file( data, output_type );
496 grid.add_child( attribute );
499 domain.add_child( grid );
500 xml.add_child( domain );
504 std::ofstream step_stream( step_file_path );
505 step_stream <<
"<?xml version=\"1.0\" ?>\n";
506 step_stream <<
"<!DOCTYPE Xdmf SYSTEM \"Xdmf.dtd\" []>\n";
507 step_stream << xml.to_string();
512 first_write_happened_ =
true;
516 template <
typename Gr
idDataType >
517 void check_extents(
const GridDataType& data )
519 if ( data.extent( 0 ) != coords_radii_device_.extent( 0 ) )
521 Kokkos::abort(
"XDMF: Number of subdomains of added data item does not match mesh." );
524 if ( data.extent( 1 ) != coords_shell_device_.extent( 1 ) )
526 Kokkos::abort(
"XDMF: Dim x of added data item does not match mesh." );
529 if ( data.extent( 2 ) != coords_shell_device_.extent( 2 ) )
531 Kokkos::abort(
"XDMF: Dim y of added data item does not match mesh." );
534 if ( data.extent( 3 ) != coords_radii_device_.extent( 1 ) )
536 Kokkos::abort(
"XDMF: Dim r of added data item does not match mesh." );
540 bool is_label_taken(
const std::string& label )
542 for (
auto [grid, _] : device_data_views_scalar_double_ )
544 if ( grid.label() == label )
550 for (
auto [grid, _] : device_data_views_scalar_float_ )
552 if ( grid.label() == label )
558 for (
auto [grid, _] : device_data_views_vec_double_ )
560 if ( grid.label() == label )
566 for (
auto [grid, _] : device_data_views_vec_float_ )
568 if ( grid.label() == label )
577 template < std::
floating_po
int FloatingPo
intOutputType >
578 void write_geometry_binary_data( std::stringstream& out )
582 const typename grid::Grid3DDataVec< InputGridScalarType, 3 >::HostMirror coords_shell_host =
583 Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace{}, coords_shell_device_ );
584 const typename grid::Grid2DDataScalar< InputGridScalarType >::HostMirror coords_radii_host =
585 Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace{}, coords_radii_device_ );
589 for (
int r = 0;
r < coords_radii_host.extent( 1 );
r++ )
591 for (
int y = 0; y < coords_shell_host.extent( 2 ); y++ )
593 for (
int x = 0; x < coords_shell_host.extent( 1 ); x++ )
598 for (
int d = 0; d < 3; d++ )
600 const auto cd =
static_cast< FloatingPointOutputType
>( c( d ) );
601 out.write(
reinterpret_cast< const char*
>( &cd ),
sizeof( FloatingPointOutputType ) );
609 template < std::
integral IntegerOutputType >
610 void write_topology_binary_data( std::stringstream& out, IntegerOutputType number_of_nodes_offset )
612 const int num_subdomains = coords_shell_device_.extent( 0 );
613 const int nodes_x = coords_shell_device_.extent( 1 );
614 const int nodes_y = coords_shell_device_.extent( 2 );
615 const int nodes_r = coords_radii_device_.extent( 1 );
617 const int stride_0 = nodes_x * nodes_y * nodes_r;
618 const int stride_1 = nodes_x * nodes_y;
619 const int stride_2 = nodes_x;
623 for (
int r = 0;
r < nodes_r - 1;
r++ )
625 for (
int y = 0; y < nodes_y - 1; y++ )
627 for (
int x = 0; x < nodes_x - 1; x++ )
630 IntegerOutputType v[8];
632 v[0] = number_of_nodes_offset +
local_subdomain_id * stride_0 +
r * stride_1 + y * stride_2 + x;
634 v[2] = v[0] + nodes_x;
635 v[3] = v[0] + nodes_x + 1;
640 v[6] = v[4] + nodes_x;
641 v[7] = v[4] + nodes_x + 1;
643 IntegerOutputType wedge_0[6] = { v[0], v[1], v[2], v[4], v[5], v[6] };
644 IntegerOutputType wedge_1[6] = { v[3], v[2], v[1], v[7], v[6], v[5] };
646 out.write(
reinterpret_cast< const char*
>( wedge_0 ),
sizeof( IntegerOutputType ) * 6 );
647 out.write(
reinterpret_cast< const char*
>( wedge_1 ),
sizeof( IntegerOutputType ) * 6 );
654 template <
typename ScalarTypeIn,
typename ScalarTypeOut >
655 void write_scalar_attribute_binary_data(
656 const grid::Grid4DDataScalar< ScalarTypeIn >& device_data,
657 std::stringstream& out )
660 if constexpr ( std::is_same_v< ScalarTypeIn, double > )
662 if ( !host_data_mirror_scalar_double_.has_value() )
664 host_data_mirror_scalar_double_ = Kokkos::create_mirror( Kokkos::HostSpace{}, device_data );
667 Kokkos::deep_copy( host_data_mirror_scalar_double_.value(), device_data );
669 const auto& host_data = host_data_mirror_scalar_double_.value();
673 for (
int r = 0;
r < host_data.extent( 3 );
r++ )
675 for (
int y = 0; y < host_data.extent( 2 ); y++ )
677 for (
int x = 0; x < host_data.extent( 1 ); x++ )
679 const auto value =
static_cast< ScalarTypeOut
>( host_data( local_subdomain_id, x, y, r ) );
680 out.write(
reinterpret_cast< const char*
>( &value ),
sizeof( ScalarTypeOut ) );
686 else if constexpr ( std::is_same_v< ScalarTypeIn, float > )
688 if ( !host_data_mirror_scalar_float_.has_value() )
690 host_data_mirror_scalar_float_ = Kokkos::create_mirror( Kokkos::HostSpace{}, device_data );
693 Kokkos::deep_copy( host_data_mirror_scalar_float_.value(), device_data );
695 const auto& host_data = host_data_mirror_scalar_float_.value();
699 for (
int r = 0;
r < host_data.extent( 3 );
r++ )
701 for (
int y = 0; y < host_data.extent( 2 ); y++ )
703 for (
int x = 0; x < host_data.extent( 1 ); x++ )
705 const auto value =
static_cast< ScalarTypeOut
>( host_data( local_subdomain_id, x, y, r ) );
706 out.write(
reinterpret_cast< const char*
>( &value ),
sizeof( ScalarTypeOut ) );
714 Kokkos::abort(
"XDMF: Only double precision grids supported for scalar attributes." );
718 template <
typename ScalarTypeIn >
719 util::XML write_scalar_attribute_file(
720 const grid::Grid4DDataScalar< ScalarTypeIn >& data,
723 const auto attribute_file_base = data.label() +
"_" + std::to_string( write_counter_ ) +
".bin";
724 const auto attribute_file_path = directory_path_ +
"/" + attribute_file_base;
727 std::stringstream attribute_stream;
728 switch ( output_type )
731 write_scalar_attribute_binary_data< ScalarTypeIn, float >( data, attribute_stream );
734 write_scalar_attribute_binary_data< ScalarTypeIn, double >( data, attribute_stream );
740 MPI_COMM_WORLD, attribute_file_path.c_str(), MPI_MODE_CREATE | MPI_MODE_RDWR, MPI_INFO_NULL, &fh );
743 MPI_Offset disp = number_of_nodes_offset_ *
static_cast< int >( output_type_points_ );
744 MPI_File_set_view( fh, disp, MPI_CHAR, MPI_CHAR,
"native", MPI_INFO_NULL );
746 std::string attr_str = attribute_stream.str();
750 fh, attr_str.data(),
static_cast< int >( attr_str.size() ), MPI_CHAR, MPI_STATUS_IGNORE );
753 MPI_File_close( &fh );
757 util::XML(
"Attribute", { {
"Name", data.label() }, {
"AttributeType",
"Scalar" }, {
"Center",
"Node" } } )
761 { {
"Format",
"Binary" },
762 {
"DataType",
"Float" },
763 {
"Precision", std::to_string(
static_cast< int >( output_type ) ) },
764 {
"Endian",
"Little" },
765 {
"Dimensions", std::to_string( number_of_nodes_global_ ) } },
766 attribute_file_base ) );
771 template <
typename ScalarTypeIn,
typename ScalarTypeOut,
int VecDim >
772 void write_vec_attribute_binary_data(
773 const grid::Grid4DDataVec< ScalarTypeIn, VecDim >& device_data,
774 std::stringstream& out )
777 if constexpr ( std::is_same_v< ScalarTypeIn, double > )
779 if ( !host_data_mirror_vec_double_.has_value() )
781 host_data_mirror_vec_double_ = Kokkos::create_mirror( Kokkos::HostSpace{}, device_data );
784 Kokkos::deep_copy( host_data_mirror_vec_double_.value(), device_data );
786 const auto& host_data = host_data_mirror_vec_double_.value();
790 for (
int r = 0;
r < host_data.extent( 3 );
r++ )
792 for (
int y = 0; y < host_data.extent( 2 ); y++ )
794 for (
int x = 0; x < host_data.extent( 1 ); x++ )
796 for (
int d = 0; d < VecDim; d++ )
799 static_cast< ScalarTypeOut
>( host_data( local_subdomain_id, x, y, r, d ) );
800 out.write(
reinterpret_cast< const char*
>( &value ),
sizeof( ScalarTypeOut ) );
807 else if constexpr ( std::is_same_v< ScalarTypeIn, float > )
809 if ( !host_data_mirror_vec_float_.has_value() )
811 host_data_mirror_vec_float_ = Kokkos::create_mirror( Kokkos::HostSpace{}, device_data );
814 Kokkos::deep_copy( host_data_mirror_vec_float_.value(), device_data );
816 const auto& host_data = host_data_mirror_vec_float_.value();
820 for (
int r = 0;
r < host_data.extent( 3 );
r++ )
822 for (
int y = 0; y < host_data.extent( 2 ); y++ )
824 for (
int x = 0; x < host_data.extent( 1 ); x++ )
826 for (
int d = 0; d < VecDim; d++ )
829 static_cast< ScalarTypeOut
>( host_data( local_subdomain_id, x, y, r, d ) );
830 out.write(
reinterpret_cast< const char*
>( &value ),
sizeof( ScalarTypeOut ) );
839 Kokkos::abort(
"XDMF: Only double precision grids supported for vector-valued attributes." );
843 template <
typename ScalarTypeIn,
int VecDim >
844 util::XML write_vec_attribute_file(
845 const grid::Grid4DDataVec< ScalarTypeIn, VecDim >& data,
848 const auto attribute_file_base = data.label() +
"_" + std::to_string( write_counter_ ) +
".bin";
849 const auto attribute_file_path = directory_path_ +
"/" + attribute_file_base;
852 std::stringstream attribute_stream;
853 switch ( output_type )
856 write_vec_attribute_binary_data< ScalarTypeIn, float >( data, attribute_stream );
859 write_vec_attribute_binary_data< ScalarTypeIn, double >( data, attribute_stream );
865 MPI_COMM_WORLD, attribute_file_path.c_str(), MPI_MODE_CREATE | MPI_MODE_RDWR, MPI_INFO_NULL, &fh );
868 MPI_Offset disp = VecDim * number_of_nodes_offset_ *
static_cast< int >( output_type_points_ );
869 MPI_File_set_view( fh, disp, MPI_CHAR, MPI_CHAR,
"native", MPI_INFO_NULL );
871 std::string attr_str = attribute_stream.str();
875 fh, attr_str.data(),
static_cast< int >( attr_str.size() ), MPI_CHAR, MPI_STATUS_IGNORE );
878 MPI_File_close( &fh );
882 util::XML(
"Attribute", { {
"Name", data.label() }, {
"AttributeType",
"Vector" }, {
"Center",
"Node" } } )
886 { {
"Format",
"Binary" },
887 {
"DataType",
"Float" },
888 {
"Precision", std::to_string(
static_cast< int >( output_type ) ) },
889 {
"Endian",
"Little" },
891 std::to_string( number_of_nodes_global_ ) +
" " + std::to_string( VecDim ) } },
892 attribute_file_base ) );
897 void write_checkpoint_metadata()
899 const auto checkpoint_metadata_file_path = directory_path_ +
"/" +
"checkpoint_metadata.bin";
901 std::stringstream checkpoint_metadata_stream;
903 auto write_i32 = [&](
const int32_t
value ) {
904 checkpoint_metadata_stream.write(
reinterpret_cast< const char*
>( &value ),
sizeof( int32_t ) );
907 auto write_i64 = [&](
const int64_t
value ) {
908 checkpoint_metadata_stream.write(
reinterpret_cast< const char*
>( &value ),
sizeof( int64_t ) );
911 auto write_f64 = [&](
const double value ) {
912 checkpoint_metadata_stream.write(
reinterpret_cast< const char*
>( &value ),
sizeof( double ) );
919 write_i32( coords_shell_device_.extent( 1 ) );
920 write_i32( coords_shell_device_.extent( 2 ) );
921 write_i32( coords_radii_device_.extent( 1 ) );
923 for (
const auto r : distributed_domain_.domain_info().radii() )
925 write_f64(
static_cast< double >( r ) );
928 write_i32(
static_cast< int32_t
>( output_type_points_ ) );
931 device_data_views_scalar_float_.size() + device_data_views_scalar_double_.size() +
932 device_data_views_vec_float_.size() + device_data_views_vec_double_.size() );
934 for (
const auto& [data, output_type] : device_data_views_scalar_float_ )
936 write_i32( data.label().size() );
937 checkpoint_metadata_stream.write( data.label().data(), data.label().size() );
941 write_i32(
sizeof(
float ) );
945 write_i32(
sizeof(
double ) );
949 Kokkos::abort(
"Invalid output type." );
955 for (
const auto& [data, output_type] : device_data_views_scalar_double_ )
957 write_i32( data.label().size() );
958 checkpoint_metadata_stream.write( data.label().data(), data.label().size() );
962 write_i32(
sizeof(
float ) );
966 write_i32(
sizeof(
double ) );
970 Kokkos::abort(
"Invalid output type." );
975 for (
const auto& [data, output_type] : device_data_views_vec_float_ )
977 write_i32( data.label().size() );
978 checkpoint_metadata_stream.write( data.label().data(), data.label().size() );
982 write_i32(
sizeof(
float ) );
986 write_i32(
sizeof(
double ) );
990 Kokkos::abort(
"Invalid output type." );
992 write_i32( data.extent( 4 ) );
995 for (
const auto& [data, output_type] : device_data_views_vec_double_ )
997 write_i32( data.label().size() );
998 checkpoint_metadata_stream.write( data.label().data(), data.label().size() );
1002 write_i32(
sizeof(
float ) );
1006 write_i32(
sizeof(
double ) );
1010 Kokkos::abort(
"Invalid output type." );
1012 write_i32( data.extent( 4 ) );
1025 checkpoint_metadata_file_path.c_str(),
1026 MPI_MODE_CREATE | MPI_MODE_RDWR,
1031 MPI_Offset disp = 0;
1032 const auto offset_metadata_size_bytes =
static_cast< int >( checkpoint_metadata_stream.str().size() );
1040 disp = offset_metadata_size_bytes + number_of_subdomains_offset_ *
sizeof( int64_t );
1041 checkpoint_metadata_stream.clear();
1042 checkpoint_metadata_stream.str(
"" );
1053 MPI_File_set_view( fh, disp, MPI_CHAR, MPI_CHAR,
"native", MPI_INFO_NULL );
1055 std::string checkpoint_metadata_str = checkpoint_metadata_stream.str();
1060 checkpoint_metadata_str.data(),
1061 static_cast< int >( checkpoint_metadata_str.size() ),
1063 MPI_STATUS_IGNORE );
1066 MPI_File_close( &fh );
1069 std::string directory_path_;
1071 grid::shell::DistributedDomain distributed_domain_;
1073 grid::Grid3DDataVec< InputGridScalarType, 3 > coords_shell_device_;
1074 grid::Grid2DDataScalar< InputGridScalarType > coords_radii_device_;
1080 std::vector< std::pair< grid::Grid4DDataScalar< double >,
OutputTypeFloat > > device_data_views_scalar_double_;
1081 std::vector< std::pair< grid::Grid4DDataScalar< float >,
OutputTypeFloat > > device_data_views_scalar_float_;
1083 std::vector< std::pair< grid::Grid4DDataVec< double, 3 >,
OutputTypeFloat > > device_data_views_vec_double_;
1084 std::vector< std::pair< grid::Grid4DDataVec< float, 3 >,
OutputTypeFloat > > device_data_views_vec_float_;
1087 std::optional< grid::Grid4DDataScalar< double >::HostMirror > host_data_mirror_scalar_double_;
1088 std::optional< grid::Grid4DDataScalar< float >::HostMirror > host_data_mirror_scalar_float_;
1090 std::optional< grid::Grid4DDataVec< double, 3 >::HostMirror > host_data_mirror_vec_double_;
1091 std::optional< grid::Grid4DDataVec< float, 3 >::HostMirror > host_data_mirror_vec_float_;
1093 int write_counter_ = 0;
1094 bool first_write_happened_ =
false;
1096 int number_of_nodes_offset_ = -1;
1097 int number_of_elements_offset_ = -1;
1098 int number_of_subdomains_offset_ = -1;
1100 int number_of_nodes_global_ = -1;
1101 int number_of_elements_global_ = -1;
1102 int number_of_subdomains_global_ = -1;
1283 const std::string& checkpoint_directory,
1284 const std::string& data_label,
1287 GridDataType& grid_data_device )
1291 if ( checkpoint_metadata_result.is_err() )
1293 return "Could not read checkpoint metadata: " + checkpoint_metadata_result.error();
1296 const auto& checkpoint_metadata = checkpoint_metadata_result.unwrap();
1298 if ( !( checkpoint_metadata.version == 0 || checkpoint_metadata.version == 1 ) )
1301 "Supported checkpoint verions: 0, 1. This checkpoint has version " +
1302 std::to_string( checkpoint_metadata.version ) +
"." };
1307 std::optional< CheckpointMetadata::GridDataFile > requested_grid_data_file;
1308 for (
const auto& grid_data_file : checkpoint_metadata.grid_data_files )
1310 if ( grid_data_file.grid_name_string == data_label )
1312 requested_grid_data_file = grid_data_file;
1317 if ( !requested_grid_data_file.has_value() )
1319 return {
"Could not find requested data (" + data_label +
") in checkpoint" };
1324 const auto data_file_path = checkpoint_directory +
"/" + data_label +
"_" + std::to_string( step ) +
".bin";
1326 if ( !std::filesystem::exists( data_file_path ) )
1328 return {
"Could not find checkpoint data file for requested label and step." };
1333 if ( grid_data_device.extent( 1 ) != checkpoint_metadata.size_x ||
1334 grid_data_device.extent( 2 ) != checkpoint_metadata.size_y ||
1335 grid_data_device.extent( 3 ) != checkpoint_metadata.size_r )
1337 return {
"Grid data extents do not match metadata." };
1346 if ( checkpoint_metadata.checkpoint_subdomain_ordering != 0 )
1348 return {
"Checkpoint ordering type is not 0. Not supported." };
1353 const auto num_local_subdomains = grid_data_device.extent( 0 );
1355 const auto local_subdomain_num_scalars_v = checkpoint_metadata.size_x * checkpoint_metadata.size_y *
1356 checkpoint_metadata.size_r * requested_grid_data_file.value().vec_dim;
1358 const auto local_subdomain_data_size_in_bytes =
1359 local_subdomain_num_scalars_v * requested_grid_data_file.value().scalar_bytes;
1361 std::vector< MPI_Aint > local_subdomain_offsets_in_file_bytes( num_local_subdomains );
1362 std::vector< int > local_subdomain_num_bytes( num_local_subdomains, local_subdomain_data_size_in_bytes );
1364 for (
int local_subdomain_id = 0; local_subdomain_id < num_local_subdomains; local_subdomain_id++ )
1366 const auto global_subdomain_id =
1369 const auto index_in_file =
1370 std::ranges::find( checkpoint_metadata.checkpoint_ordering_0_global_subdomain_ids, global_subdomain_id ) -
1371 checkpoint_metadata.checkpoint_ordering_0_global_subdomain_ids.begin();
1373 local_subdomain_offsets_in_file_bytes[local_subdomain_id] = index_in_file * local_subdomain_data_size_in_bytes;
1378 std::vector< char > buffer( num_local_subdomains * local_subdomain_data_size_in_bytes );
1381 MPI_File_open( MPI_COMM_WORLD, data_file_path.c_str(), MPI_MODE_RDONLY, MPI_INFO_NULL, &fh );
1383 MPI_Datatype filetype;
1384 MPI_Type_create_hindexed(
1385 num_local_subdomains,
1386 local_subdomain_num_bytes.data(),
1387 local_subdomain_offsets_in_file_bytes.data(),
1390 MPI_Type_commit( &filetype );
1393 MPI_File_set_view( fh, 0, MPI_CHAR, filetype,
"native", MPI_INFO_NULL );
1395 MPI_File_read_all( fh, buffer.data(), buffer.size(), MPI_CHAR, MPI_STATUS_IGNORE );
1397 MPI_Type_free( &filetype );
1398 MPI_File_close( &fh );
1402 typename GridDataType::HostMirror grid_data_host = Kokkos::create_mirror( Kokkos::HostSpace{}, grid_data_device );
1404 const auto checkpoint_is_float =
1405 requested_grid_data_file.value().scalar_data_type == 2 && requested_grid_data_file.value().scalar_bytes == 4;
1406 const auto checkpoint_is_double =
1407 requested_grid_data_file.value().scalar_data_type == 2 && requested_grid_data_file.value().scalar_bytes == 8;
1409 if ( !( checkpoint_is_float || checkpoint_is_double ) )
1411 return {
"Unsupported data type in checkpoint." };
1415 std::string_view view(
reinterpret_cast< const char*
>( buffer.data() ), buffer.size() );
1416 std::istringstream stream{ std::string( view ) };
1418 auto read_f32 = [&]() ->
float {
1420 stream.read(
reinterpret_cast< char*
>( &value ),
sizeof( float ) );
1421 if ( stream.fail() )
1423 Kokkos::abort(
"Failed to read from stream." );
1428 auto read_f64 = [&]() ->
double {
1430 stream.read(
reinterpret_cast< char*
>( &value ),
sizeof( double ) );
1431 if ( stream.fail() )
1433 Kokkos::abort(
"Failed to read from stream." );
1438 for (
int local_subdomain_id = 0; local_subdomain_id < grid_data_host.extent( 0 ); local_subdomain_id++ )
1440 for (
int r = 0; r < grid_data_host.extent( 3 ); r++ )
1442 for (
int y = 0; y < grid_data_host.extent( 2 ); y++ )
1444 for (
int x = 0; x < grid_data_host.extent( 1 ); x++ )
1447 std::is_same_v< GridDataType, grid::Grid4DDataScalar< float > > ||
1448 std::is_same_v< GridDataType, grid::Grid4DDataScalar< double > > )
1450 if ( requested_grid_data_file.value().vec_dim != 1 )
1452 return {
"Checkpoint is scalar, passed grid data view dims do not match." };
1456 if ( checkpoint_is_float )
1458 grid_data_host( local_subdomain_id, x, y, r ) =
1459 static_cast< GridDataType::value_type
>( read_f32() );
1461 else if ( checkpoint_is_double )
1463 grid_data_host( local_subdomain_id, x, y, r ) =
1464 static_cast< GridDataType::value_type
>( read_f64() );
1468 std::is_same_v< GridDataType, grid::Grid4DDataVec< float, 3 > > ||
1469 std::is_same_v< GridDataType, grid::Grid4DDataVec< double, 3 > > )
1471 if ( requested_grid_data_file.value().vec_dim != 3 )
1473 return {
"Checkpoint is vector-valued, passed grid data view dims do not match." };
1477 for (
int d = 0; d < grid_data_host.extent( 4 ); d++ )
1479 if ( checkpoint_is_float )
1481 grid_data_host( local_subdomain_id, x, y, r, d ) =
1482 static_cast< GridDataType::value_type
>( read_f32() );
1484 else if ( checkpoint_is_double )
1486 grid_data_host( local_subdomain_id, x, y, r, d ) =
1487 static_cast< GridDataType::value_type
>( read_f64() );
1496 Kokkos::deep_copy( grid_data_device, grid_data_host );