231 lines
6.7 KiB
C++
231 lines
6.7 KiB
C++
/* ----------------------------------------------------------------------
|
|
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
|
https://www.lammps.org/, Sandia National Laboratories
|
|
LAMMPS development team: developers@lammps.org
|
|
|
|
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: Axel Kohlmeyer (Temple U)
|
|
------------------------------------------------------------------------- */
|
|
|
|
#include "reader_xyz.h"
|
|
|
|
#include "atom.h"
|
|
#include "error.h"
|
|
#include "label_map.h"
|
|
#include "memory.h"
|
|
#include "tokenizer.h"
|
|
|
|
using namespace LAMMPS_NS;
|
|
|
|
static constexpr int MAXLINE = 1024; // max line length in dump file
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
ReaderXYZ::ReaderXYZ(LAMMPS *lmp) : Reader(lmp)
|
|
{
|
|
line = new char[MAXLINE];
|
|
fieldindex = nullptr;
|
|
nstep = 0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
ReaderXYZ::~ReaderXYZ()
|
|
{
|
|
delete[] line;
|
|
memory->destroy(fieldindex);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
read and return time stamp from dump file
|
|
if first read reaches end-of-file, return 1 so caller can open next file
|
|
only called by proc 0
|
|
------------------------------------------------------------------------- */
|
|
|
|
int ReaderXYZ::read_time(bigint &ntimestep)
|
|
{
|
|
char *eof = fgets(line, MAXLINE, fp);
|
|
if (eof == nullptr) return 1;
|
|
|
|
// first line has to have the number of atoms
|
|
// truncate the string to the first whitespace,
|
|
// so force->bnumeric() does not hiccup
|
|
|
|
for (int i = 0; (i < MAXLINE) && (eof[i] != '\0'); ++i) {
|
|
if (eof[i] == '\n' || eof[i] == '\r' || eof[i] == ' ' || eof[i] == '\t') {
|
|
eof[i] = '\0';
|
|
break;
|
|
}
|
|
}
|
|
natoms = utils::bnumeric(FLERR, line, false, lmp);
|
|
if (natoms < 1) error->one(FLERR, "Dump file is incorrectly formatted");
|
|
|
|
// skip over comment/title line
|
|
|
|
read_lines(1);
|
|
|
|
// fake time step numbers
|
|
|
|
ntimestep = nstep;
|
|
|
|
// count this frame
|
|
|
|
++nstep;
|
|
return 0;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
skip snapshot from timestamp onward
|
|
only called by proc 0
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReaderXYZ::skip()
|
|
{
|
|
// invoke read_lines() in chunks no larger than MAXSMALLINT
|
|
|
|
bigint nchunk;
|
|
bigint nremain = natoms;
|
|
while (nremain) {
|
|
nchunk = MIN(nremain, MAXSMALLINT);
|
|
read_lines((int) nchunk);
|
|
nremain -= nchunk;
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
read remaining header info:
|
|
return natoms
|
|
box bounds, triclinic (inferred), fieldflag (1 if any fields not found),
|
|
xyz flags = from input scaleflag & wrapflag
|
|
if fieldflag set:
|
|
match Nfield fields to per-atom column labels
|
|
allocate and set fieldindex = which column each field maps to
|
|
fieldtype = X,VX,IZ etc
|
|
fieldlabel = user-specified label or nullptr if use fieldtype default
|
|
xyz flag = scaledflag if has fieldlabel name, else set by x,xs,xu,xsu
|
|
only called by proc 0
|
|
------------------------------------------------------------------------- */
|
|
|
|
bigint ReaderXYZ::read_header(double /*box*/[3][3], int &boxinfo, int & /*triclinic*/,
|
|
int fieldinfo, int nfield, int *fieldtype, char ** /*fieldlabel*/,
|
|
int scaleflag, int wrapflag, int &fieldflag, int &xflag, int &yflag,
|
|
int &zflag)
|
|
{
|
|
|
|
nid = 0;
|
|
|
|
// signal that we have no box info at all
|
|
|
|
boxinfo = 0;
|
|
|
|
// if no field info requested, just return
|
|
|
|
if (!fieldinfo) return natoms;
|
|
|
|
memory->create(fieldindex, nfield, "read_dump:fieldindex");
|
|
|
|
// for xyz we know nothing about the style of coordinates,
|
|
// so caller has to set the proper flags
|
|
|
|
xflag = 2 * scaleflag + wrapflag + 1;
|
|
yflag = 2 * scaleflag + wrapflag + 1;
|
|
zflag = 2 * scaleflag + wrapflag + 1;
|
|
|
|
// copy fieldtype list for supported fields
|
|
|
|
fieldflag = 0;
|
|
for (int i = 0; i < nfield; i++) {
|
|
if ((fieldtype[i] == X) || (fieldtype[i] == Y) || (fieldtype[i] == Z) || (fieldtype[i] == ID) ||
|
|
(fieldtype[i] == TYPE)) {
|
|
fieldindex[i] = fieldtype[i];
|
|
} else {
|
|
fieldflag = 1;
|
|
}
|
|
}
|
|
|
|
return natoms;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
read N atom lines from dump file
|
|
stores appropriate values in fields array
|
|
return 0 if success, 1 if error
|
|
only called by proc 0
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReaderXYZ::read_atoms(int n, int nfield, double **fields)
|
|
{
|
|
int i, m;
|
|
char *eof;
|
|
int mytype;
|
|
double myx, myy, myz;
|
|
|
|
try {
|
|
for (i = 0; i < n; i++) {
|
|
eof = fgets(line, MAXLINE, fp);
|
|
if (eof == nullptr) error->one(FLERR, "Unexpected end of dump file");
|
|
|
|
++nid;
|
|
|
|
auto values = ValueTokenizer(line);
|
|
auto label = values.next_string();
|
|
|
|
// must have a complete atom type label map to parse xyz files with string labels
|
|
if (!utils::is_integer(label)) {
|
|
if (!atom->labelmapflag || !atom->lmap->is_complete(Atom::ATOM))
|
|
error->one(FLERR, "Must define atom labelmap to parse XYZ files with strings for types");
|
|
}
|
|
mytype = utils::expand_type_int(FLERR, label, Atom::ATOM, lmp);
|
|
myx = values.next_double();
|
|
myy = values.next_double();
|
|
myz = values.next_double();
|
|
|
|
for (m = 0; m < nfield; m++) {
|
|
switch (fieldindex[m]) {
|
|
case X:
|
|
fields[i][m] = myx;
|
|
break;
|
|
case Y:
|
|
fields[i][m] = myy;
|
|
break;
|
|
case Z:
|
|
fields[i][m] = myz;
|
|
break;
|
|
case ID:
|
|
fields[i][m] = nid;
|
|
break;
|
|
case TYPE:
|
|
fields[i][m] = mytype;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
} catch (TokenizerException &e) {
|
|
error->one(FLERR, "Error reading xyz file: {}", e.what());
|
|
} catch (LAMMPSAbortException &e) {
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
read N lines from dump file
|
|
only last one is saved in line
|
|
only called by proc 0
|
|
------------------------------------------------------------------------- */
|
|
|
|
void ReaderXYZ::read_lines(int n)
|
|
{
|
|
char *eof = nullptr;
|
|
if (n <= 0) return;
|
|
for (int i = 0; i < n; i++) eof = fgets(line, MAXLINE, fp);
|
|
if (eof == nullptr) error->one(FLERR, "Unexpected end of dump file");
|
|
}
|