since the check for Pair::one_coeff was moved to the Input class (to reduce redundant code), hybrid substyles could "escape" that requirement. Thus checks have to be added to the hybrid coeff() methods.
1150 lines
37 KiB
C++
1150 lines
37 KiB
C++
// clang-format off
|
|
|
|
/* ----------------------------------------------------------------------
|
|
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
|
https://www.lammps.org/, Sandia National Laboratories
|
|
Steve Plimpton, sjplimp@sandia.gov
|
|
|
|
Copyright (2003) Sandia Corporation. Under the terms of Contract
|
|
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
|
certain rights in this software. This software is distributed under
|
|
the GNU General Public License.
|
|
|
|
See the README file in the top-level LAMMPS directory.
|
|
------------------------------------------------------------------------- */
|
|
|
|
#include "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), 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];
|
|
if (special_lj[m]) delete [] special_lj[m];
|
|
if (special_coul[m]) delete [] special_coul[m];
|
|
}
|
|
}
|
|
delete [] styles;
|
|
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 = (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::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];
|
|
if (special_lj[m]) delete [] special_lj[m];
|
|
if (special_coul[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];
|
|
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);
|
|
force->store_style(keywords[nstyles],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
|
|
// 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;
|
|
|
|
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]->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;
|
|
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 (i = 0; i < neighbor->nrequest; i++) {
|
|
if (!neighbor->requests[i]->pair) continue;
|
|
|
|
// istyle = associated sub-style for the request
|
|
|
|
for (istyle = 0; istyle < nstyles; istyle++)
|
|
if (styles[istyle] == neighbor->requests[i]->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) {
|
|
neighbor->requests[i]->skip = 1;
|
|
neighbor->requests[i]->iskip = iskip;
|
|
neighbor->requests[i]->ijskip = 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);
|
|
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);
|
|
}
|
|
|
|
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];
|
|
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;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
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");
|
|
if (strcmp(arg[iarg+1],"yes") == 0) {
|
|
compute_tally[m] = 1;
|
|
} else if (strcmp(arg[iarg+1],"no") == 0) {
|
|
compute_tally[m] = 0;
|
|
} else error->all(FLERR,"Illegal pair_modify compute/tally command");
|
|
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 is 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()
|
|
{
|
|
double *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");
|
|
double *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;
|
|
}
|