54static void backup_file(
const std::string &from,
const std::string &to) {
59 boost::filesystem::path pfrom(from), pto(to);
60 auto constexpr option_fail_if_exists = boost::filesystem::copy_options::none;
62 boost::filesystem::copy_file(pfrom, pto, option_fail_if_exists);
63 }
catch (
const boost::filesystem::filesystem_error &) {
68template <
typename extent_type>
70 extent_type
const &change_extent) {
71 auto const rank =
static_cast<h5xx::dataspace
>(dataset).rank();
72 auto extents =
static_cast<h5xx::dataspace
>(dataset).extents();
74 for (
int i = 0; i < rank; i++) {
75 extents[i] += change_extent[i];
77 H5Dset_extent(dataset.hid(), extents.data());
80template <
typename value_type,
typename extent_type>
81static void write_dataset(value_type
const &data, h5xx::dataset &dataset,
82 extent_type
const &change_extent,
83 extent_type
const &offset, extent_type
const &count) {
86 h5xx::write_dataset(dataset, data, h5xx::slice(offset, count));
90 boost::filesystem::path
const &script_path) {
91 if (!script_path.empty()) {
92 std::ifstream scriptfile(script_path.string());
93 std::string buffer((std::istreambuf_iterator<char>(scriptfile)),
94 std::istreambuf_iterator<char>());
95 auto file = h5xx::file(target, h5xx::file::out);
96 auto const group = h5xx::group(file,
"parameters/files");
97 h5xx::write_attribute(group,
"script", buffer);
103void File::init_file(std::string
const &file_path) {
105 if (m_script_path.empty()) {
106 m_absolute_script_path = boost::filesystem::path();
108 boost::filesystem::path
script_path(m_script_path);
109 m_absolute_script_path = boost::filesystem::canonical(
script_path);
111 auto const file_exists = boost::filesystem::exists(
file_path);
112 auto const backup_file_exists = boost::filesystem::exists(m_backup_filename);
124 if (m_comm.rank() == 0)
128 throw incompatible_h5mdfile();
131 if (backup_file_exists)
132 throw left_backupfile();
137void File::load_datasets() {
138 for (
auto const &d : m_h5md_specification.get_datasets()) {
141 datasets[d.path()] = h5xx::dataset(m_h5md_file, d.path());
145void File::create_groups() {
146 h5xx::group group(m_h5md_file);
147 for (
auto const &d : m_h5md_specification.get_datasets()) {
148 h5xx::group new_group(group, d.group);
152static std::vector<hsize_t>
create_dims(hsize_t rank, hsize_t data_dim) {
155 return std::vector<hsize_t>{0, 0, data_dim};
157 return std::vector<hsize_t>{0, data_dim};
159 return std::vector<hsize_t>{data_dim};
161 throw std::runtime_error(
162 "H5MD Error: datasets with this dimension are not implemented\n");
167 hsize_t chunk_size = (rank > 1) ? 1000 : 1;
170 return {1, chunk_size, data_dim};
172 return {1, chunk_size};
176 throw std::runtime_error(
177 "H5MD Error: datasets with this dimension are not implemented\n");
181void File::create_datasets() {
182 namespace hps = h5xx::policy::storage;
183 for (
const auto &d : m_h5md_specification.get_datasets()) {
186 auto maxdims = std::vector<hsize_t>(d.rank, H5S_UNLIMITED);
187 auto dataspace = h5xx::dataspace(
create_dims(d.rank, d.data_dim), maxdims);
189 .set(hps::fill_value(-10));
190 datasets[d.path()] = h5xx::dataset(m_h5md_file, d.path(), d.type, dataspace,
191 storage, H5P_DEFAULT, H5P_DEFAULT);
195void File::load_file(
const std::string &file_path) {
196 m_h5md_file = h5xx::file(
file_path, m_comm, MPI_INFO_NULL, h5xx::file::out);
201 auto h5md_group = h5xx::group(h5md_file,
"h5md");
202 h5xx::write_attribute(h5md_group,
"version",
203 boost::array<hsize_t, 2>{{1, 1}});
204 auto h5md_creator_group = h5xx::group(h5md_group,
"creator");
205 h5xx::write_attribute(h5md_creator_group,
"name",
"ESPResSo");
206 h5xx::write_attribute(h5md_creator_group,
"version", ESPRESSO_VERSION);
207 auto h5md_author_group = h5xx::group(h5md_group,
"author");
208 h5xx::write_attribute(h5md_author_group,
"name",
"N/A");
209 auto group = h5xx::group(h5md_file,
"particles/atoms/box");
210 h5xx::write_attribute(group,
"dimension", 3);
211 h5xx::write_attribute(group,
"boundary",
"periodic");
214void File::write_units() {
216 h5xx::write_attribute(datasets[
"particles/atoms/mass/value"],
"unit",
220 h5xx::write_attribute(datasets[
"particles/atoms/charge/value"],
"unit",
224 h5xx::write_attribute(datasets[
"particles/atoms/position/value"],
"unit",
226 h5xx::write_attribute(datasets[
"particles/atoms/box/edges/value"],
"unit",
230 h5xx::write_attribute(datasets[
"particles/atoms/lees_edwards/offset/value"],
234 h5xx::write_attribute(datasets[
"particles/atoms/velocity/value"],
"unit",
238 h5xx::write_attribute(datasets[
"particles/atoms/force/value"],
"unit",
242 h5xx::write_attribute(datasets[
"particles/atoms/id/time"],
"unit",
247void File::create_hard_links() {
248 std::string path_step =
"particles/atoms/id/step";
249 std::string path_time =
"particles/atoms/id/time";
250 for (
auto &ds : m_h5md_specification.get_datasets()) {
252 char const *from =
nullptr;
253 if (ds.name ==
"step") {
254 from = path_step.c_str();
255 }
else if (ds.name ==
"time") {
256 from = path_time.c_str();
258 assert(from !=
nullptr);
259 if (H5Lcreate_hard(m_h5md_file.hid(), from, m_h5md_file.hid(),
260 ds.path().c_str(), H5P_DEFAULT, H5P_DEFAULT) < 0) {
261 throw std::runtime_error(
"Error creating hard link for " + ds.path());
267void File::create_file(
const std::string &file_path) {
268 if (m_comm.rank() == 0)
271 m_h5md_file = h5xx::file(
file_path, m_comm, MPI_INFO_NULL, h5xx::file::out);
280 if (m_comm.rank() == 0)
281 boost::filesystem::remove(m_backup_filename);
286template <std::
size_t rank>
struct slice_info {};
288template <>
struct slice_info<3> {
289 static auto extent(hsize_t n_part_diff) {
292 static constexpr auto count() {
return Vector3hs{1, 1, 3}; }
293 static auto offset(hsize_t n_time_steps, hsize_t prefix) {
294 return Vector3hs{n_time_steps, prefix, 0};
298template <>
struct slice_info<2> {
299 static auto extent(hsize_t n_part_diff) {
return Vector2hs{1, n_part_diff}; }
300 static constexpr auto count() {
return Vector2hs{1, 1}; }
301 static auto offset(hsize_t n_time_steps, hsize_t prefix) {
308template <std::
size_t dim,
typename Op>
311 h5xx::dataset &dataset, Op op) {
312 auto const old_extents =
static_cast<h5xx::dataspace
>(dataset).extents();
313 auto const extent_particle_number =
314 std::max(n_part_global, old_extents[1]) - old_extents[1];
316 detail::slice_info<dim>::extent(extent_particle_number));
317 auto const count = detail::slice_info<dim>::count();
318 auto offset = detail::slice_info<dim>::offset(old_extents[0], prefix);
319 for (
auto const &p : particles) {
320 h5xx::write_dataset(dataset, op(p), h5xx::slice(offset, count));
327 auto const extents =
static_cast<h5xx::dataspace
>(dataset).extents();
329 h5xx::write_dataset(dataset, box_geo.
length(),
334 auto const extents =
static_cast<h5xx::dataspace
>(dataset).extents();
342 auto const extents =
static_cast<h5xx::dataspace
>(dataset).extents();
350 auto const extents =
static_cast<h5xx::dataspace
>(dataset).extents();
359 write_box(box_geo, datasets[
"particles/atoms/box/edges/value"]);
363 write_le_off(lebc, datasets[
"particles/atoms/lees_edwards/offset/value"]);
367 datasets[
"particles/atoms/lees_edwards/direction/value"]);
371 datasets[
"particles/atoms/lees_edwards/normal/value"]);
374 auto const n_part_local =
static_cast<int>(particles.
size());
378 BOOST_MPI_CHECK_RESULT(MPI_Exscan,
379 (&n_part_local, &prefix, 1, MPI_INT, MPI_SUM, m_comm));
381 auto const n_part_global =
382 boost::mpi::all_reduce(m_comm, n_part_local, std::plus<int>());
384 write_td_particle_property<2>(
385 prefix, n_part_global, particles, datasets[
"particles/atoms/id/value"],
389 h5xx::dataset &dataset = datasets[
"particles/atoms/id/value"];
390 auto const extents =
static_cast<h5xx::dataspace
>(dataset).extents();
392 datasets[
"particles/atoms/id/time"],
Vector1hs{1},
395 datasets[
"particles/atoms/id/step"],
Vector1hs{1},
400 write_td_particle_property<2>(
401 prefix, n_part_global, particles,
402 datasets[
"particles/atoms/species/value"],
406 write_td_particle_property<2>(
407 prefix, n_part_global, particles,
408 datasets[
"particles/atoms/mass/value"],
412 write_td_particle_property<3>(
413 prefix, n_part_global, particles,
414 datasets[
"particles/atoms/position/value"],
418 write_td_particle_property<3>(
419 prefix, n_part_global, particles,
420 datasets[
"particles/atoms/image/value"], [&](
auto const &p) {
425 write_td_particle_property<3>(prefix, n_part_global, particles,
426 datasets[
"particles/atoms/velocity/value"],
427 [](
auto const &p) {
return p.v(); });
430 write_td_particle_property<3>(prefix, n_part_global, particles,
431 datasets[
"particles/atoms/force/value"],
432 [](
auto const &p) {
return p.force(); });
435 write_td_particle_property<2>(
436 prefix, n_part_global, particles,
437 datasets[
"particles/atoms/charge/value"],
441 write_connectivity(particles);
445void File::write_connectivity(
const ParticleRange &particles) {
447 for (
auto const &p : particles) {
448 auto nbonds_local =
static_cast<decltype(bond)::index
>(bond.shape()[1]);
449 for (
auto const b : p.bonds()) {
450 auto const partner_ids = b.partner_ids();
451 if (partner_ids.size() == 1u) {
452 bond.resize(boost::extents[1][nbonds_local + 1][2]);
453 bond[0][nbonds_local][0] = p.id();
454 bond[0][nbonds_local][1] = partner_ids[0];
460 auto const n_bonds_local =
static_cast<int>(bond.shape()[1]);
461 int prefix_bonds = 0;
462 BOOST_MPI_CHECK_RESULT(
463 MPI_Exscan, (&n_bonds_local, &prefix_bonds, 1, MPI_INT, MPI_SUM, m_comm));
464 auto const n_bonds_total =
465 boost::mpi::all_reduce(m_comm, n_bonds_local, std::plus<int>());
467 static_cast<h5xx::dataspace
>(datasets[
"connectivity/atoms/value"])
469 Vector3hs offset_bonds = {extents[0],
static_cast<hsize_t
>(prefix_bonds), 0};
470 Vector3hs count_bonds = {1,
static_cast<hsize_t
>(n_bonds_local), 2};
471 auto const n_bond_diff =
472 std::max(
static_cast<hsize_t
>(n_bonds_total), extents[1]) - extents[1];
473 Vector3hs change_extent_bonds = {1,
static_cast<hsize_t
>(n_bond_diff), 0};
474 write_dataset(bond, datasets[
"connectivity/atoms/value"], change_extent_bonds,
475 offset_bonds, count_bonds);