git-svn-id: svn://svn.icms.temple.edu/lammps-ro/trunk@6796 f3b2605a-c512-4ea7-a41b-209d697bcdaa

This commit is contained in:
sjplimp 2011-08-25 15:30:15 +00:00
parent 9eb5aebed9
commit 3a9ba7dd28
11 changed files with 3184 additions and 0 deletions

15
src/MC/Install.sh Normal file
View File

@ -0,0 +1,15 @@
# Install/unInstall package files in LAMMPS
if (test $1 = 1) then
cp pair_dsmc.cpp ..
cp pair_dsmc.h ..
elif (test $1 = 0) then
rm -f ../pair_dsmc.cpp
rm -f ../pair_dsmc.h
fi

392
src/MC/fix_bond_break.cpp Executable file
View File

@ -0,0 +1,392 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, 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 "math.h"
#include "mpi.h"
#include "string.h"
#include "stdlib.h"
#include "fix_bond_break.h"
#include "update.h"
#include "respa.h"
#include "atom.h"
#include "force.h"
#include "comm.h"
#include "neighbor.h"
#include "domain.h"
#include "random_mars.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define MIN(A,B) ((A) < (B)) ? (A) : (B)
#define MAX(A,B) ((A) > (B)) ? (A) : (B)
/* ---------------------------------------------------------------------- */
FixBondBreak::FixBondBreak(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg < 6) error->all("Illegal fix bond/break command");
MPI_Comm_rank(world,&me);
nevery = atoi(arg[3]);
if (nevery <= 0) error->all("Illegal fix bond/break command");
force_reneighbor = 1;
next_reneighbor = -1;
vector_flag = 1;
size_vector = 2;
global_freq = 1;
extvector = 0;
btype = atoi(arg[4]);
double cutoff = atof(arg[5]);
if (btype < 1 || btype > atom->nbondtypes)
error->all("Invalid bond type in fix bond/break command");
if (cutoff < 0.0) error->all("Illegal fix bond/break command");
cutsq = cutoff*cutoff;
// optional keywords
fraction = 1.0;
int seed = 12345;
int iarg = 6;
while (iarg < narg) {
if (strcmp(arg[iarg],"prob") == 0) {
if (iarg+3 > narg) error->all("Illegal fix bond/break command");
fraction = atof(arg[iarg+1]);
seed = atoi(arg[iarg+2]);
if (fraction < 0.0 || fraction > 1.0)
error->all("Illegal fix bond/break command");
if (seed <= 0) error->all("Illegal fix bond/break command");
iarg += 3;
} else error->all("Illegal fix bond/break command");
}
// error check
if (atom->molecular == 0)
error->all("Cannot use fix bond/break with non-molecular systems");
// initialize Marsaglia RNG with processor-unique seed
random = new RanMars(lmp,seed + me);
// set comm sizes needed by this fix
comm_forward = 2;
comm_reverse = 2;
// allocate arrays local to this fix
nmax = 0;
partner = NULL;
distsq = NULL;
// zero out stats
breakcount = 0;
breakcounttotal = 0;
}
/* ---------------------------------------------------------------------- */
FixBondBreak::~FixBondBreak()
{
delete random;
// delete locally stored arrays
memory->destroy(partner);
memory->destroy(distsq);
}
/* ---------------------------------------------------------------------- */
int FixBondBreak::setmask()
{
int mask = 0;
mask |= POST_INTEGRATE;
mask |= POST_INTEGRATE_RESPA;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixBondBreak::init()
{
// require special bonds = 0,1,1
int flag = 0;
if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 ||
force->special_lj[3] != 1.0) flag = 1;
if (force->special_coul[1] != 0.0 || force->special_coul[2] != 1.0 ||
force->special_coul[3] != 1.0) flag = 1;
if (flag) error->all("Fix bond/break requires special_bonds = 0,1,1");
// warn if angles, dihedrals, impropers are being used
if (force->angle || force->dihedral || force->improper) {
if (me == 0)
error->warning("Broken bonds will not alter angles, "
"dihedrals, or impropers");
}
if (strstr(update->integrate_style,"respa"))
nlevels_respa = ((Respa *) update->integrate)->nlevels;
}
/* ---------------------------------------------------------------------- */
void FixBondBreak::post_integrate()
{
int i,j,k,m,n,i1,i2,n1,n3,type;
double delx,dely,delz,rsq,min,max;
int *slist;
if (update->ntimestep % nevery) return;
// need updated ghost atom positions
comm->forward_comm();
// resize bond partner list and initialize it
// probability array overlays distsq array
// needs to be atom->nmax in length
if (atom->nmax > nmax) {
memory->destroy(partner);
memory->destroy(distsq);
nmax = atom->nmax;
memory->create(partner,nmax,"bond/break:partner");
memory->create(distsq,nmax,"bond/break:distsq");
probability = distsq;
}
int nlocal = atom->nlocal;
int nall = atom->nlocal + atom->nghost;
for (i = 0; i < nall; i++) {
partner[i] = 0;
distsq[i] = 0.0;
}
// loop over bond list
// setup possible partner list of bonds to break
double **x = atom->x;
int *tag = atom->tag;
int *mask = atom->mask;
int **bondlist = neighbor->bondlist;
int nbondlist = neighbor->nbondlist;
for (n = 0; n < nbondlist; n++) {
i1 = bondlist[n][0];
i2 = bondlist[n][1];
type = bondlist[n][2];
if (!(mask[i1] & groupbit)) continue;
if (!(mask[i2] & groupbit)) continue;
if (type != btype) continue;
delx = x[i1][0] - x[i2][0];
dely = x[i1][1] - x[i2][1];
delz = x[i1][2] - x[i2][2];
domain->minimum_image(delx,dely,delz);
rsq = delx*delx + dely*dely + delz*delz;
if (rsq <= cutsq) continue;
if (rsq > distsq[i1]) {
partner[i1] = tag[i2];
distsq[i1] = rsq;
}
if (rsq > distsq[i2]) {
partner[i2] = tag[i1];
distsq[i2] = rsq;
}
}
// reverse comm of partner info
if (force->newton_bond) comm->reverse_comm_fix(this);
// each atom now knows its winning partner
// for prob check, generate random value for each atom with a bond partner
// forward comm of partner and random value, so ghosts have it
if (fraction < 1.0) {
for (i = 0; i < nlocal; i++)
if (partner[i]) probability[i] = random->uniform();
}
comm->forward_comm_fix(this);
// break bonds
// if both atoms list each other as winning bond partner
// and probability constraint is satisfied
int **bond_type = atom->bond_type;
int **bond_atom = atom->bond_atom;
int *num_bond = atom->num_bond;
int **nspecial = atom->nspecial;
int **special = atom->special;
int nbreak = 0;
for (i = 0; i < nlocal; i++) {
if (partner[i] == 0) continue;
j = atom->map(partner[i]);
if (partner[j] != tag[i]) continue;
// apply probability constraint
// MIN,MAX insures values are added in same order on different procs
if (fraction < 1.0) {
min = MIN(probability[i],probability[j]);
max = MAX(probability[i],probability[j]);
if (0.5*(min+max) >= fraction) continue;
}
// delete bond from atom I if I stores it
// atom J will also do this
for (m = 0; m < num_bond[i]; m++) {
if (bond_atom[i][m] == partner[i]) {
for (k = m; k < num_bond[i]-1; k++) {
bond_atom[i][k] = bond_atom[i][k+1];
bond_type[i][k] = bond_type[i][k+1];
}
num_bond[i]--;
break;
}
}
// remove J from special bond list for atom I
// atom J will also do this
slist = special[i];
n1 = nspecial[i][0];
n3 = nspecial[i][2];
for (m = 0; m < n1; m++)
if (slist[m] == partner[i]) break;
for (; m < n3-1; m++) slist[m] = slist[m+1];
nspecial[i][0]--;
nspecial[i][1]--;
nspecial[i][2]--;
// count the broken bond once
if (tag[i] < tag[j]) nbreak++;
}
// tally stats
MPI_Allreduce(&nbreak,&breakcount,1,MPI_INT,MPI_SUM,world);
breakcounttotal += breakcount;
atom->nbonds -= breakcount;
// trigger reneighboring if any bonds were formed
if (breakcount) next_reneighbor = update->ntimestep;
}
/* ---------------------------------------------------------------------- */
void FixBondBreak::post_integrate_respa(int ilevel, int iloop)
{
if (ilevel == nlevels_respa-1) post_integrate();
}
/* ---------------------------------------------------------------------- */
int FixBondBreak::pack_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++] = partner[j];
buf[m++] = probability[j];
}
return 2;
}
/* ---------------------------------------------------------------------- */
void FixBondBreak::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
partner[i] = static_cast<int> (buf[m++]);
probability[i] = buf[m++];
}
}
/* ---------------------------------------------------------------------- */
int FixBondBreak::pack_reverse_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
for (i = first; i < last; i++) {
buf[m++] = partner[i];
buf[m++] = distsq[i];
}
return 2;
}
/* ---------------------------------------------------------------------- */
void FixBondBreak::unpack_reverse_comm(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
for (i = 0; i < n; i++) {
j = list[i];
if (buf[m+1] > distsq[j]) {
partner[j] = static_cast<int> (buf[m++]);
distsq[j] = buf[m++];
} else m += 2;
}
}
/* ---------------------------------------------------------------------- */
double FixBondBreak::compute_vector(int n)
{
if (n == 1) return (double) breakcount;
return (double) breakcounttotal;
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixBondBreak::memory_usage()
{
int nmax = atom->nmax;
double bytes = nmax * sizeof(int);
bytes += nmax * sizeof(double);
return bytes;
}

60
src/MC/fix_bond_break.h Executable file
View File

@ -0,0 +1,60 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, 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.
------------------------------------------------------------------------- */
#ifdef FIX_CLASS
FixStyle(bond/break,FixBondBreak)
#else
#ifndef LMP_FIX_BOND_BREAK_H
#define LMP_FIX_BOND_BREAK_H
#include "fix.h"
namespace LAMMPS_NS {
class FixBondBreak : public Fix {
public:
FixBondBreak(class LAMMPS *, int, char **);
~FixBondBreak();
int setmask();
void init();
void post_integrate();
void post_integrate_respa(int,int);
int pack_comm(int, int *, double *, int, int *);
void unpack_comm(int, int, double *);
int pack_reverse_comm(int, int, double *);
void unpack_reverse_comm(int, int *, double *);
double compute_vector(int);
double memory_usage();
private:
int me;
int btype,seed;
double cutsq,fraction;
int breakcount,breakcounttotal;
int nmax;
int *partner;
double *distsq,*probability;
class RanMars *random;
int nlevels_respa;
};
}
#endif
#endif

617
src/MC/fix_bond_create.cpp Executable file
View File

@ -0,0 +1,617 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, 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 "math.h"
#include "mpi.h"
#include "string.h"
#include "stdlib.h"
#include "fix_bond_create.h"
#include "update.h"
#include "respa.h"
#include "atom.h"
#include "force.h"
#include "pair.h"
#include "comm.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "random_mars.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
#define BIG 1.0e20
#define MIN(A,B) ((A) < (B)) ? (A) : (B)
#define MAX(A,B) ((A) > (B)) ? (A) : (B)
/* ---------------------------------------------------------------------- */
FixBondCreate::FixBondCreate(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg < 8) error->all("Illegal fix bond/create command");
MPI_Comm_rank(world,&me);
nevery = atoi(arg[3]);
if (nevery <= 0) error->all("Illegal fix bond/create command");
force_reneighbor = 1;
next_reneighbor = -1;
vector_flag = 1;
size_vector = 2;
global_freq = 1;
extvector = 0;
iatomtype = atoi(arg[4]);
jatomtype = atoi(arg[5]);
double cutoff = atof(arg[6]);
btype = atoi(arg[7]);
if (iatomtype < 1 || iatomtype > atom->ntypes ||
jatomtype < 1 || jatomtype > atom->ntypes)
error->all("Invalid atom type in fix bond/create command");
if (cutoff < 0.0) error->all("Illegal fix bond/create command");
if (btype < 1 || btype > atom->nbondtypes)
error->all("Invalid bond type in fix bond/create command");
cutsq = cutoff*cutoff;
// optional keywords
imaxbond = 0;
inewtype = iatomtype;
jmaxbond = 0;
jnewtype = jatomtype;
fraction = 1.0;
int seed = 12345;
int iarg = 8;
while (iarg < narg) {
if (strcmp(arg[iarg],"iparam") == 0) {
if (iarg+3 > narg) error->all("Illegal fix bond/create command");
imaxbond = atoi(arg[iarg+1]);
inewtype = atoi(arg[iarg+2]);
if (imaxbond < 0) error->all("Illegal fix bond/create command");
if (inewtype < 1 || inewtype > atom->ntypes)
error->all("Invalid atom type in fix bond/create command");
iarg += 3;
} else if (strcmp(arg[iarg],"jparam") == 0) {
if (iarg+3 > narg) error->all("Illegal fix bond/create command");
jmaxbond = atoi(arg[iarg+1]);
jnewtype = atoi(arg[iarg+2]);
if (jmaxbond < 0) error->all("Illegal fix bond/create command");
if (jnewtype < 1 || jnewtype > atom->ntypes)
error->all("Invalid atom type in fix bond/create command");
iarg += 3;
} else if (strcmp(arg[iarg],"prob") == 0) {
if (iarg+3 > narg) error->all("Illegal fix bond/create command");
fraction = atof(arg[iarg+1]);
seed = atoi(arg[iarg+2]);
if (fraction < 0.0 || fraction > 1.0)
error->all("Illegal fix bond/create command");
if (seed <= 0) error->all("Illegal fix bond/create command");
iarg += 3;
} else error->all("Illegal fix bond/create command");
}
// error check
if (atom->molecular == 0)
error->all("Cannot use fix bond/create with non-molecular systems");
if (iatomtype == jatomtype &&
((imaxbond != jmaxbond) || (inewtype != jnewtype)))
error->all("Inconsistent iparam/jparam values in fix bond/create command");
// initialize Marsaglia RNG with processor-unique seed
random = new RanMars(lmp,seed + me);
// perform initial allocation of atom-based arrays
// register with Atom class
// bondcount values will be initialized in setup()
bondcount = NULL;
grow_arrays(atom->nmax);
atom->add_callback(0);
countflag = 0;
// set comm sizes needed by this fix
comm_forward = 2;
comm_reverse = 2;
// allocate arrays local to this fix
nmax = 0;
partner = NULL;
distsq = NULL;
// zero out stats
createcount = 0;
createcounttotal = 0;
}
/* ---------------------------------------------------------------------- */
FixBondCreate::~FixBondCreate()
{
// unregister callbacks to this fix from Atom class
atom->delete_callback(id,0);
delete random;
// delete locally stored arrays
memory->destroy(bondcount);
memory->destroy(partner);
memory->destroy(distsq);
}
/* ---------------------------------------------------------------------- */
int FixBondCreate::setmask()
{
int mask = 0;
mask |= POST_INTEGRATE;
mask |= POST_INTEGRATE_RESPA;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixBondCreate::init()
{
// check cutoff for iatomtype,jatomtype
if (force->pair == NULL || cutsq > force->pair->cutsq[iatomtype][jatomtype])
error->all("Fix bond/create cutoff is longer than pairwise cutoff");
// require special bonds = 0,1,1
if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 ||
force->special_lj[3] != 1.0)
error->all("Fix bond/create requires special_bonds lj = 0,1,1");
if (atom->q_flag)
if (force->special_coul[1] != 0.0 || force->special_coul[2] != 1.0 ||
force->special_coul[3] != 1.0)
error->all("Fix bond/create requires special_bonds coul = 0,1,1");
// warn if angles, dihedrals, impropers are being used
if (force->angle || force->dihedral || force->improper) {
if (me == 0)
error->warning("Created bonds will not create angles, "
"dihedrals, or impropers");
}
// need a half neighbor list, built when ever re-neighboring occurs
int irequest = neighbor->request((void *) this);
neighbor->requests[irequest]->pair = 0;
neighbor->requests[irequest]->fix = 1;
if (strstr(update->integrate_style,"respa"))
nlevels_respa = ((Respa *) update->integrate)->nlevels;
}
/* ---------------------------------------------------------------------- */
void FixBondCreate::init_list(int id, NeighList *ptr)
{
list = ptr;
}
/* ---------------------------------------------------------------------- */
void FixBondCreate::setup(int vflag)
{
int i,j,m;
// compute initial bondcount if this is first run
// can't do this earlier, like in constructor or init, b/c need ghost info
if (countflag) return;
countflag = 1;
// count bonds stored with each bond I own
// if newton bond is not set, just increment count on atom I
// if newton bond is set, also increment count on atom J even if ghost
// bondcount is long enough to tally ghost atom counts
int *num_bond = atom->num_bond;
int **bond_type = atom->bond_type;
int **bond_atom = atom->bond_atom;
int nlocal = atom->nlocal;
int nghost = atom->nghost;
int nall = nlocal + nghost;
int newton_bond = force->newton_bond;
for (i = 0; i < nall; i++) bondcount[i] = 0;
for (i = 0; i < nlocal; i++)
for (j = 0; j < num_bond[i]; j++) {
if (bond_type[i][j] == btype) {
bondcount[i]++;
if (newton_bond) {
m = atom->map(bond_atom[i][j]);
if (m < 0)
error->one("Could not count initial bonds in fix bond/create");
bondcount[m]++;
}
}
}
// if newton_bond is set, need to sum bondcount
commflag = 0;
if (newton_bond) comm->reverse_comm_fix(this);
}
/* ---------------------------------------------------------------------- */
void FixBondCreate::post_integrate()
{
int i,j,m,ii,jj,inum,jnum,itype,jtype,n1,n3,possible;
double xtmp,ytmp,ztmp,delx,dely,delz,rsq,min,max;
int *ilist,*jlist,*numneigh,**firstneigh,*slist;
if (update->ntimestep % nevery) return;
// need updated ghost atom positions
comm->forward_comm();
// forward comm of bondcount, so ghosts have it
commflag = 0;
comm->forward_comm_fix(this);
// resize bond partner list and initialize it
// probability array overlays distsq array
// needs to be atom->nmax in length
if (atom->nmax > nmax) {
memory->destroy(partner);
memory->destroy(distsq);
nmax = atom->nmax;
memory->create(partner,nmax,"bond/create:partner");
memory->create(distsq,nmax,"bond/create:distsq");
probability = distsq;
}
int nlocal = atom->nlocal;
int nall = atom->nlocal + atom->nghost;
for (i = 0; i < nall; i++) {
partner[i] = 0;
distsq[i] = BIG;
}
// loop over neighbors of my atoms
// each atom sets one closest eligible partner atom ID to bond with
double **x = atom->x;
int *tag = atom->tag;
int *mask = atom->mask;
int *type = atom->type;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
if (!(mask[i] & groupbit)) continue;
itype = type[i];
xtmp = x[i][0];
ytmp = x[i][1];
ztmp = x[i][2];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
if (!(mask[j] & groupbit)) continue;
jtype = type[j];
possible = 0;
if (itype == iatomtype && jtype == jatomtype) {
if ((imaxbond == 0 || bondcount[i] < imaxbond) &&
(jmaxbond == 0 || bondcount[j] < jmaxbond))
possible = 1;
} else if (itype == jatomtype && jtype == iatomtype) {
if ((jmaxbond == 0 || bondcount[i] < jmaxbond) &&
(imaxbond == 0 || bondcount[j] < imaxbond))
possible = 1;
}
if (!possible) continue;
delx = xtmp - x[j][0];
dely = ytmp - x[j][1];
delz = ztmp - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
if (rsq >= cutsq) continue;
if (rsq < distsq[i]) {
partner[i] = tag[j];
distsq[i] = rsq;
}
if (rsq < distsq[j]) {
partner[j] = tag[i];
distsq[j] = rsq;
}
}
}
// reverse comm of distsq and partner
// not needed if newton_pair off since I,J pair was seen by both procs
commflag = 1;
if (force->newton_pair) comm->reverse_comm_fix(this);
// each atom now knows its winning partner
// for prob check, generate random value for each atom with a bond partner
// forward comm of partner and random value, so ghosts have it
if (fraction < 1.0) {
for (i = 0; i < nlocal; i++)
if (partner[i]) probability[i] = random->uniform();
}
commflag = 1;
comm->forward_comm_fix(this);
// create bonds for atoms I own
// if other atom is owned by another proc, it should create same bond
// if both atoms list each other as winning bond partner
// and probability constraint is satisfied
int **bond_type = atom->bond_type;
int **bond_atom = atom->bond_atom;
int *num_bond = atom->num_bond;
int **nspecial = atom->nspecial;
int **special = atom->special;
int newton_bond = force->newton_bond;
int ncreate = 0;
for (i = 0; i < nlocal; i++) {
if (partner[i] == 0) continue;
j = atom->map(partner[i]);
if (partner[j] != tag[i]) continue;
// apply probability constraint
// MIN,MAX insures values are added in same order on different procs
if (fraction < 1.0) {
min = MIN(probability[i],probability[j]);
max = MAX(probability[i],probability[j]);
if (0.5*(min+max) >= fraction) continue;
}
// if newton_bond is set, only store with I or J
// if not newton_bond, store bond with both I and J
if (!newton_bond || tag[i] < tag[j]) {
if (num_bond[i] == atom->bond_per_atom)
error->one("New bond exceeded bonds per atom in fix bond/create");
bond_type[i][num_bond[i]] = btype;
bond_atom[i][num_bond[i]] = tag[j];
num_bond[i]++;
}
// add a 1-2 neighbor to special bond list for atom I
// atom J will also do this
slist = special[i];
n1 = nspecial[i][0];
n3 = nspecial[i][2];
if (n3 == atom->maxspecial)
error->one("New bond exceeded special list size in fix bond/create");
for (m = n3; m > n1; m--) slist[m+1] = slist[m];
slist[n1] = tag[j];
nspecial[i][0]++;
nspecial[i][1]++;
nspecial[i][2]++;
// increment bondcount, convert atom to new type if limit reached
bondcount[i]++;
if (type[i] == iatomtype) {
if (bondcount[i] == imaxbond) type[i] = inewtype;
} else {
if (bondcount[i] == jmaxbond) type[i] = jnewtype;
}
// count the created bond once
if (tag[i] < tag[j]) ncreate++;
}
// tally stats
MPI_Allreduce(&ncreate,&createcount,1,MPI_INT,MPI_SUM,world);
createcounttotal += createcount;
atom->nbonds += createcount;
// trigger reneighboring if any bonds were formed
if (createcount) next_reneighbor = update->ntimestep;
}
/* ---------------------------------------------------------------------- */
void FixBondCreate::post_integrate_respa(int ilevel, int iloop)
{
if (ilevel == nlevels_respa-1) post_integrate();
}
/* ---------------------------------------------------------------------- */
int FixBondCreate::pack_comm(int n, int *list, double *buf,
int pbc_flag, int *pbc)
{
int i,j,m;
m = 0;
if (commflag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = bondcount[j];
}
return 1;
} else {
for (i = 0; i < n; i++) {
j = list[i];
buf[m++] = partner[j];
buf[m++] = probability[j];
}
return 2;
}
}
/* ---------------------------------------------------------------------- */
void FixBondCreate::unpack_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
if (commflag == 0) {
for (i = first; i < last; i++)
bondcount[i] = static_cast<int> (buf[m++]);
} else {
for (i = first; i < last; i++) {
partner[i] = static_cast<int> (buf[m++]);
probability[i] = buf[m++];
}
}
}
/* ---------------------------------------------------------------------- */
int FixBondCreate::pack_reverse_comm(int n, int first, double *buf)
{
int i,m,last;
m = 0;
last = first + n;
if (commflag == 0) {
for (i = first; i < last; i++)
buf[m++] = bondcount[i];
return 1;
} else {
for (i = first; i < last; i++) {
buf[m++] = distsq[i];
buf[m++] = partner[i];
}
return 2;
}
}
/* ---------------------------------------------------------------------- */
void FixBondCreate::unpack_reverse_comm(int n, int *list, double *buf)
{
int i,j,m;
m = 0;
if (commflag == 0) {
for (i = 0; i < n; i++) {
j = list[i];
bondcount[j] += static_cast<int> (buf[m++]);
}
} else {
for (i = 0; i < n; i++) {
j = list[i];
if (buf[m] < distsq[j]) {
distsq[j] = buf[m++];
partner[j] = static_cast<int> (buf[m++]);
} else m += 2;
}
}
}
/* ----------------------------------------------------------------------
allocate local atom-based arrays
------------------------------------------------------------------------- */
void FixBondCreate::grow_arrays(int nmax)
{
memory->grow(bondcount,nmax,"bond/create:bondcount");
}
/* ----------------------------------------------------------------------
copy values within local atom-based arrays
------------------------------------------------------------------------- */
void FixBondCreate::copy_arrays(int i, int j)
{
bondcount[j] = bondcount[i];
}
/* ----------------------------------------------------------------------
pack values in local atom-based arrays for exchange with another proc
------------------------------------------------------------------------- */
int FixBondCreate::pack_exchange(int i, double *buf)
{
buf[0] = bondcount[i];
return 1;
}
/* ----------------------------------------------------------------------
unpack values in local atom-based arrays from exchange with another proc
------------------------------------------------------------------------- */
int FixBondCreate::unpack_exchange(int nlocal, double *buf)
{
bondcount[nlocal] = static_cast<int> (buf[0]);
return 1;
}
/* ---------------------------------------------------------------------- */
double FixBondCreate::compute_vector(int n)
{
if (n == 1) return (double) createcount;
return (double) createcounttotal;
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixBondCreate::memory_usage()
{
int nmax = atom->nmax;
double bytes = nmax*2 * sizeof(int);
bytes += nmax * sizeof(double);
return bytes;
}

74
src/MC/fix_bond_create.h Executable file
View File

@ -0,0 +1,74 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, 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.
------------------------------------------------------------------------- */
#ifdef FIX_CLASS
FixStyle(bond/create,FixBondCreate)
#else
#ifndef LMP_FIX_BOND_CREATE_H
#define LMP_FIX_BOND_CREATE_H
#include "fix.h"
namespace LAMMPS_NS {
class FixBondCreate : public Fix {
public:
FixBondCreate(class LAMMPS *, int, char **);
~FixBondCreate();
int setmask();
void init();
void init_list(int, class NeighList *);
void setup(int);
void post_integrate();
void post_integrate_respa(int, int);
int pack_comm(int, int *, double *, int, int *);
void unpack_comm(int, int, double *);
int pack_reverse_comm(int, int, double *);
void unpack_reverse_comm(int, int *, double *);
void grow_arrays(int);
void copy_arrays(int, int);
int pack_exchange(int, double *);
int unpack_exchange(int, double *);
double compute_vector(int);
double memory_usage();
private:
int me;
int iatomtype,jatomtype;
int btype,seed;
int imaxbond,jmaxbond;
int inewtype,jnewtype;
double cutsq,fraction;
int createcount,createcounttotal; // bond formation stats
int nmax;
int *bondcount; // count of created bonds this atom is part of
int *partner; // ID of preferred atom for this atom to bond to
double *distsq; // distance to preferred bond partner
double *probability; // random # to use in decision to form bond
class RanMars *random;
class NeighList *list;
int countflag,commflag;
int nlevels_respa;
};
}
#endif
#endif

689
src/MC/fix_bond_swap.cpp Normal file
View File

@ -0,0 +1,689 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, 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 "math.h"
#include "stdlib.h"
#include "string.h"
#include "fix_bond_swap.h"
#include "atom.h"
#include "force.h"
#include "pair.h"
#include "bond.h"
#include "angle.h"
#include "neighbor.h"
#include "neigh_list.h"
#include "neigh_request.h"
#include "group.h"
#include "comm.h"
#include "domain.h"
#include "modify.h"
#include "compute.h"
#include "random_mars.h"
#include "memory.h"
#include "error.h"
#include "update.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
FixBondSwap::FixBondSwap(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg != 6) error->all("Illegal fix bond/swap command");
vector_flag = 1;
size_vector = 2;
global_freq = 1;
extvector = 0;
fraction = atof(arg[3]);
double cutoff = atof(arg[4]);
cutsq = cutoff*cutoff;
// initialize Marsaglia RNG with processor-unique seed
int seed = atoi(arg[5]);
random = new RanMars(lmp,seed + comm->me);
// create a new compute temp style
// id = fix-ID + temp, compute group = fix group
int n = strlen(id) + 6;
id_temp = new char[n];
strcpy(id_temp,id);
strcat(id_temp,"_temp");
char **newarg = new char*[3];
newarg[0] = id_temp;
newarg[1] = "all";
newarg[2] = "temp";
modify->add_compute(3,newarg);
delete [] newarg;
tflag = 1;
// initialize atom list
nmax = 0;
alist = NULL;
naccept = foursome = 0;
}
/* ---------------------------------------------------------------------- */
FixBondSwap::~FixBondSwap()
{
delete random;
// delete temperature if fix created it
if (tflag) modify->delete_compute(id_temp);
delete [] id_temp;
memory->destroy(alist);
}
/* ---------------------------------------------------------------------- */
int FixBondSwap::setmask()
{
int mask = 0;
mask |= PRE_NEIGHBOR;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixBondSwap::init()
{
// require an atom style with molecule IDs
if (atom->molecule == NULL)
error->all("Must use atom style with molecule IDs with fix bond/swap");
int icompute = modify->find_compute(id_temp);
if (icompute < 0)
error->all("Temperature ID for fix bond/swap does not exist");
temperature = modify->compute[icompute];
// pair and bonds must be defined
// no dihedral or improper potentials allowed
// special bonds must be 0 1 1
if (force->pair == NULL || force->bond == NULL)
error->all("Fix bond/swap requires pair and bond styles");
if (force->pair->single_enable == 0)
error->all("Pair style does not support fix bond/swap");
if (force->angle == NULL && atom->nangles > 0 && comm->me == 0)
error->warning("Fix bond/swap will ignore defined angles");
if (force->dihedral || force->improper)
error->all("Fix bond/swap cannot use dihedral or improper styles");
if (force->special_lj[1] != 0.0 || force->special_lj[2] != 1.0 ||
force->special_lj[3] != 1.0)
error->all("Fix bond/swap requires special_bonds = 0,1,1");
// need a half neighbor list, built when ever re-neighboring occurs
int irequest = neighbor->request((void *) this);
neighbor->requests[irequest]->pair = 0;
neighbor->requests[irequest]->fix = 1;
// zero out stats
naccept = foursome = 0;
angleflag = 0;
if (force->angle) angleflag = 1;
}
/* ---------------------------------------------------------------------- */
void FixBondSwap::init_list(int id, NeighList *ptr)
{
list = ptr;
}
/* ---------------------------------------------------------------------- */
void FixBondSwap::pre_neighbor()
{
int i,j,ii,jj,m,inum,jnum;
int inext,iprev,ilast,jnext,jprev,jlast,ibond,iangle,jbond,jangle;
int itag,inexttag,iprevtag,ilasttag,jtag,jnexttag,jprevtag,jlasttag;
int ibondtype,jbondtype,iangletype,inextangletype,jangletype,jnextangletype;
int i1,i2,i3,j1,j2,j3,tmp;
int *ilist,*jlist,*numneigh,**firstneigh;
double delta,factor;
// compute current temp for Boltzmann factor test
double t_current = temperature->compute_scalar();
// local ptrs to atom arrays
int *tag = atom->tag;
int *mask = atom->mask;
int *molecule = atom->molecule;
int *num_bond = atom->num_bond;
int **bond_atom = atom->bond_atom;
int **bond_type = atom->bond_type;
int *num_angle = atom->num_angle;
int **angle_atom1 = atom->angle_atom1;
int **angle_atom2 = atom->angle_atom2;
int **angle_atom3 = atom->angle_atom3;
int **angle_type = atom->angle_type;
int **nspecial = atom->nspecial;
int **special = atom->special;
int newton_bond = force->newton_bond;
int nlocal = atom->nlocal;
type = atom->type;
x = atom->x;
inum = list->inum;
ilist = list->ilist;
numneigh = list->numneigh;
firstneigh = list->firstneigh;
// randomize list of my owned atoms that are in fix group
// grow atom list if necessary
if (nlocal > nmax) {
memory->destroy(alist);
nmax = atom->nmax;
memory->create(alist,nmax,"bondswap:alist");
}
int neligible = 0;
for (ii = 0; ii < inum; ii++) {
i = ilist[ii];
if (mask[i] & groupbit)
alist[neligible++] = i;
}
for (i = 0; i < neligible; i++) {
j = static_cast<int> (random->uniform() * neligible);
tmp = alist[i];
alist[i] = alist[j];
alist[j] = tmp;
}
// examine ntest of my eligible atoms for potential swaps
// atom i is randomly selected via atom list
// look at all j neighbors of atom i
// atom j must be on-processor (j < nlocal)
// atom j must be in fix group
// i and j must be same distance from chain end (mol[i] = mol[j])
// NOTE: must use extra parens in if test on mask[j] & groupbit
int ntest = static_cast<int> (fraction * neligible);
int accept = 0;
for (int itest = 0; itest < ntest; itest++) {
i = alist[itest];
jlist = firstneigh[i];
jnum = numneigh[i];
for (jj = 0; jj < jnum; jj++) {
j = jlist[jj];
j &= NEIGHMASK;
if (j >= nlocal) continue;
if ((mask[j] & groupbit) == 0) continue;
if (molecule[i] != molecule[j]) continue;
// look at all bond partners of atoms i and j
// use num_bond for this, not special list, so also find bondtypes
// inext,jnext = bonded atoms
// inext,jnext must be on-processor (inext,jnext < nlocal)
// inext,jnext must be same dist from chain end (mol[inext] = mol[jnext])
// since swaps may occur between two ends of a single chain, insure
// the 4 atoms are unique (no duplicates): inext != jnext, inext != j
// all 4 old and new bonds must have length < cutoff
for (ibond = 0; ibond < num_bond[i]; ibond++) {
inext = atom->map(bond_atom[i][ibond]);
if (inext >= nlocal || inext < 0) continue;
ibondtype = bond_type[i][ibond];
for (jbond = 0; jbond < num_bond[j]; jbond++) {
jnext = atom->map(bond_atom[j][jbond]);
if (jnext >= nlocal || jnext < 0) continue;
jbondtype = bond_type[j][jbond];
if (molecule[inext] != molecule[jnext]) continue;
if (inext == jnext || inext == j) continue;
if (dist_rsq(i,inext) >= cutsq) continue;
if (dist_rsq(j,jnext) >= cutsq) continue;
if (dist_rsq(i,jnext) >= cutsq) continue;
if (dist_rsq(j,inext) >= cutsq) continue;
// if angles are enabled:
// find other atoms i,inext,j,jnext are in angles with
// and angletypes: i/j angletype, i/j nextangletype
// use num_angle for this, not special list, so also find angletypes
// 4 atoms consecutively along 1st chain: iprev,i,inext,ilast
// 4 atoms consecutively along 2nd chain: jprev,j,jnext,jlast
// prev or last atom can be non-existent at end of chain
// set prev/last = -1 in this case
// if newton bond = 0, then angles are stored by all 4 atoms
// so require that iprev,ilast,jprev,jlast be owned by this proc
// so all copies of angles can be updated if a swap takes place
if (angleflag) {
itag = tag[i];
inexttag = tag[inext];
jtag = tag[j];
jnexttag = tag[jnext];
iprev = -1;
for (iangle = 0; iangle < num_angle[i]; iangle++) {
i1 = angle_atom1[i][iangle];
i2 = angle_atom2[i][iangle];
i3 = angle_atom3[i][iangle];
if (i2 == itag && i3 == inexttag) iprev = atom->map(i1);
else if (i1 == inexttag && i2 == itag) iprev = atom->map(i3);
if (iprev >= 0) {
iangletype = angle_type[i][iangle];
break;
}
}
if (!newton_bond && iprev >= nlocal) continue;
ilast = -1;
for (iangle = 0; iangle < num_angle[inext]; iangle++) {
i1 = angle_atom1[inext][iangle];
i2 = angle_atom2[inext][iangle];
i3 = angle_atom3[inext][iangle];
if (i1 == itag && i2 == inexttag) ilast = atom->map(i3);
else if (i2 == inexttag && i3 == itag) ilast = atom->map(i1);
if (ilast >= 0) {
inextangletype = angle_type[inext][iangle];
break;
}
}
if (!newton_bond && ilast >= nlocal) continue;
jprev = -1;
for (jangle = 0; jangle < num_angle[j]; jangle++) {
j1 = angle_atom1[j][jangle];
j2 = angle_atom2[j][jangle];
j3 = angle_atom3[j][jangle];
if (j2 == jtag && j3 == jnexttag) jprev = atom->map(j1);
else if (j1 == jnexttag && j2 == jtag) jprev = atom->map(j3);
if (jprev >= 0) {
jangletype = angle_type[j][jangle];
break;
}
}
if (!newton_bond && jprev >= nlocal) continue;
jlast = -1;
for (jangle = 0; jangle < num_angle[jnext]; jangle++) {
j1 = angle_atom1[jnext][jangle];
j2 = angle_atom2[jnext][jangle];
j3 = angle_atom3[jnext][jangle];
if (j1 == jtag && j2 == jnexttag) jlast = atom->map(j3);
else if (j2 == jnexttag && j3 == jtag) jlast = atom->map(j1);
if (jlast >= 0) {
jnextangletype = angle_type[jnext][jangle];
break;
}
}
if (!newton_bond && jlast >= nlocal) continue;
}
// valid foursome found between 2 chains:
// chains = iprev-i-inext-ilast and jprev-j-jnext-jlast
// prev or last values are -1 if do not exist due to end of chain
// OK to call angle_eng with -1 atom, since just return 0.0
// current energy of foursome =
// E_nb(i,j) + E_nb(i,jnext) + E_nb(inext,j) + E_nb(inext,jnext) +
// E_bond(i,inext) + E_bond(j,jnext) +
// E_angle(iprev,i,inext) + E_angle(i,inext,ilast) +
// E_angle(jprev,j,jnext) + E_angle(j,jnext,jlast)
// new energy of foursome with swapped bonds =
// E_nb(i,j) + E_nb(i,inext) + E_nb(j,jnext) + E_nb(inext,jnext) +
// E_bond(i,jnext) + E_bond(j,inext) +
// E_angle(iprev,i,jnext) + E_angle(i,jnext,jlast) +
// E_angle(jprev,j,inext) + E_angle(j,inext,ilast)
// energy delta = add/subtract differing terms between 2 formulas
foursome++;
delta = pair_eng(i,inext) + pair_eng(j,jnext) -
pair_eng(i,jnext) - pair_eng(inext,j);
delta += bond_eng(ibondtype,i,jnext) + bond_eng(jbondtype,j,inext) -
bond_eng(ibondtype,i,inext) - bond_eng(jbondtype,j,jnext);
if (angleflag)
delta += angle_eng(iangletype,iprev,i,jnext) +
angle_eng(jnextangletype,i,jnext,jlast) +
angle_eng(jangletype,jprev,j,inext) +
angle_eng(inextangletype,j,inext,ilast) -
angle_eng(iangletype,iprev,i,inext) -
angle_eng(inextangletype,i,inext,ilast) -
angle_eng(jangletype,jprev,j,jnext) -
angle_eng(jnextangletype,j,jnext,jlast);
// if delta <= 0, accept swap
// if delta > 0, compute Boltzmann factor with current temperature
// only accept if greater than random value
// whether accept or not, exit test loop
if (delta < 0.0) accept = 1;
else {
factor = exp(-delta/force->boltz/t_current);
if (random->uniform() < factor) accept = 1;
}
goto done;
}
}
}
}
done:
if (!accept) return;
naccept++;
// change bond partners of affected atoms
// on atom i: bond i-inext changes to i-jnext
// on atom j: bond j-jnext changes to j-inext
// on atom inext: bond inext-i changes to inext-j
// on atom jnext: bond jnext-j changes to jnext-i
for (ibond = 0; ibond < num_bond[i]; ibond++)
if (bond_atom[i][ibond] == tag[inext]) bond_atom[i][ibond] = tag[jnext];
for (jbond = 0; jbond < num_bond[j]; jbond++)
if (bond_atom[j][jbond] == tag[jnext]) bond_atom[j][jbond] = tag[inext];
for (ibond = 0; ibond < num_bond[inext]; ibond++)
if (bond_atom[inext][ibond] == tag[i]) bond_atom[inext][ibond] = tag[j];
for (jbond = 0; jbond < num_bond[jnext]; jbond++)
if (bond_atom[jnext][jbond] == tag[j]) bond_atom[jnext][jbond] = tag[i];
// set global tags of 4 atoms in bonds
itag = tag[i];
inexttag = tag[inext];
jtag = tag[j];
jnexttag = tag[jnext];
// change 1st special neighbors of affected atoms: i,j,inext,jnext
// don't need to change 2nd/3rd special neighbors for any atom
// since special bonds = 0 1 1 means they are never used
for (m = 0; m < nspecial[i][0]; m++)
if (special[i][m] == inexttag) special[i][m] = jnexttag;
for (m = 0; m < nspecial[j][0]; m++)
if (special[j][m] == jnexttag) special[j][m] = inexttag;
for (m = 0; m < nspecial[inext][0]; m++)
if (special[inext][m] == itag) special[inext][m] = jtag;
for (m = 0; m < nspecial[jnext][0]; m++)
if (special[jnext][m] == jtag) special[jnext][m] = itag;
// done if no angles
if (!angleflag) return;
// set global tags of 4 additional atoms in angles, 0 if no angle
if (iprev >= 0) iprevtag = tag[iprev];
else iprevtag = 0;
if (ilast >= 0) ilasttag = tag[ilast];
else ilasttag = 0;
if (jprev >= 0) jprevtag = tag[jprev];
else jprevtag = 0;
if (jlast >= 0) jlasttag = tag[jlast];
else jlasttag = 0;
// change angle partners of affected atoms
// must check if each angle is stored as a-b-c or c-b-a
// on atom i:
// angle iprev-i-inext changes to iprev-i-jnext
// angle i-inext-ilast changes to i-jnext-jlast
// on atom j:
// angle jprev-j-jnext changes to jprev-j-inext
// angle j-jnext-jlast changes to j-inext-ilast
// on atom inext:
// angle iprev-i-inext changes to jprev-j-inext
// angle i-inext-ilast changes to j-inext-ilast
// on atom jnext:
// angle jprev-j-jnext changes to iprev-i-jnext
// angle j-jnext-jlast changes to i-jnext-jlast
for (iangle = 0; iangle < num_angle[i]; iangle++) {
i1 = angle_atom1[i][iangle];
i2 = angle_atom2[i][iangle];
i3 = angle_atom3[i][iangle];
if (i1 == iprevtag && i2 == itag && i3 == inexttag)
angle_atom3[i][iangle] = jnexttag;
else if (i1 == inexttag && i2 == itag && i3 == iprevtag)
angle_atom1[i][iangle] = jnexttag;
else if (i1 == itag && i2 == inexttag && i3 == ilasttag) {
angle_atom2[i][iangle] = jnexttag;
angle_atom3[i][iangle] = jlasttag;
} else if (i1 == ilasttag && i2 == inexttag && i3 == itag) {
angle_atom1[i][iangle] = jlasttag;
angle_atom2[i][iangle] = jnexttag;
}
}
for (jangle = 0; jangle < num_angle[j]; jangle++) {
j1 = angle_atom1[j][jangle];
j2 = angle_atom2[j][jangle];
j3 = angle_atom3[j][jangle];
if (j1 == jprevtag && j2 == jtag && j3 == jnexttag)
angle_atom3[j][jangle] = inexttag;
else if (j1 == jnexttag && j2 == jtag && j3 == jprevtag)
angle_atom1[j][jangle] = inexttag;
else if (j1 == jtag && j2 == jnexttag && j3 == jlasttag) {
angle_atom2[j][jangle] = inexttag;
angle_atom3[j][jangle] = ilasttag;
} else if (j1 == jlasttag && j2 == jnexttag && j3 == jtag) {
angle_atom1[j][jangle] = ilasttag;
angle_atom2[j][jangle] = inexttag;
}
}
for (iangle = 0; iangle < num_angle[inext]; iangle++) {
i1 = angle_atom1[inext][iangle];
i2 = angle_atom2[inext][iangle];
i3 = angle_atom3[inext][iangle];
if (i1 == iprevtag && i2 == itag && i3 == inexttag) {
angle_atom1[inext][iangle] = jprevtag;
angle_atom2[inext][iangle] = jtag;
} else if (i1 == inexttag && i2 == itag && i3 == iprevtag) {
angle_atom2[inext][iangle] = jtag;
angle_atom3[inext][iangle] = jprevtag;
} else if (i1 == itag && i2 == inexttag && i3 == ilasttag)
angle_atom1[inext][iangle] = jtag;
else if (i1 == ilasttag && i2 == inexttag && i3 == itag)
angle_atom3[inext][iangle] = jtag;
}
for (jangle = 0; jangle < num_angle[jnext]; jangle++) {
j1 = angle_atom1[jnext][jangle];
j2 = angle_atom2[jnext][jangle];
j3 = angle_atom3[jnext][jangle];
if (j1 == jprevtag && j2 == jtag && j3 == jnexttag) {
angle_atom1[jnext][jangle] = iprevtag;
angle_atom2[jnext][jangle] = itag;
} else if (j1 == jnexttag && j2 == jtag && j3 == jprevtag) {
angle_atom2[jnext][jangle] = itag;
angle_atom3[jnext][jangle] = iprevtag;
} else if (j1 == jtag && j2 == jnexttag && j3 == jlasttag)
angle_atom1[jnext][jangle] = itag;
else if (j1 == jlasttag && j2 == jnexttag && j3 == jtag)
angle_atom3[jnext][jangle] = itag;
}
// done if newton bond set
if (newton_bond) return;
// change angles stored by iprev,ilast,jprev,jlast
// on atom iprev: angle iprev-i-inext changes to iprev-i-jnext
// on atom jprev: angle jprev-j-jnext changes to jprev-j-inext
// on atom ilast: angle i-inext-ilast changes to j-inext-ilast
// on atom jlast: angle j-jnext-jlast changes to i-jnext-jlast
for (iangle = 0; iangle < num_angle[iprev]; iangle++) {
i1 = angle_atom1[iprev][iangle];
i2 = angle_atom2[iprev][iangle];
i3 = angle_atom3[iprev][iangle];
if (i1 == iprevtag && i2 == itag && i3 == inexttag)
angle_atom3[iprev][iangle] = jnexttag;
else if (i1 == inexttag && i2 == itag && i3 == iprevtag)
angle_atom1[iprev][iangle] = jnexttag;
}
for (jangle = 0; jangle < num_angle[jprev]; jangle++) {
j1 = angle_atom1[jprev][jangle];
j2 = angle_atom2[jprev][jangle];
j3 = angle_atom3[jprev][jangle];
if (j1 == jprevtag && j2 == jtag && j3 == jnexttag)
angle_atom3[jprev][jangle] = inexttag;
else if (j1 == jnexttag && j2 == jtag && j3 == jprevtag)
angle_atom1[jprev][jangle] = inexttag;
}
for (iangle = 0; iangle < num_angle[ilast]; iangle++) {
i1 = angle_atom1[ilast][iangle];
i2 = angle_atom2[ilast][iangle];
i3 = angle_atom3[ilast][iangle];
if (i1 == itag && i2 == inexttag && i3 == ilasttag)
angle_atom1[ilast][iangle] = jtag;
else if (i1 == ilasttag && i2 == inexttag && i3 == itag)
angle_atom3[ilast][iangle] = jtag;
}
for (jangle = 0; jangle < num_angle[jlast]; jangle++) {
j1 = angle_atom1[jlast][jangle];
j2 = angle_atom2[jlast][jangle];
j3 = angle_atom3[jlast][jangle];
if (j1 == jtag && j2 == jnexttag && j3 == jlasttag)
angle_atom1[jlast][jangle] = itag;
else if (j1 == jlasttag && j2 == jnexttag && j3 == jtag)
angle_atom3[jlast][jangle] = itag;
}
}
/* ---------------------------------------------------------------------- */
int FixBondSwap::modify_param(int narg, char **arg)
{
if (strcmp(arg[0],"temp") == 0) {
if (narg < 2) error->all("Illegal fix_modify command");
if (tflag) {
modify->delete_compute(id_temp);
tflag = 0;
}
delete [] id_temp;
int n = strlen(arg[1]) + 1;
id_temp = new char[n];
strcpy(id_temp,arg[1]);
int icompute = modify->find_compute(id_temp);
if (icompute < 0) error->all("Could not find fix_modify temperature ID");
temperature = modify->compute[icompute];
if (temperature->tempflag == 0)
error->all("Fix_modify temperature ID does not compute temperature");
if (temperature->igroup != igroup && comm->me == 0)
error->warning("Group for fix_modify temp != fix group");
return 2;
}
return 0;
}
/* ----------------------------------------------------------------------
compute squared distance between atoms I,J
must use minimum_image since J was found thru atom->map()
------------------------------------------------------------------------- */
double FixBondSwap::dist_rsq(int i, int j)
{
double delx = x[i][0] - x[j][0];
double dely = x[i][1] - x[j][1];
double delz = x[i][2] - x[j][2];
domain->minimum_image(delx,dely,delz);
return (delx*delx + dely*dely + delz*delz);
}
/* ----------------------------------------------------------------------
return pairwise interaction energy between atoms I,J
will always be full non-bond interaction, so factors = 1 in single() call
------------------------------------------------------------------------- */
double FixBondSwap::pair_eng(int i, int j)
{
double tmp;
double rsq = dist_rsq(i,j);
return force->pair->single(i,j,type[i],type[j],rsq,1.0,1.0,tmp);
}
/* ---------------------------------------------------------------------- */
double FixBondSwap::bond_eng(int btype, int i, int j)
{
double rsq = dist_rsq(i,j);
return force->bond->single(btype,rsq,i,j);
}
/* ---------------------------------------------------------------------- */
double FixBondSwap::angle_eng(int atype, int i, int j, int k)
{
// test for non-existent angle at end of chain
if (i == -1 || k == -1) return 0.0;
return force->angle->single(atype,i,j,k);
}
/* ----------------------------------------------------------------------
return bond swapping stats
n = 1 is # of swaps
n = 2 is # of attempted swaps
------------------------------------------------------------------------- */
double FixBondSwap::compute_vector(int n)
{
double one,all;
if (n == 0) one = naccept;
else one = foursome;
MPI_Allreduce(&one,&all,1,MPI_DOUBLE,MPI_SUM,world);
return all;
}
/* ----------------------------------------------------------------------
memory usage of alist
------------------------------------------------------------------------- */
double FixBondSwap::memory_usage()
{
double bytes = nmax * sizeof(int);
return bytes;
}

63
src/MC/fix_bond_swap.h Normal file
View File

@ -0,0 +1,63 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, 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.
------------------------------------------------------------------------- */
#ifdef FIX_CLASS
FixStyle(bond/swap,FixBondSwap)
#else
#ifndef LMP_FIX_BONDSWAP_H
#define LMP_FIX_BONDSWAP_H
#include "fix.h"
#include "pair.h"
namespace LAMMPS_NS {
class FixBondSwap : public Fix {
public:
FixBondSwap(class LAMMPS *, int, char **);
~FixBondSwap();
int setmask();
void init();
void init_list(int, class NeighList *);
void pre_neighbor();
int modify_param(int, char **);
double compute_vector(int);
double memory_usage();
private:
double fraction,cutsq;
int nmax,tflag;
int *alist;
int naccept,foursome;
int angleflag;
char *id_temp;
int *type;
double **x;
class NeighList *list;
class Compute *temperature;
class RanMars *random;
double dist_rsq(int, int);
double pair_eng(int, int);
double bond_eng(int, int, int);
double angle_eng(int, int, int, int);
};
}
#endif
#endif

562
src/MC/fix_gcmc.cpp Normal file
View File

@ -0,0 +1,562 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, 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.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Paul Crozier (SNL)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdlib.h"
#include "string.h"
#include "fix_gcmc.h"
#include "atom.h"
#include "atom_vec.h"
#include "update.h"
#include "modify.h"
#include "fix.h"
#include "comm.h"
#include "group.h"
#include "domain.h"
#include "random_park.h"
#include "force.h"
#include "pair.h"
#include "memory.h"
#include "error.h"
using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
FixGCMC::FixGCMC(LAMMPS *lmp, int narg, char **arg) :
Fix(lmp, narg, arg)
{
if (narg < 11) error->all("Illegal fix GCMC command");
vector_flag = 1;
size_vector = 6;
global_freq = 1;
extvector = 0;
restart_global = 1;
time_depend = 1;
// required args
nevery = atoi(arg[3]);
nexchanges = atoi(arg[4]);
nmcmoves = atoi(arg[5]);
ntype = atoi(arg[6]);
seed = atoi(arg[7]);
reservoir_temperature = atof(arg[8]);
chemical_potential = atof(arg[9]);
displace = atof(arg[10]);
if (ntype <= 0 || ntype > atom->ntypes)
error->all("Invalid atom type in fix GCMC command");
if (nexchanges < 0) error->all("Illegal fix GCMC command");
if (nmcmoves < 0) error->all("Illegal fix GCMC command");
if (seed <= 0) error->all("Illegal fix GCMC command");
if (reservoir_temperature < 0.0) error->all("Illegal fix GCMC command");
if (displace < 0.0) error->all("Illegal fix GCMC command");
// compute beta, lambda, sigma, and the zz factor
beta = 1.0/(force->boltz*reservoir_temperature);
double PI = 4.0*atan(1.0);
double gas_mass = atom->mass[ntype];
double lambda = sqrt(force->hplanck*force->hplanck/
(2.0*PI*gas_mass*force->mvv2e*
force->boltz*reservoir_temperature));
sigma = sqrt(force->boltz*reservoir_temperature/gas_mass/force->mvv2e);
zz = exp(beta*chemical_potential)/(pow(lambda,3));
// set defaults
molflag = 0;
// read options from end of input line
options(narg-11,&arg[11]);
// random number generator, same for all procs
random_equal = new RanPark(lmp,seed);
// random number generator, not the same for all procs
random_unequal = new RanPark(lmp,seed);
// compute the number of MC cycles that occur nevery timesteps
ncycles = nexchanges + nmcmoves;
// set up reneighboring
force_reneighbor = 1;
next_reneighbor = update->ntimestep + 1;
// zero out counters
nmove_attempts = 0.0;
nmove_successes = 0.0;
ndel_attempts = 0.0;
ndel_successes = 0.0;
ninsert_attempts = 0.0;
ninsert_successes = 0.0;
nmax = 0;
local_gas_list = NULL;
}
/* ---------------------------------------------------------------------- */
FixGCMC::~FixGCMC()
{
delete random_equal;
delete random_unequal;
memory->sfree(local_gas_list);
}
/* ---------------------------------------------------------------------- */
int FixGCMC::setmask()
{
int mask = 0;
mask |= PRE_EXCHANGE;
return mask;
}
/* ---------------------------------------------------------------------- */
void FixGCMC::init()
{
// check that no deletable atoms are in atom->firstgroup
// deleting such an atom would not leave firstgroup atoms first
int *type = atom->type;
if (atom->firstgroup >= 0) {
int *mask = atom->mask;
int nlocal = atom->nlocal;
int firstgroupbit = group->bitmask[atom->firstgroup];
int flag = 0;
for (int i = 0; i < nlocal; i++)
if ((type[i] == ntype) && (mask[i] && firstgroupbit)) flag = 1;
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall)
error->all("Cannot do GCMC on atoms in atom_modify first group");
}
// if molflag not set, warn if any deletable atom has a mol ID
if (molflag == 0 && atom->molecule_flag) {
int *molecule = atom->molecule;
int *mask = atom->mask;
int nlocal = atom->nlocal;
int flag = 0;
for (int i = 0; i < nlocal; i++)
if (type[i] == ntype)
if (molecule[i]) flag = 1;
int flagall;
MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world);
if (flagall && comm->me == 0)
error->warning("Fix GCMC may delete atom with non-zero molecule ID");
}
if (molflag && atom->molecule_flag == 0)
error->all("Fix GCMC molecule command requires atom attribute molecule");
if (molflag != 0) error->all("Fix GCMC molecule feature does not yet work");
if (force->pair->single_enable == 0)
error->all("Fix GCMC incompatible with given pair_style");
}
/* ----------------------------------------------------------------------
attempt particle insertions and deletions
done before exchange, borders, reneighbor
so that ghost atoms and neighbor lists will be correct
------------------------------------------------------------------------- */
void FixGCMC::pre_exchange()
{
// just return if should not be called on this timestep
if (next_reneighbor != update->ntimestep) return;
if (domain->triclinic == 0) {
xlo = domain->boxlo[0];
xhi = domain->boxhi[0];
ylo = domain->boxlo[1];
yhi = domain->boxhi[1];
zlo = domain->boxlo[2];
zhi = domain->boxhi[2];
sublo = domain->sublo;
subhi = domain->subhi;
} else {
xlo = domain->boxlo_bound[0];
xhi = domain->boxhi_bound[0];
ylo = domain->boxlo_bound[1];
yhi = domain->boxhi_bound[1];
zlo = domain->boxlo_bound[2];
zhi = domain->boxhi_bound[2];
sublo = domain->sublo_lamda;
subhi = domain->subhi_lamda;
}
volume = domain->xprd * domain->yprd * domain->zprd;
// grow local_gas_list array if necessary
if (atom->nlocal > nmax) {
memory->sfree(local_gas_list);
nmax = atom->nmax;
local_gas_list = (int *) memory->smalloc(nmax*sizeof(int),
"GCMC:local_gas_list");
}
int *type = atom->type;
ngas_local = 0;
for (int i = 0; i < atom->nlocal; i++)
if (type[i] == ntype)
local_gas_list[ngas_local++] = i;
MPI_Allreduce(&ngas_local,&ngas,1,MPI_INT,MPI_SUM,world);
MPI_Scan(&ngas_local,&ngas_before,1,MPI_INT,MPI_SUM,world);
ngas_before -= ngas_local;
// perform ncycles MC cycles
for (int i = 0; i < ncycles; i++) {
int random_int_fraction =
static_cast<int>(random_equal->uniform()*ncycles) + 1;
if (random_int_fraction <= nmcmoves) {
attempt_move();
} else {
if (random_equal->uniform() < 0.5) attempt_deletion();
else attempt_insertion();
}
}
next_reneighbor = update->ntimestep + nevery;
}
/* ----------------------------------------------------------------------
choose particle randomly across all procs and attempt displacement
------------------------------------------------------------------------- */
void FixGCMC::attempt_move()
{
int i,iwhichglobal,iwhichlocal;
double rx,ry,rz;
double coord[3];
double **x = atom->x;
nmove_attempts += 1.0;
int success = 0;
iwhichglobal = static_cast<int> (ngas*random_equal->uniform());
if ((iwhichglobal >= ngas_before) &&
(iwhichglobal < ngas_before + ngas_local)) {
iwhichlocal = iwhichglobal - ngas_before;
i = local_gas_list[iwhichlocal];
double energy_before = energy(i,x[i]);
double rsq = 1.1;
while (rsq > 1.0) {
rx = 2*random_unequal->uniform() - 1.0;
ry = 2*random_unequal->uniform() - 1.0;
if (domain->dimension == 3) rz = 2*random_unequal->uniform() - 1.0;
else rz = 0.0;
rsq = rx*rx + ry*ry + rz*rz;
}
coord[0] = x[i][0] + displace*rx;
coord[1] = x[i][1] + displace*ry;
coord[2] = x[i][2] + displace*rz;
double energy_after = energy(i,coord);
if (random_unequal->uniform() < exp(-beta*(energy_after - energy_before))) {
x[i][0] = coord[0];
x[i][1] = coord[1];
x[i][2] = coord[2];
success = 1;
}
}
int success_all = 0;
MPI_Allreduce(&success,&success_all,1,MPI_INT,MPI_MAX,world);
if (success_all) {
nmove_successes += 1.0;
comm->borders();
}
}
/* ----------------------------------------------------------------------
attempt particle deletion
------------------------------------------------------------------------- */
void FixGCMC::attempt_deletion()
{
ndel_attempts += 1.0;
if (ngas == 0) return;
int i,iwhichglobal,iwhichlocal;
AtomVec *avec = atom->avec;
// choose particle randomly across all procs and delete it
// keep ngas, ngas_local, ngas_before, and local_gas_list current
// after each deletion
int success = 0;
iwhichglobal = static_cast<int> (ngas*random_equal->uniform());
if ((iwhichglobal >= ngas_before) &&
(iwhichglobal < ngas_before + ngas_local)) {
iwhichlocal = iwhichglobal - ngas_before;
i = local_gas_list[iwhichlocal];
double deletion_energy = energy(i,atom->x[i]);
if (random_unequal->uniform() <
ngas*exp(beta*deletion_energy)/(zz*volume)) {
avec->copy(atom->nlocal-1,i,1);
atom->nlocal--;
local_gas_list[iwhichlocal] = local_gas_list[ngas_local-1];
ngas_local--;
success = 1;
}
}
int success_all = 0;
MPI_Allreduce(&success,&success_all,1,MPI_INT,MPI_MAX,world);
if (success_all) {
ngas--;
ndel_successes += 1.0;
atom->natoms--;
if (iwhichglobal < ngas_before) ngas_before--;
comm->borders();
if (atom->tag_enable) {
atom->tag_extend();
if (atom->map_style) {
atom->map_init();
atom->map_set();
}
}
}
}
/* ----------------------------------------------------------------------
attempt particle insertion
------------------------------------------------------------------------- */
void FixGCMC::attempt_insertion()
{
int flag,success;
double coord[3],lamda[3];
double *newcoord;
ninsert_attempts += 1.0;
// choose random position for new atom within box
coord[0] = xlo + random_equal->uniform() * (xhi-xlo);
coord[1] = ylo + random_equal->uniform() * (yhi-ylo);
coord[2] = zlo + random_equal->uniform() * (zhi-zlo);
// check if new atom is in my sub-box or above it if I'm highest proc
// if so, add to my list via create_atom()
// initialize info about the atoms
// set group mask to "all" plus fix group
if (domain->triclinic) {
domain->x2lamda(coord,lamda);
newcoord = lamda;
} else newcoord = coord;
flag = 0;
if (newcoord[0] >= sublo[0] && newcoord[0] < subhi[0] &&
newcoord[1] >= sublo[1] && newcoord[1] < subhi[1] &&
newcoord[2] >= sublo[2] && newcoord[2] < subhi[2]) flag = 1;
success = 0;
if (flag) {
int nall = atom->nlocal + atom->nghost;
double insertion_energy = energy(nall,coord);
if (random_unequal->uniform() <
zz*volume*exp(-beta*insertion_energy)/(ngas+1)) {
atom->avec->create_atom(ntype,coord);
int m = atom->nlocal - 1;
atom->type[m] = ntype;
atom->mask[m] = 1 | groupbit;
atom->v[m][0] = random_unequal->gaussian()*sigma;
atom->v[m][1] = random_unequal->gaussian()*sigma;
atom->v[m][2] = random_unequal->gaussian()*sigma;
int nfix = modify->nfix;
Fix **fix = modify->fix;
for (int j = 0; j < nfix; j++)
if (fix[j]->create_attribute) fix[j]->set_arrays(m);
if (atom->nlocal > nmax) {
nmax = atom->nmax;
local_gas_list = (int *)
memory->srealloc(local_gas_list,nmax*sizeof(int),
"GCMC:local_gas_list");
}
local_gas_list[ngas_local] = atom->nlocal;
ngas_local++;
success = 1;
}
}
int success_all = 0;
MPI_Allreduce(&success,&success_all,1,MPI_INT,MPI_MAX,world);
if (success_all) {
ngas++;
ninsert_successes += 1.0;
MPI_Scan(&ngas_local,&ngas_before,1,MPI_INT,MPI_SUM,world);
ngas_before -= ngas_local;
comm->borders();
if (atom->tag_enable) {
atom->natoms++;
atom->tag_extend();
if (atom->map_style) {
atom->map_init();
atom->map_set();
}
}
}
}
/* ----------------------------------------------------------------------
compute particle's interaction energy with the rest of the system
------------------------------------------------------------------------- */
double FixGCMC::energy(int i, double *coord)
{
double delx,dely,delz,rsq;
double **x = atom->x;
int *type = atom->type;
int nall = atom->nlocal + atom->nghost;
pair = force->pair;
cutsq = force->pair->cutsq;
double fpair = 0.0;
double factor_coul = 1.0;
double factor_lj = 1.0;
double total_energy = 0.0;
for (int j = 0; j < nall; j++) {
if (i == j) continue;
delx = coord[0] - x[j][0];
dely = coord[1] - x[j][1];
delz = coord[2] - x[j][2];
rsq = delx*delx + dely*dely + delz*delz;
int jtype = type[j];
if (rsq < cutsq[ntype][jtype])
total_energy +=
pair->single(i,j,ntype,jtype,rsq,factor_coul,factor_lj,fpair);
}
return total_energy;
}
/* ----------------------------------------------------------------------
parse optional parameters at end of input line
------------------------------------------------------------------------- */
void FixGCMC::options(int narg, char **arg)
{
if (narg < 0) error->all("Illegal fix GCMC command");
int iarg = 0;
while (iarg < narg) {
if (strcmp(arg[iarg],"molecule") == 0) {
if (iarg+2 > narg) error->all("Illegal fix GCMC command");
if (strcmp(arg[iarg+1],"no") == 0) molflag = 0;
else if (strcmp(arg[iarg+1],"yes") == 0) molflag = 1;
else error->all("Illegal fix evaporate command");
iarg += 2;
} else error->all("Illegal fix GCMC command");
}
}
/* ----------------------------------------------------------------------
return acceptance ratios
------------------------------------------------------------------------- */
double FixGCMC::compute_vector(int n)
{
if (n == 0) return nmove_attempts;
if (n == 1) return nmove_successes;
if (n == 2) return ndel_attempts;
if (n == 3) return ndel_successes;
if (n == 4) return ninsert_attempts;
if (n == 5) return ninsert_successes;
return 0.0;
}
/* ----------------------------------------------------------------------
memory usage of local atom-based arrays
------------------------------------------------------------------------- */
double FixGCMC::memory_usage()
{
double bytes = nmax * sizeof(int);
return bytes;
}
/* ----------------------------------------------------------------------
pack entire state of Fix into one write
------------------------------------------------------------------------- */
void FixGCMC::write_restart(FILE *fp)
{
int n = 0;
double list[4];
list[n++] = random_equal->state();
list[n++] = random_unequal->state();
list[n++] = next_reneighbor;
if (comm->me == 0) {
int size = n * sizeof(double);
fwrite(&size,sizeof(int),1,fp);
fwrite(list,sizeof(double),n,fp);
}
}
/* ----------------------------------------------------------------------
use state info from restart file to restart the Fix
------------------------------------------------------------------------- */
void FixGCMC::restart(char *buf)
{
int n = 0;
double *list = (double *) buf;
seed = static_cast<int> (list[n++]);
random_equal->reset(seed);
seed = static_cast<int> (list[n++]);
random_unequal->reset(seed);
next_reneighbor = static_cast<int> (list[n++]);
}

78
src/MC/fix_gcmc.h Normal file
View File

@ -0,0 +1,78 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, 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.
------------------------------------------------------------------------- */
#ifdef FIX_CLASS
FixStyle(gcmc,FixGCMC)
#else
#ifndef LMP_FIX_GCMC_H
#define LMP_FIX_GCMC_H
#include "stdio.h"
#include "fix.h"
namespace LAMMPS_NS {
class FixGCMC : public Fix {
public:
FixGCMC(class LAMMPS *, int, char **);
~FixGCMC();
int setmask();
void init();
void pre_exchange();
void attempt_move();
void attempt_deletion();
void attempt_insertion();
double energy(int, double *);
double compute_vector(int);
double memory_usage();
void write_restart(FILE *);
void restart(char *);
private:
int ntype,nevery,seed;
int ncycles,nexchanges,nmcmoves;
int ngas; // # of gas molecules (or atoms) on all procs
int ngas_local; // # of gas molecules (or atoms) on this proc
int ngas_before; // # of gas molecules (or atoms) on procs < this proc
int molflag; // 0 = atomic, 1 = molecular system
double nmove_attempts;
double nmove_successes;
double ndel_attempts;
double ndel_successes;
double ninsert_attempts;
double ninsert_successes;
int nmax;
double reservoir_temperature;
double chemical_potential;
double displace;
double beta,zz,sigma,volume;
double xlo,xhi,ylo,yhi,zlo,zhi;
double *sublo,*subhi;
int *local_gas_list;
double **cutsq;
class Pair *pair;
class RanPark *random_equal;
class RanPark *random_unequal;
void options(int, char **);
};
}
#endif
#endif

525
src/MC/pair_dsmc.cpp Normal file
View File

@ -0,0 +1,525 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, 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.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing authors: Paul Crozier (SNL)
------------------------------------------------------------------------- */
#include "math.h"
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "pair_dsmc.h"
#include "atom.h"
#include "comm.h"
#include "force.h"
#include "memory.h"
#include "error.h"
#include "domain.h"
#include "update.h"
#include "random_mars.h"
#include "limits.h"
using namespace LAMMPS_NS;
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) > (b) ? (a) : (b))
/* ---------------------------------------------------------------------- */
PairDSMC::PairDSMC(LAMMPS *lmp) : Pair(lmp)
{
single_enable = 0;
total_number_of_collisions = 0;
max_particles = max_particle_list = 0;
next_particle = NULL;
random = NULL;
}
/* ---------------------------------------------------------------------- */
PairDSMC::~PairDSMC()
{
if (allocated) {
memory->destroy(setflag);
memory->destroy(cutsq);
memory->destroy(sigma);
memory->destroy(cut);
memory->destroy(V_sigma_max);
memory->destroy(particle_list);
memory->destroy(first);
memory->destroy(number);
}
delete [] next_particle;
delete random;
}
/* ---------------------------------------------------------------------- */
void PairDSMC::compute(int eflag, int vflag)
{
double **x = atom->x;
double *mass = atom->mass;
int *type = atom->type;
int nlocal = atom->nlocal;
for (int i = 1; i <= atom->ntypes; ++i)
for (int j = 0; j < total_ncells; ++j) {
first[i][j] = -1;
number[i][j] = 0;
}
if (atom->nmax > max_particles) {
delete [] next_particle;
max_particles = atom->nmax;
next_particle = new int[max_particles];
}
// find each particle's cell and sort by type
// assume a constant volume and shape simulation domain
// skip particle if outside processor domain
for (int i = 0; i < nlocal; ++i) {
int xcell = static_cast<int>((x[i][0] - domain->boxlo[0])/cellx);
int ycell = static_cast<int>((x[i][1] - domain->boxlo[1])/celly);
int zcell = static_cast<int>((x[i][2] - domain->boxlo[2])/cellz);
if ((xcell < 0) or (xcell > ncellsx-1) or
(ycell < 0) or (ycell > ncellsy-1) or
(zcell < 0) or (zcell > ncellsz-1)) continue;
int icell = xcell + ycell*ncellsx + zcell*ncellsx*ncellsy;
itype = type[i];
next_particle[i] = first[itype][icell];
first[itype][icell] = i;
number[itype][icell]++;
}
for (int icell = 0; icell < total_ncells; ++icell) {
for (itype = 1; itype <= atom->ntypes; ++itype) {
number_of_A = number[itype][icell];
if (number_of_A > max_particle_list) {
max_particle_list = number_of_A;
memory->grow(particle_list,atom->ntypes+1,max_particle_list,
"pair:particle_list");
}
int m = first[itype][icell];
for (int k = 0; k < number_of_A; k++) {
particle_list[itype][k] = m;
m = next_particle[m];
}
}
for (itype = 1; itype <= atom->ntypes; ++itype) {
imass = mass[itype];
number_of_A = number[itype][icell];
for (jtype = itype; jtype <= atom->ntypes; ++jtype) {
jmass = mass[jtype];
number_of_B = number[jtype][icell];
reduced_mass = imass*jmass/(imass + jmass);
total_mass = imass + jmass;
jmass_tmass = jmass/total_mass;
imass_tmass = imass/total_mass;
// if necessary, recompute V_sigma_max values
if (recompute_vsigmamax_stride &&
(update->ntimestep % recompute_vsigmamax_stride == 0))
recompute_V_sigma_max(icell);
// # of collisions to perform for itype-jtype pairs
double &Vs_max = V_sigma_max[itype][jtype];
double num_of_collisions_double = number_of_A * number_of_B *
weighting * Vs_max * update->dt / vol;
if ((itype == jtype) and number_of_B)
num_of_collisions_double *=
0.5 * double(number_of_B - 1) / double(number_of_B);
int num_of_collisions =
convert_double_to_equivalent_int(num_of_collisions_double);
if (num_of_collisions > number_of_A)
error->warning("Pair dsmc: num_of_collisions > number_of_A",0);
if (num_of_collisions > number_of_B)
error->warning("Pair dsmc: num_of_collisions > number_of_B",0);
// perform collisions on pairs of particles in icell
for (int k = 0; k < num_of_collisions; k++) {
if ((number_of_A < 1) or (number_of_B < 1)) break;
int ith_A = static_cast<int>(random->uniform()*number_of_A);
int jth_B = static_cast<int>(random->uniform()*number_of_B);
int i = particle_list[itype][ith_A];
int j = particle_list[jtype][jth_B];
if (i == j) {
k--;
continue;
}
double probability = V_sigma(i,j)/Vs_max;
if (probability > random->uniform()) scatter_random(i,j,icell);
}
}
}
}
}
/* ----------------------------------------------------------------------
allocate all arrays
------------------------------------------------------------------------- */
void PairDSMC::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(cut,n+1,n+1,"pair:cut");
memory->create(sigma,n+1,n+1,"pair:sigma");
memory->create(V_sigma_max,n+1,n+1,"pair:V_sigma_max");
}
/* ----------------------------------------------------------------------
global settings
------------------------------------------------------------------------- */
void PairDSMC::settings(int narg, char **arg)
{
if (narg != 6) error->all("Illegal pair_style command");
cut_global = 0.0;
max_cell_size = force->numeric(arg[0]);
seed = force->inumeric(arg[1]);
weighting = force->numeric(arg[2]);
T_ref = force->numeric(arg[3]);
recompute_vsigmamax_stride = force->inumeric(arg[4]);
vsigmamax_samples = force->inumeric(arg[5]);
// initialize Marsaglia RNG with processor-unique seed
if (max_cell_size <= 0.0) error->all("Illegal pair_style command");
if (seed <= 0) error->all("Illegal pair_style command");
if (random) delete random;
random = new RanMars(lmp,seed + comm->me);
kT_ref = force->boltz*T_ref;
// reset cutoffs that have been explicitly set
if (allocated) {
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i+1; j <= atom->ntypes; j++)
if (setflag[i][j]) cut[i][j] = cut_global;
}
}
/* ----------------------------------------------------------------------
set coeffs for one or more type pairs
------------------------------------------------------------------------- */
void PairDSMC::coeff(int narg, char **arg)
{
if (narg < 3 || narg > 4) error->all("Incorrect args for pair coefficients");
if (!allocated) allocate();
int ilo,ihi,jlo,jhi;
force->bounds(arg[0],atom->ntypes,ilo,ihi);
force->bounds(arg[1],atom->ntypes,jlo,jhi);
double sigma_one = force->numeric(arg[2]);
double cut_one = cut_global;
if (narg == 4) cut_one = force->numeric(arg[3]);
int count = 0;
for (int i = ilo; i <= ihi; i++) {
for (int j = MAX(jlo,i); j <= jhi; j++) {
sigma[i][j] = sigma_one;
cut[i][j] = cut_one;
setflag[i][j] = 1;
count++;
}
}
if (count == 0) error->all("Incorrect args for pair coefficients");
}
/* ----------------------------------------------------------------------
init specific to this pair style
------------------------------------------------------------------------- */
void PairDSMC::init_style()
{
ncellsx = ncellsy = ncellsz = 1;
while (((domain->boxhi[0] - domain->boxlo[0])/ncellsx) > max_cell_size)
ncellsx++;
while (((domain->boxhi[1] - domain->boxlo[1])/ncellsy) > max_cell_size)
ncellsy++;
while (((domain->boxhi[2] - domain->boxlo[2])/ncellsz) > max_cell_size)
ncellsz++;
cellx = (domain->boxhi[0] - domain->boxlo[0])/ncellsx;
celly = (domain->boxhi[1] - domain->boxlo[1])/ncellsy;
cellz = (domain->boxhi[2] - domain->boxlo[2])/ncellsz;
if (comm->me == 0) {
if (screen) fprintf(screen,"DSMC cell size = %g x %g x %g\n",
cellx,celly,cellz);
if (logfile) fprintf(logfile,"DSMC cell size = %g x %g x %g\n",
cellx,celly,cellz);
}
total_ncells = ncellsx*ncellsy*ncellsz;
vol = cellx*celly*cellz;
memory->create(particle_list,atom->ntypes+1,0,"pair:particle_list");
memory->create(first,atom->ntypes+1,total_ncells,"pair:first");
memory->create(number,atom->ntypes+1,total_ncells,"pair:number");
for (int i = 1; i <= atom->ntypes; i++)
for (int j = 1; j <= atom->ntypes; j++)
V_sigma_max[i][j] = 0.0;
two_pi = 8.0*atan(1.0);
}
/* ----------------------------------------------------------------------
init for one type pair i,j and corresponding j,i
------------------------------------------------------------------------- */
double PairDSMC::init_one(int i, int j)
{
if (setflag[i][j] == 0) cut[i][j] = 0.0;
return cut[i][j];
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairDSMC::write_restart(FILE *fp)
{
write_restart_settings(fp);
int i,j;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
fwrite(&setflag[i][j],sizeof(int),1,fp);
if (setflag[i][j]) {
fwrite(&sigma[i][j],sizeof(double),1,fp);
fwrite(&cut[i][j],sizeof(double),1,fp);
}
}
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairDSMC::read_restart(FILE *fp)
{
read_restart_settings(fp);
allocate();
int i,j;
int me = comm->me;
for (i = 1; i <= atom->ntypes; i++)
for (j = i; j <= atom->ntypes; j++) {
if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp);
MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world);
if (setflag[i][j]) {
if (me == 0) {
fread(&sigma[i][j],sizeof(double),1,fp);
fread(&cut[i][j],sizeof(double),1,fp);
}
MPI_Bcast(&sigma[i][j],1,MPI_DOUBLE,0,world);
MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
}
}
}
/* ----------------------------------------------------------------------
proc 0 writes to restart file
------------------------------------------------------------------------- */
void PairDSMC::write_restart_settings(FILE *fp)
{
fwrite(&cut_global,sizeof(double),1,fp);
fwrite(&max_cell_size,sizeof(double),1,fp);
fwrite(&seed,sizeof(int),1,fp);
fwrite(&offset_flag,sizeof(int),1,fp);
fwrite(&mix_flag,sizeof(int),1,fp);
}
/* ----------------------------------------------------------------------
proc 0 reads from restart file, bcasts
------------------------------------------------------------------------- */
void PairDSMC::read_restart_settings(FILE *fp)
{
if (comm->me == 0) {
fread(&cut_global,sizeof(double),1,fp);
fread(&max_cell_size,sizeof(double),1,fp);
fread(&seed,sizeof(int),1,fp);
fread(&offset_flag,sizeof(int),1,fp);
fread(&mix_flag,sizeof(int),1,fp);
}
MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
MPI_Bcast(&max_cell_size,1,MPI_DOUBLE,0,world);
MPI_Bcast(&seed,1,MPI_INT,0,world);
MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
// initialize Marsaglia RNG with processor-unique seed
// same seed that pair_style command initially specified
if (random) delete random;
random = new RanMars(lmp,seed + comm->me);
}
/*-------------------------------------------------------------------------
rezero and recompute the V_sigma_max values this timestep for use during
the next nrezero timesteps
-------------------------------------------------------------------------*/
void PairDSMC::recompute_V_sigma_max(int icell)
{
int i,j,k;
double Vsigma_max = 0;
if (number_of_A && number_of_B) {
for (k = 0; k < vsigmamax_samples; k++) {
i = particle_list[itype]
[static_cast<int>(random->uniform()*number_of_A)];
j = particle_list[jtype]
[static_cast<int>(random->uniform()*number_of_B)];
if (i == j) continue;
Vsigma_max = MAX(Vsigma_max,V_sigma(i,j));
}
}
V_sigma_max[itype][jtype] = Vsigma_max;
}
/*-------------------------------------------------------------------------
VHS model
compute the velocity vector difference between i and j and multiply by
their combined collision cross section, sigma, for neutral-neutral
collisions using the Variable Hard Sphere model
-------------------------------------------------------------------------*/
double PairDSMC::V_sigma(int i, int j)
{
double relative_velocity_sq,relative_velocity,pair_sigma;
double delv[3];
double *vi = atom->v[i];
double *vj = atom->v[j];
subtract3d(vi,vj,delv);
relative_velocity_sq = dot3d(delv,delv);
relative_velocity = sqrt(relative_velocity_sq);
// from Bird eq 4.63, and omega=0.67
// (omega - 0.5) = 0.17
// 1/GAMMA(2.5 - omega) = 1.06418029298371
if (relative_velocity_sq != 0.0)
pair_sigma = sigma[itype][jtype]*
pow(kT_ref/(0.5*reduced_mass*relative_velocity_sq),0.17) *
1.06418029298371;
else
pair_sigma = 0.0;
return relative_velocity*pair_sigma;
}
/*-------------------------------------------------------------------------
generate new velocities for collided particles
-------------------------------------------------------------------------*/
void PairDSMC::scatter_random(int i, int j, int icell)
{
double mag_delv,cos_phi,cos_squared,r,theta;
double delv[3],vcm[3];
double *vi = atom->v[i];
double *vj = atom->v[j];
subtract3d(vi,vj,delv);
if (itype == jtype) mag_delv = sqrt(dot3d(delv,delv))*0.5;
else mag_delv = sqrt(dot3d(delv,delv));
cos_phi = 1.0 - (2.0*random->uniform());
cos_squared = MIN(1.0,cos_phi*cos_phi);
r = sqrt(1.0 - cos_squared);
delv[0] = cos_phi*mag_delv;
theta = two_pi*random->uniform();
delv[1] = r*mag_delv*cos(theta);
delv[2] = r*mag_delv*sin(theta);
if (itype == jtype) {
vcm[0] = (vi[0]+vj[0])*0.5;
vcm[1] = (vi[1]+vj[1])*0.5;
vcm[2] = (vi[2]+vj[2])*0.5;
vi[0] = vcm[0] + delv[0];
vi[1] = vcm[1] + delv[1];
vi[2] = vcm[2] + delv[2];
vj[0] = vcm[0] - delv[0];
vj[1] = vcm[1] - delv[1];
vj[2] = vcm[2] - delv[2];
} else {
vcm[0] = vi[0]*imass_tmass + vj[0]*jmass_tmass;
vcm[1] = vi[1]*imass_tmass + vj[1]*jmass_tmass;
vcm[2] = vi[2]*imass_tmass + vj[2]*jmass_tmass;
vi[0] = vcm[0] + delv[0]*jmass_tmass;
vi[1] = vcm[1] + delv[1]*jmass_tmass;
vi[2] = vcm[2] + delv[2]*jmass_tmass;
vj[0] = vcm[0] - delv[0]*imass_tmass;
vj[1] = vcm[1] - delv[1]*imass_tmass;
vj[2] = vcm[2] - delv[2]*imass_tmass;
}
total_number_of_collisions++;
}
/* ----------------------------------------------------------------------
This method converts the double supplied by the calling function into
an int, which is returned. By adding a random number between 0 and 1
to the double before converting it to an int, we ensure that,
statistically, we round down with probability identical to the
remainder and up the rest of the time. So even though we're using an
integer, we're statistically matching the exact expression represented
by the double.
------------------------------------------------------------------------- */
int PairDSMC::convert_double_to_equivalent_int(double input_double)
{
if (input_double > INT_MAX)
error->all("Tried to convert a double to int, but input_double > INT_MAX");
int output_int = static_cast<int>(input_double + random->uniform());
return output_int;
}

109
src/MC/pair_dsmc.h Normal file
View File

@ -0,0 +1,109 @@
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, 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.
------------------------------------------------------------------------- */
#ifdef PAIR_CLASS
PairStyle(dsmc,PairDSMC)
#else
#ifndef LMP_PAIR_DSMC_H
#define LMP_PAIR_DSMC_H
#include "pair.h"
namespace LAMMPS_NS {
class PairDSMC : public Pair {
public:
PairDSMC(class LAMMPS *);
virtual ~PairDSMC();
virtual void compute(int, int);
virtual void settings(int, char **);
void coeff(int, char **);
void init_style();
double init_one(int, int);
void write_restart(FILE *);
void read_restart(FILE *);
virtual void write_restart_settings(FILE *);
virtual void read_restart_settings(FILE *);
private:
double cut_global;
double **cut;
double **sigma;
double cellx;
double celly;
double cellz;
int ncellsx;
int ncellsy;
int ncellsz;
int total_ncells;
int total_number_of_collisions;
int recompute_vsigmamax_stride;
int vsigmamax_samples;
double T_ref;
double kT_ref;
double two_pi;
double max_cell_size;
int seed;
int number_of_A;
int number_of_B;
int max_particle_list;
class RanMars *random;
int **particle_list;
int **first;
int **number;
double **V_sigma_max;
int max_particles;
int *next_particle;
int itype;
int jtype;
double imass;
double jmass;
double total_mass;
double reduced_mass;
double imass_tmass;
double jmass_tmass;
double vol;
double weighting;
void allocate();
void recompute_V_sigma_max(int);
double V_sigma(int, int);
void scatter_random(int, int, int);
int convert_double_to_equivalent_int(double);
inline void subtract3d(const double *v1, const double *v2, double *v3) {
v3[0] = v2[0] - v1[0];
v3[1] = v2[1] - v1[1];
v3[2] = v2[2] - v1[2];
}
inline double dot3d(const double *v1, const double *v2) {
return( v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2] );
}
};
}
#endif
#endif