Files
lammps/src/AMOEBA/fix_amoeba_pitorsion.cpp
2024-01-25 02:17:28 -05:00

1115 lines
35 KiB
C++

// clang-format off
/* ----------------------------------------------------------------------
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_amoeba_pitorsion.h"
#include "atom.h"
#include "comm.h"
#include "domain.h"
#include "error.h"
#include "force.h"
#include "math_const.h"
#include "memory.h"
#include "pair.h"
#include "respa.h"
#include "update.h"
#include <cmath>
#include <cstring>
using namespace LAMMPS_NS;
using namespace FixConst;
using namespace MathConst;
static constexpr int PITORSIONMAX = 6; // max # of PiTorsion terms stored by one atom
static constexpr int LISTDELTA = 8196;
static constexpr double LB_FACTOR = 1.5;
/* ---------------------------------------------------------------------- */
FixAmoebaPiTorsion::FixAmoebaPiTorsion(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg), num_pitorsion(nullptr), pitorsion_type(nullptr), pitorsion_atom1(nullptr),
pitorsion_atom2(nullptr), pitorsion_atom3(nullptr), pitorsion_atom4(nullptr), pitorsion_atom5(nullptr),
pitorsion_atom6(nullptr), pitorsion_list(nullptr)
{
if (narg != 3) error->all(FLERR,"Illegal fix amoeba/pitorsion command");
// settings for this fix
restart_global = 1;
restart_peratom = 1;
energy_global_flag = energy_peratom_flag = 1;
virial_global_flag = virial_peratom_flag = 1;
thermo_energy = thermo_virial = 1;
centroidstressflag = CENTROID_NOTAVAIL;
peratom_freq = 1;
scalar_flag = 1;
global_freq = 1;
extscalar = 1;
extvector = 1;
wd_header = 1;
wd_section = 1;
respa_level_support = 1;
ilevel_respa = 0;
MPI_Comm_rank(world,&me);
MPI_Comm_size(world,&nprocs);
// perform initial allocation of atom-based arrays
num_pitorsion = nullptr;
pitorsion_type = nullptr;
pitorsion_atom1 = nullptr;
pitorsion_atom2 = nullptr;
pitorsion_atom3 = nullptr;
pitorsion_atom4 = nullptr;
pitorsion_atom5 = nullptr;
pitorsion_atom6 = nullptr;
// register with Atom class
nmax_previous = 0;
grow_arrays(atom->nmax);
atom->add_callback(Atom::GROW);
atom->add_callback(Atom::RESTART);
// list of all pitorsions to compute on this proc
npitorsion_list = 0;
max_pitorsion_list = 0;
pitorsion_list = nullptr;
// pitorsion coeff
kpit = nullptr;
// zero thermo energy
epitorsion = 0.0;
}
/* --------------------------------------------------------------------- */
FixAmoebaPiTorsion::~FixAmoebaPiTorsion()
{
// unregister callbacks to this fix from Atom class
atom->delete_callback(id,Atom::GROW);
atom->delete_callback(id,Atom::RESTART);
// per-atom data
memory->destroy(num_pitorsion);
memory->destroy(pitorsion_type);
memory->destroy(pitorsion_atom1);
memory->destroy(pitorsion_atom2);
memory->destroy(pitorsion_atom3);
memory->destroy(pitorsion_atom4);
memory->destroy(pitorsion_atom5);
memory->destroy(pitorsion_atom6);
// local list of bitorsions to compute
memory->destroy(pitorsion_list);
// coeff
memory->destroy(kpit);
}
/* ---------------------------------------------------------------------- */
int FixAmoebaPiTorsion::setmask()
{
int mask = 0;
mask |= PRE_NEIGHBOR;
mask |= PRE_REVERSE;
mask |= POST_FORCE;
mask |= POST_FORCE_RESPA;
mask |= MIN_POST_FORCE;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixAmoebaPiTorsion::init()
{
if (utils::strmatch(update->integrate_style,"^respa")) {
ilevel_respa = ((Respa *) update->integrate)->nlevels-1;
if (respa_level >= 0) ilevel_respa = MIN(respa_level,ilevel_respa);
}
// check if PairAmoeba or PairHippo disabled pitorsion terms
Pair *pair = nullptr;
pair = force->pair_match("amoeba",1,0);
if (!pair) pair = force->pair_match("hippo",1,0);
if (!pair) disable = 0;
else {
int tmp;
int flag = *((int *) pair->extract("pitorsion_flag",tmp));
disable = flag ? 0 : 1;
}
// constant
onesixth = 1.0/6.0;
}
/* --------------------------------------------------------------------- */
void FixAmoebaPiTorsion::setup(int vflag)
{
pre_neighbor();
if (utils::strmatch(update->integrate_style,"^verlet"))
post_force(vflag);
else {
((Respa *) update->integrate)->copy_flevel_f(ilevel_respa);
post_force_respa(vflag,ilevel_respa,0);
((Respa *) update->integrate)->copy_f_flevel(ilevel_respa);
}
}
/* --------------------------------------------------------------------- */
void FixAmoebaPiTorsion::setup_pre_neighbor()
{
pre_neighbor();
}
/* --------------------------------------------------------------------- */
void FixAmoebaPiTorsion::setup_pre_reverse(int eflag, int vflag)
{
pre_reverse(eflag,vflag);
}
/* --------------------------------------------------------------------- */
void FixAmoebaPiTorsion::min_setup(int vflag)
{
pre_neighbor();
post_force(vflag);
}
/* ----------------------------------------------------------------------
create local list of pitorsions
if one or more atoms in pitorsion are on this proc,
this proc lists the pitorsion exactly once
------------------------------------------------------------------------- */
void FixAmoebaPiTorsion::pre_neighbor()
{
int i,m,atom1,atom2,atom3,atom4,atom5,atom6;
// guesstimate initial length of local pitorsion list
// if npitorsions was not set (due to read_restart, no read_data),
// then list will grow by LISTDELTA chunks
if (max_pitorsion_list == 0) {
if (nprocs == 1) max_pitorsion_list = npitorsions;
else max_pitorsion_list =
static_cast<int> (LB_FACTOR*npitorsions/nprocs);
memory->create(pitorsion_list,max_pitorsion_list,7,
"pitorsion:pitorsion_list");
}
int nlocal = atom->nlocal;
npitorsion_list = 0;
for (i = 0; i < nlocal; i++) {
for (m = 0; m < num_pitorsion[i]; m++) {
atom1 = atom->map(pitorsion_atom1[i][m]);
atom2 = atom->map(pitorsion_atom2[i][m]);
atom3 = atom->map(pitorsion_atom3[i][m]);
atom4 = atom->map(pitorsion_atom4[i][m]);
atom5 = atom->map(pitorsion_atom5[i][m]);
atom6 = atom->map(pitorsion_atom6[i][m]);
if (atom1 == -1 || atom2 == -1 || atom3 == -1 ||
atom4 == -1 || atom5 == -1 || atom6 == -1)
error->one(FLERR,"PiTorsion atoms {} {} {} {} {} {} missing on "
"proc {} at step {}",
pitorsion_atom1[i][m],pitorsion_atom2[i][m],
pitorsion_atom3[i][m],pitorsion_atom4[i][m],
pitorsion_atom5[i][m],pitorsion_atom6[i][m],
me,update->ntimestep);
atom1 = domain->closest_image(i,atom1);
atom2 = domain->closest_image(i,atom2);
atom3 = domain->closest_image(i,atom3);
atom4 = domain->closest_image(i,atom4);
atom5 = domain->closest_image(i,atom5);
atom6 = domain->closest_image(i,atom6);
if (i <= atom1 && i <= atom2 && i <= atom3 &&
i <= atom4 && i <= atom5 && i <= atom6) {
if (npitorsion_list == max_pitorsion_list) {
max_pitorsion_list += LISTDELTA;
memory->grow(pitorsion_list,max_pitorsion_list,7,
"pitorsion:pitorsion_list");
}
pitorsion_list[npitorsion_list][0] = atom1;
pitorsion_list[npitorsion_list][1] = atom2;
pitorsion_list[npitorsion_list][2] = atom3;
pitorsion_list[npitorsion_list][3] = atom4;
pitorsion_list[npitorsion_list][4] = atom5;
pitorsion_list[npitorsion_list][5] = atom6;
pitorsion_list[npitorsion_list][6] = pitorsion_type[i][m];
npitorsion_list++;
}
}
}
}
/* ----------------------------------------------------------------------
store eflag, so can use it in post_force to tally per-atom energies
------------------------------------------------------------------------- */
void FixAmoebaPiTorsion::pre_reverse(int eflag, int /*vflag*/)
{
eflag_caller = eflag;
}
/* ----------------------------------------------------------------------
compute PiTorsion terms
------------------------------------------------------------------------- */
void FixAmoebaPiTorsion::post_force(int vflag)
{
if (disable) return;
int ia,ib,ic,id,ie,ig,ptype;
double e,dedphi,engfraction;
double xt,yt,zt,rt2;
double xu,yu,zu,ru2;
double xtu,ytu,ztu;
double rdc,rtru;
double v2,c2,s2;
double phi2,dphi2;
double sine,cosine;
double sine2,cosine2;
double xia,yia,zia;
double xib,yib,zib;
double xic,yic,zic;
double xid,yid,zid;
double xie,yie,zie;
double xig,yig,zig;
double xip,yip,zip;
double xiq,yiq,ziq;
double xad,yad,zad;
double xbd,ybd,zbd;
double xec,yec,zec;
double xgc,ygc,zgc;
double xcp,ycp,zcp;
double xdc,ydc,zdc;
double xqd,yqd,zqd;
double xdp,ydp,zdp;
double xqc,yqc,zqc;
double dedxt,dedyt,dedzt;
double dedxu,dedyu,dedzu;
double dedxia,dedyia,dedzia;
double dedxib,dedyib,dedzib;
double dedxic,dedyic,dedzic;
double dedxid,dedyid,dedzid;
double dedxie,dedyie,dedzie;
double dedxig,dedyig,dedzig;
double dedxip,dedyip,dedzip;
double dedxiq,dedyiq,dedziq;
double vxterm,vyterm,vzterm;
int nlist,list[6];
double v[6];
epitorsion = 0.0;
int eflag = eflag_caller;
ev_init(eflag,vflag);
double **x = atom->x;
double **f = atom->f;
int nlocal = atom->nlocal;
for (int n = 0; n < npitorsion_list; n++) {
ia = pitorsion_list[n][0];
ib = pitorsion_list[n][1];
ic = pitorsion_list[n][2];
id = pitorsion_list[n][3];
ie = pitorsion_list[n][4];
ig = pitorsion_list[n][5];
ptype = pitorsion_list[n][6];
// compute the value of the pi-system torsion angle
xia = x[ia][0];
yia = x[ia][1];
zia = x[ia][2];
xib = x[ib][0];
yib = x[ib][1];
zib = x[ib][2];
xic = x[ic][0];
yic = x[ic][1];
zic = x[ic][2];
xid = x[id][0];
yid = x[id][1];
zid = x[id][2];
xie = x[ie][0];
yie = x[ie][1];
zie = x[ie][2];
xig = x[ig][0];
yig = x[ig][1];
zig = x[ig][2];
xad = xia - xid;
yad = yia - yid;
zad = zia - zid;
xbd = xib - xid;
ybd = yib - yid;
zbd = zib - zid;
xec = xie - xic;
yec = yie - yic;
zec = zie - zic;
xgc = xig - xic;
ygc = yig - yic;
zgc = zig - zic;
xip = yad*zbd - ybd*zad + xic;
yip = zad*xbd - zbd*xad + yic;
zip = xad*ybd - xbd*yad + zic;
xiq = yec*zgc - ygc*zec + xid;
yiq = zec*xgc - zgc*xec + yid;
ziq = xec*ygc - xgc*yec + zid;
xcp = xic - xip;
ycp = yic - yip;
zcp = zic - zip;
xdc = xid - xic;
ydc = yid - yic;
zdc = zid - zic;
xqd = xiq - xid;
yqd = yiq - yid;
zqd = ziq - zid;
xt = ycp*zdc - ydc*zcp;
yt = zcp*xdc - zdc*xcp;
zt = xcp*ydc - xdc*ycp;
xu = ydc*zqd - yqd*zdc;
yu = zdc*xqd - zqd*xdc;
zu = xdc*yqd - xqd*ydc;
xtu = yt*zu - yu*zt;
ytu = zt*xu - zu*xt;
ztu = xt*yu - xu*yt;
rt2 = xt*xt + yt*yt + zt*zt;
ru2 = xu*xu + yu*yu + zu*zu;
rtru = sqrt(rt2*ru2);
if (rtru <= 0.0) continue;
rdc = sqrt(xdc*xdc + ydc*ydc + zdc*zdc);
cosine = (xt*xu + yt*yu + zt*zu) / rtru;
sine = (xdc*xtu + ydc*ytu + zdc*ztu) / (rdc*rtru);
// set the pi-system torsion parameters for this angle
v2 = kpit[ptype];
c2 = -1.0;
s2 = 0.0;
// compute the multiple angle trigonometry and the phase terms
cosine2 = cosine*cosine - sine*sine;
sine2 = 2.0 * cosine * sine;
phi2 = 1.0 + (cosine2*c2 + sine2*s2);
dphi2 = 2.0 * (cosine2*s2 - sine2*c2);
// calculate pi-system torsion energy and master chain rule term
e = v2 * phi2;
dedphi = v2 * dphi2;
// fraction of energy for each atom
engfraction = e * onesixth;
// chain rule terms for first derivative components
xdp = xid - xip;
ydp = yid - yip;
zdp = zid - zip;
xqc = xiq - xic;
yqc = yiq - yic;
zqc = ziq - zic;
dedxt = dedphi * (yt*zdc - ydc*zt) / (rt2*rdc);
dedyt = dedphi * (zt*xdc - zdc*xt) / (rt2*rdc);
dedzt = dedphi * (xt*ydc - xdc*yt) / (rt2*rdc);
dedxu = -dedphi * (yu*zdc - ydc*zu) / (ru2*rdc);
dedyu = -dedphi * (zu*xdc - zdc*xu) / (ru2*rdc);
dedzu = -dedphi * (xu*ydc - xdc*yu) / (ru2*rdc);
// compute first derivative components for pi-system angle
dedxip = zdc*dedyt - ydc*dedzt;
dedyip = xdc*dedzt - zdc*dedxt;
dedzip = ydc*dedxt - xdc*dedyt;
dedxic = ydp*dedzt - zdp*dedyt + zqd*dedyu - yqd*dedzu;
dedyic = zdp*dedxt - xdp*dedzt + xqd*dedzu - zqd*dedxu;
dedzic = xdp*dedyt - ydp*dedxt + yqd*dedxu - xqd*dedyu;
dedxid = zcp*dedyt - ycp*dedzt + yqc*dedzu - zqc*dedyu;
dedyid = xcp*dedzt - zcp*dedxt + zqc*dedxu - xqc*dedzu;
dedzid = ycp*dedxt - xcp*dedyt + xqc*dedyu - yqc*dedxu;
dedxiq = zdc*dedyu - ydc*dedzu;
dedyiq = xdc*dedzu - zdc*dedxu;
dedziq = ydc*dedxu - xdc*dedyu;
// compute first derivative components for individual atoms
dedxia = ybd*dedzip - zbd*dedyip;
dedyia = zbd*dedxip - xbd*dedzip;
dedzia = xbd*dedyip - ybd*dedxip;
dedxib = zad*dedyip - yad*dedzip;
dedyib = xad*dedzip - zad*dedxip;
dedzib = yad*dedxip - xad*dedyip;
dedxie = ygc*dedziq - zgc*dedyiq;
dedyie = zgc*dedxiq - xgc*dedziq;
dedzie = xgc*dedyiq - ygc*dedxiq;
dedxig = zec*dedyiq - yec*dedziq;
dedyig = xec*dedziq - zec*dedxiq;
dedzig = yec*dedxiq - xec*dedyiq;
dedxic = dedxic + dedxip - dedxie - dedxig;
dedyic = dedyic + dedyip - dedyie - dedyig;
dedzic = dedzic + dedzip - dedzie - dedzig;
dedxid = dedxid + dedxiq - dedxia - dedxib;
dedyid = dedyid + dedyiq - dedyia - dedyib;
dedzid = dedzid + dedziq - dedzia - dedzib;
// forces and energy
if (ia < nlocal) {
epitorsion += engfraction;
f[ia][0] -= dedxia;
f[ia][1] -= dedyia;
f[ia][2] -= dedzia;
}
if (ib < nlocal) {
epitorsion += engfraction;
f[ib][0] -= dedxib;
f[ib][1] -= dedyib;
f[ib][2] -= dedzib;
}
if (ic < nlocal) {
epitorsion += engfraction;
f[ic][0] -= dedxic;
f[ic][1] -= dedyic;
f[ic][2] -= dedzic;
}
if (id < nlocal) {
epitorsion += engfraction;
f[id][0] -= dedxid;
f[id][1] -= dedyid;
f[id][2] -= dedzid;
}
if (ie < nlocal) {
epitorsion += engfraction;
f[ie][0] -= dedxie;
f[ie][1] -= dedyie;
f[ie][2] -= dedzie;
}
if (ig < nlocal) {
epitorsion += engfraction;
f[ig][0] -= dedxig;
f[ig][1] -= dedyig;
f[ig][2] -= dedzig;
}
// virial tensor components
if (evflag) {
nlist = 0;
if (ia < nlocal) list[nlist++] = ia;
if (ib < nlocal) list[nlist++] = ib;
if (ic < nlocal) list[nlist++] = ic;
if (id < nlocal) list[nlist++] = id;
if (ie < nlocal) list[nlist++] = ie;
if (ig < nlocal) list[nlist++] = ig;
vxterm = dedxid + dedxia + dedxib;
vyterm = dedyid + dedyia + dedyib;
vzterm = dedzid + dedzia + dedzib;
v[0] = -xdc*vxterm - xcp*dedxip + xqd*dedxiq;
v[1] = -ydc*vyterm - ycp*dedyip + yqd*dedyiq;
v[2] = -zdc*vzterm - zcp*dedzip + zqd*dedziq;
v[3] = -ydc*vxterm - ycp*dedxip + yqd*dedxiq;
v[4] = -zdc*vxterm - zcp*dedxip + zqd*dedxiq;
v[5] = -zdc*vyterm - zcp*dedyip + zqd*dedyiq;
ev_tally(nlist,list,6.0,e,v);
}
}
}
/* ---------------------------------------------------------------------- */
void FixAmoebaPiTorsion::post_force_respa(int vflag, int ilevel, int /*iloop*/)
{
if (ilevel == ilevel_respa) post_force(vflag);
}
/* ---------------------------------------------------------------------- */
void FixAmoebaPiTorsion::min_post_force(int vflag)
{
post_force(vflag);
}
/* ----------------------------------------------------------------------
energy of PiTorsion term
------------------------------------------------------------------------- */
double FixAmoebaPiTorsion::compute_scalar()
{
double all;
MPI_Allreduce(&epitorsion,&all,1,MPI_DOUBLE,MPI_SUM,world);
return all;
}
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// methods to read and write data file
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
void FixAmoebaPiTorsion::read_data_header(char *line)
{
if (strstr(line,"pitorsions")) {
sscanf(line,BIGINT_FORMAT,&npitorsions);
} else if (strstr(line,"pitorsion types")) {
sscanf(line,"%d",&npitorsion_types);
} else error->all(FLERR,
"Invalid read data header line for amoeba/fix pitorsion");
}
/* ----------------------------------------------------------------------
unpack N lines in buf from section of data file labeled by keyword
id_offset is applied to atomID fields if multiple data files are read
------------------------------------------------------------------------- */
void FixAmoebaPiTorsion::read_data_section(char *keyword, int n, char *buf, tagint id_offset)
{
int which = -1;
if (strstr(keyword,"PiTorsions")) {
sscanf(keyword,BIGINT_FORMAT,&npitorsions);
which = 0;
} else if (strstr(keyword,"PiTorsion Coeffs")) {
sscanf(keyword,"%d",&npitorsion_types);
which = 1;
} else error->all(FLERR,"Invalid read data section for fix amoeba/pitorsion");
// loop over lines of PiTorsion Coeffs
// tokenize the line into values
// initialize kpit vector
if (which == 1) {
int itype;
double value;
char *next;
memory->create(kpit,npitorsion_types+1,"pitorsion:kpit");
for (int i = 0; i < n; i++) {
next = strchr(buf,'\n');
*next = '\0';
sscanf(buf,"%d %lg",&itype,&value);
if (itype <= 0 || itype > npitorsion_types)
error->all(FLERR,"Incorrect args for fix amoeba/pitorsion coeffs");
kpit[itype] = value;
buf = next + 1;
}
}
// loop over lines of PiTorsions
// tokenize the line into values
// each atom in the PiTorsion stores it
if (which == 0) {
int m,tmp,itype;
tagint atom1,atom2,atom3,atom4,atom5,atom6;
char *next;
next = strchr(buf,'\n');
*next = '\0';
int nwords = utils::count_words(utils::trim_comment(buf));
*next = '\n';
if (nwords != 8)
error->all(FLERR,"Incorrect {} format in data file",keyword);
for (int i = 0; i < n; i++) {
next = strchr(buf,'\n');
*next = '\0';
sscanf(buf,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT
" " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT,
&tmp,&itype,&atom1,&atom2,&atom3,&atom4,&atom5,&atom6);
atom1 += id_offset;
atom2 += id_offset;
atom3 += id_offset;
atom4 += id_offset;
atom5 += id_offset;
atom6 += id_offset;
if ((m = atom->map(atom1)) >= 0) {
if (num_pitorsion[m] == PITORSIONMAX)
error->one(FLERR,"Too many PiTorsions for one atom");
pitorsion_type[m][num_pitorsion[m]] = itype;
pitorsion_atom1[m][num_pitorsion[m]] = atom1;
pitorsion_atom2[m][num_pitorsion[m]] = atom2;
pitorsion_atom3[m][num_pitorsion[m]] = atom3;
pitorsion_atom4[m][num_pitorsion[m]] = atom4;
pitorsion_atom5[m][num_pitorsion[m]] = atom5;
pitorsion_atom6[m][num_pitorsion[m]] = atom6;
num_pitorsion[m]++;
}
if ((m = atom->map(atom2)) >= 0) {
if (num_pitorsion[m] == PITORSIONMAX)
error->one(FLERR,"Too many PiTorsions for one atom");
pitorsion_type[m][num_pitorsion[m]] = itype;
pitorsion_atom1[m][num_pitorsion[m]] = atom1;
pitorsion_atom2[m][num_pitorsion[m]] = atom2;
pitorsion_atom3[m][num_pitorsion[m]] = atom3;
pitorsion_atom4[m][num_pitorsion[m]] = atom4;
pitorsion_atom5[m][num_pitorsion[m]] = atom5;
pitorsion_atom6[m][num_pitorsion[m]] = atom6;
num_pitorsion[m]++;
}
if ((m = atom->map(atom3)) >= 0) {
if (num_pitorsion[m] == PITORSIONMAX)
error->one(FLERR,"Too many PiTorsions for one atom");
pitorsion_type[m][num_pitorsion[m]] = itype;
pitorsion_atom1[m][num_pitorsion[m]] = atom1;
pitorsion_atom2[m][num_pitorsion[m]] = atom2;
pitorsion_atom3[m][num_pitorsion[m]] = atom3;
pitorsion_atom4[m][num_pitorsion[m]] = atom4;
pitorsion_atom5[m][num_pitorsion[m]] = atom5;
pitorsion_atom6[m][num_pitorsion[m]] = atom6;
num_pitorsion[m]++;
}
if ((m = atom->map(atom4)) >= 0) {
if (num_pitorsion[m] == PITORSIONMAX)
error->one(FLERR,"Too many PiTorsions for one atom");
pitorsion_type[m][num_pitorsion[m]] = itype;
pitorsion_atom1[m][num_pitorsion[m]] = atom1;
pitorsion_atom2[m][num_pitorsion[m]] = atom2;
pitorsion_atom3[m][num_pitorsion[m]] = atom3;
pitorsion_atom4[m][num_pitorsion[m]] = atom4;
pitorsion_atom5[m][num_pitorsion[m]] = atom5;
pitorsion_atom6[m][num_pitorsion[m]] = atom6;
num_pitorsion[m]++;
}
if ((m = atom->map(atom5)) >= 0) {
if (num_pitorsion[m] == PITORSIONMAX)
error->one(FLERR,"Too many PiTorsions for one atom");
pitorsion_type[m][num_pitorsion[m]] = itype;
pitorsion_atom1[m][num_pitorsion[m]] = atom1;
pitorsion_atom2[m][num_pitorsion[m]] = atom2;
pitorsion_atom3[m][num_pitorsion[m]] = atom3;
pitorsion_atom4[m][num_pitorsion[m]] = atom4;
pitorsion_atom5[m][num_pitorsion[m]] = atom5;
pitorsion_atom6[m][num_pitorsion[m]] = atom6;
num_pitorsion[m]++;
}
if ((m = atom->map(atom6)) >= 0) {
if (num_pitorsion[m] == PITORSIONMAX)
error->one(FLERR,"Too many PiTorsions for one atom");
pitorsion_type[m][num_pitorsion[m]] = itype;
pitorsion_atom1[m][num_pitorsion[m]] = atom1;
pitorsion_atom2[m][num_pitorsion[m]] = atom2;
pitorsion_atom3[m][num_pitorsion[m]] = atom3;
pitorsion_atom4[m][num_pitorsion[m]] = atom4;
pitorsion_atom5[m][num_pitorsion[m]] = atom5;
pitorsion_atom6[m][num_pitorsion[m]] = atom6;
num_pitorsion[m]++;
}
buf = next + 1;
}
}
}
/* ---------------------------------------------------------------------- */
bigint FixAmoebaPiTorsion::read_data_skip_lines(char *keyword)
{
if (strcmp(keyword,"PiTorsions") == 0) return npitorsions;
if (strcmp(keyword,"PiTorsion Coeffs") == 0) return (bigint) npitorsion_types;
return 0;
}
/* ----------------------------------------------------------------------
write Mth header line to file
only called by proc 0
------------------------------------------------------------------------- */
void FixAmoebaPiTorsion::write_data_header(FILE *fp, int mth)
{
if (mth == 0) fmt::print(fp,"{} pitorsions\n",npitorsions);
else if (mth == 1)
fmt::print(fp, "{} pitorsion types\n",npitorsion_types);
}
/* ----------------------------------------------------------------------
return size I own for Mth data section
# of data sections = 2 for this fix
------------------------------------------------------------------------- */
void FixAmoebaPiTorsion::write_data_section_size(int mth, int &nx, int &ny)
{
int i,m;
// PiTorsions section
// nx = # of PiTorsions owned by my local atoms
// only atom3 owns the PiTorsion in this context
// ny = 7 columns = type + 6 atom IDs
if (mth == 0) {
tagint *tag = atom->tag;
int nlocal = atom->nlocal;
nx = 0;
for (i = 0; i < nlocal; i++)
for (m = 0; m < num_pitorsion[i]; m++)
if (pitorsion_atom3[i][m] == tag[i]) nx++;
ny = 7;
// PiTorsion Coeffs section
// nx = # of PiTorsion types
// ny = 2 columns = PiTorsion type + value
// only proc 0 returns a non-zero nx
} else if (mth == 1) {
if (me == 0) nx = npitorsion_types;
else nx = 0;
ny = 2;
}
}
/* ----------------------------------------------------------------------
pack values for Mth data section into 2d buf
buf allocated by caller as owned PiTorsions by 7
------------------------------------------------------------------------- */
void FixAmoebaPiTorsion::write_data_section_pack(int mth, double **buf)
{
int i,m;
// PiTorsions section
// 1st column = PiTorsion type
// 2nd-7th columns = 6 atom IDs
if (mth == 0) {
tagint *tag = atom->tag;
int nlocal = atom->nlocal;
int n = 0;
for (i = 0; i < nlocal; i++) {
for (m = 0; m < num_pitorsion[i]; m++) {
if (pitorsion_atom3[i][m] != tag[i]) continue;
buf[n][0] = ubuf(pitorsion_type[i][m]).d;
buf[n][1] = ubuf(pitorsion_atom1[i][m]).d;
buf[n][2] = ubuf(pitorsion_atom2[i][m]).d;
buf[n][3] = ubuf(pitorsion_atom3[i][m]).d;
buf[n][4] = ubuf(pitorsion_atom4[i][m]).d;
buf[n][5] = ubuf(pitorsion_atom5[i][m]).d;
buf[n][6] = ubuf(pitorsion_atom6[i][m]).d;
n++;
}
}
// PiTorsion Coeffs section
// 1st column = pitorsion type
// 2nd column = value
// only proc 0 returns any data
} else if (mth == 1) {
if (me) return;
int n = 0;
for (i = 1; i <= npitorsion_types; i++) {
buf[n][0] = ubuf(i).d;
buf[n][1] = kpit[i];
n += 2;
}
}
}
/* ----------------------------------------------------------------------
write section keyword for Mth data section to file
use Molecules or Charges if that is only field, else use fix ID
only called by proc 0
------------------------------------------------------------------------- */
void FixAmoebaPiTorsion::write_data_section_keyword(int mth, FILE *fp)
{
if (mth == 0) fprintf(fp,"\nPiTorsions\n\n");
else if (mth == 1) fprintf(fp,"\nPiTorsion Coeffs\n\n");
}
/* ----------------------------------------------------------------------
write N lines from buf to file
convert buf fields to int or double depending on styles
index can be used to prepend global numbering
only called by proc 0
------------------------------------------------------------------------- */
void FixAmoebaPiTorsion::write_data_section(int mth, FILE *fp,
int n, double **buf, int index)
{
// PiTorsions section
if (mth == 0) {
for (int i = 0; i < n; i++)
fprintf(fp,"%d %d " TAGINT_FORMAT " " TAGINT_FORMAT
" " TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT
" " TAGINT_FORMAT "\n",
index+i,(int) ubuf(buf[i][0]).i,(tagint) ubuf(buf[i][1]).i,
(tagint) ubuf(buf[i][2]).i,(tagint) ubuf(buf[i][3]).i,
(tagint) ubuf(buf[i][4]).i,(tagint) ubuf(buf[i][5]).i,
(tagint) ubuf(buf[i][6]).i);
// PiTorsion Coeffs section
} else if (mth == 1) {
for (int i = 0; i < n; i++)
fprintf(fp,"%d %g\n",(int) ubuf(buf[i][0]).i,buf[i][1]);
}
}
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
// methods for restart and communication
// ----------------------------------------------------------------------
// ----------------------------------------------------------------------
/* ----------------------------------------------------------------------
pack entire state of Fix into one write
------------------------------------------------------------------------- */
void FixAmoebaPiTorsion::write_restart(FILE *fp)
{
if (comm->me == 0) {
int size = sizeof(bigint);
fwrite(&size,sizeof(int),1,fp);
fwrite(&npitorsions,sizeof(bigint),1,fp);
}
}
/* ----------------------------------------------------------------------
use state info from restart file to restart the Fix
------------------------------------------------------------------------- */
void FixAmoebaPiTorsion::restart(char *buf)
{
npitorsions = *((bigint *) buf);
}
/* ----------------------------------------------------------------------
pack values in local atom-based arrays for restart file
------------------------------------------------------------------------- */
int FixAmoebaPiTorsion::pack_restart(int i, double *buf)
{
int n = 1;
for (int m = 0; m < num_pitorsion[i]; m++) {
buf[n++] = ubuf(MAX(pitorsion_type[i][m],-pitorsion_type[i][m])).d;
buf[n++] = ubuf(pitorsion_atom1[i][m]).d;
buf[n++] = ubuf(pitorsion_atom2[i][m]).d;
buf[n++] = ubuf(pitorsion_atom3[i][m]).d;
buf[n++] = ubuf(pitorsion_atom4[i][m]).d;
buf[n++] = ubuf(pitorsion_atom5[i][m]).d;
buf[n++] = ubuf(pitorsion_atom6[i][m]).d;
}
buf[0] = n;
return n;
}
/* ----------------------------------------------------------------------
unpack values from atom->extra array to restart the fix
------------------------------------------------------------------------- */
void FixAmoebaPiTorsion::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 n = 0;
for (int i = 0; i < nth; i++) n += static_cast<int> (extra[nlocal][n]);
int count = static_cast<int> (extra[nlocal][n++]);
num_pitorsion[nlocal] = (count-1)/7;
for (int m = 0; m < num_pitorsion[nlocal]; m++) {
pitorsion_type[nlocal][m] = (int) ubuf(extra[nlocal][n++]).i;
pitorsion_atom1[nlocal][m] = (tagint) ubuf(extra[nlocal][n++]).i;
pitorsion_atom2[nlocal][m] = (tagint) ubuf(extra[nlocal][n++]).i;
pitorsion_atom3[nlocal][m] = (tagint) ubuf(extra[nlocal][n++]).i;
pitorsion_atom4[nlocal][m] = (tagint) ubuf(extra[nlocal][n++]).i;
pitorsion_atom5[nlocal][m] = (tagint) ubuf(extra[nlocal][n++]).i;
pitorsion_atom6[nlocal][m] = (tagint) ubuf(extra[nlocal][n++]).i;
}
}
/* ----------------------------------------------------------------------
maxsize of any atom's restart data
------------------------------------------------------------------------- */
int FixAmoebaPiTorsion::maxsize_restart()
{
return 1 + PITORSIONMAX*6;
}
/* ----------------------------------------------------------------------
size of atom nlocal's restart data
------------------------------------------------------------------------- */
int FixAmoebaPiTorsion::size_restart(int nlocal)
{
return 1 + num_pitorsion[nlocal]*7;
}
/* ----------------------------------------------------------------------
allocate atom-based arrays
------------------------------------------------------------------------- */
void FixAmoebaPiTorsion::grow_arrays(int nmax)
{
num_pitorsion = memory->grow(num_pitorsion,nmax,"pitorsion:num_pitorsion");
pitorsion_type = memory->grow(pitorsion_type,nmax,PITORSIONMAX,
"pitorsion:pitorsion_type");
pitorsion_atom1 = memory->grow(pitorsion_atom1,nmax,PITORSIONMAX,
"pitorsion:pitorsion_atom1");
pitorsion_atom2 = memory->grow(pitorsion_atom2,nmax,PITORSIONMAX,
"pitorsion:pitorsion_atom2");
pitorsion_atom3 = memory->grow(pitorsion_atom3,nmax,PITORSIONMAX,
"pitorsion:pitorsion_atom3");
pitorsion_atom4 = memory->grow(pitorsion_atom4,nmax,PITORSIONMAX,
"pitorsion:pitorsion_atom4");
pitorsion_atom5 = memory->grow(pitorsion_atom5,nmax,PITORSIONMAX,
"pitorsion:pitorsion_atom5");
pitorsion_atom6 = memory->grow(pitorsion_atom6,nmax,PITORSIONMAX,
"pitorsion:pitorsion_atom6");
// initialize num_pitorion to 0 for added atoms
// may never be set for some atoms when data file is read
for (int i = nmax_previous; i < nmax; i++) num_pitorsion[i] = 0;
nmax_previous = nmax;
}
/* ----------------------------------------------------------------------
copy values within local atom-based array
------------------------------------------------------------------------- */
void FixAmoebaPiTorsion::copy_arrays(int i, int j, int /*delflag*/)
{
num_pitorsion[j] = num_pitorsion[i];
for (int k = 0; k < num_pitorsion[j]; k++) {
pitorsion_type[j][k] = pitorsion_type[i][k];
pitorsion_atom1[j][k] = pitorsion_atom1[i][k];
pitorsion_atom2[j][k] = pitorsion_atom2[i][k];
pitorsion_atom3[j][k] = pitorsion_atom3[i][k];
pitorsion_atom4[j][k] = pitorsion_atom4[i][k];
pitorsion_atom5[j][k] = pitorsion_atom5[i][k];
pitorsion_atom6[j][k] = pitorsion_atom6[i][k];
}
}
/* ----------------------------------------------------------------------
initialize one atom's array values, called when atom is created
------------------------------------------------------------------------- */
void FixAmoebaPiTorsion::set_arrays(int i)
{
num_pitorsion[i] = 0;
}
/* ----------------------------------------------------------------------
pack values in local atom-based array for exchange with another proc
------------------------------------------------------------------------- */
int FixAmoebaPiTorsion::pack_exchange(int i, double *buf)
{
int n = 0;
buf[n++] = ubuf(num_pitorsion[i]).d;
for (int m = 0; m < num_pitorsion[i]; m++) {
buf[n++] = ubuf(pitorsion_type[i][m]).d;
buf[n++] = ubuf(pitorsion_atom1[i][m]).d;
buf[n++] = ubuf(pitorsion_atom2[i][m]).d;
buf[n++] = ubuf(pitorsion_atom3[i][m]).d;
buf[n++] = ubuf(pitorsion_atom4[i][m]).d;
buf[n++] = ubuf(pitorsion_atom5[i][m]).d;
buf[n++] = ubuf(pitorsion_atom6[i][m]).d;
}
return n;
}
/* ----------------------------------------------------------------------
unpack values in local atom-based array from exchange with another proc
------------------------------------------------------------------------- */
int FixAmoebaPiTorsion::unpack_exchange(int nlocal, double *buf)
{
int n = 0;
num_pitorsion[nlocal] = (int) ubuf(buf[n++]).i;
for (int m = 0; m < num_pitorsion[nlocal]; m++) {
pitorsion_type[nlocal][m] = (int) ubuf(buf[n++]).i;
pitorsion_atom1[nlocal][m] = (tagint) ubuf(buf[n++]).i;
pitorsion_atom2[nlocal][m] = (tagint) ubuf(buf[n++]).i;
pitorsion_atom3[nlocal][m] = (tagint) ubuf(buf[n++]).i;
pitorsion_atom4[nlocal][m] = (tagint) ubuf(buf[n++]).i;
pitorsion_atom5[nlocal][m] = (tagint) ubuf(buf[n++]).i;
pitorsion_atom6[nlocal][m] = (tagint) ubuf(buf[n++]).i;
}
return n;
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixAmoebaPiTorsion::memory_usage()
{
int nmax = atom->nmax;
double bytes = (double)nmax * sizeof(int); // num_pitorsion
bytes += (double)nmax*PITORSIONMAX * sizeof(int); // pitorsion_type
bytes += (double)6*nmax*PITORSIONMAX * sizeof(int); // pitorsion_atom 123456
bytes += (double)7*max_pitorsion_list * sizeof(int); // pitorsion_list
return bytes;
}