update and improve ADIOS support

- modernize code
- remove dead code and unused definitions, enums, and includes
- create default adios2_config.xml file if it doesn't exist
- enable and apply clang-format
- update documentation
This commit is contained in:
Axel Kohlmeyer
2022-03-29 00:31:12 -04:00
parent 333e3b0491
commit b211f97efa
6 changed files with 787 additions and 924 deletions

View File

@ -35,13 +35,21 @@ Examples
Description Description
""""""""""" """""""""""
Dump a snapshot of atom coordinates every N timesteps in the Dump a snapshot of atom coordinates every N timesteps in the `ADIOS
`ADIOS <adios_>`_ based "BP" file format, or using different I/O solutions in ADIOS, <adios_>`_ based "BP" file format, or using different I/O solutions in
to a stream that can be read on-line by another program. ADIOS, to a stream that can be read on-line by another program.
ADIOS-BP files are binary, portable and self-describing. ADIOS-BP files are binary, portable and self-describing.
.. _adios: https://github.com/ornladios/ADIOS2 .. _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:** **Use from write_dump:**
It is possible to use these dump styles with the It is possible to use these dump styles with the

39
src/ADIOS/adios_common.h Normal file
View File

@ -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[] = "<?xml version=\"1.0\"?>\n"
"<adios-config>\n"
" <io name=\"atom\">\n"
" <engine type=\"BP4\">\n"
" <parameter key=\"substreams\" value=\"1\"/>\n"
" </engine>\n"
" </io>\n"
" <io name=\"custom\">\n"
" <engine type=\"BP4\">\n"
" <parameter key=\"substreams\" value=\"1\"/>\n"
" </engine>\n"
" </io>\n"
" <io name=\"read_dump\">\n"
" <engine type=\"BP4\">\n"
" </engine>\n"
" </io>\n"
"</adios-config>\n";
#endif

View File

@ -1,4 +1,3 @@
// clang-format off
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, Sandia National Laboratories https://www.lammps.org/, Sandia National Laboratories
@ -24,61 +23,58 @@
#include "memory.h" #include "memory.h"
#include "universe.h" #include "universe.h"
#include "update.h" #include "update.h"
#include <cstring> #include <cstring>
#include "adios2.h" #include "adios2.h"
#include "adios_common.h"
using namespace LAMMPS_NS; using namespace LAMMPS_NS;
#define MAX_TEXT_HEADER_SIZE 4096 namespace LAMMPS_NS {
#define DUMP_BUF_CHUNK_SIZE 16384 class DumpAtomADIOSInternal {
#define DUMP_BUF_INCREMENT_SIZE 4096
namespace LAMMPS_NS public:
{ DumpAtomADIOSInternal(){};
class DumpAtomADIOSInternal ~DumpAtomADIOSInternal() = default;
{
public: // name of adios group, referrable in adios2_config.xml
DumpAtomADIOSInternal() {}; const std::string ioName = "atom";
~DumpAtomADIOSInternal() = default; adios2::ADIOS *ad = nullptr; // adios object
adios2::IO io; // adios group of variables and attributes in this dump
// name of adios group, referrable in adios2_config.xml adios2::Engine fh; // adios file/stream handle object
const std::string ioName = "atom"; // one ADIOS output variable we need to change every step
adios2::ADIOS *ad = nullptr; // adios object adios2::Variable<double> varAtoms;
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<double> varAtoms;
}; };
} // namespace LAMMPS_NS } // namespace LAMMPS_NS
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
DumpAtomADIOS::DumpAtomADIOS(LAMMPS *lmp, int narg, char **arg) DumpAtomADIOS::DumpAtomADIOS(LAMMPS *lmp, int narg, char **arg) : DumpAtom(lmp, narg, arg)
: DumpAtom(lmp, narg, arg)
{ {
internal = new DumpAtomADIOSInternal(); // create a default adios2_config.xml if it doesn't exist yet.
try { FILE *cfgfp = fopen("adios2_config.xml", "r");
internal->ad = if (!cfgfp) {
new adios2::ADIOS("adios2_config.xml", world, adios2::DebugON); cfgfp = fopen("adios2_config.xml", "w");
} catch (std::ios_base::failure &e) { if (cfgfp) fputs(default_config, cfgfp);
char str[256]; }
snprintf(str, sizeof(str), "ADIOS initialization failed with error: %s", if (cfgfp) fclose(cfgfp);
e.what());
error->one(FLERR, str); 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() DumpAtomADIOS::~DumpAtomADIOS()
{ {
if (internal->fh) { if (internal->fh) internal->fh.Close();
internal->fh.Close(); delete internal->ad;
} delete internal;
delete internal->ad;
delete internal;
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -129,228 +125,215 @@ void DumpAtomADIOS::openfile()
void DumpAtomADIOS::write() void DumpAtomADIOS::write()
{ {
if (domain->triclinic == 0) { if (domain->triclinic == 0) {
boxxlo = domain->boxlo[0]; boxxlo = domain->boxlo[0];
boxxhi = domain->boxhi[0]; boxxhi = domain->boxhi[0];
boxylo = domain->boxlo[1]; boxylo = domain->boxlo[1];
boxyhi = domain->boxhi[1]; boxyhi = domain->boxhi[1];
boxzlo = domain->boxlo[2]; boxzlo = domain->boxlo[2];
boxzhi = domain->boxhi[2]; boxzhi = domain->boxhi[2];
} else { } else {
boxxlo = domain->boxlo_bound[0]; boxxlo = domain->boxlo_bound[0];
boxxhi = domain->boxhi_bound[0]; boxxhi = domain->boxhi_bound[0];
boxylo = domain->boxlo_bound[1]; boxylo = domain->boxlo_bound[1];
boxyhi = domain->boxhi_bound[1]; boxyhi = domain->boxhi_bound[1];
boxzlo = domain->boxlo_bound[2]; boxzlo = domain->boxlo_bound[2];
boxzhi = domain->boxhi_bound[2]; boxzhi = domain->boxhi_bound[2];
boxxy = domain->xy; boxxy = domain->xy;
boxxz = domain->xz; boxxz = domain->xz;
boxyz = domain->yz; 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<size_t>(ntotal);
size_t startRow = static_cast<size_t>(atomOffset);
size_t nAtomsLocal = static_cast<size_t>(nme);
size_t nColumns = static_cast<size_t>(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<uint64_t>("ntimestep", update->ntimestep);
internal->fh.Put<int>("nprocs", nprocs);
internal->fh.Put<double>("boxxlo", boxxlo);
internal->fh.Put<double>("boxxhi", boxxhi);
internal->fh.Put<double>("boxylo", boxylo);
internal->fh.Put<double>("boxyhi", boxyhi);
internal->fh.Put<double>("boxzlo", boxzlo);
internal->fh.Put<double>("boxzhi", boxzhi);
if (domain->triclinic) {
internal->fh.Put<double>("boxxy", boxxy);
internal->fh.Put<double>("boxxz", boxxz);
internal->fh.Put<double>("boxyz", boxyz);
} }
}
// Everyone needs to write scalar variables that are used as dimensions and
// offsets of arrays
internal->fh.Put<uint64_t>("natoms", ntotal);
internal->fh.Put<int>("ncolumns", size_one);
internal->fh.Put<uint64_t>("nme", bnme);
internal->fh.Put<uint64_t>("offset", atomOffset);
// now write the atoms
internal->fh.Put<double>(internal->varAtoms, buf);
internal->fh.EndStep(); // I/O will happen now...
// nme = # of dump lines this proc contributes to dump if (multifile) internal->fh.Close();
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<size_t>(ntotal);
size_t startRow = static_cast<size_t>(atomOffset);
size_t nAtomsLocal = static_cast<size_t>(nme);
size_t nColumns = static_cast<size_t>(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<uint64_t>("ntimestep", update->ntimestep);
internal->fh.Put<int>("nprocs", nprocs);
internal->fh.Put<double>("boxxlo", boxxlo);
internal->fh.Put<double>("boxxhi", boxxhi);
internal->fh.Put<double>("boxylo", boxylo);
internal->fh.Put<double>("boxyhi", boxyhi);
internal->fh.Put<double>("boxzlo", boxzlo);
internal->fh.Put<double>("boxzhi", boxzhi);
if (domain->triclinic) {
internal->fh.Put<double>("boxxy", boxxy);
internal->fh.Put<double>("boxxz", boxxz);
internal->fh.Put<double>("boxyz", boxyz);
}
}
// Everyone needs to write scalar variables that are used as dimensions and
// offsets of arrays
internal->fh.Put<uint64_t>("natoms", ntotal);
internal->fh.Put<int>("ncolumns", size_one);
internal->fh.Put<uint64_t>("nme", bnme);
internal->fh.Put<uint64_t>("offset", atomOffset);
// now write the atoms
internal->fh.Put<double>(internal->varAtoms, buf);
internal->fh.EndStep(); // I/O will happen now...
if (multifile) {
internal->fh.Close();
}
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
void DumpAtomADIOS::init_style() void DumpAtomADIOS::init_style()
{ {
if (image_flag == 0) if (image_flag == 0)
size_one = 5; size_one = 5;
else else
size_one = 8; 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 // remove % from filename since ADIOS always writes a global file with
// data/metadata // data/metadata.
int len = strlen(filename); char *ptr = strchr(filename, '%');
char *ptr = strchr(filename, '%'); if (ptr) {
if (ptr) { while (*ptr) {
*ptr = '\0'; ptr[0] = ptr[1];
char *s = new char[len - 1]; ++ptr;
snprintf(s, sizeof(s), "%s%s", filename, ptr + 1);
strncpy(filename, s, len);
} }
}
// setup column string // setup column string
std::vector<std::string> columnNames; std::vector<std::string> columnNames;
if (scale_flag == 0 && image_flag == 0) { if (scale_flag == 0 && image_flag == 0) {
columns = (char *)"id type x y z"; columns = (char *) "id type x y z";
columnNames = {"id", "type", "x", "y", "z"}; columnNames = {"id", "type", "x", "y", "z"};
} else if (scale_flag == 0 && image_flag == 1) { } else if (scale_flag == 0 && image_flag == 1) {
columns = (char *)"id type x y z ix iy iz"; columns = (char *) "id type x y z ix iy iz";
columnNames = {"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) { } else if (scale_flag == 1 && image_flag == 0) {
columns = (char *)"id type xs ys zs"; columns = (char *) "id type xs ys zs";
columnNames = {"id", "type", "xs", "ys", "zs"}; columnNames = {"id", "type", "xs", "ys", "zs"};
} else if (scale_flag == 1 && image_flag == 1) { } else if (scale_flag == 1 && image_flag == 1) {
columns = (char *)"id type xs ys zs ix iy iz"; columns = (char *) "id type xs ys zs ix iy iz";
columnNames = {"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) if (scale_flag == 1 && image_flag == 0 && domain->triclinic == 0)
pack_choice = &DumpAtomADIOS::pack_scale_noimage; pack_choice = &DumpAtomADIOS::pack_scale_noimage;
else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 0) else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 0)
pack_choice = &DumpAtomADIOS::pack_scale_image; pack_choice = &DumpAtomADIOS::pack_scale_image;
else if (scale_flag == 1 && image_flag == 0 && domain->triclinic == 1) else if (scale_flag == 1 && image_flag == 0 && domain->triclinic == 1)
pack_choice = &DumpAtomADIOS::pack_scale_noimage_triclinic; pack_choice = &DumpAtomADIOS::pack_scale_noimage_triclinic;
else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 1) else if (scale_flag == 1 && image_flag == 1 && domain->triclinic == 1)
pack_choice = &DumpAtomADIOS::pack_scale_image_triclinic; pack_choice = &DumpAtomADIOS::pack_scale_image_triclinic;
else if (scale_flag == 0 && image_flag == 0) else if (scale_flag == 0 && image_flag == 0)
pack_choice = &DumpAtomADIOS::pack_noscale_noimage; pack_choice = &DumpAtomADIOS::pack_noscale_noimage;
else if (scale_flag == 0 && image_flag == 1) else if (scale_flag == 0 && image_flag == 1)
pack_choice = &DumpAtomADIOS::pack_noscale_image; 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 */ * set */
internal->io = internal->ad->DeclareIO(internal->ioName); internal->io = internal->ad->DeclareIO(internal->ioName);
if (!internal->io.InConfigFile()) { if (!internal->io.InConfigFile()) {
// if not defined by user, we can change the default settings // if not defined by user, we can change the default settings
// BPFile is the default writer // BPFile is the default writer
internal->io.SetEngine("BPFile"); internal->io.SetEngine("BPFile");
int num_aggregators = multiproc; int num_aggregators = multiproc;
if (num_aggregators == 0) if (num_aggregators == 0) num_aggregators = 1;
num_aggregators = 1; auto nstreams = std::to_string(num_aggregators);
char nstreams[128]; internal->io.SetParameters({{"substreams", nstreams}});
snprintf(nstreams, sizeof(nstreams), "%d", num_aggregators); if (me == 0)
internal->io.SetParameters({{"substreams", nstreams}}); utils::logmesg(lmp, "ADIOS method for {} is n-to-m (aggregation with {} writers)\n", filename,
if (me == 0 && screen) nstreams);
fprintf( }
screen,
"ADIOS method for %s is n-to-m (aggregation with %s writers)\n",
filename, nstreams);
}
internal->io.DefineVariable<uint64_t>("ntimestep"); internal->io.DefineVariable<uint64_t>("ntimestep");
internal->io.DefineVariable<uint64_t>("natoms"); internal->io.DefineVariable<uint64_t>("natoms");
internal->io.DefineVariable<int>("nprocs"); internal->io.DefineVariable<int>("nprocs");
internal->io.DefineVariable<int>("ncolumns"); internal->io.DefineVariable<int>("ncolumns");
internal->io.DefineVariable<double>("boxxlo"); internal->io.DefineVariable<double>("boxxlo");
internal->io.DefineVariable<double>("boxxhi"); internal->io.DefineVariable<double>("boxxhi");
internal->io.DefineVariable<double>("boxylo"); internal->io.DefineVariable<double>("boxylo");
internal->io.DefineVariable<double>("boxyhi"); internal->io.DefineVariable<double>("boxyhi");
internal->io.DefineVariable<double>("boxzlo"); internal->io.DefineVariable<double>("boxzlo");
internal->io.DefineVariable<double>("boxzhi"); internal->io.DefineVariable<double>("boxzhi");
internal->io.DefineVariable<double>("boxxy"); internal->io.DefineVariable<double>("boxxy");
internal->io.DefineVariable<double>("boxxz"); internal->io.DefineVariable<double>("boxxz");
internal->io.DefineVariable<double>("boxyz"); internal->io.DefineVariable<double>("boxyz");
internal->io.DefineAttribute<int>("triclinic", domain->triclinic); internal->io.DefineAttribute<int>("triclinic", domain->triclinic);
internal->io.DefineAttribute<int>("scaled", scale_flag); internal->io.DefineAttribute<int>("scaled", scale_flag);
internal->io.DefineAttribute<int>("image", image_flag); internal->io.DefineAttribute<int>("image", image_flag);
int *boundaryptr = reinterpret_cast<int *>(domain->boundary); int *boundaryptr = reinterpret_cast<int *>(domain->boundary);
internal->io.DefineAttribute<int>("boundary", boundaryptr, 6); internal->io.DefineAttribute<int>("boundary", boundaryptr, 6);
size_t nColumns = static_cast<size_t>(size_one); size_t nColumns = static_cast<size_t>(size_one);
internal->io.DefineAttribute<std::string>("columns", columnNames.data(), internal->io.DefineAttribute<std::string>("columns", columnNames.data(), nColumns);
nColumns); internal->io.DefineAttribute<std::string>("columnstr", columns);
internal->io.DefineAttribute<std::string>("columnstr", columns); internal->io.DefineAttribute<std::string>("boundarystr", boundstr);
internal->io.DefineAttribute<std::string>("boundarystr", boundstr); internal->io.DefineAttribute<std::string>("LAMMPS/dump_style", "atom");
internal->io.DefineAttribute<std::string>("LAMMPS/dump_style", "atom"); internal->io.DefineAttribute<std::string>("LAMMPS/version", lmp->version);
internal->io.DefineAttribute<std::string>("LAMMPS/version", internal->io.DefineAttribute<std::string>("LAMMPS/num_ver", std::to_string(lmp->num_ver));
lmp->version);
internal->io.DefineAttribute<std::string>("LAMMPS/num_ver",
std::to_string(lmp->num_ver));
internal->io.DefineVariable<uint64_t>( // local dimension variables
"nme", {adios2::LocalValueDim}); // local dimension variable internal->io.DefineVariable<uint64_t>("nme", {adios2::LocalValueDim});
internal->io.DefineVariable<uint64_t>( internal->io.DefineVariable<uint64_t>("offset", {adios2::LocalValueDim});
"offset", {adios2::LocalValueDim}); // local dimension variable
// atom table size is not known at the moment // atom table size is not known at the moment
// it will be correctly defined at the moment of write // it will be correctly defined at the moment of write
size_t UnknownSizeYet = 1; size_t UnknownSizeYet = 1;
internal->varAtoms = internal->io.DefineVariable<double>( internal->varAtoms = internal->io.DefineVariable<double>(
"atoms", {UnknownSizeYet, nColumns}, {UnknownSizeYet, 0}, "atoms", {UnknownSizeYet, nColumns}, {UnknownSizeYet, 0}, {UnknownSizeYet, nColumns});
{UnknownSizeYet, nColumns});
} }

View File

@ -1,4 +1,3 @@
// clang-format off
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, Sandia National Laboratories https://www.lammps.org/, Sandia National Laboratories
@ -17,152 +16,77 @@
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
#include "dump_custom_adios.h" #include "dump_custom_adios.h"
#include "atom.h" #include "atom.h"
#include "compute.h" #include "compute.h"
#include "domain.h" #include "domain.h"
#include "error.h" #include "error.h"
#include "fix.h" #include "fix.h"
#include "force.h"
#include "group.h"
#include "input.h" #include "input.h"
#include "memory.h" #include "memory.h"
#include "modify.h" #include "modify.h"
#include "region.h"
#include "universe.h"
#include "update.h" #include "update.h"
#include "variable.h" #include "variable.h"
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include "adios2.h" #include "adios2.h"
#include "adios_common.h"
using namespace LAMMPS_NS; using namespace LAMMPS_NS;
#define MAX_TEXT_HEADER_SIZE 4096 namespace LAMMPS_NS {
#define DUMP_BUF_CHUNK_SIZE 16384 class DumpCustomADIOSInternal {
#define DUMP_BUF_INCREMENT_SIZE 4096
enum { public:
ID, DumpCustomADIOSInternal(){};
MOL, ~DumpCustomADIOSInternal() = default;
TYPE,
ELEMENT, // name of adios group, referrable in adios2_config.xml
MASS, const std::string ioName = "custom";
X, adios2::ADIOS *ad = nullptr; // adios object
Y, adios2::IO io; // adios group of variables and attributes in this dump
Z, adios2::Engine fh; // adios file/stream handle object
XS, // one ADIOS output variable we need to change every step
YS, adios2::Variable<double> varAtoms;
ZS, // list of column names for the atom table
XSTRI, // (individual list of 'columns' string)
YSTRI, std::vector<std::string> columnNames;
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
}; };
enum { LT, LE, GT, GE, EQ, NEQ }; } // namespace LAMMPS_NS
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<double> varAtoms;
// list of column names for the atom table
// (individual list of 'columns' string)
std::vector<std::string> columnNames;
};
} // namespace LAMMPS_NS
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
DumpCustomADIOS::DumpCustomADIOS(LAMMPS *lmp, int narg, char **arg) DumpCustomADIOS::DumpCustomADIOS(LAMMPS *lmp, int narg, char **arg) : DumpCustom(lmp, narg, arg)
: DumpCustom(lmp, narg, arg)
{ {
internal = new DumpCustomADIOSInternal(); // create a default adios2_config.xml if it doesn't exist yet.
try { FILE *cfgfp = fopen("adios2_config.xml", "r");
internal->ad = if (!cfgfp) {
new adios2::ADIOS("adios2_config.xml", world, adios2::DebugON); cfgfp = fopen("adios2_config.xml", "w");
} catch (std::ios_base::failure &e) { if (cfgfp) fputs(default_config, cfgfp);
char str[256]; }
snprintf(str, sizeof(str), "ADIOS initialization failed with error: %s", if (cfgfp) fclose(cfgfp);
e.what());
error->one(FLERR, str);
}
// if (screen) fprintf(screen, "DumpCustomADIOS constructor: nvariable=%d internal = new DumpCustomADIOSInternal();
// id_variable=%p, variables=%p, nfield=%d, earg=%p\n", nvariable, try {
// id_variable, variable, nfield, earg); internal->ad = new adios2::ADIOS("adios2_config.xml", world, adios2::DebugON);
internal->columnNames.reserve(nfield); } catch (std::ios_base::failure &e) {
for (int i = 0; i < nfield; ++i) { error->all(FLERR, "ADIOS initialization failed with error: {}", e.what());
internal->columnNames.push_back(earg[i]); }
// if (screen) fprintf(screen, "earg[%d] = '%s'\n", i, earg[i]);
} internal->columnNames.reserve(nfield);
for (int i = 0; i < nfield; ++i) { internal->columnNames.push_back(earg[i]); }
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
DumpCustomADIOS::~DumpCustomADIOS() DumpCustomADIOS::~DumpCustomADIOS()
{ {
internal->columnNames.clear(); internal->columnNames.clear();
if (internal->fh) { if (internal->fh) { internal->fh.Close(); }
internal->fh.Close(); delete internal->ad;
} delete internal;
delete internal->ad;
delete internal;
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
@ -211,233 +135,214 @@ void DumpCustomADIOS::openfile()
void DumpCustomADIOS::write() void DumpCustomADIOS::write()
{ {
if (domain->triclinic == 0) { if (domain->triclinic == 0) {
boxxlo = domain->boxlo[0]; boxxlo = domain->boxlo[0];
boxxhi = domain->boxhi[0]; boxxhi = domain->boxhi[0];
boxylo = domain->boxlo[1]; boxylo = domain->boxlo[1];
boxyhi = domain->boxhi[1]; boxyhi = domain->boxhi[1];
boxzlo = domain->boxlo[2]; boxzlo = domain->boxlo[2];
boxzhi = domain->boxhi[2]; boxzhi = domain->boxhi[2];
} else { } else {
boxxlo = domain->boxlo_bound[0]; boxxlo = domain->boxlo_bound[0];
boxxhi = domain->boxhi_bound[0]; boxxhi = domain->boxhi_bound[0];
boxylo = domain->boxlo_bound[1]; boxylo = domain->boxlo_bound[1];
boxyhi = domain->boxhi_bound[1]; boxyhi = domain->boxhi_bound[1];
boxzlo = domain->boxlo_bound[2]; boxzlo = domain->boxlo_bound[2];
boxzhi = domain->boxhi_bound[2]; boxzhi = domain->boxhi_bound[2];
boxxy = domain->xy; boxxy = domain->xy;
boxxz = domain->xz; boxxz = domain->xz;
boxyz = domain->yz; 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<size_t>(ntotal);
size_t startRow = static_cast<size_t>(atomOffset);
size_t nAtomsLocal = static_cast<size_t>(nme);
size_t nColumns = static_cast<size_t>(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<uint64_t>("ntimestep", update->ntimestep);
internal->fh.Put<int>("nprocs", nprocs);
internal->fh.Put<double>("boxxlo", boxxlo);
internal->fh.Put<double>("boxxhi", boxxhi);
internal->fh.Put<double>("boxylo", boxylo);
internal->fh.Put<double>("boxyhi", boxyhi);
internal->fh.Put<double>("boxzlo", boxzlo);
internal->fh.Put<double>("boxzhi", boxzhi);
if (domain->triclinic) {
internal->fh.Put<double>("boxxy", boxxy);
internal->fh.Put<double>("boxxz", boxxz);
internal->fh.Put<double>("boxyz", boxyz);
} }
}
// Everyone needs to write scalar variables that are used as dimensions and
// offsets of arrays
internal->fh.Put<uint64_t>("natoms", ntotal);
internal->fh.Put<int>("ncolumns", size_one);
internal->fh.Put<uint64_t>("nme", bnme);
internal->fh.Put<uint64_t>("offset", atomOffset);
// now write the atoms
internal->fh.Put<double>("atoms", buf);
internal->fh.EndStep(); // I/O will happen now...
// nme = # of dump lines this proc contributes to dump if (multifile) { internal->fh.Close(); }
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<size_t>(ntotal);
size_t startRow = static_cast<size_t>(atomOffset);
size_t nAtomsLocal = static_cast<size_t>(nme);
size_t nColumns = static_cast<size_t>(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<uint64_t>("ntimestep", update->ntimestep);
internal->fh.Put<int>("nprocs", nprocs);
internal->fh.Put<double>("boxxlo", boxxlo);
internal->fh.Put<double>("boxxhi", boxxhi);
internal->fh.Put<double>("boxylo", boxylo);
internal->fh.Put<double>("boxyhi", boxyhi);
internal->fh.Put<double>("boxzlo", boxzlo);
internal->fh.Put<double>("boxzhi", boxzhi);
if (domain->triclinic) {
internal->fh.Put<double>("boxxy", boxxy);
internal->fh.Put<double>("boxxz", boxxz);
internal->fh.Put<double>("boxyz", boxyz);
}
}
// Everyone needs to write scalar variables that are used as dimensions and
// offsets of arrays
internal->fh.Put<uint64_t>("natoms", ntotal);
internal->fh.Put<int>("ncolumns", size_one);
internal->fh.Put<uint64_t>("nme", bnme);
internal->fh.Put<uint64_t>("offset", atomOffset);
// now write the atoms
internal->fh.Put<double>("atoms", buf);
internal->fh.EndStep(); // I/O will happen now...
if (multifile) {
internal->fh.Close();
}
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
void DumpCustomADIOS::init_style() 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
// remove % from filename since ADIOS always writes a global file with char *ptr = strchr(filename, '%');
// data/metadata if (ptr) {
int len = strlen(filename); while (*ptr) {
char *ptr = strchr(filename, '%'); ptr[0] = ptr[1];
if (ptr) { ++ptr;
*ptr = '\0';
char *s = new char[len - 1];
sprintf(s, "%s%s", filename, ptr + 1);
strncpy(filename, s, len);
} }
}
/* The next four loops are copied from dump_custom_mpiio, but nothing is /* The next four loops are copied from dump_custom_mpiio, but nothing is
* done with them. * done with them.
* It is unclear why we need them here. * It is unclear why we need them here.
* For metadata, variable[] will be written out as an ADIOS attribute if * For metadata, variable[] will be written out as an ADIOS attribute if
* nvariable>0 * nvariable>0
*/ */
// find current ptr for each compute,fix,variable // find current ptr for each compute,fix,variable
// check that fix frequency is acceptable // check that fix frequency is acceptable
int icompute; int icompute;
for (int i = 0; i < ncompute; i++) { for (int i = 0; i < ncompute; i++) {
icompute = modify->find_compute(id_compute[i]); icompute = modify->find_compute(id_compute[i]);
if (icompute < 0) if (icompute < 0) error->all(FLERR, "Could not find dump custom compute ID");
error->all(FLERR, "Could not find dump custom compute ID"); compute[i] = modify->compute[icompute];
compute[i] = modify->compute[icompute]; }
}
int ifix; int ifix;
for (int i = 0; i < nfix; i++) { for (int i = 0; i < nfix; i++) {
ifix = modify->find_fix(id_fix[i]); ifix = modify->find_fix(id_fix[i]);
if (ifix < 0) if (ifix < 0) error->all(FLERR, "Could not find dump custom fix ID");
error->all(FLERR, "Could not find dump custom fix ID"); fix[i] = modify->fix[ifix];
fix[i] = modify->fix[ifix]; if (nevery % modify->fix[ifix]->peratom_freq)
if (nevery % modify->fix[ifix]->peratom_freq) error->all(FLERR, "Dump custom and fix not computed at compatible times");
error->all(FLERR, }
"Dump custom and fix not computed at compatible times");
}
int ivariable; int ivariable;
for (int i = 0; i < nvariable; i++) { for (int i = 0; i < nvariable; i++) {
ivariable = input->variable->find(id_variable[i]); ivariable = input->variable->find(id_variable[i]);
if (ivariable < 0) if (ivariable < 0) error->all(FLERR, "Could not find dump custom variable name");
error->all(FLERR, "Could not find dump custom variable name"); variable[i] = ivariable;
variable[i] = ivariable; }
}
// set index and check validity of region // set index and check validity of region
if (iregion >= 0) { if (iregion >= 0) {
iregion = domain->find_region(idregion); iregion = domain->find_region(idregion);
if (iregion == -1) if (iregion == -1) error->all(FLERR, "Region ID for dump custom does not exist");
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 /* Define the group of variables for the atom style here since it's a fixed
* set */ * set */
internal->io = internal->ad->DeclareIO(internal->ioName); internal->io = internal->ad->DeclareIO(internal->ioName);
if (!internal->io.InConfigFile()) { if (!internal->io.InConfigFile()) {
// if not defined by user, we can change the default settings // if not defined by user, we can change the default settings
// BPFile is the default writer // BPFile is the default writer
internal->io.SetEngine("BPFile"); internal->io.SetEngine("BPFile");
int num_aggregators = multiproc; int num_aggregators = multiproc;
if (num_aggregators == 0) if (num_aggregators == 0) num_aggregators = 1;
num_aggregators = 1; auto nstreams = std::to_string(num_aggregators);
char nstreams[128]; internal->io.SetParameters({{"substreams", nstreams}});
sprintf(nstreams, "%d", num_aggregators); if (me == 0)
internal->io.SetParameters({{"substreams", nstreams}}); utils::logmesg(lmp, "ADIOS method for {} is n-to-m (aggregation with {} writers)\n", filename,
if (me == 0 && screen) nstreams);
fprintf( }
screen,
"ADIOS method for %s is n-to-m (aggregation with %s writers)\n",
filename, nstreams);
}
internal->io.DefineVariable<uint64_t>("ntimestep"); internal->io.DefineVariable<uint64_t>("ntimestep");
internal->io.DefineVariable<uint64_t>("natoms"); internal->io.DefineVariable<uint64_t>("natoms");
internal->io.DefineVariable<int>("nprocs"); internal->io.DefineVariable<int>("nprocs");
internal->io.DefineVariable<int>("ncolumns"); internal->io.DefineVariable<int>("ncolumns");
internal->io.DefineVariable<double>("boxxlo"); internal->io.DefineVariable<double>("boxxlo");
internal->io.DefineVariable<double>("boxxhi"); internal->io.DefineVariable<double>("boxxhi");
internal->io.DefineVariable<double>("boxylo"); internal->io.DefineVariable<double>("boxylo");
internal->io.DefineVariable<double>("boxyhi"); internal->io.DefineVariable<double>("boxyhi");
internal->io.DefineVariable<double>("boxzlo"); internal->io.DefineVariable<double>("boxzlo");
internal->io.DefineVariable<double>("boxzhi"); internal->io.DefineVariable<double>("boxzhi");
internal->io.DefineVariable<double>("boxxy"); internal->io.DefineVariable<double>("boxxy");
internal->io.DefineVariable<double>("boxxz"); internal->io.DefineVariable<double>("boxxz");
internal->io.DefineVariable<double>("boxyz"); internal->io.DefineVariable<double>("boxyz");
internal->io.DefineAttribute<int>("triclinic", domain->triclinic); internal->io.DefineAttribute<int>("triclinic", domain->triclinic);
int *boundaryptr = reinterpret_cast<int *>(domain->boundary); int *boundaryptr = reinterpret_cast<int *>(domain->boundary);
internal->io.DefineAttribute<int>("boundary", boundaryptr, 6); internal->io.DefineAttribute<int>("boundary", boundaryptr, 6);
size_t nColumns = static_cast<size_t>(size_one); size_t nColumns = static_cast<size_t>(size_one);
internal->io.DefineAttribute<std::string>( internal->io.DefineAttribute<std::string>("columns", internal->columnNames.data(), nColumns);
"columns", internal->columnNames.data(), nColumns); internal->io.DefineAttribute<std::string>("columnstr", columns);
internal->io.DefineAttribute<std::string>("columnstr", columns); internal->io.DefineAttribute<std::string>("boundarystr", boundstr);
internal->io.DefineAttribute<std::string>("boundarystr", boundstr); internal->io.DefineAttribute<std::string>("LAMMPS/dump_style", "custom");
internal->io.DefineAttribute<std::string>("LAMMPS/dump_style", "custom"); internal->io.DefineAttribute<std::string>("LAMMPS/version", lmp->version);
internal->io.DefineAttribute<std::string>("LAMMPS/version", internal->io.DefineAttribute<std::string>("LAMMPS/num_ver", std::to_string(lmp->num_ver));
lmp->version);
internal->io.DefineAttribute<std::string>("LAMMPS/num_ver",
std::to_string(lmp->num_ver));
internal->io.DefineVariable<uint64_t>( internal->io.DefineVariable<uint64_t>("nme",
"nme", {adios2::LocalValueDim}); // local dimension variable {adios2::LocalValueDim}); // local dimension variable
internal->io.DefineVariable<uint64_t>( internal->io.DefineVariable<uint64_t>("offset",
"offset", {adios2::LocalValueDim}); // local dimension variable {adios2::LocalValueDim}); // local dimension variable
// atom table size is not known at the moment // atom table size is not known at the moment
// it will be correctly defined at the moment of write // it will be correctly defined at the moment of write
size_t UnknownSizeYet = 1; size_t UnknownSizeYet = 1;
internal->varAtoms = internal->io.DefineVariable<double>( internal->varAtoms = internal->io.DefineVariable<double>(
"atoms", {UnknownSizeYet, nColumns}, {UnknownSizeYet, 0}, "atoms", {UnknownSizeYet, nColumns}, {UnknownSizeYet, 0}, {UnknownSizeYet, nColumns});
{UnknownSizeYet, nColumns});
} }

View File

@ -1,4 +1,3 @@
// clang-format off
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, Sandia National Laboratories https://www.lammps.org/, Sandia National Laboratories
@ -17,20 +16,20 @@
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
#include "reader_adios.h" #include "reader_adios.h"
#include "comm.h" #include "comm.h"
#include "error.h" #include "error.h"
#include "memory.h" #include "memory.h"
#include <cmath> #include <cmath>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include "adios2.h" #include "adios2.h"
#include "math_const.h" #include "adios_common.h"
using namespace LAMMPS_NS; using namespace LAMMPS_NS;
using namespace MathConst;
// also in read_dump.cpp // also in read_dump.cpp
enum { ID, TYPE, X, Y, Z, VX, VY, VZ, Q, IX, IY, IZ, FX, FY, FZ }; 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 #define SMALL 1.0e-6
// true if the difference between two floats is "small". namespace LAMMPS_NS {
// cannot use fabsf() since it is not fully portable. class ReadADIOSInternal {
static bool is_smalldiff(const float &val1, const float &val2)
{
return (fabs(static_cast<double>(val1 - val2)) < SMALL);
}
namespace LAMMPS_NS public:
{ ReadADIOSInternal(){};
class ReadADIOSInternal ~ReadADIOSInternal() = default;
{
public: // name of adios group, referrable in adios2_config.xml
ReadADIOSInternal() {}; const std::string ioName = "read_dump";
~ReadADIOSInternal() = default; adios2::ADIOS *ad = nullptr; // adios object
adios2::IO io; // adios group of variables and attributes in this dump
// name of adios group, referrable in adios2_config.xml adios2::Engine fh; // adios file/stream handle object
const std::string ioName = "read_dump"; // ADIOS input variables we need to change every step
adios2::ADIOS *ad = nullptr; // adios object adios2::Variable<uint64_t> varNtimestep;
adios2::IO io; // adios group of variables and attributes in this dump adios2::Variable<uint64_t> varNatoms;
adios2::Engine fh; // adios file/stream handle object adios2::Variable<double> varAtoms;
// ADIOS input variables we need to change every step // list of column names for the atom table
adios2::Variable<uint64_t> varNtimestep; // (individual list of 'columns' string)
adios2::Variable<uint64_t> varNatoms; std::vector<std::string> columnNames;
adios2::Variable<double> varAtoms; float timeout = 0.0;
// list of column names for the atom table
// (individual list of 'columns' string)
std::vector<std::string> columnNames;
float timeout = 0.0;
}; };
} // namespace LAMMPS_NS } // namespace LAMMPS_NS
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
ReaderADIOS::ReaderADIOS(LAMMPS *lmp) : Reader(lmp) ReaderADIOS::ReaderADIOS(LAMMPS *lmp) : Reader(lmp)
{ {
fieldindex = nullptr; fieldindex = nullptr;
nAtoms = 0; nAtoms = 0;
nAtomsTotal = 0; nAtomsTotal = 0;
atomOffset = 0; atomOffset = 0;
nstep = 0; nstep = 0;
nid = 0; nid = 0;
me = comm->me; me = comm->me;
internal = new ReadADIOSInternal(); // create a default adios2_config.xml if it doesn't exist yet.
try { FILE *cfgfp = fopen("adios2_config.xml", "r");
internal->ad = if (!cfgfp) {
new adios2::ADIOS("adios2_config.xml", world, adios2::DebugON); cfgfp = fopen("adios2_config.xml", "w");
} catch (std::ios_base::failure &e) { if (cfgfp) fputs(default_config, cfgfp);
char str[256]; }
snprintf(str, sizeof(str), "ADIOS initialization failed with error: %s", if (cfgfp) fclose(cfgfp);
e.what());
error->one(FLERR, str);
}
/* Define the group holding all variables and attributes */ internal = new ReadADIOSInternal();
internal->io = internal->ad->DeclareIO(internal->ioName); 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() ReaderADIOS::~ReaderADIOS()
{ {
if (me == 0) { if (me == 0) memory->destroy(fieldindex);
memory->destroy(fieldindex); internal->columnNames.clear();
} if (internal->fh) internal->fh.Close();
internal->columnNames.clear(); delete internal->ad;
if (internal->fh) { delete internal;
internal->fh.Close();
}
delete internal->ad;
delete internal;
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
@ -118,23 +108,19 @@ ReaderADIOS::~ReaderADIOS()
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
void ReaderADIOS::settings(int narg, char **arg) void ReaderADIOS::settings(int narg, char **arg)
{ {
int idx = 0; int idx = 0;
while (idx < narg) { while (idx < narg) {
if (!strcmp(arg[idx], "timeout")) { if (!strcmp(arg[idx], "timeout")) {
if (idx + 1 < narg) { if (idx + 1 < narg) {
internal->timeout = std::stof(arg[idx + 1]); internal->timeout = std::stof(arg[idx + 1]);
internal->io.SetParameter("OpenTimeoutSecs", 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);
}
}
++idx; ++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 Every process must call this Collective operation
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
void ReaderADIOS::open_file(const char *file) void ReaderADIOS::open_file(const std::string &file)
{ {
int rv; // close open file, if needed.
char str[1024]; if (internal->fh) internal->fh.Close();
// close open file, if needed. try {
if (internal->fh) internal->fh = internal->io.Open(file, adios2::Mode::Read, world);
internal->fh.Close(); } catch (std::ios_base::failure &e) {
error->one(FLERR, "Error opening file {}: {}", file, e.what());
try { }
internal->fh = internal->io.Open(file, adios2::Mode::Read, world); if (!internal->fh) error->one(FLERR, "Cannot open file {} using ADIOS", file);
} 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);
}
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
@ -171,10 +148,8 @@ void ReaderADIOS::open_file(const char *file)
void ReaderADIOS::close_file() void ReaderADIOS::close_file()
{ {
// close open file, if needed. // close open file, if needed.
if (internal->fh) { if (internal->fh) { internal->fh.Close(); }
internal->fh.Close();
}
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
@ -185,34 +160,24 @@ void ReaderADIOS::close_file()
int ReaderADIOS::read_time(bigint &ntimestep) int ReaderADIOS::read_time(bigint &ntimestep)
{ {
char str[1024]; adios2::StepStatus status = internal->fh.BeginStep(adios2::StepMode::Read, internal->timeout);
adios2::StepStatus status = switch (status) {
internal->fh.BeginStep(adios2::StepMode::Read, internal->timeout);
switch (status) {
case adios2::StepStatus::EndOfStream: case adios2::StepStatus::EndOfStream:
case adios2::StepStatus::NotReady: case adios2::StepStatus::NotReady:
case adios2::StepStatus::OtherError: case adios2::StepStatus::OtherError:
return 1; return 1;
default: default:
break; break;
} }
internal->varNtimestep = internal->varNtimestep = internal->io.InquireVariable<uint64_t>("ntimestep");
internal->io.InquireVariable<uint64_t>("ntimestep");
if (!internal->varNtimestep) { if (!internal->varNtimestep)
snprintf(str, sizeof(str), error->one(FLERR, "Did not find 'ntimestep' variable in ADIOS file {}", internal->fh.Name());
"Did not find 'ntimestep' variable in ADIOS file %s",
internal->fh.Name().c_str());
error->one(FLERR, str);
}
ntimestep = static_cast<bigint>(internal->varNtimestep.Max()); ntimestep = static_cast<bigint>(internal->varNtimestep.Max());
// std::cerr << " **** ReaderADIOS::read_time found step " << ntimestep return 0;
// << " **** " << std::endl;
return 0;
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
@ -220,7 +185,10 @@ int ReaderADIOS::read_time(bigint &ntimestep)
Called by all processors. Called by all processors.
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
void ReaderADIOS::skip() { internal->fh.EndStep(); } void ReaderADIOS::skip()
{
internal->fh.EndStep();
}
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
read remaining header info: read remaining header info:
@ -236,234 +204,205 @@ void ReaderADIOS::skip() { internal->fh.EndStep(); }
only called by proc 0 only called by proc 0
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
bigint ReaderADIOS::read_header(double box[3][3], int &boxinfo, int &triclinic, bigint ReaderADIOS::read_header(double box[3][3], int &boxinfo, int &triclinic, int fieldinfo,
int fieldinfo, int nfield, int *fieldtype, int nfield, int *fieldtype, char **fieldlabel, int scaleflag,
char **fieldlabel, int scaleflag, int wrapflag, int wrapflag, int &fieldflag, int &xflag, int &yflag, int &zflag)
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<uint64_t>("natoms"); internal->varNatoms = internal->io.InquireVariable<uint64_t>("natoms");
if (!internal->varNatoms) { if (!internal->varNatoms)
snprintf(str, sizeof(str), error->one(FLERR, "Did not find 'natoms' variable in ADIOS file {}", internal->fh.Name());
"Did not find 'natoms' variable in ADIOS file %s",
internal->fh.Name().c_str()); /* nAtoms */
error->one(FLERR, str); 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<int32_t> attTriclinic = internal->io.InquireAttribute<int32_t>("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<double> varBoxxlo = internal->io.InquireVariable<double>("boxxlo");
adios2::Variable<double> varBoxxhi = internal->io.InquireVariable<double>("boxxhi");
adios2::Variable<double> varBoxylo = internal->io.InquireVariable<double>("boxylo");
adios2::Variable<double> varBoxyhi = internal->io.InquireVariable<double>("boxyhi");
adios2::Variable<double> varBoxzlo = internal->io.InquireVariable<double>("boxzlo");
adios2::Variable<double> varBoxzhi = internal->io.InquireVariable<double>("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<double> varBoxxy = internal->io.InquireVariable<double>("boxxy");
adios2::Variable<double> varBoxxz = internal->io.InquireVariable<double>("boxxz");
adios2::Variable<double> varBoxyz = internal->io.InquireVariable<double>("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<std::string> attColumns = internal->io.InquireAttribute<std::string>("columns");
std::vector<std::string> labelVector = attColumns.Data();
int nwords = labelVector.size();
std::map<std::string, int> 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 */ else if (fieldtype[i] == ID)
nAtomsTotal = internal->varNatoms.Max(); fieldindex[i] = find_label("id", labels);
uint64_t rem = nAtomsTotal % comm->nprocs; else if (fieldtype[i] == TYPE)
nAtoms = nAtomsTotal / comm->nprocs; fieldindex[i] = find_label("type", labels);
atomOffset = comm->me * nAtoms;
if (comm->me < rem) {
++nAtoms;
atomOffset += comm->me;
} else {
atomOffset += rem;
}
/* triclinic */ else if (fieldtype[i] == X) {
adios2::Attribute<int32_t> attTriclinic = fieldindex[i] = find_label("x", labels);
internal->io.InquireAttribute<int32_t>("triclinic"); xflag = NOSCALE_WRAP;
if (!attTriclinic) { if (fieldindex[i] < 0) {
snprintf(str, sizeof(str), fieldindex[i] = nwords;
"Did not find 'triclinic' attribute in ADIOS file %s", s_index = find_label("xs", labels);
internal->fh.Name().c_str()); u_index = find_label("xu", labels);
error->one(FLERR, str); su_index = find_label("xsu", labels);
} if (s_index >= 0 && s_index < fieldindex[i]) {
fieldindex[i] = s_index;
triclinic = attTriclinic.Data()[0]; xflag = SCALE_WRAP;
/* read Box */
adios2::Variable<double> varBoxxlo =
internal->io.InquireVariable<double>("boxxlo");
adios2::Variable<double> varBoxxhi =
internal->io.InquireVariable<double>("boxxhi");
adios2::Variable<double> varBoxylo =
internal->io.InquireVariable<double>("boxylo");
adios2::Variable<double> varBoxyhi =
internal->io.InquireVariable<double>("boxyhi");
adios2::Variable<double> varBoxzlo =
internal->io.InquireVariable<double>("boxzlo");
adios2::Variable<double> varBoxzhi =
internal->io.InquireVariable<double>("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<double> varBoxxy =
internal->io.InquireVariable<double>("boxxy");
adios2::Variable<double> varBoxxz =
internal->io.InquireVariable<double>("boxxz");
adios2::Variable<double> varBoxyz =
internal->io.InquireVariable<double>("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<std::string> attColumns =
internal->io.InquireAttribute<std::string>("columns");
std::vector<std::string> labelVector = attColumns.Data();
int nwords = labelVector.size();
std::map<std::string, int> 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;
} }
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) } else if (fieldtype[i] == Y) {
fieldindex[i] = find_label("id", labels); fieldindex[i] = find_label("y", labels);
else if (fieldtype[i] == TYPE) yflag = NOSCALE_WRAP;
fieldindex[i] = find_label("type", labels); 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) { } else if (fieldtype[i] == Z) {
fieldindex[i] = find_label("x", labels); fieldindex[i] = find_label("z", labels);
xflag = NOSCALE_WRAP; zflag = NOSCALE_WRAP;
if (fieldindex[i] < 0) { if (fieldindex[i] < 0) {
fieldindex[i] = nwords; fieldindex[i] = nwords;
s_index = find_label("xs", labels); s_index = find_label("zs", labels);
u_index = find_label("xu", labels); u_index = find_label("zu", labels);
su_index = find_label("xsu", labels); su_index = find_label("zsu", labels);
if (s_index >= 0 && s_index < fieldindex[i]) { if (s_index >= 0 && s_index < fieldindex[i]) {
fieldindex[i] = s_index; fieldindex[i] = s_index;
xflag = SCALE_WRAP; zflag = SCALE_WRAP;
} }
if (u_index >= 0 && u_index < fieldindex[i]) { if (u_index >= 0 && u_index < fieldindex[i]) {
fieldindex[i] = u_index; fieldindex[i] = u_index;
xflag = NOSCALE_NOWRAP; zflag = NOSCALE_NOWRAP;
} }
if (su_index >= 0 && su_index < fieldindex[i]) { if (su_index >= 0 && su_index < fieldindex[i]) {
fieldindex[i] = su_index; fieldindex[i] = su_index;
xflag = SCALE_NOWRAP; zflag = SCALE_NOWRAP;
} }
} }
if (fieldindex[i] == nwords) if (fieldindex[i] == nwords) fieldindex[i] = -1;
fieldindex[i] = -1;
} else if (fieldtype[i] == Y) { } else if (fieldtype[i] == VX)
fieldindex[i] = find_label("y", labels); fieldindex[i] = find_label("vx", labels);
yflag = NOSCALE_WRAP; else if (fieldtype[i] == VY)
if (fieldindex[i] < 0) { fieldindex[i] = find_label("vy", labels);
fieldindex[i] = nwords; else if (fieldtype[i] == VZ)
s_index = find_label("ys", labels); fieldindex[i] = find_label("vz", 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] == Z) { else if (fieldtype[i] == FX)
fieldindex[i] = find_label("z", labels); fieldindex[i] = find_label("fx", labels);
zflag = NOSCALE_WRAP; else if (fieldtype[i] == FY)
if (fieldindex[i] < 0) { fieldindex[i] = find_label("fy", labels);
fieldindex[i] = nwords; else if (fieldtype[i] == FZ)
s_index = find_label("zs", labels); fieldindex[i] = find_label("fz", 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] == VX) else if (fieldtype[i] == Q)
fieldindex[i] = find_label("vx", labels); fieldindex[i] = find_label("q", 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] == FX) else if (fieldtype[i] == IX)
fieldindex[i] = find_label("fx", labels); fieldindex[i] = find_label("ix", labels);
else if (fieldtype[i] == FY) else if (fieldtype[i] == IY)
fieldindex[i] = find_label("fy", labels); fieldindex[i] = find_label("iy", labels);
else if (fieldtype[i] == FZ) else if (fieldtype[i] == IZ)
fieldindex[i] = find_label("fz", labels); fieldindex[i] = find_label("iz", labels);
}
else if (fieldtype[i] == Q) // set fieldflag = -1 if any unfound fields
fieldindex[i] = find_label("q", labels);
else if (fieldtype[i] == IX) fieldflag = 0;
fieldindex[i] = find_label("ix", labels); for (int i = 0; i < nfield; i++)
else if (fieldtype[i] == IY) if (fieldindex[i] < 0) fieldflag = -1;
fieldindex[i] = find_label("iy", labels);
else if (fieldtype[i] == IZ)
fieldindex[i] = find_label("iz", labels);
}
// set fieldflag = -1 if any unfound fields return nAtoms;
fieldflag = 0;
for (int i = 0; i < nfield; i++)
if (fieldindex[i] < 0)
fieldflag = -1;
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) 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 */ adios2::Variable<double> varAtoms = internal->io.InquireVariable<double>("atoms");
/* This is the firsts (and last) read of array data, so we
* call EndStep() here instead of PerformGets()
*/
adios2::Variable<double> varAtoms = if ((uint64_t)n != nAtoms)
internal->io.InquireVariable<double>("atoms"); 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) { size_t ncols = varAtoms.Count()[1];
snprintf( varAtoms.SetSelection({{atomOffset, 0}, {nAtoms, ncols}});
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]; std::vector<double> table;
varAtoms.SetSelection({{atomOffset, 0}, {nAtoms, ncols}});
std::vector<double> table; internal->fh.Get<double>(varAtoms, table);
// EndStep or PerformGets required to make the read happen
internal->fh.EndStep();
internal->fh.Get<double>(varAtoms, table); size_t idx;
// EndStep or PerformGets required to make the read happen for (uint64_t i = 0; i < nAtoms; i++) {
internal->fh.EndStep(); idx = i * ncols;
for (int m = 0; m < nfield; m++) { fields[i][m] = table[idx + fieldindex[m]]; }
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]];
}
}
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
@ -517,12 +448,9 @@ void ReaderADIOS::read_atoms(int n, int nfield, double **fields)
return index of match or -1 if no match return index of match or -1 if no match
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
int ReaderADIOS::find_label(const std::string &label, int ReaderADIOS::find_label(const std::string &label, const std::map<std::string, int> &labels)
const std::map<std::string, int> &labels)
{ {
std::map<std::string, int>::const_iterator it = labels.find(label); std::map<std::string, int>::const_iterator it = labels.find(label);
if (it != labels.end()) { if (it != labels.end()) { return it->second; }
return it->second; return -1;
}
return -1;
} }

View File

@ -44,7 +44,7 @@ class ReaderADIOS : public Reader {
int &, int &, int &) override; int &, int &, int &) override;
void read_atoms(int, int, double **) 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; void close_file() override;
private: private: