add general tri options to read and write data commands and Domain class

This commit is contained in:
Steve Plimpton
2023-08-31 14:34:37 -06:00
parent dc3c8da52b
commit db72d4b73a
9 changed files with 426 additions and 73 deletions

View File

@ -1041,7 +1041,8 @@ void Atom::deallocate_topology()
------------------------------------------------------------------------- */ ------------------------------------------------------------------------- */
void Atom::data_atoms(int n, char *buf, tagint id_offset, tagint mol_offset, void Atom::data_atoms(int n, char *buf, tagint id_offset, tagint mol_offset,
int type_offset, int shiftflag, double *shift, int type_offset, int triclinic_general,
int shiftflag, double *shift,
int labelflag, int *ilabel) int labelflag, int *ilabel)
{ {
int xptr,iptr; int xptr,iptr;
@ -1053,6 +1054,7 @@ void Atom::data_atoms(int n, char *buf, tagint id_offset, tagint mol_offset,
auto location = "Atoms section of data file"; auto location = "Atoms section of data file";
// use the first line to detect and validate the number of words/tokens per line // use the first line to detect and validate the number of words/tokens per line
next = strchr(buf,'\n'); next = strchr(buf,'\n');
if (!next) error->all(FLERR, "Missing data in {}", location); if (!next) error->all(FLERR, "Missing data in {}", location);
*next = '\0'; *next = '\0';
@ -1069,6 +1071,7 @@ void Atom::data_atoms(int n, char *buf, tagint id_offset, tagint mol_offset,
error->all(FLERR,"Incorrect format in {}: {}", location, utils::trim(buf)); error->all(FLERR,"Incorrect format in {}: {}", location, utils::trim(buf));
*next = '\n'; *next = '\n';
// set bounds for my proc // set bounds for my proc
// if periodic and I am lo/hi proc, adjust bounds by EPSILON // if periodic and I am lo/hi proc, adjust bounds by EPSILON
// ensures all data atoms will be owned even with round-off // ensures all data atoms will be owned even with round-off
@ -1143,11 +1146,19 @@ void Atom::data_atoms(int n, char *buf, tagint id_offset, tagint mol_offset,
*next = '\0'; *next = '\0';
auto values = Tokenizer(buf).as_vector(); auto values = Tokenizer(buf).as_vector();
int nvalues = values.size(); int nvalues = values.size();
if ((nvalues == 0) || (utils::strmatch(values[0],"^#.*"))) {
// skip over empty or comment lines // skip comment lines
if ((nvalues == 0) || (utils::strmatch(values[0],"^#.*"))) {
// check that line has correct # of words
} else if ((nvalues < nwords) || } else if ((nvalues < nwords) ||
((nvalues > nwords) && (!utils::strmatch(values[nwords],"^#")))) { ((nvalues > nwords) && (!utils::strmatch(values[nwords],"^#")))) {
error->all(FLERR, "Incorrect format in {}: {}", location, utils::trim(buf)); error->all(FLERR, "Incorrect format in {}: {}", location, utils::trim(buf));
// extract the atom coords and image flags (if they exist)
} else { } else {
int imx = 0, imy = 0, imz = 0; int imx = 0, imy = 0, imz = 0;
if (imageflag) { if (imageflag) {
@ -1167,13 +1178,25 @@ void Atom::data_atoms(int n, char *buf, tagint id_offset, tagint mol_offset,
xdata[0] = utils::numeric(FLERR,values[xptr],false,lmp); xdata[0] = utils::numeric(FLERR,values[xptr],false,lmp);
xdata[1] = utils::numeric(FLERR,values[xptr+1],false,lmp); xdata[1] = utils::numeric(FLERR,values[xptr+1],false,lmp);
xdata[2] = utils::numeric(FLERR,values[xptr+2],false,lmp); xdata[2] = utils::numeric(FLERR,values[xptr+2],false,lmp);
// convert atom coords from general triclinic to restricted triclinic
if (triclinic_general) domain->general_to_restricted(xdata);
// apply shift if requested by read_data command
if (shiftflag) { if (shiftflag) {
xdata[0] += shift[0]; xdata[0] += shift[0];
xdata[1] += shift[1]; xdata[1] += shift[1];
xdata[2] += shift[2]; xdata[2] += shift[2];
} }
// map atom into simulation box for periodic dimensions
domain->remap(xdata,imagedata); domain->remap(xdata,imagedata);
// determine if this proc owns the atom
if (triclinic) { if (triclinic) {
domain->x2lamda(xdata,lamda); domain->x2lamda(xdata,lamda);
coord = lamda; coord = lamda;

View File

@ -328,7 +328,8 @@ class Atom : protected Pointers {
void deallocate_topology(); void deallocate_topology();
void data_atoms(int, char *, tagint, tagint, int, int, double *, int, int *); void data_atoms(int, char *, tagint, tagint, int, int,
int, double *, int, int *);
void data_vels(int, char *, tagint); void data_vels(int, char *, tagint);
void data_bonds(int, char *, int *, tagint, int, int, int *); void data_bonds(int, char *, int *, tagint, int, int, int *);
void data_angles(int, char *, int *, tagint, int, int, int *); void data_angles(int, char *, int *, tagint, int, int, int *);

View File

@ -28,6 +28,7 @@
#include "force.h" #include "force.h"
#include "kspace.h" #include "kspace.h"
#include "lattice.h" #include "lattice.h"
#include "math_extra.h"
#include "memory.h" #include "memory.h"
#include "modify.h" #include "modify.h"
#include "molecule.h" #include "molecule.h"
@ -41,6 +42,7 @@
#include <cmath> #include <cmath>
using namespace LAMMPS_NS; using namespace LAMMPS_NS;
using namespace MathExtra;
#define BIG 1.0e20 #define BIG 1.0e20
#define SMALL 1.0e-4 #define SMALL 1.0e-4
@ -81,7 +83,7 @@ Domain::Domain(LAMMPS *lmp) : Pointers(lmp)
minylo = minyhi = 0.0; minylo = minyhi = 0.0;
minzlo = minzhi = 0.0; minzlo = minzhi = 0.0;
triclinic = 0; triclinic = triclinic_general = 0;
boxlo[0] = boxlo[1] = boxlo[2] = -0.5; boxlo[0] = boxlo[1] = boxlo[2] = -0.5;
boxhi[0] = boxhi[1] = boxhi[2] = 0.5; boxhi[0] = boxhi[1] = boxhi[2] = 0.5;
@ -516,6 +518,180 @@ void Domain::reset_box()
} }
} }
/* ----------------------------------------------------------------------
define and store a general triclinic simulation box
3 edge vectors of box = avec/bvec/cvec caller
origin of edge vectors = origin_caller = lower left corner of box
create mapping to restricted triclinic box
set boxlo[3], boxhi[3] and 3 tilt factors
create rotation matrices for general <--> restricted transformations
------------------------------------------------------------------------- */
void Domain::set_general_triclinic(double *avec_caller, double *bvec_caller,
double *cvec_caller, double *origin_caller)
{
if (triclinic || triclinic_general)
error->all(FLERR,"General triclinic box edge vectors are already set");
triclinic = triclinic_general = 1;
avec[0] = avec_caller[0];
avec[1] = avec_caller[1];
avec[2] = avec_caller[2];
bvec[0] = bvec_caller[0];
bvec[1] = bvec_caller[1];
bvec[2] = bvec_caller[2];
cvec[0] = cvec_caller[0];
cvec[1] = cvec_caller[1];
cvec[2] = cvec_caller[2];
tri_origin[0] = origin_caller[0];
tri_origin[1] = origin_caller[1];
tri_origin[2] = origin_caller[2];
// error check for co-planar A,B,C
double abcross[3];
MathExtra::cross3(avec,bvec,abcross);
double dot = MathExtra::dot3(abcross,cvec);
if (dot == 0.0)
error->all(FLERR,"General triclinic box edge vectors are co-planar");
// quat1 = convert A into A' along x-axis
// rot1 = unit vector to rotate A around
// theta1 = angle of rotation calculated from
// A dot xunit = Ax = |A| cos(theta1)
double rot1[3],quat1[4];
double xaxis[3] = {1.0, 0.0, 0.0};
double avec_len = MathExtra::len3(avec);
MathExtra::cross3(avec,xaxis,rot1);
MathExtra::norm3(rot1);
double theta1 = acos(avec[0]/avec_len);
MathExtra::axisangle_to_quat(rot1,theta1,quat1);
// rotmat1 = rotation matrix associated with quat1
double rotmat1[3][3];
MathExtra::quat_to_mat(quat1,rotmat1);
// B1 = rotation of B by quat1 rotation matrix
double bvec1[3];
MathExtra::matvec(rotmat1,bvec,bvec1);
// quat2 = rotation to convert B1 into B' in xy plane
// Byz1 = projection of B1 into yz plane
// rot2 = unit vector to rotate B1 around = -x axis
// theta2 = angle of rotation calculated from
// Byz1 dot yunit = B1y = |Byz1} cos(theta2)
double byzvec1[3],quat2[4];
MathExtra::copy3(bvec1,byzvec1);
byzvec1[0] = 0.0;
double byzvec1_len = MathExtra::len3(byzvec1);
double rot2[3] = {-1.0, 0.0, 0.0};
double theta2 = acos(bvec1[1]/byzvec1_len);
MathExtra::axisangle_to_quat(rot2,theta2,quat2);
// quat = product of quat2 * quat1 = transformation via single quat
// rotate_g2r = general to restricted transformation matrix
// rotate_r2g = restricted to general transformation matrix
// if A x B not in direction of C, flip sign of z component of transform
// done by flipping sign of 3rd row of rotate_g2r matrix
double quat[4];
MathExtra::quatquat(quat2,quat1,quat);
MathExtra::quat_to_mat(quat,rotate_g2r);
if (dot < 0.0) {
rotate_g2r[2][0] = -rotate_g2r[2][0];
rotate_g2r[2][1] = -rotate_g2r[2][1];
rotate_g2r[2][2] = -rotate_g2r[2][2];
}
MathExtra::transpose3(rotate_g2r,rotate_r2g);
// A',B',C' = transformation of A,B,C to restricted triclinic
double aprime[3],bprime[3],cprime[3];
MathExtra::matvec(rotate_g2r,avec,aprime);
MathExtra::matvec(rotate_g2r,bvec,bprime);
MathExtra::matvec(rotate_g2r,cvec,cprime);
// set restricted triclinic boxlo, boxhi, and tilt factors
boxlo[0] = tri_origin[0];
boxlo[1] = tri_origin[1];
boxlo[2] = tri_origin[2];
boxhi[0] = boxlo[0] + aprime[0];
boxhi[1] = boxlo[1] + bprime[1];
boxhi[2] = boxlo[2] + cprime[2];
xy = bprime[1];
xz = cprime[0];
yz = cprime[1];
// debug
/*
printf("Quat: %g %g %g %g\n",quat[0],quat[1],quat[2],quat[3]);
double angle = 2.0*acos(quat[0]);
printf("Theta: %g\n",angle);
printf("Rotvec: %g %g %g\n",quat[1]/sin(0.5*angle),quat[2]/sin(0.5*angle),quat[3]/sin(0.5*angle));
printf("Aprime: %g %g %g\n",aprime[0],aprime[1],aprime[2]);
printf("Bprime: %g %g %g\n",bprime[0],bprime[1],bprime[2]);
printf("Cprime: %g %g %g\n",cprime[0],cprime[1],cprime[2]);
printf("Length A: %g %g\n",MathExtra::len3(avec),MathExtra::len3(aprime));
printf("Length B: %g %g\n",MathExtra::len3(bvec),MathExtra::len3(bprime));
printf("Length C: %g %g\n",MathExtra::len3(cvec),MathExtra::len3(cprime));
double coord1[3] = {0.5,0.0,0.0};
double coord2[3] = {0.5,0.0,0.3};
double newcoord[3];
MathExtra::matvec(rotate_g2r,coord1,newcoord);
printf("Atom1: %g %g %g\n",newcoord[0],newcoord[1],newcoord[2]);
MathExtra::matvec(rotate_g2r,coord2,newcoord);
printf("Atom2: %g %g %g\n",newcoord[0],newcoord[1],newcoord[2]);
*/
}
/* ----------------------------------------------------------------------
transform one atom's coords from general triclinic to restricted triclinic
------------------------------------------------------------------------- */
void Domain::general_to_restricted(double *x)
{
double xnew[3];
MathExtra::matvec(rotate_g2r,x,xnew);
x[0] = xnew[0] + tri_origin[0];
x[1] = xnew[1] + tri_origin[1];
x[2] = xnew[2] + tri_origin[2];
}
/* ----------------------------------------------------------------------
transform one atom's coords from restricted triclinic to general triclinic
------------------------------------------------------------------------- */
void Domain::restricted_to_general(double *x)
{
double xshift[3],xnew[3];
xshift[0] = x[0] - tri_origin[0];
xshift[1] = x[1] - tri_origin[1];
xshift[2] = x[2] - tri_origin[2];
MathExtra::matvec(rotate_r2g,xshift,xnew);
x[0] = xnew[0];
x[1] = xnew[1];
x[2] = xnew[2];
}
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
enforce PBC and modify box image flags for each atom enforce PBC and modify box image flags for each atom
called every reneighboring and by other commands that change atoms called every reneighboring and by other commands that change atoms
@ -676,9 +852,7 @@ int Domain::inside(double* x)
lamda[1] < lo[1] || lamda[1] >= hi[1] || lamda[1] < lo[1] || lamda[1] >= hi[1] ||
lamda[2] < lo[2] || lamda[2] >= hi[2]) return 0; lamda[2] < lo[2] || lamda[2] >= hi[2]) return 0;
else return 1; else return 1;
} }
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------
@ -713,7 +887,6 @@ int Domain::inside_nonperiodic(double* x)
if (!zperiodic && (lamda[2] < lo[2] || lamda[2] >= hi[2])) return 0; if (!zperiodic && (lamda[2] < lo[2] || lamda[2] >= hi[2])) return 0;
return 1; return 1;
} }
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------

View File

@ -39,8 +39,9 @@ class Domain : protected Pointers {
// 2 = shrink-wrap non-periodic // 2 = shrink-wrap non-periodic
// 3 = shrink-wrap non-per w/ min // 3 = shrink-wrap non-per w/ min
int triclinic; // 0 = orthog box, 1 = triclinic int triclinic; // 0 = orthog box, 1 = triclinic (restricted or general)
int triclinic_general; // 1 if mapping to/from general triclinic is stored, 0 if not
// orthogonal box // orthogonal box
double xprd, yprd, zprd; // global box dimensions double xprd, yprd, zprd; // global box dimensions
@ -48,8 +49,8 @@ class Domain : protected Pointers {
double prd[3]; // array form of dimensions double prd[3]; // array form of dimensions
double prd_half[3]; // array form of half dimensions double prd_half[3]; // array form of half dimensions
// triclinic box // restricted triclinic box
// xyzprd,xyzprd_half and prd,prd_half = same as if untilted // xyzprd,xyzprd_half and prd,prd_half = same as if not tilted
double prd_lamda[3]; // lamda box = (1,1,1) double prd_lamda[3]; // lamda box = (1,1,1)
double prd_half_lamda[3]; // lamda half box = (0.5,0.5,0.5) double prd_half_lamda[3]; // lamda half box = (0.5,0.5,0.5)
@ -58,14 +59,14 @@ class Domain : protected Pointers {
double boxlo[3], boxhi[3]; double boxlo[3], boxhi[3];
// triclinic box // restricted triclinic box
// boxlo/hi = same as if untilted // boxlo/hi = same as if not tilted
double boxlo_lamda[3], boxhi_lamda[3]; // lamda box = (0,1) double boxlo_lamda[3], boxhi_lamda[3]; // lamda box = (0,1)
double boxlo_bound[3], boxhi_bound[3]; // bounding box of tilted domain double boxlo_bound[3], boxhi_bound[3]; // bounding box of tilted domain
double corners[8][3]; // 8 corner points double corners[8][3]; // 8 corner points
// orthogonal box & triclinic box // orthogonal box & restricted triclinic box
double minxlo, minxhi; // minimum size of global box double minxlo, minxhi; // minimum size of global box
double minylo, minyhi; // when shrink-wrapping double minylo, minyhi; // when shrink-wrapping
@ -75,18 +76,27 @@ class Domain : protected Pointers {
double sublo[3], subhi[3]; // sub-box bounds on this proc double sublo[3], subhi[3]; // sub-box bounds on this proc
// triclinic box // restricted triclinic box
// sublo/hi = undefined // sublo/hi = undefined
double sublo_lamda[3], subhi_lamda[3]; // bounds of subbox in lamda double sublo_lamda[3], subhi_lamda[3]; // bounds of subbox in lamda
// triclinic box // restricted triclinic box
double xy, xz, yz; // 3 tilt factors double xy, xz, yz; // 3 tilt factors
double h[6], h_inv[6]; // shape matrix in Voigt ordering double h[6], h_inv[6]; // shape matrix in Voigt ordering
// Voigt = xx,yy,zz,yz,xz,xy // Voigt = xx,yy,zz,yz,xz,xy
double h_rate[6], h_ratelo[3]; // rate of box size/shape change double h_rate[6], h_ratelo[3]; // rate of box size/shape change
// general triclinic box
double avec[3], bvec[3], cvec[3]; // ABC edge vectors of general triclinic box
double tri_origin[3]; // origin of general triclinic box
double rotate_g2r[3][3]; // rotation matrix from general --> restricted tri
double rotate_r2g[3][3]; // rotation matrix from restricted --> general tri
// box flags
int box_change; // 1 if any of next 3 flags are set, else 0 int box_change; // 1 if any of next 3 flags are set, else 0
int box_change_size; // 1 if box size changes, 0 if not int box_change_size; // 1 if box size changes, 0 if not
int box_change_shape; // 1 if box shape changes, 0 if not int box_change_shape; // 1 if box shape changes, 0 if not
@ -131,6 +141,10 @@ class Domain : protected Pointers {
void image_flip(int, int, int); void image_flip(int, int, int);
int ownatom(int, double *, imageint *, int); int ownatom(int, double *, imageint *, int);
void set_general_triclinic(double *, double *, double *, double *);
void general_to_restricted(double *);
void restricted_to_general(double *);
void set_lattice(int, char **); void set_lattice(int, char **);
void add_region(int, char **); void add_region(int, char **);
void delete_region(Region *); void delete_region(Region *);

View File

@ -47,6 +47,7 @@ inline void cross3(const double *v1, const double *v2, double *ans);
inline void zeromat3(double m[3][3]); inline void zeromat3(double m[3][3]);
inline void zeromat3(double **m); inline void zeromat3(double **m);
inline void transpose3(const double m[3][3], double ans[3][3]);
inline void col2mat(const double *ex, const double *ey, const double *ez, double m[3][3]); inline void col2mat(const double *ex, const double *ey, const double *ez, double m[3][3]);
inline double det3(const double mat[3][3]); inline double det3(const double mat[3][3]);
@ -763,6 +764,21 @@ inline void MathExtra::zeromat3(double **m)
m[2][0] = m[2][1] = m[2][2] = 0.0; m[2][0] = m[2][1] = m[2][2] = 0.0;
} }
// transpose a matrix
inline void MathExtra::transpose3(const double m[3][3], double ans[3][3])
{
ans[0][0] = m[0][0];
ans[0][1] = m[1][0];
ans[0][2] = m[2][0];
ans[1][0] = m[0][1];
ans[1][1] = m[1][1];
ans[1][2] = m[2][1];
ans[2][0] = m[0][2];
ans[2][1] = m[1][2];
ans[2][2] = m[2][2];
}
// add two matrices // add two matrices
inline void MathExtra::plus3(const double m[3][3], double **m2, double **ans) inline void MathExtra::plus3(const double m[3][3], double **m2, double **ans)

View File

@ -474,11 +474,14 @@ void ReadData::command(int narg, char **arg)
int atomflag, topoflag; int atomflag, topoflag;
int bondflag, angleflag, dihedralflag, improperflag; int bondflag, angleflag, dihedralflag, improperflag;
int ellipsoidflag, lineflag, triflag, bodyflag; int ellipsoidflag, lineflag, triflag, bodyflag;
atomflag = topoflag = 0; atomflag = topoflag = 0;
bondflag = angleflag = dihedralflag = improperflag = 0; bondflag = angleflag = dihedralflag = improperflag = 0;
ellipsoidflag = lineflag = triflag = bodyflag = 0; ellipsoidflag = lineflag = triflag = bodyflag = 0;
xloxhi_flag = yloyhi_flag = zlozhi_flag = tilt_flag = 0;
avec_flag = bvec_flag = cvec_flag = 0;
// values in this data file // values in this data file
natoms = 0; natoms = 0;
@ -488,7 +491,12 @@ void ReadData::command(int narg, char **arg)
boxlo[0] = boxlo[1] = boxlo[2] = -0.5; boxlo[0] = boxlo[1] = boxlo[2] = -0.5;
boxhi[0] = boxhi[1] = boxhi[2] = 0.5; boxhi[0] = boxhi[1] = boxhi[2] = 0.5;
triclinic = 0; avec[0] = avec[1] = avec[2] = 0.0;
bvec[0] = bvec[1] = bvec[2] = 0.0;
cvec[0] = cvec[1] = cvec[2] = 0.0;
avec[0] = bvec[1] = cvec[2] = 1.0;
tri_origin[0] = tri_origin[1] = tri_origin[2] = 0.0;
keyword[0] = '\0'; keyword[0] = '\0';
nlocal_previous = atom->nlocal; nlocal_previous = atom->nlocal;
@ -508,6 +516,17 @@ void ReadData::command(int narg, char **arg)
header(firstpass); header(firstpass);
// check if simulation box specified consistently
if (!avec_flag && !bvec_flag && !cvec_flag) {
triclinic = triclinic_general = 0;
if (tilt_flag) triclinic = 1;
} else {
if (xloxhi_flag || yloyhi_flag || zlozhi_flag || tilt_flag)
error->all(FLERR,"Read_data header cannot specify simulation box lo/hi/tilt and ABC vectors");
triclinic = triclinic_general = 1;
}
// problem setup using info from header // problem setup using info from header
// only done once, if firstpass and first data file // only done once, if firstpass and first data file
// apply extra settings before grow(), even if no topology in file // apply extra settings before grow(), even if no topology in file
@ -536,31 +555,69 @@ void ReadData::command(int narg, char **arg)
n = static_cast<int>(nbig); n = static_cast<int>(nbig);
atom->avec->grow(n); atom->avec->grow(n);
domain->boxlo[0] = boxlo[0]; // setup simulation box
domain->boxhi[0] = boxhi[0]; // 3 options: orthogonal, restricted triclinic, general triclinic
domain->boxlo[1] = boxlo[1]; // for general triclinic: convect general ABC edge vectors to LAMMPS restricted triclinic
domain->boxhi[1] = boxhi[1];
domain->boxlo[2] = boxlo[2];
domain->boxhi[2] = boxhi[2];
if (triclinic) { if (!triclinic_general) {
domain->triclinic = 1; domain->boxlo[0] = boxlo[0];
domain->xy = xy; domain->boxhi[0] = boxhi[0];
domain->xz = xz; domain->boxlo[1] = boxlo[1];
domain->yz = yz; domain->boxhi[1] = boxhi[1];
domain->boxlo[2] = boxlo[2];
domain->boxhi[2] = boxhi[2];
if (triclinic) {
domain->triclinic = 1;
domain->xy = xy;
domain->xz = xz;
domain->yz = yz;
}
} else if (triclinic_general) {
domain->set_general_triclinic(avec,bvec,cvec,tri_origin);
} }
domain->print_box(" ");
domain->set_initial_box();
domain->set_global_box();
comm->set_proc_grid();
domain->set_local_box();
} }
// change simulation box to be union of existing box and new box + shift // change simulation box to be union of existing box and new box + shift
// only done if firstpass and not first data file // only done if firstpass and not first data file
// shift not allowed for general triclinic
if (firstpass && addflag != NONE) { if (firstpass && addflag != NONE) {
// general triclinic
// first data file must also be general triclinic
// avec,bvec,vec must match first data file
// shift not allowed
if (triclinic_general) {
if (!domain->triclinic_general)
error->all(FLERR,"Read_data subsequent file cannot switch to general triclinic");
int errflag = 0;
if (avec[0] != domain->avec[0] || avec[1] != domain->avec[1] || avec[2] != domain->avec[2])
errflag = 1;
if (bvec[0] != domain->bvec[0] || bvec[1] != domain->bvec[1] || bvec[2] != domain->bvec[2])
errflag = 1;
if (cvec[0] != domain->cvec[0] || cvec[1] != domain->cvec[1] || cvec[2] != domain->cvec[2])
errflag = 1;
if (tri_origin[0] != domain->tri_origin[0] || tri_origin[1] != domain->tri_origin[1] ||
tri_origin[2] != domain->tri_origin[2])
errflag = 1;
if (errflag)
error->all(FLERR,"Read_data subsequent file ABC vectors must be same as first file");
if (shift[0] != 0.0 || shift[1] != 0.0 || shift[2] != 0.0)
error->all(FLERR,"Read_data subsequent file with ABC vectors cannot define shift");
// restricted triclinic
// tilt factors must match first data file
} else if (triclinic) {
if (!domain->triclinic || domain->triclinic_general)
error->all(FLERR,"Read_data subsequent file cannot switch to restricted triclinic");
if (xy != domain->xy || xz != domain->xz || yz != domain->yz)
error->all(FLERR,"Read_data subsequent file tilt factors must be same as first file");
}
double oldboxlo[3] = {domain->boxlo[0], domain->boxlo[1], domain->boxlo[2]}; double oldboxlo[3] = {domain->boxlo[0], domain->boxlo[1], domain->boxlo[2]};
double oldboxhi[3] = {domain->boxhi[0], domain->boxhi[1], domain->boxhi[2]}; double oldboxhi[3] = {domain->boxhi[0], domain->boxhi[1], domain->boxhi[2]};
domain->boxlo[0] = MIN(domain->boxlo[0], boxlo[0] + shift[0]); domain->boxlo[0] = MIN(domain->boxlo[0], boxlo[0] + shift[0]);
@ -570,7 +627,9 @@ void ReadData::command(int narg, char **arg)
domain->boxlo[2] = MIN(domain->boxlo[2], boxlo[2] + shift[2]); domain->boxlo[2] = MIN(domain->boxlo[2], boxlo[2] + shift[2]);
domain->boxhi[2] = MAX(domain->boxhi[2], boxhi[2] + shift[2]); domain->boxhi[2] = MAX(domain->boxhi[2], boxhi[2] + shift[2]);
// check of box has changed. If yes, warn about non-zero image flags // check if box has changed
// if yes, warn about non-zero image flags
if ((oldboxlo[0] != domain->boxlo[0]) || (oldboxlo[1] != domain->boxlo[1]) || if ((oldboxlo[0] != domain->boxlo[0]) || (oldboxlo[1] != domain->boxlo[1]) ||
(oldboxlo[2] != domain->boxlo[2]) || (oldboxhi[0] != domain->boxhi[0]) || (oldboxlo[2] != domain->boxlo[2]) || (oldboxhi[0] != domain->boxhi[0]) ||
(oldboxhi[1] != domain->boxhi[1]) || (oldboxhi[2] != domain->boxhi[2])) { (oldboxhi[1] != domain->boxhi[1]) || (oldboxhi[2] != domain->boxhi[2])) {
@ -588,19 +647,16 @@ void ReadData::command(int narg, char **arg)
if ((flag_all > 0) && (comm->me == 0)) if ((flag_all > 0) && (comm->me == 0))
error->warning(FLERR, "Non-zero image flags with growing box leads to bad coordinates"); error->warning(FLERR, "Non-zero image flags with growing box leads to bad coordinates");
} }
// NOTE: not sure what to do about tilt value in subsequent data files
//if (triclinic) {
// domain->xy = xy; domain->xz = xz; domain->yz = yz;
// }
domain->print_box(" ");
domain->set_initial_box();
domain->set_global_box();
comm->set_proc_grid();
domain->set_local_box();
} }
// setup simulation box and paritioning in Domain and Comm classes
domain->print_box(" ");
domain->set_initial_box();
domain->set_global_box();
comm->set_proc_grid();
domain->set_local_box();
// allocate space for type label map // allocate space for type label map
if (firstpass) { if (firstpass) {
@ -608,8 +664,9 @@ void ReadData::command(int narg, char **arg)
lmap = new LabelMap(lmp, ntypes, nbondtypes, nangletypes, ndihedraltypes, nimpropertypes); lmap = new LabelMap(lmp, ntypes, nbondtypes, nangletypes, ndihedraltypes, nimpropertypes);
} }
// rest of data file is Sections
// read in any order, except where error checks
// customize for new sections // customize for new sections
// read rest of file in free format
while (strlen(keyword)) { while (strlen(keyword)) {
@ -1140,7 +1197,8 @@ void ReadData::header(int firstpass)
// initialize type counts by the "extra" numbers so they get counted // initialize type counts by the "extra" numbers so they get counted
// in case the corresponding "types" line is missing and thus the extra // in case the corresponding "types" line is missing and thus the extra
// value will not be processed. // value will not be processed
if (addflag == NONE) { if (addflag == NONE) {
atom->ntypes = extra_atom_types; atom->ntypes = extra_atom_types;
atom->nbondtypes = extra_bond_types; atom->nbondtypes = extra_bond_types;
@ -1156,6 +1214,7 @@ void ReadData::header(int firstpass)
if (eof == nullptr) error->one(FLERR, "Unexpected end of data file"); if (eof == nullptr) error->one(FLERR, "Unexpected end of data file");
// check for units keyword in first line and print warning on mismatch // check for units keyword in first line and print warning on mismatch
auto units = Tokenizer(utils::strfind(line, "units = \\w+")).as_vector(); auto units = Tokenizer(utils::strfind(line, "units = \\w+")).as_vector();
if (units.size() > 2) { if (units.size() > 2) {
if (units[2] != update->unit_style) if (units[2] != update->unit_style)
@ -1278,7 +1337,7 @@ void ReadData::header(int firstpass)
else if (firstpass) else if (firstpass)
atom->nimpropers += nimpropers; atom->nimpropers += nimpropers;
// Atom class type settings are only set by first data file // Atom class type settings are only set by first data file
} else if (utils::strmatch(line, "^\\s*\\d+\\s+atom\\s+types\\s")) { } else if (utils::strmatch(line, "^\\s*\\d+\\s+atom\\s+types\\s")) {
ntypes = utils::inumeric(FLERR, words[0], false, lmp); ntypes = utils::inumeric(FLERR, words[0], false, lmp);
@ -1300,11 +1359,11 @@ void ReadData::header(int firstpass)
nimpropertypes = utils::inumeric(FLERR, words[0], false, lmp); nimpropertypes = utils::inumeric(FLERR, words[0], false, lmp);
if (addflag == NONE) atom->nimpropertypes = nimpropertypes + extra_improper_types; if (addflag == NONE) atom->nimpropertypes = nimpropertypes + extra_improper_types;
// these settings only used by first data file // these settings only used by first data file
// also, these are obsolescent. we parse them to maintain backward // also, these are obsolescent. we parse them to maintain backward
// compatibility, but the recommended way is to set them via keywords // compatibility, but the recommended way is to set them via keywords
// in the LAMMPS input file. In case these flags are set in both, // in the LAMMPS input file. In case these flags are set in both,
// the input and the data file, we use the larger of the two. // the input and the data file, we use the larger of the two.
} else if (strstr(line, "extra bond per atom")) { } else if (strstr(line, "extra bond per atom")) {
if (addflag == NONE) extra_flag_value = utils::inumeric(FLERR, words[0], false, lmp); if (addflag == NONE) extra_flag_value = utils::inumeric(FLERR, words[0], false, lmp);
@ -1322,26 +1381,50 @@ void ReadData::header(int firstpass)
if (addflag == NONE) extra_flag_value = utils::inumeric(FLERR, words[0], false, lmp); if (addflag == NONE) extra_flag_value = utils::inumeric(FLERR, words[0], false, lmp);
force->special_extra = MAX(force->special_extra, extra_flag_value); force->special_extra = MAX(force->special_extra, extra_flag_value);
// local copy of box info // local copy of box info
// so can treat differently for first vs subsequent data files // so can treat differently for first vs subsequent data files
} else if (utils::strmatch(line, "^\\s*\\f+\\s+\\f+\\s+xlo\\s+xhi\\s")) { } else if (utils::strmatch(line, "^\\s*\\f+\\s+\\f+\\s+xlo\\s+xhi\\s")) {
xloxhi_flag = 1;
boxlo[0] = utils::numeric(FLERR, words[0], false, lmp); boxlo[0] = utils::numeric(FLERR, words[0], false, lmp);
boxhi[0] = utils::numeric(FLERR, words[1], false, lmp); boxhi[0] = utils::numeric(FLERR, words[1], false, lmp);
} else if (utils::strmatch(line, "^\\s*\\f+\\s+\\f+\\s+ylo\\s+yhi\\s")) { } else if (utils::strmatch(line, "^\\s*\\f+\\s+\\f+\\s+ylo\\s+yhi\\s")) {
yloyhi_flag = 1;
boxlo[1] = utils::numeric(FLERR, words[0], false, lmp); boxlo[1] = utils::numeric(FLERR, words[0], false, lmp);
boxhi[1] = utils::numeric(FLERR, words[1], false, lmp); boxhi[1] = utils::numeric(FLERR, words[1], false, lmp);
} else if (utils::strmatch(line, "^\\s*\\f+\\s+\\f+\\s+zlo\\s+zhi\\s")) { } else if (utils::strmatch(line, "^\\s*\\f+\\s+\\f+\\s+zlo\\s+zhi\\s")) {
zlozhi_flag = 1;
boxlo[2] = utils::numeric(FLERR, words[0], false, lmp); boxlo[2] = utils::numeric(FLERR, words[0], false, lmp);
boxhi[2] = utils::numeric(FLERR, words[1], false, lmp); boxhi[2] = utils::numeric(FLERR, words[1], false, lmp);
} else if (utils::strmatch(line, "^\\s*\\f+\\s+\\f+\\s+\\f+\\s+xy\\s+xz\\s+yz\\s")) { } else if (utils::strmatch(line, "^\\s*\\f+\\s+\\f+\\s+\\f+\\s+xy\\s+xz\\s+yz\\s")) {
triclinic = 1; tilt_flag = 1;
xy = utils::numeric(FLERR, words[0], false, lmp); xy = utils::numeric(FLERR, words[0], false, lmp);
xz = utils::numeric(FLERR, words[1], false, lmp); xz = utils::numeric(FLERR, words[1], false, lmp);
yz = utils::numeric(FLERR, words[2], false, lmp); yz = utils::numeric(FLERR, words[2], false, lmp);
} else if (utils::strmatch(line, "^\\s*\\f+\\s+\\f+\\s+\\f+\\s+\\f+\\s+\\avec\\s")) {
avec_flag = 1;
avec[0] = utils::numeric(FLERR, words[0], false, lmp);
avec[1] = utils::numeric(FLERR, words[1], false, lmp);
avec[2] = utils::numeric(FLERR, words[2], false, lmp);
tri_origin[0] = utils::numeric(FLERR, words[3], false, lmp);
} else if (utils::strmatch(line, "^\\s*\\f+\\s+\\f+\\s+\\f+\\s+\\f+\\s+\\bvec\\s")) {
bvec_flag = 1;
bvec[0] = utils::numeric(FLERR, words[0], false, lmp);
bvec[1] = utils::numeric(FLERR, words[1], false, lmp);
bvec[2] = utils::numeric(FLERR, words[2], false, lmp);
tri_origin[1] = utils::numeric(FLERR, words[3], false, lmp);
} else if (utils::strmatch(line, "^\\s*\\f+\\s+\\f+\\s+\\f+\\s+\\f+\\s+\\cvec\\s")) {
cvec_flag = 1;
cvec[0] = utils::numeric(FLERR, words[0], false, lmp);
cvec[1] = utils::numeric(FLERR, words[1], false, lmp);
cvec[2] = utils::numeric(FLERR, words[2], false, lmp);
tri_origin[2] = utils::numeric(FLERR, words[3], false, lmp);
} else } else
break; break;
@ -1407,8 +1490,8 @@ void ReadData::atoms()
if (eof) error->all(FLERR, "Unexpected end of data file"); if (eof) error->all(FLERR, "Unexpected end of data file");
if (tlabelflag && !lmap->is_complete(Atom::ATOM)) if (tlabelflag && !lmap->is_complete(Atom::ATOM))
error->all(FLERR, "Label map is incomplete: all types must be assigned a unique type label"); error->all(FLERR, "Label map is incomplete: all types must be assigned a unique type label");
atom->data_atoms(nchunk, buffer, id_offset, mol_offset, toffset, shiftflag, shift, tlabelflag, atom->data_atoms(nchunk, buffer, id_offset, mol_offset, toffset, triclinic_general,
lmap->lmap2lmap.atom); shiftflag, shift, tlabelflag, lmap->lmap2lmap.atom);
nread += nchunk; nread += nchunk;
} }

View File

@ -63,8 +63,11 @@ class ReadData : public Command {
double boxlo[3], boxhi[3]; double boxlo[3], boxhi[3];
double xy, xz, yz; double xy, xz, yz;
int triclinic; double avec[3], bvec[3], cvec[3], tri_origin[3];
int triclinic, triclinic_general;
int xloxhi_flag, yloyhi_flag, zlozhi_flag, tilt_flag;
int avec_flag, bvec_flag, cvec_flag;
// optional args // optional args
int addflag, offsetflag, shiftflag, coeffflag, settypeflag; int addflag, offsetflag, shiftflag, coeffflag, settypeflag;

View File

@ -72,8 +72,11 @@ void WriteData::command(int narg, char **arg)
pairflag = II; pairflag = II;
coeffflag = 1; coeffflag = 1;
fixflag = 1; fixflag = 1;
triclinic_general = 0;
lmapflag = 1; lmapflag = 1;
// store current (default) setting since we may change it.
// store current (default) setting since we may change it
int types_style = atom->types_style; int types_style = atom->types_style;
int noinit = 0; int noinit = 0;
@ -94,6 +97,9 @@ void WriteData::command(int narg, char **arg)
} else if (strcmp(arg[iarg],"nofix") == 0) { } else if (strcmp(arg[iarg],"nofix") == 0) {
fixflag = 0; fixflag = 0;
iarg++; iarg++;
} else if (strcmp(arg[iarg],"triclinic") == 0) {
triclinic_general = 1;
iarg++;
} else if (strcmp(arg[iarg],"nolabelmap") == 0) { } else if (strcmp(arg[iarg],"nolabelmap") == 0) {
lmapflag = 0; lmapflag = 0;
iarg++; iarg++;
@ -135,7 +141,9 @@ void WriteData::command(int narg, char **arg)
} }
write(file); write(file);
// restore saved setting // restore saved setting
atom->types_style = types_style; atom->types_style = types_style;
} }
@ -206,8 +214,32 @@ void WriteData::write(const std::string &file)
} }
// per atom info in Atoms and Velocities sections // per atom info in Atoms and Velocities sections
// if general triclinic:
// save restricted triclinic atom coords
// transform atom coords from restricted to general
// restore save atom coords after output
// NOTE: do same for velocities as well ?
double **xstore = nullptr;
if (triclinic_general) {
double **x = atom->x;
int nlocal = atom->nlocal;
memory->create(xstore,nlocal,3,"write_data:xstore");
if (nlocal) memcpy(&xstore[0][0],&x[0][0],3*nlocal*sizeof(double));
for (int i = 0; i < nlocal; i++)
domain->restricted_to_general(x[i]);
}
if (natoms) atoms(); if (natoms) atoms();
if (triclinic_general) {
double **x = atom->x;
int nlocal = atom->nlocal;
if (nlocal) memcpy(&x[0][0],&xstore[0][0],3*nlocal*sizeof(double));
memory->destroy(xstore);
}
if (natoms) velocities(); if (natoms) velocities();
// molecular topology info if defined // molecular topology info if defined
@ -289,15 +321,22 @@ void WriteData::header()
for (int m = 0; m < ifix->wd_header; m++) for (int m = 0; m < ifix->wd_header; m++)
ifix->write_data_header(fp,m); ifix->write_data_header(fp,m);
// box info // box info: orthogonal, restricted triclinic, or general triclinic (if requested)
auto box = fmt::format("\n{} {} xlo xhi\n{} {} ylo yhi\n{} {} zlo zhi\n", if (!triclinic_general) {
domain->boxlo[0],domain->boxhi[0], fmt::print(fp,"\n{} {} xlo xhi\n{} {} ylo yhi\n{} {} zlo zhi\n",
domain->boxlo[1],domain->boxhi[1], domain->boxlo[0],domain->boxhi[0],
domain->boxlo[2],domain->boxhi[2]); domain->boxlo[1],domain->boxhi[1],
if (domain->triclinic) domain->boxlo[2],domain->boxhi[2]);
box += fmt::format("{} {} {} xy xz yz\n",domain->xy,domain->xz,domain->yz); if (domain->triclinic)
fputs(box.c_str(),fp); fmt::print(fp,"{} {} {} xy xz yz\n",domain->xy,domain->xz,domain->yz);
} else if (triclinic_general) {
fmt::print(fp,"\n{} {} {} {} avec\n{} {} {} {} bvec\n{} {} {} {} cvec\n",
domain->avec[0],domain->avec[1],domain->avec[2],domain->tri_origin[0],
domain->bvec[0],domain->bvec[1],domain->bvec[2],domain->tri_origin[1],
domain->cvec[0],domain->cvec[1],domain->cvec[2],domain->tri_origin[2]);
}
} }
/* ---------------------------------------------------------------------- /* ----------------------------------------------------------------------

View File

@ -35,6 +35,7 @@ class WriteData : public Command {
int pairflag; int pairflag;
int coeffflag; int coeffflag;
int fixflag; int fixflag;
int triclinic_general;
int lmapflag; int lmapflag;
FILE *fp; FILE *fp;
bigint nbonds_local, nbonds; bigint nbonds_local, nbonds;