diff --git a/src/USER-MISC/fix_filter_corotate.cpp b/src/USER-MISC/fix_filter_corotate.cpp index 3e427f1f92533e858d3bcc6ef39c7870aad00cd5..7279859edb5fa301ced6705c230e3bb04ffde1d3 100644 --- a/src/USER-MISC/fix_filter_corotate.cpp +++ b/src/USER-MISC/fix_filter_corotate.cpp @@ -1,2065 +1,2062 @@ -/* ---------------------------------------------------------------------- - 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: Lukas Fath (KIT) - some subroutines are from fix_shake.cpp - ------------------------------------------------------------------------- */ - -#include <mpi.h> -#include "string.h" -#include "stdlib.h" -#include "fix_filter_corotate.h" -#include "atom.h" -#include "atom_vec.h" -#include "molecule.h" -#include "bond.h" -#include "angle.h" -#include "math_const.h" -#include "update.h" -#include "modify.h" -#include "domain.h" -#include "region.h" -#include "memory.h" -#include "error.h" -#include "force.h" -#include "comm.h" -#include "error.h" -#include "memory.h" -#include "domain.h" -#include "integrate.h" -#include "respa.h" -#include "timer.h" -#include "neighbor.h" -#include "citeme.h" - -using namespace LAMMPS_NS; -using namespace MathConst; -using namespace FixConst; - -// allocate space for static class variable - -FixFilterCorotate *FixFilterCorotate::fsptr; - -#define BIG 1.0e20 -#define MASSDELTA 0.1 - -static const char cite_filter_corotate[] = - "Mollified Impulse Method with Corotational Filter:\n\n" - "@Article{Fath2017,\n" - " Title = {A fast mollified impulse method for biomolecular atomistic simulations},\n" - " Author = {L. Fath and M. Hochbruck and C.V. Singh},\n" - " Journal = {Journal of Computational Physics},\n" - " Year = {2017},\n" - " Pages = {180 - 198},\n" - " Volume = {333},\n\n" - " Doi = {http://dx.doi.org/10.1016/j.jcp.2016.12.024},\n" - " ISSN = {0021-9991},\n" - " Keywords = {Mollified impulse method},\n" - " Url = {http://www.sciencedirect.com/science/article/pii/S0021999116306787}\n" - "}\n\n"; - -/* ---------------------------------------------------------------------- */ - -FixFilterCorotate::FixFilterCorotate(LAMMPS *lmp, int narg, char **arg):Fix(lmp,narg,arg) -{ - if (lmp->citeme) lmp->citeme->add(cite_filter_corotate); - - MPI_Comm_rank(world,&me); - MPI_Comm_size(world,&nprocs); - - molecular = atom->molecular; - if (molecular == 0) - error->all(FLERR,"Cannot use fix filter/corotate with non-molecular system"); - if (molecular == 2) - error->all(FLERR,"Cannot use fix filter/corotate with molecule template system"); - - // parse args for bond and angle types - // will be used by find_clusters - // store args for "b" "a" "t" as flags in (1:n) list for fast access - // store args for "m" in list of length nmass for looping over - // for "m" verify that atom masses have been set - - bond_flag = new int[atom->nbondtypes+1]; - for (int i = 1; i <= atom->nbondtypes; i++) bond_flag[i] = 0; - angle_flag = new int[atom->nangletypes+1]; - for (int i = 1; i <= atom->nangletypes; i++) angle_flag[i] = 0; - type_flag = new int[atom->ntypes+1]; - for (int i = 1; i <= atom->ntypes; i++) type_flag[i] = 0; - mass_list = new double[atom->ntypes]; - nmass = 0; - - char mode = '\0'; - int next = 3; - while (next < narg) { - if (strcmp(arg[next],"b") == 0) mode = 'b'; - else if (strcmp(arg[next],"a") == 0) mode = 'a'; - else if (strcmp(arg[next],"t") == 0) mode = 't'; - else if (strcmp(arg[next],"m") == 0) { - mode = 'm'; - atom->check_mass(FLERR); - - // break if keyword that is not b,a,t,m - - } else if (isalpha(arg[next][0])) break; - - // read numeric args of b,a,t,m - - else if (mode == 'b') { - int i = force->inumeric(FLERR,arg[next]); - if (i < 1 || i > atom->nbondtypes) - error->all(FLERR,"Invalid bond type index for fix filter/corotate"); - bond_flag[i] = 1; - - } else if (mode == 'a') { - int i = force->inumeric(FLERR,arg[next]); - if (i < 1 || i > atom->nangletypes) - error->all(FLERR,"Invalid angle type index for fix filter/corotate"); - angle_flag[i] = 1; - - } else if (mode == 't') { - int i = force->inumeric(FLERR,arg[next]); - if (i < 1 || i > atom->ntypes) - error->all(FLERR,"Invalid atom type index for fix filter/corotate"); - type_flag[i] = 1; - - } else if (mode == 'm') { - double massone = force->numeric(FLERR,arg[next]); - if (massone == 0.0) error->all(FLERR,"Invalid atom mass for fix filter/corotate"); - if (nmass == atom->ntypes) - error->all(FLERR,"Too many masses for fix filter/corotate"); - mass_list[nmass++] = massone; - - } else error->all(FLERR,"Illegal fix filter/corotate command"); - next++; - } - - - // parse optional args - nlevels_respa = 1; //initialize - - // allocate bond and angle distance arrays, indexed from 1 to n - - bond_distance = new double[atom->nbondtypes+1]; - angle_distance = new double[atom->nangletypes+1]; - - //grow_arrays - array_atom = NULL; - shake_flag = NULL; - shake_atom = NULL; - shake_type = NULL; - - grow_arrays(atom->nmax); - atom->add_callback(0); //calls grow_arrays - - x_store = NULL; - - - //STUFF - g = NULL; - help2 = NULL; - - dn1dx = dn2dx = dn3dx = NULL; - n1 = n2 = n3 = del1 = del2 = del3 = NULL; - - memory->grow(help2,15,15,"FilterCorotate:help2"); - memory->grow(n1,3,"FilterCorotate:n1"); - memory->grow(n2,3,"FilterCorotate:n2"); - memory->grow(n3,3,"FilterCorotate:n3"); - memory->grow(del1,3,"FilterCorotate:del1"); - memory->grow(del2,3,"FilterCorotate:del2"); - memory->grow(del3,3,"FilterCorotate:del3"); - memory->grow(dn1dx,3,15,"FilterCorotate:dn1dx"); - memory->grow(dn2dx,3,15,"FilterCorotate:dn2dx"); - memory->grow(dn3dx,3,15,"FilterCorotate:dn3dx"); - - memory->grow(g,15,"FilterCorotate:g"); - - comm_forward = 3; - - // identify all clusters - - find_clusters(); - - // initialize list of clusters to constrain - - maxlist = 0; - list = NULL; - clist_derv = NULL; - clist_q0 = NULL; //list for derivative and ref. config - clist_nselect1 = clist_nselect2 = NULL; - clist_select1 = clist_select2 = NULL; - -} - -/* ---------------------------------------------------------------------- */ - -FixFilterCorotate::~FixFilterCorotate() -{ - memory->destroy(g); - memory->destroy(help2); - memory->destroy(n1); - memory->destroy(n2); - memory->destroy(n3); - memory->destroy(del1); - memory->destroy(del2); - memory->destroy(del3); - memory->destroy(dn1dx); - memory->destroy(dn2dx); - memory->destroy(dn3dx); - - atom->delete_callback(id,2); - atom->delete_callback(id,0); - - // delete locally stored arrays - - memory->destroy(shake_flag); - memory->destroy(shake_atom); - memory->destroy(shake_type); - memory->destroy(array_atom); - - delete [] bond_flag; - delete [] angle_flag; - delete [] type_flag; - delete [] mass_list; - - delete [] bond_distance; - delete [] angle_distance; - - memory->destroy(list); - memory->destroy(clist_derv); - memory->destroy(clist_q0); - memory->destroy(clist_nselect1); - memory->destroy(clist_nselect2); - memory->destroy(clist_select1); - memory->destroy(clist_select2); -} - - -/* ---------------------------------------------------------------------- */ - -int FixFilterCorotate::setmask() -{ - int mask = 0; - - mask |= PRE_NEIGHBOR; - mask |= PRE_FORCE_RESPA; - mask |= POST_FORCE_RESPA; - - return mask; -} - - -/* ---------------------------------------------------------------------- */ - -void FixFilterCorotate::init() -{ - int i; - // error if more than one filter - int count = 0; - for (i = 0; i < modify->nfix; i++) - if (strcmp(modify->fix[i]->style,"filter/corotate") == 0) count++; - if (count > 1) error->all(FLERR,"More than one fix filter/corotate"); - - // check for fix shake: - count = 0; - for (i = 0; i < modify->nfix; i++) - if (strcmp(modify->fix[i]->style,"shake") == 0) count++; - if (count > 1) error->one(FLERR,"Fix shake and fix filter/corotate detected, are you sure?"); - - // if rRESPA, find associated fix that must exist - // could have changed locations in fix list since created - // set ptrs to rRESPA variables - - if (strstr(update->integrate_style,"respa")) { - nlevels_respa = ((Respa *) update->integrate)->nlevels; - } - else error->all(FLERR,"Fix filter/corotate requires rRESPA!"); - - // set equilibrium bond distances - - if (force->bond == NULL) - error->all(FLERR,"Bond potential must be defined for fix filter/corotate"); - for (i = 1; i <= atom->nbondtypes; i++) - bond_distance[i] = force->bond->equilibrium_distance(i); - - // set equilibrium angle value - - for (i = 1; i <= atom->nangletypes; i++) { - angle_distance[i] = force->angle->equilibrium_angle(i); - } -} - -/* ---------------------------------------------------------------------- - * pre-integrator setup - * ------------------------------------------------------------------------- */ - -void FixFilterCorotate::setup_pre_neighbor() -{ - pre_neighbor(); -} - - -/* ---------------------------------------------------------------------- - * build list of clusters to constrain - * if one or more atoms in cluster are on this proc, - * this proc lists the cluster exactly once - * ------------------------------------------------------------------------- */ - -void FixFilterCorotate::pre_neighbor() -{ - int atom1,atom2,atom3,atom4,atom5; - - // local copies of atom quantities - // used until next re-neighboring - - x = atom->x; - v = atom->v; - f = atom->f; - mass = atom->mass; - rmass = atom->rmass; - type = atom->type; - nlocal = atom->nlocal; - - // extend size of list if necessary - - if (nlocal > maxlist) { - maxlist = nlocal; - - memory->destroy(list); - memory->destroy(clist_derv); - memory->destroy(clist_q0); - memory->destroy(clist_nselect1); - memory->destroy(clist_nselect2); - memory->destroy(clist_select1); - memory->destroy(clist_select2); - - memory->create(list,maxlist,"FilterCorotate:list"); - memory->create(clist_derv,maxlist,15,15,"FilterCorotate:derivative"); - memory->create(clist_q0,maxlist,15,"FilterCorotate:q0"); - memory->create(clist_nselect1,maxlist,"FilterCorotate:nselect1"); - memory->create(clist_nselect2,maxlist,"FilterCorotate:nselect2"); - memory->create(clist_select1,maxlist,5,"FilterCorotate:select1"); - memory->create(clist_select2,maxlist,5,"FilterCorotate:select2"); - } - - // build list of clusters I compute - - nlist = 0; - - for (int i = 0; i < nlocal; i++) - if (shake_flag[i]) { - if (shake_flag[i] == 2) { - atom1 = atom->map(shake_atom[i][0]); - atom2 = atom->map(shake_atom[i][1]); - if (atom1 == -1 || atom2 == -1) { - char str[128]; - sprintf(str,"Cluster atoms " TAGINT_FORMAT " " TAGINT_FORMAT - " missing on proc %d at step " BIGINT_FORMAT, - shake_atom[i][0],shake_atom[i][1],me,update->ntimestep); - error->one(FLERR,str); - } - if (i <= atom1 && i <= atom2) list[nlist++] = i; - } else if (shake_flag[i] == 1 || shake_flag[i] == 3) { - atom1 = atom->map(shake_atom[i][0]); - atom2 = atom->map(shake_atom[i][1]); - atom3 = atom->map(shake_atom[i][2]); - if (atom1 == -1 || atom2 == -1 || atom3 == -1) { - char str[128]; - sprintf(str,"Cluster atoms " - TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT - " missing on proc %d at step " BIGINT_FORMAT, - shake_atom[i][0],shake_atom[i][1],shake_atom[i][2], - me,update->ntimestep); - error->one(FLERR,str); - } - if (i <= atom1 && i <= atom2 && i <= atom3) list[nlist++] = i; - } else if (shake_flag[i] == 4) { - atom1 = atom->map(shake_atom[i][0]); - atom2 = atom->map(shake_atom[i][1]); - atom3 = atom->map(shake_atom[i][2]); - atom4 = atom->map(shake_atom[i][3]); - if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) { - char str[128]; - sprintf(str,"Cluster atoms " - TAGINT_FORMAT " " TAGINT_FORMAT " " - TAGINT_FORMAT " " TAGINT_FORMAT - " missing on proc %d at step " BIGINT_FORMAT, - shake_atom[i][0],shake_atom[i][1], - shake_atom[i][2],shake_atom[i][3], - me,update->ntimestep); - error->one(FLERR,str); - } - if (i <= atom1 && i <= atom2 && i <= atom3 && i <= atom4) - list[nlist++] = i; - } else if (shake_flag[i] == 5) { - atom1 = atom->map(shake_atom[i][0]); - atom2 = atom->map(shake_atom[i][1]); - atom3 = atom->map(shake_atom[i][2]); - atom4 = atom->map(shake_atom[i][3]); - atom5 = atom->map(shake_atom[i][4]); - if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1 || atom5 == -1) { - char str[128]; - sprintf(str,"Cluster atoms " - TAGINT_FORMAT " " TAGINT_FORMAT " " - TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT - " missing on proc %d at step " BIGINT_FORMAT, - shake_atom[i][0],shake_atom[i][1], - shake_atom[i][2],shake_atom[i][3],shake_atom[i][4], - me,update->ntimestep); - error->one(FLERR,str); - } - if (i <= atom1 && i <= atom2 && i <= atom3 && i <= atom4 && i <= atom5) - list[nlist++] = i; - } - } - - //also build reference config lists - int m,N,oxy; - double r0,r1,r2,r3,theta0; - double m1,m2,m3,m4,m5,m_all; - - double *mass = atom->mass; - int *type = atom->type; - - for (int i=0; i<nlist; i++) - { - m = list[i]; - N = shake_flag[m]; - - //switch cluster type 3 to angle cluster: - if (N == 3) - { - //make it an angle cluster: - if (shake_type[m][2] == 0) - shake_type[m][2] = angletype_findset(atom->map(shake_atom[m][0]),shake_atom[m][1],shake_atom[m][2],0); - } - - if (N == 1) N = 3; //angle cluster - - if (N == 2) //cluster of size 2: - { - atom1 = atom->map(shake_atom[m][0]); - atom2 = atom->map(shake_atom[m][1]); - - r0 = bond_distance[shake_type[m][0]]; - - m1 = mass[type[atom1]]; - m2 = mass[type[atom2]]; - m_all = m1 + m2; - - double a1 = -m2/(m1+m2)*r0; - double a2 = m1/(m1+m2)*r0; - - clist_q0[i][0] = a1; - clist_q0[i][1] = 0; - clist_q0[i][2] = 0; - - clist_q0[i][3] = a2; - clist_q0[i][4] = 0; - clist_q0[i][5] = 0; - - clist_nselect1[i] = 1; - clist_select1[i][0] = 1; - - clist_nselect2[i] = 0; - clist_select2[i][0] = 0; - } else if (N == 3) //angle cluster - { - oxy = atom->map(shake_atom[m][0]); - atom1 = atom->map(shake_atom[m][1]); - atom2 = atom->map(shake_atom[m][2]); - - r0 = bond_distance[shake_type[m][0]]; - r1 = bond_distance[shake_type[m][1]]; - - - theta0 = angle_distance[shake_type[m][2]]; - - m1 = mass[type[oxy]]; - m2 = mass[type[atom1]]; - m3 = mass[type[atom2]]; - m_all = m1 + m2 + m3; - - double alpha1 = 0.5*(MY_PI - theta0); - - double xcenter = m2/m_all*r0*sin(alpha1) + m3/m_all*r1*sin(alpha1); - double ycenter = -m2/m_all*r0*cos(alpha1)+ m3/m_all*r1*cos(alpha1); - - double q1 = -xcenter; - double q2 = -ycenter; - - double q4 = r0*sin(alpha1)-xcenter; - double q5 = r0*cos(alpha1)-ycenter; - - double q7 = r1*sin(alpha1)-xcenter; - double q8 = -r1*cos(alpha1)-ycenter; - - clist_q0[i][0] = q1; - clist_q0[i][1] = q2; - clist_q0[i][2] = 0; - - clist_q0[i][3] = q4; - clist_q0[i][4] = q5; - clist_q0[i][5] = 0; - - clist_q0[i][6] = q7; - clist_q0[i][7] = q8; - clist_q0[i][8] = 0; - - clist_nselect1[i] = 2; - clist_select1[i][0] = 1; clist_select1[i][1] = 2; - clist_nselect2[i] = 1; - clist_select2[i][0] = 1; - } else if (N == 4) - { - oxy = atom->map(shake_atom[m][0]); - atom1 = atom->map(shake_atom[m][1]); - atom2 = atom->map(shake_atom[m][2]); - atom3 = atom->map(shake_atom[m][3]); - - r0 = bond_distance[shake_type[m][0]]; - r1 = bond_distance[shake_type[m][1]]; - r2 = bond_distance[shake_type[m][2]]; - - m1 = atom->mass[atom->type[oxy]]; - m2 = atom->mass[atom->type[atom1]]; - m3 = atom->mass[atom->type[atom2]]; - m4 = atom->mass[atom->type[atom3]]; - m_all = m1 + m2 + m3 + m4; - - //how to get these angles? - double alpha1 = MY_PI/2.57; //roughly 70 degrees - double alpha2 = MY_PI/3; - //ENSURE ycenter,zcenter = 0! - //approximate xcenter, if r0 !=r1 != r2, exact if r0 = r1 = r2 - double xcenter = (m2*r0+m3*r1+m4*r2)/m_all*cos(alpha1); - - clist_q0[i][0] = -xcenter; - clist_q0[i][1] = 0.0; - clist_q0[i][2] = 0.0; - clist_q0[i][3] = r0*cos(alpha1)-xcenter; - clist_q0[i][4] = -r0*sin(alpha1); - clist_q0[i][5] = 0.0; - clist_q0[i][6] = r1*cos(alpha1)-xcenter; - clist_q0[i][7] = r1*sin(alpha1)*cos(alpha2); - clist_q0[i][8] = -r1*sin(alpha1)*sin(alpha2); - clist_q0[i][9] = r2*cos(alpha1)-xcenter; - clist_q0[i][10] = r2*sin(alpha1)*cos(alpha2); - clist_q0[i][11] = r2*sin(alpha1)*sin(alpha2); - - clist_nselect1[i] = 3; - clist_nselect2[i] = 2; - - clist_select1[i][0] = 1;clist_select1[i][1] = 2;clist_select1[i][2] = 3; - clist_select2[i][0] = 2;clist_select2[i][1] = 3; - - //signum ensures correct ordering of three satellites - //signum = sign(cross(x2-x1,x3-x1))T*(x1-x0)) - double del1[3], del2[3], del3[3]; - del1[0] = x[atom1][0]-x[oxy][0]; - del1[1] = x[atom1][1]-x[oxy][1]; - del1[2] = x[atom1][2]-x[oxy][2]; - domain->minimum_image(del1); - - del2[0] = x[atom2][0]-x[atom1][0]; - del2[1] = x[atom2][1]-x[atom1][1]; - del2[2] = x[atom2][2]-x[atom1][2]; - domain->minimum_image(del2); - - del3[0] = x[atom3][0]-x[atom1][0]; - del3[1] = x[atom3][1]-x[atom1][1]; - del3[2] = x[atom3][2]-x[atom1][2]; - domain->minimum_image(del3); - - double a = (del2[1])*(del3[2]) - (del2[2])*(del3[1]); - double b = (del2[2])*(del3[0]) - (del2[0])*(del3[2]); - double c = (del2[0])*(del3[1]) - (del2[1])*(del3[0]); - int signum = sgn(a*(del1[0]) + b*(del1[1]) + c*(del1[2])); - - if (fabs(signum)!= 1) error->all(FLERR,"Wrong orientation in cluster of size 4 in fix filter/corotate!"); - clist_q0[i][8] *= signum; - clist_q0[i][11] *= signum; - - } else if (N == 5) - { - oxy = atom->map(shake_atom[m][0]); - atom1 = atom->map(shake_atom[m][1]); - atom2 = atom->map(shake_atom[m][2]); - atom3 = atom->map(shake_atom[m][3]); - int c1 = atom->map(shake_atom[m][4]); - - r1 = bond_distance[shake_type[m][3]]; - r0 = bond_distance[shake_type[m][0]]; - theta0 = angle_distance[shake_type[m][2]]; - - m1 = atom->mass[atom->type[oxy]]; - m2 = atom->mass[atom->type[atom1]]; - m3 = atom->mass[atom->type[atom2]]; - m4 = atom->mass[atom->type[atom3]]; - m5 = atom->mass[atom->type[c1]]; - m_all = m1 + m2 + m3 + m4 + m5; - - double alpha1 = MY_PI/2.57; //roughly 70 degrees - double alpha2 = MY_PI/3; - //ENSURE ycenter,zcenter = 0! - double xcenter = -(m2+m3+m4)/m_all*r0*cos(alpha1) +r1*m5/m_all; - - clist_q0[i][0] = -xcenter; - clist_q0[i][1] = 0.0; - clist_q0[i][2] = 0.0; - clist_q0[i][3] = -r0*cos(alpha1)-xcenter; - clist_q0[i][4] = -r0*sin(alpha1); - clist_q0[i][5] = 0.0; - clist_q0[i][6] = -r0*cos(alpha1)-xcenter; - clist_q0[i][7] = r0*sin(alpha1)*cos(alpha2); - clist_q0[i][8] = r0*sin(alpha1)*sin(alpha2); - clist_q0[i][9] = -r0*cos(alpha1)-xcenter; - clist_q0[i][10] = r0*sin(alpha1)*cos(alpha2); - clist_q0[i][11] = -r0*sin(alpha1)*sin(alpha2); - clist_q0[i][12] = r1-xcenter; - clist_q0[i][13] = 0.0; - clist_q0[i][14] = 0.0; - clist_nselect1[i] = 1; - clist_nselect2[i] = 2; - - clist_select1[i][0] = 4; - clist_select2[i][0] = 2;clist_select2[i][1] = 3; - - //signum ensures correct ordering of three satellites - //signum = sign(cross(x2-x1,x3-x1))T*(x1-x0)) - double del1[3], del2[3], del3[3]; - del1[0] = x[atom1][0]-x[oxy][0]; - del1[1] = x[atom1][1]-x[oxy][1]; - del1[2] = x[atom1][2]-x[oxy][2]; - domain->minimum_image(del1); - - del2[0] = x[atom2][0]-x[atom1][0]; - del2[1] = x[atom2][1]-x[atom1][1]; - del2[2] = x[atom2][2]-x[atom1][2]; - domain->minimum_image(del2); - - del3[0] = x[atom3][0]-x[atom1][0]; - del3[1] = x[atom3][1]-x[atom1][1]; - del3[2] = x[atom3][2]-x[atom1][2]; - domain->minimum_image(del3); - - double a = (del2[1])*(del3[2]) - (del2[2])*(del3[1]); - double b = (del2[2])*(del3[0]) - (del2[0])*(del3[2]); - double c = (del2[0])*(del3[1]) - (del2[1])*(del3[0]); - int signum = sgn(a*(del1[0]) + b*(del1[1]) + c*(del1[2])); - - if (fabs(signum)!= 1) error->all(FLERR,"Wrong orientation in cluster of size 5 in fix filter/corotate!"); - clist_q0[i][8] *= signum; - clist_q0[i][11] *= signum; - } - else - { - error->all(FLERR,"Fix filter/corotate cluster with size > 5 not yet configured..."); - } - - } -} - -/* ---------------------------------------------------------------------- - * setup, needs to patch missing setup_post_force_respa() in respa... - * ------------------------------------------------------------------------- */ - -void FixFilterCorotate::setup(int vflag) -{ - ((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1); - post_force_respa(vflag,nlevels_respa-1,0); - ((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1); -} - - -void FixFilterCorotate::setup_pre_force_respa(int vflag,int ilevel){ - pre_force_respa(vflag,ilevel,0); -} - -//void FixFilterCorotate::setup_post_force_respa(int vflag,int ilevel){ -// post_force_respa(vflag,ilevel,0); -//} - - -double FixFilterCorotate::compute_array(int,int) -{ - filter_inner(); - return 1; -} - -void FixFilterCorotate::pre_force_respa(int vflag, int ilevel, int iloop) -{ - if (ilevel == nlevels_respa-1) - { - filter_inner(); - - //%Switch pointers x<-->x_filter - x_store = atom->x; - atom->x = array_atom; - } -} - - -void FixFilterCorotate::post_force_respa(int vflag, int ilevel, int iloop) -{ - if (ilevel == nlevels_respa-1) - { - atom->x = x_store; - - comm->forward_comm_fix(this); //comm forward of forces for outer filter - - filter_outer(); - } -} - -/* ---------------------------------------------------------------------- */ - -void FixFilterCorotate::filter_inner() -{ - //periodic boundaries, proc boundaries - - int nall = atom->nlocal + atom->nghost; - - double **x = atom->x; - - int nlocal = atom->nlocal; - int* type = atom->type; - - //set array_atom to atom->x, in case some atoms are not part of any cluster: - for (int i=0; i<nall; i++) - { - array_atom[i][0] = x[i][0]; - array_atom[i][1] = x[i][1]; - array_atom[i][2] = x[i][2]; - } - - int m; - //iterate through list: - for (int i=0; i<nlist; i++) - { - m = list[i]; - - //filter: - general_cluster(m,i); - } - -} - - -/* ---------------------------------------------------------------------- */ - -void FixFilterCorotate::filter_outer() -{ - double sum1,sum2,sum3; - - double** f = atom->f; - int nlocal = atom->nlocal; - - int m; - - for (int i=0; i<nlist; i++) - { - m = list[i]; - int dim = shake_flag[m]; - if (dim == 1) //case: angle - dim = 3; - - for (int j = 0; j < dim; j++) - { - sum1 = sum2 = sum3 = 0; - for (int k = 0; k < dim; k++) - { - //get local tag of k-th atom in cluster i: - int kk = atom->map(shake_atom[m][k]); - //apply derivative times force - sum1 += clist_derv[i][3*j][3*k]*f[kk][0]+clist_derv[i][3*j][3*k+1]*f[kk][1]+clist_derv[i][3*j][3*k+2]*f[kk][2]; - sum2 += clist_derv[i][3*j+1][3*k]*f[kk][0]+clist_derv[i][3*j+1][3*k+1]*f[kk][1]+clist_derv[i][3*j+1][3*k+2]*f[kk][2]; - sum3 += clist_derv[i][3*j+2][3*k]*f[kk][0]+clist_derv[i][3*j+2][3*k+1]*f[kk][1]+clist_derv[i][3*j+2][3*k+2]*f[kk][2]; - } - - g[3*j] = sum1; - g[3*j+1] = sum2; - g[3*j+2] = sum3; - } - - //replace force f with filtered value: - for (int j = 0; j < dim; j++) - { - int kk = atom->map(shake_atom[m][j]); - - f[kk][0] = g[3*j]; - f[kk][1] = g[3*j+1]; - f[kk][2] = g[3*j+2]; - } - - } - -} - - -/* ---------------------------------------------------------------------- - * identify whether each atom is in a SHAKE cluster - * only include atoms in fix group and those bonds/angles specified in input - * test whether all clusters are valid - * set shake_flag, shake_atom, shake_type values - * set bond,angle types negative so will be ignored in neighbor lists - * ------------------------------------------------------------------------- */ - -void FixFilterCorotate::find_clusters() -{ - int i,j,m,n,iatom; - int flag,flag_all,nbuf,size; - tagint tagprev; - double massone; - tagint *buf; - - if (me == 0 && screen) - fprintf(screen,"Finding filter clusters ...\n"); - - - - tagint *tag = atom->tag; - int *type = atom->type; - int *mask = atom->mask; - double *mass = atom->mass; - double *rmass = atom->rmass; - int **nspecial = atom->nspecial; - tagint **special = atom->special; - - - int nlocal = atom->nlocal; - int angles_allow = atom->avec->angles_allow; - - // setup ring of procs - - int next = me + 1; - int prev = me -1; - if (next == nprocs) next = 0; - if (prev < 0) prev = nprocs - 1; - - // ----------------------------------------------------- - // allocate arrays for self (1d) and bond partners (2d) - // max = max # of bond partners for owned atoms = 2nd dim of partner arrays - // npartner[i] = # of bonds attached to atom i - // nshake[i] = # of SHAKE bonds attached to atom i - // partner_tag[i][] = global IDs of each partner - // partner_mask[i][] = mask of each partner - // partner_type[i][] = type of each partner - // partner_massflag[i][] = 1 if partner meets mass criterion, 0 if not - // partner_bondtype[i][] = type of bond attached to each partner - // partner_shake[i][] = 1 if SHAKE bonded to partner, 0 if not - // partner_nshake[i][] = nshake value for each partner - // ----------------------------------------------------- - - int max = 0; - - for (i = 0; i < nlocal; i++) max = MAX(max,nspecial[i][0]); - - int *npartner; - memory->create(npartner,nlocal,"shake:npartner"); - memory->create(nshake,nlocal,"shake:nshake"); - - tagint **partner_tag; - int **partner_mask,**partner_type,**partner_massflag; - int **partner_bondtype,**partner_shake,**partner_nshake; - memory->create(partner_tag,nlocal,max,"shake:partner_tag"); - memory->create(partner_mask,nlocal,max,"shake:partner_mask"); - memory->create(partner_type,nlocal,max,"shake:partner_type"); - memory->create(partner_massflag,nlocal,max,"shake:partner_massflag"); - memory->create(partner_bondtype,nlocal,max,"shake:partner_bondtype"); - memory->create(partner_shake,nlocal,max,"shake:partner_shake"); - memory->create(partner_nshake,nlocal,max,"shake:partner_nshake"); - - // ----------------------------------------------------- - // set npartner and partner_tag from special arrays - // ----------------------------------------------------- - - - for (i = 0; i < nlocal; i++) { - npartner[i] = nspecial[i][0]; - for (j = 0; j < npartner[i]; j++) - partner_tag[i][j] = special[i][j]; - } - - - // ----------------------------------------------------- - // set partner_mask, partner_type, partner_massflag, partner_bondtype - // for bonded partners - // requires communication for off-proc partners - // ----------------------------------------------------- - - // fill in mask, type, massflag, bondtype if own bond partner - // info to store in buf for each off-proc bond = nper = 6 - // 2 atoms IDs in bond, space for mask, type, massflag, bondtype - // nbufmax = largest buffer needed to hold info from any proc - - int nper = 6; - - nbuf = 0; - for (i = 0; i < nlocal; i++) { - for (j = 0; j < npartner[i]; j++) { - partner_mask[i][j] = 0; - partner_type[i][j] = 0; - partner_massflag[i][j] = 0; - partner_bondtype[i][j] = 0; - - m = atom->map(partner_tag[i][j]); - if (m >= 0 && m < nlocal) { - partner_mask[i][j] = mask[m]; - partner_type[i][j] = type[m]; - if (nmass) { - if (rmass) massone = rmass[m]; - else massone = mass[type[m]]; - partner_massflag[i][j] = masscheck(massone); - } - n = bondtype_findset(i,tag[i],partner_tag[i][j],0); - if (n) partner_bondtype[i][j] = n; - else { - n = bondtype_findset(m,tag[i],partner_tag[i][j],0); - if (n) partner_bondtype[i][j] = n; - } - } else nbuf += nper; - } - } - - memory->create(buf,nbuf,"filter/corotate:buf"); - - // fill buffer with info - - size = 0; - for (i = 0; i < nlocal; i++) { - for (j = 0; j < npartner[i]; j++) { - m = atom->map(partner_tag[i][j]); - if (m < 0 || m >= nlocal) { - buf[size] = tag[i]; - buf[size+1] = partner_tag[i][j]; - buf[size+2] = 0; - buf[size+3] = 0; - buf[size+4] = 0; - n = bondtype_findset(i,tag[i],partner_tag[i][j],0); - if (n) buf[size+5] = n; - else buf[size+5] = 0; - size += nper; - } - } - } - - // cycle buffer around ring of procs back to self - - fsptr = this; - comm->ring(size,sizeof(tagint),buf,1,ring_bonds,buf); - - // store partner info returned to me - - m = 0; - while (m < size) { - i = atom->map(buf[m]); - for (j = 0; j < npartner[i]; j++) - if (buf[m+1] == partner_tag[i][j]) break; - partner_mask[i][j] = buf[m+2]; - partner_type[i][j] = buf[m+3]; - partner_massflag[i][j] = buf[m+4]; - partner_bondtype[i][j] = buf[m+5]; - m += nper; - } - - memory->destroy(buf); - - // error check for unfilled partner info - // if partner_type not set, is an error - // partner_bondtype may not be set if special list is not consistent - // with bondatom (e.g. due to delete_bonds command) - // this is OK if one or both atoms are not in fix group, since - // bond won't be SHAKEn anyway - // else it's an error - - flag = 0; - for (i = 0; i < nlocal; i++) - for (j = 0; j < npartner[i]; j++) { - if (partner_type[i][j] == 0) flag = 1; - if (!(mask[i] & groupbit)) continue; - if (!(partner_mask[i][j] & groupbit)) continue; - if (partner_bondtype[i][j] == 0) flag = 1; - } - - MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world); - if (flag_all) error->all(FLERR,"Did not find fix filter/corotate partner info"); - - // ----------------------------------------------------- - // identify SHAKEable bonds - // set nshake[i] = # of SHAKE bonds attached to atom i - // set partner_shake[i][] = 1 if SHAKE bonded to partner, 0 if not - // both atoms must be in group, bondtype must be > 0 - // check if bondtype is in input bond_flag - // check if type of either atom is in input type_flag - // check if mass of either atom is in input mass_list - // ----------------------------------------------------- - - int np; - - for (i = 0; i < nlocal; i++) { - nshake[i] = 0; - np = npartner[i]; - for (j = 0; j < np; j++) { - partner_shake[i][j] = 0; - - if (!(mask[i] & groupbit)) continue; - if (!(partner_mask[i][j] & groupbit)) continue; - if (partner_bondtype[i][j] <= 0) continue; - - if (bond_flag[partner_bondtype[i][j]]) { - partner_shake[i][j] = 1; - nshake[i]++; - continue; - } - if (type_flag[type[i]] || type_flag[partner_type[i][j]]) { - partner_shake[i][j] = 1; - nshake[i]++; - continue; - } - if (nmass) { - if (partner_massflag[i][j]) { - partner_shake[i][j] = 1; - nshake[i]++; - continue; - } else { - if (rmass) massone = rmass[i]; - else massone = mass[type[i]]; - if (masscheck(massone)) { - partner_shake[i][j] = 1; - nshake[i]++; - continue; - } - } - } - } - } - - // ----------------------------------------------------- - // set partner_nshake for bonded partners - // requires communication for off-proc partners - // ----------------------------------------------------- - - // fill in partner_nshake if own bond partner - // info to store in buf for each off-proc bond = - // 2 atoms IDs in bond, space for nshake value - // nbufmax = largest buffer needed to hold info from any proc - - nbuf = 0; - for (i = 0; i < nlocal; i++) { - for (j = 0; j < npartner[i]; j++) { - m = atom->map(partner_tag[i][j]); - if (m >= 0 && m < nlocal) partner_nshake[i][j] = nshake[m]; - else nbuf += 3; - } - } - - memory->create(buf,nbuf,"filter/corotate:buf"); - - // fill buffer with info - - size = 0; - for (i = 0; i < nlocal; i++) { - for (j = 0; j < npartner[i]; j++) { - m = atom->map(partner_tag[i][j]); - if (m < 0 || m >= nlocal) { - buf[size] = tag[i]; - buf[size+1] = partner_tag[i][j]; - size += 3; - } - } - } - - // cycle buffer around ring of procs back to self - - fsptr = this; - comm->ring(size,sizeof(tagint),buf,2,ring_nshake,buf); - - // store partner info returned to me - - m = 0; - while (m < size) { - i = atom->map(buf[m]); - for (j = 0; j < npartner[i]; j++) - if (buf[m+1] == partner_tag[i][j]) break; - partner_nshake[i][j] = buf[m+2]; - m += 3; - } - - memory->destroy(buf); - - // ----------------------------------------------------- - // error checks - // no atom with nshake > 3 - // no connected atoms which both have nshake > 1 - // ----------------------------------------------------- - - flag = 0; - for (i = 0; i < nlocal; i++) if (nshake[i] > 4) flag = 1; - MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world); - if (flag_all) error->all(FLERR,"Cluster of more than 5 atoms"); - - flag = 0; - for (i = 0; i < nlocal; i++) { - if (nshake[i] <= 1) continue; - for (j = 0; j < npartner[i]; j++) - if (partner_shake[i][j] && partner_nshake[i][j] > 1) flag = 1; - } - MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world); - if (flag_all) error->all(FLERR,"Clusters are connected"); - - // ----------------------------------------------------- - // set SHAKE arrays that are stored with atoms & add angle constraints - // zero shake arrays for all owned atoms - // if I am central atom set shake_flag & shake_atom & shake_type - // for 2-atom clusters, I am central atom if my atom ID < partner ID - // for 3-atom clusters, test for angle constraint - // angle will be stored by this atom if it exists - // if angle type matches angle_flag, then it is angle-constrained - // shake_flag[] = 0 if atom not in SHAKE cluster - // 2,3,4 = size of bond-only cluster - // 1 = 3-atom angle cluster - // shake_atom[][] = global IDs of 2,3,4 atoms in cluster - // central atom is 1st - // for 2-atom cluster, lowest ID is 1st - // shake_type[][] = bondtype of each bond in cluster - // for 3-atom angle cluster, 3rd value is angletype - // ----------------------------------------------------- - - for (i = 0; i < nlocal; i++) { - shake_flag[i] = 0; - shake_atom[i][0] = 0; - shake_atom[i][1] = 0; - shake_atom[i][2] = 0; - shake_atom[i][3] = 0; - shake_atom[i][4] = 0; - shake_type[i][0] = 0; - shake_type[i][1] = 0; - shake_type[i][2] = 0; - shake_type[i][3] = 0; - - if (nshake[i] == 1) { - for (j = 0; j < npartner[i]; j++) - if (partner_shake[i][j]) break; - if (partner_nshake[i][j] == 1 && tag[i] < partner_tag[i][j]) { - shake_flag[i] = 2; - shake_atom[i][0] = tag[i]; - shake_atom[i][1] = partner_tag[i][j]; - shake_type[i][0] = partner_bondtype[i][j]; - } - } - - if (nshake[i] > 1) { - shake_flag[i] = 1; - shake_atom[i][0] = tag[i]; - for (j = 0; j < npartner[i]; j++) - if (partner_shake[i][j]) { - m = shake_flag[i]; - shake_atom[i][m] = partner_tag[i][j]; - shake_type[i][m-1] = partner_bondtype[i][j]; - shake_flag[i]++; - } - } - - if (nshake[i] == 2 && angles_allow) { - n = angletype_findset(i,shake_atom[i][1],shake_atom[i][2],0); - if (n <= 0) continue; - //if (angle_flag[n]) { Take all angles! - shake_flag[i] = 1; - shake_type[i][2] = n; - //} - } - } - - // ----------------------------------------------------- - // set shake_flag,shake_atom,shake_type for non-central atoms - // requires communication for off-proc atoms - // ----------------------------------------------------- - - // fill in shake arrays for each bond partner I own - // info to store in buf for each off-proc bond = - // all values from shake_flag, shake_atom, shake_type - // nbufmax = largest buffer needed to hold info from any proc - - nbuf = 0; - for (i = 0; i < nlocal; i++) { - if (shake_flag[i] == 0) continue; - for (j = 0; j < npartner[i]; j++) { - if (partner_shake[i][j] == 0) continue; - m = atom->map(partner_tag[i][j]); - if (m >= 0 && m < nlocal) { - shake_flag[m] = shake_flag[i]; - shake_atom[m][0] = shake_atom[i][0]; - shake_atom[m][1] = shake_atom[i][1]; - shake_atom[m][2] = shake_atom[i][2]; - shake_atom[m][3] = shake_atom[i][3]; - shake_atom[m][4] = shake_atom[i][4]; - shake_type[m][0] = shake_type[i][0]; - shake_type[m][1] = shake_type[i][1]; - shake_type[m][2] = shake_type[i][2]; - shake_type[m][3] = shake_type[i][3]; - } else nbuf += 11; - } - } - - memory->create(buf,nbuf,"filter/corotate:buf"); - - // fill buffer with info - - size = 0; - for (i = 0; i < nlocal; i++) { - if (shake_flag[i] == 0) continue; - for (j = 0; j < npartner[i]; j++) { - if (partner_shake[i][j] == 0) continue; - m = atom->map(partner_tag[i][j]); - if (m < 0 || m >= nlocal) { - buf[size] = partner_tag[i][j]; - buf[size+1] = shake_flag[i]; - buf[size+2] = shake_atom[i][0]; - buf[size+3] = shake_atom[i][1]; - buf[size+4] = shake_atom[i][2]; - buf[size+5] = shake_atom[i][3]; - buf[size+6] = shake_atom[i][4]; - buf[size+7] = shake_type[i][0]; - buf[size+8] = shake_type[i][1]; - buf[size+9] = shake_type[i][2]; - buf[size+10] = shake_type[i][3]; - size += 11; - } - } - } - - // cycle buffer around ring of procs back to self - - fsptr = this; - comm->ring(size,sizeof(tagint),buf,3,ring_shake,NULL); - - memory->destroy(buf); - - // ----------------------------------------------------- - // free local memory - // ----------------------------------------------------- - - memory->destroy(npartner); - memory->destroy(nshake); - memory->destroy(partner_tag); - memory->destroy(partner_mask); - memory->destroy(partner_type); - memory->destroy(partner_massflag); - memory->destroy(partner_bondtype); - memory->destroy(partner_shake); - memory->destroy(partner_nshake); - - // ----------------------------------------------------- - // set bond_type and angle_type negative for SHAKE clusters - // must set for all SHAKE bonds and angles stored by each atom - // ----------------------------------------------------- - - /* for (i = 0; i < nlocal; i++) { - * if (shake_flag[i] == 0) continue; - * else if (shake_flag[i] == 1) { - * bondtype_findset(i,shake_atom[i][0],shake_atom[i][1],-1); - * bondtype_findset(i,shake_atom[i][0],shake_atom[i][2],-1); - * angletype_findset(i,shake_atom[i][1],shake_atom[i][2],-1); -} else if (shake_flag[i] == 2) { - bondtype_findset(i,shake_atom[i][0],shake_atom[i][1],-1); -} else if (shake_flag[i] == 3) { - bondtype_findset(i,shake_atom[i][0],shake_atom[i][1],-1); - bondtype_findset(i,shake_atom[i][0],shake_atom[i][2],-1); -} else if (shake_flag[i] == 4) { - bondtype_findset(i,shake_atom[i][0],shake_atom[i][1],-1); - bondtype_findset(i,shake_atom[i][0],shake_atom[i][2],-1); - bondtype_findset(i,shake_atom[i][0],shake_atom[i][3],-1); -} -}*/ - - // ----------------------------------------------------- - // print info on SHAKE clusters - // ----------------------------------------------------- - - int count1,count2,count3,count4,count5; - count1 = count2 = count3 = count4 = count5 = 0; - for (i = 0; i < nlocal; i++) { - if (shake_flag[i] == 1) count1++; - else if (shake_flag[i] == 2) count2++; - else if (shake_flag[i] == 3) count3++; - else if (shake_flag[i] == 4) count4++; - else if (shake_flag[i] == 5) count5++; - } - - int tmp; - tmp = count1; - MPI_Allreduce(&tmp,&count1,1,MPI_INT,MPI_SUM,world); - tmp = count2; - MPI_Allreduce(&tmp,&count2,1,MPI_INT,MPI_SUM,world); - tmp = count3; - MPI_Allreduce(&tmp,&count3,1,MPI_INT,MPI_SUM,world); - tmp = count4; - MPI_Allreduce(&tmp,&count4,1,MPI_INT,MPI_SUM,world); - tmp = count5; - MPI_Allreduce(&tmp,&count5,1,MPI_INT,MPI_SUM,world); - - if (me == 0) { - if (screen) { - fprintf(screen," %d = # of size 2 clusters\n",count2/2); - fprintf(screen," %d = # of size 3 clusters\n",count3/3); - fprintf(screen," %d = # of size 4 clusters\n",count4/4); - fprintf(screen," %d = # of size 5 clusters\n",count5/5); - fprintf(screen," %d = # of frozen angles\n",count1/3); - } - if (logfile) { - fprintf(logfile," %d = # of size 2 clusters\n",count2/2); - fprintf(logfile," %d = # of size 3 clusters\n",count3/3); - fprintf(logfile," %d = # of size 4 clusters\n",count4/4); - fprintf(logfile," %d = # of size 5 clusters\n",count5/5); - fprintf(logfile," %d = # of frozen angles\n",count1/3); - } - } -} - -/* ---------------------------------------------------------------------- - * when receive buffer, scan bond partner IDs for atoms I own - * if I own partner: - * fill in mask and type and massflag - * search for bond with 1st atom and fill in bondtype - * ------------------------------------------------------------------------- */ - -void FixFilterCorotate::ring_bonds(int ndatum, char *cbuf) -{ - Atom *atom = fsptr->atom; - double *rmass = atom->rmass; - double *mass = atom->mass; - int *mask = atom->mask; - int *type = atom->type; - int nlocal = atom->nlocal; - int nmass = fsptr->nmass; - - tagint *buf = (tagint *) cbuf; - int m,n; - double massone; - - for (int i = 0; i < ndatum; i += 6) { - m = atom->map(buf[i+1]); - if (m >= 0 && m < nlocal) { - buf[i+2] = mask[m]; - buf[i+3] = type[m]; - if (nmass) { - if (rmass) massone = rmass[m]; - else massone = mass[type[m]]; - buf[i+4] = fsptr->masscheck(massone); - } - if (buf[i+5] == 0) { - n = fsptr->bondtype_findset(m,buf[i],buf[i+1],0); - if (n) buf[i+5] = n; - } - } - } -} - -/* ---------------------------------------------------------------------- - * when receive buffer, scan bond partner IDs for atoms I own - * if I own partner, fill in nshake value - * ------------------------------------------------------------------------- */ - -void FixFilterCorotate::ring_nshake(int ndatum, char *cbuf) -{ - Atom *atom = fsptr->atom; - int nlocal = atom->nlocal; - - int *nshake = fsptr->nshake; - - tagint *buf = (tagint *) cbuf; - int m; - - for (int i = 0; i < ndatum; i += 3) { - m = atom->map(buf[i+1]); - if (m >= 0 && m < nlocal) buf[i+2] = nshake[m]; - } -} - -/* ---------------------------------------------------------------------- - * when receive buffer, scan bond partner IDs for atoms I own - * if I own partner, fill in nshake value - * ------------------------------------------------------------------------- */ - -void FixFilterCorotate::ring_shake(int ndatum, char *cbuf) -{ - Atom *atom = fsptr->atom; - int nlocal = atom->nlocal; - - int *shake_flag = fsptr->shake_flag; - tagint **shake_atom = fsptr->shake_atom; - int **shake_type = fsptr->shake_type; - - tagint *buf = (tagint *) cbuf; - int m; - - for (int i = 0; i < ndatum; i += 11) { - m = atom->map(buf[i]); - if (m >= 0 && m < nlocal) { - shake_flag[m] = buf[i+1]; - shake_atom[m][0] = buf[i+2]; - shake_atom[m][1] = buf[i+3]; - shake_atom[m][2] = buf[i+4]; - shake_atom[m][3] = buf[i+5]; - shake_atom[m][4] = buf[i+6]; - shake_type[m][0] = buf[i+7]; - shake_type[m][1] = buf[i+8]; - shake_type[m][2] = buf[i+9]; - shake_type[m][3] = buf[i+10]; - } - } -} - -/* ---------------------------------------------------------------------- - * check if massone is within MASSDELTA of any mass in mass_list - * return 1 if yes, 0 if not - * ------------------------------------------------------------------------- */ - -int FixFilterCorotate::masscheck(double massone) -{ - for (int i = 0; i < nmass; i++) - if (fabs(mass_list[i]-massone) <= MASSDELTA) return 1; - return 0; -} - -/* -------------------------------------------------------------------------- - * filter one cluster of arbitrary size - * ---------------------------------------------------------------------------*/ - -void FixFilterCorotate::general_cluster(int index, int index_in_list) -{ - //index: shake index, index_in_list: corresponding index in list - - //get q0, nselect: - double *q0 = clist_q0[index_in_list]; - int nselect1 = clist_nselect1[index_in_list]; - int nselect2 = clist_nselect2[index_in_list]; - int *select1 = clist_select1[index_in_list]; - int *select2 = clist_select2[index_in_list]; - - int N = shake_flag[index]; //number of atoms in cluster - if (N == 1) N = 3; //angle cluster - - double**x = atom->x; - double norm1, norm2, norm3; - - int* list_cluster = new int[N]; //contains local IDs of cluster atoms, 0 = center - double* m = new double[N]; //contains local mass - double *r = new double[N]; //contains r[i] = 1/||del[i]|| - double** del = new double*[N]; //contains del[i] = x_i-x_0 - for (int i = 0; i<N; i++) - del[i] = new double[3]; - - for (int i = 0; i < N; i++) - { - list_cluster[i] = atom->map(shake_atom[index][i]); - m[i] = atom->mass[atom->type[list_cluster[i]]]; - } - - //%CALC r_i: - for (int i = 1; i < N; i++) - { - del[i][0] = x[list_cluster[i]][0] - x[list_cluster[0]][0]; - del[i][1] = x[list_cluster[i]][1] - x[list_cluster[0]][1]; - del[i][2] = x[list_cluster[i]][2] - x[list_cluster[0]][2]; - domain->minimum_image(del[i]); - r[i] = 1.0/sqrt(del[i][0]*del[i][0]+del[i][1]*del[i][1]+del[i][2]*del[i][2]); - } - //special case i=0: need del[0] for compact notation of array_atom later... - del[0][0] = del[0][1] = del[0][2] = r[0] = 0.0; - - //calc n1: - n1[0] = n1[1] = n1[2] = 0.0; - - int k; - for (int i = 0; i < nselect1; i++) - { - k = select1[i]; - n1[0] += del[k][0]*r[k]; - n1[1] += del[k][1]*r[k]; - n1[2] += del[k][2]*r[k]; - } - norm1 = 1.0/sqrt(n1[0]*n1[0]+n1[1]*n1[1]+n1[2]*n1[2]); - - n1[0] *= norm1; - n1[1] *= norm1; - n1[2] *= norm1; - - //calc n2: - n2[0] = n2[1] = n2[2] = 0.0; - - for (int i = 0; i < nselect2; i++) - { - k = select2[i]; - n2[0] += del[k][0]*r[k]; - n2[1] += del[k][1]*r[k]; - n2[2] += del[k][2]*r[k]; - } - if (!nselect2) //cluster of size 2, has only one direction - n2[0] = n2[1] = n2[2] = 1.0; - - double alpha = n2[0]*n1[0] + n2[1]*n1[1] + n2[2]*n1[2]; - - n2[0] -= alpha*n1[0]; - n2[1] -= alpha*n1[1]; - n2[2] -= alpha*n1[2]; - - norm2 = 1.0/sqrt(n2[0]*n2[0]+n2[1]*n2[1]+n2[2]*n2[2]); - - n2[0] *= norm2; - n2[1] *= norm2; - n2[2] *= norm2; - - n3[0] = n1[1]*n2[2] - n1[2]*n2[1]; - n3[1] = n1[2]*n2[0] - n1[0]*n2[2]; - n3[2] = n1[0]*n2[1] - n1[1]*n2[0]; - - norm3 = 1.0/sqrt(n3[0]*n3[0]+n3[1]*n3[1]+n3[2]*n3[2]); - - n3[0] *= norm3; - n3[1] *= norm3; - n3[2] *= norm3; - - //%x_filter: - for (int i = 0; i < N; i++) - { - k = list_cluster[i]; - array_atom[k][0] = x[k][0]+q0[3*i]*n1[0]+q0[3*i+1]*n2[0]+q0[3*i+2]*n3[0]; - array_atom[k][1] = x[k][1]+q0[3*i]*n1[1]+q0[3*i+1]*n2[1]+q0[3*i+2]*n3[1]; - array_atom[k][2] = x[k][2]+q0[3*i]*n1[2]+q0[3*i+1]*n2[2]+q0[3*i+2]*n3[2]; - } - - double m_all = 0.0; - for (int i = 0; i<N; i++) - m_all += m[i]; - - //%x+X_center - - for (int i = 0; i<N; i++) - { - k = list_cluster[i]; - for (int j = 0; j < N; j++) - { - array_atom[k][0] += m[j]/m_all*(del[j][0]-del[i][0]); - array_atom[k][1] += m[j]/m_all*(del[j][1]-del[i][1]); - array_atom[k][2] += m[j]/m_all*(del[j][2]-del[i][2]); - } - } - - //derivative: - //dn1dx: - double sum1[3][3*N]; - for (int i=0; i<3; i++) - for (int j=0; j<3*N; j++) - sum1[i][j] = 0; - - double I3mn1n1T[3][3]; //(I_3 - n1n1T) - for (int i=0; i<3; i++) - { - for (int j=0; j<3; j++) - I3mn1n1T[i][j] = -n1[i]*n1[j]; - I3mn1n1T[i][i] += 1.0; - } - // sum1 part of dn1dx: - for (int l = 0; l < nselect1; l++) - { - k = select1[l]; - for (int i=0; i<3; i++) - { - for (int j=0; j<3; j++) - { - double help = del[k][i]*del[k][j]*r[k]*r[k]*r[k]; - sum1[i][j+3*k] -= help; - sum1[i][j] += help; - } - sum1[i][i+3*k] += r[k]; - sum1[i][i] -= r[k]; - } - } - //dn1dx = norm1 * I3mn1n1T * sum1 - for (int i=0; i<3; i++) - { - for (int j=0; j<3*N; j++) - { - double sum = 0; - for (int l = 0; l<3; l++) - sum += I3mn1n1T[i][l]*sum1[l][j]; - dn1dx[i][j] = norm1*sum; - } - } - - //dn2dx: norm2 * I3mn2n2T * (I3mn1n1T*sum2 - rkn1pn1rk*dn1dx) - double sum2[3][3*N]; - for (int i=0; i<3; i++) - for (int j=0; j<3*N; j++) - sum2[i][j] = 0; - - double I3mn2n2T[3][3]; //(I_3 - n2n2T) - for (int i=0; i<3; i++) - { - for (int j=0; j<3; j++) - I3mn2n2T[i][j] = -n2[i]*n2[j]; - I3mn2n2T[i][i] += 1.0; - } - - // sum2 part of dn1dx: - for (int l = 0; l < nselect2; l++) - { - k = select2[l]; - for (int i=0; i<3; i++) - { - for (int j=0; j<3; j++) - { - double help = del[k][i]*del[k][j]*r[k]*r[k]*r[k]; - sum2[i][j+3*k] -= help; - sum2[i][j] += help; - } - sum2[i][i+3*k] += r[k]; - sum2[i][i] -= r[k]; - } - } - - //prefaktor: - double rkn1pn1rk[3][3]; - double rk[3]; rk[0] = rk[1] = rk[2] = 0.0; - - for (int i = 0; i < nselect2; i++) - { - k = select2[i]; - rk[0] += del[k][0]*r[k]; - rk[1] += del[k][1]*r[k]; - rk[2] += del[k][2]*r[k]; - } - //rkn1pn1rk = rkT*n1*I3 + n1*rkT - double scalar = rk[0]*n1[0]+rk[1]*n1[1]+rk[2]*n1[2]; - for (int i=0; i<3; i++) - { - for (int j=0; j<3; j++) - rkn1pn1rk[i][j] = n1[i]*rk[j]; - rkn1pn1rk[i][i] += scalar; - } - //dn2dx: norm2 * I3mn2n2T * (I3mn1n1T*sum2 - rkn1pn1rk*dn1dx) - //sum3 = (I3mn1n1T*sum2 - rkn1pn1rk*dn1dx) - double sum3[3][3*N]; - for (int i=0; i<3; i++) - { - for (int j=0; j<3*N; j++) - { - double sum = 0; - for (int l = 0; l<3; l++) - sum += I3mn1n1T[i][l]*sum2[l][j] - rkn1pn1rk[i][l]*dn1dx[l][j]; - sum3[i][j] = sum; - } - } - //dn2dx = norm2 * I3mn2n2T * sum3 - for (int i=0; i<3; i++) - { - for (int j=0; j<3*N; j++) - { - double sum = 0; - for (int l = 0; l<3; l++) - sum += I3mn2n2T[i][l]*sum3[l][j]; - dn2dx[i][j] = norm2*sum; - } - } - - //dn3dx = norm3 * I3mn3n3T * cross - double I3mn3n3T[3][3]; //(I_3 - n3n3T) - for (int i=0; i<3; i++) - { - for (int j=0; j<3; j++) - I3mn3n3T[i][j] = -n3[i]*n3[j]; - I3mn3n3T[i][i] += 1.0; - } - - double cross[3][3*N]; - - for (int j=0; j<3*N; j++) - { - cross[0][j] = dn1dx[1][j]*n2[2] -dn1dx[2][j]*n2[1] + n1[1]*dn2dx[2][j]-n1[2]*dn2dx[1][j]; - cross[1][j] = dn1dx[2][j]*n2[0] -dn1dx[0][j]*n2[2] + n1[2]*dn2dx[0][j]-n1[0]*dn2dx[2][j]; - cross[2][j] = dn1dx[0][j]*n2[1] -dn1dx[1][j]*n2[0] + n1[0]*dn2dx[1][j]-n1[1]*dn2dx[0][j]; - } - - for (int i=0; i<3; i++) - { - for (int j=0; j<3*N; j++) - { - double sum = 0; - for (int l = 0; l<3; l++) - sum += I3mn3n3T[i][l]*cross[l][j]; - dn3dx[i][j] = norm3*sum; - } - } - for (int l=0; l<N; l++) - for (int i=0; i<3; i++) - for (int j=0; j<3*N; j++) - help2[i+3*l][j] = q0[3*l]*dn1dx[i][j] + q0[3*l+1]*dn2dx[i][j] + q0[3*l+2]*dn3dx[i][j]; - - for (int j=0; j<N; j++) - for (int l=0; l<N; l++) - for (int i=0; i<3; i++) - help2[i+3*l][i+3*j] += m[j]/m_all; - - //need transposed of help2: - for (int ii = 0; ii < 3*N; ii++) - for (int jj = 0; jj < 3*N; jj++) - clist_derv[index_in_list][ii][jj] = help2[jj][ii]; - - //free memory - delete [] list_cluster; - delete [] m; - delete [] r; - for (int i = 0; i<N; i++) - delete [] del[i]; - delete [] del; -} - - - -int FixFilterCorotate::pack_forward_comm(int n, int *list, double *buf,int pbc_flag, int *pbc) -{ - int i,j,m; - double**f = atom->f; - m = 0; - for (i = 0; i < n; i++) - { - j = list[i]; - - buf[m++] = f[j][0]; - buf[m++] = f[j][1]; - buf[m++] = f[j][2]; - } - return m; -} - -void FixFilterCorotate::unpack_forward_comm(int n, int first, double *buf) -{ - int i,m,last; - double **f = atom->f; - m = 0; - last = first + n; - - for (i = first; i < last; i++) - { - f[i][0] = buf[m++]; - f[i][1] = buf[m++]; - f[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- - * find a bond between global atom IDs n1 and n2 stored with local atom i - * if find it: - * if setflag = 0, return bond type - * if setflag = -1/1, set bond type to negative/positive and return 0 - * if do not find it, return 0 - * ------------------------------------------------------------------------- */ - -int FixFilterCorotate::bondtype_findset(int i, tagint n1, tagint n2, int setflag) -{ - int m,nbonds; - int *btype; - - - tagint *tag = atom->tag; - tagint **bond_atom = atom->bond_atom; - nbonds = atom->num_bond[i]; - - for (m = 0; m < nbonds; m++) { - if (n1 == tag[i] && n2 == bond_atom[i][m]) break; - if (n1 == bond_atom[i][m] && n2 == tag[i]) break; - } - - - - if (m < nbonds) { - if (setflag == 0) - return atom->bond_type[i][m]; - - if ((setflag < 0 && atom->bond_type[i][m] > 0) || - (setflag > 0 && atom->bond_type[i][m] < 0)) - atom->bond_type[i][m] = -atom->bond_type[i][m]; - - } - - return 0; -} - -/* ---------------------------------------------------------------------- - * find an angle with global end atom IDs n1 and n2 stored with local atom i - * if find it: - * if setflag = 0, return angle type - * if setflag = -1/1, set angle type to negative/positive and return 0 - * if do not find it, return 0 - * ------------------------------------------------------------------------- */ - -int FixFilterCorotate::angletype_findset(int i, tagint n1, tagint n2, int setflag) -{ - int m,nangles; - int *atype; - - - tagint **angle_atom1 = atom->angle_atom1; - tagint **angle_atom3 = atom->angle_atom3; - nangles = atom->num_angle[i]; - - for (m = 0; m < nangles; m++) { - if (n1 == angle_atom1[i][m] && n2 == angle_atom3[i][m]) break; - if (n1 == angle_atom3[i][m] && n2 == angle_atom1[i][m]) break; - } - - - if (m < nangles) { - if (setflag == 0) { - return atom->angle_type[i][m]; - } - - if ((setflag < 0 && atom->angle_type[i][m] > 0) || - (setflag > 0 && atom->angle_type[i][m] < 0)) - atom->angle_type[i][m] = -atom->angle_type[i][m]; - - } - - return 0; -} - - -/* ---------------------------------------------------------------------- - * allocate local atom-based arrays - * ------------------------------------------------------------------------- */ - -void FixFilterCorotate::grow_arrays(int nmax) -{ - memory->grow(array_atom,nmax,3,"FilterCorotate:peratomarray"); - memory->grow(shake_flag,nmax,"FilterCorotate::shake_flag"); - memory->grow(shake_atom,nmax,5,"FilterCorotate::shake_atom"); - memory->grow(shake_type,nmax,4,"FilterCorotate::shake_type"); -} - -/* ---------------------------------------------------------------------- - * memory usage of local atom-based arrays - * ------------------------------------------------------------------------- */ - -double FixFilterCorotate::memory_usage() -{ - double bytes = 0; - //GROW: - bytes += 3*sizeof(double) + 5*sizeof(tagint) + 5*sizeof(int); - //clist - bytes += 13*atom->nlocal*sizeof(int); - bytes += 15*16*nlocal*sizeof(double); - - //fixed: - int nb = atom->nbondtypes+1; - int na = atom->nangletypes+1; - int nt = atom->ntypes+1; - bytes += (nb+na+nt)*sizeof(int); - bytes += (nt-1+nb+na+15*15+18+10*15)*sizeof(double); - - //output: - //bytes += (2*nb+2*na)*sizeof(int); - //bytes += (6*na+6*nb)*sizeof(double); - - return bytes; -} - - -/* ---------------------------------------------------------------------- - * copy values within local atom-based arrays - * ------------------------------------------------------------------------- */ - -void FixFilterCorotate::copy_arrays(int i, int j, int delflag) -{ - int flag = shake_flag[j] = shake_flag[i]; - if (flag == 1) { - shake_atom[j][0] = shake_atom[i][0]; - shake_atom[j][1] = shake_atom[i][1]; - shake_atom[j][2] = shake_atom[i][2]; - shake_type[j][0] = shake_type[i][0]; - shake_type[j][1] = shake_type[i][1]; - shake_type[j][2] = shake_type[i][2]; - } else if (flag == 2) { - shake_atom[j][0] = shake_atom[i][0]; - shake_atom[j][1] = shake_atom[i][1]; - shake_type[j][0] = shake_type[i][0]; - } else if (flag == 3) { - shake_atom[j][0] = shake_atom[i][0]; - shake_atom[j][1] = shake_atom[i][1]; - shake_atom[j][2] = shake_atom[i][2]; - shake_type[j][0] = shake_type[i][0]; - shake_type[j][1] = shake_type[i][1]; - shake_type[j][2] = shake_type[i][2]; - } else if (flag == 4) { - shake_atom[j][0] = shake_atom[i][0]; - shake_atom[j][1] = shake_atom[i][1]; - shake_atom[j][2] = shake_atom[i][2]; - shake_atom[j][3] = shake_atom[i][3]; - shake_type[j][0] = shake_type[i][0]; - shake_type[j][1] = shake_type[i][1]; - shake_type[j][2] = shake_type[i][2]; - } else if (flag == 5) { - shake_atom[j][0] = shake_atom[i][0]; - shake_atom[j][1] = shake_atom[i][1]; - shake_atom[j][2] = shake_atom[i][2]; - shake_atom[j][3] = shake_atom[i][3]; - shake_atom[j][4] = shake_atom[i][4]; - shake_type[j][0] = shake_type[i][0]; - shake_type[j][1] = shake_type[i][1]; - shake_type[j][2] = shake_type[i][2]; - shake_type[j][3] = shake_type[i][3]; - } -} - -/* ---------------------------------------------------------------------- - * initialize one atom's array values, called when atom is created - * ------------------------------------------------------------------------- */ - -void FixFilterCorotate::set_arrays(int i) -{ - shake_flag[i] = 0; -} - -/* ---------------------------------------------------------------------- - * update one atom's array values - * called when molecule is created from fix gcmc - * ------------------------------------------------------------------------- */ - -void FixFilterCorotate::update_arrays(int i, int atom_offset) -{ - int flag = shake_flag[i]; - - if (flag == 1) { - shake_atom[i][0] += atom_offset; - shake_atom[i][1] += atom_offset; - shake_atom[i][2] += atom_offset; - } else if (flag == 2) { - shake_atom[i][0] += atom_offset; - shake_atom[i][1] += atom_offset; - } else if (flag == 3) { - shake_atom[i][0] += atom_offset; - shake_atom[i][1] += atom_offset; - shake_atom[i][2] += atom_offset; - } else if (flag == 4) { - shake_atom[i][0] += atom_offset; - shake_atom[i][1] += atom_offset; - shake_atom[i][2] += atom_offset; - shake_atom[i][3] += atom_offset; - } else if (flag == 5) { - shake_atom[i][0] += atom_offset; - shake_atom[i][1] += atom_offset; - shake_atom[i][2] += atom_offset; - shake_atom[i][3] += atom_offset; - shake_atom[i][4] += atom_offset; - } -} - - -/* ---------------------------------------------------------------------- - * pack values in local atom-based arrays for exchange with another proc - * ------------------------------------------------------------------------- */ - -int FixFilterCorotate::pack_exchange(int i, double *buf) -{ - int m = 0; - buf[m++] = shake_flag[i]; - int flag = shake_flag[i]; - if (flag == 1) { - buf[m++] = shake_atom[i][0]; - buf[m++] = shake_atom[i][1]; - buf[m++] = shake_atom[i][2]; - buf[m++] = shake_type[i][0]; - buf[m++] = shake_type[i][1]; - buf[m++] = shake_type[i][2]; - } else if (flag == 2) { - buf[m++] = shake_atom[i][0]; - buf[m++] = shake_atom[i][1]; - buf[m++] = shake_type[i][0]; - } else if (flag == 3) { - buf[m++] = shake_atom[i][0]; - buf[m++] = shake_atom[i][1]; - buf[m++] = shake_atom[i][2]; - buf[m++] = shake_type[i][0]; - buf[m++] = shake_type[i][1]; - buf[m++] = shake_type[i][2]; - } else if (flag == 4) { - buf[m++] = shake_atom[i][0]; - buf[m++] = shake_atom[i][1]; - buf[m++] = shake_atom[i][2]; - buf[m++] = shake_atom[i][3]; - buf[m++] = shake_type[i][0]; - buf[m++] = shake_type[i][1]; - buf[m++] = shake_type[i][2]; - } else if (flag == 5) { - buf[m++] = shake_atom[i][0]; - buf[m++] = shake_atom[i][1]; - buf[m++] = shake_atom[i][2]; - buf[m++] = shake_atom[i][3]; - buf[m++] = shake_atom[i][4]; - buf[m++] = shake_type[i][0]; - buf[m++] = shake_type[i][1]; - buf[m++] = shake_type[i][2]; - buf[m++] = shake_type[i][3]; - } - return m; -} - -/* ---------------------------------------------------------------------- - * unpack values in local atom-based arrays from exchange with another proc - * ------------------------------------------------------------------------- */ - -int FixFilterCorotate::unpack_exchange(int nlocal, double *buf) -{ - int m = 0; - int flag = shake_flag[nlocal] = static_cast<int> (buf[m++]); - if (flag == 1) { - shake_atom[nlocal][0] = static_cast<tagint> (buf[m++]); - shake_atom[nlocal][1] = static_cast<tagint> (buf[m++]); - shake_atom[nlocal][2] = static_cast<tagint> (buf[m++]); - shake_type[nlocal][0] = static_cast<int> (buf[m++]); - shake_type[nlocal][1] = static_cast<int> (buf[m++]); - shake_type[nlocal][2] = static_cast<int> (buf[m++]); - } else if (flag == 2) { - shake_atom[nlocal][0] = static_cast<tagint> (buf[m++]); - shake_atom[nlocal][1] = static_cast<tagint> (buf[m++]); - shake_type[nlocal][0] = static_cast<int> (buf[m++]); - } else if (flag == 3) { - shake_atom[nlocal][0] = static_cast<tagint> (buf[m++]); - shake_atom[nlocal][1] = static_cast<tagint> (buf[m++]); - shake_atom[nlocal][2] = static_cast<tagint> (buf[m++]); - shake_type[nlocal][0] = static_cast<int> (buf[m++]); - shake_type[nlocal][1] = static_cast<int> (buf[m++]); - shake_type[nlocal][2] = static_cast<int> (buf[m++]); - } else if (flag == 4) { - shake_atom[nlocal][0] = static_cast<tagint> (buf[m++]); - shake_atom[nlocal][1] = static_cast<tagint> (buf[m++]); - shake_atom[nlocal][2] = static_cast<tagint> (buf[m++]); - shake_atom[nlocal][3] = static_cast<tagint> (buf[m++]); - shake_type[nlocal][0] = static_cast<int> (buf[m++]); - shake_type[nlocal][1] = static_cast<int> (buf[m++]); - shake_type[nlocal][2] = static_cast<int> (buf[m++]); - } else if (flag == 5) { - shake_atom[nlocal][0] = static_cast<tagint> (buf[m++]); - shake_atom[nlocal][1] = static_cast<tagint> (buf[m++]); - shake_atom[nlocal][2] = static_cast<tagint> (buf[m++]); - shake_atom[nlocal][3] = static_cast<tagint> (buf[m++]); - shake_atom[nlocal][4] = static_cast<tagint> (buf[m++]); - shake_type[nlocal][0] = static_cast<int> (buf[m++]); - shake_type[nlocal][1] = static_cast<int> (buf[m++]); - shake_type[nlocal][2] = static_cast<int> (buf[m++]); - shake_type[nlocal][3] = static_cast<int> (buf[m++]); - } - return m; -} +/* ---------------------------------------------------------------------- + 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: Lukas Fath (KIT) + some subroutines are from fix_shake.cpp + ------------------------------------------------------------------------- */ + +#include <mpi.h> +#include <string.h> +#include <stdlib.h> +#include "fix_filter_corotate.h" +#include "atom.h" +#include "atom_vec.h" +#include "molecule.h" +#include "bond.h" +#include "angle.h" +#include "math_const.h" +#include "update.h" +#include "modify.h" +#include "domain.h" +#include "region.h" +#include "memory.h" +#include "error.h" +#include "force.h" +#include "comm.h" +#include "error.h" +#include "memory.h" +#include "domain.h" +#include "integrate.h" +#include "respa.h" +#include "neighbor.h" +#include "citeme.h" + +using namespace LAMMPS_NS; +using namespace MathConst; +using namespace FixConst; + +// allocate space for static class variable + +FixFilterCorotate *FixFilterCorotate::fsptr; + +#define BIG 1.0e20 +#define MASSDELTA 0.1 + +static const char cite_filter_corotate[] = +"Mollified Impulse Method with Corotational Filter:\n\n" +"@Article{Fath2017,\n" +" Title =" +"{A fast mollified impulse method for biomolecular atomistic simulations},\n" +" Author = {L. Fath and M. Hochbruck and C.V. Singh},\n" +" Journal = {Journal of Computational Physics},\n" +" Year = {2017},\n" +" Pages = {180 - 198},\n" +" Volume = {333},\n\n" +" Doi = {http://dx.doi.org/10.1016/j.jcp.2016.12.024},\n" +" ISSN = {0021-9991},\n" +" Keywords = {Mollified impulse method},\n" +" Url = {http://www.sciencedirect.com/science/article/pii/S0021999116306787}\n" +"}\n\n"; + +/* ---------------------------------------------------------------------- */ + +FixFilterCorotate::FixFilterCorotate(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp,narg,arg) +{ + if (lmp->citeme) lmp->citeme->add(cite_filter_corotate); + + MPI_Comm_rank(world,&me); + MPI_Comm_size(world,&nprocs); + + molecular = atom->molecular; + if (molecular == 0) + error->all(FLERR,"Cannot use fix filter/corotate " + "with non-molecular system"); + if (molecular == 2) + error->all(FLERR,"Cannot use fix filter/corotate " + "with molecular template system"); + + // parse args for bond and angle types + // will be used by find_clusters + // store args for "b" "a" "t" as flags in (1:n) list for fast access + // store args for "m" in list of length nmass for looping over + // for "m" verify that atom masses have been set + + bond_flag = new int[atom->nbondtypes+1]; + for (int i = 1; i <= atom->nbondtypes; i++) bond_flag[i] = 0; + angle_flag = new int[atom->nangletypes+1]; + for (int i = 1; i <= atom->nangletypes; i++) angle_flag[i] = 0; + type_flag = new int[atom->ntypes+1]; + for (int i = 1; i <= atom->ntypes; i++) type_flag[i] = 0; + mass_list = new double[atom->ntypes]; + nmass = 0; + + char mode = '\0'; + int next = 3; + while (next < narg) { + if (strcmp(arg[next],"b") == 0) mode = 'b'; + else if (strcmp(arg[next],"a") == 0) mode = 'a'; + else if (strcmp(arg[next],"t") == 0) mode = 't'; + else if (strcmp(arg[next],"m") == 0) { + mode = 'm'; + atom->check_mass(FLERR); + + // break if keyword that is not b,a,t,m + + } else if (isalpha(arg[next][0])) break; + + // read numeric args of b,a,t,m + + else if (mode == 'b') { + int i = force->inumeric(FLERR,arg[next]); + if (i < 1 || i > atom->nbondtypes) + error->all(FLERR,"Invalid bond type index for fix filter/corotate"); + bond_flag[i] = 1; + + } else if (mode == 'a') { + int i = force->inumeric(FLERR,arg[next]); + if (i < 1 || i > atom->nangletypes) + error->all(FLERR,"Invalid angle type index for fix filter/corotate"); + angle_flag[i] = 1; + + } else if (mode == 't') { + int i = force->inumeric(FLERR,arg[next]); + if (i < 1 || i > atom->ntypes) + error->all(FLERR,"Invalid atom type index for fix filter/corotate"); + type_flag[i] = 1; + + } else if (mode == 'm') { + double massone = force->numeric(FLERR,arg[next]); + if (massone == 0.0) + error->all(FLERR,"Invalid atom mass for fix filter/corotate"); + if (nmass == atom->ntypes) + error->all(FLERR,"Too many masses for fix filter/corotate"); + mass_list[nmass++] = massone; + + } else error->all(FLERR,"Illegal fix filter/corotate command"); + next++; + } + + + // parse optional args + nlevels_respa = 1; //initialize + + // allocate bond and angle distance arrays, indexed from 1 to n + + bond_distance = new double[atom->nbondtypes+1]; + angle_distance = new double[atom->nangletypes+1]; + + //grow_arrays + array_atom = NULL; + shake_flag = NULL; + shake_atom = NULL; + shake_type = NULL; + + grow_arrays(atom->nmax); + atom->add_callback(0); //calls grow_arrays + + x_store = NULL; + + //STUFF + g = NULL; + help2 = NULL; + + dn1dx = dn2dx = dn3dx = NULL; + n1 = n2 = n3 = del1 = del2 = del3 = NULL; + + memory->grow(help2,15,15,"FilterCorotate:help2"); + memory->grow(n1,3,"FilterCorotate:n1"); + memory->grow(n2,3,"FilterCorotate:n2"); + memory->grow(n3,3,"FilterCorotate:n3"); + memory->grow(del1,3,"FilterCorotate:del1"); + memory->grow(del2,3,"FilterCorotate:del2"); + memory->grow(del3,3,"FilterCorotate:del3"); + memory->grow(dn1dx,3,15,"FilterCorotate:dn1dx"); + memory->grow(dn2dx,3,15,"FilterCorotate:dn2dx"); + memory->grow(dn3dx,3,15,"FilterCorotate:dn3dx"); + + memory->grow(g,15,"FilterCorotate:g"); + + comm_forward = 3; + + // identify all clusters + + find_clusters(); + + // initialize list of clusters to constrain + + maxlist = 0; + list = NULL; + clist_derv = NULL; + clist_q0 = NULL; //list for derivative and ref. config + clist_nselect1 = clist_nselect2 = NULL; + clist_select1 = clist_select2 = NULL; + +} + +/* ---------------------------------------------------------------------- */ + +FixFilterCorotate::~FixFilterCorotate() +{ + memory->destroy(g); + memory->destroy(help2); + memory->destroy(n1); + memory->destroy(n2); + memory->destroy(n3); + memory->destroy(del1); + memory->destroy(del2); + memory->destroy(del3); + memory->destroy(dn1dx); + memory->destroy(dn2dx); + memory->destroy(dn3dx); + + atom->delete_callback(id,2); + atom->delete_callback(id,0); + + // delete locally stored arrays + + memory->destroy(shake_flag); + memory->destroy(shake_atom); + memory->destroy(shake_type); + memory->destroy(array_atom); + + delete [] bond_flag; + delete [] angle_flag; + delete [] type_flag; + delete [] mass_list; + + delete [] bond_distance; + delete [] angle_distance; + + memory->destroy(list); + memory->destroy(clist_derv); + memory->destroy(clist_q0); + memory->destroy(clist_nselect1); + memory->destroy(clist_nselect2); + memory->destroy(clist_select1); + memory->destroy(clist_select2); +} + + +/* ---------------------------------------------------------------------- */ + +int FixFilterCorotate::setmask() +{ + int mask = 0; + + mask |= PRE_NEIGHBOR; + mask |= PRE_FORCE_RESPA; + mask |= POST_FORCE_RESPA; + + return mask; +} + + +/* ---------------------------------------------------------------------- */ + +void FixFilterCorotate::init() +{ + int i; + // error if more than one filter + int count = 0; + for (i = 0; i < modify->nfix; i++){ + if (strcmp(modify->fix[i]->style,"filter/corotate") == 0) count++; + } + if (count > 1) error->all(FLERR,"More than one fix filter/corotate"); + + // check for fix shake: + count = 0; + for (i = 0; i < modify->nfix; i++){ + if (strcmp(modify->fix[i]->style,"shake") == 0) count++; + } + if (count > 1) + error->one(FLERR,"Both fix shake and fix filter/corotate detected."); + + // if rRESPA, find associated fix that must exist + // could have changed locations in fix list since created + // set ptrs to rRESPA variables + + if (strstr(update->integrate_style,"respa")) { + nlevels_respa = ((Respa *) update->integrate)->nlevels; + } + else error->all(FLERR,"Fix filter/corotate requires rRESPA!"); + + // set equilibrium bond distances + + if (force->bond == NULL) + error->all(FLERR,"Bond potential must be defined for fix filter/corotate"); + for (i = 1; i <= atom->nbondtypes; i++) + bond_distance[i] = force->bond->equilibrium_distance(i); + + // set equilibrium angle value + + for (i = 1; i <= atom->nangletypes; i++) { + angle_distance[i] = force->angle->equilibrium_angle(i); + } +} + +/* ---------------------------------------------------------------------- + * pre-integrator setup + * ------------------------------------------------------------------------- */ + +void FixFilterCorotate::setup_pre_neighbor() +{ + pre_neighbor(); +} + + +/* ---------------------------------------------------------------------- + * build list of clusters to constrain + * if one or more atoms in cluster are on this proc, + * this proc lists the cluster exactly once + * ------------------------------------------------------------------------- */ + +void FixFilterCorotate::pre_neighbor() +{ + int atom1,atom2,atom3,atom4,atom5; + + // local copies of atom quantities + // used until next re-neighboring + + x = atom->x; + v = atom->v; + f = atom->f; + mass = atom->mass; + rmass = atom->rmass; + type = atom->type; + nlocal = atom->nlocal; + + // extend size of list if necessary + + if (nlocal > maxlist) { + maxlist = nlocal; + + memory->destroy(list); + memory->destroy(clist_derv); + memory->destroy(clist_q0); + memory->destroy(clist_nselect1); + memory->destroy(clist_nselect2); + memory->destroy(clist_select1); + memory->destroy(clist_select2); + + memory->create(list,maxlist,"FilterCorotate:list"); + memory->create(clist_derv,maxlist,15,15,"FilterCorotate:derivative"); + memory->create(clist_q0,maxlist,15,"FilterCorotate:q0"); + memory->create(clist_nselect1,maxlist,"FilterCorotate:nselect1"); + memory->create(clist_nselect2,maxlist,"FilterCorotate:nselect2"); + memory->create(clist_select1,maxlist,5,"FilterCorotate:select1"); + memory->create(clist_select2,maxlist,5,"FilterCorotate:select2"); + } + + // build list of clusters I compute + + nlist = 0; + + for (int i = 0; i < nlocal; i++){ + if (shake_flag[i]) { + if (shake_flag[i] == 2) { + atom1 = atom->map(shake_atom[i][0]); + atom2 = atom->map(shake_atom[i][1]); + if (atom1 == -1 || atom2 == -1) { + char str[128]; + sprintf(str,"Cluster atoms " TAGINT_FORMAT " " TAGINT_FORMAT + " missing on proc %d at step " BIGINT_FORMAT, + shake_atom[i][0],shake_atom[i][1],me,update->ntimestep); + error->one(FLERR,str); + } + if (i <= atom1 && i <= atom2) list[nlist++] = i; + } else if (shake_flag[i] == 1 || shake_flag[i] == 3) { + atom1 = atom->map(shake_atom[i][0]); + atom2 = atom->map(shake_atom[i][1]); + atom3 = atom->map(shake_atom[i][2]); + if (atom1 == -1 || atom2 == -1 || atom3 == -1) { + char str[128]; + sprintf(str,"Cluster atoms " + TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT + " missing on proc %d at step " BIGINT_FORMAT, + shake_atom[i][0],shake_atom[i][1],shake_atom[i][2], + me,update->ntimestep); + error->one(FLERR,str); + } + if (i <= atom1 && i <= atom2 && i <= atom3) list[nlist++] = i; + } else if (shake_flag[i] == 4) { + atom1 = atom->map(shake_atom[i][0]); + atom2 = atom->map(shake_atom[i][1]); + atom3 = atom->map(shake_atom[i][2]); + atom4 = atom->map(shake_atom[i][3]); + if (atom1 == -1 || atom2 == -1 || atom3 == -1 || atom4 == -1) { + char str[128]; + sprintf(str,"Cluster atoms " + TAGINT_FORMAT " " TAGINT_FORMAT " " + TAGINT_FORMAT " " TAGINT_FORMAT + " missing on proc %d at step " BIGINT_FORMAT, + shake_atom[i][0],shake_atom[i][1], + shake_atom[i][2],shake_atom[i][3], + me,update->ntimestep); + error->one(FLERR,str); + } + if (i <= atom1 && i <= atom2 && i <= atom3 && i <= atom4) + list[nlist++] = i; + } else if (shake_flag[i] == 5) { + atom1 = atom->map(shake_atom[i][0]); + atom2 = atom->map(shake_atom[i][1]); + atom3 = atom->map(shake_atom[i][2]); + atom4 = atom->map(shake_atom[i][3]); + atom5 = atom->map(shake_atom[i][4]); + if (atom1 == -1 || atom2 == -1 || atom3 == -1 || + atom4 == -1 || atom5 == -1) { + char str[128]; + sprintf(str,"Cluster atoms " + TAGINT_FORMAT " " TAGINT_FORMAT " " + TAGINT_FORMAT " " TAGINT_FORMAT " " TAGINT_FORMAT + " missing on proc %d at step " BIGINT_FORMAT, + shake_atom[i][0],shake_atom[i][1], + shake_atom[i][2],shake_atom[i][3],shake_atom[i][4], + me,update->ntimestep); + error->one(FLERR,str); + } + if (i <= atom1 && i <= atom2 && i <= atom3 && i <= atom4 && i <= atom5) + list[nlist++] = i; + } + } + } + + //also build reference config lists + int m,N,oxy; + double r0,r1,r2,theta0; + double m1,m2,m3,m4,m5,m_all; + + double *mass = atom->mass; + int *type = atom->type; + + for (int i=0; i<nlist; i++) + { + m = list[i]; + N = shake_flag[m]; + + //switch cluster type 3 to angle cluster: + if (N == 3) + { + //make it an angle cluster: + if (shake_type[m][2] == 0) + shake_type[m][2] = angletype_findset(atom->map(shake_atom[m][0]), + shake_atom[m][1],shake_atom[m][2],0); + } + + if (N == 1) N = 3; //angle cluster + + if (N == 2) //cluster of size 2: + { + atom1 = atom->map(shake_atom[m][0]); + atom2 = atom->map(shake_atom[m][1]); + + r0 = bond_distance[shake_type[m][0]]; + + m1 = mass[type[atom1]]; + m2 = mass[type[atom2]]; + m_all = m1 + m2; + + double a1 = -m2/(m1+m2)*r0; + double a2 = m1/(m1+m2)*r0; + + clist_q0[i][0] = a1; + clist_q0[i][1] = 0; + clist_q0[i][2] = 0; + + clist_q0[i][3] = a2; + clist_q0[i][4] = 0; + clist_q0[i][5] = 0; + + clist_nselect1[i] = 1; + clist_select1[i][0] = 1; + + clist_nselect2[i] = 0; + clist_select2[i][0] = 0; + } else if (N == 3) //angle cluster + { + oxy = atom->map(shake_atom[m][0]); + atom1 = atom->map(shake_atom[m][1]); + atom2 = atom->map(shake_atom[m][2]); + + r0 = bond_distance[shake_type[m][0]]; + r1 = bond_distance[shake_type[m][1]]; + + + theta0 = angle_distance[shake_type[m][2]]; + + m1 = mass[type[oxy]]; + m2 = mass[type[atom1]]; + m3 = mass[type[atom2]]; + m_all = m1 + m2 + m3; + + double alpha1 = 0.5*(MY_PI - theta0); + + double xcenter = m2/m_all*r0*sin(alpha1) + m3/m_all*r1*sin(alpha1); + double ycenter = -m2/m_all*r0*cos(alpha1)+ m3/m_all*r1*cos(alpha1); + + double q1 = -xcenter; + double q2 = -ycenter; + + double q4 = r0*sin(alpha1)-xcenter; + double q5 = r0*cos(alpha1)-ycenter; + + double q7 = r1*sin(alpha1)-xcenter; + double q8 = -r1*cos(alpha1)-ycenter; + + clist_q0[i][0] = q1; + clist_q0[i][1] = q2; + clist_q0[i][2] = 0; + + clist_q0[i][3] = q4; + clist_q0[i][4] = q5; + clist_q0[i][5] = 0; + + clist_q0[i][6] = q7; + clist_q0[i][7] = q8; + clist_q0[i][8] = 0; + + clist_nselect1[i] = 2; + clist_select1[i][0] = 1; clist_select1[i][1] = 2; + clist_nselect2[i] = 1; + clist_select2[i][0] = 1; + } else if (N == 4) + { + oxy = atom->map(shake_atom[m][0]); + atom1 = atom->map(shake_atom[m][1]); + atom2 = atom->map(shake_atom[m][2]); + atom3 = atom->map(shake_atom[m][3]); + + r0 = bond_distance[shake_type[m][0]]; + r1 = bond_distance[shake_type[m][1]]; + r2 = bond_distance[shake_type[m][2]]; + + m1 = atom->mass[atom->type[oxy]]; + m2 = atom->mass[atom->type[atom1]]; + m3 = atom->mass[atom->type[atom2]]; + m4 = atom->mass[atom->type[atom3]]; + m_all = m1 + m2 + m3 + m4; + + //how to get these angles? + double alpha1 = MY_PI/2.57; //roughly 70 degrees + double alpha2 = MY_PI/3; + //ENSURE ycenter,zcenter = 0! + //approximate xcenter, if r0 !=r1 != r2, exact if r0 = r1 = r2 + double xcenter = (m2*r0+m3*r1+m4*r2)/m_all*cos(alpha1); + + clist_q0[i][0] = -xcenter; + clist_q0[i][1] = 0.0; + clist_q0[i][2] = 0.0; + clist_q0[i][3] = r0*cos(alpha1)-xcenter; + clist_q0[i][4] = -r0*sin(alpha1); + clist_q0[i][5] = 0.0; + clist_q0[i][6] = r1*cos(alpha1)-xcenter; + clist_q0[i][7] = r1*sin(alpha1)*cos(alpha2); + clist_q0[i][8] = -r1*sin(alpha1)*sin(alpha2); + clist_q0[i][9] = r2*cos(alpha1)-xcenter; + clist_q0[i][10] = r2*sin(alpha1)*cos(alpha2); + clist_q0[i][11] = r2*sin(alpha1)*sin(alpha2); + + clist_nselect1[i] = 3; + clist_nselect2[i] = 2; + + clist_select1[i][0] = 1;clist_select1[i][1] = 2;clist_select1[i][2] = 3; + clist_select2[i][0] = 2;clist_select2[i][1] = 3; + + //signum ensures correct ordering of three satellites + //signum = sign(cross(x2-x1,x3-x1))T*(x1-x0)) + double del1[3], del2[3], del3[3]; + del1[0] = x[atom1][0]-x[oxy][0]; + del1[1] = x[atom1][1]-x[oxy][1]; + del1[2] = x[atom1][2]-x[oxy][2]; + domain->minimum_image(del1); + + del2[0] = x[atom2][0]-x[atom1][0]; + del2[1] = x[atom2][1]-x[atom1][1]; + del2[2] = x[atom2][2]-x[atom1][2]; + domain->minimum_image(del2); + + del3[0] = x[atom3][0]-x[atom1][0]; + del3[1] = x[atom3][1]-x[atom1][1]; + del3[2] = x[atom3][2]-x[atom1][2]; + domain->minimum_image(del3); + + double a = (del2[1])*(del3[2]) - (del2[2])*(del3[1]); + double b = (del2[2])*(del3[0]) - (del2[0])*(del3[2]); + double c = (del2[0])*(del3[1]) - (del2[1])*(del3[0]); + int signum = sgn(a*(del1[0]) + b*(del1[1]) + c*(del1[2])); + + if (fabs(signum)!= 1) + error->all(FLERR,"Wrong orientation in cluster of size 4" + "in fix filter/corotate!"); + clist_q0[i][8] *= signum; + clist_q0[i][11] *= signum; + + } else if (N == 5) + { + oxy = atom->map(shake_atom[m][0]); + atom1 = atom->map(shake_atom[m][1]); + atom2 = atom->map(shake_atom[m][2]); + atom3 = atom->map(shake_atom[m][3]); + int c1 = atom->map(shake_atom[m][4]); + + r1 = bond_distance[shake_type[m][3]]; + r0 = bond_distance[shake_type[m][0]]; + theta0 = angle_distance[shake_type[m][2]]; + + m1 = atom->mass[atom->type[oxy]]; + m2 = atom->mass[atom->type[atom1]]; + m3 = atom->mass[atom->type[atom2]]; + m4 = atom->mass[atom->type[atom3]]; + m5 = atom->mass[atom->type[c1]]; + m_all = m1 + m2 + m3 + m4 + m5; + + double alpha1 = MY_PI/2.57; //roughly 70 degrees + double alpha2 = MY_PI/3; + //ENSURE ycenter,zcenter = 0! + double xcenter = -(m2+m3+m4)/m_all*r0*cos(alpha1) +r1*m5/m_all; + + clist_q0[i][0] = -xcenter; + clist_q0[i][1] = 0.0; + clist_q0[i][2] = 0.0; + clist_q0[i][3] = -r0*cos(alpha1)-xcenter; + clist_q0[i][4] = -r0*sin(alpha1); + clist_q0[i][5] = 0.0; + clist_q0[i][6] = -r0*cos(alpha1)-xcenter; + clist_q0[i][7] = r0*sin(alpha1)*cos(alpha2); + clist_q0[i][8] = r0*sin(alpha1)*sin(alpha2); + clist_q0[i][9] = -r0*cos(alpha1)-xcenter; + clist_q0[i][10] = r0*sin(alpha1)*cos(alpha2); + clist_q0[i][11] = -r0*sin(alpha1)*sin(alpha2); + clist_q0[i][12] = r1-xcenter; + clist_q0[i][13] = 0.0; + clist_q0[i][14] = 0.0; + clist_nselect1[i] = 1; + clist_nselect2[i] = 2; + + clist_select1[i][0] = 4; + clist_select2[i][0] = 2;clist_select2[i][1] = 3; + + //signum ensures correct ordering of three satellites + //signum = sign(cross(x2-x1,x3-x1))T*(x1-x0)) + double del1[3], del2[3], del3[3]; + del1[0] = x[atom1][0]-x[oxy][0]; + del1[1] = x[atom1][1]-x[oxy][1]; + del1[2] = x[atom1][2]-x[oxy][2]; + domain->minimum_image(del1); + + del2[0] = x[atom2][0]-x[atom1][0]; + del2[1] = x[atom2][1]-x[atom1][1]; + del2[2] = x[atom2][2]-x[atom1][2]; + domain->minimum_image(del2); + + del3[0] = x[atom3][0]-x[atom1][0]; + del3[1] = x[atom3][1]-x[atom1][1]; + del3[2] = x[atom3][2]-x[atom1][2]; + domain->minimum_image(del3); + + double a = (del2[1])*(del3[2]) - (del2[2])*(del3[1]); + double b = (del2[2])*(del3[0]) - (del2[0])*(del3[2]); + double c = (del2[0])*(del3[1]) - (del2[1])*(del3[0]); + int signum = sgn(a*(del1[0]) + b*(del1[1]) + c*(del1[2])); + + if (fabs(signum)!= 1) + error->all(FLERR,"Wrong orientation in cluster of size 5" + "in fix filter/corotate!"); + clist_q0[i][8] *= signum; + clist_q0[i][11] *= signum; + } + else + { + error->all(FLERR,"Fix filter/corotate cluster with size > 5" + "not yet configured..."); + } + } +} + +/* ---------------------------------------------------------------------- + * setup, needs to patch missing setup_post_force_respa() in respa... + * ------------------------------------------------------------------------- */ + +void FixFilterCorotate::setup(int vflag) +{ + ((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1); + post_force_respa(vflag,nlevels_respa-1,0); + ((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1); +} + +void FixFilterCorotate::setup_pre_force_respa(int vflag,int ilevel){ + pre_force_respa(vflag,ilevel,0); +} + +//void FixFilterCorotate::setup_post_force_respa(int vflag,int ilevel){ +// post_force_respa(vflag,ilevel,0); +//} + +double FixFilterCorotate::compute_array(int,int) +{ + filter_inner(); + return 1; +} + +void FixFilterCorotate::pre_force_respa(int vflag, int ilevel, int iloop) +{ + if (ilevel == nlevels_respa-1) + { + filter_inner(); + + //%Switch pointers x<-->x_filter + x_store = atom->x; + atom->x = array_atom; + } +} + +void FixFilterCorotate::post_force_respa(int vflag, int ilevel, int iloop) +{ + if (ilevel == nlevels_respa-1) + { + atom->x = x_store; + + comm->forward_comm_fix(this); //comm forward of forces for outer filter + + filter_outer(); + } +} + +/* ---------------------------------------------------------------------- */ + +void FixFilterCorotate::filter_inner() +{ + int nall = atom->nlocal + atom->nghost; + double **x = atom->x; + + //set array_atom to atom->x, in case some atoms are not part of any cluster: + for (int i=0; i<nall; i++) + { + array_atom[i][0] = x[i][0]; + array_atom[i][1] = x[i][1]; + array_atom[i][2] = x[i][2]; + } + + int m; + //iterate through list: + for (int i=0; i<nlist; i++) + { + m = list[i]; + + //filter: + general_cluster(m,i); + } +} + +/* ---------------------------------------------------------------------- */ + +void FixFilterCorotate::filter_outer() +{ + double sum1,sum2,sum3; + double** f = atom->f; + int m; + + for (int i=0; i<nlist; i++) + { + m = list[i]; + int dim = shake_flag[m]; + if (dim == 1) //case: angle + dim = 3; + + for (int j = 0; j < dim; j++) + { + sum1 = sum2 = sum3 = 0; + for (int k = 0; k < dim; k++) + { + //get local tag of k-th atom in cluster i: + int kk = atom->map(shake_atom[m][k]); + //apply derivative times force + sum1 += clist_derv[i][3*j][3*k]*f[kk][0]+clist_derv[i][3*j][3*k+1]* + f[kk][1]+clist_derv[i][3*j][3*k+2]*f[kk][2]; + sum2 += clist_derv[i][3*j+1][3*k]*f[kk][0]+clist_derv[i][3*j+1][3*k+1]* + f[kk][1]+clist_derv[i][3*j+1][3*k+2]*f[kk][2]; + sum3 += clist_derv[i][3*j+2][3*k]*f[kk][0]+clist_derv[i][3*j+2][3*k+1]* + f[kk][1]+clist_derv[i][3*j+2][3*k+2]*f[kk][2]; + } + + g[3*j] = sum1; + g[3*j+1] = sum2; + g[3*j+2] = sum3; + } + + //replace force f with filtered value: + for (int j = 0; j < dim; j++) + { + int kk = atom->map(shake_atom[m][j]); + + f[kk][0] = g[3*j]; + f[kk][1] = g[3*j+1]; + f[kk][2] = g[3*j+2]; + } + } +} + +/* ---------------------------------------------------------------------- + * identify whether each atom is in a SHAKE cluster + * only include atoms in fix group and those bonds/angles specified in input + * test whether all clusters are valid + * set shake_flag, shake_atom, shake_type values + * set bond,angle types negative so will be ignored in neighbor lists + * ------------------------------------------------------------------------- */ + +void FixFilterCorotate::find_clusters() +{ + int i,j,m,n; + int flag,flag_all,nbuf,size; + double massone; + tagint *buf; + + if (me == 0 && screen) + fprintf(screen,"Finding filter clusters ...\n"); + + tagint *tag = atom->tag; + int *type = atom->type; + int *mask = atom->mask; + double *mass = atom->mass; + double *rmass = atom->rmass; + int **nspecial = atom->nspecial; + tagint **special = atom->special; + + int nlocal = atom->nlocal; + int angles_allow = atom->avec->angles_allow; + + // setup ring of procs + + int next = me + 1; + int prev = me -1; + if (next == nprocs) next = 0; + if (prev < 0) prev = nprocs - 1; + + // ----------------------------------------------------- + // allocate arrays for self (1d) and bond partners (2d) + // max = max # of bond partners for owned atoms = 2nd dim of partner arrays + // npartner[i] = # of bonds attached to atom i + // nshake[i] = # of SHAKE bonds attached to atom i + // partner_tag[i][] = global IDs of each partner + // partner_mask[i][] = mask of each partner + // partner_type[i][] = type of each partner + // partner_massflag[i][] = 1 if partner meets mass criterion, 0 if not + // partner_bondtype[i][] = type of bond attached to each partner + // partner_shake[i][] = 1 if SHAKE bonded to partner, 0 if not + // partner_nshake[i][] = nshake value for each partner + // ----------------------------------------------------- + + int max = 0; + + for (i = 0; i < nlocal; i++) max = MAX(max,nspecial[i][0]); + + int *npartner; + memory->create(npartner,nlocal,"shake:npartner"); + memory->create(nshake,nlocal,"shake:nshake"); + + tagint **partner_tag; + int **partner_mask,**partner_type,**partner_massflag; + int **partner_bondtype,**partner_shake,**partner_nshake; + memory->create(partner_tag,nlocal,max,"shake:partner_tag"); + memory->create(partner_mask,nlocal,max,"shake:partner_mask"); + memory->create(partner_type,nlocal,max,"shake:partner_type"); + memory->create(partner_massflag,nlocal,max,"shake:partner_massflag"); + memory->create(partner_bondtype,nlocal,max,"shake:partner_bondtype"); + memory->create(partner_shake,nlocal,max,"shake:partner_shake"); + memory->create(partner_nshake,nlocal,max,"shake:partner_nshake"); + + // ----------------------------------------------------- + // set npartner and partner_tag from special arrays + // ----------------------------------------------------- + + for (i = 0; i < nlocal; i++) { + npartner[i] = nspecial[i][0]; + for (j = 0; j < npartner[i]; j++) + partner_tag[i][j] = special[i][j]; + } + + // ----------------------------------------------------- + // set partner_mask, partner_type, partner_massflag, partner_bondtype + // for bonded partners + // requires communication for off-proc partners + // ----------------------------------------------------- + + // fill in mask, type, massflag, bondtype if own bond partner + // info to store in buf for each off-proc bond = nper = 6 + // 2 atoms IDs in bond, space for mask, type, massflag, bondtype + // nbufmax = largest buffer needed to hold info from any proc + + int nper = 6; + + nbuf = 0; + for (i = 0; i < nlocal; i++) { + for (j = 0; j < npartner[i]; j++) { + partner_mask[i][j] = 0; + partner_type[i][j] = 0; + partner_massflag[i][j] = 0; + partner_bondtype[i][j] = 0; + + m = atom->map(partner_tag[i][j]); + if (m >= 0 && m < nlocal) { + partner_mask[i][j] = mask[m]; + partner_type[i][j] = type[m]; + if (nmass) { + if (rmass) massone = rmass[m]; + else massone = mass[type[m]]; + partner_massflag[i][j] = masscheck(massone); + } + n = bondtype_findset(i,tag[i],partner_tag[i][j],0); + if (n) partner_bondtype[i][j] = n; + else { + n = bondtype_findset(m,tag[i],partner_tag[i][j],0); + if (n) partner_bondtype[i][j] = n; + } + } else nbuf += nper; + } + } + + memory->create(buf,nbuf,"filter/corotate:buf"); + + // fill buffer with info + + size = 0; + for (i = 0; i < nlocal; i++) { + for (j = 0; j < npartner[i]; j++) { + m = atom->map(partner_tag[i][j]); + if (m < 0 || m >= nlocal) { + buf[size] = tag[i]; + buf[size+1] = partner_tag[i][j]; + buf[size+2] = 0; + buf[size+3] = 0; + buf[size+4] = 0; + n = bondtype_findset(i,tag[i],partner_tag[i][j],0); + if (n) buf[size+5] = n; + else buf[size+5] = 0; + size += nper; + } + } + } + + // cycle buffer around ring of procs back to self + + fsptr = this; + comm->ring(size,sizeof(tagint),buf,1,ring_bonds,buf); + + // store partner info returned to me + + m = 0; + while (m < size) { + i = atom->map(buf[m]); + for (j = 0; j < npartner[i]; j++){ + if (buf[m+1] == partner_tag[i][j]) break; + } + partner_mask[i][j] = buf[m+2]; + partner_type[i][j] = buf[m+3]; + partner_massflag[i][j] = buf[m+4]; + partner_bondtype[i][j] = buf[m+5]; + m += nper; + } + + memory->destroy(buf); + + // error check for unfilled partner info + // if partner_type not set, is an error + // partner_bondtype may not be set if special list is not consistent + // with bondatom (e.g. due to delete_bonds command) + // this is OK if one or both atoms are not in fix group, since + // bond won't be SHAKEn anyway + // else it's an error + + flag = 0; + for (i = 0; i < nlocal; i++){ + for (j = 0; j < npartner[i]; j++) { + if (partner_type[i][j] == 0) flag = 1; + if (!(mask[i] & groupbit)) continue; + if (!(partner_mask[i][j] & groupbit)) continue; + if (partner_bondtype[i][j] == 0) flag = 1; + } + } + + MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world); + if (flag_all) + error->all(FLERR,"Did not find fix filter/corotate partner info"); + + // ----------------------------------------------------- + // identify SHAKEable bonds + // set nshake[i] = # of SHAKE bonds attached to atom i + // set partner_shake[i][] = 1 if SHAKE bonded to partner, 0 if not + // both atoms must be in group, bondtype must be > 0 + // check if bondtype is in input bond_flag + // check if type of either atom is in input type_flag + // check if mass of either atom is in input mass_list + // ----------------------------------------------------- + + int np; + + for (i = 0; i < nlocal; i++) { + nshake[i] = 0; + np = npartner[i]; + for (j = 0; j < np; j++) { + partner_shake[i][j] = 0; + + if (!(mask[i] & groupbit)) continue; + if (!(partner_mask[i][j] & groupbit)) continue; + if (partner_bondtype[i][j] <= 0) continue; + + if (bond_flag[partner_bondtype[i][j]]) { + partner_shake[i][j] = 1; + nshake[i]++; + continue; + } + if (type_flag[type[i]] || type_flag[partner_type[i][j]]) { + partner_shake[i][j] = 1; + nshake[i]++; + continue; + } + if (nmass) { + if (partner_massflag[i][j]) { + partner_shake[i][j] = 1; + nshake[i]++; + continue; + } else { + if (rmass) massone = rmass[i]; + else massone = mass[type[i]]; + if (masscheck(massone)) { + partner_shake[i][j] = 1; + nshake[i]++; + continue; + } + } + } + } + } + + // ----------------------------------------------------- + // set partner_nshake for bonded partners + // requires communication for off-proc partners + // ----------------------------------------------------- + + // fill in partner_nshake if own bond partner + // info to store in buf for each off-proc bond = + // 2 atoms IDs in bond, space for nshake value + // nbufmax = largest buffer needed to hold info from any proc + + nbuf = 0; + for (i = 0; i < nlocal; i++) { + for (j = 0; j < npartner[i]; j++) { + m = atom->map(partner_tag[i][j]); + if (m >= 0 && m < nlocal) partner_nshake[i][j] = nshake[m]; + else nbuf += 3; + } + } + + memory->create(buf,nbuf,"filter/corotate:buf"); + + // fill buffer with info + + size = 0; + for (i = 0; i < nlocal; i++) { + for (j = 0; j < npartner[i]; j++) { + m = atom->map(partner_tag[i][j]); + if (m < 0 || m >= nlocal) { + buf[size] = tag[i]; + buf[size+1] = partner_tag[i][j]; + size += 3; + } + } + } + + // cycle buffer around ring of procs back to self + + fsptr = this; + comm->ring(size,sizeof(tagint),buf,2,ring_nshake,buf); + + // store partner info returned to me + + m = 0; + while (m < size) { + i = atom->map(buf[m]); + for (j = 0; j < npartner[i]; j++){ + if (buf[m+1] == partner_tag[i][j]) break; + } + partner_nshake[i][j] = buf[m+2]; + m += 3; + } + + memory->destroy(buf); + + // ----------------------------------------------------- + // error checks + // no atom with nshake > 3 + // no connected atoms which both have nshake > 1 + // ----------------------------------------------------- + + flag = 0; + for (i = 0; i < nlocal; i++) if (nshake[i] > 4) flag = 1; + MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world); + if (flag_all) error->all(FLERR,"Cluster of more than 5 atoms"); + + flag = 0; + for (i = 0; i < nlocal; i++) { + if (nshake[i] <= 1) continue; + for (j = 0; j < npartner[i]; j++) + if (partner_shake[i][j] && partner_nshake[i][j] > 1) flag = 1; + } + MPI_Allreduce(&flag,&flag_all,1,MPI_INT,MPI_SUM,world); + if (flag_all) error->all(FLERR,"Clusters are connected"); + + // ----------------------------------------------------- + // set SHAKE arrays that are stored with atoms & add angle constraints + // zero shake arrays for all owned atoms + // if I am central atom set shake_flag & shake_atom & shake_type + // for 2-atom clusters, I am central atom if my atom ID < partner ID + // for 3-atom clusters, test for angle constraint + // angle will be stored by this atom if it exists + // if angle type matches angle_flag, then it is angle-constrained + // shake_flag[] = 0 if atom not in SHAKE cluster + // 2,3,4 = size of bond-only cluster + // 1 = 3-atom angle cluster + // shake_atom[][] = global IDs of 2,3,4 atoms in cluster + // central atom is 1st + // for 2-atom cluster, lowest ID is 1st + // shake_type[][] = bondtype of each bond in cluster + // for 3-atom angle cluster, 3rd value is angletype + // ----------------------------------------------------- + + for (i = 0; i < nlocal; i++) { + shake_flag[i] = 0; + shake_atom[i][0] = 0; + shake_atom[i][1] = 0; + shake_atom[i][2] = 0; + shake_atom[i][3] = 0; + shake_atom[i][4] = 0; + shake_type[i][0] = 0; + shake_type[i][1] = 0; + shake_type[i][2] = 0; + shake_type[i][3] = 0; + + if (nshake[i] == 1) { + for (j = 0; j < npartner[i]; j++){ + if (partner_shake[i][j]) break; + } + if (partner_nshake[i][j] == 1 && tag[i] < partner_tag[i][j]) { + shake_flag[i] = 2; + shake_atom[i][0] = tag[i]; + shake_atom[i][1] = partner_tag[i][j]; + shake_type[i][0] = partner_bondtype[i][j]; + } + } + + if (nshake[i] > 1) { + shake_flag[i] = 1; + shake_atom[i][0] = tag[i]; + for (j = 0; j < npartner[i]; j++) + if (partner_shake[i][j]) { + m = shake_flag[i]; + shake_atom[i][m] = partner_tag[i][j]; + shake_type[i][m-1] = partner_bondtype[i][j]; + shake_flag[i]++; + } + } + + if (nshake[i] == 2 && angles_allow) { + n = angletype_findset(i,shake_atom[i][1],shake_atom[i][2],0); + if (n <= 0) continue; + //if (angle_flag[n]) { Take all angles! + shake_flag[i] = 1; + shake_type[i][2] = n; + //} + } + } + + // ----------------------------------------------------- + // set shake_flag,shake_atom,shake_type for non-central atoms + // requires communication for off-proc atoms + // ----------------------------------------------------- + + // fill in shake arrays for each bond partner I own + // info to store in buf for each off-proc bond = + // all values from shake_flag, shake_atom, shake_type + // nbufmax = largest buffer needed to hold info from any proc + + nbuf = 0; + for (i = 0; i < nlocal; i++) { + if (shake_flag[i] == 0) continue; + for (j = 0; j < npartner[i]; j++) { + if (partner_shake[i][j] == 0) continue; + m = atom->map(partner_tag[i][j]); + if (m >= 0 && m < nlocal) { + shake_flag[m] = shake_flag[i]; + shake_atom[m][0] = shake_atom[i][0]; + shake_atom[m][1] = shake_atom[i][1]; + shake_atom[m][2] = shake_atom[i][2]; + shake_atom[m][3] = shake_atom[i][3]; + shake_atom[m][4] = shake_atom[i][4]; + shake_type[m][0] = shake_type[i][0]; + shake_type[m][1] = shake_type[i][1]; + shake_type[m][2] = shake_type[i][2]; + shake_type[m][3] = shake_type[i][3]; + } else nbuf += 11; + } + } + + memory->create(buf,nbuf,"filter/corotate:buf"); + + // fill buffer with info + + size = 0; + for (i = 0; i < nlocal; i++) { + if (shake_flag[i] == 0) continue; + for (j = 0; j < npartner[i]; j++) { + if (partner_shake[i][j] == 0) continue; + m = atom->map(partner_tag[i][j]); + if (m < 0 || m >= nlocal) { + buf[size] = partner_tag[i][j]; + buf[size+1] = shake_flag[i]; + buf[size+2] = shake_atom[i][0]; + buf[size+3] = shake_atom[i][1]; + buf[size+4] = shake_atom[i][2]; + buf[size+5] = shake_atom[i][3]; + buf[size+6] = shake_atom[i][4]; + buf[size+7] = shake_type[i][0]; + buf[size+8] = shake_type[i][1]; + buf[size+9] = shake_type[i][2]; + buf[size+10] = shake_type[i][3]; + size += 11; + } + } + } + + // cycle buffer around ring of procs back to self + + fsptr = this; + comm->ring(size,sizeof(tagint),buf,3,ring_shake,NULL); + + memory->destroy(buf); + + // ----------------------------------------------------- + // free local memory + // ----------------------------------------------------- + + memory->destroy(npartner); + memory->destroy(nshake); + memory->destroy(partner_tag); + memory->destroy(partner_mask); + memory->destroy(partner_type); + memory->destroy(partner_massflag); + memory->destroy(partner_bondtype); + memory->destroy(partner_shake); + memory->destroy(partner_nshake); + + // ----------------------------------------------------- + // set bond_type and angle_type negative for SHAKE clusters + // must set for all SHAKE bonds and angles stored by each atom + // ----------------------------------------------------- + + /* for (i = 0; i < nlocal; i++) { + * if (shake_flag[i] == 0) continue; + * else if (shake_flag[i] == 1) { + * bondtype_findset(i,shake_atom[i][0],shake_atom[i][1],-1); + * bondtype_findset(i,shake_atom[i][0],shake_atom[i][2],-1); + * angletype_findset(i,shake_atom[i][1],shake_atom[i][2],-1); +} else if (shake_flag[i] == 2) { + bondtype_findset(i,shake_atom[i][0],shake_atom[i][1],-1); +} else if (shake_flag[i] == 3) { + bondtype_findset(i,shake_atom[i][0],shake_atom[i][1],-1); + bondtype_findset(i,shake_atom[i][0],shake_atom[i][2],-1); +} else if (shake_flag[i] == 4) { + bondtype_findset(i,shake_atom[i][0],shake_atom[i][1],-1); + bondtype_findset(i,shake_atom[i][0],shake_atom[i][2],-1); + bondtype_findset(i,shake_atom[i][0],shake_atom[i][3],-1); +} +}*/ + + // ----------------------------------------------------- + // print info on SHAKE clusters + // ----------------------------------------------------- + + int count1,count2,count3,count4,count5; + count1 = count2 = count3 = count4 = count5 = 0; + for (i = 0; i < nlocal; i++) { + if (shake_flag[i] == 1) count1++; + else if (shake_flag[i] == 2) count2++; + else if (shake_flag[i] == 3) count3++; + else if (shake_flag[i] == 4) count4++; + else if (shake_flag[i] == 5) count5++; + } + + int tmp; + tmp = count1; + MPI_Allreduce(&tmp,&count1,1,MPI_INT,MPI_SUM,world); + tmp = count2; + MPI_Allreduce(&tmp,&count2,1,MPI_INT,MPI_SUM,world); + tmp = count3; + MPI_Allreduce(&tmp,&count3,1,MPI_INT,MPI_SUM,world); + tmp = count4; + MPI_Allreduce(&tmp,&count4,1,MPI_INT,MPI_SUM,world); + tmp = count5; + MPI_Allreduce(&tmp,&count5,1,MPI_INT,MPI_SUM,world); + + if (me == 0) { + if (screen) { + fprintf(screen," %d = # of size 2 clusters\n",count2/2); + fprintf(screen," %d = # of size 3 clusters\n",count3/3); + fprintf(screen," %d = # of size 4 clusters\n",count4/4); + fprintf(screen," %d = # of size 5 clusters\n",count5/5); + fprintf(screen," %d = # of frozen angles\n",count1/3); + } + if (logfile) { + fprintf(logfile," %d = # of size 2 clusters\n",count2/2); + fprintf(logfile," %d = # of size 3 clusters\n",count3/3); + fprintf(logfile," %d = # of size 4 clusters\n",count4/4); + fprintf(logfile," %d = # of size 5 clusters\n",count5/5); + fprintf(logfile," %d = # of frozen angles\n",count1/3); + } + } +} + +/* ---------------------------------------------------------------------- + * when receive buffer, scan bond partner IDs for atoms I own + * if I own partner: + * fill in mask and type and massflag + * search for bond with 1st atom and fill in bondtype + * ------------------------------------------------------------------------- */ + +void FixFilterCorotate::ring_bonds(int ndatum, char *cbuf) +{ + Atom *atom = fsptr->atom; + double *rmass = atom->rmass; + double *mass = atom->mass; + int *mask = atom->mask; + int *type = atom->type; + int nlocal = atom->nlocal; + int nmass = fsptr->nmass; + + tagint *buf = (tagint *) cbuf; + int m,n; + double massone; + + for (int i = 0; i < ndatum; i += 6) { + m = atom->map(buf[i+1]); + if (m >= 0 && m < nlocal) { + buf[i+2] = mask[m]; + buf[i+3] = type[m]; + if (nmass) { + if (rmass) massone = rmass[m]; + else massone = mass[type[m]]; + buf[i+4] = fsptr->masscheck(massone); + } + if (buf[i+5] == 0) { + n = fsptr->bondtype_findset(m,buf[i],buf[i+1],0); + if (n) buf[i+5] = n; + } + } + } +} + +/* ---------------------------------------------------------------------- + * when receive buffer, scan bond partner IDs for atoms I own + * if I own partner, fill in nshake value + * ------------------------------------------------------------------------- */ + +void FixFilterCorotate::ring_nshake(int ndatum, char *cbuf) +{ + Atom *atom = fsptr->atom; + int nlocal = atom->nlocal; + + int *nshake = fsptr->nshake; + + tagint *buf = (tagint *) cbuf; + int m; + + for (int i = 0; i < ndatum; i += 3) { + m = atom->map(buf[i+1]); + if (m >= 0 && m < nlocal) buf[i+2] = nshake[m]; + } +} + +/* ---------------------------------------------------------------------- + * when receive buffer, scan bond partner IDs for atoms I own + * if I own partner, fill in nshake value + * ------------------------------------------------------------------------- */ + +void FixFilterCorotate::ring_shake(int ndatum, char *cbuf) +{ + Atom *atom = fsptr->atom; + int nlocal = atom->nlocal; + + int *shake_flag = fsptr->shake_flag; + tagint **shake_atom = fsptr->shake_atom; + int **shake_type = fsptr->shake_type; + + tagint *buf = (tagint *) cbuf; + int m; + + for (int i = 0; i < ndatum; i += 11) { + m = atom->map(buf[i]); + if (m >= 0 && m < nlocal) { + shake_flag[m] = buf[i+1]; + shake_atom[m][0] = buf[i+2]; + shake_atom[m][1] = buf[i+3]; + shake_atom[m][2] = buf[i+4]; + shake_atom[m][3] = buf[i+5]; + shake_atom[m][4] = buf[i+6]; + shake_type[m][0] = buf[i+7]; + shake_type[m][1] = buf[i+8]; + shake_type[m][2] = buf[i+9]; + shake_type[m][3] = buf[i+10]; + } + } +} + +/* ---------------------------------------------------------------------- + * check if massone is within MASSDELTA of any mass in mass_list + * return 1 if yes, 0 if not + * ------------------------------------------------------------------------- */ + +int FixFilterCorotate::masscheck(double massone) +{ + for (int i = 0; i < nmass; i++){ + if (fabs(mass_list[i]-massone) <= MASSDELTA) return 1; + } + return 0; +} + +/* -------------------------------------------------------------------------- + * filter one cluster of arbitrary size + * ---------------------------------------------------------------------------*/ + +void FixFilterCorotate::general_cluster(int index, int index_in_list) +{ + //index: shake index, index_in_list: corresponding index in list + //get q0, nselect: + double *q0 = clist_q0[index_in_list]; + int nselect1 = clist_nselect1[index_in_list]; + int nselect2 = clist_nselect2[index_in_list]; + int *select1 = clist_select1[index_in_list]; + int *select2 = clist_select2[index_in_list]; + + int N = shake_flag[index]; //number of atoms in cluster + if (N == 1) N = 3; //angle cluster + + double**x = atom->x; + double norm1, norm2, norm3; + + int* list_cluster = new int[N]; // contains local IDs of cluster atoms, + // 0 = center + double* m = new double[N]; //contains local mass + double *r = new double[N]; //contains r[i] = 1/||del[i]|| + double** del = new double*[N]; //contains del[i] = x_i-x_0 + for (int i = 0; i<N; i++) + del[i] = new double[3]; + + for (int i = 0; i < N; i++) + { + list_cluster[i] = atom->map(shake_atom[index][i]); + m[i] = atom->mass[atom->type[list_cluster[i]]]; + } + + //%CALC r_i: + for (int i = 1; i < N; i++) + { + del[i][0] = x[list_cluster[i]][0] - x[list_cluster[0]][0]; + del[i][1] = x[list_cluster[i]][1] - x[list_cluster[0]][1]; + del[i][2] = x[list_cluster[i]][2] - x[list_cluster[0]][2]; + domain->minimum_image(del[i]); + r[i] = 1.0/sqrt(del[i][0]*del[i][0]+del[i][1]*del[i][1]+ + del[i][2]*del[i][2]); + } + //special case i=0: need del[0] for compact notation of array_atom later... + del[0][0] = del[0][1] = del[0][2] = r[0] = 0.0; + + //calc n1: + n1[0] = n1[1] = n1[2] = 0.0; + + int k; + for (int i = 0; i < nselect1; i++) + { + k = select1[i]; + n1[0] += del[k][0]*r[k]; + n1[1] += del[k][1]*r[k]; + n1[2] += del[k][2]*r[k]; + } + norm1 = 1.0/sqrt(n1[0]*n1[0]+n1[1]*n1[1]+n1[2]*n1[2]); + + n1[0] *= norm1; + n1[1] *= norm1; + n1[2] *= norm1; + + //calc n2: + n2[0] = n2[1] = n2[2] = 0.0; + + for (int i = 0; i < nselect2; i++) + { + k = select2[i]; + n2[0] += del[k][0]*r[k]; + n2[1] += del[k][1]*r[k]; + n2[2] += del[k][2]*r[k]; + } + if (!nselect2) //cluster of size 2, has only one direction + n2[0] = n2[1] = n2[2] = 1.0; + + double alpha = n2[0]*n1[0] + n2[1]*n1[1] + n2[2]*n1[2]; + + n2[0] -= alpha*n1[0]; + n2[1] -= alpha*n1[1]; + n2[2] -= alpha*n1[2]; + + norm2 = 1.0/sqrt(n2[0]*n2[0]+n2[1]*n2[1]+n2[2]*n2[2]); + + n2[0] *= norm2; + n2[1] *= norm2; + n2[2] *= norm2; + + n3[0] = n1[1]*n2[2] - n1[2]*n2[1]; + n3[1] = n1[2]*n2[0] - n1[0]*n2[2]; + n3[2] = n1[0]*n2[1] - n1[1]*n2[0]; + + norm3 = 1.0/sqrt(n3[0]*n3[0]+n3[1]*n3[1]+n3[2]*n3[2]); + + n3[0] *= norm3; + n3[1] *= norm3; + n3[2] *= norm3; + + //%x_filter: + for (int i = 0; i < N; i++) + { + k = list_cluster[i]; + array_atom[k][0] = x[k][0]+q0[3*i]*n1[0]+q0[3*i+1]*n2[0]+q0[3*i+2]*n3[0]; + array_atom[k][1] = x[k][1]+q0[3*i]*n1[1]+q0[3*i+1]*n2[1]+q0[3*i+2]*n3[1]; + array_atom[k][2] = x[k][2]+q0[3*i]*n1[2]+q0[3*i+1]*n2[2]+q0[3*i+2]*n3[2]; + } + + double m_all = 0.0; + for (int i = 0; i<N; i++) + m_all += m[i]; + + //%x+X_center + + for (int i = 0; i<N; i++) + { + k = list_cluster[i]; + for (int j = 0; j < N; j++) + { + array_atom[k][0] += m[j]/m_all*(del[j][0]-del[i][0]); + array_atom[k][1] += m[j]/m_all*(del[j][1]-del[i][1]); + array_atom[k][2] += m[j]/m_all*(del[j][2]-del[i][2]); + } + } + + //derivative: + //dn1dx: + double sum1[3][3*N]; + for (int i=0; i<3; i++) + for (int j=0; j<3*N; j++) + sum1[i][j] = 0; + + double I3mn1n1T[3][3]; //(I_3 - n1n1T) + for (int i=0; i<3; i++) + { + for (int j=0; j<3; j++) + I3mn1n1T[i][j] = -n1[i]*n1[j]; + I3mn1n1T[i][i] += 1.0; + } + // sum1 part of dn1dx: + for (int l = 0; l < nselect1; l++) + { + k = select1[l]; + for (int i=0; i<3; i++) + { + for (int j=0; j<3; j++) + { + double help = del[k][i]*del[k][j]*r[k]*r[k]*r[k]; + sum1[i][j+3*k] -= help; + sum1[i][j] += help; + } + sum1[i][i+3*k] += r[k]; + sum1[i][i] -= r[k]; + } + } + //dn1dx = norm1 * I3mn1n1T * sum1 + for (int i=0; i<3; i++) + { + for (int j=0; j<3*N; j++) + { + double sum = 0; + for (int l = 0; l<3; l++) + sum += I3mn1n1T[i][l]*sum1[l][j]; + dn1dx[i][j] = norm1*sum; + } + } + + //dn2dx: norm2 * I3mn2n2T * (I3mn1n1T*sum2 - rkn1pn1rk*dn1dx) + double sum2[3][3*N]; + for (int i=0; i<3; i++) + for (int j=0; j<3*N; j++) + sum2[i][j] = 0; + + double I3mn2n2T[3][3]; //(I_3 - n2n2T) + for (int i=0; i<3; i++) + { + for (int j=0; j<3; j++) + I3mn2n2T[i][j] = -n2[i]*n2[j]; + I3mn2n2T[i][i] += 1.0; + } + + // sum2 part of dn1dx: + for (int l = 0; l < nselect2; l++) + { + k = select2[l]; + for (int i=0; i<3; i++) + { + for (int j=0; j<3; j++) + { + double help = del[k][i]*del[k][j]*r[k]*r[k]*r[k]; + sum2[i][j+3*k] -= help; + sum2[i][j] += help; + } + sum2[i][i+3*k] += r[k]; + sum2[i][i] -= r[k]; + } + } + + //prefaktor: + double rkn1pn1rk[3][3]; + double rk[3]; rk[0] = rk[1] = rk[2] = 0.0; + + for (int i = 0; i < nselect2; i++) + { + k = select2[i]; + rk[0] += del[k][0]*r[k]; + rk[1] += del[k][1]*r[k]; + rk[2] += del[k][2]*r[k]; + } + //rkn1pn1rk = rkT*n1*I3 + n1*rkT + double scalar = rk[0]*n1[0]+rk[1]*n1[1]+rk[2]*n1[2]; + for (int i=0; i<3; i++) + { + for (int j=0; j<3; j++) + rkn1pn1rk[i][j] = n1[i]*rk[j]; + rkn1pn1rk[i][i] += scalar; + } + //dn2dx: norm2 * I3mn2n2T * (I3mn1n1T*sum2 - rkn1pn1rk*dn1dx) + //sum3 = (I3mn1n1T*sum2 - rkn1pn1rk*dn1dx) + double sum3[3][3*N]; + for (int i=0; i<3; i++) + { + for (int j=0; j<3*N; j++) + { + double sum = 0; + for (int l = 0; l<3; l++) + sum += I3mn1n1T[i][l]*sum2[l][j] - rkn1pn1rk[i][l]*dn1dx[l][j]; + sum3[i][j] = sum; + } + } + //dn2dx = norm2 * I3mn2n2T * sum3 + for (int i=0; i<3; i++) + { + for (int j=0; j<3*N; j++) + { + double sum = 0; + for (int l = 0; l<3; l++) + sum += I3mn2n2T[i][l]*sum3[l][j]; + dn2dx[i][j] = norm2*sum; + } + } + + //dn3dx = norm3 * I3mn3n3T * cross + double I3mn3n3T[3][3]; //(I_3 - n3n3T) + for (int i=0; i<3; i++) + { + for (int j=0; j<3; j++) + I3mn3n3T[i][j] = -n3[i]*n3[j]; + I3mn3n3T[i][i] += 1.0; + } + + double cross[3][3*N]; + + for (int j=0; j<3*N; j++) + { + cross[0][j] = dn1dx[1][j]*n2[2] -dn1dx[2][j]*n2[1] + + n1[1]*dn2dx[2][j]-n1[2]*dn2dx[1][j]; + cross[1][j] = dn1dx[2][j]*n2[0] -dn1dx[0][j]*n2[2] + + n1[2]*dn2dx[0][j]-n1[0]*dn2dx[2][j]; + cross[2][j] = dn1dx[0][j]*n2[1] -dn1dx[1][j]*n2[0] + + n1[0]*dn2dx[1][j]-n1[1]*dn2dx[0][j]; + } + + for (int i=0; i<3; i++) + { + for (int j=0; j<3*N; j++) + { + double sum = 0; + for (int l = 0; l<3; l++) + sum += I3mn3n3T[i][l]*cross[l][j]; + dn3dx[i][j] = norm3*sum; + } + } + + for (int l=0; l<N; l++) + for (int i=0; i<3; i++) + for (int j=0; j<3*N; j++) + help2[i+3*l][j] = q0[3*l]*dn1dx[i][j] + q0[3*l+1]*dn2dx[i][j] + + q0[3*l+2]*dn3dx[i][j]; + + for (int j=0; j<N; j++) + for (int l=0; l<N; l++) + for (int i=0; i<3; i++) + help2[i+3*l][i+3*j] += m[j]/m_all; + + //need transposed of help2: + for (int ii = 0; ii < 3*N; ii++) + for (int jj = 0; jj < 3*N; jj++) + clist_derv[index_in_list][ii][jj] = help2[jj][ii]; + + //free memory + delete [] list_cluster; + delete [] m; + delete [] r; + for (int i = 0; i<N; i++) + delete [] del[i]; + delete [] del; +} + +int FixFilterCorotate::pack_forward_comm(int n, int *list, double *buf, + int pbc_flag, int *pbc) +{ + int i,j,m; + double**f = atom->f; + m = 0; + for (i = 0; i < n; i++) + { + j = list[i]; + + buf[m++] = f[j][0]; + buf[m++] = f[j][1]; + buf[m++] = f[j][2]; + } + return m; +} + +void FixFilterCorotate::unpack_forward_comm(int n, int first, double *buf) +{ + int i,m,last; + double **f = atom->f; + m = 0; + last = first + n; + + for (i = first; i < last; i++) + { + f[i][0] = buf[m++]; + f[i][1] = buf[m++]; + f[i][2] = buf[m++]; + } +} + +/* ---------------------------------------------------------------------- + * find a bond between global atom IDs n1 and n2 stored with local atom i + * if find it: + * if setflag = 0, return bond type + * if setflag = -1/1, set bond type to negative/positive and return 0 + * if do not find it, return 0 + * ------------------------------------------------------------------------- */ + +int FixFilterCorotate::bondtype_findset(int i, tagint n1, tagint n2, + int setflag) +{ + int m,nbonds; + + tagint *tag = atom->tag; + tagint **bond_atom = atom->bond_atom; + nbonds = atom->num_bond[i]; + + for (m = 0; m < nbonds; m++) { + if (n1 == tag[i] && n2 == bond_atom[i][m]) break; + if (n1 == bond_atom[i][m] && n2 == tag[i]) break; + } + + if (m < nbonds) { + if (setflag == 0) + return atom->bond_type[i][m]; + + if ((setflag < 0 && atom->bond_type[i][m] > 0) || + (setflag > 0 && atom->bond_type[i][m] < 0)) + atom->bond_type[i][m] = -atom->bond_type[i][m]; + + } + + return 0; +} + +/* ---------------------------------------------------------------------- + * find an angle with global end atom IDs n1 and n2 stored with local atom i + * if find it: + * if setflag = 0, return angle type + * if setflag = -1/1, set angle type to negative/positive and return 0 + * if do not find it, return 0 + * ------------------------------------------------------------------------- */ + +int FixFilterCorotate::angletype_findset(int i, tagint n1, tagint n2, + int setflag) +{ + int m,nangles; + + tagint **angle_atom1 = atom->angle_atom1; + tagint **angle_atom3 = atom->angle_atom3; + nangles = atom->num_angle[i]; + + for (m = 0; m < nangles; m++) { + if (n1 == angle_atom1[i][m] && n2 == angle_atom3[i][m]) break; + if (n1 == angle_atom3[i][m] && n2 == angle_atom1[i][m]) break; + } + + if (m < nangles) { + if (setflag == 0) { + return atom->angle_type[i][m]; + } + + if ((setflag < 0 && atom->angle_type[i][m] > 0) || + (setflag > 0 && atom->angle_type[i][m] < 0)) + atom->angle_type[i][m] = -atom->angle_type[i][m]; + } + + return 0; +} + +/* ---------------------------------------------------------------------- + * allocate local atom-based arrays + * ------------------------------------------------------------------------- */ + +void FixFilterCorotate::grow_arrays(int nmax) +{ + memory->grow(array_atom,nmax,3,"FilterCorotate:peratomarray"); + memory->grow(shake_flag,nmax,"FilterCorotate::shake_flag"); + memory->grow(shake_atom,nmax,5,"FilterCorotate::shake_atom"); + memory->grow(shake_type,nmax,4,"FilterCorotate::shake_type"); +} + +/* ---------------------------------------------------------------------- + * memory usage of local atom-based arrays + * ------------------------------------------------------------------------- */ + +double FixFilterCorotate::memory_usage() +{ + double bytes = 0; + //GROW: + bytes += 3*sizeof(double) + 5*sizeof(tagint) + 5*sizeof(int); + //clist + bytes += 13*atom->nlocal*sizeof(int); + bytes += 15*16*nlocal*sizeof(double); + + //fixed: + int nb = atom->nbondtypes+1; + int na = atom->nangletypes+1; + int nt = atom->ntypes+1; + bytes += (nb+na+nt)*sizeof(int); + bytes += (nt-1+nb+na+15*15+18+10*15)*sizeof(double); + + //output: + //bytes += (2*nb+2*na)*sizeof(int); + //bytes += (6*na+6*nb)*sizeof(double); + + return bytes; +} + + +/* ---------------------------------------------------------------------- + * copy values within local atom-based arrays + * ------------------------------------------------------------------------- */ + +void FixFilterCorotate::copy_arrays(int i, int j, int delflag) +{ + int flag = shake_flag[j] = shake_flag[i]; + if (flag == 1) { + shake_atom[j][0] = shake_atom[i][0]; + shake_atom[j][1] = shake_atom[i][1]; + shake_atom[j][2] = shake_atom[i][2]; + shake_type[j][0] = shake_type[i][0]; + shake_type[j][1] = shake_type[i][1]; + shake_type[j][2] = shake_type[i][2]; + } else if (flag == 2) { + shake_atom[j][0] = shake_atom[i][0]; + shake_atom[j][1] = shake_atom[i][1]; + shake_type[j][0] = shake_type[i][0]; + } else if (flag == 3) { + shake_atom[j][0] = shake_atom[i][0]; + shake_atom[j][1] = shake_atom[i][1]; + shake_atom[j][2] = shake_atom[i][2]; + shake_type[j][0] = shake_type[i][0]; + shake_type[j][1] = shake_type[i][1]; + shake_type[j][2] = shake_type[i][2]; + } else if (flag == 4) { + shake_atom[j][0] = shake_atom[i][0]; + shake_atom[j][1] = shake_atom[i][1]; + shake_atom[j][2] = shake_atom[i][2]; + shake_atom[j][3] = shake_atom[i][3]; + shake_type[j][0] = shake_type[i][0]; + shake_type[j][1] = shake_type[i][1]; + shake_type[j][2] = shake_type[i][2]; + } else if (flag == 5) { + shake_atom[j][0] = shake_atom[i][0]; + shake_atom[j][1] = shake_atom[i][1]; + shake_atom[j][2] = shake_atom[i][2]; + shake_atom[j][3] = shake_atom[i][3]; + shake_atom[j][4] = shake_atom[i][4]; + shake_type[j][0] = shake_type[i][0]; + shake_type[j][1] = shake_type[i][1]; + shake_type[j][2] = shake_type[i][2]; + shake_type[j][3] = shake_type[i][3]; + } +} + +/* ---------------------------------------------------------------------- + * initialize one atom's array values, called when atom is created + * ------------------------------------------------------------------------- */ + +void FixFilterCorotate::set_arrays(int i) +{ + shake_flag[i] = 0; +} + +/* ---------------------------------------------------------------------- + * update one atom's array values + * called when molecule is created from fix gcmc + * ------------------------------------------------------------------------- */ + +void FixFilterCorotate::update_arrays(int i, int atom_offset) +{ + int flag = shake_flag[i]; + + if (flag == 1) { + shake_atom[i][0] += atom_offset; + shake_atom[i][1] += atom_offset; + shake_atom[i][2] += atom_offset; + } else if (flag == 2) { + shake_atom[i][0] += atom_offset; + shake_atom[i][1] += atom_offset; + } else if (flag == 3) { + shake_atom[i][0] += atom_offset; + shake_atom[i][1] += atom_offset; + shake_atom[i][2] += atom_offset; + } else if (flag == 4) { + shake_atom[i][0] += atom_offset; + shake_atom[i][1] += atom_offset; + shake_atom[i][2] += atom_offset; + shake_atom[i][3] += atom_offset; + } else if (flag == 5) { + shake_atom[i][0] += atom_offset; + shake_atom[i][1] += atom_offset; + shake_atom[i][2] += atom_offset; + shake_atom[i][3] += atom_offset; + shake_atom[i][4] += atom_offset; + } +} + + +/* ---------------------------------------------------------------------- + * pack values in local atom-based arrays for exchange with another proc + * ------------------------------------------------------------------------- */ + +int FixFilterCorotate::pack_exchange(int i, double *buf) +{ + int m = 0; + buf[m++] = shake_flag[i]; + int flag = shake_flag[i]; + if (flag == 1) { + buf[m++] = shake_atom[i][0]; + buf[m++] = shake_atom[i][1]; + buf[m++] = shake_atom[i][2]; + buf[m++] = shake_type[i][0]; + buf[m++] = shake_type[i][1]; + buf[m++] = shake_type[i][2]; + } else if (flag == 2) { + buf[m++] = shake_atom[i][0]; + buf[m++] = shake_atom[i][1]; + buf[m++] = shake_type[i][0]; + } else if (flag == 3) { + buf[m++] = shake_atom[i][0]; + buf[m++] = shake_atom[i][1]; + buf[m++] = shake_atom[i][2]; + buf[m++] = shake_type[i][0]; + buf[m++] = shake_type[i][1]; + buf[m++] = shake_type[i][2]; + } else if (flag == 4) { + buf[m++] = shake_atom[i][0]; + buf[m++] = shake_atom[i][1]; + buf[m++] = shake_atom[i][2]; + buf[m++] = shake_atom[i][3]; + buf[m++] = shake_type[i][0]; + buf[m++] = shake_type[i][1]; + buf[m++] = shake_type[i][2]; + } else if (flag == 5) { + buf[m++] = shake_atom[i][0]; + buf[m++] = shake_atom[i][1]; + buf[m++] = shake_atom[i][2]; + buf[m++] = shake_atom[i][3]; + buf[m++] = shake_atom[i][4]; + buf[m++] = shake_type[i][0]; + buf[m++] = shake_type[i][1]; + buf[m++] = shake_type[i][2]; + buf[m++] = shake_type[i][3]; + } + return m; +} + +/* ---------------------------------------------------------------------- + * unpack values in local atom-based arrays from exchange with another proc + * ------------------------------------------------------------------------- */ + +int FixFilterCorotate::unpack_exchange(int nlocal, double *buf) +{ + int m = 0; + int flag = shake_flag[nlocal] = static_cast<int> (buf[m++]); + if (flag == 1) { + shake_atom[nlocal][0] = static_cast<tagint> (buf[m++]); + shake_atom[nlocal][1] = static_cast<tagint> (buf[m++]); + shake_atom[nlocal][2] = static_cast<tagint> (buf[m++]); + shake_type[nlocal][0] = static_cast<int> (buf[m++]); + shake_type[nlocal][1] = static_cast<int> (buf[m++]); + shake_type[nlocal][2] = static_cast<int> (buf[m++]); + } else if (flag == 2) { + shake_atom[nlocal][0] = static_cast<tagint> (buf[m++]); + shake_atom[nlocal][1] = static_cast<tagint> (buf[m++]); + shake_type[nlocal][0] = static_cast<int> (buf[m++]); + } else if (flag == 3) { + shake_atom[nlocal][0] = static_cast<tagint> (buf[m++]); + shake_atom[nlocal][1] = static_cast<tagint> (buf[m++]); + shake_atom[nlocal][2] = static_cast<tagint> (buf[m++]); + shake_type[nlocal][0] = static_cast<int> (buf[m++]); + shake_type[nlocal][1] = static_cast<int> (buf[m++]); + shake_type[nlocal][2] = static_cast<int> (buf[m++]); + } else if (flag == 4) { + shake_atom[nlocal][0] = static_cast<tagint> (buf[m++]); + shake_atom[nlocal][1] = static_cast<tagint> (buf[m++]); + shake_atom[nlocal][2] = static_cast<tagint> (buf[m++]); + shake_atom[nlocal][3] = static_cast<tagint> (buf[m++]); + shake_type[nlocal][0] = static_cast<int> (buf[m++]); + shake_type[nlocal][1] = static_cast<int> (buf[m++]); + shake_type[nlocal][2] = static_cast<int> (buf[m++]); + } else if (flag == 5) { + shake_atom[nlocal][0] = static_cast<tagint> (buf[m++]); + shake_atom[nlocal][1] = static_cast<tagint> (buf[m++]); + shake_atom[nlocal][2] = static_cast<tagint> (buf[m++]); + shake_atom[nlocal][3] = static_cast<tagint> (buf[m++]); + shake_atom[nlocal][4] = static_cast<tagint> (buf[m++]); + shake_type[nlocal][0] = static_cast<int> (buf[m++]); + shake_type[nlocal][1] = static_cast<int> (buf[m++]); + shake_type[nlocal][2] = static_cast<int> (buf[m++]); + shake_type[nlocal][3] = static_cast<int> (buf[m++]); + } + return m; +} \ No newline at end of file diff --git a/src/USER-MISC/fix_filter_corotate.h b/src/USER-MISC/fix_filter_corotate.h index fdac4bed748374bfaf97ef97f3476211cde5b8b0..da9e2dedb3eb19c421201e5c00c8c833b33a1df9 100644 --- a/src/USER-MISC/fix_filter_corotate.h +++ b/src/USER-MISC/fix_filter_corotate.h @@ -1,139 +1,139 @@ -/* ---------------------------------------------------------------------- - 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: Lukas Fath (KIT) - some subroutines are from fix_shake.cpp - ------------------------------------------------------------------------- */ - -#ifdef FIX_CLASS - -FixStyle(filter/corotate,FixFilterCorotate) - -#else - -#ifndef LMP_FIX_FILTER_COROTATE_H -#define LMP_FIX_FILTER_COROTATE_H - -#include "fix.h" - -namespace LAMMPS_NS -{ - - class FixFilterCorotate : public Fix - { - public: - - FixFilterCorotate(class LAMMPS *, int, char **); - ~FixFilterCorotate(); - void setup(int); - void setup_pre_neighbor(); - void pre_neighbor(); - void setup_pre_force_respa(int,int); -// void setup_post_force_respa(int,int); - void pre_force_respa(int, int, int); - void post_force_respa(int, int, int); - - void init(); - int setmask(); - - double compute_array(int,int); - - int pack_forward_comm(int, int *, double *, int, int *); - void unpack_forward_comm(int, int, double *); - void grow_arrays(int ); - double memory_usage(); - - void copy_arrays(int, int, int); - void set_arrays(int); - void update_arrays(int, int); - - int pack_exchange(int, double *); - int unpack_exchange(int, double *); - - protected: - - int me,nprocs; - - int flevel; //filtered respa level - - double **help2; //temp derivative - double **x_store; //temp for atom->x - double *g; //temp for derivative - - double*n1,*n2,*n3, *del1, *del2,*del3; - - double**dn1dx,**dn2dx,**dn3dx; - - int *bond_flag,*angle_flag; // bond/angle types to constrain - int *type_flag; // constrain bonds to these types - double *mass_list; // constrain bonds to these masses - int nmass; // # of masses in mass_list - - int molecular; // copy of atom->molecular - double *bond_distance,*angle_distance; // constraint distances - - int nlevels_respa; // copies of needed rRESPA variables - - double **x,**v,**f; // local ptrs to atom class quantities - double *mass,*rmass; - int *type; - int nlocal; - // atom-based arrays - int *shake_flag; // 0 if atom not in SHAKE cluster - // 1 = size 3 angle cluster - // 2,3,4 = size of bond-only cluster - tagint **shake_atom; // global IDs of atoms in cluster - // central atom is 1st - // lowest global ID is 1st for size 2 - int **shake_type; // bondtype of each bond in cluster - // for angle cluster, 3rd value - // is angletype - int *nshake; // count - - int *list; // list of clusters to SHAKE - int nlist,maxlist; // size and max-size of list - double ***clist_derv; //stores derivative - double **clist_q0; //stores reference config - int *clist_nselect1, *clist_nselect2; //stores length of each selec. list - int **clist_select1, **clist_select2; //stores selection lists - - void find_clusters(); - int masscheck(double); - - void filter_inner(); - void filter_outer(); - - void general_cluster(int,int); - - void stats(); - int bondtype_findset(int, tagint, tagint, int); - int angletype_findset(int, tagint, tagint, int); - - // static variable for ring communication callback to access class data - // callback functions for ring communication - - static FixFilterCorotate *fsptr; - static void ring_bonds(int, char *); - static void ring_nshake(int, char *); - static void ring_shake(int, char *); - - int sgn(double val) { - return (0 < val) - (val < 0); - }; - }; - -} - -#endif +/* ---------------------------------------------------------------------- + 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: Lukas Fath (KIT) + some subroutines are from fix_shake.cpp + ------------------------------------------------------------------------- */ + +#ifdef FIX_CLASS + +FixStyle(filter/corotate,FixFilterCorotate) + +#else + +#ifndef LMP_FIX_FILTER_COROTATE_H +#define LMP_FIX_FILTER_COROTATE_H + +#include "fix.h" + +namespace LAMMPS_NS +{ + + class FixFilterCorotate : public Fix + { + public: + + FixFilterCorotate(class LAMMPS *, int, char **); + ~FixFilterCorotate(); + void setup(int); + void setup_pre_neighbor(); + void pre_neighbor(); + void setup_pre_force_respa(int,int); +// void setup_post_force_respa(int,int); + void pre_force_respa(int, int, int); + void post_force_respa(int, int, int); + + void init(); + int setmask(); + + double compute_array(int,int); + + int pack_forward_comm(int, int *, double *, int, int *); + void unpack_forward_comm(int, int, double *); + void grow_arrays(int ); + double memory_usage(); + + void copy_arrays(int, int, int); + void set_arrays(int); + void update_arrays(int, int); + + int pack_exchange(int, double *); + int unpack_exchange(int, double *); + + protected: + + int me,nprocs; + + int flevel; //filtered respa level + + double **help2; //temp derivative + double **x_store; //temp for atom->x + double *g; //temp for derivative + + double*n1,*n2,*n3, *del1, *del2,*del3; + + double**dn1dx,**dn2dx,**dn3dx; + + int *bond_flag,*angle_flag; // bond/angle types to constrain + int *type_flag; // constrain bonds to these types + double *mass_list; // constrain bonds to these masses + int nmass; // # of masses in mass_list + + int molecular; // copy of atom->molecular + double *bond_distance,*angle_distance; // constraint distances + + int nlevels_respa; // copies of needed rRESPA variables + + double **x,**v,**f; // local ptrs to atom class quantities + double *mass,*rmass; + int *type; + int nlocal; + // atom-based arrays + int *shake_flag; // 0 if atom not in SHAKE cluster + // 1 = size 3 angle cluster + // 2,3,4 = size of bond-only cluster + tagint **shake_atom; // global IDs of atoms in cluster + // central atom is 1st + // lowest global ID is 1st for size 2 + int **shake_type; // bondtype of each bond in cluster + // for angle cluster, 3rd value + // is angletype + int *nshake; // count + + int *list; // list of clusters to SHAKE + int nlist,maxlist; // size and max-size of list + double ***clist_derv; //stores derivative + double **clist_q0; //stores reference config + int *clist_nselect1, *clist_nselect2; //stores length of each selec. list + int **clist_select1, **clist_select2; //stores selection lists + + void find_clusters(); + int masscheck(double); + + void filter_inner(); + void filter_outer(); + + void general_cluster(int,int); + + void stats(); + int bondtype_findset(int, tagint, tagint, int); + int angletype_findset(int, tagint, tagint, int); + + // static variable for ring communication callback to access class data + // callback functions for ring communication + + static FixFilterCorotate *fsptr; + static void ring_bonds(int, char *); + static void ring_nshake(int, char *); + static void ring_shake(int, char *); + + int sgn(double val) { + return (0 < val) - (val < 0); + }; + }; + +} + +#endif #endif \ No newline at end of file