1006 lines
31 KiB
C++
1006 lines
31 KiB
C++
// clang-format off
|
|
/* ----------------------------------------------------------------------
|
|
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
|
https://www.lammps.org/ Sandia National Laboratories
|
|
LAMMPS development team: developers@lammps.org
|
|
|
|
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.
|
|
------------------------------------------------------------------------- */
|
|
|
|
#include "pair_amoeba.h"
|
|
|
|
#include "amoeba_convolution.h"
|
|
#include "atom.h"
|
|
#include "comm.h"
|
|
#include "domain.h"
|
|
#include "math_const.h"
|
|
#include "math_special.h"
|
|
#include "neigh_list.h"
|
|
|
|
#include <cmath>
|
|
|
|
using namespace LAMMPS_NS;
|
|
using namespace MathConst;
|
|
|
|
using MathSpecial::square;
|
|
|
|
enum{FIELD,ZRSD,TORQUE,UFLD}; // reverse comm
|
|
enum{VDWL,REPULSE,QFER,DISP,MPOLE,POLAR,USOLV,DISP_LONG,MPOLE_LONG,POLAR_LONG};
|
|
|
|
#ifdef FFT_SINGLE
|
|
#define ZEROF 0.0f
|
|
#define ONEF 1.0f
|
|
#else
|
|
#define ZEROF 0.0
|
|
#define ONEF 1.0
|
|
#endif
|
|
|
|
/* ----------------------------------------------------------------------
|
|
multipole = multipole interactions
|
|
adapted from Tinker empole1d() routine
|
|
------------------------------------------------------------------------- */
|
|
|
|
void PairAmoeba::multipole()
|
|
{
|
|
double e;
|
|
double felec;
|
|
double term,fterm;
|
|
double ci;
|
|
double dix,diy,diz;
|
|
double qixx,qixy,qixz,qiyy,qiyz,qizz;
|
|
double cii,dii,qii;
|
|
|
|
double time0,time1,time2;
|
|
|
|
// set cutoffs, taper coeffs, and PME params
|
|
|
|
if (use_ewald) choose(MPOLE_LONG);
|
|
else choose(MPOLE);
|
|
|
|
// owned atoms
|
|
|
|
const int nlocal = atom->nlocal;
|
|
|
|
// zero repulsion torque on owned + ghost atoms
|
|
|
|
const int nall = nlocal + atom->nghost;
|
|
|
|
for (int i = 0; i < nall; i++) {
|
|
tq[i][0] = 0.0;
|
|
tq[i][1] = 0.0;
|
|
tq[i][2] = 0.0;
|
|
}
|
|
|
|
// set the energy unit conversion factor
|
|
|
|
felec = electric / am_dielectric;
|
|
|
|
MPI_Barrier(world);
|
|
time0 = MPI_Wtime();
|
|
|
|
// compute the real space part of the Ewald summation
|
|
|
|
if (mpole_rspace_flag) multipole_real();
|
|
time1 = MPI_Wtime();
|
|
|
|
// compute the reciprocal space part of the Ewald summation
|
|
|
|
if (mpole_kspace_flag) multipole_kspace();
|
|
time2 = MPI_Wtime();
|
|
|
|
// compute the Ewald self-energy term over all the atoms
|
|
|
|
term = 2.0 * aewald * aewald;
|
|
fterm = -felec * aewald / MY_PIS;
|
|
|
|
for (int i = 0; i < nlocal; i++) {
|
|
ci = rpole[i][0];
|
|
dix = rpole[i][1];
|
|
diy = rpole[i][2];
|
|
diz = rpole[i][3];
|
|
qixx = rpole[i][4];
|
|
qixy = rpole[i][5];
|
|
qixz = rpole[i][6];
|
|
qiyy = rpole[i][8];
|
|
qiyz = rpole[i][9];
|
|
qizz = rpole[i][12];
|
|
cii = ci*ci;
|
|
dii = dix*dix + diy*diy + diz*diz;
|
|
qii = 2.0*(qixy*qixy+qixz*qixz+qiyz*qiyz) +
|
|
qixx*qixx + qiyy*qiyy + qizz*qizz;
|
|
e = fterm * (cii + term*(dii/3.0+2.0*term*qii/5.0));
|
|
empole += e;
|
|
}
|
|
|
|
// accumulate timing information
|
|
|
|
time_mpole_rspace += time1 - time0;
|
|
time_mpole_kspace += time2 - time1;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
multipole_real = real-space portion of mulipole interactions
|
|
adapted from Tinker emreal1d() routine
|
|
------------------------------------------------------------------------- */
|
|
|
|
void PairAmoeba::multipole_real()
|
|
{
|
|
int i,j,k,itype,jtype,iclass,jclass;
|
|
int ii,jj;
|
|
int ix,iy,iz;
|
|
double e,de,felec;
|
|
double bfac;
|
|
double alsq2,alsq2n;
|
|
double exp2a,ralpha;
|
|
double scalek;
|
|
double xi,yi,zi;
|
|
double xr,yr,zr;
|
|
double xix,yix,zix;
|
|
double xiy,yiy,ziy;
|
|
double xiz,yiz,ziz;
|
|
double r,r2,rr1,rr3;
|
|
double rr5,rr7,rr9,rr11;
|
|
double rr1i,rr3i,rr5i,rr7i;
|
|
double rr1k,rr3k,rr5k,rr7k;
|
|
double rr1ik,rr3ik,rr5ik;
|
|
double rr7ik,rr9ik,rr11ik;
|
|
double ci,dix,diy,diz;
|
|
double qixx,qixy,qixz;
|
|
double qiyy,qiyz,qizz;
|
|
double ck,dkx,dky,dkz;
|
|
double qkxx,qkxy,qkxz;
|
|
double qkyy,qkyz,qkzz;
|
|
double dir,dkr,dik,qik;
|
|
double qix,qiy,qiz,qir;
|
|
double qkx,qky,qkz,qkr;
|
|
double diqk,dkqi,qiqk;
|
|
double dirx,diry,dirz;
|
|
double dkrx,dkry,dkrz;
|
|
double dikx,diky,dikz;
|
|
double qirx,qiry,qirz;
|
|
double qkrx,qkry,qkrz;
|
|
double qikx,qiky,qikz;
|
|
double qixk,qiyk,qizk;
|
|
double qkxi,qkyi,qkzi;
|
|
double qikrx,qikry,qikrz;
|
|
double qkirx,qkiry,qkirz;
|
|
double diqkx,diqky,diqkz;
|
|
double dkqix,dkqiy,dkqiz;
|
|
double diqkrx,diqkry,diqkrz;
|
|
double dkqirx,dkqiry,dkqirz;
|
|
double dqikx,dqiky,dqikz;
|
|
double corei,corek;
|
|
double vali,valk;
|
|
double alphai,alphak;
|
|
double term1,term2,term3;
|
|
double term4,term5,term6;
|
|
double term1i,term2i,term3i;
|
|
double term1k,term2k,term3k;
|
|
double term1ik,term2ik,term3ik;
|
|
double term4ik,term5ik;
|
|
double frcx,frcy,frcz;
|
|
double vxx,vyy,vzz;
|
|
double vxy,vxz,vyz;
|
|
double factor_mpole;
|
|
double ttmi[3],ttmk[3];
|
|
double fix[3],fiy[3],fiz[3];
|
|
double dmpi[9],dmpj[9];
|
|
double dmpij[11];
|
|
double bn[6];
|
|
|
|
int inum,jnum;
|
|
int *ilist,*jlist,*numneigh,**firstneigh;
|
|
|
|
// owned atoms
|
|
|
|
double *pval = atom->dvector[index_pval];
|
|
double **x = atom->x;
|
|
double **f = atom->f;
|
|
int nlocal = atom->nlocal;
|
|
|
|
// neigh list
|
|
|
|
inum = list->inum;
|
|
ilist = list->ilist;
|
|
numneigh = list->numneigh;
|
|
firstneigh = list->firstneigh;
|
|
|
|
// set conversion factor, cutoff and switching coefficients
|
|
|
|
felec = electric / am_dielectric;
|
|
|
|
// DEBUG
|
|
|
|
//int count = 0;
|
|
//int imin,imax;
|
|
|
|
// compute the real space portion of the Ewald summation
|
|
|
|
for (ii = 0; ii < inum; ii++) {
|
|
i = ilist[ii];
|
|
itype = amtype[i];
|
|
iclass = amtype2class[itype];
|
|
jlist = firstneigh[i];
|
|
jnum = numneigh[i];
|
|
|
|
xi = x[i][0];
|
|
yi = x[i][1];
|
|
zi = x[i][2];
|
|
ci = rpole[i][0];
|
|
dix = rpole[i][1];
|
|
diy = rpole[i][2];
|
|
diz = rpole[i][3];
|
|
qixx = rpole[i][4];
|
|
qixy = rpole[i][5];
|
|
qixz = rpole[i][6];
|
|
qiyy = rpole[i][8];
|
|
qiyz = rpole[i][9];
|
|
qizz = rpole[i][12];
|
|
if (!amoeba) {
|
|
corei = pcore[iclass];
|
|
alphai = palpha[iclass];
|
|
vali = pval[i];
|
|
}
|
|
|
|
// evaluate all sites within the cutoff distance
|
|
|
|
for (jj = 0; jj < jnum; jj++) {
|
|
j = jlist[jj];
|
|
factor_mpole = special_mpole[sbmask15(j)];
|
|
j &= NEIGHMASK15;
|
|
|
|
xr = x[j][0] - xi;
|
|
yr = x[j][1] - yi;
|
|
zr = x[j][2] - zi;
|
|
r2 = xr*xr + yr*yr + zr*zr;
|
|
if (r2 > off2) continue;
|
|
|
|
// DEBUG
|
|
|
|
//imin = MIN(atom->tag[i],atom->tag[j]);
|
|
//imax = MAX(atom->tag[i],atom->tag[j]);
|
|
|
|
jtype = amtype[j];
|
|
jclass = amtype2class[jtype];
|
|
|
|
r = sqrt(r2);
|
|
ck = rpole[j][0];
|
|
dkx = rpole[j][1];
|
|
dky = rpole[j][2];
|
|
dkz = rpole[j][3];
|
|
qkxx = rpole[j][4];
|
|
qkxy = rpole[j][5];
|
|
qkxz = rpole[j][6];
|
|
qkyy = rpole[j][8];
|
|
qkyz = rpole[j][9];
|
|
qkzz = rpole[j][12];
|
|
|
|
// intermediates involving moments and separation distance
|
|
|
|
dir = dix*xr + diy*yr + diz*zr;
|
|
qix = qixx*xr + qixy*yr + qixz*zr;
|
|
qiy = qixy*xr + qiyy*yr + qiyz*zr;
|
|
qiz = qixz*xr + qiyz*yr + qizz*zr;
|
|
qir = qix*xr + qiy*yr + qiz*zr;
|
|
dkr = dkx*xr + dky*yr + dkz*zr;
|
|
qkx = qkxx*xr + qkxy*yr + qkxz*zr;
|
|
qky = qkxy*xr + qkyy*yr + qkyz*zr;
|
|
qkz = qkxz*xr + qkyz*yr + qkzz*zr;
|
|
qkr = qkx*xr + qky*yr + qkz*zr;
|
|
dik = dix*dkx + diy*dky + diz*dkz;
|
|
qik = qix*qkx + qiy*qky + qiz*qkz;
|
|
diqk = dix*qkx + diy*qky + diz*qkz;
|
|
dkqi = dkx*qix + dky*qiy + dkz*qiz;
|
|
qiqk = 2.0*(qixy*qkxy+qixz*qkxz+qiyz*qkyz) +
|
|
qixx*qkxx + qiyy*qkyy + qizz*qkzz;
|
|
|
|
// additional intermediates involving moments and distance
|
|
|
|
dirx = diy*zr - diz*yr;
|
|
diry = diz*xr - dix*zr;
|
|
dirz = dix*yr - diy*xr;
|
|
dkrx = dky*zr - dkz*yr;
|
|
dkry = dkz*xr - dkx*zr;
|
|
dkrz = dkx*yr - dky*xr;
|
|
dikx = diy*dkz - diz*dky;
|
|
diky = diz*dkx - dix*dkz;
|
|
dikz = dix*dky - diy*dkx;
|
|
qirx = qiz*yr - qiy*zr;
|
|
qiry = qix*zr - qiz*xr;
|
|
qirz = qiy*xr - qix*yr;
|
|
qkrx = qkz*yr - qky*zr;
|
|
qkry = qkx*zr - qkz*xr;
|
|
qkrz = qky*xr - qkx*yr;
|
|
qikx = qky*qiz - qkz*qiy;
|
|
qiky = qkz*qix - qkx*qiz;
|
|
qikz = qkx*qiy - qky*qix;
|
|
qixk = qixx*qkx + qixy*qky + qixz*qkz;
|
|
qiyk = qixy*qkx + qiyy*qky + qiyz*qkz;
|
|
qizk = qixz*qkx + qiyz*qky + qizz*qkz;
|
|
qkxi = qkxx*qix + qkxy*qiy + qkxz*qiz;
|
|
qkyi = qkxy*qix + qkyy*qiy + qkyz*qiz;
|
|
qkzi = qkxz*qix + qkyz*qiy + qkzz*qiz;
|
|
qikrx = qizk*yr - qiyk*zr;
|
|
qikry = qixk*zr - qizk*xr;
|
|
qikrz = qiyk*xr - qixk*yr;
|
|
qkirx = qkzi*yr - qkyi*zr;
|
|
qkiry = qkxi*zr - qkzi*xr;
|
|
qkirz = qkyi*xr - qkxi*yr;
|
|
diqkx = dix*qkxx + diy*qkxy + diz*qkxz;
|
|
diqky = dix*qkxy + diy*qkyy + diz*qkyz;
|
|
diqkz = dix*qkxz + diy*qkyz + diz*qkzz;
|
|
dkqix = dkx*qixx + dky*qixy + dkz*qixz;
|
|
dkqiy = dkx*qixy + dky*qiyy + dkz*qiyz;
|
|
dkqiz = dkx*qixz + dky*qiyz + dkz*qizz;
|
|
diqkrx = diqkz*yr - diqky*zr;
|
|
diqkry = diqkx*zr - diqkz*xr;
|
|
diqkrz = diqky*xr - diqkx*yr;
|
|
dkqirx = dkqiz*yr - dkqiy*zr;
|
|
dkqiry = dkqix*zr - dkqiz*xr;
|
|
dkqirz = dkqiy*xr - dkqix*yr;
|
|
dqikx = diy*qkz - diz*qky + dky*qiz - dkz*qiy -
|
|
2.0*(qixy*qkxz+qiyy*qkyz+qiyz*qkzz - qixz*qkxy-qiyz*qkyy-qizz*qkyz);
|
|
dqiky = diz*qkx - dix*qkz + dkz*qix - dkx*qiz -
|
|
2.0*(qixz*qkxx+qiyz*qkxy+qizz*qkxz - qixx*qkxz-qixy*qkyz-qixz*qkzz);
|
|
dqikz = dix*qky - diy*qkx + dkx*qiy - dky*qix -
|
|
2.0*(qixx*qkxy+qixy*qkyy+qixz*qkyz - qixy*qkxx-qiyy*qkxy-qiyz*qkxz);
|
|
|
|
// get reciprocal distance terms for this interaction
|
|
|
|
rr1 = felec / r;
|
|
rr3 = rr1 / r2;
|
|
rr5 = 3.0 * rr3 / r2;
|
|
rr7 = 5.0 * rr5 / r2;
|
|
rr9 = 7.0 * rr7 / r2;
|
|
rr11 = 9.0 * rr9 / r2;
|
|
|
|
// calculate the real space Ewald error function terms
|
|
|
|
ralpha = aewald * r;
|
|
bn[0] = erfc(ralpha) / r;
|
|
alsq2 = 2.0 * aewald*aewald;
|
|
alsq2n = 0.0;
|
|
if (aewald > 0.0) alsq2n = 1.0 / (MY_PIS*aewald);
|
|
exp2a = exp(-ralpha*ralpha);
|
|
for (k = 1; k < 6; k++) {
|
|
bfac = (double) (k+k-1);
|
|
alsq2n = alsq2 * alsq2n;
|
|
bn[k] = (bfac*bn[k-1]+alsq2n*exp2a) / r2;
|
|
}
|
|
for (k = 0; k < 6; k++) bn[k] *= felec;
|
|
//if (i == 0 && j < 10) {
|
|
// printf("j = %d: aewald = %f; rr1 = %f; bn: %f %f %f %f %f %f\n", j, aewald, rr1, bn[0], bn[1], bn[2], bn[3], bn[4], bn[5]);
|
|
//}
|
|
|
|
// find damped multipole intermediates and energy value
|
|
|
|
if (!amoeba) {
|
|
corek = pcore[jclass];
|
|
alphak = palpha[jclass];
|
|
valk = pval[j];
|
|
|
|
term1 = corei*corek;
|
|
term1i = corek*vali;
|
|
term2i = corek*dir;
|
|
term3i = corek*qir;
|
|
term1k = corei*valk;
|
|
term2k = -corei*dkr;
|
|
term3k = corei*qkr;
|
|
term1ik = vali*valk;
|
|
term2ik = valk*dir - vali*dkr + dik;
|
|
term3ik = vali*qkr + valk*qir - dir*dkr + 2.0*(dkqi-diqk+qiqk);
|
|
term4ik = dir*qkr - dkr*qir - 4.0*qik;
|
|
term5ik = qir*qkr;
|
|
damppole(r,11,alphai,alphak,dmpi,dmpj,dmpij);
|
|
scalek = factor_mpole;
|
|
rr1i = bn[0] - (1.0-scalek*dmpi[0])*rr1;
|
|
rr3i = bn[1] - (1.0-scalek*dmpi[2])*rr3;
|
|
rr5i = bn[2] - (1.0-scalek*dmpi[4])*rr5;
|
|
rr7i = bn[3] - (1.0-scalek*dmpi[6])*rr7;
|
|
rr1k = bn[0] - (1.0-scalek*dmpj[0])*rr1;
|
|
rr3k = bn[1] - (1.0-scalek*dmpj[2])*rr3;
|
|
rr5k = bn[2] - (1.0-scalek*dmpj[4])*rr5;
|
|
rr7k = bn[3] - (1.0-scalek*dmpj[6])*rr7;
|
|
rr1ik = bn[0] - (1.0-scalek*dmpij[0])*rr1;
|
|
rr3ik = bn[1] - (1.0-scalek*dmpij[2])*rr3;
|
|
rr5ik = bn[2] - (1.0-scalek*dmpij[4])*rr5;
|
|
rr7ik = bn[3] - (1.0-scalek*dmpij[6])*rr7;
|
|
rr9ik = bn[4] - (1.0-scalek*dmpij[8])*rr9;
|
|
rr11ik = bn[5] - (1.0-scalek*dmpij[10])*rr11;
|
|
rr1 = bn[0] - (1.0-scalek)*rr1;
|
|
rr3 = bn[1] - (1.0-scalek)*rr3;
|
|
e = term1*rr1 + term4ik*rr7ik + term5ik*rr9ik +
|
|
term1i*rr1i + term1k*rr1k + term1ik*rr1ik +
|
|
term2i*rr3i + term2k*rr3k + term2ik*rr3ik +
|
|
term3i*rr5i + term3k*rr5k + term3ik*rr5ik;
|
|
|
|
|
|
|
|
// find damped multipole intermediates for force and torque
|
|
|
|
de = term1*rr3 + term4ik*rr9ik + term5ik*rr11ik +
|
|
term1i*rr3i + term1k*rr3k + term1ik*rr3ik +
|
|
term2i*rr5i + term2k*rr5k + term2ik*rr5ik +
|
|
term3i*rr7i + term3k*rr7k + term3ik*rr7ik;
|
|
term1 = -corek*rr3i - valk*rr3ik + dkr*rr5ik - qkr*rr7ik;
|
|
term2 = corei*rr3k + vali*rr3ik + dir*rr5ik + qir*rr7ik;
|
|
term3 = 2.0 * rr5ik;
|
|
term4 = -2.0 * (corek*rr5i+valk*rr5ik - dkr*rr7ik+qkr*rr9ik);
|
|
term5 = -2.0 * (corei*rr5k+vali*rr5ik + dir*rr7ik+qir*rr9ik);
|
|
term6 = 4.0 * rr7ik;
|
|
rr3 = rr3ik;
|
|
|
|
// find standard multipole intermediates and energy value
|
|
|
|
} else {
|
|
term1 = ci*ck;
|
|
term2 = ck*dir - ci*dkr + dik;
|
|
term3 = ci*qkr + ck*qir - dir*dkr + 2.0*(dkqi-diqk+qiqk);
|
|
term4 = dir*qkr - dkr*qir - 4.0*qik;
|
|
term5 = qir*qkr;
|
|
scalek = 1.0 - factor_mpole;
|
|
rr1 = bn[0] - scalek*rr1;
|
|
rr3 = bn[1] - scalek*rr3;
|
|
rr5 = bn[2] - scalek*rr5;
|
|
rr7 = bn[3] - scalek*rr7;
|
|
rr9 = bn[4] - scalek*rr9;
|
|
rr11 = bn[5] - scalek*rr11;
|
|
e = term1*rr1 + term2*rr3 + term3*rr5 + term4*rr7 + term5*rr9;
|
|
if (i == 0 && j < 10) {
|
|
//printf("j = %d: scalek = %f; rr11 = %f; terms: %f %f %f %f %f\n", j, scalek, rr11, term1, term2, term3, term4, term5);
|
|
//printf("j = %d: felec = %f; rr1 = %f; bn0 = %f\n", j, felec, rr1, bn[0]);
|
|
}
|
|
|
|
// find standard multipole intermediates for force and torque
|
|
|
|
de = term1*rr3 + term2*rr5 + term3*rr7 + term4*rr9 + term5*rr11;
|
|
term1 = -ck*rr3 + dkr*rr5 - qkr*rr7;
|
|
term2 = ci*rr3 + dir*rr5 + qir*rr7;
|
|
term3 = 2.0 * rr5;
|
|
term4 = 2.0 * (-ck*rr5+dkr*rr7-qkr*rr9);
|
|
term5 = 2.0 * (-ci*rr5-dir*rr7-qir*rr9);
|
|
term6 = 4.0 * rr7;
|
|
|
|
}
|
|
|
|
empole += e;
|
|
|
|
// compute the force components for this interaction
|
|
|
|
frcx = de*xr + term1*dix + term2*dkx + term3*(diqkx-dkqix) +
|
|
term4*qix + term5*qkx + term6*(qixk+qkxi);
|
|
frcy = de*yr + term1*diy + term2*dky + term3*(diqky-dkqiy) +
|
|
term4*qiy + term5*qky + term6*(qiyk+qkyi);
|
|
frcz = de*zr + term1*diz + term2*dkz + term3*(diqkz-dkqiz) +
|
|
term4*qiz + term5*qkz + term6*(qizk+qkzi);
|
|
|
|
// compute the torque components for this interaction
|
|
|
|
ttmi[0] = -rr3*dikx + term1*dirx + term3*(dqikx+dkqirx) -
|
|
term4*qirx - term6*(qikrx+qikx);
|
|
ttmi[1] = -rr3*diky + term1*diry + term3*(dqiky+dkqiry) -
|
|
term4*qiry - term6*(qikry+qiky);
|
|
ttmi[2] = -rr3*dikz + term1*dirz + term3*(dqikz+dkqirz) -
|
|
term4*qirz - term6*(qikrz+qikz);
|
|
ttmk[0] = rr3*dikx + term2*dkrx - term3*(dqikx+diqkrx) -
|
|
term5*qkrx - term6*(qkirx-qikx);
|
|
ttmk[1] = rr3*diky + term2*dkry - term3*(dqiky+diqkry) -
|
|
term5*qkry - term6*(qkiry-qiky);
|
|
ttmk[2] = rr3*dikz + term2*dkrz - term3*(dqikz+diqkrz) -
|
|
term5*qkrz - term6*(qkirz-qikz);
|
|
|
|
// increment force-based gradient and torque on first site
|
|
|
|
f[i][0] -= frcx;
|
|
f[i][1] -= frcy;
|
|
f[i][2] -= frcz;
|
|
tq[i][0] += ttmi[0];
|
|
tq[i][1] += ttmi[1];
|
|
tq[i][2] += ttmi[2];
|
|
|
|
// increment force-based gradient and torque on second site
|
|
// commenting out j parts for DEBUGGING
|
|
|
|
f[j][0] += frcx;
|
|
f[j][1] += frcy;
|
|
f[j][2] += frcz;
|
|
tq[j][0] += ttmk[0];
|
|
tq[j][1] += ttmk[1];
|
|
tq[j][2] += ttmk[2];
|
|
|
|
// increment the virial due to pairwise Cartesian forces
|
|
|
|
if (vflag_global) {
|
|
vxx = -xr * frcx;
|
|
vxy = -0.5 * (yr*frcx+xr*frcy);
|
|
vxz = -0.5 * (zr*frcx+xr*frcz);
|
|
vyy = -yr * frcy;
|
|
vyz = -0.5 * (zr*frcy+yr*frcz);
|
|
vzz = -zr * frcz;
|
|
|
|
virmpole[0] -= vxx;
|
|
virmpole[1] -= vyy;
|
|
virmpole[2] -= vzz;
|
|
virmpole[3] -= vxy;
|
|
virmpole[4] -= vxz;
|
|
virmpole[5] -= vyz;
|
|
}
|
|
}
|
|
}
|
|
|
|
// reverse comm to sum torque from ghost atoms to owned atoms
|
|
|
|
crstyle = TORQUE;
|
|
comm->reverse_comm(this);
|
|
|
|
// resolve site torques then increment forces and virial
|
|
|
|
for (i = 0; i < nlocal; i++) {
|
|
torque2force(i,tq[i],fix,fiy,fiz,f);
|
|
|
|
if (!vflag_global) continue;
|
|
|
|
iz = zaxis2local[i];
|
|
ix = xaxis2local[i];
|
|
iy = yaxis2local[i];
|
|
|
|
xiz = x[iz][0] - x[i][0];
|
|
yiz = x[iz][1] - x[i][1];
|
|
ziz = x[iz][2] - x[i][2];
|
|
xix = x[ix][0] - x[i][0];
|
|
yix = x[ix][1] - x[i][1];
|
|
zix = x[ix][2] - x[i][2];
|
|
xiy = x[iy][0] - x[i][0];
|
|
yiy = x[iy][1] - x[i][1];
|
|
ziy = x[iy][2] - x[i][2];
|
|
|
|
vxx = xix*fix[0] + xiy*fiy[0] + xiz*fiz[0];
|
|
vxy = 0.5 * (yix*fix[0] + yiy*fiy[0] + yiz*fiz[0] +
|
|
xix*fix[1] + xiy*fiy[1] + xiz*fiz[1]);
|
|
vxz = 0.5 * (zix*fix[0] + ziy*fiy[0] + ziz*fiz[0] +
|
|
xix*fix[2] + xiy*fiy[2] + xiz*fiz[2]);
|
|
vyy = yix*fix[1] + yiy*fiy[1] + yiz*fiz[1];
|
|
vyz = 0.5 * (zix*fix[1] + ziy*fiy[1] + ziz*fiz[1] +
|
|
yix*fix[2] + yiy*fiy[2] + yiz*fiz[2]);
|
|
vzz = zix*fix[2] + ziy*fiy[2] + ziz*fiz[2];
|
|
|
|
virmpole[0] -= vxx;
|
|
virmpole[1] -= vyy;
|
|
virmpole[2] -= vzz;
|
|
virmpole[3] -= vxy;
|
|
virmpole[4] -= vxz;
|
|
virmpole[5] -= vyz;
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
multipole_kspace = KSpace portion of multipole interactions
|
|
adapted from Tinker emrecip1() routine
|
|
literature reference:
|
|
C. Sagui, L. G. Pedersen and T. A. Darden, "Towards an Accurate
|
|
Representation of Electrostatics in Classical Force Fields:
|
|
Efficient Implementation of Multipolar Interactions in
|
|
Biomolecular Simulations", Journal of Chemical Physics, 120,
|
|
73-87 (2004)
|
|
------------------------------------------------------------------------- */
|
|
|
|
void PairAmoeba::multipole_kspace()
|
|
{
|
|
int i,j,k,n,ix,iy,iz;
|
|
int nhalf1,nhalf2,nhalf3;
|
|
int nxlo,nxhi,nylo,nyhi,nzlo,nzhi;
|
|
double e,eterm,felec;
|
|
double r1,r2,r3;
|
|
double h1,h2,h3;
|
|
double f1,f2,f3;
|
|
double xix,yix,zix;
|
|
double xiy,yiy,ziy;
|
|
double xiz,yiz,ziz;
|
|
double vxx,vyy,vzz,vxy,vxz,vyz;
|
|
double volterm,denom;
|
|
double hsq,expterm;
|
|
double term,pterm;
|
|
double vterm,struc2;
|
|
double tem[3],fix[3],fiy[3],fiz[3];
|
|
|
|
// indices into the electrostatic field array
|
|
// decremented by 1 versus Fortran
|
|
|
|
int deriv1[10] = {1, 4, 7, 8, 10, 15, 17, 13, 14, 19};
|
|
int deriv2[10] = {2, 7, 5, 9, 13, 11, 18, 15, 19, 16};
|
|
int deriv3[10] = {3, 8, 9, 6, 14, 16, 12, 19, 17, 18};
|
|
|
|
// return if the Ewald coefficient is zero
|
|
|
|
if (aewald < 1.0e-6) return;
|
|
|
|
// owned atoms
|
|
|
|
double **x = atom->x;
|
|
double **f = atom->f;
|
|
int nlocal = atom->nlocal;
|
|
|
|
double volbox = domain->prd[0] * domain->prd[1] * domain->prd[2];
|
|
|
|
felec = electric / am_dielectric;
|
|
|
|
// FFT moduli pre-computations
|
|
// set igrid for each atom and its B-spline coeffs
|
|
|
|
nfft1 = m_kspace->nx;
|
|
nfft2 = m_kspace->ny;
|
|
nfft3 = m_kspace->nz;
|
|
bsorder = m_kspace->order;
|
|
|
|
moduli();
|
|
bspline_fill();
|
|
|
|
// copy multipole info to Cartesian cmp
|
|
|
|
for (i = 0; i < nlocal; i++) {
|
|
cmp[i][0] = rpole[i][0];
|
|
cmp[i][1] = rpole[i][1];
|
|
cmp[i][2] = rpole[i][2];
|
|
cmp[i][3] = rpole[i][3];
|
|
cmp[i][4] = rpole[i][4];
|
|
cmp[i][5] = rpole[i][8];
|
|
cmp[i][6] = rpole[i][12];
|
|
cmp[i][7] = 2.0 * rpole[i][5];
|
|
cmp[i][8] = 2.0 * rpole[i][6];
|
|
cmp[i][9] = 2.0 * rpole[i][9];
|
|
}
|
|
|
|
// convert Cartesian multipoles to fractional multipoles
|
|
|
|
cmp_to_fmp(cmp,fmp);
|
|
|
|
// gridpre = my portion of 3d grid in brick decomp w/ ghost values
|
|
|
|
double ***gridpre = (double ***) m_kspace->zero();
|
|
|
|
// map atoms to grid
|
|
|
|
grid_mpole(fmp,gridpre);
|
|
|
|
// pre-convolution operations including forward FFT
|
|
// gridfft = my portion of complex 3d grid in FFT decomp as 1d vector
|
|
|
|
double *gridfft = m_kspace->pre_convolution();
|
|
|
|
// ---------------------
|
|
// convolution operation
|
|
// ---------------------
|
|
|
|
// zero virial accumulation variables
|
|
|
|
vxx = vyy = vzz = vxy = vxz = vyz = 0.0;
|
|
|
|
// perform convolution on K-space points I own
|
|
|
|
nhalf1 = (nfft1+1) / 2;
|
|
nhalf2 = (nfft2+1) / 2;
|
|
nhalf3 = (nfft3+1) / 2;
|
|
|
|
nxlo = m_kspace->nxlo_fft;
|
|
nxhi = m_kspace->nxhi_fft;
|
|
nylo = m_kspace->nylo_fft;
|
|
nyhi = m_kspace->nyhi_fft;
|
|
nzlo = m_kspace->nzlo_fft;
|
|
nzhi = m_kspace->nzhi_fft;
|
|
|
|
pterm = square(MY_PI/aewald);
|
|
volterm = MY_PI * volbox;
|
|
|
|
n = 0;
|
|
for (k = nzlo; k <= nzhi; k++) {
|
|
for (j = nylo; j <= nyhi; j++) {
|
|
for (i = nxlo; i <= nxhi; i++) {
|
|
r1 = (i >= nhalf1) ? i-nfft1 : i;
|
|
r2 = (j >= nhalf2) ? j-nfft2 : j;
|
|
r3 = (k >= nhalf3) ? k-nfft3 : k;
|
|
h1 = recip[0][0]*r1 + recip[0][1]*r2 + recip[0][2]*r3; // matvec
|
|
h2 = recip[1][0]*r1 + recip[1][1]*r2 + recip[1][2]*r3;
|
|
h3 = recip[2][0]*r1 + recip[2][1]*r2 + recip[2][2]*r3;
|
|
hsq = h1*h1 + h2*h2 + h3*h3;
|
|
term = -pterm * hsq;
|
|
expterm = 0.0;
|
|
if (term > -50.0 && hsq != 0.0) {
|
|
denom = volterm*hsq*bsmod1[i]*bsmod2[j]*bsmod3[k];
|
|
expterm = exp(term) / denom;
|
|
struc2 = gridfft[n]*gridfft[n] + gridfft[n+1]*gridfft[n+1];
|
|
eterm = 0.5 * felec * expterm * struc2;
|
|
vterm = (2.0/hsq) * (1.0-term) * eterm;
|
|
vxx += h1*h1*vterm - eterm;
|
|
vyy += h2*h2*vterm - eterm;
|
|
vzz += h3*h3*vterm - eterm;
|
|
vxy += h1*h2*vterm;
|
|
vxz += h1*h3*vterm;
|
|
vyz += h2*h3*vterm;
|
|
}
|
|
gridfft[n] *= expterm;
|
|
gridfft[n+1] *= expterm;
|
|
n += 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
// save multipole virial for use in polarization computation
|
|
|
|
vmsave[0] = vxx;
|
|
vmsave[1] = vyy;
|
|
vmsave[2] = vzz;
|
|
vmsave[3] = vxy;
|
|
vmsave[4] = vxz;
|
|
vmsave[5] = vyz;
|
|
|
|
// post-convolution operations including backward FFT
|
|
// gridppost = my portion of 3d grid in brick decomp w/ ghost values
|
|
|
|
double ***gridpost = (double ***) m_kspace->post_convolution();
|
|
|
|
// get potential
|
|
|
|
fphi_mpole(gridpost,fphi);
|
|
|
|
for (i = 0; i < nlocal; i++) {
|
|
for (k = 0; k < 20; k++)
|
|
fphi[i][k] *= felec;
|
|
}
|
|
|
|
// convert field from fractional to Cartesian
|
|
|
|
fphi_to_cphi(fphi,cphi);
|
|
|
|
// increment the permanent multipole energy and gradient
|
|
|
|
e = 0.0;
|
|
for (i = 0; i < nlocal; i++) {
|
|
f1 = 0.0;
|
|
f2 = 0.0;
|
|
f3 = 0.0;
|
|
for (k = 0; k < 10; k++) {
|
|
e += fmp[i][k]*fphi[i][k];
|
|
f1 += fmp[i][k]*fphi[i][deriv1[k]];
|
|
f2 += fmp[i][k]*fphi[i][deriv2[k]];
|
|
f3 += fmp[i][k]*fphi[i][deriv3[k]];
|
|
}
|
|
f1 *= nfft1;
|
|
f2 *= nfft2;
|
|
f3 *= nfft3;
|
|
h1 = recip[0][0]*f1 + recip[0][1]*f2 + recip[0][2]*f3; // matvec?
|
|
h2 = recip[1][0]*f1 + recip[1][1]*f2 + recip[1][2]*f3;
|
|
h3 = recip[2][0]*f1 + recip[2][1]*f2 + recip[2][2]*f3;
|
|
f[i][0] -= h1;
|
|
f[i][1] -= h2;
|
|
f[i][2] -= h3;
|
|
}
|
|
empole += 0.5*e;
|
|
|
|
// augment the permanent multipole virial contributions
|
|
|
|
if (vflag_global) {
|
|
for (i = 0; i < nlocal; i++) {
|
|
vxx = vxx - cmp[i][1]*cphi[i][1] - 2.0*cmp[i][4]*cphi[i][4] -
|
|
cmp[i][7]*cphi[i][7] - cmp[i][8]*cphi[i][8];
|
|
vxy = vxy - 0.5*(cmp[i][2]*cphi[i][1]+cmp[i][1]*cphi[i][2]) -
|
|
(cmp[i][4]+cmp[i][5])*cphi[i][7] - 0.5*cmp[i][7]*(cphi[i][4]+cphi[i][5]) -
|
|
0.5*(cmp[i][8]*cphi[i][9]+cmp[i][9]*cphi[i][8]);
|
|
vxz = vxz - 0.5*(cmp[i][3]*cphi[i][1]+cmp[i][1]*cphi[i][3]) -
|
|
(cmp[i][4]+cmp[i][6])*cphi[i][8] - 0.5*cmp[i][8]*(cphi[i][4]+cphi[i][6]) -
|
|
0.5*(cmp[i][7]*cphi[i][9]+cmp[i][9]*cphi[i][7]);
|
|
vyy = vyy - cmp[i][2]*cphi[i][2] - 2.0*cmp[i][5]*cphi[i][5] -
|
|
cmp[i][7]*cphi[i][7] - cmp[i][9]*cphi[i][9];
|
|
vyz = vyz - 0.5*(cmp[i][3]*cphi[i][2]+cmp[i][2]*cphi[i][3]) -
|
|
(cmp[i][5]+cmp[i][6])*cphi[i][9] - 0.5*cmp[i][9]*(cphi[i][5]+cphi[i][6]) -
|
|
0.5*(cmp[i][7]*cphi[i][8]+cmp[i][8]*cphi[i][7]);
|
|
vzz = vzz - cmp[i][3]*cphi[i][3] - 2.0*cmp[i][6]*cphi[i][6] -
|
|
cmp[i][8]*cphi[i][8] - cmp[i][9]*cphi[i][9];
|
|
}
|
|
}
|
|
|
|
// resolve site torques then increment forces and virial
|
|
|
|
for (i = 0; i < nlocal; i++) {
|
|
tem[0] = cmp[i][3]*cphi[i][2] - cmp[i][2]*cphi[i][3] +
|
|
2.0*(cmp[i][6]-cmp[i][5])*cphi[i][9] +
|
|
cmp[i][8]*cphi[i][7] + cmp[i][9]*cphi[i][5] -
|
|
cmp[i][7]*cphi[i][8] - cmp[i][9]*cphi[i][6];
|
|
tem[1] = cmp[i][1]*cphi[i][3] - cmp[i][3]*cphi[i][1] +
|
|
2.0*(cmp[i][4]-cmp[i][6])*cphi[i][8] +
|
|
cmp[i][7]*cphi[i][9] + cmp[i][8]*cphi[i][6] -
|
|
cmp[i][8]*cphi[i][4] - cmp[i][9]*cphi[i][7];
|
|
tem[2] = cmp[i][2]*cphi[i][1] - cmp[i][1]*cphi[i][2] +
|
|
2.0*(cmp[i][5]-cmp[i][4])*cphi[i][7] +
|
|
cmp[i][7]*cphi[i][4] + cmp[i][9]*cphi[i][8] -
|
|
cmp[i][7]*cphi[i][5] - cmp[i][8]*cphi[i][9];
|
|
|
|
torque2force(i,tem,fix,fiy,fiz,f);
|
|
|
|
if (vflag_global) {
|
|
iz = zaxis2local[i];
|
|
ix = xaxis2local[i];
|
|
iy = yaxis2local[i];
|
|
|
|
xiz = x[iz][0] - x[i][0];
|
|
yiz = x[iz][1] - x[i][1];
|
|
ziz = x[iz][2] - x[i][2];
|
|
xix = x[ix][0] - x[i][0];
|
|
yix = x[ix][1] - x[i][1];
|
|
zix = x[ix][2] - x[i][2];
|
|
xiy = x[iy][0] - x[i][0];
|
|
yiy = x[iy][1] - x[i][1];
|
|
ziy = x[iy][2] - x[i][2];
|
|
|
|
vxx += xix*fix[0] + xiy*fiy[0] + xiz*fiz[0];
|
|
vxy += 0.5*(yix*fix[0] + yiy*fiy[0] + yiz*fiz[0] +
|
|
xix*fix[1] + xiy*fiy[1] + xiz*fiz[1]);
|
|
vxz += 0.5*(zix*fix[0] + ziy*fiy[0] + ziz*fiz[0] +
|
|
xix*fix[2] + xiy*fiy[2] + xiz*fiz[2]);
|
|
vyy += yix*fix[1] + yiy*fiy[1] + yiz*fiz[1];
|
|
vyz += 0.5*(zix*fix[1] + ziy*fiy[1] + ziz*fiz[1] +
|
|
yix*fix[2] + yiy*fiy[2] + yiz*fiz[2]);
|
|
vzz += zix*fix[2] + ziy*fiy[2] + ziz*fiz[2];
|
|
}
|
|
}
|
|
|
|
// increment total internal virial tensor components
|
|
|
|
if (vflag_global) {
|
|
virmpole[0] -= vxx;
|
|
virmpole[1] -= vyy;
|
|
virmpole[2] -= vzz;
|
|
virmpole[3] -= vxy;
|
|
virmpole[4] -= vxz;
|
|
virmpole[5] -= vyz;
|
|
}
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
damppole generates coefficients for the charge penetration
|
|
damping function for powers of the interatomic distance
|
|
|
|
literature references:
|
|
|
|
L. V. Slipchenko and M. S. Gordon, "Electrostatic Energy in the
|
|
Effective Fragment Potential Method: Theory and Application to
|
|
the Benzene Dimer", Journal of Computational Chemistry, 28,
|
|
276-291 (2007) [Gordon f1 and f2 models]
|
|
|
|
J. A. Rackers, Q. Wang, C. Liu, J.-P. Piquemal, P. Ren and
|
|
J. W. Ponder, "An Optimized Charge Penetration Model for Use with
|
|
the AMOEBA Force Field", Physical Chemistry Chemical Physics, 19,
|
|
276-291 (2017)
|
|
------------------------------------------------------------------------- */
|
|
|
|
void PairAmoeba::damppole(double r, int rorder, double alphai, double alphak,
|
|
double *dmpi, double *dmpk, double *dmpik)
|
|
{
|
|
double termi,termk;
|
|
double termi2,termk2;
|
|
double alphai2,alphak2;
|
|
double eps,diff;
|
|
double expi,expk;
|
|
double dampi,dampk;
|
|
double dampi2,dampi3;
|
|
double dampi4,dampi5;
|
|
double dampi6,dampi7;
|
|
double dampi8;
|
|
double dampk2,dampk3;
|
|
double dampk4,dampk5;
|
|
double dampk6;
|
|
|
|
// compute tolerance and exponential damping factors
|
|
|
|
eps = 0.001;
|
|
diff = fabs(alphai-alphak);
|
|
dampi = alphai * r;
|
|
dampk = alphak * r;
|
|
expi = exp(-dampi);
|
|
expk = exp(-dampk);
|
|
|
|
// core-valence charge penetration damping for Gordon f1
|
|
|
|
dampi2 = dampi * dampi;
|
|
dampi3 = dampi * dampi2;
|
|
dampi4 = dampi2 * dampi2;
|
|
dampi5 = dampi2 * dampi3;
|
|
dmpi[0] = 1.0 - (1.0 + 0.5*dampi)*expi;
|
|
dmpi[2] = 1.0 - (1.0 + dampi + 0.5*dampi2)*expi;
|
|
dmpi[4] = 1.0 - (1.0 + dampi + 0.5*dampi2 + dampi3/6.0)*expi;
|
|
dmpi[6] = 1.0 - (1.0 + dampi + 0.5*dampi2 + dampi3/6.0 + dampi4/30.0)*expi;
|
|
dmpi[8] = 1.0 - (1.0 + dampi + 0.5*dampi2 + dampi3/6.0 +
|
|
4.0*dampi4/105.0 + dampi5/210.0)*expi;
|
|
if (diff < eps) {
|
|
dmpk[0] = dmpi[0];
|
|
dmpk[2] = dmpi[2];
|
|
dmpk[4] = dmpi[4];
|
|
dmpk[6] = dmpi[6];
|
|
dmpk[8] = dmpi[8];
|
|
} else {
|
|
dampk2 = dampk * dampk;
|
|
dampk3 = dampk * dampk2;
|
|
dampk4 = dampk2 * dampk2;
|
|
dampk5 = dampk2 * dampk3;
|
|
dmpk[0] = 1.0 - (1.0 + 0.5*dampk)*expk;
|
|
dmpk[2] = 1.0 - (1.0 + dampk + 0.5*dampk2)*expk;
|
|
dmpk[4] = 1.0 - (1.0 + dampk + 0.5*dampk2 + dampk3/6.0)*expk;
|
|
dmpk[6] = 1.0 - (1.0 + dampk + 0.5*dampk2 + dampk3/6.0 + dampk4/30.0)*expk;
|
|
dmpk[8] = 1.0 - (1.0 + dampk + 0.5*dampk2 + dampk3/6.0 +
|
|
4.0*dampk4/105.0 + dampk5/210.0)*expk;
|
|
}
|
|
|
|
// valence-valence charge penetration damping for Gordon f1
|
|
|
|
if (diff < eps) {
|
|
dampi6 = dampi3 * dampi3;
|
|
dampi7 = dampi3 * dampi4;
|
|
dmpik[0] = 1.0 - (1.0 + 11.0*dampi/16.0 + 3.0*dampi2/16.0 +
|
|
dampi3/48.0)*expi;
|
|
dmpik[2] = 1.0 - (1.0 + dampi + 0.5*dampi2 +
|
|
7.0*dampi3/48.0 + dampi4/48.0)*expi;
|
|
dmpik[4] = 1.0 - (1.0 + dampi + 0.5*dampi2 + dampi3/6.0 +
|
|
dampi4/24.0 + dampi5/144.0)*expi;
|
|
dmpik[6] = 1.0 - (1.0 + dampi + 0.5*dampi2 + dampi3/6.0 +
|
|
dampi4/24.0 + dampi5/120.0 + dampi6/720.0)*expi;
|
|
dmpik[8] = 1.0 - (1.0 + dampi + 0.5*dampi2 + dampi3/6.0 +
|
|
dampi4/24.0 + dampi5/120.0 + dampi6/720.0 +
|
|
dampi7/5040.0)*expi;
|
|
if (rorder >= 11) {
|
|
dampi8 = dampi4 * dampi4;
|
|
dmpik[10] = 1.0 - (1.0 + dampi + 0.5*dampi2 + dampi3/6.0 +
|
|
dampi4/24.0 + dampi5/120.0 + dampi6/720.0 +
|
|
dampi7/5040.0 + dampi8/45360.0)*expi;
|
|
}
|
|
|
|
} else {
|
|
alphai2 = alphai * alphai;
|
|
alphak2 = alphak * alphak;
|
|
termi = alphak2 / (alphak2-alphai2);
|
|
termk = alphai2 / (alphai2-alphak2);
|
|
termi2 = termi * termi;
|
|
termk2 = termk * termk;
|
|
dmpik[0] = 1.0 - termi2*(1.0 + 2.0*termk + 0.5*dampi)*expi -
|
|
termk2*(1.0 + 2.0*termi + 0.5*dampk)*expk;
|
|
dmpik[2] = 1.0 - termi2*(1.0+dampi+0.5*dampi2)*expi -
|
|
termk2*(1.0+dampk+0.5*dampk2)*expk -
|
|
2.0*termi2*termk*(1.0+dampi)*expi -
|
|
2.0*termk2*termi*(1.0+dampk)*expk;
|
|
dmpik[4] = 1.0 - termi2*(1.0 + dampi + 0.5*dampi2 + dampi3/6.0)*expi -
|
|
termk2*(1.0 + dampk + 0.5*dampk2 + dampk3/6.0)*expk -
|
|
2.0*termi2*termk*(1.0 + dampi + dampi2/3.0)*expi -
|
|
2.0*termk2*termi*(1.0 + dampk + dampk2/3.0)*expk;
|
|
dmpik[6] = 1.0 - termi2*(1.0 + dampi + 0.5*dampi2 +
|
|
dampi3/6.0 + dampi4/30.0)*expi -
|
|
termk2*(1.0 + dampk + 0.5*dampk2 + dampk3/6.0 + dampk4/30.0)*expk -
|
|
2.0*termi2*termk*(1.0 + dampi + 2.0*dampi2/5.0 + dampi3/15.0)*expi -
|
|
2.0*termk2*termi*(1.0 + dampk + 2.0*dampk2/5.0 + dampk3/15.0)*expk;
|
|
dmpik[8] = 1.0 - termi2*(1.0 + dampi + 0.5*dampi2 + dampi3/6.0 +
|
|
4.0*dampi4/105.0 + dampi5/210.0)*expi -
|
|
termk2*(1.0 + dampk + 0.5*dampk2 + dampk3/6.0 +
|
|
4.0*dampk4/105.0 + dampk5/210.0)*expk -
|
|
2.0*termi2*termk*(1.0 + dampi + 3.0*dampi2/7.0 +
|
|
2.0*dampi3/21.0 + dampi4/105.0)*expi -
|
|
2.0*termk2*termi*(1.0 + dampk + 3.0*dampk2/7.0 +
|
|
2.0*dampk3/21.0 + dampk4/105.0)*expk;
|
|
|
|
if (rorder >= 11) {
|
|
dampi6 = dampi3 * dampi3;
|
|
dampk6 = dampk3 * dampk3;
|
|
dmpik[10] = 1.0 - termi2*(1.0 + dampi + 0.5*dampi2 + dampi3/6.0 +
|
|
5.0*dampi4/126.0 + 2.0*dampi5/315.0 +
|
|
dampi6/1890.0)*expi -
|
|
termk2*(1.0 + dampk + 0.5*dampk2 + dampk3/6.0 + 5.0*dampk4/126.0 +
|
|
2.0*dampk5/315.0 + dampk6/1890.0)*expk -
|
|
2.0*termi2*termk*(1.0 + dampi + 4.0*dampi2/9.0 + dampi3/9.0 +
|
|
dampi4/63.0 + dampi5/945.0)*expi -
|
|
2.0*termk2*termi*(1.0 + dampk + 4.0*dampk2/9.0 + dampk3/9.0 +
|
|
dampk4/63.0 + dampk5/945.0)*expk;
|
|
}
|
|
}
|
|
}
|