diff --git a/doc/src/Eqs/pair_coul_shield.jpg b/doc/src/Eqs/pair_coul_shield.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..83eb059ac800f604eeb2f8628735fa468914c946
Binary files /dev/null and b/doc/src/Eqs/pair_coul_shield.jpg differ
diff --git a/doc/src/Eqs/pair_coul_shield.tex b/doc/src/Eqs/pair_coul_shield.tex
new file mode 100644
index 0000000000000000000000000000000000000000..bd92fb680165fcc59eaf88ce8faead7171e79f91
--- /dev/null
+++ b/doc/src/Eqs/pair_coul_shield.tex
@@ -0,0 +1,33 @@
+\documentclass[aps,pr,onecolumn,superscriptaddress,noshowpacs,a4paper,15pt]{revtex4}
+\pdfoutput=1
+\bibliographystyle{apsrev4}
+\usepackage{color}
+\usepackage{dcolumn} %Align table columns on decimal point
+\usepackage{amssymb}
+\usepackage{amsmath}
+\usepackage{amsthm}
+\usepackage{graphicx}
+\usepackage[pdftex]{hyperref}
+\hypersetup{colorlinks=true,citecolor=blue,linkcolor=red,urlcolor=blue}
+\usepackage[all]{hypcap}
+\newcommand{\red}{\color{red}}
+\newcommand{\blue}{\color{blue}}
+\definecolor{green}{rgb}{0,0.5,0}
+\newcommand{\green}{\color{green}}
+\newcommand{\white}{\color{white}}
+%\newcommand{\cite}[1]{\hspace{-1 ex} % \nocite{#1}\citenum{#1}}
+\thickmuskip=0.5\thickmuskip %shorter spaces in math
+
+\begin{document}
+\begingroup
+\Large
+\begin{eqnarray*}
+  E & = & \frac{1}{2} \sum_i \sum_{j \neq i} V_{ij} \\[15pt]
+  V_{ij} & = & {\rm Tap}(r_{ij})\frac{\kappa q_i q_j}{\sqrt[3]{r_{ij}^3+(1/\lambda_{ij})^3}}\\[15pt]
+  {\rm Tap}(r_{ij}) & = & 20\left ( \frac{r_{ij}}{R_{cut}} \right )^7 -
+                          70\left ( \frac{r_{ij}}{R_{cut}} \right )^6 +
+                          84\left ( \frac{r_{ij}}{R_{cut}} \right )^5 -
+                          35\left ( \frac{r_{ij}}{R_{cut}} \right )^4 + 1
+\end{eqnarray*}
+\endgroup
+\end{document}
diff --git a/doc/src/Eqs/pair_ilp_gr_hBN.jpg b/doc/src/Eqs/pair_ilp_gr_hBN.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..b28c0c6dc92c3fb7316ac941eba7bb1622495334
Binary files /dev/null and b/doc/src/Eqs/pair_ilp_gr_hBN.jpg differ
diff --git a/doc/src/Eqs/pair_ilp_gr_hBN.tex b/doc/src/Eqs/pair_ilp_gr_hBN.tex
new file mode 100644
index 0000000000000000000000000000000000000000..47ce30ac7c9f130a4c4c777346690c0041b5a9fc
--- /dev/null
+++ b/doc/src/Eqs/pair_ilp_gr_hBN.tex
@@ -0,0 +1,42 @@
+\documentclass[aps,pr,onecolumn,superscriptaddress,noshowpacs,a4paper,15pt]{revtex4}
+\pdfoutput=1
+\bibliographystyle{apsrev4}
+\usepackage{color}
+\usepackage{dcolumn} %Align table columns on decimal point
+\usepackage{amssymb}
+\usepackage{amsmath}
+\usepackage{amsthm}
+\usepackage{graphicx}
+\usepackage[pdftex]{hyperref}
+\hypersetup{colorlinks=true,citecolor=blue,linkcolor=red,urlcolor=blue}
+\usepackage[all]{hypcap}
+\newcommand{\red}{\color{red}}
+\newcommand{\blue}{\color{blue}}
+\definecolor{green}{rgb}{0,0.5,0}
+\newcommand{\green}{\color{green}}
+\newcommand{\white}{\color{white}}
+%\newcommand{\cite}[1]{\hspace{-1 ex} % \nocite{#1}\citenum{#1}}
+\thickmuskip=0.5\thickmuskip %shorter spaces in math
+%
+\begin{document}
+%
+\begingroup
+\Large
+\begin{eqnarray*}
+  E & = & \frac{1}{2} \sum_i \sum_{j \neq i} V_{ij} \\[15pt]
+  V_{ij} & = & {\rm Tap}(r_{ij})\left \{ e^{-\alpha (r_{ij}/\beta -1)} 
+               \left [ \epsilon + f(\rho_{ij}) + f(\rho_{ji})\right ] - 
+                \frac{1}{1+e^{-d\left [ \left ( r_{ij}/\left (s_R \cdot r^{eff} \right ) \right )-1 \right ]}}
+                \cdot \frac{C_6}{r^6_{ij}} \right \}\\[15pt]
+  \rho_{ij}^2 & = & r_{ij}^2 - ({\bf r}_{ij} \cdot {\bf n}_i)^2 \\[15pt]
+  \rho_{ji}^2 & = & r_{ij}^2 - ({\bf r}_{ij} \cdot {\bf n}_j)^2 \\[15pt]
+  f(\rho) & = &  C e^{ -( \rho / \delta )^2 }\\[15pt]
+  {\rm Tap}(r_{ij}) & = & 20\left ( \frac{r_{ij}}{R_{cut}} \right )^7 -
+                          70\left ( \frac{r_{ij}}{R_{cut}} \right )^6 +
+                          84\left ( \frac{r_{ij}}{R_{cut}} \right )^5 -
+                          35\left ( \frac{r_{ij}}{R_{cut}} \right )^4 + 1
+\end{eqnarray*}
+\endgroup
+%
+\end{document}
+%
diff --git a/doc/src/Eqs/pair_kolmogorov_crespi_full.jpg b/doc/src/Eqs/pair_kolmogorov_crespi_full.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..e9d306d5050faa7957b9a827b2546d03e0efd10b
Binary files /dev/null and b/doc/src/Eqs/pair_kolmogorov_crespi_full.jpg differ
diff --git a/doc/src/Eqs/pair_kolmogorov_crespi_full.tex b/doc/src/Eqs/pair_kolmogorov_crespi_full.tex
new file mode 100644
index 0000000000000000000000000000000000000000..606aa8b5fe1142464ce290f2f38268961839ee1f
--- /dev/null
+++ b/doc/src/Eqs/pair_kolmogorov_crespi_full.tex
@@ -0,0 +1,33 @@
+\documentclass[aps,pr,onecolumn,superscriptaddress,noshowpacs,a4paper,15pt]{revtex4}
+\pdfoutput=1
+\bibliographystyle{apsrev4}
+\usepackage{color}
+\usepackage{dcolumn} %Align table columns on decimal point
+\usepackage{amssymb}
+\usepackage{amsmath}
+\usepackage{amsthm}
+\usepackage{graphicx}
+\usepackage[pdftex]{hyperref}
+\hypersetup{colorlinks=true,citecolor=blue,linkcolor=red,urlcolor=blue}
+\usepackage[all]{hypcap}
+\newcommand{\red}{\color{red}}
+\newcommand{\blue}{\color{blue}}
+\definecolor{green}{rgb}{0,0.5,0}
+\newcommand{\green}{\color{green}}
+\newcommand{\white}{\color{white}}
+%\newcommand{\cite}[1]{\hspace{-1 ex} % \nocite{#1}\citenum{#1}}
+\thickmuskip=0.5\thickmuskip %shorter spaces in math
+
+\begin{document}
+
+\begingroup
+\Large
+\begin{eqnarray*}
+  E & = & \frac{1}{2} \sum_i \sum_{j \neq i} V_{ij} \\[15pt]
+  V_{ij} & = & e^{-\lambda (r_{ij} -z_0)} \left [ C + f(\rho_{ij}) + f(\rho_{ji}) - A \left ( \frac{r_{ij}}{z_0}\right )^{-6} \right ] \\
+  \rho_{ij}^2 & = & r_{ij}^2 - ({\bf r}_{ij}\cdot {\bf n}_{i})^2 \\[15pt]
+  \rho_{ji}^2 & = & r_{ij}^2 - ({\bf r}_{ij}\cdot  {\bf n}_{j})^2 \\[15pt]
+  f(\rho) & = &  e^{-(\rho/\delta)^2} \sum_{n=0}^2 C_{2n} { \rho/\delta }^{2n}
+\end{eqnarray*}
+\endgroup
+\end{document}
diff --git a/doc/src/pair_coul_shield.txt b/doc/src/pair_coul_shield.txt
new file mode 100644
index 0000000000000000000000000000000000000000..80a79cd383265400fe76517fea0a1fa2b1168461
--- /dev/null
+++ b/doc/src/pair_coul_shield.txt
@@ -0,0 +1,83 @@
+"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
+
+:link(lws,http://lammps.sandia.gov)
+:link(ld,Manual.html)
+:link(lc,Section_commands.html#comm)
+
+:line
+
+pair_style coul/shield command :h3
+
+[Syntax:]
+
+pair_style coul/shield cutoff tap_flag :pre
+
+cutoff = global cutoff (distance units)
+tap_flag = 0/1 to turn off/on the Tapper function
+
+[Examples:]
+
+pair_style coul/shield 16.0 1
+pair_coeff 1 2 0.70 :pre
+
+
+[Description:]
+
+Style {coul/shield} computes a Coulomb interaction for boron and nitrigon
+atoms locate in different layers of hexagonal boron nitride. This potential must
+be used in combination with the potential "pair_style pair_ilp_gr_hBN"_pair_ilp_gr_hBN.html
+
+NOTE: This potential is intended for electrostatic interactions between two different
+layers of hexagonal boron nitride. Therefore, to avoid interaction within the same layers,
+each layer should have a separate molecule id and is recommended to use
+"full" atom style in the data file.
+
+:c,image(Eqs/pair_coul_shield.jpg)
+
+Where Tap(r_ij) is the tapper function which provides a continuous cutoff (up to third derivative)
+for interatomic separations larger than r_c "(Maaravi)"_#Maaravi. Here \lambda is the shielding
+parameter that eliminates the short-range sigularity of the classical monopolar electrostatic
+interaction expression "(Maaravi)"_#Maaravi.
+
+The shielding parameter \lambda (1/distance units) must be defined for each pair of atom
+types via the "pair_coeff"_pair_coeff.html command as in the example
+above, or in the data file or restart files read by the
+"read_data"_read_data.html or "read_restart"_read_restart.html
+commands:
+
+The global cutoff (r_c) specified in the pair_style command is used.
+
+:line
+
+[Mixing, shift, table, tail correction, restart, rRESPA info]:
+
+This pair style does not support parameter mixing. Coefficients must be given explicitly for each type of particle pairs.
+
+The "pair_modify"_pair_modify.html table option is not relevant
+for this pair style.
+
+This pair style does not support the "pair_modify"_pair_modify.html
+tail option for adding long-range tail corrections to energy and
+pressure.
+
+This pair style can only be used via the {pair} keyword of the
+"run_style respa"_run_style.html command.  It does not support the
+{inner}, {middle}, {outer} keywords.
+
+[Restrictions:]
+
+This style is part of the "user-misc" package.  It is only enabled
+if LAMMPS was built with that package.  See the "Making
+LAMMPS"_Section_start.html#start_2_3 section for more info.
+
+[Related commands:]
+
+"pair_coeff"_pair_coeff.html
+"pair_style pair_ilp_gr_hBN"_pair_ilp_gr_hBN.html
+
+[Default:] tap_flag = 1
+
+:line
+
+:link(Maaravi)
+[(Maaravi)] T. Maaravi et al, J. Phys. Chem. C 121, 22826-22835 (2017).
diff --git a/doc/src/pair_ilp_gr_hBN.txt b/doc/src/pair_ilp_gr_hBN.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9f0f0c5d17b62370095897cd324262f529feddef
--- /dev/null
+++ b/doc/src/pair_ilp_gr_hBN.txt
@@ -0,0 +1,106 @@
+"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
+
+:link(lws,http://lammps.sandia.gov)
+:link(ld,Manual.html)
+:link(lc,Section_commands.html#comm)
+
+:line
+
+pair_style ILP/graphene/hBN command :h3
+
+[Syntax:]
+
+pair_style hybrid/overlay ILP/graphene/hBN cutoff tap_flag :pre
+
+cutoff = global cutoff (distance units)
+tap_flag = 0/1 to turn off/on the Tapper function 
+
+[Examples:]
+
+pair_style hybrid/overlay ILP/graphene/hBN 16.0 1
+pair_coeff * * ILP/graphene/hBN  BNCH.ILP B N C :pre
+
+pair_style  hybrid/overlay rebo tersoff ILP/graphene/hBN 16.0 coul/shield 16.0
+pair_coeff  * * rebo                 CH.airebo   NULL NULL C
+pair_coeff  * * tersoff              BNC.tersoff B    N    NULL
+pair_coeff  * * ILP/graphene/hBN     BNCH.ILP    B    N    C :pre
+pair_coeff  1 1 coul/shield 0.70
+pair_coeff  1 2 coul/shield 0.69498201415576216335
+pair_coeff  2 2 coul/shield 0.69
+
+[Description:]
+
+The {ILP/graphene/hBN} style computes the registry-dependent interlayer potential (RDILP)
+potential as described in "(Leven)"_#Leven and "(Maaravi)"_#Maaravi. The normals are calculated in 
+the way as described in "(Kolmogorov)"_#Kolmogorov.
+
+:c,image(Eqs/pair_ilp_gr_hBN.jpg)
+
+Where Tap(r_ij) is the tapper function which provides a continuous cutoff (up to third derivative)
+for interatomic separations larger than r_c "(Maaravi)"_#Maaravi. The definitons of each parameter
+in the above equation can be found in "(Leven)"_#Leven and "(Maaravi)"_#Maaravi.
+
+It is important to include all the pairs to build the neighbor list for
+calculating the normals.
+
+NOTE: This potential is intended for interactions between two different layers
+of graphene or hexagonal boron nitride. Therefore, to avoid interaction within
+the same layers, each layer should have a separate molecule id and is recommended
+to use "full" atom style in the data file.
+
+The parameter file (e.g. BNCH.ILP), is intended for use with metal
+"units"_units.html, with energies in meV. Two additional parameters, {S},
+and {rcut} are included in the parameter file. {S} is designed to 
+facilitate scaling of energies. {rcut} is designed to build the neighbor
+list for calculating the normals for each atom pair.
+
+NOTE: The parameters presented in the parameter file (e.g. BNCH.ILP), are
+fitted with tapper function by setting the cutoff equal to 16.0 Angstrom.
+Using different cutoff or tapper function should be careful.
+
+This potential must be used in combination with hybrid/overlay.
+Other interactions can be set to zero using pair_style {none}.
+
+:line
+
+[Mixing, shift, table, tail correction, restart, rRESPA info]:
+
+This pair style does not support the pair_modify mix, shift, table, and tail options.
+
+This pair style does not write their information to binary restart files, 
+since it is stored in potential files. Thus, you need to re-specify the 
+pair_style and pair_coeff commands in an input script that reads a restart file.
+
+[Restrictions:]
+
+This fix is part of the USER-MISC package.  It is only enabled if
+LAMMPS was built with that package.  See the "Making
+LAMMPS"_Section_start.html#start_3 section for more info.
+
+This pair potential requires the newton setting to be “on” for pair interactions.
+
+The BNCH.ILP potential file provided with LAMMPS (see the potentials directory) are parameterized for metal units. 
+You can use this potential with any LAMMPS units, but you would need to create your BNCH.ILP potential file with 
+coefficients listed in the appropriate units, if your simulation doesn’t use “metal” units.
+
+[Related commands:]
+
+"pair_coeff"_pair_coeff.html
+"pair_none"_pair_none.html
+"pair_style hybrid/overlay"_pair_hybrid.html
+"pair_style pair_kolmogorov_crespi_z"_pair_kolmogorov_crespi_z.html
+"pair_style pair_kolmogorov_crespi_full"_pair_kolmogorov_crespi_full.html
+"pair_style pair_coul_shield"_pair_coul_shield.html
+
+[Default:] tap_flag = 1
+
+:line
+
+:link(Leven)
+[(Leven)] I. Leven et al, J. Chem.Theory Comput. 12, 2896-905 (2016)
+
+:link(Maaravi)
+[(Maaravi)] T. Maaravi et al, J. Phys. Chem. C 121, 22826-22835 (2017).
+
+:link(Kolmogorov)
+[(Kolmogorov)] A. N. Kolmogorov, V. H. Crespi, Phys. Rev. B 71, 235415 (2005)
diff --git a/doc/src/pair_kolmogorov_crespi_full.txt b/doc/src/pair_kolmogorov_crespi_full.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f921fc043a6fe8ef8fe21a8f83c24da67ea2c8f9
--- /dev/null
+++ b/doc/src/pair_kolmogorov_crespi_full.txt
@@ -0,0 +1,90 @@
+"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c
+
+:link(lws,http://lammps.sandia.gov)
+:link(ld,Manual.html)
+:link(lc,Section_commands.html#comm)
+
+:line
+
+pair_style kolmogorov/crespi/full command :h3
+
+[Syntax:]
+
+pair_style hybrid/overlay kolmogorov/crespi/full cutoff tap_flag:pre
+
+cutoff = global cutoff (distance units)
+tap_flag = 0/1 to turn off/on the Tapper function 
+
+[Examples:]
+
+pair_style hybrid/overlay kolmogorov/crespi/full 20.0 0
+pair_coeff * * none
+pair_coeff * * kolmogorov/crespi/full  CC.KC   C C :pre
+
+pair_style hybrid/overlay rebo kolmogorov/crespi/full 16.0
+pair_coeff * * rebo                    CH.airebo  C C
+pair_coeff * * kolmogorov/crespi/full  CC.KC      C C :pre
+
+[Description:]
+
+The {kolmogorov/crespi/full} style computes the Kolmogorov-Crespi interaction
+potential as described in "(Kolmogorov)"_#Kolmogorov. No simplification is made,
+
+:c,image(Eqs/pair_kolmogorov_crespi_full.jpg)
+
+It is important to have a suffiently large cutoff to ensure smooth forces and
+to include all the pairs to build the neighbor list for calculating the normals.
+Energies are shifted so that they go continously to zero at the cutoff assuming
+that the exponential part of {Vij} (first term) decays sufficiently fast.
+This shift is achieved by the last term in the equation for {Vij} above.
+
+NOTE: This potential is intended for interactions between two different graphene
+layers. Therefore, to avoid interaction within the same layers, each layer
+should have a separate molecule id and is recommended to use
+"full" atom style in the data file.
+
+The parameter file (e.g. CC.KC), is intended for use with metal
+"units"_units.html, with energies in meV. Two additional parameters, {S},
+and {rcut} are included in the parameter file. {S} is designed to
+facilitate scaling of energies. {rcut} is designed to build the neighbor
+list for calculating the normals for each atom pair.
+
+This potential must be used in combination with hybrid/overlay.
+Other interactions can be set to zero using pair_style {none}.
+
+:line
+
+[Mixing, shift, table, tail correction, restart, rRESPA info]:
+
+This pair style does not support the pair_modify mix, shift, table, and tail options.
+
+This pair style does not write their information to binary restart files, 
+since it is stored in potential files. Thus, you need to re-specify the
+pair_style and pair_coeff commands in an input script that reads a restart file.
+
+[Restrictions:]
+
+This fix is part of the USER-MISC package.  It is only enabled if
+LAMMPS was built with that package.  See the "Making
+LAMMPS"_Section_start.html#start_3 section for more info.
+
+This pair potential requires the newton setting to be “on” for pair interactions.
+
+The CC.KC potential file provided with LAMMPS (see the potentials directory) are parameterized for metal units. 
+You can use this potential with any LAMMPS units, but you would need to create your CC.KC potential file with 
+coefficients listed in the appropriate units, if your simulation doesn’t use “metal” units.
+
+[Related commands:]
+
+"pair_coeff"_pair_coeff.html
+"pair_none"_pair_none.html
+"pair_style hybrid/overlay"_pair_hybrid.html
+"pair_style pair_kolmogorov_crespi_z"_pair_kolmogorov_crespi_z.html
+"pair_style pair_ilp_gr_hBN"_pair_ilp_gr_hBN.html
+
+[Default:] tap_flag = 0
+
+:line
+
+:link(Kolmogorov)
+[(Kolmogorov)] A. N. Kolmogorov, V. H. Crespi, Phys. Rev. B 71, 235415 (2005)
diff --git a/src/USER-MISC/pair_coul_shield.cpp b/src/USER-MISC/pair_coul_shield.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cf75b6c6c828e69ac5d1ac3b4b01abf79ae3ddd6
--- /dev/null
+++ b/src/USER-MISC/pair_coul_shield.cpp
@@ -0,0 +1,370 @@
+/* ----------------------------------------------------------------------
+   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: Wengen Ouyang (Tel Aviv University)
+   e-mail: w.g.ouyang at gmail dot com
+  
+   This is a Coulomb potential described in
+   [Maaravi et al, J. Phys. Chem. C 121, 22826-22835 (2017)]
+------------------------------------------------------------------------- */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "pair_coul_shield.h"
+#include "atom.h"
+#include "comm.h"
+#include "force.h"
+#include "neighbor.h"
+#include "neigh_list.h"
+#include "memory.h"
+#include "error.h"
+
+using namespace LAMMPS_NS;
+
+/* ---------------------------------------------------------------------- */
+
+PairCoulshield::PairCoulshield(LAMMPS *lmp) : Pair(lmp) {
+Tapflag = 1;
+}
+
+/* ---------------------------------------------------------------------- */
+
+PairCoulshield::~PairCoulshield()
+{
+  if (allocated) {
+    memory->destroy(setflag);
+    memory->destroy(sigmae);
+    memory->destroy(offset);
+    memory->destroy(cutsq);
+    memory->destroy(cut);
+    allocated = 0;
+  }
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairCoulshield::compute(int eflag, int vflag)
+{
+  int i,j,ii,jj,inum,jnum,itype,jtype;
+  double qtmp,xtmp,ytmp,ztmp,delx,dely,delz,ecoul,fpair,Tap,dTap;
+  double rsq,r,r3,rarg,th,depsdr,epsr,forcecoul,factor_coul,Vc,fvc;
+  int *ilist,*jlist,*numneigh,**firstneigh;
+
+  ecoul = 0.0;
+  if (eflag || vflag) ev_setup(eflag,vflag);
+  else evflag = vflag_fdotr = 0;
+
+  double **x = atom->x;
+  double **f = atom->f;
+  double *q = atom->q;
+  int *type = atom->type;
+  int nlocal = atom->nlocal;
+  double *special_coul = force->special_coul;
+  int newton_pair = force->newton_pair;
+  double qqrd2e = force->qqrd2e;
+
+  inum = list->inum;
+  ilist = list->ilist;
+  numneigh = list->numneigh;
+  firstneigh = list->firstneigh;
+
+  // loop over neighbors of my atoms
+
+  for (ii = 0; ii < inum; ii++) {
+    i = ilist[ii];
+    qtmp = q[i];
+    xtmp = x[i][0];
+    ytmp = x[i][1];
+    ztmp = x[i][2];
+    itype = type[i];
+    jlist = firstneigh[i];
+    jnum = numneigh[i];
+
+    for (jj = 0; jj < jnum; jj++) {
+      j = jlist[jj];
+
+      factor_coul = special_coul[sbmask(j)];
+      j &= NEIGHMASK;
+
+      delx = xtmp - x[j][0];
+      dely = ytmp - x[j][1];
+      delz = ztmp - x[j][2];
+      rsq = delx*delx + dely*dely + delz*delz;
+      jtype = type[j];
+
+      // only include the interation between different layers
+      if (rsq < cutsq[itype][jtype] && atom->molecule[i] != atom->molecule[j]) {
+        r = sqrt(rsq);
+	r3 = rsq*r;
+        rarg = 1.0/sigmae[itype][jtype];
+        th = r3 + pow(rarg,3.0);
+        epsr = 1.0/pow(th,0.333333333333333333333333);
+        depsdr = pow(epsr,4.0);
+	Vc = qqrd2e*qtmp*q[j]*epsr;
+
+	// turn on/off Tapper function
+        if (Tapflag) {
+          Tap = calc_Tap(r,sqrt(cutsq[itype][jtype]));
+          dTap = calc_dTap(r,sqrt(cutsq[itype][jtype]));
+        } else {Tap = 1.0; dTap = 0.0;}
+
+        forcecoul = qqrd2e*qtmp*q[j]*r*depsdr;
+        fvc = forcecoul*Tap - Vc*dTap/r;
+        fpair = factor_coul*fvc;
+
+        f[i][0] += delx*fpair;
+        f[i][1] += dely*fpair;
+        f[i][2] += delz*fpair;
+        if (newton_pair || j < nlocal) {
+          f[j][0] -= delx*fpair;
+          f[j][1] -= dely*fpair;
+          f[j][2] -= delz*fpair;
+        }
+
+        if (eflag) {
+	  if (Tapflag) ecoul = Vc*Tap;
+	  else ecoul = Vc - offset[itype][jtype];
+          ecoul *= factor_coul;
+        }
+
+        if (evflag) ev_tally(i,j,nlocal,newton_pair,0.0,
+                             ecoul,fpair,delx,dely,delz);
+      }
+    }
+  }
+
+  if (vflag_fdotr) virial_fdotr_compute();
+}
+
+/* ----------------------------------------------------------------------
+   allocate all arrays
+------------------------------------------------------------------------- */
+
+void PairCoulshield::allocate()
+{
+  allocated = 1;
+  int n = atom->ntypes;
+
+  memory->create(setflag,n+1,n+1,"pair:setflag");
+  for (int i = 1; i <= n; i++)
+    for (int j = i; j <= n; j++)
+      setflag[i][j] = 0;
+
+  memory->create(cutsq,n+1,n+1,"pair:cutsq");
+  memory->create(cut,n+1,n+1,"pair:cut");
+  memory->create(sigmae,n+1,n+1,"pair:sigmae");
+  //memory->create(rme,n+1,n+1,"pair:rme");
+  memory->create(offset,n+1,n+1,"pair:offset");
+}
+
+/* ----------------------------------------------------------------------
+   global settings
+------------------------------------------------------------------------- */
+
+void PairCoulshield::settings(int narg, char **arg)
+{
+  if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command");
+
+  cut_global = force->numeric(FLERR,arg[0]);
+  if (narg == 2) Tapflag = force->numeric(FLERR,arg[1]);
+
+  // reset cutoffs that have been explicitly set
+
+  if (allocated) {
+    int i,j;
+    for (i = 1; i <= atom->ntypes; i++)
+      for (j = i+1; j <= atom->ntypes; j++)
+        if (setflag[i][j]) cut[i][j] = cut_global;
+  }
+}
+
+/* ----------------------------------------------------------------------
+   set coeffs for one or more type pairs
+------------------------------------------------------------------------- */
+
+void PairCoulshield::coeff(int narg, char **arg)
+{
+  if (narg < 3 || narg > 4) error->all(FLERR,"Incorrect args for pair coefficients");
+  if (!allocated) allocate();
+
+  int ilo,ihi,jlo,jhi;
+  force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
+  force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
+
+  double sigmae_one = force->numeric(FLERR,arg[2]);
+
+  double cut_one = cut_global;
+  if (narg == 4) cut_one = force->numeric(FLERR,arg[3]);
+
+  int count = 0;
+  for (int i = ilo; i <= ihi; i++) {
+    for (int j = MAX(jlo,i); j <= jhi; j++) {
+      sigmae[i][j] = sigmae_one;
+      cut[i][j] = cut_one;
+      setflag[i][j] = 1;
+      count++;
+    }
+  }
+
+  if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
+}
+
+
+/* ----------------------------------------------------------------------
+   init specific to this pair style
+------------------------------------------------------------------------- */
+
+void PairCoulshield::init_style()
+{
+  if (!atom->q_flag)
+    error->all(FLERR,"Pair style coul/shield requires atom attribute q");
+
+  neighbor->request(this,instance_me);
+}
+
+/* ----------------------------------------------------------------------
+   init for one type pair i,j and corresponding j,i
+------------------------------------------------------------------------- */
+
+double PairCoulshield::init_one(int i, int j)
+{
+  if (setflag[i][j] == 0) {
+    error->all(FLERR,"for pair style coul/shield, parameters need to be set explicitly for all pairs.");
+  }
+
+  double *q = atom->q;
+  double qqrd2e = force->qqrd2e;
+  double r,r3,rarg,th,epsr;
+
+  if (offset_flag) {
+     r = cut[i][j];
+     r3 = r*r*r;
+     rarg = 1.0/sigmae[i][j];
+     th = r3 + pow(rarg,3.0);
+     epsr = 1.0/pow(th,0.333333333333333333);
+     offset[i][j] = qqrd2e*q[i]*q[j]*epsr;
+  } else offset[i][j] = 0.0;
+
+
+  sigmae[j][i] = sigmae[i][j];
+  offset[j][i] = offset[i][j];
+  cut[j][i] = cut[i][j];
+
+  return cut[i][j];
+}
+
+/* ----------------------------------------------------------------------
+  proc 0 writes to restart file
+------------------------------------------------------------------------- */
+
+void PairCoulshield::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(&sigmae[i][j],sizeof(double),1,fp);
+        fwrite(&cut[i][j],sizeof(double),1,fp);
+      }
+    }
+}
+
+/* ----------------------------------------------------------------------
+  proc 0 reads from restart file, bcasts
+------------------------------------------------------------------------- */
+
+void PairCoulshield::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 (setflag[i][j]) {
+        if (me == 0) {
+          fread(&sigmae[i][j],sizeof(double),1,fp);
+          fread(&cut[i][j],sizeof(double),1,fp);
+        }
+        MPI_Bcast(&sigmae[i][j],1,MPI_DOUBLE,0,world);
+        MPI_Bcast(&cut[i][j],1,MPI_DOUBLE,0,world);
+      }
+    }
+}
+
+/* ----------------------------------------------------------------------
+  proc 0 writes to restart file
+------------------------------------------------------------------------- */
+
+void PairCoulshield::write_restart_settings(FILE *fp)
+{
+  fwrite(&cut_global,sizeof(double),1,fp);
+  fwrite(&offset_flag,sizeof(int),1,fp);
+  fwrite(&mix_flag,sizeof(int),1,fp);
+}
+
+/* ----------------------------------------------------------------------
+  proc 0 reads from restart file, bcasts
+------------------------------------------------------------------------- */
+
+void PairCoulshield::read_restart_settings(FILE *fp)
+{
+  if (comm->me == 0) {
+    fread(&cut_global,sizeof(double),1,fp);
+    fread(&offset_flag,sizeof(int),1,fp);
+    fread(&mix_flag,sizeof(int),1,fp);
+  }
+  MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world);
+  MPI_Bcast(&offset_flag,1,MPI_INT,0,world);
+  MPI_Bcast(&mix_flag,1,MPI_INT,0,world);
+}
+
+/* ---------------------------------------------------------------------- */
+
+double PairCoulshield::single(int i, int j, int itype, int jtype,
+                           double rsq, double factor_coul, double factor_lj,
+                           double &fforce)
+{
+  double r, rarg,Vc,fvc,forcecoul,phishieldec;
+  double r3,th,epsr,depsdr,Tap,dTap;
+  double *q = atom->q;
+  double qqrd2e = force->qqrd2e;
+
+   r = sqrt(rsq);
+   r3 = rsq*r;
+   rarg = 1.0/sigmae[itype][jtype];
+   th = r3 + pow(rarg,3.0);
+   epsr = 1.0/pow(th,0.333333333333333333);
+   depsdr = pow(epsr,4.0);
+   Vc = qqrd2e*q[i]*q[j]*epsr;
+
+   // turn on/off Tapper function
+   if (Tapflag) {
+     Tap = calc_Tap(r,sqrt(cutsq[itype][jtype]));
+     dTap = calc_dTap(r,sqrt(cutsq[itype][jtype]));
+   } else {Tap = 1.0; dTap = 0.0;}
+
+   forcecoul = qqrd2e*q[i]*q[j]*r*depsdr;
+   fvc = forcecoul*Tap - Vc*dTap/r;
+   fforce = factor_coul*fvc;
+
+  if (Tapflag) phishieldec = factor_coul*Vc*Tap;
+  else phishieldec = Vc - offset[itype][jtype];
+  return factor_coul*phishieldec;
+}
diff --git a/src/USER-MISC/pair_coul_shield.h b/src/USER-MISC/pair_coul_shield.h
new file mode 100644
index 0000000000000000000000000000000000000000..1d2b7b526a937ca0a0cbddbddbe50ea61f81b464
--- /dev/null
+++ b/src/USER-MISC/pair_coul_shield.h
@@ -0,0 +1,97 @@
+/* -*- c++ -*- ----------------------------------------------------------
+   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
+   http://lammps.sandia.gov, Sandia National Laboratories
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#ifdef PAIR_CLASS
+
+PairStyle(coul/shield,PairCoulshield)
+
+#else
+
+#ifndef LMP_PAIR_COUL_SHIELD_H
+#define LMP_PAIR_COUL_SHIELD_H
+
+#include "pair.h"
+
+namespace LAMMPS_NS {
+
+class PairCoulshield : public Pair {
+ public:
+  PairCoulshield(class LAMMPS *);
+  virtual ~PairCoulshield();
+
+  virtual void compute(int, int);
+
+  virtual void settings(int, char **);
+  virtual void coeff(int, char **);
+  virtual void init_style();
+  virtual double init_one(int, int);
+  virtual void write_restart(FILE *);
+  virtual void read_restart(FILE *);
+  virtual void write_restart_settings(FILE *);
+  virtual void read_restart_settings(FILE *);
+
+  virtual double single(int, int, int, int, double, double, double, double &);
+
+ protected:
+  double cut_global;
+  double **cut;
+  double **sigmae, **offset;
+  //double a_eps, b_eps, eps_s;
+  int Tapflag;
+
+  void allocate();
+
+/* ----Calculate the long-range cutoff term */
+  inline double calc_Tap(double r_ij, double Rcut) {
+    double Tap,r;
+    //int Tap_coeff[8] = {1,0,0,0,-35,84,-70,20};
+    double Tap_coeff[8] = {1.0,0.0,0.0,0.0,-35.0,84.0,-70.0,20.0};
+
+    r = r_ij/Rcut;
+    Tap = 0.0;
+
+    Tap = Tap_coeff[7] * r + Tap_coeff[6];
+    Tap = Tap * r  + Tap_coeff[5];
+    Tap = Tap * r  + Tap_coeff[4];
+    Tap = Tap * r  + Tap_coeff[3];
+    Tap = Tap * r  + Tap_coeff[2];
+    Tap = Tap * r  + Tap_coeff[1];
+    Tap = Tap * r  + Tap_coeff[0];
+
+    return(Tap);
+  }
+
+ /* ----Calculate the derivatives of long-range cutoff term */
+  inline double calc_dTap(double r_ij, double Rcut) {
+    double dTap,r;
+    double Tap_coeff[8] = {1.0,0.0,0.0,0.0,-35.0,84.0,-70.0,20.0};
+
+    r = r_ij/Rcut;
+    dTap = 0.0;
+
+    dTap = 7.0*Tap_coeff[7] * r + 6.0*Tap_coeff[6];
+    dTap = dTap * r  + 5.0*Tap_coeff[5];
+    dTap = dTap * r  + 4.0*Tap_coeff[4];
+    dTap = dTap * r  + 3.0*Tap_coeff[3];
+    dTap = dTap * r  + 2.0*Tap_coeff[2];
+    dTap = dTap * r  + Tap_coeff[1];
+    dTap = dTap/Rcut;
+
+    return(dTap);
+  }
+};
+
+}
+
+#endif
+#endif
diff --git a/src/USER-MISC/pair_ilp_gr_hBN.cpp b/src/USER-MISC/pair_ilp_gr_hBN.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c60262d1d5ceb656ad0e5e0fc9e23d52d4786a8c
--- /dev/null
+++ b/src/USER-MISC/pair_ilp_gr_hBN.cpp
@@ -0,0 +1,1117 @@
+/* ----------------------------------------------------------------------
+   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: Wengen Ouyang (Tel Aviv University)
+   e-mail: w.g.ouyang at gmail dot com
+  
+   This is a full version of the potential described in
+   [Maaravi et al, J. Phys. Chem. C 121, 22826-22835 (2017)]
+   The definition of normals are the same as that in
+   [Kolmogorov & Crespi, Phys. Rev. B 71, 235415 (2005)]
+------------------------------------------------------------------------- */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mpi.h>
+#include "pair_ilp_gr_hBN.h"
+#include "atom.h"
+#include "comm.h"
+#include "force.h"
+#include "neighbor.h"
+#include "neigh_list.h"
+#include "neigh_request.h"
+#include "my_page.h"
+#include "memory.h"
+#include "error.h"
+
+using namespace LAMMPS_NS;
+
+#define MAXLINE 1024
+#define DELTA 4
+#define PGDELTA 1
+
+/* ---------------------------------------------------------------------- */
+
+PairILP::PairILP(LAMMPS *lmp) : Pair(lmp)
+{
+  writedata = 1;
+
+  // initialize element to parameter maps
+  nelements = 0;
+  elements = NULL;
+  nparams = maxparam = 0;
+  params = NULL;
+  elem2param = NULL;
+  cutILPsq = NULL;
+  map = NULL;
+
+  nmax = 0;
+  maxlocal = 0;
+  ILP_numneigh = NULL;
+  ILP_firstneigh = NULL;
+  ipage = NULL;
+  pgsize = oneatom = 0;
+
+  normal = NULL;
+  dnormal = NULL;
+  dnormdri = NULL;
+
+  // always compute energy offset
+  offset_flag = 1;
+
+  // set comm size needed by this Pair
+  comm_forward = 39;
+  tap_flag = 1;
+}
+
+/* ---------------------------------------------------------------------- */
+
+PairILP::~PairILP()
+{
+  memory->destroy(ILP_numneigh);
+  memory->sfree(ILP_firstneigh);
+  delete [] ipage;
+  memory->destroy(normal);
+  memory->destroy(dnormal);
+  memory->destroy(dnormdri);
+  
+  if (allocated) {
+    memory->destroy(setflag);
+    memory->destroy(cutsq);
+    memory->destroy(cut);
+    memory->destroy(offset);
+  }
+
+  if (elements)
+    for (int i = 0; i < nelements; i++) delete [] elements[i];
+  delete [] elements;
+  memory->destroy(params);
+  memory->destroy(elem2param);
+  memory->destroy(cutILPsq);
+  if (allocated) delete [] map;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairILP::compute(int eflag, int vflag)
+{
+  int i,j,ii,jj,inum,jnum,itype,jtype,id,k,l,kk,ll;
+  tagint itag,jtag;
+  double prodnorm1,prodnorm2,fkcx,fkcy,fkcz;
+  double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair,fpair1,fpair2;
+  double rsq,r,Rcut,rhosq1,rhosq2,exp0,exp1,exp2,r2inv,r6inv,r8inv,Tap,dTap,Vkc;
+  double frho1,frho2,TSvdw,TSvdw2inv,Erep,fsum,rdsq1,rdsq2;
+  int *ilist,*jlist,*numneigh,**firstneigh;
+  int *ILP_neighs_i,*ILP_neighs_j;
+  
+  evdwl = 0.0;
+  if (eflag || vflag) ev_setup(eflag,vflag);
+  else evflag = vflag_fdotr = 0;
+
+  double **x = atom->x;
+  double **f = atom->f;
+  int *type = atom->type;
+  tagint *tag = atom->tag;
+  int nlocal = atom->nlocal;
+  int newton_pair = force->newton_pair;
+  double dprodnorm1[3] = {0.0, 0.0, 0.0};
+  double dprodnorm2[3] = {0.0, 0.0, 0.0};
+  double fp1[3] = {0.0, 0.0, 0.0};
+  double fp2[3] = {0.0, 0.0, 0.0};
+  double fprod1[3] = {0.0, 0.0, 0.0};
+  double fprod2[3] = {0.0, 0.0, 0.0};
+
+  inum = list->inum;	
+  ilist = list->ilist;  
+  numneigh = list->numneigh; 
+  firstneigh = list->firstneigh;
+  // Build full neighbor list
+  ILP_neigh(); 
+  // Calculate the normals
+  calc_normal();
+
+  // communicate the normal vector and its derivatives
+  comm->forward_comm_pair(this);
+
+  // loop over neighbors of my atoms
+  for (ii = 0; ii < inum; ii++) {
+    i = ilist[ii];
+    itag = tag[i];
+    xtmp = x[i][0];
+    ytmp = x[i][1];
+    ztmp = x[i][2];
+    itype = type[i];
+    jlist = firstneigh[i];
+    jnum = numneigh[i];
+
+    for (jj = 0; jj < jnum; jj++) {
+      j = jlist[jj];
+      j &= NEIGHMASK;
+      jtype = type[j];
+      jtag = tag[j];
+
+      // two-body interactions from full neighbor list, skip half of them
+      if (itag > jtag) {
+        if ((itag+jtag) % 2 == 0) continue;
+      } else if (itag < jtag) {
+        if ((itag+jtag) % 2 == 1) continue;
+      } else {
+        if (x[j][2] < ztmp) continue;
+        if (x[j][2] == ztmp && x[j][1] < ytmp) continue;
+        if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue;
+      }
+
+      delx = xtmp - x[j][0];
+      dely = ytmp - x[j][1];
+      delz = ztmp - x[j][2];
+      rsq = delx*delx + dely*dely + delz*delz;
+      
+      // only include the interation between different layers
+      if (rsq < cutsq[itype][jtype] && atom->molecule[i] != atom->molecule[j]) {
+
+        int iparam_ij = elem2param[map[itype]][map[jtype]];
+        Param& p = params[iparam_ij];
+
+        r = sqrt(rsq);
+	r2inv = 1.0/rsq;
+        r6inv = r2inv*r2inv*r2inv;
+        r8inv = r6inv*r2inv;
+	// turn on/off Tapper function
+	if (tap_flag) {
+          Rcut = sqrt(cutsq[itype][jtype]);
+	  Tap = calc_Tap(r,Rcut);
+	  dTap = calc_dTap(r,Rcut);
+	} else {Tap = 1.0; dTap = 0.0;}
+
+        // Calculate the transverse distance
+        // note that rho_ij does not equal to rho_ji except when normals are all along z
+        prodnorm1 = normal[i][0]*delx + normal[i][1]*dely + normal[i][2]*delz;
+        prodnorm2 = normal[j][0]*delx + normal[j][1]*dely + normal[j][2]*delz;
+        rhosq1 = rsq - prodnorm1*prodnorm1;  // rho_ij
+        rhosq2 = rsq - prodnorm2*prodnorm2;  // rho_ji
+        rdsq1 = rhosq1*p.delta2inv; // (rho_ij/delta)^2
+        rdsq2 = rhosq2*p.delta2inv; // (rho_ji/delta)^2
+
+        // store exponents
+        exp0 = exp(-p.lambda*(r-p.z0));
+        exp1 = exp(-rdsq1);
+        exp2 = exp(-rdsq2);
+
+	TSvdw = 1.0 + exp(-p.d*(r/p.seff - 1.0));
+	TSvdw2inv = 1.0/pow(TSvdw,2.0);
+        frho1 = exp1*p.C;
+        frho2 = exp2*p.C;
+        Erep = p.epsilon + frho1 + frho2;
+	Vkc = -p.C6*r6inv/TSvdw + exp0*Erep;
+
+        // derivatives
+        fpair = -6.0*p.C6*r8inv/TSvdw + p.d/p.seff*p.C6*(TSvdw-1.0)*TSvdw2inv*r8inv*r + p.lambda*exp0/r*Erep;
+        fpair1 = 2.0*exp0*frho1*p.delta2inv;
+        fpair2 = 2.0*exp0*frho2*p.delta2inv;
+        fsum = fpair + fpair1 + fpair2;
+	// derivatives of the product of rij and ni, the result is a vector
+        dprodnorm1[0] = dnormdri[0][0][i]*delx + dnormdri[1][0][i]*dely + dnormdri[2][0][i]*delz;
+        dprodnorm1[1] = dnormdri[0][1][i]*delx + dnormdri[1][1][i]*dely + dnormdri[2][1][i]*delz;
+        dprodnorm1[2] = dnormdri[0][2][i]*delx + dnormdri[1][2][i]*dely + dnormdri[2][2][i]*delz;
+        // derivatives of the product of rji and nj, the result is a vector
+        dprodnorm2[0] = dnormdri[0][0][j]*delx + dnormdri[1][0][j]*dely + dnormdri[2][0][j]*delz;
+        dprodnorm2[1] = dnormdri[0][1][j]*delx + dnormdri[1][1][j]*dely + dnormdri[2][1][j]*delz;
+        dprodnorm2[2] = dnormdri[0][2][j]*delx + dnormdri[1][2][j]*dely + dnormdri[2][2][j]*delz;
+        fp1[0] = prodnorm1*normal[i][0]*fpair1;
+        fp1[1] = prodnorm1*normal[i][1]*fpair1;
+        fp1[2] = prodnorm1*normal[i][2]*fpair1;
+        fp2[0] = prodnorm2*normal[j][0]*fpair2;
+        fp2[1] = prodnorm2*normal[j][1]*fpair2;
+        fp2[2] = prodnorm2*normal[j][2]*fpair2;
+        fprod1[0] = prodnorm1*dprodnorm1[0]*fpair1;
+        fprod1[1] = prodnorm1*dprodnorm1[1]*fpair1;
+        fprod1[2] = prodnorm1*dprodnorm1[2]*fpair1;
+        fprod2[0] = prodnorm2*dprodnorm2[0]*fpair2;
+        fprod2[1] = prodnorm2*dprodnorm2[1]*fpair2;
+        fprod2[2] = prodnorm2*dprodnorm2[2]*fpair2;
+        fkcx = (delx*fsum - fp1[0] - fp2[0])*Tap - Vkc*dTap*delx/r;
+        fkcy = (dely*fsum - fp1[1] - fp2[1])*Tap - Vkc*dTap*dely/r; 
+        fkcz = (delz*fsum - fp1[2] - fp2[2])*Tap - Vkc*dTap*delz/r; 
+
+        f[i][0] += fkcx - fprod1[0]*Tap;
+        f[i][1] += fkcy - fprod1[1]*Tap;
+        f[i][2] += fkcz - fprod1[2]*Tap;
+        if (newton_pair || j < nlocal) {
+          f[j][0] -= fkcx + fprod2[0]*Tap;
+          f[j][1] -= fkcy + fprod2[1]*Tap;
+          f[j][2] -= fkcz + fprod2[2]*Tap;
+        }
+
+	// calculate the forces acted on the neighbors of atom i from atom j
+	ILP_neighs_i = ILP_firstneigh[i];
+  	for (kk = 0; kk < ILP_numneigh[i]; kk++) {
+	  k = ILP_neighs_i[kk];
+          if (k == i) continue;
+          // derivatives of the product of rij and ni respect to rk, k=0,1,2, where atom k is the neighbors of atom i
+          dprodnorm1[0] = dnormal[0][0][kk][i]*delx + dnormal[1][0][kk][i]*dely + dnormal[2][0][kk][i]*delz;
+          dprodnorm1[1] = dnormal[0][1][kk][i]*delx + dnormal[1][1][kk][i]*dely + dnormal[2][1][kk][i]*delz;
+          dprodnorm1[2] = dnormal[0][2][kk][i]*delx + dnormal[1][2][kk][i]*dely + dnormal[2][2][kk][i]*delz;
+	  f[k][0] += (-prodnorm1*dprodnorm1[0]*fpair1)*Tap;
+	  f[k][1] += (-prodnorm1*dprodnorm1[1]*fpair1)*Tap;
+	  f[k][2] += (-prodnorm1*dprodnorm1[2]*fpair1)*Tap;
+	}
+
+	// calculate the forces acted on the neighbors of atom j from atom i
+	ILP_neighs_j = ILP_firstneigh[j];
+  	for (ll = 0; ll < ILP_numneigh[j]; ll++) {
+	  l = ILP_neighs_j[ll];
+          if (l == j) continue;
+          if (newton_pair || l < nlocal) {
+            // derivatives of the product of rji and nj respect to rl, l=0,1,2, where atom l is the neighbors of atom j
+            dprodnorm2[0] = dnormal[0][0][ll][j]*delx + dnormal[1][0][ll][j]*dely + dnormal[2][0][ll][j]*delz;
+            dprodnorm2[1] = dnormal[0][1][ll][j]*delx + dnormal[1][1][ll][j]*dely + dnormal[2][1][ll][j]*delz;
+            dprodnorm2[2] = dnormal[0][2][ll][j]*delx + dnormal[1][2][ll][j]*dely + dnormal[2][2][ll][j]*delz;
+	    f[l][0] += (-prodnorm2*dprodnorm2[0]*fpair2)*Tap;
+	    f[l][1] += (-prodnorm2*dprodnorm2[1]*fpair2)*Tap;
+	    f[l][2] += (-prodnorm2*dprodnorm2[2]*fpair2)*Tap;
+	  }
+	}
+
+        if (eflag) {
+          if (tap_flag) evdwl = Tap*Vkc;
+          else  evdwl = Vkc - offset[itype][jtype];
+        }
+
+        if (evflag){
+          ev_tally_xyz(i,j,nlocal,newton_pair,evdwl,0,
+                       fkcx,fkcy,fkcz,delx,dely,delz);
+        }
+      }
+    }
+  }
+  if (vflag_fdotr) virial_fdotr_compute();
+}
+
+/* ----------------------------------------------------------------------
+   Calculate the normals for each atom
+------------------------------------------------------------------------- */
+void PairILP::calc_normal()
+{
+  int i,j,ii,jj,inum,jnum,itype,jtype;
+  int cont,k,kk,cont1,id,ip,m;
+  tagint itag,jtag;
+  double dist,nn,xtp,ytp,ztp,delx,dely,delz,nn2;
+  int *ilist,*jlist;
+  double pv12[3],pv31[3],pv23[3],n1[3],dni[3],dnn[3][3],vet[3][3],dpvdri[3][3];
+  double dn1[3][3][3],dpv12[3][3][3],dpv23[3][3][3],dpv31[3][3][3];
+
+  double **x = atom->x;
+  int *type = atom->type;
+  int ntypes = atom->ntypes;
+  int nlocal = atom->nlocal;
+  tagint *tag = atom->tag;
+  
+  // grow normal array if necessary
+
+  if (atom->nmax > nmax) {
+    memory->destroy(normal);
+    memory->destroy(dnormal);
+    memory->destroy(dnormdri);
+    nmax = atom->nmax;
+    memory->create(normal,nmax,3,"ILP:normal");
+    memory->create(dnormdri,3,3,nmax,"ILP:dnormdri");
+    memory->create(dnormal,3,3,3,nmax,"ILP:dnormal");
+  }
+
+  inum = list->inum;	
+  ilist = list->ilist;  
+  //Calculate normals
+  for (ii = 0; ii < inum; ii++) {
+    i = ilist[ii];
+    xtp = x[i][0];
+    ytp = x[i][1];
+    ztp = x[i][2];
+    itype = type[i];
+
+    //   Initialize the arrays
+    for (id = 0; id < 3; id++){
+      pv12[id] = 0.0;
+      pv31[id] = 0.0;
+      pv23[id] = 0.0;
+      n1[id] = 0.0;
+      dni[id] = 0.0;
+      normal[i][id] = 0.0;
+      for (ip = 0; ip < 3; ip++){
+        vet[ip][id] = 0.0;
+        dnn[ip][id] = 0.0;
+        dpvdri[ip][id] = 0.0;
+        dnormdri[ip][id][i] = 0.0;
+        for (m = 0; m < 3; m++){
+          dpv12[ip][id][m] = 0.0;
+          dpv31[ip][id][m] = 0.0;
+          dpv23[ip][id][m] = 0.0;
+          dn1[ip][id][m] = 0.0;
+          dnormal[ip][id][m][i] = 0.0;
+        }
+      }
+    }
+
+    cont = 0;
+    jlist = ILP_firstneigh[i];
+    jnum = ILP_numneigh[i];
+    for (jj = 0; jj < jnum; jj++) {
+      j = jlist[jj];
+      j &= NEIGHMASK;
+      
+      delx = x[j][0] - xtp;
+      dely = x[j][1] - ytp;
+      delz = x[j][2] - ztp;
+      vet[cont][0] = delx;
+      vet[cont][1] = dely;
+      vet[cont][2] = delz;
+      cont++;
+    }
+
+    if (cont <= 1) { 
+      normal[i][0] = 0.0;
+      normal[i][1] = 0.0;
+      normal[i][2] = 1.0;
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          dnormdri[id][ip][i] = 0.0;
+          for (m = 0; m < 3; m++){
+            dnormal[id][ip][m][i] = 0.0;
+          }
+        } 
+      }
+    }
+    else if (cont == 2) {
+      pv12[0] = vet[0][1]*vet[1][2] - vet[1][1]*vet[0][2];
+      pv12[1] = vet[0][2]*vet[1][0] - vet[1][2]*vet[0][0];
+      pv12[2] = vet[0][0]*vet[1][1] - vet[1][0]*vet[0][1];
+      // derivatives of pv12[0] to ri
+      dpvdri[0][0] = 0.0;
+      dpvdri[0][1] = vet[0][2]-vet[1][2];
+      dpvdri[0][2] = vet[1][1]-vet[0][1];
+      // derivatives of pv12[1] to ri
+      dpvdri[1][0] = vet[1][2]-vet[0][2];
+      dpvdri[1][1] = 0.0;
+      dpvdri[1][2] = vet[0][0]-vet[1][0];
+      // derivatives of pv12[2] to ri
+      dpvdri[2][0] = vet[0][1]-vet[1][1];
+      dpvdri[2][1] = vet[1][0]-vet[0][0];
+      dpvdri[2][2] = 0.0;
+
+      dpv12[0][0][0] =  0.0;
+      dpv12[0][1][0] =  vet[1][2];
+      dpv12[0][2][0] = -vet[1][1];
+      dpv12[1][0][0] = -vet[1][2];
+      dpv12[1][1][0] =  0.0;
+      dpv12[1][2][0] =  vet[1][0];
+      dpv12[2][0][0] =  vet[1][1];
+      dpv12[2][1][0] = -vet[1][0];
+      dpv12[2][2][0] =  0.0;
+      
+      // derivatives respect to the second neighbor, atom l
+      dpv12[0][0][1] =  0.0;
+      dpv12[0][1][1] = -vet[0][2];
+      dpv12[0][2][1] =  vet[0][1];
+      dpv12[1][0][1] =  vet[0][2];
+      dpv12[1][1][1] =  0.0;
+      dpv12[1][2][1] = -vet[0][0];
+      dpv12[2][0][1] = -vet[0][1];
+      dpv12[2][1][1] =  vet[0][0];
+      dpv12[2][2][1] =  0.0;
+
+      // derivatives respect to the third neighbor, atom n
+      // derivatives of pv12 to rn is zero
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          dpv12[id][ip][2] = 0.0;
+        } 
+      }
+
+      n1[0] = pv12[0];
+      n1[1] = pv12[1];
+      n1[2] = pv12[2];
+      // the magnitude of the normal vector
+      nn2 = n1[0]*n1[0] + n1[1]*n1[1] + n1[2]*n1[2];
+      nn = sqrt(nn2);
+      if (nn == 0) error->all(FLERR,"The magnitude of the normal vector is zero");
+      // the unit normal vector
+      normal[i][0] = n1[0]/nn;
+      normal[i][1] = n1[1]/nn;
+      normal[i][2] = n1[2]/nn;
+      // derivatives of nn, dnn:3x1 vector
+      dni[0] = (n1[0]*dpvdri[0][0] + n1[1]*dpvdri[1][0] + n1[2]*dpvdri[2][0])/nn;
+      dni[1] = (n1[0]*dpvdri[0][1] + n1[1]*dpvdri[1][1] + n1[2]*dpvdri[2][1])/nn;
+      dni[2] = (n1[0]*dpvdri[0][2] + n1[1]*dpvdri[1][2] + n1[2]*dpvdri[2][2])/nn;
+      // derivatives of unit vector ni respect to ri, the result is 3x3 matrix
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          dnormdri[id][ip][i] = dpvdri[id][ip]/nn - n1[id]*dni[ip]/nn2;
+        }
+      }
+      // derivatives of non-normalized normal vector, dn1:3x3x3 array
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          for (m = 0; m < 3; m++){
+            dn1[id][ip][m] = dpv12[id][ip][m];
+          }
+        } 
+      }
+      // derivatives of nn, dnn:3x3 vector
+      // dnn[id][m]: the derivative of nn respect to r[id][m], id,m=0,1,2
+      // r[id][m]: the id's component of atom m
+      for (m = 0; m < 3; m++){
+        for (id = 0; id < 3; id++){
+          dnn[id][m] = (n1[0]*dn1[0][id][m] + n1[1]*dn1[1][id][m] + n1[2]*dn1[2][id][m])/nn;
+        }
+      }
+      // dnormal[id][ip][m][i]: the derivative of normal[id] respect to r[ip][m], id,ip=0,1,2
+      // for atom m, which is a neighbor atom of atom i, m=0,jnum-1
+      for (m = 0; m < 3; m++){
+        for (id = 0; id < 3; id++){
+          for (ip = 0; ip < 3; ip++){
+            dnormal[id][ip][m][i] = dn1[id][ip][m]/nn - n1[id]*dnn[ip][m]/nn2;
+          }
+        }
+      }
+    }
+//##############################################################################################
+
+    else if(cont == 3) {
+      pv12[0] = vet[0][1]*vet[1][2] - vet[1][1]*vet[0][2];
+      pv12[1] = vet[0][2]*vet[1][0] - vet[1][2]*vet[0][0];
+      pv12[2] = vet[0][0]*vet[1][1] - vet[1][0]*vet[0][1];
+      // derivatives respect to the first neighbor, atom k
+      dpv12[0][0][0] =  0.0;
+      dpv12[0][1][0] =  vet[1][2];
+      dpv12[0][2][0] = -vet[1][1];
+      dpv12[1][0][0] = -vet[1][2];
+      dpv12[1][1][0] =  0.0;
+      dpv12[1][2][0] =  vet[1][0];
+      dpv12[2][0][0] =  vet[1][1];
+      dpv12[2][1][0] = -vet[1][0];
+      dpv12[2][2][0] =  0.0;
+      // derivatives respect to the second neighbor, atom l
+      dpv12[0][0][1] =  0.0;
+      dpv12[0][1][1] = -vet[0][2];
+      dpv12[0][2][1] =  vet[0][1];
+      dpv12[1][0][1] =  vet[0][2];
+      dpv12[1][1][1] =  0.0;
+      dpv12[1][2][1] = -vet[0][0];
+      dpv12[2][0][1] = -vet[0][1];
+      dpv12[2][1][1] =  vet[0][0];
+      dpv12[2][2][1] =  0.0;
+
+      // derivatives respect to the third neighbor, atom n
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          dpv12[id][ip][2] = 0.0;
+        } 
+      }
+
+      pv31[0] = vet[2][1]*vet[0][2] - vet[0][1]*vet[2][2];
+      pv31[1] = vet[2][2]*vet[0][0] - vet[0][2]*vet[2][0];
+      pv31[2] = vet[2][0]*vet[0][1] - vet[0][0]*vet[2][1];
+      // derivatives respect to the first neighbor, atom k
+      dpv31[0][0][0] =  0.0;
+      dpv31[0][1][0] = -vet[2][2];
+      dpv31[0][2][0] =  vet[2][1];
+      dpv31[1][0][0] =  vet[2][2];
+      dpv31[1][1][0] =  0.0;
+      dpv31[1][2][0] = -vet[2][0];
+      dpv31[2][0][0] = -vet[2][1];
+      dpv31[2][1][0] =  vet[2][0];
+      dpv31[2][2][0] =  0.0;
+      // derivatives respect to the third neighbor, atom n
+      dpv31[0][0][2] =  0.0;
+      dpv31[0][1][2] =  vet[0][2];
+      dpv31[0][2][2] = -vet[0][1];
+      dpv31[1][0][2] = -vet[0][2];
+      dpv31[1][1][2] =  0.0;
+      dpv31[1][2][2] =  vet[0][0];
+      dpv31[2][0][2] =  vet[0][1];
+      dpv31[2][1][2] = -vet[0][0];
+      dpv31[2][2][2] =  0.0;
+      // derivatives respect to the second neighbor, atom l
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          dpv31[id][ip][1] = 0.0;
+        } 
+      }
+
+      pv23[0] = vet[1][1]*vet[2][2] - vet[2][1]*vet[1][2];
+      pv23[1] = vet[1][2]*vet[2][0] - vet[2][2]*vet[1][0];
+      pv23[2] = vet[1][0]*vet[2][1] - vet[2][0]*vet[1][1];
+      // derivatives respect to the second neighbor, atom k
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          dpv23[id][ip][0] = 0.0;
+        } 
+      }
+      // derivatives respect to the second neighbor, atom l
+      dpv23[0][0][1] =  0.0;
+      dpv23[0][1][1] =  vet[2][2];
+      dpv23[0][2][1] = -vet[2][1];
+      dpv23[1][0][1] = -vet[2][2];
+      dpv23[1][1][1] =  0.0;
+      dpv23[1][2][1] =  vet[2][0];
+      dpv23[2][0][1] =  vet[2][1];
+      dpv23[2][1][1] = -vet[2][0];
+      dpv23[2][2][1] =  0.0;
+      // derivatives respect to the third neighbor, atom n
+      dpv23[0][0][2] =  0.0;
+      dpv23[0][1][2] = -vet[1][2];
+      dpv23[0][2][2] =  vet[1][1];
+      dpv23[1][0][2] =  vet[1][2];
+      dpv23[1][1][2] =  0.0;
+      dpv23[1][2][2] = -vet[1][0];
+      dpv23[2][0][2] = -vet[1][1];
+      dpv23[2][1][2] =  vet[1][0];
+      dpv23[2][2][2] =  0.0;
+
+//############################################################################################
+      // average the normal vectors by using the 3 neighboring planes
+      n1[0] = (pv12[0] + pv31[0] + pv23[0])/cont;
+      n1[1] = (pv12[1] + pv31[1] + pv23[1])/cont;
+      n1[2] = (pv12[2] + pv31[2] + pv23[2])/cont;
+      // the magnitude of the normal vector
+      nn2 = n1[0]*n1[0] + n1[1]*n1[1] + n1[2]*n1[2];
+      nn = sqrt(nn2);
+      if (nn == 0) error->all(FLERR,"The magnitude of the normal vector is zero");
+      // the unit normal vector
+      normal[i][0] = n1[0]/nn;
+      normal[i][1] = n1[1]/nn;
+      normal[i][2] = n1[2]/nn;
+
+      // for the central atoms, dnormdri is always zero
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          dnormdri[id][ip][i] = 0.0;
+        }
+      } 
+
+      // derivatives of non-normalized normal vector, dn1:3x3x3 array
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          for (m = 0; m < 3; m++){
+            dn1[id][ip][m] = (dpv12[id][ip][m] + dpv23[id][ip][m] + dpv31[id][ip][m])/cont;
+          }
+        } 
+      }
+      // derivatives of nn, dnn:3x3 vector
+      // dnn[id][m]: the derivative of nn respect to r[id][m], id,m=0,1,2
+      // r[id][m]: the id's component of atom m
+      for (m = 0; m < 3; m++){
+        for (id = 0; id < 3; id++){
+          dnn[id][m] = (n1[0]*dn1[0][id][m] + n1[1]*dn1[1][id][m] + n1[2]*dn1[2][id][m])/nn;
+        }
+      }
+      // dnormal[id][ip][m][i]: the derivative of normal[id] respect to r[ip][m], id,ip=0,1,2
+      // for atom m, which is a neighbor atom of atom i, m=0,jnum-1
+      for (m = 0; m < 3; m++){
+        for (id = 0; id < 3; id++){
+          for (ip = 0; ip < 3; ip++){
+            dnormal[id][ip][m][i] = dn1[id][ip][m]/nn - n1[id]*dnn[ip][m]/nn2;
+          }
+        }
+      }
+    }
+    else {
+      error->all(FLERR,"There are too many neighbors for calculating normals");
+    }
+
+//##############################################################################################
+  }
+}
+
+/* ----------------------------------------------------------------------
+   init specific to this pair style
+------------------------------------------------------------------------- */
+
+void PairILP::init_style()
+{
+  if (force->newton_pair == 0)
+    error->all(FLERR,"Pair style ILP requires newton pair on");
+
+  // need a full neighbor list, including neighbors of ghosts
+
+  int irequest = neighbor->request(this,instance_me);
+  neighbor->requests[irequest]->half = 0;
+  neighbor->requests[irequest]->full = 1;
+  neighbor->requests[irequest]->ghost = 1;
+
+  // local ILP neighbor list
+  // create pages if first time or if neighbor pgsize/oneatom has changed
+
+  int create = 0;
+  if (ipage == NULL) create = 1;
+  if (pgsize != neighbor->pgsize) create = 1;
+  if (oneatom != neighbor->oneatom) create = 1;
+
+  if (create) {
+    delete [] ipage;
+    pgsize = neighbor->pgsize;
+    oneatom = neighbor->oneatom;
+
+    int nmypage= comm->nthreads;
+    ipage = new MyPage<int>[nmypage];
+    for (int i = 0; i < nmypage; i++)
+      ipage[i].init(oneatom,pgsize,PGDELTA);
+  }
+}
+
+
+/* ----------------------------------------------------------------------
+   create ILP neighbor list from main neighbor list
+   ILP neighbor list stores neighbors of ghost atoms
+   ILP_numneigh for calcualting normals and
+   ILP_pair_numneigh for calculating force
+------------------------------------------------------------------------- */
+
+void PairILP::ILP_neigh()
+{
+  int i,j,ii,jj,n,np,allnum,inum,jnum,itype,jtype;
+  double xtmp,ytmp,ztmp,delx,dely,delz,rsq;
+  int *ilist,*jlist,*numneigh,**firstneigh;
+  int *neighptr;
+
+  double **x = atom->x;
+  int *type = atom->type;
+
+  if (atom->nmax > maxlocal) {
+    maxlocal = atom->nmax;
+    memory->destroy(ILP_numneigh);
+    memory->sfree(ILP_firstneigh);
+    memory->create(ILP_numneigh,maxlocal,"ILP:numneigh");
+    ILP_firstneigh = (int **) memory->smalloc(maxlocal*sizeof(int *),"ILP:firstneigh");
+  }
+
+  inum = list->inum;
+  allnum = list->inum + list->gnum;
+  ilist = list->ilist;
+  numneigh = list->numneigh;
+  firstneigh = list->firstneigh;
+
+  // store all ILP neighs of owned and ghost atoms
+  // scan full neighbor list of I
+
+  ipage->reset();
+
+  for (ii = 0; ii < allnum; ii++) {
+    i = ilist[ii];
+
+    n = 0;
+    neighptr = ipage->vget();
+
+    xtmp = x[i][0];
+    ytmp = x[i][1];
+    ztmp = x[i][2];
+    itype = map[type[i]];
+    jlist = firstneigh[i];
+    jnum = numneigh[i];
+    
+    for (jj = 0; jj < jnum; jj++) {
+      j = jlist[jj];
+      j &= NEIGHMASK;
+      jtype = map[type[j]];
+      delx = xtmp - x[j][0];
+      dely = ytmp - x[j][1];
+      delz = ztmp - x[j][2];
+      rsq = delx*delx + dely*dely + delz*delz;
+
+      if (rsq != 0 && rsq < cutILPsq[itype][jtype] && atom->molecule[i] == atom->molecule[j]) {
+	neighptr[n++] = j;
+      }
+    }
+
+    ILP_firstneigh[i] = neighptr;
+    ILP_numneigh[i] = n;
+    ipage->vgot(n);
+    if (ipage->status())
+      error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
+  }
+}
+
+
+/* ----------------------------------------------------------------------
+   allocate all arrays
+------------------------------------------------------------------------- */
+
+void PairILP::allocate()
+{
+  allocated = 1;
+  int n = atom->ntypes;
+
+  memory->create(setflag,n+1,n+1,"pair:setflag");
+  for (int i = 1; i <= n; i++)
+    for (int j = i; j <= n; j++)
+      setflag[i][j] = 0;
+
+  memory->create(cutsq,n+1,n+1,"pair:cutsq");
+  memory->create(cut,n+1,n+1,"pair:cut");
+  memory->create(offset,n+1,n+1,"pair:offset");
+  map = new int[atom->ntypes+1];
+}
+
+/* ----------------------------------------------------------------------
+   global settings
+------------------------------------------------------------------------- */
+
+void PairILP::settings(int narg, char **arg)
+{
+  if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command");
+  if (strcmp(force->pair_style,"hybrid/overlay")!=0)
+    error->all(FLERR,"ERROR: requires hybrid/overlay pair_style");
+
+  cut_global = force->numeric(FLERR,arg[0]);
+  if (narg == 2) tap_flag = force->numeric(FLERR,arg[1]);
+
+  // reset cutoffs that have been explicitly set
+
+  if (allocated) {
+    int i,j;
+    for (i = 1; i <= atom->ntypes; i++)
+      for (j = i; j <= atom->ntypes; j++)
+        if (setflag[i][j]) cut[i][j] = cut_global;
+  }
+}
+
+/* ----------------------------------------------------------------------
+   set coeffs for one or more type pairs
+------------------------------------------------------------------------- */
+
+void PairILP::coeff(int narg, char **arg)
+{
+  int i,j,n; 
+
+  if (narg != 3 + atom->ntypes) 
+    error->all(FLERR,"Incorrect args for pair coefficients");
+  if (!allocated) allocate();
+
+  int ilo,ihi,jlo,jhi;
+  force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
+  force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
+
+  // read args that map atom types to elements in potential file
+  // map[i] = which element the Ith atom type is, -1 if NULL
+  // nelements = # of unique elements
+  // elements = list of element names
+
+  if (elements) {
+    for (i = 0; i < nelements; i++) delete [] elements[i];
+    delete [] elements;
+  }
+  elements = new char*[atom->ntypes];
+  for (i = 0; i < atom->ntypes; i++) elements[i] = NULL;
+
+  nelements = 0;
+  for (i = 3; i < narg; i++) {
+    if (strcmp(arg[i],"NULL") == 0) {
+      map[i-2] = -1;
+      continue;
+    }
+    for (j = 0; j < nelements; j++)
+      if (strcmp(arg[i],elements[j]) == 0) break;
+    map[i-2] = j;
+    if (j == nelements) {
+      n = strlen(arg[i]) + 1;
+      elements[j] = new char[n];
+      strcpy(elements[j],arg[i]);
+      nelements++;
+    }
+  }
+
+
+  read_file(arg[2]);
+  
+  double cut_one = cut_global;
+
+  int count = 0;
+  for (int i = ilo; i <= ihi; i++) {
+    for (int j = MAX(jlo,i); j <= jhi; j++) {
+      cut[i][j] = cut_one;
+      setflag[i][j] = 1;
+      count++;
+    }
+  }
+
+  if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
+}
+
+
+/* ----------------------------------------------------------------------
+   init for one type pair i,j and corresponding j,i
+------------------------------------------------------------------------- */
+
+double PairILP::init_one(int i, int j)
+{
+  if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
+
+  if (offset_flag  && (cut[i][j] > 0.0)) {
+    int iparam_ij = elem2param[map[i]][map[j]];
+    Param& p = params[iparam_ij];
+    offset[i][j] = -p.C6*pow(1.0/cut[i][j],6)/(1.0 + exp(-p.d*(cut[i][j]/p.seff - 1.0)));
+  } else offset[i][j] = 0.0;
+  offset[j][i] = offset[i][j];
+
+  return cut[i][j];
+}
+
+/* ----------------------------------------------------------------------
+   read Interlayer potential file
+------------------------------------------------------------------------- */
+
+void PairILP::read_file(char *filename)
+{
+  int params_per_line = 13;
+  char **words = new char*[params_per_line+1];
+  memory->sfree(params);
+  params = NULL;
+  nparams = maxparam = 0;
+
+  // open file on proc 0
+
+  FILE *fp;
+  if (comm->me == 0) {
+    fp = force->open_potential(filename);
+    if (fp == NULL) {
+      char str[128];
+      sprintf(str,"Cannot open ILP potential file %s",filename);
+      error->one(FLERR,str);
+    }
+  }
+
+  // read each line out of file, skipping blank lines or leading '#'
+  // store line of params if all 3 element tags are in element list
+
+  int i,j,n,m,nwords,ielement,jelement;
+  char line[MAXLINE],*ptr;
+  int eof = 0;
+
+  while (1) {
+    if (comm->me == 0) {
+      ptr = fgets(line,MAXLINE,fp);
+      if (ptr == NULL) {
+        eof = 1;
+        fclose(fp);
+      } else n = strlen(line) + 1;
+    }
+    MPI_Bcast(&eof,1,MPI_INT,0,world);
+    if (eof) break;
+    MPI_Bcast(&n,1,MPI_INT,0,world);
+    MPI_Bcast(line,n,MPI_CHAR,0,world);
+
+    // strip comment, skip line if blank
+
+    if ((ptr = strchr(line,'#'))) *ptr = '\0';
+    nwords = atom->count_words(line);
+    if (nwords == 0) continue;
+
+    // concatenate additional lines until have params_per_line words
+
+    while (nwords < params_per_line) {
+      n = strlen(line);
+      if (comm->me == 0) {
+        ptr = fgets(&line[n],MAXLINE-n,fp);
+        if (ptr == NULL) {
+          eof = 1;
+          fclose(fp);
+        } else n = strlen(line) + 1;
+      }
+      MPI_Bcast(&eof,1,MPI_INT,0,world);
+      if (eof) break;
+      MPI_Bcast(&n,1,MPI_INT,0,world);
+      MPI_Bcast(line,n,MPI_CHAR,0,world);
+      if ((ptr = strchr(line,'#'))) *ptr = '\0';
+      nwords = atom->count_words(line);
+    }
+
+    if (nwords != params_per_line)
+      error->all(FLERR,"Insufficient format in ILP potential file");
+
+    // words = ptrs to all words in line
+
+    nwords = 0;
+    words[nwords++] = strtok(line," \t\n\r\f");
+    while ((words[nwords++] = strtok(NULL," \t\n\r\f"))) continue;
+
+    // ielement,jelement = 1st args
+    // if these 2 args are in element list, then parse this line
+    // else skip to next line (continue)
+
+    for (ielement = 0; ielement < nelements; ielement++)
+      if (strcmp(words[0],elements[ielement]) == 0) break;
+    if (ielement == nelements) continue;
+    for (jelement = 0; jelement < nelements; jelement++)
+      if (strcmp(words[1],elements[jelement]) == 0) break;
+    if (jelement == nelements) continue;
+
+    // load up parameter settings and error check their values
+
+    if (nparams == maxparam) {
+      maxparam += DELTA;
+      params = (Param *) memory->srealloc(params,maxparam*sizeof(Param),
+                                          "pair:params");
+    }
+
+    params[nparams].ielement = ielement;
+    params[nparams].jelement = jelement;
+    params[nparams].z0       = atof(words[2]);
+    params[nparams].alpha    = atof(words[3]);
+    params[nparams].delta    = atof(words[4]);
+    params[nparams].epsilon  = atof(words[5]);
+    params[nparams].C        = atof(words[6]);
+    params[nparams].d        = atof(words[7]);
+    params[nparams].sR       = atof(words[8]);
+    params[nparams].reff     = atof(words[9]);
+    params[nparams].C6       = atof(words[10]);
+    // S provides a convenient scaling of all energies
+    params[nparams].S        = atof(words[11]);
+    params[nparams].rcut     = atof(words[12]);
+
+    // energies in meV further scaled by S
+    // S = 43.3634 meV = 1 kcal/mol
+    double meV = 1e-3*params[nparams].S; 
+    params[nparams].C *= meV;
+    params[nparams].C6 *= meV;
+    params[nparams].epsilon *= meV;
+
+    // precompute some quantities
+    params[nparams].delta2inv = pow(params[nparams].delta,-2.0);
+    params[nparams].lambda = params[nparams].alpha/params[nparams].z0;
+    params[nparams].seff = params[nparams].sR * params[nparams].reff;
+
+    nparams++;
+  }
+  memory->destroy(elem2param);
+  memory->destroy(cutILPsq);
+  memory->create(elem2param,nelements,nelements,"pair:elem2param");
+  memory->create(cutILPsq,nelements,nelements,"pair:cutILPsq");
+  for (i = 0; i < nelements; i++) {
+    for (j = 0; j < nelements; j++) {
+      n = -1;
+      for (m = 0; m < nparams; m++) {
+        if (i == params[m].ielement && j == params[m].jelement) {
+          if (n >= 0) error->all(FLERR,"Potential file has duplicate entry");
+          n = m;
+        }
+      }
+      if (n < 0) error->all(FLERR,"Potential file is missing an entry");
+      elem2param[i][j] = n;
+      cutILPsq[i][j] = params[n].rcut*params[n].rcut;
+    }
+  }
+  delete [] words;
+}
+
+/* ---------------------------------------------------------------------- */
+
+double PairILP::single(int i, int j, int itype, int jtype, double rsq,
+                         double factor_coul, double factor_lj,
+                         double &fforce)
+{
+  double r,r2inv,r6inv,r8inv,forcelj,philj,fpair;
+  double Tap,dTap,Vkc,TSvdw,TSvdw2inv;
+
+  int iparam_ij = elem2param[map[itype]][map[jtype]];
+  Param& p = params[iparam_ij];
+
+  r = sqrt(rsq);
+  // turn on/off Tapper function
+  if (tap_flag) {
+    Tap = calc_Tap(r,sqrt(cutsq[itype][jtype]));
+    dTap = calc_dTap(r,sqrt(cutsq[itype][jtype]));
+  } else {Tap = 1.0; dTap = 0.0;}
+
+  r2inv = 1.0/rsq;
+  r6inv = r2inv*r2inv*r2inv;
+  r8inv = r2inv*r6inv;
+
+  TSvdw = 1.0 + exp(-p.d*(r/p.seff - 1.0));
+  TSvdw2inv = pow(TSvdw,-2.0);
+  Vkc = -p.C6*r6inv/TSvdw;
+  // derivatives
+  fpair = -6.0*p.C6*r8inv/TSvdw + p.d/p.seff*p.C6*(TSvdw - 1.0)*r6inv*TSvdw2inv/r;
+  forcelj = fpair;
+  fforce = factor_lj*(forcelj*Tap - Vkc*dTap/r);
+
+  philj = Vkc*Tap;
+  return factor_lj*philj;
+}
+
+
+/* ---------------------------------------------------------------------- */
+
+int PairILP::pack_forward_comm(int n, int *list, double *buf,
+                               int pbc_flag, int *pbc)
+{
+  int i,j,m,id,ip,l;
+
+  m = 0;
+  for (i = 0; i < n; i++) {
+    j = list[i];
+    buf[m++] = normal[j][0];
+    buf[m++] = normal[j][1];
+    buf[m++] = normal[j][2];
+    buf[m++] = dnormdri[0][0][j];
+    buf[m++] = dnormdri[0][1][j];
+    buf[m++] = dnormdri[0][2][j];
+    buf[m++] = dnormdri[1][0][j];
+    buf[m++] = dnormdri[1][1][j];
+    buf[m++] = dnormdri[1][2][j];
+    buf[m++] = dnormdri[2][0][j];
+    buf[m++] = dnormdri[2][1][j];
+    buf[m++] = dnormdri[2][2][j];
+    for (l = 0; l < 3; l++){
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+	  buf[m++] = dnormal[id][ip][l][j];
+        }
+      }
+    }
+  }
+  return m;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairILP::unpack_forward_comm(int n, int first, double *buf)
+{
+  int i,m,last,id,ip,l;
+
+  m = 0;
+  last = first + n; 
+  for (i = first; i < last; i++) {
+    normal[i][0] = buf[m++];
+    normal[i][1] = buf[m++];
+    normal[i][2] = buf[m++];
+    dnormdri[0][0][i] = buf[m++];
+    dnormdri[0][1][i] = buf[m++];
+    dnormdri[0][2][i] = buf[m++];
+    dnormdri[1][0][i] = buf[m++];
+    dnormdri[1][1][i] = buf[m++];
+    dnormdri[1][2][i] = buf[m++];
+    dnormdri[2][0][i] = buf[m++];
+    dnormdri[2][1][i] = buf[m++];
+    dnormdri[2][2][i] = buf[m++];
+    for (l = 0; l < 3; l++){
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+	  dnormal[id][ip][l][i] = buf[m++];
+        }
+      }
+    }
+  }
+}
+
+/* ---------------------------------------------------------------------- */
diff --git a/src/USER-MISC/pair_ilp_gr_hBN.h b/src/USER-MISC/pair_ilp_gr_hBN.h
new file mode 100644
index 0000000000000000000000000000000000000000..e25910d929eed85e3245852986f2e9d12758fd30
--- /dev/null
+++ b/src/USER-MISC/pair_ilp_gr_hBN.h
@@ -0,0 +1,143 @@
+/* ----------------------------------------------------------------------
+   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
+   http://lammps.sandia.gov, Sandia National Laboratories
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#ifdef PAIR_CLASS
+
+PairStyle(ILP/graphene/hBN,PairILP)
+
+#else
+
+#ifndef LMP_PAIR_ILP_H
+#define LMP_PAIR_ILP_H
+
+#include "pair.h"
+#include "my_page.h"
+#include <math.h>
+
+namespace LAMMPS_NS {
+
+class PairILP : public Pair {
+ public:
+  PairILP(class LAMMPS *);
+  virtual ~PairILP();
+
+  virtual void compute(int, int);
+  void settings(int, char **);
+  void coeff(int, char **);
+  double init_one(int, int);
+  void init_style();
+  void calc_normal();
+  int pack_forward_comm(int, int *, double *, int, int *);
+  void unpack_forward_comm(int, int, double *);
+  double single(int, int, int, int, double, double, double, double &);
+
+ protected:
+  int me;
+  int maxlocal;                    // size of numneigh, firstneigh arrays
+  int pgsize;                      // size of neighbor page
+  int oneatom;                     // max # of neighbors for one atom
+  MyPage<int> *ipage;              // neighbor list pages
+  int *ILP_numneigh;                // # of pair neighbors for each atom
+  int **ILP_firstneigh;             // ptr to 1st neighbor of each atom
+  int tap_flag;			   // flag to turn on/off Tapper function
+
+  struct Param {
+    double z0,alpha,epsilon,C,delta,d,sR,reff,C6,S;
+    double delta2inv,seff,lambda,rcut;
+    int ielement,jelement;
+  };
+  Param *params;       // parameter set for I-J interactions
+  char **elements;     // names of unique elements
+  int **elem2param;    // mapping from element pairs to parameters
+  int *map;            // mapping from atom types to elements
+  int nelements;       // # of unique elements
+  int nparams;         // # of stored parameter sets
+  int maxparam;        // max # of parameter sets
+  int nmax;            // max # of atoms
+
+  double cut_global;
+  double cut_normal;
+  double **cut;
+  double **cutILPsq;    // mapping the cutoff from element pairs to parameters
+  double **offset;
+  double **normal;
+  double ***dnormdri;
+  double ****dnormal;
+  
+  void read_file( char * );
+  void allocate();
+  void ILP_neigh();
+  
+  /* ----Calculate the long-range cutoff term */
+  inline double calc_Tap(double r_ij, double Rcut) {
+    double Tap,r;
+    double Tap_coeff[8] = {1.0,0.0,0.0,0.0,-35.0,84.0,-70.0,20.0};
+  
+    r = r_ij/Rcut; 
+    if(r >= 1.0) {Tap = 0.0;}
+    else {
+      Tap = Tap_coeff[7] * r + Tap_coeff[6];
+      Tap = Tap * r  + Tap_coeff[5];
+      Tap = Tap * r  + Tap_coeff[4];
+      Tap = Tap * r  + Tap_coeff[3];
+      Tap = Tap * r  + Tap_coeff[2];
+      Tap = Tap * r  + Tap_coeff[1];
+      Tap = Tap * r  + Tap_coeff[0];
+    }
+    return(Tap);
+}
+
+  /* ----Calculate the derivatives of long-range cutoff term */
+  inline double calc_dTap(double r_ij, double Rcut) {
+    double dTap,r;
+    double Tap_coeff[8] = {1.0,0.0,0.0,0.0,-35.0,84.0,-70.0,20.0};
+
+    r = r_ij/Rcut; 
+    if(r >= 1.0) {dTap = 0.0;}
+    else {
+      dTap = 7.0*Tap_coeff[7] * r + 6.0*Tap_coeff[6];
+      dTap = dTap * r  + 5.0*Tap_coeff[5];
+      dTap = dTap * r  + 4.0*Tap_coeff[4];
+      dTap = dTap * r  + 3.0*Tap_coeff[3];
+      dTap = dTap * r  + 2.0*Tap_coeff[2];
+      dTap = dTap * r  + Tap_coeff[1];
+      dTap = dTap/Rcut;
+    }
+    return(dTap);
+  }
+};
+
+}
+
+#endif
+#endif
+
+/* ERROR/WARNING messages:
+
+E: Illegal ... command
+
+Self-explanatory.  Check the input script syntax and compare to the
+documentation for the command.  You can use -echo screen as a
+command-line option when running LAMMPS to see the offending line.
+
+E: Incorrect args for pair coefficients
+
+Self-explanatory.  Check the input script or data file.
+
+E: All pair coeffs are not set
+
+All pair coefficients must be set in the data file or by the
+pair_coeff command before running a simulation.
+
+*/
+
diff --git a/src/USER-MISC/pair_kolmogorov_crespi_full.cpp b/src/USER-MISC/pair_kolmogorov_crespi_full.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0068144e4a7056d7566e51988044eaa3521b8413
--- /dev/null
+++ b/src/USER-MISC/pair_kolmogorov_crespi_full.cpp
@@ -0,0 +1,1121 @@
+/* ----------------------------------------------------------------------
+   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: Wengen Ouyang (Tel Aviv University)
+   e-mail: w.g.ouyang at gmail dot com
+   based on previous versions by Jaap Kroes
+  
+   This is a complete version of the potential described in
+   [Kolmogorov & Crespi, Phys. Rev. B 71, 235415 (2005)]
+------------------------------------------------------------------------- */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mpi.h>
+#include "pair_kolmogorov_crespi_full.h"
+#include "atom.h"
+#include "comm.h"
+#include "force.h"
+#include "neighbor.h"
+#include "neigh_list.h"
+#include "neigh_request.h"
+#include "my_page.h"
+#include "memory.h"
+#include "error.h"
+
+using namespace LAMMPS_NS;
+
+#define MAXLINE 1024
+#define DELTA 4
+#define PGDELTA 1
+
+/* ---------------------------------------------------------------------- */
+
+PairKolmogorovCrespiFull::PairKolmogorovCrespiFull(LAMMPS *lmp) : Pair(lmp)
+{
+  writedata = 1;
+
+  // initialize element to parameter maps
+  nelements = 0;
+  elements = NULL;
+  nparams = maxparam = 0;
+  params = NULL;
+  elem2param = NULL;
+  cutKCsq = NULL;
+  map = NULL;
+
+  nmax = 0;
+  maxlocal = 0;
+  KC_numneigh = NULL;
+  KC_firstneigh = NULL;
+  ipage = NULL;
+  pgsize = oneatom = 0;
+
+  normal = NULL;
+  dnormal = NULL;
+  dnormdri = NULL;
+
+  // always compute energy offset
+  offset_flag = 1;
+
+  // set comm size needed by this Pair
+  comm_forward = 39;
+  tap_flag = 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+PairKolmogorovCrespiFull::~PairKolmogorovCrespiFull()
+{
+  memory->destroy(KC_numneigh);
+  memory->sfree(KC_firstneigh);
+  delete [] ipage;
+  memory->destroy(normal);
+  memory->destroy(dnormal);
+  memory->destroy(dnormdri);
+  
+  if (allocated) {
+    memory->destroy(setflag);
+    memory->destroy(cutsq);
+    memory->destroy(cut);
+    memory->destroy(offset);
+  }
+
+  if (elements)
+    for (int i = 0; i < nelements; i++) delete [] elements[i];
+  delete [] elements;
+  memory->destroy(params);
+  memory->destroy(elem2param);
+  memory->destroy(cutKCsq);
+  if (allocated) delete [] map;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairKolmogorovCrespiFull::compute(int eflag, int vflag)
+{
+  int i,j,ii,jj,inum,jnum,itype,jtype,id,k,l,kk,ll;
+  tagint itag,jtag;
+  double prodnorm1,prodnorm2,fkcx,fkcy,fkcz;
+  double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair,fpair1,fpair2;
+  double rsq,r,rhosq1,rhosq2,exp0,exp1,exp2,r2inv,r6inv,r8inv,Tap,dTap,Vkc;
+  double frho1,frho2,sumC1,sumC2,sumC11,sumC22,sumCff,fsum,rdsq1,rdsq2;
+  int *ilist,*jlist,*numneigh,**firstneigh;
+  int *KC_neighs_i,*KC_neighs_j;
+  
+  evdwl = 0.0;
+  if (eflag || vflag) ev_setup(eflag,vflag);
+  else evflag = vflag_fdotr = 0;
+
+  double **x = atom->x;
+  double **f = atom->f;
+  int *type = atom->type;
+  tagint *tag = atom->tag;
+  int nlocal = atom->nlocal;
+  int newton_pair = force->newton_pair;
+  double dprodnorm1[3] = {0.0, 0.0, 0.0};
+  double dprodnorm2[3] = {0.0, 0.0, 0.0};
+  double fp1[3] = {0.0, 0.0, 0.0};
+  double fp2[3] = {0.0, 0.0, 0.0};
+  double fprod1[3] = {0.0, 0.0, 0.0};
+  double fprod2[3] = {0.0, 0.0, 0.0};
+
+  inum = list->inum;	
+  ilist = list->ilist;  
+  numneigh = list->numneigh;  
+  firstneigh = list->firstneigh; 
+  // Build full neighbor list
+  KC_neigh(); 
+  // Calculate the normals
+  calc_normal();
+
+  // communicate the normal vector and its derivatives
+  comm->forward_comm_pair(this);
+
+  // loop over neighbors of my atoms
+  for (ii = 0; ii < inum; ii++) {
+    i = ilist[ii];
+    itag = tag[i];
+    xtmp = x[i][0];
+    ytmp = x[i][1];
+    ztmp = x[i][2];
+    itype = type[i];
+    jlist = firstneigh[i];
+    jnum = numneigh[i];
+
+    for (jj = 0; jj < jnum; jj++) {
+      j = jlist[jj];
+      j &= NEIGHMASK;
+      jtype = type[j];
+      jtag = tag[j];
+
+      // two-body interactions from full neighbor list, skip half of them
+      if (itag > jtag) {
+        if ((itag+jtag) % 2 == 0) continue;
+      } else if (itag < jtag) {
+        if ((itag+jtag) % 2 == 1) continue;
+      } else {
+        if (x[j][2] < ztmp) continue;
+        if (x[j][2] == ztmp && x[j][1] < ytmp) continue;
+        if (x[j][2] == ztmp && x[j][1] == ytmp && x[j][0] < xtmp) continue;
+      }
+
+      delx = xtmp - x[j][0];
+      dely = ytmp - x[j][1];
+      delz = ztmp - x[j][2];
+      rsq = delx*delx + dely*dely + delz*delz;
+      
+      // only include the interation between different layers
+      if (rsq < cutsq[itype][jtype] && atom->molecule[i] != atom->molecule[j]) {
+
+        int iparam_ij = elem2param[map[itype]][map[jtype]];
+        Param& p = params[iparam_ij];
+
+        r = sqrt(rsq);
+        r2inv = 1.0/rsq;
+        r6inv = r2inv*r2inv*r2inv;
+        r8inv = r2inv*r6inv;
+	// turn on/off Tapper function
+	if (tap_flag) {
+	  Tap = calc_Tap(r,sqrt(cutsq[itype][jtype]));
+	  dTap = calc_dTap(r,sqrt(cutsq[itype][jtype]));
+	} else {Tap = 1.0; dTap = 0.0;}
+
+        // Calculate the transverse distance
+        // note that rho_ij does not equal to rho_ji except when normals are all along z
+        prodnorm1 = normal[i][0]*delx + normal[i][1]*dely + normal[i][2]*delz;
+        prodnorm2 = normal[j][0]*delx + normal[j][1]*dely + normal[j][2]*delz;
+        rhosq1 = rsq - prodnorm1*prodnorm1;  // rho_ij
+        rhosq2 = rsq - prodnorm2*prodnorm2;  // rho_ji
+        rdsq1 = rhosq1*p.delta2inv; // (rho_ij/delta)^2
+        rdsq2 = rhosq2*p.delta2inv; // (rho_ji/delta)^2
+
+        // store exponents
+        exp0 = exp(-p.lambda*(r-p.z0));
+        exp1 = exp(-rdsq1);
+        exp2 = exp(-rdsq2);
+
+        sumC1 = p.C0 + p.C2*rdsq1 + p.C4*rdsq1*rdsq1; 
+        sumC2 = p.C0 + p.C2*rdsq2 + p.C4*rdsq2*rdsq2; 
+        sumC11 = (p.C2 + 2.0*p.C4*rdsq1)*p.delta2inv;
+        sumC22 = (p.C2 + 2.0*p.C4*rdsq2)*p.delta2inv;
+        frho1 = exp1*sumC1;
+        frho2 = exp2*sumC2;
+        sumCff = p.C + frho1 + frho2;
+	Vkc = -p.A*p.z06*r6inv + exp0*sumCff;
+
+        // derivatives
+        fpair = -6.0*p.A*p.z06*r8inv + p.lambda*exp0/r*sumCff;
+        fpair1 = 2.0*exp0*exp1*(p.delta2inv*sumC1 - sumC11);
+        fpair2 = 2.0*exp0*exp2*(p.delta2inv*sumC2 - sumC22);
+        fsum = fpair + fpair1 + fpair2;
+        // derivatives of the product of rij and ni, the result is a vector
+        dprodnorm1[0] = dnormdri[0][0][i]*delx + dnormdri[1][0][i]*dely + dnormdri[2][0][i]*delz;
+        dprodnorm1[1] = dnormdri[0][1][i]*delx + dnormdri[1][1][i]*dely + dnormdri[2][1][i]*delz;
+        dprodnorm1[2] = dnormdri[0][2][i]*delx + dnormdri[1][2][i]*dely + dnormdri[2][2][i]*delz;
+        // derivatives of the product of rji and nj, the result is a vector
+        dprodnorm2[0] = dnormdri[0][0][j]*delx + dnormdri[1][0][j]*dely + dnormdri[2][0][j]*delz;
+        dprodnorm2[1] = dnormdri[0][1][j]*delx + dnormdri[1][1][j]*dely + dnormdri[2][1][j]*delz;
+        dprodnorm2[2] = dnormdri[0][2][j]*delx + dnormdri[1][2][j]*dely + dnormdri[2][2][j]*delz;
+        fp1[0] = prodnorm1*normal[i][0]*fpair1;
+        fp1[1] = prodnorm1*normal[i][1]*fpair1;
+        fp1[2] = prodnorm1*normal[i][2]*fpair1;
+        fp2[0] = prodnorm2*normal[j][0]*fpair2;
+        fp2[1] = prodnorm2*normal[j][1]*fpair2;
+        fp2[2] = prodnorm2*normal[j][2]*fpair2;
+        fprod1[0] = prodnorm1*dprodnorm1[0]*fpair1;
+        fprod1[1] = prodnorm1*dprodnorm1[1]*fpair1;
+        fprod1[2] = prodnorm1*dprodnorm1[2]*fpair1;
+        fprod2[0] = prodnorm2*dprodnorm2[0]*fpair2;
+        fprod2[1] = prodnorm2*dprodnorm2[1]*fpair2;
+        fprod2[2] = prodnorm2*dprodnorm2[2]*fpair2;
+        fkcx = (delx*fsum - fp1[0] - fp2[0])*Tap - Vkc*dTap*delx/r;
+        fkcy = (dely*fsum - fp1[1] - fp2[1])*Tap - Vkc*dTap*dely/r; 
+        fkcz = (delz*fsum - fp1[2] - fp2[2])*Tap - Vkc*dTap*delz/r; 
+
+        f[i][0] += fkcx - fprod1[0]*Tap;
+        f[i][1] += fkcy - fprod1[1]*Tap;
+        f[i][2] += fkcz - fprod1[2]*Tap;
+        if (newton_pair || j < nlocal) {
+          f[j][0] -= fkcx + fprod2[0]*Tap;
+          f[j][1] -= fkcy + fprod2[1]*Tap;
+          f[j][2] -= fkcz + fprod2[2]*Tap;
+        }
+
+	// calculate the forces acted on the neighbors of atom i from atom j
+	KC_neighs_i = KC_firstneigh[i];
+  	for (kk = 0; kk < KC_numneigh[i]; kk++) {
+	  k = KC_neighs_i[kk];
+          if (k == i) continue;
+          // derivatives of the product of rij and ni respect to rk, k=0,1,2, where atom k is the neighbors of atom i
+          dprodnorm1[0] = dnormal[0][0][kk][i]*delx + dnormal[1][0][kk][i]*dely + dnormal[2][0][kk][i]*delz;
+          dprodnorm1[1] = dnormal[0][1][kk][i]*delx + dnormal[1][1][kk][i]*dely + dnormal[2][1][kk][i]*delz;
+          dprodnorm1[2] = dnormal[0][2][kk][i]*delx + dnormal[1][2][kk][i]*dely + dnormal[2][2][kk][i]*delz;
+	  f[k][0] += (-prodnorm1*dprodnorm1[0]*fpair1)*Tap;
+	  f[k][1] += (-prodnorm1*dprodnorm1[1]*fpair1)*Tap;
+	  f[k][2] += (-prodnorm1*dprodnorm1[2]*fpair1)*Tap;
+	}
+
+	// calculate the forces acted on the neighbors of atom j from atom i
+	KC_neighs_j = KC_firstneigh[j];
+  	for (ll = 0; ll < KC_numneigh[j]; ll++) {
+	  l = KC_neighs_j[ll];
+          if (l == j) continue;
+          if (newton_pair || l < nlocal) {
+            // derivatives of the product of rji and nj respect to rl, l=0,1,2, where atom l is the neighbors of atom j
+            dprodnorm2[0] = dnormal[0][0][ll][j]*delx + dnormal[1][0][ll][j]*dely + dnormal[2][0][ll][j]*delz;
+            dprodnorm2[1] = dnormal[0][1][ll][j]*delx + dnormal[1][1][ll][j]*dely + dnormal[2][1][ll][j]*delz;
+            dprodnorm2[2] = dnormal[0][2][ll][j]*delx + dnormal[1][2][ll][j]*dely + dnormal[2][2][ll][j]*delz;
+	    f[l][0] += (-prodnorm2*dprodnorm2[0]*fpair2)*Tap;
+	    f[l][1] += (-prodnorm2*dprodnorm2[1]*fpair2)*Tap;
+	    f[l][2] += (-prodnorm2*dprodnorm2[2]*fpair2)*Tap;
+	  }
+	}
+
+        if (eflag) {
+          if (tap_flag) evdwl = Tap*Vkc;
+          else  evdwl = Vkc - offset[itype][jtype];
+        }
+
+        if (evflag){
+          ev_tally_xyz(i,j,nlocal,newton_pair,evdwl,0,
+                       fkcx,fkcy,fkcz,delx,dely,delz);
+        }
+      }
+    }
+  }
+  if (vflag_fdotr) virial_fdotr_compute();
+}
+
+/* ----------------------------------------------------------------------
+   Calculate the normals for each atom
+------------------------------------------------------------------------- */
+void PairKolmogorovCrespiFull::calc_normal()
+{
+  int i,j,ii,jj,inum,jnum,itype,jtype;
+  int cont,k,kk,cont1,id,ip,m;
+  tagint itag,jtag;
+  double dist,nn,xtp,ytp,ztp,delx,dely,delz,nn2;
+  int *ilist,*jlist;
+  double pv12[3],pv31[3],pv23[3],n1[3],dni[3],dnn[3][3],vet[3][3],dpvdri[3][3];
+  double dn1[3][3][3],dpv12[3][3][3],dpv23[3][3][3],dpv31[3][3][3];
+
+  double **x = atom->x;
+  int *type = atom->type;
+  int ntypes = atom->ntypes;
+  int nlocal = atom->nlocal;
+  tagint *tag = atom->tag;
+  
+  // grow normal array if necessary
+
+  if (atom->nmax > nmax) {
+    memory->destroy(normal);
+    memory->destroy(dnormal);
+    memory->destroy(dnormdri);
+    nmax = atom->nmax;
+    memory->create(normal,nmax,3,"KolmogorovCrespiFull:normal");
+    memory->create(dnormdri,3,3,nmax,"KolmogorovCrespiFull:dnormdri");
+    memory->create(dnormal,3,3,3,nmax,"KolmogorovCrespiFull:dnormal");
+  }
+
+  inum = list->inum;	
+  ilist = list->ilist;  
+  //Calculate normals
+  for (ii = 0; ii < inum; ii++) {
+    i = ilist[ii];
+    xtp = x[i][0];
+    ytp = x[i][1];
+    ztp = x[i][2];
+    itype = type[i];
+
+    //   Initialize the arrays
+    for (id = 0; id < 3; id++){
+      pv12[id] = 0.0;
+      pv31[id] = 0.0;
+      pv23[id] = 0.0;
+      n1[id] = 0.0;
+      dni[id] = 0.0;
+      normal[i][id] = 0.0;
+      for (ip = 0; ip < 3; ip++){
+        vet[ip][id] = 0.0;
+        dnn[ip][id] = 0.0;
+        dpvdri[ip][id] = 0.0;
+        dnormdri[ip][id][i] = 0.0;
+        for (m = 0; m < 3; m++){
+          dpv12[ip][id][m] = 0.0;
+          dpv31[ip][id][m] = 0.0;
+          dpv23[ip][id][m] = 0.0;
+          dn1[ip][id][m] = 0.0;
+          dnormal[ip][id][m][i] = 0.0;
+        }
+      }
+    }
+
+    cont = 0;
+    jlist = KC_firstneigh[i];
+    jnum = KC_numneigh[i];
+    for (jj = 0; jj < jnum; jj++) {
+      j = jlist[jj];
+      j &= NEIGHMASK;
+      
+      delx = x[j][0] - xtp;
+      dely = x[j][1] - ytp;
+      delz = x[j][2] - ztp;
+      vet[cont][0] = delx;
+      vet[cont][1] = dely;
+      vet[cont][2] = delz;
+      cont++;
+    }
+
+    if (cont <= 1) { 
+      normal[i][0] = 0.0;
+      normal[i][1] = 0.0;
+      normal[i][2] = 1.0;
+      // derivatives of normal vector is zero
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          dnormdri[id][ip][i] = 0.0;
+          for (m = 0; m < 3; m++){
+            dnormal[id][ip][m][i] = 0.0;
+          }
+        } 
+      }
+    }
+    else if (cont == 2) {
+      // for the atoms at the edge who has only two neighbor atoms
+      pv12[0] = vet[0][1]*vet[1][2] - vet[1][1]*vet[0][2];
+      pv12[1] = vet[0][2]*vet[1][0] - vet[1][2]*vet[0][0];
+      pv12[2] = vet[0][0]*vet[1][1] - vet[1][0]*vet[0][1];
+      dpvdri[0][0] = 0.0;
+      dpvdri[0][1] = vet[0][2]-vet[1][2];
+      dpvdri[0][2] = vet[1][1]-vet[0][1];
+      dpvdri[1][0] = vet[1][2]-vet[0][2];
+      dpvdri[1][1] = 0.0;
+      dpvdri[1][2] = vet[0][0]-vet[1][0];
+      dpvdri[2][0] = vet[0][1]-vet[1][1];
+      dpvdri[2][1] = vet[1][0]-vet[0][0];
+      dpvdri[2][2] = 0.0;
+
+      // derivatives respect to the first neighbor, atom k
+      dpv12[0][0][0] =  0.0;
+      dpv12[0][1][0] =  vet[1][2];
+      dpv12[0][2][0] = -vet[1][1];
+      dpv12[1][0][0] = -vet[1][2];
+      dpv12[1][1][0] =  0.0;
+      dpv12[1][2][0] =  vet[1][0];
+      dpv12[2][0][0] =  vet[1][1];
+      dpv12[2][1][0] = -vet[1][0];
+      dpv12[2][2][0] =  0.0;
+      
+      // derivatives respect to the second neighbor, atom l
+      dpv12[0][0][1] =  0.0;
+      dpv12[0][1][1] = -vet[0][2];
+      dpv12[0][2][1] =  vet[0][1];
+      dpv12[1][0][1] =  vet[0][2];
+      dpv12[1][1][1] =  0.0;
+      dpv12[1][2][1] = -vet[0][0];
+      dpv12[2][0][1] = -vet[0][1];
+      dpv12[2][1][1] =  vet[0][0];
+      dpv12[2][2][1] =  0.0;
+
+      // derivatives respect to the third neighbor, atom n
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          dpv12[id][ip][2] = 0.0;
+        } 
+      }
+
+      n1[0] = pv12[0];
+      n1[1] = pv12[1];
+      n1[2] = pv12[2];
+      // the magnitude of the normal vector
+      nn2 = n1[0]*n1[0] + n1[1]*n1[1] + n1[2]*n1[2];
+      nn = sqrt(nn2);
+      if (nn == 0) error->all(FLERR,"The magnitude of the normal vector is zero");
+      // the unit normal vector
+      normal[i][0] = n1[0]/nn;
+      normal[i][1] = n1[1]/nn;
+      normal[i][2] = n1[2]/nn;
+      // derivatives of nn, dnn:3x1 vector
+      dni[0] = (n1[0]*dpvdri[0][0] + n1[1]*dpvdri[1][0] + n1[2]*dpvdri[2][0])/nn;
+      dni[1] = (n1[0]*dpvdri[0][1] + n1[1]*dpvdri[1][1] + n1[2]*dpvdri[2][1])/nn;
+      dni[2] = (n1[0]*dpvdri[0][2] + n1[1]*dpvdri[1][2] + n1[2]*dpvdri[2][2])/nn;
+      // derivatives of unit vector ni respect to ri, the result is 3x3 matrix
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          dnormdri[id][ip][i] = dpvdri[id][ip]/nn - n1[id]*dni[ip]/nn2;
+        }
+      }
+
+      // derivatives of non-normalized normal vector, dn1:3x3x3 array
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          for (m = 0; m < 3; m++){
+            dn1[id][ip][m] = dpv12[id][ip][m];
+          }
+        } 
+      }
+      // derivatives of nn, dnn:3x3 vector
+      // dnn[id][m]: the derivative of nn respect to r[id][m], id,m=0,1,2
+      // r[id][m]: the id's component of atom m
+      for (m = 0; m < 3; m++){
+        for (id = 0; id < 3; id++){
+          dnn[id][m] = (n1[0]*dn1[0][id][m] + n1[1]*dn1[1][id][m] + n1[2]*dn1[2][id][m])/nn;
+        }
+      }
+      // dnormal[id][ip][m][i]: the derivative of normal[id] respect to r[ip][m], id,ip=0,1,2
+      // for atom m, which is a neighbor atom of atom i, m=0,jnum-1
+      for (m = 0; m < 3; m++){
+        for (id = 0; id < 3; id++){
+          for (ip = 0; ip < 3; ip++){
+            dnormal[id][ip][m][i] = dn1[id][ip][m]/nn - n1[id]*dnn[ip][m]/nn2;
+          }
+        }
+      }
+    }
+//##############################################################################################
+
+    else if(cont == 3) {
+      // for the atoms at the edge who has only two neighbor atoms
+      pv12[0] = vet[0][1]*vet[1][2] - vet[1][1]*vet[0][2];
+      pv12[1] = vet[0][2]*vet[1][0] - vet[1][2]*vet[0][0];
+      pv12[2] = vet[0][0]*vet[1][1] - vet[1][0]*vet[0][1];
+      // derivatives respect to the first neighbor, atom k
+      dpv12[0][0][0] =  0.0;
+      dpv12[0][1][0] =  vet[1][2];
+      dpv12[0][2][0] = -vet[1][1];
+      dpv12[1][0][0] = -vet[1][2];
+      dpv12[1][1][0] =  0.0;
+      dpv12[1][2][0] =  vet[1][0];
+      dpv12[2][0][0] =  vet[1][1];
+      dpv12[2][1][0] = -vet[1][0];
+      dpv12[2][2][0] =  0.0;
+      // derivatives respect to the second neighbor, atom l
+      dpv12[0][0][1] =  0.0;
+      dpv12[0][1][1] = -vet[0][2];
+      dpv12[0][2][1] =  vet[0][1];
+      dpv12[1][0][1] =  vet[0][2];
+      dpv12[1][1][1] =  0.0;
+      dpv12[1][2][1] = -vet[0][0];
+      dpv12[2][0][1] = -vet[0][1];
+      dpv12[2][1][1] =  vet[0][0];
+      dpv12[2][2][1] =  0.0;
+
+      // derivatives respect to the third neighbor, atom n
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          dpv12[id][ip][2] = 0.0;
+        } 
+      }
+
+      pv31[0] = vet[2][1]*vet[0][2] - vet[0][1]*vet[2][2];
+      pv31[1] = vet[2][2]*vet[0][0] - vet[0][2]*vet[2][0];
+      pv31[2] = vet[2][0]*vet[0][1] - vet[0][0]*vet[2][1];
+      // derivatives respect to the first neighbor, atom k
+      dpv31[0][0][0] =  0.0;
+      dpv31[0][1][0] = -vet[2][2];
+      dpv31[0][2][0] =  vet[2][1];
+      dpv31[1][0][0] =  vet[2][2];
+      dpv31[1][1][0] =  0.0;
+      dpv31[1][2][0] = -vet[2][0];
+      dpv31[2][0][0] = -vet[2][1];
+      dpv31[2][1][0] =  vet[2][0];
+      dpv31[2][2][0] =  0.0;
+      // derivatives respect to the third neighbor, atom n
+      dpv31[0][0][2] =  0.0;
+      dpv31[0][1][2] =  vet[0][2];
+      dpv31[0][2][2] = -vet[0][1];
+      // derivatives of pv13[1] to rn
+      dpv31[1][0][2] = -vet[0][2];
+      dpv31[1][1][2] =  0.0;
+      dpv31[1][2][2] =  vet[0][0];
+      // derivatives of pv13[2] to rn
+      dpv31[2][0][2] =  vet[0][1];
+      dpv31[2][1][2] = -vet[0][0];
+      dpv31[2][2][2] =  0.0;
+
+      // derivatives respect to the second neighbor, atom l
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          dpv31[id][ip][1] = 0.0;
+        } 
+      }
+
+      pv23[0] = vet[1][1]*vet[2][2] - vet[2][1]*vet[1][2];
+      pv23[1] = vet[1][2]*vet[2][0] - vet[2][2]*vet[1][0];
+      pv23[2] = vet[1][0]*vet[2][1] - vet[2][0]*vet[1][1];
+      // derivatives respect to the second neighbor, atom k
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          dpv23[id][ip][0] = 0.0;
+        } 
+      }
+      // derivatives respect to the second neighbor, atom l
+      dpv23[0][0][1] =  0.0;
+      dpv23[0][1][1] =  vet[2][2];
+      dpv23[0][2][1] = -vet[2][1];
+      dpv23[1][0][1] = -vet[2][2];
+      dpv23[1][1][1] =  0.0;
+      dpv23[1][2][1] =  vet[2][0];
+      dpv23[2][0][1] =  vet[2][1];
+      dpv23[2][1][1] = -vet[2][0];
+      dpv23[2][2][1] =  0.0;
+      // derivatives respect to the third neighbor, atom n
+      dpv23[0][0][2] =  0.0;
+      dpv23[0][1][2] = -vet[1][2];
+      dpv23[0][2][2] =  vet[1][1];
+      dpv23[1][0][2] =  vet[1][2];
+      dpv23[1][1][2] =  0.0;
+      dpv23[1][2][2] = -vet[1][0];
+      dpv23[2][0][2] = -vet[1][1];
+      dpv23[2][1][2] =  vet[1][0];
+      dpv23[2][2][2] =  0.0;
+
+//############################################################################################
+      // average the normal vectors by using the 3 neighboring planes
+      n1[0] = (pv12[0] + pv31[0] + pv23[0])/cont;
+      n1[1] = (pv12[1] + pv31[1] + pv23[1])/cont;
+      n1[2] = (pv12[2] + pv31[2] + pv23[2])/cont;
+      // the magnitude of the normal vector
+      nn2 = n1[0]*n1[0] + n1[1]*n1[1] + n1[2]*n1[2];
+      nn = sqrt(nn2);
+      if (nn == 0) error->all(FLERR,"The magnitude of the normal vector is zero");
+      // the unit normal vector
+      normal[i][0] = n1[0]/nn;
+      normal[i][1] = n1[1]/nn;
+      normal[i][2] = n1[2]/nn;
+
+      // for the central atoms, dnormdri is always zero
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          dnormdri[id][ip][i] = 0.0;
+        }
+      } // end of derivatives of normals respect to atom i
+
+      // derivatives of non-normalized normal vector, dn1:3x3x3 array
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+          for (m = 0; m < 3; m++){
+            dn1[id][ip][m] = (dpv12[id][ip][m] + dpv23[id][ip][m] + dpv31[id][ip][m])/cont;
+          }
+        } 
+      }
+      // derivatives of nn, dnn:3x3 vector
+      // dnn[id][m]: the derivative of nn respect to r[id][m], id,m=0,1,2
+      // r[id][m]: the id's component of atom m
+      for (m = 0; m < 3; m++){
+        for (id = 0; id < 3; id++){
+          dnn[id][m] = (n1[0]*dn1[0][id][m] + n1[1]*dn1[1][id][m] + n1[2]*dn1[2][id][m])/nn;
+        }
+      }
+      // dnormal[id][ip][m][i]: the derivative of normal[id] respect to r[ip][m], id,ip=0,1,2
+      // for atom m, which is a neighbor atom of atom i, m=0,jnum-1
+      for (m = 0; m < 3; m++){
+        for (id = 0; id < 3; id++){
+          for (ip = 0; ip < 3; ip++){
+            dnormal[id][ip][m][i] = dn1[id][ip][m]/nn - n1[id]*dnn[ip][m]/nn2;
+          }
+        }
+      }
+    }
+    else {
+      error->all(FLERR,"There are too many neighbors for calculating normals");
+    }
+
+//##############################################################################################
+  }
+}
+
+/* ----------------------------------------------------------------------
+   init specific to this pair style
+------------------------------------------------------------------------- */
+
+void PairKolmogorovCrespiFull::init_style()
+{
+  if (force->newton_pair == 0)
+    error->all(FLERR,"Pair style KC requires newton pair on");
+
+  // need a full neighbor list, including neighbors of ghosts
+
+  int irequest = neighbor->request(this,instance_me);
+  neighbor->requests[irequest]->half = 0;
+  neighbor->requests[irequest]->full = 1;
+  neighbor->requests[irequest]->ghost = 1;
+
+  // local KC neighbor list
+  // create pages if first time or if neighbor pgsize/oneatom has changed
+
+  int create = 0;
+  if (ipage == NULL) create = 1;
+  if (pgsize != neighbor->pgsize) create = 1;
+  if (oneatom != neighbor->oneatom) create = 1;
+
+  if (create) {
+    delete [] ipage;
+    pgsize = neighbor->pgsize;
+    oneatom = neighbor->oneatom;
+
+    int nmypage= comm->nthreads;
+    ipage = new MyPage<int>[nmypage];
+    for (int i = 0; i < nmypage; i++)
+      ipage[i].init(oneatom,pgsize,PGDELTA);
+  }
+}
+
+
+/* ----------------------------------------------------------------------
+   create KC neighbor list from main neighbor list
+   KC neighbor list stores neighbors of ghost atoms
+   KC_numneigh for calcualting normals and
+   KC_pair_numneigh for calculating force
+------------------------------------------------------------------------- */
+
+void PairKolmogorovCrespiFull::KC_neigh()
+{
+  int i,j,ii,jj,n,np,allnum,inum,jnum,itype,jtype;
+  double xtmp,ytmp,ztmp,delx,dely,delz,rsq,dS;
+  int *ilist,*jlist,*numneigh,**firstneigh;
+  int *neighptr;
+
+  double **x = atom->x;
+  int *type = atom->type;
+
+  if (atom->nmax > maxlocal) {
+    maxlocal = atom->nmax;
+    memory->destroy(KC_numneigh);
+    memory->sfree(KC_firstneigh);
+    memory->create(KC_numneigh,maxlocal,"KolmogorovCrespiFull:numneigh");
+    KC_firstneigh = (int **) memory->smalloc(maxlocal*sizeof(int *),
+                                               "KolmogorovCrespiFull:firstneigh");
+  }
+
+  inum = list->inum;
+  allnum = list->inum + list->gnum;
+  ilist = list->ilist;
+  numneigh = list->numneigh;
+  firstneigh = list->firstneigh;
+
+  // store all KC neighs of owned and ghost atoms
+  // scan full neighbor list of I
+
+  ipage->reset();
+
+  for (ii = 0; ii < allnum; ii++) {
+    i = ilist[ii];
+
+    n = 0;
+    neighptr = ipage->vget();
+
+    xtmp = x[i][0];
+    ytmp = x[i][1];
+    ztmp = x[i][2];
+    itype = map[type[i]];
+    jlist = firstneigh[i];
+    jnum = numneigh[i];
+    
+    for (jj = 0; jj < jnum; jj++) {
+      j = jlist[jj];
+      j &= NEIGHMASK;
+      jtype = map[type[j]];
+      delx = xtmp - x[j][0];
+      dely = ytmp - x[j][1];
+      delz = ztmp - x[j][2];
+      rsq = delx*delx + dely*dely + delz*delz;
+
+      if (rsq != 0 && rsq < cutKCsq[itype][jtype] && atom->molecule[i] == atom->molecule[j]) {
+        neighptr[n++] = j;
+      }
+    }
+
+    KC_firstneigh[i] = neighptr;
+    KC_numneigh[i] = n;
+    ipage->vgot(n);
+    if (ipage->status())
+      error->one(FLERR,"Neighbor list overflow, boost neigh_modify one");
+  }
+}
+
+
+/* ----------------------------------------------------------------------
+   allocate all arrays
+------------------------------------------------------------------------- */
+
+void PairKolmogorovCrespiFull::allocate()
+{
+  allocated = 1;
+  int n = atom->ntypes;
+
+  memory->create(setflag,n+1,n+1,"pair:setflag");
+  for (int i = 1; i <= n; i++)
+    for (int j = i; j <= n; j++)
+      setflag[i][j] = 0;
+
+  memory->create(cutsq,n+1,n+1,"pair:cutsq");
+  memory->create(cut,n+1,n+1,"pair:cut");
+  memory->create(offset,n+1,n+1,"pair:offset");
+  map = new int[atom->ntypes+1];
+}
+
+/* ----------------------------------------------------------------------
+   global settings
+------------------------------------------------------------------------- */
+
+void PairKolmogorovCrespiFull::settings(int narg, char **arg)
+{
+  if (narg < 1 || narg > 2) error->all(FLERR,"Illegal pair_style command");
+  if (strcmp(force->pair_style,"hybrid/overlay")!=0)
+    error->all(FLERR,"ERROR: requires hybrid/overlay pair_style");
+
+  cut_global = force->numeric(FLERR,arg[0]);
+  if (narg == 2) tap_flag = force->numeric(FLERR,arg[1]);
+
+  // reset cutoffs that have been explicitly set
+
+  if (allocated) {
+    int i,j;
+    for (i = 1; i <= atom->ntypes; i++)
+      for (j = i; j <= atom->ntypes; j++)
+        if (setflag[i][j]) cut[i][j] = cut_global;
+  }
+}
+
+/* ----------------------------------------------------------------------
+   set coeffs for one or more type pairs
+------------------------------------------------------------------------- */
+
+void PairKolmogorovCrespiFull::coeff(int narg, char **arg)
+{
+  int i,j,n; 
+
+  if (narg != 3 + atom->ntypes) 
+    error->all(FLERR,"Incorrect args for pair coefficients");
+  if (!allocated) allocate();
+
+  int ilo,ihi,jlo,jhi;
+  force->bounds(FLERR,arg[0],atom->ntypes,ilo,ihi);
+  force->bounds(FLERR,arg[1],atom->ntypes,jlo,jhi);
+
+  // read args that map atom types to elements in potential file
+  // map[i] = which element the Ith atom type is, -1 if NULL
+  // nelements = # of unique elements
+  // elements = list of element names
+
+  if (elements) {
+    for (i = 0; i < nelements; i++) delete [] elements[i];
+    delete [] elements;
+  }
+  elements = new char*[atom->ntypes];
+  for (i = 0; i < atom->ntypes; i++) elements[i] = NULL;
+
+  nelements = 0;
+  for (i = 3; i < narg; i++) {
+    if (strcmp(arg[i],"NULL") == 0) {
+      map[i-2] = -1;
+      continue;
+    }
+    for (j = 0; j < nelements; j++)
+      if (strcmp(arg[i],elements[j]) == 0) break;
+    map[i-2] = j;
+    if (j == nelements) {
+      n = strlen(arg[i]) + 1;
+      elements[j] = new char[n];
+      strcpy(elements[j],arg[i]);
+      nelements++;
+    }
+  }
+
+
+  read_file(arg[2]);
+  
+  double cut_one = cut_global;
+
+  int count = 0;
+  for (int i = ilo; i <= ihi; i++) {
+    for (int j = MAX(jlo,i); j <= jhi; j++) {
+      cut[i][j] = cut_one;
+      setflag[i][j] = 1;
+      count++;
+    }
+  }
+
+  if (count == 0) error->all(FLERR,"Incorrect args for pair coefficients");
+}
+
+
+/* ----------------------------------------------------------------------
+   init for one type pair i,j and corresponding j,i
+------------------------------------------------------------------------- */
+
+double PairKolmogorovCrespiFull::init_one(int i, int j)
+{
+  if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set");
+
+  if (offset_flag && (cut[i][j] > 0.0)) {
+    int iparam_ij = elem2param[map[i]][map[j]];
+    Param& p = params[iparam_ij];
+    offset[i][j] = -p.A*pow(p.z0/cut[i][j],6);
+  } else offset[i][j] = 0.0;
+  offset[j][i] = offset[i][j];
+
+  return cut[i][j];
+}
+
+/* ----------------------------------------------------------------------
+   read Kolmogorov-Crespi potential file
+------------------------------------------------------------------------- */
+
+void PairKolmogorovCrespiFull::read_file(char *filename)
+{
+  int params_per_line = 12;
+  char **words = new char*[params_per_line+1];
+  memory->sfree(params);
+  params = NULL;
+  nparams = maxparam = 0;
+
+  // open file on proc 0
+
+  FILE *fp;
+  if (comm->me == 0) {
+    fp = force->open_potential(filename);
+    if (fp == NULL) {
+      char str[128];
+      sprintf(str,"Cannot open KC potential file %s",filename);
+      error->one(FLERR,str);
+    }
+  }
+
+  // read each line out of file, skipping blank lines or leading '#'
+  // store line of params if all 3 element tags are in element list
+
+  int i,j,n,m,nwords,ielement,jelement;
+  char line[MAXLINE],*ptr;
+  int eof = 0;
+
+  while (1) {
+    if (comm->me == 0) {
+      ptr = fgets(line,MAXLINE,fp);
+      if (ptr == NULL) {
+        eof = 1;
+        fclose(fp);
+      } else n = strlen(line) + 1;
+    }
+    MPI_Bcast(&eof,1,MPI_INT,0,world);
+    if (eof) break;
+    MPI_Bcast(&n,1,MPI_INT,0,world);
+    MPI_Bcast(line,n,MPI_CHAR,0,world);
+
+    // strip comment, skip line if blank
+
+    if ((ptr = strchr(line,'#'))) *ptr = '\0';
+    nwords = atom->count_words(line);
+    if (nwords == 0) continue;
+
+    // concatenate additional lines until have params_per_line words
+
+    while (nwords < params_per_line) {
+      n = strlen(line);
+      if (comm->me == 0) {
+        ptr = fgets(&line[n],MAXLINE-n,fp);
+        if (ptr == NULL) {
+          eof = 1;
+          fclose(fp);
+        } else n = strlen(line) + 1;
+      }
+      MPI_Bcast(&eof,1,MPI_INT,0,world);
+      if (eof) break;
+      MPI_Bcast(&n,1,MPI_INT,0,world);
+      MPI_Bcast(line,n,MPI_CHAR,0,world);
+      if ((ptr = strchr(line,'#'))) *ptr = '\0';
+      nwords = atom->count_words(line);
+    }
+
+    if (nwords != params_per_line)
+      error->all(FLERR,"Insufficient format in KC potential file");
+
+    // words = ptrs to all words in line
+
+    nwords = 0;
+    words[nwords++] = strtok(line," \t\n\r\f");
+    while ((words[nwords++] = strtok(NULL," \t\n\r\f"))) continue;
+
+    // ielement,jelement = 1st args
+    // if these 2 args are in element list, then parse this line
+    // else skip to next line (continue)
+
+    for (ielement = 0; ielement < nelements; ielement++)
+      if (strcmp(words[0],elements[ielement]) == 0) break;
+    if (ielement == nelements) continue;
+    for (jelement = 0; jelement < nelements; jelement++)
+      if (strcmp(words[1],elements[jelement]) == 0) break;
+    if (jelement == nelements) continue;
+
+    // load up parameter settings and error check their values
+
+    if (nparams == maxparam) {
+      maxparam += DELTA;
+      params = (Param *) memory->srealloc(params,maxparam*sizeof(Param),
+                                          "pair:params");
+    }
+
+    params[nparams].ielement = ielement;
+    params[nparams].jelement = jelement;
+    params[nparams].z0       = atof(words[2]);
+    params[nparams].C0       = atof(words[3]);
+    params[nparams].C2       = atof(words[4]);
+    params[nparams].C4       = atof(words[5]);
+    params[nparams].C        = atof(words[6]);
+    params[nparams].delta    = atof(words[7]);
+    params[nparams].lambda   = atof(words[8]);
+    params[nparams].A        = atof(words[9]);
+    // S provides a convenient scaling of all energies
+    params[nparams].S        = atof(words[10]);
+    params[nparams].rcut     = atof(words[11]);
+
+    // energies in meV further scaled by S
+    double meV = 1.0e-3*params[nparams].S; 
+    params[nparams].C *= meV;
+    params[nparams].A *= meV;
+    params[nparams].C0 *= meV;
+    params[nparams].C2 *= meV;
+    params[nparams].C4 *= meV;
+
+    // precompute some quantities
+    params[nparams].delta2inv = pow(params[nparams].delta,-2);
+    params[nparams].z06 = pow(params[nparams].z0,6);
+
+    nparams++;
+    //if(nparams >= pow(atom->ntypes,3)) break;
+  }
+  memory->destroy(elem2param);
+  memory->destroy(cutKCsq);
+  memory->create(elem2param,nelements,nelements,"pair:elem2param");
+  memory->create(cutKCsq,nelements,nelements,"pair:cutKCsq");
+  for (i = 0; i < nelements; i++) {
+    for (j = 0; j < nelements; j++) {
+      n = -1;
+      for (m = 0; m < nparams; m++) {
+        if (i == params[m].ielement && j == params[m].jelement) {
+          if (n >= 0) error->all(FLERR,"Potential file has duplicate entry");
+          n = m;
+        }
+      }
+      if (n < 0) error->all(FLERR,"Potential file is missing an entry");
+      elem2param[i][j] = n;
+      cutKCsq[i][j] = params[n].rcut*params[n].rcut;
+    }
+  }
+  delete [] words;
+}
+
+/* ---------------------------------------------------------------------- */
+
+double PairKolmogorovCrespiFull::single(int i, int j, int itype, int jtype, double rsq,
+                         double factor_coul, double factor_lj,
+                         double &fforce)
+{
+  double r,r2inv,r6inv,r8inv,forcelj,philj;
+  double Tap,dTap,Vkc,fpair;
+
+  int iparam_ij = elem2param[map[itype]][map[jtype]];
+  Param& p = params[iparam_ij];
+
+  r = sqrt(rsq);
+  // turn on/off Tapper function
+  if (tap_flag) {
+    Tap = calc_Tap(r,sqrt(cutsq[itype][jtype]));
+    dTap = calc_dTap(r,sqrt(cutsq[itype][jtype]));
+  } else {Tap = 1.0; dTap = 0.0;}
+
+  r2inv = 1.0/rsq;
+  r6inv = r2inv*r2inv*r2inv;
+  r8inv = r2inv*r6inv;
+
+  Vkc = -p.A*p.z06*r6inv;
+  // derivatives
+  fpair = -6.0*p.A*p.z06*r8inv;
+  forcelj = fpair;
+  fforce = factor_lj*(forcelj*Tap - Vkc*dTap/r);
+
+  if (tap_flag) philj = Vkc*Tap;
+  else philj = Vkc - offset[itype][jtype];
+  return factor_lj*philj;
+}
+
+/* ---------------------------------------------------------------------- */
+
+int PairKolmogorovCrespiFull::pack_forward_comm(int n, int *list, double *buf,
+                               int pbc_flag, int *pbc)
+{
+  int i,j,m,l,ip,id;
+
+  m = 0;
+  for (i = 0; i < n; i++) {
+    j = list[i];
+    buf[m++] = normal[j][0];
+    buf[m++] = normal[j][1];
+    buf[m++] = normal[j][2];
+    buf[m++] = dnormdri[0][0][j];
+    buf[m++] = dnormdri[0][1][j];
+    buf[m++] = dnormdri[0][2][j];
+    buf[m++] = dnormdri[1][0][j];
+    buf[m++] = dnormdri[1][1][j];
+    buf[m++] = dnormdri[1][2][j];
+    buf[m++] = dnormdri[2][0][j];
+    buf[m++] = dnormdri[2][1][j];
+    buf[m++] = dnormdri[2][2][j];
+    for (l = 0; l < 3; l++){
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+	  buf[m++] = dnormal[id][ip][l][j];
+        }
+      }
+    }
+  }
+  return m;
+}
+
+/* ---------------------------------------------------------------------- */
+
+void PairKolmogorovCrespiFull::unpack_forward_comm(int n, int first, double *buf)
+{
+  int i,m,last,l,ip,id;
+
+  m = 0;
+  last = first + n; 
+  for (i = first; i < last; i++) {
+    normal[i][0] = buf[m++];
+    normal[i][1] = buf[m++];
+    normal[i][2] = buf[m++];
+    dnormdri[0][0][i] = buf[m++];
+    dnormdri[0][1][i] = buf[m++];
+    dnormdri[0][2][i] = buf[m++];
+    dnormdri[1][0][i] = buf[m++];
+    dnormdri[1][1][i] = buf[m++];
+    dnormdri[1][2][i] = buf[m++];
+    dnormdri[2][0][i] = buf[m++];
+    dnormdri[2][1][i] = buf[m++];
+    dnormdri[2][2][i] = buf[m++];
+    for (l = 0; l < 3; l++){
+      for (id = 0; id < 3; id++){
+        for (ip = 0; ip < 3; ip++){
+	  dnormal[id][ip][l][i] = buf[m++];
+        }
+      }
+    }
+  }
+}
+
+/* ---------------------------------------------------------------------- */
diff --git a/src/USER-MISC/pair_kolmogorov_crespi_full.h b/src/USER-MISC/pair_kolmogorov_crespi_full.h
new file mode 100644
index 0000000000000000000000000000000000000000..74ba3c4bc8336aa11a2cc2358020f0cdf13af1e5
--- /dev/null
+++ b/src/USER-MISC/pair_kolmogorov_crespi_full.h
@@ -0,0 +1,147 @@
+/* ----------------------------------------------------------------------
+   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
+   http://lammps.sandia.gov, Sandia National Laboratories
+   Steve Plimpton, sjplimp@sandia.gov
+
+   Copyright (2003) Sandia Corporation.  Under the terms of Contract
+   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
+   certain rights in this software.  This software is distributed under
+   the GNU General Public License.
+
+   See the README file in the top-level LAMMPS directory.
+------------------------------------------------------------------------- */
+
+#ifdef PAIR_CLASS
+
+PairStyle(kolmogorov/crespi/full,PairKolmogorovCrespiFull)
+
+#else
+
+#ifndef LMP_PAIR_KolmogorovCrespi_FULL_H
+#define LMP_PAIR_KolmogorovCrespi_FULL_H
+
+#include "pair.h"
+#include "my_page.h"
+#include <math.h>
+
+namespace LAMMPS_NS {
+
+class PairKolmogorovCrespiFull : public Pair {
+ public:
+  PairKolmogorovCrespiFull(class LAMMPS *);
+  virtual ~PairKolmogorovCrespiFull();
+
+  virtual void compute(int, int);
+  void settings(int, char **);
+  void coeff(int, char **);
+  double init_one(int, int);
+  void init_style();
+  void calc_normal();
+  int pack_forward_comm(int, int *, double *, int, int *);
+  void unpack_forward_comm(int, int, double *);
+  double single(int, int, int, int, double, double, double, double &);
+
+ protected:
+  int me;
+  int maxlocal;                    // size of numneigh, firstneigh arrays
+  int pgsize;                      // size of neighbor page
+  int oneatom;                     // max # of neighbors for one atom
+  MyPage<int> *ipage;              // neighbor list pages
+  int *KC_numneigh;                // # of pair neighbors for each atom
+  int **KC_firstneigh;             // ptr to 1st neighbor of each atom
+  int tap_flag;			   // flag to turn on/off Tapper function
+
+
+  struct Param {
+    double z0,C0,C2,C4,C,delta,lambda,A,S;
+    double delta2inv,z06,rcut;
+    int ielement,jelement;
+  };
+  Param *params;       // parameter set for I-J interactions
+  char **elements;     // names of unique elements
+  int **elem2param;    // mapping from element pairs to parameters
+  int *map;            // mapping from atom types to elements
+  int nelements;       // # of unique elements
+  int nparams;         // # of stored parameter sets
+  int maxparam;        // max # of parameter sets
+  int nmax;            // max # of atoms
+
+  double cut_global;
+  double cut_normal;
+  double **cut;
+  double **cutKCsq;
+  double **offset;
+  double **normal;
+  double ***dnormdri;
+  double ****dnormal;
+  
+  void read_file( char * );
+  void allocate();
+  void KC_neigh();
+
+  
+  /* ----Calculate the long-range cutoff term */
+  inline double calc_Tap(double r_ij, double Rcut) {
+    double Tap,r;
+    double Tap_coeff[8] = {1.0,0.0,0.0,0.0,-35.0,84.0,-70.0,20.0};
+  
+    r = r_ij/Rcut; 
+    if(r >= 1.0) {Tap = 0.0;}
+    else{
+      Tap = Tap_coeff[7] * r + Tap_coeff[6];
+      Tap = Tap * r  + Tap_coeff[5];
+      Tap = Tap * r  + Tap_coeff[4];
+      Tap = Tap * r  + Tap_coeff[3];
+      Tap = Tap * r  + Tap_coeff[2];
+      Tap = Tap * r  + Tap_coeff[1];
+      Tap = Tap * r  + Tap_coeff[0];
+    }
+
+    return(Tap);
+  }
+
+  /* ----Calculate the derivatives of long-range cutoff term */
+  inline double calc_dTap(double r_ij, double Rcut) {
+    double dTap,r;
+    double Tap_coeff[8] = {1.0,0.0,0.0,0.0,-35.0,84.0,-70.0,20.0};
+
+    r = r_ij/Rcut; 
+    if(r >= 1.0) {dTap = 0.0;}
+    else {
+      dTap = 7.0*Tap_coeff[7] * r + 6.0*Tap_coeff[6];
+      dTap = dTap * r  + 5.0*Tap_coeff[5];
+      dTap = dTap * r  + 4.0*Tap_coeff[4];
+      dTap = dTap * r  + 3.0*Tap_coeff[3];
+      dTap = dTap * r  + 2.0*Tap_coeff[2];
+      dTap = dTap * r  + Tap_coeff[1];
+      dTap = dTap/Rcut;
+    }
+
+    return(dTap);
+  }
+};
+
+}
+
+#endif
+#endif
+
+/* ERROR/WARNING messages:
+
+E: Illegal ... command
+
+Self-explanatory.  Check the input script syntax and compare to the
+documentation for the command.  You can use -echo screen as a
+command-line option when running LAMMPS to see the offending line.
+
+E: Incorrect args for pair coefficients
+
+Self-explanatory.  Check the input script or data file.
+
+E: All pair coeffs are not set
+
+All pair coefficients must be set in the data file or by the
+pair_coeff command before running a simulation.
+
+*/
+