forked from lijiext/lammps
Creatd new compute ADF for angular distribution function
This commit is contained in:
parent
52f02f2bbb
commit
04a4a29fcf
|
@ -0,0 +1,207 @@
|
|||
"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
|
||||
|
||||
:link(lws,http://lammps.sandia.gov)
|
||||
:link(ld,Manual.html)
|
||||
:link(lc,Section_commands.html#comm)
|
||||
|
||||
:line
|
||||
|
||||
compute adf command :h3
|
||||
|
||||
[Syntax:]
|
||||
|
||||
compute ID group-ID adf Nbin itype1 jtype1 ktype1 Rjinner1 Rjouter1 Rkinner1 Rkouter1 ... :pre
|
||||
|
||||
ID, group-ID are documented in "compute"_compute.html command :ulb,l
|
||||
adf = style name of this compute command :l
|
||||
Nbin = number of ADF bins :l
|
||||
itypeN = central atom type for Nth ADF histogram (see asterisk form below) :l
|
||||
jtypeN = J atom type for Nth ADF histogram (see asterisk form below) :l
|
||||
ktypeN = K atom type for Nth ADF histogram (see asterisk form below) :l
|
||||
RjinnerN = inner radius of J atom shell for Nth ADF histogram (distance units) :l
|
||||
RjouterN = outer radius of J atom shell for Nth ADF histogram (distance units) :l
|
||||
RkinnerN = inner radius of K atom shell for Nth ADF histogram (distance units) :l
|
||||
RkouterN = outer radius of K atom shell for Nth ADF histogram (distance units) :l
|
||||
|
||||
zero or one keyword/value pairs may be appended :l
|
||||
keyword = {ordinate} :l
|
||||
{ordinate} value = {degree} or {radian} or {cosine}
|
||||
Choose the ordinate parameter for the histogram :pre
|
||||
:ule
|
||||
|
||||
[Examples:]
|
||||
|
||||
compute 1 fluid adf 32 1 1 1 0.0 1.2 0.0 1.2 &
|
||||
1 1 2 0.0 1.2 0.0 1.5 &
|
||||
1 2 2 0.0 1.5 0.0 1.5 &
|
||||
2 1 1 0.0 1.2 0.0 1.2 &
|
||||
2 1 2 0.0 1.5 2.0 3.5 &
|
||||
2 2 2 2.0 3.5 2.0 3.5
|
||||
compute 1 fluid adf 32 1*2 1*2 1*2 0.5 3.5
|
||||
compute 1 fluid adf 32 :pre
|
||||
|
||||
[Description:]
|
||||
|
||||
Define a computation that calculates one or more angular distribution functions
|
||||
(ADF) for a group of particles. Each ADF is calculated in histogram form
|
||||
by measuring the angle formed by a central atom and two neighbor atoms and
|
||||
binning these angles into {Nbin} bins.
|
||||
Only neighbors for which {Rinner} < {R} < {Router} are counted, where
|
||||
{Rinner} and {Router} are specified separately for the first and second
|
||||
neighbor atom in each requested ADF.
|
||||
|
||||
NOTE: If you have a bonded system, then the settings of
|
||||
"special_bonds"_special_bonds.html command can remove pairwise
|
||||
interactions between atoms in the same bond, angle, or dihedral. This
|
||||
is the default setting for the "special_bonds"_special_bonds.html
|
||||
command, and means those pairwise interactions do not appear in the
|
||||
neighbor list. Because this fix uses a neighbor list, it also means
|
||||
those pairs will not be included in the ADF. This does not apply when
|
||||
using long-range coulomb interactions ({coul/long}, {coul/msm},
|
||||
{coul/wolf} or similar. One way to get around this would be to set
|
||||
special_bond scaling factors to very tiny numbers that are not exactly
|
||||
zero (e.g. 1.0e-50). Another workaround is to write a dump file, and
|
||||
use the "rerun"_rerun.html command to compute the ADF for snapshots in
|
||||
the dump file. The rerun script can use a
|
||||
"special_bonds"_special_bonds.html command that includes all pairs in
|
||||
the neighbor list.
|
||||
|
||||
NOTE: If you request any outer cutoff {Router} > force cutoff, or if no
|
||||
pair style is defined, e.g. the "rerun"_rerun.html command is being used to
|
||||
post-process a dump file of snapshots you must insure ghost atom information
|
||||
out to the largest value of {Router} + {skin} is communicated, via the
|
||||
"comm_modify cutoff"_comm_modify.html command, else the ADF computation
|
||||
cannot be performed, and LAMMPS will give an error message. The {skin} value
|
||||
is what is specified with the "neighbor"_neighbor.html command.
|
||||
|
||||
The {itypeN},{jtypeN},{ktypeN} settings can be specified in one of two
|
||||
ways. An explicit numeric value can be used, as in the 1st example
|
||||
above. Or a wild-card asterisk can be used to specify a range of atom
|
||||
types as in the 2nd example above.
|
||||
This takes the form "*" or "*n" or "n*" or "m*n". If N = the
|
||||
number of atom types, then an asterisk with no numeric values means
|
||||
all types from 1 to N. A leading asterisk means all types from 1 to n
|
||||
(inclusive). A trailing asterisk means all types from n to N
|
||||
(inclusive). A middle asterisk means all types from m to n
|
||||
(inclusive).
|
||||
|
||||
If {itypeN}, {jtypeN}, and {ktypeN} are single values, as in the 1st example
|
||||
above, this means that the ADF is computed where atoms of type {itypeN}
|
||||
are the central atom, and neighbor atoms of type {jtypeN} and {ktypeN}
|
||||
are forming the angle. If any of {itypeN}, {jtypeN}, or {ktypeN}
|
||||
represent a range of values via
|
||||
the wild-card asterisk, as in the 2nd example above, this means that the
|
||||
ADF is computed where atoms of any of the range of types represented
|
||||
by {itypeN} are the central atom, and the angle is formed by two neighbors,
|
||||
one neighbor in the range of types represented by {jtypeN} and another neighbor
|
||||
in the range of types represented by {ktypeN}.
|
||||
|
||||
If no {itypeN}, {jtypeN}, {ktypeN} settings are specified, then
|
||||
LAMMPS will generate a single ADF for all atoms in the group.
|
||||
The inner cutoff is set to zero and the outer cutoff is set
|
||||
to the force cutoff. If no pair_style is specified, there is no
|
||||
force cutoff and LAMMPS will give an error message. Note that
|
||||
in most cases, generating an ADF for all atoms is not a good thing.
|
||||
Such an ADF is both uninformative and
|
||||
extremely expensive to compute. For example, with liquid water
|
||||
with a 10 A force cutoff, there are 80,000 angles per atom.
|
||||
In addition, most of the interesting angular structure occurs for
|
||||
neighbors that are the closest to the central atom, involving
|
||||
just a few dozen angles.
|
||||
|
||||
Angles for each ADF are generated by double-looping over the list of
|
||||
neighbors of each central atom I,
|
||||
just as they would be in the force calculation for
|
||||
a threebody potential such as "Stillinger-Weber"_pair_sw.html.
|
||||
The angle formed by central atom I and neighbor atoms J and K is included in an
|
||||
ADF if the following criteria are met:
|
||||
|
||||
atoms I,J,K are all in the specified compute group
|
||||
the distance between atoms I,J is between Rjinner and Rjouter
|
||||
the distance between atoms I,K is between Rkinner and Rkouter
|
||||
the type of the I atom matches itypeN (one or a range of types)
|
||||
atoms I,J,K are distinct
|
||||
the type of the J atom matches jtypeN (one or a range of types)
|
||||
the type of the K atom matches ktypeN (one or a range of types) :ul
|
||||
|
||||
Each unique angle satisfying the above criteria is counted only once, regardless
|
||||
of whether either or both of the neighbor atoms making up the
|
||||
angle appear in both the J and K lists.
|
||||
It is OK if a particular angle is included in more than
|
||||
one individual histogram, due to the way the {itypeN}, {jtypeN}, {ktypeN}
|
||||
arguments are specified.
|
||||
|
||||
The first ADF value for a bin is calculated from the histogram count by
|
||||
dividing by the total number of triples satisfying the criteria,
|
||||
so that the integral of the ADF w.r.t. angle is one i.e. the ADF
|
||||
is a probability density function.
|
||||
|
||||
The second ADF value is reported as a cumulative sum of
|
||||
all bins up to the current bins, averaged
|
||||
over atoms of type {itypeN}. It represents the
|
||||
number of angles per central atom with angle less
|
||||
than or equal to the angle of the current bin,
|
||||
analogous to the coordination
|
||||
number radial distribution function.
|
||||
|
||||
The {ordinate} optional keyword determines
|
||||
whether the bins are of uniform angular size from zero
|
||||
to 180 ({degree}), zero to Pi ({radian}), or the
|
||||
cosine of the angle uniform in the range \[-1,1\] ({cosine}).
|
||||
Regardless of which is chosen, the first ADF will be normalized
|
||||
so that the integral w.r.t. the ordinate is one.
|
||||
|
||||
The simplest way to output the results of the compute adf calculation
|
||||
to a file is to use the "fix ave/time"_fix_ave_time.html command, for
|
||||
example:
|
||||
|
||||
compute myADF all adf 32 2 2 2 0.5 3.5 0.5 3.5
|
||||
fix 1 all ave/time 100 1 100 c_myADF\[*\] file tmp.adf mode vector :pre
|
||||
|
||||
[Output info:]
|
||||
|
||||
This compute calculates a global array with the number of rows =
|
||||
{Nbins}, and the number of columns = 1 + 2*Ntriples, where Ntriples is the
|
||||
number of I,J,K triples specified. The first column has the bin
|
||||
coordinate (angle-related ordinate at midpoint of bin). Each subsequent column has
|
||||
the two ADF values for a specific set of ({itypeN},{jtypeN},{ktypeN})
|
||||
interactions, as described above. These values can be used
|
||||
by any command that uses a global values from a compute as input. See
|
||||
"Section 6.15"_Section_howto.html#howto_15 for an overview of
|
||||
LAMMPS output options.
|
||||
|
||||
The array values calculated by this compute are all "intensive".
|
||||
|
||||
The first column of array values is the angle-related ordinate, either
|
||||
the angle in degrees or radians, or the cosine of the angle. Each
|
||||
subsequent pair of columns gives the first and second kinds of ADF
|
||||
for a specific set of ({itypeN},{jtypeN},{ktypeN}). The values
|
||||
in the first ADF column are normalized numbers >= 0.0,
|
||||
whose integral w.r.t. the ordinate is one,
|
||||
i.e. the first ADF is a normalized probability distribution.
|
||||
The values in the second ADF column are also numbers >= 0.0.
|
||||
They are the cumulative density distribution of angles per atom.
|
||||
By definition, this ADF is monotonically increasing from zero to
|
||||
a maximum value equal to the average total number of
|
||||
angles per atom satisfying the ADF criteria.
|
||||
|
||||
[Restrictions:]
|
||||
|
||||
The ADF is not computed for neighbors outside the force cutoff,
|
||||
since processors (in parallel) don't know about atom coordinates for
|
||||
atoms further away than that distance. If you want an ADF for larger
|
||||
distances, you can use the "rerun"_rerun.html command to post-process
|
||||
a dump file and set the cutoff for the potential to be longer in the
|
||||
rerun script. Note that in the rerun context, the force cutoff is
|
||||
arbitrary, since you aren't running dynamics and thus are not changing
|
||||
your model.
|
||||
|
||||
[Related commands:]
|
||||
|
||||
"compute rdf"_compute_rdf.html, "fix ave/time"_fix_ave_time.html, "compute_modify"_compute_modify.html
|
||||
|
||||
[Default:]
|
||||
|
||||
The keyword default is ordinate = degree.
|
||||
|
||||
|
|
@ -0,0 +1,580 @@
|
|||
/* ----------------------------------------------------------------------
|
||||
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: Aidan P. Thompson (SNL)
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
#include <mpi.h>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include "compute_adf.h"
|
||||
#include "atom.h"
|
||||
#include "update.h"
|
||||
#include "force.h"
|
||||
#include "pair.h"
|
||||
#include "domain.h"
|
||||
#include "neighbor.h"
|
||||
#include "neigh_request.h"
|
||||
#include "neigh_list.h"
|
||||
#include "group.h"
|
||||
#include "math_const.h"
|
||||
#include "memory.h"
|
||||
#include "error.h"
|
||||
#include "comm.h"
|
||||
|
||||
using namespace LAMMPS_NS;
|
||||
using namespace MathConst;
|
||||
|
||||
enum{DEGREE, RADIAN, COSINE};
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
compute angular distribution functions for I, J, K atoms
|
||||
---------------------------------------------------------------------- */
|
||||
|
||||
ComputeADF::ComputeADF(LAMMPS *lmp, int narg, char **arg) :
|
||||
Compute(lmp, narg, arg),
|
||||
ilo(NULL), ihi(NULL), jlo(NULL), jhi(NULL), klo(NULL), khi(NULL),
|
||||
iatomcount(NULL), iatomcountall(NULL),
|
||||
hist(NULL), histall(NULL),
|
||||
iatomflag(NULL),
|
||||
jatomflag(NULL), rcutinnerj(NULL), rcutouterj(NULL),
|
||||
katomflag(NULL), rcutinnerk(NULL), rcutouterk(NULL),
|
||||
maxjatom(NULL), numjatom(NULL), neighjatom(NULL),
|
||||
maxkatom(NULL), numkatom(NULL), neighkatom(NULL),
|
||||
maxjkatom(NULL), numjkatom(NULL), neighjkatom(NULL), bothjkatom(NULL)
|
||||
{
|
||||
int nargsperadf = 7;
|
||||
|
||||
if (narg < 4 ) error->all(FLERR,"Illegal compute adf command");
|
||||
|
||||
array_flag = 1;
|
||||
extarray = 0;
|
||||
|
||||
// default values
|
||||
|
||||
ordinate_style = DEGREE;
|
||||
cutflag = 0;
|
||||
|
||||
nbin = force->inumeric(FLERR,arg[3]);
|
||||
if (nbin < 1) error->all(FLERR,"Illegal compute adf command");
|
||||
|
||||
// optional args
|
||||
// nargtriple = # of triplewise args, starting at iarg = 4
|
||||
|
||||
int iarg;
|
||||
for (iarg = 4; iarg < narg; iarg++)
|
||||
if (strcmp(arg[iarg],"ordinate") == 0) break;
|
||||
|
||||
int nargtriple = iarg - 4;
|
||||
|
||||
// loop over keywords
|
||||
|
||||
while (iarg < narg) {
|
||||
if (strcmp(arg[iarg],"ordinate") == 0) {
|
||||
if (iarg+2 > narg) error->all(FLERR,"Illegal compute adf command");
|
||||
if (strcmp(arg[iarg+1],"degree") == 0) ordinate_style = DEGREE;
|
||||
else if (strcmp(arg[iarg+1],"radian") == 0) ordinate_style = RADIAN;
|
||||
else if (strcmp(arg[iarg+1],"cosine") == 0) ordinate_style = COSINE;
|
||||
else error->all(FLERR,"Illegal compute adf command");
|
||||
iarg += 2;
|
||||
} else error->all(FLERR,"Illegal compute adf command");
|
||||
}
|
||||
|
||||
// triplewise args
|
||||
|
||||
if (!nargtriple) ntriples = 1;
|
||||
else {
|
||||
if (nargtriple % nargsperadf)
|
||||
error->all(FLERR,"Illegal compute adf command");
|
||||
ntriples = nargtriple/nargsperadf;
|
||||
}
|
||||
|
||||
size_array_rows = nbin;
|
||||
size_array_cols = 1 + 2*ntriples;
|
||||
|
||||
int ntypes = atom->ntypes;
|
||||
memory->create(iatomflag,ntriples,ntypes+1,
|
||||
"adf:iatomflag");
|
||||
memory->create(jatomflag,ntriples,ntypes+1,
|
||||
"adf:jatomflag");
|
||||
memory->create(katomflag,ntriples,ntypes+1,
|
||||
"adf:katomflag");
|
||||
|
||||
ilo = new int[ntriples];
|
||||
ihi = new int[ntriples];
|
||||
jlo = new int[ntriples];
|
||||
jhi = new int[ntriples];
|
||||
klo = new int[ntriples];
|
||||
khi = new int[ntriples];
|
||||
iatomcount = new int[ntriples];
|
||||
iatomcountall = new int[ntriples];
|
||||
|
||||
rcutinnerj = new double[ntriples];
|
||||
rcutouterj = new double[ntriples];
|
||||
rcutinnerk = new double[ntriples];
|
||||
rcutouterk = new double[ntriples];
|
||||
|
||||
if (!nargtriple) {
|
||||
ilo[0] = 1; ihi[0] = ntypes;
|
||||
jlo[0] = 1; jhi[0] = ntypes;
|
||||
klo[0] = 1; khi[0] = ntypes;
|
||||
} else {
|
||||
cutflag = 1;
|
||||
iarg = 4;
|
||||
for (int itriple = 0; itriple < ntriples; itriple++) {
|
||||
force->bounds(FLERR,arg[iarg],atom->ntypes,ilo[itriple],ihi[itriple]);
|
||||
force->bounds(FLERR,arg[iarg+1],atom->ntypes,jlo[itriple],jhi[itriple]);
|
||||
force->bounds(FLERR,arg[iarg+2],atom->ntypes,klo[itriple],khi[itriple]);
|
||||
if (ilo[itriple] > ihi[itriple] ||
|
||||
jlo[itriple] > jhi[itriple] ||
|
||||
klo[itriple] > khi[itriple])
|
||||
error->all(FLERR,"Illegal compute adf command");
|
||||
rcutinnerj[itriple] = force->numeric(FLERR,arg[iarg+3]);
|
||||
rcutouterj[itriple] = force->numeric(FLERR,arg[iarg+4]);
|
||||
if (rcutinnerj[itriple] < 0.0 || rcutinnerj[itriple] >= rcutouterj[itriple])
|
||||
error->all(FLERR,"Illegal compute adf command");
|
||||
rcutinnerk[itriple] = force->numeric(FLERR,arg[iarg+5]);
|
||||
rcutouterk[itriple] = force->numeric(FLERR,arg[iarg+6]);
|
||||
if (rcutinnerk[itriple] < 0.0 || rcutinnerk[itriple] >= rcutouterk[itriple])
|
||||
error->all(FLERR,"Illegal compute adf command");
|
||||
iarg += nargsperadf;
|
||||
}
|
||||
}
|
||||
|
||||
// identify central atom types
|
||||
|
||||
int i,j,k;
|
||||
|
||||
for (int m = 0; m < ntriples; m++) {
|
||||
for (i = 1; i <= ntypes; i++)
|
||||
iatomflag[m][i] = 0;
|
||||
for (i = ilo[m]; i <= ihi[m]; i++)
|
||||
iatomflag[m][i] = 1;
|
||||
}
|
||||
|
||||
// identify j atom types
|
||||
|
||||
for (int m = 0; m < ntriples; m++) {
|
||||
for (j = 1; j <= ntypes; j++)
|
||||
jatomflag[m][j] = 0;
|
||||
for (j = jlo[m]; j <= jhi[m]; j++)
|
||||
jatomflag[m][j] = 1;
|
||||
}
|
||||
|
||||
// identify k atom types
|
||||
|
||||
for (int m = 0; m < ntriples; m++) {
|
||||
for (k = 1; k <= ntypes; k++)
|
||||
katomflag[m][k] = 0;
|
||||
for (k = klo[m]; k <= khi[m]; k++)
|
||||
katomflag[m][k] = 1;
|
||||
}
|
||||
|
||||
memory->create(hist,ntriples,nbin,"adf:hist");
|
||||
memory->create(histall,ntriples,nbin,"adf:histall");
|
||||
memory->create(array,nbin,1+2*ntriples,"adf:array");
|
||||
|
||||
// initialize list of jatom neighbor lists
|
||||
|
||||
maxjatom = new int[ntriples];
|
||||
numjatom = new int[ntriples];
|
||||
neighjatom = new int*[ntriples];
|
||||
for (int m = 0; m < ntriples; m++) {
|
||||
maxjatom[m] = 10;
|
||||
memory->create(neighjatom[m],maxjatom[m],"adf:neighjatom");
|
||||
}
|
||||
|
||||
// initialize list of katom neighbor lists
|
||||
|
||||
maxkatom = new int[ntriples];
|
||||
numkatom = new int[ntriples];
|
||||
neighkatom = new int*[ntriples];
|
||||
for (int m = 0; m < ntriples; m++) {
|
||||
maxkatom[m] = 10;
|
||||
memory->create(neighkatom[m],maxkatom[m],"adf:neighkatom");
|
||||
}
|
||||
|
||||
// initialize list of short neighbor lists
|
||||
|
||||
maxjkatom = new int[ntriples];
|
||||
numjkatom = new int[ntriples];
|
||||
neighjkatom = new int*[ntriples];
|
||||
bothjkatom = new int*[ntriples];
|
||||
delrjkatom = new double**[ntriples];
|
||||
for (int m = 0; m < ntriples; m++) {
|
||||
maxjkatom[m] = 10;
|
||||
memory->create(neighjkatom[m],maxjkatom[m],"adf:neighjkatom");
|
||||
memory->create(bothjkatom[m],maxjkatom[m],"adf:bothjkatom");
|
||||
memory->create(delrjkatom[m],maxjkatom[m],4,"adf:delrjkatom");
|
||||
}
|
||||
|
||||
rad2deg = 180.0 / MY_PI;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
ComputeADF::~ComputeADF()
|
||||
{
|
||||
memory->destroy(iatomflag);
|
||||
delete [] ilo;
|
||||
delete [] ihi;
|
||||
delete [] jlo;
|
||||
delete [] jhi;
|
||||
delete [] klo;
|
||||
delete [] khi;
|
||||
delete [] iatomcount;
|
||||
delete [] iatomcountall;
|
||||
memory->destroy(hist);
|
||||
memory->destroy(histall);
|
||||
memory->destroy(array);
|
||||
|
||||
memory->destroy(jatomflag);
|
||||
delete [] rcutinnerj;
|
||||
delete [] rcutouterj;
|
||||
delete [] maxjatom;
|
||||
delete [] numjatom;
|
||||
for (int m = 0; m < ntriples; m++)
|
||||
memory->destroy(neighjatom[m]);
|
||||
delete [] neighjatom;
|
||||
|
||||
memory->destroy(katomflag);
|
||||
delete [] rcutinnerk;
|
||||
delete [] rcutouterk;
|
||||
delete [] maxkatom;
|
||||
delete [] numkatom;
|
||||
for (int m = 0; m < ntriples; m++)
|
||||
memory->destroy(neighkatom[m]);
|
||||
delete [] neighkatom;
|
||||
|
||||
delete [] maxjkatom;
|
||||
delete [] numjkatom;
|
||||
for (int m = 0; m < ntriples; m++)
|
||||
memory->destroy(neighjkatom[m]);
|
||||
delete [] neighjkatom;
|
||||
for (int m = 0; m < ntriples; m++)
|
||||
memory->destroy(bothjkatom[m]);
|
||||
delete [] bothjkatom;
|
||||
for (int m = 0; m < ntriples; m++)
|
||||
memory->destroy(delrjkatom[m]);
|
||||
delete [] delrjkatom;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
void ComputeADF::init()
|
||||
{
|
||||
double mycutneigh;
|
||||
double maxouter;
|
||||
|
||||
if (!cutflag) {
|
||||
if (!force->pair)
|
||||
error->all(FLERR,"Compute adf requires a pair style be defined "
|
||||
"or outer cutoff specified");
|
||||
rcutinnerj[0] = 0.0;
|
||||
rcutinnerk[0] = 0.0;
|
||||
rcutouterj[0] = force->pair->cutforce;
|
||||
rcutouterk[0] = force->pair->cutforce;
|
||||
maxouter = force->pair->cutforce;;
|
||||
} else {
|
||||
maxouter = 0.0;
|
||||
for (int m = 0; m < ntriples; m++) {
|
||||
maxouter = MAX(rcutouterj[m],maxouter);
|
||||
maxouter = MAX(rcutouterk[m],maxouter);
|
||||
}
|
||||
}
|
||||
|
||||
// specify mycutneigh if force cutoff too small or non-existent
|
||||
|
||||
if (!(force->pair) || maxouter > force->pair->cutforce) {
|
||||
double skin = neighbor->skin;
|
||||
mycutneigh = maxouter + skin;
|
||||
if (mycutneigh > comm->cutghostuser)
|
||||
error->all(FLERR,"Compute adf outer cutoff exceeds ghost atom range - "
|
||||
"use comm_modify cutoff command");
|
||||
}
|
||||
|
||||
// assign ordinate values to 1st column of output array
|
||||
|
||||
int x0;
|
||||
if (ordinate_style == DEGREE) {
|
||||
deltax = MY_PI / nbin * rad2deg;
|
||||
deltaxinv = nbin / MY_PI;
|
||||
x0 = 0.0;
|
||||
|
||||
} else if (ordinate_style == RADIAN) {
|
||||
deltax = MY_PI / nbin;
|
||||
deltaxinv = nbin / MY_PI;
|
||||
x0 = 0.0;
|
||||
|
||||
} else if (ordinate_style == COSINE) {
|
||||
deltax = 2.0 / nbin;
|
||||
deltaxinv = 1.0/deltax;
|
||||
x0 = -1.0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < nbin; i++)
|
||||
array[i][0] = x0 + (i+0.5) * deltax;
|
||||
|
||||
// need an occasional full neighbor list
|
||||
// if mycutneigh specified, request a cutoff = maxouter + skin
|
||||
// skin is included b/c Neighbor uses this value similar
|
||||
// to its cutneighmax = force cutoff + skin
|
||||
// also, this NeighList may be used by this compute for multiple steps
|
||||
// (until next reneighbor), so it needs to contain atoms further
|
||||
// than maxouter apart, just like a normal neighbor list does
|
||||
|
||||
int irequest = neighbor->request(this,instance_me);
|
||||
neighbor->requests[irequest]->half = 0;
|
||||
neighbor->requests[irequest]->full = 1;
|
||||
neighbor->requests[irequest]->pair = 0;
|
||||
neighbor->requests[irequest]->compute = 1;
|
||||
neighbor->requests[irequest]->occasional = 1;
|
||||
if (mycutneigh > 0.0) {
|
||||
neighbor->requests[irequest]->cut = 1;
|
||||
neighbor->requests[irequest]->cutoff = mycutneigh;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
void ComputeADF::init_list(int /*id*/, NeighList *ptr)
|
||||
{
|
||||
list = ptr;
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
void ComputeADF::compute_array()
|
||||
{
|
||||
int i,j,k,m,ii,jj,jatom,katom,jk,jjj,kkk;
|
||||
int inum,jnum,itype,jtype,ibin,ihisto;
|
||||
double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
|
||||
int *ilist,*jlist,*klist,*numneigh,**firstneigh;
|
||||
double factor_lj,factor_coul;
|
||||
double delr1[3],delr2[3],rinv1,rinv2,rinv12,cs,theta;
|
||||
|
||||
invoked_array = update->ntimestep;
|
||||
|
||||
// invoke full neighbor list (will copy or build if necessary)
|
||||
|
||||
neighbor->build_one(list);
|
||||
|
||||
inum = list->inum;
|
||||
ilist = list->ilist;
|
||||
numneigh = list->numneigh;
|
||||
firstneigh = list->firstneigh;
|
||||
|
||||
// zero the histogram counts
|
||||
|
||||
for (i = 0; i < ntriples; i++)
|
||||
for (j = 0; j < nbin; j++)
|
||||
hist[i][j] = 0.0;
|
||||
|
||||
// zero the central atom counts
|
||||
|
||||
for (i = 0; i < ntriples; i++)
|
||||
iatomcount[m] = 0;
|
||||
|
||||
// tally the ADFs
|
||||
// all three atoms i, j, and k must be in fix group
|
||||
// tally I,J,K triple only if I is central atom
|
||||
// and J,K matches unordered neighbor types (JJ,KK)
|
||||
|
||||
double **x = atom->x;
|
||||
int *type = atom->type;
|
||||
int *mask = atom->mask;
|
||||
int nlocal = atom->nlocal;
|
||||
|
||||
double *special_coul = force->special_coul;
|
||||
double *special_lj = force->special_lj;
|
||||
int newton_pair = force->newton_pair;
|
||||
|
||||
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];
|
||||
|
||||
// count atom i in each matching ADF
|
||||
// zero the jatom, katom neighbor list counts
|
||||
|
||||
for (m = 0; m < ntriples; m++) {
|
||||
if (iatomflag[m][itype]) {
|
||||
iatomcount[m]++;
|
||||
}
|
||||
numjatom[m] = 0;
|
||||
numkatom[m] = 0;
|
||||
numjkatom[m] = 0;
|
||||
}
|
||||
|
||||
for (jj = 0; jj < jnum; jj++) {
|
||||
j = jlist[jj];
|
||||
factor_lj = special_lj[sbmask(j)];
|
||||
factor_coul = special_coul[sbmask(j)];
|
||||
j &= NEIGHMASK;
|
||||
|
||||
// if both weighting factors are 0, skip this pair
|
||||
// could be 0 and still be in neigh list for long-range Coulombics
|
||||
// want consistency with non-charged triples which wouldn't be in list
|
||||
|
||||
if (factor_lj == 0.0 && factor_coul == 0.0) continue;
|
||||
|
||||
if (!(mask[j] & groupbit)) continue;
|
||||
jtype = type[j];
|
||||
|
||||
delx = xtmp - x[j][0];
|
||||
dely = ytmp - x[j][1];
|
||||
delz = ztmp - x[j][2];
|
||||
rsq = delx*delx + dely*dely + delz*delz;
|
||||
|
||||
for (m = 0; m < ntriples; m++) {
|
||||
|
||||
// check if itype, jtype, ktype match this ADF definition
|
||||
// if yes, add j to jatom, katom, and jkatom lists
|
||||
|
||||
if (!iatomflag[m][itype]) continue;
|
||||
|
||||
int jflag = 0;
|
||||
if (jatomflag[m][jtype] &&
|
||||
rsq >= rcutinnerj[m]*rcutinnerj[m] &&
|
||||
rsq <= rcutouterj[m]*rcutouterj[m]) {
|
||||
jflag = 1;
|
||||
jatom = numjatom[m]++;
|
||||
neighjatom[m][jatom] = numjkatom[m];
|
||||
if (numjatom[m] >= maxjatom[m]) {
|
||||
maxjatom[m] += maxjatom[m]/2;
|
||||
memory->grow(neighjatom[m],maxjatom[m],"adf:neighjatom");
|
||||
}
|
||||
}
|
||||
|
||||
int kflag = 0;
|
||||
if (katomflag[m][jtype] &&
|
||||
rsq >= rcutinnerk[m]*rcutinnerk[m] &&
|
||||
rsq <= rcutouterk[m]*rcutouterk[m]) {
|
||||
kflag = 1;
|
||||
katom = numkatom[m]++;
|
||||
neighkatom[m][katom] = numjkatom[m];
|
||||
if (numkatom[m] >= maxkatom[m]) {
|
||||
maxkatom[m] += maxkatom[m]/2;
|
||||
memory->grow(neighkatom[m],maxkatom[m],"adf:neighkatom");
|
||||
}
|
||||
}
|
||||
|
||||
// if atom in either list, add to jklist
|
||||
|
||||
if (jflag || kflag) {
|
||||
jk = numjkatom[m]++;
|
||||
neighjkatom[m][jk] = j;
|
||||
delrjkatom[m][jk][0] = delx;
|
||||
delrjkatom[m][jk][1] = dely;
|
||||
delrjkatom[m][jk][2] = delz;
|
||||
delrjkatom[m][jk][3] = 1.0/sqrt(rsq);
|
||||
if (numjkatom[m] >= maxjkatom[m]) {
|
||||
maxjkatom[m] += maxjkatom[m]/2;
|
||||
memory->grow(neighjkatom[m],maxjkatom[m],"adf:neighjkatom");
|
||||
memory->grow(bothjkatom[m],maxjkatom[m],"adf:bothjkatom");
|
||||
memory->grow(delrjkatom[m],maxjkatom[m],4,"adf:delrjkatom");
|
||||
}
|
||||
|
||||
// indicate if atom in both lists
|
||||
|
||||
if (jflag && kflag)
|
||||
bothjkatom[m][jk] = 1;
|
||||
else
|
||||
bothjkatom[m][jk] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loop over ADFs
|
||||
|
||||
for (m = 0; m < ntriples; m++) {
|
||||
|
||||
// loop over (j,k) pairs
|
||||
|
||||
for (jatom = 0; jatom < numjatom[m]; jatom++) {
|
||||
jjj = neighjatom[m][jatom];
|
||||
j = neighjkatom[m][jjj];
|
||||
|
||||
delr1[0] = delrjkatom[m][jjj][0];
|
||||
delr1[1] = delrjkatom[m][jjj][1];
|
||||
delr1[2] = delrjkatom[m][jjj][2];
|
||||
rinv1 = delrjkatom[m][jjj][3];
|
||||
|
||||
for (katom = 0; katom < numkatom[m]; katom++) {
|
||||
kkk = neighkatom[m][katom];
|
||||
k = neighjkatom[m][kkk];
|
||||
|
||||
// skip if j==k, or j > k and both are in both lists
|
||||
|
||||
if (k == j || (j > k && bothjkatom[m][jjj] && bothjkatom[m][kkk])) continue;
|
||||
|
||||
delr2[0] = delrjkatom[m][kkk][0];
|
||||
delr2[1] = delrjkatom[m][kkk][1];
|
||||
delr2[2] = delrjkatom[m][kkk][2];
|
||||
rinv2 = delrjkatom[m][kkk][3];
|
||||
rinv12 = rinv1*rinv2;
|
||||
cs = (delr1[0]*delr2[0] + delr1[1]*delr2[1] + delr1[2]*delr2[2]) * rinv12;
|
||||
|
||||
if (ordinate_style == COSINE) {
|
||||
ibin = static_cast<int> ((cs+1.0)*deltaxinv);
|
||||
if (ibin >= nbin || ibin < 0) continue;
|
||||
hist[m][ibin] += 1.0;
|
||||
} else {
|
||||
if (cs > 1.0) cs = 1.0;
|
||||
if (cs < -1.0) cs = -1.0;
|
||||
theta = acos(cs);
|
||||
ibin = static_cast<int> (theta*deltaxinv);
|
||||
if (ibin >= nbin || ibin < 0) continue;
|
||||
hist[m][ibin] += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sum histograms across procs
|
||||
|
||||
MPI_Allreduce(hist[0],histall[0],ntriples*nbin,MPI_DOUBLE,MPI_SUM,world);
|
||||
MPI_Allreduce(iatomcount,iatomcountall,ntriples,MPI_INT,MPI_SUM,world);
|
||||
|
||||
// convert counts to pdf(theta) and adf(theta)
|
||||
// copy into output array
|
||||
|
||||
for (m = 0; m < ntriples; m++) {
|
||||
|
||||
double count = 0;
|
||||
for (ibin = 0; ibin < nbin; ibin++)
|
||||
count += histall[m][ibin];
|
||||
|
||||
double normfac1, pdftheta, normfac2, adftheta;
|
||||
if (count > 0.0) normfac1 = deltaxinv/count;
|
||||
else normfac1 = 0.0;
|
||||
if (iatomcountall[m] > 0.0) normfac2 = 1.0/iatomcountall[m];
|
||||
else normfac2 = 0.0;
|
||||
adftheta = 0.0;
|
||||
for (ibin = 0; ibin < nbin; ibin++) {
|
||||
pdftheta = histall[m][ibin] * normfac1;
|
||||
adftheta += histall[m][ibin] * normfac2;
|
||||
array[ibin][1+2*m] = pdftheta;
|
||||
array[ibin][2+2*m] = adftheta;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/* -*- c++ -*- ----------------------------------------------------------
|
||||
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 COMPUTE_CLASS
|
||||
|
||||
ComputeStyle(adf,ComputeADF)
|
||||
|
||||
#else
|
||||
|
||||
#ifndef LMP_COMPUTE_ADF_H
|
||||
#define LMP_COMPUTE_ADF_H
|
||||
|
||||
#include <cstdio>
|
||||
#include "compute.h"
|
||||
|
||||
namespace LAMMPS_NS {
|
||||
|
||||
class ComputeADF : public Compute {
|
||||
public:
|
||||
ComputeADF(class LAMMPS *, int, char **);
|
||||
~ComputeADF();
|
||||
void init();
|
||||
void init_list(int, class NeighList *);
|
||||
void compute_array();
|
||||
|
||||
private:
|
||||
int nbin; // # of adf bins
|
||||
int ntriples; // # of adf triples
|
||||
double deltax,deltaxinv; // bin width and inverse-width
|
||||
int *ilo,*ihi,*jlo,*jhi,*klo,*khi;
|
||||
double **hist; // histogram bins
|
||||
double **histall; // summed histogram bins across all procs
|
||||
|
||||
double *rcutinnerj, *rcutinnerk; // list of inner cutoffs
|
||||
double *rcutouterj, *rcutouterk; // list of outer cutoffs
|
||||
|
||||
class NeighList *list; // full neighbor list
|
||||
|
||||
int *iatomcount; // local number of central atoms
|
||||
int *iatomcountall; // total number of central atoms
|
||||
int **iatomflag; // 1 if type is central atom in ADF
|
||||
int *maxjatom, *maxkatom; // allocated size jatom, katom neighlist
|
||||
int *numjatom, *numkatom; // actual size of jatom, katom neighlist
|
||||
int **neighjatom, **neighkatom;// list of short neighbor lists
|
||||
int **jatomflag, **katomflag; // 1 if type is neighbor atom in ADF
|
||||
|
||||
int *maxjkatom; // allocated size short neighlist
|
||||
int *numjkatom; // actual size of short neighlist
|
||||
int **neighjkatom; // list of short neighbor lists
|
||||
int **bothjkatom; // 1 if atom is in both jatom and katom lists
|
||||
double ***delrjkatom; // list of 4-vectors: delx, dely, delx, and 1/r
|
||||
|
||||
double rad2deg; // conversion factor from radians to degrees
|
||||
int ordinate_style; // DEGREE, RADIAN, or COSINE
|
||||
int cutflag; // 1 if at least one outer cutoff specified
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* ERROR/WARNING messages:
|
||||
|
||||
E: Illegal ... command
|
||||
|
||||
Self-explanatory. Check the input script syntax and compare to the
|
||||
documentation for the command. You can use -echo screen as a
|
||||
command-line option when running LAMMPS to see the offending line.
|
||||
|
||||
E: Compute adf requires a pair style be defined or outer cutoff specified
|
||||
|
||||
Self-explanatory.
|
||||
|
||||
E: Compute adf cutoff exceeds ghost atom range - use comm_modify cutoff command
|
||||
|
||||
Self-explanatary.
|
||||
|
||||
*/
|
Loading…
Reference in New Issue