43 const std::string& filename,
44 const Kokkos::View<
double** [3] >& vertices,
48 const size_t nx = vertices.extent( 0 );
49 const size_t ny = vertices.extent( 1 );
50 const size_t num_points = nx * ny;
52 size_t num_elements = 0;
53 size_t points_per_element = 0;
54 uint8_t vtk_cell_type_id = 0;
58 if ( nx < 2 || ny < 2 )
60 throw std::runtime_error(
"XML: Cannot create linear quads from a mesh smaller than 2x2 points." );
62 num_elements = ( nx - 1 ) * ( ny - 1 );
63 points_per_element = 4;
64 vtk_cell_type_id =
static_cast< uint8_t
>(
VTK_QUAD );
68 if ( nx < 3 || ny < 3 )
70 throw std::runtime_error(
"XML: Cannot create quadratic quads from a mesh smaller than 3x3 points." );
72 if ( nx % 2 == 0 || ny % 2 == 0 )
74 throw std::runtime_error(
75 "XML: For QUADRATIC_QUAD elements using the 'every second node' scheme, Nx and Ny must be odd." );
77 size_t num_quad_elems_x = ( nx - 1 ) / 2;
78 size_t num_quad_elems_y = ( ny - 1 ) / 2;
79 num_elements = num_quad_elems_x * num_quad_elems_y;
80 points_per_element = 8;
85 throw std::runtime_error(
"XML: Unsupported VtkElementType." );
88 if ( num_elements == 0 && num_points > 0 )
92 std::cout <<
"Warning: Input dimensions result in zero elements. Writing points only." << std::endl;
94 else if ( num_elements == 0 && num_points == 0 )
96 throw std::runtime_error(
"XML: Input dimensions result in zero points and zero elements." );
100 auto h_vertices = Kokkos::create_mirror_view( vertices );
101 Kokkos::deep_copy( h_vertices, vertices );
105 std::ofstream ofs( filename );
106 if ( !ofs.is_open() )
108 throw std::runtime_error(
"XML: Could not open file for writing: " + filename );
110 ofs << std::fixed << std::setprecision( 8 );
113 ofs <<
"<?xml version=\"1.0\"?>\n";
115 ofs <<
"<VTKFile type=\"UnstructuredGrid\" version=\"1.0\" byte_order=\"LittleEndian\">\n";
116 ofs <<
" <UnstructuredGrid>\n";
118 ofs <<
" <Piece NumberOfPoints=\"" << num_points <<
"\" NumberOfCells=\"" << num_elements <<
"\">\n";
121 ofs <<
" <Points>\n";
123 ofs <<
" <DataArray type=\"Float64\" Name=\"Coordinates\" NumberOfComponents=\"3\" format=\"ascii\">\n";
124 for (
size_t i = 0; i < nx; ++i )
126 for (
size_t j = 0; j < ny; ++j )
128 ofs <<
" " << h_vertices( i, j, 0 ) <<
" " << h_vertices( i, j, 1 ) <<
" " << h_vertices( i, j, 2 )
132 ofs <<
" </DataArray>\n";
133 ofs <<
" </Points>\n";
140 std::vector< int64_t > connectivity;
141 connectivity.reserve( num_elements * points_per_element );
144 std::vector< int64_t > offsets;
145 offsets.reserve( num_elements );
146 int64_t current_offset = 0;
149 std::vector< uint8_t > types;
150 types.reserve( num_elements );
155 for (
size_t i = 0; i < nx - 1; ++i )
157 for (
size_t j = 0; j < ny - 1; ++j )
160 int64_t p0_idx =
static_cast< int64_t
>( i * ny + j );
161 int64_t p1_idx =
static_cast< int64_t
>( ( i + 1 ) * ny + j );
162 int64_t p2_idx =
static_cast< int64_t
>( ( i + 1 ) * ny + ( j + 1 ) );
163 int64_t p3_idx =
static_cast< int64_t
>( i * ny + ( j + 1 ) );
166 connectivity.push_back( p0_idx );
167 connectivity.push_back( p1_idx );
168 connectivity.push_back( p2_idx );
169 connectivity.push_back( p3_idx );
172 current_offset += points_per_element;
173 offsets.push_back( current_offset );
176 types.push_back( vtk_cell_type_id );
182 for (
size_t i = 0; i < nx - 1; i += 2 )
184 for (
size_t j = 0; j < ny - 1; j += 2 )
187 int64_t p0_idx =
static_cast< int64_t
>( i * ny + j );
188 int64_t p1_idx =
static_cast< int64_t
>( ( i + 2 ) * ny + j );
189 int64_t p2_idx =
static_cast< int64_t
>( ( i + 2 ) * ny + ( j + 2 ) );
190 int64_t p3_idx =
static_cast< int64_t
>( i * ny + ( j + 2 ) );
191 int64_t m01_idx =
static_cast< int64_t
>( ( i + 1 ) * ny + j );
192 int64_t m12_idx =
static_cast< int64_t
>( ( i + 2 ) * ny + ( j + 1 ) );
193 int64_t m23_idx =
static_cast< int64_t
>( ( i + 1 ) * ny + ( j + 2 ) );
194 int64_t m30_idx =
static_cast< int64_t
>( i * ny + ( j + 1 ) );
197 connectivity.push_back( p0_idx );
198 connectivity.push_back( p1_idx );
199 connectivity.push_back( p2_idx );
200 connectivity.push_back( p3_idx );
201 connectivity.push_back( m01_idx );
202 connectivity.push_back( m12_idx );
203 connectivity.push_back( m23_idx );
204 connectivity.push_back( m30_idx );
207 current_offset += points_per_element;
208 offsets.push_back( current_offset );
211 types.push_back( vtk_cell_type_id );
218 ofs <<
" <DataArray type=\"Int64\" Name=\"connectivity\" format=\"ascii\">\n";
220 for (
size_t i = 0; i < connectivity.size(); ++i )
222 ofs << connectivity[i] << ( ( i + 1 ) % 12 == 0 ?
"\n " :
" " );
224 ofs <<
"\n </DataArray>\n";
227 ofs <<
" <DataArray type=\"Int64\" Name=\"offsets\" format=\"ascii\">\n";
229 for (
size_t i = 0; i < offsets.size(); ++i )
231 ofs << offsets[i] << ( ( i + 1 ) % 12 == 0 ?
"\n " :
" " );
233 ofs <<
"\n </DataArray>\n";
236 ofs <<
" <DataArray type=\"UInt8\" Name=\"types\" format=\"ascii\">\n";
238 for (
size_t i = 0; i < types.size(); ++i )
241 ofs << static_cast< int >( types[i] ) << ( ( i + 1 ) % 20 == 0 ?
"\n " :
" " );
243 ofs <<
"\n </DataArray>\n";
245 ofs <<
" </Cells>\n";
248 ofs <<
" <PointData>\n";
250 ofs <<
" </PointData>\n";
251 ofs <<
" <CellData>\n";
253 ofs <<
" </CellData>\n";
256 ofs <<
" </Piece>\n";
257 ofs <<
" </UnstructuredGrid>\n";
258 ofs <<
"</VTKFile>\n";
264 throw std::runtime_error(
"XML: Error occurred during writing or closing file: " + filename );
439 std::optional< AttachedDataType > optional_attached_data_device_view,
440 const std::string& vector_data_name,
441 const std::string& filename,
445 std::is_same_v< AttachedDataType, grid::Grid3DDataScalar< double > > ||
446 std::is_same_v< AttachedDataType, grid::Grid3DDataVec< double, 3 > > );
448 const bool has_attached_data = optional_attached_data_device_view.has_value();
449 const int is_scalar_data = std::is_same_v< AttachedDataType, grid::Grid3DDataScalar< double > >;
450 const int num_vec_components = has_attached_data ? optional_attached_data_device_view.value().extent( 3 ) : 1;
453 auto surface_points_host = Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace{}, surface_points_device_view );
454 auto radii_host = Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace{}, radii_device_view );
456 typename AttachedDataType::HostMirror vector_data_host;
457 if ( has_attached_data )
460 Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace{}, optional_attached_data_device_view.value() );
465 const int Ns = surface_points_host.extent( 0 );
466 const int Nt = surface_points_host.extent( 1 );
467 const int Nw_radii = radii_host.extent( 0 );
469 if ( Ns < 2 || Nt < 2 )
471 throw std::runtime_error(
"Surface grid dimensions (Ns, Nt) must be >= 2 to form base triangles." );
475 throw std::runtime_error(
"Radii view must contain at least one radius value (Nw_radii >= 1)." );
479 if ( has_attached_data )
481 if ( vector_data_host.extent( 0 ) != Ns || vector_data_host.extent( 1 ) != Nt ||
482 vector_data_host.extent( 2 ) != Nw_radii )
484 throw std::runtime_error(
485 "VTK: Vector data dimensions (Ns, Nt, Nw_radii) do not match generated point structure." );
488 if ( vector_data_name.empty() )
490 throw std::runtime_error(
"VTK: Vector data name must be provided if vector data is present." );
495 const long long num_total_points =
static_cast< long long >( Ns ) * Nt * Nw_radii;
496 long long num_cells = 0;
499 const long long num_quads_in_surface_plane =
static_cast< long long >( Ns - 1 ) * ( Nt - 1 );
500 const long long num_wedge_layers =
static_cast< long long >( Nw_radii - 1 );
501 num_cells = num_quads_in_surface_plane * 2 * num_wedge_layers;
505 std::ofstream vtk_file( filename );
506 if ( !vtk_file.is_open() )
508 throw std::runtime_error(
"Failed to open file: " + filename );
511 <<
"<VTKFile type=\"UnstructuredGrid\" version=\"1.0\" byte_order=\"LittleEndian\" header_type=\"UInt64\">\n";
512 vtk_file <<
" <UnstructuredGrid>\n";
513 vtk_file <<
" <Piece NumberOfPoints=\"" << num_total_points <<
"\" NumberOfCells=\"" << num_cells <<
"\">\n";
516 vtk_file <<
" <Points>\n";
517 vtk_file <<
" <DataArray type=\"" << get_vtk_type_string< PointRealT >()
518 <<
"\" Name=\"Coordinates\" NumberOfComponents=\"3\" format=\"ascii\">\n";
519 vtk_file << std::fixed << std::setprecision( 10 );
521 PointRealT base_s_pt_coords[3];
522 for (
int s_idx = 0; s_idx < Ns; ++s_idx )
524 for (
int t_idx = 0; t_idx < Nt; ++t_idx )
527 base_s_pt_coords[0] = surface_points_host( s_idx, t_idx, 0 );
528 base_s_pt_coords[1] = surface_points_host( s_idx, t_idx, 1 );
529 base_s_pt_coords[2] = surface_points_host( s_idx, t_idx, 2 );
530 for (
int w_rad_idx = 0; w_rad_idx < Nw_radii; ++w_rad_idx )
532 PointRealT current_radius_val = radii_host( w_rad_idx );
533 vtk_file <<
" " << base_s_pt_coords[0] * current_radius_val <<
" "
534 << base_s_pt_coords[1] * current_radius_val <<
" " << base_s_pt_coords[2] * current_radius_val
539 vtk_file <<
" </DataArray>\n";
540 vtk_file <<
" </Points>\n";
543 vtk_file <<
" <Cells>\n";
544 std::vector< long long > connectivity_data;
547 connectivity_data.reserve( num_cells * 6 );
549 auto pt_gid = [&](
int s_surf_idx,
int t_surf_idx,
int w_rad_layer_idx ) {
550 return static_cast< long long >( s_surf_idx ) * ( Nt * Nw_radii ) +
551 static_cast< long long >( t_surf_idx ) * Nw_radii +
static_cast< long long >( w_rad_layer_idx );
554 for (
int s = 0; s < Ns - 1; ++s )
556 for (
int t = 0; t < Nt - 1; ++t )
558 for (
int w_rad_layer_idx = 0; w_rad_layer_idx < Nw_radii - 1; ++w_rad_layer_idx )
560 int base_rad_idx = w_rad_layer_idx;
561 int top_rad_idx = w_rad_layer_idx + 1;
563 long long p00_base = pt_gid( s, t, base_rad_idx );
564 long long p10_base = pt_gid( s + 1, t, base_rad_idx );
565 long long p01_base = pt_gid( s, t + 1, base_rad_idx );
566 long long p11_base = pt_gid( s + 1, t + 1, base_rad_idx );
568 long long p00_top = pt_gid( s, t, top_rad_idx );
569 long long p10_top = pt_gid( s + 1, t, top_rad_idx );
570 long long p01_top = pt_gid( s, t + 1, top_rad_idx );
571 long long p11_top = pt_gid( s + 1, t + 1, top_rad_idx );
576 connectivity_data.push_back( p00_base );
577 connectivity_data.push_back( p10_base );
578 connectivity_data.push_back( p11_base );
579 connectivity_data.push_back( p00_top );
580 connectivity_data.push_back( p10_top );
581 connectivity_data.push_back( p11_top );
583 connectivity_data.push_back( p00_base );
584 connectivity_data.push_back( p11_base );
585 connectivity_data.push_back( p01_base );
586 connectivity_data.push_back( p00_top );
587 connectivity_data.push_back( p11_top );
588 connectivity_data.push_back( p01_top );
593 connectivity_data.push_back( p00_base );
594 connectivity_data.push_back( p10_base );
595 connectivity_data.push_back( p01_base );
596 connectivity_data.push_back( p00_top );
597 connectivity_data.push_back( p10_top );
598 connectivity_data.push_back( p01_top );
600 connectivity_data.push_back( p10_base );
601 connectivity_data.push_back( p11_base );
602 connectivity_data.push_back( p01_base );
603 connectivity_data.push_back( p10_top );
604 connectivity_data.push_back( p11_top );
605 connectivity_data.push_back( p01_top );
612 vtk_file <<
" <DataArray type=\"" << get_vtk_type_string< long long >()
613 <<
"\" Name=\"connectivity\" format=\"ascii\">\n";
614 if ( !connectivity_data.empty() )
617 for (
size_t k = 0; k < connectivity_data.size(); ++k )
619 vtk_file << connectivity_data[k] << ( ( k == connectivity_data.size() - 1 ) ?
"" :
" " );
620 if ( ( k + 1 ) % 6 == 0 && k < connectivity_data.size() - 1 )
625 vtk_file <<
" </DataArray>\n";
628 vtk_file <<
" <DataArray type=\"" << get_vtk_type_string< long long >()
629 <<
"\" Name=\"offsets\" format=\"ascii\">\n";
632 long long current_offset = 0;
633 for (
long long c = 0; c < num_cells; ++c )
636 vtk_file <<
" " << current_offset <<
"\n";
639 vtk_file <<
" </DataArray>\n";
642 vtk_file <<
" <DataArray type=\"" << get_vtk_type_string< uint8_t >()
643 <<
"\" Name=\"types\" format=\"ascii\">\n";
646 for (
long long c = 0; c < num_cells; ++c )
651 vtk_file <<
" </DataArray>\n";
652 vtk_file <<
" </Cells>\n";
655 if ( has_attached_data )
657 std::string point_data_attributes_str;
658 if ( is_scalar_data )
660 point_data_attributes_str =
" Scalars=\"" + vector_data_name +
"\"";
664 point_data_attributes_str =
" Vectors=\"" + vector_data_name +
"\"";
667 vtk_file <<
" <PointData" << point_data_attributes_str <<
">\n";
668 vtk_file <<
" <DataArray type=\"" << get_vtk_type_string< double >() <<
"\" Name=\"" << vector_data_name
669 <<
"\" NumberOfComponents=\"" << num_vec_components <<
"\" format=\"ascii\">\n";
670 vtk_file << std::fixed << std::setprecision( 10 );
673 for (
int s_idx = 0; s_idx < Ns; ++s_idx )
675 for (
int t_idx = 0; t_idx < Nt; ++t_idx )
677 for (
int w_rad_idx = 0; w_rad_idx < Nw_radii; ++w_rad_idx )
680 if constexpr ( is_scalar_data )
682 vtk_file << vector_data_host( s_idx, t_idx, w_rad_idx ) <<
" ";
686 for (
size_t comp = 0; comp < num_vec_components; ++comp )
688 vtk_file << vector_data_host( s_idx, t_idx, w_rad_idx, comp )
689 << ( comp == num_vec_components - 1 ?
"" :
" " );
697 vtk_file <<
" </DataArray>\n";
698 vtk_file <<
" </PointData>\n";
702 vtk_file <<
" <PointData>\n";
703 vtk_file <<
" </PointData>\n";
707 vtk_file <<
" </Piece>\n";
708 vtk_file <<
" </UnstructuredGrid>\n";
709 vtk_file <<
"</VTKFile>\n";
727 template <
class ShellCoordsView,
class RadiiView >
729 const ShellCoordsView& shell_node_coords_device,
730 const RadiiView& radii_per_layer_device,
731 bool generate_quadratic_elements_from_linear_input =
false )
732 : is_quadratic_( generate_quadratic_elements_from_linear_input )
735 h_shell_coords_managed_ = Kokkos::create_mirror_view( shell_node_coords_device );
736 Kokkos::deep_copy( h_shell_coords_managed_, shell_node_coords_device );
737 h_radii_managed_ = Kokkos::create_mirror_view( radii_per_layer_device );
738 Kokkos::deep_copy( h_radii_managed_, radii_per_layer_device );
741 num_subdomains_ = h_shell_coords_managed_.extent( 0 );
742 NX_nodes_surf_input_ = h_shell_coords_managed_.extent( 1 );
743 NY_nodes_surf_input_ = h_shell_coords_managed_.extent( 2 );
744 NR_nodes_rad_input_ = h_radii_managed_.extent( 1 );
746 if ( NX_nodes_surf_input_ < 1 || NY_nodes_surf_input_ < 1 || NR_nodes_rad_input_ < 1 )
748 throw std::runtime_error(
"Input node counts must be at least 1 in each dimension." );
751 bool can_form_cells = ( NX_nodes_surf_input_ > 1 || NY_nodes_surf_input_ > 1 || NR_nodes_rad_input_ > 1 );
752 if ( !can_form_cells && ( NX_nodes_surf_input_ * NY_nodes_surf_input_ * NR_nodes_rad_input_ > 1 ) )
757 if ( NX_nodes_surf_input_ < 2 && NY_nodes_surf_input_ < 2 && NR_nodes_rad_input_ < 2 &&
758 ( NX_nodes_surf_input_ + NY_nodes_surf_input_ + NR_nodes_rad_input_ > 3 ) )
767 NX_nodes_surf_output_ =
768 ( NX_nodes_surf_input_ > 1 ) ? ( 2 * ( NX_nodes_surf_input_ - 1 ) + 1 ) : NX_nodes_surf_input_;
769 NY_nodes_surf_output_ =
770 ( NY_nodes_surf_input_ > 1 ) ? ( 2 * ( NY_nodes_surf_input_ - 1 ) + 1 ) : NY_nodes_surf_input_;
771 NR_nodes_rad_output_ =
772 ( NR_nodes_rad_input_ > 1 ) ? ( 2 * ( NR_nodes_rad_input_ - 1 ) + 1 ) : NR_nodes_rad_input_;
776 NX_nodes_surf_output_ = NX_nodes_surf_input_;
777 NY_nodes_surf_output_ = NY_nodes_surf_input_;
778 NR_nodes_rad_output_ = NR_nodes_rad_input_;
781 num_total_points_ = num_subdomains_ * NX_nodes_surf_output_ * NY_nodes_surf_output_ * NR_nodes_rad_output_;
783 size_t num_cells_x_surf = ( NX_nodes_surf_input_ > 1 ) ? NX_nodes_surf_input_ - 1 : 0;
784 size_t num_cells_y_surf = ( NY_nodes_surf_input_ > 1 ) ? NY_nodes_surf_input_ - 1 : 0;
785 size_t num_cells_r_rad = ( NR_nodes_rad_input_ > 1 ) ? NR_nodes_rad_input_ - 1 : 0;
786 num_total_cells_ = num_subdomains_ * num_cells_x_surf * num_cells_y_surf * num_cells_r_rad;
789 template <
class ScalarFieldViewDevice >
792 if ( field_data_view_device.rank() != 4 )
794 throw std::runtime_error(
"Scalar field data view must have rank 4: (sd, x_in, y_in, r_in)." );
796 validate_field_view_dimensions_for_input_grid( field_data_view_device, field_data_view_device.label() );
798 PointDataEntry entry;
799 entry.name = field_data_view_device.label();
800 entry.num_components = 1;
801 entry.data_type_str =
"Float32";
802 entry.device_view_input_data = field_data_view_device;
803 point_data_entries_.push_back( std::move( entry ) );
806 template <
class VectorFieldViewDevice >
809 if ( field_data_view_device.rank() != 5 )
811 throw std::runtime_error(
"Vector field data view must have rank 5." );
813 int num_vec_components = field_data_view_device.extent( 4 );
814 if ( num_vec_components <= 0 )
816 throw std::runtime_error(
"Vector field must have at least one component." );
818 validate_field_view_dimensions_for_input_grid( field_data_view_device, field_data_view_device.label() );
820 PointDataEntry entry;
821 entry.name = field_data_view_device.label();
822 entry.num_components = num_vec_components;
823 entry.data_type_str =
"Float32";
824 entry.device_view_input_data = field_data_view_device;
825 point_data_entries_.push_back( std::move( entry ) );
828 void write(
const std::string& output_file )
830 std::ofstream vtk_file( output_file );
831 if ( !vtk_file.is_open() )
833 throw std::runtime_error(
"Failed to open VTK output file: " + output_file );
835 vtk_file << std::fixed << std::setprecision( 8 );
837 vtk_file <<
"<VTKFile type=\"UnstructuredGrid\" version=\"1.0\" byte_order=\"LittleEndian\">\n";
838 vtk_file <<
" <UnstructuredGrid>\n";
839 vtk_file <<
" <Piece NumberOfPoints=\"" << num_total_points_ <<
"\" NumberOfCells=\"" << num_total_cells_
843 vtk_file <<
" <Points>\n";
845 <<
" <DataArray type=\"Float32\" Name=\"Coordinates\" NumberOfComponents=\"3\" format=\"ascii\">\n";
846 write_points_data( vtk_file );
847 vtk_file <<
" </DataArray>\n";
848 vtk_file <<
" </Points>\n";
851 if ( num_total_cells_ > 0 )
853 vtk_file <<
" <Cells>\n";
854 vtk_file <<
" <DataArray type=\"Int64\" Name=\"connectivity\" format=\"ascii\">\n";
855 write_cell_connectivity_data( vtk_file );
856 vtk_file <<
" </DataArray>\n";
857 vtk_file <<
" <DataArray type=\"Int64\" Name=\"offsets\" format=\"ascii\">\n";
858 write_cell_offsets_data( vtk_file );
859 vtk_file <<
" </DataArray>\n";
860 vtk_file <<
" <DataArray type=\"UInt8\" Name=\"types\" format=\"ascii\">\n";
861 write_cell_types_data( vtk_file );
862 vtk_file <<
" </DataArray>\n";
863 vtk_file <<
" </Cells>\n";
867 if ( !point_data_entries_.empty() && num_total_points_ > 0 )
869 vtk_file <<
" <PointData>\n";
870 for (
const auto& entry : point_data_entries_ )
872 vtk_file <<
" <DataArray type=\"" << entry.data_type_str <<
"\" Name=\"" << entry.name <<
"\"";
873 if ( entry.num_components > 1 )
875 vtk_file <<
" NumberOfComponents=\"" << entry.num_components <<
"\"";
877 vtk_file <<
" format=\"ascii\">\n";
878 write_field_data( vtk_file, entry );
879 vtk_file <<
" </DataArray>\n";
881 vtk_file <<
" </PointData>\n";
884 vtk_file <<
" </Piece>\n";
885 vtk_file <<
" </UnstructuredGrid>\n";
886 vtk_file <<
"</VTKFile>\n";
892 struct PointDataEntry
896 std::variant< ScalarFieldDeviceView, VectorFieldDeviceView > device_view_input_data;
898 std::string data_type_str;
902 size_t get_global_output_node_id(
size_t sd_idx,
size_t ix_out,
size_t iy_out,
size_t ir_out )
const
904 size_t nodes_per_surf_layer_output = NX_nodes_surf_output_ * NY_nodes_surf_output_;
905 size_t nodes_per_subdomain_output = nodes_per_surf_layer_output * NR_nodes_rad_output_;
906 size_t base_offset_sd = sd_idx * nodes_per_subdomain_output;
907 size_t offset_in_sd = ir_out * nodes_per_surf_layer_output + iy_out * NX_nodes_surf_output_ + ix_out;
908 return base_offset_sd + offset_in_sd;
912 template <
class FieldView >
913 void validate_field_view_dimensions_for_input_grid(
const FieldView& view,
const std::string& field_name )
915 if ( view.extent( 0 ) != num_subdomains_ )
916 throw std::runtime_error(
"Field '" + field_name +
"' sd mismatch." );
917 if ( view.extent( 1 ) != NX_nodes_surf_input_ )
918 throw std::runtime_error(
"Field '" + field_name +
"' X_in mismatch." );
919 if ( view.extent( 2 ) != NY_nodes_surf_input_ )
920 throw std::runtime_error(
"Field '" + field_name +
"' Y_in mismatch." );
921 if ( view.extent( 3 ) != NR_nodes_rad_input_ )
922 throw std::runtime_error(
"Field '" + field_name +
"' R_in mismatch." );
926 void write_points_data( std::ostream& os )
928 for (
size_t sd = 0; sd < num_subdomains_; ++sd )
930 for (
size_t ir_out = 0; ir_out < NR_nodes_rad_output_; ++ir_out )
932 for (
size_t iy_out = 0; iy_out < NY_nodes_surf_output_; ++iy_out )
934 for (
size_t ix_out = 0; ix_out < NX_nodes_surf_output_; ++ix_out )
936 double final_px, final_py, final_pz;
937 get_interpolated_point_coordinates( sd, ix_out, iy_out, ir_out, final_px, final_py, final_pz );
938 os <<
" " <<
static_cast< float >( final_px ) <<
" "
939 <<
static_cast< float >( final_py ) <<
" " <<
static_cast< float >( final_pz ) <<
"\n";
947 void get_interpolated_point_coordinates(
954 double& final_pz )
const
956 if ( !is_quadratic_ || ( NX_nodes_surf_input_ <= 1 && NY_nodes_surf_input_ <= 1 && NR_nodes_rad_input_ <= 1 ) )
958 size_t ix_in = ix_out;
959 size_t iy_in = iy_out;
960 size_t ir_in = ir_out;
962 if ( NX_nodes_surf_input_ == 1 )
964 if ( NY_nodes_surf_input_ == 1 )
966 if ( NR_nodes_rad_input_ == 1 )
969 double radius = h_radii_managed_( sd, ir_in );
970 final_px = h_shell_coords_managed_( sd, ix_in, iy_in, 0 ) * radius;
971 final_py = h_shell_coords_managed_( sd, ix_in, iy_in, 1 ) * radius;
972 final_pz = h_shell_coords_managed_( sd, ix_in, iy_in, 2 ) * radius;
976 size_t ix_in0 = ix_out / 2;
977 size_t iy_in0 = iy_out / 2;
978 size_t ir_in0 = ir_out / 2;
980 double base_x_sum = 0.0, base_y_sum = 0.0, base_z_sum = 0.0;
981 double W_shell_sum = 0.0;
983 double wx_param = ( NX_nodes_surf_input_ > 1 ) ? ( ix_out % 2 ) * 0.5 : 0.0;
984 double wy_param = ( NY_nodes_surf_input_ > 1 ) ? ( iy_out % 2 ) * 0.5 : 0.0;
986 for (
int j_off = 0; j_off <= ( ( wy_param > 0.0 && iy_in0 + 1 < NY_nodes_surf_input_ ) ? 1 : 0 ); ++j_off )
988 size_t iy_in = iy_in0 + j_off;
989 double W_j = ( j_off == 0 ) ? ( 1.0 - wy_param ) : wy_param;
990 for (
int i_off = 0; i_off <= ( ( wx_param > 0.0 && ix_in0 + 1 < NX_nodes_surf_input_ ) ? 1 : 0 );
993 size_t ix_in = ix_in0 + i_off;
994 double W_i = ( i_off == 0 ) ? ( 1.0 - wx_param ) : wx_param;
996 double shell_w = W_i * W_j;
997 base_x_sum += shell_w * h_shell_coords_managed_( sd, ix_in, iy_in, 0 );
998 base_y_sum += shell_w * h_shell_coords_managed_( sd, ix_in, iy_in, 1 );
999 base_z_sum += shell_w * h_shell_coords_managed_( sd, ix_in, iy_in, 2 );
1000 W_shell_sum += shell_w;
1005 ( W_shell_sum > 1e-9 ) ?
1006 base_x_sum / W_shell_sum :
1007 h_shell_coords_managed_(
1008 sd, ( NX_nodes_surf_input_ > 1 ? ix_in0 : 0 ), ( NY_nodes_surf_input_ > 1 ? iy_in0 : 0 ), 0 );
1010 ( W_shell_sum > 1e-9 ) ?
1011 base_y_sum / W_shell_sum :
1012 h_shell_coords_managed_(
1013 sd, ( NX_nodes_surf_input_ > 1 ? ix_in0 : 0 ), ( NY_nodes_surf_input_ > 1 ? iy_in0 : 0 ), 1 );
1015 ( W_shell_sum > 1e-9 ) ?
1016 base_z_sum / W_shell_sum :
1017 h_shell_coords_managed_(
1018 sd, ( NX_nodes_surf_input_ > 1 ? ix_in0 : 0 ), ( NY_nodes_surf_input_ > 1 ? iy_in0 : 0 ), 2 );
1020 double radius_sum = 0.0;
1021 double W_radius_sum = 0.0;
1022 double wr_param = ( NR_nodes_rad_input_ > 1 ) ? ( ir_out % 2 ) * 0.5 : 0.0;
1024 for (
int k_off = 0; k_off <= ( ( wr_param > 0.0 && ir_in0 + 1 < NR_nodes_rad_input_ ) ? 1 : 0 ); ++k_off )
1026 size_t ir_in = ir_in0 + k_off;
1027 double R_k = ( k_off == 0 ) ? ( 1.0 - wr_param ) : wr_param;
1028 radius_sum += R_k * h_radii_managed_( sd, ir_in );
1029 W_radius_sum += R_k;
1031 double current_radius = ( W_radius_sum > 1e-9 ) ?
1032 radius_sum / W_radius_sum :
1033 h_radii_managed_( sd, ( NR_nodes_rad_input_ > 1 ? ir_in0 : 0 ) );
1035 final_px = unit_px * current_radius;
1036 final_py = unit_py * current_radius;
1037 final_pz = unit_pz * current_radius;
1042 void write_cell_connectivity_data( std::ostream& os )
1044 if ( num_total_cells_ == 0 )
1046 size_t nodes_per_cell_out = is_quadratic_ ? 20 : 8;
1048 size_t num_cells_x_surf = ( NX_nodes_surf_input_ > 1 ) ? NX_nodes_surf_input_ - 1 : 0;
1049 size_t num_cells_y_surf = ( NY_nodes_surf_input_ > 1 ) ? NY_nodes_surf_input_ - 1 : 0;
1050 size_t num_cells_r_rad = ( NR_nodes_rad_input_ > 1 ) ? NR_nodes_rad_input_ - 1 : 0;
1052 for (
size_t sd = 0; sd < num_subdomains_; ++sd )
1054 for (
size_t k_cell_in = 0; k_cell_in < num_cells_r_rad; ++k_cell_in )
1056 for (
size_t j_cell_in = 0; j_cell_in < num_cells_y_surf; ++j_cell_in )
1058 for (
size_t i_cell_in = 0; i_cell_in < num_cells_x_surf; ++i_cell_in )
1061 std::vector< size_t > cell_node_ids( nodes_per_cell_out );
1062 if ( is_quadratic_ )
1064 size_t ix0_out = i_cell_in * 2;
1065 size_t ix1_out = ix0_out + 1;
1066 size_t ix2_out = ix0_out + 2;
1067 size_t iy0_out = j_cell_in * 2;
1068 size_t iy1_out = iy0_out + 1;
1069 size_t iy2_out = iy0_out + 2;
1070 size_t ir0_out = k_cell_in * 2;
1071 size_t ir1_out = ir0_out + 1;
1072 size_t ir2_out = ir0_out + 2;
1074 cell_node_ids[0] = get_global_output_node_id( sd, ix0_out, iy0_out, ir0_out );
1075 cell_node_ids[1] = get_global_output_node_id( sd, ix2_out, iy0_out, ir0_out );
1076 cell_node_ids[2] = get_global_output_node_id( sd, ix2_out, iy2_out, ir0_out );
1077 cell_node_ids[3] = get_global_output_node_id( sd, ix0_out, iy2_out, ir0_out );
1078 cell_node_ids[4] = get_global_output_node_id( sd, ix0_out, iy0_out, ir2_out );
1079 cell_node_ids[5] = get_global_output_node_id( sd, ix2_out, iy0_out, ir2_out );
1080 cell_node_ids[6] = get_global_output_node_id( sd, ix2_out, iy2_out, ir2_out );
1081 cell_node_ids[7] = get_global_output_node_id( sd, ix0_out, iy2_out, ir2_out );
1082 cell_node_ids[8] = get_global_output_node_id( sd, ix1_out, iy0_out, ir0_out );
1083 cell_node_ids[9] = get_global_output_node_id( sd, ix2_out, iy1_out, ir0_out );
1084 cell_node_ids[10] = get_global_output_node_id( sd, ix1_out, iy2_out, ir0_out );
1085 cell_node_ids[11] = get_global_output_node_id( sd, ix0_out, iy1_out, ir0_out );
1086 cell_node_ids[12] = get_global_output_node_id( sd, ix1_out, iy0_out, ir2_out );
1087 cell_node_ids[13] = get_global_output_node_id( sd, ix2_out, iy1_out, ir2_out );
1088 cell_node_ids[14] = get_global_output_node_id( sd, ix1_out, iy2_out, ir2_out );
1089 cell_node_ids[15] = get_global_output_node_id( sd, ix0_out, iy1_out, ir2_out );
1090 cell_node_ids[16] = get_global_output_node_id( sd, ix0_out, iy0_out, ir1_out );
1091 cell_node_ids[17] = get_global_output_node_id( sd, ix2_out, iy0_out, ir1_out );
1092 cell_node_ids[18] = get_global_output_node_id( sd, ix2_out, iy2_out, ir1_out );
1093 cell_node_ids[19] = get_global_output_node_id( sd, ix0_out, iy2_out, ir1_out );
1097 size_t ix0_out = i_cell_in;
1098 size_t ix1_out = i_cell_in + 1;
1099 size_t iy0_out = j_cell_in;
1100 size_t iy1_out = j_cell_in + 1;
1101 size_t ir0_out = k_cell_in;
1102 size_t ir1_out = k_cell_in + 1;
1103 cell_node_ids[0] = get_global_output_node_id( sd, ix0_out, iy0_out, ir0_out );
1104 cell_node_ids[1] = get_global_output_node_id( sd, ix1_out, iy0_out, ir0_out );
1105 cell_node_ids[2] = get_global_output_node_id( sd, ix1_out, iy1_out, ir0_out );
1106 cell_node_ids[3] = get_global_output_node_id( sd, ix0_out, iy1_out, ir0_out );
1107 cell_node_ids[4] = get_global_output_node_id( sd, ix0_out, iy0_out, ir1_out );
1108 cell_node_ids[5] = get_global_output_node_id( sd, ix1_out, iy0_out, ir1_out );
1109 cell_node_ids[6] = get_global_output_node_id( sd, ix1_out, iy1_out, ir1_out );
1110 cell_node_ids[7] = get_global_output_node_id( sd, ix0_out, iy1_out, ir1_out );
1113 for (
size_t i = 0; i < nodes_per_cell_out; ++i )
1115 os << cell_node_ids[i] << ( i == nodes_per_cell_out - 1 ?
"" :
" " );
1125 void write_cell_offsets_data( std::ostream& os )
1127 if ( num_total_cells_ == 0 )
1129 size_t nodes_per_cell_out = is_quadratic_ ? 20 : 8;
1130 int64_t current_offset = 0;
1131 for (
size_t i = 0; i < num_total_cells_; ++i )
1133 current_offset += nodes_per_cell_out;
1134 os <<
" " << current_offset <<
"\n";
1139 void write_cell_types_data( std::ostream& os )
1141 if ( num_total_cells_ == 0 )
1143 uint8_t cell_type_out = is_quadratic_ ? 25 : 12;
1144 for (
size_t i = 0; i < num_total_cells_; ++i )
1146 os <<
" " <<
static_cast< int >( cell_type_out ) <<
"\n";
1152 template <
typename InputFieldViewType >
1153 void get_interpolated_field_value_at_output_node(
1154 const InputFieldViewType& h_field_data_input,
1160 std::vector< double >& interpolated_values )
const
1162 interpolated_values.assign( num_components, 0.0 );
1164 bool use_direct_mapping =
1165 !is_quadratic_ || ( NX_nodes_surf_input_ <= 1 && NY_nodes_surf_input_ <= 1 && NR_nodes_rad_input_ <= 1 );
1167 if ( use_direct_mapping )
1169 size_t ix_in = ix_out;
1170 size_t iy_in = iy_out;
1171 size_t ir_in = ir_out;
1172 if ( NX_nodes_surf_input_ == 1 )
1174 if ( NY_nodes_surf_input_ == 1 )
1176 if ( NR_nodes_rad_input_ == 1 )
1179 if constexpr ( std::is_same_v< InputFieldViewType, ScalarFieldHostView > )
1181 interpolated_values[0] = h_field_data_input( sd, ix_in, iy_in, ir_in );
1185 for (
int comp = 0; comp < num_components; ++comp )
1187 interpolated_values[comp] = h_field_data_input( sd, ix_in, iy_in, ir_in, comp );
1193 size_t ix_in0 = ix_out / 2;
1194 size_t iy_in0 = iy_out / 2;
1195 size_t ir_in0 = ir_out / 2;
1197 std::vector< double > val_sum( num_components, 0.0 );
1200 double wx_param = ( NX_nodes_surf_input_ > 1 ) ? ( ix_out % 2 ) * 0.5 : 0.0;
1201 double wy_param = ( NY_nodes_surf_input_ > 1 ) ? ( iy_out % 2 ) * 0.5 : 0.0;
1202 double wr_param = ( NR_nodes_rad_input_ > 1 ) ? ( ir_out % 2 ) * 0.5 : 0.0;
1204 for (
int k_off = 0; k_off <= ( ( wr_param > 0.0 && ir_in0 + 1 < NR_nodes_rad_input_ ) ? 1 : 0 ); ++k_off )
1206 size_t ir_in = ir_in0 + k_off;
1207 double R_k = ( k_off == 0 ) ? ( 1.0 - wr_param ) : wr_param;
1208 for (
int j_off = 0; j_off <= ( ( wy_param > 0.0 && iy_in0 + 1 < NY_nodes_surf_input_ ) ? 1 : 0 );
1211 size_t iy_in = iy_in0 + j_off;
1212 double W_j = ( j_off == 0 ) ? ( 1.0 - wy_param ) : wy_param;
1213 for (
int i_off = 0; i_off <= ( ( wx_param > 0.0 && ix_in0 + 1 < NX_nodes_surf_input_ ) ? 1 : 0 );
1216 size_t ix_in = ix_in0 + i_off;
1217 double W_i = ( i_off == 0 ) ? ( 1.0 - wx_param ) : wx_param;
1219 double weight = W_i * W_j * R_k;
1220 if constexpr ( std::is_same_v< InputFieldViewType, ScalarFieldHostView > )
1222 val_sum[0] += weight * h_field_data_input( sd, ix_in, iy_in, ir_in );
1226 for (
int comp = 0; comp < num_components; ++comp )
1228 val_sum[comp] += weight * h_field_data_input( sd, ix_in, iy_in, ir_in, comp );
1238 for (
int comp = 0; comp < num_components; ++comp )
1240 interpolated_values[comp] = val_sum[comp] / W_sum;
1245 if constexpr ( std::is_same_v< InputFieldViewType, ScalarFieldHostView > )
1247 interpolated_values[0] = h_field_data_input(
1249 ( NX_nodes_surf_input_ > 1 ? ix_in0 : 0 ),
1250 ( NY_nodes_surf_input_ > 1 ? iy_in0 : 0 ),
1251 ( NR_nodes_rad_input_ > 1 ? ir_in0 : 0 ) );
1255 for (
int comp = 0; comp < num_components; ++comp )
1257 interpolated_values[comp] = h_field_data_input(
1259 ( NX_nodes_surf_input_ > 1 ? ix_in0 : 0 ),
1260 ( NY_nodes_surf_input_ > 1 ? iy_in0 : 0 ),
1261 ( NR_nodes_rad_input_ > 1 ? ir_in0 : 0 ),
1269 void write_field_data( std::ostream& os,
const PointDataEntry& entry )
1271 std::variant< ScalarFieldHostView, VectorFieldHostView > host_view;
1273 if ( entry.num_components == 1 )
1275 if ( !scalar_field_host_buffer_.has_value() )
1277 ScalarFieldHostView host_mirror = Kokkos::create_mirror_view_and_copy(
1278 Kokkos::HostSpace(), std::get< ScalarFieldDeviceView >( entry.device_view_input_data ) );
1279 scalar_field_host_buffer_ = host_mirror;
1284 scalar_field_host_buffer_.value(),
1285 std::get< ScalarFieldDeviceView >( entry.device_view_input_data ) );
1288 host_view = scalar_field_host_buffer_.value();
1292 if ( !vector_field_host_buffer_.has_value() )
1294 VectorFieldHostView host_mirror = Kokkos::create_mirror_view_and_copy(
1295 Kokkos::HostSpace(), std::get< VectorFieldDeviceView >( entry.device_view_input_data ) );
1296 vector_field_host_buffer_ = host_mirror;
1301 vector_field_host_buffer_.value(),
1302 std::get< VectorFieldDeviceView >( entry.device_view_input_data ) );
1305 host_view = vector_field_host_buffer_.value();
1308 std::vector< double > interpolated_values_buffer( entry.num_components );
1309 for (
size_t sd = 0; sd < num_subdomains_; ++sd )
1311 for (
size_t ir_out = 0; ir_out < NR_nodes_rad_output_; ++ir_out )
1313 for (
size_t iy_out = 0; iy_out < NY_nodes_surf_output_; ++iy_out )
1315 for (
size_t ix_out = 0; ix_out < NX_nodes_surf_output_; ++ix_out )
1319 [&](
const auto& view_arg ) {
1320 this->get_interpolated_field_value_at_output_node(
1326 entry.num_components,
1327 interpolated_values_buffer );
1332 for (
int comp = 0; comp < entry.num_components; ++comp )
1334 os << static_cast< float >( interpolated_values_buffer[comp] )
1335 << ( comp == entry.num_components - 1 ?
"" :
" " );
1347 grid::Grid3DDataVec< double, 3 >::HostMirror h_shell_coords_managed_;
1348 grid::Grid2DDataScalar< double >::HostMirror h_radii_managed_;
1350 size_t num_subdomains_;
1351 size_t NX_nodes_surf_input_, NY_nodes_surf_input_, NR_nodes_rad_input_;
1352 size_t NX_nodes_surf_output_, NY_nodes_surf_output_, NR_nodes_rad_output_;
1354 size_t num_total_points_;
1355 size_t num_total_cells_;
1357 std::vector< PointDataEntry > point_data_entries_;
1359 std::optional< ScalarFieldHostView > scalar_field_host_buffer_;
1360 std::optional< VectorFieldHostView > vector_field_host_buffer_;