13#ifndef CD_DISCHARGEIOIMPLEM_H
14#define CD_DISCHARGEIOIMPLEM_H
22#include <ParticleIO.H>
26#include <CD_NamespaceHeader.H>
42template <
typename Traits,
typename =
void>
43struct HasH5PartColumns : std::false_type
51template <
typename Traits>
52struct HasH5PartColumns<Traits, VoidT<
decltype(Traits::h5PartColumns)>> : std::true_type
70template <
typename P,
typename Traits,
typename Gather>
72writeH5PartScalarDataset(hid_t a_grp,
76 const std::string& a_name,
77 Gather a_gather)
noexcept
80 dataset = H5Dcreate2(a_grp, a_name.c_str(), H5T_NATIVE_DOUBLE, a_fileSpace, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
82 std::vector<double> ds;
84 for (
int lvl = 0; lvl <= a_particles.getFinestLevel(); lvl++) {
85 const DisjointBoxLayout& dbl = a_particles.getGrids()[lvl];
86 const DataIterator& dit = dbl.dataIterator();
87 const int nbox = dit.size();
89 for (
int mybox = 0; mybox < nbox; mybox++) {
90 const DataIndex& din = dit[mybox];
93 for (std::size_t i = 0; i < leaf.
size(); i++) {
94 ds.push_back(a_gather(leaf, i));
99 H5Dwrite(dataset, H5T_NATIVE_DOUBLE, a_memSpace, a_fileSpace, H5P_DEFAULT, ds.data());
115template <std::size_t I,
typename P,
typename Traits, std::size_t... Dirs>
117writeH5PartVectorColumn(hid_t a_grp,
121 [[maybe_unused]] std::index_sequence<Dirs...> a_dirs)
noexcept
123 constexpr auto desc = std::get<I>(Traits::h5PartColumns);
124 const char*
const suffix[3] = {
"-x",
"-y",
"-z"};
126 (writeH5PartScalarDataset(a_grp,
130 std::string(desc.name) + suffix[Dirs],
132 constexpr auto member = std::get<Dirs>(std::get<I>(Traits::h5PartColumns).members);
133 return static_cast<double>(a_leaf.template get<member>(a_i));
149template <std::
size_t I,
typename P,
typename Traits>
151writeH5PartColumn(hid_t a_grp,
156 constexpr auto desc = std::get<I>(Traits::h5PartColumns);
158 if constexpr (
decltype(desc)::s_isVector) {
159 writeH5PartVectorColumn<I>(a_grp, a_fileSpace, a_memSpace, a_particles, std::make_index_sequence<SpaceDim>{});
162 writeH5PartScalarDataset(a_grp,
168 constexpr auto member = desc.member;
169 return static_cast<double>(a_leaf.template get<member>(a_i));
185template <
typename P,
typename Traits, std::size_t... I>
187writeH5PartColumns(hid_t a_grp,
191 [[maybe_unused]] std::index_sequence<I...> a_indices)
noexcept
193 (writeH5PartColumn<I>(a_grp, a_fileSpace, a_memSpace, a_particles), ...);
199template <
typename P,
typename Traits>
204 Real a_time)
noexcept
207 CH_TIME(
"DischargeIO::writeH5Part(SoA)");
210 const unsigned long long numParticlesLocal = a_particles.getNumberOfValidParticlesLocal();
211 const unsigned long long numParticlesGlobal = a_particles.getNumberOfValidParticlesGlobal();
213 std::vector<unsigned long long> particlesPerRank;
215 particlesPerRank.resize(numProc(), 0ULL);
217 std::vector<int> recv(numProc(), 1);
218 std::vector<int> displ(numProc(), 0);
219 for (
int i = 0; i < numProc(); i++) {
222 MPI_Allgatherv(&numParticlesLocal,
224 MPI_UNSIGNED_LONG_LONG,
225 &particlesPerRank[0],
228 MPI_UNSIGNED_LONG_LONG,
231 particlesPerRank.resize(1);
232 particlesPerRank[0] = numParticlesGlobal;
236 hid_t fileAccess = 0;
238 fileAccess = H5Pcreate(H5P_FILE_ACCESS);
239 H5Pset_fapl_mpio(fileAccess, Chombo_MPI::comm, MPI_INFO_NULL);
242 hid_t fileID = H5Fcreate(a_filename.c_str(), H5F_ACC_TRUNC, H5P_DEFAULT, fileAccess);
244 H5Pclose(fileAccess);
248 hid_t grp = H5Gcreate2(fileID,
"Step#0", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
251 hid_t scal = H5Screate(H5S_SCALAR);
252 hid_t timeAttr = H5Acreate(grp,
"time", H5T_NATIVE_DOUBLE, scal, H5P_DEFAULT, H5P_DEFAULT);
253 H5Awrite(timeAttr, H5T_NATIVE_DOUBLE, &a_time);
260 dims[0] = numParticlesGlobal;
262 hid_t fileSpaceID = H5Screate_simple(1, dims,
nullptr);
266 memDims[0] = numParticlesLocal;
267 hid_t memSpaceID = H5Screate_simple(1, memDims,
nullptr);
270 hsize_t fileStart[1];
271 hsize_t fileCount[1];
278 for (
int i = 0; i < procID(); i++) {
279 fileStart[0] += particlesPerRank[i];
281 fileCount[0] = particlesPerRank[procID()];
282 memCount[0] = particlesPerRank[procID()];
284 H5Sselect_hyperslab(fileSpaceID, H5S_SELECT_SET, fileStart,
nullptr, fileCount,
nullptr);
285 H5Sselect_hyperslab(memSpaceID, H5S_SELECT_SET, memStart,
nullptr, memCount,
nullptr);
288 hid_t datasetID = H5Dcreate2(grp,
"id", H5T_NATIVE_LLONG, fileSpaceID, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
289 hid_t datasetX = H5Dcreate2(grp,
"x", H5T_NATIVE_DOUBLE, fileSpaceID, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
290 hid_t datasetY = H5Dcreate2(grp,
"y", H5T_NATIVE_DOUBLE, fileSpaceID, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
292 hid_t datasetZ = H5Dcreate2(grp,
"z", H5T_NATIVE_DOUBLE, fileSpaceID, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT);
295 std::vector<long long> id;
296 std::vector<double> x;
297 std::vector<double> y;
298 std::vector<double> z;
300 for (
int lvl = 0; lvl <= a_particles.getFinestLevel(); lvl++) {
301 const DisjointBoxLayout& dbl = a_particles.getGrids()[lvl];
302 const DataIterator& dit = dbl.dataIterator();
304 const int nbox = dit.size();
306 for (
int mybox = 0; mybox < nbox; mybox++) {
307 const DataIndex& din = dit[mybox];
311 for (std::size_t i = 0; i < leaf.
size(); i++) {
312 const RealVect pos = leaf.
position(i);
314 id.push_back(
static_cast<long long>(leaf.
particleID(i)));
315 x.push_back(pos[0] - a_shift[0]);
316 y.push_back(pos[1] - a_shift[1]);
318 z.push_back(pos[2] - a_shift[2]);
324 H5Dwrite(datasetID, H5T_NATIVE_LLONG, memSpaceID, fileSpaceID, H5P_DEFAULT,
id.data());
325 H5Dwrite(datasetX, H5T_NATIVE_DOUBLE, memSpaceID, fileSpaceID, H5P_DEFAULT, x.data());
326 H5Dwrite(datasetY, H5T_NATIVE_DOUBLE, memSpaceID, fileSpaceID, H5P_DEFAULT, y.data());
328 H5Dwrite(datasetZ, H5T_NATIVE_DOUBLE, memSpaceID, fileSpaceID, H5P_DEFAULT, z.data());
339 writeH5PartScalarDataset(grp,
345 return a_leaf.
weight(a_i);
349 if constexpr (HasH5PartColumns<Traits>::value) {
350 using H5PartTuple = std::remove_cv_t<std::remove_reference_t<
decltype(Traits::h5PartColumns)>>;
351 writeH5PartColumns(grp,
355 std::make_index_sequence<std::tuple_size<H5PartTuple>::value>{});
359 H5Sclose(fileSpaceID);
360 H5Sclose(memSpaceID);
367template <
typename P,
typename Traits>
369DischargeIO::writeCheckParticlesToHDF(HDF5Handle& a_handle,
371 const std::string& a_dataType)
373 CH_TIMERS(
"writeParticlesToHDF(SoA)");
375 const BoxLayout& grids = a_particles.boxLayout();
377 std::vector<unsigned long long> locParticlesPerBox(grids.size(), 0);
378 unsigned long long numLocalParticles = 0;
381 const DataIterator& dit = grids.dataIterator();
382 const int nbox = dit.size();
383 for (
int mybox = 0; mybox < nbox; mybox++) {
384 const DataIndex& din = dit[mybox];
385 const size_t numItems = a_particles[din].size();
386 numLocalParticles += (
unsigned long long)numItems;
387 locParticlesPerBox[grids.index(din)] = (
unsigned long long)numItems;
390 std::vector<unsigned long long> particlesPerBox(grids.size());
393 int result = MPI_Allreduce(&locParticlesPerBox[0],
395 locParticlesPerBox.size(),
396 MPI_UNSIGNED_LONG_LONG,
399 if (result != MPI_SUCCESS) {
400 MayDay::Error(
"MPI communication error in ParticleIO (SoA)");
403 for (
int i = 0; i < grids.size(); i++) {
404 particlesPerBox[i] = (
unsigned long long)locParticlesPerBox[i];
408 write_hdf_part_header(a_handle, grids, particlesPerBox, a_dataType);
417 std::vector<unsigned long long> offsets;
418 unsigned long long totNumParticles = 0;
419 for (
int i = 0; i < grids.size(); i++) {
420 offsets.push_back(objSize * totNumParticles);
421 totNumParticles += particlesPerBox[i];
424 if (totNumParticles == 0) {
428 hsize_t dataSize = totNumParticles * objSize;
429 hid_t dataspace = H5Screate_simple(1, &dataSize,
nullptr);
430 hid_t H5T_type = H5T_NATIVE_CHAR;
431 std::string dataname = a_dataType +
":data";
434 hid_t dataset = H5Dcreate(a_handle.groupID(), dataname.c_str(), H5T_type, dataspace, H5P_DEFAULT);
436 hid_t dataset = H5Dcreate2(a_handle.groupID(),
445 if (numLocalParticles > 0) {
446 const size_t chunkSize = objSize * _CHUNK;
447 char*
const chunkBase =
new char[chunkSize];
448 char* chunk = chunkBase;
450 if (chunkBase ==
nullptr) {
451 MayDay::Error(
"WritePart(SoA)::Error: new returned NULL pointer ");
455 const DataIterator& dit = grids.dataIterator();
456 const int nbox = dit.size();
458 for (
int mybox = 0; mybox < nbox; mybox++) {
459 const DataIndex& din = dit[mybox];
460 size_t offset = offsets[grids.index(din)];
463 const size_t n = leaf.
size();
465 for (
size_t ip = 0; ip < n; ip++) {
469 if ((ip + 1) % _CHUNK == 0) {
471 writeDataChunk(offset, dataspace, dataset, H5T_type, chunkSize, chunk);
475 const size_t nResidual = n % _CHUNK;
477 chunk -= (nResidual * objSize);
478 writeDataChunk(offset, dataspace, dataset, H5T_type, nResidual * objSize, chunk);
493template <
typename P,
typename Traits>
495DischargeIO::readCheckParticlesFromHDF(HDF5Handle& a_handle,
497 const std::string& a_dataType)
499 CH_TIMERS(
"readParticlesFromHDF(SoA)");
501 std::vector<unsigned long long> particlesPerBox;
503 read_hdf_part_header(a_handle, grids, particlesPerBox, a_dataType, a_handle.getGroup());
505 const BoxLayout& bl = a_particles.boxLayout();
511 std::vector<unsigned long long> offsets;
512 unsigned long long totNumParticles = 0;
513 for (
int i = 0; i < grids.size(); i++) {
514 offsets.push_back(objSize * totNumParticles);
515 totNumParticles += particlesPerBox[i];
518 if (totNumParticles == 0) {
522 hid_t H5T_type = H5T_NATIVE_CHAR;
523 std::string dataname = a_dataType +
":data";
526 hid_t dataset = H5Dopen(a_handle.groupID(), dataname.c_str());
528 hid_t dataset = H5Dopen2(a_handle.groupID(), dataname.c_str(), H5P_DEFAULT);
531 hid_t dataspace = H5Dget_space(dataset);
533 const size_t chunkSize = objSize * _CHUNK;
534 char* chunk =
new char[chunkSize];
537 const DataIterator& dit = bl.dataIterator();
538 const int nbox = dit.size();
539 for (
int mybox = 0; mybox < nbox; mybox++) {
540 const DataIndex& din = dit[mybox];
541 size_t boxData = objSize * particlesPerBox[bl.index(din)];
542 size_t offset = offsets[bl.index(din)];
547 while (dataIn < boxData) {
548 int size = ((boxData - dataIn) >= chunkSize) ? chunkSize : boxData - dataIn;
549 readDataChunk(offset, dataspace, dataset, H5T_type, size, chunk);
551 for (
int ip = 0; ip < size / (int)objSize; ip++) {
568#include <CD_NamespaceFooter.H>
Silly, but useful functions that override standard Chombo HDF5 IO.
AMR-hierarchy container of computational particles, stored per patch in Struct-of-Arrays form.
Definition CD_ParticleContainer.H:123
Arena-backed Struct-of-Arrays particle container for a single grid patch.
Definition CD_ParticleSoA.H:655
RealVect position(const std::size_t a_index) const noexcept
Position of particle i as a RealVect (by value, assembled from the scalar columns).
Definition CD_ParticleSoA.H:1188
double & weight(const std::size_t a_index) noexcept
Weight of particle i.
Definition CD_ParticleSoA.H:1222
std::size_t size() const noexcept
Number of particles currently stored.
Definition CD_ParticleSoA.H:882
void h5DelinearizeAndAppend(const void *a_buffer)
Append a particle whose HDF5-checkpointed columns come from a buffer.
Definition CD_ParticleSoAImplem.H:275
void h5LinearizeParticle(void *a_buffer, const std::size_t a_index) const noexcept
Linearize the HDF5-checkpointed columns of particle i (no id/rank).
Definition CD_ParticleSoAImplem.H:258
static constexpr std::size_t h5BytesPerParticle() noexcept
Bytes for one HDF5-linearized particle (position + weight + h5 payload subset).
Definition CD_ParticleSoA.H:1380
ParticleID & particleID(const std::size_t a_index) noexcept
Global id of particle i (container-owned metadata).
Definition CD_ParticleSoA.H:1253
Namespace which encapsulates chombo-discharge IO functionality.
Definition CD_DischargeIO.H:42
void writeH5Part(std::string a_filename, const ParticleContainer< P, Traits > &a_particles, RealVect a_shift, Real a_time) noexcept
Write an SoA particle container to an H5Part file (quick visualization).
Definition CD_DischargeIOImplem.H:201