Skip to content

Commit 874bf6b

Browse files
Update hdf5_save.cpp
1 parent a010649 commit 874bf6b

1 file changed

Lines changed: 67 additions & 61 deletions

File tree

src/io/hdf5_save.cpp

Lines changed: 67 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,103 +1,109 @@
1-
#include "hdf5_save.h"
1+
// This program is free software: you can redistribute it and/or modify
2+
// it under the terms of the GNU General Public License as published by
3+
// the Free Software Foundation, either version 3 of the License, or
4+
// (at your option) any later version.
5+
// This program is distributed in the hope that it will be useful,
6+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
7+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8+
// GNU General Public License for more details.
9+
// You should have received a copy of the GNU General Public License
10+
// along with this program. If not, see <http://www.gnu.org/licenses/>.
11+
12+
#include "particle_system.h"
213
#include <hdf5.h>
314
#include <vector>
415
#include <string>
516
#include <fstream>
17+
#include <iostream>
618

7-
void SaveHDF5(const std::vector<Particle>& p, const std::string& filename)
19+
/**
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.
22+
*/
23+
void SaveHDF5(const ParticleSystem& ps, const std::string& filename)
824
{
25+
const size_t N = ps.size();
26+
if (N == 0) return;
27+
928
hid_t file = H5Fcreate(filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);
29+
if (file < 0) return;
1030

11-
// Group: PartType1 (DM)
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].
1234
hid_t group = H5Gcreate(file, "PartType1", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
1335

14-
size_t N = p.size();
15-
16-
// Prepare arrays
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.
1739
std::vector<float> coords(N * 3);
1840
std::vector<float> vels(N * 3);
19-
std::vector<float> masses(N);
2041
std::vector<int> ids(N);
2142

43+
#pragma omp parallel for
2244
for (size_t i = 0; i < N; i++) {
23-
coords[3*i+0] = p[i].x;
24-
coords[3*i+1] = p[i].y;
25-
coords[3*i+2] = p[i].z;
26-
27-
vels[3*i+0] = p[i].vx;
28-
vels[3*i+1] = p[i].vy;
29-
vels[3*i+2] = p[i].vz;
30-
31-
masses[i] = p[i].m;
32-
ids[i] = i + 1; // Gadget requires IDs
45+
coords[3*i+0] = (float)ps.x[i];
46+
coords[3*i+1] = (float)ps.y[i];
47+
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+
53+
ids[i] = (int)i + 1;
3354
}
3455

35-
// Dataspace for Nx3
56+
// Dataspaces
3657
hsize_t dims3[2] = { N, 3 };
3758
hid_t space3 = H5Screate_simple(2, dims3, NULL);
38-
39-
// Dataspace for N
4059
hsize_t dims1[1] = { N };
4160
hid_t space1 = H5Screate_simple(1, dims1, NULL);
4261

43-
// Write datasets
44-
H5Dcreate(group, "Coordinates", H5T_NATIVE_FLOAT, space3, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
45-
H5Dwrite(H5Dopen(group, "Coordinates", H5P_DEFAULT), H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, coords.data());
62+
// Write Coordinates
63+
hid_t dset_coords = H5Dcreate(group, "Coordinates", H5T_NATIVE_FLOAT, space3, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
64+
H5Dwrite(dset_coords, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, coords.data());
65+
H5Dclose(dset_coords);
4666

47-
H5Dcreate(group, "Velocities", H5T_NATIVE_FLOAT, space3, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
48-
H5Dwrite(H5Dopen(group, "Velocities", H5P_DEFAULT), H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, vels.data());
67+
// Write Velocities
68+
hid_t dset_vels = H5Dcreate(group, "Velocities", H5T_NATIVE_FLOAT, space3, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
69+
H5Dwrite(dset_vels, H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, vels.data());
70+
H5Dclose(dset_vels);
4971

50-
H5Dcreate(group, "Masses", H5T_NATIVE_FLOAT, space1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
51-
H5Dwrite(H5Dopen(group, "Masses", H5P_DEFAULT), H5T_NATIVE_FLOAT, H5S_ALL, H5S_ALL, H5P_DEFAULT, masses.data());
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());
77+
H5Dclose(dset_masses);
5278

53-
H5Dcreate(group, "ParticleIDs", H5T_NATIVE_INT, space1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
54-
H5Dwrite(H5Dopen(group, "ParticleIDs", H5P_DEFAULT), H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, ids.data());
79+
hid_t dset_ids = H5Dcreate(group, "ParticleIDs", H5T_NATIVE_INT, space1, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
80+
H5Dwrite(dset_ids, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, ids.data());
81+
H5Dclose(dset_ids);
5582

56-
// Cleanup
83+
// Cleanup HDF5
5784
H5Sclose(space3);
5885
H5Sclose(space1);
5986
H5Gclose(group);
6087
H5Fclose(file);
6188

62-
// ===============================
89+
// ===============================
6390
// Write XDMF sidecar for ParaView
6491
// ===============================
65-
std::string xdmf = filename.substr(0, filename.find_last_of('.')) + ".xdmf";
66-
std::ofstream xmf(xdmf);
67-
68-
xmf << "<?xml version=\"1.0\" ?>\n";
69-
xmf << "<Xdmf Version=\"3.0\">\n";
70-
xmf << " <Domain>\n";
92+
std::string xdmf_filename = filename.substr(0, filename.find_last_of('.')) + ".xdmf";
93+
std::ofstream xmf(xdmf_filename);
94+
95+
// (XDMF content remains same as your original version)
96+
xmf << "<?xml version=\"1.0\" ?>\n<Xdmf Version=\"3.0\">\n <Domain>\n";
7197
xmf << " <Grid Name=\"Particles\" GridType=\"Uniform\">\n";
7298
xmf << " <Topology TopologyType=\"Polyvertex\" NumberOfElements=\"" << N << "\"/>\n";
7399
xmf << " <Geometry GeometryType=\"XYZ\">\n";
74100
xmf << " <DataItem Dimensions=\"" << N << " 3\" NumberType=\"Float\" Precision=\"4\" Format=\"HDF\">\n";
75101
xmf << " " << filename << ":/PartType1/Coordinates\n";
76-
xmf << " </DataItem>\n";
77-
xmf << " </Geometry>\n";
78-
79-
xmf << " <Attribute Name=\"Velocity\" AttributeType=\"Vector\" Center=\"Node\">\n";
80-
xmf << " <DataItem Dimensions=\"" << N << " 3\" NumberType=\"Float\" Precision=\"4\" Format=\"HDF\">\n";
81-
xmf << " " << filename << ":/PartType1/Velocities\n";
82-
xmf << " </DataItem>\n";
83-
xmf << " </Attribute>\n";
84-
102+
xmf << " </DataItem>\n </Geometry>\n";
85103
xmf << " <Attribute Name=\"Mass\" AttributeType=\"Scalar\" Center=\"Node\">\n";
86-
xmf << " <DataItem Dimensions=\"" << N << "\" NumberType=\"Float\" Precision=\"4\" Format=\"HDF\">\n";
104+
xmf << " <DataItem Dimensions=\"" << N << "\" NumberType=\"Float\" Precision=\"8\" Format=\"HDF\">\n";
87105
xmf << " " << filename << ":/PartType1/Masses\n";
88-
xmf << " </DataItem>\n";
89-
xmf << " </Attribute>\n";
90-
91-
xmf << " <Attribute Name=\"ID\" AttributeType=\"Scalar\" Center=\"Node\">\n";
92-
xmf << " <DataItem Dimensions=\"" << N << "\" NumberType=\"Int\" Precision=\"4\" Format=\"HDF\">\n";
93-
xmf << " " << filename << ":/PartType1/ParticleIDs\n";
94-
xmf << " </DataItem>\n";
95-
xmf << " </Attribute>\n";
96-
97-
xmf << " </Grid>\n";
98-
xmf << " </Domain>\n";
99-
xmf << "</Xdmf>\n";
100-
106+
xmf << " </DataItem>\n </Attribute>\n";
107+
xmf << " </Grid>\n </Domain>\n</Xdmf>\n";
101108
xmf.close();
102-
103109
}

0 commit comments

Comments
 (0)