-
Cristian Lalescu authoredCristian Lalescu authored
particles_output_hdf5.hpp 14.99 KiB
/******************************************************************************
* *
* Copyright 2019 Max Planck Institute for Dynamics and Self-Organization *
* *
* This file is part of TurTLE. *
* *
* TurTLE is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published *
* by the Free Software Foundation, either version 3 of the License, *
* or (at your option) any later version. *
* *
* TurTLE is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with TurTLE. If not, see <http://www.gnu.org/licenses/> *
* *
* Contact: Cristian.Lalescu@ds.mpg.de *
* *
******************************************************************************/
#ifndef PARTICLES_OUTPUT_HDF5_HPP
#define PARTICLES_OUTPUT_HDF5_HPP
#include <memory>
#include <vector>
#include <hdf5.h>
#include <sys/stat.h>
#include "abstract_particles_output.hpp"
#include "scope_timer.hpp"
template <class partsize_t,
class real_number,
int size_particle_positions>
class particles_output_hdf5 : public abstract_particles_output<partsize_t,
real_number,
size_particle_positions>{
using Parent = abstract_particles_output<partsize_t,
real_number,
size_particle_positions>;
std::string particle_species_name;
hid_t file_id;
const partsize_t total_nb_particles;
std::vector<hsize_t> particle_file_layout; // to hold the shape of initial condition array
hid_t dset_id_state;
hid_t dset_id_rhs;
bool use_collective_io;
public:
particles_output_hdf5(MPI_Comm in_mpi_com,
const std::string ps_name,
const partsize_t inTotalNbParticles,
const int in_nb_rhs,
const bool in_use_collective_io = false)
: abstract_particles_output<partsize_t,
real_number,
size_particle_positions>(
in_mpi_com,
inTotalNbParticles,
in_nb_rhs),
particle_species_name(ps_name),
file_id(0),
total_nb_particles(inTotalNbParticles),
dset_id_state(0),
dset_id_rhs(0),
use_collective_io(in_use_collective_io){}
int open_file(std::string filename){
if(Parent::isInvolved()){
TIMEZONE("particles_output_hdf5::open_file");
this->require_checkpoint_groups(filename);
hid_t plist_id_par = H5Pcreate(H5P_FILE_ACCESS);
assert(plist_id_par >= 0);
int retTest = H5Pset_fapl_mpio(
plist_id_par,
Parent::getComWriter(),
MPI_INFO_NULL);
variable_used_only_in_assert(retTest);
assert(retTest >= 0);
// Parallel HDF5 write
file_id = H5Fopen(
filename.c_str(),
H5F_ACC_RDWR | H5F_ACC_DEBUG,
plist_id_par);
// file_id = H5Fcreate(filename.c_str(), H5F_ACC_TRUNC | H5F_ACC_DEBUG/*H5F_ACC_EXCL*/, H5P_DEFAULT/*H5F_ACC_RDWR*/, plist_id_par);
assert(file_id >= 0);
H5Pclose(plist_id_par);
dset_id_state = H5Gopen(
file_id,
(this->particle_species_name + std::string("/state")).c_str(),
H5P_DEFAULT);
assert(dset_id_state >= 0);
dset_id_rhs = H5Gopen(
file_id,
(this->particle_species_name + std::string("/rhs")).c_str(),
H5P_DEFAULT);
assert(dset_id_rhs >= 0);
}
return EXIT_SUCCESS;
}
~particles_output_hdf5(){}
void update_particle_species_name(
const std::string new_name)
{
this->particle_species_name.assign(new_name);
}
int close_file(void){
if(Parent::isInvolved()){
TIMEZONE("particles_output_hdf5::close_file");
int rethdf = H5Gclose(dset_id_state);
variable_used_only_in_assert(rethdf);
assert(rethdf >= 0);
rethdf = H5Gclose(dset_id_rhs);
assert(rethdf >= 0);
rethdf = H5Fclose(file_id);
assert(rethdf >= 0);
}
return EXIT_SUCCESS;
}
void require_checkpoint_groups(std::string filename){
if(Parent::isInvolved()){
if (Parent::getMyRank() == 0)
{
bool file_exists = false;
{
struct stat file_buffer;
file_exists = (stat(filename.c_str(), &file_buffer) == 0);
}
hid_t file_id;
if (file_exists)
file_id = H5Fopen(
filename.c_str(),
H5F_ACC_RDWR | H5F_ACC_DEBUG,
H5P_DEFAULT);
else
file_id = H5Fcreate(
filename.c_str(),
H5F_ACC_EXCL | H5F_ACC_DEBUG,
H5P_DEFAULT,
H5P_DEFAULT);
assert(file_id >= 0);
bool group_exists = H5Lexists(
file_id,
this->particle_species_name.c_str(),
H5P_DEFAULT);
if (!group_exists)
{
hid_t gg = H5Gcreate(
file_id,
this->particle_species_name.c_str(),
H5P_DEFAULT,
H5P_DEFAULT,
H5P_DEFAULT);
assert(gg >= 0);
H5Gclose(gg);
}
hid_t gg = H5Gopen(
file_id,
this->particle_species_name.c_str(),
H5P_DEFAULT);
assert(gg >= 0);
group_exists = H5Lexists(
gg,
"state",
H5P_DEFAULT);
if (!group_exists)
{
hid_t ggg = H5Gcreate(
gg,
"state",
H5P_DEFAULT,
H5P_DEFAULT,
H5P_DEFAULT);
assert(ggg >= 0);
H5Gclose(ggg);
}
group_exists = H5Lexists(
gg,
"rhs",
H5P_DEFAULT);
if (!group_exists)
{
hid_t ggg = H5Gcreate(
gg,
"rhs",
H5P_DEFAULT,
H5P_DEFAULT,
H5P_DEFAULT);
assert(ggg >= 0);
H5Gclose(ggg);
}
H5Gclose(gg);
H5Fclose(file_id);
}
MPI_Barrier(Parent::getComWriter());
}
}
void write(
const int idx_time_step,
const real_number* particles_positions,
const std::unique_ptr<real_number[]>* particles_rhs,
const partsize_t nb_particles,
const partsize_t particles_idx_offset,
const int size_particle_rhs) final{
assert(Parent::isInvolved());
TIMEZONE("particles_output_hdf5::write");
assert(particles_idx_offset < Parent::getTotalNbParticles() || (particles_idx_offset == Parent::getTotalNbParticles() && nb_particles == 0));
assert(particles_idx_offset+nb_particles <= Parent::getTotalNbParticles());
static_assert(std::is_same<real_number, double>::value ||
std::is_same<real_number, float>::value,
"real_number must be double or float");
const hid_t type_id = (sizeof(real_number) == 8 ? H5T_NATIVE_DOUBLE : H5T_NATIVE_FLOAT);
hid_t plist_id = H5Pcreate(H5P_DATASET_XFER);
assert(plist_id >= 0);
{
int rethdf = H5Pset_dxpl_mpio(plist_id, use_collective_io ? H5FD_MPIO_COLLECTIVE : H5FD_MPIO_INDEPENDENT);
variable_used_only_in_assert(rethdf);
assert(rethdf >= 0);
}
{
std::vector<hsize_t> datacount = std::vector<hsize_t>(this->particle_file_layout);
datacount.push_back(size_particle_positions);
hid_t dataspace = H5Screate_simple(datacount.size(), &datacount.front(), NULL);
assert(dataspace >= 0);
hid_t dataset_id = H5Dcreate( dset_id_state,
std::to_string(idx_time_step).c_str(),
type_id,
dataspace,
H5P_DEFAULT,
H5P_DEFAULT,
H5P_DEFAULT);
assert(dataset_id >= 0);
assert(nb_particles >= 0);
assert(particles_idx_offset >= 0);
const hsize_t count[2] = {hsize_t(nb_particles), size_particle_positions};
const hsize_t offset[2] = {hsize_t(particles_idx_offset), 0};
hid_t memspace = H5Screate_simple(2, count, NULL);
assert(memspace >= 0);
assert(total_nb_particles >= 0);
assert(size_particle_positions >= 0);
const hsize_t file_count[2] = {hsize_t(total_nb_particles), size_particle_positions};
hid_t filespace = H5Screate_simple(2, file_count, NULL);
assert(filespace >= 0);
int rethdf = H5Sselect_hyperslab(
filespace,
H5S_SELECT_SET,
offset,
NULL,
count,
NULL);
variable_used_only_in_assert(rethdf);
assert(rethdf >= 0);
herr_t status = H5Dwrite(
dataset_id,
type_id,
memspace,
filespace,
plist_id,
particles_positions);
variable_used_only_in_assert(status);
assert(status >= 0);
rethdf = H5Sclose(memspace);
assert(rethdf >= 0);
rethdf = H5Dclose(dataset_id);
assert(rethdf >= 0);
rethdf = H5Sclose(filespace);
assert(rethdf >= 0);
}
{
assert(size_particle_rhs >= 0);
std::vector<hsize_t> datacount = std::vector<hsize_t>(this->particle_file_layout);
datacount.insert(datacount.begin(), hsize_t(Parent::getNbRhs()));
datacount.push_back(size_particle_rhs);
hid_t dataspace = H5Screate_simple(datacount.size(), &datacount.front(), NULL);
assert(dataspace >= 0);
hid_t dataset_id = H5Dcreate( dset_id_rhs,
std::to_string(idx_time_step).c_str(),
type_id,
dataspace,
H5P_DEFAULT,
H5P_DEFAULT,
H5P_DEFAULT);
assert(dataset_id >= 0);
assert(particles_idx_offset >= 0);
for(int idx_rhs = 0 ; idx_rhs < Parent::getNbRhs() ; ++idx_rhs){
const hsize_t count[3] = {
1,
hsize_t(nb_particles),
hsize_t(size_particle_rhs)};
const hsize_t offset[3] = {
hsize_t(idx_rhs),
hsize_t(particles_idx_offset),
0};
hid_t memspace = H5Screate_simple(3, count, NULL);
assert(memspace >= 0);
assert(total_nb_particles >= 0);
assert(size_particle_positions >= 0);
const hsize_t file_count[3] = {hsize_t(Parent::getNbRhs()), hsize_t(total_nb_particles), size_particle_positions};
hid_t filespace = H5Screate_simple(3, file_count, NULL);
assert(filespace >= 0);
int rethdf = H5Sselect_hyperslab(
filespace,
H5S_SELECT_SET,
offset,
NULL,
count,
NULL);
variable_used_only_in_assert(rethdf);
assert(rethdf >= 0);
herr_t status = H5Dwrite(
dataset_id,
type_id,
memspace,
filespace,
plist_id,
particles_rhs[idx_rhs].get());
variable_used_only_in_assert(status);
assert(status >= 0);
rethdf = H5Sclose(filespace);
assert(rethdf >= 0);
rethdf = H5Sclose(memspace);
assert(rethdf >= 0);
}
int rethdf = H5Dclose(dataset_id);
variable_used_only_in_assert(rethdf);
assert(rethdf >= 0);
}
{
int rethdf = H5Pclose(plist_id);
variable_used_only_in_assert(rethdf);
assert(rethdf >= 0);
}
}
int setParticleFileLayout(std::vector<hsize_t> input_layout){
this->particle_file_layout.resize(input_layout.size());
for (unsigned int i=0; i<this->particle_file_layout.size(); i++)
this->particle_file_layout[i] = input_layout[i];
return EXIT_SUCCESS;
}
std::vector<hsize_t> getParticleFileLayout(void){
return std::vector<hsize_t>(this->particle_file_layout);
}
};
#endif//PARTICLES_OUTPUT_HDF5_HPP