Merge pull request #2136 from rbberger/refactor-reading

Refactor value parsing code segments and add dump tests
This commit is contained in:
Axel Kohlmeyer 2020-08-18 16:18:33 -04:00 committed by GitHub
commit 43f6fa4b29
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 2222 additions and 549 deletions

View File

@ -166,8 +166,83 @@ void DumpAtom::write_data(int n, double *mybuf)
/* ---------------------------------------------------------------------- */
void DumpAtom::format_magic_string_binary()
{
// use negative ntimestep as marker for new format
bigint fmtlen = strlen(MAGIC_STRING);
bigint marker = -fmtlen;
fwrite(&marker, sizeof(bigint), 1, fp);
fwrite(MAGIC_STRING, sizeof(char), fmtlen, fp);
}
/* ---------------------------------------------------------------------- */
void DumpAtom::format_endian_binary()
{
int endian = ENDIAN;
fwrite(&endian, sizeof(int), 1, fp);
}
/* ---------------------------------------------------------------------- */
void DumpAtom::format_revision_binary()
{
int revision = FORMAT_REVISION;
fwrite(&revision, sizeof(int), 1, fp);
}
/* ---------------------------------------------------------------------- */
void DumpAtom::header_unit_style_binary()
{
int len = 0;
if (unit_flag && !unit_count) {
++unit_count;
len = strlen(update->unit_style);
fwrite(&len, sizeof(int), 1, fp);
fwrite(update->unit_style, sizeof(char), len, fp);
} else {
fwrite(&len, sizeof(int), 1, fp);
}
}
/* ---------------------------------------------------------------------- */
void DumpAtom::header_columns_binary()
{
int len = strlen(columns);
fwrite(&len, sizeof(int), 1, fp);
fwrite(columns, sizeof(char), len, fp);
}
/* ---------------------------------------------------------------------- */
void DumpAtom::header_time_binary()
{
char flag = time_flag ? 1 : 0;
fwrite(&flag, sizeof(char), 1, fp);
if (time_flag) {
double t = compute_time();
fwrite(&t, sizeof(double), 1, fp);
}
}
/* ---------------------------------------------------------------------- */
void DumpAtom::header_format_binary()
{
format_magic_string_binary();
format_endian_binary();
format_revision_binary();
}
/* ---------------------------------------------------------------------- */
void DumpAtom::header_binary(bigint ndump)
{
header_format_binary();
fwrite(&update->ntimestep,sizeof(bigint),1,fp);
fwrite(&ndump,sizeof(bigint),1,fp);
fwrite(&domain->triclinic,sizeof(int),1,fp);
@ -179,6 +254,11 @@ void DumpAtom::header_binary(bigint ndump)
fwrite(&boxzlo,sizeof(double),1,fp);
fwrite(&boxzhi,sizeof(double),1,fp);
fwrite(&size_one,sizeof(int),1,fp);
header_unit_style_binary();
header_time_binary();
header_columns_binary();
if (multiproc) fwrite(&nclusterprocs,sizeof(int),1,fp);
else fwrite(&nprocs,sizeof(int),1,fp);
}
@ -187,6 +267,8 @@ void DumpAtom::header_binary(bigint ndump)
void DumpAtom::header_binary_triclinic(bigint ndump)
{
header_format_binary();
fwrite(&update->ntimestep,sizeof(bigint),1,fp);
fwrite(&ndump,sizeof(bigint),1,fp);
fwrite(&domain->triclinic,sizeof(int),1,fp);
@ -201,6 +283,11 @@ void DumpAtom::header_binary_triclinic(bigint ndump)
fwrite(&boxxz,sizeof(double),1,fp);
fwrite(&boxyz,sizeof(double),1,fp);
fwrite(&size_one,sizeof(int),1,fp);
header_unit_style_binary();
header_time_binary();
header_columns_binary();
if (multiproc) fwrite(&nclusterprocs,sizeof(int),1,fp);
else fwrite(&nprocs,sizeof(int),1,fp);
}

View File

@ -28,6 +28,10 @@ class DumpAtom : public Dump {
public:
DumpAtom(LAMMPS *, int, char**);
const char * MAGIC_STRING = "DUMPATOM";
const int FORMAT_REVISION = 0x0002;
const int ENDIAN = 0x0001;
protected:
int scale_flag; // 1 if atom coords are scaled, 0 if no
int image_flag; // 1 if append box count to atom coords, 0 if no
@ -41,6 +45,14 @@ class DumpAtom : public Dump {
int convert_string(int, double *);
void write_data(int, double *);
void header_format_binary();
void header_unit_style_binary();
void header_time_binary();
void header_columns_binary();
void format_magic_string_binary();
void format_endian_binary();
void format_revision_binary();
typedef void (DumpAtom::*FnPtrHeader)(bigint);
FnPtrHeader header_choice; // ptr to write header functions
void header_binary(bigint);

View File

@ -183,7 +183,7 @@ DumpCustom::DumpCustom(LAMMPS *lmp, int narg, char **arg) :
columns[0] = '\0';
for (int iarg = 0; iarg < nfield; iarg++) {
strcat(columns,earg[iarg]);
strcat(columns," ");
if (iarg+1 < nfield) strcat(columns," ");
}
}
@ -302,7 +302,7 @@ void DumpCustom::init_style()
strcpy(vformat[i],ptr);
}
vformat[i] = strcat(vformat[i]," ");
if (i+1 < size_one) vformat[i] = strcat(vformat[i]," ");
}
// setup boundary string
@ -381,8 +381,83 @@ void DumpCustom::write_header(bigint ndump)
/* ---------------------------------------------------------------------- */
void DumpCustom::format_magic_string_binary()
{
// use negative ntimestep as marker for new format
bigint fmtlen = strlen(MAGIC_STRING);
bigint marker = -fmtlen;
fwrite(&marker, sizeof(bigint), 1, fp);
fwrite(MAGIC_STRING, sizeof(char), fmtlen, fp);
}
/* ---------------------------------------------------------------------- */
void DumpCustom::format_endian_binary()
{
int endian = ENDIAN;
fwrite(&endian, sizeof(int), 1, fp);
}
/* ---------------------------------------------------------------------- */
void DumpCustom::format_revision_binary()
{
int revision = FORMAT_REVISION;
fwrite(&revision, sizeof(int), 1, fp);
}
/* ---------------------------------------------------------------------- */
void DumpCustom::header_unit_style_binary()
{
int len = 0;
if (unit_flag && !unit_count) {
++unit_count;
len = strlen(update->unit_style);
fwrite(&len, sizeof(int), 1, fp);
fwrite(update->unit_style, sizeof(char), len, fp);
} else {
fwrite(&len, sizeof(int), 1, fp);
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::header_columns_binary()
{
int len = strlen(columns);
fwrite(&len, sizeof(int), 1, fp);
fwrite(columns, sizeof(char), len, fp);
}
/* ---------------------------------------------------------------------- */
void DumpCustom::header_time_binary()
{
char flag = time_flag ? 1 : 0;
fwrite(&flag, sizeof(char), 1, fp);
if (time_flag) {
double t = compute_time();
fwrite(&t, sizeof(double), 1, fp);
}
}
/* ---------------------------------------------------------------------- */
void DumpCustom::header_format_binary()
{
format_magic_string_binary();
format_endian_binary();
format_revision_binary();
}
/* ---------------------------------------------------------------------- */
void DumpCustom::header_binary(bigint ndump)
{
header_format_binary();
fwrite(&update->ntimestep,sizeof(bigint),1,fp);
fwrite(&ndump,sizeof(bigint),1,fp);
fwrite(&domain->triclinic,sizeof(int),1,fp);
@ -394,6 +469,11 @@ void DumpCustom::header_binary(bigint ndump)
fwrite(&boxzlo,sizeof(double),1,fp);
fwrite(&boxzhi,sizeof(double),1,fp);
fwrite(&size_one,sizeof(int),1,fp);
header_unit_style_binary();
header_time_binary();
header_columns_binary();
if (multiproc) fwrite(&nclusterprocs,sizeof(int),1,fp);
else fwrite(&nprocs,sizeof(int),1,fp);
}
@ -402,6 +482,8 @@ void DumpCustom::header_binary(bigint ndump)
void DumpCustom::header_binary_triclinic(bigint ndump)
{
header_format_binary();
fwrite(&update->ntimestep,sizeof(bigint),1,fp);
fwrite(&ndump,sizeof(bigint),1,fp);
fwrite(&domain->triclinic,sizeof(int),1,fp);
@ -416,6 +498,11 @@ void DumpCustom::header_binary_triclinic(bigint ndump)
fwrite(&boxxz,sizeof(double),1,fp);
fwrite(&boxyz,sizeof(double),1,fp);
fwrite(&size_one,sizeof(int),1,fp);
header_unit_style_binary();
header_time_binary();
header_columns_binary();
if (multiproc) fwrite(&nclusterprocs,sizeof(int),1,fp);
else fwrite(&nprocs,sizeof(int),1,fp);
}

View File

@ -29,6 +29,10 @@ class DumpCustom : public Dump {
DumpCustom(class LAMMPS *, int, char **);
virtual ~DumpCustom();
const char * MAGIC_STRING = "DUMPCUSTOM";
const int FORMAT_REVISION = 0x0002;
const int ENDIAN = 0x0001;
protected:
int nevery; // dump frequency for output
int iregion; // -1 if no region, else which region
@ -107,6 +111,14 @@ class DumpCustom : public Dump {
int add_custom(char *, int);
virtual int modify_param(int, char **);
void header_format_binary();
void header_unit_style_binary();
void header_time_binary();
void header_columns_binary();
void format_magic_string_binary();
void format_endian_binary();
void format_revision_binary();
typedef void (DumpCustom::*FnPtrHeader)(bigint);
FnPtrHeader header_choice; // ptr to write header functions
void header_binary(bigint);

View File

@ -1243,6 +1243,26 @@ string Info::get_openmp_info()
#endif
}
string Info::get_mpi_vendor() {
#if defined(MPI_STUBS)
return "MPI STUBS";
#elif defined(OPEN_MPI)
return "Open MPI";
#elif defined(MPICH_NAME)
return "MPICH";
#elif defined(I_MPI_VERSION)
return "Intel MPI";
#elif defined(PLATFORM_MPI)
return "Platform MPI";
#elif defined(HP_MPI)
return "HP MPI";
#elif defined(MSMPI_VER)
return "Microsoft MPI";
#else
return "Unknown";
#endif
}
string Info::get_mpi_info(int &major, int &minor)
{
int len;

View File

@ -48,6 +48,7 @@ class Info : protected Pointers {
static std::string get_os_info();
static std::string get_compiler_info();
static std::string get_openmp_info();
static std::string get_mpi_vendor();
static std::string get_mpi_info(int &, int &);
static std::string get_cxx_info();

View File

@ -91,33 +91,6 @@ using namespace LAMMPS_NS;
#define END_CAPTURE
#endif
// ----------------------------------------------------------------------
// helper functions, not in library API
// ----------------------------------------------------------------------
/* ----------------------------------------------------------------------
concatenate one or more LAMMPS input lines starting at ptr
removes NULL terminator when last printable char of line = '&'
by replacing both NULL and '&' with space character
repeat as many times as needed
on return, ptr now points to longer line
------------------------------------------------------------------------- */
void concatenate_lines(char *ptr)
{
int nend = strlen(ptr);
int n = nend-1;
while (n && isspace(ptr[n])) n--;
while (ptr[n] == '&') {
ptr[nend] = ' ';
ptr[n] = ' ';
strtok(ptr,"\n");
nend = strlen(ptr);
n = nend-1;
while (n && isspace(ptr[n])) n--;
}
}
// ----------------------------------------------------------------------
// library API functions to create/destroy an instance of LAMMPS
// and communicate commands to it

View File

@ -27,6 +27,7 @@
#include "error.h"
#include "utils.h"
#include "fmt/format.h"
#include "tokenizer.h"
using namespace LAMMPS_NS;
@ -47,7 +48,7 @@ Molecule::Molecule(LAMMPS *lmp, int narg, char **arg, int &index) :
improper_type(NULL), improper_atom1(NULL), improper_atom2(NULL),
improper_atom3(NULL), improper_atom4(NULL), nspecial(NULL), special(NULL),
shake_flag(NULL), shake_atom(NULL), shake_type(NULL), avec_body(NULL), ibodyparams(NULL),
dbodyparams(NULL), fragmentmask(NULL), fragmentnames(NULL),
dbodyparams(NULL), fragmentmask(NULL),
dx(NULL), dxcom(NULL), dxbody(NULL), quat_external(NULL), fp(NULL), count(NULL)
{
me = comm->me;
@ -424,65 +425,77 @@ void Molecule::read(int flag)
if (strspn(line," \t\n\r") == strlen(line)) continue;
// search line for header keywords and set corresponding variable
try {
ValueTokenizer values(line);
int nmatch = 0;
int nwant = 0;
if (strstr(line,"atoms")) {
nmatch = sscanf(line,"%d",&natoms);
nwant = 1;
} else if (strstr(line,"bonds")) {
nmatch = sscanf(line,"%d",&nbonds);
nwant = 1;
} else if (strstr(line,"angles")) {
nmatch = sscanf(line,"%d",&nangles);
nwant = 1;
} else if (strstr(line,"dihedrals")) {
nmatch = sscanf(line,"%d",&ndihedrals);
nwant = 1;
} else if (strstr(line,"impropers")) {
nmatch = sscanf(line,"%d",&nimpropers);
nwant = 1;
} else if (strstr(line,"fragments")) {
nmatch = sscanf(line,"%d",&nfragments);
nwant = 1;
} else if (strstr(line,"mass")) {
massflag = 1;
nmatch = sscanf(line,"%lg",&masstotal);
nwant = 1;
masstotal *= sizescale*sizescale*sizescale;
} else if (strstr(line,"com")) {
comflag = 1;
nmatch = sscanf(line,"%lg %lg %lg",&com[0],&com[1],&com[2]);
nwant = 3;
com[0] *= sizescale;
com[1] *= sizescale;
com[2] *= sizescale;
if (domain->dimension == 2 && com[2] != 0.0)
error->all(FLERR,"Molecule file z center-of-mass must be 0.0 for 2d");
} else if (strstr(line,"inertia")) {
inertiaflag = 1;
nmatch = sscanf(line,"%lg %lg %lg %lg %lg %lg",
&itensor[0],&itensor[1],&itensor[2],
&itensor[3],&itensor[4],&itensor[5]);
nwant = 6;
const double scale5 = sizescale*sizescale*sizescale*sizescale*sizescale;
itensor[0] *= scale5;
itensor[1] *= scale5;
itensor[2] *= scale5;
itensor[3] *= scale5;
itensor[4] *= scale5;
itensor[5] *= scale5;
} else if (strstr(line,"body")) {
bodyflag = 1;
avec_body = (AtomVecBody *) atom->style_match("body");
if (!avec_body)
error->all(FLERR,"Molecule file requires atom style body");
nmatch = sscanf(line,"%d %d",&nibody,&ndbody);
nwant = 2;
} else break;
int nmatch = values.count();
int nwant = 0;
if (values.contains("atoms")) {
natoms = values.next_int();
nwant = 2;
} else if (values.contains("bonds")) {
nbonds = values.next_int();
nwant = 2;
} else if (values.contains("angles")) {
nangles = values.next_int();
nwant = 2;
} else if (values.contains("dihedrals")) {
ndihedrals = values.next_int();
nwant = 2;
} else if (values.contains("impropers")) {
nimpropers = values.next_int();
nwant = 2;
} else if (values.contains("fragments")) {
nfragments = values.next_int();
nwant = 2;
} else if (values.contains("mass")) {
massflag = 1;
masstotal = values.next_double();
nwant = 2;
masstotal *= sizescale*sizescale*sizescale;
} else if (values.contains("com")) {
comflag = 1;
com[0] = values.next_double();
com[1] = values.next_double();
com[2] = values.next_double();
nwant = 4;
com[0] *= sizescale;
com[1] *= sizescale;
com[2] *= sizescale;
if (domain->dimension == 2 && com[2] != 0.0)
error->all(FLERR,"Molecule file z center-of-mass must be 0.0 for 2d");
} else if (values.contains("inertia")) {
inertiaflag = 1;
itensor[0] = values.next_double();
itensor[1] = values.next_double();
itensor[2] = values.next_double();
itensor[3] = values.next_double();
itensor[4] = values.next_double();
itensor[5] = values.next_double();
nwant = 7;
const double scale5 = sizescale*sizescale*sizescale*sizescale*sizescale;
itensor[0] *= scale5;
itensor[1] *= scale5;
itensor[2] *= scale5;
itensor[3] *= scale5;
itensor[4] *= scale5;
itensor[5] *= scale5;
} else if (values.contains("body")) {
bodyflag = 1;
avec_body = (AtomVecBody *) atom->style_match("body");
if (!avec_body)
error->all(FLERR,"Molecule file requires atom style body");
nibody = values.next_int();
ndbody = values.next_int();
nwant = 3;
} else break;
if (nmatch != nwant)
error->all(FLERR,"Invalid header in molecule file");
if (nmatch != nwant)
error->one(FLERR,"Invalid header in molecule file");
} catch (TokenizerException & e) {
error->one(FLERR, fmt::format("Invalid header in molecule file\n"
"{}", e.what()));
}
}
// error checks
@ -659,15 +672,25 @@ void Molecule::read(int flag)
void Molecule::coords(char *line)
{
int tmp;
for (int i = 0; i < natoms; i++) {
readline(line);
if (4 != sscanf(line,"%d %lg %lg %lg",&tmp,&x[i][0],&x[i][1],&x[i][2]))
error->all(FLERR,"Invalid Coords section in molecule file");
try {
for (int i = 0; i < natoms; i++) {
readline(line);
x[i][0] *= sizescale;
x[i][1] *= sizescale;
x[i][2] *= sizescale;
ValueTokenizer values(line);
if (values.count() != 4) error->one(FLERR,"Invalid Coords section in molecule file");
values.next_int();
x[i][0] = values.next_double();
x[i][1] = values.next_double();
x[i][2] = values.next_double();
x[i][0] *= sizescale;
x[i][1] *= sizescale;
x[i][2] *= sizescale;
}
} catch (TokenizerException & e) {
error->one(FLERR, fmt::format("Invalid Coords section in molecule file\n"
"{}", e.what()));
}
if (domain->dimension == 2) {
@ -684,12 +707,20 @@ void Molecule::coords(char *line)
void Molecule::types(char *line)
{
int tmp;
for (int i = 0; i < natoms; i++) {
readline(line);
if (2 != sscanf(line,"%d %d",&tmp,&type[i]))
error->all(FLERR,"Invalid Types section in molecule file");
type[i] += toffset;
try {
for (int i = 0; i < natoms; i++) {
readline(line);
ValueTokenizer values(line);
if (values.count() != 2) error->one(FLERR,"Invalid Types section in molecule file");
values.next_int();
type[i] = values.next_int();
type[i] += toffset;
}
} catch (TokenizerException & e) {
error->one(FLERR, fmt::format("Invalid Types section in molecule file\n"
"{}", e.what()));
}
for (int i = 0; i < natoms; i++)
@ -707,12 +738,19 @@ void Molecule::types(char *line)
void Molecule::molecules(char *line)
{
int tmp;
for (int i = 0; i < natoms; i++) {
readline(line);
if (2 != sscanf(line,"%d %d",&tmp,&molecule[i]))
error->all(FLERR,"Invalid Molecules section in molecule file");
// molecule[i] += moffset; // placeholder for possible molecule offset
try {
for (int i = 0; i < natoms; i++) {
readline(line);
ValueTokenizer values(line);
if (values.count() != 2) error->one(FLERR,"Invalid Molecules section in molecule file");
values.next_int();
molecule[i] = values.next_int();
// molecule[i] += moffset; // placeholder for possible molecule offset
}
} catch (TokenizerException & e) {
error->one(FLERR, fmt::format("Invalid Molecules section in molecule file\n"
"{}", e.what()));
}
for (int i = 0; i < natoms; i++)
@ -729,27 +767,28 @@ void Molecule::molecules(char *line)
void Molecule::fragments(char *line)
{
int n,m,atomID,nwords;
char **words = new char*[natoms+1];
try {
for (int i = 0; i < nfragments; i++) {
readline(line);
for (int i = 0; i < nfragments; i++) {
readline(line);
nwords = parse(line,words,natoms+1);
if (nwords > natoms+1)
error->all(FLERR,"Invalid atom ID in Fragments section of molecule file");
n = strlen(words[0]) + 1;
fragmentnames[i] = new char[n];
strcpy(fragmentnames[i],words[0]);
ValueTokenizer values(line);
for (m = 1; m < nwords; m++) {
atomID = atoi(words[m]);
if (atomID <= 0 || atomID > natoms)
error->all(FLERR,"Invalid atom ID in Fragments section of molecule file");
fragmentmask[i][atomID-1] = 1;
if (values.count() > natoms+1)
error->one(FLERR,"Invalid atom ID in Fragments section of molecule file");
fragmentnames[i] = values.next_string();
while(values.has_next()) {
int atomID = values.next_int();
if (atomID <= 0 || atomID > natoms)
error->one(FLERR,"Invalid atom ID in Fragments section of molecule file");
fragmentmask[i][atomID-1] = 1;
}
}
} catch (TokenizerException & e) {
error->one(FLERR, fmt::format("Invalid atom ID in Fragments section of molecule file\n"
"{}", e.what()));
}
delete [] words;
}
/* ----------------------------------------------------------------------
@ -758,11 +797,19 @@ void Molecule::fragments(char *line)
void Molecule::charges(char *line)
{
int tmp;
for (int i = 0; i < natoms; i++) {
readline(line);
if (2 != sscanf(line,"%d %lg",&tmp,&q[i]))
error->all(FLERR,"Invalid Charges section in molecule file");
try {
for (int i = 0; i < natoms; i++) {
readline(line);
ValueTokenizer values(line);
if (values.count() != 2) error->one(FLERR,"Invalid Charges section in molecule file");
values.next_int();
q[i] = values.next_double();
}
} catch (TokenizerException & e) {
error->one(FLERR, fmt::format("Invalid Charges section in molecule file\n"
"{}", e.what()));
}
}
@ -772,15 +819,23 @@ void Molecule::charges(char *line)
void Molecule::diameters(char *line)
{
int tmp;
maxradius = 0.0;
for (int i = 0; i < natoms; i++) {
readline(line);
if (2 != sscanf(line,"%d %lg",&tmp,&radius[i]))
error->all(FLERR,"Invalid Diameters section in molecule file");
radius[i] *= sizescale;
radius[i] *= 0.5;
maxradius = MAX(maxradius,radius[i]);
try {
maxradius = 0.0;
for (int i = 0; i < natoms; i++) {
readline(line);
ValueTokenizer values(line);
if (values.count() != 2) error->one(FLERR,"Invalid Diameters section in molecule file");
values.next_int();
radius[i] = values.next_double();
radius[i] *= sizescale;
radius[i] *= 0.5;
maxradius = MAX(maxradius,radius[i]);
}
} catch (TokenizerException & e) {
error->one(FLERR, fmt::format("Invalid Diameters section in molecule file\n"
"{}", e.what()));
}
for (int i = 0; i < natoms; i++)
@ -794,12 +849,20 @@ void Molecule::diameters(char *line)
void Molecule::masses(char *line)
{
int tmp;
for (int i = 0; i < natoms; i++) {
readline(line);
if (2 != sscanf(line,"%d %lg",&tmp,&rmass[i]))
error->all(FLERR,"Invalid Masses section in molecule file");
rmass[i] *= sizescale*sizescale*sizescale;
try {
for (int i = 0; i < natoms; i++) {
readline(line);
ValueTokenizer values(line);
if (values.count() != 2) error->one(FLERR,"Invalid Masses section in molecule file");
values.next_int();
rmass[i] = values.next_double();
rmass[i] *= sizescale*sizescale*sizescale;
}
} catch (TokenizerException & e) {
error->one(FLERR, fmt::format("Invalid Masses section in molecule file\n"
"{}", e.what()));
}
for (int i = 0; i < natoms; i++)
@ -827,9 +890,19 @@ void Molecule::bonds(int flag, char *line)
for (int i = 0; i < nbonds; i++) {
readline(line);
if (4 != sscanf(line,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT,
&tmp,&itype,&atom1,&atom2))
error->all(FLERR,"Invalid Bonds section in molecule file");
try {
ValueTokenizer values(line);
if (values.count() != 4) error->one(FLERR,"Invalid Bonds section in molecule file");
values.next_int();
itype = values.next_int();
atom1 = values.next_tagint();
atom2 = values.next_tagint();
} catch (TokenizerException & e) {
error->one(FLERR, fmt::format("Invalid Bonds section in molecule file\n"
"{}", e.what()));
}
itype += boffset;
if ((atom1 <= 0) || (atom1 > natoms) ||
@ -885,9 +958,20 @@ void Molecule::angles(int flag, char *line)
for (int i = 0; i < nangles; i++) {
readline(line);
if (5 != sscanf(line,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT,
&tmp,&itype,&atom1,&atom2,&atom3))
error->all(FLERR,"Invalid Angles section in molecule file");
try {
ValueTokenizer values(line);
if (values.count() != 5) error->one(FLERR,"Invalid Angles section in molecule file");
values.next_int();
itype = values.next_int();
atom1 = values.next_tagint();
atom2 = values.next_tagint();
atom3 = values.next_tagint();
} catch (TokenizerException & e) {
error->one(FLERR, fmt::format("Invalid Angles section in molecule file\n"
"{}", e.what()));
}
itype += aoffset;
if ((atom1 <= 0) || (atom1 > natoms) ||
@ -958,10 +1042,21 @@ void Molecule::dihedrals(int flag, char *line)
for (int i = 0; i < ndihedrals; i++) {
readline(line);
if (6 != sscanf(line,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT " "
TAGINT_FORMAT " " TAGINT_FORMAT " ",
&tmp,&itype,&atom1,&atom2,&atom3,&atom4))
error->all(FLERR,"Invalid Dihedrals section in molecule file");
try {
ValueTokenizer values(line);
if (values.count() != 6) error->one(FLERR,"Invalid Dihedrals section in molecule file");
values.next_int();
itype = values.next_int();
atom1 = values.next_tagint();
atom2 = values.next_tagint();
atom3 = values.next_tagint();
atom4 = values.next_tagint();
} catch (TokenizerException & e) {
error->one(FLERR, fmt::format("Invalid Dihedrals section in molecule file\n"
"{}", e.what()));
}
itype += doffset;
if ((atom1 <= 0) || (atom1 > natoms) ||
@ -1047,10 +1142,21 @@ void Molecule::impropers(int flag, char *line)
for (int i = 0; i < nimpropers; i++) {
readline(line);
if (6 != sscanf(line,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT " "
TAGINT_FORMAT " " TAGINT_FORMAT " ",
&tmp,&itype,&atom1,&atom2,&atom3,&atom4))
error->all(FLERR,"Invalid Impropers section in molecule file");
try {
ValueTokenizer values(line);
if (values.count() != 6) error->one(FLERR,"Invalid Impropers section in molecule file");
values.next_int();
itype = values.next_int();
atom1 = values.next_tagint();
atom2 = values.next_tagint();
atom3 = values.next_tagint();
atom4 = values.next_tagint();
} catch (TokenizerException & e) {
error->one(FLERR, fmt::format("Invalid Impropers section in molecule file\n"
"{}", e.what()));
}
itype += ioffset;
if ((atom1 <= 0) || (atom1 > natoms) ||
@ -1124,15 +1230,24 @@ void Molecule::impropers(int flag, char *line)
void Molecule::nspecial_read(int flag, char *line)
{
int tmp,c1,c2,c3;
if (flag == 0) maxspecial = 0;
for (int i = 0; i < natoms; i++) {
readline(line);
if (4 != sscanf(line,"%d %d %d %d",&tmp,&c1,&c2,&c3))
error->all(FLERR,"Invalid Special Bond Counts section in "
"molecule file");
int c1, c2, c3;
try {
ValueTokenizer values(line);
if (values.count() != 4) error->one(FLERR,"Invalid Special Bond Counts section in molecule file");
values.next_int();
c1 = values.next_tagint();
c2 = values.next_tagint();
c3 = values.next_tagint();
} catch (TokenizerException & e) {
error->one(FLERR, fmt::format("Invalid Special Bond Counts section in molecule file\n"
"{}", e.what()));
}
if (flag) {
nspecial[i][0] = c1;
@ -1148,25 +1263,30 @@ void Molecule::nspecial_read(int flag, char *line)
void Molecule::special_read(char *line)
{
int m,nwords;
char **words = new char*[maxspecial+1];
try {
for (int i = 0; i < natoms; i++) {
readline(line);
for (int i = 0; i < natoms; i++) {
readline(line);
nwords = parse(line,words,maxspecial+1);
if (nwords != nspecial[i][2]+1)
error->all(FLERR,"Molecule file special list "
"does not match special count");
ValueTokenizer values(line);
int nwords = values.count();
for (m = 1; m < nwords; m++) {
special[i][m-1] = ATOTAGINT(words[m]);
if (special[i][m-1] <= 0 || special[i][m-1] > natoms ||
special[i][m-1] == i+1)
error->all(FLERR,"Invalid special atom index in molecule file");
if (nwords != nspecial[i][2]+1)
error->one(FLERR,"Molecule file special list "
"does not match special count");
values.next_int(); // ignore
for (int m = 1; m < nwords; m++) {
special[i][m-1] = values.next_tagint();
if (special[i][m-1] <= 0 || special[i][m-1] > natoms ||
special[i][m-1] == i+1)
error->one(FLERR,"Invalid special atom index in molecule file");
}
}
} catch (TokenizerException & e) {
error->one(FLERR, fmt::format("Invalid Molecule file special list\n"
"{}", e.what()));
}
delete [] words;
}
/* ----------------------------------------------------------------------
@ -1283,16 +1403,26 @@ void Molecule::special_generate()
void Molecule::shakeflag_read(char *line)
{
int tmp;
for (int i = 0; i < natoms; i++) {
readline(line);
if (2 != sscanf(line,"%d %d",&tmp,&shake_flag[i]))
error->all(FLERR,"Invalid Shake Flags section in molecule file");
try {
for (int i = 0; i < natoms; i++) {
readline(line);
ValueTokenizer values(line);
if (values.count() != 2)
error->one(FLERR,"Invalid Shake Flags section in molecule file");
values.next_int();
shake_flag[i] = values.next_int();
}
} catch (TokenizerException & e) {
error->one(FLERR, fmt::format("Invalid Shake Flags section in molecule file\n"
"{}", e.what()));
}
for (int i = 0; i < natoms; i++)
if (shake_flag[i] < 0 || shake_flag[i] > 4)
error->all(FLERR,"Invalid shake flag in molecule file");
error->one(FLERR,"Invalid shake flag in molecule file");
}
/* ----------------------------------------------------------------------
@ -1301,32 +1431,58 @@ void Molecule::shakeflag_read(char *line)
void Molecule::shakeatom_read(char *line)
{
int tmp, nmatch=0, nwant=0;
for (int i = 0; i < natoms; i++) {
readline(line);
if (shake_flag[i] == 1) {
nmatch = sscanf(line,"%d " TAGINT_FORMAT " " TAGINT_FORMAT
" " TAGINT_FORMAT,&tmp,&shake_atom[i][0],
&shake_atom[i][1],&shake_atom[i][2]);
nwant = 4;
} else if (shake_flag[i] == 2) {
nmatch = sscanf(line,"%d " TAGINT_FORMAT " " TAGINT_FORMAT,
&tmp,&shake_atom[i][0],&shake_atom[i][1]);
nwant = 3;
} else if (shake_flag[i] == 3) {
nmatch = sscanf(line,"%d " TAGINT_FORMAT " " TAGINT_FORMAT
" " TAGINT_FORMAT,&tmp,&shake_atom[i][0],
&shake_atom[i][1],&shake_atom[i][2]);
nwant = 4;
} else if (shake_flag[i] == 4) {
nmatch = sscanf(line,"%d " TAGINT_FORMAT " " TAGINT_FORMAT " "
TAGINT_FORMAT " " TAGINT_FORMAT,
&tmp,&shake_atom[i][0],&shake_atom[i][1],
&shake_atom[i][2],&shake_atom[i][3]);
nwant = 5;
int nmatch=0, nwant=0;
try {
for (int i = 0; i < natoms; i++) {
readline(line);
ValueTokenizer values(line);
nmatch = values.count();
switch (shake_flag[i]) {
case 1:
values.next_int();
shake_atom[i][0] = values.next_tagint();
shake_atom[i][1] = values.next_tagint();
shake_atom[i][2] = values.next_tagint();
nwant = 4;
break;
case 2:
values.next_int();
shake_atom[i][0] = values.next_tagint();
shake_atom[i][1] = values.next_tagint();
nwant = 3;
break;
case 3:
values.next_int();
shake_atom[i][0] = values.next_tagint();
shake_atom[i][1] = values.next_tagint();
shake_atom[i][2] = values.next_tagint();
nwant = 4;
break;
case 4:
values.next_int();
shake_atom[i][0] = values.next_tagint();
shake_atom[i][1] = values.next_tagint();
shake_atom[i][2] = values.next_tagint();
shake_atom[i][3] = values.next_tagint();
nwant = 5;
break;
default:
error->one(FLERR,"Invalid shake atom in molecule file");
}
if (nmatch != nwant)
error->one(FLERR,"Invalid shake atom in molecule file");
}
if (nmatch != nwant)
error->all(FLERR,"Invalid shake atom in molecule file");
} catch (TokenizerException & e) {
error->one(FLERR,fmt::format("Invalid shake atom in molecule file\n"
"{}", e.what()));
}
for (int i = 0; i < natoms; i++) {
@ -1334,7 +1490,7 @@ void Molecule::shakeatom_read(char *line)
if (m == 1) m = 3;
for (int j = 0; j < m; j++)
if (shake_atom[i][j] <= 0 || shake_atom[i][j] > natoms)
error->all(FLERR,"Invalid shake atom in molecule file");
error->one(FLERR,"Invalid shake atom in molecule file");
}
}
@ -1344,27 +1500,54 @@ void Molecule::shakeatom_read(char *line)
void Molecule::shaketype_read(char *line)
{
int tmp, nmatch=0, nwant=0;
for (int i = 0; i < natoms; i++) {
readline(line);
if (shake_flag[i] == 1) {
nmatch = sscanf(line,"%d %d %d %d",&tmp,&shake_type[i][0],
&shake_type[i][1],&shake_type[i][2]);
nwant = 4;
} else if (shake_flag[i] == 2) {
nmatch = sscanf(line,"%d %d",&tmp,&shake_type[i][0]);
nwant = 2;
} else if (shake_flag[i] == 3) {
nmatch = sscanf(line,"%d %d %d",&tmp,&shake_type[i][0],
&shake_type[i][1]);
nwant = 3;
} else if (shake_flag[i] == 4) {
nmatch = sscanf(line,"%d %d %d %d",&tmp,&shake_type[i][0],
&shake_type[i][1],&shake_type[i][2]);
nwant = 4;
try {
int nmatch=0, nwant=0;
for (int i = 0; i < natoms; i++) {
readline(line);
ValueTokenizer values(line);
nmatch = values.count();
switch (shake_flag[i]) {
case 1:
values.next_int();
shake_type[i][0] = values.next_int();
shake_type[i][1] = values.next_int();
shake_type[i][2] = values.next_int();
nwant = 4;
break;
case 2:
values.next_int();
shake_type[i][0] = values.next_int();
nwant = 2;
break;
case 3:
values.next_int();
shake_type[i][0] = values.next_int();
shake_type[i][1] = values.next_int();
nwant = 3;
break;
case 4:
values.next_int();
shake_type[i][0] = values.next_int();
shake_type[i][1] = values.next_int();
shake_type[i][2] = values.next_int();
nwant = 4;
break;
default:
error->one(FLERR,"Invalid shake type data in molecule file");
}
if (nmatch != nwant)
error->one(FLERR,"Invalid shake type data in molecule file");
}
if (nmatch != nwant)
error->all(FLERR,"Invalid shake type data in molecule file");
} catch (TokenizerException & e) {
error->one(FLERR, fmt::format("Invalid shake type data in molecule file\n",
"{}", e.what()));
}
for (int i = 0; i < natoms; i++) {
@ -1372,10 +1555,10 @@ void Molecule::shaketype_read(char *line)
if (m == 1) m = 3;
for (int j = 0; j < m-1; j++)
if (shake_type[i][j] <= 0)
error->all(FLERR,"Invalid shake bond type in molecule file");
error->one(FLERR,"Invalid shake bond type in molecule file");
if (shake_flag[i] == 1)
if (shake_type[i][2] <= 0)
error->all(FLERR,"Invalid shake angle type in molecule file");
error->one(FLERR,"Invalid shake angle type in molecule file");
}
}
@ -1386,34 +1569,38 @@ void Molecule::shaketype_read(char *line)
void Molecule::body(int flag, int pflag, char *line)
{
int i,ncount;
int nparam = nibody;
if (pflag) nparam = ndbody;
int nword = 0;
while (nword < nparam) {
readline(line);
ncount = utils::trim_and_count_words(line);
if (ncount == 0)
error->one(FLERR,"Too few values in body section of molecule file");
if (nword+ncount > nparam)
error->all(FLERR,"Too many values in body section of molecule file");
try {
while (nword < nparam) {
readline(line);
if (flag) {
if (pflag == 0) {
ibodyparams[nword++] = force->inumeric(FLERR,strtok(line," \t\n\r\f"));
for (i = 1; i < ncount; i++)
ibodyparams[nword++] =
force->inumeric(FLERR,strtok(NULL," \t\n\r\f"));
} else {
dbodyparams[nword++] = force->numeric(FLERR,strtok(line," \t\n\r\f"));
for (i = 1; i < ncount; i++)
dbodyparams[nword++] =
force->numeric(FLERR,strtok(NULL," \t\n\r\f"));
}
} else nword += ncount;
ValueTokenizer values(line);
int ncount = values.count();
if (ncount == 0)
error->one(FLERR,"Too few values in body section of molecule file");
if (nword+ncount > nparam)
error->one(FLERR,"Too many values in body section of molecule file");
if (flag) {
if (pflag == 0) {
while(values.has_next()) {
ibodyparams[nword++] = values.next_int();
}
} else {
while(values.has_next()) {
dbodyparams[nword++] = values.next_double();
}
}
} else nword += ncount;
}
} catch (TokenizerException & e) {
error->one(FLERR, fmt::format("Invalid body params in molecule file\n",
"{}", e.what()));
}
}
@ -1424,7 +1611,7 @@ void Molecule::body(int flag, int pflag, char *line)
int Molecule::findfragment(const char *name)
{
for (int i = 0; i < nfragments; i++)
if (fragmentnames[i] && strcmp(name,fragmentnames[i]) == 0) return i;
if (fragmentnames[i] == name) return i;
return -1;
}
@ -1565,7 +1752,7 @@ void Molecule::allocate()
if (typeflag) memory->create(type,natoms,"molecule:type");
if (moleculeflag) memory->create(molecule,natoms,"molecule:molecule");
if (fragmentflag) {
fragmentnames = new char*[nfragments];
fragmentnames.resize(nfragments);
memory->create(fragmentmask,nfragments,natoms,"molecule:fragmentmask");
for (int i = 0; i < nfragments; i++)
for (int j = 0; j < natoms; j++) fragmentmask[i][j] = 0;
@ -1664,9 +1851,9 @@ void Molecule::deallocate()
memory->destroy(molecule);
memory->destroy(fragmentmask);
if (fragmentflag) {
for (int i = 0; i < nfragments; i++) delete [] fragmentnames[i];
delete [] fragmentnames;
fragmentnames.clear();
}
memory->destroy(num_bond);
@ -1793,27 +1980,6 @@ void Molecule::skip_lines(int n, char *line)
for (int i = 0; i < n; i++) readline(line);
}
/* ----------------------------------------------------------------------
parse line into words separated by whitespace
return # of words
max = max pointers storable in words
------------------------------------------------------------------------- */
int Molecule::parse(char *line, char **words, int max)
{
char *ptr;
int nwords = 0;
words[nwords++] = strtok(line," \t\n\r\f");
while ((ptr = strtok(NULL," \t\n\r\f"))) {
if (nwords < max) words[nwords] = ptr;
nwords++;
}
return nwords;
}
/* ----------------------------------------------------------------------
proc 0 prints molecule params
------------------------------------------------------------------------- */

View File

@ -15,6 +15,8 @@
#define LMP_ONE_MOLECULE_H
#include "pointers.h"
#include <string>
#include <vector>
namespace LAMMPS_NS {
@ -94,7 +96,7 @@ class Molecule : protected Pointers {
// fragment info
int **fragmentmask; // nfragments by natoms
char **fragmentnames;
std::vector<std::string> fragmentnames;
double center[3]; // geometric center of molecule
double masstotal; // total mass of molecule
@ -163,7 +165,6 @@ class Molecule : protected Pointers {
void readline(char *);
void parse_keyword(int, char *, char *);
void skip_lines(int, char *);
int parse(char *, char **, int);
// void print();
};

View File

@ -32,6 +32,7 @@
#include "error.h"
#include "utils.h"
#include "fmt/format.h"
#include "potential_file_reader.h"
using namespace LAMMPS_NS;
using namespace MathConst;
@ -237,109 +238,71 @@ double PairCoulStreitz::init_one(int i, int j)
void PairCoulStreitz::read_file(char *file)
{
int params_per_line = 6;
char **words = new char*[params_per_line+1];
memory->sfree(params);
params = NULL;
params = nullptr;
nparams = 0;
maxparam = 0;
// open file on proc 0
FILE *fp;
if (comm->me == 0) {
fp = force->open_potential(file);
if (fp == NULL)
error->one(FLERR,fmt::format("Cannot open coul/streitz potential "
"file {}",file));
}
PotentialFileReader reader(lmp, file, "coul/streitz");
char * line;
// read each line out of file, skipping blank lines or leading '#'
// store line of params if all 3 element tags are in element list
while((line = reader.next_line(NPARAMS_PER_LINE))) {
try {
ValueTokenizer values(line);
int n,nwords,ielement;
char line[MAXLINE],*ptr;
int eof = 0;
std::string iname = values.next_string();
while (1) {
if (comm->me == 0) {
ptr = fgets(line,MAXLINE,fp);
if (ptr == NULL) {
eof = 1;
fclose(fp);
} else n = strlen(line) + 1;
}
MPI_Bcast(&eof,1,MPI_INT,0,world);
if (eof) break;
MPI_Bcast(&n,1,MPI_INT,0,world);
MPI_Bcast(line,n,MPI_CHAR,0,world);
// ielement = 1st args
int ielement;
// strip comment, skip line if blank
for (ielement = 0; ielement < nelements; ielement++)
if (iname == elements[ielement]) break;
if ((ptr = strchr(line,'#'))) *ptr = '\0';
nwords = utils::count_words(line);
if (nwords == 0) continue;
// load up parameter settings and error check their values
// concatenate additional lines until have params_per_line words
if (nparams == maxparam) {
maxparam += DELTA;
params = (Param *) memory->srealloc(params,maxparam*sizeof(Param),
"pair:params");
while (nwords < params_per_line) {
n = strlen(line);
if (comm->me == 0) {
ptr = fgets(&line[n],MAXLINE-n,fp);
if (ptr == NULL) {
eof = 1;
fclose(fp);
} else n = strlen(line) + 1;
// make certain all addional allocated storage is initialized
// to avoid false positives when checking with valgrind
memset(params + nparams, 0, DELTA*sizeof(Param));
}
params[nparams].ielement = ielement;
params[nparams].chi = values.next_double();
params[nparams].eta = values.next_double();
params[nparams].gamma = values.next_double();
params[nparams].zeta = values.next_double();
params[nparams].zcore = values.next_double();
} catch (TokenizerException & e) {
error->one(FLERR, e.what());
}
MPI_Bcast(&eof,1,MPI_INT,0,world);
if (eof) break;
MPI_Bcast(&n,1,MPI_INT,0,world);
MPI_Bcast(line,n,MPI_CHAR,0,world);
if ((ptr = strchr(line,'#'))) *ptr = '\0';
nwords = utils::count_words(line);
// parameter sanity check
if (params[nparams].eta < 0.0 || params[nparams].zeta < 0.0 ||
params[nparams].zcore < 0.0 || params[nparams].gamma != 0.0 )
error->one(FLERR,"Illegal coul/streitz parameter");
nparams++;
}
if (nwords != params_per_line)
error->all(FLERR,"Incorrect format in coul/streitz potential file");
// words = ptrs to all words in line
nwords = 0;
words[nwords++] = strtok(line," \t\n\r\f");
while ((words[nwords++] = strtok(NULL," \t\n\r\f"))) continue;
// ielement = 1st args
for (ielement = 0; ielement < nelements; ielement++)
if (strcmp(words[0],elements[ielement]) == 0) break;
if (ielement == nelements) continue;
// load up parameter settings and error check their values
if (nparams == maxparam) {
maxparam += DELTA;
params = (Param *) memory->srealloc(params,maxparam*sizeof(Param),
"pair:params");
}
params[nparams].ielement = ielement;
params[nparams].chi = atof(words[1]);
params[nparams].eta = atof(words[2]);
params[nparams].gamma = atof(words[3]);
params[nparams].zeta = atof(words[4]);
params[nparams].zcore = atof(words[5]);
// parameter sanity check
if (params[nparams].eta < 0.0 || params[nparams].zeta < 0.0 ||
params[nparams].zcore < 0.0 || params[nparams].gamma != 0.0 )
error->all(FLERR,"Illegal coul/streitz parameter");
nparams++;
}
delete [] words;
MPI_Bcast(&nparams, 1, MPI_INT, 0, world);
MPI_Bcast(&maxparam, 1, MPI_INT, 0, world);
if(comm->me != 0) {
params = (Param *) memory->srealloc(params,maxparam*sizeof(Param), "pair:params");
}
MPI_Bcast(params, maxparam*sizeof(Param), MPI_BYTE, 0, world);
}
/* ---------------------------------------------------------------------- */

View File

@ -36,6 +36,8 @@ class PairCoulStreitz : public Pair {
double memory_usage();
virtual void *extract(const char *, int &);
static const int NPARAMS_PER_LINE = 6;
protected:
struct Param {
double chi, eta, gamma, zeta, zcore;

View File

@ -18,6 +18,7 @@
#include "memory.h"
#include "error.h"
#include "utils.h"
#include "tokenizer.h"
using namespace LAMMPS_NS;
@ -33,7 +34,6 @@ enum{UNSET,NOSCALE_NOWRAP,NOSCALE_WRAP,SCALE_NOWRAP,SCALE_WRAP};
ReaderNative::ReaderNative(LAMMPS *lmp) : Reader(lmp)
{
line = new char[MAXLINE];
words = NULL;
fieldindex = NULL;
}
@ -42,7 +42,6 @@ ReaderNative::ReaderNative(LAMMPS *lmp) : Reader(lmp)
ReaderNative::~ReaderNative()
{
delete [] line;
delete [] words;
memory->destroy(fieldindex);
}
@ -162,19 +161,16 @@ bigint ReaderNative::read_header(double box[3][3], int &boxinfo, int &triclinic,
char *labelline = &line[strlen("ITEM: ATOMS ")];
nwords = utils::trim_and_count_words(labelline);
char **labels = new char*[nwords];
labels[0] = strtok(labelline," \t\n\r\f");
if (labels[0] == NULL) {
delete[] labels;
return 1;
std::map<std::string, int> labels;
Tokenizer tokens(labelline);
nwords = 0;
while(tokens.has_next()) {
labels[tokens.next()] = nwords++;
}
for (int m = 1; m < nwords; m++) {
labels[m] = strtok(NULL," \t\n\r\f");
if (labels[m] == NULL) {
delete[] labels;
return 1;
}
if(nwords == 0) {
return 1;
}
// match each field with a column of per-atom data
@ -191,25 +187,25 @@ bigint ReaderNative::read_header(double box[3][3], int &boxinfo, int &triclinic,
for (int i = 0; i < nfield; i++) {
if (fieldlabel[i]) {
fieldindex[i] = find_label(fieldlabel[i],nwords,labels);
fieldindex[i] = find_label(fieldlabel[i], labels);
if (fieldtype[i] == X) xflag = 2*scaleflag + wrapflag + 1;
else if (fieldtype[i] == Y) yflag = 2*scaleflag + wrapflag + 1;
else if (fieldtype[i] == Z) zflag = 2*scaleflag + wrapflag + 1;
}
else if (fieldtype[i] == ID)
fieldindex[i] = find_label("id",nwords,labels);
fieldindex[i] = find_label("id", labels);
else if (fieldtype[i] == TYPE)
fieldindex[i] = find_label("type",nwords,labels);
fieldindex[i] = find_label("type", labels);
else if (fieldtype[i] == X) {
fieldindex[i] = find_label("x",nwords,labels);
fieldindex[i] = find_label("x", labels);
xflag = NOSCALE_WRAP;
if (fieldindex[i] < 0) {
fieldindex[i] = nwords;
s_index = find_label("xs",nwords,labels);
u_index = find_label("xu",nwords,labels);
su_index = find_label("xsu",nwords,labels);
s_index = find_label("xs", labels);
u_index = find_label("xu", labels);
su_index = find_label("xsu", labels);
if (s_index >= 0 && s_index < fieldindex[i]) {
fieldindex[i] = s_index;
xflag = SCALE_WRAP;
@ -226,13 +222,13 @@ bigint ReaderNative::read_header(double box[3][3], int &boxinfo, int &triclinic,
if (fieldindex[i] == nwords) fieldindex[i] = -1;
} else if (fieldtype[i] == Y) {
fieldindex[i] = find_label("y",nwords,labels);
fieldindex[i] = find_label("y", labels);
yflag = NOSCALE_WRAP;
if (fieldindex[i] < 0) {
fieldindex[i] = nwords;
s_index = find_label("ys",nwords,labels);
u_index = find_label("yu",nwords,labels);
su_index = find_label("ysu",nwords,labels);
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;
@ -249,13 +245,13 @@ bigint ReaderNative::read_header(double box[3][3], int &boxinfo, int &triclinic,
if (fieldindex[i] == nwords) fieldindex[i] = -1;
} else if (fieldtype[i] == Z) {
fieldindex[i] = find_label("z",nwords,labels);
fieldindex[i] = find_label("z", labels);
zflag = NOSCALE_WRAP;
if (fieldindex[i] < 0) {
fieldindex[i] = nwords;
s_index = find_label("zs",nwords,labels);
u_index = find_label("zu",nwords,labels);
su_index = find_label("zsu",nwords,labels);
s_index = find_label("zs", labels);
u_index = find_label("zu", labels);
su_index = find_label("zsu", labels);
if (s_index >= 0 && s_index < fieldindex[i]) {
fieldindex[i] = s_index;
zflag = SCALE_WRAP;
@ -272,42 +268,36 @@ bigint ReaderNative::read_header(double box[3][3], int &boxinfo, int &triclinic,
if (fieldindex[i] == nwords) fieldindex[i] = -1;
} else if (fieldtype[i] == VX)
fieldindex[i] = find_label("vx",nwords,labels);
fieldindex[i] = find_label("vx", labels);
else if (fieldtype[i] == VY)
fieldindex[i] = find_label("vy",nwords,labels);
fieldindex[i] = find_label("vy", labels);
else if (fieldtype[i] == VZ)
fieldindex[i] = find_label("vz",nwords,labels);
fieldindex[i] = find_label("vz", labels);
else if (fieldtype[i] == FX)
fieldindex[i] = find_label("fx",nwords,labels);
fieldindex[i] = find_label("fx", labels);
else if (fieldtype[i] == FY)
fieldindex[i] = find_label("fy",nwords,labels);
fieldindex[i] = find_label("fy", labels);
else if (fieldtype[i] == FZ)
fieldindex[i] = find_label("fz",nwords,labels);
fieldindex[i] = find_label("fz", labels);
else if (fieldtype[i] == Q)
fieldindex[i] = find_label("q",nwords,labels);
fieldindex[i] = find_label("q", labels);
else if (fieldtype[i] == IX)
fieldindex[i] = find_label("ix",nwords,labels);
fieldindex[i] = find_label("ix", labels);
else if (fieldtype[i] == IY)
fieldindex[i] = find_label("iy",nwords,labels);
fieldindex[i] = find_label("iy", labels);
else if (fieldtype[i] == IZ)
fieldindex[i] = find_label("iz",nwords,labels);
fieldindex[i] = find_label("iz", labels);
}
delete [] labels;
// set fieldflag = -1 if any unfound fields
fieldflag = 0;
for (int i = 0; i < nfield; i++)
if (fieldindex[i] < 0) fieldflag = -1;
// create internal vector of word ptrs for future parsing of per-atom lines
words = new char*[nwords];
return natoms;
}
@ -328,15 +318,14 @@ void ReaderNative::read_atoms(int n, int nfield, double **fields)
if (eof == NULL) error->one(FLERR,"Unexpected end of dump file");
// tokenize the line
std::vector<std::string> words = Tokenizer(line).as_vector();
words[0] = strtok(line," \t\n\r\f");
for (m = 1; m < nwords; m++)
words[m] = strtok(NULL," \t\n\r\f");
if (words.size() < nwords) error->one(FLERR,"Insufficient columns in dump file");
// convert selected fields to floats
for (m = 0; m < nfield; m++)
fields[i][m] = atof(words[fieldindex[m]]);
fields[i][m] = atof(words[fieldindex[m]].c_str());
}
}
@ -345,10 +334,12 @@ void ReaderNative::read_atoms(int n, int nfield, double **fields)
return index of match or -1 if no match
------------------------------------------------------------------------- */
int ReaderNative::find_label(const char *label, int n, char **labels)
int ReaderNative::find_label(const std::string & label, const std::map<std::string, int> & labels)
{
for (int i = 0; i < n; i++)
if (strcmp(label,labels[i]) == 0) return i;
auto it = labels.find(label);
if (it != labels.end()) {
return it->second;
}
return -1;
}

View File

@ -23,6 +23,9 @@ ReaderStyle(native,ReaderNative)
#define LMP_READER_NATIVE_H
#include "reader.h"
#include <string>
#include <map>
#include <vector>
namespace LAMMPS_NS {
@ -41,10 +44,9 @@ private:
char *line; // line read from dump file
int nwords; // # of per-atom columns in dump file
char **words; // ptrs to values in parsed per-atom line
int *fieldindex; //
int find_label(const char *, int, char **);
int find_label(const std::string & label, const std::map<std::string, int> & labels);
void read_lines(int);
};

View File

@ -46,6 +46,7 @@
#include "math_const.h"
#include "utils.h"
#include "fmt/format.h"
#include "tokenizer.h"
using namespace LAMMPS_NS;
using namespace MathConst;
@ -226,37 +227,36 @@ void Thermo::init()
// add '/n' every 3 values if lineflag = MULTILINE
// add trailing '/n' to last value
char *format_line = NULL;
ValueTokenizer * format_line = nullptr;
if (format_line_user) {
int n = strlen(format_line_user) + 1;
format_line = new char[n];
strcpy(format_line,format_line_user);
format_line = new ValueTokenizer(format_line_user);
}
char *ptr,*format_line_ptr;
const char *ptr = nullptr;
std::string format_line_user_def;
for (i = 0; i < nfield; i++) {
format[i][0] = '\0';
if (lineflag == MULTILINE && i % 3 == 0) strcat(format[i],"\n");
if (format_line) {
if (i == 0) format_line_ptr = strtok(format_line," \0");
else format_line_ptr = strtok(NULL," \0");
if (format_line_user) {
format_line_user_def = format_line->next_string();
}
if (format_column_user[i]) ptr = format_column_user[i];
else if (vtype[i] == FLOAT) {
if (format_float_user) ptr = format_float_user;
else if (format_line_user) ptr = format_line_ptr;
else if (format_line_user) ptr = format_line_user_def.c_str();
else if (lineflag == ONELINE) ptr = format_float_one_def;
else if (lineflag == MULTILINE) ptr = format_float_multi_def;
} else if (vtype[i] == INT) {
if (format_int_user) ptr = format_int_user;
else if (format_line_user) ptr = format_line_ptr;
else if (format_line_user) ptr = format_line_user_def.c_str();
else if (lineflag == ONELINE) ptr = format_int_one_def;
else if (lineflag == MULTILINE) ptr = format_int_multi_def;
} else if (vtype[i] == BIGINT) {
if (format_bigint_user) ptr = format_bigint_user;
else if (format_line_user) ptr = format_line_ptr;
else if (format_line_user) ptr = format_line_user_def.c_str();
else if (lineflag == ONELINE) ptr = format_bigint_one_def;
else if (lineflag == MULTILINE) ptr = format_bigint_multi_def;
}
@ -267,7 +267,7 @@ void Thermo::init()
}
strcat(format[nfield-1],"\n");
delete [] format_line;
delete format_line;
// find current ptr for each Compute ID
@ -709,185 +709,186 @@ void Thermo::parse_fields(char *str)
// customize a new keyword by adding to if statement
char *word = strtok(str," \0");
while (word) {
ValueTokenizer keywords(str);
while (keywords.has_next()) {
std::string word = keywords.next_string();
if (strcmp(word,"step") == 0) {
if (word == "step") {
addfield("Step",&Thermo::compute_step,BIGINT);
} else if (strcmp(word,"elapsed") == 0) {
} else if (word == "elapsed") {
addfield("Elapsed",&Thermo::compute_elapsed,BIGINT);
} else if (strcmp(word,"elaplong") == 0) {
} else if (word == "elaplong") {
addfield("Elaplong",&Thermo::compute_elapsed_long,BIGINT);
} else if (strcmp(word,"dt") == 0) {
} else if (word == "dt") {
addfield("Dt",&Thermo::compute_dt,FLOAT);
} else if (strcmp(word,"time") == 0) {
} else if (word == "time") {
addfield("Time",&Thermo::compute_time,FLOAT);
} else if (strcmp(word,"cpu") == 0) {
} else if (word == "cpu") {
addfield("CPU",&Thermo::compute_cpu,FLOAT);
} else if (strcmp(word,"tpcpu") == 0) {
} else if (word == "tpcpu") {
addfield("T/CPU",&Thermo::compute_tpcpu,FLOAT);
} else if (strcmp(word,"spcpu") == 0) {
} else if (word == "spcpu") {
addfield("S/CPU",&Thermo::compute_spcpu,FLOAT);
} else if (strcmp(word,"cpuremain") == 0) {
} else if (word == "cpuremain") {
addfield("CPULeft",&Thermo::compute_cpuremain,FLOAT);
} else if (strcmp(word,"part") == 0) {
} else if (word == "part") {
addfield("Part",&Thermo::compute_part,INT);
} else if (strcmp(word,"timeremain") == 0) {
} else if (word == "timeremain") {
addfield("TimeoutLeft",&Thermo::compute_timeremain,FLOAT);
} else if (strcmp(word,"atoms") == 0) {
} else if (word == "atoms") {
addfield("Atoms",&Thermo::compute_atoms,BIGINT);
} else if (strcmp(word,"temp") == 0) {
} else if (word == "temp") {
addfield("Temp",&Thermo::compute_temp,FLOAT);
index_temp = add_compute(id_temp,SCALAR);
} else if (strcmp(word,"press") == 0) {
} else if (word == "press") {
addfield("Press",&Thermo::compute_press,FLOAT);
index_press_scalar = add_compute(id_press,SCALAR);
} else if (strcmp(word,"pe") == 0) {
} else if (word == "pe") {
addfield("PotEng",&Thermo::compute_pe,FLOAT);
index_pe = add_compute(id_pe,SCALAR);
} else if (strcmp(word,"ke") == 0) {
} else if (word == "ke") {
addfield("KinEng",&Thermo::compute_ke,FLOAT);
index_temp = add_compute(id_temp,SCALAR);
} else if (strcmp(word,"etotal") == 0) {
} else if (word == "etotal") {
addfield("TotEng",&Thermo::compute_etotal,FLOAT);
index_temp = add_compute(id_temp,SCALAR);
index_pe = add_compute(id_pe,SCALAR);
} else if (strcmp(word,"enthalpy") == 0) {
} else if (word == "enthalpy") {
addfield("Enthalpy",&Thermo::compute_enthalpy,FLOAT);
index_temp = add_compute(id_temp,SCALAR);
index_press_scalar = add_compute(id_press,SCALAR);
index_pe = add_compute(id_pe,SCALAR);
} else if (strcmp(word,"evdwl") == 0) {
} else if (word == "evdwl") {
addfield("E_vdwl",&Thermo::compute_evdwl,FLOAT);
index_pe = add_compute(id_pe,SCALAR);
} else if (strcmp(word,"ecoul") == 0) {
} else if (word == "ecoul") {
addfield("E_coul",&Thermo::compute_ecoul,FLOAT);
index_pe = add_compute(id_pe,SCALAR);
} else if (strcmp(word,"epair") == 0) {
} else if (word == "epair") {
addfield("E_pair",&Thermo::compute_epair,FLOAT);
index_pe = add_compute(id_pe,SCALAR);
} else if (strcmp(word,"ebond") == 0) {
} else if (word == "ebond") {
addfield("E_bond",&Thermo::compute_ebond,FLOAT);
index_pe = add_compute(id_pe,SCALAR);
} else if (strcmp(word,"eangle") == 0) {
} else if (word == "eangle") {
addfield("E_angle",&Thermo::compute_eangle,FLOAT);
index_pe = add_compute(id_pe,SCALAR);
} else if (strcmp(word,"edihed") == 0) {
} else if (word == "edihed") {
addfield("E_dihed",&Thermo::compute_edihed,FLOAT);
index_pe = add_compute(id_pe,SCALAR);
} else if (strcmp(word,"eimp") == 0) {
} else if (word == "eimp") {
addfield("E_impro",&Thermo::compute_eimp,FLOAT);
index_pe = add_compute(id_pe,SCALAR);
} else if (strcmp(word,"emol") == 0) {
} else if (word == "emol") {
addfield("E_mol",&Thermo::compute_emol,FLOAT);
index_pe = add_compute(id_pe,SCALAR);
} else if (strcmp(word,"elong") == 0) {
} else if (word == "elong") {
addfield("E_long",&Thermo::compute_elong,FLOAT);
index_pe = add_compute(id_pe,SCALAR);
} else if (strcmp(word,"etail") == 0) {
} else if (word == "etail") {
addfield("E_tail",&Thermo::compute_etail,FLOAT);
index_pe = add_compute(id_pe,SCALAR);
} else if (strcmp(word,"vol") == 0) {
} else if (word == "vol") {
addfield("Volume",&Thermo::compute_vol,FLOAT);
} else if (strcmp(word,"density") == 0) {
} else if (word == "density") {
addfield("Density",&Thermo::compute_density,FLOAT);
} else if (strcmp(word,"lx") == 0) {
} else if (word == "lx") {
addfield("Lx",&Thermo::compute_lx,FLOAT);
} else if (strcmp(word,"ly") == 0) {
} else if (word == "ly") {
addfield("Ly",&Thermo::compute_ly,FLOAT);
} else if (strcmp(word,"lz") == 0) {
} else if (word == "lz") {
addfield("Lz",&Thermo::compute_lz,FLOAT);
} else if (strcmp(word,"xlo") == 0) {
} else if (word == "xlo") {
addfield("Xlo",&Thermo::compute_xlo,FLOAT);
} else if (strcmp(word,"xhi") == 0) {
} else if (word == "xhi") {
addfield("Xhi",&Thermo::compute_xhi,FLOAT);
} else if (strcmp(word,"ylo") == 0) {
} else if (word == "ylo") {
addfield("Ylo",&Thermo::compute_ylo,FLOAT);
} else if (strcmp(word,"yhi") == 0) {
} else if (word == "yhi") {
addfield("Yhi",&Thermo::compute_yhi,FLOAT);
} else if (strcmp(word,"zlo") == 0) {
} else if (word == "zlo") {
addfield("Zlo",&Thermo::compute_zlo,FLOAT);
} else if (strcmp(word,"zhi") == 0) {
} else if (word == "zhi") {
addfield("Zhi",&Thermo::compute_zhi,FLOAT);
} else if (strcmp(word,"xy") == 0) {
} else if (word == "xy") {
addfield("Xy",&Thermo::compute_xy,FLOAT);
} else if (strcmp(word,"xz") == 0) {
} else if (word == "xz") {
addfield("Xz",&Thermo::compute_xz,FLOAT);
} else if (strcmp(word,"yz") == 0) {
} else if (word == "yz") {
addfield("Yz",&Thermo::compute_yz,FLOAT);
} else if (strcmp(word,"xlat") == 0) {
} else if (word == "xlat") {
addfield("Xlat",&Thermo::compute_xlat,FLOAT);
} else if (strcmp(word,"ylat") == 0) {
} else if (word == "ylat") {
addfield("Ylat",&Thermo::compute_ylat,FLOAT);
} else if (strcmp(word,"zlat") == 0) {
} else if (word == "zlat") {
addfield("Zlat",&Thermo::compute_zlat,FLOAT);
} else if (strcmp(word,"bonds") == 0) {
} else if (word == "bonds") {
addfield("Bonds",&Thermo::compute_bonds,BIGINT);
} else if (strcmp(word,"angles") == 0) {
} else if (word == "angles") {
addfield("Angles",&Thermo::compute_angles,BIGINT);
} else if (strcmp(word,"dihedrals") == 0) {
} else if (word == "dihedrals") {
addfield("Diheds",&Thermo::compute_dihedrals,BIGINT);
} else if (strcmp(word,"impropers") == 0) {
} else if (word == "impropers") {
addfield("Impros",&Thermo::compute_impropers,BIGINT);
} else if (strcmp(word,"pxx") == 0) {
} else if (word == "pxx") {
addfield("Pxx",&Thermo::compute_pxx,FLOAT);
index_press_vector = add_compute(id_press,VECTOR);
} else if (strcmp(word,"pyy") == 0) {
} else if (word == "pyy") {
addfield("Pyy",&Thermo::compute_pyy,FLOAT);
index_press_vector = add_compute(id_press,VECTOR);
} else if (strcmp(word,"pzz") == 0) {
} else if (word == "pzz") {
addfield("Pzz",&Thermo::compute_pzz,FLOAT);
index_press_vector = add_compute(id_press,VECTOR);
} else if (strcmp(word,"pxy") == 0) {
} else if (word == "pxy") {
addfield("Pxy",&Thermo::compute_pxy,FLOAT);
index_press_vector = add_compute(id_press,VECTOR);
} else if (strcmp(word,"pxz") == 0) {
} else if (word == "pxz") {
addfield("Pxz",&Thermo::compute_pxz,FLOAT);
index_press_vector = add_compute(id_press,VECTOR);
} else if (strcmp(word,"pyz") == 0) {
} else if (word == "pyz") {
addfield("Pyz",&Thermo::compute_pyz,FLOAT);
index_press_vector = add_compute(id_press,VECTOR);
} else if (strcmp(word,"fmax") == 0) {
} else if (word == "fmax") {
addfield("Fmax",&Thermo::compute_fmax,FLOAT);
} else if (strcmp(word,"fnorm") == 0) {
} else if (word == "fnorm") {
addfield("Fnorm",&Thermo::compute_fnorm,FLOAT);
} else if (strcmp(word,"nbuild") == 0) {
} else if (word == "nbuild") {
addfield("Nbuild",&Thermo::compute_nbuild,BIGINT);
} else if (strcmp(word,"ndanger") == 0) {
} else if (word == "ndanger") {
addfield("Ndanger",&Thermo::compute_ndanger,BIGINT);
} else if (strcmp(word,"cella") == 0) {
} else if (word == "cella") {
addfield("Cella",&Thermo::compute_cella,FLOAT);
} else if (strcmp(word,"cellb") == 0) {
} else if (word == "cellb") {
addfield("Cellb",&Thermo::compute_cellb,FLOAT);
} else if (strcmp(word,"cellc") == 0) {
} else if (word == "cellc") {
addfield("Cellc",&Thermo::compute_cellc,FLOAT);
} else if (strcmp(word,"cellalpha") == 0) {
} else if (word == "cellalpha") {
addfield("CellAlpha",&Thermo::compute_cellalpha,FLOAT);
} else if (strcmp(word,"cellbeta") == 0) {
} else if (word == "cellbeta") {
addfield("CellBeta",&Thermo::compute_cellbeta,FLOAT);
} else if (strcmp(word,"cellgamma") == 0) {
} else if (word == "cellgamma") {
addfield("CellGamma",&Thermo::compute_cellgamma,FLOAT);
// compute value = c_ID, fix value = f_ID, variable value = v_ID
// count trailing [] and store int arguments
} else if ((strncmp(word,"c_",2) == 0) || (strncmp(word,"f_",2) == 0) ||
(strncmp(word,"v_",2) == 0)) {
} else if ((word.substr(0, 2) == "c_") || (word.substr(0, 2) == "f_") ||
(word.substr(0, 2) == "v_")) {
int n = strlen(word);
int n = word.length() - 1;
char *id = new char[n];
strcpy(id,&word[2]);
strcpy(id, &word.c_str()[2]);
// parse zero or one or two trailing brackets from ID
// argindex1,argindex2 = int inside each bracket pair, 0 if no bracket
@ -929,12 +930,12 @@ void Thermo::parse_fields(char *str)
}
if (argindex1[nfield] == 0)
field2index[nfield] = add_compute(id,SCALAR);
field2index[nfield] = add_compute(id, SCALAR);
else if (argindex2[nfield] == 0)
field2index[nfield] = add_compute(id,VECTOR);
field2index[nfield] = add_compute(id, VECTOR);
else
field2index[nfield] = add_compute(id,ARRAY);
addfield(word,&Thermo::compute_compute,FLOAT);
field2index[nfield] = add_compute(id, ARRAY);
addfield(word.c_str(), &Thermo::compute_compute, FLOAT);
} else if (word[0] == 'f') {
n = modify->find_fix(id);
@ -959,7 +960,7 @@ void Thermo::parse_fields(char *str)
}
field2index[nfield] = add_fix(id);
addfield(word,&Thermo::compute_fix,FLOAT);
addfield(word.c_str(), &Thermo::compute_fix, FLOAT);
} else if (word[0] == 'v') {
n = input->variable->find(id);
@ -975,14 +976,13 @@ void Thermo::parse_fields(char *str)
error->all(FLERR,"Thermo custom variable cannot have two indices");
field2index[nfield] = add_variable(id);
addfield(word,&Thermo::compute_variable,FLOAT);
addfield(word.c_str(), &Thermo::compute_variable, FLOAT);
}
delete [] id;
} else error->all(FLERR,"Unknown keyword in thermo_style custom command");
word = strtok(NULL," \0");
}
}

View File

@ -18,6 +18,7 @@
#include "comm.h"
#include "error.h"
#include "force.h"
#include "utils.h"
#ifdef _WIN32
#include <windows.h>
@ -31,32 +32,6 @@
using namespace LAMMPS_NS;
// convert a timespec ([[HH:]MM:]SS) to seconds
// the strings "off" and "unlimited" result in -1;
static double timespec2seconds(char *timespec)
{
double vals[3];
char *num;
int i = 0;
// first handle allowed textual inputs
if (strcmp(timespec,"off") == 0) return -1;
if (strcmp(timespec,"unlimited") == 0) return -1;
vals[0] = vals[1] = vals[2] = 0;
num = strtok(timespec,":");
while ((num != NULL) && (i < 3)) {
vals[i] = atoi(num);
++i;
num = strtok(NULL,":");
}
if (i == 3) return (vals[0]*60 + vals[1])*60 + vals[2];
else if (i == 2) return vals[0]*60 + vals[1];
else return vals[0];
}
// Return the CPU time for the current process in seconds very
// much in the same way as MPI_Wtime() returns the wall time.
@ -297,7 +272,7 @@ void Timer::modify_params(int narg, char **arg)
} else if (strcmp(arg[iarg],"timeout") == 0) {
++iarg;
if (iarg < narg) {
_timeout = timespec2seconds(arg[iarg]);
_timeout = utils::timespec2seconds(arg[iarg]);
} else error->all(FLERR,"Illegal timers command");
} else if (strcmp(arg[iarg],"every") == 0) {
++iarg;

View File

@ -17,6 +17,7 @@
#include "tokenizer.h"
#include "utils.h"
#include <algorithm>
#include "fmt/format.h"
using namespace LAMMPS_NS;
@ -51,6 +52,10 @@ void Tokenizer::reset() {
start = text.find_first_not_of(separators);
}
bool Tokenizer::contains(const std::string & str) const {
return text.find(str) != std::string::npos;
}
void Tokenizer::skip(int n) {
for(int i = 0; i < n; ++i) {
if(!has_next()) throw TokenizerException("No more tokens", "");
@ -126,6 +131,10 @@ bool ValueTokenizer::has_next() const {
return tokens.has_next();
}
bool ValueTokenizer::contains(const std::string & value) const {
return tokens.contains(value);
}
std::string ValueTokenizer::next_string() {
if (has_next()) {
std::string value = tokens.next();

View File

@ -42,6 +42,7 @@ public:
void reset();
void skip(int n);
bool has_next() const;
bool contains(const std::string & str) const;
std::string next();
size_t count();
@ -89,7 +90,8 @@ public:
double next_double();
bool has_next() const;
void skip(int n);
bool contains(const std::string & value) const;
void skip(int ntokens);
size_t count();
};

View File

@ -705,6 +705,38 @@ double utils::get_conversion_factor(const int property, const int conversion)
return 0.0;
}
/* ----------------------------------------------------------------------
convert a timespec ([[HH:]MM:]SS) to seconds
the strings "off" and "unlimited" result in -1.0;
------------------------------------------------------------------------- */
double utils::timespec2seconds(const std::string & timespec)
{
double vals[3];
int i = 0;
// first handle allowed textual inputs
if (timespec == "off") return -1.0;
if (timespec == "unlimited") return -1.0;
vals[0] = vals[1] = vals[2] = 0;
ValueTokenizer values(timespec, ":");
try {
for (i = 0; i < 3; i++) {
if (!values.has_next()) break;
vals[i] = values.next_int();
}
} catch (TokenizerException & e) {
return -1.0;
}
if (i == 3) return (vals[0]*60 + vals[1])*60 + vals[2];
else if (i == 2) return vals[0]*60 + vals[1];
return vals[0];
}
/* ------------------------------------------------------------------ */
extern "C" {

View File

@ -291,6 +291,14 @@ namespace LAMMPS_NS {
* \return conversion factor
*/
double get_conversion_factor(const int property, const int conversion);
/**
* \brief Convert a time string to seconds
* The strings "off" and "unlimited" result in -1
* \param timespec a string in the following format: ([[HH:]MM:]SS)
* \return total in seconds
*/
double timespec2seconds(const std::string & timespec);
}
}

View File

@ -90,9 +90,16 @@ int main(int narg, char **arg)
FILE *fptxt = fopen(filetxt,"w");
delete [] filetxt;
// detect newer format
char * magic_string = nullptr;
char * columns = nullptr;
char * unit_style = nullptr;
// loop over snapshots in file
while (1) {
int endian = 0x0001;
int revision = 0x0001;
fread(&ntimestep,sizeof(bigint),1,fp);
@ -104,6 +111,26 @@ int main(int narg, char **arg)
break;
}
// detect newer format
if (ntimestep < 0) {
// first bigint encodes negative format name length
bigint magic_string_len = -ntimestep;
delete [] magic_string;
magic_string = new char[magic_string_len + 1];
fread(magic_string, sizeof(char), magic_string_len, fp);
magic_string[magic_string_len] = '\0';
// read endian flag
fread(&endian, sizeof(int), 1, fp);
// read revision number
fread(&revision, sizeof(int), 1, fp);
// read the real ntimestep
fread(&ntimestep,sizeof(bigint),1,fp);
}
fread(&natoms,sizeof(bigint),1,fp);
fread(&triclinic,sizeof(int),1,fp);
fread(&boundary[0][0],6*sizeof(int),1,fp);
@ -119,6 +146,39 @@ int main(int narg, char **arg)
fread(&yz,sizeof(double),1,fp);
}
fread(&size_one,sizeof(int),1,fp);
if (magic_string && revision > 0x0001) {
// newer format includes units string, columns string
// and time
int len = 0;
fread(&len, sizeof(int), 1, fp);
if (len > 0) {
// has units
delete [] unit_style;
unit_style = new char[len+1];
fread(unit_style, sizeof(char), len, fp);
unit_style[len+1] = '\0';
fprintf(fptxt, "ITEM: UNITS\n");
fprintf(fptxt, "%s\n", unit_style);
}
char flag = 0;
fread(&flag, sizeof(char), 1, fp);
if (flag) {
double time;
fread(&time, sizeof(double), 1, fp);
fprintf(fptxt, "ITEM: TIME\n%.16g\n", time);
}
fread(&len, sizeof(int), 1, fp);
delete [] columns;
columns = new char[len+1];
fread(columns, sizeof(char), len, fp);
columns[len+1] = '\0';
}
fread(&nchunk,sizeof(int),1,fp);
fprintf(fptxt,"ITEM: TIMESTEP\n");
@ -140,18 +200,20 @@ int main(int narg, char **arg)
if (!triclinic) {
fprintf(fptxt,"ITEM: BOX BOUNDS %s\n",boundstr);
fprintf(fptxt,"%g %g\n",xlo,xhi);
fprintf(fptxt,"%g %g\n",ylo,yhi);
fprintf(fptxt,"%g %g\n",zlo,zhi);
fprintf(fptxt,"%-1.16e %-1.16e\n",xlo,xhi);
fprintf(fptxt,"%-1.16e %-1.16e\n",ylo,yhi);
fprintf(fptxt,"%-1.16e %-1.16e\n",zlo,zhi);
} else {
fprintf(fptxt,"ITEM: BOX BOUNDS %s xy xz yz\n",boundstr);
fprintf(fptxt,"%g %g %g\n",xlo,xhi,xy);
fprintf(fptxt,"%g %g %g\n",ylo,yhi,xz);
fprintf(fptxt,"%g %g %g\n",zlo,zhi,yz);
fprintf(fptxt,"ITEM: BOX BOUNDS xy xz yz %s\n",boundstr);
fprintf(fptxt,"%-1.16e %-1.16e %-1.16e\n",xlo,xhi,xy);
fprintf(fptxt,"%-1.16e %-1.16e %-1.16e\n",ylo,yhi,xz);
fprintf(fptxt,"%-1.16e %-1.16e %-1.16e\n",zlo,zhi,yz);
}
fprintf(fptxt,"ITEM: ATOMS\n");
if (columns)
fprintf(fptxt,"ITEM: ATOMS %s\n", columns);
else
fprintf(fptxt,"ITEM: ATOMS\n");
// loop over processor chunks in file
@ -172,7 +234,13 @@ int main(int narg, char **arg)
n /= size_one;
m = 0;
for (j = 0; j < n; j++) {
for (k = 0; k < size_one; k++) fprintf(fptxt,"%g ",buf[m++]);
for (k = 0; k < size_one; k++) {
if(k+1 < size_one) {
fprintf(fptxt,"%g ",buf[m++]);
} else {
fprintf(fptxt,"%g",buf[m++]);
}
}
fprintf(fptxt,"\n");
}
}
@ -181,6 +249,12 @@ int main(int narg, char **arg)
fflush(stdout);
}
printf("\n");
delete [] columns;
delete [] magic_string;
delete [] unit_style;
columns = nullptr;
magic_string = nullptr;
unit_style = nullptr;
}
if (buf) delete [] buf;

View File

@ -23,3 +23,23 @@ endif()
add_executable(test_file_operations test_file_operations.cpp)
target_link_libraries(test_file_operations PRIVATE lammps GTest::GMock GTest::GTest)
add_test(NAME FileOperations COMMAND test_file_operations WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_executable(test_dump_atom test_dump_atom.cpp)
target_link_libraries(test_dump_atom PRIVATE lammps GTest::GMock GTest::GTest)
add_test(NAME DumpAtom COMMAND test_dump_atom WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set_tests_properties(DumpAtom PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
add_executable(test_dump_custom test_dump_custom.cpp)
target_link_libraries(test_dump_custom PRIVATE lammps GTest::GMock GTest::GTest)
add_test(NAME DumpCustom COMMAND test_dump_custom WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set_tests_properties(DumpCustom PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
add_executable(test_dump_cfg test_dump_cfg.cpp)
target_link_libraries(test_dump_cfg PRIVATE lammps GTest::GMock GTest::GTest)
add_test(NAME DumpCfg COMMAND test_dump_cfg WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
set_tests_properties(DumpCfg PROPERTIES ENVIRONMENT "LAMMPS_POTENTIALS=${LAMMPS_POTENTIALS_DIR}")
if (BUILD_TOOLS)
set_tests_properties(DumpAtom PROPERTIES ENVIRONMENT "BINARY2TXT_BINARY=$<TARGET_FILE:binary2txt>")
set_tests_properties(DumpCustom PROPERTIES ENVIRONMENT "BINARY2TXT_BINARY=$<TARGET_FILE:binary2txt>")
endif()

View File

@ -0,0 +1,600 @@
/* ----------------------------------------------------------------------
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.
------------------------------------------------------------------------- */
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "fmt/format.h"
#include "utils.h"
#include "../testing/core.h"
#include "../testing/systems/melt.h"
#include "../testing/utils.h"
#include <string>
using ::testing::Eq;
char * BINARY2TXT_BINARY = nullptr;
class DumpAtomTest : public MeltTest {
std::string dump_style = "atom";
public:
void enable_triclinic() {
if (!verbose) ::testing::internal::CaptureStdout();
command("change_box all triclinic");
if (!verbose) ::testing::internal::GetCapturedStdout();
}
void generate_dump(std::string dump_file, std::string dump_modify_options, int ntimesteps) {
if (!verbose) ::testing::internal::CaptureStdout();
command(fmt::format("dump id all {} 1 {}", dump_style, dump_file));
if (!dump_modify_options.empty()) {
command(fmt::format("dump_modify id {}", dump_modify_options));
}
command(fmt::format("run {}", ntimesteps));
if (!verbose) ::testing::internal::GetCapturedStdout();
}
void generate_text_and_binary_dump(std::string text_file, std::string binary_file, std::string dump_modify_options, int ntimesteps) {
if (!verbose) ::testing::internal::CaptureStdout();
command(fmt::format("dump id0 all {} 1 {}", dump_style, text_file));
command(fmt::format("dump id1 all {} 1 {}", dump_style, binary_file));
if (!dump_modify_options.empty()) {
command(fmt::format("dump_modify id0 {}", dump_modify_options));
command(fmt::format("dump_modify id1 {}", dump_modify_options));
}
command(fmt::format("run {}", ntimesteps));
if (!verbose) ::testing::internal::GetCapturedStdout();
}
std::string convert_binary_to_text(std::string binary_file) {
if (!verbose) ::testing::internal::CaptureStdout();
std::string cmdline = fmt::format("{} {}", BINARY2TXT_BINARY, binary_file);
system(cmdline.c_str());
if (!verbose) ::testing::internal::GetCapturedStdout();
return fmt::format("{}.txt", binary_file);
}
};
TEST_F(DumpAtomTest, run0)
{
auto dump_file = "dump_run0.melt";
generate_dump(dump_file, "scale yes image no", 0);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 41);
ASSERT_THAT(lines[4], Eq("ITEM: BOX BOUNDS pp pp pp"));
ASSERT_EQ(utils::split_words(lines[5]).size(), 2);
ASSERT_THAT(lines[8], Eq("ITEM: ATOMS id type xs ys zs"));
ASSERT_EQ(utils::split_words(lines[9]).size(), 5);
ASSERT_THAT(lines[9], Eq("1 1 0 0 0"));
delete_file(dump_file);
}
TEST_F(DumpAtomTest, format_line_run0)
{
auto dump_file = "dump_format_line_run0.melt";
generate_dump(dump_file, "format line \"%d %d %20.15g %g %g\" scale yes image no", 0);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 41);
ASSERT_THAT(lines[4], Eq("ITEM: BOX BOUNDS pp pp pp"));
ASSERT_EQ(utils::split_words(lines[5]).size(), 2);
ASSERT_THAT(lines[8], Eq("ITEM: ATOMS id type xs ys zs"));
ASSERT_EQ(utils::split_words(lines[9]).size(), 5);
ASSERT_THAT(lines[9], Eq("1 1 0 0 0"));
delete_file(dump_file);
}
TEST_F(DumpAtomTest, no_scale_run0)
{
auto dump_file = "dump_no_scale_run0.melt";
generate_dump(dump_file, "scale no", 0);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 41);
ASSERT_THAT(lines[4], Eq("ITEM: BOX BOUNDS pp pp pp"));
ASSERT_EQ(utils::split_words(lines[5]).size(), 2);
ASSERT_THAT(lines[8], Eq("ITEM: ATOMS id type x y z"));
ASSERT_EQ(utils::split_words(lines[9]).size(), 5);
delete_file(dump_file);
}
TEST_F(DumpAtomTest, no_buffer_no_scale_run0)
{
auto dump_file = "dump_no_buffer_no_scale_run0.melt";
generate_dump(dump_file, "scale no", 0);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 41);
ASSERT_THAT(lines[4], Eq("ITEM: BOX BOUNDS pp pp pp"));
ASSERT_EQ(utils::split_words(lines[5]).size(), 2);
ASSERT_THAT(lines[8], Eq("ITEM: ATOMS id type x y z"));
ASSERT_EQ(utils::split_words(lines[9]).size(), 5);
delete_file(dump_file);
}
TEST_F(DumpAtomTest, no_buffer_with_scale_run0)
{
auto dump_file = "dump_no_buffer_with_scale_run0.melt";
generate_dump(dump_file, "buffer no scale yes", 0);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 41);
ASSERT_THAT(lines[4], Eq("ITEM: BOX BOUNDS pp pp pp"));
ASSERT_EQ(utils::split_words(lines[5]).size(), 2);
ASSERT_THAT(lines[8], Eq("ITEM: ATOMS id type xs ys zs"));
ASSERT_EQ(utils::split_words(lines[9]).size(), 5);
delete_file(dump_file);
}
TEST_F(DumpAtomTest, with_image_run0)
{
auto dump_file = "dump_with_image_run0.melt";
generate_dump(dump_file, "scale no image yes", 0);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 41);
ASSERT_THAT(lines[8], Eq("ITEM: ATOMS id type x y z ix iy iz"));
ASSERT_EQ(utils::split_words(lines[9]).size(), 8);
delete_file(dump_file);
}
TEST_F(DumpAtomTest, with_units_run0)
{
auto dump_file = "dump_with_units_run0.melt";
generate_dump(dump_file, "scale no units yes", 0);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 43);
ASSERT_THAT(lines[0], Eq("ITEM: UNITS"));
ASSERT_THAT(lines[1], Eq("lj"));
ASSERT_THAT(lines[10], Eq("ITEM: ATOMS id type x y z"));
ASSERT_EQ(utils::split_words(lines[11]).size(), 5);
delete_file(dump_file);
}
TEST_F(DumpAtomTest, with_time_run0)
{
auto dump_file = "dump_with_time_run0.melt";
generate_dump(dump_file, "scale no time yes", 0);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 43);
ASSERT_THAT(lines[0], Eq("ITEM: TIME"));
ASSERT_THAT(lines[10], Eq("ITEM: ATOMS id type x y z"));
ASSERT_EQ(utils::split_words(lines[11]).size(), 5);
delete_file(dump_file);
}
TEST_F(DumpAtomTest, with_units_run1)
{
auto dump_file = "dump_with_units_run1.melt";
generate_dump(dump_file, "scale no units yes", 1);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 84);
ASSERT_THAT(lines[0], Eq("ITEM: UNITS"));
ASSERT_THAT(lines[1], Eq("lj"));
ASSERT_THAT(lines[10], Eq("ITEM: ATOMS id type x y z"));
ASSERT_EQ(utils::split_words(lines[11]).size(), 5);
delete_file(dump_file);
}
TEST_F(DumpAtomTest, no_buffer_with_scale_and_image_run0)
{
auto dump_file = "dump_no_buffer_with_scale_and_image_run0.melt";
generate_dump(dump_file, "buffer no scale yes image yes", 0);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 41);
ASSERT_THAT(lines[4], Eq("ITEM: BOX BOUNDS pp pp pp"));
ASSERT_EQ(utils::split_words(lines[5]).size(), 2);
ASSERT_THAT(lines[8], Eq("ITEM: ATOMS id type xs ys zs ix iy iz"));
ASSERT_EQ(utils::split_words(lines[9]).size(), 8);
delete_file(dump_file);
}
TEST_F(DumpAtomTest, triclinic_run0)
{
auto dump_file = "dump_triclinic_run0.melt";
enable_triclinic();
generate_dump(dump_file, "", 0);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 41);
ASSERT_THAT(lines[4], Eq("ITEM: BOX BOUNDS xy xz yz pp pp pp"));
ASSERT_EQ(utils::split_words(lines[5]).size(), 3);
ASSERT_THAT(lines[8], Eq("ITEM: ATOMS id type xs ys zs"));
ASSERT_EQ(utils::split_words(lines[9]).size(), 5);
delete_file(dump_file);
}
TEST_F(DumpAtomTest, triclinic_with_units_run0)
{
auto dump_file = "dump_triclinic_with_units_run0.melt";
enable_triclinic();
generate_dump(dump_file, "units yes", 0);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 43);
ASSERT_THAT(lines[0], Eq("ITEM: UNITS"));
ASSERT_THAT(lines[1], Eq("lj"));
ASSERT_THAT(lines[6], Eq("ITEM: BOX BOUNDS xy xz yz pp pp pp"));
ASSERT_EQ(utils::split_words(lines[7]).size(), 3);
ASSERT_THAT(lines[10], Eq("ITEM: ATOMS id type xs ys zs"));
ASSERT_EQ(utils::split_words(lines[11]).size(), 5);
delete_file(dump_file);
}
TEST_F(DumpAtomTest, triclinic_with_time_run0)
{
auto dump_file = "dump_triclinic_with_time_run0.melt";
enable_triclinic();
generate_dump(dump_file, "time yes", 0);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 43);
ASSERT_THAT(lines[0], Eq("ITEM: TIME"));
ASSERT_THAT(lines[6], Eq("ITEM: BOX BOUNDS xy xz yz pp pp pp"));
ASSERT_EQ(utils::split_words(lines[7]).size(), 3);
ASSERT_THAT(lines[10], Eq("ITEM: ATOMS id type xs ys zs"));
ASSERT_EQ(utils::split_words(lines[11]).size(), 5);
delete_file(dump_file);
}
TEST_F(DumpAtomTest, triclinic_with_image_run0)
{
auto dump_file = "dump_triclinic_with_image_run0.melt";
enable_triclinic();
generate_dump(dump_file, "image yes", 0);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 41);
ASSERT_THAT(lines[4], Eq("ITEM: BOX BOUNDS xy xz yz pp pp pp"));
ASSERT_EQ(utils::split_words(lines[5]).size(), 3);
ASSERT_THAT(lines[8], Eq("ITEM: ATOMS id type xs ys zs ix iy iz"));
ASSERT_EQ(utils::split_words(lines[9]).size(), 8);
delete_file(dump_file);
}
//-------------------------------------------------------------------------------------------------
// binary formats
//-------------------------------------------------------------------------------------------------
TEST_F(DumpAtomTest, binary_run0)
{
if(!BINARY2TXT_BINARY) GTEST_SKIP();
auto text_file = "dump_text_run0.melt";
auto binary_file = "dump_binary_run0.melt.bin";
generate_text_and_binary_dump(text_file, binary_file, "", 0);
ASSERT_FILE_EXISTS(text_file);
ASSERT_FILE_EXISTS(binary_file);
auto converted_file = convert_binary_to_text(binary_file);
ASSERT_FILE_EXISTS(converted_file);
ASSERT_FILE_EQUAL(text_file, converted_file);
delete_file(text_file);
delete_file(binary_file);
delete_file(converted_file);
}
TEST_F(DumpAtomTest, binary_with_units_run0)
{
if(!BINARY2TXT_BINARY) GTEST_SKIP();
auto text_file = "dump_text_with_units_run0.melt";
auto binary_file = "dump_binary_with_units_run0.melt.bin";
generate_text_and_binary_dump(text_file, binary_file, "scale no units yes", 0);
ASSERT_FILE_EXISTS(text_file);
ASSERT_FILE_EXISTS(binary_file);
auto converted_file = convert_binary_to_text(binary_file);
ASSERT_FILE_EXISTS(converted_file);
ASSERT_FILE_EQUAL(text_file, converted_file);
delete_file(text_file);
delete_file(binary_file);
delete_file(converted_file);
}
TEST_F(DumpAtomTest, binary_with_time_run0)
{
if(!BINARY2TXT_BINARY) GTEST_SKIP();
auto text_file = "dump_text_with_time_run0.melt";
auto binary_file = "dump_binary_with_time_run0.melt.bin";
generate_text_and_binary_dump(text_file, binary_file, "scale no time yes", 0);
ASSERT_FILE_EXISTS(text_file);
ASSERT_FILE_EXISTS(binary_file);
auto converted_file = convert_binary_to_text(binary_file);
ASSERT_FILE_EXISTS(converted_file);
ASSERT_FILE_EQUAL(text_file, converted_file);
delete_file(text_file);
delete_file(binary_file);
delete_file(converted_file);
}
TEST_F(DumpAtomTest, binary_triclinic_run0)
{
if(!BINARY2TXT_BINARY) GTEST_SKIP();
auto text_file = "dump_text_tri_run0.melt";
auto binary_file = "dump_binary_tri_run0.melt.bin";
enable_triclinic();
generate_text_and_binary_dump(text_file, binary_file, "", 0);
ASSERT_FILE_EXISTS(text_file);
ASSERT_FILE_EXISTS(binary_file);
auto converted_file = convert_binary_to_text(binary_file);
ASSERT_FILE_EXISTS(converted_file);
ASSERT_FILE_EQUAL(text_file, converted_file);
delete_file(text_file);
delete_file(binary_file);
delete_file(converted_file);
}
TEST_F(DumpAtomTest, binary_triclinic_with_units_run0)
{
if(!BINARY2TXT_BINARY) GTEST_SKIP();
auto text_file = "dump_text_tri_with_units_run0.melt";
auto binary_file = "dump_binary_tri_with_units_run0.melt.bin";
enable_triclinic();
generate_text_and_binary_dump(text_file, binary_file, "scale no units yes", 0);
ASSERT_FILE_EXISTS(text_file);
ASSERT_FILE_EXISTS(binary_file);
auto converted_file = convert_binary_to_text(binary_file);
ASSERT_FILE_EXISTS(converted_file);
ASSERT_FILE_EQUAL(text_file, converted_file);
delete_file(text_file);
delete_file(binary_file);
delete_file(converted_file);
}
TEST_F(DumpAtomTest, binary_triclinic_with_time_run0)
{
if(!BINARY2TXT_BINARY) GTEST_SKIP();
auto text_file = "dump_text_tri_with_time_run0.melt";
auto binary_file = "dump_binary_tri_with_time_run0.melt.bin";
enable_triclinic();
generate_text_and_binary_dump(text_file, binary_file, "scale no time yes", 0);
ASSERT_FILE_EXISTS(text_file);
ASSERT_FILE_EXISTS(binary_file);
auto converted_file = convert_binary_to_text(binary_file);
ASSERT_FILE_EXISTS(converted_file);
ASSERT_FILE_EQUAL(text_file, converted_file);
delete_file(text_file);
delete_file(binary_file);
delete_file(converted_file);
}
TEST_F(DumpAtomTest, binary_triclinic_with_image_run0)
{
if(!BINARY2TXT_BINARY) GTEST_SKIP();
auto text_file = "dump_text_tri_with_image_run0.melt";
auto binary_file = "dump_binary_tri_with_image_run0.melt.bin";
enable_triclinic();
generate_text_and_binary_dump(text_file, binary_file, "image yes", 0);
ASSERT_FILE_EXISTS(text_file);
ASSERT_FILE_EXISTS(binary_file);
auto converted_file = convert_binary_to_text(binary_file);
ASSERT_FILE_EXISTS(converted_file);
ASSERT_FILE_EQUAL(text_file, converted_file);
delete_file(text_file);
delete_file(binary_file);
delete_file(converted_file);
}
TEST_F(DumpAtomTest, run1)
{
auto dump_file = "dump_run1.melt";
generate_dump(dump_file, "", 1);
ASSERT_FILE_EXISTS(dump_file);
ASSERT_EQ(count_lines(dump_file), 82);
delete_file(dump_file);
}
TEST_F(DumpAtomTest, run2)
{
auto dump_file = "dump_run2.melt";
generate_dump(dump_file, "", 2);
ASSERT_FILE_EXISTS(dump_file);
ASSERT_EQ(count_lines(dump_file), 123);
delete_file(dump_file);
}
TEST_F(DumpAtomTest, multi_file_run1)
{
auto dump_file = "dump_run1_*.melt";
generate_dump(dump_file, "", 1);
ASSERT_FILE_EXISTS("dump_run1_0.melt");
ASSERT_FILE_EXISTS("dump_run1_1.melt");
ASSERT_EQ(count_lines("dump_run1_0.melt"), 41);
ASSERT_EQ(count_lines("dump_run1_1.melt"), 41);
delete_file("dump_run1_0.melt");
delete_file("dump_run1_1.melt");
}
TEST_F(DumpAtomTest, per_processor_file_run1)
{
auto dump_file = "dump_run1_p%.melt";
generate_dump(dump_file, "", 1);
ASSERT_FILE_EXISTS("dump_run1_p0.melt");
ASSERT_EQ(count_lines("dump_run1_p0.melt"), 82);
delete_file("dump_run1_p0.melt");
}
TEST_F(DumpAtomTest, per_processor_multi_file_run1)
{
auto dump_file = "dump_run1_p%_*.melt";
generate_dump(dump_file, "", 1);
ASSERT_FILE_EXISTS("dump_run1_p0_0.melt");
ASSERT_FILE_EXISTS("dump_run1_p0_1.melt");
ASSERT_EQ(count_lines("dump_run1_p0_0.melt"), 41);
ASSERT_EQ(count_lines("dump_run1_p0_1.melt"), 41);
delete_file("dump_run1_p0_0.melt");
delete_file("dump_run1_p0_1.melt");
}
TEST_F(DumpAtomTest, dump_modify_scale_invalid)
{
if (!verbose) ::testing::internal::CaptureStdout();
command("dump id all atom 1 dump.txt");
if (!verbose) ::testing::internal::GetCapturedStdout();
TEST_FAILURE(".*Illegal dump_modify command.*",
command("dump_modify id scale true"););
}
TEST_F(DumpAtomTest, dump_modify_image_invalid)
{
if (!verbose) ::testing::internal::CaptureStdout();
command("dump id all atom 1 dump.txt");
if (!verbose) ::testing::internal::GetCapturedStdout();
TEST_FAILURE(".*Illegal dump_modify command.*",
command("dump_modify id image true"););
}
TEST_F(DumpAtomTest, dump_modify_invalid)
{
if (!verbose) ::testing::internal::CaptureStdout();
command("dump id all atom 1 dump.txt");
if (!verbose) ::testing::internal::GetCapturedStdout();
TEST_FAILURE(".*Illegal dump_modify command.*",
command("dump_modify id true"););
}
TEST_F(DumpAtomTest, write_dump)
{
auto reference = "dump_ref_run0.melt";
auto dump_file = "write_dump_atom_run0.melt";
if (!verbose) ::testing::internal::CaptureStdout();
command(fmt::format("dump id all atom 1 {}", reference));
command("dump_modify id scale no units yes");
command("run 0");
command("write_dump all atom write_dump_atom_run*.melt modify scale no units yes");
if (!verbose) ::testing::internal::GetCapturedStdout();
ASSERT_FILE_EXISTS(reference);
ASSERT_FILE_EXISTS(dump_file);
ASSERT_FILE_EQUAL(reference, dump_file);
delete_file(reference);
delete_file(dump_file);
}
TEST_F(DumpAtomTest, binary_write_dump)
{
if(!BINARY2TXT_BINARY) GTEST_SKIP();
auto reference = "dump_run0.melt.bin";
auto dump_file = "write_dump_atom_run0_p0.melt.bin";
if (!verbose) ::testing::internal::CaptureStdout();
command(fmt::format("dump id all atom 1 {}", reference));
command("dump_modify id scale no units yes");
command("run 0");
command("write_dump all atom write_dump_atom_run*_p%.melt.bin modify scale no units yes");
if (!verbose) ::testing::internal::GetCapturedStdout();
ASSERT_FILE_EXISTS(reference);
ASSERT_FILE_EXISTS(dump_file);
auto reference_txt = convert_binary_to_text(reference);
auto dump_file_txt = convert_binary_to_text(dump_file);
ASSERT_FILE_EXISTS(reference_txt);
ASSERT_FILE_EXISTS(dump_file_txt);
ASSERT_FILE_EQUAL(reference_txt, dump_file_txt);
delete_file(reference_txt);
delete_file(dump_file_txt);
delete_file(reference);
delete_file(dump_file);
}
int main(int argc, char **argv)
{
MPI_Init(&argc, &argv);
::testing::InitGoogleMock(&argc, argv);
// handle arguments passed via environment variable
if (const char *var = getenv("TEST_ARGS")) {
std::vector<std::string> env = utils::split_words(var);
for (auto arg : env) {
if (arg == "-v") {
verbose = true;
}
}
}
BINARY2TXT_BINARY = getenv("BINARY2TXT_BINARY");
if ((argc > 1) && (strcmp(argv[1], "-v") == 0)) verbose = true;
int rv = RUN_ALL_TESTS();
MPI_Finalize();
return rv;
}

View File

@ -0,0 +1,138 @@
/* ----------------------------------------------------------------------
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.
------------------------------------------------------------------------- */
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "fmt/format.h"
#include "utils.h"
#include "../testing/core.h"
#include "../testing/systems/melt.h"
#include "../testing/utils.h"
using ::testing::Eq;
class DumpCfgTest : public MeltTest {
std::string dump_style = "cfg";
public:
void generate_dump(std::string dump_file, std::string fields, std::string dump_modify_options, int ntimesteps) {
if (!verbose) ::testing::internal::CaptureStdout();
command(fmt::format("dump id all {} 1 {} {}", dump_style, dump_file, fields));
if (!dump_modify_options.empty()) {
command(fmt::format("dump_modify id {}", dump_modify_options));
}
command(fmt::format("run {}", ntimesteps));
if (!verbose) ::testing::internal::GetCapturedStdout();
}
};
TEST_F(DumpCfgTest, invalid_options)
{
TEST_FAILURE(".*Dump cfg arguments must start with 'mass type xs ys zs'.*",
command("dump id all cfg 1 dump.cfg id type proc procp1 mass x y z");
);
}
TEST_F(DumpCfgTest, require_multifile)
{
auto dump_file = "dump_melt_run.cfg";
auto fields = "mass type xs ys zs id proc procp1 x y z ix iy iz xu yu zu xsu ysu zsu vx vy vz fx fy fz";
if (!verbose) ::testing::internal::CaptureStdout();
command(fmt::format("dump id all cfg 1 {} {}", dump_file, fields));
if (!verbose) ::testing::internal::GetCapturedStdout();
TEST_FAILURE(".*Dump cfg requires one snapshot per file.*",
command("run 0");
);
}
TEST_F(DumpCfgTest, run0)
{
auto dump_file = "dump_cfg_run*.melt";
auto fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz";
generate_dump(dump_file, fields, "", 0);
ASSERT_FILE_EXISTS("dump_cfg_run0.melt");
auto lines = read_lines("dump_cfg_run0.melt");
ASSERT_EQ(lines.size(), 124);
ASSERT_THAT(lines[0], Eq("Number of particles = 32"));
delete_file("dump_cfg_run0.melt");
}
TEST_F(DumpCfgTest, unwrap_run0)
{
auto dump_file = "dump_cfg_unwrap_run*.melt";
auto fields = "mass type xsu ysu zsu id proc procp1 x y z ix iy iz vx vy vz fx fy fz";
generate_dump(dump_file, fields, "", 0);
ASSERT_FILE_EXISTS("dump_cfg_unwrap_run0.melt");
auto lines = read_lines("dump_cfg_unwrap_run0.melt");
ASSERT_EQ(lines.size(), 124);
ASSERT_THAT(lines[0], Eq("Number of particles = 32"));
delete_file("dump_cfg_unwrap_run0.melt");
}
TEST_F(DumpCfgTest, no_buffer_run0)
{
auto dump_file = "dump_cfg_no_buffer_run*.melt";
auto fields = "mass type xsu ysu zsu id proc procp1 x y z ix iy iz vx vy vz fx fy fz";
generate_dump(dump_file, fields, "buffer no", 0);
ASSERT_FILE_EXISTS("dump_cfg_no_buffer_run0.melt");
auto lines = read_lines("dump_cfg_no_buffer_run0.melt");
ASSERT_EQ(lines.size(), 124);
ASSERT_THAT(lines[0], Eq("Number of particles = 32"));
delete_file("dump_cfg_no_buffer_run0.melt");
}
TEST_F(DumpCfgTest, no_unwrap_no_buffer_run0)
{
auto dump_file = "dump_cfg_no_unwrap_no_buffer_run*.melt";
auto fields = "mass type xs ys zs id proc procp1 x y z ix iy iz vx vy vz fx fy fz";
generate_dump(dump_file, fields, "buffer no", 0);
ASSERT_FILE_EXISTS("dump_cfg_no_unwrap_no_buffer_run0.melt");
auto lines = read_lines("dump_cfg_no_unwrap_no_buffer_run0.melt");
ASSERT_EQ(lines.size(), 124);
ASSERT_THAT(lines[0], Eq("Number of particles = 32"));
delete_file("dump_cfg_no_unwrap_no_buffer_run0.melt");
}
int main(int argc, char **argv)
{
MPI_Init(&argc, &argv);
::testing::InitGoogleMock(&argc, argv);
// handle arguments passed via environment variable
if (const char *var = getenv("TEST_ARGS")) {
std::vector<std::string> env = utils::split_words(var);
for (auto arg : env) {
if (arg == "-v") {
verbose = true;
}
}
}
if ((argc > 1) && (strcmp(argv[1], "-v") == 0)) verbose = true;
int rv = RUN_ALL_TESTS();
MPI_Finalize();
return rv;
}

View File

@ -0,0 +1,279 @@
/* ----------------------------------------------------------------------
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.
------------------------------------------------------------------------- */
#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "fmt/format.h"
#include "utils.h"
#include "../testing/core.h"
#include "../testing/systems/melt.h"
#include "../testing/utils.h"
using ::testing::Eq;
char * BINARY2TXT_BINARY = nullptr;
class DumpCustomTest : public MeltTest {
std::string dump_style = "custom";
public:
void enable_triclinic() {
if (!verbose) ::testing::internal::CaptureStdout();
command("change_box all triclinic");
if (!verbose) ::testing::internal::GetCapturedStdout();
}
void generate_dump(std::string dump_file, std::string fields, std::string dump_modify_options, int ntimesteps) {
if (!verbose) ::testing::internal::CaptureStdout();
command(fmt::format("dump id all {} 1 {} {}", dump_style, dump_file, fields));
if (!dump_modify_options.empty()) {
command(fmt::format("dump_modify id {}", dump_modify_options));
}
command(fmt::format("run {}", ntimesteps));
if (!verbose) ::testing::internal::GetCapturedStdout();
}
void generate_text_and_binary_dump(std::string text_file, std::string binary_file, std::string fields,
std::string dump_modify_options, int ntimesteps) {
if (!verbose) ::testing::internal::CaptureStdout();
command(fmt::format("dump id0 all {} 1 {} {}", dump_style, text_file, fields));
command(fmt::format("dump id1 all {} 1 {} {}", dump_style, binary_file, fields));
if (!dump_modify_options.empty()) {
command(fmt::format("dump_modify id0 {}", dump_modify_options));
command(fmt::format("dump_modify id1 {}", dump_modify_options));
}
command(fmt::format("run {}", ntimesteps));
if (!verbose) ::testing::internal::GetCapturedStdout();
}
std::string convert_binary_to_text(std::string binary_file) {
if (!verbose) ::testing::internal::CaptureStdout();
std::string cmdline = fmt::format("{} {}", BINARY2TXT_BINARY, binary_file);
system(cmdline.c_str());
if (!verbose) ::testing::internal::GetCapturedStdout();
return fmt::format("{}.txt", binary_file);
}
};
TEST_F(DumpCustomTest, run1)
{
auto dump_file = "dump_custom_run1.melt";
auto fields = "id type proc procp1 mass x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz";
generate_dump(dump_file, fields, "units yes", 1);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 84);
ASSERT_THAT(lines[6], Eq("ITEM: BOX BOUNDS pp pp pp"));
ASSERT_EQ(utils::split_words(lines[7]).size(), 2);
ASSERT_THAT(lines[10], Eq(fmt::format("ITEM: ATOMS {}", fields)));
ASSERT_EQ(utils::split_words(lines[11]).size(), 26);
delete_file(dump_file);
}
TEST_F(DumpCustomTest, thresh_run0)
{
auto dump_file = "dump_custom_thresh_run0.melt";
auto fields = "id type x y z";
generate_dump(dump_file, fields, "units yes thresh x < 1 thresh y < 1 thresh z < 1", 0);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 15);
ASSERT_THAT(lines[6], Eq("ITEM: BOX BOUNDS pp pp pp"));
ASSERT_EQ(utils::split_words(lines[7]).size(), 2);
ASSERT_THAT(lines[10], Eq(fmt::format("ITEM: ATOMS {}", fields)));
ASSERT_EQ(utils::split_words(lines[11]).size(), 5);
delete_file(dump_file);
}
TEST_F(DumpCustomTest, compute_run0)
{
if (!verbose) ::testing::internal::CaptureStdout();
command("compute comp all property/atom x y z");
if (!verbose) ::testing::internal::GetCapturedStdout();
auto dump_file = "dump_custom_compute_run0.melt";
auto fields = "id type x y z c_comp[1] c_comp[2] c_comp[3]";
generate_dump(dump_file, fields, "units yes", 0);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 43);
ASSERT_THAT(lines[6], Eq("ITEM: BOX BOUNDS pp pp pp"));
ASSERT_EQ(utils::split_words(lines[7]).size(), 2);
ASSERT_THAT(lines[10], Eq(fmt::format("ITEM: ATOMS {}", fields)));
ASSERT_EQ(utils::split_words(lines[11]).size(), 8);
delete_file(dump_file);
}
TEST_F(DumpCustomTest, fix_run0)
{
if (!verbose) ::testing::internal::CaptureStdout();
command("fix numdiff all numdiff 1 0.0001");
if (!verbose) ::testing::internal::GetCapturedStdout();
auto dump_file = "dump_custom_compute_run0.melt";
auto fields = "id x y z f_numdiff[1] f_numdiff[2] f_numdiff[3]";
generate_dump(dump_file, fields, "units yes", 0);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 43);
ASSERT_THAT(lines[6], Eq("ITEM: BOX BOUNDS pp pp pp"));
ASSERT_EQ(utils::split_words(lines[7]).size(), 2);
ASSERT_THAT(lines[10], Eq(fmt::format("ITEM: ATOMS {}", fields)));
ASSERT_EQ(utils::split_words(lines[11]).size(), 7);
delete_file(dump_file);
}
TEST_F(DumpCustomTest, custom_run0)
{
if (!verbose) ::testing::internal::CaptureStdout();
command("fix prop all property/atom i_flag1 d_flag2");
command("compute 1 all property/atom i_flag1 d_flag2");
if (!verbose) ::testing::internal::GetCapturedStdout();
auto dump_file = "dump_custom_custom_run0.melt";
auto fields = "id x y z i_flag1 d_flag2";
generate_dump(dump_file, fields, "units yes", 0);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 43);
ASSERT_THAT(lines[6], Eq("ITEM: BOX BOUNDS pp pp pp"));
ASSERT_EQ(utils::split_words(lines[7]).size(), 2);
ASSERT_THAT(lines[10], Eq(fmt::format("ITEM: ATOMS {}", fields)));
ASSERT_EQ(utils::split_words(lines[11]).size(), 6);
delete_file(dump_file);
}
TEST_F(DumpCustomTest, binary_run1)
{
if(!BINARY2TXT_BINARY) GTEST_SKIP();
auto text_file = "dump_custom_text_run1.melt";
auto binary_file = "dump_custom_binary_run1.melt.bin";
auto fields = "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz";
generate_text_and_binary_dump(text_file, binary_file, fields, "units yes", 1);
ASSERT_FILE_EXISTS(text_file);
ASSERT_FILE_EXISTS(binary_file);
auto converted_file = convert_binary_to_text(binary_file);
ASSERT_FILE_EXISTS(converted_file);
ASSERT_FILE_EQUAL(text_file, converted_file);
delete_file(text_file);
delete_file(binary_file);
delete_file(converted_file);
}
TEST_F(DumpCustomTest, triclinic_run1)
{
auto dump_file = "dump_custom_tri_run1.melt";
auto fields = "id type proc x y z ix iy iz xs ys zs xu yu zu xsu ysu zsu vx vy vz fx fy fz";
enable_triclinic();
generate_dump(dump_file, fields, "units yes", 1);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_THAT(lines[6], Eq("ITEM: BOX BOUNDS xy xz yz pp pp pp"));
ASSERT_EQ(utils::split_words(lines[7]).size(), 3);
ASSERT_EQ(lines.size(), 84);
delete_file(dump_file);
}
TEST_F(DumpCustomTest, binary_triclinic_run1)
{
if(!BINARY2TXT_BINARY) GTEST_SKIP();
auto text_file = "dump_custom_tri_text_run1.melt";
auto binary_file = "dump_custom_tri_binary_run1.melt.bin";
auto fields = "id type proc x y z xs ys zs xsu ysu zsu vx vy vz fx fy fz";
enable_triclinic();
generate_text_and_binary_dump(text_file, binary_file, fields, "units yes", 1);
ASSERT_FILE_EXISTS(text_file);
ASSERT_FILE_EXISTS(binary_file);
auto converted_file = convert_binary_to_text(binary_file);
ASSERT_FILE_EXISTS(converted_file);
ASSERT_FILE_EQUAL(text_file, converted_file);
delete_file(text_file);
delete_file(binary_file);
delete_file(converted_file);
}
TEST_F(DumpCustomTest, with_variable_run1)
{
if (!verbose) ::testing::internal::CaptureStdout();
command("compute 1 all property/atom proc");
command("variable p atom (c_1%10)+1");
if (!verbose) ::testing::internal::GetCapturedStdout();
auto dump_file = "dump_custom_with_variable_run1.melt";
auto fields = "id type x y z v_p";
generate_dump(dump_file, fields, "units yes", 1);
ASSERT_FILE_EXISTS(dump_file);
auto lines = read_lines(dump_file);
ASSERT_EQ(lines.size(), 84);
ASSERT_THAT(lines[6], Eq("ITEM: BOX BOUNDS pp pp pp"));
ASSERT_EQ(utils::split_words(lines[7]).size(), 2);
ASSERT_THAT(lines[10], Eq("ITEM: ATOMS id type x y z v_p"));
ASSERT_EQ(utils::split_words(lines[11]).size(), 6);
delete_file(dump_file);
}
int main(int argc, char **argv)
{
MPI_Init(&argc, &argv);
::testing::InitGoogleMock(&argc, argv);
// handle arguments passed via environment variable
if (const char *var = getenv("TEST_ARGS")) {
std::vector<std::string> env = utils::split_words(var);
for (auto arg : env) {
if (arg == "-v") {
verbose = true;
}
}
}
BINARY2TXT_BINARY = getenv("BINARY2TXT_BINARY");
if ((argc > 1) && (strcmp(argv[1], "-v") == 0)) verbose = true;
int rv = RUN_ALL_TESTS();
MPI_Finalize();
return rv;
}

79
unittest/testing/core.h Normal file
View File

@ -0,0 +1,79 @@
/* ----------------------------------------------------------------------
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.
------------------------------------------------------------------------- */
#ifndef TESTING_CORE__H
#define TESTING_CORE__H
#include "info.h"
#include "input.h"
#include "lammps.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
using namespace LAMMPS_NS;
using ::testing::MatchesRegex;
#define TEST_FAILURE(errmsg, ...) \
if (Info::has_exceptions()) { \
::testing::internal::CaptureStdout(); \
ASSERT_ANY_THROW({__VA_ARGS__}); \
auto mesg = ::testing::internal::GetCapturedStdout(); \
ASSERT_THAT(mesg, MatchesRegex(errmsg)); \
} else { \
if (Info::get_mpi_vendor() != "Open MPI") { \
::testing::internal::CaptureStdout(); \
ASSERT_DEATH({__VA_ARGS__}, ""); \
auto mesg = ::testing::internal::GetCapturedStdout(); \
ASSERT_THAT(mesg, MatchesRegex(errmsg)); \
} \
}
// whether to print verbose output (i.e. not capturing LAMMPS screen output).
bool verbose = false;
class LAMMPSTest : public ::testing::Test {
public:
void command(const std::string &line) {
lmp->input->one(line.c_str());
}
protected:
const char * testbinary = "LAMMPSTest";
LAMMPS *lmp;
void SetUp() override
{
const char *args[] = { testbinary, "-log", "none", "-echo", "screen", "-nocite"};
char **argv = (char **)args;
int argc = sizeof(args) / sizeof(char *);
if (!verbose) ::testing::internal::CaptureStdout();
lmp = new LAMMPS(argc, argv, MPI_COMM_WORLD);
InitSystem();
if (!verbose) ::testing::internal::GetCapturedStdout();
}
virtual void InitSystem() {
}
void TearDown() override
{
if (!verbose) ::testing::internal::CaptureStdout();
delete lmp;
if (!verbose) ::testing::internal::GetCapturedStdout();
}
};
#endif

View File

@ -0,0 +1,41 @@
/* ----------------------------------------------------------------------
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.
------------------------------------------------------------------------- */
#ifndef TEST_EXAMPLE_MELT__H
#define TEST_EXAMPLE_MELT__H
#include "../core.h"
class MeltTest : public LAMMPSTest {
protected:
virtual void InitSystem() override {
command("units lj");
command("atom_style atomic");
command("atom_modify map yes");
command("lattice fcc 0.8442");
command("region box block 0 2 0 2 0 2");
command("create_box 1 box");
command("create_atoms 1 box");
command("mass 1 1.0");
command("velocity all create 3.0 87287");
command("pair_style lj/cut 2.5");
command("pair_coeff 1 1 1.0 1.0 2.5");
command("neighbor 0.3 bin");
command("neigh_modify every 20 delay 0 check no");
}
};
#endif

73
unittest/testing/utils.h Normal file
View File

@ -0,0 +1,73 @@
/* ----------------------------------------------------------------------
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.
------------------------------------------------------------------------- */
#ifndef TEST_EXTENSIONS__H
#define TEST_EXTENSIONS__H
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
static void delete_file(const std::string &filename)
{
remove(filename.c_str());
}
static size_t count_lines(const std::string &filename)
{
std::ifstream infile(filename);
std::string line;
size_t nlines = 0;
while (std::getline(infile, line))
++nlines;
return nlines;
}
static bool equal_lines(const std::string &fileA, const std::string &fileB)
{
std::ifstream afile(fileA);
std::ifstream bfile(fileB);
std::string lineA, lineB;
while (std::getline(afile, lineA)) {
if(!std::getline(bfile, lineB)) return false;
if(lineA != lineB) return false;
}
return true;
}
static std::vector<std::string> read_lines(const std::string &filename) {
std::vector<std::string> lines;
std::ifstream infile(filename);
std::string line;
while (std::getline(infile, line))
lines.push_back(line);
return lines;
}
static bool file_exists(const std::string &filename) {
struct stat result;
return stat(filename.c_str(), &result) == 0;
}
#define ASSERT_FILE_EXISTS(NAME) ASSERT_TRUE(file_exists(NAME))
#define ASSERT_FILE_EQUAL(FILE_A, FILE_B) ASSERT_TRUE(equal_lines(FILE_A, FILE_B))
#endif

View File

@ -125,3 +125,14 @@ TEST(ValueTokenizer, valid_double_with_exponential)
ValueTokenizer values("3.14e22");
ASSERT_DOUBLE_EQ(values.next_double(), 3.14e22);
}
TEST(ValueTokenizer, contains) {
ValueTokenizer values("test word");
ASSERT_TRUE(values.contains("test"));
ASSERT_TRUE(values.contains("word"));
}
TEST(ValueTokenizer, not_contains) {
ValueTokenizer values("test word");
ASSERT_FALSE(values.contains("test2"));
}

View File

@ -462,3 +462,18 @@ TEST(Utils, unit_conversion)
factor = utils::get_conversion_factor(utils::ENERGY, utils::REAL2METAL);
ASSERT_DOUBLE_EQ(factor, 1.0 / 23.060549);
}
TEST(Utils, timespec2seconds_ss)
{
ASSERT_DOUBLE_EQ(utils::timespec2seconds("45"), 45.0);
}
TEST(Utils, timespec2seconds_mmss)
{
ASSERT_DOUBLE_EQ(utils::timespec2seconds("10:45"), 645.0);
}
TEST(Utils, timespec2seconds_hhmmss)
{
ASSERT_DOUBLE_EQ(utils::timespec2seconds("2:10:45"), 7845.0);
}