803 lines
25 KiB
C++
803 lines
25 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 "pair_hybrid_scaled.h"
|
|
|
|
#include "atom.h"
|
|
#include "atom_vec.h"
|
|
#include "comm.h"
|
|
#include "error.h"
|
|
#include "force.h"
|
|
#include "input.h"
|
|
#include "memory.h"
|
|
#include "respa.h"
|
|
#include "suffix.h"
|
|
#include "update.h"
|
|
#include "variable.h"
|
|
|
|
#include <cstring>
|
|
|
|
using namespace LAMMPS_NS;
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
PairHybridScaled::PairHybridScaled(LAMMPS *lmp) :
|
|
PairHybrid(lmp), fsum(nullptr), tsum(nullptr), scaleval(nullptr), scaleidx(nullptr),
|
|
atomvar(nullptr), atomscale(nullptr)
|
|
{
|
|
nmaxfsum = -1;
|
|
|
|
// set comm size needed by this Pair (if atomscaleflag)
|
|
|
|
comm_forward = 1;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
PairHybridScaled::~PairHybridScaled()
|
|
{
|
|
memory->destroy(fsum);
|
|
memory->destroy(tsum);
|
|
delete[] scaleval;
|
|
delete[] scaleidx;
|
|
delete[] atomvar;
|
|
memory->destroy(atomscale);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
call each sub-style's compute() or compute_outer() function
|
|
accumulate sub-style global/peratom energy/virial in hybrid
|
|
for global vflag = VIRIAL_PAIR:
|
|
each sub-style computes own virial[6]
|
|
sum sub-style virial[6] to hybrid's virial[6]
|
|
for global vflag = VIRIAL_FDOTR:
|
|
call sub-style with adjusted vflag to prevent it calling
|
|
virial_fdotr_compute()
|
|
hybrid calls virial_fdotr_compute() on final accumulated f
|
|
------------------------------------------------------------------------- */
|
|
|
|
void PairHybridScaled::compute(int eflag, int vflag)
|
|
{
|
|
int i, j, m, n;
|
|
|
|
// update scale values from variables where needed
|
|
|
|
const int nvars = scalevars.size();
|
|
int atomscaleflag = 0;
|
|
if (nvars > 0) {
|
|
auto vals = new double[nvars];
|
|
auto vars = new int[nvars];
|
|
for (int k = 0; k < nvars; ++k) {
|
|
int m = input->variable->find(scalevars[k].c_str());
|
|
if (m < 0)
|
|
error->all(FLERR, "Variable '{}' not found when updating scale factors", scalevars[k]);
|
|
|
|
// for equal-style, compute variable, set variable index to -1
|
|
if (input->variable->equalstyle(m)) {
|
|
vals[k] = input->variable->compute_equal(m);
|
|
vars[k] = -1;
|
|
// for atom-style, store variable index, set variable to 0.0, set atomscaleflag
|
|
} else if (input->variable->atomstyle(m)) {
|
|
vals[k] = 0.0;
|
|
vars[k] = m;
|
|
atomscaleflag = 1;
|
|
} else
|
|
error->all(FLERR, "Variable '{}' has incompatible style", scalevars[k]);
|
|
}
|
|
for (int k = 0; k < nstyles; ++k) {
|
|
if (scaleidx[k] >= 0) {
|
|
scaleval[k] = vals[scaleidx[k]];
|
|
atomvar[k] = vars[scaleidx[k]];
|
|
}
|
|
}
|
|
delete[] vals;
|
|
delete[] vars;
|
|
}
|
|
|
|
// check if no_virial_fdotr_compute is set and global component of
|
|
// incoming vflag = VIRIAL_FDOTR
|
|
// if so, reset vflag as if global component were VIRIAL_PAIR
|
|
// necessary since one or more sub-styles cannot compute virial as F dot r
|
|
|
|
if (no_virial_fdotr_compute && (vflag & VIRIAL_FDOTR))
|
|
vflag = VIRIAL_PAIR | (vflag & ~VIRIAL_FDOTR);
|
|
|
|
ev_init(eflag, vflag);
|
|
|
|
// grow fsum array if needed, and copy existing forces (usually 0.0) to it.
|
|
|
|
if (atom->nmax > nmaxfsum) {
|
|
memory->destroy(fsum);
|
|
if (atom->torque_flag) memory->destroy(tsum);
|
|
if (atomscaleflag) memory->destroy(atomscale);
|
|
nmaxfsum = atom->nmax;
|
|
memory->create(fsum, nmaxfsum, 3, "pair:fsum");
|
|
if (atom->torque_flag) memory->create(tsum, nmaxfsum, 3, "pair:tsum");
|
|
if (atomscaleflag) memory->create(atomscale, nmaxfsum, "pair:atomscale");
|
|
}
|
|
const int nall = atom->nlocal + atom->nghost;
|
|
auto f = atom->f;
|
|
auto t = atom->torque;
|
|
for (i = 0; i < nall; ++i) {
|
|
fsum[i][0] = f[i][0];
|
|
fsum[i][1] = f[i][1];
|
|
fsum[i][2] = f[i][2];
|
|
if (atom->torque_flag) {
|
|
tsum[i][0] = t[i][0];
|
|
tsum[i][1] = t[i][1];
|
|
tsum[i][2] = t[i][2];
|
|
}
|
|
}
|
|
|
|
// check if global component of incoming vflag = VIRIAL_FDOTR
|
|
// if so, reset vflag passed to substyle so VIRIAL_FDOTR is turned off
|
|
// necessary so substyle will not invoke virial_fdotr_compute()
|
|
|
|
int vflag_substyle;
|
|
if (vflag & VIRIAL_FDOTR)
|
|
vflag_substyle = vflag & ~VIRIAL_FDOTR;
|
|
else
|
|
vflag_substyle = vflag;
|
|
|
|
double *saved_special = save_special();
|
|
|
|
// check if we are running with r-RESPA using the hybrid keyword
|
|
|
|
Respa *respa = nullptr;
|
|
respaflag = 0;
|
|
if (utils::strmatch(update->integrate_style, "^respa")) {
|
|
respa = dynamic_cast<Respa *>(update->integrate);
|
|
if (respa->nhybrid_styles > 0) respaflag = 1;
|
|
}
|
|
|
|
for (m = 0; m < nstyles; m++) {
|
|
|
|
// clear forces and torques
|
|
|
|
memset(&f[0][0], 0, nall * 3 * sizeof(double));
|
|
if (atom->torque_flag) memset(&t[0][0], 0, nall * 3 * sizeof(double));
|
|
|
|
set_special(m);
|
|
|
|
if (!respaflag || (respaflag && respa->hybrid_compute[m])) {
|
|
|
|
// invoke compute() unless compute flag is turned off or
|
|
// outerflag is set and sub-style has a compute_outer() method
|
|
|
|
if (styles[m]->compute_flag == 0) continue;
|
|
if (outerflag && styles[m]->respa_enable)
|
|
styles[m]->compute_outer(eflag, vflag_substyle);
|
|
else
|
|
styles[m]->compute(eflag, vflag_substyle);
|
|
}
|
|
|
|
// add scaled forces to global sum
|
|
const double scale = scaleval[m];
|
|
|
|
// if scale factor is constant or equal-style variable
|
|
if (scaleidx[m] < 0 || atomvar[m] < 0) {
|
|
for (i = 0; i < nall; ++i) {
|
|
fsum[i][0] += scale * f[i][0];
|
|
fsum[i][1] += scale * f[i][1];
|
|
fsum[i][2] += scale * f[i][2];
|
|
if (atom->torque_flag) {
|
|
tsum[i][0] += scale * t[i][0];
|
|
tsum[i][1] += scale * t[i][1];
|
|
tsum[i][2] += scale * t[i][2];
|
|
}
|
|
}
|
|
// if scale factor is atom-style variable
|
|
} else {
|
|
const int igroupall = 0;
|
|
input->variable->compute_atom(atomvar[m], igroupall, atomscale, 1, 0);
|
|
comm->forward_comm(this);
|
|
for (i = 0; i < nall; ++i) {
|
|
const double ascale = atomscale[i];
|
|
fsum[i][0] += ascale * f[i][0];
|
|
fsum[i][1] += ascale * f[i][1];
|
|
fsum[i][2] += ascale * f[i][2];
|
|
if (atom->torque_flag) {
|
|
tsum[i][0] += ascale * t[i][0];
|
|
tsum[i][1] += ascale * t[i][1];
|
|
tsum[i][2] += ascale * t[i][2];
|
|
}
|
|
}
|
|
}
|
|
|
|
restore_special(saved_special);
|
|
|
|
// jump to next sub-style if r-RESPA does not want global accumulated data
|
|
|
|
if (respaflag && !respa->tally_global) continue;
|
|
|
|
if (eflag_global) {
|
|
eng_vdwl += scale * styles[m]->eng_vdwl;
|
|
eng_coul += scale * styles[m]->eng_coul;
|
|
}
|
|
if (vflag_global) {
|
|
for (n = 0; n < 6; n++) virial[n] += scale * styles[m]->virial[n];
|
|
}
|
|
if (eflag_atom) {
|
|
n = atom->nlocal;
|
|
if (force->newton_pair) n += atom->nghost;
|
|
double *eatom_substyle = styles[m]->eatom;
|
|
for (i = 0; i < n; i++) eatom[i] += scale * eatom_substyle[i];
|
|
}
|
|
if (vflag_atom) {
|
|
n = atom->nlocal;
|
|
if (force->newton_pair) n += atom->nghost;
|
|
double **vatom_substyle = styles[m]->vatom;
|
|
for (i = 0; i < n; i++)
|
|
for (j = 0; j < 6; j++) vatom[i][j] += scale * vatom_substyle[i][j];
|
|
}
|
|
|
|
// substyles may be CENTROID_SAME or CENTROID_AVAIL
|
|
|
|
if (cvflag_atom) {
|
|
n = atom->nlocal;
|
|
if (force->newton_pair) n += atom->nghost;
|
|
if (styles[m]->centroidstressflag == CENTROID_AVAIL) {
|
|
double **cvatom_substyle = styles[m]->cvatom;
|
|
for (i = 0; i < n; i++)
|
|
for (j = 0; j < 9; j++) cvatom[i][j] += scale * cvatom_substyle[i][j];
|
|
} else {
|
|
double **vatom_substyle = styles[m]->vatom;
|
|
for (i = 0; i < n; i++) {
|
|
for (j = 0; j < 6; j++) { cvatom[i][j] += scale * vatom_substyle[i][j]; }
|
|
for (j = 6; j < 9; j++) { cvatom[i][j] += scale * vatom_substyle[i][j - 3]; }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// copy accumulated scaled forces to original force array
|
|
|
|
for (i = 0; i < nall; ++i) {
|
|
f[i][0] = fsum[i][0];
|
|
f[i][1] = fsum[i][1];
|
|
f[i][2] = fsum[i][2];
|
|
if (atom->torque_flag) {
|
|
t[i][0] = tsum[i][0];
|
|
t[i][1] = tsum[i][1];
|
|
t[i][2] = tsum[i][2];
|
|
}
|
|
}
|
|
delete[] saved_special;
|
|
|
|
if (vflag_fdotr) virial_fdotr_compute();
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
create one pair style for each arg in list
|
|
------------------------------------------------------------------------- */
|
|
|
|
void PairHybridScaled::settings(int narg, char **arg)
|
|
{
|
|
if (narg < 1) error->all(FLERR, "Illegal pair_style command");
|
|
if (lmp->kokkos && !utils::strmatch(force->pair_style, "^hybrid.*/kk$"))
|
|
error->all(FLERR, "Must use pair_style {}/kk with Kokkos", force->pair_style);
|
|
|
|
if (atom->avec->forceclearflag)
|
|
error->all(FLERR, "Atom style is not compatible with pair_style hybrid/scaled");
|
|
|
|
// delete old lists, since cannot just change settings
|
|
|
|
if (nstyles > 0) {
|
|
for (int m = 0; m < nstyles; m++) {
|
|
delete styles[m];
|
|
delete[] keywords[m];
|
|
delete[] special_lj[m];
|
|
delete[] special_coul[m];
|
|
}
|
|
delete[] styles;
|
|
delete[] cutmax_style;
|
|
delete[] keywords;
|
|
delete[] multiple;
|
|
delete[] special_lj;
|
|
delete[] special_coul;
|
|
delete[] compute_tally;
|
|
delete[] scaleval;
|
|
delete[] scaleidx;
|
|
delete[] atomvar;
|
|
scalevars.clear();
|
|
}
|
|
|
|
if (allocated) {
|
|
memory->destroy(setflag);
|
|
memory->destroy(cutsq);
|
|
memory->destroy(cutghost);
|
|
memory->destroy(nmap);
|
|
memory->destroy(map);
|
|
}
|
|
allocated = 0;
|
|
|
|
// allocate list of sub-styles as big as possibly needed if no extra args
|
|
|
|
styles = new Pair *[narg];
|
|
cutmax_style = new double[narg];
|
|
memset(cutmax_style, 0.0, narg * sizeof(double));
|
|
keywords = new char *[narg];
|
|
multiple = new int[narg];
|
|
|
|
special_lj = new double *[narg];
|
|
special_coul = new double *[narg];
|
|
compute_tally = new int[narg];
|
|
|
|
scaleval = new double[narg];
|
|
scaleidx = new int[narg];
|
|
atomvar = new int[narg];
|
|
scalevars.reserve(narg);
|
|
|
|
// allocate each sub-style
|
|
// allocate uses suffix, but don't store suffix version in keywords,
|
|
// else syntax in coeff() will not match
|
|
// call settings() with set of args that are not pair style names
|
|
// use force->pair_map to determine which args these are
|
|
|
|
int iarg, jarg, dummy;
|
|
|
|
iarg = 0;
|
|
nstyles = 0;
|
|
while (iarg < narg - 1) {
|
|
|
|
// first process scale factor or variable
|
|
// scaleidx[k] < 0 indicates constant value, otherwise index in variable name list
|
|
// initialize atomvar[k] to -1, indicates not atom-style variable
|
|
|
|
double val = 0.0;
|
|
int idx = -1;
|
|
if (utils::strmatch(arg[iarg], "^v_")) {
|
|
for (std::size_t i = 0; i < scalevars.size(); ++i) {
|
|
if (scalevars[i] == arg[iarg] + 2) {
|
|
idx = i;
|
|
break;
|
|
}
|
|
}
|
|
if (idx < 0) {
|
|
idx = scalevars.size();
|
|
scalevars.emplace_back(arg[iarg] + 2);
|
|
}
|
|
} else {
|
|
val = utils::numeric(FLERR, arg[iarg], false, lmp);
|
|
}
|
|
scaleval[nstyles] = val;
|
|
scaleidx[nstyles] = idx;
|
|
atomvar[nstyles] = -1;
|
|
++iarg;
|
|
|
|
if (utils::strmatch(arg[iarg], "^hybrid"))
|
|
error->all(FLERR, "Pair style hybrid/scaled cannot have hybrid as an argument");
|
|
if (strcmp(arg[iarg], "none") == 0)
|
|
error->all(FLERR, "Pair style hybrid/scaled cannot have none as an argument");
|
|
|
|
styles[nstyles] = force->new_pair(arg[iarg], 1, dummy);
|
|
keywords[nstyles] = force->store_style(arg[iarg], 0);
|
|
special_lj[nstyles] = special_coul[nstyles] = nullptr;
|
|
compute_tally[nstyles] = 1;
|
|
|
|
if ((styles[nstyles]->suffix_flag & (Suffix::INTEL | Suffix::GPU | Suffix::OMP)) != 0)
|
|
error->all(FLERR,
|
|
"Pair style hybrid/scaled does not support "
|
|
"accelerator styles");
|
|
|
|
// determine list of arguments for pair style settings
|
|
// by looking for the next known pair style name.
|
|
|
|
jarg = iarg + 1;
|
|
while ((jarg < narg) && !force->pair_map->count(arg[jarg]) &&
|
|
!lmp->match_style("pair", arg[jarg]))
|
|
jarg++;
|
|
|
|
// decrement to account for scale factor except when last argument
|
|
|
|
if (jarg < narg) --jarg;
|
|
|
|
styles[nstyles]->settings(jarg - iarg - 1, arg + iarg + 1);
|
|
iarg = jarg;
|
|
nstyles++;
|
|
}
|
|
|
|
// multiple[i] = 1 to M if sub-style used multiple times, else 0
|
|
|
|
for (int i = 0; i < nstyles; i++) {
|
|
int count = 0;
|
|
for (int j = 0; j < nstyles; j++) {
|
|
if (strcmp(keywords[j], keywords[i]) == 0) count++;
|
|
if (j == i) multiple[i] = count;
|
|
}
|
|
if (count == 1) multiple[i] = 0;
|
|
}
|
|
|
|
// set pair flags from sub-style flags
|
|
|
|
flags();
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
call sub-style to compute single interaction
|
|
error if sub-style does not support single() call
|
|
since overlay could have multiple sub-styles, sum results explicitly
|
|
------------------------------------------------------------------------- */
|
|
|
|
double PairHybridScaled::single(int i, int j, int itype, int jtype, double rsq, double factor_coul,
|
|
double factor_lj, double &fforce)
|
|
{
|
|
if (nmap[itype][jtype] == 0) error->one(FLERR, "Invoked pair single on pair style none");
|
|
|
|
// update scale values from variables where needed
|
|
|
|
const int nvars = scalevars.size();
|
|
if (nvars > 0) {
|
|
auto vals = new double[nvars];
|
|
auto vars = new int[nvars];
|
|
for (int k = 0; k < nvars; ++k) {
|
|
int m = input->variable->find(scalevars[k].c_str());
|
|
if (m < 0)
|
|
error->all(FLERR, "Variable '{}' not found when updating scale factors", scalevars[k]);
|
|
|
|
// for equal-style, compute variable, set variable index to -1
|
|
if (input->variable->equalstyle(m)) {
|
|
vals[k] = input->variable->compute_equal(m);
|
|
vars[k] = -1;
|
|
// for atom-style, store variable index, set variable to 0.0, set atomscaleflag
|
|
} else if (input->variable->atomstyle(m)) {
|
|
vals[k] = 0.0;
|
|
vars[k] = m;
|
|
} else
|
|
error->all(FLERR, "Variable '{}' has incompatible style", scalevars[k]);
|
|
}
|
|
for (int k = 0; k < nstyles; ++k) {
|
|
if (scaleidx[k] >= 0) {
|
|
scaleval[k] = vals[scaleidx[k]];
|
|
atomvar[k] = vars[scaleidx[k]];
|
|
}
|
|
}
|
|
delete[] vals;
|
|
delete[] vars;
|
|
}
|
|
|
|
double fone;
|
|
fforce = 0.0;
|
|
double esum = 0.0;
|
|
|
|
for (int m = 0; m < nmap[itype][jtype]; m++) {
|
|
auto pstyle = styles[map[itype][jtype][m]];
|
|
if (rsq < pstyle->cutsq[itype][jtype]) {
|
|
if (pstyle->single_enable == 0)
|
|
error->one(FLERR, "Pair hybrid sub-style does not support single call");
|
|
|
|
if ((special_lj[map[itype][jtype][m]] != nullptr) ||
|
|
(special_coul[map[itype][jtype][m]] != nullptr))
|
|
error->one(FLERR, "Pair hybrid single() does not support per sub-style special_bond");
|
|
|
|
double scale = scaleval[map[itype][jtype][m]];
|
|
esum += scale * pstyle->single(i, j, itype, jtype, rsq, factor_coul, factor_lj, fone);
|
|
|
|
// if scale factor is constant or equal-style variable
|
|
if (scaleidx[m] < 0 || atomvar[m] < 0) {
|
|
fforce += scale * fone;
|
|
// if scale factor is atom-style variable, average i and j
|
|
} else {
|
|
const int igroupall = 0;
|
|
input->variable->compute_atom(atomvar[m], igroupall, atomscale, 1, 0);
|
|
comm->forward_comm(this);
|
|
const double ascale = 0.5 * (atomscale[i] + atomscale[j]);
|
|
fforce += ascale * fone;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (single_extra) copy_svector(itype, jtype);
|
|
return esum;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
call sub-style to compute born matrix interaction
|
|
error if sub-style does not support born_matrix call
|
|
since overlay could have multiple sub-styles, sum results explicitly
|
|
------------------------------------------------------------------------- */
|
|
|
|
void PairHybridScaled::born_matrix(int i, int j, int itype, int jtype, double rsq,
|
|
double factor_coul, double factor_lj, double &dupair,
|
|
double &du2pair)
|
|
{
|
|
if (nmap[itype][jtype] == 0) error->one(FLERR, "Invoked pair born_matrix on pair style none");
|
|
|
|
// update scale values from variables where needed
|
|
|
|
const int nvars = scalevars.size();
|
|
if (nvars > 0) {
|
|
auto vals = new double[nvars];
|
|
auto vars = new int[nvars];
|
|
for (int k = 0; k < nvars; ++k) {
|
|
int m = input->variable->find(scalevars[k].c_str());
|
|
if (m < 0)
|
|
error->all(FLERR, "Variable '{}' not found when updating scale factors", scalevars[k]);
|
|
|
|
// for equal-style, compute variable, set variable index to -1
|
|
if (input->variable->equalstyle(m)) {
|
|
vals[k] = input->variable->compute_equal(m);
|
|
vars[k] = -1;
|
|
// for atom-style, store variable index, set variable to 0.0, set atomscaleflag
|
|
} else if (input->variable->atomstyle(m)) {
|
|
vals[k] = 0.0;
|
|
vars[k] = m;
|
|
} else
|
|
error->all(FLERR, "Variable '{}' has incompatible style", scalevars[k]);
|
|
}
|
|
for (int k = 0; k < nstyles; ++k) {
|
|
if (scaleidx[k] >= 0) {
|
|
scaleval[k] = vals[scaleidx[k]];
|
|
atomvar[k] = vars[scaleidx[k]];
|
|
}
|
|
}
|
|
delete[] vals;
|
|
delete[] vars;
|
|
}
|
|
|
|
double du, du2;
|
|
dupair = du2pair = 0.0;
|
|
|
|
for (int m = 0; m < nmap[itype][jtype]; m++) {
|
|
auto pstyle = styles[map[itype][jtype][m]];
|
|
if (rsq < pstyle->cutsq[itype][jtype]) {
|
|
if (pstyle->single_enable == 0)
|
|
error->one(FLERR, "Pair hybrid sub-style does not support single call");
|
|
|
|
if ((special_lj[map[itype][jtype][m]] != nullptr) ||
|
|
(special_coul[map[itype][jtype][m]] != nullptr))
|
|
error->one(FLERR, "Pair hybrid single() does not support per sub-style special_bond");
|
|
|
|
du = du2 = 0.0;
|
|
double scale = scaleval[map[itype][jtype][m]];
|
|
pstyle->born_matrix(i, j, itype, jtype, rsq, factor_coul, factor_lj, du, du2);
|
|
|
|
// if scale factor is constant or equal-style variable
|
|
if (scaleidx[m] < 0 || atomvar[m] < 0) {
|
|
dupair += scale * du;
|
|
du2pair += scale * du2;
|
|
// if scale factor is atom-style variable, average i and j
|
|
} else {
|
|
const int igroupall = 0;
|
|
input->variable->compute_atom(atomvar[m], igroupall, atomscale, 1, 0);
|
|
comm->forward_comm(this);
|
|
const double ascale = 0.5 * (atomscale[i] + atomscale[j]);
|
|
dupair += ascale * du;
|
|
du2pair += ascale * du2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
set coeffs for one or more type pairs
|
|
------------------------------------------------------------------------- */
|
|
|
|
void PairHybridScaled::coeff(int narg, char **arg)
|
|
{
|
|
if (narg < 3) error->all(FLERR, "Incorrect args for pair coefficients" + utils::errorurl(21));
|
|
if (!allocated) allocate();
|
|
|
|
int ilo, ihi, jlo, jhi;
|
|
utils::bounds(FLERR, arg[0], 1, atom->ntypes, ilo, ihi, error);
|
|
utils::bounds(FLERR, arg[1], 1, atom->ntypes, jlo, jhi, error);
|
|
|
|
// 3rd arg = pair sub-style name
|
|
// 4th arg = pair sub-style index if name used multiple times
|
|
// allow for "none" as valid sub-style name
|
|
|
|
int multflag = 0;
|
|
int m;
|
|
|
|
for (m = 0; m < nstyles; m++) {
|
|
multflag = 0;
|
|
if (strcmp(arg[2], keywords[m]) == 0) {
|
|
if (multiple[m]) {
|
|
multflag = 1;
|
|
if (narg < 4) error->all(FLERR, "Incorrect args for pair coefficients" + utils::errorurl(21));
|
|
int index = utils::inumeric(FLERR, arg[3], false, lmp);
|
|
if (index == multiple[m])
|
|
break;
|
|
else
|
|
continue;
|
|
} else
|
|
break;
|
|
}
|
|
}
|
|
|
|
int none = 0;
|
|
if (m == nstyles) {
|
|
if (strcmp(arg[2], "none") == 0)
|
|
none = 1;
|
|
else
|
|
error->all(FLERR, "Expected hybrid sub-style instead of {} in pair_coeff command", arg[2]);
|
|
}
|
|
|
|
// move 1st/2nd args to 2nd/3rd args
|
|
// if multflag: move 1st/2nd args to 3rd/4th args
|
|
// just copy ptrs, since arg[] points into original input line
|
|
|
|
arg[2 + multflag] = arg[1];
|
|
arg[1 + multflag] = arg[0];
|
|
|
|
// ensure that one_coeff flag is honored
|
|
|
|
if (!none && styles[m]->one_coeff)
|
|
if ((strcmp(arg[0], "*") != 0) || (strcmp(arg[1], "*") != 0))
|
|
error->all(FLERR, "Incorrect args for pair coefficients" + utils::errorurl(21));
|
|
|
|
// invoke sub-style coeff() starting with 1st remaining arg
|
|
|
|
if (!none) styles[m]->coeff(narg - 1 - multflag, &arg[1 + multflag]);
|
|
|
|
// set setflag and which type pairs map to which sub-style
|
|
// if sub-style is none: set hybrid subflag, wipe out map
|
|
// else: set hybrid setflag & map only if substyle setflag is set
|
|
// if sub-style is new for type pair, add as multiple mapping
|
|
// if sub-style exists for type pair, don't add, just update coeffs
|
|
|
|
int count = 0;
|
|
for (int i = ilo; i <= ihi; i++) {
|
|
for (int j = MAX(jlo, i); j <= jhi; j++) {
|
|
if (none) {
|
|
setflag[i][j] = 1;
|
|
nmap[i][j] = 0;
|
|
count++;
|
|
} else if (styles[m]->setflag[i][j]) {
|
|
int k;
|
|
for (k = 0; k < nmap[i][j]; k++)
|
|
if (map[i][j][k] == m) break;
|
|
if (k == nmap[i][j]) map[i][j][nmap[i][j]++] = m;
|
|
setflag[i][j] = 1;
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (count == 0) error->all(FLERR, "Incorrect args for pair coefficients" + utils::errorurl(21));
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
proc 0 writes to restart file
|
|
------------------------------------------------------------------------- */
|
|
|
|
void PairHybridScaled::write_restart(FILE *fp)
|
|
{
|
|
PairHybrid::write_restart(fp);
|
|
|
|
fwrite(scaleval, sizeof(double), nstyles, fp);
|
|
fwrite(scaleidx, sizeof(int), nstyles, fp);
|
|
fwrite(atomvar, sizeof(int), nstyles, fp);
|
|
|
|
int n = scalevars.size();
|
|
fwrite(&n, sizeof(int), 1, fp);
|
|
for (auto &var : scalevars) {
|
|
n = var.size() + 1;
|
|
fwrite(&n, sizeof(int), 1, fp);
|
|
fwrite(var.c_str(), sizeof(char), n, fp);
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
proc 0 reads from restart file, bcasts
|
|
------------------------------------------------------------------------- */
|
|
|
|
void PairHybridScaled::read_restart(FILE *fp)
|
|
{
|
|
PairHybrid::read_restart(fp);
|
|
|
|
delete[] scaleval;
|
|
delete[] scaleidx;
|
|
delete[] atomvar;
|
|
scalevars.clear();
|
|
scaleval = new double[nstyles];
|
|
scaleidx = new int[nstyles];
|
|
atomvar = new int[nstyles];
|
|
|
|
int n, me = comm->me;
|
|
if (me == 0) {
|
|
utils::sfread(FLERR, scaleval, sizeof(double), nstyles, fp, nullptr, error);
|
|
utils::sfread(FLERR, scaleidx, sizeof(int), nstyles, fp, nullptr, error);
|
|
utils::sfread(FLERR, atomvar, sizeof(int), nstyles, fp, nullptr, error);
|
|
}
|
|
MPI_Bcast(scaleval, nstyles, MPI_DOUBLE, 0, world);
|
|
MPI_Bcast(scaleidx, nstyles, MPI_INT, 0, world);
|
|
MPI_Bcast(atomvar, nstyles, MPI_INT, 0, world);
|
|
|
|
char *tmp;
|
|
if (me == 0) utils::sfread(FLERR, &n, sizeof(int), 1, fp, nullptr, error);
|
|
MPI_Bcast(&n, 1, MPI_INT, 0, world);
|
|
scalevars.resize(n);
|
|
for (auto &scale : scalevars) {
|
|
if (me == 0) utils::sfread(FLERR, &n, sizeof(int), 1, fp, nullptr, error);
|
|
MPI_Bcast(&n, 1, MPI_INT, 0, world);
|
|
tmp = new char[n];
|
|
if (me == 0) utils::sfread(FLERR, tmp, sizeof(char), n, fp, nullptr, error);
|
|
MPI_Bcast(tmp, n, MPI_CHAR, 0, world);
|
|
scale = tmp;
|
|
delete[] tmp;
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
we need to handle Pair::svector special for hybrid/scaled
|
|
------------------------------------------------------------------------- */
|
|
|
|
void PairHybridScaled::init_svector()
|
|
{
|
|
// single_extra = list all sub-style single_extra
|
|
// allocate svector
|
|
|
|
single_extra = 0;
|
|
for (int m = 0; m < nstyles; m++) single_extra += styles[m]->single_extra;
|
|
|
|
if (single_extra) {
|
|
delete[] svector;
|
|
svector = new double[single_extra];
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
we need to handle Pair::svector special for hybrid/scaled
|
|
------------------------------------------------------------------------- */
|
|
|
|
void PairHybridScaled::copy_svector(int itype, int jtype)
|
|
{
|
|
int n = 0;
|
|
Pair *this_style = nullptr;
|
|
|
|
// fill svector array.
|
|
// copy data from active styles and use 0.0 for inactive ones
|
|
for (int m = 0; m < nstyles; m++) {
|
|
for (int k = 0; k < nmap[itype][jtype]; ++k) {
|
|
if (m == map[itype][jtype][k]) {
|
|
this_style = styles[m];
|
|
} else {
|
|
this_style = nullptr;
|
|
}
|
|
}
|
|
for (int l = 0; l < styles[m]->single_extra; ++l) {
|
|
if (this_style) {
|
|
svector[n++] = this_style->svector[l];
|
|
} else {
|
|
svector[n++] = 0.0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
int PairHybridScaled::pack_forward_comm(int n, int *list, double *buf, int /*pbc_flag*/, int * /*pbc*/)
|
|
{
|
|
int i,j,m;
|
|
|
|
m = 0;
|
|
for (i = 0; i < n; i++) {
|
|
j = list[i];
|
|
buf[m++] = atomscale[j];
|
|
}
|
|
return m;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------- */
|
|
|
|
void PairHybridScaled::unpack_forward_comm(int n, int first, double *buf)
|
|
{
|
|
int i,m,last;
|
|
|
|
m = 0;
|
|
last = first + n;
|
|
for (i = first; i < last; i++) atomscale[i] = buf[m++];
|
|
}
|