diff --git a/src/USER-ACKLAND/Install.csh b/src/USER-ACKLAND/Install.csh new file mode 100644 index 0000000000..63f2e503cc --- /dev/null +++ b/src/USER-ACKLAND/Install.csh @@ -0,0 +1,20 @@ +# Install/unInstall package classes in LAMMPS + +if ($1 == 1) then + + cp -p style_user_ackland.h .. + + cp -p compute_ackland_atom.cpp .. + + cp -p compute_ackland_atom.h .. + +else if ($1 == 0) then + + rm ../style_user_ackland.h + touch ../style_user_ackland.h + + rm ../compute_ackland_atom.cpp + + rm ../compute_ackland_atom.h + +endif diff --git a/src/USER-ACKLAND/README b/src/USER-ACKLAND/README new file mode 100644 index 0000000000..fedf5fbbb8 --- /dev/null +++ b/src/USER-ACKLAND/README @@ -0,0 +1,18 @@ +The files in this directory are a user-contributed package for LAMMPS. + +The person who created these files is Gerolf Ziegenhain +(gerolf@ziegenhain.com). Contact him directly if you have questions. + +This package implements a "compute ackland/atom" command which can be +used in a LAMMPS input script. Like other per-atom compute commands, +the results can be accessed when dumping atom information to a file, +or by other fixes that do averaging of various kinds. See the +documentation files for these commands for details. + +The Ackland computation is a means of detecting local lattice +structure around an atom, as described in G. Ackland, +PRB(2006)73:054104. + +The output is a number with the following mapping: + +enum{UNKNOWN,BCC,FCC,HCP,ICO}; diff --git a/src/USER-ACKLAND/compute_ackland_atom.cpp b/src/USER-ACKLAND/compute_ackland_atom.cpp new file mode 100644 index 0000000000..398d140420 --- /dev/null +++ b/src/USER-ACKLAND/compute_ackland_atom.cpp @@ -0,0 +1,385 @@ +/* ---------------------------------------------------------------------- + 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: G. Ziegenhain, gerolf@ziegenhain.com + Copyright (C) 2007 +------------------------------------------------------------------------- */ + +#include "string.h" +#include "compute_ackland_atom.h" +#include "atom.h" +#include "modify.h" +#include "update.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "force.h" +#include "pair.h" +#include "comm.h" +#include "memory.h" +#include "error.h" +#include + +using namespace LAMMPS_NS; + +enum{UNKNOWN,BCC,FCC,HCP,ICO}; + +/* ---------------------------------------------------------------------- */ + +ComputeAcklandAtom::ComputeAcklandAtom(LAMMPS *lmp, int narg, char **arg) : + Compute(lmp, narg, arg) +{ + if (narg != 3) error->all("Illegal compute ackland/atom command"); + + peratom_flag = 1; + size_peratom = 0; + + nmax = 0; + structure = NULL; + maxneigh = 0; + distsq = NULL; + nearest = NULL; + nearest_n0 = NULL; + nearest_n1 = NULL; +} + +/* ---------------------------------------------------------------------- */ + +ComputeAcklandAtom::~ComputeAcklandAtom() +{ + memory->sfree(structure); + memory->sfree(distsq); + memory->sfree(nearest); + memory->sfree(nearest_n0); + memory->sfree(nearest_n1); +} + +/* ---------------------------------------------------------------------- */ + +void ComputeAcklandAtom::init() +{ + // need an occasional full neighbor list + + int irequest = neighbor->request((void *) this); + neighbor->requests[irequest]->pair = 0; + neighbor->requests[irequest]->compute = 1; + neighbor->requests[irequest]->half = 0; + neighbor->requests[irequest]->full = 1; + neighbor->requests[irequest]->occasional = 1; + + int count = 0; + for (int i = 0; i < modify->ncompute; i++) + if (strcmp(modify->compute[i]->style,"ackland/atom") == 0) count++; + if (count > 1 && comm->me == 0) + error->warning("More than one compute ackland/atom"); +} + +/* ---------------------------------------------------------------------- */ +void ComputeAcklandAtom::compute_peratom() +{ + int i,j,ii,jj,k,n,inum,jnum; + double xtmp,ytmp,ztmp,delx,dely,delz,rsq,value; + int *ilist,*jlist,*numneigh,**firstneigh; + double pairs[66]; + int chi[8]; + + // grow structure array if necessary + + if (atom->nlocal > nmax) { + memory->sfree(structure); + nmax = atom->nmax; + structure = (double *) + memory->smalloc(nmax*sizeof(double),"compute/ackland/atom:ackland"); + scalar_atom = structure; + } + + // invoke half neighbor list (will copy or build if necessary) + + neighbor->build_one(list->index); + + inum = list->inum; + ilist = list->ilist; + numneigh = list->numneigh; + firstneigh = list->firstneigh; + + // compute structure parameter for each atom in group + // use full neighbor list + + double **x = atom->x; + int *mask = atom->mask; + int nlocal = atom->nlocal; + int nall = atom->nlocal + atom->nghost; + double cutsq = force->pair->cutforce * force->pair->cutforce; + + for (ii = 0; ii < inum; ii++) { + i = ilist[ii]; + if (mask[i] & groupbit) { + xtmp = x[i][0]; + ytmp = x[i][1]; + ztmp = x[i][2]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + + // ensure distsq and nearest arrays are long enough + + if (jnum > maxneigh) { + memory->sfree(distsq); + memory->sfree(nearest); + memory->sfree(nearest_n0); + memory->sfree(nearest_n1); + maxneigh = jnum; + distsq = (double *) memory->smalloc(maxneigh*sizeof(double), + "compute/ackland/atom:distsq"); + nearest = (int *) memory->smalloc(maxneigh*sizeof(int), + "compute/ackland/atom:nearest"); + nearest_n0 = (int *) memory->smalloc(maxneigh*sizeof(int), + "compute/ackland/atom:nearest_n0"); + nearest_n1 = (int *) memory->smalloc(maxneigh*sizeof(int), + "compute/ackland/atom:nearest_n1"); + } + + // loop over list of all neighbors within force cutoff + // distsq[] = distance sq to each + // nearest[] = atom indices of neighbors + + n = 0; + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + if (j >= nall) j %= nall; + + delx = xtmp - x[j][0]; + dely = ytmp - x[j][1]; + delz = ztmp - x[j][2]; + rsq = delx*delx + dely*dely + delz*delz; + if (rsq < cutsq) { + distsq[n] = rsq; + nearest[n++] = j; + } + } + + // Select 6 nearest neighbors + + select2(6,n,distsq,nearest); + + // Mean squared separation + + double r0_sq = 0.; + for (j = 0; j < 6; j++) + r0_sq += distsq[j]; + r0_sq /= 6.; + + // n0 near neighbors with: distsq<1.45*r0_sq + // n1 near neighbors with: distsq<1.55*r0_sq + + double n0_dist_sq = 1.45*r0_sq, + n1_dist_sq = 1.55*r0_sq; + int n0 = 0, n1 = 0; + for (j = 0; j < n; j++) { + if (distsq[j] < n1_dist_sq) { + nearest_n1[n1++] = nearest[j]; + if (distsq[j] < n0_dist_sq) { + nearest_n0[n0++] = nearest[j]; + } + } + } + + // Evaluate all angles <(r_ij,rik) forall n0 particles with: distsq<1.45*r0_sq + double bond_angle; + double norm_j, norm_k; + chi[0] = chi[1] = chi[2] = chi[3] = chi[4] = chi[5] = chi[6] = chi[7] = 0; + double x_ij, y_ij, z_ij, x_ik, y_ik, z_ik; + for (j = 0; j < n0; j++) { + x_ij = x[i][0]-x[nearest_n0[j]][0]; + y_ij = x[i][1]-x[nearest_n0[j]][1]; + z_ij = x[i][2]-x[nearest_n0[j]][2]; + norm_j = sqrt (x_ij*x_ij + y_ij*y_ij + z_ij*z_ij); + if (norm_j <= 0.) continue; + for (k = j+1; k < n0; k++) { + x_ik = x[i][0]-x[nearest_n0[k]][0]; + y_ik = x[i][1]-x[nearest_n0[k]][1]; + z_ik = x[i][2]-x[nearest_n0[k]][2]; + norm_k = sqrt (x_ik*x_ik + y_ik*y_ik + z_ik*z_ik); + if (norm_k <= 0.) + continue; + + bond_angle = (x_ij*x_ik + y_ij*y_ik + z_ij*z_ik) / (norm_j*norm_k); + + // Histogram for identifying the relevant peaks + if (-1. <= bond_angle && bond_angle < -0.945) { chi[0]++; } + else if (-0.945 <= bond_angle && bond_angle < -0.915) { chi[1]++; } + else if (-0.915 <= bond_angle && bond_angle < -0.755) { chi[2]++; } + else if (-0.755 <= bond_angle && bond_angle < -0.195) { chi[3]++; } + else if (-0.195 <= bond_angle && bond_angle < 0.195) { chi[4]++; } + else if (0.195 <= bond_angle && bond_angle < 0.245) { chi[5]++; } + else if (0.245 <= bond_angle && bond_angle < 0.795) { chi[6]++; } + else if (0.795 <= bond_angle && bond_angle < 1.) { chi[7]++; } + } + } + + // Deviations from the different lattice structures + double delta_bcc = 0.35*chi[4]/(double)(chi[5]+chi[6]-chi[4]), + delta_cp = fabs(1.-(double)chi[6]/24.), + delta_fcc = 0.61*(fabs((double)(chi[0]+chi[1]-6.))+(double)chi[2])/6., + delta_hcp = (fabs((double)chi[0]-3.)+fabs((double)chi[0]+(double)chi[1]+(double)chi[2]+(double)chi[3]-9.))/12.; + + // Identification of the local structure according to the reference + if (chi[0] == 7) { delta_bcc = 0.; } + else if (chi[0] == 6) { delta_fcc = 0.; } + else if (chi[0] <= 3) { delta_hcp = 0.; } + + if (chi[7] > 0.) + structure[i] = UNKNOWN; + else + if (chi[4] < 3.) + { + if (n1 > 13 || n1 < 11) + structure[i] = UNKNOWN; + else + structure[i] = ICO; + } else + if (delta_bcc <= delta_cp) + { + if (n1 < 11) + structure[i] = UNKNOWN; + else + structure[i] = BCC; + } else + if (n1 > 12 || n1 < 11) + structure[i] = UNKNOWN; + else + if (delta_fcc < delta_hcp) + structure[i] = FCC; + else + structure[i] = HCP; + + } // end loop over all particles + } +} + +/* ---------------------------------------------------------------------- + 2 select routines from Numerical Recipes (slightly modified) + find k smallest values in array of length n + 2nd routine sorts auxiliary array at same time +------------------------------------------------------------------------- */ + +#define SWAP(a,b) tmp = a; a = b; b = tmp; +#define ISWAP(a,b) itmp = a; a = b; b = itmp; + +void ComputeAcklandAtom::select(int k, int n, double *arr) + { + int i,ir,j,l,mid; + double a,tmp; + + arr--; + l = 1; + ir = n; + for (;;) { + if (ir <= l+1) { + if (ir == l+1 && arr[ir] < arr[l]) { + SWAP(arr[l],arr[ir]) + } + return; + } else { + mid=(l+ir) >> 1; + SWAP(arr[mid],arr[l+1]) + if (arr[l] > arr[ir]) { + SWAP(arr[l],arr[ir]) + } + if (arr[l+1] > arr[ir]) { + SWAP(arr[l+1],arr[ir]) + } + if (arr[l] > arr[l+1]) { + SWAP(arr[l],arr[l+1]) + } + i = l+1; + j = ir; + a = arr[l+1]; + for (;;) { + do i++; while (arr[i] < a); + do j--; while (arr[j] > a); + if (j < i) break; + SWAP(arr[i],arr[j]) + } + arr[l+1] = arr[j]; + arr[j] = a; + if (j >= k) ir = j-1; + if (j <= k) l = i; + } + } +} + +/* ---------------------------------------------------------------------- */ + +void ComputeAcklandAtom::select2(int k, int n, double *arr, int *iarr) +{ + int i,ir,j,l,mid,ia,itmp; + double a,tmp; + + arr--; + iarr--; + l = 1; + ir = n; + for (;;) { + if (ir <= l+1) { + if (ir == l+1 && arr[ir] < arr[l]) { + SWAP(arr[l],arr[ir]) + ISWAP(iarr[l],iarr[ir]) + } + return; + } else { + mid=(l+ir) >> 1; + SWAP(arr[mid],arr[l+1]) + ISWAP(iarr[mid],iarr[l+1]) + if (arr[l] > arr[ir]) { + SWAP(arr[l],arr[ir]) + ISWAP(iarr[l],iarr[ir]) + } + if (arr[l+1] > arr[ir]) { + SWAP(arr[l+1],arr[ir]) + ISWAP(iarr[l+1],iarr[ir]) + } + if (arr[l] > arr[l+1]) { + SWAP(arr[l],arr[l+1]) + ISWAP(iarr[l],iarr[l+1]) + } + i = l+1; + j = ir; + a = arr[l+1]; + ia = iarr[l+1]; + for (;;) { + do i++; while (arr[i] < a); + do j--; while (arr[j] > a); + if (j < i) break; + SWAP(arr[i],arr[j]) + ISWAP(iarr[i],iarr[j]) + } + arr[l+1] = arr[j]; + arr[j] = a; + iarr[l+1] = iarr[j]; + iarr[j] = ia; + if (j >= k) ir = j-1; + if (j <= k) l = i; + } + } +} + +/* ---------------------------------------------------------------------- + memory usage of local atom-based array +------------------------------------------------------------------------- */ + +int ComputeAcklandAtom::memory_usage() +{ + int bytes = nmax * sizeof(double); + return bytes; +} diff --git a/src/USER-ACKLAND/compute_ackland_atom.h b/src/USER-ACKLAND/compute_ackland_atom.h new file mode 100644 index 0000000000..6dce8fa52e --- /dev/null +++ b/src/USER-ACKLAND/compute_ackland_atom.h @@ -0,0 +1,42 @@ +/* ---------------------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +#ifndef COMPUTE_ACKLAND_ATOM_H +#define COMPUTE_ACKLAND_ATOM_H + +#include "compute.h" + +namespace LAMMPS_NS { + +class ComputeAcklandAtom : public Compute { + public: + ComputeAcklandAtom(class LAMMPS *, int, char **); + ~ComputeAcklandAtom(); + void init(); + void compute_peratom(); + int memory_usage(); + + private: + int nmax,maxneigh; + double *distsq; + int *nearest, *nearest_n0, *nearest_n1; + double *structure; + class NeighList *list; + + void select(int, int, double *); + void select2(int, int, double *, int *); +}; + +} + +#endif diff --git a/src/USER-ACKLAND/style_user_ackland.h b/src/USER-ACKLAND/style_user_ackland.h new file mode 100644 index 0000000000..6e7483a9f7 --- /dev/null +++ b/src/USER-ACKLAND/style_user_ackland.h @@ -0,0 +1,20 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef ComputeInclude +#include "compute_ackland_atom.h" +#endif + +#ifdef ComputeClass +ComputeStyle(ackland/atom,ComputeAcklandAtom) +#endif diff --git a/src/USER-EWALDN/Install.csh b/src/USER-EWALDN/Install.csh new file mode 100644 index 0000000000..786946702a --- /dev/null +++ b/src/USER-EWALDN/Install.csh @@ -0,0 +1,34 @@ +# Install/unInstall package classes in LAMMPS + +if ($1 == 1) then + + cp -p style_user_ewaldn.h .. + + cp -p ewald_n.cpp .. + cp -p pair_buck_coul.cpp .. + cp -p pair_lj_coul.cpp .. + + cp -p ewald_n.h .. + cp -p pair_buck_coul.h .. + cp -p pair_lj_coul.h .. + + cp -p math_vector.h .. + cp -p math_complex.h .. + +else if ($1 == 0) then + + rm ../style_user_ewaldn.h + touch ../style_user_ewaldn.h + + rm ../ewald_n.cpp + rm ../pair_buck_coul.cpp + rm ../pair_lj_coul.cpp + + rm ../ewald_n.h + rm ../pair_buck_coul.h + rm ../pair_lj_coul.h + + rm ../math_vector.h + rm ../math_complex.h + +endif diff --git a/src/USER-EWALDN/README b/src/USER-EWALDN/README new file mode 100644 index 0000000000..8931245a2a --- /dev/null +++ b/src/USER-EWALDN/README @@ -0,0 +1,22 @@ +The files in this directory are a user-contributed package for LAMMPS. + +The person who created these files is Pieter in' t Veld at Sandia +(pjintve@sandia.gov). Contact him directly if you have questions. + +This package implements 3 commands which can be used in a LAMMPS input +script: pair_style lj/coul, pair_style buck/coul, and kspace_style +ewald/n. See the documentation files for these commands for details. + +The "kspace_style ewald/n" command is similar to standard Ewald for +charges, but also enables the Lennard-Jones interaction, or any 1/r^N +interaction to be of infinite extent, instead of being cutoff. LAMMPS +pair potentials for long-range Coulombic interactions, such as +lj/cut/coul/long can be used with ewald/n. The two new pair_style +commands provide the modifications for the short-range LJ and +Buckingham interactions that can also be used with ewald/n. + +Another advantage of kspace_style ewald/n is that it can be used with +non-orthogonal (triclinic symmetry) simulation boxes, either for just +long-range Coulombic interactions, or for both Coulombic and 1/r^N LJ +or Buckingham, which is not currently possible for other kspace styles +such as PPPM and ewald. diff --git a/src/USER-EWALDN/ewald_n.cpp b/src/USER-EWALDN/ewald_n.cpp new file mode 100644 index 0000000000..af898f712b --- /dev/null +++ b/src/USER-EWALDN/ewald_n.cpp @@ -0,0 +1,704 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + www.cs.sandia.gov/~sjplimp/lammps.html + Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories + + 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: Pieter J. in 't Veld (SNL) +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + module: ewald_n.cpp + author: Pieter J. in 't Veld for SNL + date: September 13, 2006. + usage: kspace ewald/n precision + precision set precision of all orders + remarks: - cut off and precision are assumed identical for all orders + - coulombics from Macromolecules 1989, 93, 7320 + - dipoles from J. Chem. Phys. 2000, 113, 10913 +* ---------------------------------------------------------------------- */ + +#include "mpi.h" +#include "string.h" +#include "stdio.h" +#include "stdlib.h" +#include "math.h" +#include "ewald_n.h" +#include "math_vector.h" +#include "atom.h" +#include "comm.h" +#include "force.h" +#include "pair.h" +#include "domain.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; + +#define KSPACE_ILLEGAL "Illegal kspace_style ewald/n command" +#define KSPACE_ORDER "Unsupported order in kspace_style ewald/n for" +#define KSPACE_MIX "Unsupported mixing rule in kspace_style ewald/n for" + +enum{GEOMETRIC,ARITHMETIC,SIXTHPOWER}; // same as in pair.cpp + +//#define DEBUG + +/* ---------------------------------------------------------------------- */ + +EwaldN::EwaldN(LAMMPS *lmp, int narg, char **arg) : KSpace(lmp, narg, arg) +{ + if (narg!=1) error->all(KSPACE_ILLEGAL); + precision = fabs(atof(arg[0])); + memset(function, 0, EWALD_NORDER*sizeof(int)); + kenergy = kvirial = NULL; + cek_local = cek_global = NULL; + ekr_local = NULL; + hvec = NULL; + kvec = NULL; + B = NULL; + first_output = 0; +} + +EwaldN::~EwaldN() +{ + deallocate(); + delete [] ekr_local; + delete [] B; +} + +/* --------------------------------------------------------------------- */ + +void EwaldN::init() +{ + nkvec = nkvec_max = nevec = nevec_max = bytes = 0; + nfunctions = nsums = sums = 0; + nbox = -1; + + if (!comm->me) { // output message + if (screen) fprintf(screen,"EwaldN initialization ...\n"); + if (logfile) fprintf(logfile,"EwaldN initialization ...\n"); + } + + if (domain->dimension == 2) // check for errors + error->all("Cannot use EwaldN with 2d simulation"); + if (slabflag == 0 && domain->nonperiodic > 0) + error->all("Cannot use nonperiodic boundaries with EwaldN"); + if (slabflag == 1) { + if (domain->xperiodic != 1 || domain->yperiodic != 1 || + domain->boundary[2][0] != 1 || domain->boundary[2][1] != 1) + error->all("Incorrect boundaries with slab EwaldN"); + } + + qqrd2e = force->qqrd2e; // check pair_style + //mumurd2e = force->mumurd2e; + //dielectric = force->dielectric; + mumurd2e = dielectric = 1.0; + + Pair *pair = force->pair; + void *ptr = pair ? pair->extract_ptr("ewald_order") : NULL; + if (!ptr) error->all("KSpace style is incompatible with Pair style"); + int ewald_order = *((int *) ptr); + int ewald_mix = *((int *) pair->extract_ptr("ewald_mix")); + double cutoff = *((double *) pair->extract_ptr("ewald_cut")); + memset(function, 0, EWALD_NFUNCS*sizeof(int)); + for (int i=0; i<=EWALD_NORDER; ++i) // transcribe order + if (ewald_order&(1<pair_style); + error->all(str); + default: + sprintf(str, "%s pair_style %s", KSPACE_ORDER, force->pair_style); + error->all(str); + } + nfunctions += function[k] = 1; + nsums += n[k]; + } + + g_ewald = (1.35 - 0.15*log(precision))/cutoff; // determine resolution + g2_max = -4.0*g_ewald*g_ewald*log(precision); + + if (!comm->me) { // output results + if (screen) fprintf(screen, " G vector = %g\n", g_ewald); + if (logfile) fprintf(logfile, " G vector = %g\n", g_ewald); + } +} + + +/* ---------------------------------------------------------------------- + adjust EwaldN coeffs, called initially and whenever volume has changed +------------------------------------------------------------------------- */ + +void EwaldN::setup() +{ + volume = shape_det(domain->h)*slab_volfactor; // cell volume + memcpy(unit, domain->h_inv, sizeof(shape)); // wave vector units + shape_scalar_mult(unit, 2.0*M_PI); + unit[2] /= slab_volfactor; + + //int nbox_old = nbox, nkvec_old = nkvec; + if (precision>=1) nbox = 0; + else { + vector n = {1.0, 1.0, 1.0}; // based on cutoff + vec_scalar_mult(n, g_ewald*sqrt(-log(precision))/M_PI); + shape_vec_dot(n, n, domain->h); + n[2] *= slab_volfactor; + nbox = (int) n[0]; + if (nbox<(int) n[1]) nbox = (int) n[1]; + if (nbox<(int) n[2]) nbox = (int) n[2]; + } + reallocate(); + + coefficients(); // compute coeffs + init_coeffs(); + init_coeff_sums(); + init_self(); + + if (!(first_output||comm->me)) { // output on first + first_output = 1; + if (screen) fprintf(screen, + " vectors: nbox = %d, nkvec = %d\n", nbox, nkvec); + if (logfile) fprintf(logfile, + " vectors: nbox = %d, nkvec = %d\n", nbox, nkvec); + } +} + + +void EwaldN::reallocate() // allocate memory +{ + int ix, iy, iz; + int nkvec_max = nkvec; + vector h; + + nkvec = 0; // determine size(kvec) + int kflag[(nbox+1)*(2*nbox+1)*(2*nbox+1)], *flag = kflag; + for (ix=0; ix<=nbox; ++ix) + for (iy=-nbox; iy<=nbox; ++iy) + for (iz=-nbox; iz<=nbox; ++iz) + if (!(ix||iy||iz)) *(flag++) = 0; + else if ((!ix)&&(iy<0)) *(flag++) = 0; + else if ((!(ix||iy))&&(iz<0)) *(flag++) = 0; // use symmetry + else { + h[0] = unit[0]*ix; + h[1] = unit[5]*ix+unit[1]*iy; + h[2] = unit[4]*ix+unit[3]*iy+unit[2]*iz; + if ((*(flag++) = h[0]*h[0]+h[1]*h[1]+h[2]*h[2]<=g2_max)) ++nkvec; + } + + if (nkvec>nkvec_max) { + deallocate(); // free memory + hvec = new hvector[nkvec]; // hvec + bytes += (nkvec-nkvec_max)*sizeof(hvector); + kvec = new kvector[nkvec]; // kvec + bytes += (nkvec-nkvec_max)*sizeof(kvector); + kenergy = new double[nkvec*nfunctions]; // kenergy + bytes += (nkvec-nkvec_max)*nfunctions*sizeof(double); + kvirial = new double[6*nkvec*nfunctions]; // kvirial + bytes += 6*(nkvec-nkvec_max)*nfunctions*sizeof(double); + cek_local = new complex[nkvec*nsums]; // cek_local + bytes += (nkvec-nkvec_max)*nsums*sizeof(complex); + cek_global = new complex[nkvec*nsums]; // cek_global + bytes += (nkvec-nkvec_max)*nsums*sizeof(complex); + nkvec_max = nkvec; + } + + flag = kflag; // create index and + kvector *k = kvec; // wave vectors + hvector *hi = hvec; + for (ix=0; ix<=nbox; ++ix) + for (iy=-nbox; iy<=nbox; ++iy) + for (iz=-nbox; iz<=nbox; ++iz) + if (*(flag++)) { + hi->x = unit[0]*ix; + hi->y = unit[5]*ix+unit[1]*iy; + (hi++)->z = unit[4]*ix+unit[3]*iy+unit[2]*iz; + k->x = ix+nbox; k->y = iy+nbox; (k++)->z = iz+nbox; } + +} + + +void EwaldN::reallocate_atoms() +{ + if ((nevec = atom->nmax*(2*nbox+1))<=nevec_max) return; + delete [] ekr_local; + ekr_local = new cvector[nevec]; + bytes += (nevec-nevec_max)*sizeof(cvector); + nevec_max = nevec; +} + + +void EwaldN::deallocate() // free memory +{ + delete [] hvec; hvec = NULL; + delete [] kvec; kvec = NULL; + delete [] kenergy; kenergy = NULL; + delete [] kvirial; kvirial = NULL; + delete [] cek_local; cek_local = NULL; + delete [] cek_global; cek_global = NULL; +} + + +void EwaldN::coefficients() // set up pre-factors +{ + vector h; + hvector *hi = hvec, *nh; + double eta2 = 0.25/(g_ewald*g_ewald); + double b1, b2, expb2, h1, h2, c1, c2; + double *ke = kenergy, *kv = kvirial; + int func0 = function[0], func12 = function[1]||function[2], + func3 = function[3]; + + for (nh = (hi = hvec)+nkvec; hintypes; + + if (function[1]) { // geometric 1/r^6 + double **b = (double **) force->pair->extract_ptr("B"); + delete [] B; + B = new double[n+1]; + bytes += (n+1)*sizeof(double); + for (int i=0; i<=n; ++i) B[i] = sqrt(fabs(b[i][i])); + } + if (function[2]) { // arithmetic 1/r^6 + double **epsilon = (double **) force->pair->extract_ptr("epsilon"); + double **sigma = (double **) force->pair->extract_ptr("sigma"); + if (!(epsilon&&sigma)) + error->all("epsilon or sigma reference not set by pair style in ewald/n"); + double eps_i, sigma_i, sigma_n, *bi = B = new double[7*n+7]; + double c[7] = { + 1.0, sqrt(6.0), sqrt(15.0), sqrt(20.0), sqrt(15.0), sqrt(6.0), 1.0}; + for (int i=0; i<=n; ++i) { + eps_i = sqrt(epsilon[i][i]); + sigma_i = sigma[i][i]; + sigma_n = 1.0; + for (int j=0; j<7; ++j) { + *(bi++) = sigma_n*eps_i*c[j]; sigma_n *= sigma_i; + } + } + } +} + + +void EwaldN::init_coeff_sums() // sums based on atoms +{ + if (sums) return; // calculated only once + sums = 1; + + Sum sum_local[EWALD_MAX_NSUMS]; + + memset(sum_local, 0, EWALD_MAX_NSUMS*sizeof(Sum)); + if (function[0]) { // 1/r + double *q = atom->q, *qn = q+atom->nlocal; + for (double *i=q; itype, *ntype = type+atom->nlocal; + for (int *i=type; itype, *ntype = type+atom->nlocal; + for (int *i=type; itype, *ntype = type+atom->nlocal; + double *dipole = atom->dipole; + for (int *i=type; ix[0], *xn = x+3*atom->nlocal, *q = atom->q, qi, bi, ci[7]; + double *dipole = atom->dipole, *mu = atom->mu ? atom->mu[0] : NULL; + int i, kx, ky, n = nkvec*nsums, *type = atom->type, tri = domain->triclinic; + int func[EWALD_NFUNCS]; + + memcpy(func, function, EWALD_NFUNCS*sizeof(int)); + memset(cek_local, 0, n*sizeof(complex)); // reset sums + while (xx, 1, 0); C_SET(zz->y, 1, 0); C_SET(zz->z, 1, 0); // z[0] + if (tri) { // triclinic z[1] + C_ANGLE(z1.x, unit[0]*x[0]+unit[5]*x[1]+unit[4]*x[2]); + C_ANGLE(z1.y, unit[1]*x[1]+unit[3]*x[2]); + C_ANGLE(z1.z, x[2]*unit[2]); x += 3; + } + else { // orthogonal z[1] + C_ANGLE(z1.x, *(x++)*unit[0]); + C_ANGLE(z1.y, *(x++)*unit[1]); + C_ANGLE(z1.z, *(x++)*unit[2]); + } + for (; zzx, zz->x, z1.x); // 3D k-vector + C_RMULT(zy->y, zz->y, z1.y); C_CONJ(zx->y, zy->y); + C_RMULT(zy->z, zz->z, z1.z); C_CONJ(zx->z, zy->z); + } + kx = ky = -1; + cek = cek_local; + if (func[0]) qi = *(q++); + if (func[1]) bi = B[*type]; + if (func[2]) memcpy(ci, B+7*type[0], 7*sizeof(double)); + if (func[3]) { + memcpy(mui, mu, sizeof(vector)); mu += 3; + vec_scalar_mult(mui, dipole[*type]); + h = hvec; + } + for (k=kvec; ky) { // based on order in + if (kx!=k->x) cx = z[kx = k->x].x; // reallocate + C_RMULT(zxy, z[ky = k->y].y, cx); + } + C_RMULT(zxyz, z[k->z].z, zxy); + if (func[0]) { + cek->re += zxyz.re*qi; (cek++)->im += zxyz.im*qi; + } + if (func[1]) { + cek->re += zxyz.re*bi; (cek++)->im += zxyz.im*bi; + } + if (func[2]) for (i=0; i<7; ++i) { + cek->re += zxyz.re*ci[i]; (cek++)->im += zxyz.im*ci[i]; + } + if (func[3]) { + register double muk = mui[0]*h->x+mui[1]*h->y+mui[2]*h->z; ++h; + cek->re += zxyz.re*muk; (cek++)->im += zxyz.im*muk; + } + } + ekr = (cvector *) ((char *) memcpy(ekr, z, lbytes)+lbytes); + ++type; + } + MPI_Allreduce(cek_local, cek_global, 2*n, MPI_DOUBLE, MPI_SUM, world); +} + + +void EwaldN::compute_force() +{ + kvector *k; + hvector *h, *nh; + cvector *z = ekr_local; + vector sum[EWALD_MAX_NSUMS], mui; + complex *cek, zc, zx, zxy; + double *f = atom->f[0], *fn = f+3*atom->nlocal, *q = atom->q, *t = NULL; + double *dipole = atom->dipole, *mu = atom->mu ? atom->mu[0] : NULL; + double *ke, c[EWALD_NFUNCS] = { + 8.0*M_PI*qqrd2e/volume, 2.0*M_PI*sqrt(M_PI)/(12.0*volume), + 2.0*M_PI*sqrt(M_PI)/(192.0*volume), 8.0*M_PI*mumurd2e/volume}; + double kt = 4.0*pow(g_ewald, 3.0)/3.0/sqrt(M_PI)/c[3]; + int i, kx, ky, lbytes = (2*nbox+1)*sizeof(cvector), *type = atom->type; + int func[EWALD_NFUNCS]; + + if (atom->torque) t = atom->torque[0]; + memcpy(func, function, EWALD_NFUNCS*sizeof(int)); + memset(sum, 0, EWALD_MAX_NSUMS*sizeof(vector)); // fj = -dE/dr = + for (; fy) { // based on order in + if (kx!=k->x) zx = z[kx = k->x].x; // reallocate + C_RMULT(zxy, z[ky = k->y].y, zx); + } + C_CRMULT(zc, z[k->z].z, zxy); + if (func[0]) { // 1/r + register double im = *(ke++)*(zc.im*cek->re+cek->im*zc.re); ++cek; + sum[0][0] += h->x*im; sum[0][1] += h->y*im; sum[0][2] += h->z*im; + } + if (func[1]) { // geometric 1/r^6 + register double im = *(ke++)*(zc.im*cek->re+cek->im*zc.re); ++cek; + sum[1][0] += h->x*im; sum[1][1] += h->y*im; sum[1][2] += h->z*im; + } + if (func[2]) { // arithmetic 1/r^6 + register double im, c = *(ke++); + for (i=2; i<9; ++i) { + im = c*(zc.im*cek->re+cek->im*zc.re); ++cek; + sum[i][0] += h->x*im; sum[i][1] += h->y*im; sum[i][2] += h->z*im; + } + } + if (func[3]) { // dipole + register double im = *(ke++)*(zc.im*cek->re+ + cek->im*zc.re)*(mui[0]*h->x+mui[1]*h->y+mui[2]*h->z); ++cek; + sum[9][0] += h->x*im; sum[9][1] += h->y*im; sum[9][2] += h->z*im; + } + } + if (func[0]) { // 1/r + register double qi = *(q++)*c[0]; + f[0] -= sum[0][0]*qi; f[1] -= sum[0][1]*qi; f[2] -= sum[0][2]*qi; + } + if (func[1]) { // geometric 1/r^6 + register double bi = B[*type]*c[1]; + f[0] -= sum[1][0]*bi; f[1] -= sum[1][1]*bi; f[2] -= sum[1][2]*bi; + } + if (func[2]) { // arithmetic 1/r^6 + register double *bi = B+7*type[0]+7; + for (i=2; i<9; ++i) { + register double c2 = (--bi)[0]*c[2]; + f[0] -= sum[i][0]*c2; f[1] -= sum[i][1]*c2; f[2] -= sum[i][2]*c2; + } + } + if (func[3]) { // dipole + f[0] -= sum[9][0]; f[1] -= sum[9][1]; f[2] -= sum[9][2]; + *(t++) -= mui[1]*sum[0][2]+mui[2]*sum[0][1]-mui[0]*kt; // torque + *(t++) -= mui[2]*sum[0][0]+mui[0]*sum[0][2]-mui[1]*kt; + *(t++) -= mui[0]*sum[0][1]+mui[1]*sum[0][0]-mui[2]*kt; + } + z = (cvector *) ((char *) z+lbytes); + ++type; + } +} + + +void EwaldN::compute_surface() +{ + if (!function[3]) return; + + vector sum_local = VECTOR_NULL, sum_total; + double *mu = atom->mu ? atom->mu[0] : NULL, *dipole = atom->dipole; + int *type = atom->type, *ntype = type+atom->nlocal; + + for (int *i=type; ire*cek->re+cek->im*cek->im); ++cek; } + if (func[1]) { // geometric 1/r^6 + sum[1] += *(ke++)*(cek->re*cek->re+cek->im*cek->im); ++cek; } + if (func[2]) { // arithmetic 1/r^6 + register double r = + (cek[0].re*cek[6].re+cek[0].im*cek[6].im)+ + (cek[1].re*cek[5].re+cek[1].im*cek[5].im)+ + (cek[2].re*cek[4].re+cek[2].im*cek[4].im)+ + 0.5*(cek[3].re*cek[3].re+cek[3].im*cek[3].im); cek += 7; + sum[2] += *(ke++)*r; + } + if (func[3]) { // dipole + sum[3] += *(ke++)*(cek->re*cek->re+cek->im*cek->im); ++cek; } + } + for (int k=0; kre*cek->re+cek->im*cek->im; ++cek; + sum[0][0] += *(kv++)*r; sum[0][1] += *(kv++)*r; sum[0][2] += *(kv++)*r; + sum[0][3] += *(kv++)*r; sum[0][4] += *(kv++)*r; sum[0][5] += *(kv++)*r; + } + if (func[1]) { // geometric 1/r^6 + register double r = cek->re*cek->re+cek->im*cek->im; ++cek; + sum[1][0] += *(kv++)*r; sum[1][1] += *(kv++)*r; sum[1][2] += *(kv++)*r; + sum[1][3] += *(kv++)*r; sum[1][4] += *(kv++)*r; sum[1][5] += *(kv++)*r; + } + if (func[2]) { // arithmetic 1/r^6 + register double r = + (cek[0].re*cek[6].re+cek[0].im*cek[6].im)+ + (cek[1].re*cek[5].re+cek[1].im*cek[5].im)+ + (cek[2].re*cek[4].re+cek[2].im*cek[4].im)+ + 0.5*(cek[3].re*cek[3].re+cek[3].im*cek[3].im); cek += 7; + sum[2][0] += *(kv++)*r; sum[2][1] += *(kv++)*r; sum[2][2] += *(kv++)*r; + sum[2][3] += *(kv++)*r; sum[2][4] += *(kv++)*r; sum[2][5] += *(kv++)*r; + } + if (func[3]) { + register double r = cek->re*cek->re+cek->im*cek->im; ++cek; + sum[3][0] += *(kv++)*r; sum[3][1] += *(kv++)*r; sum[3][2] += *(kv++)*r; + sum[3][3] += *(kv++)*r; sum[3][4] += *(kv++)*r; sum[3][5] += *(kv++)*r; + } + } + for (int k=0; kq; + double *x = atom->x[0]-1, *xn = x+3*atom->nlocal-1; + double dipole = 0.0, dipole_all; + + while ((x+=3)f[0]-1, *fn = f+3*atom->nlocal-3; + + q = atom->q; + while ((f+=3)-FZERO) && ((x)1) xtx[4] = xtx[2]; + if (!form_inv(xtx_inv, xtx)) return 0; + memcpy(eqn, xty, sizeof(vector)); + form_vec_dot(eqn, xtx_inv); + return 1; } + +// cubic regression: y = eqn[0] + eqn[1]*x + eqn[2]*x*x + eqn[3]*x*x*x + +inline int regress3(vector4 &eqn, int order, double *x, double *y, int n) { + form4 xtx = FORM4_NULL, xtx_inv; + vector4 xty = VECTOR4_NULL; + double xn, xi, yi; + int i; + + vec4_null(eqn); + xtx[0] = n; + if ((order = order%3)<0) order = -order; // max: cubic regress + if (order<1) xtx[1] = 1.0; + if (order<2) xtx[2] = 1.0; + if (order<3) xtx[3] = 1.0; + for (i=0; i1) xtx[8] = xtx[1]; + if (order>2) { xtx[6] = xtx[7]; xtx[5] = xtx[2]; } + if (!form4_inv(xtx_inv, xtx)) return 0; + memcpy(eqn, xty, sizeof(vector4)); + form4_vec4_dot(eqn, xtx_inv); + return 1; } + +} + +#endif diff --git a/src/USER-EWALDN/pair_buck_coul.cpp b/src/USER-EWALDN/pair_buck_coul.cpp new file mode 100644 index 0000000000..123f02d542 --- /dev/null +++ b/src/USER-EWALDN/pair_buck_coul.cpp @@ -0,0 +1,1176 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + www.cs.sandia.gov/~sjplimp/lammps.html + Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories + + 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: Pieter J. in 't Veld (SNL) +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + module: pair_buck_coul.cpp + author: Pieter J. in 't Veld for SNL + date: October 2, 2006. + purpose: definition of short and long range buckingham and coulombic + pair potentials. + usage: pair_style buck/coul + long|cut|off control r^-6 contribution + long|cut|off control r^-1 contribution + rcut6 set r^-6 cut off + [rcut1] set r^-1 cut off + remarks: rcut1 cannot be set when both contributions are set to long, + rcut1 = rcut6 when ommited. +* ---------------------------------------------------------------------- */ + +#include "math.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "math_vector.h" +#include "pair_buck_coul.h" +#include "atom.h" +#include "comm.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "force.h" +#include "kspace.h" +#include "update.h" +#include "integrate.h" +#include "respa.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +#define EWALD_F 1.12837917 +#define EWALD_P 0.3275911 +#define A1 0.254829592 +#define A2 -0.284496736 +#define A3 1.421413741 +#define A4 -1.453152027 +#define A5 1.061405429 + +/* ---------------------------------------------------------------------- */ + +PairBuckCoul::PairBuckCoul(LAMMPS *lmp) : Pair(lmp) +{ + respa_enable = 1; + ftable = NULL; +} + +/* ---------------------------------------------------------------------- + global settings +------------------------------------------------------------------------- */ + +#define PAIR_ILLEGAL "Illegal pair_style buck/coul command" +#define PAIR_CUTOFF "Only one cut-off allowed when requesting all long" +#define PAIR_MISSING "Cut-offs missing in pair_style buck/coul" +#define PAIR_LJ_OFF "LJ6 off not supported in pair_style buck/coul" +#define PAIR_COUL_CUT "Coulombic cut not supported in pair_style buck/coul" +#define PAIR_MANY "Too many pair_style buck/coul commands" +#define PAIR_LARGEST "Using largest cut-off for buck/coul long long" +#define PAIR_MIX "Geometric mixing assumed for 1/r^6 coefficients" + +void PairBuckCoul::options(char **arg, int order) +{ + char *option[] = {"long", "cut", "off", NULL}; + int i; + + if (!*arg) error->all(PAIR_ILLEGAL); + for (i=0; option[i]&&strcmp(arg[0], option[i]); ++i); + switch (i) { + default: error->all(PAIR_ILLEGAL); + case 0: ewald_order |= 1<me && ewald_order&(1<<6)) error->warning(PAIR_MIX); + if (!comm->me && ewald_order==((1<<1)|(1<<6))) error->warning(PAIR_LARGEST); + if (!*(++arg)) error->all(PAIR_MISSING); + if (ewald_off&(1<<6)) error->all(PAIR_LJ_OFF); + if (!((ewald_order^ewald_off)&(1<<1))) error->all(PAIR_COUL_CUT); + cut_buck_global = atof(*(arg++)); + if (*arg&&(ewald_order&0x42==0x42)) error->all(PAIR_CUTOFF); + cut_coul = *arg ? atof(*(arg++)) : cut_buck_global; + if (*arg) error->all(PAIR_MANY); + + if (allocated) { // reset explicit cuts + int i,j; + for (i = 1; i <= atom->ntypes; i++) + for (j = i+1; j <= atom->ntypes; j++) + if (setflag[i][j]) cut_buck[i][j] = cut_buck_global; + } +} + +/* ---------------------------------------------------------------------- + free all arrays +------------------------------------------------------------------------- */ + +PairBuckCoul::~PairBuckCoul() +{ + if (allocated) { + memory->destroy_2d_int_array(setflag); + memory->destroy_2d_double_array(cutsq); + + memory->destroy_2d_double_array(cut_buck_read); + memory->destroy_2d_double_array(cut_buck); + memory->destroy_2d_double_array(cut_bucksq); + memory->destroy_2d_double_array(buck_a_read); + memory->destroy_2d_double_array(buck_a); + memory->destroy_2d_double_array(buck_c_read); + memory->destroy_2d_double_array(buck_c); + memory->destroy_2d_double_array(buck_rho_read); + memory->destroy_2d_double_array(buck_rho); + memory->destroy_2d_double_array(buck1); + memory->destroy_2d_double_array(buck2); + memory->destroy_2d_double_array(rhoinv); + memory->destroy_2d_double_array(offset); + } + if (ftable) free_tables(); +} + +/* ---------------------------------------------------------------------- + allocate all arrays +------------------------------------------------------------------------- */ + +void PairBuckCoul::allocate() +{ + allocated = 1; + int n = atom->ntypes; + + setflag = memory->create_2d_int_array(n+1,n+1,"pair:setflag"); + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) + setflag[i][j] = 0; + + cutsq = memory->create_2d_double_array(n+1,n+1,"pair:cutsq"); + + cut_buck_read = memory->create_2d_double_array(n+1,n+1,"pair:cut_buck_read"); + cut_buck = memory->create_2d_double_array(n+1,n+1,"pair:cut_buck"); + cut_bucksq = memory->create_2d_double_array(n+1,n+1,"pair:cut_bucksq"); + buck_a_read = memory->create_2d_double_array(n+1,n+1,"pair:buck_a_read"); + buck_a = memory->create_2d_double_array(n+1,n+1,"pair:buck_a"); + buck_c_read = memory->create_2d_double_array(n+1,n+1,"pair:buck_c_read"); + buck_c = memory->create_2d_double_array(n+1,n+1,"pair:buck_c"); + buck_rho_read = memory->create_2d_double_array(n+1,n+1,"pair:buck_rho_read"); + buck_rho = memory->create_2d_double_array(n+1,n+1,"pair:buck_rho"); + buck1 = memory->create_2d_double_array(n+1,n+1,"pair:buck1"); + buck2 = memory->create_2d_double_array(n+1,n+1,"pair:buck2"); + rhoinv = memory->create_2d_double_array(n+1,n+1,"pair:rhoinv"); + offset = memory->create_2d_double_array(n+1,n+1,"pair:offset"); +} + +/* ---------------------------------------------------------------------- + extract protected data from object +------------------------------------------------------------------------- */ + +void *PairBuckCoul::extract_ptr(char *id) +{ + char *ids[] = { + "B", "sigma", "epsilon", "ewald_order", "ewald_cut", "ewald_mix", NULL}; + void *ptrs[] = { + buck_c, NULL, NULL, &ewald_order, &cut_coul, &mix_flag, NULL}; + int i; + + for (i=0; ids[i]&&strcmp(ids[i], id); ++i); + return ptrs[i]; +} + +/* ---------------------------------------------------------------------- */ + +void PairBuckCoul::extract_long(double *p_cut_coul) +{ + *p_cut_coul = cut_coul; +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs +------------------------------------------------------------------------- */ + +void PairBuckCoul::coeff(int narg, char **arg) +{ + if (narg < 5 || narg > 6) error->all("Incorrect args for pair coefficients"); + if (!allocated) allocate(); + + int ilo,ihi,jlo,jhi; + force->bounds(*(arg++),atom->ntypes,ilo,ihi); + force->bounds(*(arg++),atom->ntypes,jlo,jhi); + + double buck_a_one = atof(*(arg++)); + double buck_rho_one = atof(*(arg++)); + double buck_c_one = atof(*(arg++)); + + double cut_buck_one = cut_buck_global; + if (narg == 6) cut_buck_one = atof(*(arg++)); + + int count = 0; + for (int i = ilo; i <= ihi; i++) { + for (int j = MAX(jlo,i); j <= jhi; j++) { + buck_a_read[i][j] = buck_a_one; + buck_c_read[i][j] = buck_c_one; + buck_rho_read[i][j] = buck_rho_one; + cut_buck_read[i][j] = cut_buck_one; + setflag[i][j] = 1; + count++; + } + } + + if (count == 0) error->all("Incorrect args for pair coefficients"); +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i +------------------------------------------------------------------------- */ + +double PairBuckCoul::init_one(int i, int j) +{ + if (setflag[i][j] == 0) error->all("All pair coeffs are not set"); + + cut_buck[i][j] = cut_buck_read[i][j]; + buck_a[i][j] = buck_a_read[i][j]; + buck_c[i][j] = buck_c_read[i][j]; + buck_rho[i][j] = buck_rho_read[i][j]; + + double cut = MAX(cut_buck[i][j], cut_coul); + cutsq[i][j] = cut*cut; + cut_bucksq[i][j] = cut_buck[i][j] * cut_buck[i][j]; + + buck1[i][j] = buck_a[i][j]/buck_rho[i][j]; + buck2[i][j] = 6.0*buck_c[i][j]; + rhoinv[i][j] = 1.0/buck_rho[i][j]; + + if (offset_flag) { + double rexp = exp(-cut_buck[i][j]/buck_rho[i][j]); + offset[i][j] = buck_a[i][j]*rexp - buck_c[i][j]/pow(cut_buck[i][j],6.0); + } else offset[i][j] = 0.0; + + cutsq[j][i] = cutsq[i][j]; + cut_bucksq[j][i] = cut_bucksq[i][j]; + buck_a[j][i] = buck_a[i][j]; + buck_c[j][i] = buck_c[i][j]; + rhoinv[j][i] = rhoinv[i][j]; + buck1[j][i] = buck1[i][j]; + buck2[j][i] = buck2[i][j]; + offset[j][i] = offset[i][j]; + + return cut; +} + +/* ---------------------------------------------------------------------- + init specific to this pair style +------------------------------------------------------------------------- */ + +void PairBuckCoul::init_style() +{ + int i,j; + + // require an atom style with charge defined + + //if (atom->charge_allow == 0) + //error->all("Must use charged atom style with this pair style"); + if (!atom->q_flag && (ewald_order&(1<<1))) + error->all( + "Invoking coulombic in pair style lj/coul requires atom attribute q"); + + cut_coulsq = cut_coul * cut_coul; + + // set & error check interior rRESPA cutoffs + + if (strcmp(update->integrate_style,"respa") == 0) { + if (((Respa *) update->integrate)->level_inner >= 0) { + cut_respa = ((Respa *) update->integrate)->cutoff; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) + if (MIN(cut_buck[i][j],cut_coul) < cut_respa[3]) + error->all("Pair cutoff < Respa interior cutoff"); + } + } else cut_respa = NULL; + + // ensure use of KSpace long-range solver, set g_ewald + + if (ewald_order&(1<<1)) { // r^-1 kspace + if (force->kspace == NULL) + error->all("Pair style is incompatible with KSpace style"); + else if (strcmp(force->kspace_style,"ewald") == 0) + g_ewald = force->kspace->g_ewald; + else if (strcmp(force->kspace_style,"ewald/n") == 0) + g_ewald = force->kspace->g_ewald; + else if (strcmp(force->kspace_style,"pppm") == 0) + g_ewald = force->kspace->g_ewald; + else error->all("Pair style is incompatible with KSpace style"); + } + if (ewald_order&(1<<6)) { // r^-6 kspace + if (!force->kspace && strcmp(force->kspace_style,"ewald/n")) + error->all("Pair style is incompatible with KSpace style"); + else g_ewald = force->kspace->g_ewald; + } + + // setup force tables + + if (ncoultablebits) init_tables(); +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file +------------------------------------------------------------------------- */ + +void PairBuckCoul::write_restart(FILE *fp) +{ + write_restart_settings(fp); + + int i,j; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) { + fwrite(&setflag[i][j],sizeof(int),1,fp); + if (setflag[i][j]) { + fwrite(&buck_a_read[i][j],sizeof(double),1,fp); + fwrite(&buck_c_read[i][j],sizeof(double),1,fp); + fwrite(&buck_rho_read[i][j],sizeof(double),1,fp); + fwrite(&cut_buck_read[i][j],sizeof(double),1,fp); + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts +------------------------------------------------------------------------- */ + +void PairBuckCoul::read_restart(FILE *fp) +{ + read_restart_settings(fp); + + allocate(); + + int i,j; + int me = comm->me; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) { + if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); + MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); + if (setflag[i][j]) { + if (me == 0) { + fread(&buck_a_read[i][j],sizeof(double),1,fp); + fread(&buck_c_read[i][j],sizeof(double),1,fp); + fread(&buck_rho_read[i][j],sizeof(double),1,fp); + fread(&cut_buck_read[i][j],sizeof(double),1,fp); + } + MPI_Bcast(&buck_a_read[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&buck_c_read[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&buck_rho_read[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&cut_buck_read[i][j],1,MPI_DOUBLE,0,world); + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file +------------------------------------------------------------------------- */ + +void PairBuckCoul::write_restart_settings(FILE *fp) +{ + fwrite(&cut_buck_global,sizeof(double),1,fp); + fwrite(&cut_coul,sizeof(double),1,fp); + fwrite(&offset_flag,sizeof(int),1,fp); + fwrite(&mix_flag,sizeof(int),1,fp); + fwrite(&ewald_order,sizeof(int),1,fp); +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts +------------------------------------------------------------------------- */ + +void PairBuckCoul::read_restart_settings(FILE *fp) +{ + if (comm->me == 0) { + fread(&cut_buck_global,sizeof(double),1,fp); + fread(&cut_coul,sizeof(double),1,fp); + fread(&offset_flag,sizeof(int),1,fp); + fread(&mix_flag,sizeof(int),1,fp); + fread(&ewald_order,sizeof(int),1,fp); + } + MPI_Bcast(&cut_buck_global,1,MPI_DOUBLE,0,world); + MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); + MPI_Bcast(&offset_flag,1,MPI_INT,0,world); + MPI_Bcast(&mix_flag,1,MPI_INT,0,world); + MPI_Bcast(&ewald_order,1,MPI_INT,0,world); +} + +/* ---------------------------------------------------------------------- + compute pair interactions +------------------------------------------------------------------------- */ + +void PairBuckCoul::compute(int eflag, int vflag) +{ + double **x = atom->x, *x0 = x[0]; + double **f = atom->f, *f0 = f[0], *fi = f0; + double *q = atom->q; + int *type = atom->type; + int nlocal = atom->nlocal; + int nall = atom->nlocal + atom->nghost; + double *special_coul = force->special_coul; + double *special_lj = force->special_lj; + int newton_pair = force->newton_pair; + double qqrd2e = force->qqrd2e; + + int i, j, order1 = ewald_order&(1<<1), order6 = ewald_order&(1<<6); + int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni; + double qi, qri, *cutsqi, *cut_bucksqi, + *buck1i, *buck2i, *buckai, *buckci, *rhoinvi, *offseti; + double r, rsq, r2inv, force_coul, force_buck, fforce, factor; + double g2 = g_ewald*g_ewald, g6 = g2*g2*g2, g8 = g6*g2; + vector xi, d; + + eng_vdwl = eng_coul = 0.0; // reset energy&virial + if (vflag) memset(virial, 0, sizeof(shape)); + + ineighn = (ineigh = list->ilist)+list->inum; + + for (; ineighfirstneigh[i])+list->numneigh[i]; + + for (; jneigh= cutsqi[typej = type[j]]) continue; + r2inv = 1.0/rsq; + r = sqrt(rsq); + + factor = newton_pair || j>ncoulshiftbits; + register double f = (rsq-rtable[k])*drtable[k], qiqj = qi*q[j]; + if (ni < 0) { + force_coul = qiqj*(ftable[k]+f*dftable[k]); + if (eflag) eng_coul += factor*qiqj*(etable[k]+f*detable[k]); + } + else { // special case + t = (1.0-special_coul[ni])*(ctable[k]+f*dctable[k]); + force_coul = qiqj*(ftable[k]+f*dftable[k]-t); + if (eflag) eng_coul += factor*qiqj*(etable[k]+f*detable[k]-t); + } + } + } + else force_coul = 0.0; + + if (rsq < cut_bucksqi[typej]) { // buckingham + register double rn = r2inv*r2inv*r2inv, + expr = exp(-r*rhoinvi[typej]); + if (order6) { // long-range + register double x2 = g2*rsq, a2 = 1.0/x2; + x2 = a2*exp(-x2)*buckci[typej]; + if (ni < 0) { + force_buck = + r*expr*buck1i[typej]-g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq; + if (eflag) eng_vdwl += + factor*(expr*buckai[typej]-g6*((a2+1.0)*a2+0.5)*x2); + } + else { // special case + register double f = special_lj[ni], t = rn*(1.0-f); + force_buck = f*r*expr*buck1i[typej]- + g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq+t*buck2i[typej]; + if (eflag) eng_vdwl += factor*( + f*expr*buckai[typej]-g6*((a2+1.0)*a2+0.5)*x2+t*buckci[typej]); + } + } + else { // cut + if (ni < 0) { + force_buck = r*expr*buck1i[typej]-rn*buck2i[typej]; + if (eflag) eng_vdwl += factor*( + expr*buckai[typej]-rn*buckci[typej]-offseti[typej]); + } + else { // special case + register double f = special_lj[ni]; + force_buck = f*(r*expr*buck1i[typej]-rn*buck2i[typej]); + if (eflag) eng_vdwl += f*factor*( + expr*buckai[typej]-rn*buckci[typej]-offseti[typej]); + } + } + } + else force_buck = 0.0; + + fforce = (force_coul+force_buck)*r2inv; // force and virial + if (vflag==1) { + if (newton_pair || j < nlocal) { + register double f = d[0]*fforce, *fj = f0+(j+(j<<1)); + fi[0] += f; fj[0] -= f; + virial[0] += f*d[0]; virial[3] += f*d[1]; + fi[1] += f = d[1]*fforce; fj[1] -= f; + virial[1] += f*d[1]; virial[5] += f*d[2]; + fi[2] += f = d[2]*fforce; fj[2] -= f; + virial[2] += f*d[2]; virial[4] += f*d[0]; + } + else { + register double f = d[0]*fforce; + fi[0] += f; virial[0] += (f *= 0.5)*d[0]; virial[3] += f*d[1]; + fi[1] += f = d[1]*fforce; virial[1] += 0.5*f*d[1]; + fi[2] += f = d[2]*fforce; virial[2] += (f *= 0.5)*d[2]; + virial[4] += f*d[0]; virial[5] += f*d[1]; + } + } + else if (newton_pair || j < nlocal) { + register double *fj = f0+(j+(j<<1)), f; + fi[0] += f = d[0]*fforce; fj[0] -= f; + fi[1] += f = d[1]*fforce; fj[1] -= f; + fi[2] += f = d[2]*fforce; fj[2] -= f; + } + else { + fi[0] += d[0]*fforce; + fi[1] += d[1]*fforce; + fi[2] += d[2]*fforce; + } + } + } + if (vflag == 2) virial_compute(); +} + +/* ---------------------------------------------------------------------- */ + +void PairBuckCoul::compute_inner() +{ + double r, rsq, r2inv, force_coul, force_buck, fforce; + + int *type = atom->type; + int nlocal = atom->nlocal; + int nall = atom->nlocal + atom->nghost; + double *x0 = atom->x[0], *f0 = atom->f[0], *fi = f0, *q = atom->q; + double *special_coul = force->special_coul; + double *special_lj = force->special_lj; + int newton_pair = force->newton_pair; + double qqrd2e = force->qqrd2e; + + double cut_out_on = cut_respa[0]; + double cut_out_off = cut_respa[1]; + + double cut_out_diff = cut_out_off - cut_out_on; + double cut_out_on_sq = cut_out_on*cut_out_on; + double cut_out_off_sq = cut_out_off*cut_out_off; + + int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni; + int i, j, order1 = (ewald_order|(ewald_off^-1))&(1<<1); + double qri, *cut_bucksqi, *buck1i, *buck2i, *rhoinvi, *offseti; + vector xi, d; + + ineighn = (ineigh = list->ilist)+list->inum; + + for (; ineighfirstneigh[i])+list->numneigh[i]; + + for (; jneigh= cut_out_off_sq) continue; + r2inv = 1.0/rsq; + r = sqrt(r); + + if (order1 && (rsq < cut_coulsq)) // coulombic + force_coul = ni<0 ? + qri*q[j]/r : qri*q[j]/r*special_coul[ni]; + + if (rsq < cut_bucksqi[typej = type[j]]) { // buckingham + register double rn = r2inv*r2inv*r2inv, + expr = exp(-r*rhoinvi[typej]); + force_buck = ni<0 ? + (r*expr*buck1i[typej]-rn*buck2i[typej]) : + (r*expr*buck1i[typej]-rn*buck2i[typej])*special_lj[ni]; + } + else force_buck = 0.0; + + fforce = (force_coul + force_buck) * r2inv; + + if (rsq > cut_out_on_sq) { // switching + register double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; + fforce *= 1.0 + rsw*rsw*(2.0*rsw-3.0); + } + + if (newton_pair || j < nlocal) { // force update + register double *fj = f0+(j+(j<<1)), f; + fi[0] += f = d[0]*fforce; fj[0] -= f; + fi[1] += f = d[1]*fforce; fj[1] -= f; + fi[2] += f = d[2]*fforce; fj[2] -= f; + } + else { + fi[0] += d[0]*fforce; + fi[1] += d[1]*fforce; + fi[2] += d[2]*fforce; + } + } + } +} + +/* ---------------------------------------------------------------------- */ + +void PairBuckCoul::compute_middle() +{ + double r, rsq, r2inv, force_coul, force_buck, fforce; + + int *type = atom->type; + int nlocal = atom->nlocal; + int nall = atom->nlocal + atom->nghost; + double *x0 = atom->x[0], *f0 = atom->f[0], *fi = f0, *q = atom->q; + double *special_coul = force->special_coul; + double *special_lj = force->special_lj; + int newton_pair = force->newton_pair; + double qqrd2e = force->qqrd2e; + + double cut_in_off = cut_respa[0]; + double cut_in_on = cut_respa[1]; + double cut_out_on = cut_respa[2]; + double cut_out_off = cut_respa[3]; + + double cut_in_diff = cut_in_on - cut_in_off; + double cut_out_diff = cut_out_off - cut_out_on; + double cut_in_off_sq = cut_in_off*cut_in_off; + double cut_in_on_sq = cut_in_on*cut_in_on; + double cut_out_on_sq = cut_out_on*cut_out_on; + double cut_out_off_sq = cut_out_off*cut_out_off; + + int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni; + int i, j, order1 = (ewald_order|(ewald_off^-1))&(1<<1); + double qri, *cut_bucksqi, *buck1i, *buck2i, *rhoinvi, *offseti; + vector xi, d; + + ineighn = (ineigh = list->ilist)+list->inum; + + for (; ineighfirstneigh[i])+list->numneigh[i]; + + for (; jneigh= cut_out_off_sq) continue; + if (rsq <= cut_in_off_sq) continue; + r2inv = 1.0/rsq; + r = sqrt(rsq); + + if (order1 && (rsq < cut_coulsq)) // coulombic + force_coul = ni<0 ? + qri*q[j]/r : qri*q[j]/r*special_coul[ni]; + + if (rsq < cut_bucksqi[typej = type[j]]) { // buckingham + register double rn = r2inv*r2inv*r2inv, + expr = exp(-r*rhoinvi[typej]); + force_buck = ni<0 ? + (r*expr*buck1i[typej]-rn*buck2i[typej]) : + (r*expr*buck1i[typej]-rn*buck2i[typej])*special_lj[ni]; + } + else force_buck = 0.0; + + fforce = (force_coul + force_buck) * r2inv; + + if (rsq < cut_in_on_sq) { // switching + register double rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff; + fforce *= rsw*rsw*(3.0 - 2.0*rsw); + } + if (rsq > cut_out_on_sq) { + register double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; + fforce *= 1.0 + rsw*rsw*(2.0*rsw-3.0); + } + + if (newton_pair || j < nlocal) { // force update + register double *fj = f0+(j+(j<<1)), f; + fi[0] += f = d[0]*fforce; fj[0] -= f; + fi[1] += f = d[1]*fforce; fj[1] -= f; + fi[2] += f = d[2]*fforce; fj[2] -= f; + } + else { + fi[0] += d[0]*fforce; + fi[1] += d[1]*fforce; + fi[2] += d[2]*fforce; + } + } + } +} + +/* ---------------------------------------------------------------------- */ + +void PairBuckCoul::compute_outer(int eflag, int vflag) +{ + double **x = atom->x, *x0 = x[0]; + double **f = atom->f, *f0 = f[0], *fi = f0; + double *q = atom->q; + int *type = atom->type; + int nlocal = atom->nlocal; + int nall = atom->nlocal + atom->nghost; + double *special_coul = force->special_coul; + double *special_lj = force->special_lj; + int newton_pair = force->newton_pair; + double qqrd2e = force->qqrd2e; + + int i, j, order1 = ewald_order&(1<<1), order6 = ewald_order&(1<<6); + int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni, respa_flag; + double qi, qri, *cutsqi, *cut_bucksqi, + *buck1i, *buck2i, *buckai, *buckci, *rhoinvi, *offseti; + double r, rsq, r2inv, force_coul, force_buck, fforce, factor; + double g2 = g_ewald*g_ewald, g6 = g2*g2*g2, g8 = g6*g2; + double respa_buck, respa_coul, frespa; + vector xi, d; + + double cut_in_off = cut_respa[2]; + double cut_in_on = cut_respa[3]; + + double cut_in_diff = cut_in_on - cut_in_off; + double cut_in_off_sq = cut_in_off*cut_in_off; + double cut_in_on_sq = cut_in_on*cut_in_on; + + eng_vdwl = eng_coul = 0.0; // reset energy&virial + if (vflag) memset(virial, 0, sizeof(shape)); + + ineighn = (ineigh = list->ilist)+list->inum; + + for (; ineighfirstneigh[i])+list->numneigh[i]; + + for (; jneigh= cutsqi[typej = type[j]]) continue; + r2inv = 1.0/rsq; + r = sqrt(rsq); + + factor = newton_pair || jcut_in_off_sq)&&(rsq>ncoulshiftbits; + register double f = (rsq-rtable[k])*drtable[k], qiqj = qi*q[j]; + if (ni < 0) { + force_coul = qiqj*(ftable[k]+f*dftable[k]); + if (eflag) eng_coul += factor*qiqj*(etable[k]+f*detable[k]); + } + else { // correct for special + t = (1.0-special_coul[ni])*(ctable[k]+f*dctable[k]); + force_coul = qiqj*(ftable[k]+f*dftable[k]-t); + if (eflag) eng_coul += factor*qiqj*(etable[k]+f*detable[k]-t); + } + } + } + else force_coul = respa_coul = 0.0; + + if (rsq < cut_bucksqi[typej]) { // buckingham + register double rn = r2inv*r2inv*r2inv, + expr = exp(-r*rhoinvi[typej]); + if (respa_flag) respa_buck = ni<0 ? // correct for respa + frespa*(r*expr*buck1i[typej]-rn*buck2i[typej]) : + frespa*(r*expr*buck1i[typej]-rn*buck2i[typej])*special_lj[ni]; + if (order6) { // long-range form + register double x2 = g2*rsq, a2 = 1.0/x2; + x2 = a2*exp(-x2)*buckci[typej]; + if (ni < 0) { + force_buck = + r*expr*buck1i[typej]-g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq; + if (eflag) eng_vdwl += + factor*(expr*buckai[typej]-g6*((a2+1.0)*a2+0.5)*x2); + } + else { // correct for special + register double f = special_lj[ni], t = rn*(1.0-f); + force_buck = f*r*expr*buck1i[typej]- + g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq+t*buck2i[typej]; + if (eflag) eng_vdwl += factor*( + f*expr*buckai[typej]-g6*((a2+1.0)*a2+0.5)*x2+t*buckci[typej]); + } + } + else { // cut form + if (ni < 0) { + force_buck = r*expr*buck1i[typej]-rn*buck2i[typej]; + if (eflag) eng_vdwl += factor*( + expr*buckai[typej]-rn*buckci[typej]-offseti[typej]); + } + else { // correct for special + register double f = special_lj[ni]; + force_buck = f*(r*expr*buck1i[typej]-rn*buck2i[typej]); + if (eflag) eng_vdwl += f*factor*( + expr*buckai[typej]-rn*buckci[typej]-offseti[typej]); + } + } + } + else force_buck = respa_buck = 0.0; + + fforce = (force_coul+force_buck)*r2inv; // force and virial + frespa = fforce-(respa_coul+respa_buck)*r2inv; + if (newton_pair || j < nlocal) { + register double *fj = f0+(j+(j<<1)), f; + fi[0] += f = d[0]*frespa; fj[0] -= f; + fi[1] += f = d[1]*frespa; fj[1] -= f; + fi[2] += f = d[2]*frespa; fj[2] -= f; + if (vflag==1) { + virial[0] += (f = d[0]*fforce)*d[0]; virial[3] += f*d[1]; + virial[1] += (f = d[1]*fforce)*d[1]; virial[5] += f*d[2]; + virial[2] += (f = d[2]*fforce)*d[2]; virial[4] += f*d[0]; + } + } + else { + fi[0] += d[0]*frespa; + fi[1] += d[1]*frespa; + fi[2] += d[2]*frespa; + if (vflag==1) { + register double f; + virial[0] += (f = 0.5*d[0]*fforce)*d[0]; virial[3] += f*d[1]; + virial[1] += (f = 0.5*d[1]*fforce)*d[1]; virial[5] += f*d[2]; + virial[2] += (f = 0.5*d[2]*fforce)*d[2]; virial[4] += f*d[0]; + } + } + } + } + if (vflag == 2) virial_compute(); +} + +/* ---------------------------------------------------------------------- + setup force tables used in compute routines +------------------------------------------------------------------------- */ + +void PairBuckCoul::init_tables() +{ + int masklo,maskhi; + double r,grij,expm2,derfc,rsw; + double qqrd2e = force->qqrd2e; + + tabinnersq = tabinner*tabinner; + init_bitmap(tabinner,cut_coul,ncoultablebits, + masklo,maskhi,ncoulmask,ncoulshiftbits); + + int ntable = 1; + for (int i = 0; i < ncoultablebits; i++) ntable *= 2; + + // linear lookup tables of length N = 2^ncoultablebits + // stored value = value at lower edge of bin + // d values = delta from lower edge to upper edge of bin + + if (ftable) free_tables(); + + rtable = (double *) memory->smalloc(ntable*sizeof(double),"pair:rtable"); + ftable = (double *) memory->smalloc(ntable*sizeof(double),"pair:ftable"); + ctable = (double *) memory->smalloc(ntable*sizeof(double),"pair:ctable"); + etable = (double *) memory->smalloc(ntable*sizeof(double),"pair:etable"); + drtable = (double *) memory->smalloc(ntable*sizeof(double),"pair:drtable"); + dftable = (double *) memory->smalloc(ntable*sizeof(double),"pair:dftable"); + dctable = (double *) memory->smalloc(ntable*sizeof(double),"pair:dctable"); + detable = (double *) memory->smalloc(ntable*sizeof(double),"pair:detable"); + + if (cut_respa == NULL) { + vtable = ptable = dvtable = dptable = NULL; + } else { + vtable = (double *) memory->smalloc(ntable*sizeof(double),"pair:vtable"); + ptable = (double *) memory->smalloc(ntable*sizeof(double),"pair:ptable"); + dvtable = (double *) memory->smalloc(ntable*sizeof(double),"pair:dvtable"); + dptable = (double *) memory->smalloc(ntable*sizeof(double),"pair:dptable"); + } + + float rsq; + int *int_rsq = (int *) &rsq; + float minrsq; + int *int_minrsq = (int *) &minrsq; + int itablemin; + *int_minrsq = 0 << ncoulshiftbits; + *int_minrsq = *int_minrsq | maskhi; + + for (int i = 0; i < ntable; i++) { + *int_rsq = i << ncoulshiftbits; + *int_rsq = *int_rsq | masklo; + if (rsq < tabinnersq) { + *int_rsq = i << ncoulshiftbits; + *int_rsq = *int_rsq | maskhi; + } + r = sqrt(rsq); + grij = g_ewald * r; + expm2 = exp(-grij*grij); + derfc = erfc(grij); + if (cut_respa == NULL) { + rtable[i] = rsq; + ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); + ctable[i] = qqrd2e/r; + etable[i] = qqrd2e/r * derfc; + } else { + rtable[i] = rsq; + ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); + ctable[i] = 0.0; + etable[i] = qqrd2e/r * derfc; + ptable[i] = qqrd2e/r; + vtable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); + if (rsq > cut_respa[2]*cut_respa[2]) { + if (rsq < cut_respa[3]*cut_respa[3]) { + rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); + ftable[i] += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); + ctable[i] = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); + } else { + ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); + ctable[i] = qqrd2e/r; + } + } + } + minrsq = MIN(minrsq,rsq); + } + + tabinnersq = minrsq; + + int ntablem1 = ntable - 1; + + for (int i = 0; i < ntablem1; i++) { + drtable[i] = 1.0/(rtable[i+1] - rtable[i]); + dftable[i] = ftable[i+1] - ftable[i]; + dctable[i] = ctable[i+1] - ctable[i]; + detable[i] = etable[i+1] - etable[i]; + } + + if (cut_respa) { + for (int i = 0; i < ntablem1; i++) { + dvtable[i] = vtable[i+1] - vtable[i]; + dptable[i] = ptable[i+1] - ptable[i]; + } + } + + // get the delta values for the last table entries + // tables are connected periodically between 0 and ntablem1 + + drtable[ntablem1] = 1.0/(rtable[0] - rtable[ntablem1]); + dftable[ntablem1] = ftable[0] - ftable[ntablem1]; + dctable[ntablem1] = ctable[0] - ctable[ntablem1]; + detable[ntablem1] = etable[0] - etable[ntablem1]; + if (cut_respa) { + dvtable[ntablem1] = vtable[0] - vtable[ntablem1]; + dptable[ntablem1] = ptable[0] - ptable[ntablem1]; + } + + // get the correct delta values at itablemax + // smallest r is in bin itablemin + // largest r is in bin itablemax, which is itablemin-1, + // or ntablem1 if itablemin=0 + // deltas at itablemax only needed if corresponding rsq < cut*cut + // if so, compute deltas between rsq and cut*cut + + double f_tmp,c_tmp,e_tmp,p_tmp,v_tmp; + itablemin = *int_minrsq & ncoulmask; + itablemin >>= ncoulshiftbits; + int itablemax = itablemin - 1; + if (itablemin == 0) itablemax = ntablem1; + *int_rsq = itablemax << ncoulshiftbits; + *int_rsq = *int_rsq | maskhi; + + if (rsq < cut_coulsq) { + rsq = cut_coulsq; + r = sqrt(rsq); + grij = g_ewald * r; + expm2 = exp(-grij*grij); + derfc = erfc(grij); + + if (cut_respa == NULL) { + f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); + c_tmp = qqrd2e/r; + e_tmp = qqrd2e/r * derfc; + } else { + f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); + c_tmp = 0.0; + e_tmp = qqrd2e/r * derfc; + p_tmp = qqrd2e/r; + v_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); + if (rsq > cut_respa[2]*cut_respa[2]) { + if (rsq < cut_respa[3]*cut_respa[3]) { + rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); + f_tmp += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); + c_tmp = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); + } else { + f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); + c_tmp = qqrd2e/r; + } + } + } + + drtable[itablemax] = 1.0/(rsq - rtable[itablemax]); + dftable[itablemax] = f_tmp - ftable[itablemax]; + dctable[itablemax] = c_tmp - ctable[itablemax]; + detable[itablemax] = e_tmp - etable[itablemax]; + if (cut_respa) { + dvtable[itablemax] = v_tmp - vtable[itablemax]; + dptable[itablemax] = p_tmp - ptable[itablemax]; + } + } +} + +/* ---------------------------------------------------------------------- + free memory for tables used in pair computations +------------------------------------------------------------------------- */ + +void PairBuckCoul::free_tables() +{ + memory->sfree(rtable); + memory->sfree(drtable); + memory->sfree(ftable); + memory->sfree(dftable); + memory->sfree(ctable); + memory->sfree(dctable); + memory->sfree(etable); + memory->sfree(detable); + memory->sfree(vtable); + memory->sfree(dvtable); + memory->sfree(ptable); + memory->sfree(dptable); +} + +/* ---------------------------------------------------------------------- */ + +void PairBuckCoul::single(int i, int j, int itype, int jtype, + double rsq, + double factor_coul, double factor_buck, + int eflag, One &one) +{ + double f, r, r2inv, r6inv, force_coul, force_buck; + double g2 = g_ewald*g_ewald, g6 = g2*g2*g2, g8 = g6*g2, *q = atom->q; + + r = sqrt(rsq); + r2inv = 1.0/rsq; + one.eng_coul = 0.0; + if ((ewald_order&2) && (rsq < cut_coulsq)) { // coulombic + if (!ncoultablebits || rsq <= tabinnersq) { // series real space + register double x = g_ewald*r; + register double s = force->qqrd2e*q[i]*q[j], t = 1.0/(1.0+EWALD_P*x); + f = s*(1.0-factor_coul)/r; s *= g_ewald*exp(-x*x); + force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-f; + if (eflag) one.eng_coul = t-f; + } + else { // table real space + register float t = rsq; + register int k = (((int *) &t)[0] & ncoulmask)>>ncoulshiftbits; + register double f = (rsq-rtable[k])*drtable[k], qiqj = q[i]*q[j]; + t = (1.0-factor_coul)*(ctable[k]+f*dctable[k]); + force_coul = qiqj*(ftable[k]+f*dftable[k]-t); + if (eflag) one.eng_coul = qiqj*(etable[k]+f*detable[k]-t); + } + } + else force_coul = 0.0; + + one.eng_vdwl = 0.0; + if (rsq < cut_bucksq[itype][jtype]) { // buckingham + register double expr = factor_buck*exp(-sqrt(rsq)*rhoinv[itype][jtype]); + r6inv = r2inv*r2inv*r2inv; + if (ewald_order&64) { // long-range + register double x2 = g2*rsq, a2 = 1.0/x2, t = r6inv*(1.0-factor_buck); + x2 = a2*exp(-x2)*buck_c[itype][jtype]; + force_buck = buck1[itype][jtype]*r*expr- + g8*(((6.0*a2+6.0)*a2+3.0)*a2+a2)*x2*rsq+t*buck2[itype][jtype]; + if (eflag) one.eng_vdwl = buck_a[itype][jtype]*expr- + g6*((a2+1.0)*a2+0.5)*x2+t*buck_c[itype][jtype]; + } + else { // cut + force_buck = + buck1[itype][jtype]*r*expr-factor_buck*buck_c[itype][jtype]*r6inv; + if (eflag) one.eng_vdwl = buck_a[itype][jtype]*expr- + factor_buck*(buck_c[itype][jtype]*r6inv-offset[itype][jtype]); + } + } + else force_buck = 0.0; + + one.fforce = (force_coul+force_buck)*r2inv; +} + diff --git a/src/USER-EWALDN/pair_buck_coul.h b/src/USER-EWALDN/pair_buck_coul.h new file mode 100644 index 0000000000..0b6fc79208 --- /dev/null +++ b/src/USER-EWALDN/pair_buck_coul.h @@ -0,0 +1,69 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + www.cs.sandia.gov/~sjplimp/lammps.html + Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories + + 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. +------------------------------------------------------------------------- */ + +#ifndef PAIR_BUCK_COUL_H +#define PAIR_BUCK_COUL_H + +#include "pair.h" + +namespace LAMMPS_NS { + +class PairBuckCoul : public Pair { + public: + double cut_coul; + + PairBuckCoul(class LAMMPS *); + ~PairBuckCoul(); + virtual void compute(int, int); + + virtual void settings(int, char **); + void coeff(int, char **); + double init_one(int, int); + virtual void init_style(); + void write_restart(FILE *); + void read_restart(FILE *); + + virtual void write_restart_settings(FILE *); + virtual void read_restart_settings(FILE *); + virtual void single(int, int, int, int, double, double, double, int, One &); + virtual void *extract_ptr(char *); + virtual void extract_long(double *); + + void compute_inner(); + void compute_middle(); + void compute_outer(int, int); + + protected: + double cut_buck_global; + double **cut_buck, **cut_buck_read, **cut_bucksq; + double cut_coulsq; + double **buck_a_read, **buck_a, **buck_c_read, **buck_c; + double **buck1, **buck2, **buck_rho_read, **buck_rho, **rhoinv, **offset; + double *cut_respa; + double g_ewald; + int ewald_order, ewald_off; + + double tabinnersq; + double *rtable, *drtable, *ftable, *dftable, *ctable, *dctable; + double *etable, *detable, *ptable, *dptable, *vtable, *dvtable; + int ncoulshiftbits, ncoulmask; + + void options(char **arg, int order); + void allocate(); + void init_tables(); + void free_tables(); +}; + +} + +#endif diff --git a/src/USER-EWALDN/pair_lj_coul.cpp b/src/USER-EWALDN/pair_lj_coul.cpp new file mode 100644 index 0000000000..1ce093e576 --- /dev/null +++ b/src/USER-EWALDN/pair_lj_coul.cpp @@ -0,0 +1,1159 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + www.cs.sandia.gov/~sjplimp/lammps.html + Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories + + 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: Pieter J. in 't Veld (SNL) +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + module: pair_lj_coul.cpp + author: Pieter J. in 't Veld for SNL + date: September 21, 2006. + purpose: definition of short and long range lj and coulombic pair + potentials. + usage: pair_style lj/coul + long|cut|off control r^-6 contribution + long|cut|off control r^-1 contribution + rcut6 set r^-6 cut off + [rcut1] set r^-1 cut off + remarks: - rcut1 cannot be set when both contributions are set to long, + rcut1 = rcut6 when ommited + - coulombics from Macromolecules 1989, 93, 7320 +* ---------------------------------------------------------------------- */ + +#include "math.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "math_vector.h" +#include "pair_lj_coul.h" +#include "atom.h" +#include "comm.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "force.h" +#include "kspace.h" +#include "update.h" +#include "integrate.h" +#include "respa.h" +#include "memory.h" +#include "error.h" + +using namespace LAMMPS_NS; + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +#define EWALD_F 1.12837917 +#define EWALD_P 0.3275911 +#define A1 0.254829592 +#define A2 -0.284496736 +#define A3 1.421413741 +#define A4 -1.453152027 +#define A5 1.061405429 + +/* ---------------------------------------------------------------------- */ + +PairLJCoul::PairLJCoul(LAMMPS *lmp) : Pair(lmp) +{ + respa_enable = 1; + ftable = NULL; +} + +/* ---------------------------------------------------------------------- + global settings +------------------------------------------------------------------------- */ + +#define PAIR_ILLEGAL "Illegal pair_style lj/coul command" +#define PAIR_CUTOFF "Only one cut-off allowed when requesting all long" +#define PAIR_MISSING "Cut-offs missing in pair_style lj/coul" +#define PAIR_COUL_CUT "Coulombic cut not supported in pair_style lj/coul" +#define PAIR_MANY "Too many pair_style lj/coul commands" +#define PAIR_LARGEST "Using largest cut-off for lj/coul long long" +#define PAIR_MIX "Mixing forced for lj coefficients" + +void PairLJCoul::options(char **arg, int order) +{ + char *option[] = {"long", "cut", "off", NULL}; + int i; + + if (!*arg) error->all(PAIR_ILLEGAL); + for (i=0; option[i]&&strcmp(arg[0], option[i]); ++i); + switch (i) { + default: error->all(PAIR_ILLEGAL); + case 0: ewald_order |= 1<me && ewald_order&(1<<6)) error->warning(PAIR_MIX); + if (!comm->me && ewald_order==((1<<1)|(1<<6))) error->warning(PAIR_LARGEST); + if (!*(++arg)) error->all(PAIR_MISSING); + if (!((ewald_order^ewald_off)&(1<<1))) error->all(PAIR_COUL_CUT); + cut_lj_global = atof(*(arg++)); + if (*arg&&(ewald_order&0x42==0x42)) error->all(PAIR_CUTOFF); + cut_coul = *arg ? atof(*(arg++)) : cut_lj_global; + if (*arg) error->all(PAIR_MANY); + + if (allocated) { // reset explicit cuts + int i,j; + for (i = 1; i <= atom->ntypes; i++) + for (j = i+1; j <= atom->ntypes; j++) + if (setflag[i][j]) cut_lj[i][j] = cut_lj_global; + } +} + +/* ---------------------------------------------------------------------- + free all arrays +------------------------------------------------------------------------- */ + +PairLJCoul::~PairLJCoul() +{ + if (allocated) { + memory->destroy_2d_int_array(setflag); + memory->destroy_2d_double_array(cutsq); + + memory->destroy_2d_double_array(cut_lj_read); + memory->destroy_2d_double_array(cut_lj); + memory->destroy_2d_double_array(cut_ljsq); + memory->destroy_2d_double_array(epsilon_read); + memory->destroy_2d_double_array(epsilon); + memory->destroy_2d_double_array(sigma_read); + memory->destroy_2d_double_array(sigma); + memory->destroy_2d_double_array(lj1); + memory->destroy_2d_double_array(lj2); + memory->destroy_2d_double_array(lj3); + memory->destroy_2d_double_array(lj4); + memory->destroy_2d_double_array(offset); + } + if (ftable) free_tables(); +} + +/* ---------------------------------------------------------------------- + allocate all arrays +------------------------------------------------------------------------- */ + +void PairLJCoul::allocate() +{ + allocated = 1; + int n = atom->ntypes; + + setflag = memory->create_2d_int_array(n+1,n+1,"pair:setflag"); + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) + setflag[i][j] = 0; + + cutsq = memory->create_2d_double_array(n+1,n+1,"pair:cutsq"); + + cut_lj_read = memory->create_2d_double_array(n+1,n+1,"pair:cut_lj_read"); + cut_lj = memory->create_2d_double_array(n+1,n+1,"pair:cut_lj"); + cut_ljsq = memory->create_2d_double_array(n+1,n+1,"pair:cut_ljsq"); + epsilon_read = memory->create_2d_double_array(n+1,n+1,"pair:epsilon_read"); + epsilon = memory->create_2d_double_array(n+1,n+1,"pair:epsilon"); + sigma_read = memory->create_2d_double_array(n+1,n+1,"pair:sigma_read"); + sigma = memory->create_2d_double_array(n+1,n+1,"pair:sigma"); + lj1 = memory->create_2d_double_array(n+1,n+1,"pair:lj1"); + lj2 = memory->create_2d_double_array(n+1,n+1,"pair:lj2"); + lj3 = memory->create_2d_double_array(n+1,n+1,"pair:lj3"); + lj4 = memory->create_2d_double_array(n+1,n+1,"pair:lj4"); + offset = memory->create_2d_double_array(n+1,n+1,"pair:offset"); +} + +/* ---------------------------------------------------------------------- + extract protected data from object +------------------------------------------------------------------------- */ + +void *PairLJCoul::extract_ptr(char *id) +{ + char *ids[] = { + "B", "sigma", "epsilon", "ewald_order", "ewald_cut", "ewald_mix", NULL}; + void *ptrs[] = { + lj4, sigma, epsilon, &ewald_order, &cut_coul, &mix_flag, NULL}; + int i; + + for (i=0; ids[i]&&strcmp(ids[i], id); ++i); + return ptrs[i]; +} + +/* ---------------------------------------------------------------------- */ + +void PairLJCoul::extract_long(double *p_cut_coul) +{ + *p_cut_coul = cut_coul; +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs +------------------------------------------------------------------------- */ + +void PairLJCoul::coeff(int narg, char **arg) +{ + if (narg < 4 || narg > 5) error->all("Incorrect args for pair coefficients"); + if (!allocated) allocate(); + + int ilo,ihi,jlo,jhi; + force->bounds(arg[0],atom->ntypes,ilo,ihi); + force->bounds(arg[1],atom->ntypes,jlo,jhi); + + double epsilon_one = atof(arg[2]); + double sigma_one = atof(arg[3]); + + double cut_lj_one = cut_lj_global; + if (narg == 5) cut_lj_one = atof(arg[4]); + + int count = 0; + for (int i = ilo; i <= ihi; i++) { + for (int j = MAX(jlo,i); j <= jhi; j++) { + epsilon_read[i][j] = epsilon_one; + sigma_read[i][j] = sigma_one; + cut_lj_read[i][j] = cut_lj_one; + setflag[i][j] = 1; + count++; + } + } + + if (count == 0) error->all("Incorrect args for pair coefficients"); +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i +------------------------------------------------------------------------- */ + +double PairLJCoul::init_one(int i, int j) +{ + if ((ewald_order&(1<<6))||(setflag[i][j] == 0)) { + epsilon[i][j] = mix_energy(epsilon_read[i][i],epsilon_read[j][j], + sigma_read[i][i],sigma_read[j][j]); + sigma[i][j] = mix_distance(sigma_read[i][i],sigma_read[j][j]); + if (ewald_order&(1<<6)) + cut_lj[i][j] = cut_lj_global; + else + cut_lj[i][j] = mix_distance(cut_lj_read[i][i],cut_lj_read[j][j]); + } + else { + sigma[i][j] = sigma_read[i][j]; + epsilon[i][j] = epsilon_read[i][j]; + cut_lj[i][j] = cut_lj_read[i][j]; + } + + double cut = MAX(cut_lj[i][j], cut_coul); + cutsq[i][j] = cut*cut; + cut_ljsq[i][j] = cut_lj[i][j] * cut_lj[i][j]; + + lj1[i][j] = 48.0 * epsilon[i][j] * pow(sigma[i][j],12.0); + lj2[i][j] = 24.0 * epsilon[i][j] * pow(sigma[i][j],6.0); + lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); + lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); + + if (offset_flag) { + double ratio = sigma[i][j] / cut_lj[i][j]; + offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); + } else offset[i][j] = 0.0; + + cutsq[j][i] = cutsq[i][j]; + cut_ljsq[j][i] = cut_ljsq[i][j]; + lj1[j][i] = lj1[i][j]; + lj2[j][i] = lj2[i][j]; + lj3[j][i] = lj3[i][j]; + lj4[j][i] = lj4[i][j]; + offset[j][i] = offset[i][j]; + + return cut; +} + +/* ---------------------------------------------------------------------- + init specific to this pair style +------------------------------------------------------------------------- */ + +void PairLJCoul::init_style() +{ + char *style1[] = {"ewald", "ewald/n", "pppm", NULL}; + char *style6[] = {"ewald/n", NULL}; + int i,j; + + // require an atom style with charge defined + + //if (atom->charge_allow == 0) + //error->all("Must use charged atom style with this pair style"); + if (!atom->q_flag && (ewald_order&(1<<1))) + error->all( + "Invoking coulombic in pair style lj/coul requires atom attribute q"); + + cut_coulsq = cut_coul * cut_coul; + + // set & error check interior rRESPA cutoffs + + if (strcmp(update->integrate_style,"respa") == 0) { + if (((Respa *) update->integrate)->level_inner >= 0) { + cut_respa = ((Respa *) update->integrate)->cutoff; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) + if (MIN(cut_lj[i][j],cut_coul) < cut_respa[3]) + error->all("Pair cutoff < Respa interior cutoff"); + } + } else cut_respa = NULL; + + // ensure use of KSpace long-range solver, set g_ewald + + if (ewald_order&(1<<1)) { // r^-1 kspace + if (force->kspace == NULL) + error->all("Pair style is incompatible with KSpace style"); + for (i=0; style1[i]&&strcmp(force->kspace_style, style1[i]); ++i); + if (!style1[i]) error->all("Pair style is incompatible with KSpace style"); + } + if (ewald_order&(1<<6)) { // r^-6 kspace + if (force->kspace == NULL) + error->all("Pair style is incompatible with KSpace style"); + for (i=0; style6[i]&&strcmp(force->kspace_style, style6[i]); ++i); + if (!style6[i]) error->all("Pair style is incompatible with KSpace style"); + } + if (force->kspace) g_ewald = force->kspace->g_ewald; + + // setup force tables + + if (ncoultablebits) init_tables(); +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file +------------------------------------------------------------------------- */ + +void PairLJCoul::write_restart(FILE *fp) +{ + write_restart_settings(fp); + + int i,j; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) { + fwrite(&setflag[i][j],sizeof(int),1,fp); + if (setflag[i][j]) { + fwrite(&epsilon_read[i][j],sizeof(double),1,fp); + fwrite(&sigma_read[i][j],sizeof(double),1,fp); + fwrite(&cut_lj_read[i][j],sizeof(double),1,fp); + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts +------------------------------------------------------------------------- */ + +void PairLJCoul::read_restart(FILE *fp) +{ + read_restart_settings(fp); + + allocate(); + + int i,j; + int me = comm->me; + for (i = 1; i <= atom->ntypes; i++) + for (j = i; j <= atom->ntypes; j++) { + if (me == 0) fread(&setflag[i][j],sizeof(int),1,fp); + MPI_Bcast(&setflag[i][j],1,MPI_INT,0,world); + if (setflag[i][j]) { + if (me == 0) { + fread(&epsilon_read[i][j],sizeof(double),1,fp); + fread(&sigma_read[i][j],sizeof(double),1,fp); + fread(&cut_lj_read[i][j],sizeof(double),1,fp); + } + MPI_Bcast(&epsilon_read[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&sigma_read[i][j],1,MPI_DOUBLE,0,world); + MPI_Bcast(&cut_lj_read[i][j],1,MPI_DOUBLE,0,world); + } + } +} + +/* ---------------------------------------------------------------------- + proc 0 writes to restart file +------------------------------------------------------------------------- */ + +void PairLJCoul::write_restart_settings(FILE *fp) +{ + fwrite(&cut_lj_global,sizeof(double),1,fp); + fwrite(&cut_coul,sizeof(double),1,fp); + fwrite(&offset_flag,sizeof(int),1,fp); + fwrite(&mix_flag,sizeof(int),1,fp); + fwrite(&ewald_order,sizeof(int),1,fp); +} + +/* ---------------------------------------------------------------------- + proc 0 reads from restart file, bcasts +------------------------------------------------------------------------- */ + +void PairLJCoul::read_restart_settings(FILE *fp) +{ + if (comm->me == 0) { + fread(&cut_lj_global,sizeof(double),1,fp); + fread(&cut_coul,sizeof(double),1,fp); + fread(&offset_flag,sizeof(int),1,fp); + fread(&mix_flag,sizeof(int),1,fp); + fread(&ewald_order,sizeof(int),1,fp); + } + MPI_Bcast(&cut_lj_global,1,MPI_DOUBLE,0,world); + MPI_Bcast(&cut_coul,1,MPI_DOUBLE,0,world); + MPI_Bcast(&offset_flag,1,MPI_INT,0,world); + MPI_Bcast(&mix_flag,1,MPI_INT,0,world); + MPI_Bcast(&ewald_order,1,MPI_INT,0,world); +} + +/* ---------------------------------------------------------------------- + compute pair interactions +------------------------------------------------------------------------- */ + +void PairLJCoul::compute(int eflag, int vflag) +{ + double **x = atom->x, *x0 = x[0]; + double **f = atom->f, *f0 = f[0], *fi = f0; + double *q = atom->q; + int *type = atom->type; + int nlocal = atom->nlocal; + int nall = atom->nlocal + atom->nghost; + double *special_coul = force->special_coul; + double *special_lj = force->special_lj; + int newton_pair = force->newton_pair; + double qqrd2e = force->qqrd2e; + + int i, j, order1 = ewald_order&(1<<1), order6 = ewald_order&(1<<6); + int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni; + double qi, qri, *cutsqi, *cut_ljsqi, *lj1i, *lj2i, *lj3i, *lj4i, *offseti; + double rsq, r2inv, force_coul, force_lj, fforce, factor; + double g2 = g_ewald*g_ewald, g6 = g2*g2*g2, g8 = g6*g2; + vector xi, d; + + eng_vdwl = eng_coul = 0.0; // reset energy&virial + if (vflag) memset(virial, 0, sizeof(shape)); + ineighn = (ineigh = list->ilist)+list->inum; + + for (; ineighfirstneigh[i])+list->numneigh[i]; + + for (; jneigh= cutsqi[typej = type[j]]) continue; + r2inv = 1.0/rsq; + + factor = newton_pair || j>ncoulshiftbits; + register double f = (rsq-rtable[k])*drtable[k], qiqj = qi*q[j]; + if (ni < 0) { + force_coul = qiqj*(ftable[k]+f*dftable[k]); + if (eflag) eng_coul += factor*qiqj*(etable[k]+f*detable[k]); + } + else { // special case + t = (1.0-special_coul[ni])*(ctable[k]+f*dctable[k]); + force_coul = qiqj*(ftable[k]+f*dftable[k]-t); + if (eflag) eng_coul += factor*qiqj*(etable[k]+f*detable[k]-t); + } + } + } + else force_coul = 0.0; + + if (rsq < cut_ljsqi[typej]) { // lj + if (order6) { // long-range lj + register double rn = r2inv*r2inv*r2inv; + register double x2 = g2*rsq, a2 = 1.0/x2; + x2 = a2*exp(-x2)*lj4i[typej]; + if (ni < 0) { + force_lj = + (rn*=rn)*lj1i[typej]-g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq; + if (eflag) eng_vdwl += + factor*(rn*lj3i[typej]-g6*((a2+1.0)*a2+0.5)*x2); + } + else { // special case + register double f = special_lj[ni], t = rn*(1.0-f); + force_lj = f*(rn *= rn)*lj1i[typej]- + g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq+t*lj2i[typej]; + if (eflag) eng_vdwl += factor*( + f*rn*lj3i[typej]-g6*((a2+1.0)*a2+0.5)*x2+t*lj4i[typej]); + } + } + else { // cut lj + register double rn = r2inv*r2inv*r2inv; + if (ni < 0) { + force_lj = rn*(rn*lj1i[typej]-lj2i[typej]); + if (eflag) eng_vdwl += factor*( + rn*(rn*lj3i[typej]-lj4i[typej])-offseti[typej]); + } + else { // special case + register double f = special_lj[ni]; + force_lj = f*rn*(rn*lj1i[typej]-lj2i[typej]); + if (eflag) eng_vdwl += f*factor*( + rn*(rn*lj3i[typej]-lj4i[typej])-offseti[typej]); + } + } + } + else force_lj = 0.0; + + fforce = (force_coul+force_lj)*r2inv; // force and virial + if (vflag==1) { + if (newton_pair || j < nlocal) { + register double f = d[0]*fforce, *fj = f0+(j+(j<<1)); + fi[0] += f; fj[0] -= f; + virial[0] += f*d[0]; virial[3] += f*d[1]; + fi[1] += f = d[1]*fforce; fj[1] -= f; + virial[1] += f*d[1]; virial[5] += f*d[2]; + fi[2] += f = d[2]*fforce; fj[2] -= f; + virial[2] += f*d[2]; virial[4] += f*d[0]; + } + else { + register double f = d[0]*fforce; + fi[0] += f; virial[0] += (f *= 0.5)*d[0]; virial[3] += f*d[1]; + fi[1] += f = d[1]*fforce; virial[1] += 0.5*f*d[1]; + fi[2] += f = d[2]*fforce; virial[2] += (f *= 0.5)*d[2]; + virial[4] += f*d[0]; virial[5] += f*d[1]; + } + } + else if (newton_pair || j < nlocal) { + register double *fj = f0+(j+(j<<1)), f; + fi[0] += f = d[0]*fforce; fj[0] -= f; + fi[1] += f = d[1]*fforce; fj[1] -= f; + fi[2] += f = d[2]*fforce; fj[2] -= f; + } + else { + fi[0] += d[0]*fforce; + fi[1] += d[1]*fforce; + fi[2] += d[2]*fforce; + } + } + } + if (vflag == 2) virial_compute(); +} + +/* ---------------------------------------------------------------------- */ + +void PairLJCoul::compute_inner() +{ + double rsq, r2inv, force_coul, force_lj, fforce; + + int *type = atom->type; + int nlocal = atom->nlocal; + int nall = atom->nlocal + atom->nghost; + double *x0 = atom->x[0], *f0 = atom->f[0], *fi = f0, *q = atom->q; + double *special_coul = force->special_coul; + double *special_lj = force->special_lj; + int newton_pair = force->newton_pair; + double qqrd2e = force->qqrd2e; + + double cut_out_on = cut_respa[0]; + double cut_out_off = cut_respa[1]; + + double cut_out_diff = cut_out_off - cut_out_on; + double cut_out_on_sq = cut_out_on*cut_out_on; + double cut_out_off_sq = cut_out_off*cut_out_off; + + int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni; + int i, j, order1 = (ewald_order|(ewald_off^-1))&(1<<1); + double qri, *cut_ljsqi, *lj1i, *lj2i, *offseti; + vector xi, d; + + ineighn = (ineigh = list->ilist)+list->inum; + + for (; ineighfirstneigh[i])+list->numneigh[i]; + + for (; jneigh= cut_out_off_sq) continue; + r2inv = 1.0/rsq; + + if (order1 && (rsq < cut_coulsq)) // coulombic + force_coul = ni<0 ? + qri*q[j]*sqrt(r2inv) : qri*q[j]*sqrt(r2inv)*special_coul[ni]; + + if (rsq < cut_ljsqi[typej = type[j]]) { // lennard-jones + register double rn = r2inv*r2inv*r2inv; + force_lj = ni<0 ? + rn*(rn*lj1i[typej]-lj2i[typej]) : + rn*(rn*lj1i[typej]-lj2i[typej])*special_lj[ni]; + } + else force_lj = 0.0; + + fforce = (force_coul + force_lj) * r2inv; + + if (rsq > cut_out_on_sq) { // switching + register double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; + fforce *= 1.0 + rsw*rsw*(2.0*rsw-3.0); + } + + if (newton_pair || j < nlocal) { // force update + register double *fj = f0+(j+(j<<1)), f; + fi[0] += f = d[0]*fforce; fj[0] -= f; + fi[1] += f = d[1]*fforce; fj[1] -= f; + fi[2] += f = d[2]*fforce; fj[2] -= f; + } + else { + fi[0] += d[0]*fforce; + fi[1] += d[1]*fforce; + fi[2] += d[2]*fforce; + } + } + } +} + +/* ---------------------------------------------------------------------- */ + +void PairLJCoul::compute_middle() +{ + double rsq, r2inv, force_coul, force_lj, fforce; + + int *type = atom->type; + int nlocal = atom->nlocal; + int nall = atom->nlocal + atom->nghost; + double *x0 = atom->x[0], *f0 = atom->f[0], *fi = f0, *q = atom->q; + double *special_coul = force->special_coul; + double *special_lj = force->special_lj; + int newton_pair = force->newton_pair; + double qqrd2e = force->qqrd2e; + + double cut_in_off = cut_respa[0]; + double cut_in_on = cut_respa[1]; + double cut_out_on = cut_respa[2]; + double cut_out_off = cut_respa[3]; + + double cut_in_diff = cut_in_on - cut_in_off; + double cut_out_diff = cut_out_off - cut_out_on; + double cut_in_off_sq = cut_in_off*cut_in_off; + double cut_in_on_sq = cut_in_on*cut_in_on; + double cut_out_on_sq = cut_out_on*cut_out_on; + double cut_out_off_sq = cut_out_off*cut_out_off; + + int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni; + int i, j, order1 = (ewald_order|(ewald_off^-1))&(1<<1); + double qri, *cut_ljsqi, *lj1i, *lj2i, *offseti; + vector xi, d; + + ineighn = (ineigh = list->ilist)+list->inum; + + for (; ineighfirstneigh[i])+list->numneigh[i]; + + for (; jneigh= cut_out_off_sq) continue; + if (rsq <= cut_in_off_sq) continue; + r2inv = 1.0/rsq; + + if (order1 && (rsq < cut_coulsq)) // coulombic + force_coul = ni<0 ? + qri*q[j]*sqrt(r2inv) : qri*q[j]*sqrt(r2inv)*special_coul[ni]; + + if (rsq < cut_ljsqi[typej = type[j]]) { // lennard-jones + register double rn = r2inv*r2inv*r2inv; + force_lj = ni<0 ? + rn*(rn*lj1i[typej]-lj2i[typej]) : + rn*(rn*lj1i[typej]-lj2i[typej])*special_lj[ni]; + } + else force_lj = 0.0; + + fforce = (force_coul + force_lj) * r2inv; + + if (rsq < cut_in_on_sq) { // switching + register double rsw = (sqrt(rsq) - cut_in_off)/cut_in_diff; + fforce *= rsw*rsw*(3.0 - 2.0*rsw); + } + if (rsq > cut_out_on_sq) { + register double rsw = (sqrt(rsq) - cut_out_on)/cut_out_diff; + fforce *= 1.0 + rsw*rsw*(2.0*rsw-3.0); + } + + if (newton_pair || j < nlocal) { // force update + register double *fj = f0+(j+(j<<1)), f; + fi[0] += f = d[0]*fforce; fj[0] -= f; + fi[1] += f = d[1]*fforce; fj[1] -= f; + fi[2] += f = d[2]*fforce; fj[2] -= f; + } + else { + fi[0] += d[0]*fforce; + fi[1] += d[1]*fforce; + fi[2] += d[2]*fforce; + } + } + } +} + +/* ---------------------------------------------------------------------- */ + +void PairLJCoul::compute_outer(int eflag, int vflag) +{ + double **x = atom->x, *x0 = x[0]; + double **f = atom->f, *f0 = f[0], *fi = f0; + double *q = atom->q; + int *type = atom->type; + int nlocal = atom->nlocal; + int nall = atom->nlocal + atom->nghost; + double *special_coul = force->special_coul; + double *special_lj = force->special_lj; + int newton_pair = force->newton_pair; + double qqrd2e = force->qqrd2e; + + int i, j, order1 = ewald_order&(1<<1), order6 = ewald_order&(1<<6); + int *ineigh, *ineighn, *jneigh, *jneighn, typei, typej, ni, respa_flag; + double qi, qri, *cutsqi, *cut_ljsqi, *lj1i, *lj2i, *lj3i, *lj4i, *offseti; + double rsq, r2inv, force_coul, force_lj, fforce, factor; + double g2 = g_ewald*g_ewald, g6 = g2*g2*g2, g8 = g6*g2; + double respa_lj, respa_coul, frespa; + vector xi, d; + + double cut_in_off = cut_respa[2]; + double cut_in_on = cut_respa[3]; + + double cut_in_diff = cut_in_on - cut_in_off; + double cut_in_off_sq = cut_in_off*cut_in_off; + double cut_in_on_sq = cut_in_on*cut_in_on; + + eng_vdwl = eng_coul = 0.0; // reset energy&virial + if (vflag) memset(virial, 0, sizeof(shape)); + + ineighn = (ineigh = list->ilist)+list->inum; + + for (; ineighfirstneigh[i])+list->numneigh[i]; + + for (; jneigh= cutsqi[typej = type[j]]) continue; + r2inv = 1.0/rsq; + + factor = newton_pair || jcut_in_off_sq)&&(rsq>ncoulshiftbits; + register double f = (rsq-rtable[k])*drtable[k], qiqj = qi*q[j]; + if (ni < 0) { + force_coul = qiqj*(ftable[k]+f*dftable[k]); + if (eflag) eng_coul += factor*qiqj*(etable[k]+f*detable[k]); + } + else { // correct for special + t = (1.0-special_coul[ni])*(ctable[k]+f*dctable[k]); + force_coul = qiqj*(ftable[k]+f*dftable[k]-t); + if (eflag) eng_coul += factor*qiqj*(etable[k]+f*detable[k]-t); + } + } + } + else force_coul = respa_coul = 0.0; + + if (rsq < cut_ljsqi[typej]) { // lennard-jones + register double rn = r2inv*r2inv*r2inv; + if (respa_flag) respa_lj = ni<0 ? // correct for respa + frespa*rn*(rn*lj1i[typej]-lj2i[typej]) : + frespa*rn*(rn*lj1i[typej]-lj2i[typej])*special_lj[ni]; + if (order6) { // long-range form + register double x2 = g2*rsq, a2 = 1.0/x2; + x2 = a2*exp(-x2)*lj4i[typej]; + if (ni < 0) { + force_lj = + (rn*=rn)*lj1i[typej]-g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq; + if (eflag) eng_vdwl += + factor*(rn*lj3i[typej]-g6*((a2+1.0)*a2+0.5)*x2); + } + else { // correct for special + register double f = special_lj[ni], t = rn*(1.0-f); + force_lj = f*(rn *= rn)*lj1i[typej]- + g8*(((6.0*a2+6.0)*a2+3.0)*a2+1.0)*x2*rsq+t*lj2i[typej]; + if (eflag) eng_vdwl += factor*( + f*rn*lj3i[typej]-g6*((a2+1.0)*a2+0.5)*x2+t*lj4i[typej]); + } + } + else { // cut form + if (ni < 0) { + force_lj = rn*(rn*lj1i[typej]-lj2i[typej]); + if (eflag) eng_vdwl += factor*( + rn*(rn*lj3i[typej]-lj4i[typej])-offseti[typej]); + } + else { // correct for special + register double f = special_lj[ni]; + force_lj = f*rn*(rn*lj1i[typej]-lj2i[typej]); + if (eflag) eng_vdwl += f*factor*( + rn*(rn*lj3i[typej]-lj4i[typej])-offseti[typej]); + } + } + } + else force_lj = respa_lj = 0.0; + + fforce = (force_coul+force_lj)*r2inv; // force and virial + frespa = fforce-(respa_coul+respa_lj)*r2inv; + if (newton_pair || j < nlocal) { + register double *fj = f0+(j+(j<<1)), f; + fi[0] += f = d[0]*frespa; fj[0] -= f; + fi[1] += f = d[1]*frespa; fj[1] -= f; + fi[2] += f = d[2]*frespa; fj[2] -= f; + if (vflag==1) { + virial[0] += (f = d[0]*fforce)*d[0]; virial[3] += f*d[1]; + virial[1] += (f = d[1]*fforce)*d[1]; virial[5] += f*d[2]; + virial[2] += (f = d[2]*fforce)*d[2]; virial[4] += f*d[0]; + } + } + else { + fi[0] += d[0]*frespa; + fi[1] += d[1]*frespa; + fi[2] += d[2]*frespa; + if (vflag==1) { + register double f; + virial[0] += (f = 0.5*d[0]*fforce)*d[0]; virial[3] += f*d[1]; + virial[1] += (f = 0.5*d[1]*fforce)*d[1]; virial[5] += f*d[2]; + virial[2] += (f = 0.5*d[2]*fforce)*d[2]; virial[4] += f*d[0]; + } + } + } + } + if (vflag == 2) virial_compute(); +} + +/* ---------------------------------------------------------------------- + setup force tables used in compute routines +------------------------------------------------------------------------- */ + +void PairLJCoul::init_tables() +{ + int masklo,maskhi; + double r,grij,expm2,derfc,rsw; + double qqrd2e = force->qqrd2e; + + tabinnersq = tabinner*tabinner; + init_bitmap(tabinner,cut_coul,ncoultablebits, + masklo,maskhi,ncoulmask,ncoulshiftbits); + + int ntable = 1; + for (int i = 0; i < ncoultablebits; i++) ntable *= 2; + + // linear lookup tables of length N = 2^ncoultablebits + // stored value = value at lower edge of bin + // d values = delta from lower edge to upper edge of bin + + if (ftable) free_tables(); + + rtable = (double *) memory->smalloc(ntable*sizeof(double),"pair:rtable"); + ftable = (double *) memory->smalloc(ntable*sizeof(double),"pair:ftable"); + ctable = (double *) memory->smalloc(ntable*sizeof(double),"pair:ctable"); + etable = (double *) memory->smalloc(ntable*sizeof(double),"pair:etable"); + drtable = (double *) memory->smalloc(ntable*sizeof(double),"pair:drtable"); + dftable = (double *) memory->smalloc(ntable*sizeof(double),"pair:dftable"); + dctable = (double *) memory->smalloc(ntable*sizeof(double),"pair:dctable"); + detable = (double *) memory->smalloc(ntable*sizeof(double),"pair:detable"); + + if (cut_respa == NULL) { + vtable = ptable = dvtable = dptable = NULL; + } else { + vtable = (double *) memory->smalloc(ntable*sizeof(double),"pair:vtable"); + ptable = (double *) memory->smalloc(ntable*sizeof(double),"pair:ptable"); + dvtable = (double *) memory->smalloc(ntable*sizeof(double),"pair:dvtable"); + dptable = (double *) memory->smalloc(ntable*sizeof(double),"pair:dptable"); + } + + float rsq; + int *int_rsq = (int *) &rsq; + float minrsq; + int *int_minrsq = (int *) &minrsq; + int itablemin; + *int_minrsq = 0 << ncoulshiftbits; + *int_minrsq = *int_minrsq | maskhi; + + for (int i = 0; i < ntable; i++) { + *int_rsq = i << ncoulshiftbits; + *int_rsq = *int_rsq | masklo; + if (rsq < tabinnersq) { + *int_rsq = i << ncoulshiftbits; + *int_rsq = *int_rsq | maskhi; + } + r = sqrt(rsq); + grij = g_ewald * r; + expm2 = exp(-grij*grij); + derfc = erfc(grij); + if (cut_respa == NULL) { + rtable[i] = rsq; + ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); + ctable[i] = qqrd2e/r; + etable[i] = qqrd2e/r * derfc; + } else { + rtable[i] = rsq; + ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); + ctable[i] = 0.0; + etable[i] = qqrd2e/r * derfc; + ptable[i] = qqrd2e/r; + vtable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); + if (rsq > cut_respa[2]*cut_respa[2]) { + if (rsq < cut_respa[3]*cut_respa[3]) { + rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); + ftable[i] += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); + ctable[i] = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); + } else { + ftable[i] = qqrd2e/r * (derfc + EWALD_F*grij*expm2); + ctable[i] = qqrd2e/r; + } + } + } + minrsq = MIN(minrsq,rsq); + } + + tabinnersq = minrsq; + + int ntablem1 = ntable - 1; + + for (int i = 0; i < ntablem1; i++) { + drtable[i] = 1.0/(rtable[i+1] - rtable[i]); + dftable[i] = ftable[i+1] - ftable[i]; + dctable[i] = ctable[i+1] - ctable[i]; + detable[i] = etable[i+1] - etable[i]; + } + + if (cut_respa) { + for (int i = 0; i < ntablem1; i++) { + dvtable[i] = vtable[i+1] - vtable[i]; + dptable[i] = ptable[i+1] - ptable[i]; + } + } + + // get the delta values for the last table entries + // tables are connected periodically between 0 and ntablem1 + + drtable[ntablem1] = 1.0/(rtable[0] - rtable[ntablem1]); + dftable[ntablem1] = ftable[0] - ftable[ntablem1]; + dctable[ntablem1] = ctable[0] - ctable[ntablem1]; + detable[ntablem1] = etable[0] - etable[ntablem1]; + if (cut_respa) { + dvtable[ntablem1] = vtable[0] - vtable[ntablem1]; + dptable[ntablem1] = ptable[0] - ptable[ntablem1]; + } + + // get the correct delta values at itablemax + // smallest r is in bin itablemin + // largest r is in bin itablemax, which is itablemin-1, + // or ntablem1 if itablemin=0 + // deltas at itablemax only needed if corresponding rsq < cut*cut + // if so, compute deltas between rsq and cut*cut + + double f_tmp,c_tmp,e_tmp,p_tmp,v_tmp; + itablemin = *int_minrsq & ncoulmask; + itablemin >>= ncoulshiftbits; + int itablemax = itablemin - 1; + if (itablemin == 0) itablemax = ntablem1; + *int_rsq = itablemax << ncoulshiftbits; + *int_rsq = *int_rsq | maskhi; + + if (rsq < cut_coulsq) { + rsq = cut_coulsq; + r = sqrt(rsq); + grij = g_ewald * r; + expm2 = exp(-grij*grij); + derfc = erfc(grij); + + if (cut_respa == NULL) { + f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); + c_tmp = qqrd2e/r; + e_tmp = qqrd2e/r * derfc; + } else { + f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2 - 1.0); + c_tmp = 0.0; + e_tmp = qqrd2e/r * derfc; + p_tmp = qqrd2e/r; + v_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); + if (rsq > cut_respa[2]*cut_respa[2]) { + if (rsq < cut_respa[3]*cut_respa[3]) { + rsw = (r - cut_respa[2])/(cut_respa[3] - cut_respa[2]); + f_tmp += qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); + c_tmp = qqrd2e/r * rsw*rsw*(3.0 - 2.0*rsw); + } else { + f_tmp = qqrd2e/r * (derfc + EWALD_F*grij*expm2); + c_tmp = qqrd2e/r; + } + } + } + + drtable[itablemax] = 1.0/(rsq - rtable[itablemax]); + dftable[itablemax] = f_tmp - ftable[itablemax]; + dctable[itablemax] = c_tmp - ctable[itablemax]; + detable[itablemax] = e_tmp - etable[itablemax]; + if (cut_respa) { + dvtable[itablemax] = v_tmp - vtable[itablemax]; + dptable[itablemax] = p_tmp - ptable[itablemax]; + } + } +} + +/* ---------------------------------------------------------------------- + free memory for tables used in pair computations +------------------------------------------------------------------------- */ + +void PairLJCoul::free_tables() +{ + memory->sfree(rtable); + memory->sfree(drtable); + memory->sfree(ftable); + memory->sfree(dftable); + memory->sfree(ctable); + memory->sfree(dctable); + memory->sfree(etable); + memory->sfree(detable); + memory->sfree(vtable); + memory->sfree(dvtable); + memory->sfree(ptable); + memory->sfree(dptable); +} + +/* ---------------------------------------------------------------------- */ + +void PairLJCoul::single(int i, int j, int itype, int jtype, + double rsq, + double factor_coul, double factor_lj, + int eflag, One &one) +{ + double r2inv, r6inv, force_coul, force_lj; + double g2 = g_ewald*g_ewald, g6 = g2*g2*g2, g8 = g6*g2, *q = atom->q; + + r2inv = 1.0/rsq; + one.eng_coul = 0.0; + if ((ewald_order&2) && (rsq < cut_coulsq)) { // coulombic + if (!ncoultablebits || rsq <= tabinnersq) { // series real space + register double r = sqrt(rsq), x = g_ewald*r; + register double s = force->qqrd2e*q[i]*q[j], t = 1.0/(1.0+EWALD_P*x); + r = s*(1.0-factor_coul)/r; s *= g_ewald*exp(-x*x); + force_coul = (t *= ((((t*A5+A4)*t+A3)*t+A2)*t+A1)*s/x)+EWALD_F*s-r; + if (eflag) one.eng_coul = t-r; + } + else { // table real space + register float t = rsq; + register int k = (((int *) &t)[0] & ncoulmask)>>ncoulshiftbits; + register double f = (rsq-rtable[k])*drtable[k], qiqj = q[i]*q[j]; + t = (1.0-factor_coul)*(ctable[k]+f*dctable[k]); + force_coul = qiqj*(ftable[k]+f*dftable[k]-t); + if (eflag) one.eng_coul = qiqj*(etable[k]+f*detable[k]-t); + } + } + else force_coul = 0.0; + + one.eng_vdwl = 0.0; + if (rsq < cut_ljsq[itype][jtype]) { // lennard-jones + r6inv = r2inv*r2inv*r2inv; + if (ewald_order&64) { // long-range + register double x2 = g2*rsq, a2 = 1.0/x2, t = r6inv*(1.0-factor_lj); + x2 = a2*exp(-x2)*lj4[itype][jtype]; + force_lj = factor_lj*(r6inv *= r6inv)*lj1[itype][jtype]- + g8*(((6.0*a2+6.0)*a2+3.0)*a2+a2)*x2*rsq+t*lj2[itype][jtype]; + if (eflag) one.eng_vdwl = factor_lj*r6inv*lj3[itype][jtype]- + g6*((a2+1.0)*a2+0.5)*x2+t*lj4[itype][jtype]; + } + else { // cut + force_lj = factor_lj*r6inv*(lj1[itype][jtype]*r6inv-lj2[itype][jtype]); + if (eflag) one.eng_vdwl = factor_lj*(r6inv*(r6inv*lj3[itype][jtype]- + lj4[itype][jtype])-offset[itype][jtype]); + } + } + else force_lj = 0.0; + + one.fforce = (force_coul+force_lj)*r2inv; +} + diff --git a/src/USER-EWALDN/pair_lj_coul.h b/src/USER-EWALDN/pair_lj_coul.h new file mode 100644 index 0000000000..01b43623eb --- /dev/null +++ b/src/USER-EWALDN/pair_lj_coul.h @@ -0,0 +1,68 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + www.cs.sandia.gov/~sjplimp/lammps.html + Steve Plimpton, sjplimp@sandia.gov, Sandia National Laboratories + + 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. +------------------------------------------------------------------------- */ + +#ifndef PAIR_LJ_COUL_H +#define PAIR_LJ_COUL_H + +#include "pair.h" + +namespace LAMMPS_NS { + +class PairLJCoul : public Pair { + public: + double cut_coul; + + PairLJCoul(class LAMMPS *); + virtual ~PairLJCoul(); + virtual void compute(int, int); + virtual void settings(int, char **); + void coeff(int, char **); + double init_one(int, int); + virtual void init_style(); + void write_restart(FILE *); + void read_restart(FILE *); + + virtual void write_restart_settings(FILE *); + virtual void read_restart_settings(FILE *); + virtual void single(int, int, int, int, double, double, double, int, One &); + virtual void *extract_ptr(char *); + virtual void extract_long(double *); + + void compute_inner(); + void compute_middle(); + void compute_outer(int, int); + + protected: + double cut_lj_global; + double **cut_lj, **cut_lj_read, **cut_ljsq; + double cut_coulsq; + double **epsilon_read, **epsilon, **sigma_read, **sigma; + double **lj1, **lj2, **lj3, **lj4, **offset; + double *cut_respa; + double g_ewald; + int ewald_order, ewald_off; + + double tabinnersq; + double *rtable, *drtable, *ftable, *dftable, *ctable, *dctable; + double *etable, *detable, *ptable, *dptable, *vtable, *dvtable; + int ncoulshiftbits, ncoulmask; + + void options(char **arg, int order); + void allocate(); + void init_tables(); + void free_tables(); +}; + +} + +#endif diff --git a/src/USER-EWALDN/style_user_ewaldn.h b/src/USER-EWALDN/style_user_ewaldn.h new file mode 100644 index 0000000000..3eafa50744 --- /dev/null +++ b/src/USER-EWALDN/style_user_ewaldn.h @@ -0,0 +1,30 @@ +/* ---------------------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifdef KSpaceInclude +#include "ewald_n.h" +#endif + +#ifdef KSpaceClass +KSpaceStyle(ewald/n,EwaldN) +#endif + +#ifdef PairInclude +#include "pair_buck_coul.h" +#include "pair_lj_coul.h" +#endif + +#ifdef PairClass +PairStyle(buck/coul,PairBuckCoul) +PairStyle(lj/coul,PairLJCoul) +#endif diff --git a/src/style_user_ackland.h b/src/style_user_ackland.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/style_user_ewaldn.h b/src/style_user_ewaldn.h new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/style_user_packages.h b/src/style_user_packages.h new file mode 100644 index 0000000000..f11fd7849c --- /dev/null +++ b/src/style_user_packages.h @@ -0,0 +1,18 @@ +/* ---------------------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +// style flies for user-contributed packages +// see the README files in individual user-package directories for details + +#include "style_user_ackland.h" +#include "style_user_ewaldn.h"