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 int64_t number_of_nodes_local =
static_cast< int64_t
>( num_subdomains ) * nodes_x * nodes_y * nodes_r;
313 const int64_t number_of_elements_local =
static_cast< int64_t
>( num_subdomains ) * ( nodes_x - 1 ) * ( nodes_y - 1 ) * ( nodes_r - 1 ) * 2;
315 if ( !first_write_happened_ )
319 int64_t num_nodes_elements_subdomains_global[3] = {
320 number_of_nodes_local, number_of_elements_local,
static_cast< int64_t
>( num_subdomains ) };
321 MPI_Allreduce( MPI_IN_PLACE, &num_nodes_elements_subdomains_global, 3, MPI_LONG_LONG, 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 int64_t local_values[3] = { number_of_nodes_local, number_of_elements_local,
static_cast< int64_t
>( num_subdomains ) };
337 MPI_Scan( &local_values, &offsets, 3, MPI_LONG_LONG, 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< int64_t
>( 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 =
static_cast< int64_t
>( 6 ) * number_of_elements_offset_ *
static_cast< int64_t
>( 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, int64_t 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 IntegerOutputType stride_0 =
static_cast< IntegerOutputType
>( nodes_x ) * nodes_y * nodes_r;
618 const IntegerOutputType stride_1 =
static_cast< IntegerOutputType
>( nodes_x ) * nodes_y;
619 const IntegerOutputType stride_2 = nodes_x;
620 const IntegerOutputType offset =
static_cast< IntegerOutputType
>( number_of_nodes_offset );
624 for (
int r = 0;
r < nodes_r - 1;
r++ )
626 for (
int y = 0; y < nodes_y - 1; y++ )
628 for (
int x = 0; x < nodes_x - 1; x++ )
631 IntegerOutputType v[8];
635 v[2] = v[0] + nodes_x;
636 v[3] = v[0] + nodes_x + 1;
641 v[6] = v[4] + nodes_x;
642 v[7] = v[4] + nodes_x + 1;
644 IntegerOutputType wedge_0[6] = { v[0], v[1], v[2], v[4], v[5], v[6] };
645 IntegerOutputType wedge_1[6] = { v[3], v[2], v[1], v[7], v[6], v[5] };
647 out.write(
reinterpret_cast< const char*
>( wedge_0 ),
sizeof( IntegerOutputType ) * 6 );
648 out.write(
reinterpret_cast< const char*
>( wedge_1 ),
sizeof( IntegerOutputType ) * 6 );
655 template <
typename ScalarTypeIn,
typename ScalarTypeOut >
656 void write_scalar_attribute_binary_data(
657 const grid::Grid4DDataScalar< ScalarTypeIn >& device_data,
658 std::stringstream& out )
661 if constexpr ( std::is_same_v< ScalarTypeIn, double > )
663 if ( !host_data_mirror_scalar_double_.has_value() )
665 host_data_mirror_scalar_double_ = Kokkos::create_mirror( Kokkos::HostSpace{}, device_data );
668 Kokkos::deep_copy( host_data_mirror_scalar_double_.value(), device_data );
670 const auto& host_data = host_data_mirror_scalar_double_.value();
674 for (
int r = 0;
r < host_data.extent( 3 );
r++ )
676 for (
int y = 0; y < host_data.extent( 2 ); y++ )
678 for (
int x = 0; x < host_data.extent( 1 ); x++ )
680 const auto value =
static_cast< ScalarTypeOut
>( host_data( local_subdomain_id, x, y, r ) );
681 out.write(
reinterpret_cast< const char*
>( &value ),
sizeof( ScalarTypeOut ) );
687 else if constexpr ( std::is_same_v< ScalarTypeIn, float > )
689 if ( !host_data_mirror_scalar_float_.has_value() )
691 host_data_mirror_scalar_float_ = Kokkos::create_mirror( Kokkos::HostSpace{}, device_data );
694 Kokkos::deep_copy( host_data_mirror_scalar_float_.value(), device_data );
696 const auto& host_data = host_data_mirror_scalar_float_.value();
700 for (
int r = 0;
r < host_data.extent( 3 );
r++ )
702 for (
int y = 0; y < host_data.extent( 2 ); y++ )
704 for (
int x = 0; x < host_data.extent( 1 ); x++ )
706 const auto value =
static_cast< ScalarTypeOut
>( host_data( local_subdomain_id, x, y, r ) );
707 out.write(
reinterpret_cast< const char*
>( &value ),
sizeof( ScalarTypeOut ) );
715 Kokkos::abort(
"XDMF: Only double precision grids supported for scalar attributes." );
719 template <
typename ScalarTypeIn >
720 util::XML write_scalar_attribute_file(
721 const grid::Grid4DDataScalar< ScalarTypeIn >& data,
724 const auto attribute_file_base = data.label() +
"_" + std::to_string( write_counter_ ) +
".bin";
725 const auto attribute_file_path = directory_path_ +
"/" + attribute_file_base;
728 std::stringstream attribute_stream;
729 switch ( output_type )
732 write_scalar_attribute_binary_data< ScalarTypeIn, float >( data, attribute_stream );
735 write_scalar_attribute_binary_data< ScalarTypeIn, double >( data, attribute_stream );
741 MPI_COMM_WORLD, attribute_file_path.c_str(), MPI_MODE_CREATE | MPI_MODE_RDWR, MPI_INFO_NULL, &fh );
744 MPI_Offset disp = number_of_nodes_offset_ *
static_cast< int64_t
>( output_type_points_ );
745 MPI_File_set_view( fh, disp, MPI_CHAR, MPI_CHAR,
"native", MPI_INFO_NULL );
747 std::string attr_str = attribute_stream.str();
751 fh, attr_str.data(),
static_cast< int >( attr_str.size() ), MPI_CHAR, MPI_STATUS_IGNORE );
754 MPI_File_close( &fh );
758 util::XML(
"Attribute", { {
"Name", data.label() }, {
"AttributeType",
"Scalar" }, {
"Center",
"Node" } } )
762 { {
"Format",
"Binary" },
763 {
"DataType",
"Float" },
764 {
"Precision", std::to_string(
static_cast< int >( output_type ) ) },
765 {
"Endian",
"Little" },
766 {
"Dimensions", std::to_string( number_of_nodes_global_ ) } },
767 attribute_file_base ) );
772 template <
typename ScalarTypeIn,
typename ScalarTypeOut,
int VecDim >
773 void write_vec_attribute_binary_data(
774 const grid::Grid4DDataVec< ScalarTypeIn, VecDim >& device_data,
775 std::stringstream& out )
778 if constexpr ( std::is_same_v< ScalarTypeIn, double > )
780 if ( !host_data_mirror_vec_double_.has_value() )
787 const auto& host_data = host_data_mirror_vec_double_.value();
791 for (
int r = 0;
r < host_data.extent( 3 );
r++ )
793 for (
int y = 0; y < host_data.extent( 2 ); y++ )
795 for (
int x = 0; x < host_data.extent( 1 ); x++ )
797 for (
int d = 0; d < VecDim; d++ )
800 static_cast< ScalarTypeOut
>( host_data( local_subdomain_id, x, y, r, d ) );
801 out.write(
reinterpret_cast< const char*
>( &value ),
sizeof( ScalarTypeOut ) );
808 else if constexpr ( std::is_same_v< ScalarTypeIn, float > )
810 if ( !host_data_mirror_vec_float_.has_value() )
817 const auto& host_data = host_data_mirror_vec_float_.value();
821 for (
int r = 0;
r < host_data.extent( 3 );
r++ )
823 for (
int y = 0; y < host_data.extent( 2 ); y++ )
825 for (
int x = 0; x < host_data.extent( 1 ); x++ )
827 for (
int d = 0; d < VecDim; d++ )
830 static_cast< ScalarTypeOut
>( host_data( local_subdomain_id, x, y, r, d ) );
831 out.write(
reinterpret_cast< const char*
>( &value ),
sizeof( ScalarTypeOut ) );
840 Kokkos::abort(
"XDMF: Only double precision grids supported for vector-valued attributes." );
844 template <
typename ScalarTypeIn,
int VecDim >
845 util::XML write_vec_attribute_file(
846 const grid::Grid4DDataVec< ScalarTypeIn, VecDim >& data,
849 const auto attribute_file_base = data.label() +
"_" + std::to_string( write_counter_ ) +
".bin";
850 const auto attribute_file_path = directory_path_ +
"/" + attribute_file_base;
853 std::stringstream attribute_stream;
854 switch ( output_type )
857 write_vec_attribute_binary_data< ScalarTypeIn, float >( data, attribute_stream );
860 write_vec_attribute_binary_data< ScalarTypeIn, double >( data, attribute_stream );
866 MPI_COMM_WORLD, attribute_file_path.c_str(), MPI_MODE_CREATE | MPI_MODE_RDWR, MPI_INFO_NULL, &fh );
869 MPI_Offset disp =
static_cast< int64_t
>( VecDim ) * number_of_nodes_offset_ *
static_cast< int64_t
>( output_type_points_ );
870 MPI_File_set_view( fh, disp, MPI_CHAR, MPI_CHAR,
"native", MPI_INFO_NULL );
872 std::string attr_str = attribute_stream.str();
876 fh, attr_str.data(),
static_cast< int >( attr_str.size() ), MPI_CHAR, MPI_STATUS_IGNORE );
879 MPI_File_close( &fh );
883 util::XML(
"Attribute", { {
"Name", data.label() }, {
"AttributeType",
"Vector" }, {
"Center",
"Node" } } )
887 { {
"Format",
"Binary" },
888 {
"DataType",
"Float" },
889 {
"Precision", std::to_string(
static_cast< int >( output_type ) ) },
890 {
"Endian",
"Little" },
892 std::to_string( number_of_nodes_global_ ) +
" " + std::to_string( VecDim ) } },
893 attribute_file_base ) );
898 void write_checkpoint_metadata()
900 const auto checkpoint_metadata_file_path = directory_path_ +
"/" +
"checkpoint_metadata.bin";
902 std::stringstream checkpoint_metadata_stream;
904 auto write_i32 = [&](
const int32_t
value ) {
905 checkpoint_metadata_stream.write(
reinterpret_cast< const char*
>( &value ),
sizeof( int32_t ) );
908 auto write_i64 = [&](
const int64_t
value ) {
909 checkpoint_metadata_stream.write(
reinterpret_cast< const char*
>( &value ),
sizeof( int64_t ) );
912 auto write_f64 = [&](
const double value ) {
913 checkpoint_metadata_stream.write(
reinterpret_cast< const char*
>( &value ),
sizeof( double ) );
920 write_i32( coords_shell_device_.extent( 1 ) );
921 write_i32( coords_shell_device_.extent( 2 ) );
922 write_i32( coords_radii_device_.extent( 1 ) );
924 for (
const auto r : distributed_domain_.domain_info().radii() )
926 write_f64(
static_cast< double >( r ) );
929 write_i32(
static_cast< int32_t
>( output_type_points_ ) );
932 device_data_views_scalar_float_.size() + device_data_views_scalar_double_.size() +
933 device_data_views_vec_float_.size() + device_data_views_vec_double_.size() );
935 for (
const auto& [data, output_type] : device_data_views_scalar_float_ )
937 write_i32( data.label().size() );
938 checkpoint_metadata_stream.write( data.label().data(), data.label().size() );
942 write_i32(
sizeof(
float ) );
946 write_i32(
sizeof(
double ) );
950 Kokkos::abort(
"Invalid output type." );
956 for (
const auto& [data, output_type] : device_data_views_scalar_double_ )
958 write_i32( data.label().size() );
959 checkpoint_metadata_stream.write( data.label().data(), data.label().size() );
963 write_i32(
sizeof(
float ) );
967 write_i32(
sizeof(
double ) );
971 Kokkos::abort(
"Invalid output type." );
976 for (
const auto& [data, output_type] : device_data_views_vec_float_ )
978 write_i32( data.label().size() );
979 checkpoint_metadata_stream.write( data.label().data(), data.label().size() );
983 write_i32(
sizeof(
float ) );
987 write_i32(
sizeof(
double ) );
991 Kokkos::abort(
"Invalid output type." );
993 write_i32( data.extent( 4 ) );
996 for (
const auto& [data, output_type] : device_data_views_vec_double_ )
998 write_i32( data.label().size() );
999 checkpoint_metadata_stream.write( data.label().data(), data.label().size() );
1003 write_i32(
sizeof(
float ) );
1007 write_i32(
sizeof(
double ) );
1011 Kokkos::abort(
"Invalid output type." );
1013 write_i32( data.extent( 4 ) );
1026 checkpoint_metadata_file_path.c_str(),
1027 MPI_MODE_CREATE | MPI_MODE_RDWR,
1032 MPI_Offset disp = 0;
1033 const auto offset_metadata_size_bytes =
static_cast< int >( checkpoint_metadata_stream.str().size() );
1041 disp = offset_metadata_size_bytes + number_of_subdomains_offset_ *
sizeof( int64_t );
1042 checkpoint_metadata_stream.clear();
1043 checkpoint_metadata_stream.str(
"" );
1054 MPI_File_set_view( fh, disp, MPI_CHAR, MPI_CHAR,
"native", MPI_INFO_NULL );
1056 std::string checkpoint_metadata_str = checkpoint_metadata_stream.str();
1061 checkpoint_metadata_str.data(),
1062 static_cast< int >( checkpoint_metadata_str.size() ),
1064 MPI_STATUS_IGNORE );
1067 MPI_File_close( &fh );
1070 std::string directory_path_;
1072 grid::shell::DistributedDomain distributed_domain_;
1074 grid::Grid3DDataVec< InputGridScalarType, 3 > coords_shell_device_;
1075 grid::Grid2DDataScalar< InputGridScalarType > coords_radii_device_;
1081 std::vector< std::pair< grid::Grid4DDataScalar< double >,
OutputTypeFloat > > device_data_views_scalar_double_;
1082 std::vector< std::pair< grid::Grid4DDataScalar< float >,
OutputTypeFloat > > device_data_views_scalar_float_;
1084 std::vector< std::pair< grid::Grid4DDataVec< double, 3 >,
OutputTypeFloat > > device_data_views_vec_double_;
1085 std::vector< std::pair< grid::Grid4DDataVec< float, 3 >,
OutputTypeFloat > > device_data_views_vec_float_;
1088 std::optional< grid::Grid4DDataScalar< double >::HostMirror > host_data_mirror_scalar_double_;
1089 std::optional< grid::Grid4DDataScalar< float >::HostMirror > host_data_mirror_scalar_float_;
1091 std::optional< grid::Grid4DDataVec< double, 3 >::HostMirror > host_data_mirror_vec_double_;
1092 std::optional< grid::Grid4DDataVec< float, 3 >::HostMirror > host_data_mirror_vec_float_;
1094 int write_counter_ = 0;
1095 bool first_write_happened_ =
false;
1097 int64_t number_of_nodes_offset_ = -1;
1098 int64_t number_of_elements_offset_ = -1;
1099 int64_t number_of_subdomains_offset_ = -1;
1101 int64_t number_of_nodes_global_ = -1;
1102 int64_t number_of_elements_global_ = -1;
1103 int64_t number_of_subdomains_global_ = -1;
1284 const std::string& checkpoint_directory,
1285 const std::string& data_label,
1288 GridDataType& grid_data_device )
1292 if ( checkpoint_metadata_result.is_err() )
1294 return "Could not read checkpoint metadata: " + checkpoint_metadata_result.error();
1297 const auto& checkpoint_metadata = checkpoint_metadata_result.unwrap();
1299 if ( !( checkpoint_metadata.version == 0 || checkpoint_metadata.version == 1 ) )
1302 "Supported checkpoint verions: 0, 1. This checkpoint has version " +
1303 std::to_string( checkpoint_metadata.version ) +
"." };
1308 std::optional< CheckpointMetadata::GridDataFile > requested_grid_data_file;
1309 for (
const auto& grid_data_file : checkpoint_metadata.grid_data_files )
1311 if ( grid_data_file.grid_name_string == data_label )
1313 requested_grid_data_file = grid_data_file;
1318 if ( !requested_grid_data_file.has_value() )
1320 return {
"Could not find requested data (" + data_label +
") in checkpoint" };
1325 const auto data_file_path = checkpoint_directory +
"/" + data_label +
"_" + std::to_string( step ) +
".bin";
1327 if ( !std::filesystem::exists( data_file_path ) )
1329 return {
"Could not find checkpoint data file for requested label and step." };
1334 if ( grid_data_device.extent( 1 ) != checkpoint_metadata.size_x ||
1335 grid_data_device.extent( 2 ) != checkpoint_metadata.size_y ||
1336 grid_data_device.extent( 3 ) != checkpoint_metadata.size_r )
1338 return {
"Grid data extents do not match metadata." };
1347 if ( checkpoint_metadata.checkpoint_subdomain_ordering != 0 )
1349 return {
"Checkpoint ordering type is not 0. Not supported." };
1354 const auto num_local_subdomains = grid_data_device.extent( 0 );
1356 const auto local_subdomain_num_scalars_v = checkpoint_metadata.size_x * checkpoint_metadata.size_y *
1357 checkpoint_metadata.size_r * requested_grid_data_file.value().vec_dim;
1359 const auto local_subdomain_data_size_in_bytes =
1360 local_subdomain_num_scalars_v * requested_grid_data_file.value().scalar_bytes;
1362 std::vector< MPI_Aint > local_subdomain_offsets_in_file_bytes( num_local_subdomains );
1363 std::vector< int > local_subdomain_num_bytes( num_local_subdomains, local_subdomain_data_size_in_bytes );
1365 for (
int local_subdomain_id = 0; local_subdomain_id < num_local_subdomains; local_subdomain_id++ )
1367 const auto global_subdomain_id =
1370 const auto index_in_file =
1371 std::ranges::find( checkpoint_metadata.checkpoint_ordering_0_global_subdomain_ids, global_subdomain_id ) -
1372 checkpoint_metadata.checkpoint_ordering_0_global_subdomain_ids.begin();
1374 local_subdomain_offsets_in_file_bytes[local_subdomain_id] = index_in_file * local_subdomain_data_size_in_bytes;
1379 std::vector< char > buffer( num_local_subdomains * local_subdomain_data_size_in_bytes );
1382 MPI_File_open( MPI_COMM_WORLD, data_file_path.c_str(), MPI_MODE_RDONLY, MPI_INFO_NULL, &fh );
1384 MPI_Datatype filetype;
1385 MPI_Type_create_hindexed(
1386 num_local_subdomains,
1387 local_subdomain_num_bytes.data(),
1388 local_subdomain_offsets_in_file_bytes.data(),
1391 MPI_Type_commit( &filetype );
1394 MPI_File_set_view( fh, 0, MPI_CHAR, filetype,
"native", MPI_INFO_NULL );
1396 MPI_File_read_all( fh, buffer.data(), buffer.size(), MPI_CHAR, MPI_STATUS_IGNORE );
1398 MPI_Type_free( &filetype );
1399 MPI_File_close( &fh );
1403 typename GridDataType::HostMirror grid_data_host =
grid::create_mirror( Kokkos::HostSpace{}, grid_data_device );
1405 const auto checkpoint_is_float =
1406 requested_grid_data_file.value().scalar_data_type == 2 && requested_grid_data_file.value().scalar_bytes == 4;
1407 const auto checkpoint_is_double =
1408 requested_grid_data_file.value().scalar_data_type == 2 && requested_grid_data_file.value().scalar_bytes == 8;
1410 if ( !( checkpoint_is_float || checkpoint_is_double ) )
1412 return {
"Unsupported data type in checkpoint." };
1416 std::string_view view(
reinterpret_cast< const char*
>( buffer.data() ), buffer.size() );
1417 std::istringstream stream{ std::string( view ) };
1419 auto read_f32 = [&]() ->
float {
1421 stream.read(
reinterpret_cast< char*
>( &value ),
sizeof( float ) );
1422 if ( stream.fail() )
1424 Kokkos::abort(
"Failed to read from stream." );
1429 auto read_f64 = [&]() ->
double {
1431 stream.read(
reinterpret_cast< char*
>( &value ),
sizeof( double ) );
1432 if ( stream.fail() )
1434 Kokkos::abort(
"Failed to read from stream." );
1439 for (
int local_subdomain_id = 0; local_subdomain_id < grid_data_host.extent( 0 ); local_subdomain_id++ )
1441 for (
int r = 0; r < grid_data_host.extent( 3 ); r++ )
1443 for (
int y = 0; y < grid_data_host.extent( 2 ); y++ )
1445 for (
int x = 0; x < grid_data_host.extent( 1 ); x++ )
1448 std::is_same_v< GridDataType, grid::Grid4DDataScalar< float > > ||
1449 std::is_same_v< GridDataType, grid::Grid4DDataScalar< double > > )
1451 if ( requested_grid_data_file.value().vec_dim != 1 )
1453 return {
"Checkpoint is scalar, passed grid data view dims do not match." };
1457 if ( checkpoint_is_float )
1459 grid_data_host( local_subdomain_id, x, y, r ) =
1460 static_cast< GridDataType::value_type
>( read_f32() );
1462 else if ( checkpoint_is_double )
1464 grid_data_host( local_subdomain_id, x, y, r ) =
1465 static_cast< GridDataType::value_type
>( read_f64() );
1469 std::is_same_v< GridDataType, grid::Grid4DDataVec< float, 3 > > ||
1470 std::is_same_v< GridDataType, grid::Grid4DDataVec< double, 3 > > )
1472 if ( requested_grid_data_file.value().vec_dim != 3 )
1474 return {
"Checkpoint is vector-valued, passed grid data view dims do not match." };
1478 for (
int d = 0; d < grid_data_host.extent( 4 ); d++ )
1480 if ( checkpoint_is_float )
1482 grid_data_host( local_subdomain_id, x, y, r, d ) =
1483 static_cast< GridDataType::value_type
>( read_f32() );
1485 else if ( checkpoint_is_double )
1487 grid_data_host( local_subdomain_id, x, y, r, d ) =
1488 static_cast< GridDataType::value_type
>( read_f64() );