Page MenuHomec4science

region.cpp
No OneTemporary

File Metadata

Created
Sat, Nov 2, 08:31

region.cpp

/* ----------------------------------------------------------------------
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 "math.h"
#include "stdlib.h"
#include "string.h"
#include "region.h"
#include "update.h"
#include "domain.h"
#include "lattice.h"
#include "error.h"
using namespace LAMMPS_NS;
enum{NONE,VELOCITY,WIGGLE,ROTATE,VARIABLE};
/* ---------------------------------------------------------------------- */
Region::Region(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp)
{
int n = strlen(arg[0]) + 1;
id = new char[n];
strcpy(id,arg[0]);
n = strlen(arg[1]) + 1;
style = new char[n];
strcpy(style,arg[1]);
time_origin = update->ntimestep;
}
/* ---------------------------------------------------------------------- */
Region::~Region()
{
delete [] id;
delete [] style;
}
/* ---------------------------------------------------------------------- */
void Region::init()
{
dt = update->dt;
}
/* ----------------------------------------------------------------------
parse optional parameters at end of region input line
------------------------------------------------------------------------- */
void Region::options(int narg, char **arg)
{
if (narg < 0) error->all("Illegal region command");
// option defaults
interior = 1;
scaleflag = 1;
dynamic = NONE;
int iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"units") == 0) {
if (iarg+2 > narg) error->all("Illegal region command");
if (strcmp(arg[iarg+1],"box") == 0) scaleflag = 0;
else if (strcmp(arg[iarg+1],"lattice") == 0) scaleflag = 1;
else error->all("Illegal region command");
iarg += 2;
} else if (strcmp(arg[iarg],"side") == 0) {
if (iarg+2 > narg) error->all("Illegal region command");
if (strcmp(arg[iarg+1],"in") == 0) interior = 1;
else if (strcmp(arg[iarg+1],"out") == 0) interior = 0;
else error->all("Illegal region command");
iarg += 2;
} else if (strcmp(arg[iarg],"vel") == 0) {
if (iarg+4 > narg) error->all("Illegal region command");
vx = atof(arg[iarg+1]);
vy = atof(arg[iarg+2]);
vz = atof(arg[iarg+3]);
dynamic = VELOCITY;
iarg += 4;
} else if (strcmp(arg[iarg],"wiggle") == 0) {
if (iarg+5 > narg) error->all("Illegal region command");
ax = atof(arg[iarg+1]);
ay = atof(arg[iarg+2]);
az = atof(arg[iarg+3]);
period = atof(arg[iarg+4]);
dynamic = WIGGLE;
iarg += 5;
} else if (strcmp(arg[iarg],"rotate") == 0) {
if (iarg+8 > narg) error->all("Illegal region command");
point[0] = atof(arg[iarg+1]);
point[1] = atof(arg[iarg+2]);
point[2] = atof(arg[iarg+3]);
axis[0] = atof(arg[iarg+4]);
axis[1] = atof(arg[iarg+5]);
axis[2] = atof(arg[iarg+6]);
period = atof(arg[iarg+7]);
dynamic = ROTATE;
iarg += 8;
} else error->all("Illegal region command");
}
// error check
if (dynamic &&
(strcmp(style,"union") == 0 || strcmp(style,"intersect") == 0))
error->all("Region union or intersect cannot be dynamic");
// setup scaling
if (scaleflag && domain->lattice == NULL)
error->all("Use of region with undefined lattice");
if (scaleflag) {
xscale = domain->lattice->xlattice;
yscale = domain->lattice->ylattice;
zscale = domain->lattice->zlattice;
}
else xscale = yscale = zscale = 1.0;
if (dynamic == VELOCITY) {
vx *= xscale;
vy *= yscale;
vz *= zscale;
} else if (dynamic == WIGGLE) {
ax *= xscale;
ay *= yscale;
az *= zscale;
} else if (dynamic == ROTATE) {
point[0] *= xscale;
point[1] *= yscale;
point[2] *= zscale;
}
if (dynamic == WIGGLE || dynamic == ROTATE) {
double PI = 4.0 * atan(1.0);
omega_rotate = 2.0*PI / period;
}
// runit = unit vector along rotation axis
if (dynamic == ROTATE) {
double len = sqrt(axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2]);
if (len == 0.0)
error->all("Region cannot have 0 length rotation vector");
runit[0] = axis[0]/len;
runit[1] = axis[1]/len;
runit[2] = axis[2]/len;
}
}
/* ----------------------------------------------------------------------
return 1 if region is dynamic, 0 if static
only primitive regions define it here
union/intersect regions have their own dynamic_check()
------------------------------------------------------------------------- */
int Region::dynamic_check()
{
return dynamic;
}
/* ----------------------------------------------------------------------
determine if point x,y,z is a match to region volume
XOR computes 0 if 2 args are the same, 1 if different
note that inside() returns 1 for points on surface of region
thus point on surface of exterior region will not match
if region is dynamic, apply inverse of region change to x
------------------------------------------------------------------------- */
int Region::match(double x, double y, double z)
{
double a[3],b[3],c[3],d[3];
if (dynamic) {
double delta = (update->ntimestep - time_origin) * dt;
if (dynamic == VELOCITY) {
x -= vx*delta;
y -= vy*delta;
z -= vz*delta;
} else if (dynamic == WIGGLE) {
double arg = omega_rotate * delta;
double sine = sin(arg);
x -= ax*sine;
y -= ay*sine;
z -= az*sine;
} else if (dynamic == ROTATE) {
double angle = -omega_rotate*delta;
rotate(x,y,z,angle);
}
}
return !(inside(x,y,z) ^ interior);
}
/* ----------------------------------------------------------------------
generate list of contact points for interior or exterior regions
if region is dynamic:
change x by inverse of region change
change contact point by region change
------------------------------------------------------------------------- */
int Region::surface(double x, double y, double z, double cutoff)
{
int ncontact;
double xnear[3],xhold[3];
if (dynamic) {
double delta = (update->ntimestep - time_origin) * dt;
if (dynamic == VELOCITY) {
x -= vx*delta;
y -= vy*delta;
z -= vz*delta;
} else if (dynamic == WIGGLE) {
double arg = omega_rotate * delta;
double sine = sin(arg);
x -= ax*sine;
y -= ay*sine;
z -= az*sine;
} else if (dynamic == ROTATE) {
xhold[0] = x;
xhold[1] = y;
xhold[2] = z;
double angle = -omega_rotate*delta;
rotate(x,y,z,angle);
}
}
xnear[0] = x;
xnear[1] = y;
xnear[2] = z;
if (interior) ncontact = surface_interior(xnear,cutoff);
else ncontact = surface_exterior(xnear,cutoff);
if (dynamic && ncontact) {
double delta = (update->ntimestep - time_origin) * dt;
if (dynamic == ROTATE) {
for (int i = 0; i < ncontact; i++) {
x -= contact[i].delx;
y -= contact[i].dely;
z -= contact[i].delz;
double angle = omega_rotate*delta;
rotate(x,y,z,angle);
contact[i].delx = xhold[0] - x;
contact[i].dely = xhold[1] - y;
contact[i].delz = xhold[2] - z;
}
}
}
return ncontact;
}
/* ----------------------------------------------------------------------
add a single contact at Nth location in contact array
x = particle position
xp,yp,zp = region surface point
------------------------------------------------------------------------- */
void Region::add_contact(int n, double *x, double xp, double yp, double zp)
{
double delx = x[0] - xp;
double dely = x[1] - yp;
double delz = x[2] - zp;
contact[n].r = sqrt(delx*delx + dely*dely + delz*delz);
contact[n].delx = delx;
contact[n].dely = dely;
contact[n].delz = delz;
}
/* ----------------------------------------------------------------------
rotate x,y,z by angle via right-hand rule around point and runit normal
sign of angle determines whether rotating forward/backward in time
return updated x,y,z
P = point = vector = point of rotation
R = vector = axis of rotation
w = omega of rotation (from period)
X0 = x,y,z = initial coord of atom
R0 = runit = unit vector for R
C = (X0 dot R0) R0 = projection of atom coord onto R
D = X0 - P = vector from P to X0
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,y,z = P + C + A cos(w*dt) + B sin(w*dt)
------------------------------------------------------------------------- */
void Region::rotate(double &x, double &y, double &z, double angle)
{
double a[3],b[3],c[3],d[3],disp[3];
double sine = sin(angle);
double cosine = cos(angle);
double x0dotr = x*runit[0] + y*runit[1] + z*runit[2];
c[0] = x0dotr * runit[0];
c[1] = x0dotr * runit[1];
c[2] = x0dotr * runit[2];
d[0] = x - point[0];
d[1] = y - point[1];
d[2] = z - point[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 = point[0] + c[0] + disp[0];
y = point[1] + c[1] + disp[1];
z = point[2] + c[2] + disp[2];
}

Event Timeline