68static void backup_file(
const std::string &from,
const std::string &to) {
73 boost::filesystem::path pfrom(from), pto(to);
74 auto constexpr option_fail_if_exists = boost::filesystem::copy_options::none;
76 boost::filesystem::copy_file(pfrom, pto, option_fail_if_exists);
77 }
catch (
const boost::filesystem::filesystem_error &) {
82template <
typename extent_type>
84 extent_type
const &change_extent) {
85 auto const rank =
static_cast<h5xx::dataspace
>(dataset).rank();
86 auto extents =
static_cast<h5xx::dataspace
>(dataset).extents();
88 for (
auto i = 0u; i < rank; i++) {
89 extents[i] += change_extent[i];
91 H5Dset_extent(dataset.hid(), extents.data());
94template <
typename value_type,
typename extent_type>
95static void write_dataset(value_type
const &data, h5xx::dataset &dataset,
96 extent_type
const &change_extent,
97 extent_type
const &offset, extent_type
const &count) {
100 h5xx::write_dataset(dataset, data, h5xx::slice(offset, count));
104 boost::filesystem::path
const &script_path) {
105 if (!script_path.empty()) {
106 std::ifstream scriptfile(script_path.string());
107 std::string buffer((std::istreambuf_iterator<char>(scriptfile)),
108 std::istreambuf_iterator<char>());
109 auto file = h5xx::file(target, h5xx::file::out);
110 auto const group = h5xx::group(file,
"parameters/files");
111 h5xx::write_attribute(group,
"script", buffer);
117void File::init_file(std::string
const &file_path) {
119 if (m_script_path.empty()) {
120 m_absolute_script_path = boost::filesystem::path();
122 boost::filesystem::path
script_path(m_script_path);
123 m_absolute_script_path = boost::filesystem::canonical(
script_path);
125 auto const file_exists = boost::filesystem::exists(
file_path);
126 auto const backup_file_exists = boost::filesystem::exists(m_backup_filename);
138 if (m_comm.rank() == 0)
142 throw incompatible_h5mdfile();
145 if (backup_file_exists)
146 throw left_backupfile();
151void File::load_datasets() {
152 auto &datasets = *m_datasets;
153 for (
auto const &ds : m_h5md_specification.get_datasets()) {
156 datasets[ds.path()] = h5xx::dataset(*m_h5md_file, ds.path());
160void File::create_groups() {
161 h5xx::group group(*m_h5md_file);
162 for (
auto const &ds : m_h5md_specification.get_datasets()) {
163 h5xx::group new_group(group, ds.group);
167static std::vector<hsize_t>
create_dims(hsize_t rank, hsize_t data_dim) {
170 return std::vector<hsize_t>{0ul, 0ul, data_dim};
172 return std::vector<hsize_t>{0ul, data_dim};
174 return std::vector<hsize_t>{data_dim};
176 throw std::runtime_error(
177 "H5MD Error: datasets with this dimension are not implemented\n");
182 hsize_t chunk_size = (rank > 1ul) ? 1000ul : 1ul;
185 return {1ul, chunk_size, data_dim};
187 return {1ul, chunk_size};
191 throw std::runtime_error(
192 "H5MD Error: datasets with this dimension are not implemented\n");
196void File::create_datasets() {
197 namespace hps = h5xx::policy::storage;
198 auto &datasets = *m_datasets;
199 for (
auto const &ds : m_h5md_specification.get_datasets()) {
202 auto maxdims = std::vector<hsize_t>(ds.rank, H5S_UNLIMITED);
204 h5xx::dataspace(
create_dims(ds.rank, ds.data_dim), maxdims);
206 .set(hps::fill_value(-10));
207 datasets[ds.path()] =
208 h5xx::dataset(*m_h5md_file, ds.path(), ds.type, dataspace, storage,
209 H5P_DEFAULT, H5P_DEFAULT);
213void File::load_file(
const std::string &file_path) {
214 *m_h5md_file = h5xx::file(
file_path, m_comm, MPI_INFO_NULL, h5xx::file::out);
219 auto h5md_group = h5xx::group(h5md_file,
"h5md");
220 h5xx::write_attribute(h5md_group,
"version",
221 boost::array<hsize_t, 2>{{1ul, 1ul}});
222 auto h5md_creator_group = h5xx::group(h5md_group,
"creator");
223 h5xx::write_attribute(h5md_creator_group,
"name",
"ESPResSo");
224 h5xx::write_attribute(h5md_creator_group,
"version", ESPRESSO_VERSION);
225 auto h5md_author_group = h5xx::group(h5md_group,
"author");
226 h5xx::write_attribute(h5md_author_group,
"name",
"N/A");
227 auto group = h5xx::group(h5md_file,
"particles/atoms/box");
228 h5xx::write_attribute(group,
"dimension", 3);
229 h5xx::write_attribute(group,
"boundary",
"periodic");
232void File::write_units() {
233 auto const &datasets = *m_datasets;
235 h5xx::write_attribute(datasets.at(
"particles/atoms/mass/value"),
"unit",
239 h5xx::write_attribute(datasets.at(
"particles/atoms/charge/value"),
"unit",
243 h5xx::write_attribute(datasets.at(
"particles/atoms/position/value"),
"unit",
245 h5xx::write_attribute(datasets.at(
"particles/atoms/box/edges/value"),
249 h5xx::write_attribute(
250 datasets.at(
"particles/atoms/lees_edwards/offset/value"),
"unit",
254 h5xx::write_attribute(datasets.at(
"particles/atoms/velocity/value"),
"unit",
258 h5xx::write_attribute(datasets.at(
"particles/atoms/force/value"),
"unit",
262 h5xx::write_attribute(datasets.at(
"particles/atoms/id/time"),
"unit",
267void File::create_hard_links() {
268 std::string path_step =
"particles/atoms/id/step";
269 std::string path_time =
"particles/atoms/id/time";
270 for (
auto &ds : m_h5md_specification.get_datasets()) {
272 char const *from =
nullptr;
273 if (ds.name ==
"step") {
274 from = path_step.c_str();
275 }
else if (ds.name ==
"time") {
276 from = path_time.c_str();
278 assert(from !=
nullptr);
279 if (H5Lcreate_hard(m_h5md_file->hid(), from, m_h5md_file->hid(),
280 ds.path().c_str(), H5P_DEFAULT, H5P_DEFAULT) < 0) {
281 throw std::runtime_error(
"Error creating hard link for " + ds.path());
287void File::create_file(
const std::string &file_path) {
288 if (m_comm.rank() == 0)
291 m_h5md_file = std::make_unique<h5xx::file>(
file_path, m_comm, MPI_INFO_NULL,
301 if (m_comm.rank() == 0)
302 boost::filesystem::remove(m_backup_filename);
307template <std::
size_t rank>
struct slice_info {};
309template <>
struct slice_info<3> {
310 static auto extent(hsize_t n_part_diff) {
313 static constexpr auto count() {
return Vector3hs{1, 1, 3}; }
314 static auto offset(hsize_t n_time_steps, hsize_t prefix) {
315 return Vector3hs{n_time_steps, prefix, 0};
319template <>
struct slice_info<2> {
320 static auto extent(hsize_t n_part_diff) {
return Vector2hs{1, n_part_diff}; }
321 static constexpr auto count() {
return Vector2hs{1, 1}; }
322 static auto offset(hsize_t n_time_steps, hsize_t prefix) {
329template <std::
size_t dim,
typename Op>
332 h5xx::dataset &dataset, Op op) {
333 auto const old_extents =
static_cast<h5xx::dataspace
>(dataset).extents();
334 auto const extent_particle_number =
335 std::max(n_part_global, old_extents[1]) - old_extents[1];
337 detail::slice_info<dim>::extent(extent_particle_number));
338 auto const count = detail::slice_info<dim>::count();
339 auto offset = detail::slice_info<dim>::offset(old_extents[0], prefix);
340 for (
auto const &p : particles) {
341 h5xx::write_dataset(dataset, op(p), h5xx::slice(offset, count));
348 auto const extents =
static_cast<h5xx::dataspace
>(dataset).extents();
350 h5xx::write_dataset(dataset, box_geo.
length(),
355 auto const extents =
static_cast<h5xx::dataspace
>(dataset).extents();
363 auto const extents =
static_cast<h5xx::dataspace
>(dataset).extents();
371 auto const extents =
static_cast<h5xx::dataspace
>(dataset).extents();
379 auto &datasets = *m_datasets;
381 write_box(box_geo, datasets[
"particles/atoms/box/edges/value"]);
385 write_le_off(lebc, datasets[
"particles/atoms/lees_edwards/offset/value"]);
389 datasets[
"particles/atoms/lees_edwards/direction/value"]);
393 datasets[
"particles/atoms/lees_edwards/normal/value"]);
396 auto const n_part_local =
static_cast<int>(particles.
size());
400 BOOST_MPI_CHECK_RESULT(MPI_Exscan,
401 (&n_part_local, &prefix, 1, MPI_INT, MPI_SUM, m_comm));
403 auto const n_part_global =
404 boost::mpi::all_reduce(m_comm, n_part_local, std::plus<int>());
406 write_td_particle_property<2>(
407 prefix, n_part_global, particles, datasets[
"particles/atoms/id/value"],
411 h5xx::dataset &dataset = datasets[
"particles/atoms/id/value"];
412 auto const extents =
static_cast<h5xx::dataspace
>(dataset).extents();
414 datasets[
"particles/atoms/id/time"],
Vector1hs{1},
417 datasets[
"particles/atoms/id/step"],
Vector1hs{1},
422 write_td_particle_property<2>(
423 prefix, n_part_global, particles,
424 datasets[
"particles/atoms/species/value"],
428 write_td_particle_property<2>(
429 prefix, n_part_global, particles,
430 datasets[
"particles/atoms/mass/value"],
434 write_td_particle_property<3>(
435 prefix, n_part_global, particles,
436 datasets[
"particles/atoms/position/value"],
440 write_td_particle_property<3>(
441 prefix, n_part_global, particles,
442 datasets[
"particles/atoms/image/value"], [&](
auto const &p) {
447 write_td_particle_property<3>(prefix, n_part_global, particles,
448 datasets[
"particles/atoms/velocity/value"],
449 [](
auto const &p) {
return p.v(); });
452 write_td_particle_property<3>(prefix, n_part_global, particles,
453 datasets[
"particles/atoms/force/value"],
454 [](
auto const &p) {
return p.force(); });
457 write_td_particle_property<2>(
458 prefix, n_part_global, particles,
459 datasets[
"particles/atoms/charge/value"],
463 write_connectivity(particles);
467void File::write_connectivity(
const ParticleRange &particles) {
469 for (
auto const &p : particles) {
470 auto nbonds_local =
static_cast<decltype(bond)::index
>(bond.shape()[1]);
471 for (
auto const b : p.bonds()) {
472 auto const partner_ids = b.partner_ids();
473 if (partner_ids.size() == 1u) {
474 bond.resize(boost::extents[1][nbonds_local + 1][2]);
475 bond[0][nbonds_local][0] = p.id();
476 bond[0][nbonds_local][1] = partner_ids[0];
482 auto const n_bonds_local =
static_cast<int>(bond.shape()[1]);
483 auto &datasets = *m_datasets;
484 int prefix_bonds = 0;
485 BOOST_MPI_CHECK_RESULT(
486 MPI_Exscan, (&n_bonds_local, &prefix_bonds, 1, MPI_INT, MPI_SUM, m_comm));
487 auto const n_bonds_total =
488 boost::mpi::all_reduce(m_comm, n_bonds_local, std::plus<int>());
490 static_cast<h5xx::dataspace
>(datasets[
"connectivity/atoms/value"])
492 Vector3hs offset_bonds = {extents[0],
static_cast<hsize_t
>(prefix_bonds), 0};
493 Vector3hs count_bonds = {1,
static_cast<hsize_t
>(n_bonds_local), 2};
494 auto const n_bond_diff =
495 std::max(
static_cast<hsize_t
>(n_bonds_total), extents[1]) - extents[1];
496 Vector3hs change_extent_bonds = {1,
static_cast<hsize_t
>(n_bond_diff), 0};
497 write_dataset(bond, datasets[
"connectivity/atoms/value"], change_extent_bonds,
498 offset_bonds, count_bonds);
506 std::vector<std::string>
const &output_fields, std::string mass_unit,
507 std::string length_unit, std::string time_unit,
508 std::string force_unit, std::string velocity_unit,
509 std::string charge_unit)
510 : m_script_path(std::move(script_path)), m_mass_unit(std::move(mass_unit)),
511 m_length_unit(std::move(length_unit)), m_time_unit(std::move(time_unit)),
512 m_force_unit(std::move(force_unit)),
513 m_velocity_unit(std::move(velocity_unit)),
516 m_h5md_file(std::make_unique<
h5xx::file>()),
517 m_datasets(std::make_unique<decltype(m_datasets)::element_type>()),
518 m_h5md_specification(m_fields) {