1356 lines
40 KiB
C++
1356 lines
40 KiB
C++
/* ----------------------------------------------------------------------
|
|
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
|
http://lammps.sandia.gov, 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.
|
|
------------------------------------------------------------------------- */
|
|
|
|
/* ----------------------------------------------------------------------
|
|
Contributing author: Timothy Sirk (ARL)
|
|
------------------------------------------------------------------------- */
|
|
|
|
// lmptype.h must be first b/c this file uses MAXBIGINT and includes mpi.h
|
|
// due to OpenMPI bug which sets INT64_MAX via its mpi.h
|
|
// before lmptype.h can set flags to insure it is done correctly
|
|
|
|
#include "read_dump.h"
|
|
#include <mpi.h>
|
|
#include <cstring>
|
|
#include <string>
|
|
#include "reader.h"
|
|
#include "style_reader.h"
|
|
#include "atom.h"
|
|
#include "atom_vec.h"
|
|
#include "update.h"
|
|
#include "domain.h"
|
|
#include "comm.h"
|
|
#include "force.h"
|
|
#include "irregular.h"
|
|
#include "error.h"
|
|
#include "memory.h"
|
|
#include "utils.h"
|
|
#include "fmt/format.h"
|
|
|
|
using namespace LAMMPS_NS;
|
|
|
|
#define CHUNK 16384
|
|
|
|
// also in reader_native.cpp
|
|
|
|
enum{ID,TYPE,X,Y,Z,VX,VY,VZ,Q,IX,IY,IZ,FX,FY,FZ};
|
|
enum{UNSET,NOSCALE_NOWRAP,NOSCALE_WRAP,SCALE_NOWRAP,SCALE_WRAP};
|
|
enum{NOADD,YESADD,KEEPADD};
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
ReadDump::ReadDump(LAMMPS *lmp) : Pointers(lmp)
|
|
{
|
|
MPI_Comm_rank(world,&me);
|
|
MPI_Comm_size(world,&nprocs);
|
|
|
|
dimension = domain->dimension;
|
|
triclinic = domain->triclinic;
|
|
|
|
nfile = 0;
|
|
files = NULL;
|
|
|
|
nnew = maxnew = 0;
|
|
nfield = 0;
|
|
fieldtype = NULL;
|
|
fieldlabel = NULL;
|
|
fields = NULL;
|
|
buf = NULL;
|
|
|
|
int n = strlen("native") + 1;
|
|
readerstyle = new char[n];
|
|
strcpy(readerstyle,"native");
|
|
|
|
nreader = 0;
|
|
readers = NULL;
|
|
nsnapatoms = NULL;
|
|
clustercomm = MPI_COMM_NULL;
|
|
filereader = 0;
|
|
parallel = 0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
ReadDump::~ReadDump()
|
|
{
|
|
for (int i = 0; i < nfile; i++) delete [] files[i];
|
|
delete [] files;
|
|
for (int i = 0; i < nfield; i++) delete [] fieldlabel[i];
|
|
delete [] fieldlabel;
|
|
delete [] fieldtype;
|
|
delete [] readerstyle;
|
|
|
|
memory->destroy(fields);
|
|
memory->destroy(buf);
|
|
|
|
for (int i = 0; i < nreader; i++) delete readers[i];
|
|
delete [] readers;
|
|
delete [] nsnapatoms;
|
|
|
|
MPI_Comm_free(&clustercomm);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void ReadDump::command(int narg, char **arg)
|
|
{
|
|
if (domain->box_exist == 0)
|
|
error->all(FLERR,"Read_dump command before simulation box is defined");
|
|
|
|
if (narg < 2) error->all(FLERR,"Illegal read_dump command");
|
|
|
|
store_files(1,&arg[0]);
|
|
bigint nstep = force->bnumeric(FLERR,arg[1]);
|
|
|
|
int nremain = narg - 2;
|
|
if (nremain) nremain = fields_and_keywords(nremain,&arg[narg-nremain]);
|
|
else nremain = fields_and_keywords(0,NULL);
|
|
if (nremain) setup_reader(nremain,&arg[narg-nremain]);
|
|
else setup_reader(0,NULL);
|
|
|
|
// find the snapshot and read/bcast/process header info
|
|
|
|
if (me == 0 && screen) fprintf(screen,"Scanning dump file ...\n");
|
|
|
|
bigint ntimestep = seek(nstep,1);
|
|
if (ntimestep < 0)
|
|
error->all(FLERR,"Dump file does not contain requested snapshot");
|
|
header(1);
|
|
|
|
// reset timestep to nstep
|
|
|
|
update->reset_timestep(nstep);
|
|
|
|
// counters
|
|
|
|
// read in the snapshot and reset system
|
|
|
|
if (me == 0 && screen)
|
|
fprintf(screen,"Reading snapshot from dump file ...\n");
|
|
|
|
bigint natoms_prev = atom->natoms;
|
|
atoms();
|
|
|
|
if (filereader)
|
|
for (int i = 0; i < nreader; i++)
|
|
readers[i]->close_file();
|
|
|
|
// print out stats
|
|
|
|
bigint nsnap_all,npurge_all,nreplace_all,ntrim_all,nadd_all;
|
|
|
|
bigint tmp = 0;
|
|
if (filereader)
|
|
for (int i = 0; i < nreader; i++)
|
|
tmp += nsnapatoms[i];
|
|
MPI_Allreduce(&tmp,&nsnap_all,1,MPI_LMP_BIGINT,MPI_SUM,world);
|
|
|
|
tmp = npurge;
|
|
MPI_Allreduce(&tmp,&npurge_all,1,MPI_LMP_BIGINT,MPI_SUM,world);
|
|
tmp = nreplace;
|
|
MPI_Allreduce(&tmp,&nreplace_all,1,MPI_LMP_BIGINT,MPI_SUM,world);
|
|
tmp = ntrim;
|
|
MPI_Allreduce(&tmp,&ntrim_all,1,MPI_LMP_BIGINT,MPI_SUM,world);
|
|
tmp = nadd;
|
|
MPI_Allreduce(&tmp,&nadd_all,1,MPI_LMP_BIGINT,MPI_SUM,world);
|
|
|
|
domain->print_box(" ");
|
|
|
|
if (me == 0)
|
|
utils::logmesg(lmp, fmt::format(" {} atoms before read\n",natoms_prev)
|
|
+ fmt::format(" {} atoms in snapshot\n",nsnap_all)
|
|
+ fmt::format(" {} atoms purged\n",npurge_all)
|
|
+ fmt::format(" {} atoms replaced\n",nreplace_all)
|
|
+ fmt::format(" {} atoms trimmed\n",ntrim_all)
|
|
+ fmt::format(" {} atoms added\n",nadd_all)
|
|
+ fmt::format(" {} atoms after read\n",atom->natoms));
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void ReadDump::store_files(int nstr, char **str)
|
|
{
|
|
nfile = nstr;
|
|
files = new char*[nfile];
|
|
|
|
// either all or none of files must have '%' wild-card
|
|
|
|
for (int i = 0; i < nfile; i++) {
|
|
int n = strlen(str[i]) + 1;
|
|
files[i] = new char[n];
|
|
strcpy(files[i],str[i]);
|
|
|
|
if (i == 0) {
|
|
if (strchr(files[i],'%')) multiproc = 1;
|
|
else multiproc = 0;
|
|
} else {
|
|
if (multiproc && !strchr(files[i],'%'))
|
|
error->all(FLERR,"All read_dump files must be serial or parallel");
|
|
if (!multiproc && strchr(files[i],'%'))
|
|
error->all(FLERR,"All read_dump files must be serial or parallel");
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void ReadDump::setup_reader(int narg, char **arg)
|
|
{
|
|
// setup serial or parallel file reading
|
|
// multiproc = 0: only one file to read from, only proc 0 is a reader
|
|
// multiproc_nfile >= nprocs: every proc reads one or more files
|
|
// multiproc_nfile < nprocs: multiproc_nfile readers, create clusters
|
|
// see read_dump.h for explanation of these variables
|
|
|
|
if (multiproc == 0) {
|
|
nreader = 1;
|
|
firstfile = -1;
|
|
MPI_Comm_dup(world,&clustercomm);
|
|
} else if (multiproc_nfile >= nprocs) {
|
|
firstfile = static_cast<int> ((bigint) me * multiproc_nfile/nprocs);
|
|
int lastfile = static_cast<int> ((bigint) (me+1) * multiproc_nfile/nprocs);
|
|
nreader = lastfile - firstfile;
|
|
MPI_Comm_split(world,me,0,&clustercomm);
|
|
} else if (multiproc_nfile < nprocs) {
|
|
nreader = 1;
|
|
int icluster = static_cast<int> ((bigint) me * multiproc_nfile/nprocs);
|
|
firstfile = icluster;
|
|
MPI_Comm_split(world,icluster,0,&clustercomm);
|
|
}
|
|
|
|
MPI_Comm_rank(clustercomm,&me_cluster);
|
|
MPI_Comm_size(clustercomm,&nprocs_cluster);
|
|
if (me_cluster == 0) filereader = 1;
|
|
else filereader = 0;
|
|
|
|
readers = new Reader*[nreader];
|
|
nsnapatoms = new bigint[nreader];
|
|
|
|
// create Nreader reader classes per reader
|
|
// match readerstyle to options in style_reader.h
|
|
|
|
if (0) return; // dummy line to enable else-if macro expansion
|
|
|
|
#define READER_CLASS
|
|
#define ReaderStyle(key,Class) \
|
|
else if (strcmp(readerstyle,#key) == 0) { \
|
|
for (int i = 0; i < nreader; i++) \
|
|
readers[i] = new Class(lmp); \
|
|
}
|
|
#include "style_reader.h"
|
|
#undef READER_CLASS
|
|
|
|
// unrecognized style
|
|
|
|
else error->all(FLERR,utils::check_packages_for_style("reader",readerstyle,lmp));
|
|
|
|
if (utils::strmatch(readerstyle,"^adios")) {
|
|
// everyone is a reader with adios
|
|
parallel = 1;
|
|
filereader = 1;
|
|
}
|
|
|
|
// pass any arguments to readers
|
|
|
|
if (narg > 0 && filereader)
|
|
for (int i = 0; i < nreader; i++)
|
|
readers[i]->settings(narg,arg);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
seek Nrequest timestep in one or more dump files
|
|
if exact = 1, must find exactly Nrequest
|
|
if exact = 0, find first step >= Nrequest
|
|
return matching ntimestep or -1 if did not find a match
|
|
------------------------------------------------------------------------- */
|
|
|
|
bigint ReadDump::seek(bigint nrequest, int exact)
|
|
{
|
|
int ifile,eofflag;
|
|
bigint ntimestep;
|
|
|
|
// proc 0 finds the timestep in its first reader
|
|
|
|
if (me == 0 || parallel) {
|
|
|
|
// exit file loop when dump timestep >= nrequest
|
|
// or files exhausted
|
|
|
|
for (ifile = 0; ifile < nfile; ifile++) {
|
|
ntimestep = -1;
|
|
if (multiproc) {
|
|
std::string multiname = files[ifile];
|
|
multiname.replace(multiname.find("%"),1,"0");
|
|
readers[0]->open_file(multiname.c_str());
|
|
} else readers[0]->open_file(files[ifile]);
|
|
|
|
while (1) {
|
|
eofflag = readers[0]->read_time(ntimestep);
|
|
if (eofflag) break;
|
|
if (ntimestep >= nrequest) break;
|
|
readers[0]->skip();
|
|
}
|
|
|
|
if (ntimestep >= nrequest) break;
|
|
readers[0]->close_file();
|
|
}
|
|
|
|
currentfile = ifile;
|
|
if (ntimestep < nrequest) ntimestep = -1;
|
|
if (exact && ntimestep != nrequest) ntimestep = -1;
|
|
}
|
|
|
|
if (!parallel) {
|
|
// proc 0 broadcasts timestep and currentfile to all procs
|
|
|
|
MPI_Bcast(&ntimestep,1,MPI_LMP_BIGINT,0,world);
|
|
MPI_Bcast(¤tfile,1,MPI_INT,0,world);
|
|
}
|
|
|
|
// if ntimestep < 0:
|
|
// all filereader procs close all their files and return
|
|
|
|
if (ntimestep < 0) {
|
|
if (filereader)
|
|
for (int i = 0; i < nreader; i++)
|
|
readers[i]->close_file();
|
|
return ntimestep;
|
|
}
|
|
|
|
// for multiproc mode:
|
|
// all filereader procs search for same ntimestep in currentfile
|
|
|
|
if (multiproc && filereader) {
|
|
for (int i = 0; i < nreader; i++) {
|
|
if (me == 0 && i == 0) continue; // proc 0, reader 0 already found it
|
|
std::string multiname = files[currentfile];
|
|
multiname.replace(multiname.find("%"),1,fmt::format("{}",firstfile+i));
|
|
readers[i]->open_file(multiname.c_str());
|
|
|
|
bigint step;
|
|
while (1) {
|
|
eofflag = readers[i]->read_time(step);
|
|
if (eofflag) break;
|
|
if (step == ntimestep) break;
|
|
readers[i]->skip();
|
|
}
|
|
|
|
if (eofflag)
|
|
error->one(FLERR,"Read dump parallel files "
|
|
"do not all have same timestep");
|
|
}
|
|
}
|
|
|
|
return ntimestep;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
find next matching snapshot in one or more dump files
|
|
Ncurrent = current timestep from last snapshot
|
|
Nlast = match no timestep bigger than Nlast
|
|
Nevery = only match timesteps that are a multiple of Nevery
|
|
Nskip = skip every this many timesteps
|
|
return matching ntimestep or -1 if did not find a match
|
|
------------------------------------------------------------------------- */
|
|
|
|
bigint ReadDump::next(bigint ncurrent, bigint nlast, int nevery, int nskip)
|
|
{
|
|
int ifile,eofflag;
|
|
bigint ntimestep;
|
|
|
|
// proc 0 finds the timestep in its first reader
|
|
|
|
if (me == 0 || parallel) {
|
|
|
|
// exit file loop when dump timestep matches all criteria
|
|
// or files exhausted
|
|
|
|
int iskip = 0;
|
|
|
|
for (ifile = currentfile; ifile < nfile; ifile++) {
|
|
ntimestep = -1;
|
|
if (ifile != currentfile) {
|
|
if (multiproc) {
|
|
std::string multiname = files[ifile];
|
|
multiname.replace(multiname.find("%"),1,"0");
|
|
readers[0]->open_file(multiname.c_str());
|
|
} else readers[0]->open_file(files[ifile]);
|
|
}
|
|
|
|
while (1) {
|
|
eofflag = readers[0]->read_time(ntimestep);
|
|
if (eofflag) break;
|
|
if (ntimestep > nlast) break;
|
|
if (ntimestep <= ncurrent) {
|
|
readers[0]->skip();
|
|
continue;
|
|
}
|
|
if (iskip == nskip) iskip = 0;
|
|
iskip++;
|
|
if (nevery && ntimestep % nevery) readers[0]->skip();
|
|
else if (iskip < nskip) readers[0]->skip();
|
|
else break;
|
|
}
|
|
|
|
if (eofflag) readers[0]->close_file();
|
|
else break;
|
|
}
|
|
|
|
currentfile = ifile;
|
|
if (eofflag) ntimestep = -1;
|
|
if (ntimestep <= ncurrent) ntimestep = -1;
|
|
if (ntimestep > nlast) ntimestep = -1;
|
|
}
|
|
|
|
if (!parallel) {
|
|
// proc 0 broadcasts timestep and currentfile to all procs
|
|
|
|
MPI_Bcast(&ntimestep,1,MPI_LMP_BIGINT,0,world);
|
|
MPI_Bcast(¤tfile,1,MPI_INT,0,world);
|
|
}
|
|
|
|
// if ntimestep < 0:
|
|
// all filereader procs close all their files and return
|
|
|
|
if (ntimestep < 0) {
|
|
if (filereader)
|
|
for (int i = 0; i < nreader; i++)
|
|
readers[i]->close_file();
|
|
return ntimestep;
|
|
}
|
|
|
|
// for multiproc mode:
|
|
// all filereader procs search for same ntimestep in currentfile
|
|
|
|
if (multiproc && filereader) {
|
|
for (int i = 0; i < nreader; i++) {
|
|
if (me == 0 && i == 0) continue;
|
|
std::string multiname = files[currentfile];
|
|
multiname.replace(multiname.find("%"),1,fmt::format("{}",firstfile+i));
|
|
readers[i]->open_file(multiname.c_str());
|
|
|
|
bigint step;
|
|
while (1) {
|
|
eofflag = readers[i]->read_time(step);
|
|
if (eofflag) break;
|
|
if (step == ntimestep) break;
|
|
readers[i]->skip();
|
|
}
|
|
|
|
if (eofflag)
|
|
error->one(FLERR,"Read dump parallel files "
|
|
"do not all have same timestep");
|
|
}
|
|
}
|
|
|
|
return ntimestep;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
read and broadcast and store snapshot header info
|
|
set nsnapatoms = # of atoms in snapshot
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadDump::header(int fieldinfo)
|
|
{
|
|
int boxinfo, triclinic_snap;
|
|
int fieldflag,xflag,yflag,zflag;
|
|
|
|
if (filereader) {
|
|
for (int i = 0; i < nreader; i++)
|
|
nsnapatoms[i] = readers[i]->read_header(box,boxinfo,triclinic_snap,fieldinfo,
|
|
nfield,fieldtype,fieldlabel,
|
|
scaleflag,wrapflag,fieldflag,
|
|
xflag,yflag,zflag);
|
|
}
|
|
|
|
if (!parallel) {
|
|
MPI_Bcast(nsnapatoms,nreader,MPI_LMP_BIGINT,0,clustercomm);
|
|
MPI_Bcast(&boxinfo,1,MPI_INT,0,clustercomm);
|
|
MPI_Bcast(&triclinic_snap,1,MPI_INT,0,clustercomm);
|
|
MPI_Bcast(&box[0][0],9,MPI_DOUBLE,0,clustercomm);
|
|
}
|
|
|
|
// local copy of snapshot box parameters
|
|
// used in xfield,yfield,zfield when converting dump atom to absolute coords
|
|
|
|
if (boxinfo) {
|
|
xlo = box[0][0];
|
|
xhi = box[0][1];
|
|
ylo = box[1][0];
|
|
yhi = box[1][1];
|
|
zlo = box[2][0];
|
|
zhi = box[2][1];
|
|
|
|
if (triclinic_snap) {
|
|
xy = box[0][2];
|
|
xz = box[1][2];
|
|
yz = box[2][2];
|
|
double xdelta = MIN(0.0,xy);
|
|
xdelta = MIN(xdelta,xz);
|
|
xdelta = MIN(xdelta,xy+xz);
|
|
xlo = xlo - xdelta;
|
|
xdelta = MAX(0.0,xy);
|
|
xdelta = MAX(xdelta,xz);
|
|
xdelta = MAX(xdelta,xy+xz);
|
|
xhi = xhi - xdelta;
|
|
ylo = ylo - MIN(0.0,yz);
|
|
yhi = yhi - MAX(0.0,yz);
|
|
}
|
|
xprd = xhi - xlo;
|
|
yprd = yhi - ylo;
|
|
zprd = zhi - zlo;
|
|
}
|
|
|
|
// done if not checking fields
|
|
|
|
if (!fieldinfo) return;
|
|
|
|
MPI_Bcast(&fieldflag,1,MPI_INT,0,clustercomm);
|
|
MPI_Bcast(&xflag,1,MPI_INT,0,clustercomm);
|
|
MPI_Bcast(&yflag,1,MPI_INT,0,clustercomm);
|
|
MPI_Bcast(&zflag,1,MPI_INT,0,clustercomm);
|
|
|
|
// error check on current vs new box and fields
|
|
// boxinfo == 0 means no box info in file
|
|
|
|
if (boxflag) {
|
|
if (!boxinfo)
|
|
error->all(FLERR,"No box information in dump, must use 'box no'");
|
|
else if ((triclinic_snap && !triclinic) ||
|
|
(!triclinic_snap && triclinic))
|
|
error->one(FLERR,"Read_dump triclinic status does not match simulation");
|
|
}
|
|
|
|
// error check on requested fields existing in dump file
|
|
|
|
if (fieldflag < 0)
|
|
error->one(FLERR,"Read_dump field not found in dump file");
|
|
|
|
// all explicitly requested x,y,z must have consistent scaling & wrapping
|
|
|
|
int value = MAX(xflag,yflag);
|
|
value = MAX(zflag,value);
|
|
if ((xflag != UNSET && xflag != value) ||
|
|
(yflag != UNSET && yflag != value) ||
|
|
(zflag != UNSET && zflag != value))
|
|
error->one(FLERR,
|
|
"Read_dump xyz fields do not have consistent scaling/wrapping");
|
|
|
|
// set scaled/wrapped based on xyz flags
|
|
|
|
value = UNSET;
|
|
if (xflag != UNSET) value = xflag;
|
|
if (yflag != UNSET) value = yflag;
|
|
if (zflag != UNSET) value = zflag;
|
|
|
|
if (value == UNSET) {
|
|
scaled = wrapped = 0;
|
|
} else if (value == NOSCALE_NOWRAP) {
|
|
scaled = wrapped = 0;
|
|
} else if (value == NOSCALE_WRAP) {
|
|
scaled = 0;
|
|
wrapped = 1;
|
|
} else if (value == SCALE_NOWRAP) {
|
|
scaled = 1;
|
|
wrapped = 0;
|
|
} else if (value == SCALE_WRAP) {
|
|
scaled = wrapped = 1;
|
|
}
|
|
|
|
// scaled, triclinic coords require all 3 x,y,z fields, to perform unscaling
|
|
// set yindex,zindex = column index of Y and Z fields in fields array
|
|
// needed for unscaling to absolute coords in xfield(), yfield(), zfield()
|
|
|
|
if (scaled && triclinic == 1) {
|
|
int flag = 0;
|
|
if (xflag == UNSET) flag = 1;
|
|
if (yflag == UNSET) flag = 1;
|
|
if (dimension == 3 && zflag == UNSET) flag = 1;
|
|
if (flag)
|
|
error->one(FLERR,"All read_dump x,y,z fields must be specified for "
|
|
"scaled, triclinic coords");
|
|
|
|
for (int i = 0; i < nfield; i++) {
|
|
if (fieldtype[i] == Y) yindex = i;
|
|
if (fieldtype[i] == Z) zindex = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
read and process one snapshot of atoms
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadDump::atoms()
|
|
{
|
|
// initialize counters
|
|
|
|
npurge = nreplace = ntrim = nadd = 0;
|
|
|
|
// if purgeflag set, delete all current atoms
|
|
|
|
if (purgeflag) {
|
|
if (atom->map_style) atom->map_clear();
|
|
npurge = atom->nlocal;
|
|
atom->nlocal = atom->nghost = 0;
|
|
atom->natoms = 0;
|
|
}
|
|
|
|
// read all the snapshot atoms into fields
|
|
// each proc will own an arbitrary subset of atoms
|
|
|
|
read_atoms();
|
|
|
|
// migrate old owned atoms to new procs based on atom IDs
|
|
// not necessary if purged all old atoms or if only 1 proc
|
|
|
|
if (!purgeflag && nprocs > 1) migrate_old_atoms();
|
|
|
|
// migrate new snapshot atoms to same new procs based on atom IDs
|
|
// not necessary if purged all old atoms or if only 1 proc
|
|
|
|
if (!purgeflag && nprocs > 1) migrate_new_atoms();
|
|
|
|
// must build map if not a molecular system
|
|
// this will be needed to match new atoms to old atoms
|
|
|
|
int mapflag = 0;
|
|
if (atom->map_style == 0) {
|
|
mapflag = 1;
|
|
atom->map_init();
|
|
atom->map_set();
|
|
}
|
|
|
|
// each proc now owns both old and new info for same subset of atoms
|
|
// update each local atom with new info
|
|
|
|
process_atoms();
|
|
|
|
// check that atom IDs are valid
|
|
|
|
atom->tag_check();
|
|
|
|
// delete atom map if created it above
|
|
// else reinitialize map for current atoms
|
|
// do this before migrating atoms to new procs via Irregular
|
|
|
|
if (mapflag) {
|
|
atom->map_delete();
|
|
atom->map_style = 0;
|
|
} else {
|
|
atom->nghost = 0;
|
|
atom->map_init();
|
|
atom->map_set();
|
|
}
|
|
|
|
// overwrite simulation box with dump snapshot box if requested
|
|
// reallocate processors to box
|
|
|
|
if (boxflag) {
|
|
domain->boxlo[0] = xlo;
|
|
domain->boxhi[0] = xhi;
|
|
domain->boxlo[1] = ylo;
|
|
domain->boxhi[1] = yhi;
|
|
if (dimension == 3) {
|
|
domain->boxlo[2] = zlo;
|
|
domain->boxhi[2] = zhi;
|
|
}
|
|
if (triclinic) {
|
|
domain->xy = xy;
|
|
if (dimension == 3) {
|
|
domain->xz = xz;
|
|
domain->yz = yz;
|
|
}
|
|
}
|
|
|
|
domain->set_initial_box();
|
|
domain->set_global_box();
|
|
comm->set_proc_grid(0);
|
|
domain->set_local_box();
|
|
}
|
|
|
|
// migrate atoms to their new owing proc, based on atom coords
|
|
|
|
migrate_atoms_by_coords();
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
read all the snapshot atoms into fields
|
|
done in different ways for multiproc no/yes and # of procs < or >= nprocs
|
|
nnew = # of snapshot atoms this proc stores
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadDump::read_atoms()
|
|
{
|
|
int count,nread,nsend,nrecv,otherproc;
|
|
bigint nsnap,ntotal,ofirst,olast,rfirst,rlast,lo,hi;
|
|
MPI_Request request;
|
|
MPI_Status status;
|
|
|
|
// one reader per cluster of procs
|
|
// each reading proc reads one file and splits data across cluster
|
|
// cluster can be all procs or a subset
|
|
|
|
if (!parallel && (!multiproc || multiproc_nfile < nprocs)) {
|
|
nsnap = nsnapatoms[0];
|
|
|
|
if (filereader) {
|
|
if (!buf) memory->create(buf,CHUNK,nfield,"read_dump:buf");
|
|
|
|
otherproc = 0;
|
|
ofirst = (bigint) otherproc * nsnap/nprocs_cluster;
|
|
olast = (bigint) (otherproc+1) * nsnap/nprocs_cluster;
|
|
if (olast-ofirst > MAXSMALLINT)
|
|
error->one(FLERR,"Read dump snapshot is too large for a proc");
|
|
nnew = static_cast<int> (olast - ofirst);
|
|
|
|
if (nnew > maxnew || maxnew == 0) {
|
|
memory->destroy(fields);
|
|
maxnew = MAX(nnew,1); // avoid NULL ptr
|
|
memory->create(fields,maxnew,nfield,"read_dump:fields");
|
|
}
|
|
|
|
ntotal = 0;
|
|
while (ntotal < nsnap) {
|
|
nread = MIN(CHUNK,nsnap-ntotal);
|
|
readers[0]->read_atoms(nread,nfield,buf);
|
|
rfirst = ntotal;
|
|
rlast = ntotal + nread;
|
|
|
|
nsend = 0;
|
|
while (nsend < nread) {
|
|
lo = MAX(ofirst,rfirst);
|
|
hi = MIN(olast,rlast);
|
|
if (otherproc) // send to otherproc or copy to self
|
|
MPI_Send(&buf[nsend][0],(hi-lo)*nfield,MPI_DOUBLE,
|
|
otherproc,0,clustercomm);
|
|
else
|
|
memcpy(&fields[rfirst][0],&buf[nsend][0],
|
|
(hi-lo)*nfield*sizeof(double));
|
|
nsend += hi-lo;
|
|
if (hi == olast) {
|
|
otherproc++;
|
|
ofirst = (bigint) otherproc * nsnap/nprocs_cluster;
|
|
olast = (bigint) (otherproc+1) * nsnap/nprocs_cluster;
|
|
}
|
|
}
|
|
|
|
ntotal += nread;
|
|
}
|
|
|
|
} else {
|
|
ofirst = (bigint) me_cluster * nsnap/nprocs_cluster;
|
|
olast = (bigint) (me_cluster+1) * nsnap/nprocs_cluster;
|
|
if (olast-ofirst > MAXSMALLINT)
|
|
error->one(FLERR,"Read dump snapshot is too large for a proc");
|
|
nnew = static_cast<int> (olast - ofirst);
|
|
if (nnew > maxnew || maxnew == 0) {
|
|
memory->destroy(fields);
|
|
maxnew = MAX(nnew,1); // avoid NULL ptr
|
|
memory->create(fields,maxnew,nfield,"read_dump:fields");
|
|
}
|
|
|
|
nrecv = 0;
|
|
while (nrecv < nnew) {
|
|
MPI_Irecv(&fields[nrecv][0],(nnew-nrecv)*nfield,MPI_DOUBLE,0,0,
|
|
clustercomm,&request);
|
|
MPI_Wait(&request,&status);
|
|
MPI_Get_count(&status,MPI_DOUBLE,&count);
|
|
nrecv += count/nfield;
|
|
}
|
|
}
|
|
|
|
// every proc is a filereader, reads one or more files
|
|
// each proc keeps all data it reads, no communication required
|
|
|
|
} else if (multiproc_nfile >= nprocs || parallel) {
|
|
bigint sum = 0;
|
|
for (int i = 0; i < nreader; i++)
|
|
sum += nsnapatoms[i];
|
|
if (sum > MAXSMALLINT)
|
|
error->one(FLERR,"Read dump snapshot is too large for a proc");
|
|
nnew = static_cast<int> (sum);
|
|
if (nnew > maxnew || maxnew == 0) {
|
|
memory->destroy(fields);
|
|
maxnew = MAX(nnew,1); // avoid NULL ptr
|
|
memory->create(fields,maxnew,nfield,"read_dump:fields");
|
|
}
|
|
|
|
nnew = 0;
|
|
for (int i = 0; i < nreader; i++) {
|
|
nsnap = nsnapatoms[i];
|
|
ntotal = 0;
|
|
while (ntotal < nsnap) {
|
|
if (parallel) {
|
|
// read the whole thing at once
|
|
nread = nsnap-ntotal;
|
|
} else {
|
|
nread = MIN(CHUNK,nsnap-ntotal);
|
|
}
|
|
readers[i]->read_atoms(nread,nfield,&fields[nnew+ntotal]);
|
|
ntotal += nread;
|
|
}
|
|
nnew += nsnap;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
update info for each old atom I own based on snapshot info
|
|
if in replace mode and atom ID matches current atom,
|
|
overwrite atom info with fields from dump file
|
|
if in add mode and atom ID does not match any old atom,
|
|
create new atom with dump file field values
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadDump::process_atoms()
|
|
{
|
|
int i,m,ifield,itype;
|
|
int xbox,ybox,zbox;
|
|
tagint mtag;
|
|
int *updateflag,*newflag;
|
|
|
|
// updateflag[i] = flag for old atoms, 1 if updated, else 0
|
|
// newflag[i] = flag for new atoms, 0 if used to update old atom, else 1
|
|
|
|
int nlocal = atom->nlocal;
|
|
memory->create(updateflag,nlocal,"read_dump:updateflag");
|
|
for (int i = 0; i < nlocal; i++) updateflag[i] = 0;
|
|
memory->create(newflag,nnew,"read_dump:newflag");
|
|
for (int i = 0; i < nnew; i++) newflag[i] = 1;
|
|
|
|
// loop over new atoms
|
|
|
|
double **x = atom->x;
|
|
double **v = atom->v;
|
|
double *q = atom->q;
|
|
double **f = atom->f;
|
|
tagint *tag = atom->tag;
|
|
imageint *image = atom->image;
|
|
tagint map_tag_max = atom->map_tag_max;
|
|
|
|
for (i = 0; i < nnew; i++) {
|
|
|
|
// check if new atom matches one I own
|
|
// setting m = -1 forces new atom not to match
|
|
// NOTE: atom ID in fields is stored as double, not as ubuf
|
|
// so can only cast it to tagint, thus cannot be full 64-bit ID
|
|
|
|
mtag = static_cast<tagint> (fields[i][0]);
|
|
if (mtag <= map_tag_max) m = atom->map(mtag);
|
|
else m = -1;
|
|
if (m < 0 || m >= nlocal) continue;
|
|
|
|
updateflag[m] = 1;
|
|
newflag[i] = 0;
|
|
|
|
if (replaceflag) {
|
|
nreplace++;
|
|
|
|
// current image flags
|
|
|
|
xbox = (image[m] & IMGMASK) - IMGMAX;
|
|
ybox = (image[m] >> IMGBITS & IMGMASK) - IMGMAX;
|
|
zbox = (image[m] >> IMG2BITS) - IMGMAX;
|
|
|
|
// overwrite atom attributes with field info
|
|
// start from field 1 since 0 = id, 1 will be skipped if type
|
|
|
|
for (ifield = 1; ifield < nfield; ifield++) {
|
|
switch (fieldtype[ifield]) {
|
|
case X:
|
|
x[m][0] = xfield(i,ifield);
|
|
break;
|
|
case Y:
|
|
x[m][1] = yfield(i,ifield);
|
|
break;
|
|
case Z:
|
|
x[m][2] = zfield(i,ifield);
|
|
break;
|
|
case VX:
|
|
v[m][0] = fields[i][ifield];
|
|
break;
|
|
case Q:
|
|
q[m] = fields[i][ifield];
|
|
break;
|
|
case VY:
|
|
v[m][1] = fields[i][ifield];
|
|
break;
|
|
case VZ:
|
|
v[m][2] = fields[i][ifield];
|
|
break;
|
|
case IX:
|
|
xbox = static_cast<int> (fields[i][ifield]);
|
|
break;
|
|
case IY:
|
|
ybox = static_cast<int> (fields[i][ifield]);
|
|
break;
|
|
case IZ:
|
|
zbox = static_cast<int> (fields[i][ifield]);
|
|
break;
|
|
case FX:
|
|
f[m][0] = fields[i][ifield];
|
|
break;
|
|
case FY:
|
|
f[m][1] = fields[i][ifield];
|
|
break;
|
|
case FZ:
|
|
f[m][2] = fields[i][ifield];
|
|
break;
|
|
}
|
|
}
|
|
|
|
// replace image flag in case changed by ix,iy,iz fields or unwrapping
|
|
|
|
if (!wrapped) xbox = ybox = zbox = 0;
|
|
|
|
image[m] = ((imageint) (xbox + IMGMAX) & IMGMASK) |
|
|
(((imageint) (ybox + IMGMAX) & IMGMASK) << IMGBITS) |
|
|
(((imageint) (zbox + IMGMAX) & IMGMASK) << IMG2BITS);
|
|
}
|
|
}
|
|
|
|
// if trimflag set, delete atoms not updated by snapshot atoms
|
|
|
|
if (trimflag) {
|
|
AtomVec *avec = atom->avec;
|
|
|
|
int i = 0;
|
|
while (i < nlocal) {
|
|
if (!updateflag[i]) {
|
|
avec->copy(nlocal-1,i,1);
|
|
updateflag[i] = updateflag[nlocal-1];
|
|
nlocal--;
|
|
ntrim++;
|
|
} else i++;
|
|
}
|
|
|
|
atom->nlocal = nlocal;
|
|
bigint nblocal = atom->nlocal;
|
|
MPI_Allreduce(&nblocal,&atom->natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
|
|
}
|
|
|
|
// done if cannot add new atoms
|
|
|
|
if (addflag == NOADD) {
|
|
memory->destroy(updateflag);
|
|
memory->destroy(newflag);
|
|
return;
|
|
}
|
|
|
|
// ----------------------------------------------------
|
|
// create new atoms for dump file atoms with ID that matches no old atom
|
|
// ----------------------------------------------------
|
|
|
|
// first check that dump file snapshot has atom type field
|
|
|
|
int tflag = 0;
|
|
for (ifield = 0; ifield < nfield; ifield++)
|
|
if (fieldtype[ifield] == TYPE) tflag = 1;
|
|
if (!tflag)
|
|
error->all(FLERR,"Cannot add atoms if dump file does not store atom type");
|
|
|
|
int nlocal_previous = atom->nlocal;
|
|
double one[3];
|
|
|
|
for (i = 0; i < nnew; i++) {
|
|
if (!newflag[i]) continue;
|
|
|
|
// create type and coord fields from dump file
|
|
// coord = 0.0 unless corresponding dump file field was specified
|
|
|
|
itype = 0;
|
|
one[0] = one[1] = one[2] = 0.0;
|
|
for (ifield = 1; ifield < nfield; ifield++) {
|
|
switch (fieldtype[ifield]) {
|
|
case TYPE:
|
|
itype = static_cast<int> (fields[i][ifield]);
|
|
break;
|
|
case X:
|
|
one[0] = xfield(i,ifield);
|
|
break;
|
|
case Y:
|
|
one[1] = yfield(i,ifield);
|
|
break;
|
|
case Z:
|
|
one[2] = zfield(i,ifield);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// create the atom on proc that owns it
|
|
// reset v,image ptrs in case they are reallocated
|
|
|
|
m = atom->nlocal;
|
|
atom->avec->create_atom(itype,one);
|
|
nadd++;
|
|
|
|
tag = atom->tag;
|
|
v = atom->v;
|
|
q = atom->q;
|
|
image = atom->image;
|
|
|
|
// set atom attributes from other dump file fields
|
|
|
|
xbox = ybox = zbox = 0;
|
|
|
|
for (ifield = 0; ifield < nfield; ifield++) {
|
|
switch (fieldtype[ifield]) {
|
|
case ID:
|
|
if (addflag == KEEPADD)
|
|
tag[m] = static_cast<tagint> (fields[i][ifield]);
|
|
break;
|
|
case VX:
|
|
v[m][0] = fields[i][ifield];
|
|
break;
|
|
case VY:
|
|
v[m][1] = fields[i][ifield];
|
|
break;
|
|
case VZ:
|
|
v[m][2] = fields[i][ifield];
|
|
break;
|
|
case Q:
|
|
q[m] = fields[i][ifield];
|
|
break;
|
|
case IX:
|
|
xbox = static_cast<int> (fields[i][ifield]);
|
|
break;
|
|
case IY:
|
|
ybox = static_cast<int> (fields[i][ifield]);
|
|
break;
|
|
case IZ:
|
|
zbox = static_cast<int> (fields[i][ifield]);
|
|
break;
|
|
}
|
|
|
|
// reset image flag in case changed by ix,iy,iz fields
|
|
|
|
image[m] = ((imageint) (xbox + IMGMAX) & IMGMASK) |
|
|
(((imageint) (ybox + IMGMAX) & IMGMASK) << IMGBITS) |
|
|
(((imageint) (zbox + IMGMAX) & IMGMASK) << IMG2BITS);
|
|
}
|
|
}
|
|
|
|
// if addflag = YESADD or KEEPADD, update total atom count
|
|
|
|
if (addflag == YESADD || addflag == KEEPADD) {
|
|
bigint nblocal = atom->nlocal;
|
|
MPI_Allreduce(&nblocal,&atom->natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
|
|
}
|
|
|
|
// if addflag = YESADD,
|
|
// assign consistent IDs to new snapshot atoms across all procs
|
|
|
|
if (addflag == YESADD) {
|
|
if (atom->natoms < 0 || atom->natoms >= MAXBIGINT)
|
|
error->all(FLERR,"Too many total atoms");
|
|
if (atom->tag_enable) atom->tag_extend();
|
|
}
|
|
|
|
// init per-atom fix/compute/variable values for created atoms
|
|
|
|
atom->data_fix_compute_variable(nlocal_previous,atom->nlocal);
|
|
|
|
// free allocated vectors
|
|
|
|
memory->destroy(updateflag);
|
|
memory->destroy(newflag);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
migrate old atoms to new procs based on atom IDs
|
|
use migrate_atoms() with explicit processor assignments
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadDump::migrate_old_atoms()
|
|
{
|
|
tagint *tag = atom->tag;
|
|
int nlocal = atom->nlocal;
|
|
|
|
int *procassign;
|
|
memory->create(procassign,nlocal,"read_dump:procassign");
|
|
for (int i = 0; i < nlocal; i++)
|
|
procassign[i] = tag[i] % nprocs;
|
|
|
|
Irregular *irregular = new Irregular(lmp);
|
|
irregular->migrate_atoms(1,1,procassign);
|
|
delete irregular;
|
|
|
|
memory->destroy(procassign);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
migrate new atoms to same new procs based on atom IDs
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadDump::migrate_new_atoms()
|
|
{
|
|
tagint mtag;
|
|
int *procassign;
|
|
double **newfields;
|
|
|
|
memory->create(procassign,nnew,"read_dump:procassign");
|
|
for (int i = 0; i < nnew; i++) {
|
|
mtag = static_cast<tagint> (fields[i][0]);
|
|
procassign[i] = mtag % nprocs;
|
|
}
|
|
|
|
Irregular *irregular = new Irregular(lmp);
|
|
int nrecv = irregular->create_data(nnew,procassign,1);
|
|
int newmaxnew = MAX(nrecv,maxnew);
|
|
newmaxnew = MAX(newmaxnew,1); // avoid NULL ptr
|
|
memory->create(newfields,newmaxnew,nfield,"read_dump:newfields");
|
|
irregular->exchange_data((char *) &fields[0][0],nfield*sizeof(double),
|
|
(char *) &newfields[0][0]);
|
|
irregular->destroy_data();
|
|
delete irregular;
|
|
|
|
memory->destroy(fields);
|
|
memory->destroy(procassign);
|
|
|
|
// point fields at newfields
|
|
|
|
fields = newfields;
|
|
maxnew = newmaxnew;
|
|
nnew = nrecv;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
migrate final atoms to new procs based on atom coords
|
|
use migrate_atoms() with implicit processor assignments based on atom coords
|
|
move atoms back inside simulation box and to new processors
|
|
use remap() instead of pbc() in case atoms moved a long distance
|
|
adjust image flags of all atoms (old and new) based on current box
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReadDump::migrate_atoms_by_coords()
|
|
{
|
|
double **x = atom->x;
|
|
imageint *image = atom->image;
|
|
int nlocal = atom->nlocal;
|
|
for (int i = 0; i < nlocal; i++) domain->remap(x[i],image[i]);
|
|
|
|
if (triclinic) domain->x2lamda(atom->nlocal);
|
|
domain->reset_box();
|
|
Irregular *irregular = new Irregular(lmp);
|
|
irregular->migrate_atoms(1);
|
|
delete irregular;
|
|
if (triclinic) domain->lamda2x(atom->nlocal);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
process arg list for dump file fields and optional keywords
|
|
------------------------------------------------------------------------- */
|
|
|
|
int ReadDump::fields_and_keywords(int narg, char **arg)
|
|
{
|
|
// per-field vectors, leave space for ID and TYPE
|
|
|
|
fieldtype = new int[narg+2];
|
|
fieldlabel = new char*[narg+2];
|
|
|
|
// add id and type fields as needed
|
|
// scan ahead to see if "add yes/keep" keyword/value is used
|
|
// requires extra "type" field from from dump file
|
|
|
|
int iarg;
|
|
for (iarg = 0; iarg < narg; iarg++)
|
|
if (strcmp(arg[iarg],"add") == 0)
|
|
if (iarg < narg-1 && (strcmp(arg[iarg+1],"yes") == 0 ||
|
|
strcmp(arg[iarg+1],"keep") == 0)) break;
|
|
|
|
nfield = 0;
|
|
fieldtype[nfield++] = ID;
|
|
if (iarg < narg) fieldtype[nfield++] = TYPE;
|
|
|
|
// parse fields
|
|
|
|
iarg = 0;
|
|
while (iarg < narg) {
|
|
int type = whichtype(arg[iarg]);
|
|
if (type < 0) break;
|
|
if (type == Q && !atom->q_flag)
|
|
error->all(FLERR,"Read dump of atom property that isn't allocated");
|
|
fieldtype[nfield++] = type;
|
|
iarg++;
|
|
}
|
|
|
|
// check for no fields
|
|
|
|
if (fieldtype[nfield-1] == ID || fieldtype[nfield-1] == TYPE)
|
|
error->all(FLERR,"Illegal read_dump command");
|
|
|
|
if (dimension == 2) {
|
|
for (int i = 0; i < nfield; i++)
|
|
if (fieldtype[i] == Z || fieldtype[i] == VZ ||
|
|
fieldtype[i] == IZ || fieldtype[i] == FZ)
|
|
error->all(FLERR,"Illegal read_dump command");
|
|
}
|
|
|
|
for (int i = 0; i < nfield; i++)
|
|
for (int j = i+1; j < nfield; j++)
|
|
if (fieldtype[i] == fieldtype[j])
|
|
error->all(FLERR,"Duplicate fields in read_dump command");
|
|
|
|
// parse optional args
|
|
|
|
multiproc_nfile = 0;
|
|
boxflag = 1;
|
|
replaceflag = 1;
|
|
purgeflag = 0;
|
|
trimflag = 0;
|
|
addflag = NOADD;
|
|
for (int i = 0; i < nfield; i++) fieldlabel[i] = NULL;
|
|
scaleflag = 0;
|
|
wrapflag = 1;
|
|
|
|
while (iarg < narg) {
|
|
if (strcmp(arg[iarg],"nfile") == 0) {
|
|
if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
|
|
multiproc_nfile = force->inumeric(FLERR,arg[iarg+1]);
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg],"box") == 0) {
|
|
if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
|
|
if (strcmp(arg[iarg+1],"yes") == 0) boxflag = 1;
|
|
else if (strcmp(arg[iarg+1],"no") == 0) boxflag = 0;
|
|
else error->all(FLERR,"Illegal read_dump command");
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg],"replace") == 0) {
|
|
if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
|
|
if (strcmp(arg[iarg+1],"yes") == 0) replaceflag = 1;
|
|
else if (strcmp(arg[iarg+1],"no") == 0) replaceflag = 0;
|
|
else error->all(FLERR,"Illegal read_dump command");
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg],"purge") == 0) {
|
|
if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
|
|
if (strcmp(arg[iarg+1],"yes") == 0) purgeflag = 1;
|
|
else if (strcmp(arg[iarg+1],"no") == 0) purgeflag = 0;
|
|
else error->all(FLERR,"Illegal read_dump command");
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg],"trim") == 0) {
|
|
if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
|
|
if (strcmp(arg[iarg+1],"yes") == 0) trimflag = 1;
|
|
else if (strcmp(arg[iarg+1],"no") == 0) trimflag = 0;
|
|
else error->all(FLERR,"Illegal read_dump command");
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg],"add") == 0) {
|
|
if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
|
|
if (strcmp(arg[iarg+1],"yes") == 0) addflag = YESADD;
|
|
else if (strcmp(arg[iarg+1],"no") == 0) addflag = NOADD;
|
|
else if (strcmp(arg[iarg+1],"keep") == 0) addflag = KEEPADD;
|
|
else error->all(FLERR,"Illegal read_dump command");
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg],"label") == 0) {
|
|
if (iarg+3 > narg) error->all(FLERR,"Illegal read_dump command");
|
|
int type = whichtype(arg[iarg+1]);
|
|
int i;
|
|
for (i = 0; i < nfield; i++)
|
|
if (type == fieldtype[i]) break;
|
|
if (i == nfield) error->all(FLERR,"Illegal read_dump command");
|
|
int n = strlen(arg[iarg+2]) + 1;
|
|
fieldlabel[i] = new char[n];
|
|
strcpy(fieldlabel[i],arg[iarg+2]);
|
|
iarg += 3;
|
|
} else if (strcmp(arg[iarg],"scaled") == 0) {
|
|
if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
|
|
if (strcmp(arg[iarg+1],"yes") == 0) scaleflag = 1;
|
|
else if (strcmp(arg[iarg+1],"no") == 0) scaleflag = 0;
|
|
else error->all(FLERR,"Illegal read_dump command");
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg],"wrapped") == 0) {
|
|
if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
|
|
if (strcmp(arg[iarg+1],"yes") == 0) wrapflag = 1;
|
|
else if (strcmp(arg[iarg+1],"no") == 0) wrapflag = 0;
|
|
else error->all(FLERR,"Illegal read_dump command");
|
|
iarg += 2;
|
|
} else if (strcmp(arg[iarg],"format") == 0) {
|
|
if (iarg+2 > narg) error->all(FLERR,"Illegal read_dump command");
|
|
delete [] readerstyle;
|
|
int n = strlen(arg[iarg+1]) + 1;
|
|
readerstyle = new char[n];
|
|
strcpy(readerstyle,arg[iarg+1]);
|
|
iarg += 2;
|
|
break;
|
|
} else error->all(FLERR,"Illegal read_dump command");
|
|
}
|
|
|
|
if (multiproc == 0 && multiproc_nfile)
|
|
error->all(FLERR,"Dump file is not a multi-proc file");
|
|
if (multiproc && multiproc_nfile == 0)
|
|
error->all(FLERR,"Dump file is a multi-proc file");
|
|
|
|
if (purgeflag && (replaceflag || trimflag))
|
|
error->all(FLERR,"If read_dump purges it cannot replace or trim");
|
|
if (addflag == KEEPADD && atom->tag_enable == 0)
|
|
error->all(FLERR,"Read_dump cannot use 'add keep' without atom IDs");
|
|
|
|
return narg-iarg;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
check if str is a field argument
|
|
if yes, return index of which
|
|
if not, return -1
|
|
------------------------------------------------------------------------- */
|
|
|
|
int ReadDump::whichtype(char *str)
|
|
{
|
|
int type = -1;
|
|
if (strcmp(str,"id") == 0) type = ID;
|
|
else if (strcmp(str,"type") == 0) type = TYPE;
|
|
else if (strcmp(str,"x") == 0) type = X;
|
|
else if (strcmp(str,"y") == 0) type = Y;
|
|
else if (strcmp(str,"z") == 0) type = Z;
|
|
else if (strcmp(str,"vx") == 0) type = VX;
|
|
else if (strcmp(str,"vy") == 0) type = VY;
|
|
else if (strcmp(str,"vz") == 0) type = VZ;
|
|
else if (strcmp(str,"q") == 0) type = Q;
|
|
else if (strcmp(str,"ix") == 0) type = IX;
|
|
else if (strcmp(str,"iy") == 0) type = IY;
|
|
else if (strcmp(str,"iz") == 0) type = IZ;
|
|
else if (strcmp(str,"fx") == 0) type = FX;
|
|
else if (strcmp(str,"fy") == 0) type = FY;
|
|
else if (strcmp(str,"fz") == 0) type = FZ;
|
|
return type;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
convert XYZ fields in dump file into absolute, unscaled coordinates
|
|
depends on scaled vs unscaled and triclinic vs orthogonal
|
|
does not depend on wrapped vs unwrapped
|
|
------------------------------------------------------------------------- */
|
|
|
|
double ReadDump::xfield(int i, int j)
|
|
{
|
|
if (!scaled) return fields[i][j];
|
|
else if (!triclinic) return fields[i][j]*xprd + xlo;
|
|
else if (dimension == 2)
|
|
return xprd*fields[i][j] + xy*fields[i][yindex] + xlo;
|
|
return xprd*fields[i][j] + xy*fields[i][yindex] + xz*fields[i][zindex] + xlo;
|
|
}
|
|
|
|
double ReadDump::yfield(int i, int j)
|
|
{
|
|
if (!scaled) return fields[i][j];
|
|
else if (!triclinic) return fields[i][j]*yprd + ylo;
|
|
else if (dimension == 2) return yprd*fields[i][j] + ylo;
|
|
return yprd*fields[i][j] + yz*fields[i][zindex] + ylo;
|
|
}
|
|
|
|
double ReadDump::zfield(int i, int j)
|
|
{
|
|
if (!scaled) return fields[i][j];
|
|
return fields[i][j]*zprd + zlo;
|
|
}
|