#include "dump_atom_adios.h"
#include <cstring>
#include "atom.h"
#include "domain.h"
#include "error.h"
#include "group.h"
#include "memory.h"
#include "universe.h"
#include "update.h"
#include "adios2.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
{
public:
DumpAtomADIOSInternal(){};
~DumpAtomADIOSInternal() = default;
const std::string ioName = "atom";
adios2::ADIOS *ad = nullptr; adios2::IO io; adios2::Engine fh; adios2::Variable<double> varAtoms;
};
}
DumpAtomADIOS::DumpAtomADIOS(LAMMPS *lmp, int narg, char **arg)
: DumpAtom(lmp, narg, arg)
{
internal = new DumpAtomADIOSInternal();
internal->ad =
new adios2::ADIOS("adios2_config.xml", world, adios2::DebugON);
}
DumpAtomADIOS::~DumpAtomADIOS()
{
if (internal->fh) {
internal->fh.Close();
}
delete internal->ad;
delete internal;
}
void DumpAtomADIOS::openfile()
{
if (multifile) {
char *filestar = strdup(filename);
char *filecurrent = new char[strlen(filestar) + 16];
char *ptr = strchr(filestar, '*');
*ptr = '\0';
if (padflag == 0)
snprintf(filecurrent, sizeof(filecurrent), "%s" BIGINT_FORMAT "%s",
filestar, update->ntimestep, ptr + 1);
else {
char bif[8], pad[16];
strcpy(bif, BIGINT_FORMAT);
snprintf(pad, sizeof(pad), "%%s%%0%d%s%%s", padflag, &bif[1]);
snprintf(filecurrent, sizeof(filecurrent), pad, filestar,
update->ntimestep, ptr + 1);
}
internal->fh =
internal->io.Open(filecurrent, adios2::Mode::Write, world);
if (!internal->fh) {
char str[128];
snprintf(str, sizeof(str), "Cannot open dump file %s", filecurrent);
error->one(FLERR, str);
}
free(filestar);
delete[] filecurrent;
} else {
if (!singlefile_opened) {
internal->fh =
internal->io.Open(filename, adios2::Mode::Write, world);
if (!internal->fh) {
char str[128];
snprintf(str, sizeof(str), "Cannot open dump file %s",
filename);
error->one(FLERR, str);
}
singlefile_opened = 1;
}
}
}
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;
}
nme = count();
bigint bnme = nme;
MPI_Allreduce(&bnme, &ntotal, 1, MPI_LMP_BIGINT, MPI_SUM, world);
bigint atomOffset; MPI_Scan(&bnme, &atomOffset, 1, MPI_LMP_BIGINT, MPI_SUM, world);
atomOffset -= nme;
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}});
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(NULL);
if (sort_flag)
sort();
openfile();
internal->fh.BeginStep();
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);
}
}
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);
internal->fh.Put<double>(internal->varAtoms, buf);
internal->fh.EndStep();
if (multifile) {
internal->fh.Close();
}
}
void DumpAtomADIOS::init_style()
{
if (image_flag == 0)
size_one = 5;
else
size_one = 8;
domain->boundary_string(boundstr);
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);
}
if (scale_flag == 0 && image_flag == 0)
columns = (char *)"id type x y z";
else if (scale_flag == 0 && image_flag == 1)
columns = (char *)"id type x y z ix iy iz";
else if (scale_flag == 1 && image_flag == 0)
columns = (char *)"id type xs ys zs";
else if (scale_flag == 1 && image_flag == 1)
columns = (char *)"id type xs ys zs ix iy iz";
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;
internal->io = internal->ad->DeclareIO(internal->ioName);
if (!internal->io.InConfigFile()) {
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.DefineVariable<uint64_t>("ntimestep");
internal->io.DefineVariable<uint64_t>("natoms");
internal->io.DefineVariable<int>("nprocs");
internal->io.DefineVariable<int>("ncolumns");
internal->io.DefineVariable<double>("boxxlo");
internal->io.DefineVariable<double>("boxxhi");
internal->io.DefineVariable<double>("boxylo");
internal->io.DefineVariable<double>("boxyhi");
internal->io.DefineVariable<double>("boxzlo");
internal->io.DefineVariable<double>("boxzhi");
internal->io.DefineVariable<double>("boxxy");
internal->io.DefineVariable<double>("boxxz");
internal->io.DefineVariable<double>("boxyz");
internal->io.DefineAttribute<int>("triclinic", domain->triclinic);
internal->io.DefineAttribute<int>("scaled", scale_flag);
internal->io.DefineAttribute<int>("image", image_flag);
int *boundaryptr = reinterpret_cast<int *>(domain->boundary);
internal->io.DefineAttribute<int>("boundary", boundaryptr, 6);
internal->io.DefineAttribute<std::string>("columns", columns);
internal->io.DefineAttribute<std::string>("boundarystr", boundstr);
internal->io.DefineAttribute<std::string>("LAMMPS/dump_style", "atom");
internal->io.DefineAttribute<std::string>("LAMMPS/version",
universe->version);
internal->io.DefineAttribute<std::string>("LAMMPS/num_ver",
universe->num_ver);
internal->io.DefineVariable<uint64_t>(
"nme", {adios2::LocalValueDim}); internal->io.DefineVariable<uint64_t>(
"offset", {adios2::LocalValueDim});
size_t UnknownSizeYet = 1;
size_t nColumns = static_cast<size_t>(size_one);
internal->varAtoms = internal->io.DefineVariable<double>(
"atoms", {UnknownSizeYet, nColumns}, {UnknownSizeYet, 0},
{UnknownSizeYet, nColumns});
}