diff --git a/doc/src/compute_coord_atom.txt b/doc/src/compute_coord_atom.txt index 012a87a9a7b17bdbae1f38e4c57cf3cbb2d7bf84..f1a6bf7ffb14085cebd25775f050703456e0b766 100644 --- a/doc/src/compute_coord_atom.txt +++ b/doc/src/compute_coord_atom.txt @@ -10,22 +10,34 @@ compute coord/atom command :h3 [Syntax:] -compute ID group-ID coord/atom cutoff type1 type2 ... :pre +compute ID group-ID coord/atom cstyle args ... :pre ID, group-ID are documented in "compute"_compute.html command coord/atom = style name of this compute command -cutoff = distance within which to count coordination neighbors (distance units) -typeN = atom type for Nth coordination count (see asterisk form below) :ul +one cstyle must be appended :ul + +cstyle = {cutoff} or {orientorder} + +{cutoff} args = cutoff typeN + cutoff = distance within which to count coordination neighbors (distance units) + typeN = atom type for Nth coordination count (see asterisk form below) :pre + +{orientorder} args = orientorderID threshold + orientorderID = ID of a previously defined orientorder/atom compute + threshold = minimum value of the scalar product between two 'connected' atoms (see text for explanation) :pre [Examples:] -compute 1 all coord/atom 2.0 -compute 1 all coord/atom 6.0 1 2 -compute 1 all coord/atom 6.0 2*4 5*8 * :pre +compute 1 all coord/atom cutoff 2.0 +compute 1 all coord/atom cutoff 6.0 1 2 +compute 1 all coord/atom cutoff 6.0 2*4 5*8 * +compute 1 all coord/atom orientorder 2 0.5 :pre [Description:] -Define a computation that calculates one or more coordination numbers +This compute performs generic calculations between neighboring atoms. So far, +there are two cstyles implemented: {cutoff} and {orientorder}. +The {cutoff} cstyle calculates one or more coordination numbers for each atom in a group. A coordination number is defined as the number of neighbor atoms with @@ -49,6 +61,14 @@ from 1 to N. A leading asterisk means all types from 1 to n (inclusive). A middle asterisk means all types from m to n (inclusive). +The {orientorder} cstyle calculates the number of 'connected' atoms j +around each atom i. The atom j is connected to i if the scalar product +({Ybar_lm(i)},{Ybar_lm(j)}) is larger than {threshold}. Thus, this cstyle +will work only if a "compute orientorder/atom"_compute_orientorder_atom.html +has been previously defined. This cstyle allows one to apply the +ten Wolde's criterion to identify cristal-like atoms in a system +(see "ten Wolde et al."_#tenWolde). + The value of all coordination numbers will be 0.0 for atoms not in the specified compute group. @@ -83,10 +103,19 @@ options. The per-atom vector or array values will be a number >= 0.0, as explained above. -[Restrictions:] none +[Restrictions:] +The cstyle {orientorder} can only be used if a +"compute orientorder/atom"_compute_orientorder_atom.html command +was previously defined. Otherwise, an error message will be issued. [Related commands:] "compute cluster/atom"_compute_cluster_atom.html +"compute orientorder/atom"_compute_orientorder_atom.html [Default:] none + +:line + +:link(tenWolde) +[(tenWolde)] P. R. ten Wolde, M. J. Ruiz-Montero, D. Frenkel, J. Chem. Phys. 104, 9932 (1996). diff --git a/doc/src/compute_orientorder_atom.txt b/doc/src/compute_orientorder_atom.txt index c5ecef3cb29ee3656a79f01965ddcf62a0687baa..74426dd33b2a5d74dc683b8d9bf1e5375ffc5714 100644 --- a/doc/src/compute_orientorder_atom.txt +++ b/doc/src/compute_orientorder_atom.txt @@ -15,17 +15,19 @@ compute ID group-ID orientorder/atom keyword values ... :pre ID, group-ID are documented in "compute"_compute.html command :ulb,l orientorder/atom = style name of this compute command :l one or more keyword/value pairs may be appended :l -keyword = {cutoff} or {nnn} or {degrees} +keyword = {cutoff} or {nnn} or {degrees} or {components} {cutoff} value = distance cutoff {nnn} value = number of nearest neighbors - {degrees} values = nlvalues, l1, l2,... :pre + {degrees} values = nlvalues, l1, l2,... + {components} value = l :pre :ule [Examples:] compute 1 all orientorder/atom -compute 1 all orientorder/atom degrees 5 4 6 8 10 12 nnn NULL cutoff 1.5 :pre +compute 1 all orientorder/atom degrees 5 4 6 8 10 12 nnn NULL cutoff 1.5 +compute 1 all orientorder/atom degrees 4 6 components 6 nnn NULL cutoff 3.0 :pre [Description:] @@ -71,6 +73,13 @@ The numerical values of all order parameters up to {Q}12 for a range of commonly encountered high-symmetry structures are given in Table I of "Mickel et al."_#Mickel. +The optional keyword {components} will output the components of +the normalized complex vector {Ybar_lm} of degree {l}, which must be +explicitly included in the keyword {degrees}. This option can be used +in conjunction with "compute coord_atom"_compute_coord_atom.html to +calculate the ten Wolde's criterion to identify crystal-like particles +(see "ten Wolde et al."_#tenWolde96). + The value of {Ql} is set to zero for atoms not in the specified compute group, as well as for atoms that have less than {nnn} neighbors within the distance cutoff. @@ -98,6 +107,12 @@ the neighbor list. This compute calculates a per-atom array with {nlvalues} columns, giving the {Ql} values for each atom, which are real numbers on the range 0 <= {Ql} <= 1. +If the keyword {components} is set, then the real and imaginary parts of each +component of (normalized) {Ybar_lm} will be added to the output array in the +following order: +Re({Ybar_-m}) Im({Ybar_-m}) Re({Ybar_-m+1}) Im({Ybar_-m+1}) ... Re({Ybar_m}) Im({Ybar_m}). +This way, the per-atom array will have a total of {nlvalues}+2*(2{l}+1) columns. + These values can be accessed by any command that uses per-atom values from a compute as input. See "Section 6.15"_Section_howto.html#howto_15 for an overview of LAMMPS output @@ -117,5 +132,9 @@ The option defaults are {cutoff} = pair style cutoff, {nnn} = 12, {degrees} = 5 :link(Steinhardt) [(Steinhardt)] P. Steinhardt, D. Nelson, and M. Ronchetti, Phys. Rev. B 28, 784 (1983). + :link(Mickel) [(Mickel)] W. Mickel, S. C. Kapfer, G. E. Schroeder-Turkand, K. Mecke, J. Chem. Phys. 138, 044501 (2013). + +:link(tenWolde96) +[(tenWolde)] P. R. ten Wolde, M. J. Ruiz-Montero, D. Frenkel, J. Chem. Phys. 104, 9932 (1996). diff --git a/examples/prd/in.prd b/examples/prd/in.prd index ea5220ab445516e6128f128fe9cbb007be2a4281..be3454bcb969ab0fb74f7a70a4ef43cb08ad35dc 100644 --- a/examples/prd/in.prd +++ b/examples/prd/in.prd @@ -78,7 +78,7 @@ run 100 # only output atoms near vacancy -compute coord all coord/atom $r +compute coord all coord/atom cutoff $r #dump events all custom 1 dump.prd id type x y z #dump_modify events thresh c_coord != 4 diff --git a/examples/tad/in.tad b/examples/tad/in.tad index da3d2175aa26def703b7c03f795d503a3f325cc8..687e1dde0cb260ab06c401cc96e76c57e801e8d5 100644 --- a/examples/tad/in.tad +++ b/examples/tad/in.tad @@ -80,7 +80,7 @@ velocity all zero linear # only output atoms near vacancy -compute coord all coord/atom $r +compute coord all coord/atom cutoff $r #dump events all custom 1 dump.prd id type x y z #dump_modify events thresh c_coord != 4 diff --git a/src/compute_coord_atom.cpp b/src/compute_coord_atom.cpp index 21744dcc93839b4e1baf264c554b77de8dfe13b2..36f0b635047fb4aadaa8331325694b0d628648da 100644 --- a/src/compute_coord_atom.cpp +++ b/src/compute_coord_atom.cpp @@ -15,6 +15,7 @@ #include <string.h> #include <stdlib.h> #include "compute_coord_atom.h" +#include "compute_orientorder_atom.h" #include "atom.h" #include "update.h" #include "modify.h" @@ -29,37 +30,70 @@ using namespace LAMMPS_NS; +#define INVOKED_PERATOM 8 + /* ---------------------------------------------------------------------- */ ComputeCoordAtom::ComputeCoordAtom(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), - typelo(NULL), typehi(NULL), cvec(NULL), carray(NULL) + typelo(NULL), typehi(NULL), cvec(NULL), carray(NULL), + id_orientorder(NULL), normv(NULL) { - if (narg < 4) error->all(FLERR,"Illegal compute coord/atom command"); + if (narg < 5) error->all(FLERR,"Illegal compute coord/atom command"); + + cstyle = NONE; + + if (strcmp(arg[3],"cutoff") == 0) { + cstyle = CUTOFF; + double cutoff = force->numeric(FLERR,arg[4]); + cutsq = cutoff*cutoff; + + ncol = narg-5 + 1; + int ntypes = atom->ntypes; + typelo = new int[ncol]; + typehi = new int[ncol]; + + if (narg == 5) { + ncol = 1; + typelo[0] = 1; + typehi[0] = ntypes; + } else { + ncol = 0; + int iarg = 5; + while (iarg < narg) { + force->bounds(FLERR,arg[iarg],ntypes,typelo[ncol],typehi[ncol]); + if (typelo[ncol] > typehi[ncol]) + error->all(FLERR,"Illegal compute coord/atom command"); + ncol++; + iarg++; + } + } + + } else if (strcmp(arg[3],"orientorder") == 0) { + cstyle = ORIENT; + if (narg != 6) error->all(FLERR,"Illegal compute coord/atom command"); - double cutoff = force->numeric(FLERR,arg[3]); - cutsq = cutoff*cutoff; + int n = strlen(arg[4]) + 1; + id_orientorder = new char[n]; + strcpy(id_orientorder,arg[4]); - ncol = narg-4 + 1; - int ntypes = atom->ntypes; - typelo = new int[ncol]; - typehi = new int[ncol]; + int iorientorder = modify->find_compute(id_orientorder); + if (iorientorder < 0) + error->all(FLERR,"Could not find compute coord/atom compute ID"); + if (strcmp(modify->compute[iorientorder]->style,"orientorder/atom") != 0) + error->all(FLERR,"Compute coord/atom compute ID does not compute orientorder/atom"); + + threshold = force->numeric(FLERR,arg[5]); + if (threshold <= -1.0 || threshold >= 1.0) + error->all(FLERR,"Compute coord/atom threshold value must lie between -1 and 1"); - if (narg == 4) { ncol = 1; + typelo = new int[ncol]; + typehi = new int[ncol]; typelo[0] = 1; - typehi[0] = ntypes; - } else { - ncol = 0; - int iarg = 4; - while (iarg < narg) { - force->bounds(FLERR,arg[iarg],ntypes,typelo[ncol],typehi[ncol]); - if (typelo[ncol] > typehi[ncol]) - error->all(FLERR,"Illegal compute coord/atom command"); - ncol++; - iarg++; - } - } + typehi[0] = atom->ntypes; + + } else error->all(FLERR,"Invalid cstyle in compute coord/atom"); peratom_flag = 1; if (ncol == 1) size_peratom_cols = 0; @@ -76,12 +110,25 @@ ComputeCoordAtom::~ComputeCoordAtom() delete [] typehi; memory->destroy(cvec); memory->destroy(carray); + delete [] id_orientorder; } /* ---------------------------------------------------------------------- */ void ComputeCoordAtom::init() { + if (cstyle == ORIENT) { + int iorientorder = modify->find_compute(id_orientorder); + c_orientorder = (ComputeOrientOrderAtom*)(modify->compute[iorientorder]); + cutsq = c_orientorder->cutsq; + l = c_orientorder->qlcomp; + // communicate real and imaginary 2*l+1 components of the normalized vector + comm_forward = 2*(2*l+1); + if (c_orientorder->iqlcomp < 0) + error->all(FLERR,"Compute coord/atom requires components " + "option in compute orientorder/atom be defined"); + } + if (force->pair == NULL) error->all(FLERR,"Compute coord/atom requires a pair style be defined"); if (sqrt(cutsq) > force->pair->cutforce) @@ -122,6 +169,9 @@ void ComputeCoordAtom::compute_peratom() invoked_peratom = update->ntimestep; +// printf("Number of degrees %i components degree %i",nqlist,l); +// printf("Particle \t %i \t Norm \t %g \n",0,norm[0][0]); + // grow coordination array if necessary if (atom->nmax > nmax) { @@ -138,6 +188,19 @@ void ComputeCoordAtom::compute_peratom() } } + if (cstyle == ORIENT) { + if (!(c_orientorder->invoked_flag & INVOKED_PERATOM)) { + c_orientorder->compute_peratom(); + c_orientorder->invoked_flag |= INVOKED_PERATOM; + } + nqlist = c_orientorder->nqlist; + int ltmp = l; +// l = c_orientorder->qlcomp; + if (ltmp != l) error->all(FLERR,"Debug error, ltmp != l\n"); + normv = c_orientorder->array_atom; + comm->forward_comm_compute(this); + } + // invoke full neighbor list (will copy or build if necessary) neighbor->build_one(list); @@ -154,7 +217,72 @@ void ComputeCoordAtom::compute_peratom() int *type = atom->type; int *mask = atom->mask; - if (ncol == 1) { + if (cstyle == CUTOFF) { + + if (ncol == 1) { + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + if (mask[i] & groupbit) { + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + n = 0; + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + j &= NEIGHMASK; + + 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; + if (rsq < cutsq && jtype >= typelo[0] && jtype <= typehi[0]) + n++; + } + + cvec[i] = n; + } else cvec[i] = 0.0; + } + + } else { + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + count = carray[i]; + for (m = 0; m < ncol; m++) count[m] = 0.0; + + if (mask[i] & groupbit) { + 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; + + 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; + if (rsq < cutsq) { + for (m = 0; m < ncol; m++) + if (jtype >= typelo[m] && jtype <= typehi[m]) + count[m] += 1.0; + } + } + } + } + } + + } else if (cstyle == ORIENT) { + for (ii = 0; ii < inum; ii++) { i = ilist[ii]; if (mask[i] & groupbit) { @@ -168,51 +296,51 @@ void ComputeCoordAtom::compute_peratom() for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; j &= NEIGHMASK; - - 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; - if (rsq < cutsq && jtype >= typelo[0] && jtype <= typehi[0]) n++; + if (rsq < cutsq) { + double dot_product = 0.0; + for (int m=0; m < 2*(2*l+1); m++) { + dot_product += normv[i][nqlist+m]*normv[j][nqlist+m]; + } + if (dot_product > threshold) n++; + } } - cvec[i] = n; } else cvec[i] = 0.0; } + } +} - } else { - for (ii = 0; ii < inum; ii++) { - i = ilist[ii]; - count = carray[i]; - for (m = 0; m < ncol; m++) count[m] = 0.0; +/* ---------------------------------------------------------------------- */ - if (mask[i] & groupbit) { - xtmp = x[i][0]; - ytmp = x[i][1]; - ztmp = x[i][2]; - jlist = firstneigh[i]; - jnum = numneigh[i]; +int ComputeCoordAtom::pack_forward_comm(int n, int *list, double *buf, + int pbc_flag, int *pbc) +{ + int i,m=0,j; + for (i = 0; i < n; ++i) { + for (j = nqlist; j < nqlist + 2*(2*l+1); ++j) { + buf[m++] = normv[list[i]][j]; + } + } + return m; +} - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - j &= NEIGHMASK; +/* ---------------------------------------------------------------------- */ - 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; - if (rsq < cutsq) { - for (m = 0; m < ncol; m++) - if (jtype >= typelo[m] && jtype <= typehi[m]) - count[m] += 1.0; - } - } - } +void ComputeCoordAtom::unpack_forward_comm(int n, int first, double *buf) +{ + int i,last,m=0,j; + last = first + n; + for (i = first; i < last; ++i) { + for (j = nqlist; j < nqlist + 2*(2*l+1); ++j) { + normv[i][j] = buf[m++]; } } + } /* ---------------------------------------------------------------------- diff --git a/src/compute_coord_atom.h b/src/compute_coord_atom.h index 0ff373f133695b4c90bca9508950479311a3bb3a..2ad46fa854b233e461cd0bc0d53fc7b017a8006e 100644 --- a/src/compute_coord_atom.h +++ b/src/compute_coord_atom.h @@ -31,7 +31,10 @@ class ComputeCoordAtom : public Compute { void init(); void init_list(int, class NeighList *); void compute_peratom(); + int pack_forward_comm(int, int *, double *, int, int *); + void unpack_forward_comm(int, int, double *); double memory_usage(); + enum {NONE,CUTOFF,ORIENT}; private: int nmax,ncol; @@ -41,6 +44,12 @@ class ComputeCoordAtom : public Compute { int *typelo,*typehi; double *cvec; double **carray; + + class ComputeOrientOrderAtom *c_orientorder; + char *id_orientorder; + double threshold; + double **normv; + int cstyle,nqlist,l; }; } diff --git a/src/compute_orientorder_atom.cpp b/src/compute_orientorder_atom.cpp index 6c5a2c0c0e10b0df9e0d32521a7e0230ca1c2eb8..5f78b33b61d02e08411dbcfcb91e2492c3625ac1 100644 --- a/src/compute_orientorder_atom.cpp +++ b/src/compute_orientorder_atom.cpp @@ -46,7 +46,8 @@ using namespace std; ComputeOrientOrderAtom::ComputeOrientOrderAtom(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), - distsq(NULL), nearest(NULL), rlist(NULL), qlist(NULL), qnarray(NULL), qnm_r(NULL), qnm_i(NULL) + qlist(NULL), distsq(NULL), nearest(NULL), rlist(NULL), + qnarray(NULL), qnm_r(NULL), qnm_i(NULL) { if (narg < 3 ) error->all(FLERR,"Illegal compute orientorder/atom command"); @@ -54,9 +55,10 @@ ComputeOrientOrderAtom::ComputeOrientOrderAtom(LAMMPS *lmp, int narg, char **arg nnn = 12; cutsq = 0.0; + qlcompflag = 0; // specify which orders to request - + nqlist = 5; memory->create(qlist,nqlist,"orientorder/atom:qlist"); qlist[0] = 4; @@ -72,40 +74,63 @@ ComputeOrientOrderAtom::ComputeOrientOrderAtom(LAMMPS *lmp, int narg, char **arg while (iarg < narg) { if (strcmp(arg[iarg],"nnn") == 0) { if (iarg+2 > narg) error->all(FLERR,"Illegal compute orientorder/atom command"); - if (strcmp(arg[iarg+1],"NULL") == 0) - nnn = 0; - else { - nnn = force->numeric(FLERR,arg[iarg+1]); - if (nnn <= 0) - error->all(FLERR,"Illegal compute orientorder/atom command"); + if (strcmp(arg[iarg+1],"NULL") == 0) { + nnn = 0; + } else { + nnn = force->numeric(FLERR,arg[iarg+1]); + if (nnn <= 0) + error->all(FLERR,"Illegal compute orientorder/atom command"); } iarg += 2; } else if (strcmp(arg[iarg],"degrees") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal compute orientorder/atom command"); + if (iarg+2 > narg) + error->all(FLERR,"Illegal compute orientorder/atom command"); nqlist = force->numeric(FLERR,arg[iarg+1]); - if (nqlist <= 0) error->all(FLERR,"Illegal compute orientorder/atom command"); + if (nqlist <= 0) + error->all(FLERR,"Illegal compute orientorder/atom command"); memory->destroy(qlist); memory->create(qlist,nqlist,"orientorder/atom:qlist"); iarg += 2; if (iarg+nqlist > narg) error->all(FLERR,"Illegal compute orientorder/atom command"); qmax = 0; for (int iw = 0; iw < nqlist; iw++) { - qlist[iw] = force->numeric(FLERR,arg[iarg+iw]); - if (qlist[iw] < 0) - error->all(FLERR,"Illegal compute orientorder/atom command"); - if (qlist[iw] > qmax) qmax = qlist[iw]; + qlist[iw] = force->numeric(FLERR,arg[iarg+iw]); + if (qlist[iw] < 0) + error->all(FLERR,"Illegal compute orientorder/atom command"); + if (qlist[iw] > qmax) qmax = qlist[iw]; } iarg += nqlist; + if (strcmp(arg[iarg],"components") == 0) { + qlcompflag = 1; + if (iarg+2 > narg) + error->all(FLERR,"Illegal compute orientorder/atom command"); + qlcomp = force->numeric(FLERR,arg[iarg+1]); + if (qlcomp <= 0) + error->all(FLERR,"Illegal compute orientorder/atom command"); + iqlcomp = -1; + for (int iw = 0; iw < nqlist; iw++) + if (qlcomp == qlist[iw]) { + iqlcomp = iw; + break; + } + if (iqlcomp < 0) + error->all(FLERR,"Illegal compute orientorder/atom command"); + iarg += 2; + } } else if (strcmp(arg[iarg],"cutoff") == 0) { - if (iarg+2 > narg) error->all(FLERR,"Illegal compute orientorder/atom command"); + if (iarg+2 > narg) + error->all(FLERR,"Illegal compute orientorder/atom command"); double cutoff = force->numeric(FLERR,arg[iarg+1]); - if (cutoff <= 0.0) error->all(FLERR,"Illegal compute orientorder/atom command"); + if (cutoff <= 0.0) + error->all(FLERR,"Illegal compute orientorder/atom command"); cutsq = cutoff*cutoff; iarg += 2; } else error->all(FLERR,"Illegal compute orientorder/atom command"); } - ncol = nqlist; + if (qlcompflag) ncol = nqlist + 2*(2*qlcomp+1); + else ncol = nqlist; + peratom_flag = 1; size_peratom_cols = ncol; @@ -124,7 +149,7 @@ ComputeOrientOrderAtom::~ComputeOrientOrderAtom() memory->destroy(qlist); memory->destroy(qnm_r); memory->destroy(qnm_i); - + } /* ---------------------------------------------------------------------- */ @@ -207,7 +232,7 @@ void ComputeOrientOrderAtom::compute_peratom() ztmp = x[i][2]; jlist = firstneigh[i]; jnum = numneigh[i]; - + // insure distsq and nearest arrays are long enough if (jnum > maxneigh) { @@ -236,9 +261,9 @@ void ComputeOrientOrderAtom::compute_peratom() rsq = delx*delx + dely*dely + delz*delz; if (rsq < cutsq) { distsq[ncount] = rsq; - rlist[ncount][0] = delx; - rlist[ncount][1] = dely; - rlist[ncount][2] = delz; + rlist[ncount][0] = delx; + rlist[ncount][1] = dely; + rlist[ncount][2] = delz; nearest[ncount++] = j; } } @@ -246,16 +271,16 @@ void ComputeOrientOrderAtom::compute_peratom() // if not nnn neighbors, order parameter = 0; if ((ncount == 0) || (ncount < nnn)) { - for (int iw = 0; iw < nqlist; iw++) - qn[iw] = 0.0; + for (int iw = 0; iw < nqlist; iw++) + qn[iw] = 0.0; continue; } // if nnn > 0, use only nearest nnn neighbors if (nnn > 0) { - select3(nnn,ncount,distsq,nearest,rlist); - ncount = nnn; + select3(nnn,ncount,distsq,nearest,rlist); + ncount = nnn; } calc_boop(rlist, ncount, qn, qlist, nqlist); @@ -270,8 +295,8 @@ void ComputeOrientOrderAtom::compute_peratom() double ComputeOrientOrderAtom::memory_usage() { double bytes = ncol*nmax * sizeof(double); - bytes += (qmax*(2*qmax+1)+maxneigh*4) * sizeof(double); - bytes += (nqlist+maxneigh) * sizeof(int); + bytes += (qmax*(2*qmax+1)+maxneigh*4) * sizeof(double); + bytes += (nqlist+maxneigh) * sizeof(int); return bytes; } @@ -283,18 +308,18 @@ double ComputeOrientOrderAtom::memory_usage() // Use no-op do while to create single statement -#define SWAP(a,b) do { \ - tmp = a; a = b; b = tmp; \ +#define SWAP(a,b) do { \ + tmp = a; a = b; b = tmp; \ } while(0) -#define ISWAP(a,b) do { \ - itmp = a; a = b; b = itmp; \ +#define ISWAP(a,b) do { \ + itmp = a; a = b; b = itmp; \ } while(0) -#define SWAP3(a,b) do { \ - tmp = a[0]; a[0] = b[0]; b[0] = tmp; \ - tmp = a[1]; a[1] = b[1]; b[1] = tmp; \ - tmp = a[2]; a[2] = b[2]; b[2] = tmp; \ +#define SWAP3(a,b) do { \ + tmp = a[0]; a[0] = b[0]; b[0] = tmp; \ + tmp = a[1]; a[1] = b[1]; b[1] = tmp; \ + tmp = a[2]; a[2] = b[2]; b[2] = tmp; \ } while(0) /* ---------------------------------------------------------------------- */ @@ -313,7 +338,7 @@ void ComputeOrientOrderAtom::select3(int k, int n, double *arr, int *iarr, doubl if (ir <= l+1) { if (ir == l+1 && arr[ir] < arr[l]) { SWAP(arr[l],arr[ir]); - ISWAP(iarr[l],iarr[ir]); + ISWAP(iarr[l],iarr[ir]); SWAP3(arr3[l],arr3[ir]); } return; @@ -325,17 +350,17 @@ void ComputeOrientOrderAtom::select3(int k, int n, double *arr, int *iarr, doubl if (arr[l] > arr[ir]) { SWAP(arr[l],arr[ir]); ISWAP(iarr[l],iarr[ir]); - SWAP3(arr3[l],arr3[ir]); + SWAP3(arr3[l],arr3[ir]); } if (arr[l+1] > arr[ir]) { SWAP(arr[l+1],arr[ir]); ISWAP(iarr[l+1],iarr[ir]); - SWAP3(arr3[l+1],arr3[ir]); + SWAP3(arr3[l+1],arr3[ir]); } if (arr[l] > arr[l+1]) { SWAP(arr[l],arr[l+1]); ISWAP(iarr[l],iarr[l+1]); - SWAP3(arr3[l],arr3[l+1]); + SWAP3(arr3[l],arr3[l+1]); } i = l+1; j = ir; @@ -350,7 +375,7 @@ void ComputeOrientOrderAtom::select3(int k, int n, double *arr, int *iarr, doubl if (j < i) break; SWAP(arr[i],arr[j]); ISWAP(iarr[i],iarr[j]); - SWAP3(arr3[i],arr3[j]); + SWAP3(arr3[i],arr3[j]); } arr[l+1] = arr[j]; arr[j] = a; @@ -372,9 +397,9 @@ void ComputeOrientOrderAtom::select3(int k, int n, double *arr, int *iarr, doubl calculate the bond orientational order parameters ------------------------------------------------------------------------- */ -void ComputeOrientOrderAtom::calc_boop(double **rlist, - int ncount, double qn[], - int qlist[], int nqlist) { +void ComputeOrientOrderAtom::calc_boop(double **rlist, + int ncount, double qn[], + int qlist[], int nqlist) { for (int iw = 0; iw < nqlist; iw++) { int n = qlist[iw]; @@ -412,37 +437,50 @@ void ComputeOrientOrderAtom::calc_boop(double **rlist, double expphim_r = expphi_r; double expphim_i = expphi_i; for(int m = 1; m <= +n; m++) { - double prefactor = polar_prefactor(n, m, costheta); - double c_r = prefactor * expphim_r; - double c_i = prefactor * expphim_i; - qnm_r[iw][m+n] += c_r; - qnm_i[iw][m+n] += c_i; - if(m & 1) { - qnm_r[iw][-m+n] -= c_r; - qnm_i[iw][-m+n] += c_i; - } else { - qnm_r[iw][-m+n] += c_r; - qnm_i[iw][-m+n] -= c_i; - } - double tmp_r = expphim_r*expphi_r - expphim_i*expphi_i; - double tmp_i = expphim_r*expphi_i + expphim_i*expphi_r; - expphim_r = tmp_r; - expphim_i = tmp_i; + double prefactor = polar_prefactor(n, m, costheta); + double c_r = prefactor * expphim_r; + double c_i = prefactor * expphim_i; + qnm_r[iw][m+n] += c_r; + qnm_i[iw][m+n] += c_i; + if(m & 1) { + qnm_r[iw][-m+n] -= c_r; + qnm_i[iw][-m+n] += c_i; + } else { + qnm_r[iw][-m+n] += c_r; + qnm_i[iw][-m+n] -= c_i; + } + double tmp_r = expphim_r*expphi_r - expphim_i*expphi_i; + double tmp_i = expphim_r*expphi_i + expphim_i*expphi_r; + expphim_r = tmp_r; + expphim_i = tmp_i; } } } double fac = sqrt(MY_4PI) / ncount; + double normfac = 0.0; for (int iw = 0; iw < nqlist; iw++) { int n = qlist[iw]; double qm_sum = 0.0; for(int m = 0; m < 2*n+1; m++) { qm_sum += qnm_r[iw][m]*qnm_r[iw][m] + qnm_i[iw][m]*qnm_i[iw][m]; // printf("Ylm^2 = %d %d %g\n",n,m, - // qnm_r[iw][m]*qnm_r[iw][m] + qnm_i[iw][m]*qnm_i[iw][m]); + // qnm_r[iw][m]*qnm_r[iw][m] + qnm_i[iw][m]*qnm_i[iw][m]); } qn[iw] = fac * sqrt(qm_sum / (2*n+1)); + if (qlcompflag && iqlcomp == iw) normfac = 1.0/sqrt(qm_sum); + + } + + // output of the complex vector + + if (qlcompflag) { + int j = nqlist; + for(int m = 0; m < 2*qlcomp+1; m++) { + qn[j++] = qnm_r[iqlcomp][m] * normfac; + qn[j++] = qnm_i[iqlcomp][m] * normfac; + } } } @@ -455,7 +493,7 @@ double ComputeOrientOrderAtom::dist(const double r[]) { } /* ---------------------------------------------------------------------- - polar prefactor for spherical harmonic Y_l^m, where + polar prefactor for spherical harmonic Y_l^m, where Y_l^m (theta, phi) = prefactor(l, m, cos(theta)) * exp(i*m*phi) ------------------------------------------------------------------------- */ diff --git a/src/compute_orientorder_atom.h b/src/compute_orientorder_atom.h index 9c5ec14f562efe1300c19719ce22456e6d001cc8..81b08dbddc17740538545d8ea7b6add7cd90ed7a 100644 --- a/src/compute_orientorder_atom.h +++ b/src/compute_orientorder_atom.h @@ -32,6 +32,10 @@ class ComputeOrientOrderAtom : public Compute { void init_list(int, class NeighList *); void compute_peratom(); double memory_usage(); + double cutsq; + int iqlcomp, qlcomp, qlcompflag; + int *qlist; + int nqlist; private: int nmax,maxneigh,ncol,nnn; @@ -39,16 +43,13 @@ class ComputeOrientOrderAtom : public Compute { double *distsq; int *nearest; double **rlist; - int *qlist; - int nqlist; int qmax; double **qnarray; - double cutsq; double **qnm_r; double **qnm_i; void select3(int, int, double *, int *, double **); - void calc_boop(double **rlist, int numNeighbors, + void calc_boop(double **rlist, int numNeighbors, double qn[], int nlist[], int nnlist); double dist(const double r[]);