diff --git a/doc/src/dump_adios.rst b/doc/src/dump_adios.rst index 71ab6a07d9..750d697e2c 100644 --- a/doc/src/dump_adios.rst +++ b/doc/src/dump_adios.rst @@ -35,13 +35,21 @@ Examples Description """"""""""" -Dump a snapshot of atom coordinates every N timesteps in the -`ADIOS `_ based "BP" file format, or using different I/O solutions in ADIOS, -to a stream that can be read on-line by another program. +Dump a snapshot of atom coordinates every N timesteps in the `ADIOS +`_ based "BP" file format, or using different I/O solutions in +ADIOS, to a stream that can be read on-line by another program. ADIOS-BP files are binary, portable and self-describing. .. _adios: https://github.com/ornladios/ADIOS2 +.. note:: + + To be able to use ADIOS, a file ``adios2_config.xml`` with specific + configuration settings is expected in the current working directory. + If the file is not present, LAMMPS will try to create a minimal + default file. Please refer to the ADIOS documentation for details on + how to adjust this file for optimal performance and desired features. + **Use from write_dump:** It is possible to use these dump styles with the diff --git a/src/ADIOS/adios_common.h b/src/ADIOS/adios_common.h new file mode 100644 index 0000000000..9b0fb357ea --- /dev/null +++ b/src/ADIOS/adios_common.h @@ -0,0 +1,39 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. + + Contributed by Norbert Podhorszki (Oak Ridge National Laboratory) +------------------------------------------------------------------------- */ + +#ifndef LMP_ADIOS_COMMON_H +#define LMP_ADIOS_COMMON_H + +// common definitions for all ADIOS package classes + +static const char default_config[] = "\n" + "\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "\n"; + +#endif diff --git a/src/ADIOS/dump_atom_adios.cpp b/src/ADIOS/dump_atom_adios.cpp index 7265ef75f5..a56f31b6c5 100644 --- a/src/ADIOS/dump_atom_adios.cpp +++ b/src/ADIOS/dump_atom_adios.cpp @@ -1,4 +1,3 @@ -// clang-format off /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://www.lammps.org/, Sandia National Laboratories @@ -24,61 +23,58 @@ #include "memory.h" #include "universe.h" #include "update.h" + #include #include "adios2.h" +#include "adios_common.h" using namespace LAMMPS_NS; -#define MAX_TEXT_HEADER_SIZE 4096 -#define DUMP_BUF_CHUNK_SIZE 16384 -#define DUMP_BUF_INCREMENT_SIZE 4096 +namespace LAMMPS_NS { +class DumpAtomADIOSInternal { -namespace LAMMPS_NS -{ -class DumpAtomADIOSInternal -{ + public: + DumpAtomADIOSInternal(){}; + ~DumpAtomADIOSInternal() = default; -public: - DumpAtomADIOSInternal() {}; - ~DumpAtomADIOSInternal() = default; - - // name of adios group, referrable in adios2_config.xml - const std::string ioName = "atom"; - adios2::ADIOS *ad = nullptr; // adios object - adios2::IO io; // adios group of variables and attributes in this dump - adios2::Engine fh; // adios file/stream handle object - // one ADIOS output variable we need to change every step - adios2::Variable varAtoms; + // name of adios group, referrable in adios2_config.xml + const std::string ioName = "atom"; + adios2::ADIOS *ad = nullptr; // adios object + adios2::IO io; // adios group of variables and attributes in this dump + adios2::Engine fh; // adios file/stream handle object + // one ADIOS output variable we need to change every step + adios2::Variable varAtoms; }; -} // namespace LAMMPS_NS +} // namespace LAMMPS_NS /* ---------------------------------------------------------------------- */ -DumpAtomADIOS::DumpAtomADIOS(LAMMPS *lmp, int narg, char **arg) -: DumpAtom(lmp, narg, arg) +DumpAtomADIOS::DumpAtomADIOS(LAMMPS *lmp, int narg, char **arg) : DumpAtom(lmp, narg, arg) { - internal = new DumpAtomADIOSInternal(); - try { - internal->ad = - new adios2::ADIOS("adios2_config.xml", world, adios2::DebugON); - } catch (std::ios_base::failure &e) { - char str[256]; - snprintf(str, sizeof(str), "ADIOS initialization failed with error: %s", - e.what()); - error->one(FLERR, str); - } + // create a default adios2_config.xml if it doesn't exist yet. + FILE *cfgfp = fopen("adios2_config.xml", "r"); + if (!cfgfp) { + cfgfp = fopen("adios2_config.xml", "w"); + if (cfgfp) fputs(default_config, cfgfp); + } + if (cfgfp) fclose(cfgfp); + + internal = new DumpAtomADIOSInternal(); + try { + internal->ad = new adios2::ADIOS("adios2_config.xml", world, adios2::DebugON); + } catch (std::ios_base::failure &e) { + error->all(FLERR, "ADIOS initialization failed with error: {}", e.what()); + } } /* ---------------------------------------------------------------------- */ DumpAtomADIOS::~DumpAtomADIOS() { - if (internal->fh) { - internal->fh.Close(); - } - delete internal->ad; - delete internal; + if (internal->fh) internal->fh.Close(); + delete internal->ad; + delete internal; } /* ---------------------------------------------------------------------- */ @@ -129,228 +125,215 @@ void DumpAtomADIOS::openfile() void DumpAtomADIOS::write() { - if (domain->triclinic == 0) { - boxxlo = domain->boxlo[0]; - boxxhi = domain->boxhi[0]; - boxylo = domain->boxlo[1]; - boxyhi = domain->boxhi[1]; - boxzlo = domain->boxlo[2]; - boxzhi = domain->boxhi[2]; - } else { - boxxlo = domain->boxlo_bound[0]; - boxxhi = domain->boxhi_bound[0]; - boxylo = domain->boxlo_bound[1]; - boxyhi = domain->boxhi_bound[1]; - boxzlo = domain->boxlo_bound[2]; - boxzhi = domain->boxhi_bound[2]; - boxxy = domain->xy; - boxxz = domain->xz; - boxyz = domain->yz; + if (domain->triclinic == 0) { + boxxlo = domain->boxlo[0]; + boxxhi = domain->boxhi[0]; + boxylo = domain->boxlo[1]; + boxyhi = domain->boxhi[1]; + boxzlo = domain->boxlo[2]; + boxzhi = domain->boxhi[2]; + } else { + boxxlo = domain->boxlo_bound[0]; + boxxhi = domain->boxhi_bound[0]; + boxylo = domain->boxlo_bound[1]; + boxyhi = domain->boxhi_bound[1]; + boxzlo = domain->boxlo_bound[2]; + boxzhi = domain->boxhi_bound[2]; + boxxy = domain->xy; + boxxz = domain->xz; + boxyz = domain->yz; + } + + // nme = # of dump lines this proc contributes to dump + + nme = count(); + + // ntotal = total # of atoms in snapshot + // atomOffset = sum of # of atoms up to this proc (exclusive prefix sum) + + bigint bnme = nme; + MPI_Allreduce(&bnme, &ntotal, 1, MPI_LMP_BIGINT, MPI_SUM, world); + + bigint atomOffset; // sum of all atoms on processes 0..me-1 + MPI_Scan(&bnme, &atomOffset, 1, MPI_LMP_BIGINT, MPI_SUM, world); + atomOffset -= nme; // exclusive prefix sum needed + + // Now we know the global size and the local subset size and offset + // of the atoms table + size_t nAtomsGlobal = static_cast(ntotal); + size_t startRow = static_cast(atomOffset); + size_t nAtomsLocal = static_cast(nme); + size_t nColumns = static_cast(size_one); + internal->varAtoms.SetShape({nAtomsGlobal, nColumns}); + internal->varAtoms.SetSelection({{startRow, 0}, {nAtomsLocal, nColumns}}); + + // insure buf is sized for packing + // adios does not limit per-process data size so nme*size_one is not + // constrained to int + // if sorting on IDs also request ID list from pack() + // sort buf as needed + + if (nme > maxbuf) { + maxbuf = nme; + memory->destroy(buf); + memory->create(buf, (maxbuf * size_one), "dump:buf"); + } + if (sort_flag && sortcol == 0 && nme > maxids) { + maxids = nme; + memory->destroy(ids); + memory->create(ids, maxids, "dump:ids"); + } + + if (sort_flag && sortcol == 0) + pack(ids); + else + pack(nullptr); + if (sort_flag) sort(); + + openfile(); + internal->fh.BeginStep(); + // write info on data as scalars (by me==0) + if (me == 0) { + internal->fh.Put("ntimestep", update->ntimestep); + internal->fh.Put("nprocs", nprocs); + + internal->fh.Put("boxxlo", boxxlo); + internal->fh.Put("boxxhi", boxxhi); + internal->fh.Put("boxylo", boxylo); + internal->fh.Put("boxyhi", boxyhi); + internal->fh.Put("boxzlo", boxzlo); + internal->fh.Put("boxzhi", boxzhi); + + if (domain->triclinic) { + internal->fh.Put("boxxy", boxxy); + internal->fh.Put("boxxz", boxxz); + internal->fh.Put("boxyz", boxyz); } + } + // Everyone needs to write scalar variables that are used as dimensions and + // offsets of arrays + internal->fh.Put("natoms", ntotal); + internal->fh.Put("ncolumns", size_one); + internal->fh.Put("nme", bnme); + internal->fh.Put("offset", atomOffset); + // now write the atoms + internal->fh.Put(internal->varAtoms, buf); + internal->fh.EndStep(); // I/O will happen now... - // nme = # of dump lines this proc contributes to dump - - nme = count(); - - // ntotal = total # of atoms in snapshot - // atomOffset = sum of # of atoms up to this proc (exclusive prefix sum) - - bigint bnme = nme; - MPI_Allreduce(&bnme, &ntotal, 1, MPI_LMP_BIGINT, MPI_SUM, world); - - bigint atomOffset; // sum of all atoms on processes 0..me-1 - MPI_Scan(&bnme, &atomOffset, 1, MPI_LMP_BIGINT, MPI_SUM, world); - atomOffset -= nme; // exclusive prefix sum needed - - // Now we know the global size and the local subset size and offset - // of the atoms table - size_t nAtomsGlobal = static_cast(ntotal); - size_t startRow = static_cast(atomOffset); - size_t nAtomsLocal = static_cast(nme); - size_t nColumns = static_cast(size_one); - internal->varAtoms.SetShape({nAtomsGlobal, nColumns}); - internal->varAtoms.SetSelection({{startRow, 0}, {nAtomsLocal, nColumns}}); - - // insure buf is sized for packing - // adios does not limit per-process data size so nme*size_one is not - // constrained to int - // if sorting on IDs also request ID list from pack() - // sort buf as needed - - if (nme > maxbuf) { - maxbuf = nme; - memory->destroy(buf); - memory->create(buf, (maxbuf * size_one), "dump:buf"); - } - if (sort_flag && sortcol == 0 && nme > maxids) { - maxids = nme; - memory->destroy(ids); - memory->create(ids, maxids, "dump:ids"); - } - - if (sort_flag && sortcol == 0) - pack(ids); - else - pack(nullptr); - if (sort_flag) - sort(); - - openfile(); - internal->fh.BeginStep(); - // write info on data as scalars (by me==0) - if (me == 0) { - internal->fh.Put("ntimestep", update->ntimestep); - internal->fh.Put("nprocs", nprocs); - - internal->fh.Put("boxxlo", boxxlo); - internal->fh.Put("boxxhi", boxxhi); - internal->fh.Put("boxylo", boxylo); - internal->fh.Put("boxyhi", boxyhi); - internal->fh.Put("boxzlo", boxzlo); - internal->fh.Put("boxzhi", boxzhi); - - if (domain->triclinic) { - internal->fh.Put("boxxy", boxxy); - internal->fh.Put("boxxz", boxxz); - internal->fh.Put("boxyz", boxyz); - } - } - // Everyone needs to write scalar variables that are used as dimensions and - // offsets of arrays - internal->fh.Put("natoms", ntotal); - internal->fh.Put("ncolumns", size_one); - internal->fh.Put("nme", bnme); - internal->fh.Put("offset", atomOffset); - // now write the atoms - internal->fh.Put(internal->varAtoms, buf); - internal->fh.EndStep(); // I/O will happen now... - - if (multifile) { - internal->fh.Close(); - } + if (multifile) internal->fh.Close(); } /* ---------------------------------------------------------------------- */ void DumpAtomADIOS::init_style() { - if (image_flag == 0) - size_one = 5; - else - size_one = 8; + if (image_flag == 0) + size_one = 5; + else + size_one = 8; - // setup boundary string + // setup boundary string - domain->boundary_string(boundstr); + domain->boundary_string(boundstr); - // remove % from filename since ADIOS always writes a global file with - // data/metadata - int len = strlen(filename); - char *ptr = strchr(filename, '%'); - if (ptr) { - *ptr = '\0'; - char *s = new char[len - 1]; - snprintf(s, sizeof(s), "%s%s", filename, ptr + 1); - strncpy(filename, s, len); + // remove % from filename since ADIOS always writes a global file with + // data/metadata. + char *ptr = strchr(filename, '%'); + if (ptr) { + while (*ptr) { + ptr[0] = ptr[1]; + ++ptr; } + } - // setup column string + // setup column string - std::vector columnNames; + std::vector columnNames; - if (scale_flag == 0 && image_flag == 0) { - columns = (char *)"id type x y z"; - columnNames = {"id", "type", "x", "y", "z"}; - } else if (scale_flag == 0 && image_flag == 1) { - columns = (char *)"id type x y z ix iy iz"; - columnNames = {"id", "type", "x", "y", "z", "ix", "iy", "iz"}; - } else if (scale_flag == 1 && image_flag == 0) { - columns = (char *)"id type xs ys zs"; - columnNames = {"id", "type", "xs", "ys", "zs"}; - } else if (scale_flag == 1 && image_flag == 1) { - columns = (char *)"id type xs ys zs ix iy iz"; - columnNames = {"id", "type", "xs", "ys", "zs", "ix", "iy", "iz"}; - } + if (scale_flag == 0 && image_flag == 0) { + columns = (char *) "id type x y z"; + columnNames = {"id", "type", "x", "y", "z"}; + } else if (scale_flag == 0 && image_flag == 1) { + columns = (char *) "id type x y z ix iy iz"; + columnNames = {"id", "type", "x", "y", "z", "ix", "iy", "iz"}; + } else if (scale_flag == 1 && image_flag == 0) { + columns = (char *) "id type xs ys zs"; + columnNames = {"id", "type", "xs", "ys", "zs"}; + } else if (scale_flag == 1 && image_flag == 1) { + columns = (char *) "id type xs ys zs ix iy iz"; + columnNames = {"id", "type", "xs", "ys", "zs", "ix", "iy", "iz"}; + } - // setup function ptrs + // setup function ptrs - if (scale_flag == 1 && image_flag == 0 && domain->triclinic == 0) - pack_choice = &DumpAtomADIOS::pack_scale_noimage; - else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 0) - pack_choice = &DumpAtomADIOS::pack_scale_image; - else if (scale_flag == 1 && image_flag == 0 && domain->triclinic == 1) - pack_choice = &DumpAtomADIOS::pack_scale_noimage_triclinic; - else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 1) - pack_choice = &DumpAtomADIOS::pack_scale_image_triclinic; - else if (scale_flag == 0 && image_flag == 0) - pack_choice = &DumpAtomADIOS::pack_noscale_noimage; - else if (scale_flag == 0 && image_flag == 1) - pack_choice = &DumpAtomADIOS::pack_noscale_image; + if (scale_flag == 1 && image_flag == 0 && domain->triclinic == 0) + pack_choice = &DumpAtomADIOS::pack_scale_noimage; + else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 0) + pack_choice = &DumpAtomADIOS::pack_scale_image; + else if (scale_flag == 1 && image_flag == 0 && domain->triclinic == 1) + pack_choice = &DumpAtomADIOS::pack_scale_noimage_triclinic; + else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 1) + pack_choice = &DumpAtomADIOS::pack_scale_image_triclinic; + else if (scale_flag == 0 && image_flag == 0) + pack_choice = &DumpAtomADIOS::pack_noscale_noimage; + else if (scale_flag == 0 && image_flag == 1) + pack_choice = &DumpAtomADIOS::pack_noscale_image; - /* Define the group of variables for the atom style here since it's a fixed + /* Define the group of variables for the atom style here since it's a fixed * set */ - internal->io = internal->ad->DeclareIO(internal->ioName); - if (!internal->io.InConfigFile()) { - // if not defined by user, we can change the default settings - // BPFile is the default writer - internal->io.SetEngine("BPFile"); - int num_aggregators = multiproc; - if (num_aggregators == 0) - num_aggregators = 1; - char nstreams[128]; - snprintf(nstreams, sizeof(nstreams), "%d", num_aggregators); - internal->io.SetParameters({{"substreams", nstreams}}); - if (me == 0 && screen) - fprintf( - screen, - "ADIOS method for %s is n-to-m (aggregation with %s writers)\n", - filename, nstreams); - } + internal->io = internal->ad->DeclareIO(internal->ioName); + if (!internal->io.InConfigFile()) { + // if not defined by user, we can change the default settings + // BPFile is the default writer + internal->io.SetEngine("BPFile"); + int num_aggregators = multiproc; + if (num_aggregators == 0) num_aggregators = 1; + auto nstreams = std::to_string(num_aggregators); + internal->io.SetParameters({{"substreams", nstreams}}); + if (me == 0) + utils::logmesg(lmp, "ADIOS method for {} is n-to-m (aggregation with {} writers)\n", filename, + nstreams); + } - internal->io.DefineVariable("ntimestep"); - internal->io.DefineVariable("natoms"); + internal->io.DefineVariable("ntimestep"); + internal->io.DefineVariable("natoms"); - internal->io.DefineVariable("nprocs"); - internal->io.DefineVariable("ncolumns"); + internal->io.DefineVariable("nprocs"); + internal->io.DefineVariable("ncolumns"); - internal->io.DefineVariable("boxxlo"); - internal->io.DefineVariable("boxxhi"); - internal->io.DefineVariable("boxylo"); - internal->io.DefineVariable("boxyhi"); - internal->io.DefineVariable("boxzlo"); - internal->io.DefineVariable("boxzhi"); + internal->io.DefineVariable("boxxlo"); + internal->io.DefineVariable("boxxhi"); + internal->io.DefineVariable("boxylo"); + internal->io.DefineVariable("boxyhi"); + internal->io.DefineVariable("boxzlo"); + internal->io.DefineVariable("boxzhi"); - internal->io.DefineVariable("boxxy"); - internal->io.DefineVariable("boxxz"); - internal->io.DefineVariable("boxyz"); + internal->io.DefineVariable("boxxy"); + internal->io.DefineVariable("boxxz"); + internal->io.DefineVariable("boxyz"); - internal->io.DefineAttribute("triclinic", domain->triclinic); - internal->io.DefineAttribute("scaled", scale_flag); - internal->io.DefineAttribute("image", image_flag); + internal->io.DefineAttribute("triclinic", domain->triclinic); + internal->io.DefineAttribute("scaled", scale_flag); + internal->io.DefineAttribute("image", image_flag); - int *boundaryptr = reinterpret_cast(domain->boundary); - internal->io.DefineAttribute("boundary", boundaryptr, 6); + int *boundaryptr = reinterpret_cast(domain->boundary); + internal->io.DefineAttribute("boundary", boundaryptr, 6); - size_t nColumns = static_cast(size_one); - internal->io.DefineAttribute("columns", columnNames.data(), - nColumns); - internal->io.DefineAttribute("columnstr", columns); - internal->io.DefineAttribute("boundarystr", boundstr); - internal->io.DefineAttribute("LAMMPS/dump_style", "atom"); - internal->io.DefineAttribute("LAMMPS/version", - lmp->version); - internal->io.DefineAttribute("LAMMPS/num_ver", - std::to_string(lmp->num_ver)); + size_t nColumns = static_cast(size_one); + internal->io.DefineAttribute("columns", columnNames.data(), nColumns); + internal->io.DefineAttribute("columnstr", columns); + internal->io.DefineAttribute("boundarystr", boundstr); + internal->io.DefineAttribute("LAMMPS/dump_style", "atom"); + internal->io.DefineAttribute("LAMMPS/version", lmp->version); + internal->io.DefineAttribute("LAMMPS/num_ver", std::to_string(lmp->num_ver)); - internal->io.DefineVariable( - "nme", {adios2::LocalValueDim}); // local dimension variable - internal->io.DefineVariable( - "offset", {adios2::LocalValueDim}); // local dimension variable + // local dimension variables + internal->io.DefineVariable("nme", {adios2::LocalValueDim}); + internal->io.DefineVariable("offset", {adios2::LocalValueDim}); - // atom table size is not known at the moment - // it will be correctly defined at the moment of write - size_t UnknownSizeYet = 1; - internal->varAtoms = internal->io.DefineVariable( - "atoms", {UnknownSizeYet, nColumns}, {UnknownSizeYet, 0}, - {UnknownSizeYet, nColumns}); + // atom table size is not known at the moment + // it will be correctly defined at the moment of write + size_t UnknownSizeYet = 1; + internal->varAtoms = internal->io.DefineVariable( + "atoms", {UnknownSizeYet, nColumns}, {UnknownSizeYet, 0}, {UnknownSizeYet, nColumns}); } diff --git a/src/ADIOS/dump_custom_adios.cpp b/src/ADIOS/dump_custom_adios.cpp index 344c6ff6e9..a947f02d35 100644 --- a/src/ADIOS/dump_custom_adios.cpp +++ b/src/ADIOS/dump_custom_adios.cpp @@ -1,4 +1,3 @@ -// clang-format off /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://www.lammps.org/, Sandia National Laboratories @@ -17,152 +16,77 @@ ------------------------------------------------------------------------- */ #include "dump_custom_adios.h" + #include "atom.h" #include "compute.h" #include "domain.h" #include "error.h" #include "fix.h" -#include "force.h" -#include "group.h" #include "input.h" #include "memory.h" #include "modify.h" -#include "region.h" -#include "universe.h" #include "update.h" #include "variable.h" + #include #include #include "adios2.h" +#include "adios_common.h" using namespace LAMMPS_NS; -#define MAX_TEXT_HEADER_SIZE 4096 -#define DUMP_BUF_CHUNK_SIZE 16384 -#define DUMP_BUF_INCREMENT_SIZE 4096 +namespace LAMMPS_NS { +class DumpCustomADIOSInternal { -enum { - ID, - MOL, - TYPE, - ELEMENT, - MASS, - X, - Y, - Z, - XS, - YS, - ZS, - XSTRI, - YSTRI, - ZSTRI, - XU, - YU, - ZU, - XUTRI, - YUTRI, - ZUTRI, - XSU, - YSU, - ZSU, - XSUTRI, - YSUTRI, - ZSUTRI, - IX, - IY, - IZ, - VX, - VY, - VZ, - FX, - FY, - FZ, - Q, - MUX, - MUY, - MUZ, - MU, - RADIUS, - DIAMETER, - OMEGAX, - OMEGAY, - OMEGAZ, - ANGMOMX, - ANGMOMY, - ANGMOMZ, - TQX, - TQY, - TQZ, - SPIN, - ERADIUS, - ERVEL, - ERFORCE, - COMPUTE, - FIX, - VARIABLE + public: + DumpCustomADIOSInternal(){}; + ~DumpCustomADIOSInternal() = default; + + // name of adios group, referrable in adios2_config.xml + const std::string ioName = "custom"; + adios2::ADIOS *ad = nullptr; // adios object + adios2::IO io; // adios group of variables and attributes in this dump + adios2::Engine fh; // adios file/stream handle object + // one ADIOS output variable we need to change every step + adios2::Variable varAtoms; + // list of column names for the atom table + // (individual list of 'columns' string) + std::vector columnNames; }; -enum { LT, LE, GT, GE, EQ, NEQ }; -enum { INT, DOUBLE, STRING, BIGINT }; // same as in DumpCustom - -namespace LAMMPS_NS -{ -class DumpCustomADIOSInternal -{ - -public: - DumpCustomADIOSInternal() {}; - ~DumpCustomADIOSInternal() = default; - - // name of adios group, referrable in adios2_config.xml - const std::string ioName = "custom"; - adios2::ADIOS *ad = nullptr; // adios object - adios2::IO io; // adios group of variables and attributes in this dump - adios2::Engine fh; // adios file/stream handle object - // one ADIOS output variable we need to change every step - adios2::Variable varAtoms; - // list of column names for the atom table - // (individual list of 'columns' string) - std::vector columnNames; -}; -} // namespace LAMMPS_NS +} // namespace LAMMPS_NS /* ---------------------------------------------------------------------- */ -DumpCustomADIOS::DumpCustomADIOS(LAMMPS *lmp, int narg, char **arg) -: DumpCustom(lmp, narg, arg) +DumpCustomADIOS::DumpCustomADIOS(LAMMPS *lmp, int narg, char **arg) : DumpCustom(lmp, narg, arg) { - internal = new DumpCustomADIOSInternal(); - try { - internal->ad = - new adios2::ADIOS("adios2_config.xml", world, adios2::DebugON); - } catch (std::ios_base::failure &e) { - char str[256]; - snprintf(str, sizeof(str), "ADIOS initialization failed with error: %s", - e.what()); - error->one(FLERR, str); - } + // create a default adios2_config.xml if it doesn't exist yet. + FILE *cfgfp = fopen("adios2_config.xml", "r"); + if (!cfgfp) { + cfgfp = fopen("adios2_config.xml", "w"); + if (cfgfp) fputs(default_config, cfgfp); + } + if (cfgfp) fclose(cfgfp); - // if (screen) fprintf(screen, "DumpCustomADIOS constructor: nvariable=%d - // id_variable=%p, variables=%p, nfield=%d, earg=%p\n", nvariable, - // id_variable, variable, nfield, earg); - internal->columnNames.reserve(nfield); - for (int i = 0; i < nfield; ++i) { - internal->columnNames.push_back(earg[i]); - // if (screen) fprintf(screen, "earg[%d] = '%s'\n", i, earg[i]); - } + internal = new DumpCustomADIOSInternal(); + try { + internal->ad = new adios2::ADIOS("adios2_config.xml", world, adios2::DebugON); + } catch (std::ios_base::failure &e) { + error->all(FLERR, "ADIOS initialization failed with error: {}", e.what()); + } + + internal->columnNames.reserve(nfield); + for (int i = 0; i < nfield; ++i) { internal->columnNames.push_back(earg[i]); } } /* ---------------------------------------------------------------------- */ DumpCustomADIOS::~DumpCustomADIOS() { - internal->columnNames.clear(); - if (internal->fh) { - internal->fh.Close(); - } - delete internal->ad; - delete internal; + internal->columnNames.clear(); + if (internal->fh) { internal->fh.Close(); } + delete internal->ad; + delete internal; } /* ---------------------------------------------------------------------- */ @@ -211,233 +135,214 @@ void DumpCustomADIOS::openfile() void DumpCustomADIOS::write() { - if (domain->triclinic == 0) { - boxxlo = domain->boxlo[0]; - boxxhi = domain->boxhi[0]; - boxylo = domain->boxlo[1]; - boxyhi = domain->boxhi[1]; - boxzlo = domain->boxlo[2]; - boxzhi = domain->boxhi[2]; - } else { - boxxlo = domain->boxlo_bound[0]; - boxxhi = domain->boxhi_bound[0]; - boxylo = domain->boxlo_bound[1]; - boxyhi = domain->boxhi_bound[1]; - boxzlo = domain->boxlo_bound[2]; - boxzhi = domain->boxhi_bound[2]; - boxxy = domain->xy; - boxxz = domain->xz; - boxyz = domain->yz; + if (domain->triclinic == 0) { + boxxlo = domain->boxlo[0]; + boxxhi = domain->boxhi[0]; + boxylo = domain->boxlo[1]; + boxyhi = domain->boxhi[1]; + boxzlo = domain->boxlo[2]; + boxzhi = domain->boxhi[2]; + } else { + boxxlo = domain->boxlo_bound[0]; + boxxhi = domain->boxhi_bound[0]; + boxylo = domain->boxlo_bound[1]; + boxyhi = domain->boxhi_bound[1]; + boxzlo = domain->boxlo_bound[2]; + boxzhi = domain->boxhi_bound[2]; + boxxy = domain->xy; + boxxz = domain->xz; + boxyz = domain->yz; + } + + // nme = # of dump lines this proc contributes to dump + + nme = count(); + + // ntotal = total # of atoms in snapshot + // atomOffset = sum of # of atoms up to this proc (exclusive prefix sum) + + bigint bnme = nme; + MPI_Allreduce(&bnme, &ntotal, 1, MPI_LMP_BIGINT, MPI_SUM, world); + + bigint atomOffset; // sum of all atoms on processes 0..me-1 + MPI_Scan(&bnme, &atomOffset, 1, MPI_LMP_BIGINT, MPI_SUM, world); + atomOffset -= nme; // exclusive prefix sum needed + + // Now we know the global size and the local subset size and offset + // of the atoms table + size_t nAtomsGlobal = static_cast(ntotal); + size_t startRow = static_cast(atomOffset); + size_t nAtomsLocal = static_cast(nme); + size_t nColumns = static_cast(size_one); + internal->varAtoms.SetShape({nAtomsGlobal, nColumns}); + internal->varAtoms.SetSelection({{startRow, 0}, {nAtomsLocal, nColumns}}); + + // insure filewriter proc can receive everyone's info + // limit nmax*size_one to int since used as arg in MPI_Rsend() below + // pack my data into buf + // if sorting on IDs also request ID list from pack() + // sort buf as needed + + if (nme > maxbuf) { + if ((bigint) nme * size_one > MAXSMALLINT) error->all(FLERR, "Too much per-proc info for dump"); + maxbuf = nme; + memory->destroy(buf); + memory->create(buf, (maxbuf * size_one), "dump:buf"); + } + if (sort_flag && sortcol == 0 && nme > maxids) { + maxids = nme; + memory->destroy(ids); + memory->create(ids, maxids, "dump:ids"); + } + + if (sort_flag && sortcol == 0) + pack(ids); + else + pack(nullptr); + if (sort_flag) sort(); + + openfile(); + internal->fh.BeginStep(); + // write info on data as scalars (by me==0) + if (me == 0) { + internal->fh.Put("ntimestep", update->ntimestep); + internal->fh.Put("nprocs", nprocs); + + internal->fh.Put("boxxlo", boxxlo); + internal->fh.Put("boxxhi", boxxhi); + internal->fh.Put("boxylo", boxylo); + internal->fh.Put("boxyhi", boxyhi); + internal->fh.Put("boxzlo", boxzlo); + internal->fh.Put("boxzhi", boxzhi); + + if (domain->triclinic) { + internal->fh.Put("boxxy", boxxy); + internal->fh.Put("boxxz", boxxz); + internal->fh.Put("boxyz", boxyz); } + } + // Everyone needs to write scalar variables that are used as dimensions and + // offsets of arrays + internal->fh.Put("natoms", ntotal); + internal->fh.Put("ncolumns", size_one); + internal->fh.Put("nme", bnme); + internal->fh.Put("offset", atomOffset); + // now write the atoms + internal->fh.Put("atoms", buf); + internal->fh.EndStep(); // I/O will happen now... - // nme = # of dump lines this proc contributes to dump - - nme = count(); - - // ntotal = total # of atoms in snapshot - // atomOffset = sum of # of atoms up to this proc (exclusive prefix sum) - - bigint bnme = nme; - MPI_Allreduce(&bnme, &ntotal, 1, MPI_LMP_BIGINT, MPI_SUM, world); - - bigint atomOffset; // sum of all atoms on processes 0..me-1 - MPI_Scan(&bnme, &atomOffset, 1, MPI_LMP_BIGINT, MPI_SUM, world); - atomOffset -= nme; // exclusive prefix sum needed - - // Now we know the global size and the local subset size and offset - // of the atoms table - size_t nAtomsGlobal = static_cast(ntotal); - size_t startRow = static_cast(atomOffset); - size_t nAtomsLocal = static_cast(nme); - size_t nColumns = static_cast(size_one); - internal->varAtoms.SetShape({nAtomsGlobal, nColumns}); - internal->varAtoms.SetSelection({{startRow, 0}, {nAtomsLocal, nColumns}}); - - // insure filewriter proc can receive everyone's info - // limit nmax*size_one to int since used as arg in MPI_Rsend() below - // pack my data into buf - // if sorting on IDs also request ID list from pack() - // sort buf as needed - - if (nme > maxbuf) { - if ((bigint)nme * size_one > MAXSMALLINT) - error->all(FLERR, "Too much per-proc info for dump"); - maxbuf = nme; - memory->destroy(buf); - memory->create(buf, (maxbuf * size_one), "dump:buf"); - } - if (sort_flag && sortcol == 0 && nme > maxids) { - maxids = nme; - memory->destroy(ids); - memory->create(ids, maxids, "dump:ids"); - } - - if (sort_flag && sortcol == 0) - pack(ids); - else - pack(nullptr); - if (sort_flag) - sort(); - - openfile(); - internal->fh.BeginStep(); - // write info on data as scalars (by me==0) - if (me == 0) { - internal->fh.Put("ntimestep", update->ntimestep); - internal->fh.Put("nprocs", nprocs); - - internal->fh.Put("boxxlo", boxxlo); - internal->fh.Put("boxxhi", boxxhi); - internal->fh.Put("boxylo", boxylo); - internal->fh.Put("boxyhi", boxyhi); - internal->fh.Put("boxzlo", boxzlo); - internal->fh.Put("boxzhi", boxzhi); - - if (domain->triclinic) { - internal->fh.Put("boxxy", boxxy); - internal->fh.Put("boxxz", boxxz); - internal->fh.Put("boxyz", boxyz); - } - } - // Everyone needs to write scalar variables that are used as dimensions and - // offsets of arrays - internal->fh.Put("natoms", ntotal); - internal->fh.Put("ncolumns", size_one); - internal->fh.Put("nme", bnme); - internal->fh.Put("offset", atomOffset); - // now write the atoms - internal->fh.Put("atoms", buf); - internal->fh.EndStep(); // I/O will happen now... - - if (multifile) { - internal->fh.Close(); - } + if (multifile) { internal->fh.Close(); } } /* ---------------------------------------------------------------------- */ void DumpCustomADIOS::init_style() { + // setup boundary string - // setup boundary string + domain->boundary_string(boundstr); - domain->boundary_string(boundstr); - - // remove % from filename since ADIOS always writes a global file with - // data/metadata - int len = strlen(filename); - char *ptr = strchr(filename, '%'); - if (ptr) { - *ptr = '\0'; - char *s = new char[len - 1]; - sprintf(s, "%s%s", filename, ptr + 1); - strncpy(filename, s, len); + // remove % from filename since ADIOS always writes a global file with + // data/metadata + char *ptr = strchr(filename, '%'); + if (ptr) { + while (*ptr) { + ptr[0] = ptr[1]; + ++ptr; } + } - /* The next four loops are copied from dump_custom_mpiio, but nothing is - * done with them. - * It is unclear why we need them here. - * For metadata, variable[] will be written out as an ADIOS attribute if - * nvariable>0 - */ - // find current ptr for each compute,fix,variable - // check that fix frequency is acceptable - int icompute; - for (int i = 0; i < ncompute; i++) { - icompute = modify->find_compute(id_compute[i]); - if (icompute < 0) - error->all(FLERR, "Could not find dump custom compute ID"); - compute[i] = modify->compute[icompute]; - } + /* The next four loops are copied from dump_custom_mpiio, but nothing is + * done with them. + * It is unclear why we need them here. + * For metadata, variable[] will be written out as an ADIOS attribute if + * nvariable>0 + */ + // find current ptr for each compute,fix,variable + // check that fix frequency is acceptable + int icompute; + for (int i = 0; i < ncompute; i++) { + icompute = modify->find_compute(id_compute[i]); + if (icompute < 0) error->all(FLERR, "Could not find dump custom compute ID"); + compute[i] = modify->compute[icompute]; + } - int ifix; - for (int i = 0; i < nfix; i++) { - ifix = modify->find_fix(id_fix[i]); - if (ifix < 0) - error->all(FLERR, "Could not find dump custom fix ID"); - fix[i] = modify->fix[ifix]; - if (nevery % modify->fix[ifix]->peratom_freq) - error->all(FLERR, - "Dump custom and fix not computed at compatible times"); - } + int ifix; + for (int i = 0; i < nfix; i++) { + ifix = modify->find_fix(id_fix[i]); + if (ifix < 0) error->all(FLERR, "Could not find dump custom fix ID"); + fix[i] = modify->fix[ifix]; + if (nevery % modify->fix[ifix]->peratom_freq) + error->all(FLERR, "Dump custom and fix not computed at compatible times"); + } - int ivariable; - for (int i = 0; i < nvariable; i++) { - ivariable = input->variable->find(id_variable[i]); - if (ivariable < 0) - error->all(FLERR, "Could not find dump custom variable name"); - variable[i] = ivariable; - } + int ivariable; + for (int i = 0; i < nvariable; i++) { + ivariable = input->variable->find(id_variable[i]); + if (ivariable < 0) error->all(FLERR, "Could not find dump custom variable name"); + variable[i] = ivariable; + } - // set index and check validity of region - if (iregion >= 0) { - iregion = domain->find_region(idregion); - if (iregion == -1) - error->all(FLERR, "Region ID for dump custom does not exist"); - } + // set index and check validity of region + if (iregion >= 0) { + iregion = domain->find_region(idregion); + if (iregion == -1) error->all(FLERR, "Region ID for dump custom does not exist"); + } - /* Define the group of variables for the atom style here since it's a fixed - * set */ - internal->io = internal->ad->DeclareIO(internal->ioName); - if (!internal->io.InConfigFile()) { - // if not defined by user, we can change the default settings - // BPFile is the default writer - internal->io.SetEngine("BPFile"); - int num_aggregators = multiproc; - if (num_aggregators == 0) - num_aggregators = 1; - char nstreams[128]; - sprintf(nstreams, "%d", num_aggregators); - internal->io.SetParameters({{"substreams", nstreams}}); - if (me == 0 && screen) - fprintf( - screen, - "ADIOS method for %s is n-to-m (aggregation with %s writers)\n", - filename, nstreams); - } + /* Define the group of variables for the atom style here since it's a fixed + * set */ + internal->io = internal->ad->DeclareIO(internal->ioName); + if (!internal->io.InConfigFile()) { + // if not defined by user, we can change the default settings + // BPFile is the default writer + internal->io.SetEngine("BPFile"); + int num_aggregators = multiproc; + if (num_aggregators == 0) num_aggregators = 1; + auto nstreams = std::to_string(num_aggregators); + internal->io.SetParameters({{"substreams", nstreams}}); + if (me == 0) + utils::logmesg(lmp, "ADIOS method for {} is n-to-m (aggregation with {} writers)\n", filename, + nstreams); + } - internal->io.DefineVariable("ntimestep"); - internal->io.DefineVariable("natoms"); + internal->io.DefineVariable("ntimestep"); + internal->io.DefineVariable("natoms"); - internal->io.DefineVariable("nprocs"); - internal->io.DefineVariable("ncolumns"); + internal->io.DefineVariable("nprocs"); + internal->io.DefineVariable("ncolumns"); - internal->io.DefineVariable("boxxlo"); - internal->io.DefineVariable("boxxhi"); - internal->io.DefineVariable("boxylo"); - internal->io.DefineVariable("boxyhi"); - internal->io.DefineVariable("boxzlo"); - internal->io.DefineVariable("boxzhi"); + internal->io.DefineVariable("boxxlo"); + internal->io.DefineVariable("boxxhi"); + internal->io.DefineVariable("boxylo"); + internal->io.DefineVariable("boxyhi"); + internal->io.DefineVariable("boxzlo"); + internal->io.DefineVariable("boxzhi"); - internal->io.DefineVariable("boxxy"); - internal->io.DefineVariable("boxxz"); - internal->io.DefineVariable("boxyz"); + internal->io.DefineVariable("boxxy"); + internal->io.DefineVariable("boxxz"); + internal->io.DefineVariable("boxyz"); - internal->io.DefineAttribute("triclinic", domain->triclinic); + internal->io.DefineAttribute("triclinic", domain->triclinic); - int *boundaryptr = reinterpret_cast(domain->boundary); - internal->io.DefineAttribute("boundary", boundaryptr, 6); + int *boundaryptr = reinterpret_cast(domain->boundary); + internal->io.DefineAttribute("boundary", boundaryptr, 6); - size_t nColumns = static_cast(size_one); - internal->io.DefineAttribute( - "columns", internal->columnNames.data(), nColumns); - internal->io.DefineAttribute("columnstr", columns); - internal->io.DefineAttribute("boundarystr", boundstr); - internal->io.DefineAttribute("LAMMPS/dump_style", "custom"); - internal->io.DefineAttribute("LAMMPS/version", - lmp->version); - internal->io.DefineAttribute("LAMMPS/num_ver", - std::to_string(lmp->num_ver)); + size_t nColumns = static_cast(size_one); + internal->io.DefineAttribute("columns", internal->columnNames.data(), nColumns); + internal->io.DefineAttribute("columnstr", columns); + internal->io.DefineAttribute("boundarystr", boundstr); + internal->io.DefineAttribute("LAMMPS/dump_style", "custom"); + internal->io.DefineAttribute("LAMMPS/version", lmp->version); + internal->io.DefineAttribute("LAMMPS/num_ver", std::to_string(lmp->num_ver)); - internal->io.DefineVariable( - "nme", {adios2::LocalValueDim}); // local dimension variable - internal->io.DefineVariable( - "offset", {adios2::LocalValueDim}); // local dimension variable + internal->io.DefineVariable("nme", + {adios2::LocalValueDim}); // local dimension variable + internal->io.DefineVariable("offset", + {adios2::LocalValueDim}); // local dimension variable - // atom table size is not known at the moment - // it will be correctly defined at the moment of write - size_t UnknownSizeYet = 1; - internal->varAtoms = internal->io.DefineVariable( - "atoms", {UnknownSizeYet, nColumns}, {UnknownSizeYet, 0}, - {UnknownSizeYet, nColumns}); + // atom table size is not known at the moment + // it will be correctly defined at the moment of write + size_t UnknownSizeYet = 1; + internal->varAtoms = internal->io.DefineVariable( + "atoms", {UnknownSizeYet, nColumns}, {UnknownSizeYet, 0}, {UnknownSizeYet, nColumns}); } diff --git a/src/ADIOS/reader_adios.cpp b/src/ADIOS/reader_adios.cpp index 04c0fed9eb..6b017599f2 100644 --- a/src/ADIOS/reader_adios.cpp +++ b/src/ADIOS/reader_adios.cpp @@ -1,4 +1,3 @@ -// clang-format off /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator https://www.lammps.org/, Sandia National Laboratories @@ -17,20 +16,20 @@ ------------------------------------------------------------------------- */ #include "reader_adios.h" + #include "comm.h" #include "error.h" #include "memory.h" + #include #include #include #include "adios2.h" -#include "math_const.h" +#include "adios_common.h" using namespace LAMMPS_NS; -using namespace MathConst; - // also in read_dump.cpp enum { ID, TYPE, X, Y, Z, VX, VY, VZ, Q, IX, IY, IZ, FX, FY, FZ }; @@ -38,78 +37,69 @@ enum { UNSET, NOSCALE_NOWRAP, NOSCALE_WRAP, SCALE_NOWRAP, SCALE_WRAP }; #define SMALL 1.0e-6 -// true if the difference between two floats is "small". -// cannot use fabsf() since it is not fully portable. -static bool is_smalldiff(const float &val1, const float &val2) -{ - return (fabs(static_cast(val1 - val2)) < SMALL); -} +namespace LAMMPS_NS { +class ReadADIOSInternal { -namespace LAMMPS_NS -{ -class ReadADIOSInternal -{ + public: + ReadADIOSInternal(){}; + ~ReadADIOSInternal() = default; -public: - ReadADIOSInternal() {}; - ~ReadADIOSInternal() = default; - - // name of adios group, referrable in adios2_config.xml - const std::string ioName = "read_dump"; - adios2::ADIOS *ad = nullptr; // adios object - adios2::IO io; // adios group of variables and attributes in this dump - adios2::Engine fh; // adios file/stream handle object - // ADIOS input variables we need to change every step - adios2::Variable varNtimestep; - adios2::Variable varNatoms; - adios2::Variable varAtoms; - // list of column names for the atom table - // (individual list of 'columns' string) - std::vector columnNames; - float timeout = 0.0; + // name of adios group, referrable in adios2_config.xml + const std::string ioName = "read_dump"; + adios2::ADIOS *ad = nullptr; // adios object + adios2::IO io; // adios group of variables and attributes in this dump + adios2::Engine fh; // adios file/stream handle object + // ADIOS input variables we need to change every step + adios2::Variable varNtimestep; + adios2::Variable varNatoms; + adios2::Variable varAtoms; + // list of column names for the atom table + // (individual list of 'columns' string) + std::vector columnNames; + float timeout = 0.0; }; -} // namespace LAMMPS_NS +} // namespace LAMMPS_NS /* ---------------------------------------------------------------------- */ ReaderADIOS::ReaderADIOS(LAMMPS *lmp) : Reader(lmp) { - fieldindex = nullptr; - nAtoms = 0; - nAtomsTotal = 0; - atomOffset = 0; - nstep = 0; - nid = 0; - me = comm->me; + fieldindex = nullptr; + nAtoms = 0; + nAtomsTotal = 0; + atomOffset = 0; + nstep = 0; + nid = 0; + me = comm->me; - internal = new ReadADIOSInternal(); - try { - internal->ad = - new adios2::ADIOS("adios2_config.xml", world, adios2::DebugON); - } catch (std::ios_base::failure &e) { - char str[256]; - snprintf(str, sizeof(str), "ADIOS initialization failed with error: %s", - e.what()); - error->one(FLERR, str); - } + // create a default adios2_config.xml if it doesn't exist yet. + FILE *cfgfp = fopen("adios2_config.xml", "r"); + if (!cfgfp) { + cfgfp = fopen("adios2_config.xml", "w"); + if (cfgfp) fputs(default_config, cfgfp); + } + if (cfgfp) fclose(cfgfp); - /* Define the group holding all variables and attributes */ - internal->io = internal->ad->DeclareIO(internal->ioName); + internal = new ReadADIOSInternal(); + try { + internal->ad = new adios2::ADIOS("adios2_config.xml", world, adios2::DebugON); + } catch (std::ios_base::failure &e) { + error->one(FLERR, "ADIOS initialization failed with error: {}", e.what()); + } + + /* Define the group holding all variables and attributes */ + internal->io = internal->ad->DeclareIO(internal->ioName); } /* ---------------------------------------------------------------------- */ ReaderADIOS::~ReaderADIOS() { - if (me == 0) { - memory->destroy(fieldindex); - } - internal->columnNames.clear(); - if (internal->fh) { - internal->fh.Close(); - } - delete internal->ad; - delete internal; + if (me == 0) memory->destroy(fieldindex); + internal->columnNames.clear(); + if (internal->fh) internal->fh.Close(); + delete internal->ad; + delete internal; } /* ---------------------------------------------------------------------- @@ -118,23 +108,19 @@ ReaderADIOS::~ReaderADIOS() ------------------------------------------------------------------------- */ void ReaderADIOS::settings(int narg, char **arg) { - int idx = 0; - while (idx < narg) { - if (!strcmp(arg[idx], "timeout")) { - if (idx + 1 < narg) { - internal->timeout = std::stof(arg[idx + 1]); - internal->io.SetParameter("OpenTimeoutSecs", arg[idx + 1]); - ++idx; - } else { - char str[128]; - snprintf(str, sizeof(str), - "Missing value for 'timeout' option for ADIOS " - "read_dump command"); - error->one(FLERR, str); - } - } + int idx = 0; + while (idx < narg) { + if (!strcmp(arg[idx], "timeout")) { + if (idx + 1 < narg) { + internal->timeout = std::stof(arg[idx + 1]); + internal->io.SetParameter("OpenTimeoutSecs", arg[idx + 1]); ++idx; + } else { + error->one(FLERR, "Missing value for 'timeout' option for ADIOS read_dump command"); + } } + ++idx; + } } /* ---------------------------------------------------------------------- @@ -142,26 +128,17 @@ void ReaderADIOS::settings(int narg, char **arg) Every process must call this Collective operation ------------------------------------------------------------------------- */ -void ReaderADIOS::open_file(const char *file) +void ReaderADIOS::open_file(const std::string &file) { - int rv; - char str[1024]; + // close open file, if needed. + if (internal->fh) internal->fh.Close(); - // close open file, if needed. - if (internal->fh) - internal->fh.Close(); - - try { - internal->fh = internal->io.Open(file, adios2::Mode::Read, world); - } catch (std::ios_base::failure &e) { - char str[256]; - snprintf(str, sizeof(str), "%s", e.what()); - error->one(FLERR, str); - } - if (!internal->fh) { - snprintf(str, sizeof(str), "Cannot open file %s using ADIOS", file); - error->one(FLERR, str); - } + try { + internal->fh = internal->io.Open(file, adios2::Mode::Read, world); + } catch (std::ios_base::failure &e) { + error->one(FLERR, "Error opening file {}: {}", file, e.what()); + } + if (!internal->fh) error->one(FLERR, "Cannot open file {} using ADIOS", file); } /* ---------------------------------------------------------------------- @@ -171,10 +148,8 @@ void ReaderADIOS::open_file(const char *file) void ReaderADIOS::close_file() { - // close open file, if needed. - if (internal->fh) { - internal->fh.Close(); - } + // close open file, if needed. + if (internal->fh) { internal->fh.Close(); } } /* ---------------------------------------------------------------------- @@ -185,34 +160,24 @@ void ReaderADIOS::close_file() int ReaderADIOS::read_time(bigint &ntimestep) { - char str[1024]; + adios2::StepStatus status = internal->fh.BeginStep(adios2::StepMode::Read, internal->timeout); - adios2::StepStatus status = - internal->fh.BeginStep(adios2::StepMode::Read, internal->timeout); - - switch (status) { + switch (status) { case adios2::StepStatus::EndOfStream: case adios2::StepStatus::NotReady: case adios2::StepStatus::OtherError: - return 1; + return 1; default: - break; - } + break; + } - internal->varNtimestep = - internal->io.InquireVariable("ntimestep"); + internal->varNtimestep = internal->io.InquireVariable("ntimestep"); - if (!internal->varNtimestep) { - snprintf(str, sizeof(str), - "Did not find 'ntimestep' variable in ADIOS file %s", - internal->fh.Name().c_str()); - error->one(FLERR, str); - } + if (!internal->varNtimestep) + error->one(FLERR, "Did not find 'ntimestep' variable in ADIOS file {}", internal->fh.Name()); - ntimestep = static_cast(internal->varNtimestep.Max()); - // std::cerr << " **** ReaderADIOS::read_time found step " << ntimestep - // << " **** " << std::endl; - return 0; + ntimestep = static_cast(internal->varNtimestep.Max()); + return 0; } /* ---------------------------------------------------------------------- @@ -220,7 +185,10 @@ int ReaderADIOS::read_time(bigint &ntimestep) Called by all processors. ------------------------------------------------------------------------- */ -void ReaderADIOS::skip() { internal->fh.EndStep(); } +void ReaderADIOS::skip() +{ + internal->fh.EndStep(); +} /* ---------------------------------------------------------------------- read remaining header info: @@ -236,234 +204,205 @@ void ReaderADIOS::skip() { internal->fh.EndStep(); } only called by proc 0 ------------------------------------------------------------------------- */ -bigint ReaderADIOS::read_header(double box[3][3], int &boxinfo, int &triclinic, - int fieldinfo, int nfield, int *fieldtype, - char **fieldlabel, int scaleflag, int wrapflag, - int &fieldflag, int &xflag, int &yflag, - int &zflag) +bigint ReaderADIOS::read_header(double box[3][3], int &boxinfo, int &triclinic, int fieldinfo, + int nfield, int *fieldtype, char **fieldlabel, int scaleflag, + int wrapflag, int &fieldflag, int &xflag, int &yflag, int &zflag) { - char str[1024]; - nid = 0; + nid = 0; - // signal that we have no box info at all so far. + // signal that we have no box info at all so far. - internal->varNatoms = internal->io.InquireVariable("natoms"); - if (!internal->varNatoms) { - snprintf(str, sizeof(str), - "Did not find 'natoms' variable in ADIOS file %s", - internal->fh.Name().c_str()); - error->one(FLERR, str); + internal->varNatoms = internal->io.InquireVariable("natoms"); + if (!internal->varNatoms) + error->one(FLERR, "Did not find 'natoms' variable in ADIOS file {}", internal->fh.Name()); + + /* nAtoms */ + nAtomsTotal = internal->varNatoms.Max(); + uint64_t rem = nAtomsTotal % comm->nprocs; + nAtoms = nAtomsTotal / comm->nprocs; + atomOffset = comm->me * nAtoms; + if (comm->me < (int)rem) { + ++nAtoms; + atomOffset += comm->me; + } else { + atomOffset += rem; + } + + /* triclinic */ + adios2::Attribute attTriclinic = internal->io.InquireAttribute("triclinic"); + if (!attTriclinic) + error->one(FLERR, "Did not find 'triclinic' attribute in ADIOS file {}", internal->fh.Name()); + + triclinic = attTriclinic.Data()[0]; + + /* read Box */ + adios2::Variable varBoxxlo = internal->io.InquireVariable("boxxlo"); + adios2::Variable varBoxxhi = internal->io.InquireVariable("boxxhi"); + adios2::Variable varBoxylo = internal->io.InquireVariable("boxylo"); + adios2::Variable varBoxyhi = internal->io.InquireVariable("boxyhi"); + adios2::Variable varBoxzlo = internal->io.InquireVariable("boxzlo"); + adios2::Variable varBoxzhi = internal->io.InquireVariable("boxzhi"); + + box[0][0] = varBoxxlo.Max(); + box[0][1] = varBoxxhi.Max(); + box[0][2] = 0.0; + box[1][0] = varBoxylo.Max(); + box[1][1] = varBoxyhi.Max(); + box[1][2] = 0.0; + box[2][0] = varBoxzlo.Max(); + box[2][1] = varBoxzhi.Max(); + box[2][2] = 0.0; + + if (triclinic) { + adios2::Variable varBoxxy = internal->io.InquireVariable("boxxy"); + adios2::Variable varBoxxz = internal->io.InquireVariable("boxxz"); + adios2::Variable varBoxyz = internal->io.InquireVariable("boxyz"); + + box[0][2] = varBoxxy.Max(); + box[1][2] = varBoxxz.Max(); + box[2][2] = varBoxyz.Max(); + } + + boxinfo = 1; + + // if no field info requested, just return + + if (!fieldinfo) return nAtoms; + + memory->create(fieldindex, nfield, "read_dump:fieldindex"); + + /* Columns */ + adios2::Attribute attColumns = internal->io.InquireAttribute("columns"); + + std::vector labelVector = attColumns.Data(); + int nwords = labelVector.size(); + std::map labels; + for (int i = 0; i < nwords; ++i) { labels.emplace(labelVector[i], i); } + + int s_index, u_index, su_index; + xflag = UNSET; + yflag = UNSET; + zflag = UNSET; + + // copy fieldtype list for supported fields + + for (int i = 0; i < nfield; i++) { + if (fieldlabel[i]) { + fieldindex[i] = find_label(fieldlabel[i], labels); + if (fieldtype[i] == X) + xflag = 2 * scaleflag + wrapflag + 1; + else if (fieldtype[i] == Y) + yflag = 2 * scaleflag + wrapflag + 1; + else if (fieldtype[i] == Z) + zflag = 2 * scaleflag + wrapflag + 1; } - /* nAtoms */ - nAtomsTotal = internal->varNatoms.Max(); - uint64_t rem = nAtomsTotal % comm->nprocs; - nAtoms = nAtomsTotal / comm->nprocs; - atomOffset = comm->me * nAtoms; - if (comm->me < rem) { - ++nAtoms; - atomOffset += comm->me; - } else { - atomOffset += rem; - } + else if (fieldtype[i] == ID) + fieldindex[i] = find_label("id", labels); + else if (fieldtype[i] == TYPE) + fieldindex[i] = find_label("type", labels); - /* triclinic */ - adios2::Attribute attTriclinic = - internal->io.InquireAttribute("triclinic"); - if (!attTriclinic) { - snprintf(str, sizeof(str), - "Did not find 'triclinic' attribute in ADIOS file %s", - internal->fh.Name().c_str()); - error->one(FLERR, str); - } - - triclinic = attTriclinic.Data()[0]; - - /* read Box */ - adios2::Variable varBoxxlo = - internal->io.InquireVariable("boxxlo"); - adios2::Variable varBoxxhi = - internal->io.InquireVariable("boxxhi"); - adios2::Variable varBoxylo = - internal->io.InquireVariable("boxylo"); - adios2::Variable varBoxyhi = - internal->io.InquireVariable("boxyhi"); - adios2::Variable varBoxzlo = - internal->io.InquireVariable("boxzlo"); - adios2::Variable varBoxzhi = - internal->io.InquireVariable("boxzhi"); - - box[0][0] = varBoxxlo.Max(); - box[0][1] = varBoxxhi.Max(); - box[0][2] = 0.0; - box[1][0] = varBoxylo.Max(); - box[1][1] = varBoxyhi.Max(); - box[1][2] = 0.0; - box[2][0] = varBoxzlo.Max(); - box[2][1] = varBoxzhi.Max(); - box[2][2] = 0.0; - - if (triclinic) { - adios2::Variable varBoxxy = - internal->io.InquireVariable("boxxy"); - adios2::Variable varBoxxz = - internal->io.InquireVariable("boxxz"); - adios2::Variable varBoxyz = - internal->io.InquireVariable("boxyz"); - - box[0][2] = varBoxxy.Max(); - box[1][2] = varBoxxz.Max(); - box[2][2] = varBoxyz.Max(); - } - - boxinfo = 1; - - // if no field info requested, just return - - if (!fieldinfo) - return nAtoms; - - memory->create(fieldindex, nfield, "read_dump:fieldindex"); - - /* Columns */ - adios2::Attribute attColumns = - internal->io.InquireAttribute("columns"); - - std::vector labelVector = attColumns.Data(); - int nwords = labelVector.size(); - std::map labels; - for (int i = 0; i < nwords; ++i) { - labels.emplace(labelVector[i], i); - } - - int s_index, u_index, su_index; - xflag = UNSET; - yflag = UNSET; - zflag = UNSET; - - // copy fieldtype list for supported fields - - for (int i = 0; i < nfield; i++) { - if (fieldlabel[i]) { - fieldindex[i] = find_label(fieldlabel[i], labels); - if (fieldtype[i] == X) - xflag = 2 * scaleflag + wrapflag + 1; - else if (fieldtype[i] == Y) - yflag = 2 * scaleflag + wrapflag + 1; - else if (fieldtype[i] == Z) - zflag = 2 * scaleflag + wrapflag + 1; + else if (fieldtype[i] == X) { + fieldindex[i] = find_label("x", labels); + xflag = NOSCALE_WRAP; + if (fieldindex[i] < 0) { + fieldindex[i] = nwords; + s_index = find_label("xs", labels); + u_index = find_label("xu", labels); + su_index = find_label("xsu", labels); + if (s_index >= 0 && s_index < fieldindex[i]) { + fieldindex[i] = s_index; + xflag = SCALE_WRAP; } + if (u_index >= 0 && u_index < fieldindex[i]) { + fieldindex[i] = u_index; + xflag = NOSCALE_NOWRAP; + } + if (su_index >= 0 && su_index < fieldindex[i]) { + fieldindex[i] = su_index; + xflag = SCALE_NOWRAP; + } + } + if (fieldindex[i] == nwords) fieldindex[i] = -1; - else if (fieldtype[i] == ID) - fieldindex[i] = find_label("id", labels); - else if (fieldtype[i] == TYPE) - fieldindex[i] = find_label("type", labels); + } else if (fieldtype[i] == Y) { + fieldindex[i] = find_label("y", labels); + yflag = NOSCALE_WRAP; + if (fieldindex[i] < 0) { + fieldindex[i] = nwords; + s_index = find_label("ys", labels); + u_index = find_label("yu", labels); + su_index = find_label("ysu", labels); + if (s_index >= 0 && s_index < fieldindex[i]) { + fieldindex[i] = s_index; + yflag = SCALE_WRAP; + } + if (u_index >= 0 && u_index < fieldindex[i]) { + fieldindex[i] = u_index; + yflag = NOSCALE_NOWRAP; + } + if (su_index >= 0 && su_index < fieldindex[i]) { + fieldindex[i] = su_index; + yflag = SCALE_NOWRAP; + } + } + if (fieldindex[i] == nwords) fieldindex[i] = -1; - else if (fieldtype[i] == X) { - fieldindex[i] = find_label("x", labels); - xflag = NOSCALE_WRAP; - if (fieldindex[i] < 0) { - fieldindex[i] = nwords; - s_index = find_label("xs", labels); - u_index = find_label("xu", labels); - su_index = find_label("xsu", labels); - if (s_index >= 0 && s_index < fieldindex[i]) { - fieldindex[i] = s_index; - xflag = SCALE_WRAP; - } - if (u_index >= 0 && u_index < fieldindex[i]) { - fieldindex[i] = u_index; - xflag = NOSCALE_NOWRAP; - } - if (su_index >= 0 && su_index < fieldindex[i]) { - fieldindex[i] = su_index; - xflag = SCALE_NOWRAP; - } - } - if (fieldindex[i] == nwords) - fieldindex[i] = -1; + } else if (fieldtype[i] == Z) { + fieldindex[i] = find_label("z", labels); + zflag = NOSCALE_WRAP; + if (fieldindex[i] < 0) { + fieldindex[i] = nwords; + s_index = find_label("zs", labels); + u_index = find_label("zu", labels); + su_index = find_label("zsu", labels); + if (s_index >= 0 && s_index < fieldindex[i]) { + fieldindex[i] = s_index; + zflag = SCALE_WRAP; + } + if (u_index >= 0 && u_index < fieldindex[i]) { + fieldindex[i] = u_index; + zflag = NOSCALE_NOWRAP; + } + if (su_index >= 0 && su_index < fieldindex[i]) { + fieldindex[i] = su_index; + zflag = SCALE_NOWRAP; + } + } + if (fieldindex[i] == nwords) fieldindex[i] = -1; - } else if (fieldtype[i] == Y) { - fieldindex[i] = find_label("y", labels); - yflag = NOSCALE_WRAP; - if (fieldindex[i] < 0) { - fieldindex[i] = nwords; - s_index = find_label("ys", labels); - u_index = find_label("yu", labels); - su_index = find_label("ysu", labels); - if (s_index >= 0 && s_index < fieldindex[i]) { - fieldindex[i] = s_index; - yflag = SCALE_WRAP; - } - if (u_index >= 0 && u_index < fieldindex[i]) { - fieldindex[i] = u_index; - yflag = NOSCALE_NOWRAP; - } - if (su_index >= 0 && su_index < fieldindex[i]) { - fieldindex[i] = su_index; - yflag = SCALE_NOWRAP; - } - } - if (fieldindex[i] == nwords) - fieldindex[i] = -1; + } else if (fieldtype[i] == VX) + fieldindex[i] = find_label("vx", labels); + else if (fieldtype[i] == VY) + fieldindex[i] = find_label("vy", labels); + else if (fieldtype[i] == VZ) + fieldindex[i] = find_label("vz", labels); - } else if (fieldtype[i] == Z) { - fieldindex[i] = find_label("z", labels); - zflag = NOSCALE_WRAP; - if (fieldindex[i] < 0) { - fieldindex[i] = nwords; - s_index = find_label("zs", labels); - u_index = find_label("zu", labels); - su_index = find_label("zsu", labels); - if (s_index >= 0 && s_index < fieldindex[i]) { - fieldindex[i] = s_index; - zflag = SCALE_WRAP; - } - if (u_index >= 0 && u_index < fieldindex[i]) { - fieldindex[i] = u_index; - zflag = NOSCALE_NOWRAP; - } - if (su_index >= 0 && su_index < fieldindex[i]) { - fieldindex[i] = su_index; - zflag = SCALE_NOWRAP; - } - } - if (fieldindex[i] == nwords) - fieldindex[i] = -1; + else if (fieldtype[i] == FX) + fieldindex[i] = find_label("fx", labels); + else if (fieldtype[i] == FY) + fieldindex[i] = find_label("fy", labels); + else if (fieldtype[i] == FZ) + fieldindex[i] = find_label("fz", labels); - } else if (fieldtype[i] == VX) - fieldindex[i] = find_label("vx", labels); - else if (fieldtype[i] == VY) - fieldindex[i] = find_label("vy", labels); - else if (fieldtype[i] == VZ) - fieldindex[i] = find_label("vz", labels); + else if (fieldtype[i] == Q) + fieldindex[i] = find_label("q", labels); - else if (fieldtype[i] == FX) - fieldindex[i] = find_label("fx", labels); - else if (fieldtype[i] == FY) - fieldindex[i] = find_label("fy", labels); - else if (fieldtype[i] == FZ) - fieldindex[i] = find_label("fz", labels); + else if (fieldtype[i] == IX) + fieldindex[i] = find_label("ix", labels); + else if (fieldtype[i] == IY) + fieldindex[i] = find_label("iy", labels); + else if (fieldtype[i] == IZ) + fieldindex[i] = find_label("iz", labels); + } - else if (fieldtype[i] == Q) - fieldindex[i] = find_label("q", labels); + // set fieldflag = -1 if any unfound fields - else if (fieldtype[i] == IX) - fieldindex[i] = find_label("ix", labels); - else if (fieldtype[i] == IY) - fieldindex[i] = find_label("iy", labels); - else if (fieldtype[i] == IZ) - fieldindex[i] = find_label("iz", labels); - } + fieldflag = 0; + for (int i = 0; i < nfield; i++) + if (fieldindex[i] < 0) fieldflag = -1; - // set fieldflag = -1 if any unfound fields - - fieldflag = 0; - for (int i = 0; i < nfield; i++) - if (fieldindex[i] < 0) - fieldflag = -1; - - return nAtoms; + return nAtoms; } /* ---------------------------------------------------------------------- @@ -475,41 +414,33 @@ bigint ReaderADIOS::read_header(double box[3][3], int &boxinfo, int &triclinic, void ReaderADIOS::read_atoms(int n, int nfield, double **fields) { - char str[1024]; + /* Read Atoms */ + /* This is the firsts (and last) read of array data, so we + * call EndStep() here instead of PerformGets() + */ - /* Read Atoms */ - /* This is the firsts (and last) read of array data, so we - * call EndStep() here instead of PerformGets() - */ + adios2::Variable varAtoms = internal->io.InquireVariable("atoms"); - adios2::Variable varAtoms = - internal->io.InquireVariable("atoms"); + if ((uint64_t)n != nAtoms) + error->one(FLERR, + "ReaderADIOS::read_atoms() expects 'n={}' equal to the number of " + "atoms (={}) for process {} in ADIOS file {}.", + n, nAtoms, comm->me, internal->fh.Name()); - if (n != nAtoms) { - snprintf( - str, sizeof(str), - "ReaderADIOS::read_atoms() expects 'n=%d' equal to the number of " - "atoms (=%" PRIu64 ") for process %d in ADIOS file %s.", - n, nAtoms, comm->me, internal->fh.Name().c_str()); - error->one(FLERR, str); - } + size_t ncols = varAtoms.Count()[1]; + varAtoms.SetSelection({{atomOffset, 0}, {nAtoms, ncols}}); - size_t ncols = varAtoms.Count()[1]; - varAtoms.SetSelection({{atomOffset, 0}, {nAtoms, ncols}}); + std::vector table; - std::vector table; + internal->fh.Get(varAtoms, table); + // EndStep or PerformGets required to make the read happen + internal->fh.EndStep(); - internal->fh.Get(varAtoms, table); - // EndStep or PerformGets required to make the read happen - internal->fh.EndStep(); - - size_t idx; - for (int i = 0; i < nAtoms; i++) { - idx = i * ncols; - for (int m = 0; m < nfield; m++) { - fields[i][m] = table[idx + fieldindex[m]]; - } - } + size_t idx; + for (uint64_t i = 0; i < nAtoms; i++) { + idx = i * ncols; + for (int m = 0; m < nfield; m++) { fields[i][m] = table[idx + fieldindex[m]]; } + } } /* ---------------------------------------------------------------------- @@ -517,12 +448,9 @@ void ReaderADIOS::read_atoms(int n, int nfield, double **fields) return index of match or -1 if no match ------------------------------------------------------------------------- */ -int ReaderADIOS::find_label(const std::string &label, - const std::map &labels) +int ReaderADIOS::find_label(const std::string &label, const std::map &labels) { - std::map::const_iterator it = labels.find(label); - if (it != labels.end()) { - return it->second; - } - return -1; + std::map::const_iterator it = labels.find(label); + if (it != labels.end()) { return it->second; } + return -1; } diff --git a/src/ADIOS/reader_adios.h b/src/ADIOS/reader_adios.h index e59c677489..06616d94fd 100644 --- a/src/ADIOS/reader_adios.h +++ b/src/ADIOS/reader_adios.h @@ -44,7 +44,7 @@ class ReaderADIOS : public Reader { int &, int &, int &) override; void read_atoms(int, int, double **) override; - void open_file(const char *) override; + void open_file(const std::string &) override; void close_file() override; private: