1717#include < iostream>
1818
1919/* *
20- * @brief Saves the ParticleSystem to an HDF5 file and creates an XDMF sidecar.
21- * Because we use SoA, we can pass buffer pointers directly to H5Dwrite .
20+ * @brief Saves the ParticleSystem to HDF5.
21+ * Detects real precision to match NEXT_FP32 or NEXT_FP64 .
2222 */
2323void SaveHDF5 (const ParticleSystem& ps, const std::string& filename)
2424{
@@ -28,14 +28,10 @@ void SaveHDF5(const ParticleSystem& ps, const std::string& filename)
2828 hid_t file = H5Fcreate (filename.c_str (), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
2929 if (file < 0 ) return ;
3030
31- // Gadget format uses PartType1 for DM and PartType4 for Stars.
32- // To keep it simple, we'll put all particles in PartType1,
33- // but you could split them using ps.type[i].
3431 hid_t group = H5Gcreate (file, " PartType1" , H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
3532
36- // 1. Prepare Coordinates (Nx3 interleaved)
37- // Unfortunately, HDF5 Gadget format expects XYZXYZXYZ.
38- // Since our SoA is XXXXX, YYYYY, ZZZZZ, we DO need one interleaved buffer for Coords.
33+ // 1. Handle Coordinate/Velocity zipping
34+ // We keep these as float for visualization efficiency (ParaView rarely needs double)
3935 std::vector<float > coords (N * 3 );
4036 std::vector<float > vels (N * 3 );
4137 std::vector<int > ids (N);
@@ -45,54 +41,47 @@ void SaveHDF5(const ParticleSystem& ps, const std::string& filename)
4541 coords[3 *i+0 ] = (float )ps.x [i];
4642 coords[3 *i+1 ] = (float )ps.y [i];
4743 coords[3 *i+2 ] = (float )ps.z [i];
48-
49- vels[3 *i+0 ] = (float )ps.vx [i];
50- vels[3 *i+1 ] = (float )ps.vy [i];
51- vels[3 *i+2 ] = (float )ps.vz [i];
52-
44+ vels[3 *i+0 ] = (float )ps.vx [i];
45+ vels[3 *i+1 ] = (float )ps.vy [i];
46+ vels[3 *i+2 ] = (float )ps.vz [i];
5347 ids[i] = (int )i + 1 ;
5448 }
5549
56- // Dataspaces
5750 hsize_t dims3[2 ] = { N, 3 };
5851 hid_t space3 = H5Screate_simple (2 , dims3, NULL );
5952 hsize_t dims1[1 ] = { N };
6053 hid_t space1 = H5Screate_simple (1 , dims1, NULL );
6154
62- // Write Coordinates
55+ // Write Coords & Vels (storing as float32)
6356 hid_t dset_coords = H5Dcreate (group, " Coordinates" , H5T_NATIVE_FLOAT, space3, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
6457 H5Dwrite (dset_coords, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, coords.data ());
6558 H5Dclose (dset_coords);
6659
67- // Write Velocities
6860 hid_t dset_vels = H5Dcreate (group, " Velocities" , H5T_NATIVE_FLOAT, space3, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
6961 H5Dwrite (dset_vels, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, vels.data ());
7062 H5Dclose (dset_vels);
7163
72- // --- DIRECT WRITE WIN ---
73- // For Masses and Types, we don't need temporary vectors!
74- // We can pass the ps.m.data() pointer directly.
75- hid_t dset_masses = H5Dcreate (group, " Masses" , H5T_NATIVE_FLOAT, space1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
76- H5Dwrite (dset_masses, H5T_NATIVE_DOUBLE, H5S_ALL, H5S_ALL, H5P_DEFAULT, ps.m .data ());
64+ // --- TYPE-SAFE DIRECT WRITE ---
65+ // Detect if 'real' is float or double for Masses
66+ hid_t h5_real_type = (sizeof (real) == 4 ) ? H5T_NATIVE_FLOAT : H5T_NATIVE_DOUBLE;
67+ int precision = (sizeof (real) == 4 ) ? 4 : 8 ;
68+
69+ hid_t dset_masses = H5Dcreate (group, " Masses" , h5_real_type, space1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
70+ H5Dwrite (dset_masses, h5_real_type, H5S_ALL, H5S_ALL, H5P_DEFAULT, ps.m .data ());
7771 H5Dclose (dset_masses);
7872
7973 hid_t dset_ids = H5Dcreate (group, " ParticleIDs" , H5T_NATIVE_INT, space1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
8074 H5Dwrite (dset_ids, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, ids.data ());
8175 H5Dclose (dset_ids);
8276
83- // Cleanup HDF5
8477 H5Sclose (space3);
8578 H5Sclose (space1);
8679 H5Gclose (group);
8780 H5Fclose (file);
8881
89- // ===============================
90- // Write XDMF sidecar for ParaView
91- // ===============================
82+ // --- XDMF SIDECAR ---
9283 std::string xdmf_filename = filename.substr (0 , filename.find_last_of (' .' )) + " .xdmf" ;
9384 std::ofstream xmf (xdmf_filename);
94-
95- // (XDMF content remains same as your original version)
9685 xmf << " <?xml version=\" 1.0\" ?>\n <Xdmf Version=\" 3.0\" >\n <Domain>\n " ;
9786 xmf << " <Grid Name=\" Particles\" GridType=\" Uniform\" >\n " ;
9887 xmf << " <Topology TopologyType=\" Polyvertex\" NumberOfElements=\" " << N << " \" />\n " ;
@@ -101,7 +90,8 @@ void SaveHDF5(const ParticleSystem& ps, const std::string& filename)
10190 xmf << " " << filename << " :/PartType1/Coordinates\n " ;
10291 xmf << " </DataItem>\n </Geometry>\n " ;
10392 xmf << " <Attribute Name=\" Mass\" AttributeType=\" Scalar\" Center=\" Node\" >\n " ;
104- xmf << " <DataItem Dimensions=\" " << N << " \" NumberType=\" Float\" Precision=\" 8\" Format=\" HDF\" >\n " ;
93+ // We dynamically set the precision here to match the file
94+ xmf << " <DataItem Dimensions=\" " << N << " \" NumberType=\" Float\" Precision=\" " << precision << " \" Format=\" HDF\" >\n " ;
10595 xmf << " " << filename << " :/PartType1/Masses\n " ;
10696 xmf << " </DataItem>\n </Attribute>\n " ;
10797 xmf << " </Grid>\n </Domain>\n </Xdmf>\n " ;
0 commit comments