Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
tsoc
openmm
Commits
b7088b74
"platforms/brook/src/BrookCalcLJ14ForceKernel.h" did not exist on "b53cd9470f91a13b54f3c9eb9471f3bd330692a6"
Commit
b7088b74
authored
Aug 10, 2015
by
peastman
Committed by
Robert McGibbon
Aug 27, 2015
Browse files
Python 2/3 compatibility in single code base, plus python 3 testing on travis.
parent
4c00b312
Changes
123
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
1206 additions
and
1172 deletions
+1206
-1172
plugins/amoeba/platforms/cuda/src/kernels/sphericalMultipoles.cu
.../amoeba/platforms/cuda/src/kernels/sphericalMultipoles.cu
+111
-0
plugins/amoeba/platforms/cuda/tests/CMakeLists.txt
plugins/amoeba/platforms/cuda/tests/CMakeLists.txt
+1
-1
plugins/amoeba/platforms/cuda/tests/TestCudaAmoebaGeneralizedKirkwoodForce.cpp
...rms/cuda/tests/TestCudaAmoebaGeneralizedKirkwoodForce.cpp
+1
-1
plugins/amoeba/platforms/reference/CMakeLists.txt
plugins/amoeba/platforms/reference/CMakeLists.txt
+1
-1
plugins/amoeba/platforms/reference/src/SimTKReference/AmoebaReferenceMultipoleForce.cpp
...ence/src/SimTKReference/AmoebaReferenceMultipoleForce.cpp
+925
-1033
plugins/amoeba/platforms/reference/src/SimTKReference/AmoebaReferenceMultipoleForce.h
...erence/src/SimTKReference/AmoebaReferenceMultipoleForce.h
+51
-0
plugins/amoeba/platforms/reference/tests/CMakeLists.txt
plugins/amoeba/platforms/reference/tests/CMakeLists.txt
+1
-1
plugins/amoeba/platforms/reference/tests/TestReferenceAmoebaGeneralizedKirkwoodForce.cpp
...nce/tests/TestReferenceAmoebaGeneralizedKirkwoodForce.cpp
+1
-1
plugins/amoeba/serialization/tests/CMakeLists.txt
plugins/amoeba/serialization/tests/CMakeLists.txt
+1
-1
plugins/cpupme/CMakeLists.txt
plugins/cpupme/CMakeLists.txt
+2
-2
plugins/cpupme/src/CpuPmeKernels.cpp
plugins/cpupme/src/CpuPmeKernels.cpp
+91
-107
plugins/cpupme/src/CpuPmeKernels.h
plugins/cpupme/src/CpuPmeKernels.h
+10
-14
plugins/cpupme/tests/CMakeLists.txt
plugins/cpupme/tests/CMakeLists.txt
+1
-1
plugins/cudacompiler/CMakeLists.txt
plugins/cudacompiler/CMakeLists.txt
+2
-2
plugins/cudacompiler/tests/CMakeLists.txt
plugins/cudacompiler/tests/CMakeLists.txt
+1
-1
plugins/drude/CMakeLists.txt
plugins/drude/CMakeLists.txt
+2
-2
plugins/drude/platforms/cuda/CMakeLists.txt
plugins/drude/platforms/cuda/CMakeLists.txt
+1
-1
plugins/drude/platforms/cuda/tests/CMakeLists.txt
plugins/drude/platforms/cuda/tests/CMakeLists.txt
+1
-1
plugins/drude/platforms/opencl/CMakeLists.txt
plugins/drude/platforms/opencl/CMakeLists.txt
+1
-1
plugins/drude/platforms/opencl/tests/CMakeLists.txt
plugins/drude/platforms/opencl/tests/CMakeLists.txt
+1
-1
No files found.
plugins/amoeba/platforms/cuda/src/kernels/sphericalMultipoles.cu
0 → 100644
View file @
b7088b74
__device__
void
buildQIRotationMatrix
(
real3
deltaR
,
real
rInv
,
real
(
&
rotationMatrix
)[
3
][
3
])
{
real3
vectorZ
=
deltaR
*
rInv
;
real3
vectorX
=
vectorZ
;
if
(
deltaR
.
y
!=
0
||
deltaR
.
z
!=
0
)
vectorX
.
x
+=
1
;
else
vectorX
.
y
+=
1
;
vectorX
-=
vectorZ
*
dot
(
vectorX
,
vectorZ
);
vectorX
=
normalize
(
vectorX
);
real3
vectorY
=
cross
(
vectorZ
,
vectorX
);
// Reorder the Cartesian {x,y,z} dipole rotation matrix, to account
// for spherical harmonic ordering {z,x,y}.
rotationMatrix
[
0
][
0
]
=
vectorZ
.
z
;
rotationMatrix
[
0
][
1
]
=
vectorZ
.
x
;
rotationMatrix
[
0
][
2
]
=
vectorZ
.
y
;
rotationMatrix
[
1
][
0
]
=
vectorX
.
z
;
rotationMatrix
[
1
][
1
]
=
vectorX
.
x
;
rotationMatrix
[
1
][
2
]
=
vectorX
.
y
;
rotationMatrix
[
2
][
0
]
=
vectorY
.
z
;
rotationMatrix
[
2
][
1
]
=
vectorY
.
x
;
rotationMatrix
[
2
][
2
]
=
vectorY
.
y
;
}
__device__
real3
rotateDipole
(
real3
&
dipole
,
const
real
(
&
rotationMatrix
)[
3
][
3
])
{
return
make_real3
(
rotationMatrix
[
0
][
0
]
*
dipole
.
x
+
rotationMatrix
[
0
][
1
]
*
dipole
.
y
+
rotationMatrix
[
0
][
2
]
*
dipole
.
z
,
rotationMatrix
[
1
][
0
]
*
dipole
.
x
+
rotationMatrix
[
1
][
1
]
*
dipole
.
y
+
rotationMatrix
[
1
][
2
]
*
dipole
.
z
,
rotationMatrix
[
2
][
0
]
*
dipole
.
x
+
rotationMatrix
[
2
][
1
]
*
dipole
.
y
+
rotationMatrix
[
2
][
2
]
*
dipole
.
z
);
}
__device__
void
rotateQuadupoles
(
const
real
(
&
rotationMatrix
)[
3
][
3
],
const
real
*
quad1
,
const
real
*
quad2
,
real
*
rotated1
,
real
*
rotated2
)
{
real
sqrtThree
=
SQRT
((
real
)
3
);
real
element
;
element
=
0.5
f
*
(
3.0
f
*
rotationMatrix
[
0
][
0
]
*
rotationMatrix
[
0
][
0
]
-
1.0
f
);
rotated1
[
0
]
+=
quad1
[
0
]
*
element
;
rotated2
[
0
]
+=
quad2
[
0
]
*
element
;
element
=
sqrtThree
*
rotationMatrix
[
0
][
0
]
*
rotationMatrix
[
0
][
1
];
rotated1
[
0
]
+=
quad1
[
1
]
*
element
;
rotated2
[
0
]
+=
quad2
[
1
]
*
element
;
element
=
sqrtThree
*
rotationMatrix
[
0
][
0
]
*
rotationMatrix
[
0
][
2
];
rotated1
[
0
]
+=
quad1
[
2
]
*
element
;
rotated2
[
0
]
+=
quad2
[
2
]
*
element
;
element
=
0.5
f
*
sqrtThree
*
(
rotationMatrix
[
0
][
1
]
*
rotationMatrix
[
0
][
1
]
-
rotationMatrix
[
0
][
2
]
*
rotationMatrix
[
0
][
2
]);
rotated1
[
0
]
+=
quad1
[
3
]
*
element
;
rotated2
[
0
]
+=
quad2
[
3
]
*
element
;
element
=
sqrtThree
*
rotationMatrix
[
0
][
1
]
*
rotationMatrix
[
0
][
2
];
rotated1
[
0
]
+=
quad1
[
4
]
*
element
;
rotated2
[
0
]
+=
quad2
[
4
]
*
element
;
element
=
sqrtThree
*
rotationMatrix
[
0
][
0
]
*
rotationMatrix
[
1
][
0
];
rotated1
[
1
]
+=
quad1
[
0
]
*
element
;
rotated2
[
1
]
+=
quad2
[
0
]
*
element
;
element
=
rotationMatrix
[
1
][
0
]
*
rotationMatrix
[
0
][
1
]
+
rotationMatrix
[
0
][
0
]
*
rotationMatrix
[
1
][
1
];
rotated1
[
1
]
+=
quad1
[
1
]
*
element
;
rotated2
[
1
]
+=
quad2
[
1
]
*
element
;
element
=
rotationMatrix
[
1
][
0
]
*
rotationMatrix
[
0
][
2
]
+
rotationMatrix
[
0
][
0
]
*
rotationMatrix
[
1
][
2
];
rotated1
[
1
]
+=
quad1
[
2
]
*
element
;
rotated2
[
1
]
+=
quad2
[
2
]
*
element
;
element
=
rotationMatrix
[
0
][
1
]
*
rotationMatrix
[
1
][
1
]
-
rotationMatrix
[
0
][
2
]
*
rotationMatrix
[
1
][
2
];
rotated1
[
1
]
+=
quad1
[
3
]
*
element
;
rotated2
[
1
]
+=
quad2
[
3
]
*
element
;
element
=
rotationMatrix
[
1
][
1
]
*
rotationMatrix
[
0
][
2
]
+
rotationMatrix
[
0
][
1
]
*
rotationMatrix
[
1
][
2
];
rotated1
[
1
]
+=
quad1
[
4
]
*
element
;
rotated2
[
1
]
+=
quad2
[
4
]
*
element
;
element
=
sqrtThree
*
rotationMatrix
[
0
][
0
]
*
rotationMatrix
[
2
][
0
];
rotated1
[
2
]
+=
quad1
[
0
]
*
element
;
rotated2
[
2
]
+=
quad2
[
0
]
*
element
;
element
=
rotationMatrix
[
2
][
0
]
*
rotationMatrix
[
0
][
1
]
+
rotationMatrix
[
0
][
0
]
*
rotationMatrix
[
2
][
1
];
rotated1
[
2
]
+=
quad1
[
1
]
*
element
;
rotated2
[
2
]
+=
quad2
[
1
]
*
element
;
element
=
rotationMatrix
[
2
][
0
]
*
rotationMatrix
[
0
][
2
]
+
rotationMatrix
[
0
][
0
]
*
rotationMatrix
[
2
][
2
];
rotated1
[
2
]
+=
quad1
[
2
]
*
element
;
rotated2
[
2
]
+=
quad2
[
2
]
*
element
;
element
=
rotationMatrix
[
0
][
1
]
*
rotationMatrix
[
2
][
1
]
-
rotationMatrix
[
0
][
2
]
*
rotationMatrix
[
2
][
2
];
rotated1
[
2
]
+=
quad1
[
3
]
*
element
;
rotated2
[
2
]
+=
quad2
[
3
]
*
element
;
element
=
rotationMatrix
[
2
][
1
]
*
rotationMatrix
[
0
][
2
]
+
rotationMatrix
[
0
][
1
]
*
rotationMatrix
[
2
][
2
];
rotated1
[
2
]
+=
quad1
[
4
]
*
element
;
rotated2
[
2
]
+=
quad2
[
4
]
*
element
;
element
=
0.5
f
*
sqrtThree
*
(
rotationMatrix
[
1
][
0
]
*
rotationMatrix
[
1
][
0
]
-
rotationMatrix
[
2
][
0
]
*
rotationMatrix
[
2
][
0
]);
rotated1
[
3
]
+=
quad1
[
0
]
*
element
;
rotated2
[
3
]
+=
quad2
[
0
]
*
element
;
element
=
rotationMatrix
[
1
][
0
]
*
rotationMatrix
[
1
][
1
]
-
rotationMatrix
[
2
][
0
]
*
rotationMatrix
[
2
][
1
];
rotated1
[
3
]
+=
quad1
[
1
]
*
element
;
rotated2
[
3
]
+=
quad2
[
1
]
*
element
;
element
=
rotationMatrix
[
1
][
0
]
*
rotationMatrix
[
1
][
2
]
-
rotationMatrix
[
2
][
0
]
*
rotationMatrix
[
2
][
2
];
rotated1
[
3
]
+=
quad1
[
2
]
*
element
;
rotated2
[
3
]
+=
quad2
[
2
]
*
element
;
element
=
0.5
f
*
(
rotationMatrix
[
1
][
1
]
*
rotationMatrix
[
1
][
1
]
-
rotationMatrix
[
2
][
1
]
*
rotationMatrix
[
2
][
1
]
-
rotationMatrix
[
1
][
2
]
*
rotationMatrix
[
1
][
2
]
+
rotationMatrix
[
2
][
2
]
*
rotationMatrix
[
2
][
2
]);
rotated1
[
3
]
+=
quad1
[
3
]
*
element
;
rotated2
[
3
]
+=
quad2
[
3
]
*
element
;
element
=
rotationMatrix
[
1
][
1
]
*
rotationMatrix
[
1
][
2
]
-
rotationMatrix
[
2
][
1
]
*
rotationMatrix
[
2
][
2
];
rotated1
[
3
]
+=
quad1
[
4
]
*
element
;
rotated2
[
3
]
+=
quad2
[
4
]
*
element
;
element
=
sqrtThree
*
rotationMatrix
[
1
][
0
]
*
rotationMatrix
[
2
][
0
];
rotated1
[
4
]
+=
quad1
[
0
]
*
element
;
rotated2
[
4
]
+=
quad2
[
0
]
*
element
;
element
=
rotationMatrix
[
2
][
0
]
*
rotationMatrix
[
1
][
1
]
+
rotationMatrix
[
1
][
0
]
*
rotationMatrix
[
2
][
1
];
rotated1
[
4
]
+=
quad1
[
1
]
*
element
;
rotated2
[
4
]
+=
quad2
[
1
]
*
element
;
element
=
rotationMatrix
[
2
][
0
]
*
rotationMatrix
[
1
][
2
]
+
rotationMatrix
[
1
][
0
]
*
rotationMatrix
[
2
][
2
];
rotated1
[
4
]
+=
quad1
[
2
]
*
element
;
rotated2
[
4
]
+=
quad2
[
2
]
*
element
;
element
=
rotationMatrix
[
1
][
1
]
*
rotationMatrix
[
2
][
1
]
-
rotationMatrix
[
1
][
2
]
*
rotationMatrix
[
2
][
2
];
rotated1
[
4
]
+=
quad1
[
3
]
*
element
;
rotated2
[
4
]
+=
quad2
[
3
]
*
element
;
element
=
rotationMatrix
[
2
][
1
]
*
rotationMatrix
[
1
][
2
]
+
rotationMatrix
[
1
][
1
]
*
rotationMatrix
[
2
][
2
];
rotated1
[
4
]
+=
quad1
[
4
]
*
element
;
rotated2
[
4
]
+=
quad2
[
4
]
*
element
;
}
plugins/amoeba/platforms/cuda/tests/CMakeLists.txt
View file @
b7088b74
...
...
@@ -17,7 +17,7 @@ FOREACH(TEST_PROG ${TEST_PROGS})
IF
(
APPLE
)
SET_TARGET_PROPERTIES
(
${
TEST_ROOT
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
-F/Library/Frameworks -framework CUDA"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
"
)
ELSE
(
APPLE
)
SET_TARGET_PROPERTIES
(
${
TEST_ROOT
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
COMPILE
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
"
)
SET_TARGET_PROPERTIES
(
${
TEST_ROOT
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
LINK
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
"
)
ENDIF
(
APPLE
)
ADD_TEST
(
${
TEST_ROOT
}
Single
${
EXECUTABLE_OUTPUT_PATH
}
/
${
TEST_ROOT
}
single
)
IF
(
OPENMM_BUILD_CUDA_DOUBLE_PRECISION_TESTS
)
...
...
plugins/amoeba/platforms/cuda/tests/TestCudaAmoebaGeneralizedKirkwoodForce.cpp
View file @
b7088b74
...
...
@@ -6980,7 +6980,7 @@ static void compareForcesEnergy(std::string& testName, double expectedEnergy, do
const std::vector<Vec3>& expectedForces,
const std::vector<Vec3>& forces, double tolerance) {
for (unsigned int ii = 0; ii < forces.size(); ii++) {
ASSERT_EQUAL_VEC
_MOD
(expectedForces[ii], forces[ii], tolerance
, testName
);
ASSERT_EQUAL_VEC(expectedForces[ii], forces[ii], tolerance);
}
ASSERT_EQUAL_TOL_MOD(expectedEnergy, energy, tolerance, testName);
}
...
...
plugins/amoeba/platforms/reference/CMakeLists.txt
View file @
b7088b74
...
...
@@ -71,7 +71,7 @@ ADD_LIBRARY(${SHARED_TARGET} SHARED ${SOURCE_FILES} ${SOURCE_INCLUDE_FILES} ${AP
TARGET_LINK_LIBRARIES
(
${
SHARED_TARGET
}
${
OPENMM_LIBRARY_NAME
}
)
TARGET_LINK_LIBRARIES
(
${
SHARED_TARGET
}
${
SHARED_AMOEBA_TARGET
}
)
SET_TARGET_PROPERTIES
(
${
SHARED_TARGET
}
PROPERTIES COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
-DOPENMM_BUILDING_SHARED_LIBRARY"
)
SET_TARGET_PROPERTIES
(
${
SHARED_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
COMPILE
_FLAGS
}
"
)
SET_TARGET_PROPERTIES
(
${
SHARED_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
LINK
_FLAGS
}
"
)
INSTALL
(
TARGETS
${
SHARED_TARGET
}
DESTINATION
${
CMAKE_INSTALL_PREFIX
}
/lib/plugins
)
...
...
plugins/amoeba/platforms/reference/src/SimTKReference/AmoebaReferenceMultipoleForce.cpp
View file @
b7088b74
...
...
@@ -317,6 +317,18 @@ void AmoebaReferenceMultipoleForce::loadParticleData(const vector<RealVec>& part
particleData
[
ii
].
quadrupole
[
QYZ
]
=
quadrupoles
[
9
*
ii
+
5
];
particleData
[
ii
].
quadrupole
[
QZZ
]
=
quadrupoles
[
9
*
ii
+
8
];
// Form spherical harmonic dipoles from Cartesian moments.
particleData
[
ii
].
sphericalDipole
[
0
]
=
dipoles
[
3
*
ii
+
2
];
// z -> Q_10
particleData
[
ii
].
sphericalDipole
[
1
]
=
dipoles
[
3
*
ii
+
0
];
// x -> Q_11c
particleData
[
ii
].
sphericalDipole
[
2
]
=
dipoles
[
3
*
ii
+
1
];
// y -> Q_11s
// Form spherical harmonic quadrupoles from Cartesian moments.
particleData
[
ii
].
sphericalQuadrupole
[
0
]
=
quadrupoles
[
9
*
ii
+
8
]
*
3.0
;
// zz -> Q_20
particleData
[
ii
].
sphericalQuadrupole
[
1
]
=
sqrtFourThirds
*
quadrupoles
[
9
*
ii
+
2
]
*
3.0
;
// xz -> Q_21c
particleData
[
ii
].
sphericalQuadrupole
[
2
]
=
sqrtFourThirds
*
quadrupoles
[
9
*
ii
+
5
]
*
3.0
;
// yz -> Q_21s
particleData
[
ii
].
sphericalQuadrupole
[
3
]
=
sqrtOneThird
*
(
quadrupoles
[
9
*
ii
+
0
]
-
quadrupoles
[
9
*
ii
+
4
])
*
3.0
;
// xx-yy -> Q_22c
particleData
[
ii
].
sphericalQuadrupole
[
4
]
=
sqrtFourThirds
*
quadrupoles
[
9
*
ii
+
1
]
*
3.0
;
// xy -> Q_22s
particleData
[
ii
].
thole
=
tholes
[
ii
];
particleData
[
ii
].
dampingFactor
=
dampingFactors
[
ii
];
particleData
[
ii
].
polarity
=
polarity
[
ii
];
...
...
@@ -335,10 +347,10 @@ void AmoebaReferenceMultipoleForce::checkChiralCenterAtParticle(MultipoleParticl
MultipoleParticleData
&
particleY
)
const
{
if (axisType == AmoebaMultipoleForce::ZThenX) {
if
(
axisType
==
AmoebaMultipoleForce
::
ZThenX
||
particleY
.
particleIndex
==
-
1
)
{
return
;
}
RealVec
deltaAD
=
particleI
.
position
-
particleY
.
position
;
RealVec
deltaBD
=
particleZ
.
position
-
particleY
.
position
;
RealVec
deltaCD
=
particleX
.
position
-
particleY
.
position
;
...
...
@@ -347,9 +359,12 @@ void AmoebaReferenceMultipoleForce::checkChiralCenterAtParticle(MultipoleParticl
RealOpenMM
volume
=
deltaC
.
dot
(
deltaAD
);
if
(
volume
<
0.0
)
{
particleI.dipole[1] *= -1.0; // pole(3,i)
particleI.quadrupole[QXY] *= -1.0; // pole(6,i) && pole(8,i)
particleI.quadrupole[QYZ] *= -1.0; // pole(10,i) && pole(12,i)
particleI
.
dipole
[
1
]
*=
-
1.0
;
// pole(3,i)
particleI
.
quadrupole
[
QXY
]
*=
-
1.0
;
// pole(6,i) && pole(8,i)
particleI
.
quadrupole
[
QYZ
]
*=
-
1.0
;
// pole(10,i) && pole(12,i)
particleI
.
sphericalDipole
[
2
]
*=
-
1.0
;
// y
particleI
.
sphericalQuadrupole
[
2
]
*=
-
1.0
;
// yz
particleI
.
sphericalQuadrupole
[
4
]
*=
-
1.0
;
// xy
}
}
...
...
@@ -359,7 +374,6 @@ void AmoebaReferenceMultipoleForce::checkChiral(vector<MultipoleParticleData>& p
const
vector
<
int
>&
multipoleAtomZs
,
const
vector
<
int
>&
axisTypes
)
const
{
for
(
unsigned
int
ii
=
0
;
ii
<
_numParticles
;
ii
++
)
{
if
(
multipoleAtomYs
[
ii
]
>
-
1
)
{
checkChiralCenterAtParticle
(
particleData
[
ii
],
axisTypes
[
ii
],
...
...
@@ -383,6 +397,7 @@ void AmoebaReferenceMultipoleForce::applyRotationMatrixToParticle( Multipol
// compute the vector between the atoms and 1/sqrt(d2), d2 is distance between
// this atom and the axis atom
RealVec
vectorY
;
RealVec
vectorZ
=
particleZ
.
position
-
particleI
.
position
;
RealVec
vectorX
=
particleX
.
position
-
particleI
.
position
;
...
...
@@ -491,6 +506,130 @@ void AmoebaReferenceMultipoleForce::applyRotationMatrixToParticle( Multipol
particleI
.
quadrupole
[
QYY
]
=
rPole
[
1
][
1
];
particleI
.
quadrupole
[
QYZ
]
=
rPole
[
1
][
2
];
particleI
.
quadrupole
[
QZZ
]
=
rPole
[
2
][
2
];
RealOpenMM
dipoleRotationMatrix
[
3
][
3
];
// Reorder the Cartesian {x,y,z} dipole rotation matrix, to account
// for spherical harmonic ordering {z,x,y}.
dipoleRotationMatrix
[
0
][
0
]
=
vectorZ
[
2
];
dipoleRotationMatrix
[
0
][
1
]
=
vectorX
[
2
];
dipoleRotationMatrix
[
0
][
2
]
=
vectorY
[
2
];
dipoleRotationMatrix
[
1
][
0
]
=
vectorZ
[
0
];
dipoleRotationMatrix
[
1
][
1
]
=
vectorX
[
0
];
dipoleRotationMatrix
[
1
][
2
]
=
vectorY
[
0
];
dipoleRotationMatrix
[
2
][
0
]
=
vectorZ
[
1
];
dipoleRotationMatrix
[
2
][
1
]
=
vectorX
[
1
];
dipoleRotationMatrix
[
2
][
2
]
=
vectorY
[
1
];
RealOpenMM
quadrupoleRotationMatrix
[
5
][
5
];
buildSphericalQuadrupoleRotationMatrix
(
dipoleRotationMatrix
,
quadrupoleRotationMatrix
);
// Rotate the dipoles
RealOpenMM
rotatedDipole
[
3
];
for
(
int
ii
=
0
;
ii
<
3
;
ii
++
)
{
RealOpenMM
val
=
0.0
;
for
(
int
jj
=
0
;
jj
<
3
;
jj
++
)
{
val
+=
dipoleRotationMatrix
[
ii
][
jj
]
*
particleI
.
sphericalDipole
[
jj
];
}
rotatedDipole
[
ii
]
=
val
;
}
for
(
int
ii
=
0
;
ii
<
3
;
ii
++
)
particleI
.
sphericalDipole
[
ii
]
=
rotatedDipole
[
ii
];
// Rotate the quadrupoles
RealOpenMM
rotatedQuadrupole
[
5
];
for
(
int
ii
=
0
;
ii
<
5
;
ii
++
)
{
RealOpenMM
val
=
0.0
;
for
(
int
jj
=
0
;
jj
<
5
;
jj
++
)
{
val
+=
quadrupoleRotationMatrix
[
ii
][
jj
]
*
particleI
.
sphericalQuadrupole
[
jj
];
}
rotatedQuadrupole
[
ii
]
=
val
;
}
for
(
int
ii
=
0
;
ii
<
5
;
ii
++
)
particleI
.
sphericalQuadrupole
[
ii
]
=
rotatedQuadrupole
[
ii
];
}
void
AmoebaReferenceMultipoleForce
::
formQIRotationMatrix
(
const
RealVec
&
iPosition
,
const
RealVec
&
jPosition
,
const
RealVec
&
deltaR
,
RealOpenMM
r
,
RealOpenMM
(
&
rotationMatrix
)[
3
][
3
])
const
{
RealVec
vectorZ
=
(
deltaR
)
/
r
;
RealVec
vectorX
(
vectorZ
);
if
((
iPosition
[
1
]
!=
jPosition
[
1
])
||
(
iPosition
[
2
]
!=
jPosition
[
2
])){
vectorX
[
0
]
+=
1.0
;
}
else
{
vectorX
[
1
]
+=
1.0
;
}
RealVec
vectorY
;
RealOpenMM
dot
=
vectorZ
.
dot
(
vectorX
);
vectorX
-=
vectorZ
*
dot
;
normalizeRealVec
(
vectorX
);
vectorY
=
vectorZ
.
cross
(
vectorX
);
// Reorder the Cartesian {x,y,z} dipole rotation matrix, to account
// for spherical harmonic ordering {z,x,y}.
rotationMatrix
[
0
][
0
]
=
vectorZ
[
2
];
rotationMatrix
[
0
][
1
]
=
vectorZ
[
0
];
rotationMatrix
[
0
][
2
]
=
vectorZ
[
1
];
rotationMatrix
[
1
][
0
]
=
vectorX
[
2
];
rotationMatrix
[
1
][
1
]
=
vectorX
[
0
];
rotationMatrix
[
1
][
2
]
=
vectorX
[
1
];
rotationMatrix
[
2
][
0
]
=
vectorY
[
2
];
rotationMatrix
[
2
][
1
]
=
vectorY
[
0
];
rotationMatrix
[
2
][
2
]
=
vectorY
[
1
];
}
void
AmoebaReferenceMultipoleForce
::
buildSphericalQuadrupoleRotationMatrix
(
const
RealOpenMM
(
&
D1
)[
3
][
3
],
RealOpenMM
(
&
D2
)[
5
][
5
])
const
{
D2
[
0
][
0
]
=
0.5
*
(
3.0
*
D1
[
0
][
0
]
*
D1
[
0
][
0
]
-
1.0
);
D2
[
1
][
0
]
=
sqrtThree
*
D1
[
0
][
0
]
*
D1
[
1
][
0
];
D2
[
2
][
0
]
=
sqrtThree
*
D1
[
0
][
0
]
*
D1
[
2
][
0
];
D2
[
3
][
0
]
=
0.5
*
sqrtThree
*
(
D1
[
1
][
0
]
*
D1
[
1
][
0
]
-
D1
[
2
][
0
]
*
D1
[
2
][
0
]);
D2
[
4
][
0
]
=
sqrtThree
*
D1
[
1
][
0
]
*
D1
[
2
][
0
];
D2
[
0
][
1
]
=
sqrtThree
*
D1
[
0
][
0
]
*
D1
[
0
][
1
];
D2
[
1
][
1
]
=
D1
[
1
][
0
]
*
D1
[
0
][
1
]
+
D1
[
0
][
0
]
*
D1
[
1
][
1
];
D2
[
2
][
1
]
=
D1
[
2
][
0
]
*
D1
[
0
][
1
]
+
D1
[
0
][
0
]
*
D1
[
2
][
1
];
D2
[
3
][
1
]
=
D1
[
1
][
0
]
*
D1
[
1
][
1
]
-
D1
[
2
][
0
]
*
D1
[
2
][
1
];
D2
[
4
][
1
]
=
D1
[
2
][
0
]
*
D1
[
1
][
1
]
+
D1
[
1
][
0
]
*
D1
[
2
][
1
];
D2
[
0
][
2
]
=
sqrtThree
*
D1
[
0
][
0
]
*
D1
[
0
][
2
];
D2
[
1
][
2
]
=
D1
[
1
][
0
]
*
D1
[
0
][
2
]
+
D1
[
0
][
0
]
*
D1
[
1
][
2
];
D2
[
2
][
2
]
=
D1
[
2
][
0
]
*
D1
[
0
][
2
]
+
D1
[
0
][
0
]
*
D1
[
2
][
2
];
D2
[
3
][
2
]
=
D1
[
1
][
0
]
*
D1
[
1
][
2
]
-
D1
[
2
][
0
]
*
D1
[
2
][
2
];
D2
[
4
][
2
]
=
D1
[
2
][
0
]
*
D1
[
1
][
2
]
+
D1
[
1
][
0
]
*
D1
[
2
][
2
];
D2
[
0
][
3
]
=
0.5
*
sqrtThree
*
(
D1
[
0
][
1
]
*
D1
[
0
][
1
]
-
D1
[
0
][
2
]
*
D1
[
0
][
2
]);
D2
[
1
][
3
]
=
D1
[
0
][
1
]
*
D1
[
1
][
1
]
-
D1
[
0
][
2
]
*
D1
[
1
][
2
];
D2
[
2
][
3
]
=
D1
[
0
][
1
]
*
D1
[
2
][
1
]
-
D1
[
0
][
2
]
*
D1
[
2
][
2
];
D2
[
3
][
3
]
=
0.5
*
(
D1
[
1
][
1
]
*
D1
[
1
][
1
]
-
D1
[
2
][
1
]
*
D1
[
2
][
1
]
-
D1
[
1
][
2
]
*
D1
[
1
][
2
]
+
D1
[
2
][
2
]
*
D1
[
2
][
2
]);
D2
[
4
][
3
]
=
D1
[
1
][
1
]
*
D1
[
2
][
1
]
-
D1
[
1
][
2
]
*
D1
[
2
][
2
];
D2
[
0
][
4
]
=
sqrtThree
*
D1
[
0
][
1
]
*
D1
[
0
][
2
];
D2
[
1
][
4
]
=
D1
[
1
][
1
]
*
D1
[
0
][
2
]
+
D1
[
0
][
1
]
*
D1
[
1
][
2
];
D2
[
2
][
4
]
=
D1
[
2
][
1
]
*
D1
[
0
][
2
]
+
D1
[
0
][
1
]
*
D1
[
2
][
2
];
D2
[
3
][
4
]
=
D1
[
1
][
1
]
*
D1
[
1
][
2
]
-
D1
[
2
][
1
]
*
D1
[
2
][
2
];
D2
[
4
][
4
]
=
D1
[
2
][
1
]
*
D1
[
1
][
2
]
+
D1
[
1
][
1
]
*
D1
[
2
][
2
];
}
void
AmoebaReferenceMultipoleForce
::
buildPartialSphericalQuadrupoleRotationMatrix
(
const
RealOpenMM
(
&
D1
)[
3
][
3
],
RealOpenMM
(
&
D2
)[
3
][
5
])
const
{
D2
[
0
][
0
]
=
0.5
*
(
3.0
*
D1
[
0
][
0
]
*
D1
[
0
][
0
]
-
1.0
);
D2
[
0
][
1
]
=
sqrtThree
*
D1
[
0
][
0
]
*
D1
[
0
][
1
];
D2
[
0
][
2
]
=
sqrtThree
*
D1
[
0
][
0
]
*
D1
[
0
][
2
];
D2
[
0
][
3
]
=
0.5
*
sqrtThree
*
(
D1
[
0
][
1
]
*
D1
[
0
][
1
]
-
D1
[
0
][
2
]
*
D1
[
0
][
2
]);
D2
[
0
][
4
]
=
sqrtThree
*
D1
[
0
][
1
]
*
D1
[
0
][
2
];
D2
[
1
][
0
]
=
sqrtThree
*
D1
[
0
][
0
]
*
D1
[
1
][
0
];
D2
[
1
][
1
]
=
D1
[
1
][
0
]
*
D1
[
0
][
1
]
+
D1
[
0
][
0
]
*
D1
[
1
][
1
];
D2
[
1
][
2
]
=
D1
[
1
][
0
]
*
D1
[
0
][
2
]
+
D1
[
0
][
0
]
*
D1
[
1
][
2
];
D2
[
1
][
3
]
=
D1
[
0
][
1
]
*
D1
[
1
][
1
]
-
D1
[
0
][
2
]
*
D1
[
1
][
2
];
D2
[
1
][
4
]
=
D1
[
1
][
1
]
*
D1
[
0
][
2
]
+
D1
[
0
][
1
]
*
D1
[
1
][
2
];
D2
[
2
][
0
]
=
sqrtThree
*
D1
[
0
][
0
]
*
D1
[
2
][
0
];
D2
[
2
][
1
]
=
D1
[
2
][
0
]
*
D1
[
0
][
1
]
+
D1
[
0
][
0
]
*
D1
[
2
][
1
];
D2
[
2
][
2
]
=
D1
[
2
][
0
]
*
D1
[
0
][
2
]
+
D1
[
0
][
0
]
*
D1
[
2
][
2
];
D2
[
2
][
3
]
=
D1
[
0
][
1
]
*
D1
[
2
][
1
]
-
D1
[
0
][
2
]
*
D1
[
2
][
2
];
D2
[
2
][
4
]
=
D1
[
2
][
1
]
*
D1
[
0
][
2
]
+
D1
[
0
][
1
]
*
D1
[
2
][
2
];
}
void
AmoebaReferenceMultipoleForce
::
applyRotationMatrix
(
vector
<
MultipoleParticleData
>&
particleData
,
...
...
@@ -552,6 +691,7 @@ void AmoebaReferenceMultipoleForce::calculateFixedMultipoleFieldPairIxn(const Mu
RealVec
deltaR
=
particleJ
.
position
-
particleI
.
position
;
RealOpenMM
r
=
SQRT
(
deltaR
.
dot
(
deltaR
));
vector
<
RealOpenMM
>
rrI
(
3
);
// get scaling factors, if needed
...
...
@@ -907,356 +1047,389 @@ RealOpenMM AmoebaReferenceMultipoleForce::calculateElectrostaticPairIxn(const Mu
vector
<
RealVec
>&
forces
,
vector
<
RealVec
>&
torque
)
const
{
RealOpenMM temp3,temp5,temp7;
RealOpenMM gl[9],gli[7],glip[7];
RealOpenMM sc[10],sci[8],scip[8];
RealOpenMM gf[7],gfi[6],gti[6];
unsigned
int
iIndex
=
particleI
.
particleIndex
;
unsigned
int
kIndex
=
particleK
.
particleIndex
;
RealVec delta = particleK.position - particleI.position;
RealOpenMM r2 = delta.dot(delta);
// set conversion factor, cutoff and switching coefficients
RealOpenMM f = _electric/_dielectric;
// set scale factors for permanent multipole and induced terms
RealOpenMM pdi = particleI.dampingFactor;
RealOpenMM pti = particleI.thole;
// apply Thole polarization damping to scale factors
RealOpenMM r = SQRT(r2);
RealOpenMM rr1 = 1.0/r;
RealOpenMM rr3 = rr1/r2;
RealOpenMM rr5 = 3.0*rr3/r2;
RealOpenMM rr7 = 5.0*rr5/r2;
RealOpenMM rr9 = 7.0*rr7/r2;
RealOpenMM rr11 = 9.0*rr9/r2;
RealOpenMM scale3 = 1.0;
RealOpenMM scale5 = 1.0;
RealOpenMM scale7 = 1.0;
RealVec ddsc3(0.0, 0.0, 0.0);
RealVec ddsc5(0.0, 0.0, 0.0);
RealVec ddsc7(0.0, 0.0, 0.0);
RealOpenMM damp = particleI.dampingFactor*particleK.dampingFactor;
if (damp != 0.0) {
RealOpenMM pgamma = particleI.thole < particleK.thole ? particleI.thole : particleK.thole;
RealOpenMM ratio = (r/damp);
damp = -pgamma * ratio*ratio*ratio;
if (damp > -50.0) {
RealOpenMM expdamp = EXP(damp);
scale3 = 1.0 - expdamp;
scale5 = 1.0 - (1.0-damp)*expdamp;
scale7 = 1.0 - (1.0-damp+0.6*damp*damp)*expdamp;
temp3 = -3.0 * damp * expdamp / r2;
temp5 = -damp;
temp7 = -0.2 - 0.6*damp;
ddsc3 = delta*temp3;
ddsc5 = ddsc3*temp5;
ddsc7 = ddsc5*temp7;
RealVec
deltaR
=
particleK
.
position
-
particleI
.
position
;
RealOpenMM
r2
=
deltaR
.
dot
(
deltaR
);
RealOpenMM
r
=
SQRT
(
r2
);
// Start by constructing rotation matrices to put dipoles and
// quadrupoles into the QI frame, from the lab frame.
RealOpenMM
qiRotationMatrix1
[
3
][
3
];
formQIRotationMatrix
(
particleI
.
position
,
particleK
.
position
,
deltaR
,
r
,
qiRotationMatrix1
);
RealOpenMM
qiRotationMatrix2
[
5
][
5
];
buildSphericalQuadrupoleRotationMatrix
(
qiRotationMatrix1
,
qiRotationMatrix2
);
// The force rotation matrix rotates the QI forces into the lab
// frame, and makes sure the result is in {x,y,z} ordering. Its
// transpose is used to rotate the induced dipoles to the QI frame.
RealOpenMM
forceRotationMatrix
[
3
][
3
];
forceRotationMatrix
[
0
][
0
]
=
qiRotationMatrix1
[
1
][
1
];
forceRotationMatrix
[
0
][
1
]
=
qiRotationMatrix1
[
2
][
1
];
forceRotationMatrix
[
0
][
2
]
=
qiRotationMatrix1
[
0
][
1
];
forceRotationMatrix
[
1
][
0
]
=
qiRotationMatrix1
[
1
][
2
];
forceRotationMatrix
[
1
][
1
]
=
qiRotationMatrix1
[
2
][
2
];
forceRotationMatrix
[
1
][
2
]
=
qiRotationMatrix1
[
0
][
2
];
forceRotationMatrix
[
2
][
0
]
=
qiRotationMatrix1
[
1
][
0
];
forceRotationMatrix
[
2
][
1
]
=
qiRotationMatrix1
[
2
][
0
];
forceRotationMatrix
[
2
][
2
]
=
qiRotationMatrix1
[
0
][
0
];
// For efficiency, we go ahead and cache that transposed version
// now, because we need to do 4 rotations in total (I,J, and p,d).
// We also fold in the factor of 0.5 needed to average the p and d
// components.
RealOpenMM
inducedDipoleRotationMatrix
[
3
][
3
];
inducedDipoleRotationMatrix
[
0
][
0
]
=
0.5
*
qiRotationMatrix1
[
0
][
1
];
inducedDipoleRotationMatrix
[
0
][
1
]
=
0.5
*
qiRotationMatrix1
[
0
][
2
];
inducedDipoleRotationMatrix
[
0
][
2
]
=
0.5
*
qiRotationMatrix1
[
0
][
0
];
inducedDipoleRotationMatrix
[
1
][
0
]
=
0.5
*
qiRotationMatrix1
[
1
][
1
];
inducedDipoleRotationMatrix
[
1
][
1
]
=
0.5
*
qiRotationMatrix1
[
1
][
2
];
inducedDipoleRotationMatrix
[
1
][
2
]
=
0.5
*
qiRotationMatrix1
[
1
][
0
];
inducedDipoleRotationMatrix
[
2
][
0
]
=
0.5
*
qiRotationMatrix1
[
2
][
1
];
inducedDipoleRotationMatrix
[
2
][
1
]
=
0.5
*
qiRotationMatrix1
[
2
][
2
];
inducedDipoleRotationMatrix
[
2
][
2
]
=
0.5
*
qiRotationMatrix1
[
2
][
0
];
// Rotate the induced dipoles to the QI frame.
RealOpenMM
qiUindI
[
3
],
qiUindJ
[
3
],
qiUinpI
[
3
],
qiUinpJ
[
3
];
for
(
int
ii
=
0
;
ii
<
3
;
ii
++
)
{
RealOpenMM
valIP
=
0.0
;
RealOpenMM
valID
=
0.0
;
RealOpenMM
valJP
=
0.0
;
RealOpenMM
valJD
=
0.0
;
for
(
int
jj
=
0
;
jj
<
3
;
jj
++
)
{
valIP
+=
inducedDipoleRotationMatrix
[
ii
][
jj
]
*
_inducedDipolePolar
[
iIndex
][
jj
];
valID
+=
inducedDipoleRotationMatrix
[
ii
][
jj
]
*
_inducedDipole
[
iIndex
][
jj
];
valJP
+=
inducedDipoleRotationMatrix
[
ii
][
jj
]
*
_inducedDipolePolar
[
kIndex
][
jj
];
valJD
+=
inducedDipoleRotationMatrix
[
ii
][
jj
]
*
_inducedDipole
[
kIndex
][
jj
];
}
qiUindI
[
ii
]
=
valID
;
qiUinpI
[
ii
]
=
valIP
;
qiUindJ
[
ii
]
=
valJD
;
qiUinpJ
[
ii
]
=
valJP
;
}
RealOpenMM scale3i = scale3*scalingFactors[U_SCALE];
RealOpenMM scale5i = scale5*scalingFactors[U_SCALE];
RealOpenMM scale7i = scale7*scalingFactors[U_SCALE];
RealOpenMM dsc3 = scale3*scalingFactors[D_SCALE];
RealOpenMM dsc5 = scale5*scalingFactors[D_SCALE];
RealOpenMM dsc7 = scale7*scalingFactors[D_SCALE];
RealOpenMM psc3 = scale3*scalingFactors[P_SCALE];
RealOpenMM psc5 = scale5*scalingFactors[P_SCALE];
RealOpenMM psc7 = scale7*scalingFactors[P_SCALE];
// construct necessary auxiliary vectors
RealVec dixdk = particleI.dipole.cross(particleK.dipole);
RealVec dixuk = particleI.dipole.cross(_inducedDipole[kIndex]);
RealVec dkxui = particleK.dipole.cross(_inducedDipole[iIndex]);
RealVec dixukp = particleI.dipole.cross(_inducedDipolePolar[kIndex]);
RealVec dkxuip = particleK.dipole.cross(_inducedDipolePolar[iIndex]);
RealVec dixr = particleI.dipole.cross(delta);
RealVec dkxr = particleK.dipole.cross(delta);
RealVec qir;
qir[0] = particleI.quadrupole[QXX]*delta[0] + particleI.quadrupole[QXY]*delta[1] + particleI.quadrupole[QXZ]*delta[2];
qir[1] = particleI.quadrupole[QXY]*delta[0] + particleI.quadrupole[QYY]*delta[1] + particleI.quadrupole[QYZ]*delta[2];
qir[2] = particleI.quadrupole[QXZ]*delta[0] + particleI.quadrupole[QYZ]*delta[1] + particleI.quadrupole[QZZ]*delta[2];
RealVec qkr;
qkr[0] = particleK.quadrupole[QXX]*delta[0] + particleK.quadrupole[QXY]*delta[1] + particleK.quadrupole[QXZ]*delta[2];
qkr[1] = particleK.quadrupole[QXY]*delta[0] + particleK.quadrupole[QYY]*delta[1] + particleK.quadrupole[QYZ]*delta[2];
qkr[2] = particleK.quadrupole[QXZ]*delta[0] + particleK.quadrupole[QYZ]*delta[1] + particleK.quadrupole[QZZ]*delta[2];
RealVec qiqkr;
qiqkr[0] = particleI.quadrupole[QXX]*qkr[0] + particleI.quadrupole[QXY]*qkr[1] + particleI.quadrupole[QXZ]*qkr[2];
qiqkr[1] = particleI.quadrupole[QXY]*qkr[0] + particleI.quadrupole[QYY]*qkr[1] + particleI.quadrupole[QYZ]*qkr[2];
qiqkr[2] = particleI.quadrupole[QXZ]*qkr[0] + particleI.quadrupole[QYZ]*qkr[1] + particleI.quadrupole[QZZ]*qkr[2];
RealVec qkqir;
qkqir[0] = particleK.quadrupole[QXX]*qir[0] + particleK.quadrupole[QXY]*qir[1] + particleK.quadrupole[QXZ]*qir[2];
qkqir[1] = particleK.quadrupole[QXY]*qir[0] + particleK.quadrupole[QYY]*qir[1] + particleK.quadrupole[QYZ]*qir[2];
qkqir[2] = particleK.quadrupole[QXZ]*qir[0] + particleK.quadrupole[QYZ]*qir[1] + particleK.quadrupole[QZZ]*qir[2];
RealVec qixqk;
qixqk[0] = particleI.quadrupole[QXY]*particleK.quadrupole[QXZ] +
particleI.quadrupole[QYY]*particleK.quadrupole[QYZ] +
particleI.quadrupole[QYZ]*particleK.quadrupole[QZZ] -
particleI.quadrupole[QXZ]*particleK.quadrupole[QXY] -
particleI.quadrupole[QYZ]*particleK.quadrupole[QYY] -
particleI.quadrupole[QZZ]*particleK.quadrupole[QYZ];
qixqk[1] = particleI.quadrupole[QXZ]*particleK.quadrupole[QXX] +
particleI.quadrupole[QYZ]*particleK.quadrupole[QXY] +
particleI.quadrupole[QZZ]*particleK.quadrupole[QXZ] -
particleI.quadrupole[QXX]*particleK.quadrupole[QXZ] -
particleI.quadrupole[QXY]*particleK.quadrupole[QYZ] -
particleI.quadrupole[QXZ]*particleK.quadrupole[QZZ];
qixqk[2] = particleI.quadrupole[QXX]*particleK.quadrupole[QXY] +
particleI.quadrupole[QXY]*particleK.quadrupole[QYY] +
particleI.quadrupole[QXZ]*particleK.quadrupole[QYZ] -
particleI.quadrupole[QXY]*particleK.quadrupole[QXX] -
particleI.quadrupole[QYY]*particleK.quadrupole[QXY] -
particleI.quadrupole[QYZ]*particleK.quadrupole[QXZ];
RealVec rxqir = delta.cross(qir);
RealVec rxqkr = delta.cross(qkr);
RealVec rxqikr = delta.cross(qiqkr);
RealVec rxqkir = delta.cross(qkqir);
RealVec qkrxqir = qkr.cross(qir);
RealVec qidk,qkdi;
qidk[0] = particleI.quadrupole[QXX]*particleK.dipole[0] + particleI.quadrupole[QXY]*particleK.dipole[1] + particleI.quadrupole[QXZ]*particleK.dipole[2];
qidk[1] = particleI.quadrupole[QXY]*particleK.dipole[0] + particleI.quadrupole[QYY]*particleK.dipole[1] + particleI.quadrupole[QYZ]*particleK.dipole[2];
qidk[2] = particleI.quadrupole[QXZ]*particleK.dipole[0] + particleI.quadrupole[QYZ]*particleK.dipole[1] + particleI.quadrupole[QZZ]*particleK.dipole[2];
qkdi[0] = particleK.quadrupole[QXX]*particleI.dipole[0] + particleK.quadrupole[QXY]*particleI.dipole[1] + particleK.quadrupole[QXZ]*particleI.dipole[2];
qkdi[1] = particleK.quadrupole[QXY]*particleI.dipole[0] + particleK.quadrupole[QYY]*particleI.dipole[1] + particleK.quadrupole[QYZ]*particleI.dipole[2];
qkdi[2] = particleK.quadrupole[QXZ]*particleI.dipole[0] + particleK.quadrupole[QYZ]*particleI.dipole[1] + particleK.quadrupole[QZZ]*particleI.dipole[2];
RealVec qiuk,qkui;
qiuk[0] = particleI.quadrupole[QXX]*_inducedDipole[kIndex][0] + particleI.quadrupole[QXY]*_inducedDipole[kIndex][1] + particleI.quadrupole[QXZ]*_inducedDipole[kIndex][2];
qiuk[1] = particleI.quadrupole[QXY]*_inducedDipole[kIndex][0] + particleI.quadrupole[QYY]*_inducedDipole[kIndex][1] + particleI.quadrupole[QYZ]*_inducedDipole[kIndex][2];
qiuk[2] = particleI.quadrupole[QXZ]*_inducedDipole[kIndex][0] + particleI.quadrupole[QYZ]*_inducedDipole[kIndex][1] + particleI.quadrupole[QZZ]*_inducedDipole[kIndex][2];
qkui[0] = particleK.quadrupole[QXX]*_inducedDipole[iIndex][0] + particleK.quadrupole[QXY]*_inducedDipole[iIndex][1] + particleK.quadrupole[QXZ]*_inducedDipole[iIndex][2];
qkui[1] = particleK.quadrupole[QXY]*_inducedDipole[iIndex][0] + particleK.quadrupole[QYY]*_inducedDipole[iIndex][1] + particleK.quadrupole[QYZ]*_inducedDipole[iIndex][2];
qkui[2] = particleK.quadrupole[QXZ]*_inducedDipole[iIndex][0] + particleK.quadrupole[QYZ]*_inducedDipole[iIndex][1] + particleK.quadrupole[QZZ]*_inducedDipole[iIndex][2];
RealVec qiukp,qkuip;
qiukp[0] = particleI.quadrupole[QXX]*_inducedDipolePolar[kIndex][0] + particleI.quadrupole[QXY]*_inducedDipolePolar[kIndex][1] + particleI.quadrupole[QXZ]*_inducedDipolePolar[kIndex][2];
qiukp[1] = particleI.quadrupole[QXY]*_inducedDipolePolar[kIndex][0] + particleI.quadrupole[QYY]*_inducedDipolePolar[kIndex][1] + particleI.quadrupole[QYZ]*_inducedDipolePolar[kIndex][2];
qiukp[2] = particleI.quadrupole[QXZ]*_inducedDipolePolar[kIndex][0] + particleI.quadrupole[QYZ]*_inducedDipolePolar[kIndex][1] + particleI.quadrupole[QZZ]*_inducedDipolePolar[kIndex][2];
qkuip[0] = particleK.quadrupole[QXX]*_inducedDipolePolar[iIndex][0] + particleK.quadrupole[QXY]*_inducedDipolePolar[iIndex][1] + particleK.quadrupole[QXZ]*_inducedDipolePolar[iIndex][2];
qkuip[1] = particleK.quadrupole[QXY]*_inducedDipolePolar[iIndex][0] + particleK.quadrupole[QYY]*_inducedDipolePolar[iIndex][1] + particleK.quadrupole[QYZ]*_inducedDipolePolar[iIndex][2];
qkuip[2] = particleK.quadrupole[QXZ]*_inducedDipolePolar[iIndex][0] + particleK.quadrupole[QYZ]*_inducedDipolePolar[iIndex][1] + particleK.quadrupole[QZZ]*_inducedDipolePolar[iIndex][2];
RealVec dixqkr = particleI.dipole.cross(qkr);
RealVec dkxqir = particleK.dipole.cross(qir);
RealVec uixqkr = _inducedDipole[iIndex].cross(qkr);
RealVec ukxqir = _inducedDipole[kIndex].cross(qir);
RealVec uixqkrp = _inducedDipolePolar[iIndex].cross(qkr);
RealVec ukxqirp = _inducedDipolePolar[kIndex].cross(qir);
RealVec rxqidk = delta.cross(qidk);
RealVec rxqkdi = delta.cross(qkdi);
RealVec rxqiuk = delta.cross(qiuk);
RealVec rxqkui = delta.cross(qkui);
RealVec rxqiukp = delta.cross(qiukp);
RealVec rxqkuip = delta.cross(qkuip);
// calculate scalar products for permanent components
sc[1] = particleI.dipole.dot(particleK.dipole);
sc[2] = particleI.dipole.dot(delta);
sc[3] = particleK.dipole.dot(delta);
sc[4] = qir.dot(delta);
sc[5] = qkr.dot(delta);
sc[6] = qir.dot(particleK.dipole);
sc[7] = qkr.dot(particleI.dipole);
sc[8] = qir.dot(qkr);
sc[9] = particleI.quadrupole[QXX]*particleK.quadrupole[QXX] + particleI.quadrupole[QXY]*particleK.quadrupole[QXY] + particleI.quadrupole[QXZ]*particleK.quadrupole[QXZ] +
particleI.quadrupole[QXY]*particleK.quadrupole[QXY] + particleI.quadrupole[QYY]*particleK.quadrupole[QYY] + particleI.quadrupole[QYZ]*particleK.quadrupole[QYZ] +
particleI.quadrupole[QXZ]*particleK.quadrupole[QXZ] + particleI.quadrupole[QYZ]*particleK.quadrupole[QYZ] + particleI.quadrupole[QZZ]*particleK.quadrupole[QZZ];
// calculate scalar products for induced components
sci[0] = _inducedDipole[iIndex][0]*particleK.dipole[0] + _inducedDipole[iIndex][1]*particleK.dipole[1] + _inducedDipole[iIndex][2]*particleK.dipole[2] +particleI.dipole[0]*_inducedDipole[kIndex][0] +particleI.dipole[1]*_inducedDipole[kIndex][1] +particleI.dipole[2]*_inducedDipole[kIndex][2];
sci[1] = _inducedDipole[iIndex][0]*_inducedDipole[kIndex][0] + _inducedDipole[iIndex][1]*_inducedDipole[kIndex][1] + _inducedDipole[iIndex][2]*_inducedDipole[kIndex][2];
sci[2] = _inducedDipole[iIndex][0]*delta[0] + _inducedDipole[iIndex][1]*delta[1] + _inducedDipole[iIndex][2]*delta[2];
sci[3] = _inducedDipole[kIndex][0]*delta[0] + _inducedDipole[kIndex][1]*delta[1] + _inducedDipole[kIndex][2]*delta[2];
sci[6] = qir[0]*_inducedDipole[kIndex][0] + qir[1]*_inducedDipole[kIndex][1] + qir[2]*_inducedDipole[kIndex][2];
sci[7] = qkr[0]*_inducedDipole[iIndex][0] + qkr[1]*_inducedDipole[iIndex][1] + qkr[2]*_inducedDipole[iIndex][2];
scip[0] = _inducedDipolePolar[iIndex][0]*particleK.dipole[0] + _inducedDipolePolar[iIndex][1]*particleK.dipole[1] + _inducedDipolePolar[iIndex][2]*particleK.dipole[2] +particleI.dipole[0]*_inducedDipolePolar[kIndex][0] +particleI.dipole[1]*_inducedDipolePolar[kIndex][1] +particleI.dipole[2]*_inducedDipolePolar[kIndex][2];
scip[1] = _inducedDipole[iIndex][0]*_inducedDipolePolar[kIndex][0]+_inducedDipole[iIndex][1]*_inducedDipolePolar[kIndex][1] + _inducedDipole[iIndex][2]*_inducedDipolePolar[kIndex][2]+_inducedDipolePolar[iIndex][0]*_inducedDipole[kIndex][0] + _inducedDipolePolar[iIndex][1]*_inducedDipole[kIndex][1]+_inducedDipolePolar[iIndex][2]*_inducedDipole[kIndex][2];
scip[2] = _inducedDipolePolar[iIndex][0]*delta[0] + _inducedDipolePolar[iIndex][1]*delta[1] + _inducedDipolePolar[iIndex][2]*delta[2];
scip[3] = _inducedDipolePolar[kIndex][0]*delta[0] + _inducedDipolePolar[kIndex][1]*delta[1] + _inducedDipolePolar[kIndex][2]*delta[2];
scip[6] = qir[0]*_inducedDipolePolar[kIndex][0] + qir[1]*_inducedDipolePolar[kIndex][1] + qir[2]*_inducedDipolePolar[kIndex][2];
scip[7] = qkr[0]*_inducedDipolePolar[iIndex][0] + qkr[1]*_inducedDipolePolar[iIndex][1] + qkr[2]*_inducedDipolePolar[iIndex][2];
// calculate the gl functions for permanent components
gl[0] = particleI.charge*particleK.charge;
gl[1] = particleK.charge*sc[2] - particleI.charge*sc[3];
gl[2] = particleI.charge*sc[5] + particleK.charge*sc[4] - sc[2]*sc[3];
gl[3] = sc[2]*sc[5] - sc[3]*sc[4];
gl[4] = sc[4]*sc[5];
gl[5] = -4.0 * sc[8];
gl[6] = sc[1];
gl[7] = 2.0 * (sc[6]-sc[7]);
gl[8] = 2.0 * sc[9];
// calculate the gl functions for induced components
gli[0] = particleK.charge*sci[2] - particleI.charge*sci[3];
gli[1] = -sc[2]*sci[3] - sci[2]*sc[3];
gli[2] = sci[2]*sc[5] - sci[3]*sc[4];
gli[5] = sci[0];
gli[6] = 2.0 * (sci[6]-sci[7]);
glip[0] = particleK.charge*scip[2] - particleI.charge*scip[3];
glip[1] = -sc[2]*scip[3] - scip[2]*sc[3];
glip[2] = scip[2]*sc[5] - scip[3]*sc[4];
glip[5] = scip[0];
glip[6] = 2.0 * (scip[6]-scip[7]);
// compute the energy contributions for this interaction
RealOpenMM energy = rr1*gl[0] + rr3*(gl[1]+gl[6]) + rr5*(gl[2]+gl[7]+gl[8]) + rr7*(gl[3]+gl[5]) + rr9*gl[4];
energy *= scalingFactors[M_SCALE];
energy += 0.5*(rr3*(gli[0]+gli[5])*psc3 + rr5*(gli[1]+gli[6])*psc5 + rr7*gli[2]*psc7);
energy *= f;
// intermediate variables for the permanent components
gf[0] = rr3*gl[0] + rr5*(gl[1]+gl[6]) + rr7*(gl[2]+gl[7]+gl[8]) + rr9*(gl[3]+gl[5]) + rr11*gl[4];
gf[1] = -particleK.charge*rr3 + sc[3]*rr5 - sc[5]*rr7;
gf[2] = particleI.charge*rr3 + sc[2]*rr5 + sc[4]*rr7;
gf[3] = 2.0*rr5;
gf[4] = 2.0*(-particleK.charge*rr5+sc[3]*rr7-sc[5]*rr9);
gf[5] = 2.0*(-particleI.charge*rr5-sc[2]*rr7-sc[4]*rr9);
gf[6] = 4.0*rr7;
// intermediate variables for the induced components
gfi[0] = 0.5 * rr5 * ((gli[0]+gli[5])*psc3 + (glip[0]+glip[5])*dsc3 + scip[1]*scale3i)
+ 0.5 * rr7 * ((gli[6]+gli[1])*psc5 + (glip[6]+glip[1])*dsc5 - (sci[2]*scip[3]+scip[2]*sci[3])*scale5i)
+ 0.5 * rr9 * (gli[2]*psc7+glip[2]*dsc7);
gfi[1] = -rr3*particleK.charge + rr5*sc[3] - rr7*sc[5];
gfi[2] = rr3*particleI.charge + rr5*sc[2] + rr7*sc[4];
gfi[3] = 2.0*rr5;
gfi[4] = rr7*(sci[3]*psc7+scip[3]*dsc7);
gfi[5] = -rr7*(sci[2]*psc7+scip[2]*dsc7);
// get the permanent force components
RealVec ftm2 = delta*gf[0] + particleI.dipole*gf[1] + particleK.dipole*gf[2] + (qkdi -qidk)*gf[3] + qir*gf[4] +
qkr*gf[5] + (qiqkr+qkqir)*gf[6];
// get the induced force components
RealVec ftm2i = delta*gfi[0] + qir*gfi[4] + qkr*gfi[5];
ftm2i += (
(_inducedDipole[iIndex]*psc3 + _inducedDipolePolar[iIndex]*dsc3)*(-rr3*particleK.charge) +
(_inducedDipole[iIndex]*psc5 + _inducedDipolePolar[iIndex]*dsc5)*(rr5*sc[3]) +
(_inducedDipole[iIndex]*psc7 + _inducedDipolePolar[iIndex]*dsc7)*(-rr7*sc[5]) +
(_inducedDipole[kIndex]*psc3 + _inducedDipolePolar[kIndex]*dsc3)*(rr3*particleI.charge) +
(_inducedDipole[kIndex]*psc5 + _inducedDipolePolar[kIndex]*dsc5)*(rr5*sc[2]) +
(_inducedDipole[kIndex]*psc7 + _inducedDipolePolar[kIndex]*dsc7)*(rr7*sc[4]) +
(_inducedDipolePolar[iIndex]*sci[3] + _inducedDipole[iIndex]*scip[3] +
_inducedDipolePolar[kIndex]*sci[2] + _inducedDipole[kIndex]*scip[2])*(rr5*scale5i) +
particleI.dipole*((sci[3]*psc5 + scip[3]*dsc5)*rr5) +
particleK.dipole*((sci[2]*psc5 + scip[2]*dsc5)*rr5) +
((qkui - qiuk)*psc5 + (qkuip - qiukp)*dsc5)*(gfi[3]))*0.5;
// account for partially excluded induced interactions
temp3 = rr3 * ((gli[0]+gli[5])*scalingFactors[P_SCALE] +(glip[0]+glip[5])*scalingFactors[D_SCALE]);
temp5 = rr5 * ((gli[1]+gli[6])*scalingFactors[P_SCALE] +(glip[1]+glip[6])*scalingFactors[D_SCALE]);
temp7 = rr7 * (gli[2]*scalingFactors[P_SCALE] +glip[2]*scalingFactors[D_SCALE]);
RealVec fridmp,findmp;
fridmp = (ddsc3*temp3 + ddsc5*temp5 + ddsc7*temp7);
// find some scaling terms for induced-induced force
temp3 = rr3*scalingFactors[U_SCALE]*scip[1];
temp5 = -rr5*scalingFactors[U_SCALE]*(sci[2]*scip[3]+scip[2]*sci[3]);
findmp = (ddsc3*temp3 + ddsc5*temp5);
// modify induced force for partially excluded interactions
ftm2i -= (fridmp + findmp)*0.5;
// correction to convert mutual to direct polarization force
if (getPolarizationType() == AmoebaReferenceMultipoleForce::Direct) {
RealOpenMM gfd = (rr5*scip[1]*scale3i - rr7*(scip[2]*sci[3]+sci[2]*scip[3])*scale5i);
temp5 = rr5*scale5i;
RealVec fdir;
fdir = delta*gfd + (_inducedDipolePolar[iIndex]*sci[3] +
_inducedDipole[iIndex]*scip[3] +
_inducedDipolePolar[kIndex]*sci[2] +
_inducedDipole[kIndex]*scip[2])*temp5;
ftm2i += (findmp - fdir)*0.5;
// The Qtilde intermediates (QI frame multipoles) for atoms I and J
RealOpenMM
qiQI
[
9
],
qiQJ
[
9
];
// Rotate the permanent multipoles to the QI frame.
qiQI
[
0
]
=
particleI
.
charge
;
qiQJ
[
0
]
=
particleK
.
charge
;
for
(
int
ii
=
0
;
ii
<
3
;
ii
++
)
{
RealOpenMM
valI
=
0.0
;
RealOpenMM
valJ
=
0.0
;
for
(
int
jj
=
0
;
jj
<
3
;
jj
++
)
{
valI
+=
qiRotationMatrix1
[
ii
][
jj
]
*
particleI
.
sphericalDipole
[
jj
];
valJ
+=
qiRotationMatrix1
[
ii
][
jj
]
*
particleK
.
sphericalDipole
[
jj
];
}
qiQI
[
ii
+
1
]
=
valI
;
qiQJ
[
ii
+
1
]
=
valJ
;
}
for
(
int
ii
=
0
;
ii
<
5
;
ii
++
)
{
RealOpenMM
valI
=
0.0
;
RealOpenMM
valJ
=
0.0
;
for
(
int
jj
=
0
;
jj
<
5
;
jj
++
)
{
valI
+=
qiRotationMatrix2
[
ii
][
jj
]
*
particleI
.
sphericalQuadrupole
[
jj
];
valJ
+=
qiRotationMatrix2
[
ii
][
jj
]
*
particleK
.
sphericalQuadrupole
[
jj
];
}
qiQI
[
ii
+
4
]
=
valI
;
qiQJ
[
ii
+
4
]
=
valJ
;
}
// intermediate terms for induced torque on multipoles
gti[1] = 0.5*rr5*(sci[3]*psc5+scip[3]*dsc5);
gti[2] = 0.5*rr5*(sci[2]*psc5+scip[2]*dsc5);
gti[3] = gfi[3];
gti[4] = gfi[4];
gti[5] = gfi[5];
// get the permanent torque components
RealVec ttm2 = dixdk*(-rr3) + dixr*gf[1] - rxqir*gf[4] +
(dixqkr + dkxqir + rxqidk - qixqk*2.0)*gf[3] -
(rxqikr + qkrxqir)*gf[6];
RealVec ttm3 = dixdk*rr3 + dkxr*gf[2] - rxqkr*gf[5] -
(dixqkr + dkxqir + rxqkdi - qixqk*2.0)*gf[3] -
(rxqkir - qkrxqir)*gf[6];
// get the induced torque components
RealVec ttm2i = (dixuk*psc3 + dixukp*dsc3)*(0.5*(-rr3)) +
dixr*gti[1] +
((ukxqir+rxqiuk)*psc5 + (ukxqirp+rxqiukp)*dsc5)*(0.5*gti[3]) -
rxqir*gti[4];
RealVec ttm3i = (dkxui*psc3 + dkxuip*dsc3)*(0.5*(-rr3)) +
dkxr*gti[2] -
((uixqkr + rxqkui)*psc5 + (uixqkrp + rxqkuip)*dsc5)*(0.5*gti[3]) -
rxqkr*gti[5];
// increment forces and torques
// remove factor of f from torques and add back in?
RealVec force = ftm2*scalingFactors[M_SCALE] + ftm2i;
force *= f;
// The Qtilde{x,y,z} torque intermediates for atoms I and J, which are used to obtain the torques on the permanent moments.
RealOpenMM
qiQIX
[
9
]
=
{
0.0
,
qiQI
[
3
],
0.0
,
-
qiQI
[
1
],
sqrtThree
*
qiQI
[
6
],
qiQI
[
8
],
-
sqrtThree
*
qiQI
[
4
]
-
qiQI
[
7
],
qiQI
[
6
],
-
qiQI
[
5
]};
RealOpenMM
qiQIY
[
9
]
=
{
0.0
,
-
qiQI
[
2
],
qiQI
[
1
],
0.0
,
-
sqrtThree
*
qiQI
[
5
],
sqrtThree
*
qiQI
[
4
]
-
qiQI
[
7
],
-
qiQI
[
8
],
qiQI
[
5
],
qiQI
[
6
]};
RealOpenMM
qiQIZ
[
9
]
=
{
0.0
,
0.0
,
-
qiQI
[
3
],
qiQI
[
2
],
0.0
,
-
qiQI
[
6
],
qiQI
[
5
],
-
2.0
*
qiQI
[
8
],
2.0
*
qiQI
[
7
]};
RealOpenMM
qiQJX
[
9
]
=
{
0.0
,
qiQJ
[
3
],
0.0
,
-
qiQJ
[
1
],
sqrtThree
*
qiQJ
[
6
],
qiQJ
[
8
],
-
sqrtThree
*
qiQJ
[
4
]
-
qiQJ
[
7
],
qiQJ
[
6
],
-
qiQJ
[
5
]};
RealOpenMM
qiQJY
[
9
]
=
{
0.0
,
-
qiQJ
[
2
],
qiQJ
[
1
],
0.0
,
-
sqrtThree
*
qiQJ
[
5
],
sqrtThree
*
qiQJ
[
4
]
-
qiQJ
[
7
],
-
qiQJ
[
8
],
qiQJ
[
5
],
qiQJ
[
6
]};
RealOpenMM
qiQJZ
[
9
]
=
{
0.0
,
0.0
,
-
qiQJ
[
3
],
qiQJ
[
2
],
0.0
,
-
qiQJ
[
6
],
qiQJ
[
5
],
-
2.0
*
qiQJ
[
8
],
2.0
*
qiQJ
[
7
]};
// The field derivatives at I due to permanent and induced moments on J, and vice-versa.
// Also, their derivatives w.r.t. R, which are needed for force calculations
RealOpenMM
Vij
[
9
],
Vji
[
9
],
VjiR
[
9
],
VijR
[
9
];
// The field derivatives at I due to only permanent moments on J, and vice-versa.
RealOpenMM
Vijp
[
3
],
Vijd
[
3
],
Vjip
[
3
],
Vjid
[
3
];
RealOpenMM
rInvVec
[
7
];
RealOpenMM
prefac
=
(
_electric
/
_dielectric
);
RealOpenMM
rInv
=
1.0
/
r
;
// The rInvVec array is defined such that the ith element is R^-i, with the
// dieleectric constant folded in, to avoid conversions later.
rInvVec
[
1
]
=
prefac
*
rInv
;
for
(
int
i
=
2
;
i
<
7
;
++
i
)
rInvVec
[
i
]
=
rInvVec
[
i
-
1
]
*
rInv
;
RealOpenMM
mScale
=
scalingFactors
[
M_SCALE
];
RealOpenMM
dScale
=
scalingFactors
[
D_SCALE
];
RealOpenMM
pScale
=
scalingFactors
[
P_SCALE
];
RealOpenMM
uScale
=
scalingFactors
[
U_SCALE
];
RealOpenMM
dmp
=
particleI
.
dampingFactor
*
particleK
.
dampingFactor
;
RealOpenMM
a
=
particleI
.
thole
<
particleK
.
thole
?
particleI
.
thole
:
particleK
.
thole
;
RealOpenMM
u
=
std
::
abs
(
dmp
)
>
1.0E-5
?
r
/
dmp
:
1E10
;
RealOpenMM
au3
=
a
*
u
*
u
*
u
;
RealOpenMM
expau3
=
au3
<
50.0
?
EXP
(
-
au3
)
:
0.0
;
RealOpenMM
a2u6
=
au3
*
au3
;
RealOpenMM
a3u9
=
a2u6
*
au3
;
// Thole damping factors for energies
RealOpenMM
thole_c
=
1.0
-
expau3
;
RealOpenMM
thole_d0
=
1.0
-
expau3
*
(
1.0
+
1.5
*
au3
);
RealOpenMM
thole_d1
=
1.0
-
expau3
;
RealOpenMM
thole_q0
=
1.0
-
expau3
*
(
1.0
+
au3
+
a2u6
);
RealOpenMM
thole_q1
=
1.0
-
expau3
*
(
1.0
+
au3
);
// Thole damping factors for derivatives
RealOpenMM
dthole_c
=
1.0
-
expau3
*
(
1.0
+
1.5
*
au3
);
RealOpenMM
dthole_d0
=
1.0
-
expau3
*
(
1.0
+
au3
+
1.5
*
a2u6
);
RealOpenMM
dthole_d1
=
1.0
-
expau3
*
(
1.0
+
au3
);
RealOpenMM
dthole_q0
=
1.0
-
expau3
*
(
1.0
+
au3
+
0.25
*
a2u6
+
0.75
*
a3u9
);
RealOpenMM
dthole_q1
=
1.0
-
expau3
*
(
1.0
+
au3
+
0.75
*
a2u6
);
// Now we compute the (attenuated) Coulomb operator and its derivatives, contracted with
// permanent moments and induced dipoles. Note that the coefficient of the permanent force
// terms is half of the expected value; this is because we compute the interaction of I with
// the sum of induced and permanent moments on J, as well as the interaction of J with I's
// permanent and induced moments; doing so double counts the permanent-permanent interaction.
RealOpenMM
ePermCoef
,
dPermCoef
,
eUIndCoef
,
dUIndCoef
,
eUInpCoef
,
dUInpCoef
;
// C-C terms (m=0)
ePermCoef
=
rInvVec
[
1
]
*
mScale
;
dPermCoef
=
-
0.5
*
mScale
*
rInvVec
[
2
];
Vij
[
0
]
=
ePermCoef
*
qiQJ
[
0
];
Vji
[
0
]
=
ePermCoef
*
qiQI
[
0
];
VijR
[
0
]
=
dPermCoef
*
qiQJ
[
0
];
VjiR
[
0
]
=
dPermCoef
*
qiQI
[
0
];
// C-D and C-Uind terms (m=0)
ePermCoef
=
rInvVec
[
2
]
*
mScale
;
eUIndCoef
=
rInvVec
[
2
]
*
pScale
*
thole_c
;
eUInpCoef
=
rInvVec
[
2
]
*
dScale
*
thole_c
;
dPermCoef
=
-
rInvVec
[
3
]
*
mScale
;
dUIndCoef
=
-
2.0
*
rInvVec
[
3
]
*
pScale
*
dthole_c
;
dUInpCoef
=
-
2.0
*
rInvVec
[
3
]
*
dScale
*
dthole_c
;
Vij
[
0
]
+=
-
(
ePermCoef
*
qiQJ
[
1
]
+
eUIndCoef
*
qiUindJ
[
0
]
+
eUInpCoef
*
qiUinpJ
[
0
]);
Vji
[
1
]
=
-
(
ePermCoef
*
qiQI
[
0
]);
VijR
[
0
]
+=
-
(
dPermCoef
*
qiQJ
[
1
]
+
dUIndCoef
*
qiUindJ
[
0
]
+
dUInpCoef
*
qiUinpJ
[
0
]);
VjiR
[
1
]
=
-
(
dPermCoef
*
qiQI
[
0
]);
Vjip
[
0
]
=
-
(
eUInpCoef
*
qiQI
[
0
]);
Vjid
[
0
]
=
-
(
eUIndCoef
*
qiQI
[
0
]);
// D-C and Uind-C terms (m=0)
Vij
[
1
]
=
ePermCoef
*
qiQJ
[
0
];
Vji
[
0
]
+=
ePermCoef
*
qiQI
[
1
]
+
eUIndCoef
*
qiUindI
[
0
]
+
eUInpCoef
*
qiUinpI
[
0
];
VijR
[
1
]
=
dPermCoef
*
qiQJ
[
0
];
VjiR
[
0
]
+=
dPermCoef
*
qiQI
[
1
]
+
dUIndCoef
*
qiUindI
[
0
]
+
dUInpCoef
*
qiUinpI
[
0
];
Vijp
[
0
]
=
eUInpCoef
*
qiQJ
[
0
];
Vijd
[
0
]
=
eUIndCoef
*
qiQJ
[
0
];
// D-D and D-Uind terms (m=0)
ePermCoef
=
-
2.0
*
rInvVec
[
3
]
*
mScale
;
eUIndCoef
=
-
2.0
*
rInvVec
[
3
]
*
pScale
*
thole_d0
;
eUInpCoef
=
-
2.0
*
rInvVec
[
3
]
*
dScale
*
thole_d0
;
dPermCoef
=
3.0
*
rInvVec
[
4
]
*
mScale
;
dUIndCoef
=
6.0
*
rInvVec
[
4
]
*
pScale
*
dthole_d0
;
dUInpCoef
=
6.0
*
rInvVec
[
4
]
*
dScale
*
dthole_d0
;
Vij
[
1
]
+=
ePermCoef
*
qiQJ
[
1
]
+
eUIndCoef
*
qiUindJ
[
0
]
+
eUInpCoef
*
qiUinpJ
[
0
];
Vji
[
1
]
+=
ePermCoef
*
qiQI
[
1
]
+
eUIndCoef
*
qiUindI
[
0
]
+
eUInpCoef
*
qiUinpI
[
0
];
VijR
[
1
]
+=
dPermCoef
*
qiQJ
[
1
]
+
dUIndCoef
*
qiUindJ
[
0
]
+
dUInpCoef
*
qiUinpJ
[
0
];
VjiR
[
1
]
+=
dPermCoef
*
qiQI
[
1
]
+
dUIndCoef
*
qiUindI
[
0
]
+
dUInpCoef
*
qiUinpI
[
0
];
Vijp
[
0
]
+=
eUInpCoef
*
qiQJ
[
1
];
Vijd
[
0
]
+=
eUIndCoef
*
qiQJ
[
1
];
Vjip
[
0
]
+=
eUInpCoef
*
qiQI
[
1
];
Vjid
[
0
]
+=
eUIndCoef
*
qiQI
[
1
];
// D-D and D-Uind terms (m=1)
ePermCoef
=
rInvVec
[
3
]
*
mScale
;
eUIndCoef
=
rInvVec
[
3
]
*
pScale
*
thole_d1
;
eUInpCoef
=
rInvVec
[
3
]
*
dScale
*
thole_d1
;
dPermCoef
=
-
1.5
*
rInvVec
[
4
]
*
mScale
;
dUIndCoef
=
-
3.0
*
rInvVec
[
4
]
*
pScale
*
dthole_d1
;
dUInpCoef
=
-
3.0
*
rInvVec
[
4
]
*
dScale
*
dthole_d1
;
Vij
[
2
]
=
ePermCoef
*
qiQJ
[
2
]
+
eUIndCoef
*
qiUindJ
[
1
]
+
eUInpCoef
*
qiUinpJ
[
1
];
Vji
[
2
]
=
ePermCoef
*
qiQI
[
2
]
+
eUIndCoef
*
qiUindI
[
1
]
+
eUInpCoef
*
qiUinpI
[
1
];
VijR
[
2
]
=
dPermCoef
*
qiQJ
[
2
]
+
dUIndCoef
*
qiUindJ
[
1
]
+
dUInpCoef
*
qiUinpJ
[
1
];
VjiR
[
2
]
=
dPermCoef
*
qiQI
[
2
]
+
dUIndCoef
*
qiUindI
[
1
]
+
dUInpCoef
*
qiUinpI
[
1
];
Vij
[
3
]
=
ePermCoef
*
qiQJ
[
3
]
+
eUIndCoef
*
qiUindJ
[
2
]
+
eUInpCoef
*
qiUinpJ
[
2
];
Vji
[
3
]
=
ePermCoef
*
qiQI
[
3
]
+
eUIndCoef
*
qiUindI
[
2
]
+
eUInpCoef
*
qiUinpI
[
2
];
VijR
[
3
]
=
dPermCoef
*
qiQJ
[
3
]
+
dUIndCoef
*
qiUindJ
[
2
]
+
dUInpCoef
*
qiUinpJ
[
2
];
VjiR
[
3
]
=
dPermCoef
*
qiQI
[
3
]
+
dUIndCoef
*
qiUindI
[
2
]
+
dUInpCoef
*
qiUinpI
[
2
];
Vijp
[
1
]
=
eUInpCoef
*
qiQJ
[
2
];
Vijd
[
1
]
=
eUIndCoef
*
qiQJ
[
2
];
Vjip
[
1
]
=
eUInpCoef
*
qiQI
[
2
];
Vjid
[
1
]
=
eUIndCoef
*
qiQI
[
2
];
Vijp
[
2
]
=
eUInpCoef
*
qiQJ
[
3
];
Vijd
[
2
]
=
eUIndCoef
*
qiQJ
[
3
];
Vjip
[
2
]
=
eUInpCoef
*
qiQI
[
3
];
Vjid
[
2
]
=
eUIndCoef
*
qiQI
[
3
];
// C-Q terms (m=0)
ePermCoef
=
mScale
*
rInvVec
[
3
];
dPermCoef
=
-
1.5
*
rInvVec
[
4
]
*
mScale
;
Vij
[
0
]
+=
ePermCoef
*
qiQJ
[
4
];
Vji
[
4
]
=
ePermCoef
*
qiQI
[
0
];
VijR
[
0
]
+=
dPermCoef
*
qiQJ
[
4
];
VjiR
[
4
]
=
dPermCoef
*
qiQI
[
0
];
// Q-C terms (m=0)
Vij
[
4
]
=
ePermCoef
*
qiQJ
[
0
];
Vji
[
0
]
+=
ePermCoef
*
qiQI
[
4
];
VijR
[
4
]
=
dPermCoef
*
qiQJ
[
0
];
VjiR
[
0
]
+=
dPermCoef
*
qiQI
[
4
];
// D-Q and Uind-Q terms (m=0)
ePermCoef
=
rInvVec
[
4
]
*
3.0
*
mScale
;
eUIndCoef
=
rInvVec
[
4
]
*
3.0
*
pScale
*
thole_q0
;
eUInpCoef
=
rInvVec
[
4
]
*
3.0
*
dScale
*
thole_q0
;
dPermCoef
=
-
6.0
*
rInvVec
[
5
]
*
mScale
;
dUIndCoef
=
-
12.0
*
rInvVec
[
5
]
*
pScale
*
dthole_q0
;
dUInpCoef
=
-
12.0
*
rInvVec
[
5
]
*
dScale
*
dthole_q0
;
Vij
[
1
]
+=
ePermCoef
*
qiQJ
[
4
];
Vji
[
4
]
+=
ePermCoef
*
qiQI
[
1
]
+
eUIndCoef
*
qiUindI
[
0
]
+
eUInpCoef
*
qiUinpI
[
0
];
VijR
[
1
]
+=
dPermCoef
*
qiQJ
[
4
];
VjiR
[
4
]
+=
dPermCoef
*
qiQI
[
1
]
+
dUIndCoef
*
qiUindI
[
0
]
+
dUInpCoef
*
qiUinpI
[
0
];
Vijp
[
0
]
+=
eUInpCoef
*
qiQJ
[
4
];
Vijd
[
0
]
+=
eUIndCoef
*
qiQJ
[
4
];
// Q-D and Q-Uind terms (m=0)
Vij
[
4
]
+=
-
(
ePermCoef
*
qiQJ
[
1
]
+
eUIndCoef
*
qiUindJ
[
0
]
+
eUInpCoef
*
qiUinpJ
[
0
]);
Vji
[
1
]
+=
-
(
ePermCoef
*
qiQI
[
4
]);
VijR
[
4
]
+=
-
(
dPermCoef
*
qiQJ
[
1
]
+
dUIndCoef
*
qiUindJ
[
0
]
+
dUInpCoef
*
qiUinpJ
[
0
]);
VjiR
[
1
]
+=
-
(
dPermCoef
*
qiQI
[
4
]);
Vjip
[
0
]
+=
-
(
eUInpCoef
*
qiQI
[
4
]);
Vjid
[
0
]
+=
-
(
eUIndCoef
*
qiQI
[
4
]);
// D-Q and Uind-Q terms (m=1)
ePermCoef
=
-
sqrtThree
*
rInvVec
[
4
]
*
mScale
;
eUIndCoef
=
-
sqrtThree
*
rInvVec
[
4
]
*
pScale
*
thole_q1
;
eUInpCoef
=
-
sqrtThree
*
rInvVec
[
4
]
*
dScale
*
thole_q1
;
dPermCoef
=
2.0
*
sqrtThree
*
rInvVec
[
5
]
*
mScale
;
dUIndCoef
=
4.0
*
sqrtThree
*
rInvVec
[
5
]
*
pScale
*
dthole_q1
;
dUInpCoef
=
4.0
*
sqrtThree
*
rInvVec
[
5
]
*
dScale
*
dthole_q1
;
Vij
[
2
]
+=
ePermCoef
*
qiQJ
[
5
];
Vji
[
5
]
=
ePermCoef
*
qiQI
[
2
]
+
eUIndCoef
*
qiUindI
[
1
]
+
eUInpCoef
*
qiUinpI
[
1
];
VijR
[
2
]
+=
dPermCoef
*
qiQJ
[
5
];
VjiR
[
5
]
=
dPermCoef
*
qiQI
[
2
]
+
dUIndCoef
*
qiUindI
[
1
]
+
dUInpCoef
*
qiUinpI
[
1
];
Vij
[
3
]
+=
ePermCoef
*
qiQJ
[
6
];
Vji
[
6
]
=
ePermCoef
*
qiQI
[
3
]
+
eUIndCoef
*
qiUindI
[
2
]
+
eUInpCoef
*
qiUinpI
[
2
];
VijR
[
3
]
+=
dPermCoef
*
qiQJ
[
6
];
VjiR
[
6
]
=
dPermCoef
*
qiQI
[
3
]
+
dUIndCoef
*
qiUindI
[
2
]
+
dUInpCoef
*
qiUinpI
[
2
];
Vijp
[
1
]
+=
eUInpCoef
*
qiQJ
[
5
];
Vijd
[
1
]
+=
eUIndCoef
*
qiQJ
[
5
];
Vijp
[
2
]
+=
eUInpCoef
*
qiQJ
[
6
];
Vijd
[
2
]
+=
eUIndCoef
*
qiQJ
[
6
];
// D-Q and Uind-Q terms (m=1)
Vij
[
5
]
=
-
(
ePermCoef
*
qiQJ
[
2
]
+
eUIndCoef
*
qiUindJ
[
1
]
+
eUInpCoef
*
qiUinpJ
[
1
]);
Vji
[
2
]
+=
-
(
ePermCoef
*
qiQI
[
5
]);
VijR
[
5
]
=
-
(
dPermCoef
*
qiQJ
[
2
]
+
dUIndCoef
*
qiUindJ
[
1
]
+
dUInpCoef
*
qiUinpJ
[
1
]);
VjiR
[
2
]
+=
-
(
dPermCoef
*
qiQI
[
5
]);
Vij
[
6
]
=
-
(
ePermCoef
*
qiQJ
[
3
]
+
eUIndCoef
*
qiUindJ
[
2
]
+
eUInpCoef
*
qiUinpJ
[
2
]);
Vji
[
3
]
+=
-
(
ePermCoef
*
qiQI
[
6
]);
VijR
[
6
]
=
-
(
dPermCoef
*
qiQJ
[
3
]
+
dUIndCoef
*
qiUindJ
[
2
]
+
dUInpCoef
*
qiUinpJ
[
2
]);
VjiR
[
3
]
+=
-
(
dPermCoef
*
qiQI
[
6
]);
Vjip
[
1
]
+=
-
(
eUInpCoef
*
qiQI
[
5
]);
Vjid
[
1
]
+=
-
(
eUIndCoef
*
qiQI
[
5
]);
Vjip
[
2
]
+=
-
(
eUInpCoef
*
qiQI
[
6
]);
Vjid
[
2
]
+=
-
(
eUIndCoef
*
qiQI
[
6
]);
// Q-Q terms (m=0)
ePermCoef
=
6.0
*
rInvVec
[
5
]
*
mScale
;
dPermCoef
=
-
15.0
*
rInvVec
[
6
]
*
mScale
;
Vij
[
4
]
+=
ePermCoef
*
qiQJ
[
4
];
Vji
[
4
]
+=
ePermCoef
*
qiQI
[
4
];
VijR
[
4
]
+=
dPermCoef
*
qiQJ
[
4
];
VjiR
[
4
]
+=
dPermCoef
*
qiQI
[
4
];
// Q-Q terms (m=1)
ePermCoef
=
-
4.0
*
rInvVec
[
5
]
*
mScale
;
dPermCoef
=
10.0
*
rInvVec
[
6
]
*
mScale
;
Vij
[
5
]
+=
ePermCoef
*
qiQJ
[
5
];
Vji
[
5
]
+=
ePermCoef
*
qiQI
[
5
];
VijR
[
5
]
+=
dPermCoef
*
qiQJ
[
5
];
VjiR
[
5
]
+=
dPermCoef
*
qiQI
[
5
];
Vij
[
6
]
+=
ePermCoef
*
qiQJ
[
6
];
Vji
[
6
]
+=
ePermCoef
*
qiQI
[
6
];
VijR
[
6
]
+=
dPermCoef
*
qiQJ
[
6
];
VjiR
[
6
]
+=
dPermCoef
*
qiQI
[
6
];
// Q-Q terms (m=2)
ePermCoef
=
rInvVec
[
5
]
*
mScale
;
dPermCoef
=
-
2.5
*
rInvVec
[
6
]
*
mScale
;
Vij
[
7
]
=
ePermCoef
*
qiQJ
[
7
];
Vji
[
7
]
=
ePermCoef
*
qiQI
[
7
];
VijR
[
7
]
=
dPermCoef
*
qiQJ
[
7
];
VjiR
[
7
]
=
dPermCoef
*
qiQI
[
7
];
Vij
[
8
]
=
ePermCoef
*
qiQJ
[
8
];
Vji
[
8
]
=
ePermCoef
*
qiQI
[
8
];
VijR
[
8
]
=
dPermCoef
*
qiQJ
[
8
];
VjiR
[
8
]
=
dPermCoef
*
qiQI
[
8
];
// Evaluate the energies, forces and torques due to permanent+induced moments
// interacting with just the permanent moments.
RealOpenMM
energy
=
0.5
*
(
qiQI
[
0
]
*
Vij
[
0
]
+
qiQJ
[
0
]
*
Vji
[
0
]);
RealOpenMM
fIZ
=
qiQI
[
0
]
*
VijR
[
0
];
RealOpenMM
fJZ
=
qiQJ
[
0
]
*
VjiR
[
0
];
RealOpenMM
EIX
=
0.0
,
EIY
=
0.0
,
EIZ
=
0.0
,
EJX
=
0.0
,
EJY
=
0.0
,
EJZ
=
0.0
;
for
(
int
i
=
1
;
i
<
9
;
++
i
){
energy
+=
0.5
*
(
qiQI
[
i
]
*
Vij
[
i
]
+
qiQJ
[
i
]
*
Vji
[
i
]);
fIZ
+=
qiQI
[
i
]
*
VijR
[
i
];
fJZ
+=
qiQJ
[
i
]
*
VjiR
[
i
];
EIX
+=
qiQIX
[
i
]
*
Vij
[
i
];
EIY
+=
qiQIY
[
i
]
*
Vij
[
i
];
EIZ
+=
qiQIZ
[
i
]
*
Vij
[
i
];
EJX
+=
qiQJX
[
i
]
*
Vji
[
i
];
EJY
+=
qiQJY
[
i
]
*
Vji
[
i
];
EJZ
+=
qiQJZ
[
i
]
*
Vji
[
i
];
}
forces[iIndex] -= force;
forces[kIndex] += force;
// Define the torque intermediates for the induced dipoles. These are simply the induced dipole torque
// intermediates dotted with the field due to permanent moments only, at each center. We inline the
// induced dipole torque intermediates here, for simplicity. N.B. There are no torques on the dipoles
// themselves, so we accumulate the torque intermediates into separate variables to allow them to be
// used only in the force calculation.
//
// The torque about the x axis (needed to obtain the y force on the induced dipoles, below)
// qiUindIx[0] = qiQUindI[2]; qiUindIx[1] = 0; qiUindIx[2] = -qiQUindI[0]
RealOpenMM
iEIX
=
qiUinpI
[
2
]
*
Vijp
[
0
]
+
qiUindI
[
2
]
*
Vijd
[
0
]
-
qiUinpI
[
0
]
*
Vijp
[
2
]
-
qiUindI
[
0
]
*
Vijd
[
2
];
RealOpenMM
iEJX
=
qiUinpJ
[
2
]
*
Vjip
[
0
]
+
qiUindJ
[
2
]
*
Vjid
[
0
]
-
qiUinpJ
[
0
]
*
Vjip
[
2
]
-
qiUindJ
[
0
]
*
Vjid
[
2
];
// The torque about the y axis (needed to obtain the x force on the induced dipoles, below)
// qiUindIy[0] = -qiQUindI[1]; qiUindIy[1] = qiQUindI[0]; qiUindIy[2] = 0
RealOpenMM
iEIY
=
qiUinpI
[
0
]
*
Vijp
[
1
]
+
qiUindI
[
0
]
*
Vijd
[
1
]
-
qiUinpI
[
1
]
*
Vijp
[
0
]
-
qiUindI
[
1
]
*
Vijd
[
0
];
RealOpenMM
iEJY
=
qiUinpJ
[
0
]
*
Vjip
[
1
]
+
qiUindJ
[
0
]
*
Vjid
[
1
]
-
qiUinpJ
[
1
]
*
Vjip
[
0
]
-
qiUindJ
[
1
]
*
Vjid
[
0
];
// Add in the induced-induced terms, if needed.
if
(
getPolarizationType
()
==
AmoebaReferenceMultipoleForce
::
Mutual
){
// Uind-Uind terms (m=0)
RealOpenMM
eCoef
=
-
4.0
*
rInvVec
[
3
]
*
uScale
*
thole_d0
;
RealOpenMM
dCoef
=
6.0
*
rInvVec
[
4
]
*
uScale
*
dthole_d0
;
iEIX
+=
eCoef
*
(
qiUinpI
[
2
]
*
qiUindJ
[
0
]
+
qiUindI
[
2
]
*
qiUinpJ
[
0
]);
iEJX
+=
eCoef
*
(
qiUinpJ
[
2
]
*
qiUindI
[
0
]
+
qiUindJ
[
2
]
*
qiUinpI
[
0
]);
iEIY
-=
eCoef
*
(
qiUinpI
[
1
]
*
qiUindJ
[
0
]
+
qiUindI
[
1
]
*
qiUinpJ
[
0
]);
iEJY
-=
eCoef
*
(
qiUinpJ
[
1
]
*
qiUindI
[
0
]
+
qiUindJ
[
1
]
*
qiUinpI
[
0
]);
fIZ
+=
dCoef
*
(
qiUinpI
[
0
]
*
qiUindJ
[
0
]
+
qiUindI
[
0
]
*
qiUinpJ
[
0
]);
fIZ
+=
dCoef
*
(
qiUinpJ
[
0
]
*
qiUindI
[
0
]
+
qiUindJ
[
0
]
*
qiUinpI
[
0
]);
// Uind-Uind terms (m=1)
eCoef
=
2.0
*
rInvVec
[
3
]
*
uScale
*
thole_d1
;
dCoef
=
-
3.0
*
rInvVec
[
4
]
*
uScale
*
dthole_d1
;
iEIX
-=
eCoef
*
(
qiUinpI
[
0
]
*
qiUindJ
[
2
]
+
qiUindI
[
0
]
*
qiUinpJ
[
2
]);
iEJX
-=
eCoef
*
(
qiUinpJ
[
0
]
*
qiUindI
[
2
]
+
qiUindJ
[
0
]
*
qiUinpI
[
2
]);
iEIY
+=
eCoef
*
(
qiUinpI
[
0
]
*
qiUindJ
[
1
]
+
qiUindI
[
0
]
*
qiUinpJ
[
1
]);
iEJY
+=
eCoef
*
(
qiUinpJ
[
0
]
*
qiUindI
[
1
]
+
qiUindJ
[
0
]
*
qiUinpI
[
1
]);
fIZ
+=
dCoef
*
(
qiUinpI
[
1
]
*
qiUindJ
[
1
]
+
qiUindI
[
1
]
*
qiUinpJ
[
1
]
+
qiUinpI
[
2
]
*
qiUindJ
[
2
]
+
qiUindI
[
2
]
*
qiUinpJ
[
2
]);
fIZ
+=
dCoef
*
(
qiUinpJ
[
1
]
*
qiUindI
[
1
]
+
qiUindJ
[
1
]
*
qiUinpI
[
1
]
+
qiUinpJ
[
2
]
*
qiUindI
[
2
]
+
qiUindJ
[
2
]
*
qiUinpI
[
2
]);
}
torque[iIndex] += (ttm2*scalingFactors[M_SCALE] + ttm2i)*f;
torque[kIndex] += (ttm3*scalingFactors[M_SCALE] + ttm3i)*f;
// The quasi-internal frame forces and torques. Note that the induced torque intermediates are
// used in the force expression, but not in the torques; the induced dipoles are isotropic.
RealOpenMM
qiForce
[
3
]
=
{
rInv
*
(
EIY
+
EJY
+
iEIY
+
iEJY
),
-
rInv
*
(
EIX
+
EJX
+
iEIX
+
iEJX
),
-
(
fJZ
+
fIZ
)};
RealOpenMM
qiTorqueI
[
3
]
=
{
-
EIX
,
-
EIY
,
-
EIZ
};
RealOpenMM
qiTorqueJ
[
3
]
=
{
-
EJX
,
-
EJY
,
-
EJZ
};
// Rotate the forces and torques back to the lab frame
for
(
int
ii
=
0
;
ii
<
3
;
ii
++
)
{
RealOpenMM
forceVal
=
0.0
;
RealOpenMM
torqueIVal
=
0.0
;
RealOpenMM
torqueJVal
=
0.0
;
for
(
int
jj
=
0
;
jj
<
3
;
jj
++
)
{
forceVal
+=
forceRotationMatrix
[
ii
][
jj
]
*
qiForce
[
jj
];
torqueIVal
+=
forceRotationMatrix
[
ii
][
jj
]
*
qiTorqueI
[
jj
];
torqueJVal
+=
forceRotationMatrix
[
ii
][
jj
]
*
qiTorqueJ
[
jj
];
}
torque
[
iIndex
][
ii
]
+=
torqueIVal
;
torque
[
kIndex
][
ii
]
+=
torqueJVal
;
forces
[
iIndex
][
ii
]
-=
forceVal
;
forces
[
kIndex
][
ii
]
+=
forceVal
;
}
return
energy
;
}
...
...
@@ -1755,10 +1928,9 @@ RealOpenMM AmoebaReferenceMultipoleForce::calculateElectrostaticPotentialForPart
RealOpenMM
r
=
SQRT
(
r2
);
RealOpenMM
rr1
=
1.0
/
r
;
RealOpenMM potential = particleI.charge*rr1;
RealOpenMM
rr2
=
rr1
*
rr1
;
RealOpenMM
rr3
=
rr1
*
rr2
;
RealOpenMM
potential
=
particleI
.
charge
*
rr1
;
RealOpenMM
scd
=
particleI
.
dipole
.
dot
(
deltaR
);
RealOpenMM
scu
=
_inducedDipole
[
particleI
.
particleIndex
].
dot
(
deltaR
);
...
...
@@ -1769,9 +1941,7 @@ RealOpenMM AmoebaReferenceMultipoleForce::calculateElectrostaticPotentialForPart
scq
+=
deltaR
[
1
]
*
(
particleI
.
quadrupole
[
QXY
]
*
deltaR
[
0
]
+
particleI
.
quadrupole
[
QYY
]
*
deltaR
[
1
]
+
particleI
.
quadrupole
[
QYZ
]
*
deltaR
[
2
]);
scq
+=
deltaR
[
2
]
*
(
particleI
.
quadrupole
[
QXZ
]
*
deltaR
[
0
]
+
particleI
.
quadrupole
[
QYZ
]
*
deltaR
[
1
]
+
particleI
.
quadrupole
[
QZZ
]
*
deltaR
[
2
]);
potential
+=
scq
*
rr5
;
return
potential
;
}
void
AmoebaReferenceMultipoleForce
::
calculateElectrostaticPotential
(
const
vector
<
RealVec
>&
particlePositions
,
...
...
@@ -4741,6 +4911,9 @@ void AmoebaReferencePmeMultipoleForce::calculateFixedMultipoleFieldPairIxn(const
RealOpenMM
dscale
,
RealOpenMM
pscale
)
{
unsigned
int
iIndex
=
particleI
.
particleIndex
;
unsigned
int
jIndex
=
particleJ
.
particleIndex
;
// compute the real space portion of the Ewald summation
if
(
particleI
.
particleIndex
==
particleJ
.
particleIndex
)
...
...
@@ -4815,8 +4988,6 @@ void AmoebaReferencePmeMultipoleForce::calculateFixedMultipoleFieldPairIxn(const
// increment the field at each site due to this interaction
unsigned int iIndex = particleI.particleIndex;
unsigned int jIndex = particleJ.particleIndex;
_fixedMultipoleField
[
iIndex
]
+=
fim
-
fid
;
_fixedMultipoleField
[
jIndex
]
+=
fjm
-
fjd
;
...
...
@@ -4980,9 +5151,9 @@ void AmoebaReferencePmeMultipoleForce::transformMultipolesToFractionalCoordinate
b
[
i
][
j
]
+=
a
[
index1
[
i
]][
index2
[
j
]]
*
a
[
index2
[
i
]][
index1
[
j
]];
}
}
// Transform the multipoles.
_transformed
.
resize
(
particleData
.
size
());
double
quadScale
[]
=
{
1
,
2
,
2
,
1
,
2
,
1
};
for
(
int
i
=
0
;
i
<
(
int
)
particleData
.
size
();
i
++
)
{
...
...
@@ -5854,21 +6025,21 @@ RealOpenMM AmoebaReferencePmeMultipoleForce::calculatePmeSelfEnergy(const vector
const
MultipoleParticleData
&
particleI
=
particleData
[
ii
];
cii += particleI.charge*particleI.charge;
dii += particleI.dipole.dot(particleI.dipole + _inducedDipole[ii]) ;
qii += particleI.quadrupole[QXX]*particleI.quadrupole[QXX] +
particleI.quadrupole[QYY]*particleI.quadrupole[QYY] +
particleI.quadrupole[QZZ]*particleI.quadrupole[QZZ] +
(particleI.quadrupole[QXY]*particleI.quadrupole[QXY] +
particleI.quadrupole[QXZ]*particleI.quadrupole[QXZ] +
particleI.quadrupole[QYZ]*particleI.quadrupole[QYZ])*2.0;
}
cii
+=
particleI
.
charge
*
particleI
.
charge
;
RealOpenMM term = 2.0*_alphaEwald*_alphaEwald;
RealOpenMM energy = (cii + term*(dii/3.0 + 2.0*term*qii/5.0));
energy *= -(_electric*_alphaEwald/(_dielectric*SQRT_PI));
RealVec
dipole
(
particleI
.
sphericalDipole
[
1
],
particleI
.
sphericalDipole
[
2
],
particleI
.
sphericalDipole
[
0
]);
dii
+=
dipole
.
dot
(
dipole
+
_inducedDipole
[
ii
]);
qii
+=
(
particleI
.
sphericalQuadrupole
[
0
]
*
particleI
.
sphericalQuadrupole
[
0
]
+
particleI
.
sphericalQuadrupole
[
1
]
*
particleI
.
sphericalQuadrupole
[
1
]
+
particleI
.
sphericalQuadrupole
[
2
]
*
particleI
.
sphericalQuadrupole
[
2
]
+
particleI
.
sphericalQuadrupole
[
3
]
*
particleI
.
sphericalQuadrupole
[
3
]
+
particleI
.
sphericalQuadrupole
[
4
]
*
particleI
.
sphericalQuadrupole
[
4
]);
}
RealOpenMM
prefac
=
-
_alphaEwald
*
_electric
/
(
_dielectric
*
SQRT_PI
);
RealOpenMM
a2
=
_alphaEwald
*
_alphaEwald
;
RealOpenMM
a4
=
a2
*
a2
;
RealOpenMM
energy
=
prefac
*
(
cii
+
twoThirds
*
a2
*
dii
+
fourOverFifteen
*
a4
*
qii
);
return
energy
;
}
...
...
@@ -5876,12 +6047,12 @@ void AmoebaReferencePmeMultipoleForce::calculatePmeSelfTorque(const vector<Multi
vector
<
RealVec
>&
torques
)
const
{
RealOpenMM
term
=
(
2.0
/
3.0
)
*
(
_electric
/
_dielectric
)
*
(
_alphaEwald
*
_alphaEwald
*
_alphaEwald
)
/
SQRT_PI
;
for
(
unsigned
int
ii
=
0
;
ii
<
_numParticles
;
ii
++
)
{
const
MultipoleParticleData
&
particleI
=
particleData
[
ii
];
RealVec
ui
=
(
_inducedDipole
[
ii
]
+
_inducedDipolePolar
[
ii
]);
RealVec torque = particleI.dipole.cross(ui);
RealVec
dipole
(
particleI
.
sphericalDipole
[
1
],
particleI
.
sphericalDipole
[
2
],
particleI
.
sphericalDipole
[
0
]);
RealVec
torque
=
dipole
.
cross
(
ui
);
torque
*=
term
;
torques
[
ii
]
+=
torque
;
}
...
...
@@ -5904,681 +6075,402 @@ RealOpenMM AmoebaReferencePmeMultipoleForce::calculatePmeDirectElectrostaticPair
if
(
r2
>
_cutoffDistanceSquared
)
return
0.0
;
RealOpenMM xr = deltaR[0];
RealOpenMM yr = deltaR[1];
RealOpenMM zr = deltaR[2];
RealOpenMM
r
=
SQRT
(
r2
);
RealOpenMM ck = particleJ.charge;
// set the permanent multipole and induced dipole values;
RealOpenMM ci = particleI.charge;
RealOpenMM di1 = particleI.dipole[0];
RealOpenMM di2 = particleI.dipole[1];
RealOpenMM di3 = particleI.dipole[2];
RealOpenMM qi1 = particleI.quadrupole[QXX];
RealOpenMM qi2 = particleI.quadrupole[QXY];
RealOpenMM qi3 = particleI.quadrupole[QXZ];
RealOpenMM qi5 = particleI.quadrupole[QYY];
RealOpenMM qi6 = particleI.quadrupole[QYZ];
RealOpenMM qi9 = -(particleI.quadrupole[QXX] + particleI.quadrupole[QYY]);
RealOpenMM dk1 = particleJ.dipole[0];
RealOpenMM dk2 = particleJ.dipole[1];
RealOpenMM dk3 = particleJ.dipole[2];
RealOpenMM qk1 = particleJ.quadrupole[QXX];
RealOpenMM qk2 = particleJ.quadrupole[QXY];
RealOpenMM qk3 = particleJ.quadrupole[QXZ];
RealOpenMM qk5 = particleJ.quadrupole[QYY];
RealOpenMM qk6 = particleJ.quadrupole[QYZ];
RealOpenMM qk9 = -(particleJ.quadrupole[QXX] + particleJ.quadrupole[QYY]);
// calculate the real space error function terms
RealOpenMM ralpha = _alphaEwald*r;
RealOpenMM bn0 = erfc(ralpha)/r;
RealOpenMM alsq2 = 2.0*_alphaEwald*_alphaEwald;
RealOpenMM alsq2n = 0.0;
if (_alphaEwald > 0.0) {
alsq2n = 1.0/(SQRT_PI*_alphaEwald);
// Start by constructing rotation matrices to put dipoles and
// quadrupoles into the QI frame, from the lab frame.
RealOpenMM
qiRotationMatrix1
[
3
][
3
];
formQIRotationMatrix
(
particleI
.
position
,
particleJ
.
position
,
deltaR
,
r
,
qiRotationMatrix1
);
RealOpenMM
qiRotationMatrix2
[
5
][
5
];
buildSphericalQuadrupoleRotationMatrix
(
qiRotationMatrix1
,
qiRotationMatrix2
);
// The force rotation matrix rotates the QI forces into the lab
// frame, and makes sure the result is in {x,y,z} ordering. Its
// transpose is used to rotate the induced dipoles to the QI frame.
RealOpenMM
forceRotationMatrix
[
3
][
3
];
forceRotationMatrix
[
0
][
0
]
=
qiRotationMatrix1
[
1
][
1
];
forceRotationMatrix
[
0
][
1
]
=
qiRotationMatrix1
[
2
][
1
];
forceRotationMatrix
[
0
][
2
]
=
qiRotationMatrix1
[
0
][
1
];
forceRotationMatrix
[
1
][
0
]
=
qiRotationMatrix1
[
1
][
2
];
forceRotationMatrix
[
1
][
1
]
=
qiRotationMatrix1
[
2
][
2
];
forceRotationMatrix
[
1
][
2
]
=
qiRotationMatrix1
[
0
][
2
];
forceRotationMatrix
[
2
][
0
]
=
qiRotationMatrix1
[
1
][
0
];
forceRotationMatrix
[
2
][
1
]
=
qiRotationMatrix1
[
2
][
0
];
forceRotationMatrix
[
2
][
2
]
=
qiRotationMatrix1
[
0
][
0
];
// For efficiency, we go ahead and cache that transposed version
// now, because we need to do 4 rotations in total (I,J, and p,d).
// We also fold in the factor of 0.5 needed to average the p and d
// components.
RealOpenMM
inducedDipoleRotationMatrix
[
3
][
3
];
inducedDipoleRotationMatrix
[
0
][
0
]
=
0.5
*
qiRotationMatrix1
[
0
][
1
];
inducedDipoleRotationMatrix
[
0
][
1
]
=
0.5
*
qiRotationMatrix1
[
0
][
2
];
inducedDipoleRotationMatrix
[
0
][
2
]
=
0.5
*
qiRotationMatrix1
[
0
][
0
];
inducedDipoleRotationMatrix
[
1
][
0
]
=
0.5
*
qiRotationMatrix1
[
1
][
1
];
inducedDipoleRotationMatrix
[
1
][
1
]
=
0.5
*
qiRotationMatrix1
[
1
][
2
];
inducedDipoleRotationMatrix
[
1
][
2
]
=
0.5
*
qiRotationMatrix1
[
1
][
0
];
inducedDipoleRotationMatrix
[
2
][
0
]
=
0.5
*
qiRotationMatrix1
[
2
][
1
];
inducedDipoleRotationMatrix
[
2
][
1
]
=
0.5
*
qiRotationMatrix1
[
2
][
2
];
inducedDipoleRotationMatrix
[
2
][
2
]
=
0.5
*
qiRotationMatrix1
[
2
][
0
];
// Rotate the induced dipoles to the QI frame.
RealOpenMM
qiUindI
[
3
],
qiUindJ
[
3
],
qiUinpI
[
3
],
qiUinpJ
[
3
];
for
(
int
ii
=
0
;
ii
<
3
;
ii
++
)
{
RealOpenMM
valIP
=
0.0
;
RealOpenMM
valID
=
0.0
;
RealOpenMM
valJP
=
0.0
;
RealOpenMM
valJD
=
0.0
;
for
(
int
jj
=
0
;
jj
<
3
;
jj
++
)
{
valIP
+=
inducedDipoleRotationMatrix
[
ii
][
jj
]
*
_inducedDipolePolar
[
iIndex
][
jj
];
valID
+=
inducedDipoleRotationMatrix
[
ii
][
jj
]
*
_inducedDipole
[
iIndex
][
jj
];
valJP
+=
inducedDipoleRotationMatrix
[
ii
][
jj
]
*
_inducedDipolePolar
[
jIndex
][
jj
];
valJD
+=
inducedDipoleRotationMatrix
[
ii
][
jj
]
*
_inducedDipole
[
jIndex
][
jj
];
}
qiUindI
[
ii
]
=
valID
;
qiUinpI
[
ii
]
=
valIP
;
qiUindJ
[
ii
]
=
valJD
;
qiUinpJ
[
ii
]
=
valJP
;
}
RealOpenMM exp2a = EXP(-(ralpha*ralpha));
alsq2n *= alsq2;
RealOpenMM bn1 = (bn0+alsq2n*exp2a)/r2;
alsq2n *= alsq2;
RealOpenMM bn2 = (3.0*bn1+alsq2n*exp2a)/r2;
alsq2n *= alsq2;
RealOpenMM bn3 = (5.0*bn2+alsq2n*exp2a)/r2;
alsq2n *= alsq2;
RealOpenMM bn4 = (7.0*bn3+alsq2n*exp2a)/r2;
alsq2n *= alsq2;
RealOpenMM bn5 = (9.0*bn4+alsq2n*exp2a)/r2;
// apply Thole polarization damping to scale factors
RealOpenMM rr1 = 1.0/r;
RealOpenMM rr3 = rr1/r2;
RealOpenMM rr5 = 3.0*rr3/r2;
RealOpenMM rr7 = 5.0*rr5/r2;
RealOpenMM rr9 = 7.0*rr7/r2;
RealOpenMM rr11 = 9.0*rr9/r2;
RealOpenMM scale3 = 1.0;
RealOpenMM scale5 = 1.0;
RealOpenMM scale7 = 1.0;
RealOpenMM ddsc31 = 0.0;
RealOpenMM ddsc32 = 0.0;
RealOpenMM ddsc33 = 0.0;
RealOpenMM ddsc51 = 0.0;
RealOpenMM ddsc52 = 0.0;
RealOpenMM ddsc53 = 0.0;
RealOpenMM ddsc71 = 0.0;
RealOpenMM ddsc72 = 0.0;
RealOpenMM ddsc73 = 0.0;
RealOpenMM damp = particleI.dampingFactor*particleJ.dampingFactor;
if (damp != 0.0) {
RealOpenMM pgamma = particleI.thole < particleJ.thole ? particleI.thole : particleJ.thole;
RealOpenMM ratio = r/damp;
damp = -pgamma*ratio*ratio*ratio;
if (damp > -50.0) {
RealOpenMM expdamp = EXP(damp);
scale3 = 1.0 - expdamp;
scale5 = 1.0 - (1.0-damp)*expdamp;
scale7 = 1.0 - (1.0-damp+0.6*damp*damp)*expdamp;
RealOpenMM temp3 = -3.0 * damp * expdamp / r2;
RealOpenMM temp5 = -damp;
RealOpenMM temp7 = -0.2 - 0.6*damp;
ddsc31 = temp3 * xr;
ddsc32 = temp3 * yr;
ddsc33 = temp3 * zr;
ddsc51 = temp5 * ddsc31;
ddsc52 = temp5 * ddsc32;
ddsc53 = temp5 * ddsc33;
ddsc71 = temp7 * ddsc51;
ddsc72 = temp7 * ddsc52;
ddsc73 = temp7 * ddsc53;
// The Qtilde intermediates (QI frame multipoles) for atoms I and J
RealOpenMM
qiQI
[
9
],
qiQJ
[
9
];
// Rotate the permanent multipoles to the QI frame.
qiQI
[
0
]
=
particleI
.
charge
;
qiQJ
[
0
]
=
particleJ
.
charge
;
for
(
int
ii
=
0
;
ii
<
3
;
ii
++
)
{
RealOpenMM
valI
=
0.0
;
RealOpenMM
valJ
=
0.0
;
for
(
int
jj
=
0
;
jj
<
3
;
jj
++
)
{
valI
+=
qiRotationMatrix1
[
ii
][
jj
]
*
particleI
.
sphericalDipole
[
jj
];
valJ
+=
qiRotationMatrix1
[
ii
][
jj
]
*
particleJ
.
sphericalDipole
[
jj
];
}
qiQI
[
ii
+
1
]
=
valI
;
qiQJ
[
ii
+
1
]
=
valJ
;
}
for
(
int
ii
=
0
;
ii
<
5
;
ii
++
)
{
RealOpenMM
valI
=
0.0
;
RealOpenMM
valJ
=
0.0
;
for
(
int
jj
=
0
;
jj
<
5
;
jj
++
)
{
valI
+=
qiRotationMatrix2
[
ii
][
jj
]
*
particleI
.
sphericalQuadrupole
[
jj
];
valJ
+=
qiRotationMatrix2
[
ii
][
jj
]
*
particleJ
.
sphericalQuadrupole
[
jj
];
}
qiQI
[
ii
+
4
]
=
valI
;
qiQJ
[
ii
+
4
]
=
valJ
;
}
RealOpenMM dsc3 = 1.0 - scale3*scalingFactors[D_SCALE];
RealOpenMM dsc5 = 1.0 - scale5*scalingFactors[D_SCALE];
RealOpenMM dsc7 = 1.0 - scale7*scalingFactors[D_SCALE];
RealOpenMM psc3 = 1.0 - scale3*scalingFactors[P_SCALE];
RealOpenMM psc5 = 1.0 - scale5*scalingFactors[P_SCALE];
RealOpenMM psc7 = 1.0 - scale7*scalingFactors[P_SCALE];
RealOpenMM usc3 = 1.0 - scale3*scalingFactors[U_SCALE];
RealOpenMM usc5 = 1.0 - scale5*scalingFactors[U_SCALE];
// construct necessary auxiliary vectors
RealOpenMM dixdk1 = di2*dk3 - di3*dk2;
RealOpenMM dixdk2 = di3*dk1 - di1*dk3;
RealOpenMM dixdk3 = di1*dk2 - di2*dk1;
RealOpenMM dixuk1 = di2*_inducedDipole[jIndex][2] - di3*_inducedDipole[jIndex][1];
RealOpenMM dixuk2 = di3*_inducedDipole[jIndex][0] - di1*_inducedDipole[jIndex][2];
RealOpenMM dixuk3 = di1*_inducedDipole[jIndex][1] - di2*_inducedDipole[jIndex][0];
RealOpenMM dkxui1 = dk2*_inducedDipole[iIndex][2] - dk3*_inducedDipole[iIndex][1];
RealOpenMM dkxui2 = dk3*_inducedDipole[iIndex][0] - dk1*_inducedDipole[iIndex][2];
RealOpenMM dkxui3 = dk1*_inducedDipole[iIndex][1] - dk2*_inducedDipole[iIndex][0];
RealOpenMM dixukp1 = di2*_inducedDipolePolar[jIndex][2] - di3*_inducedDipolePolar[jIndex][1];
RealOpenMM dixukp2 = di3*_inducedDipolePolar[jIndex][0] - di1*_inducedDipolePolar[jIndex][2];
RealOpenMM dixukp3 = di1*_inducedDipolePolar[jIndex][1] - di2*_inducedDipolePolar[jIndex][0];
RealOpenMM dkxuip1 = dk2*_inducedDipolePolar[iIndex][2] - dk3*_inducedDipolePolar[iIndex][1];
RealOpenMM dkxuip2 = dk3*_inducedDipolePolar[iIndex][0] - dk1*_inducedDipolePolar[iIndex][2];
RealOpenMM dkxuip3 = dk1*_inducedDipolePolar[iIndex][1] - dk2*_inducedDipolePolar[iIndex][0];
RealOpenMM dixr1 = di2*zr - di3*yr;
RealOpenMM dixr2 = di3*xr - di1*zr;
RealOpenMM dixr3 = di1*yr - di2*xr;
RealOpenMM dkxr1 = dk2*zr - dk3*yr;
RealOpenMM dkxr2 = dk3*xr - dk1*zr;
RealOpenMM dkxr3 = dk1*yr - dk2*xr;
RealOpenMM qir1 = qi1*xr + qi2*yr + qi3*zr;
RealOpenMM qir2 = qi2*xr + qi5*yr + qi6*zr;
RealOpenMM qir3 = qi3*xr + qi6*yr + qi9*zr;
RealOpenMM qkr1 = qk1*xr + qk2*yr + qk3*zr;
RealOpenMM qkr2 = qk2*xr + qk5*yr + qk6*zr;
RealOpenMM qkr3 = qk3*xr + qk6*yr + qk9*zr;
RealOpenMM qiqkr1 = qi1*qkr1 + qi2*qkr2 + qi3*qkr3;
RealOpenMM qiqkr2 = qi2*qkr1 + qi5*qkr2 + qi6*qkr3;
RealOpenMM qiqkr3 = qi3*qkr1 + qi6*qkr2 + qi9*qkr3;
RealOpenMM qkqir1 = qk1*qir1 + qk2*qir2 + qk3*qir3;
RealOpenMM qkqir2 = qk2*qir1 + qk5*qir2 + qk6*qir3;
RealOpenMM qkqir3 = qk3*qir1 + qk6*qir2 + qk9*qir3;
RealOpenMM qixqk1 = qi2*qk3 + qi5*qk6 + qi6*qk9 - qi3*qk2 - qi6*qk5 - qi9*qk6;
RealOpenMM qixqk2 = qi3*qk1 + qi6*qk2 + qi9*qk3 - qi1*qk3 - qi2*qk6 - qi3*qk9;
RealOpenMM qixqk3 = qi1*qk2 + qi2*qk5 + qi3*qk6 - qi2*qk1 - qi5*qk2 - qi6*qk3;
RealOpenMM rxqir1 = yr*qir3 - zr*qir2;
RealOpenMM rxqir2 = zr*qir1 - xr*qir3;
RealOpenMM rxqir3 = xr*qir2 - yr*qir1;
RealOpenMM rxqkr1 = yr*qkr3 - zr*qkr2;
RealOpenMM rxqkr2 = zr*qkr1 - xr*qkr3;
RealOpenMM rxqkr3 = xr*qkr2 - yr*qkr1;
RealOpenMM rxqikr1 = yr*qiqkr3 - zr*qiqkr2;
RealOpenMM rxqikr2 = zr*qiqkr1 - xr*qiqkr3;
RealOpenMM rxqikr3 = xr*qiqkr2 - yr*qiqkr1;
RealOpenMM rxqkir1 = yr*qkqir3 - zr*qkqir2;
RealOpenMM rxqkir2 = zr*qkqir1 - xr*qkqir3;
RealOpenMM rxqkir3 = xr*qkqir2 - yr*qkqir1;
RealOpenMM qkrxqir1 = qkr2*qir3 - qkr3*qir2;
RealOpenMM qkrxqir2 = qkr3*qir1 - qkr1*qir3;
RealOpenMM qkrxqir3 = qkr1*qir2 - qkr2*qir1;
RealOpenMM qidk1 = qi1*dk1 + qi2*dk2 + qi3*dk3;
RealOpenMM qidk2 = qi2*dk1 + qi5*dk2 + qi6*dk3;
RealOpenMM qidk3 = qi3*dk1 + qi6*dk2 + qi9*dk3;
RealOpenMM qkdi1 = qk1*di1 + qk2*di2 + qk3*di3;
RealOpenMM qkdi2 = qk2*di1 + qk5*di2 + qk6*di3;
RealOpenMM qkdi3 = qk3*di1 + qk6*di2 + qk9*di3;
RealOpenMM qiuk1 = qi1*_inducedDipole[jIndex][0] + qi2*_inducedDipole[jIndex][1] + qi3*_inducedDipole[jIndex][2];
RealOpenMM qiuk2 = qi2*_inducedDipole[jIndex][0] + qi5*_inducedDipole[jIndex][1] + qi6*_inducedDipole[jIndex][2];
RealOpenMM qiuk3 = qi3*_inducedDipole[jIndex][0] + qi6*_inducedDipole[jIndex][1] + qi9*_inducedDipole[jIndex][2];
RealOpenMM qkui1 = qk1*_inducedDipole[iIndex][0] + qk2*_inducedDipole[iIndex][1] + qk3*_inducedDipole[iIndex][2];
RealOpenMM qkui2 = qk2*_inducedDipole[iIndex][0] + qk5*_inducedDipole[iIndex][1] + qk6*_inducedDipole[iIndex][2];
RealOpenMM qkui3 = qk3*_inducedDipole[iIndex][0] + qk6*_inducedDipole[iIndex][1] + qk9*_inducedDipole[iIndex][2];
RealOpenMM qiukp1 = qi1*_inducedDipolePolar[jIndex][0] + qi2*_inducedDipolePolar[jIndex][1] + qi3*_inducedDipolePolar[jIndex][2];
RealOpenMM qiukp2 = qi2*_inducedDipolePolar[jIndex][0] + qi5*_inducedDipolePolar[jIndex][1] + qi6*_inducedDipolePolar[jIndex][2];
RealOpenMM qiukp3 = qi3*_inducedDipolePolar[jIndex][0] + qi6*_inducedDipolePolar[jIndex][1] + qi9*_inducedDipolePolar[jIndex][2];
RealOpenMM qkuip1 = qk1*_inducedDipolePolar[iIndex][0] + qk2*_inducedDipolePolar[iIndex][1] + qk3*_inducedDipolePolar[iIndex][2];
RealOpenMM qkuip2 = qk2*_inducedDipolePolar[iIndex][0] + qk5*_inducedDipolePolar[iIndex][1] + qk6*_inducedDipolePolar[iIndex][2];
RealOpenMM qkuip3 = qk3*_inducedDipolePolar[iIndex][0] + qk6*_inducedDipolePolar[iIndex][1] + qk9*_inducedDipolePolar[iIndex][2];
RealOpenMM dixqkr1 = di2*qkr3 - di3*qkr2;
RealOpenMM dixqkr2 = di3*qkr1 - di1*qkr3;
RealOpenMM dixqkr3 = di1*qkr2 - di2*qkr1;
RealOpenMM dkxqir1 = dk2*qir3 - dk3*qir2;
RealOpenMM dkxqir2 = dk3*qir1 - dk1*qir3;
RealOpenMM dkxqir3 = dk1*qir2 - dk2*qir1;
RealOpenMM uixqkr1 = _inducedDipole[iIndex][1]*qkr3 - _inducedDipole[iIndex][2]*qkr2;
RealOpenMM uixqkr2 = _inducedDipole[iIndex][2]*qkr1 - _inducedDipole[iIndex][0]*qkr3;
RealOpenMM uixqkr3 = _inducedDipole[iIndex][0]*qkr2 - _inducedDipole[iIndex][1]*qkr1;
RealOpenMM ukxqir1 = _inducedDipole[jIndex][1]*qir3 - _inducedDipole[jIndex][2]*qir2;
RealOpenMM ukxqir2 = _inducedDipole[jIndex][2]*qir1 - _inducedDipole[jIndex][0]*qir3;
RealOpenMM ukxqir3 = _inducedDipole[jIndex][0]*qir2 - _inducedDipole[jIndex][1]*qir1;
RealOpenMM uixqkrp1 = _inducedDipolePolar[iIndex][1]*qkr3 - _inducedDipolePolar[iIndex][2]*qkr2;
RealOpenMM uixqkrp2 = _inducedDipolePolar[iIndex][2]*qkr1 - _inducedDipolePolar[iIndex][0]*qkr3;
RealOpenMM uixqkrp3 = _inducedDipolePolar[iIndex][0]*qkr2 - _inducedDipolePolar[iIndex][1]*qkr1;
RealOpenMM ukxqirp1 = _inducedDipolePolar[jIndex][1]*qir3 - _inducedDipolePolar[jIndex][2]*qir2;
RealOpenMM ukxqirp2 = _inducedDipolePolar[jIndex][2]*qir1 - _inducedDipolePolar[jIndex][0]*qir3;
RealOpenMM ukxqirp3 = _inducedDipolePolar[jIndex][0]*qir2 - _inducedDipolePolar[jIndex][1]*qir1;
RealOpenMM rxqidk1 = yr*qidk3 - zr*qidk2;
RealOpenMM rxqidk2 = zr*qidk1 - xr*qidk3;
RealOpenMM rxqidk3 = xr*qidk2 - yr*qidk1;
RealOpenMM rxqkdi1 = yr*qkdi3 - zr*qkdi2;
RealOpenMM rxqkdi2 = zr*qkdi1 - xr*qkdi3;
RealOpenMM rxqkdi3 = xr*qkdi2 - yr*qkdi1;
RealOpenMM rxqiuk1 = yr*qiuk3 - zr*qiuk2;
RealOpenMM rxqiuk2 = zr*qiuk1 - xr*qiuk3;
RealOpenMM rxqiuk3 = xr*qiuk2 - yr*qiuk1;
RealOpenMM rxqkui1 = yr*qkui3 - zr*qkui2;
RealOpenMM rxqkui2 = zr*qkui1 - xr*qkui3;
RealOpenMM rxqkui3 = xr*qkui2 - yr*qkui1;
RealOpenMM rxqiukp1 = yr*qiukp3 - zr*qiukp2;
RealOpenMM rxqiukp2 = zr*qiukp1 - xr*qiukp3;
RealOpenMM rxqiukp3 = xr*qiukp2 - yr*qiukp1;
RealOpenMM rxqkuip1 = yr*qkuip3 - zr*qkuip2;
RealOpenMM rxqkuip2 = zr*qkuip1 - xr*qkuip3;
RealOpenMM rxqkuip3 = xr*qkuip2 - yr*qkuip1;
// calculate the scalar products for permanent components
RealOpenMM sc2 = di1*dk1 + di2*dk2 + di3*dk3;
RealOpenMM sc3 = di1*xr + di2*yr + di3*zr;
RealOpenMM sc4 = dk1*xr + dk2*yr + dk3*zr;
RealOpenMM sc5 = qir1*xr + qir2*yr + qir3*zr;
RealOpenMM sc6 = qkr1*xr + qkr2*yr + qkr3*zr;
RealOpenMM sc7 = qir1*dk1 + qir2*dk2 + qir3*dk3;
RealOpenMM sc8 = qkr1*di1 + qkr2*di2 + qkr3*di3;
RealOpenMM sc9 = qir1*qkr1 + qir2*qkr2 + qir3*qkr3;
RealOpenMM sc10 = qi1*qk1 + qi2*qk2 + qi3*qk3
+ qi2*qk2 + qi5*qk5 + qi6*qk6
+ qi3*qk3 + qi6*qk6 + qi9*qk9;
// calculate the scalar products for induced components
RealOpenMM sci1 = _inducedDipole[iIndex][0]*dk1 + _inducedDipole[iIndex][1]*dk2
+ _inducedDipole[iIndex][2]*dk3 + di1*_inducedDipole[jIndex][0]
+ di2*_inducedDipole[jIndex][1] + di3*_inducedDipole[jIndex][2];
RealOpenMM sci3 = _inducedDipole[iIndex][0]*xr + _inducedDipole[iIndex][1]*yr + _inducedDipole[iIndex][2]*zr;
RealOpenMM sci4 = _inducedDipole[jIndex][0]*xr + _inducedDipole[jIndex][1]*yr + _inducedDipole[jIndex][2]*zr;
RealOpenMM sci7 = qir1*_inducedDipole[jIndex][0] + qir2*_inducedDipole[jIndex][1] + qir3*_inducedDipole[jIndex][2];
RealOpenMM sci8 = qkr1*_inducedDipole[iIndex][0] + qkr2*_inducedDipole[iIndex][1] + qkr3*_inducedDipole[iIndex][2];
RealOpenMM scip1 = _inducedDipolePolar[iIndex][0]*dk1 + _inducedDipolePolar[iIndex][1]*dk2 + _inducedDipolePolar[iIndex][2]*dk3 + di1*_inducedDipolePolar[jIndex][0] + di2*_inducedDipolePolar[jIndex][1] + di3*_inducedDipolePolar[jIndex][2];
RealOpenMM scip2 = _inducedDipole[iIndex][0]*_inducedDipolePolar[jIndex][0]+_inducedDipole[iIndex][1]*_inducedDipolePolar[jIndex][1]
+ _inducedDipole[iIndex][2]*_inducedDipolePolar[jIndex][2]+_inducedDipolePolar[iIndex][0]*_inducedDipole[jIndex][0]
+ _inducedDipolePolar[iIndex][1]*_inducedDipole[jIndex][1]+_inducedDipolePolar[iIndex][2]*_inducedDipole[jIndex][2];
RealOpenMM scip3 = _inducedDipolePolar[iIndex][0]*xr + _inducedDipolePolar[iIndex][1]*yr + _inducedDipolePolar[iIndex][2]*zr;
RealOpenMM scip4 = _inducedDipolePolar[jIndex][0]*xr + _inducedDipolePolar[jIndex][1]*yr + _inducedDipolePolar[jIndex][2]*zr;
RealOpenMM scip7 = qir1*_inducedDipolePolar[jIndex][0] + qir2*_inducedDipolePolar[jIndex][1] + qir3*_inducedDipolePolar[jIndex][2];
RealOpenMM scip8 = qkr1*_inducedDipolePolar[iIndex][0] + qkr2*_inducedDipolePolar[iIndex][1] + qkr3*_inducedDipolePolar[iIndex][2];
// calculate the gl functions for permanent components
RealOpenMM gl0 = ci*ck;
RealOpenMM gl1 = ck*sc3 - ci*sc4;
RealOpenMM gl2 = ci*sc6 + ck*sc5 - sc3*sc4;
RealOpenMM gl3 = sc3*sc6 - sc4*sc5;
RealOpenMM gl4 = sc5*sc6;
RealOpenMM gl5 = -4.0*sc9;
RealOpenMM gl6 = sc2;
RealOpenMM gl7 = 2.0 * (sc7-sc8);
RealOpenMM gl8 = 2.0 * sc10;
// calculate the gl functions for induced components
RealOpenMM gli1 = ck*sci3 - ci*sci4;
RealOpenMM gli2 = -sc3*sci4 - sci3*sc4;
RealOpenMM gli3 = sci3*sc6 - sci4*sc5;
RealOpenMM gli6 = sci1;
RealOpenMM gli7 = 2.0 * (sci7-sci8);
RealOpenMM glip1 = ck*scip3 - ci*scip4;
RealOpenMM glip2 = -sc3*scip4 - scip3*sc4;
RealOpenMM glip3 = scip3*sc6 - scip4*sc5;
RealOpenMM glip6 = scip1;
RealOpenMM glip7 = 2.0 * (scip7-scip8);
// compute the energy contributions for this interaction
RealOpenMM e = bn0*gl0 + bn1*(gl1+gl6) + bn2*(gl2+gl7+gl8) + bn3*(gl3+gl5) + bn4*gl4;
RealOpenMM ei = 0.5 * (bn1*(gli1+gli6) + bn2*(gli2+gli7) + bn3*gli3);
// get the real energy without any screening function
RealOpenMM erl = rr1*gl0 + rr3*(gl1+gl6) + rr5*(gl2+gl7+gl8) + rr7*(gl3+gl5) + rr9*gl4;
RealOpenMM erli = 0.5*(rr3*(gli1+gli6)*psc3 + rr5*(gli2+gli7)*psc5 + rr7*gli3*psc7);
e = e - (1.0-scalingFactors[M_SCALE])*erl;
ei = ei - erli;
energy = (e + ei);
// intermediate variables for permanent force terms
RealOpenMM gf1 = bn1*gl0 + bn2*(gl1+gl6)
+ bn3*(gl2+gl7+gl8)
+ bn4*(gl3+gl5) + bn5*gl4;
RealOpenMM gf2 = -ck*bn1 + sc4*bn2 - sc6*bn3;
RealOpenMM gf3 = ci*bn1 + sc3*bn2 + sc5*bn3;
RealOpenMM gf4 = 2.0*bn2;
RealOpenMM gf5 = 2.0*(-ck*bn2+sc4*bn3-sc6*bn4);
RealOpenMM gf6 = 2.0*(-ci*bn2-sc3*bn3-sc5*bn4);
RealOpenMM gf7 = 4.0*bn3;
RealOpenMM gfr1 = rr3*gl0 + rr5*(gl1+gl6)
+ rr7*(gl2+gl7+gl8)
+ rr9*(gl3+gl5) + rr11*gl4;
RealOpenMM gfr2 = -ck*rr3 + sc4*rr5 - sc6*rr7;
RealOpenMM gfr3 = ci*rr3 + sc3*rr5 + sc5*rr7;
RealOpenMM gfr4 = 2.0*rr5;
RealOpenMM gfr5 = 2.0*(-ck*rr5+sc4*rr7-sc6*rr9);
RealOpenMM gfr6 = 2.0*(-ci*rr5-sc3*rr7-sc5*rr9);
RealOpenMM gfr7 = 4.0*rr7;
// intermediate variables for induced force terms
RealOpenMM gfi1 = 0.5*(bn2*(gli1+glip1+gli6+glip6)
+ bn2*scip2
+ bn3*(gli2+glip2+gli7+glip7)
- bn3*(sci3*scip4+scip3*sci4)
+ bn4*(gli3+glip3));
RealOpenMM gfi2 = -ck*bn1 + sc4*bn2 - sc6*bn3;
RealOpenMM gfi3 = ci*bn1 + sc3*bn2 + sc5*bn3;
RealOpenMM gfi4 = 2.0 * bn2;
RealOpenMM gfi5 = bn3 * (sci4+scip4);
RealOpenMM gfi6 = -bn3 * (sci3+scip3);
RealOpenMM gfri1 = 0.5*(rr5*((gli1+gli6)*psc3
+ (glip1+glip6)*dsc3
+ scip2*usc3)
+ rr7*((gli7+gli2)*psc5
+ (glip7+glip2)*dsc5
- (sci3*scip4+scip3*sci4)*usc5)
+ rr9*(gli3*psc7+glip3*dsc7));
RealOpenMM gfri4 = 2.0 * rr5;
RealOpenMM gfri5 = rr7 * (sci4*psc7+scip4*dsc7);
RealOpenMM gfri6 = -rr7 * (sci3*psc7+scip3*dsc7);
// get the permanent force with screening
RealOpenMM ftm21 = gf1*xr + gf2*di1 + gf3*dk1
+ gf4*(qkdi1-qidk1) + gf5*qir1
+ gf6*qkr1 + gf7*(qiqkr1+qkqir1);
RealOpenMM ftm22 = gf1*yr + gf2*di2 + gf3*dk2
+ gf4*(qkdi2-qidk2) + gf5*qir2
+ gf6*qkr2 + gf7*(qiqkr2+qkqir2);
RealOpenMM ftm23 = gf1*zr + gf2*di3 + gf3*dk3
+ gf4*(qkdi3-qidk3) + gf5*qir3
+ gf6*qkr3 + gf7*(qiqkr3+qkqir3);
// get the permanent force without screening
RealOpenMM ftm2r1 = gfr1*xr + gfr2*di1 + gfr3*dk1
+ gfr4*(qkdi1-qidk1) + gfr5*qir1
+ gfr6*qkr1 + gfr7*(qiqkr1+qkqir1);
RealOpenMM ftm2r2 = gfr1*yr + gfr2*di2 + gfr3*dk2
+ gfr4*(qkdi2-qidk2) + gfr5*qir2
+ gfr6*qkr2 + gfr7*(qiqkr2+qkqir2);
RealOpenMM ftm2r3 = gfr1*zr + gfr2*di3 + gfr3*dk3
+ gfr4*(qkdi3-qidk3) + gfr5*qir3
+ gfr6*qkr3 + gfr7*(qiqkr3+qkqir3);
// get the induced force with screening
RealOpenMM ftm2i1 = gfi1*xr + 0.5*
(gfi2*(_inducedDipole[iIndex][0]+_inducedDipolePolar[iIndex][0])
+ bn2*(sci4*_inducedDipolePolar[iIndex][0]+scip4*_inducedDipole[iIndex][0])
+ gfi3*(_inducedDipole[jIndex][0]+_inducedDipolePolar[jIndex][0])
+ bn2*(sci3*_inducedDipolePolar[jIndex][0]+scip3*_inducedDipole[jIndex][0])
+ (sci4+scip4)*bn2*di1
+ (sci3+scip3)*bn2*dk1
+ gfi4*(qkui1+qkuip1-qiuk1-qiukp1))
+ gfi5*qir1 + gfi6*qkr1;
RealOpenMM ftm2i2 = gfi1*yr + 0.5*
(gfi2*(_inducedDipole[iIndex][1]+_inducedDipolePolar[iIndex][1])
+ bn2*(sci4*_inducedDipolePolar[iIndex][1]+scip4*_inducedDipole[iIndex][1])
+ gfi3*(_inducedDipole[jIndex][1]+_inducedDipolePolar[jIndex][1])
+ bn2*(sci3*_inducedDipolePolar[jIndex][1]+scip3*_inducedDipole[jIndex][1])
+ (sci4+scip4)*bn2*di2
+ (sci3+scip3)*bn2*dk2
+ gfi4*(qkui2+qkuip2-qiuk2-qiukp2))
+ gfi5*qir2 + gfi6*qkr2;
RealOpenMM ftm2i3 = gfi1*zr + 0.5*
(gfi2*(_inducedDipole[iIndex][2]+_inducedDipolePolar[iIndex][2])
+ bn2*(sci4*_inducedDipolePolar[iIndex][2]+scip4*_inducedDipole[iIndex][2])
+ gfi3*(_inducedDipole[jIndex][2]+_inducedDipolePolar[jIndex][2])
+ bn2*(sci3*_inducedDipolePolar[jIndex][2]+scip3*_inducedDipole[jIndex][2])
+ (sci4+scip4)*bn2*di3
+ (sci3+scip3)*bn2*dk3
+ gfi4*(qkui3+qkuip3-qiuk3-qiukp3))
+ gfi5*qir3 + gfi6*qkr3;
// get the induced force without screening
RealOpenMM ftm2ri1 = gfri1*xr + 0.5*
(- rr3*ck*(_inducedDipole[iIndex][0]*psc3+_inducedDipolePolar[iIndex][0]*dsc3)
+ rr5*sc4*(_inducedDipole[iIndex][0]*psc5+_inducedDipolePolar[iIndex][0]*dsc5)
- rr7*sc6*(_inducedDipole[iIndex][0]*psc7+_inducedDipolePolar[iIndex][0]*dsc7))
+ (rr3*ci*(_inducedDipole[jIndex][0]*psc3+_inducedDipolePolar[jIndex][0]*dsc3)
+ rr5*sc3*(_inducedDipole[jIndex][0]*psc5+_inducedDipolePolar[jIndex][0]*dsc5)
+ rr7*sc5*(_inducedDipole[jIndex][0]*psc7+_inducedDipolePolar[jIndex][0]*dsc7))*0.5
+ rr5*usc5*(sci4*_inducedDipolePolar[iIndex][0]+scip4*_inducedDipole[iIndex][0]
+ sci3*_inducedDipolePolar[jIndex][0]+scip3*_inducedDipole[jIndex][0])*0.5
+ 0.5*(sci4*psc5+scip4*dsc5)*rr5*di1
+ 0.5*(sci3*psc5+scip3*dsc5)*rr5*dk1
+ 0.5*gfri4*((qkui1-qiuk1)*psc5
+ (qkuip1-qiukp1)*dsc5)
+ gfri5*qir1 + gfri6*qkr1;
RealOpenMM ftm2ri2 = gfri1*yr + 0.5*
(- rr3*ck*(_inducedDipole[iIndex][1]*psc3+_inducedDipolePolar[iIndex][1]*dsc3)
+ rr5*sc4*(_inducedDipole[iIndex][1]*psc5+_inducedDipolePolar[iIndex][1]*dsc5)
- rr7*sc6*(_inducedDipole[iIndex][1]*psc7+_inducedDipolePolar[iIndex][1]*dsc7))
+ (rr3*ci*(_inducedDipole[jIndex][1]*psc3+_inducedDipolePolar[jIndex][1]*dsc3)
+ rr5*sc3*(_inducedDipole[jIndex][1]*psc5+_inducedDipolePolar[jIndex][1]*dsc5)
+ rr7*sc5*(_inducedDipole[jIndex][1]*psc7+_inducedDipolePolar[jIndex][1]*dsc7))*0.5
+ rr5*usc5*(sci4*_inducedDipolePolar[iIndex][1]+scip4*_inducedDipole[iIndex][1]
+ sci3*_inducedDipolePolar[jIndex][1]+scip3*_inducedDipole[jIndex][1])*0.5
+ 0.5*(sci4*psc5+scip4*dsc5)*rr5*di2
+ 0.5*(sci3*psc5+scip3*dsc5)*rr5*dk2
+ 0.5*gfri4*((qkui2-qiuk2)*psc5
+ (qkuip2-qiukp2)*dsc5)
+ gfri5*qir2 + gfri6*qkr2;
RealOpenMM ftm2ri3 = gfri1*zr + 0.5*
(- rr3*ck*(_inducedDipole[iIndex][2]*psc3+_inducedDipolePolar[iIndex][2]*dsc3)
+ rr5*sc4*(_inducedDipole[iIndex][2]*psc5+_inducedDipolePolar[iIndex][2]*dsc5)
- rr7*sc6*(_inducedDipole[iIndex][2]*psc7+_inducedDipolePolar[iIndex][2]*dsc7))
+ (rr3*ci*(_inducedDipole[jIndex][2]*psc3+_inducedDipolePolar[jIndex][2]*dsc3)
+ rr5*sc3*(_inducedDipole[jIndex][2]*psc5+_inducedDipolePolar[jIndex][2]*dsc5)
+ rr7*sc5*(_inducedDipole[jIndex][2]*psc7+_inducedDipolePolar[jIndex][2]*dsc7))*0.5
+ rr5*usc5*(sci4*_inducedDipolePolar[iIndex][2]+scip4*_inducedDipole[iIndex][2]
+ sci3*_inducedDipolePolar[jIndex][2]+scip3*_inducedDipole[jIndex][2])*0.5
+ 0.5*(sci4*psc5+scip4*dsc5)*rr5*di3
+ 0.5*(sci3*psc5+scip3*dsc5)*rr5*dk3
+ 0.5*gfri4*((qkui3-qiuk3)*psc5
+ (qkuip3-qiukp3)*dsc5)
+ gfri5*qir3 + gfri6*qkr3;
// account for partially excluded induced interactions
RealOpenMM temp3 = 0.5 * rr3 * ((gli1+gli6)*scalingFactors[P_SCALE]
+(glip1+glip6)*scalingFactors[D_SCALE]);
RealOpenMM temp5 = 0.5 * rr5 * ((gli2+gli7)*scalingFactors[P_SCALE]
+(glip2+glip7)*scalingFactors[D_SCALE]);
RealOpenMM temp7 = 0.5 * rr7 * (gli3*scalingFactors[P_SCALE]
+glip3*scalingFactors[D_SCALE]);
RealOpenMM fridmp1 = temp3*ddsc31 + temp5*ddsc51 + temp7*ddsc71;
RealOpenMM fridmp2 = temp3*ddsc32 + temp5*ddsc52 + temp7*ddsc72;
RealOpenMM fridmp3 = temp3*ddsc33 + temp5*ddsc53 + temp7*ddsc73;
// find some scaling terms for induced-induced force
temp3 = 0.5 * rr3 * scalingFactors[U_SCALE] * scip2;
temp5 = -0.5 * rr5 * scalingFactors[U_SCALE] * (sci3*scip4+scip3*sci4);
RealOpenMM findmp1 = temp3*ddsc31 + temp5*ddsc51;
RealOpenMM findmp2 = temp3*ddsc32 + temp5*ddsc52;
RealOpenMM findmp3 = temp3*ddsc33 + temp5*ddsc53;
// modify the forces for partially excluded interactions
ftm2i1 -= (fridmp1 + findmp1);
ftm2i2 -= (fridmp2 + findmp2);
ftm2i3 -= (fridmp3 + findmp3);
// correction to convert mutual to direct polarization force
if (getPolarizationType() == AmoebaReferenceMultipoleForce::Direct) {
RealOpenMM gfd = 0.5 * (bn2*scip2 - bn3*(scip3*sci4+sci3*scip4));
ftm2i1 -= gfd*xr + 0.5*bn2*(sci4*_inducedDipolePolar[iIndex][0]+scip4*_inducedDipole[iIndex][0]+sci3*_inducedDipolePolar[jIndex][0]+scip3*_inducedDipole[jIndex][0]);
ftm2i2 -= gfd*yr + 0.5*bn2*(sci4*_inducedDipolePolar[iIndex][1]+scip4*_inducedDipole[iIndex][1]+sci3*_inducedDipolePolar[jIndex][1]+scip3*_inducedDipole[jIndex][1]);
ftm2i3 -= gfd*zr + 0.5*bn2*(sci4*_inducedDipolePolar[iIndex][2]+scip4*_inducedDipole[iIndex][2]+sci3*_inducedDipolePolar[jIndex][2]+scip3*_inducedDipole[jIndex][2]);
// The Qtilde{x,y,z} torque intermediates for atoms I and J, which are used to obtain the torques on the permanent moments.
RealOpenMM
qiQIX
[
9
]
=
{
0.0
,
qiQI
[
3
],
0.0
,
-
qiQI
[
1
],
sqrtThree
*
qiQI
[
6
],
qiQI
[
8
],
-
sqrtThree
*
qiQI
[
4
]
-
qiQI
[
7
],
qiQI
[
6
],
-
qiQI
[
5
]};
RealOpenMM
qiQIY
[
9
]
=
{
0.0
,
-
qiQI
[
2
],
qiQI
[
1
],
0.0
,
-
sqrtThree
*
qiQI
[
5
],
sqrtThree
*
qiQI
[
4
]
-
qiQI
[
7
],
-
qiQI
[
8
],
qiQI
[
5
],
qiQI
[
6
]};
RealOpenMM
qiQIZ
[
9
]
=
{
0.0
,
0.0
,
-
qiQI
[
3
],
qiQI
[
2
],
0.0
,
-
qiQI
[
6
],
qiQI
[
5
],
-
2.0
*
qiQI
[
8
],
2.0
*
qiQI
[
7
]};
RealOpenMM
qiQJX
[
9
]
=
{
0.0
,
qiQJ
[
3
],
0.0
,
-
qiQJ
[
1
],
sqrtThree
*
qiQJ
[
6
],
qiQJ
[
8
],
-
sqrtThree
*
qiQJ
[
4
]
-
qiQJ
[
7
],
qiQJ
[
6
],
-
qiQJ
[
5
]};
RealOpenMM
qiQJY
[
9
]
=
{
0.0
,
-
qiQJ
[
2
],
qiQJ
[
1
],
0.0
,
-
sqrtThree
*
qiQJ
[
5
],
sqrtThree
*
qiQJ
[
4
]
-
qiQJ
[
7
],
-
qiQJ
[
8
],
qiQJ
[
5
],
qiQJ
[
6
]};
RealOpenMM
qiQJZ
[
9
]
=
{
0.0
,
0.0
,
-
qiQJ
[
3
],
qiQJ
[
2
],
0.0
,
-
qiQJ
[
6
],
qiQJ
[
5
],
-
2.0
*
qiQJ
[
8
],
2.0
*
qiQJ
[
7
]};
// The field derivatives at I due to permanent and induced moments on J, and vice-versa.
// Also, their derivatives w.r.t. R, which are needed for force calculations
RealOpenMM
Vij
[
9
],
Vji
[
9
],
VjiR
[
9
],
VijR
[
9
];
// The field derivatives at I due to only permanent moments on J, and vice-versa.
RealOpenMM
Vijp
[
3
],
Vijd
[
3
],
Vjip
[
3
],
Vjid
[
3
];
RealOpenMM
rInvVec
[
7
],
alphaRVec
[
8
],
bVec
[
5
];
RealOpenMM
prefac
=
(
_electric
/
_dielectric
);
RealOpenMM
rInv
=
1.0
/
r
;
// The rInvVec array is defined such that the ith element is R^-i, with the
// dieleectric constant folded in, to avoid conversions later.
rInvVec
[
1
]
=
prefac
*
rInv
;
for
(
int
i
=
2
;
i
<
7
;
++
i
)
rInvVec
[
i
]
=
rInvVec
[
i
-
1
]
*
rInv
;
// The alpharVec array is defined such that the ith element is (alpha R)^i,
// where kappa (alpha in OpenMM parlance) is the Ewald attenuation parameter.
alphaRVec
[
1
]
=
_alphaEwald
*
r
;
for
(
int
i
=
2
;
i
<
8
;
++
i
)
alphaRVec
[
i
]
=
alphaRVec
[
i
-
1
]
*
alphaRVec
[
1
];
RealOpenMM
erfAlphaR
=
erf
(
alphaRVec
[
1
]);
RealOpenMM
X
=
2.0
*
EXP
(
-
alphaRVec
[
2
])
/
SQRT_PI
;
RealOpenMM
mScale
=
scalingFactors
[
M_SCALE
];
RealOpenMM
dScale
=
scalingFactors
[
D_SCALE
];
RealOpenMM
pScale
=
scalingFactors
[
P_SCALE
];
RealOpenMM
uScale
=
scalingFactors
[
U_SCALE
];
int
doubleFactorial
=
1
,
facCount
=
1
;
RealOpenMM
tmp
=
alphaRVec
[
1
];
bVec
[
1
]
=
-
erfAlphaR
;
for
(
int
i
=
2
;
i
<
5
;
++
i
){
bVec
[
i
]
=
bVec
[
i
-
1
]
+
tmp
*
X
/
(
RealOpenMM
)(
doubleFactorial
);
facCount
=
facCount
+
2
;
doubleFactorial
=
doubleFactorial
*
facCount
;
tmp
*=
2.0
*
alphaRVec
[
2
];
}
RealOpenMM gfdr = 0.5 * (rr5*scip2*usc3 - rr7*(scip3*sci4 +sci3*scip4)*usc5);
RealOpenMM fdir1 = gfdr*xr + 0.5*usc5*rr5*(sci4*_inducedDipolePolar[iIndex][0]+scip4*_inducedDipole[iIndex][0] + sci3*_inducedDipolePolar[jIndex][0]+scip3*_inducedDipole[jIndex][0]);
RealOpenMM fdir2 = gfdr*yr + 0.5*usc5*rr5*(sci4*_inducedDipolePolar[iIndex][1]+scip4*_inducedDipole[iIndex][1] + sci3*_inducedDipolePolar[jIndex][1]+scip3*_inducedDipole[jIndex][1]);
RealOpenMM fdir3 = gfdr*zr + 0.5*usc5*rr5*(sci4*_inducedDipolePolar[iIndex][2]+scip4*_inducedDipole[iIndex][2] + sci3*_inducedDipolePolar[jIndex][2]+scip3*_inducedDipole[jIndex][2]);
RealOpenMM
dmp
=
particleI
.
dampingFactor
*
particleJ
.
dampingFactor
;
RealOpenMM
a
=
particleI
.
thole
<
particleJ
.
thole
?
particleI
.
thole
:
particleJ
.
thole
;
RealOpenMM
u
=
std
::
abs
(
dmp
)
>
1.0E-5
?
r
/
dmp
:
1E10
;
RealOpenMM
au3
=
a
*
u
*
u
*
u
;
RealOpenMM
expau3
=
au3
<
50.0
?
EXP
(
-
au3
)
:
0.0
;
RealOpenMM
a2u6
=
au3
*
au3
;
RealOpenMM
a3u9
=
a2u6
*
au3
;
// Thole damping factors for energies
RealOpenMM
thole_c
=
1.0
-
expau3
;
RealOpenMM
thole_d0
=
1.0
-
expau3
*
(
1.0
+
1.5
*
au3
);
RealOpenMM
thole_d1
=
1.0
-
expau3
;
RealOpenMM
thole_q0
=
1.0
-
expau3
*
(
1.0
+
au3
+
a2u6
);
RealOpenMM
thole_q1
=
1.0
-
expau3
*
(
1.0
+
au3
);
// Thole damping factors for derivatives
RealOpenMM
dthole_c
=
1.0
-
expau3
*
(
1.0
+
1.5
*
au3
);
RealOpenMM
dthole_d0
=
1.0
-
expau3
*
(
1.0
+
au3
+
1.5
*
a2u6
);
RealOpenMM
dthole_d1
=
1.0
-
expau3
*
(
1.0
+
au3
);
RealOpenMM
dthole_q0
=
1.0
-
expau3
*
(
1.0
+
au3
+
0.25
*
a2u6
+
0.75
*
a3u9
);
RealOpenMM
dthole_q1
=
1.0
-
expau3
*
(
1.0
+
au3
+
0.75
*
a2u6
);
// Now we compute the (attenuated) Coulomb operator and its derivatives, contracted with
// permanent moments and induced dipoles. Note that the coefficient of the permanent force
// terms is half of the expected value; this is because we compute the interaction of I with
// the sum of induced and permanent moments on J, as well as the interaction of J with I's
// permanent and induced moments; doing so double counts the permanent-permanent interaction.
RealOpenMM
ePermCoef
,
dPermCoef
,
eUIndCoef
,
dUIndCoef
,
eUInpCoef
,
dUInpCoef
;
// C-C terms (m=0)
ePermCoef
=
rInvVec
[
1
]
*
(
mScale
+
bVec
[
2
]
-
alphaRVec
[
1
]
*
X
);
dPermCoef
=
-
0.5
*
(
mScale
+
bVec
[
2
])
*
rInvVec
[
2
];
Vij
[
0
]
=
ePermCoef
*
qiQJ
[
0
];
Vji
[
0
]
=
ePermCoef
*
qiQI
[
0
];
VijR
[
0
]
=
dPermCoef
*
qiQJ
[
0
];
VjiR
[
0
]
=
dPermCoef
*
qiQI
[
0
];
// C-D and C-Uind terms (m=0)
ePermCoef
=
rInvVec
[
2
]
*
(
mScale
+
bVec
[
2
]);
eUIndCoef
=
rInvVec
[
2
]
*
(
pScale
*
thole_c
+
bVec
[
2
]);
eUInpCoef
=
rInvVec
[
2
]
*
(
dScale
*
thole_c
+
bVec
[
2
]);
dPermCoef
=
-
rInvVec
[
3
]
*
(
mScale
+
bVec
[
2
]
+
alphaRVec
[
3
]
*
X
);
dUIndCoef
=
-
2.0
*
rInvVec
[
3
]
*
(
pScale
*
dthole_c
+
bVec
[
2
]
+
alphaRVec
[
3
]
*
X
);
dUInpCoef
=
-
2.0
*
rInvVec
[
3
]
*
(
dScale
*
dthole_c
+
bVec
[
2
]
+
alphaRVec
[
3
]
*
X
);
Vij
[
0
]
+=
-
(
ePermCoef
*
qiQJ
[
1
]
+
eUIndCoef
*
qiUindJ
[
0
]
+
eUInpCoef
*
qiUinpJ
[
0
]);
Vji
[
1
]
=
-
(
ePermCoef
*
qiQI
[
0
]);
VijR
[
0
]
+=
-
(
dPermCoef
*
qiQJ
[
1
]
+
dUIndCoef
*
qiUindJ
[
0
]
+
dUInpCoef
*
qiUinpJ
[
0
]);
VjiR
[
1
]
=
-
(
dPermCoef
*
qiQI
[
0
]);
Vjip
[
0
]
=
-
(
eUInpCoef
*
qiQI
[
0
]);
Vjid
[
0
]
=
-
(
eUIndCoef
*
qiQI
[
0
]);
// D-C and Uind-C terms (m=0)
Vij
[
1
]
=
ePermCoef
*
qiQJ
[
0
];
Vji
[
0
]
+=
ePermCoef
*
qiQI
[
1
]
+
eUIndCoef
*
qiUindI
[
0
]
+
eUInpCoef
*
qiUinpI
[
0
];
VijR
[
1
]
=
dPermCoef
*
qiQJ
[
0
];
VjiR
[
0
]
+=
dPermCoef
*
qiQI
[
1
]
+
dUIndCoef
*
qiUindI
[
0
]
+
dUInpCoef
*
qiUinpI
[
0
];
Vijp
[
0
]
=
eUInpCoef
*
qiQJ
[
0
];
Vijd
[
0
]
=
eUIndCoef
*
qiQJ
[
0
];
// D-D and D-Uind terms (m=0)
ePermCoef
=
-
twoThirds
*
rInvVec
[
3
]
*
(
3.0
*
(
mScale
+
bVec
[
3
])
+
alphaRVec
[
3
]
*
X
);
eUIndCoef
=
-
twoThirds
*
rInvVec
[
3
]
*
(
3.0
*
(
pScale
*
thole_d0
+
bVec
[
3
])
+
alphaRVec
[
3
]
*
X
);
eUInpCoef
=
-
twoThirds
*
rInvVec
[
3
]
*
(
3.0
*
(
dScale
*
thole_d0
+
bVec
[
3
])
+
alphaRVec
[
3
]
*
X
);
dPermCoef
=
rInvVec
[
4
]
*
(
3.0
*
(
mScale
+
bVec
[
3
])
+
2.
*
alphaRVec
[
5
]
*
X
);
dUIndCoef
=
rInvVec
[
4
]
*
(
6.0
*
(
pScale
*
dthole_d0
+
bVec
[
3
])
+
4.0
*
alphaRVec
[
5
]
*
X
);
dUInpCoef
=
rInvVec
[
4
]
*
(
6.0
*
(
dScale
*
dthole_d0
+
bVec
[
3
])
+
4.0
*
alphaRVec
[
5
]
*
X
);
Vij
[
1
]
+=
ePermCoef
*
qiQJ
[
1
]
+
eUIndCoef
*
qiUindJ
[
0
]
+
eUInpCoef
*
qiUinpJ
[
0
];
Vji
[
1
]
+=
ePermCoef
*
qiQI
[
1
]
+
eUIndCoef
*
qiUindI
[
0
]
+
eUInpCoef
*
qiUinpI
[
0
];
VijR
[
1
]
+=
dPermCoef
*
qiQJ
[
1
]
+
dUIndCoef
*
qiUindJ
[
0
]
+
dUInpCoef
*
qiUinpJ
[
0
];
VjiR
[
1
]
+=
dPermCoef
*
qiQI
[
1
]
+
dUIndCoef
*
qiUindI
[
0
]
+
dUInpCoef
*
qiUinpI
[
0
];
Vijp
[
0
]
+=
eUInpCoef
*
qiQJ
[
1
];
Vijd
[
0
]
+=
eUIndCoef
*
qiQJ
[
1
];
Vjip
[
0
]
+=
eUInpCoef
*
qiQI
[
1
];
Vjid
[
0
]
+=
eUIndCoef
*
qiQI
[
1
];
// D-D and D-Uind terms (m=1)
ePermCoef
=
rInvVec
[
3
]
*
(
mScale
+
bVec
[
3
]
-
twoThirds
*
alphaRVec
[
3
]
*
X
);
eUIndCoef
=
rInvVec
[
3
]
*
(
pScale
*
thole_d1
+
bVec
[
3
]
-
twoThirds
*
alphaRVec
[
3
]
*
X
);
eUInpCoef
=
rInvVec
[
3
]
*
(
dScale
*
thole_d1
+
bVec
[
3
]
-
twoThirds
*
alphaRVec
[
3
]
*
X
);
dPermCoef
=
-
1.5
*
rInvVec
[
4
]
*
(
mScale
+
bVec
[
3
]);
dUIndCoef
=
-
3.0
*
rInvVec
[
4
]
*
(
pScale
*
dthole_d1
+
bVec
[
3
]);
dUInpCoef
=
-
3.0
*
rInvVec
[
4
]
*
(
dScale
*
dthole_d1
+
bVec
[
3
]);
Vij
[
2
]
=
ePermCoef
*
qiQJ
[
2
]
+
eUIndCoef
*
qiUindJ
[
1
]
+
eUInpCoef
*
qiUinpJ
[
1
];
Vji
[
2
]
=
ePermCoef
*
qiQI
[
2
]
+
eUIndCoef
*
qiUindI
[
1
]
+
eUInpCoef
*
qiUinpI
[
1
];
VijR
[
2
]
=
dPermCoef
*
qiQJ
[
2
]
+
dUIndCoef
*
qiUindJ
[
1
]
+
dUInpCoef
*
qiUinpJ
[
1
];
VjiR
[
2
]
=
dPermCoef
*
qiQI
[
2
]
+
dUIndCoef
*
qiUindI
[
1
]
+
dUInpCoef
*
qiUinpI
[
1
];
Vij
[
3
]
=
ePermCoef
*
qiQJ
[
3
]
+
eUIndCoef
*
qiUindJ
[
2
]
+
eUInpCoef
*
qiUinpJ
[
2
];
Vji
[
3
]
=
ePermCoef
*
qiQI
[
3
]
+
eUIndCoef
*
qiUindI
[
2
]
+
eUInpCoef
*
qiUinpI
[
2
];
VijR
[
3
]
=
dPermCoef
*
qiQJ
[
3
]
+
dUIndCoef
*
qiUindJ
[
2
]
+
dUInpCoef
*
qiUinpJ
[
2
];
VjiR
[
3
]
=
dPermCoef
*
qiQI
[
3
]
+
dUIndCoef
*
qiUindI
[
2
]
+
dUInpCoef
*
qiUinpI
[
2
];
Vijp
[
1
]
=
eUInpCoef
*
qiQJ
[
2
];
Vijd
[
1
]
=
eUIndCoef
*
qiQJ
[
2
];
Vjip
[
1
]
=
eUInpCoef
*
qiQI
[
2
];
Vjid
[
1
]
=
eUIndCoef
*
qiQI
[
2
];
Vijp
[
2
]
=
eUInpCoef
*
qiQJ
[
3
];
Vijd
[
2
]
=
eUIndCoef
*
qiQJ
[
3
];
Vjip
[
2
]
=
eUInpCoef
*
qiQI
[
3
];
Vjid
[
2
]
=
eUIndCoef
*
qiQI
[
3
];
// C-Q terms (m=0)
ePermCoef
=
(
mScale
+
bVec
[
3
])
*
rInvVec
[
3
];
dPermCoef
=
-
oneThird
*
rInvVec
[
4
]
*
(
4.5
*
(
mScale
+
bVec
[
3
])
+
2.0
*
alphaRVec
[
5
]
*
X
);
Vij
[
0
]
+=
ePermCoef
*
qiQJ
[
4
];
Vji
[
4
]
=
ePermCoef
*
qiQI
[
0
];
VijR
[
0
]
+=
dPermCoef
*
qiQJ
[
4
];
VjiR
[
4
]
=
dPermCoef
*
qiQI
[
0
];
// Q-C terms (m=0)
Vij
[
4
]
=
ePermCoef
*
qiQJ
[
0
];
Vji
[
0
]
+=
ePermCoef
*
qiQI
[
4
];
VijR
[
4
]
=
dPermCoef
*
qiQJ
[
0
];
VjiR
[
0
]
+=
dPermCoef
*
qiQI
[
4
];
// D-Q and Uind-Q terms (m=0)
ePermCoef
=
rInvVec
[
4
]
*
(
3.0
*
(
mScale
+
bVec
[
3
])
+
fourThirds
*
alphaRVec
[
5
]
*
X
);
eUIndCoef
=
rInvVec
[
4
]
*
(
3.0
*
(
pScale
*
thole_q0
+
bVec
[
3
])
+
fourThirds
*
alphaRVec
[
5
]
*
X
);
eUInpCoef
=
rInvVec
[
4
]
*
(
3.0
*
(
dScale
*
thole_q0
+
bVec
[
3
])
+
fourThirds
*
alphaRVec
[
5
]
*
X
);
dPermCoef
=
-
fourThirds
*
rInvVec
[
5
]
*
(
4.5
*
(
mScale
+
bVec
[
3
])
+
(
1.0
+
alphaRVec
[
2
])
*
alphaRVec
[
5
]
*
X
);
dUIndCoef
=
-
fourThirds
*
rInvVec
[
5
]
*
(
9.0
*
(
pScale
*
dthole_q0
+
bVec
[
3
])
+
2.0
*
(
1.0
+
alphaRVec
[
2
])
*
alphaRVec
[
5
]
*
X
);
dUInpCoef
=
-
fourThirds
*
rInvVec
[
5
]
*
(
9.0
*
(
dScale
*
dthole_q0
+
bVec
[
3
])
+
2.0
*
(
1.0
+
alphaRVec
[
2
])
*
alphaRVec
[
5
]
*
X
);
Vij
[
1
]
+=
ePermCoef
*
qiQJ
[
4
];
Vji
[
4
]
+=
ePermCoef
*
qiQI
[
1
]
+
eUIndCoef
*
qiUindI
[
0
]
+
eUInpCoef
*
qiUinpI
[
0
];
VijR
[
1
]
+=
dPermCoef
*
qiQJ
[
4
];
VjiR
[
4
]
+=
dPermCoef
*
qiQI
[
1
]
+
dUIndCoef
*
qiUindI
[
0
]
+
dUInpCoef
*
qiUinpI
[
0
];
Vijp
[
0
]
+=
eUInpCoef
*
qiQJ
[
4
];
Vijd
[
0
]
+=
eUIndCoef
*
qiQJ
[
4
];
// Q-D and Q-Uind terms (m=0)
Vij
[
4
]
+=
-
(
ePermCoef
*
qiQJ
[
1
]
+
eUIndCoef
*
qiUindJ
[
0
]
+
eUInpCoef
*
qiUinpJ
[
0
]);
Vji
[
1
]
+=
-
(
ePermCoef
*
qiQI
[
4
]);
VijR
[
4
]
+=
-
(
dPermCoef
*
qiQJ
[
1
]
+
dUIndCoef
*
qiUindJ
[
0
]
+
dUInpCoef
*
qiUinpJ
[
0
]);
VjiR
[
1
]
+=
-
(
dPermCoef
*
qiQI
[
4
]);
Vjip
[
0
]
+=
-
(
eUInpCoef
*
qiQI
[
4
]);
Vjid
[
0
]
+=
-
(
eUIndCoef
*
qiQI
[
4
]);
// D-Q and Uind-Q terms (m=1)
ePermCoef
=
-
sqrtThree
*
rInvVec
[
4
]
*
(
mScale
+
bVec
[
3
]);
eUIndCoef
=
-
sqrtThree
*
rInvVec
[
4
]
*
(
pScale
*
thole_q1
+
bVec
[
3
]);
eUInpCoef
=
-
sqrtThree
*
rInvVec
[
4
]
*
(
dScale
*
thole_q1
+
bVec
[
3
]);
dPermCoef
=
fourSqrtOneThird
*
rInvVec
[
5
]
*
(
1.5
*
(
mScale
+
bVec
[
3
])
+
0.5
*
alphaRVec
[
5
]
*
X
);
dUIndCoef
=
fourSqrtOneThird
*
rInvVec
[
5
]
*
(
3.0
*
(
pScale
*
dthole_q1
+
bVec
[
3
])
+
alphaRVec
[
5
]
*
X
);
dUInpCoef
=
fourSqrtOneThird
*
rInvVec
[
5
]
*
(
3.0
*
(
dScale
*
dthole_q1
+
bVec
[
3
])
+
alphaRVec
[
5
]
*
X
);
Vij
[
2
]
+=
ePermCoef
*
qiQJ
[
5
];
Vji
[
5
]
=
ePermCoef
*
qiQI
[
2
]
+
eUIndCoef
*
qiUindI
[
1
]
+
eUInpCoef
*
qiUinpI
[
1
];
VijR
[
2
]
+=
dPermCoef
*
qiQJ
[
5
];
VjiR
[
5
]
=
dPermCoef
*
qiQI
[
2
]
+
dUIndCoef
*
qiUindI
[
1
]
+
dUInpCoef
*
qiUinpI
[
1
];
Vij
[
3
]
+=
ePermCoef
*
qiQJ
[
6
];
Vji
[
6
]
=
ePermCoef
*
qiQI
[
3
]
+
eUIndCoef
*
qiUindI
[
2
]
+
eUInpCoef
*
qiUinpI
[
2
];
VijR
[
3
]
+=
dPermCoef
*
qiQJ
[
6
];
VjiR
[
6
]
=
dPermCoef
*
qiQI
[
3
]
+
dUIndCoef
*
qiUindI
[
2
]
+
dUInpCoef
*
qiUinpI
[
2
];
Vijp
[
1
]
+=
eUInpCoef
*
qiQJ
[
5
];
Vijd
[
1
]
+=
eUIndCoef
*
qiQJ
[
5
];
Vijp
[
2
]
+=
eUInpCoef
*
qiQJ
[
6
];
Vijd
[
2
]
+=
eUIndCoef
*
qiQJ
[
6
];
// D-Q and Uind-Q terms (m=1)
Vij
[
5
]
=
-
(
ePermCoef
*
qiQJ
[
2
]
+
eUIndCoef
*
qiUindJ
[
1
]
+
eUInpCoef
*
qiUinpJ
[
1
]);
Vji
[
2
]
+=
-
(
ePermCoef
*
qiQI
[
5
]);
VijR
[
5
]
=
-
(
dPermCoef
*
qiQJ
[
2
]
+
dUIndCoef
*
qiUindJ
[
1
]
+
dUInpCoef
*
qiUinpJ
[
1
]);
VjiR
[
2
]
+=
-
(
dPermCoef
*
qiQI
[
5
]);
Vij
[
6
]
=
-
(
ePermCoef
*
qiQJ
[
3
]
+
eUIndCoef
*
qiUindJ
[
2
]
+
eUInpCoef
*
qiUinpJ
[
2
]);
Vji
[
3
]
+=
-
(
ePermCoef
*
qiQI
[
6
]);
VijR
[
6
]
=
-
(
dPermCoef
*
qiQJ
[
3
]
+
dUIndCoef
*
qiUindJ
[
2
]
+
dUInpCoef
*
qiUinpJ
[
2
]);
VjiR
[
3
]
+=
-
(
dPermCoef
*
qiQI
[
6
]);
Vjip
[
1
]
+=
-
(
eUInpCoef
*
qiQI
[
5
]);
Vjid
[
1
]
+=
-
(
eUIndCoef
*
qiQI
[
5
]);
Vjip
[
2
]
+=
-
(
eUInpCoef
*
qiQI
[
6
]);
Vjid
[
2
]
+=
-
(
eUIndCoef
*
qiQI
[
6
]);
// Q-Q terms (m=0)
ePermCoef
=
rInvVec
[
5
]
*
(
6.0
*
(
mScale
+
bVec
[
4
])
+
fourOverFortyFive
*
(
-
3.0
+
10.0
*
alphaRVec
[
2
])
*
alphaRVec
[
5
]
*
X
);
dPermCoef
=
-
oneNinth
*
rInvVec
[
6
]
*
(
135.0
*
(
mScale
+
bVec
[
4
])
+
4.0
*
(
1.0
+
2.0
*
alphaRVec
[
2
])
*
alphaRVec
[
7
]
*
X
);
Vij
[
4
]
+=
ePermCoef
*
qiQJ
[
4
];
Vji
[
4
]
+=
ePermCoef
*
qiQI
[
4
];
VijR
[
4
]
+=
dPermCoef
*
qiQJ
[
4
];
VjiR
[
4
]
+=
dPermCoef
*
qiQI
[
4
];
// Q-Q terms (m=1)
ePermCoef
=
-
fourOverFifteen
*
rInvVec
[
5
]
*
(
15.0
*
(
mScale
+
bVec
[
4
])
+
alphaRVec
[
5
]
*
X
);
dPermCoef
=
rInvVec
[
6
]
*
(
10.0
*
(
mScale
+
bVec
[
4
])
+
fourThirds
*
alphaRVec
[
7
]
*
X
);
Vij
[
5
]
+=
ePermCoef
*
qiQJ
[
5
];
Vji
[
5
]
+=
ePermCoef
*
qiQI
[
5
];
VijR
[
5
]
+=
dPermCoef
*
qiQJ
[
5
];
VjiR
[
5
]
+=
dPermCoef
*
qiQI
[
5
];
Vij
[
6
]
+=
ePermCoef
*
qiQJ
[
6
];
Vji
[
6
]
+=
ePermCoef
*
qiQI
[
6
];
VijR
[
6
]
+=
dPermCoef
*
qiQJ
[
6
];
VjiR
[
6
]
+=
dPermCoef
*
qiQI
[
6
];
// Q-Q terms (m=2)
ePermCoef
=
rInvVec
[
5
]
*
(
mScale
+
bVec
[
4
]
-
fourOverFifteen
*
alphaRVec
[
5
]
*
X
);
dPermCoef
=
-
2.5
*
(
mScale
+
bVec
[
4
])
*
rInvVec
[
6
];
Vij
[
7
]
=
ePermCoef
*
qiQJ
[
7
];
Vji
[
7
]
=
ePermCoef
*
qiQI
[
7
];
VijR
[
7
]
=
dPermCoef
*
qiQJ
[
7
];
VjiR
[
7
]
=
dPermCoef
*
qiQI
[
7
];
Vij
[
8
]
=
ePermCoef
*
qiQJ
[
8
];
Vji
[
8
]
=
ePermCoef
*
qiQI
[
8
];
VijR
[
8
]
=
dPermCoef
*
qiQJ
[
8
];
VjiR
[
8
]
=
dPermCoef
*
qiQI
[
8
];
// Evaluate the energies, forces and torques due to permanent+induced moments
// interacting with just the permanent moments.
energy
=
0.5
*
(
qiQI
[
0
]
*
Vij
[
0
]
+
qiQJ
[
0
]
*
Vji
[
0
]);
RealOpenMM
fIZ
=
qiQI
[
0
]
*
VijR
[
0
];
RealOpenMM
fJZ
=
qiQJ
[
0
]
*
VjiR
[
0
];
RealOpenMM
EIX
=
0.0
,
EIY
=
0.0
,
EIZ
=
0.0
,
EJX
=
0.0
,
EJY
=
0.0
,
EJZ
=
0.0
;
for
(
int
i
=
1
;
i
<
9
;
++
i
){
energy
+=
0.5
*
(
qiQI
[
i
]
*
Vij
[
i
]
+
qiQJ
[
i
]
*
Vji
[
i
]);
fIZ
+=
qiQI
[
i
]
*
VijR
[
i
];
fJZ
+=
qiQJ
[
i
]
*
VjiR
[
i
];
EIX
+=
qiQIX
[
i
]
*
Vij
[
i
];
EIY
+=
qiQIY
[
i
]
*
Vij
[
i
];
EIZ
+=
qiQIZ
[
i
]
*
Vij
[
i
];
EJX
+=
qiQJX
[
i
]
*
Vji
[
i
];
EJY
+=
qiQJY
[
i
]
*
Vji
[
i
];
EJZ
+=
qiQJZ
[
i
]
*
Vji
[
i
];
}
ftm2i1 += fdir1 + findmp1;
ftm2i2 += fdir2 + findmp2;
ftm2i3 += fdir3 + findmp3;
// Define the torque intermediates for the induced dipoles. These are simply the induced dipole torque
// intermediates dotted with the field due to permanent moments only, at each center. We inline the
// induced dipole torque intermediates here, for simplicity. N.B. There are no torques on the dipoles
// themselves, so we accumulate the torque intermediates into separate variables to allow them to be
// used only in the force calculation.
//
// The torque about the x axis (needed to obtain the y force on the induced dipoles, below)
// qiUindIx[0] = qiQUindI[2]; qiUindIx[1] = 0; qiUindIx[2] = -qiQUindI[0]
RealOpenMM
iEIX
=
qiUinpI
[
2
]
*
Vijp
[
0
]
+
qiUindI
[
2
]
*
Vijd
[
0
]
-
qiUinpI
[
0
]
*
Vijp
[
2
]
-
qiUindI
[
0
]
*
Vijd
[
2
];
RealOpenMM
iEJX
=
qiUinpJ
[
2
]
*
Vjip
[
0
]
+
qiUindJ
[
2
]
*
Vjid
[
0
]
-
qiUinpJ
[
0
]
*
Vjip
[
2
]
-
qiUindJ
[
0
]
*
Vjid
[
2
];
// The torque about the y axis (needed to obtain the x force on the induced dipoles, below)
// qiUindIy[0] = -qiQUindI[1]; qiUindIy[1] = qiQUindI[0]; qiUindIy[2] = 0
RealOpenMM
iEIY
=
qiUinpI
[
0
]
*
Vijp
[
1
]
+
qiUindI
[
0
]
*
Vijd
[
1
]
-
qiUinpI
[
1
]
*
Vijp
[
0
]
-
qiUindI
[
1
]
*
Vijd
[
0
];
RealOpenMM
iEJY
=
qiUinpJ
[
0
]
*
Vjip
[
1
]
+
qiUindJ
[
0
]
*
Vjid
[
1
]
-
qiUinpJ
[
1
]
*
Vjip
[
0
]
-
qiUindJ
[
1
]
*
Vjid
[
0
];
// Add in the induced-induced terms, if needed.
if
(
getPolarizationType
()
==
AmoebaReferenceMultipoleForce
::
Mutual
){
// Uind-Uind terms (m=0)
RealOpenMM
eCoef
=
-
fourThirds
*
rInvVec
[
3
]
*
(
3.0
*
(
uScale
*
thole_d0
+
bVec
[
3
])
+
alphaRVec
[
3
]
*
X
);
RealOpenMM
dCoef
=
rInvVec
[
4
]
*
(
6.0
*
(
uScale
*
dthole_d0
+
bVec
[
3
])
+
4.0
*
alphaRVec
[
5
]
*
X
);
iEIX
+=
eCoef
*
(
qiUinpI
[
2
]
*
qiUindJ
[
0
]
+
qiUindI
[
2
]
*
qiUinpJ
[
0
]);
iEJX
+=
eCoef
*
(
qiUinpJ
[
2
]
*
qiUindI
[
0
]
+
qiUindJ
[
2
]
*
qiUinpI
[
0
]);
iEIY
-=
eCoef
*
(
qiUinpI
[
1
]
*
qiUindJ
[
0
]
+
qiUindI
[
1
]
*
qiUinpJ
[
0
]);
iEJY
-=
eCoef
*
(
qiUinpJ
[
1
]
*
qiUindI
[
0
]
+
qiUindJ
[
1
]
*
qiUinpI
[
0
]);
fIZ
+=
dCoef
*
(
qiUinpI
[
0
]
*
qiUindJ
[
0
]
+
qiUindI
[
0
]
*
qiUinpJ
[
0
]);
fIZ
+=
dCoef
*
(
qiUinpJ
[
0
]
*
qiUindI
[
0
]
+
qiUindJ
[
0
]
*
qiUinpI
[
0
]);
// Uind-Uind terms (m=1)
eCoef
=
2.0
*
rInvVec
[
3
]
*
(
uScale
*
thole_d1
+
bVec
[
3
]
-
twoThirds
*
alphaRVec
[
3
]
*
X
);
dCoef
=
-
3.0
*
rInvVec
[
4
]
*
(
uScale
*
dthole_d1
+
bVec
[
3
]);
iEIX
-=
eCoef
*
(
qiUinpI
[
0
]
*
qiUindJ
[
2
]
+
qiUindI
[
0
]
*
qiUinpJ
[
2
]);
iEJX
-=
eCoef
*
(
qiUinpJ
[
0
]
*
qiUindI
[
2
]
+
qiUindJ
[
0
]
*
qiUinpI
[
2
]);
iEIY
+=
eCoef
*
(
qiUinpI
[
0
]
*
qiUindJ
[
1
]
+
qiUindI
[
0
]
*
qiUinpJ
[
1
]);
iEJY
+=
eCoef
*
(
qiUinpJ
[
0
]
*
qiUindI
[
1
]
+
qiUindJ
[
0
]
*
qiUinpI
[
1
]);
fIZ
+=
dCoef
*
(
qiUinpI
[
1
]
*
qiUindJ
[
1
]
+
qiUindI
[
1
]
*
qiUinpJ
[
1
]
+
qiUinpI
[
2
]
*
qiUindJ
[
2
]
+
qiUindI
[
2
]
*
qiUinpJ
[
2
]);
fIZ
+=
dCoef
*
(
qiUinpJ
[
1
]
*
qiUindI
[
1
]
+
qiUindJ
[
1
]
*
qiUinpI
[
1
]
+
qiUinpJ
[
2
]
*
qiUindI
[
2
]
+
qiUindJ
[
2
]
*
qiUinpI
[
2
]);
}
// intermediate variables for induced torque terms
RealOpenMM gti2 = 0.5 * bn2 * (sci4+scip4);
RealOpenMM gti3 = 0.5 * bn2 * (sci3+scip3);
RealOpenMM gti4 = gfi4;
RealOpenMM gti5 = gfi5;
RealOpenMM gti6 = gfi6;
RealOpenMM gtri2 = 0.5 * rr5 * (sci4*psc5+scip4*dsc5);
RealOpenMM gtri3 = 0.5 * rr5 * (sci3*psc5+scip3*dsc5);
RealOpenMM gtri4 = gfri4;
RealOpenMM gtri5 = gfri5;
RealOpenMM gtri6 = gfri6;
// get the permanent torque with screening
RealOpenMM ttm21 = -bn1*dixdk1 + gf2*dixr1
+ gf4*(dixqkr1+dkxqir1+rxqidk1-2.0*qixqk1)
- gf5*rxqir1 - gf7*(rxqikr1+qkrxqir1);
RealOpenMM ttm22 = -bn1*dixdk2 + gf2*dixr2
+ gf4*(dixqkr2+dkxqir2+rxqidk2-2.0*qixqk2)
- gf5*rxqir2 - gf7*(rxqikr2+qkrxqir2);
RealOpenMM ttm23 = -bn1*dixdk3 + gf2*dixr3
+ gf4*(dixqkr3+dkxqir3+rxqidk3-2.0*qixqk3)
- gf5*rxqir3 - gf7*(rxqikr3+qkrxqir3);
RealOpenMM ttm31 = bn1*dixdk1 + gf3*dkxr1
- gf4*(dixqkr1+dkxqir1+rxqkdi1-2.0*qixqk1)
- gf6*rxqkr1 - gf7*(rxqkir1-qkrxqir1);
RealOpenMM ttm32 = bn1*dixdk2 + gf3*dkxr2
- gf4*(dixqkr2+dkxqir2+rxqkdi2-2.0*qixqk2)
- gf6*rxqkr2 - gf7*(rxqkir2-qkrxqir2);
RealOpenMM ttm33 = bn1*dixdk3 + gf3*dkxr3
- gf4*(dixqkr3+dkxqir3+rxqkdi3-2.0*qixqk3)
- gf6*rxqkr3 - gf7*(rxqkir3-qkrxqir3);
// get the permanent torque without screening
RealOpenMM ttm2r1 = -rr3*dixdk1 + gfr2*dixr1-gfr5*rxqir1
+ gfr4*(dixqkr1+dkxqir1+rxqidk1-2.0*qixqk1)
- gfr7*(rxqikr1+qkrxqir1);
RealOpenMM ttm2r2 = -rr3*dixdk2 + gfr2*dixr2-gfr5*rxqir2
+ gfr4*(dixqkr2+dkxqir2+rxqidk2-2.0*qixqk2)
- gfr7*(rxqikr2+qkrxqir2);
RealOpenMM ttm2r3 = -rr3*dixdk3 + gfr2*dixr3-gfr5*rxqir3
+ gfr4*(dixqkr3+dkxqir3+rxqidk3-2.0*qixqk3)
- gfr7*(rxqikr3+qkrxqir3);
RealOpenMM ttm3r1 = rr3*dixdk1 + gfr3*dkxr1 -gfr6*rxqkr1
- gfr4*(dixqkr1+dkxqir1+rxqkdi1-2.0*qixqk1)
- gfr7*(rxqkir1-qkrxqir1);
RealOpenMM ttm3r2 = rr3*dixdk2 + gfr3*dkxr2 -gfr6*rxqkr2
- gfr4*(dixqkr2+dkxqir2+rxqkdi2-2.0*qixqk2)
- gfr7*(rxqkir2-qkrxqir2);
RealOpenMM ttm3r3 = rr3*dixdk3 + gfr3*dkxr3 -gfr6*rxqkr3
- gfr4*(dixqkr3+dkxqir3+rxqkdi3-2.0*qixqk3)
- gfr7*(rxqkir3-qkrxqir3);
// get the induced torque with screening
RealOpenMM ttm2i1 = -bn1*(dixuk1+dixukp1)*0.5
+ gti2*dixr1 + gti4*(ukxqir1+rxqiuk1
+ ukxqirp1+rxqiukp1)*0.5 - gti5*rxqir1;
RealOpenMM ttm2i2 = -bn1*(dixuk2+dixukp2)*0.5
+ gti2*dixr2 + gti4*(ukxqir2+rxqiuk2
+ ukxqirp2+rxqiukp2)*0.5 - gti5*rxqir2;
RealOpenMM ttm2i3 = -bn1*(dixuk3+dixukp3)*0.5
+ gti2*dixr3 + gti4*(ukxqir3+rxqiuk3
+ ukxqirp3+rxqiukp3)*0.5 - gti5*rxqir3;
RealOpenMM ttm3i1 = -bn1*(dkxui1+dkxuip1)*0.5
+ gti3*dkxr1 - gti4*(uixqkr1+rxqkui1
+ uixqkrp1+rxqkuip1)*0.5 - gti6*rxqkr1;
RealOpenMM ttm3i2 = -bn1*(dkxui2+dkxuip2)*0.5
+ gti3*dkxr2 - gti4*(uixqkr2+rxqkui2
+ uixqkrp2+rxqkuip2)*0.5 - gti6*rxqkr2;
RealOpenMM ttm3i3 = -bn1*(dkxui3+dkxuip3)*0.5
+ gti3*dkxr3 - gti4*(uixqkr3+rxqkui3
+ uixqkrp3+rxqkuip3)*0.5 - gti6*rxqkr3;
// get the induced torque without screening
RealOpenMM ttm2ri1 = -rr3*(dixuk1*psc3+dixukp1*dsc3)*0.5
+ gtri2*dixr1 + gtri4*((ukxqir1+rxqiuk1)*psc5
+(ukxqirp1+rxqiukp1)*dsc5)*0.5 - gtri5*rxqir1;
RealOpenMM ttm2ri2 = -rr3*(dixuk2*psc3+dixukp2*dsc3)*0.5
+ gtri2*dixr2 + gtri4*((ukxqir2+rxqiuk2)*psc5
+(ukxqirp2+rxqiukp2)*dsc5)*0.5 - gtri5*rxqir2;
RealOpenMM ttm2ri3 = -rr3*(dixuk3*psc3+dixukp3*dsc3)*0.5
+ gtri2*dixr3 + gtri4*((ukxqir3+rxqiuk3)*psc5
+(ukxqirp3+rxqiukp3)*dsc5)*0.5 - gtri5*rxqir3;
RealOpenMM ttm3ri1 = -rr3*(dkxui1*psc3+dkxuip1*dsc3)*0.5
+ gtri3*dkxr1 - gtri4*((uixqkr1+rxqkui1)*psc5
+(uixqkrp1+rxqkuip1)*dsc5)*0.5 - gtri6*rxqkr1;
RealOpenMM ttm3ri2 = -rr3*(dkxui2*psc3+dkxuip2*dsc3)*0.5
+ gtri3*dkxr2 - gtri4*((uixqkr2+rxqkui2)*psc5
+(uixqkrp2+rxqkuip2)*dsc5)*0.5 - gtri6*rxqkr2;
RealOpenMM ttm3ri3 = -rr3*(dkxui3*psc3+dkxuip3*dsc3)*0.5
+ gtri3*dkxr3 - gtri4*((uixqkr3+rxqkui3)*psc5
+(uixqkrp3+rxqkuip3)*dsc5)*0.5 - gtri6*rxqkr3;
// handle the case where scaling is used
ftm21 = (ftm21-(1.0-scalingFactors[M_SCALE])*ftm2r1);
ftm2i1 = (ftm2i1-ftm2ri1);
ttm21 = (ttm21-(1.0-scalingFactors[M_SCALE])*ttm2r1);
ttm2i1 = (ttm2i1-ttm2ri1);
ttm31 = (ttm31-(1.0-scalingFactors[M_SCALE])*ttm3r1);
ttm3i1 = (ttm3i1-ttm3ri1);
ftm22 = (ftm22-(1.0-scalingFactors[M_SCALE])*ftm2r2);
ftm2i2 = (ftm2i2-ftm2ri2);
ttm22 = (ttm22-(1.0-scalingFactors[M_SCALE])*ttm2r2);
ttm2i2 = (ttm2i2-ttm2ri2);
ttm32 = (ttm32-(1.0-scalingFactors[M_SCALE])*ttm3r2);
ttm3i2 = (ttm3i2-ttm3ri2);
ftm23 = (ftm23-(1.0-scalingFactors[M_SCALE])*ftm2r3);
ftm2i3 = (ftm2i3-ftm2ri3);
ttm23 = (ttm23-(1.0-scalingFactors[M_SCALE])*ttm2r3);
ttm2i3 = (ttm2i3-ttm2ri3);
ttm33 = (ttm33-(1.0-scalingFactors[M_SCALE])*ttm3r3);
ttm3i3 = (ttm3i3-ttm3ri3);
// increment gradient due to force and torque on first site;
RealOpenMM conversionFactor = (_electric/_dielectric);
energy *= conversionFactor;
forces[iIndex][0] -= (ftm21 + ftm2i1)*conversionFactor;
forces[iIndex][1] -= (ftm22 + ftm2i2)*conversionFactor;
forces[iIndex][2] -= (ftm23 + ftm2i3)*conversionFactor;
forces[jIndex][0] += (ftm21 + ftm2i1)*conversionFactor;
forces[jIndex][1] += (ftm22 + ftm2i2)*conversionFactor;
forces[jIndex][2] += (ftm23 + ftm2i3)*conversionFactor;
torques[iIndex][0] += (ttm21 + ttm2i1)*conversionFactor;
torques[iIndex][1] += (ttm22 + ttm2i2)*conversionFactor;
torques[iIndex][2] += (ttm23 + ttm2i3)*conversionFactor;
torques[jIndex][0] += (ttm31 + ttm3i1)*conversionFactor;
torques[jIndex][1] += (ttm32 + ttm3i2)*conversionFactor;
torques[jIndex][2] += (ttm33 + ttm3i3)*conversionFactor;
// The quasi-internal frame forces and torques. Note that the induced torque intermediates are
// used in the force expression, but not in the torques; the induced dipoles are isotropic.
RealOpenMM
qiForce
[
3
]
=
{
rInv
*
(
EIY
+
EJY
+
iEIY
+
iEJY
),
-
rInv
*
(
EIX
+
EJX
+
iEIX
+
iEJX
),
-
(
fJZ
+
fIZ
)};
RealOpenMM
qiTorqueI
[
3
]
=
{
-
EIX
,
-
EIY
,
-
EIZ
};
RealOpenMM
qiTorqueJ
[
3
]
=
{
-
EJX
,
-
EJY
,
-
EJZ
};
// Rotate the forces and torques back to the lab frame
for
(
int
ii
=
0
;
ii
<
3
;
ii
++
)
{
RealOpenMM
forceVal
=
0.0
;
RealOpenMM
torqueIVal
=
0.0
;
RealOpenMM
torqueJVal
=
0.0
;
for
(
int
jj
=
0
;
jj
<
3
;
jj
++
)
{
forceVal
+=
forceRotationMatrix
[
ii
][
jj
]
*
qiForce
[
jj
];
torqueIVal
+=
forceRotationMatrix
[
ii
][
jj
]
*
qiTorqueI
[
jj
];
torqueJVal
+=
forceRotationMatrix
[
ii
][
jj
]
*
qiTorqueJ
[
jj
];
}
torques
[
iIndex
][
ii
]
+=
torqueIVal
;
torques
[
jIndex
][
ii
]
+=
torqueJVal
;
forces
[
iIndex
][
ii
]
-=
forceVal
;
forces
[
jIndex
][
ii
]
+=
forceVal
;
}
return
energy
;
}
...
...
@@ -6616,6 +6508,6 @@ RealOpenMM AmoebaReferencePmeMultipoleForce::calculateElectrostatic(const vector
energy
+=
computeReciprocalSpaceInducedDipoleForceAndEnergy
(
getPolarizationType
(),
particleData
,
forces
,
torques
);
energy
+=
computeReciprocalSpaceFixedMultipoleForceAndEnergy
(
particleData
,
forces
,
torques
);
energy
+=
calculatePmeSelfEnergy
(
particleData
);
return
energy
;
}
plugins/amoeba/platforms/reference/src/SimTKReference/AmoebaReferenceMultipoleForce.h
View file @
b7088b74
...
...
@@ -37,6 +37,20 @@ typedef std::map< unsigned int, RealOpenMM> MapIntRealOpenMM;
typedef
MapIntRealOpenMM
::
iterator
MapIntRealOpenMMI
;
typedef
MapIntRealOpenMM
::
const_iterator
MapIntRealOpenMMCI
;
// A few useful constants for the spherical harmonic multipole code.
const
RealOpenMM
oneThird
=
1.0
/
3.0
;
const
RealOpenMM
twoThirds
=
2.0
/
3.0
;
const
RealOpenMM
fourThirds
=
4.0
/
3.0
;
const
RealOpenMM
fourSqrtOneThird
=
4.0
/
sqrt
(
3.0
);
const
RealOpenMM
sqrtFourThirds
=
2.0
/
sqrt
(
3.0
);
const
RealOpenMM
sqrtOneThird
=
1.0
/
sqrt
(
3.0
);
const
RealOpenMM
sqrtThree
=
sqrt
(
3.0
);
const
RealOpenMM
oneNinth
=
1.0
/
9.0
;
const
RealOpenMM
fourOverFortyFive
=
4.0
/
45.0
;
const
RealOpenMM
fourOverFifteen
=
4.0
/
15.0
;
/**
* 2-dimensional int vector
*/
...
...
@@ -589,6 +603,8 @@ protected:
RealOpenMM
charge
;
RealVec
dipole
;
RealOpenMM
quadrupole
[
6
];
RealVec
sphericalDipole
;
RealOpenMM
sphericalQuadrupole
[
5
];
RealOpenMM
thole
;
RealOpenMM
dampingFactor
;
RealOpenMM
polarity
;
...
...
@@ -795,6 +811,41 @@ protected:
const
MultipoleParticleData
&
particleX
,
MultipoleParticleData
*
particleY
,
int
axisType
)
const
;
/**
* Forms the rotation matrix for the quasi-internal coordinate system,
* which is the rotation matrix that describes the orientation of the
* internuclear vector for a given pair (I,J) in lab frame.
*
* @param particleI particleI position
* @param particleJ particleJ position
* @param deltaR the internuclear vector, corrected for periodic boundary conditions
* @param r the bond length between atoms I and J
* @param rotationmatrix the output rotation matrix for a 3-vector
*/
void
formQIRotationMatrix
(
const
RealVec
&
iPosition
,
const
RealVec
&
jPosition
,
const
RealVec
&
deltaR
,
RealOpenMM
r
,
RealOpenMM
(
&
rotationMatrix
)[
3
][
3
])
const
;
/**
* Constructs a rotation matrix for spherical harmonic quadrupoles, using the dipole rotation matrix.
*
* @param D1 The input spherical harmonic dipole rotation matrix
* @param D2 The output spherical harmonic quadrupole rotation matrix
*/
void
buildSphericalQuadrupoleRotationMatrix
(
const
RealOpenMM
(
&
D1
)[
3
][
3
],
RealOpenMM
(
&
D2
)[
5
][
5
])
const
;
/**
* Constructs a rotation matrix for spherical harmonic quadrupoles, using the dipole rotation matrix.
* Only the m={0,1c,1s} terms are constructed; these are the only terms needed to evaluate the field.
*
* @param D1 The input spherical harmonic dipole rotation matrix
* @param D2 The output spherical harmonic quadrupole rotation matrix
*/
void
buildPartialSphericalQuadrupoleRotationMatrix
(
const
RealOpenMM
(
&
D1
)[
3
][
3
],
RealOpenMM
(
&
D2
)[
3
][
5
])
const
;
/**
* Apply rotation matrix to molecular dipole/quadrupoles to get corresponding lab frame values.
*
...
...
plugins/amoeba/platforms/reference/tests/CMakeLists.txt
View file @
b7088b74
...
...
@@ -12,7 +12,7 @@ FOREACH(TEST_PROG ${TEST_PROGS})
# Link with shared library
ADD_EXECUTABLE
(
${
TEST_ROOT
}
${
TEST_PROG
}
)
TARGET_LINK_LIBRARIES
(
${
TEST_ROOT
}
${
SHARED_AMOEBA_TARGET
}
${
SHARED_TARGET
}
)
SET_TARGET_PROPERTIES
(
${
TEST_ROOT
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
COMPILE
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
"
)
SET_TARGET_PROPERTIES
(
${
TEST_ROOT
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
LINK
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
"
)
ADD_TEST
(
${
TEST_ROOT
}
${
EXECUTABLE_OUTPUT_PATH
}
/
${
TEST_ROOT
}
)
ENDFOREACH
(
TEST_PROG
${
TEST_PROGS
}
)
plugins/amoeba/platforms/reference/tests/TestReferenceAmoebaGeneralizedKirkwoodForce.cpp
View file @
b7088b74
...
...
@@ -6983,7 +6983,7 @@ static void compareForcesEnergy(std::string& testName, double expectedEnergy, do
const std::vector<Vec3>& forces, double tolerance) {
for (unsigned int ii = 0; ii < forces.size(); ii++) {
ASSERT_EQUAL_VEC
_MOD
(expectedForces[ii], forces[ii], tolerance
, testName
);
ASSERT_EQUAL_VEC(expectedForces[ii], forces[ii], tolerance);
}
ASSERT_EQUAL_TOL_MOD(expectedEnergy, energy, tolerance, testName);
}
...
...
plugins/amoeba/serialization/tests/CMakeLists.txt
View file @
b7088b74
...
...
@@ -12,7 +12,7 @@ FOREACH(TEST_PROG ${TEST_PROGS})
# All tests use shared libraries
ADD_EXECUTABLE
(
${
TEST_ROOT
}
${
TEST_PROG
}
)
TARGET_LINK_LIBRARIES
(
${
TEST_ROOT
}
${
SHARED_AMOEBA_TARGET
}
)
SET_TARGET_PROPERTIES
(
${
TEST_ROOT
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
COMPILE
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
"
)
SET_TARGET_PROPERTIES
(
${
TEST_ROOT
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
LINK
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
"
)
ADD_TEST
(
${
TEST_ROOT
}
${
EXECUTABLE_OUTPUT_PATH
}
/
${
TEST_ROOT
}
)
ENDFOREACH
(
TEST_PROG
${
TEST_PROGS
}
)
plugins/cpupme/CMakeLists.txt
View file @
b7088b74
...
...
@@ -75,7 +75,7 @@ IF (OPENMM_BUILD_SHARED_LIB)
IF
(
FFTW_THREADS_LIBRARY
)
TARGET_LINK_LIBRARIES
(
${
SHARED_TARGET
}
${
FFTW_THREADS_LIBRARY
}
)
ENDIF
(
FFTW_THREADS_LIBRARY
)
SET_TARGET_PROPERTIES
(
${
SHARED_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
COMPILE
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
-DOPENMM_PME_BUILDING_SHARED_LIBRARY"
)
SET_TARGET_PROPERTIES
(
${
SHARED_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
LINK
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
-DOPENMM_PME_BUILDING_SHARED_LIBRARY"
)
INSTALL_TARGETS
(
/lib/plugins RUNTIME_DIRECTORY /lib/plugins
${
SHARED_TARGET
}
)
ENDIF
(
OPENMM_BUILD_SHARED_LIB
)
...
...
@@ -88,7 +88,7 @@ IF(OPENMM_BUILD_STATIC_LIB)
IF
(
FFTW_THREADS_LIBRARY
)
TARGET_LINK_LIBRARIES
(
${
STATIC_TARGET
}
${
FFTW_THREADS_LIBRARY
}
)
ENDIF
(
FFTW_THREADS_LIBRARY
)
SET_TARGET_PROPERTIES
(
${
STATIC_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
COMPILE
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
-DOPENMM_PME_BUILDING_STATIC_LIBRARY"
)
SET_TARGET_PROPERTIES
(
${
STATIC_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
LINK
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
-DOPENMM_PME_BUILDING_STATIC_LIBRARY"
)
INSTALL_TARGETS
(
/lib/plugins RUNTIME_DIRECTORY /lib/plugins
${
STATIC_TARGET
}
)
ENDIF
(
OPENMM_BUILD_STATIC_LIB
)
...
...
plugins/cpupme/src/CpuPmeKernels.cpp
View file @
b7088b74
...
...
@@ -335,21 +335,19 @@ static void interpolateForces(int start, int end, float* posq, float* force, flo
}
}
class
CpuCalcPmeReciprocalForceKernel
::
ThreadData
{
class
CpuCalcPmeReciprocalForceKernel
::
ComputeTask
:
public
ThreadPool
::
Task
{
public:
CpuCalcPmeReciprocalForceKernel
&
owner
;
int
index
;
float
*
tempGrid
;
ThreadData
(
CpuCalcPmeReciprocalForceKernel
&
owner
,
int
index
)
:
owner
(
owner
),
index
(
index
),
tempGrid
(
NULL
)
{
ComputeTask
(
CpuCalcPmeReciprocalForceKernel
&
owner
)
:
owner
(
owner
)
{
}
void
execute
(
ThreadPool
&
threads
,
int
threadIndex
)
{
owner
.
runWorkerThread
(
threads
,
threadIndex
);
}
CpuCalcPmeReciprocalForceKernel
&
owner
;
};
static
void
*
threadBody
(
void
*
args
)
{
CpuCalcPmeReciprocalForceKernel
::
ThreadData
&
data
=
*
reinterpret_cast
<
CpuCalcPmeReciprocalForceKernel
::
ThreadData
*>
(
args
);
data
.
owner
.
runThread
(
data
.
index
);
if
(
data
.
tempGrid
!=
NULL
)
fftwf_free
(
data
.
tempGrid
);
delete
&
data
;
CpuCalcPmeReciprocalForceKernel
&
owner
=
*
reinterpret_cast
<
CpuCalcPmeReciprocalForceKernel
*>
(
args
);
owner
.
runMainThread
();
return
0
;
}
...
...
@@ -362,6 +360,7 @@ void CpuCalcPmeReciprocalForceKernel::initialize(int xsize, int ysize, int zsize
fftwf_init_threads
();
hasInitializedThreads
=
true
;
}
threadEnergy
.
resize
(
numThreads
);
gridx
=
findFFTDimension
(
xsize
,
false
);
gridy
=
findFFTDimension
(
ysize
,
false
);
gridz
=
findFFTDimension
(
zsize
,
true
);
...
...
@@ -372,23 +371,24 @@ void CpuCalcPmeReciprocalForceKernel::initialize(int xsize, int ysize, int zsize
// Initialize threads.
isFinished
=
false
;
pthread_cond_init
(
&
startCondition
,
NULL
);
pthread_cond_init
(
&
endCondition
,
NULL
);
pthread_cond_init
(
&
mainThreadStartCondition
,
NULL
);
pthread_cond_init
(
&
mainThreadEndCondition
,
NULL
);
pthread_mutex_init
(
&
lock
,
NULL
);
thread
.
resize
(
numThread
s
);
for
(
int
i
=
0
;
i
<
numThreads
;
i
++
)
{
ThreadData
*
data
=
new
ThreadData
(
*
this
,
i
);
threadData
.
push_back
(
data
);
pthread_
create
(
&
thread
[
i
],
NULL
,
threadBody
,
data
);
data
->
tempGrid
=
(
float
*
)
fftwf_malloc
(
sizeof
(
float
)
*
(
gridx
*
gridy
*
gridz
+
3
));
}
pthread_
create
(
&
mainThread
,
NULL
,
threadBody
,
new
ThreadData
(
*
this
,
-
1
)
);
p
thread
_create
(
&
mainThread
,
NULL
,
threadBody
,
thi
s
);
// Wait until the main thread is up and running.
pthread_
mutex_lock
(
&
lock
);
while
(
!
isFinished
)
pthread_cond_wait
(
&
endCondition
,
&
lock
);
pthread_
mutex_unlock
(
&
lock
);
// Initialize FFTW.
realGrid
=
threadData
[
0
]
->
tempGrid
;
for
(
int
i
=
0
;
i
<
numThreads
;
i
++
)
tempGrid
.
push_back
((
float
*
)
fftwf_malloc
(
sizeof
(
float
)
*
(
gridx
*
gridy
*
gridz
+
3
)));
realGrid
=
tempGrid
[
0
];
complexGrid
=
(
fftwf_complex
*
)
fftwf_malloc
(
sizeof
(
fftwf_complex
)
*
gridx
*
gridy
*
(
gridz
/
2
+
1
));
fftwf_plan_with_nthreads
(
numThreads
);
forwardFFT
=
fftwf_plan_dft_r2c_3d
(
gridx
,
gridy
,
gridz
,
realGrid
,
complexGrid
,
FFTW_MEASURE
);
...
...
@@ -455,16 +455,13 @@ CpuCalcPmeReciprocalForceKernel::~CpuCalcPmeReciprocalForceKernel() {
isDeleted
=
true
;
pthread_mutex_lock
(
&
lock
);
pthread_cond_broadcast
(
&
startCondition
);
pthread_cond_broadcast
(
&
mainThreadStartCondition
);
pthread_mutex_unlock
(
&
lock
);
for
(
int
i
=
0
;
i
<
(
int
)
thread
.
size
();
i
++
)
pthread_join
(
thread
[
i
],
NULL
);
pthread_join
(
mainThread
,
NULL
);
pthread_mutex_destroy
(
&
lock
);
pthread_cond_destroy
(
&
startCondition
);
pthread_cond_destroy
(
&
endCondition
);
pthread_cond_destroy
(
&
mainThreadStartCondition
);
pthread_cond_destroy
(
&
mainThreadEndCondition
);
for
(
int
i
=
0
;
i
<
(
int
)
tempGrid
.
size
();
i
++
)
fftwf_free
(
tempGrid
[
i
]
);
if
(
complexGrid
!=
NULL
)
fftwf_free
(
complexGrid
);
if
(
hasCreatedPlan
)
{
...
...
@@ -473,92 +470,79 @@ CpuCalcPmeReciprocalForceKernel::~CpuCalcPmeReciprocalForceKernel() {
}
}
void
CpuCalcPmeReciprocalForceKernel
::
runThread
(
int
index
)
{
if
(
index
==
-
1
)
{
// This is the main thread that coordinates all the other ones.
pthread_mutex_lock
(
&
lock
);
while
(
true
)
{
// Wait for the signal to start.
pthread_cond_wait
(
&
mainThreadStartCondition
,
&
lock
);
if
(
isDeleted
)
break
;
posq
=
io
->
getPosq
();
advanceThreads
();
// Signal threads to perform charge spreading.
advanceThreads
();
// Signal threads to sum the charge grids.
fftwf_execute_dft_r2c
(
forwardFFT
,
realGrid
,
complexGrid
);
if
(
lastBoxVectors
[
0
]
!=
periodicBoxVectors
[
0
]
||
lastBoxVectors
[
1
]
!=
periodicBoxVectors
[
1
]
||
lastBoxVectors
[
2
]
!=
periodicBoxVectors
[
2
])
advanceThreads
();
// Signal threads to compute the reciprocal scale factors.
if
(
includeEnergy
)
advanceThreads
();
// Signal threads to compute energy.
advanceThreads
();
// Signal threads to perform reciprocal convolution.
fftwf_execute_dft_c2r
(
backwardFFT
,
complexGrid
,
realGrid
);
advanceThreads
();
// Signal threads to interpolate forces.
isFinished
=
true
;
lastBoxVectors
[
0
]
=
periodicBoxVectors
[
0
];
lastBoxVectors
[
1
]
=
periodicBoxVectors
[
1
];
lastBoxVectors
[
2
]
=
periodicBoxVectors
[
2
];
pthread_cond_signal
(
&
mainThreadEndCondition
);
}
pthread_mutex_unlock
(
&
lock
);
}
else
{
// This is a worker thread.
int
particleStart
=
(
index
*
numParticles
)
/
numThreads
;
int
particleEnd
=
((
index
+
1
)
*
numParticles
)
/
numThreads
;
int
gridxStart
=
(
index
*
gridx
)
/
numThreads
;
int
gridxEnd
=
((
index
+
1
)
*
gridx
)
/
numThreads
;
int
gridSize
=
(
gridx
*
gridy
*
gridz
+
3
)
/
4
;
int
gridStart
=
4
*
((
index
*
gridSize
)
/
numThreads
);
int
gridEnd
=
4
*
(((
index
+
1
)
*
gridSize
)
/
numThreads
);
while
(
true
)
{
threadWait
();
if
(
isDeleted
)
break
;
spreadCharge
(
particleStart
,
particleEnd
,
posq
,
threadData
[
index
]
->
tempGrid
,
gridx
,
gridy
,
gridz
,
numParticles
,
periodicBoxVectors
,
recipBoxVectors
);
threadWait
();
int
numGrids
=
threadData
.
size
();
for
(
int
i
=
gridStart
;
i
<
gridEnd
;
i
+=
4
)
{
fvec4
sum
(
&
realGrid
[
i
]);
for
(
int
j
=
1
;
j
<
numGrids
;
j
++
)
sum
+=
fvec4
(
&
threadData
[
j
]
->
tempGrid
[
i
]);
sum
.
store
(
&
realGrid
[
i
]);
}
threadWait
();
if
(
lastBoxVectors
[
0
]
!=
periodicBoxVectors
[
0
]
||
lastBoxVectors
[
1
]
!=
periodicBoxVectors
[
1
]
||
lastBoxVectors
[
2
]
!=
periodicBoxVectors
[
2
])
{
computeReciprocalEterm
(
gridxStart
,
gridxEnd
,
gridx
,
gridy
,
gridz
,
recipEterm
,
alpha
,
bsplineModuli
,
periodicBoxVectors
,
recipBoxVectors
);
threadWait
();
}
if
(
includeEnergy
)
{
double
threadEnergy
=
reciprocalEnergy
(
gridxStart
,
gridxEnd
,
complexGrid
,
gridx
,
gridy
,
gridz
,
alpha
,
bsplineModuli
,
periodicBoxVectors
,
recipBoxVectors
);
pthread_mutex_lock
(
&
lock
);
energy
+=
threadEnergy
;
pthread_mutex_unlock
(
&
lock
);
threadWait
();
}
reciprocalConvolution
(
gridxStart
,
gridxEnd
,
complexGrid
,
gridx
,
gridy
,
gridz
,
recipEterm
);
threadWait
();
interpolateForces
(
particleStart
,
particleEnd
,
posq
,
&
force
[
0
],
realGrid
,
gridx
,
gridy
,
gridz
,
numParticles
,
periodicBoxVectors
,
recipBoxVectors
);
}
}
}
void
CpuCalcPmeReciprocalForceKernel
::
runMainThread
()
{
// This is the main thread that coordinates all the other ones.
void
CpuCalcPmeReciprocalForceKernel
::
threadWait
()
{
pthread_mutex_lock
(
&
lock
);
waitCount
++
;
isFinished
=
true
;
pthread_cond_signal
(
&
endCondition
);
pthread_cond_wait
(
&
startCondition
,
&
lock
);
ThreadPool
threads
(
numThreads
);
while
(
true
)
{
// Wait for the signal to start.
pthread_cond_wait
(
&
startCondition
,
&
lock
);
if
(
isDeleted
)
break
;
posq
=
io
->
getPosq
();
ComputeTask
task
(
*
this
);
threads
.
execute
(
task
);
// Signal threads to perform charge spreading.
threads
.
waitForThreads
();
threads
.
resumeThreads
();
// Signal threads to sum the charge grids.
threads
.
waitForThreads
();
fftwf_execute_dft_r2c
(
forwardFFT
,
realGrid
,
complexGrid
);
if
(
lastBoxVectors
[
0
]
!=
periodicBoxVectors
[
0
]
||
lastBoxVectors
[
1
]
!=
periodicBoxVectors
[
1
]
||
lastBoxVectors
[
2
]
!=
periodicBoxVectors
[
2
])
{
threads
.
resumeThreads
();
// Signal threads to compute the reciprocal scale factors.
threads
.
waitForThreads
();
}
if
(
includeEnergy
)
{
threads
.
resumeThreads
();
// Signal threads to compute energy.
threads
.
waitForThreads
();
for
(
int
i
=
0
;
i
<
(
int
)
threadEnergy
.
size
();
i
++
)
energy
+=
threadEnergy
[
i
];
}
threads
.
resumeThreads
();
// Signal threads to perform reciprocal convolution.
threads
.
waitForThreads
();
fftwf_execute_dft_c2r
(
backwardFFT
,
complexGrid
,
realGrid
);
threads
.
resumeThreads
();
// Signal threads to interpolate forces.
threads
.
waitForThreads
();
isFinished
=
true
;
lastBoxVectors
[
0
]
=
periodicBoxVectors
[
0
];
lastBoxVectors
[
1
]
=
periodicBoxVectors
[
1
];
lastBoxVectors
[
2
]
=
periodicBoxVectors
[
2
];
pthread_cond_signal
(
&
endCondition
);
}
pthread_mutex_unlock
(
&
lock
);
}
void
CpuCalcPmeReciprocalForceKernel
::
advanceThreads
()
{
waitCount
=
0
;
pthread_cond_broadcast
(
&
startCondition
);
while
(
waitCount
<
numThreads
)
{
pthread_cond_wait
(
&
endCondition
,
&
lock
);
void
CpuCalcPmeReciprocalForceKernel
::
runWorkerThread
(
ThreadPool
&
threads
,
int
index
)
{
int
particleStart
=
(
index
*
numParticles
)
/
numThreads
;
int
particleEnd
=
((
index
+
1
)
*
numParticles
)
/
numThreads
;
int
gridxStart
=
(
index
*
gridx
)
/
numThreads
;
int
gridxEnd
=
((
index
+
1
)
*
gridx
)
/
numThreads
;
int
gridSize
=
(
gridx
*
gridy
*
gridz
+
3
)
/
4
;
int
gridStart
=
4
*
((
index
*
gridSize
)
/
numThreads
);
int
gridEnd
=
4
*
(((
index
+
1
)
*
gridSize
)
/
numThreads
);
spreadCharge
(
particleStart
,
particleEnd
,
posq
,
tempGrid
[
index
],
gridx
,
gridy
,
gridz
,
numParticles
,
periodicBoxVectors
,
recipBoxVectors
);
threads
.
syncThreads
();
int
numGrids
=
tempGrid
.
size
();
for
(
int
i
=
gridStart
;
i
<
gridEnd
;
i
+=
4
)
{
fvec4
sum
(
&
realGrid
[
i
]);
for
(
int
j
=
1
;
j
<
numGrids
;
j
++
)
sum
+=
fvec4
(
&
tempGrid
[
j
][
i
]);
sum
.
store
(
&
realGrid
[
i
]);
}
threads
.
syncThreads
();
if
(
lastBoxVectors
[
0
]
!=
periodicBoxVectors
[
0
]
||
lastBoxVectors
[
1
]
!=
periodicBoxVectors
[
1
]
||
lastBoxVectors
[
2
]
!=
periodicBoxVectors
[
2
])
{
computeReciprocalEterm
(
gridxStart
,
gridxEnd
,
gridx
,
gridy
,
gridz
,
recipEterm
,
alpha
,
bsplineModuli
,
periodicBoxVectors
,
recipBoxVectors
);
threads
.
syncThreads
();
}
if
(
includeEnergy
)
{
threadEnergy
[
index
]
=
reciprocalEnergy
(
gridxStart
,
gridxEnd
,
complexGrid
,
gridx
,
gridy
,
gridz
,
alpha
,
bsplineModuli
,
periodicBoxVectors
,
recipBoxVectors
);
threads
.
syncThreads
();
}
reciprocalConvolution
(
gridxStart
,
gridxEnd
,
complexGrid
,
gridx
,
gridy
,
gridz
,
recipEterm
);
threads
.
syncThreads
();
interpolateForces
(
particleStart
,
particleEnd
,
posq
,
&
force
[
0
],
realGrid
,
gridx
,
gridy
,
gridz
,
numParticles
,
periodicBoxVectors
,
recipBoxVectors
);
}
void
CpuCalcPmeReciprocalForceKernel
::
beginComputation
(
IO
&
io
,
const
Vec3
*
periodicBoxVectors
,
bool
includeEnergy
)
{
...
...
@@ -581,14 +565,14 @@ void CpuCalcPmeReciprocalForceKernel::beginComputation(IO& io, const Vec3* perio
pthread_mutex_lock
(
&
lock
);
isFinished
=
false
;
pthread_cond_signal
(
&
mainThreadS
tartCondition
);
pthread_cond_signal
(
&
s
tartCondition
);
pthread_mutex_unlock
(
&
lock
);
}
double
CpuCalcPmeReciprocalForceKernel
::
finishComputation
(
IO
&
io
)
{
pthread_mutex_lock
(
&
lock
);
while
(
!
isFinished
)
{
pthread_cond_wait
(
&
mainThreadE
ndCondition
,
&
lock
);
pthread_cond_wait
(
&
e
ndCondition
,
&
lock
);
}
pthread_mutex_unlock
(
&
lock
);
io
.
setForce
(
&
force
[
0
]);
...
...
plugins/cpupme/src/CpuPmeKernels.h
View file @
b7088b74
...
...
@@ -36,6 +36,7 @@
#include "internal/windowsExportPme.h"
#include "openmm/kernels.h"
#include "openmm/Vec3.h"
#include "openmm/internal/ThreadPool.h"
#include <fftw3.h>
#include <pthread.h>
#include <vector>
...
...
@@ -49,7 +50,6 @@ namespace OpenMM {
class
OPENMM_EXPORT_PME
CpuCalcPmeReciprocalForceKernel
:
public
CalcPmeReciprocalForceKernel
{
public:
class
ThreadData
;
CpuCalcPmeReciprocalForceKernel
(
std
::
string
name
,
const
Platform
&
platform
)
:
CalcPmeReciprocalForceKernel
(
name
,
platform
),
hasCreatedPlan
(
false
),
isDeleted
(
false
),
realGrid
(
NULL
),
complexGrid
(
NULL
)
{
}
...
...
@@ -80,22 +80,19 @@ public:
*/
double
finishComputation
(
IO
&
io
);
/**
* This routine contains the code executed by
each
thread.
* This routine contains the code executed by
the main
thread.
*/
void
runThread
(
int
index
);
void
runMainThread
();
/**
* This routine contains the code executed by each worker thread.
*/
void
runWorkerThread
(
ThreadPool
&
threads
,
int
index
);
/**
* Get whether the current CPU supports all features needed by this kernel.
*/
static
bool
isProcessorSupported
();
private:
/**
* This is called by the worker threads to wait until the master thread instructs them to advance.
*/
void
threadWait
();
/**
* This is called by the master thread to instruct all the worker threads to advance.
*/
void
advanceThreads
();
class
ComputeTask
;
/**
* Select a size for one grid dimension that FFTW can handle efficiently.
*/
...
...
@@ -109,16 +106,15 @@ private:
std
::
vector
<
float
>
bsplineModuli
[
3
];
std
::
vector
<
float
>
recipEterm
;
Vec3
lastBoxVectors
[
3
];
std
::
vector
<
float
>
threadEnergy
;
std
::
vector
<
float
*>
tempGrid
;
float
*
realGrid
;
fftwf_complex
*
complexGrid
;
fftwf_plan
forwardFFT
,
backwardFFT
;
int
waitCount
;
pthread_cond_t
startCondition
,
endCondition
;
pthread_cond_t
mainThreadStartCondition
,
mainThreadEndCondition
;
pthread_mutex_t
lock
;
pthread_t
mainThread
;
std
::
vector
<
pthread_t
>
thread
;
std
::
vector
<
ThreadData
*>
threadData
;
// The following variables are used to store information about the calculation currently being performed.
IO
*
io
;
float
energy
;
...
...
plugins/cpupme/tests/CMakeLists.txt
View file @
b7088b74
...
...
@@ -13,6 +13,6 @@ FOREACH(TEST_PROG ${TEST_PROGS})
ELSE
(
OPENMM_BUILD_SHARED_LIB
)
TARGET_LINK_LIBRARIES
(
${
TEST_ROOT
}
${
STATIC_TARGET
}
${
OPENMM_LIBRARY_NAME
}
_static
)
ENDIF
(
OPENMM_BUILD_SHARED_LIB
)
SET_TARGET_PROPERTIES
(
${
TEST_ROOT
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
COMPILE
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
"
)
SET_TARGET_PROPERTIES
(
${
TEST_ROOT
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
LINK
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
"
)
ADD_TEST
(
${
TEST_ROOT
}
${
EXECUTABLE_OUTPUT_PATH
}
/
${
TEST_ROOT
}
)
ENDFOREACH
(
TEST_PROG
${
TEST_PROGS
}
)
plugins/cudacompiler/CMakeLists.txt
View file @
b7088b74
...
...
@@ -74,7 +74,7 @@ IF (OPENMM_BUILD_SHARED_LIB)
IF
(
APPLE
)
SET_TARGET_PROPERTIES
(
${
SHARED_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
-F/Library/Frameworks -framework CUDA"
)
ELSE
(
APPLE
)
SET_TARGET_PROPERTIES
(
${
SHARED_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
COMPILE
_FLAGS
}
"
)
SET_TARGET_PROPERTIES
(
${
SHARED_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
LINK
_FLAGS
}
"
)
ENDIF
(
APPLE
)
INSTALL_TARGETS
(
/lib/plugins RUNTIME_DIRECTORY /lib/plugins
${
SHARED_TARGET
}
)
...
...
@@ -91,7 +91,7 @@ IF(OPENMM_BUILD_STATIC_LIB)
IF
(
APPLE
)
SET_TARGET_PROPERTIES
(
${
STATIC_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
-F/Library/Frameworks -framework CUDA"
)
ELSE
(
APPLE
)
SET_TARGET_PROPERTIES
(
${
STATIC_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
COMPILE
_FLAGS
}
"
)
SET_TARGET_PROPERTIES
(
${
STATIC_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
LINK
_FLAGS
}
"
)
ENDIF
(
APPLE
)
INSTALL_TARGETS
(
/lib/plugins RUNTIME_DIRECTORY /lib/plugins
${
STATIC_TARGET
}
)
...
...
plugins/cudacompiler/tests/CMakeLists.txt
View file @
b7088b74
...
...
@@ -17,7 +17,7 @@ FOREACH(TEST_PROG ${TEST_PROGS})
IF
(
APPLE
)
SET_TARGET_PROPERTIES
(
${
TEST_ROOT
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
-F/Library/Frameworks -framework CUDA"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
"
)
ELSE
(
APPLE
)
SET_TARGET_PROPERTIES
(
${
TEST_ROOT
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
COMPILE
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
"
)
SET_TARGET_PROPERTIES
(
${
TEST_ROOT
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
LINK
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
"
)
ENDIF
(
APPLE
)
ADD_TEST
(
${
TEST_ROOT
}
${
EXECUTABLE_OUTPUT_PATH
}
/
${
TEST_ROOT
}
)
...
...
plugins/drude/CMakeLists.txt
View file @
b7088b74
...
...
@@ -67,14 +67,14 @@ ENDFOREACH(subdir)
INCLUDE_DIRECTORIES
(
BEFORE
${
CMAKE_CURRENT_SOURCE_DIR
}
/src
)
ADD_LIBRARY
(
${
SHARED_DRUDE_TARGET
}
SHARED
${
SOURCE_DRUDE_FILES
}
${
SOURCE_DRUDE_INCLUDE_FILES
}
${
API_DRUDE_ABS_INCLUDE_FILES
}
)
SET_TARGET_PROPERTIES
(
${
SHARED_DRUDE_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
COMPILE
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
-DOPENMM_DRUDE_BUILDING_SHARED_LIBRARY -DLEPTON_BUILDING_SHARED_LIBRARY"
)
SET_TARGET_PROPERTIES
(
${
SHARED_DRUDE_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
LINK
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
-DOPENMM_DRUDE_BUILDING_SHARED_LIBRARY -DLEPTON_BUILDING_SHARED_LIBRARY"
)
FILE
(
GLOB serialization_files
${
CMAKE_CUURENT_SOURCE_DIR
}
/serialization/src/*.cpp
)
SET_SOURCE_FILES_PROPERTIES
(
${
serialization_files
}
PROPERTIES COMPILE_FLAGS
"-DOPENMM_DRUDE_BUILDING_SHARED_LIBRARY -DTIXML_USE_STL"
)
IF
(
OPENMM_BUILD_STATIC_LIB
)
ADD_LIBRARY
(
${
STATIC_DRUDE_TARGET
}
STATIC
${
SOURCE_DRUDE_FILES
}
${
SOURCE_DRUDE_INCLUDE_FILES
}
${
API_DRUDE_ABS_INCLUDE_FILES
}
)
SET_TARGET_PROPERTIES
(
${
STATIC_DRUDE_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
COMPILE
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
-DOPENMM_DRUDE_BUILDING_STATIC_LIBRARY -DOPENMM_USE_STATIC_LIBRARIES -DOPENMM_BUILDING_STATIC_LIBRARY -DLEPTON_USE_STATIC_LIBRARIES -DLEPTON_BUILDING_STATIC_LIBRARY"
)
SET_TARGET_PROPERTIES
(
${
STATIC_DRUDE_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
LINK
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
-DOPENMM_DRUDE_BUILDING_STATIC_LIBRARY -DOPENMM_USE_STATIC_LIBRARIES -DOPENMM_BUILDING_STATIC_LIBRARY -DLEPTON_USE_STATIC_LIBRARIES -DLEPTON_BUILDING_STATIC_LIBRARY"
)
ENDIF
(
OPENMM_BUILD_STATIC_LIB
)
# ----------------------------------------------------------------------------
...
...
plugins/drude/platforms/cuda/CMakeLists.txt
View file @
b7088b74
...
...
@@ -93,7 +93,7 @@ SET_TARGET_PROPERTIES(${SHARED_TARGET} PROPERTIES COMPILE_FLAGS "${EXTRA_COMPILE
IF
(
APPLE
)
SET_TARGET_PROPERTIES
(
${
SHARED_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
-F/Library/Frameworks -framework CUDA"
)
ELSE
(
APPLE
)
SET_TARGET_PROPERTIES
(
${
SHARED_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
COMPILE
_FLAGS
}
"
)
SET_TARGET_PROPERTIES
(
${
SHARED_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
LINK
_FLAGS
}
"
)
ENDIF
(
APPLE
)
INSTALL
(
TARGETS
${
SHARED_TARGET
}
DESTINATION
${
CMAKE_INSTALL_PREFIX
}
/lib/plugins
)
...
...
plugins/drude/platforms/cuda/tests/CMakeLists.txt
View file @
b7088b74
...
...
@@ -17,7 +17,7 @@ FOREACH(TEST_PROG ${TEST_PROGS})
IF
(
APPLE
)
SET_TARGET_PROPERTIES
(
${
TEST_ROOT
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
-F/Library/Frameworks -framework CUDA"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
"
)
ELSE
(
APPLE
)
SET_TARGET_PROPERTIES
(
${
TEST_ROOT
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
COMPILE
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
"
)
SET_TARGET_PROPERTIES
(
${
TEST_ROOT
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
LINK
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
"
)
ENDIF
(
APPLE
)
ADD_TEST
(
${
TEST_ROOT
}
Single
${
EXECUTABLE_OUTPUT_PATH
}
/
${
TEST_ROOT
}
single
)
IF
(
OPENMM_BUILD_CUDA_DOUBLE_PRECISION_TESTS
)
...
...
plugins/drude/platforms/opencl/CMakeLists.txt
View file @
b7088b74
...
...
@@ -89,7 +89,7 @@ ADD_LIBRARY(${SHARED_TARGET} SHARED ${SOURCE_FILES} ${SOURCE_INCLUDE_FILES} ${AP
TARGET_LINK_LIBRARIES
(
${
SHARED_TARGET
}
${
OPENMM_LIBRARY_NAME
}
${
OPENCL_LIBRARIES
}
${
PTHREADS_LIB
}
)
TARGET_LINK_LIBRARIES
(
${
SHARED_TARGET
}
${
OPENMM_LIBRARY_NAME
}
OpenCL
)
TARGET_LINK_LIBRARIES
(
${
SHARED_TARGET
}
${
SHARED_DRUDE_TARGET
}
)
SET_TARGET_PROPERTIES
(
${
SHARED_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
COMPILE
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
-DOPENMM_BUILDING_SHARED_LIBRARY"
)
SET_TARGET_PROPERTIES
(
${
SHARED_TARGET
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
LINK
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
-DOPENMM_BUILDING_SHARED_LIBRARY"
)
INSTALL
(
TARGETS
${
SHARED_TARGET
}
DESTINATION
${
CMAKE_INSTALL_PREFIX
}
/lib/plugins
)
# Ensure that links to the main OpenCL library will be resolved.
...
...
plugins/drude/platforms/opencl/tests/CMakeLists.txt
View file @
b7088b74
...
...
@@ -14,7 +14,7 @@ FOREACH(TEST_PROG ${TEST_PROGS})
# Link with shared library
ADD_EXECUTABLE
(
${
TEST_ROOT
}
${
TEST_PROG
}
)
TARGET_LINK_LIBRARIES
(
${
TEST_ROOT
}
${
SHARED_DRUDE_TARGET
}
${
SHARED_TARGET
}
)
SET_TARGET_PROPERTIES
(
${
TEST_ROOT
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
COMPILE
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
"
)
SET_TARGET_PROPERTIES
(
${
TEST_ROOT
}
PROPERTIES LINK_FLAGS
"
${
EXTRA_
LINK
_FLAGS
}
"
COMPILE_FLAGS
"
${
EXTRA_COMPILE_FLAGS
}
"
)
ADD_TEST
(
${
TEST_ROOT
}
Single
${
EXECUTABLE_OUTPUT_PATH
}
/
${
TEST_ROOT
}
single
)
IF
(
OPENMM_BUILD_OPENCL_DOUBLE_PRECISION_TESTS
)
ADD_TEST
(
${
TEST_ROOT
}
Mixed
${
EXECUTABLE_OUTPUT_PATH
}
/
${
TEST_ROOT
}
mixed
)
...
...
Prev
1
2
3
4
5
6
7
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment