57#include "system/System.hpp"
61#include <boost/archive/binary_iarchive.hpp>
62#include <boost/archive/binary_oarchive.hpp>
63#include <boost/iostreams/device/array.hpp>
64#include <boost/iostreams/device/back_inserter.hpp>
65#include <boost/iostreams/stream.hpp>
85#pragma clang diagnostic push
86#pragma clang diagnostic ignored "-Wunreachable-code-return"
96static bool fatal_error(
char const *msg, std::string
const &fn =
"",
97 std::string
const &extra =
"") {
98 std::stringstream what;
99 what <<
"MPI-IO Error: " << msg;
100 if (not fn.empty()) {
101 what <<
" \"" << fn <<
"\"";
103 if (not extra.empty()) {
104 what <<
" :" << extra;
107 MPI_Comm_size(MPI_COMM_WORLD, &size);
109 throw std::runtime_error(what.str());
111 fprintf(stderr,
"%s\n", what.str().c_str());
115#if defined(__clang__)
116#pragma clang diagnostic pop
129static bool fatal_error(
char const *msg, std::string
const &fn, MPI_File *fp,
132 char buf[MPI_MAX_ERROR_STRING];
134 MPI_Error_string(errnum, buf, &buf_len);
156 std::size_t len, std::size_t pref,
157 MPI_Datatype MPI_T) {
160 ret = MPI_File_open(MPI_COMM_WORLD,
const_cast<char *
>(fn.c_str()),
162 MPI_MODE_WRONLY | MPI_MODE_CREATE | MPI_MODE_EXCL,
168 static_cast<MPI_Offset
>(pref) *
static_cast<MPI_Offset
>(
sizeof(T));
169 ret = MPI_File_set_view(f, offset, MPI_T, MPI_T,
const_cast<char *
>(
"native"),
171 ret |= MPI_File_write_all(f, arr,
static_cast<int>(len), MPI_T,
173 static_cast<void>(ret and
fatal_error(
"Could not write file", fn, &f, ret));
183 unsigned long offset = 0ul;
184 MPI_Exscan(&n_items, &offset, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD);
196static void dump_info(std::string
const &fn,
unsigned fields,
199 auto const nbonds = bonded_ias.
size();
200 assert(
static_cast<std::size_t
>(bonded_ias.
get_next_key()) == nbonds);
202 FILE *f = fopen(fn.c_str(),
"wb");
206 std::vector<int> npartners;
207 bool success = (fwrite(&fields,
sizeof(fields), 1u, f) == 1);
209 npartners.reserve(nbonds);
210 for (
int bond_id = 0; bond_id < bonded_ias.
get_next_key(); ++bond_id) {
215 success &= fwrite(&nbonds,
sizeof(std::size_t), 1u, f) == 1;
216 success &= fwrite(npartners.data(),
sizeof(
int), nbonds, f) == nbonds;
218 static_cast<void>(success or
fatal_error(
"Could not write file", fn));
225 auto const nlocalpart =
static_cast<unsigned long>(particles.
size());
228 auto &pos = buffers.
pos;
229 auto &vel = buffers.
vel;
230 auto &
id = buffers.
id;
231 auto &type = buffers.
type;
234 if (nlocalpart >
id.size())
235 id.resize(nlocalpart);
237 pos.resize(3ul * nlocalpart);
239 vel.resize(3ul * nlocalpart);
241 type.resize(nlocalpart);
244 auto id_it =
id.begin();
245 auto type_it = type.begin();
246 auto pos_it = pos.begin();
247 auto vel_it = vel.begin();
248 for (
auto const &p : particles) {
252 std::copy_n(std::begin(p.pos()), 3u, pos_it);
256 std::copy_n(std::begin(p.v()), 3u, vel_it);
266 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
268 dump_info(prefix +
".head", fields, bonded_ias);
269 auto const pref_offset =
static_cast<unsigned long>(rank);
270 mpiio_dump_array<unsigned long>(prefix +
".pref", &offset, 1ul, pref_offset,
272 mpiio_dump_array<int>(prefix +
".id",
id.data(), nlocalpart, offset, MPI_INT);
274 mpiio_dump_array<double>(prefix +
".pos", pos.data(), 3ul * nlocalpart,
275 3ul * offset, MPI_DOUBLE);
277 mpiio_dump_array<double>(prefix +
".vel", vel.data(), 3ul * nlocalpart,
278 3ul * offset, MPI_DOUBLE);
280 mpiio_dump_array<int>(prefix +
".type", type.data(), nlocalpart, offset,
284 std::vector<char> bonds;
288 namespace io = boost::iostreams;
289 io::stream_buffer<io::back_insert_device<std::vector<char>>> os{
290 io::back_inserter(bonds)};
291 boost::archive::binary_oarchive bond_archiver{os};
293 for (
auto const &p : particles) {
294 bond_archiver << p.bonds();
299 auto const bonds_size =
static_cast<unsigned long>(bonds.size());
302 mpiio_dump_array<unsigned long>(prefix +
".boff", &bonds_size, 1ul,
303 pref_offset, MPI_UNSIGNED_LONG);
304 mpiio_dump_array<char>(prefix +
".bond", bonds.data(), bonds.size(),
305 bonds_offset, MPI_CHAR);
317static unsigned long get_num_elem(
const std::string &fn, std::size_t elem_sz) {
322 if (stat(fn.c_str(), &st) != 0) {
323 auto const reason = strerror(errno);
324 fatal_error(
"Could not get file size of", fn, reason);
326 return static_cast<unsigned long>(st.st_size) / elem_sz;
342 std::size_t pref, MPI_Datatype MPI_T) {
345 ret = MPI_File_open(MPI_COMM_WORLD,
const_cast<char *
>(fn.c_str()),
346 MPI_MODE_RDONLY, MPI_INFO_NULL, &f);
351 static_cast<MPI_Offset
>(pref) *
static_cast<MPI_Offset
>(
sizeof(T));
352 ret = MPI_File_set_view(f, offset, MPI_T, MPI_T,
const_cast<char *
>(
"native"),
355 ret |= MPI_File_read_all(f, arr,
static_cast<int>(len), MPI_T,
357 static_cast<void>(ret and
fatal_error(
"Could not read file", fn, &f, ret));
368static unsigned read_head(
const std::string &fn,
int rank) {
369 unsigned n_fields = 0u;
372 f = fopen(fn.c_str(),
"rb");
373 static_cast<void>(not f and
fatal_error(
"Could not open file", fn));
374 auto const n = fread(
static_cast<void *
>(&n_fields),
sizeof n_fields, 1, f);
375 static_cast<void>((n == 1) or
fatal_error(
"Could not read file", fn));
377 MPI_Bcast(&n_fields, 1, MPI_UNSIGNED, 0, MPI_COMM_WORLD);
394static std::tuple<unsigned long, unsigned long>
396 unsigned long nglobalpart) {
397 auto const pref_offset =
static_cast<unsigned long>(rank);
398 unsigned long pref = 0ul;
399 unsigned long nlocalpart = 0ul;
400 mpiio_read_array<unsigned long>(fn, &pref, 1ul, pref_offset,
403 MPI_Send(&pref, 1, MPI_UNSIGNED_LONG, rank - 1, 0, MPI_COMM_WORLD);
405 MPI_Recv(&nlocalpart, 1, MPI_UNSIGNED_LONG, rank + 1, MPI_ANY_TAG,
406 MPI_COMM_WORLD, MPI_STATUS_IGNORE);
408 nlocalpart = nglobalpart;
410 return {pref, nlocalpart};
418 MPI_Comm_size(MPI_COMM_WORLD, &size);
419 MPI_Comm_rank(MPI_COMM_WORLD, &rank);
420 auto const nproc =
get_num_elem(prefix +
".pref",
sizeof(
unsigned long));
421 auto const nglobalpart =
get_num_elem(prefix +
".id",
sizeof(
int));
423 if (rank == 0 && nproc !=
static_cast<unsigned long>(size)) {
424 fatal_error(
"Trying to read a file with a different COMM "
425 "size than at point of writing.");
431 auto const avail_fields =
read_head(prefix +
".head", rank);
432 if (rank == 0 && (fields & avail_fields) != fields) {
433 fatal_error(
"Requesting to read fields which were not dumped.");
440 auto const [pref, nlocalpart] =
441 read_prefs(prefix +
".pref", rank, size, nglobalpart);
443 std::vector<Particle> particles(nlocalpart);
448 std::vector<int> id(nlocalpart);
449 auto id_it =
id.begin();
450 mpiio_read_array<int>(prefix +
".id",
id.data(), nlocalpart, pref, MPI_INT);
452 for (
auto &p : particles) {
461 std::vector<double> pos(3ul * nlocalpart);
462 auto pos_it = pos.begin();
463 mpiio_read_array<double>(prefix +
".pos", pos.data(), 3ul * nlocalpart,
464 3ul * pref, MPI_DOUBLE);
466 for (
auto &p : particles) {
467 std::copy_n(pos_it, 3u, std::begin(p.pos()));
475 std::vector<int> type(nlocalpart);
476 auto type_it = type.begin();
477 mpiio_read_array<int>(prefix +
".type", type.data(), nlocalpart, pref,
480 for (
auto &p : particles) {
489 std::vector<double> vel(3ul * nlocalpart);
490 auto vel_it = vel.begin();
491 mpiio_read_array<double>(prefix +
".vel", vel.data(), 3ul * nlocalpart,
492 3ul * pref, MPI_DOUBLE);
494 for (
auto &p : particles) {
495 std::copy_n(vel_it, 3u, std::begin(p.v()));
503 auto const pref_offset =
static_cast<unsigned long>(rank);
504 unsigned long bonds_size = 0u;
505 mpiio_read_array<unsigned long>(prefix +
".boff", &bonds_size, 1ul,
506 pref_offset, MPI_UNSIGNED_LONG);
511 std::vector<char> bond(bonds_size);
512 mpiio_read_array<char>(prefix +
".bond", bond.data(), bonds_size,
513 bonds_offset, MPI_CHAR);
515 boost::iostreams::array_source src(bond.data(), bond.size());
516 boost::iostreams::stream<boost::iostreams::array_source> ss(src);
517 boost::archive::binary_iarchive ia(ss);
519 for (
auto &p : particles) {
524 for (
auto &p : particles) {
Vector implementation and trait types for boost qvm interoperability.
Data structures for bonded interactions.
int number_of_partners(Bonded_IA_Parameters const &iaparams)
Get the number of bonded partners for the specified bond.
container for bonded interactions.
mapped_type at(key_type const &key) const
bool contains(key_type const &key) const
auto get_next_key() const
Describes a cell structure / cell system.
Particle * add_particle(Particle &&p)
Add a particle.
void remove_all_particles()
Remove all particles from the cell system.
base_type::size_type size() const
void errexit()
exit ungracefully, core dump if switched on.
This file contains the errorhandling code for severe errors, like a broken bond or illegal parameter ...
static unsigned long mpi_calculate_file_offset(unsigned long n_items)
Calculate the file offset on the local node.
void mpi_mpiio_common_write(std::string const &prefix, unsigned fields, BondedInteractionsMap const &bonded_ias, ParticleRange const &particles, write_buffers &buffers)
Parallel binary output using MPI-IO.
static std::tuple< unsigned long, unsigned long > read_prefs(const std::string &fn, int rank, int size, unsigned long nglobalpart)
Read the pref file.
static unsigned long get_num_elem(const std::string &fn, std::size_t elem_sz)
Get the number of elements in a file by its file size and elem_sz.
static void mpiio_read_array(const std::string &fn, T *arr, std::size_t len, std::size_t pref, MPI_Datatype MPI_T)
Read a previously dumped array of size len starting from prefix pref of type T using MPI_T as MPI dat...
static void mpiio_dump_array(const std::string &fn, T const *arr, std::size_t len, std::size_t pref, MPI_Datatype MPI_T)
Dump data arr of size len starting from prefix pref of type T using MPI_T as MPI datatype.
static unsigned read_head(const std::string &fn, int rank)
Read the header file and return the first value.
void mpi_mpiio_common_read(const std::string &prefix, unsigned fields, CellStructure &cell_structure)
Parallel binary input using MPI-IO.
static void dump_info(std::string const &fn, unsigned fields, BondedInteractionsMap const &bonded_ias)
Dump the fields and bond information.
static bool fatal_error(char const *msg, std::string const &fn="", std::string const &extra="")
Fatal error handler.
std::vector< double > pos
std::vector< double > vel