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

1204 lines
39 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 "pair_hybrid.h"
#include "atom.h"
#include "comm.h"
#include "error.h"
#include "force.h"
#include "memory.h"
#include "neigh_request.h"
#include "neighbor.h"
#include "pair.h"
#include "respa.h"
#include "suffix.h"
#include "update.h"
#include <cstring>
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
PairHybrid::PairHybrid(LAMMPS *lmp) :
Pair(lmp), styles(nullptr), cutmax_style(nullptr), keywords(nullptr), multiple(nullptr),
nmap(nullptr), map(nullptr), special_lj(nullptr), special_coul(nullptr), compute_tally(nullptr)
{
nstyles = 0;
outerflag = 0;
respaflag = 0;
}
/* ---------------------------------------------------------------------- */
PairHybrid::~PairHybrid()
{
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[] svector;
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(cutghost);
memory->destroy(nmap);
memory->destroy(map);
}
}
/* ----------------------------------------------------------------------
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 PairHybrid::compute(int eflag, int vflag)
{
int i,j,m,n;
// 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);
// 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++) {
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);
}
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 += styles[m]->eng_vdwl;
eng_coul += styles[m]->eng_coul;
}
if (vflag_global) {
for (n = 0; n < 6; n++) virial[n] += 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] += 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] += 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] += 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] += vatom_substyle[i][j];
}
for (j = 6; j < 9; j++) {
cvatom[i][j] += vatom_substyle[i][j-3];
}
}
}
}
}
delete[] saved_special;
if (vflag_fdotr) virial_fdotr_compute();
}
/* ---------------------------------------------------------------------- */
void PairHybrid::finish()
{
for (int m = 0; m < nstyles; m++) styles[m]->finish();
}
/* ---------------------------------------------------------------------- */
void PairHybrid::add_tally_callback(Compute *ptr)
{
for (int m = 0; m < nstyles; m++)
if (compute_tally[m]) styles[m]->add_tally_callback(ptr);
}
/* ---------------------------------------------------------------------- */
void PairHybrid::del_tally_callback(Compute *ptr)
{
for (int m = 0; m < nstyles; m++)
if (compute_tally[m]) styles[m]->del_tally_callback(ptr);
}
/* ---------------------------------------------------------------------- */
void PairHybrid::compute_inner()
{
for (int m = 0; m < nstyles; m++)
if (styles[m]->respa_enable) styles[m]->compute_inner();
}
/* ---------------------------------------------------------------------- */
void PairHybrid::compute_middle()
{
for (int m = 0; m < nstyles; m++)
if (styles[m]->respa_enable) styles[m]->compute_middle();
}
/* ---------------------------------------------------------------------- */
void PairHybrid::compute_outer(int eflag, int vflag)
{
outerflag = 1;
compute(eflag,vflag);
outerflag = 0;
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairHybrid::allocate()
{
allocated = 1;
int n = atom->ntypes;
memory->create(setflag,n+1,n+1,"pair:setflag");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
setflag[i][j] = 0;
memory->create(cutsq,n+1,n+1,"pair:cutsq");
memory->create(cutghost,n+1,n+1,"pair:cutghost");
memory->create(nmap,n+1,n+1,"pair:nmap");
memory->create(map,n+1,n+1,nstyles,"pair:map");
for (int i = 1; i <= n; i++)
for (int j = i; j <= n; j++)
nmap[i][j] = 0;
}
/* ----------------------------------------------------------------------
create one pair style for each arg in list
------------------------------------------------------------------------- */
void PairHybrid::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);
// 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[] keywords;
delete[] multiple;
delete[] special_lj;
delete[] special_coul;
delete[] compute_tally;
}
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];
// 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) {
if (utils::strmatch(arg[iarg],"^hybrid"))
error->all(FLERR,"Pair style hybrid cannot have hybrid as an argument");
if (strcmp(arg[iarg],"none") == 0)
error->all(FLERR,"Pair style hybrid 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;
// 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++;
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
int num_tip4p = 0, num_coul = 0; // count sub-styles with tip4p and coulomb
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;
if (utils::strmatch(keywords[i],"/tip4p/")) ++num_tip4p;
if (utils::strmatch(keywords[i],"/coul/")
|| utils::strmatch(keywords[i],"^comb")
|| utils::strmatch(keywords[i],"^reax/c")) ++num_coul;
}
if ((num_tip4p > 1) && (comm->me == 0))
error->warning(FLERR,"Using multiple tip4p sub-styles can result in "
"inconsistent calculation of coulomb interactions");
if ((num_tip4p > 0) && (num_coul > 0) && (comm->me == 0))
error->warning(FLERR,"Using a tip4p sub-style with other sub-styles "
"that include coulomb interactions can result in "
"inconsistent calculation of the coulomb interactions");
// set pair flags from sub-style flags
flags();
}
/* ----------------------------------------------------------------------
set top-level pair flags from sub-style flags
------------------------------------------------------------------------- */
void PairHybrid::flags()
{
int m;
// set comm_forward, comm_reverse, comm_reverse_off to max of any sub-style
for (m = 0; m < nstyles; m++) {
if (styles[m]) comm_forward = MAX(comm_forward,styles[m]->comm_forward);
if (styles[m]) comm_reverse = MAX(comm_reverse,styles[m]->comm_reverse);
if (styles[m]) comm_reverse_off = MAX(comm_reverse_off,
styles[m]->comm_reverse_off);
}
// single_enable = 1 if all sub-styles are set
// respa_enable = 1 if all sub-styles are set
// manybody_flag = 1 if any sub-style is set
// born_matrix_enable = 1 if all sub-styles are set
// no_virial_fdotr_compute = 1 if any sub-style is set
// ghostneigh = 1 if any sub-style is set
// ewaldflag, pppmflag, msmflag, dipoleflag, dispersionflag, tip4pflag = 1
// if any sub-style is set
// compute_flag = 1 if any sub-style is set
single_enable = 0;
compute_flag = 0;
respa_enable = 0;
restartinfo = 0;
born_matrix_enable = 0;
for (m = 0; m < nstyles; m++) {
if (styles[m]->single_enable) ++single_enable;
if (styles[m]->respa_enable) ++respa_enable;
if (styles[m]->restartinfo) ++restartinfo;
if (styles[m]->born_matrix_enable) ++born_matrix_enable;
if (styles[m]->manybody_flag) manybody_flag = 1;
if (styles[m]->no_virial_fdotr_compute) no_virial_fdotr_compute = 1;
if (styles[m]->ghostneigh) ghostneigh = 1;
if (styles[m]->ewaldflag) ewaldflag = 1;
if (styles[m]->pppmflag) pppmflag = 1;
if (styles[m]->msmflag) msmflag = 1;
if (styles[m]->dipoleflag) dipoleflag = 1;
if (styles[m]->spinflag) spinflag = 1;
if (styles[m]->dispersionflag) dispersionflag = 1;
if (styles[m]->tip4pflag) tip4pflag = 1;
if (styles[m]->compute_flag) compute_flag = 1;
if (styles[m]->finitecutflag) finitecutflag = 1;
}
single_enable = (single_enable == nstyles) ? 1 : 0;
respa_enable = (respa_enable == nstyles) ? 1 : 0;
restartinfo = (restartinfo == nstyles) ? 1 : 0;
born_matrix_enable = (born_matrix_enable == nstyles) ? 1 : 0;
init_svector();
// set centroidstressflag for pair hybrid
// set to CENTROID_NOTAVAIL if any substyle is NOTAVAIL
// else set to CENTROID_AVAIL if any substyle is AVAIL
// else set to CENTROID_SAME if all substyles are SAME
centroidstressflag = CENTROID_SAME;
for (m = 0; m < nstyles; m++) {
if (styles[m]->centroidstressflag == CENTROID_NOTAVAIL)
centroidstressflag = CENTROID_NOTAVAIL;
if (centroidstressflag == CENTROID_SAME &&
styles[m]->centroidstressflag == CENTROID_AVAIL)
centroidstressflag = CENTROID_AVAIL;
}
}
/* ----------------------------------------------------------------------
initialize Pair::svector array
------------------------------------------------------------------------- */
void PairHybrid::init_svector()
{
// single_extra = list all sub-style single_extra
// allocate svector
single_extra = 0;
for (int m = 0; m < nstyles; m++)
single_extra = MAX(single_extra,styles[m]->single_extra);
if (single_extra) {
delete[] svector;
svector = new double[single_extra];
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairHybrid::coeff(int narg, char **arg)
{
if (narg < 3) error->all(FLERR,"Incorrect args for pair coefficients");
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");
if (multiple[m] == utils::inumeric(FLERR,arg[3],false,lmp)) break;
else continue;
} else break;
}
}
int none = 0;
if (m == nstyles) {
if (strcmp(arg[2],"none") == 0) none = 1;
else error->all(FLERR,"Pair coeff for hybrid has invalid style: {}",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];
// invoke sub-style coeff() starting with 1st remaining arg
if (!none) styles[m]->coeff(narg-1-multflag,arg+1+multflag);
// if sub-style only allows one pair coeff call (with * * and type mapping)
// then unset setflag/map assigned to that style before setting it below
// in case pair coeff for this sub-style is being called for 2nd time
if (!none && styles[m]->one_coeff) {
if ((strcmp(arg[0],"*") != 0) || (strcmp(arg[1],"*") != 0))
error->all(FLERR,"Incorrect args for pair coefficients");
for (int i = 1; i <= atom->ntypes; i++)
for (int j = i; j <= atom->ntypes; j++)
if (nmap[i][j] && map[i][j][0] == m) {
setflag[i][j] = 0;
nmap[i][j] = 0;
}
}
// set setflag and which type pairs map to which sub-style
// if sub-style is none: set hybrid setflag, wipe out map
// else: set hybrid setflag & map only if substyle setflag is set
// previous mappings are wiped out
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]) {
setflag[i][j] = 1;
nmap[i][j] = 1;
map[i][j][0] = m;
count++;
}
}
}
if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairHybrid::init_style()
{
int i,m,itype,jtype,used,istyle,skip;
// error if a sub-style is not used
int ntypes = atom->ntypes;
for (istyle = 0; istyle < nstyles; istyle++) {
used = 0;
for (itype = 1; itype <= ntypes; itype++)
for (jtype = itype; jtype <= ntypes; jtype++)
for (m = 0; m < nmap[itype][jtype]; m++)
if (map[itype][jtype][m] == istyle) used = 1;
if (used == 0) error->all(FLERR,"Pair hybrid sub-style is not used");
}
// The GPU library uses global data for each pair style, so the
// same style must not be used multiple times
for (istyle = 0; istyle < nstyles; istyle++) {
bool is_gpu = styles[istyle]->suffix_flag & Suffix::GPU;
if (multiple[istyle] && is_gpu)
error->all(FLERR,"GPU package styles must not be used multiple times");
}
// check if special_lj/special_coul overrides are compatible
for (istyle = 0; istyle < nstyles; istyle++) {
if (special_lj[istyle]) {
for (i = 1; i < 4; ++i) {
if (((force->special_lj[i] == 0.0) || (force->special_lj[i] == 1.0))
&& (force->special_lj[i] != special_lj[istyle][i]))
error->all(FLERR,"Pair_modify special lj 1-{} setting for pair hybrid substyle {} "
"incompatible with global special_bonds setting", i+1, keywords[istyle]);
}
}
if (special_coul[istyle]) {
for (i = 1; i < 4; ++i) {
if (((force->special_coul[i] == 0.0) || (force->special_coul[i] == 1.0))
&& (force->special_coul[i] != special_coul[istyle][i]))
error->all(FLERR,"Pair_modify special coul 1-{} setting for pair hybrid substyle {} "
"incompatible with global special_bonds setting", i+1, keywords[istyle]);
}
}
}
// check beyond contact (set during pair coeff) before init style
for (istyle = 0; istyle < nstyles; istyle++)
if (styles[istyle]->beyond_contact) beyond_contact = 1;
// each sub-style makes its neighbor list request(s)
for (istyle = 0; istyle < nstyles; istyle++) styles[istyle]->init_style();
// create skip lists inside each pair neigh request
// any kind of list can have its skip flag set in this loop
for (auto &request : neighbor->get_pair_requests()) {
// istyle = associated sub-style for the request
for (istyle = 0; istyle < nstyles; istyle++)
if (styles[istyle] == request->get_requestor()) break;
// allocate iskip and ijskip
// initialize so as to skip all pair types
// set ijskip = 0 if type pair matches any entry in sub-style map
// set ijskip = 0 if mixing will assign type pair to this sub-style
// will occur if type pair is currently unassigned
// and both I,I and J,J are assigned to single sub-style
// and sub-style for both I,I and J,J match istyle
// set iskip = 1 only if all ijskip for itype are 1
int *iskip = new int[ntypes+1];
int **ijskip;
memory->create(ijskip,ntypes+1,ntypes+1,"pair_hybrid:ijskip");
for (itype = 1; itype <= ntypes; itype++)
for (jtype = 1; jtype <= ntypes; jtype++)
ijskip[itype][jtype] = 1;
for (itype = 1; itype <= ntypes; itype++)
for (jtype = itype; jtype <= ntypes; jtype++) {
for (m = 0; m < nmap[itype][jtype]; m++)
if (map[itype][jtype][m] == istyle)
ijskip[itype][jtype] = ijskip[jtype][itype] = 0;
if (nmap[itype][jtype] == 0 &&
nmap[itype][itype] == 1 && map[itype][itype][0] == istyle &&
nmap[jtype][jtype] == 1 && map[jtype][jtype][0] == istyle)
ijskip[itype][jtype] = ijskip[jtype][itype] = 0;
}
for (itype = 1; itype <= ntypes; itype++) {
iskip[itype] = 1;
for (jtype = 1; jtype <= ntypes; jtype++)
if (ijskip[itype][jtype] == 0) iskip[itype] = 0;
}
// if any skipping occurs
// set request->skip and copy iskip and ijskip into request
// else delete iskip and ijskip
// no skipping if pair style assigned to all type pairs
skip = 0;
for (itype = 1; itype <= ntypes; itype++)
for (jtype = 1; jtype <= ntypes; jtype++)
if (ijskip[itype][jtype] == 1) skip = 1;
if (skip) {
request->set_skip(iskip, ijskip);
} else {
delete[] iskip;
memory->destroy(ijskip);
}
}
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairHybrid::init_one(int i, int j)
{
// if I,J is not set explicitly:
// perform mixing only if I,I sub-style = J,J sub-style
// also require I,I and J,J are both assigned to single sub-style
if (setflag[i][j] == 0) {
if (nmap[i][i] != 1 || nmap[j][j] != 1 || map[i][i][0] != map[j][j][0])
error->one(FLERR,"All pair coeffs are not set");
nmap[i][j] = 1;
map[i][j][0] = map[i][i][0];
}
// call init/mixing for all sub-styles of I,J
// set cutsq in sub-style just as Pair::init() does via call to init_one()
// set cutghost for I,J and J,I just as sub-style does
// sum tail corrections for I,J
// return max cutoff of all sub-styles assigned to I,J
// if no sub-styles assigned to I,J (pair_coeff none), cutmax = 0.0 returned
double cutmax = 0.0;
cutghost[i][j] = cutghost[j][i] = 0.0;
if (tail_flag) etail_ij = ptail_ij = 0.0;
nmap[j][i] = nmap[i][j];
for (int k = 0; k < nmap[i][j]; k++) {
map[j][i][k] = map[i][j][k];
double cut = styles[map[i][j][k]]->init_one(i,j);
if (styles[map[i][j][k]]->did_mix) did_mix = true;
styles[map[i][j][k]]->cutsq[i][j] = styles[map[i][j][k]]->cutsq[j][i] = cut*cut;
if (styles[map[i][j][k]]->ghostneigh)
cutghost[i][j] = cutghost[j][i] = MAX(cutghost[i][j],styles[map[i][j][k]]->cutghost[i][j]);
if (tail_flag) {
etail_ij += styles[map[i][j][k]]->etail_ij;
ptail_ij += styles[map[i][j][k]]->ptail_ij;
}
cutmax = MAX(cutmax,cut);
int istyle;
for (istyle = 0; istyle < nstyles; istyle++)
if (styles[istyle] == styles[map[i][j][k]]) break;
if (styles[istyle]->trim_flag) {
if (cut > cutmax_style[istyle]) {
cutmax_style[istyle] = cut;
for (auto &request : neighbor->get_pair_requests()) {
if (styles[istyle] == request->get_requestor() && styles[istyle]->trim_flag) {
request->set_cutoff(cutmax_style[istyle]);
break;
}
}
}
}
}
return cutmax;
}
/* ----------------------------------------------------------------------
invoke setup for each sub-style
------------------------------------------------------------------------- */
void PairHybrid::setup()
{
for (int m = 0; m < nstyles; m++) styles[m]->setup();
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairHybrid::write_restart(FILE *fp)
{
fwrite(&nstyles,sizeof(int),1,fp);
// each sub-style writes its settings, but no coeff info
fwrite(compute_tally,sizeof(int),nstyles,fp);
int n;
for (int m = 0; m < nstyles; m++) {
n = strlen(keywords[m]) + 1;
fwrite(&n,sizeof(int),1,fp);
fwrite(keywords[m],sizeof(char),n,fp);
styles[m]->write_restart_settings(fp);
// write out per style special settings, if present
n = (special_lj[m] == nullptr) ? 0 : 1;
fwrite(&n,sizeof(int),1,fp);
if (n) fwrite(special_lj[m],sizeof(double),4,fp);
n = (special_coul[m] == nullptr) ? 0 : 1;
fwrite(&n,sizeof(int),1,fp);
if (n) fwrite(special_coul[m],sizeof(double),4,fp);
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairHybrid::read_restart(FILE *fp)
{
int me = comm->me;
if (me == 0) utils::sfread(FLERR,&nstyles,sizeof(int),1,fp,nullptr,error);
MPI_Bcast(&nstyles,1,MPI_INT,0,world);
// allocate list of sub-styles
delete[] styles;
delete[] keywords;
delete[] multiple;
delete[] special_lj;
delete[] special_coul;
delete[] compute_tally;
styles = new Pair*[nstyles];
cutmax_style = new double[nstyles];
memset(cutmax_style, 0.0, nstyles*sizeof(double));
keywords = new char*[nstyles];
multiple = new int[nstyles];
special_lj = new double*[nstyles];
special_coul = new double*[nstyles];
compute_tally = new int[nstyles];
// each sub-style is created via new_pair()
// each reads its settings, but no coeff info
if (me == 0) utils::sfread(FLERR,compute_tally,sizeof(int),nstyles,fp,nullptr,error);
MPI_Bcast(compute_tally,nstyles,MPI_INT,0,world);
int n,dummy;
for (int m = 0; m < nstyles; m++) {
if (me == 0) utils::sfread(FLERR,&n,sizeof(int),1,fp,nullptr,error);
MPI_Bcast(&n,1,MPI_INT,0,world);
keywords[m] = new char[n];
if (me == 0) utils::sfread(FLERR,keywords[m],sizeof(char),n,fp,nullptr,error);
MPI_Bcast(keywords[m],n,MPI_CHAR,0,world);
styles[m] = force->new_pair(keywords[m],1,dummy);
styles[m]->read_restart_settings(fp);
// read back per style special settings, if present
special_lj[m] = special_coul[m] = nullptr;
if (me == 0) utils::sfread(FLERR,&n,sizeof(int),1,fp,nullptr,error);
MPI_Bcast(&n,1,MPI_INT,0,world);
if (n > 0) {
special_lj[m] = new double[4];
if (me == 0) utils::sfread(FLERR,special_lj[m],sizeof(double),4,fp,nullptr,error);
MPI_Bcast(special_lj[m],4,MPI_DOUBLE,0,world);
}
if (me == 0) utils::sfread(FLERR,&n,sizeof(int),1,fp,nullptr,error);
MPI_Bcast(&n,1,MPI_INT,0,world);
if (n > 0) {
special_coul[m] = new double[4];
if (me == 0) utils::sfread(FLERR,special_coul[m],sizeof(double),4,fp,nullptr,error);
MPI_Bcast(special_coul[m],4,MPI_DOUBLE,0,world);
}
}
// 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 PairHybrid::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");
double fone;
fforce = 0.0;
double esum = 0.0;
for (int m = 0; m < nmap[itype][jtype]; m++) {
if (rsq < styles[map[itype][jtype][m]]->cutsq[itype][jtype]) {
if (styles[map[itype][jtype][m]]->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 calls do not support"
" per sub-style special bond values");
esum += styles[map[itype][jtype][m]]->
single(i,j,itype,jtype,rsq,factor_coul,factor_lj,fone);
fforce += 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 PairHybrid::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");
double du, du2;
dupair = du2pair = 0.0;
for (int m = 0; m < nmap[itype][jtype]; m++) {
if (rsq < styles[map[itype][jtype][m]]->cutsq[itype][jtype]) {
if (styles[map[itype][jtype][m]]->born_matrix_enable == 0)
error->one(FLERR,"Pair hybrid sub-style does not support born_matrix call");
if ((special_lj[map[itype][jtype][m]] != nullptr) ||
(special_coul[map[itype][jtype][m]] != nullptr))
error->one(FLERR,"Pair hybrid born_matrix calls do not support"
" per sub-style special bond values");
du = du2 = 0.0;
styles[map[itype][jtype][m]]->born_matrix(i,j,itype,jtype,rsq,factor_coul,factor_lj,du,du2);
dupair += du;
du2pair += du2;
}
}
}
/* ----------------------------------------------------------------------
copy Pair::svector data
------------------------------------------------------------------------- */
void PairHybrid::copy_svector(int itype, int jtype)
{
memset(svector,0,single_extra*sizeof(double));
// there is only one style in pair style hybrid for a pair of atom types
Pair *this_style = styles[map[itype][jtype][0]];
for (int l = 0; this_style->single_extra; ++l) {
svector[l] = this_style->svector[l];
}
}
/* ----------------------------------------------------------------------
modify parameters of the pair style and its sub-styles
------------------------------------------------------------------------- */
void PairHybrid::modify_params(int narg, char **arg)
{
if (narg == 0) error->all(FLERR,"Illegal pair_modify command");
// if 1st keyword is pair, apply other keywords to one sub-style
if (strcmp(arg[0],"pair") == 0) {
if (narg < 2) error->all(FLERR,"Illegal pair_modify command");
int m;
for (m = 0; m < nstyles; m++)
if (strcmp(arg[1],keywords[m]) == 0) break;
if (m == nstyles) error->all(FLERR,"Unknown pair_modify hybrid sub-style: {}",arg[1]);
int iarg = 2;
if (multiple[m]) {
if (narg < 3) error->all(FLERR,"Illegal pair_modify command");
int multiflag = utils::inumeric(FLERR,arg[2],false,lmp);
for (m = 0; m < nstyles; m++)
if (strcmp(arg[1],keywords[m]) == 0 && multiflag == multiple[m]) break;
if (m == nstyles)
error->all(FLERR,"Unknown pair_modify hybrid sub-style: {}",arg[1]);
iarg = 3;
}
// keywords "special" and "compute/tally" have to be listed directly
// after "pair" but can be given multiple times
again:
if (iarg < narg && strcmp(arg[iarg],"special") == 0) {
if (narg < iarg+5) error->all(FLERR,"Illegal pair_modify special command");
modify_special(m,narg-iarg,&arg[iarg+1]);
iarg += 5;
goto again;
}
// if 2nd keyword (after pair) is compute/tally:
// set flag to register TALLY computes accordingly
if (iarg < narg && strcmp(arg[iarg],"compute/tally") == 0) {
if (narg < iarg+2) error->all(FLERR,"Illegal pair_modify compute/tally command");
compute_tally[m] = utils::logical(FLERR,arg[iarg+1],false,lmp);
iarg += 2;
goto again;
}
// apply the remaining keywords to the base pair style itself and
// the sub-style except for "pair" and "special" or "compute/tally"
// and their arguments. the former is important for some keywords
// like "tail" or "compute"
if (narg-iarg > 0) {
Pair::modify_params(narg-iarg,&arg[iarg]);
styles[m]->modify_params(narg-iarg,&arg[iarg]);
}
// apply all keywords to pair hybrid itself and every sub-style
} else {
Pair::modify_params(narg,arg);
for (int m = 0; m < nstyles; m++) styles[m]->modify_params(narg,arg);
}
// reset global compute_flag since there may have been changes
// to any of the substyles
compute_flag = 0;
for (int m = 0; m < nstyles; m++)
if (styles[m]->compute_flag) compute_flag = 1;
}
/* ----------------------------------------------------------------------
store a local per pair style override for special_lj and special_coul
------------------------------------------------------------------------- */
void PairHybrid::modify_special(int m, int /*narg*/, char **arg)
{
double special[4];
int i;
special[0] = 1.0;
special[1] = utils::numeric(FLERR,arg[1],false,lmp);
special[2] = utils::numeric(FLERR,arg[2],false,lmp);
special[3] = utils::numeric(FLERR,arg[3],false,lmp);
if (styles[m]->suffix_flag & (Suffix::INTEL|Suffix::GPU))
error->all(FLERR,"Pair_modify special not compatible with suffix version of hybrid substyle");
if (strcmp(arg[0],"lj/coul") == 0) {
if (!special_lj[m]) special_lj[m] = new double[4];
if (!special_coul[m]) special_coul[m] = new double[4];
for (i = 0; i < 4; ++i)
special_lj[m][i] = special_coul[m][i] = special[i];
} else if (strcmp(arg[0],"lj") == 0) {
if (!special_lj[m]) special_lj[m] = new double[4];
for (i = 0; i < 4; ++i)
special_lj[m][i] = special[i];
} else if (strcmp(arg[0],"coul") == 0) {
if (!special_coul[m]) special_coul[m] = new double[4];
for (i = 0; i < 4; ++i)
special_coul[m][i] = special[i];
} else error->all(FLERR,"Illegal pair_modify special command");
}
/* ----------------------------------------------------------------------
override global special bonds settings with per substyle values
------------------------------------------------------------------------- */
void PairHybrid::set_special(int m)
{
int i;
if (special_lj[m])
for (i = 0; i < 4; ++i) force->special_lj[i] = special_lj[m][i];
if (special_coul[m])
for (i = 0; i < 4; ++i) force->special_coul[i] = special_coul[m][i];
}
/* ----------------------------------------------------------------------
store global special settings
------------------------------------------------------------------------- */
double * PairHybrid::save_special()
{
auto saved = new double[8];
for (int i = 0; i < 4; ++i) {
saved[i] = force->special_lj[i];
saved[i+4] = force->special_coul[i];
}
return saved;
}
/* ----------------------------------------------------------------------
restore global special settings from saved data
------------------------------------------------------------------------- */
void PairHybrid::restore_special(double *saved)
{
for (int i = 0; i < 4; ++i) {
force->special_lj[i] = saved[i];
force->special_coul[i] = saved[i+4];
}
}
/* ----------------------------------------------------------------------
extract a ptr to a particular quantity stored by pair
pass request thru to sub-styles
return first non-nullptr result except for cut_coul request
for cut_coul, insure all non-nullptr results are equal since required by Kspace
------------------------------------------------------------------------- */
void *PairHybrid::extract(const char *str, int &dim)
{
void *cutptr = nullptr;
void *ptr;
double cutvalue = 0.0;
int couldim = -1;
for (int m = 0; m < nstyles; m++) {
ptr = styles[m]->extract(str,dim);
if (ptr && strcmp(str,"cut_coul") == 0) {
if (couldim != -1 && dim != couldim)
error->all(FLERR, "Coulomb styles of pair hybrid sub-styles do not match");
auto p_newvalue = (double *) ptr;
double newvalue = *p_newvalue;
if (cutptr && (newvalue != cutvalue))
error->all(FLERR, "Coulomb cutoffs of pair hybrid sub-styles do not match");
if (dim == 0) {
cutptr = ptr;
cutvalue = newvalue;
}
couldim = dim;
} else if (ptr) return ptr;
}
if (strcmp(str,"cut_coul") == 0) return cutptr;
return nullptr;
}
/* ---------------------------------------------------------------------- */
void PairHybrid::reset_dt()
{
for (int m = 0; m < nstyles; m++) styles[m]->reset_dt();
}
/* ----------------------------------------------------------------------
check if itype,jtype maps to sub-style
------------------------------------------------------------------------- */
int PairHybrid::check_ijtype(int itype, int jtype, char *substyle)
{
for (int m = 0; m < nmap[itype][jtype]; m++)
if (strcmp(keywords[map[itype][jtype][m]],substyle) == 0) return 1;
return 0;
}
/* ----------------------------------------------------------------------
check if substyles calculate self-interaction range of particle
------------------------------------------------------------------------- */
double PairHybrid::atom2cut(int i)
{
double temp, cut;
cut = 0.0;
for (int m = 0; m < nstyles; m++) {
if (styles[m]->finitecutflag) {
temp = styles[m]->atom2cut(i);
if (temp > cut) cut = temp;
}
}
return cut;
}
/* ----------------------------------------------------------------------
check if substyles calculate maximum interaction range for two finite particles
------------------------------------------------------------------------- */
double PairHybrid::radii2cut(double r1, double r2)
{
double temp, cut;
cut = 0.0;
for (int m = 0; m < nstyles; m++) {
if (styles[m]->finitecutflag) {
temp = styles[m]->radii2cut(r1,r2);
if (temp > cut) cut = temp;
}
}
return cut;
}
/* ----------------------------------------------------------------------
memory usage of each sub-style
------------------------------------------------------------------------- */
double PairHybrid::memory_usage()
{
double bytes = (double)maxeatom * sizeof(double);
bytes += (double)maxvatom*6 * sizeof(double);
bytes += (double)maxcvatom*9 * sizeof(double);
for (int m = 0; m < nstyles; m++) bytes += styles[m]->memory_usage();
return bytes;
}