Files
lammps/src/fix_move.cpp
2022-10-24 11:08:26 -04:00

1532 lines
47 KiB
C++

/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, Sandia National Laboratories
LAMMPS development team: developers@lammps.org
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
#include "fix_move.h"
#include "atom.h"
#include "atom_vec_body.h"
#include "atom_vec_ellipsoid.h"
#include "atom_vec_line.h"
#include "atom_vec_tri.h"
#include "comm.h"
#include "domain.h"
#include "error.h"
#include "force.h"
#include "input.h"
#include "lattice.h"
#include "math_const.h"
#include "math_extra.h"
#include "memory.h"
#include "modify.h"
#include "respa.h"
#include "update.h"
#include "variable.h"
#include <cmath>
#include <cstring>
using namespace LAMMPS_NS;
using namespace FixConst;
using namespace MathConst;
enum { LINEAR, WIGGLE, ROTATE, VARIABLE, TRANSROT };
enum { EQUAL, ATOM };
#define INERTIA 0.2 // moment of inertia prefactor for ellipsoid
/* ---------------------------------------------------------------------- */
FixMove::FixMove(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg), xvarstr(nullptr), yvarstr(nullptr), zvarstr(nullptr), vxvarstr(nullptr),
vyvarstr(nullptr), vzvarstr(nullptr), xoriginal(nullptr), toriginal(nullptr),
qoriginal(nullptr), displace(nullptr), velocity(nullptr)
{
if (narg < 4) error->all(FLERR, "Illegal fix move command");
restart_global = 1;
restart_peratom = 1;
peratom_flag = 1;
size_peratom_cols = 3;
peratom_freq = 1;
time_integrate = 1;
create_attribute = 1;
displaceflag = 0;
velocityflag = 0;
maxatom = 0;
// parse args
int iarg = 0;
if (strcmp(arg[3], "linear") == 0) {
if (narg < 7) error->all(FLERR, "Illegal fix move command");
iarg = 7;
mstyle = LINEAR;
if (strcmp(arg[4], "NULL") == 0)
vxflag = 0;
else {
vxflag = 1;
vx = utils::numeric(FLERR, arg[4], false, lmp);
}
if (strcmp(arg[5], "NULL") == 0)
vyflag = 0;
else {
vyflag = 1;
vy = utils::numeric(FLERR, arg[5], false, lmp);
}
if (strcmp(arg[6], "NULL") == 0)
vzflag = 0;
else {
vzflag = 1;
vz = utils::numeric(FLERR, arg[6], false, lmp);
}
} else if (strcmp(arg[3], "wiggle") == 0) {
if (narg < 8) error->all(FLERR, "Illegal fix move command");
iarg = 8;
mstyle = WIGGLE;
if (strcmp(arg[4], "NULL") == 0)
axflag = 0;
else {
axflag = 1;
ax = utils::numeric(FLERR, arg[4], false, lmp);
}
if (strcmp(arg[5], "NULL") == 0)
ayflag = 0;
else {
ayflag = 1;
ay = utils::numeric(FLERR, arg[5], false, lmp);
}
if (strcmp(arg[6], "NULL") == 0)
azflag = 0;
else {
azflag = 1;
az = utils::numeric(FLERR, arg[6], false, lmp);
}
period = utils::numeric(FLERR, arg[7], false, lmp);
if (period <= 0.0) error->all(FLERR, "Illegal fix move command");
} else if (strcmp(arg[3], "rotate") == 0) {
if (narg < 11) error->all(FLERR, "Illegal fix move command");
iarg = 11;
mstyle = ROTATE;
point[0] = utils::numeric(FLERR, arg[4], false, lmp);
point[1] = utils::numeric(FLERR, arg[5], false, lmp);
point[2] = utils::numeric(FLERR, arg[6], false, lmp);
axis[0] = utils::numeric(FLERR, arg[7], false, lmp);
axis[1] = utils::numeric(FLERR, arg[8], false, lmp);
axis[2] = utils::numeric(FLERR, arg[9], false, lmp);
period = utils::numeric(FLERR, arg[10], false, lmp);
if (period <= 0.0) error->all(FLERR, "Illegal fix move command");
} else if (strcmp(arg[3], "transrot") == 0) {
if (narg < 11) error->all(FLERR, "Illegal fix move command");
iarg = 14;
mstyle = TRANSROT;
vxflag = vyflag = vzflag = 1;
vx = utils::numeric(FLERR, arg[4], false, lmp);
vy = utils::numeric(FLERR, arg[5], false, lmp);
vz = utils::numeric(FLERR, arg[6], false, lmp);
point[0] = utils::numeric(FLERR, arg[7], false, lmp);
point[1] = utils::numeric(FLERR, arg[8], false, lmp);
point[2] = utils::numeric(FLERR, arg[9], false, lmp);
axis[0] = utils::numeric(FLERR, arg[10], false, lmp);
axis[1] = utils::numeric(FLERR, arg[11], false, lmp);
axis[2] = utils::numeric(FLERR, arg[12], false, lmp);
period = utils::numeric(FLERR, arg[13], false, lmp);
if (period <= 0.0) error->all(FLERR, "Illegal fix move command");
} else if (strcmp(arg[3], "variable") == 0) {
if (narg < 10) error->all(FLERR, "Illegal fix move command");
iarg = 10;
mstyle = VARIABLE;
if (strcmp(arg[4], "NULL") == 0)
xvarstr = nullptr;
else if (utils::strmatch(arg[4], "^v_")) {
xvarstr = utils::strdup(arg[4] + 2);
} else
error->all(FLERR, "Illegal fix move command");
if (strcmp(arg[5], "NULL") == 0)
yvarstr = nullptr;
else if (utils::strmatch(arg[5], "^v_")) {
yvarstr = utils::strdup(arg[5] + 2);
} else
error->all(FLERR, "Illegal fix move command");
if (strcmp(arg[6], "NULL") == 0)
zvarstr = nullptr;
else if (utils::strmatch(arg[6], "^v_")) {
zvarstr = utils::strdup(arg[6] + 2);
} else
error->all(FLERR, "Illegal fix move command");
if (strcmp(arg[7], "NULL") == 0)
vxvarstr = nullptr;
else if (utils::strmatch(arg[7], "^v_")) {
vxvarstr = utils::strdup(arg[7] + 2);
} else
error->all(FLERR, "Illegal fix move command");
if (strcmp(arg[8], "NULL") == 0)
vyvarstr = nullptr;
else if (utils::strmatch(arg[8], "^v_")) {
vyvarstr = utils::strdup(arg[8] + 2);
} else
error->all(FLERR, "Illegal fix move command");
if (strcmp(arg[9], "NULL") == 0)
vzvarstr = nullptr;
else if (utils::strmatch(arg[9], "^v_")) {
vzvarstr = utils::strdup(arg[9] + 2);
} else
error->all(FLERR, "Illegal fix move command");
} else
error->all(FLERR, "Illegal fix move command");
// optional args
int scaleflag = 1;
while (iarg < narg) {
if (strcmp(arg[iarg], "units") == 0) {
if (iarg + 2 > narg) error->all(FLERR, "Illegal fix move command");
if (strcmp(arg[iarg + 1], "box") == 0)
scaleflag = 0;
else if (strcmp(arg[iarg + 1], "lattice") == 0)
scaleflag = 1;
else
error->all(FLERR, "Illegal fix move command");
iarg += 2;
} else
error->all(FLERR, "Illegal fix move command");
}
// error checks and warnings
if (domain->dimension == 2) {
if (((mstyle == LINEAR) || (mstyle == TRANSROT)) && vzflag && (vz != 0.0))
error->all(FLERR, "Fix move cannot set linear z motion for 2d problem");
if (mstyle == WIGGLE && azflag && az != 0.0)
error->all(FLERR, "Fix move cannot set wiggle z motion for 2d problem");
if (((mstyle == ROTATE) || (mstyle == TRANSROT)) && (axis[0] != 0.0 || axis[1] != 0.0))
error->all(FLERR, "Fix move cannot rotate around non z-axis for 2d problem");
if (mstyle == VARIABLE && (zvarstr || vzvarstr))
error->all(FLERR, "Fix move cannot define z or vz variable for 2d problem");
}
// setup scaling and apply scaling factors to velocity & amplitude
if ((mstyle != VARIABLE) && scaleflag) {
double xscale = domain->lattice->xlattice;
double yscale = domain->lattice->ylattice;
double zscale = domain->lattice->zlattice;
if (mstyle == LINEAR) {
if (vxflag) vx *= xscale;
if (vyflag) vy *= yscale;
if (vzflag) vz *= zscale;
} else if (mstyle == WIGGLE) {
if (axflag) ax *= xscale;
if (ayflag) ay *= yscale;
if (azflag) az *= zscale;
} else if (mstyle == ROTATE) {
point[0] *= xscale;
point[1] *= yscale;
point[2] *= zscale;
} else if (mstyle == TRANSROT) {
vx *= xscale;
vy *= yscale;
vz *= zscale;
point[0] *= xscale;
point[1] *= yscale;
point[2] *= zscale;
}
}
// set omega_rotate from period
if ((mstyle == WIGGLE) || (mstyle == ROTATE) || (mstyle == TRANSROT))
omega_rotate = MY_2PI / period;
// runit = unit vector along rotation axis
if ((mstyle == ROTATE) || (mstyle == TRANSROT)) {
double len = sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);
if (len == 0.0) error->all(FLERR, "Zero length rotation vector with fix move");
runit[0] = axis[0] / len;
runit[1] = axis[1] / len;
runit[2] = axis[2] / len;
}
// set flags for extra attributes particles may store
// relevant extra attributes = omega, angmom, theta, quat
omega_flag = atom->omega_flag;
angmom_flag = atom->angmom_flag;
radius_flag = atom->radius_flag;
ellipsoid_flag = atom->ellipsoid_flag;
line_flag = atom->line_flag;
tri_flag = atom->tri_flag;
body_flag = atom->body_flag;
theta_flag = quat_flag = 0;
if (line_flag) theta_flag = 1;
if (ellipsoid_flag || tri_flag || body_flag) quat_flag = 1;
extra_flag = 0;
if (omega_flag || angmom_flag || theta_flag || quat_flag) extra_flag = 1;
// perform initial allocation of atom-based array
// register with Atom class
FixMove::grow_arrays(atom->nmax);
atom->add_callback(Atom::GROW);
atom->add_callback(Atom::RESTART);
displace = velocity = nullptr;
// AtomVec pointers to retrieve per-atom storage of extra quantities
avec_ellipsoid = dynamic_cast<AtomVecEllipsoid *>(atom->style_match("ellipsoid"));
avec_line = dynamic_cast<AtomVecLine *>(atom->style_match("line"));
avec_tri = dynamic_cast<AtomVecTri *>(atom->style_match("tri"));
avec_body = dynamic_cast<AtomVecBody *>(atom->style_match("body"));
// xoriginal = initial unwrapped positions of atoms
// toriginal = initial theta of lines
// qoriginal = initial quat of extended particles
double **x = atom->x;
imageint *image = atom->image;
int *ellipsoid = atom->ellipsoid;
int *line = atom->line;
int *tri = atom->tri;
int *body = atom->body;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit)
domain->unmap(x[i], image[i], xoriginal[i]);
else
xoriginal[i][0] = xoriginal[i][1] = xoriginal[i][2] = 0.0;
}
if (theta_flag) {
for (int i = 0; i < nlocal; i++) {
if ((mask[i] & groupbit) && line[i] >= 0)
toriginal[i] = avec_line->bonus[line[i]].theta;
else
toriginal[i] = 0.0;
}
}
if (quat_flag) {
double *quat;
for (int i = 0; i < nlocal; i++) {
quat = nullptr;
if (mask[i] & groupbit) {
if (ellipsoid_flag && ellipsoid[i] >= 0)
quat = avec_ellipsoid->bonus[ellipsoid[i]].quat;
else if (tri_flag && tri[i] >= 0)
quat = avec_tri->bonus[tri[i]].quat;
else if (body_flag && body[i] >= 0)
quat = avec_body->bonus[body[i]].quat;
}
if (quat) {
qoriginal[i][0] = quat[0];
qoriginal[i][1] = quat[1];
qoriginal[i][2] = quat[2];
qoriginal[i][3] = quat[3];
} else
qoriginal[i][0] = qoriginal[i][1] = qoriginal[i][2] = qoriginal[i][3] = 0.0;
}
}
// nrestart = size of per-atom restart data
// nrestart = 1 + xorig + torig + qorig
nrestart = 4;
if (theta_flag) nrestart++;
if (quat_flag) nrestart += 4;
// time origin for movement = current timestep
time_origin = update->ntimestep;
}
/* ---------------------------------------------------------------------- */
FixMove::~FixMove()
{
// unregister callbacks to this fix from Atom class
atom->delete_callback(id, Atom::GROW);
atom->delete_callback(id, Atom::RESTART);
// delete locally stored arrays
memory->destroy(xoriginal);
memory->destroy(toriginal);
memory->destroy(qoriginal);
memory->destroy(displace);
memory->destroy(velocity);
delete[] xvarstr;
delete[] yvarstr;
delete[] zvarstr;
delete[] vxvarstr;
delete[] vyvarstr;
delete[] vzvarstr;
}
/* ---------------------------------------------------------------------- */
int FixMove::setmask()
{
int mask = 0;
mask |= INITIAL_INTEGRATE;
mask |= INITIAL_INTEGRATE_RESPA;
mask |= FINAL_INTEGRATE;
mask |= FINAL_INTEGRATE_RESPA;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixMove::init()
{
dt = update->dt;
dtv = update->dt;
dtf = 0.5 * update->dt * force->ftm2v;
// set indices and style of all variables
displaceflag = velocityflag = 0;
if (mstyle == VARIABLE) {
if (xvarstr) {
xvar = input->variable->find(xvarstr);
if (xvar < 0) error->all(FLERR, "Variable name for fix move does not exist");
if (input->variable->equalstyle(xvar))
xvarstyle = EQUAL;
else if (input->variable->atomstyle(xvar))
xvarstyle = ATOM;
else
error->all(FLERR, "Variable for fix move is invalid style");
}
if (yvarstr) {
yvar = input->variable->find(yvarstr);
if (yvar < 0) error->all(FLERR, "Variable name for fix move does not exist");
if (input->variable->equalstyle(yvar))
yvarstyle = EQUAL;
else if (input->variable->atomstyle(yvar))
yvarstyle = ATOM;
else
error->all(FLERR, "Variable for fix move is invalid style");
}
if (zvarstr) {
zvar = input->variable->find(zvarstr);
if (zvar < 0) error->all(FLERR, "Variable name for fix move does not exist");
if (input->variable->equalstyle(zvar))
zvarstyle = EQUAL;
else if (input->variable->atomstyle(zvar))
zvarstyle = ATOM;
else
error->all(FLERR, "Variable for fix move is invalid style");
}
if (vxvarstr) {
vxvar = input->variable->find(vxvarstr);
if (vxvar < 0) error->all(FLERR, "Variable name for fix move does not exist");
if (input->variable->equalstyle(vxvar))
vxvarstyle = EQUAL;
else if (input->variable->atomstyle(vxvar))
vxvarstyle = ATOM;
else
error->all(FLERR, "Variable for fix move is invalid style");
}
if (vyvarstr) {
vyvar = input->variable->find(vyvarstr);
if (vyvar < 0) error->all(FLERR, "Variable name for fix move does not exist");
if (input->variable->equalstyle(vyvar))
vyvarstyle = EQUAL;
else if (input->variable->atomstyle(vyvar))
vyvarstyle = ATOM;
else
error->all(FLERR, "Variable for fix move is invalid style");
}
if (vzvarstr) {
vzvar = input->variable->find(vzvarstr);
if (vzvar < 0) error->all(FLERR, "Variable name for fix move does not exist");
if (input->variable->equalstyle(vzvar))
vzvarstyle = EQUAL;
else if (input->variable->atomstyle(vzvar))
vzvarstyle = ATOM;
else
error->all(FLERR, "Variable for fix move is invalid style");
}
if (xvarstr && xvarstyle == ATOM) displaceflag = 1;
if (yvarstr && yvarstyle == ATOM) displaceflag = 1;
if (zvarstr && zvarstyle == ATOM) displaceflag = 1;
if (vxvarstr && vxvarstyle == ATOM) velocityflag = 1;
if (vyvarstr && vyvarstyle == ATOM) velocityflag = 1;
if (vzvarstr && vzvarstyle == ATOM) velocityflag = 1;
}
maxatom = atom->nmax;
memory->destroy(displace);
memory->destroy(velocity);
if (displaceflag)
memory->create(displace, maxatom, 3, "move:displace");
else
displace = nullptr;
if (velocityflag)
memory->create(velocity, maxatom, 3, "move:velocity");
else
velocity = nullptr;
if (utils::strmatch(update->integrate_style, "^respa"))
nlevels_respa = (dynamic_cast<Respa *>(update->integrate))->nlevels;
}
/* ----------------------------------------------------------------------
set x,v of particles
------------------------------------------------------------------------- */
void FixMove::initial_integrate(int /*vflag*/)
{
int flag;
double ddotr, dx, dy, dz;
double dtfm, theta_new;
double xold[3], a[3], b[3], c[3], d[3], disp[3], w[3], ex[3], ey[3], ez[3];
double inertia_ellipsoid[3], qrotate[4];
double *quat, *inertia, *shape;
double delta = (update->ntimestep - time_origin) * dt;
double **x = atom->x;
double **v = atom->v;
double **f = atom->f;
double **omega = atom->omega;
double **angmom = atom->angmom;
double *radius = atom->radius;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
int *ellipsoid = atom->ellipsoid;
int *line = atom->line;
int *tri = atom->tri;
int *body = atom->body;
int *mask = atom->mask;
int nlocal = atom->nlocal;
// for linear: X = X0 + V*dt
if (mstyle == LINEAR) {
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
xold[0] = x[i][0];
xold[1] = x[i][1];
xold[2] = x[i][2];
if (vxflag) {
v[i][0] = vx;
x[i][0] = xoriginal[i][0] + vx * delta;
} else if (rmass) {
dtfm = dtf / rmass[i];
v[i][0] += dtfm * f[i][0];
x[i][0] += dtv * v[i][0];
} else {
dtfm = dtf / mass[type[i]];
v[i][0] += dtfm * f[i][0];
x[i][0] += dtv * v[i][0];
}
if (vyflag) {
v[i][1] = vy;
x[i][1] = xoriginal[i][1] + vy * delta;
} else if (rmass) {
dtfm = dtf / rmass[i];
v[i][1] += dtfm * f[i][1];
x[i][1] += dtv * v[i][1];
} else {
dtfm = dtf / mass[type[i]];
v[i][1] += dtfm * f[i][1];
x[i][1] += dtv * v[i][1];
}
if (vzflag) {
v[i][2] = vz;
x[i][2] = xoriginal[i][2] + vz * delta;
} else if (rmass) {
dtfm = dtf / rmass[i];
v[i][2] += dtfm * f[i][2];
x[i][2] += dtv * v[i][2];
} else {
dtfm = dtf / mass[type[i]];
v[i][2] += dtfm * f[i][2];
x[i][2] += dtv * v[i][2];
}
domain->remap_near(x[i], xold);
}
}
// for wiggle: X = X0 + A sin(w*dt)
} else if (mstyle == WIGGLE) {
double arg = omega_rotate * delta;
double sine = sin(arg);
double cosine = cos(arg);
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
xold[0] = x[i][0];
xold[1] = x[i][1];
xold[2] = x[i][2];
if (axflag) {
v[i][0] = ax * omega_rotate * cosine;
x[i][0] = xoriginal[i][0] + ax * sine;
} else if (rmass) {
dtfm = dtf / rmass[i];
v[i][0] += dtfm * f[i][0];
x[i][0] += dtv * v[i][0];
} else {
dtfm = dtf / mass[type[i]];
v[i][0] += dtfm * f[i][0];
x[i][0] += dtv * v[i][0];
}
if (ayflag) {
v[i][1] = ay * omega_rotate * cosine;
x[i][1] = xoriginal[i][1] + ay * sine;
} else if (rmass) {
dtfm = dtf / rmass[i];
v[i][1] += dtfm * f[i][1];
x[i][1] += dtv * v[i][1];
} else {
dtfm = dtf / mass[type[i]];
v[i][1] += dtfm * f[i][1];
x[i][1] += dtv * v[i][1];
}
if (azflag) {
v[i][2] = az * omega_rotate * cosine;
x[i][2] = xoriginal[i][2] + az * sine;
} else if (rmass) {
dtfm = dtf / rmass[i];
v[i][2] += dtfm * f[i][2];
x[i][2] += dtv * v[i][2];
} else {
dtfm = dtf / mass[type[i]];
v[i][2] += dtfm * f[i][2];
x[i][2] += dtv * v[i][2];
}
domain->remap_near(x[i], xold);
}
}
// for rotate by right-hand rule around omega:
// P = point = vector = point of rotation
// R = vector = axis of rotation
// w = omega of rotation (from period)
// X0 = xoriginal = initial coord of atom
// R0 = runit = unit vector for R
// D = X0 - P = vector from P to X0
// C = (D dot R0) R0 = projection of atom coord onto R line
// A = D - C = vector from R line to X0
// B = R0 cross A = vector perp to A in plane of rotation
// A,B define plane of circular rotation around R line
// X = P + C + A cos(w*dt) + B sin(w*dt)
// V = w R0 cross (A cos(w*dt) + B sin(w*dt))
} else if (mstyle == ROTATE) {
double arg = omega_rotate * delta;
double cosine = cos(arg);
double sine = sin(arg);
double qcosine = cos(0.5 * arg);
double qsine = sin(0.5 * arg);
qrotate[0] = qcosine;
qrotate[1] = runit[0] * qsine;
qrotate[2] = runit[1] * qsine;
qrotate[3] = runit[2] * qsine;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
xold[0] = x[i][0];
xold[1] = x[i][1];
xold[2] = x[i][2];
d[0] = xoriginal[i][0] - point[0];
d[1] = xoriginal[i][1] - point[1];
d[2] = xoriginal[i][2] - point[2];
ddotr = d[0] * runit[0] + d[1] * runit[1] + d[2] * runit[2];
c[0] = ddotr * runit[0];
c[1] = ddotr * runit[1];
c[2] = ddotr * runit[2];
a[0] = d[0] - c[0];
a[1] = d[1] - c[1];
a[2] = d[2] - c[2];
b[0] = runit[1] * a[2] - runit[2] * a[1];
b[1] = runit[2] * a[0] - runit[0] * a[2];
b[2] = runit[0] * a[1] - runit[1] * a[0];
disp[0] = a[0] * cosine + b[0] * sine;
disp[1] = a[1] * cosine + b[1] * sine;
disp[2] = a[2] * cosine + b[2] * sine;
x[i][0] = point[0] + c[0] + disp[0];
x[i][1] = point[1] + c[1] + disp[1];
x[i][2] = point[2] + c[2] + disp[2];
v[i][0] = omega_rotate * (runit[1] * disp[2] - runit[2] * disp[1]);
v[i][1] = omega_rotate * (runit[2] * disp[0] - runit[0] * disp[2]);
v[i][2] = omega_rotate * (runit[0] * disp[1] - runit[1] * disp[0]);
// set any extra attributes affected by rotation
if (extra_flag) {
// omega for spheres, lines, tris
if (omega_flag) {
flag = 0;
if (radius_flag && radius[i] > 0.0) flag = 1;
if (line_flag && line[i] >= 0.0) flag = 1;
if (tri_flag && tri[i] >= 0.0) flag = 1;
if (flag) {
omega[i][0] = omega_rotate * runit[0];
omega[i][1] = omega_rotate * runit[1];
omega[i][2] = omega_rotate * runit[2];
}
}
// angmom for ellipsoids, tris, and bodies
if (angmom_flag) {
quat = inertia = nullptr;
if (ellipsoid_flag && ellipsoid[i] >= 0) {
quat = avec_ellipsoid->bonus[ellipsoid[i]].quat;
shape = avec_ellipsoid->bonus[ellipsoid[i]].shape;
inertia_ellipsoid[0] =
INERTIA * rmass[i] * (shape[1] * shape[1] + shape[2] * shape[2]);
inertia_ellipsoid[1] =
INERTIA * rmass[i] * (shape[0] * shape[0] + shape[2] * shape[2]);
inertia_ellipsoid[2] =
INERTIA * rmass[i] * (shape[0] * shape[0] + shape[1] * shape[1]);
inertia = inertia_ellipsoid;
} else if (tri_flag && tri[i] >= 0) {
quat = avec_tri->bonus[tri[i]].quat;
inertia = avec_tri->bonus[tri[i]].inertia;
} else if (body_flag && body[i] >= 0) {
quat = avec_body->bonus[body[i]].quat;
inertia = avec_body->bonus[body[i]].inertia;
}
if (quat) {
w[0] = omega_rotate * runit[0];
w[1] = omega_rotate * runit[1];
w[2] = omega_rotate * runit[2];
MathExtra::q_to_exyz(quat, ex, ey, ez);
MathExtra::omega_to_angmom(w, ex, ey, ez, inertia, angmom[i]);
}
}
// theta for lines
if (theta_flag && line[i] >= 0.0) {
theta_new = fmod(toriginal[i] + arg, MY_2PI);
avec_line->bonus[atom->line[i]].theta = theta_new;
}
// quats for ellipsoids, tris, and bodies
if (quat_flag) {
quat = nullptr;
if (ellipsoid_flag && ellipsoid[i] >= 0)
quat = avec_ellipsoid->bonus[ellipsoid[i]].quat;
else if (tri_flag && tri[i] >= 0)
quat = avec_tri->bonus[tri[i]].quat;
else if (body_flag && body[i] >= 0)
quat = avec_body->bonus[body[i]].quat;
if (quat) MathExtra::quatquat(qrotate, qoriginal[i], quat);
}
}
domain->remap_near(x[i], xold);
}
}
// for rotate by right-hand rule around omega:
// P = point = vector = point of rotation
// R = vector = axis of rotation
// w = omega of rotation (from period)
// X0 = xoriginal = initial coord of atom
// R0 = runit = unit vector for R
// D = X0 - P = vector from P to X0
// C = (D dot R0) R0 = projection of atom coord onto R line
// A = D - C = vector from R line to X0
// B = R0 cross A = vector perp to A in plane of rotation
// A,B define plane of circular rotation around R line
// X = P + C + A cos(w*dt) + B sin(w*dt)
// V = w R0 cross (A cos(w*dt) + B sin(w*dt))
//
// add translation after rotation
} else if (mstyle == TRANSROT) {
double arg = omega_rotate * delta;
double cosine = cos(arg);
double sine = sin(arg);
double qcosine = cos(0.5 * arg);
double qsine = sin(0.5 * arg);
qrotate[0] = qcosine;
qrotate[1] = runit[0] * qsine;
qrotate[2] = runit[1] * qsine;
qrotate[3] = runit[2] * qsine;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
xold[0] = x[i][0];
xold[1] = x[i][1];
xold[2] = x[i][2];
d[0] = xoriginal[i][0] - point[0];
d[1] = xoriginal[i][1] - point[1];
d[2] = xoriginal[i][2] - point[2];
ddotr = d[0] * runit[0] + d[1] * runit[1] + d[2] * runit[2];
c[0] = ddotr * runit[0];
c[1] = ddotr * runit[1];
c[2] = ddotr * runit[2];
a[0] = d[0] - c[0];
a[1] = d[1] - c[1];
a[2] = d[2] - c[2];
b[0] = runit[1] * a[2] - runit[2] * a[1];
b[1] = runit[2] * a[0] - runit[0] * a[2];
b[2] = runit[0] * a[1] - runit[1] * a[0];
disp[0] = a[0] * cosine + b[0] * sine;
disp[1] = a[1] * cosine + b[1] * sine;
disp[2] = a[2] * cosine + b[2] * sine;
x[i][0] = point[0] + c[0] + disp[0];
x[i][1] = point[1] + c[1] + disp[1];
x[i][2] = point[2] + c[2] + disp[2];
v[i][0] = omega_rotate * (runit[1] * disp[2] - runit[2] * disp[1]);
v[i][1] = omega_rotate * (runit[2] * disp[0] - runit[0] * disp[2]);
v[i][2] = omega_rotate * (runit[0] * disp[1] - runit[1] * disp[0]);
// set any extra attributes affected by rotation
if (extra_flag) {
// omega for spheres, lines, tris
if (omega_flag) {
flag = 0;
if (radius_flag && radius[i] > 0.0) flag = 1;
if (line_flag && line[i] >= 0.0) flag = 1;
if (tri_flag && tri[i] >= 0.0) flag = 1;
if (flag) {
omega[i][0] = omega_rotate * runit[0];
omega[i][1] = omega_rotate * runit[1];
omega[i][2] = omega_rotate * runit[2];
}
}
// angmom for ellipsoids, tris, and bodies
if (angmom_flag) {
quat = inertia = nullptr;
if (ellipsoid_flag && ellipsoid[i] >= 0) {
quat = avec_ellipsoid->bonus[ellipsoid[i]].quat;
shape = avec_ellipsoid->bonus[ellipsoid[i]].shape;
inertia_ellipsoid[0] =
INERTIA * rmass[i] * (shape[1] * shape[1] + shape[2] * shape[2]);
inertia_ellipsoid[1] =
INERTIA * rmass[i] * (shape[0] * shape[0] + shape[2] * shape[2]);
inertia_ellipsoid[2] =
INERTIA * rmass[i] * (shape[0] * shape[0] + shape[1] * shape[1]);
inertia = inertia_ellipsoid;
} else if (tri_flag && tri[i] >= 0) {
quat = avec_tri->bonus[tri[i]].quat;
inertia = avec_tri->bonus[tri[i]].inertia;
} else if (body_flag && body[i] >= 0) {
quat = avec_body->bonus[body[i]].quat;
inertia = avec_body->bonus[body[i]].inertia;
}
if (quat) {
w[0] = omega_rotate * runit[0];
w[1] = omega_rotate * runit[1];
w[2] = omega_rotate * runit[2];
MathExtra::q_to_exyz(quat, ex, ey, ez);
MathExtra::omega_to_angmom(w, ex, ey, ez, inertia, angmom[i]);
}
}
// theta for lines
if (theta_flag && line[i] >= 0.0) {
theta_new = fmod(toriginal[i] + arg, MY_2PI);
avec_line->bonus[atom->line[i]].theta = theta_new;
}
// quats for ellipsoids, tris, and bodies
if (quat_flag) {
quat = nullptr;
if (ellipsoid_flag && ellipsoid[i] >= 0)
quat = avec_ellipsoid->bonus[ellipsoid[i]].quat;
else if (tri_flag && tri[i] >= 0)
quat = avec_tri->bonus[tri[i]].quat;
else if (body_flag && body[i] >= 0)
quat = avec_body->bonus[body[i]].quat;
if (quat) MathExtra::quatquat(qrotate, qoriginal[i], quat);
}
}
v[i][0] += vx;
x[i][0] += vx * delta;
v[i][1] += vy;
x[i][1] += vy * delta;
v[i][2] += vz;
x[i][2] += vz * delta;
domain->remap_near(x[i], xold);
}
}
// for variable: compute x,v from variables
// NOTE: also allow for changes to extra attributes?
// omega, angmom, theta, quat
// only necessary if prescribed motion involves rotation
} else if (mstyle == VARIABLE) {
// reallocate displace and velocity arrays as necessary
if ((displaceflag || velocityflag) && atom->nmax > maxatom) {
maxatom = atom->nmax;
if (displaceflag) {
memory->destroy(displace);
memory->create(displace, maxatom, 3, "move:displace");
}
if (velocityflag) {
memory->destroy(velocity);
memory->create(velocity, maxatom, 3, "move:velocity");
}
}
// pre-compute variable values, wrap with clear/add
modify->clearstep_compute();
if (xvarstr) {
if (xvarstyle == EQUAL)
dx = input->variable->compute_equal(xvar);
else
input->variable->compute_atom(xvar, igroup, &displace[0][0], 3, 0);
}
if (yvarstr) {
if (yvarstyle == EQUAL)
dy = input->variable->compute_equal(yvar);
else
input->variable->compute_atom(yvar, igroup, &displace[0][1], 3, 0);
}
if (zvarstr) {
if (zvarstyle == EQUAL)
dz = input->variable->compute_equal(zvar);
else
input->variable->compute_atom(zvar, igroup, &displace[0][2], 3, 0);
}
if (vxvarstr) {
if (vxvarstyle == EQUAL)
vx = input->variable->compute_equal(vxvar);
else
input->variable->compute_atom(vxvar, igroup, &velocity[0][0], 3, 0);
}
if (vyvarstr) {
if (vyvarstyle == EQUAL)
vy = input->variable->compute_equal(vyvar);
else
input->variable->compute_atom(vyvar, igroup, &velocity[0][1], 3, 0);
}
if (vzvarstr) {
if (vzvarstyle == EQUAL)
vz = input->variable->compute_equal(vzvar);
else
input->variable->compute_atom(vzvar, igroup, &velocity[0][2], 3, 0);
}
modify->addstep_compute(update->ntimestep + 1);
// update x,v
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
xold[0] = x[i][0];
xold[1] = x[i][1];
xold[2] = x[i][2];
if (xvarstr && vxvarstr) {
if (vxvarstyle == EQUAL)
v[i][0] = vx;
else
v[i][0] = velocity[i][0];
if (xvarstyle == EQUAL)
x[i][0] = xoriginal[i][0] + dx;
else
x[i][0] = xoriginal[i][0] + displace[i][0];
} else if (xvarstr) {
if (xvarstyle == EQUAL)
x[i][0] = xoriginal[i][0] + dx;
else
x[i][0] = xoriginal[i][0] + displace[i][0];
} else if (vxvarstr) {
if (vxvarstyle == EQUAL)
v[i][0] = vx;
else
v[i][0] = velocity[i][0];
x[i][0] += dtv * v[i][0];
} else {
if (rmass) {
dtfm = dtf / rmass[i];
v[i][0] += dtfm * f[i][0];
} else {
dtfm = dtf / mass[type[i]];
v[i][0] += dtfm * f[i][0];
}
x[i][0] += dtv * v[i][0];
}
if (yvarstr && vyvarstr) {
if (vyvarstyle == EQUAL)
v[i][1] = vy;
else
v[i][1] = velocity[i][1];
if (yvarstyle == EQUAL)
x[i][1] = xoriginal[i][1] + dy;
else
x[i][1] = xoriginal[i][1] + displace[i][1];
} else if (yvarstr) {
if (yvarstyle == EQUAL)
x[i][1] = xoriginal[i][1] + dy;
else
x[i][1] = xoriginal[i][1] + displace[i][1];
} else if (vyvarstr) {
if (vyvarstyle == EQUAL)
v[i][1] = vy;
else
v[i][1] = velocity[i][1];
x[i][1] += dtv * v[i][1];
} else {
if (rmass) {
dtfm = dtf / rmass[i];
v[i][1] += dtfm * f[i][1];
} else {
dtfm = dtf / mass[type[i]];
v[i][1] += dtfm * f[i][1];
}
x[i][1] += dtv * v[i][1];
}
if (zvarstr && vzvarstr) {
if (vzvarstyle == EQUAL)
v[i][2] = vz;
else
v[i][2] = velocity[i][2];
if (zvarstyle == EQUAL)
x[i][2] = xoriginal[i][2] + dz;
else
x[i][2] = xoriginal[i][2] + displace[i][2];
} else if (zvarstr) {
if (zvarstyle == EQUAL)
x[i][2] = xoriginal[i][2] + dz;
else
x[i][2] = xoriginal[i][2] + displace[i][2];
} else if (vzvarstr) {
if (vzvarstyle == EQUAL)
v[i][2] = vz;
else
v[i][2] = velocity[i][2];
x[i][2] += dtv * v[i][2];
} else {
if (rmass) {
dtfm = dtf / rmass[i];
v[i][2] += dtfm * f[i][2];
} else {
dtfm = dtf / mass[type[i]];
v[i][2] += dtfm * f[i][2];
}
x[i][2] += dtv * v[i][2];
}
domain->remap_near(x[i], xold);
}
}
}
}
/* ----------------------------------------------------------------------
final NVE of particles with nullptr components
------------------------------------------------------------------------- */
void FixMove::final_integrate()
{
double dtfm;
int xflag = 1;
if (mstyle == LINEAR && vxflag)
xflag = 0;
else if (mstyle == WIGGLE && axflag)
xflag = 0;
else if (mstyle == ROTATE)
xflag = 0;
else if (mstyle == TRANSROT)
xflag = 0;
else if (mstyle == VARIABLE && (xvarstr || vxvarstr))
xflag = 0;
int yflag = 1;
if (mstyle == LINEAR && vyflag)
yflag = 0;
else if (mstyle == WIGGLE && ayflag)
yflag = 0;
else if (mstyle == ROTATE)
yflag = 0;
else if (mstyle == TRANSROT)
yflag = 0;
else if (mstyle == VARIABLE && (yvarstr || vyvarstr))
yflag = 0;
int zflag = 1;
if (mstyle == LINEAR && vzflag)
zflag = 0;
else if (mstyle == WIGGLE && azflag)
zflag = 0;
else if (mstyle == ROTATE)
zflag = 0;
else if (mstyle == TRANSROT)
zflag = 0;
else if (mstyle == VARIABLE && (zvarstr || vzvarstr))
zflag = 0;
double **v = atom->v;
double **f = atom->f;
double *rmass = atom->rmass;
double *mass = atom->mass;
int *type = atom->type;
int *mask = atom->mask;
int nlocal = atom->nlocal;
for (int i = 0; i < nlocal; i++) {
if (mask[i] & groupbit) {
if (xflag) {
if (rmass) {
dtfm = dtf / rmass[i];
v[i][0] += dtfm * f[i][0];
} else {
dtfm = dtf / mass[type[i]];
v[i][0] += dtfm * f[i][0];
}
}
if (yflag) {
if (rmass) {
dtfm = dtf / rmass[i];
v[i][1] += dtfm * f[i][1];
} else {
dtfm = dtf / mass[type[i]];
v[i][1] += dtfm * f[i][1];
}
}
if (zflag) {
if (rmass) {
dtfm = dtf / rmass[i];
v[i][2] += dtfm * f[i][2];
} else {
dtfm = dtf / mass[type[i]];
v[i][2] += dtfm * f[i][2];
}
}
}
}
}
/* ---------------------------------------------------------------------- */
void FixMove::initial_integrate_respa(int vflag, int ilevel, int /*iloop*/)
{
// outermost level - update v and x
// all other levels - nothing
if (ilevel == nlevels_respa - 1) initial_integrate(vflag);
}
/* ---------------------------------------------------------------------- */
void FixMove::final_integrate_respa(int ilevel, int /*iloop*/)
{
if (ilevel == nlevels_respa - 1) final_integrate();
}
/* ----------------------------------------------------------------------
memory usage of local atom-based array
------------------------------------------------------------------------- */
double FixMove::memory_usage()
{
double bytes = (double) atom->nmax * 3 * sizeof(double);
if (theta_flag) bytes += (double) atom->nmax * sizeof(double);
if (quat_flag) bytes += (double) atom->nmax * 4 * sizeof(double);
if (displaceflag) bytes += (double) atom->nmax * 3 * sizeof(double);
if (velocityflag) bytes += (double) atom->nmax * 3 * sizeof(double);
return bytes;
}
/* ----------------------------------------------------------------------
pack entire state of Fix into one write
------------------------------------------------------------------------- */
void FixMove::write_restart(FILE *fp)
{
int n = 0;
double list[1];
list[n++] = time_origin;
if (comm->me == 0) {
int size = n * sizeof(double);
fwrite(&size, sizeof(int), 1, fp);
fwrite(list, sizeof(double), n, fp);
}
}
/* ----------------------------------------------------------------------
use state info from restart file to restart the Fix
------------------------------------------------------------------------- */
void FixMove::restart(char *buf)
{
int n = 0;
auto list = (double *) buf;
time_origin = static_cast<int>(list[n++]);
}
/* ----------------------------------------------------------------------
allocate atom-based array
------------------------------------------------------------------------- */
void FixMove::grow_arrays(int nmax)
{
memory->grow(xoriginal, nmax, 3, "move:xoriginal");
if (theta_flag) memory->grow(toriginal, nmax, "move:toriginal");
if (quat_flag) memory->grow(qoriginal, nmax, 4, "move:qoriginal");
array_atom = xoriginal;
}
/* ----------------------------------------------------------------------
copy values within local atom-based array
------------------------------------------------------------------------- */
void FixMove::copy_arrays(int i, int j, int /*delflag*/)
{
xoriginal[j][0] = xoriginal[i][0];
xoriginal[j][1] = xoriginal[i][1];
xoriginal[j][2] = xoriginal[i][2];
if (theta_flag) toriginal[j] = toriginal[i];
if (quat_flag) {
qoriginal[j][0] = qoriginal[i][0];
qoriginal[j][1] = qoriginal[i][1];
qoriginal[j][2] = qoriginal[i][2];
qoriginal[j][3] = qoriginal[i][3];
}
}
/* ----------------------------------------------------------------------
initialize one atom's array values, called when atom is created
------------------------------------------------------------------------- */
void FixMove::set_arrays(int i)
{
double theta;
double *quat;
double **x = atom->x;
imageint *image = atom->image;
int *ellipsoid = atom->ellipsoid;
int *line = atom->line;
int *tri = atom->tri;
int *body = atom->body;
int *mask = atom->mask;
// particle not in group
if (!(mask[i] & groupbit)) {
xoriginal[i][0] = xoriginal[i][1] = xoriginal[i][2] = 0.0;
return;
}
// current time still equal fix creation time
if (update->ntimestep == time_origin) {
domain->unmap(x[i], image[i], xoriginal[i]);
return;
}
// backup particle to time_origin
if (mstyle == VARIABLE) error->all(FLERR, "Cannot add atoms to fix move variable");
domain->unmap(x[i], image[i], xoriginal[i]);
double delta = (update->ntimestep - time_origin) * update->dt;
if (mstyle == LINEAR) {
if (vxflag) xoriginal[i][0] -= vx * delta;
if (vyflag) xoriginal[i][1] -= vy * delta;
if (vzflag) xoriginal[i][2] -= vz * delta;
} else if (mstyle == WIGGLE) {
double arg = omega_rotate * delta;
double sine = sin(arg);
if (axflag) xoriginal[i][0] -= ax * sine;
if (ayflag) xoriginal[i][1] -= ay * sine;
if (azflag) xoriginal[i][2] -= az * sine;
} else if (mstyle == ROTATE) {
double a[3], b[3], c[3], d[3], disp[3], ddotr;
double arg = -omega_rotate * delta;
double sine = sin(arg);
double cosine = cos(arg);
d[0] = x[i][0] - point[0];
d[1] = x[i][1] - point[1];
d[2] = x[i][2] - point[2];
ddotr = d[0] * runit[0] + d[1] * runit[1] + d[2] * runit[2];
c[0] = ddotr * runit[0];
c[1] = ddotr * runit[1];
c[2] = ddotr * runit[2];
a[0] = d[0] - c[0];
a[1] = d[1] - c[1];
a[2] = d[2] - c[2];
b[0] = runit[1] * a[2] - runit[2] * a[1];
b[1] = runit[2] * a[0] - runit[0] * a[2];
b[2] = runit[0] * a[1] - runit[1] * a[0];
disp[0] = a[0] * cosine + b[0] * sine;
disp[1] = a[1] * cosine + b[1] * sine;
disp[2] = a[2] * cosine + b[2] * sine;
xoriginal[i][0] = point[0] + c[0] + disp[0];
xoriginal[i][1] = point[1] + c[1] + disp[1];
xoriginal[i][2] = point[2] + c[2] + disp[2];
// set theta and quat extra attributes affected by rotation
if (extra_flag) {
// theta for lines
if (theta_flag && line[i] >= 0.0) {
theta = avec_line->bonus[atom->line[i]].theta;
toriginal[i] = theta - 0.0; // NOTE: edit this line
}
// quats for ellipsoids, tris, and bodies
if (quat_flag) {
quat = nullptr;
if (ellipsoid_flag && ellipsoid[i] >= 0)
quat = avec_ellipsoid->bonus[ellipsoid[i]].quat;
else if (tri_flag && tri[i] >= 0)
quat = avec_tri->bonus[tri[i]].quat;
else if (body_flag && body[i] >= 0)
quat = avec_body->bonus[body[i]].quat;
if (quat) {
// qoriginal = f(quat,-delta); // NOTE: edit this line
}
}
}
xoriginal[i][0] -= vx * delta;
xoriginal[i][1] -= vy * delta;
xoriginal[i][2] -= vz * delta;
} else if (mstyle == TRANSROT) {
double a[3], b[3], c[3], d[3], disp[3], ddotr;
double arg = -omega_rotate * delta;
double sine = sin(arg);
double cosine = cos(arg);
d[0] = x[i][0] - point[0];
d[1] = x[i][1] - point[1];
d[2] = x[i][2] - point[2];
ddotr = d[0] * runit[0] + d[1] * runit[1] + d[2] * runit[2];
c[0] = ddotr * runit[0];
c[1] = ddotr * runit[1];
c[2] = ddotr * runit[2];
a[0] = d[0] - c[0];
a[1] = d[1] - c[1];
a[2] = d[2] - c[2];
b[0] = runit[1] * a[2] - runit[2] * a[1];
b[1] = runit[2] * a[0] - runit[0] * a[2];
b[2] = runit[0] * a[1] - runit[1] * a[0];
disp[0] = a[0] * cosine + b[0] * sine;
disp[1] = a[1] * cosine + b[1] * sine;
disp[2] = a[2] * cosine + b[2] * sine;
xoriginal[i][0] = point[0] + c[0] + disp[0];
xoriginal[i][1] = point[1] + c[1] + disp[1];
xoriginal[i][2] = point[2] + c[2] + disp[2];
// set theta and quat extra attributes affected by rotation
if (extra_flag) {
// theta for lines
if (theta_flag && line[i] >= 0.0) {
theta = avec_line->bonus[atom->line[i]].theta;
toriginal[i] = theta - 0.0; // NOTE: edit this line
}
// quats for ellipsoids, tris, and bodies
if (quat_flag) {
quat = nullptr;
if (ellipsoid_flag && ellipsoid[i] >= 0)
quat = avec_ellipsoid->bonus[ellipsoid[i]].quat;
else if (tri_flag && tri[i] >= 0)
quat = avec_tri->bonus[tri[i]].quat;
else if (body_flag && body[i] >= 0)
quat = avec_body->bonus[body[i]].quat;
if (quat) {
// qoriginal = f(quat,-delta); // NOTE: edit this line
}
}
}
}
}
/* ----------------------------------------------------------------------
pack values in local atom-based array for exchange with another proc
------------------------------------------------------------------------- */
int FixMove::pack_exchange(int i, double *buf)
{
int n = 0;
buf[n++] = xoriginal[i][0];
buf[n++] = xoriginal[i][1];
buf[n++] = xoriginal[i][2];
if (theta_flag) buf[n++] = toriginal[i];
if (quat_flag) {
buf[n++] = qoriginal[i][0];
buf[n++] = qoriginal[i][1];
buf[n++] = qoriginal[i][2];
buf[n++] = qoriginal[i][3];
}
return n;
}
/* ----------------------------------------------------------------------
unpack values in local atom-based array from exchange with another proc
------------------------------------------------------------------------- */
int FixMove::unpack_exchange(int nlocal, double *buf)
{
int n = 0;
xoriginal[nlocal][0] = buf[n++];
xoriginal[nlocal][1] = buf[n++];
xoriginal[nlocal][2] = buf[n++];
if (theta_flag) toriginal[nlocal] = buf[n++];
if (quat_flag) {
qoriginal[nlocal][0] = buf[n++];
qoriginal[nlocal][1] = buf[n++];
qoriginal[nlocal][2] = buf[n++];
qoriginal[nlocal][3] = buf[n++];
}
return n;
}
/* ----------------------------------------------------------------------
pack values in local atom-based arrays for restart file
------------------------------------------------------------------------- */
int FixMove::pack_restart(int i, double *buf)
{
int n = 1;
buf[n++] = xoriginal[i][0];
buf[n++] = xoriginal[i][1];
buf[n++] = xoriginal[i][2];
if (theta_flag) buf[n++] = toriginal[i];
if (quat_flag) {
buf[n++] = qoriginal[i][0];
buf[n++] = qoriginal[i][1];
buf[n++] = qoriginal[i][2];
buf[n++] = qoriginal[i][3];
}
// pack buf[0] this way because other fixes unpack it
buf[0] = n;
return n;
}
/* ----------------------------------------------------------------------
unpack values from atom->extra array to restart the fix
------------------------------------------------------------------------- */
void FixMove::unpack_restart(int nlocal, int nth)
{
double **extra = atom->extra;
// skip to Nth set of extra values
// unpack the Nth first values this way because other fixes pack them
int m = 0;
for (int i = 0; i < nth; i++) m += static_cast<int>(extra[nlocal][m]);
m++;
xoriginal[nlocal][0] = extra[nlocal][m++];
xoriginal[nlocal][1] = extra[nlocal][m++];
xoriginal[nlocal][2] = extra[nlocal][m++];
if (theta_flag) toriginal[nlocal] = extra[nlocal][m++];
if (quat_flag) {
qoriginal[nlocal][0] = extra[nlocal][m++];
qoriginal[nlocal][1] = extra[nlocal][m++];
qoriginal[nlocal][2] = extra[nlocal][m++];
qoriginal[nlocal][3] = extra[nlocal][m++];
}
}
/* ----------------------------------------------------------------------
maxsize of any atom's restart data
------------------------------------------------------------------------- */
int FixMove::maxsize_restart()
{
return nrestart;
}
/* ----------------------------------------------------------------------
size of atom nlocal's restart data
------------------------------------------------------------------------- */
int FixMove::size_restart(int /*nlocal*/)
{
return nrestart;
}
/* ---------------------------------------------------------------------- */
void FixMove::reset_dt()
{
error->all(FLERR, "Resetting timestep size is not allowed with fix move");
}