lammps/lib/atc/LammpsInterface.cpp

1535 lines
47 KiB
C++

// Header file for this class
#include "LammpsInterface.h"
// LAMMPS includes
#include "lammps.h"
#include "atom.h" // x, v, f
#include "atom_vec.h" //for insertion
#include "domain.h" // for basing locations on regions
#include "region.h" // region bounding box and style
#include "force.h" // boltzman constant
#include "group.h" // atom masks
#include "memory.h" // grow atom information
#include "compute.h" // computes
#include "compute_pe_atom.h" // computes potential energy per atom
#include "compute_stress_atom.h" // computes stress per atom
#include "compute_centro_atom.h" // computes centrosymmetry per atom
#include "compute_cna_atom.h" // computes common-neighbor-analysis per atom
#include "compute_coord_atom.h" // computes coordination number per atom
#include "compute_ke_atom.h" // computes kinetic energy per atom
#include "modify.h" //
#include "neighbor.h" // neighbors
#include "neigh_list.h" // neighbor list
#include "update.h" // timestepping information
#include "pair.h" // pair potentials
#include "MANYBODY/pair_eam.h" // pair potentials
#include "lattice.h" // lattice parameters
#include "bond.h" // bond potentials
#include "comm.h" //
#include "fix.h"
// ATC includes
#include "ATC_Error.h"
#include "MatrixLibrary.h"
#include "Utility.h"
using ATC_Utility::to_string;
// Other include files
#include "mpi.h"
#include <cstring>
#include <map>
#include <typeinfo>
using std::max;
using std::stringstream;
using std::copy;
using std::map;
using std::pair;
using std::string;
using std::set;
using LAMMPS_NS::bigint;
namespace ATC {
const static double PI = 3.141592653589793238;
const static int seed_ = 3141592;
const static int MAX_GROUP_BIT = 2147483647; //4294967295; // pow(2,31)-1;
double norm(double * v) {return sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]); }
LammpsInterface * LammpsInterface::myInstance_ = NULL;
// -----------------------------------------------------------------
// instance()
// -----------------------------------------------------------------
LammpsInterface * LammpsInterface::instance()
{
if (myInstance_ == NULL) {
myInstance_ = new LammpsInterface();
}
return myInstance_;
}
// -----------------------------------------------------------------
// Destroy()
// -----------------------------------------------------------------
void LammpsInterface::Destroy()
{
if (myInstance_) delete myInstance_;
myInstance_ = NULL;
}
// -----------------------------------------------------------------
// constructor
// -----------------------------------------------------------------
LammpsInterface::LammpsInterface()
: lammps_(NULL),
fixPointer_(NULL),
commRank_(0),
atomPE_(NULL),
refBoxIsSet_(false),
random_(NULL),
globalrandom_(NULL)
{
}
// -----------------------------------------------------------------
// general interface methods
// -----------------------------------------------------------------
MPI_Comm LammpsInterface::world() const { return lammps_->world; }
void LammpsInterface::set_fix_pointer(LAMMPS_NS::Fix * thisFix) { fixPointer_ = thisFix; }
void LammpsInterface::forward_comm_fix() const { lammps_->comm->forward_comm_fix(fixPointer_); }
void LammpsInterface::comm_borders() const { lammps_->comm->borders(); }
#ifndef ISOLATE_FE
void LammpsInterface::sparse_allsum(SparseMatrix<double> &toShare) const
{
toShare.compress();
// initialize MPI information
int nProcs;
int myRank;
MPI_Comm_size(MPI_COMM_WORLD, &nProcs);
MPI_Comm_rank(MPI_COMM_WORLD, &myRank);
int error;
// get numbers of rows, columns, rowsCRS, and
// sizes (number of nonzero elements in matrix)
SparseMatInfo *recInfo = new SparseMatInfo[nProcs];
SparseMatInfo myInfo;
myInfo.rows = toShare.nRows();
myInfo.cols = toShare.nCols();
myInfo.rowsCRS = toShare.nRowsCRS();
myInfo.size = toShare.size();
error = MPI_Allgather(&myInfo, 4, MPI_INT,
recInfo, 4, MPI_INT, lammps_->world);
if (error != MPI_SUCCESS) throw ATC_Error("error in sparse_allsum_numrows "+to_string(error));
// adjust row sendcounts because recRowsCRS is off by one
int rowCounts[nProcs];
int sizeCounts[nProcs];
// set up total size of receive buffers for Allgatherv calls
int totalRowsCRS = 0;
int totalSize = 0;
// set up array of displacements for Allgatherv calls
int rowOffsets[nProcs];
rowOffsets[0] = 0;
int sizeOffsets[nProcs];
sizeOffsets[0] = 0;
for (int i = 0; i < nProcs; i++) {
// find the total number of entries to share in the mpi calls below
rowCounts[i] = recInfo[i].rowsCRS + 1;
sizeCounts[i] = recInfo[i].size;
totalRowsCRS += rowCounts[i];
totalSize += recInfo[i].size;
// these already have their 0th slot filled in
if (i == 0) continue;
rowOffsets[i] = rowOffsets[i-1] + rowCounts[i-1];
sizeOffsets[i] = sizeOffsets[i-1] + sizeCounts[i-1];
}
// get actual rows
INDEX *rec_ia = new INDEX[totalRowsCRS];
if (toShare.size() == 0) {
double dummy[0];
error = MPI_Allgatherv(dummy, 0, MPI_INT,
rec_ia, rowCounts, rowOffsets, MPI_INT, lammps_->world);
}
else
error = MPI_Allgatherv(toShare.rows(), rowCounts[myRank], MPI_INT,
rec_ia, rowCounts, rowOffsets, MPI_INT, lammps_->world);
if (error != MPI_SUCCESS)
throw ATC_Error("error in sparse_allsum_rowarray "+to_string(error));
// get actual cols
INDEX *rec_ja = new INDEX[totalSize];
error = MPI_Allgatherv(toShare.cols(), sizeCounts[myRank], MPI_INT,
rec_ja, sizeCounts, sizeOffsets, MPI_INT, lammps_->world);
if (error != MPI_SUCCESS)
throw ATC_Error("error in sparse_allsum_colarray "+to_string(error));
// get the array of values
double *rec_vals = new double[totalSize];
error = MPI_Allgatherv(toShare.ptr(), sizeCounts[myRank], MPI_DOUBLE,
rec_vals, sizeCounts, sizeOffsets, MPI_DOUBLE, lammps_->world);
if (error != MPI_SUCCESS)
throw ATC_Error("error in sparse_allsum_valarray "+to_string(error));
INDEX *rec_ia_proc;
INDEX *rec_ja_proc;
double *rec_vals_proc;
for (int i = 0; i < nProcs; i++) {
if (myRank != i) {
// deallocated when tempMat is deleted since it wraps them
rec_ia_proc = new INDEX[rowCounts[i]];
rec_ja_proc = new INDEX[sizeCounts[i]];
rec_vals_proc = new double[sizeCounts[i]];
// copy the data passed with MPI into the new spots
copy(rec_ia + rowOffsets[i],
rec_ia + rowOffsets[i] + rowCounts[i],
rec_ia_proc);
copy(rec_ja + sizeOffsets[i],
rec_ja + sizeOffsets[i] + sizeCounts[i],
rec_ja_proc);
copy(rec_vals + sizeOffsets[i],
rec_vals + sizeOffsets[i] + sizeCounts[i],
rec_vals_proc);
// Does anyone know why we have to declare tempMat here (as well as set it equal to
// something) to avoid segfaults? there are still segfaults, but they happen at a much
// later stage of the game now (and for less benchmarks overall).
SparseMatrix<double> tempMat =
SparseMatrix<double>(rec_ia_proc, rec_ja_proc, rec_vals_proc,
recInfo[i].size, recInfo[i].rows,
recInfo[i].cols, recInfo[i].rowsCRS);
toShare += tempMat;
}
}
delete[] recInfo;
delete[] rec_ia;
delete[] rec_ja;
delete[] rec_vals;
}
#endif
// -----------------------------------------------------------------
// atom interface methods
// -----------------------------------------------------------------
string LammpsInterface::fix_id() const { return string(fixPointer_->id); }
int LammpsInterface::nlocal() const { return lammps_->atom->nlocal; }
int LammpsInterface::nghost() const { return lammps_->atom->nghost; }
bool LammpsInterface::atoms_sorted() const
{
int sortfreq = lammps_->atom->sortfreq;
if (sortfreq > 0) { return true; }
else { return false;
}
}
bigint LammpsInterface::natoms() const { return lammps_->atom->natoms; }
int LammpsInterface::nmax() const { return lammps_->atom->nmax; }
int LammpsInterface::ntypes() const { return lammps_->atom->ntypes; }
double ** LammpsInterface::xatom() const { return lammps_->atom->x; }
int LammpsInterface::type_to_charge(int atype) const {
double *q = lammps_->atom->q;
if (! q) return 0;
int nlocal = lammps_->atom->nlocal;
int *type = lammps_->atom->type;
double aq = 0.0;
for (int i = 0; i < nlocal; i++) {
if (type[i] == atype) {
aq = q[i];
break;
}
}
double pcharge;
MPI_Allreduce(&aq,&pcharge,1,MPI_DOUBLE,MPI_MAX,world());
double ncharge;
MPI_Allreduce(&aq,&ncharge,1,MPI_DOUBLE,MPI_MIN,world());
double charge = (pcharge == 0.0) ? ncharge : pcharge;
return charge;
}
//const double ** LammpsInterface::xatom() const { return (const double**)(lammps_->atom->x); }
double ** LammpsInterface::vatom() const { return lammps_->atom->v; }
double ** LammpsInterface::fatom() const { return lammps_->atom->f; }
const int * LammpsInterface::atom_mask() const { return (const int*)lammps_->atom->mask; }
int * LammpsInterface::atom_mask() { return lammps_->atom->mask; }
int * LammpsInterface::atom_type() const { return lammps_->atom->type; }
int * LammpsInterface::atom_tag() const { return lammps_->atom->tag; }
int * LammpsInterface::atom_to_molecule() const { return lammps_->atom->molecule; }
int * LammpsInterface::num_bond() const { return lammps_->atom->num_bond; }
int ** LammpsInterface::bond_atom() const { return lammps_->atom->bond_atom; }
int * LammpsInterface::image() const { return lammps_->atom->image; }
int LammpsInterface::bond_per_atom() const { return lammps_->atom->bond_per_atom; }
int LammpsInterface::newton_bond() const { return lammps_->force->newton_bond; }
int LammpsInterface::local_to_global_map(int global) const { return lammps_->atom->map(global); }
double * LammpsInterface::atom_mass() const { return lammps_->atom->mass; }
double LammpsInterface::atom_mass(int iType) const { return lammps_->atom->mass[iType]; }
double * LammpsInterface::atom_rmass() const { return lammps_->atom->rmass; }
double * LammpsInterface::atom_charge() const { return lammps_->atom->q; }
double * LammpsInterface::atom_scalar(FundamentalAtomQuantity quantityType) const
{
if (quantityType==ATOM_MASS) {
if (atom_mass())
throw ATC_Error("Atom mass array requested but not defined");
return atom_rmass();
}
else if (quantityType==ATOM_CHARGE) {
double * atomCharge = atom_charge();
if (!atomCharge)
throw ATC_Error("Atom charge array requested but not defined");
return atomCharge;
}
else
throw ATC_Error("BAD type requested in atom_scalar");
return NULL;
}
double ** LammpsInterface::atom_vector(FundamentalAtomQuantity quantityType) const
{
if (quantityType==ATOM_POSITION)
return xatom();
else if (quantityType==ATOM_VELOCITY)
return vatom();
else if (quantityType==ATOM_FORCE)
return fatom();
else
throw ATC_Error("BAD type requested in atom_vector");
return NULL;
}
int LammpsInterface::atom_quantity_ndof(FundamentalAtomQuantity quantityType) const
{
if (quantityType==ATOM_MASS || quantityType==ATOM_CHARGE)
return 1;
else if (quantityType==ATOM_POSITION || quantityType==ATOM_VELOCITY || quantityType==ATOM_FORCE)
return dimension();
else
throw ATC_Error("BAD type requested in atom_quantity_ndof");
}
double LammpsInterface::atom_quantity_conversion(FundamentalAtomQuantity quantityType) const
{
if (quantityType==ATOM_MASS || quantityType==ATOM_CHARGE || quantityType==ATOM_POSITION || quantityType==ATOM_VELOCITY)
return 1;
else if ( quantityType==ATOM_FORCE)
return ftm2v();
else
throw ATC_Error("BAD type requested in atom_quantity_conversion");
}
// -----------------------------------------------------------------
// domain interface methods
// -----------------------------------------------------------------
int LammpsInterface::dimension() const { return lammps_->domain->dimension; }
int LammpsInterface::nregion() const { return lammps_->domain->nregion; }
void LammpsInterface::box_bounds(double & boxxlo, double & boxxhi,
double & boxylo, double & boxyhi,
double & boxzlo, double &boxzhi) const
{
if (lammps_->domain->triclinic == 0) {
boxxlo = lammps_->domain->boxlo[0];
boxxhi = lammps_->domain->boxhi[0];
boxylo = lammps_->domain->boxlo[1];
boxyhi = lammps_->domain->boxhi[1];
boxzlo = lammps_->domain->boxlo[2];
boxzhi = lammps_->domain->boxhi[2];
}
else {
boxxlo = lammps_->domain->boxlo_bound[0];
boxxhi = lammps_->domain->boxhi_bound[0];
boxylo = lammps_->domain->boxlo_bound[1];
boxyhi = lammps_->domain->boxhi_bound[1];
boxzlo = lammps_->domain->boxlo_bound[2];
boxzhi = lammps_->domain->boxhi_bound[2];
}
}
bool LammpsInterface::in_box(double * x) const
{
double xlo,xhi,ylo,yhi,zlo,zhi;
box_bounds(xlo,xhi,ylo,yhi,zlo,zhi);
if (x[0] >= xlo && x[0] < xhi &&
x[1] >= ylo && x[1] < yhi &&
x[2] >= zlo && x[2] < zhi)
return true;
return false;
}
bool LammpsInterface::in_my_processor_box(double * x) const
{
if (x[0] >= lammps_->domain->sublo[0] && x[0] < lammps_->domain->subhi[0] &&
x[1] >= lammps_->domain->sublo[1] && x[1] < lammps_->domain->subhi[1] &&
x[2] >= lammps_->domain->sublo[2] && x[2] < lammps_->domain->subhi[2])
return true;
if (! in_box(x))
throw ATC_Error("point is in no processors box");
return false;
}
void LammpsInterface::sub_bounds(double & subxlo, double & subxhi,
double & subylo, double & subyhi,
double & subzlo, double & subzhi) const
{
if (lammps_->domain->triclinic == 0) {
subxlo = lammps_->domain->sublo[0];
subxhi = lammps_->domain->subhi[0];
subylo = lammps_->domain->sublo[1];
subyhi = lammps_->domain->subhi[1];
subzlo = lammps_->domain->sublo[2];
subzhi = lammps_->domain->subhi[2];
}
else {
ATC_Error("Subboxes not accurate when triclinic != 0.");
}
}
int LammpsInterface::xperiodic() const { return lammps_->domain->xperiodic; }
int LammpsInterface::yperiodic() const { return lammps_->domain->yperiodic; }
int LammpsInterface::zperiodic() const { return lammps_->domain->zperiodic; }
int LammpsInterface::nperiodic() const
{
int nprd = 0;
if ( lammps_->domain->xperiodic > 0 ) { nprd++ ; }
if ( lammps_->domain->yperiodic > 0 ) { nprd++ ; }
if ( lammps_->domain->zperiodic > 0 ) { nprd++ ; }
return nprd;
}
// correct posistions for periodic box
void LammpsInterface::periodicity_correction(double * x) const
{
int* periodicity = lammps_->domain->periodicity;
if (!refBoxIsSet_) set_reference_box();
for (int m = 0; m < 3; m++) {
if ((bool) periodicity[m]) {
if (x[m] < lower_[m] || x[m] > upper_[m]) {
x[m] -= length_[m]*floor((x[m]-lower_[m])/length_[m]);
}
if (x[m] < lower_[m] || x[m] > upper_[m]) {
throw ATC_Error("periodicity_correction: still out of box bounds");
}
}
}
}
void LammpsInterface::set_reference_box(void) const
{
double * hi = lammps_->domain->boxhi;
double * lo = lammps_->domain->boxlo;
double * len = lammps_->domain->prd;
for (int i = 0; i < 3; i++) {
upper_[i] = hi[i];
lower_[i] = lo[i];
length_[i] = len[i];
}
refBoxIsSet_ = true;
}
double LammpsInterface::domain_xprd() const { return lammps_->domain->xprd; }
double LammpsInterface::domain_yprd() const { return lammps_->domain->yprd; }
double LammpsInterface::domain_zprd() const { return lammps_->domain->zprd; }
double LammpsInterface::domain_volume() const
{
return (lammps_->domain->xprd)*
(lammps_->domain->yprd)*
(lammps_->domain->zprd);
}
double LammpsInterface::domain_xy() const { return lammps_->domain->xy; }
double LammpsInterface::domain_xz() const { return lammps_->domain->xz; }
double LammpsInterface::domain_yz() const { return lammps_->domain->yz; }
int LammpsInterface::domain_triclinic() const { return lammps_->domain->triclinic; }
void LammpsInterface::box_periodicity(int & xperiodic,
int & yperiodic,
int & zperiodic) const
{
xperiodic = lammps_->domain->xperiodic;
yperiodic = lammps_->domain->yperiodic;
zperiodic = lammps_->domain->zperiodic;
}
int LammpsInterface::region_id(const char * regionName) const {
int nregion = this->nregion();
for (int iregion = 0; iregion < nregion; iregion++) {
if (strcmp(regionName, region_name(iregion)) == 0) {
return iregion;
}
}
throw ATC_Error("Region has not been defined");
return -1;
}
bool LammpsInterface::region_bounds(const char * regionName,
double & xmin, double & xmax,
double & ymin, double & ymax,
double & zmin, double & zmax,
double & xscale, double & yscale, double & zscale) const
{
int iRegion = region_id(regionName);
xscale = region_xscale(iRegion);
yscale = region_yscale(iRegion);
zscale = region_zscale(iRegion);
xmin = region_xlo(iRegion);
xmax = region_xhi(iRegion);
ymin = region_ylo(iRegion);
ymax = region_yhi(iRegion);
zmin = region_zlo(iRegion);
zmax = region_zhi(iRegion);
if (strcmp(region_style(iRegion),"block")==0) { return true; }
else { return false; }
}
void LammpsInterface::minimum_image(double & dx, double & dy, double & dz) const {
lammps_->domain->minimum_image(dx,dy,dz);
}
void LammpsInterface::closest_image(const double * const xi, const double * const xj, double * const xjImage) const {
lammps_->domain->closest_image(xi,xj,xjImage);
}
// -----------------------------------------------------------------
// update interface methods
// -----------------------------------------------------------------
LammpsInterface::UnitsType LammpsInterface::units_style(void) const
{
if (strcmp(lammps_->update->unit_style,"lj") == 0) return LJ;
else if (strcmp(lammps_->update->unit_style,"real") == 0) return REAL;
else if (strcmp(lammps_->update->unit_style,"metal") == 0) return METAL;
else return UNKNOWN;
}
double LammpsInterface::convert_units(double value, UnitsType in, UnitsType out, int massExp, int lenExp, int timeExp, int engExp) const
{
double ps2fs = 1.e3;
double eV2kcal = 23.069;
if (in==REAL) {
if (out==METAL) {
return value*pow(ps2fs,-timeExp)*pow(eV2kcal,-engExp);
}
else if (out==ATC) {
if (units_style()==REAL) {
return value;
}
else if (units_style()==METAL) {
return convert_units(value, METAL, out, massExp, lenExp, timeExp)*1.0;
}
}
else throw ATC_Error("can't convert");
}
else if (in==METAL) {
if (out==REAL) {
return value*pow(ps2fs,timeExp)*pow(eV2kcal,engExp);
}
else if (out==ATC) {
if (units_style()==REAL) {
return convert_units(value, REAL, out, massExp, lenExp, timeExp)*1.0;
}
else if (units_style()==METAL) {
return value;
}
}
else throw ATC_Error("can't convert");
}
else throw ATC_Error("can't convert");
return value;
}
// -----------------------------------------------------------------
// lattice interface methods
// -----------------------------------------------------------------
double LammpsInterface::xlattice() const { return lammps_->domain->lattice->xlattice; }
double LammpsInterface::ylattice() const { return lammps_->domain->lattice->ylattice; }
double LammpsInterface::zlattice() const { return lammps_->domain->lattice->zlattice; }
LammpsInterface::LatticeType LammpsInterface::lattice_style() const
{
if (lammps_->domain->lattice)
return (LammpsInterface::LatticeType)lammps_->domain->lattice->style;
else
throw ATC_Error("Lattice has not been defined");
}
//* retuns the number of basis vectors
int LammpsInterface::n_basis() const
{
return lammps_->domain->lattice->nbasis;
}
//* returns the basis vectors, transformed to the box coords
void LammpsInterface::basis_vectors(double **basis) const
{
LAMMPS_NS::Lattice *lattice = lammps_->domain->lattice;
int i,j;
double origin[3] = {0.0, 0.0, 0.0};
lattice->lattice2box(origin[0], origin[1], origin[2]);
for (i=0; i<n_basis(); i++)
{
memcpy(basis[i],lattice->basis[i],3*sizeof(double));
lattice->lattice2box(basis[i][0], basis[i][1], basis[i][2]);
for (j=0; j<3; j++) basis[i][j] -= origin[j];
}
}
//* gets the (max) lattice constant
double LammpsInterface::max_lattice_constant(void) const
{
double a1[3], a2[3], a3[3];
unit_cell(a1,a2,a3);
double a = norm(a1);
a = max(a,norm(a2));
a = max(a,norm(a3));
return a;
}
//* computes a cutoff distance halfway between 1st and 2nd nearest neighbors
double LammpsInterface::near_neighbor_cutoff(void) const
{
double cutoff;
double alat = LammpsInterface::max_lattice_constant();
LatticeType type = lattice_style();
if (type == LammpsInterface::SC) {
cutoff = 0.5*(1.0+sqrt(2.0))*alat;
} else if (type == LammpsInterface::BCC) {
cutoff = 0.5*(0.5*sqrt(3.0)+1.0)*alat;
} else if (type == LammpsInterface::FCC) {
cutoff = 0.5*(1.0/sqrt(2.0)+1.0)*alat;
} else if (type == LammpsInterface::HCP) {
cutoff = 0.5*(1.0/sqrt(2.0)+1.0)*alat;
} else if (type == LammpsInterface::DIAMOND) {
cutoff = 0.5*(0.25*sqrt(3.0)+1.0/sqrt(2.0))*alat;
} else if (type == LammpsInterface::SQ) {
cutoff = 0.5*(1.0+sqrt(2.0))*alat;
} else if (type == LammpsInterface::SQ2) {
cutoff = 0.5*(1.0/sqrt(2.0)+1.0)*alat;
} else if (type == LammpsInterface::HEX) {
cutoff = 0.5*(1.0/sqrt(3.0)+1.0)*alat;
} else {
throw ATC_Error("Unknown lattice type");
}
return cutoff;
}
//* gets the unit cell vectors
void LammpsInterface::unit_cell(double *a1, double *a2, double *a3) const
{
int i, j;
double *a[3] = {a1,a2,a3};
double origin[3] = {0.0,0.0,0.0};
LAMMPS_NS::Lattice *lattice = lammps_->domain->lattice;
// transform origin
lattice->lattice2box(origin[0], origin[1], origin[2]);
// copy reference lattice vectors
memcpy(a[0], lattice->a1, 3*sizeof(double));
memcpy(a[1], lattice->a2, 3*sizeof(double));
memcpy(a[2], lattice->a3, 3*sizeof(double));
for (i=0; i<3; i++)
{
lattice->lattice2box(a[i][0], a[i][1], a[i][2]);
for (j=0; j<3; j++) a[i][j] -= origin[j];
}
}
//* gets number of atoms in a unit cell
int LammpsInterface::num_atoms_per_cell(void) const
{
int naCell = 0;
LatticeType type = lattice_style();
if (type == LammpsInterface::SC) naCell = 1;
else if (type == LammpsInterface::BCC) naCell = 2;
else if (type == LammpsInterface::FCC) naCell = 4;
else if (type == LammpsInterface::DIAMOND) naCell = 8;
else if (comm_rank()==0) {
//{throw ATC_Error("lattice style not currently supported by ATC");}
print_msg_once("WARNING: Cannot get number of atoms per cell from lattice");
naCell = 1;
}
return naCell;
}
//* gets tributary volume for an atom
double LammpsInterface::volume_per_atom(void) const
{
double naCell = num_atoms_per_cell();
double volPerAtom =
xlattice() * ylattice() * zlattice() / naCell;
return volPerAtom;
}
//* gets lattice basis
void LammpsInterface::lattice(MATRIX &N, MATRIX &B) const
{
int nbasis = n_basis();
double **basis = new double*[nbasis];
N.reset(3,3);
B.reset(3,nbasis);
for (int i=0; i<nbasis; i++) basis[i] = column(B,i).ptr();
basis_vectors(basis);
unit_cell(column(N,0).ptr(),
column(N,1).ptr(),
column(N,2).ptr());
delete [] basis;
}
// -----------------------------------------------------------------
// force interface methods
// -----------------------------------------------------------------
double LammpsInterface::boltz() const{ return lammps_->force->boltz; }
double LammpsInterface::mvv2e() const{ return lammps_->force->mvv2e; }
double LammpsInterface::ftm2v()const { return lammps_->force->ftm2v; }
double LammpsInterface::nktv2p()const{ return lammps_->force->nktv2p; }
double LammpsInterface::qqr2e() const{ return lammps_->force->qqr2e; }
double LammpsInterface::qe2f() const{ return lammps_->force->qe2f; }
double LammpsInterface::dielectric()const{return lammps_->force->dielectric; }
double LammpsInterface::qqrd2e()const{ return lammps_->force->qqrd2e; }
double LammpsInterface::qv2e() const{ return qe2f()*ftm2v(); }
double LammpsInterface::pair_force(int i, int j, double rsq,
double & fmag_over_rmag) const
{
int itype = (lammps_->atom->type)[i];
int jtype = (lammps_->atom->type)[j];
// return value is the energy
if (rsq < (lammps_->force->pair->cutsq)[itype][jtype]) {
return lammps_->force->pair->single(i,j,itype,jtype,
rsq,1.0,1.0,fmag_over_rmag);
}
return 0.0;
}
double LammpsInterface::pair_force(int n, double rsq,
double & fmag_over_rmag) const
{
int i = bond_list_i(n);
int j = bond_list_j(n);
int type = bond_list_type(n);
// return value is the energy
return lammps_->force->bond->single(type,rsq,i,j,fmag_over_rmag);
}
double LammpsInterface::pair_force(
map< std::pair< int,int >,int >::const_iterator itr, double rsq,
double & fmag_over_rmag, int nbonds) const
{
int n = itr->second;
if (n < nbonds) {
return pair_force(n, rsq,fmag_over_rmag);
}
else {
std::pair <int,int> ij = itr->first;
int i = ij.first;
int j = ij.second;
return pair_force(i,j, rsq,fmag_over_rmag);
}
}
double LammpsInterface::pair_force(
std::pair< std::pair< int,int >,int > apair, double rsq,
double & fmag_over_rmag, int nbonds) const
{
int n = apair.second;
if (n < nbonds) {
return pair_force(n, rsq,fmag_over_rmag);
}
else {
std::pair <int,int> ij = apair.first;
int i = ij.first;
int j = ij.second;
return pair_force(i,j, rsq,fmag_over_rmag);
}
}
double LammpsInterface::bond_stiffness(int i, int j, double rsq0) const
{
const double perturbation = 1.e-8;
double rsq1 = sqrt(rsq0)+perturbation;
rsq1 *= rsq1;
double f0,f1;
pair_force(i,j,rsq0,f0);
pair_force(i,j,rsq1,f1);
double k = (f1-f0)/perturbation;
return k;
}
double LammpsInterface::pair_cutoff() const
{
return lammps_->force->pair->cutforce;
}
void LammpsInterface::pair_reinit() const
{
lammps_->force->pair->reinit();
}
int LammpsInterface::single_enable() const
{
return lammps_->force->pair->single_enable; // all bonds have a single
}
//* insertion/deletion functions : see FixGCMC
//* delete atom
int LammpsInterface::delete_atom(int id) const
{
LAMMPS_NS::Atom * atom = lammps_->atom;
atom->avec->copy(atom->nlocal-1,id,1);
atom->nlocal--;
return atom->nlocal;
}
//* insert atom
int LammpsInterface::insert_atom(int atype, int amask,
double *ax, double *av, double aq) const
{
LAMMPS_NS::Atom * atom = lammps_->atom;
atom->avec->create_atom(atype,ax);
int m = atom->nlocal - 1;
atom->mask[m] = amask;
atom->v[m][0] = av[0];
atom->v[m][1] = av[1];
atom->v[m][2] = av[2];
if (aq != 0) atom->q[m] = aq;
int nfix = lammps_->modify->nfix;
LAMMPS_NS::Fix **fix = lammps_->modify->fix;
for (int j = 0; j < nfix; j++) {
if (fix[j]->create_attribute) fix[j]->set_arrays(m);
}
return m;
}
int LammpsInterface::reset_ghosts(int deln) const
{
LAMMPS_NS::Atom * atom = lammps_->atom;
//ATC::LammpsInterface::instance()->print_msg("reset_ghosts del n "+to_string(deln));
if (atom->tag_enable) {
atom->natoms += deln;
//ATC::LammpsInterface::instance()->print_msg("reset_ghosts natoms "+to_string(atom->natoms));
if (deln > 0) { atom->tag_extend(); }
if (atom->map_style) atom->map_init();
}
atom->nghost = 0;
lammps_->comm->borders();
//ATC::LammpsInterface::instance()->print_msg("reset_ghosts nghosts "+to_string(atom->nghost));
return atom->nghost;
}
//* energy for interactions within the shortrange cutoff
double LammpsInterface::shortrange_energy(double *coord,
int itype, int id, double max) const
{
LAMMPS_NS::Atom * atom = lammps_->atom;
double **x = atom->x;
int *type = atom->type;
int nall = atom->nlocal+ atom->nghost;
LAMMPS_NS::Pair *pair = lammps_->force->pair;
double **cutsq = lammps_->force->pair->cutsq;
double fpair = 0.0; // an output of single
double factor_coul = 1.0;
double factor_lj = 1.0;
double total_energy = 0.0;
for (int j = 0; j < nall; j++) {
if (id == j) continue;
// factor_lj = special_lj[sbmask(j)];
// factor_coul = special_coul[sbmask(j)];
//j &= NEIGHMASK;
double delx = coord[0] - x[j][0];
double dely = coord[1] - x[j][1];
double delz = coord[2] - x[j][2];
double rsq = delx*delx + dely*dely + delz*delz;
int jtype = type[j];
double cut2 = cutsq[itype][jtype];
if (rsq < cut2) {
total_energy += pair->single(id,j,itype,jtype,rsq,factor_coul,factor_lj,fpair); //id is for charge lookup
}
}
return total_energy;
}
double LammpsInterface::shortrange_energy(int id, double max) const
{
double *x = (lammps_->atom->x)[id];
int type = (lammps_->atom->type)[id];
return shortrange_energy(x,type,id,max);
}
POTENTIAL LammpsInterface::potential() const
{
// find pair style - FRAGILE
const int nStyles = 4;
string pairStyles[nStyles] = {"lj/cut",
"lj/cut/coul/long",
"lj/cut/coul/cut",
"lj/charmm/coul/long"};
LAMMPS_NS::Pair *pair = NULL;
for (int i = 0; i < nStyles; i++){
pair = lammps_->force->pair_match(pairStyles[i].c_str(),1);
if (pair != NULL) break;
}
return pair;
}
int LammpsInterface::type_to_groupbit(int itype) const
{
LAMMPS_NS::Atom * atom = lammps_->atom;
int groupbit = -1;
int *type = atom->type;
int *mask = atom->mask;
for (int i = 0; i < nlocal(); i++) {
if (type[i] == itype) {
groupbit = mask[i];
break;
}
}
return int_allmax(groupbit);
}
bool LammpsInterface::epsilons(int itype, POTENTIAL pair, double * epsilon0) const
{
// grab energy parameters
char * pair_parameter = new char[8];
strcpy(pair_parameter,"epsilon");
int dim = 2; // a return value for extract
double ** epsilons = (double**) ( pair->extract(pair_parameter,dim) );
delete [] pair_parameter;
if (epsilons == NULL) return false;
//if (epsilons == NULL) error->all(FLERR,"Fix concentration adapted pair style parameter not supported");
int i1,i2;
for (int i=1; i < ntypes()+1; i++) {
if (i < itype) { i1 = i; i2 = itype; }
else { i2 = i; i1 = itype; }
epsilon0[i-1] = epsilons[i1][i2];
}
return true;
}
bool LammpsInterface::set_epsilons(int itype, POTENTIAL pair, double * epsilon) const
{
// grab energy parameters
char * pair_parameter = new char[8];
strcpy(pair_parameter,"epsilon");
int dim = 2; // a return value for extract
double ** epsilons = (double**) ( pair->extract(pair_parameter,dim) );
delete [] pair_parameter;
if (epsilons == NULL) return false;
//if (epsilons == NULL) error->all(FLERR,"Fix concentration adapted pair style parameter not supported");
// scale interactions
int i1,i2;
for (int i = 1; i < ntypes()+1; i++) {
if (i < itype) { i1 = i; i2 = itype; }
else { i2 = i; i1 = itype; }
epsilons[i1][i2] = epsilon[i-1];
}
return true;
}
int LammpsInterface::set_charge(int itype, double charge) const
{
int nlocal = lammps_->atom->nlocal;
int *type = lammps_->atom->type;
double *q = lammps_->atom->q;
int count = 0;
for (int i = 0; i < nlocal; i++) {
if (type[i] == itype) {
q[i] = charge;
count++;
}
}
return count;
}
int LammpsInterface::change_type(int itype, int jtype) const
{
int nlocal = lammps_->atom->nlocal;
int *type = lammps_->atom->type;
int count = 0;
for (int i = 0; i < nlocal; i++) {
if (type[i] == itype) {
type[i] = jtype;
count++;
}
}
return count;
}
int LammpsInterface::count_type(int itype) const
{
int nlocal = lammps_->atom->nlocal;
int *type = lammps_->atom->type;
int count = 0;
for (int i = 0; i < nlocal; i++) {
if (type[i] == itype) { count++; }
}
return int_allsum(count);
}
// random number generators
RNG_POINTER LammpsInterface::random_number_generator() const {
RNG_POINTER p = new LAMMPS_NS::RanPark(lammps_,seed_);
return p;
}
double LammpsInterface::random_uniform(RNG_POINTER p) const {
return p->uniform();
}
double LammpsInterface::random_normal (RNG_POINTER p) const {
return p->gaussian();
}
int LammpsInterface::random_state (RNG_POINTER p) const {
return p->state();
}
void LammpsInterface::set_random_state (RNG_POINTER p, int seed) const {
return p->reset(seed);
}
void LammpsInterface::advance_random_generator (RNG_POINTER p, int n) const {
advance_random_uniform(p,n);
}
void LammpsInterface::advance_random_uniform (RNG_POINTER p, int n) const {
for (int i = 0; i < n; i++) p->uniform();
}
void LammpsInterface::advance_random_normal (RNG_POINTER p, int n) const {
for (int i = 0; i < n; i++) p->gaussian();
}
//* Boltzmann's constant in M,L,T,t units
double LammpsInterface::kBoltzmann() const {
return (lammps_->force->boltz)/(lammps_->force->mvv2e);
}
//* Planck's constant
double LammpsInterface::hbar() const {
const int UNITS_STYLE = (int) units_style();
double hbar = 1.0; // LJ: Dimensionless
if (UNITS_STYLE == 2) hbar = 15.1685792814; // Real: KCal/mol-fs
else if (UNITS_STYLE == 3) hbar = 0.000658212202469; // Metal: eV-ps
return hbar;
}
//* Dulong-Petit heat capacity
double LammpsInterface::heat_capacity() const {
double rhoCp = dimension()*kBoltzmann()/volume_per_atom();
return rhoCp;
}
//* reference mass density for a *unit cell*
// all that is needed is a unit cell: volume, types, mass per type
double LammpsInterface::mass_density(int* numPerType) const
{
const double *mass = lammps_->atom->mass;
if (!mass) throw ATC_Error("cannot compute a mass density: no mass");
const int ntypes = lammps_->atom->ntypes;
const int *mass_setflag = lammps_->atom->mass_setflag;
const int *type = lammps_->atom->type;
double naCell = num_atoms_per_cell();
double vol = volume_per_atom();
if (numPerType) {
double m = 0.0;
double n = 0;
for (int i = 0; i < ntypes; i++) {
m += numPerType[i]*mass[i+1];
n += numPerType[i];
}
if (n>naCell) throw ATC_Error("cannot compute a mass density: too many basis atoms");
return m/n/vol;
}
// since basis->type map not stored only monatomic lattices are automatic
// if not given a basis try to guess
else {
if (ntypes == 1) {
if ((this->natoms()==0) && mass_setflag[1]) {
return mass[1]/vol;
}
else {
if (type) return mass[type[0]]/vol;
else if (mass_setflag[1]) return mass[1]/vol;
}
}
}
throw ATC_Error("cannot compute a mass density");
return 0.0;
}
//* permittivity of free space
double LammpsInterface::epsilon0() const
{
return qe2f()/(4.*PI*qqr2e());
}
//* Coulomb's constant
double LammpsInterface::coulomb_constant() const
{
return qqr2e()/qe2f();
}
//* special coulombic interactions
double * LammpsInterface::special_coul() const
{
return lammps_->force->special_coul;
}
//* flag for newton
int LammpsInterface::newton_pair() const
{
return lammps_->force->newton_pair;
}
// -----------------------------------------------------------------
// group interface methods
// -----------------------------------------------------------------
int LammpsInterface::ngroup() const { return lammps_->group->ngroup; }
int LammpsInterface::group_bit(string name) const
{
return group_bit(group_index(name));
}
int LammpsInterface::group_bit(int iGroup) const
{
int mybit = 0;
mybit |= lammps_->group->bitmask[iGroup];
if (mybit < 0 || mybit > MAX_GROUP_BIT) {
string msg("LammpsInterface::group_bit() lammps group bit "+to_string(mybit)+" is out of range 0:"+to_string(MAX_GROUP_BIT));
throw ATC_Error(msg);
}
return mybit;
}
int LammpsInterface::group_index(string name) const
{
int igroup = lammps_->group->find(name.c_str());
if (igroup == -1) {
string msg("LammpsInterface::group_index() lammps group "+name+" does not exist");
throw ATC_Error(msg);
}
return igroup;
}
int LammpsInterface::group_inverse_mask(int iGroup) const
{
return lammps_->group->inversemask[iGroup];
}
char * LammpsInterface::group_name(int iGroup) const
{
return lammps_->group->names[iGroup];
}
void LammpsInterface::group_bounds(int iGroup, double * b) const
{
lammps_->group->bounds(iGroup, b);
}
// -----------------------------------------------------------------
// memory interface methods
// -----------------------------------------------------------------
double * LammpsInterface::create_1d_double_array(int length, const char *name) const {
double * myArray;
return lammps_->memory->create(myArray, length, name);
}
double *LammpsInterface::grow_1d_double_array(double *array,
int length,
const char *name) const
{
return lammps_->memory->grow(array, length, name);
}
void LammpsInterface::destroy_1d_double_array(double * d) const {
lammps_->memory->destroy(d);
}
double ** LammpsInterface::create_2d_double_array(int n1, int n2, const char *name) const {
double ** myArray;
return lammps_->memory->create(myArray, n1, n2, name);
}
void LammpsInterface::destroy_2d_double_array(double **d) const {
lammps_->memory->destroy(d);
}
double **LammpsInterface::grow_2d_double_array(double **array,
int n1,
int n2,
const char *name) const
{
return lammps_->memory->grow(array, n1, n2, name);
}
int * LammpsInterface::create_1d_int_array(int length, const char *name) const {
int * myArray;
return lammps_->memory->create(myArray, length, name);
}
int *LammpsInterface::grow_1d_int_array(int *array,
int length,
const char *name) const
{
return lammps_->memory->grow(array, length, name);
}
void LammpsInterface::destroy_1d_int_array(int * d) const {
lammps_->memory->destroy(d);
}
int ** LammpsInterface::create_2d_int_array(int n1, int n2, const char *name) const {
int ** myArray;
return lammps_->memory->create(myArray, n1, n2, name);
}
void LammpsInterface::destroy_2d_int_array(int **i) const {
lammps_->memory->destroy(i);
}
int ** LammpsInterface::grow_2d_int_array(int **array, int n1, int n2, const char *name) const {
return lammps_->memory->grow(array, n1, n2, name);
}
// -----------------------------------------------------------------
// update interface methods
// -----------------------------------------------------------------
double LammpsInterface::dt() const { return lammps_->update->dt; }
bigint LammpsInterface::ntimestep() const { return lammps_->update->ntimestep; }
int LammpsInterface::nsteps() const { return lammps_->update->nsteps; }
// -----------------------------------------------------------------
// neighbor list interface methods
// -----------------------------------------------------------------
int LammpsInterface::sbmask(int j) const {return j >> SBBITS & 3; }
void LammpsInterface::set_list(int id, LAMMPS_NS::NeighList *ptr) { list_ = ptr; }
int LammpsInterface::neighbor_list_inum() const { return list_->inum; }
int * LammpsInterface::neighbor_list_numneigh() const { return list_->numneigh; }
int * LammpsInterface::neighbor_list_ilist() const { return list_->ilist; }
int ** LammpsInterface::neighbor_list_firstneigh() const { return list_->firstneigh; }
int LammpsInterface::neighbor_ago() const { return lammps_->neighbor->ago; }
int LammpsInterface::reneighbor_frequency() const {return lammps_->neighbor->every; }
// -----------------------------------------------------------------
// bond list interface methods
// -----------------------------------------------------------------
int LammpsInterface::bond_list_length() const { return lammps_->neighbor->nbondlist; }
int** LammpsInterface::bond_list() const { return lammps_->neighbor->bondlist; }
// -----------------------------------------------------------------
// region interface methods
// -----------------------------------------------------------------
char * LammpsInterface::region_name(int iRegion) const
{
return lammps_->domain->regions[iRegion]->id;
}
char * LammpsInterface::region_style(int iRegion) const
{
return lammps_->domain->regions[iRegion]->style;
}
double LammpsInterface::region_xlo(int iRegion) const
{
return lammps_->domain->regions[iRegion]->extent_xlo;
}
double LammpsInterface::region_xhi(int iRegion) const
{
return lammps_->domain->regions[iRegion]->extent_xhi;
}
double LammpsInterface::region_ylo(int iRegion) const
{
return lammps_->domain->regions[iRegion]->extent_ylo;
}
double LammpsInterface::region_yhi(int iRegion) const
{
return lammps_->domain->regions[iRegion]->extent_yhi;
}
double LammpsInterface::region_zlo(int iRegion) const
{
return lammps_->domain->regions[iRegion]->extent_zlo;
}
double LammpsInterface::region_zhi(int iRegion) const
{
return lammps_->domain->regions[iRegion]->extent_zhi;
}
double LammpsInterface::region_xscale(int iRegion) const
{
return lammps_->domain->regions[iRegion]->xscale;
}
double LammpsInterface::region_yscale(int iRegion) const
{
return lammps_->domain->regions[iRegion]->yscale;
}
double LammpsInterface::region_zscale(int iRegion) const
{
return lammps_->domain->regions[iRegion]->zscale;
}
int LammpsInterface::region_match(int iRegion, double x, double y, double z) const {
return lammps_->domain->regions[iRegion]->match(x,y,z);
}
// -----------------------------------------------------------------
// compute methods
// -----------------------------------------------------------------
COMPUTE_POINTER LammpsInterface::compute_pointer(string tag) const
{
// get the compute id
char * name = const_cast <char*> (tag.c_str());
int id = lammps_->modify->find_compute(name);
if (id < 0) {
string msg("Could not find compute "+tag);
msg += tag;
throw ATC_Error(msg);
}
// get the compute
LAMMPS_NS::Compute* cmpt = lammps_->modify->compute[id];
// insert it into our set, recall it won't be added if it already exists
computePointers_.insert(cmpt);
return cmpt;
}
void LammpsInterface::computes_addstep(int step) const
{
set<LAMMPS_NS::Compute * >::iterator iter;
for (iter = computePointers_.begin(); iter != computePointers_.end(); iter++) {
(*iter)->addstep(step);
}
}
void LammpsInterface::compute_addstep(COMPUTE_POINTER computePointer, int step) const
{
LAMMPS_NS::Compute* cmpt = const_to_active(computePointer);
cmpt->addstep(step);
}
int LammpsInterface::compute_matchstep(COMPUTE_POINTER computePointer, int step) const
{
LAMMPS_NS::Compute* cmpt = const_to_active(computePointer);
return cmpt->matchstep(step);
}
void LammpsInterface::reset_invoked_flag(COMPUTE_POINTER computePointer) const
{
LAMMPS_NS::Compute* cmpt = const_to_active(computePointer);
cmpt->invoked_flag = 0;
}
int LammpsInterface::compute_ncols_peratom(COMPUTE_POINTER computePointer) const
{
LAMMPS_NS::Compute* cmpt = const_to_active(computePointer);
int ndof = cmpt->size_peratom_cols;
if (ndof == 0 ) ndof = 1;
return ndof;
}
double* LammpsInterface::compute_vector_peratom(COMPUTE_POINTER computePointer) const
{
LAMMPS_NS::Compute* cmpt = const_to_active(computePointer);
if (!(cmpt->invoked_flag & INVOKED_PERATOM)) {
cmpt->compute_peratom();
cmpt->invoked_flag |= INVOKED_PERATOM;
}
return cmpt->vector_atom;
}
double** LammpsInterface::compute_array_peratom(COMPUTE_POINTER computePointer) const
{
LAMMPS_NS::Compute* cmpt = const_to_active(computePointer);
if (!(cmpt->invoked_flag & INVOKED_PERATOM)) {
cmpt->compute_peratom();
cmpt->invoked_flag |= INVOKED_PERATOM;
}
return cmpt->array_atom;
}
LAMMPS_NS::Compute * LammpsInterface::const_to_active(COMPUTE_POINTER computePointer) const
{
LAMMPS_NS::Compute* cmpt = const_cast<LAMMPS_NS::Compute* >(computePointer);
set<LAMMPS_NS::Compute * >::iterator cmptPtr;
cmptPtr = computePointers_.find(cmpt);
if (cmptPtr != computePointers_.end())
return *cmptPtr;
else
throw ATC_Error("Requested bad computer pointer");
}
// -----------------------------------------------------------------
// compute pe/atom interface methods
// - the only compute "owned" by ATC
// -----------------------------------------------------------------
int LammpsInterface::create_compute_pe_peratom(void) const
{
char **list = new char*[4];
string atomPeName = compute_pe_name();
list[0] = (char *) atomPeName.c_str();
list[1] = (char *) "all";
list[2] = (char *) "pe/atom";
list[3] = (char *) "pair";
int icompute = lammps_->modify->find_compute(list[0]);
if (icompute < 0) {
lammps_->modify->add_compute(4,list);
icompute = lammps_->modify->find_compute(list[0]);
}
delete [] list;
if (! atomPE_ ) {
atomPE_ = lammps_->modify->compute[icompute];
}
computePointers_.insert(atomPE_);
stringstream ss;
ss << "peratom PE compute created with ID: " << icompute;
ATC::LammpsInterface::instance()->print_msg_once(ss.str());
return icompute;
}
double * LammpsInterface::compute_pe_peratom(void) const
{
if (atomPE_) {
atomPE_->compute_peratom();
return atomPE_->vector_atom;
}
else {
return NULL;
}
}
/* ---------------------------------------------------------------------- */
void LammpsInterface::unwrap_coordinates(int iatom, double* xatom) const
{
double **x = lammps_->atom->x;
int *image = lammps_->atom->image;
double *h = lammps_->domain->h;
double xprd = lammps_->domain->xprd;
double yprd = lammps_->domain->yprd;
double zprd = lammps_->domain->zprd;
int xbox,ybox,zbox;
// for triclinic, need to unwrap current atom coord via h matrix
if (lammps_->domain->triclinic == 0) {
xbox = (image[iatom] & 1023) - 512;
ybox = (image[iatom] >> 10 & 1023) - 512;
zbox = (image[iatom] >> 20) - 512;
xatom[0] = x[iatom][0] + xbox*xprd;
xatom[1] = x[iatom][1] + ybox*yprd;
xatom[2] = x[iatom][2] + zbox*zprd;
} else {
xbox = (image[iatom] & 1023) - 512;
ybox = (image[iatom] >> 10 & 1023) - 512;
zbox = (image[iatom] >> 20) - 512;
xatom[0] = x[iatom][0] + h[0]*xbox + h[5]*ybox + h[4]*zbox;
xatom[1] = x[iatom][1] + h[1]*ybox + h[3]*zbox;
xatom[2] = x[iatom][2] + h[2]*zbox;
}
}
/* ---------------------------------------------------------------------- */
LAMMPS_NS::PairEAM* LammpsInterface::pair_eam() const
{
//if (typeid(lammps_->force->pair) == typeid(LAMMPS_NS::PairEAM)) {
// return lammps_->force->pair;
//}
LAMMPS_NS::PairEAM* pair_eam = dynamic_cast<LAMMPS_NS::PairEAM*> (lammps_->force->pair);
if (pair_eam != NULL) {
return pair_eam;
}
else {
throw ATC_Error("LAMMPS Pair object is not of the derived class type PairEAM");
}
}
// -----------------------------------------------------------------
// other methods
// -----------------------------------------------------------------
/** Return lammps pointer -- only as a last resort! */
LAMMPS_NS::LAMMPS * LammpsInterface::lammps_pointer() const { return lammps_; }
}