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
4de0fc05
"vscode:/vscode.git/clone" did not exist on "e41e8e3e0a9a58da6928024c6ce631e92155a9d8"
Commit
4de0fc05
authored
Aug 21, 2015
by
peastman
Browse files
Switched back to cartesian multipoles everywhere that they're faster than spherical ones
parent
5c090de2
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
117 additions
and
285 deletions
+117
-285
plugins/amoeba/platforms/reference/src/SimTKReference/AmoebaReferenceMultipoleForce.cpp
...ence/src/SimTKReference/AmoebaReferenceMultipoleForce.cpp
+117
-285
No files found.
plugins/amoeba/platforms/reference/src/SimTKReference/AmoebaReferenceMultipoleForce.cpp
View file @
4de0fc05
...
...
@@ -692,123 +692,48 @@ void AmoebaReferenceMultipoleForce::calculateFixedMultipoleFieldPairIxn(const Mu
RealVec
deltaR
=
particleJ
.
position
-
particleI
.
position
;
RealOpenMM
r
=
SQRT
(
deltaR
.
dot
(
deltaR
));
unsigned
int
iIndex
=
particleI
.
particleIndex
;
unsigned
int
jIndex
=
particleJ
.
particleIndex
;
vector
<
RealOpenMM
>
rrI
(
3
);
// 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
[
3
][
5
];
buildPartialSphericalQuadrupoleRotationMatrix
(
qiRotationMatrix1
,
qiRotationMatrix2
);
// The field rotation matrix rotates the QI fields into the lab
// frame, and makes sure the result is in {x,y,z} ordering
RealOpenMM
fieldRotationMatrix
[
3
][
3
];
fieldRotationMatrix
[
0
][
0
]
=
qiRotationMatrix1
[
0
][
1
];
fieldRotationMatrix
[
0
][
1
]
=
qiRotationMatrix1
[
1
][
1
];
fieldRotationMatrix
[
0
][
2
]
=
qiRotationMatrix1
[
2
][
1
];
fieldRotationMatrix
[
1
][
0
]
=
qiRotationMatrix1
[
0
][
2
];
fieldRotationMatrix
[
1
][
1
]
=
qiRotationMatrix1
[
1
][
2
];
fieldRotationMatrix
[
1
][
2
]
=
qiRotationMatrix1
[
2
][
2
];
fieldRotationMatrix
[
2
][
0
]
=
qiRotationMatrix1
[
0
][
0
];
fieldRotationMatrix
[
2
][
1
]
=
qiRotationMatrix1
[
1
][
0
];
fieldRotationMatrix
[
2
][
2
]
=
qiRotationMatrix1
[
2
][
0
];
// get scaling factors, if needed
// 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
;
}
getAndScaleInverseRs
(
particleI
.
dampingFactor
,
particleJ
.
dampingFactor
,
particleI
.
thole
,
particleJ
.
thole
,
r
,
rrI
);
// We only need to go up to 3 in this loop; the final two term don't contribute
// to the field because of orthogonality.
for
(
int
ii
=
0
;
ii
<
3
;
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
rr3
=
rrI
[
0
];
RealOpenMM
rr5
=
rrI
[
1
];
RealOpenMM
rr7
=
rrI
[
2
];
RealOpenMM
rr5_2
=
2.0
*
rr5
;
RealOpenMM
rInvVec
[
5
];
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
]
=
rInv
;
for
(
int
i
=
2
;
i
<
5
;
++
i
)
rInvVec
[
i
]
=
rInvVec
[
i
-
1
]
*
rInv
;
// field at particle I due multipoles at particle J
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
;
// 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
);
RealVec
qDotDelta
;
qDotDelta
[
0
]
=
deltaR
[
0
]
*
particleJ
.
quadrupole
[
QXX
]
+
deltaR
[
1
]
*
particleJ
.
quadrupole
[
QXY
]
+
deltaR
[
2
]
*
particleJ
.
quadrupole
[
QXZ
];
qDotDelta
[
1
]
=
deltaR
[
0
]
*
particleJ
.
quadrupole
[
QXY
]
+
deltaR
[
1
]
*
particleJ
.
quadrupole
[
QYY
]
+
deltaR
[
2
]
*
particleJ
.
quadrupole
[
QYZ
];
qDotDelta
[
2
]
=
deltaR
[
0
]
*
particleJ
.
quadrupole
[
QXZ
]
+
deltaR
[
1
]
*
particleJ
.
quadrupole
[
QYZ
]
+
deltaR
[
2
]
*
particleJ
.
quadrupole
[
QZZ
];
// Build the QI frame multipole intermediates
RealOpenMM
qivec0
[
3
]
=
{
qiQJ
[
0
],
qiQJ
[
1
],
qiQJ
[
4
]
};
RealOpenMM
qjvec0
[
3
]
=
{
-
qiQI
[
0
],
qiQI
[
1
],
-
qiQI
[
4
]
};
RealOpenMM
qivec1
[
2
]
=
{
qiQJ
[
2
],
qiQJ
[
5
]
};
RealOpenMM
qjvec1
[
2
]
=
{
qiQI
[
2
],
-
qiQI
[
5
]
};
RealOpenMM
qivec2
[
2
]
=
{
qiQJ
[
3
],
qiQJ
[
6
]
};
RealOpenMM
qjvec2
[
2
]
=
{
qiQI
[
3
],
-
qiQI
[
6
]
};
// Build the QI frame Coulomb operator intermediates
RealOpenMM
v0d
[
3
]
=
{
-
rInvVec
[
2
]
*
dScale
*
thole_c
,
2.0
*
rInvVec
[
3
]
*
dScale
*
thole_d0
,
-
3.0
*
rInvVec
[
4
]
*
dScale
*
thole_q0
};
RealOpenMM
v0p
[
3
]
=
{
-
rInvVec
[
2
]
*
pScale
*
thole_c
,
2.0
*
rInvVec
[
3
]
*
pScale
*
thole_d0
,
-
3.0
*
rInvVec
[
4
]
*
pScale
*
thole_q0
};
RealOpenMM
v1d
[
2
]
=
{
-
rInvVec
[
3
]
*
dScale
*
thole_d1
,
sqrtThree
*
rInvVec
[
4
]
*
dScale
*
thole_q1
};
RealOpenMM
v1p
[
2
]
=
{
-
rInvVec
[
3
]
*
pScale
*
thole_d1
,
sqrtThree
*
rInvVec
[
4
]
*
pScale
*
thole_q1
};
// Contract the QI multipole intermediates and Coulomb operator to form the QI frame field.
RealOpenMM
Vijd
[
3
]
=
{
v0d
[
0
]
*
qivec0
[
0
]
+
v0d
[
1
]
*
qivec0
[
1
]
+
v0d
[
2
]
*
qivec0
[
2
],
v1d
[
0
]
*
qivec1
[
0
]
+
v1d
[
1
]
*
qivec1
[
1
],
v1d
[
0
]
*
qivec2
[
0
]
+
v1d
[
1
]
*
qivec2
[
1
]
};
RealOpenMM
Vijp
[
3
]
=
{
v0p
[
0
]
*
qivec0
[
0
]
+
v0p
[
1
]
*
qivec0
[
1
]
+
v0p
[
2
]
*
qivec0
[
2
],
v1p
[
0
]
*
qivec1
[
0
]
+
v1p
[
1
]
*
qivec1
[
1
],
v1p
[
0
]
*
qivec2
[
0
]
+
v1p
[
1
]
*
qivec2
[
1
]
};
RealOpenMM
Vjid
[
3
]
=
{
v0d
[
0
]
*
qjvec0
[
0
]
+
v0d
[
1
]
*
qjvec0
[
1
]
+
v0d
[
2
]
*
qjvec0
[
2
],
v1d
[
0
]
*
qjvec1
[
0
]
+
v1d
[
1
]
*
qjvec1
[
1
],
v1d
[
0
]
*
qjvec2
[
0
]
+
v1d
[
1
]
*
qjvec2
[
1
]
};
RealOpenMM
Vjip
[
3
]
=
{
v0p
[
0
]
*
qjvec0
[
0
]
+
v0p
[
1
]
*
qjvec0
[
1
]
+
v0p
[
2
]
*
qjvec0
[
2
],
v1p
[
0
]
*
qjvec1
[
0
]
+
v1p
[
1
]
*
qjvec1
[
1
],
v1p
[
0
]
*
qjvec2
[
0
]
+
v1p
[
1
]
*
qjvec2
[
1
]
};
RealOpenMM
dipoleDelta
=
particleJ
.
dipole
.
dot
(
deltaR
);
RealOpenMM
qdpoleDelta
=
qDotDelta
.
dot
(
deltaR
);
RealOpenMM
factor
=
rr3
*
particleJ
.
charge
-
rr5
*
dipoleDelta
+
rr7
*
qdpoleDelta
;
// Rotate the forces and torques back to the lab frame
for
(
int
ii
=
0
;
ii
<
3
;
ii
++
)
{
RealOpenMM
VijpVal
=
0.0
;
RealOpenMM
VijdVal
=
0.0
;
RealOpenMM
VjipVal
=
0.0
;
RealOpenMM
VjidVal
=
0.0
;
for
(
int
jj
=
0
;
jj
<
3
;
jj
++
)
{
VijdVal
+=
fieldRotationMatrix
[
ii
][
jj
]
*
Vijd
[
jj
];
VijpVal
+=
fieldRotationMatrix
[
ii
][
jj
]
*
Vijp
[
jj
];
VjidVal
+=
fieldRotationMatrix
[
ii
][
jj
]
*
Vjid
[
jj
];
VjipVal
+=
fieldRotationMatrix
[
ii
][
jj
]
*
Vjip
[
jj
];
}
_fixedMultipoleField
[
iIndex
][
ii
]
+=
VijdVal
;
_fixedMultipoleField
[
jIndex
][
ii
]
+=
VjidVal
;
_fixedMultipoleFieldPolar
[
iIndex
][
ii
]
+=
VijpVal
;
_fixedMultipoleFieldPolar
[
jIndex
][
ii
]
+=
VjipVal
;
}
RealVec
field
=
deltaR
*
factor
+
particleJ
.
dipole
*
rr3
-
qDotDelta
*
rr5_2
;
unsigned
int
particleIndex
=
particleI
.
particleIndex
;
_fixedMultipoleField
[
particleIndex
]
-=
field
*
dScale
;
_fixedMultipoleFieldPolar
[
particleIndex
]
-=
field
*
pScale
;
// field at particle J due multipoles at particle I
qDotDelta
[
0
]
=
deltaR
[
0
]
*
particleI
.
quadrupole
[
QXX
]
+
deltaR
[
1
]
*
particleI
.
quadrupole
[
QXY
]
+
deltaR
[
2
]
*
particleI
.
quadrupole
[
QXZ
];
qDotDelta
[
1
]
=
deltaR
[
0
]
*
particleI
.
quadrupole
[
QXY
]
+
deltaR
[
1
]
*
particleI
.
quadrupole
[
QYY
]
+
deltaR
[
2
]
*
particleI
.
quadrupole
[
QYZ
];
qDotDelta
[
2
]
=
deltaR
[
0
]
*
particleI
.
quadrupole
[
QXZ
]
+
deltaR
[
1
]
*
particleI
.
quadrupole
[
QYZ
]
+
deltaR
[
2
]
*
particleI
.
quadrupole
[
QZZ
];
dipoleDelta
=
particleI
.
dipole
.
dot
(
deltaR
);
qdpoleDelta
=
qDotDelta
.
dot
(
deltaR
);
factor
=
rr3
*
particleI
.
charge
+
rr5
*
dipoleDelta
+
rr7
*
qdpoleDelta
;
field
=
deltaR
*
factor
-
particleI
.
dipole
*
rr3
-
qDotDelta
*
rr5_2
;
particleIndex
=
particleJ
.
particleIndex
;
_fixedMultipoleField
[
particleIndex
]
+=
field
*
dScale
;
_fixedMultipoleFieldPolar
[
particleIndex
]
+=
field
*
pScale
;
}
void
AmoebaReferenceMultipoleForce
::
calculateFixedMultipoleField
(
const
vector
<
MultipoleParticleData
>&
particleData
)
...
...
@@ -2007,21 +1932,16 @@ RealOpenMM AmoebaReferenceMultipoleForce::calculateElectrostaticPotentialForPart
RealOpenMM
rr3
=
rr1
*
rr2
;
RealOpenMM
potential
=
particleI
.
charge
*
rr1
;
unsigned
int
iIndex
=
particleI
.
particleIndex
;
RealOpenMM
D1
[
3
][
3
];
formQIRotationMatrix
(
particleI
.
position
,
gridPoint
,
deltaR
,
r
,
D1
);
RealOpenMM
D2
[
5
]
=
{
1.5
*
D1
[
0
][
0
]
*
D1
[
0
][
0
]
-
0.5
,
sqrtThree
*
D1
[
0
][
0
]
*
D1
[
0
][
1
],
sqrtThree
*
D1
[
0
][
0
]
*
D1
[
0
][
2
],
0.5
*
sqrtThree
*
(
D1
[
0
][
1
]
*
D1
[
0
][
1
]
-
D1
[
0
][
2
]
*
D1
[
0
][
2
]),
sqrtThree
*
D1
[
0
][
1
]
*
D1
[
0
][
2
]
};
RealOpenMM
induced
[
3
]
=
{
_inducedDipole
[
iIndex
][
2
],
_inducedDipole
[
iIndex
][
0
],
_inducedDipole
[
iIndex
][
1
]
};
RealOpenMM
qiD0
=
0.0
;
for
(
int
i
=
0
;
i
<
3
;
++
i
)
qiD0
+=
D1
[
0
][
i
]
*
(
particleI
.
sphericalDipole
[
i
]
+
induced
[
i
]);
RealOpenMM
qiQ0
=
0.0
;
for
(
int
i
=
0
;
i
<
5
;
++
i
)
qiQ0
+=
D2
[
i
]
*
particleI
.
sphericalQuadrupole
[
i
];
potential
+=
qiQ0
*
rr3
-
qiD0
*
rr2
;
return
potential
;
RealOpenMM
scd
=
particleI
.
dipole
.
dot
(
deltaR
);
RealOpenMM
scu
=
_inducedDipole
[
particleI
.
particleIndex
].
dot
(
deltaR
);
potential
-=
(
scd
+
scu
)
*
rr3
;
RealOpenMM
rr5
=
3.0
*
rr3
*
rr2
;
RealOpenMM
scq
=
deltaR
[
0
]
*
(
particleI
.
quadrupole
[
QXX
]
*
deltaR
[
0
]
+
particleI
.
quadrupole
[
QXY
]
*
deltaR
[
1
]
+
particleI
.
quadrupole
[
QXZ
]
*
deltaR
[
2
]);
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
,
...
...
@@ -5008,140 +4928,72 @@ void AmoebaReferencePmeMultipoleForce::calculateFixedMultipoleFieldPairIxn(const
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
,
particleJ
.
position
,
deltaR
,
r
,
qiRotationMatrix1
);
RealOpenMM
qiRotationMatrix2
[
3
][
5
];
buildPartialSphericalQuadrupoleRotationMatrix
(
qiRotationMatrix1
,
qiRotationMatrix2
);
// The field rotation matrix rotates the QI fields into the lab
// frame, and makes sure the result is in {x,y,z} ordering
RealOpenMM
fieldRotationMatrix
[
3
][
3
];
fieldRotationMatrix
[
0
][
0
]
=
qiRotationMatrix1
[
0
][
1
];
fieldRotationMatrix
[
0
][
1
]
=
qiRotationMatrix1
[
1
][
1
];
fieldRotationMatrix
[
0
][
2
]
=
qiRotationMatrix1
[
2
][
1
];
fieldRotationMatrix
[
1
][
0
]
=
qiRotationMatrix1
[
0
][
2
];
fieldRotationMatrix
[
1
][
1
]
=
qiRotationMatrix1
[
1
][
2
];
fieldRotationMatrix
[
1
][
2
]
=
qiRotationMatrix1
[
2
][
2
];
fieldRotationMatrix
[
2
][
0
]
=
qiRotationMatrix1
[
0
][
0
];
fieldRotationMatrix
[
2
][
1
]
=
qiRotationMatrix1
[
1
][
0
];
fieldRotationMatrix
[
2
][
2
]
=
qiRotationMatrix1
[
2
][
0
];
// calculate the error function damping terms
// 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
;
}
RealOpenMM
ralpha
=
_alphaEwald
*
r
;
// We only need to go up to 3 in this loop; the final two term don't contribute
// to the field because of orthogonality.
for
(
int
ii
=
0
;
ii
<
3
;
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
bn0
=
erfc
(
ralpha
)
/
r
;
RealOpenMM
alsq2
=
2.0
*
_alphaEwald
*
_alphaEwald
;
RealOpenMM
alsq2n
=
1.0
/
(
SQRT_PI
*
_alphaEwald
);
RealOpenMM
exp2a
=
EXP
(
-
(
ralpha
*
ralpha
));
alsq2n
*=
alsq2
;
RealOpenMM
bn1
=
(
bn0
+
alsq2n
*
exp2a
)
/
r2
;
RealOpenMM
rInvVec
[
5
],
alphaRVec
[
6
],
bVec
[
4
];
alsq2n
*=
alsq2
;
RealOpenMM
bn2
=
(
3.0
*
bn1
+
alsq2n
*
exp2a
)
/
r2
;
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
]
=
rInv
;
for
(
int
i
=
2
;
i
<
5
;
++
i
)
rInvVec
[
i
]
=
rInvVec
[
i
-
1
]
*
rInv
;
alsq2n
*=
alsq2
;
RealOpenMM
bn3
=
(
5.0
*
bn2
+
alsq2n
*
exp2a
)
/
r2
;
// 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
<
6
;
++
i
)
alphaRVec
[
i
]
=
alphaRVec
[
i
-
1
]
*
alphaRVec
[
1
];
// compute the error function scaled and unscaled terms
RealOpenMM
erfAlphaR
=
erf
(
alphaRVec
[
1
]);
RealOpenMM
X
=
2.0
*
EXP
(
-
alphaRVec
[
2
])
/
SQRT_PI
;
RealVec
dampedDInverseDistances
;
RealVec
dampedPInverseDistances
;
getDampedInverseDistances
(
particleI
,
particleJ
,
dscale
,
pscale
,
r
,
dampedDInverseDistances
,
dampedPInverseDistances
);
bVec
[
1
]
=
-
erfAlphaR
;
bVec
[
2
]
=
bVec
[
1
]
+
alphaRVec
[
1
]
*
X
;
bVec
[
3
]
=
bVec
[
2
]
+
alphaRVec
[
3
]
*
X
*
2.0
/
3.0
;
RealOpenMM
drr3
=
dampedDInverseDistances
[
0
]
;
RealOpenMM
drr5
=
dampedDInverseDistances
[
1
];
RealOpenMM
drr7
=
dampedDInverseDistances
[
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
;
// 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
);
RealOpenMM
prr3
=
dampedPInverseDistances
[
0
];
RealOpenMM
prr5
=
dampedPInverseDistances
[
1
];
RealOpenMM
prr7
=
dampedPInverseDistances
[
2
];
// Build the QI frame multipole intermediates
RealOpenMM
qivec0
[
3
]
=
{
qiQJ
[
0
],
qiQJ
[
1
],
qiQJ
[
4
]
};
RealOpenMM
qjvec0
[
3
]
=
{
-
qiQI
[
0
],
qiQI
[
1
],
-
qiQI
[
4
]
};
RealOpenMM
qivec1
[
2
]
=
{
qiQJ
[
2
],
qiQJ
[
5
]
};
RealOpenMM
qjvec1
[
2
]
=
{
qiQI
[
2
],
-
qiQI
[
5
]
};
RealOpenMM
qivec2
[
2
]
=
{
qiQJ
[
3
],
qiQJ
[
6
]
};
RealOpenMM
qjvec2
[
2
]
=
{
qiQI
[
3
],
-
qiQI
[
6
]
};
// Build the QI frame Coulomb operator intermediates
RealOpenMM
v0d
[
3
]
=
{
-
rInvVec
[
2
]
*
(
dscale
*
thole_c
+
bVec
[
2
]),
twoThirds
*
rInvVec
[
3
]
*
(
3.0
*
(
dscale
*
thole_d0
+
bVec
[
3
])
+
alphaRVec
[
3
]
*
X
),
-
rInvVec
[
4
]
*
(
3.0
*
(
dscale
*
thole_q0
+
bVec
[
3
])
+
fourThirds
*
alphaRVec
[
5
]
*
X
)
};
RealOpenMM
v0p
[
3
]
=
{
-
rInvVec
[
2
]
*
(
pscale
*
thole_c
+
bVec
[
2
]),
twoThirds
*
rInvVec
[
3
]
*
(
3.0
*
(
pscale
*
thole_d0
+
bVec
[
3
])
+
alphaRVec
[
3
]
*
X
),
-
rInvVec
[
4
]
*
(
3.0
*
(
pscale
*
thole_q0
+
bVec
[
3
])
+
fourThirds
*
alphaRVec
[
5
]
*
X
)
};
RealOpenMM
v1d
[
2
]
=
{
-
rInvVec
[
3
]
*
(
dscale
*
thole_d1
+
bVec
[
3
]
-
twoThirds
*
alphaRVec
[
3
]
*
X
),
sqrtThree
*
rInvVec
[
4
]
*
(
dscale
*
thole_q1
+
bVec
[
3
])
};
RealOpenMM
v1p
[
2
]
=
{
-
rInvVec
[
3
]
*
(
pscale
*
thole_d1
+
bVec
[
3
]
-
twoThirds
*
alphaRVec
[
3
]
*
X
),
sqrtThree
*
rInvVec
[
4
]
*
(
pscale
*
thole_q1
+
bVec
[
3
])
};
// Contract the QI multipole intermediates and Coulomb operator to form the QI frame field.
RealOpenMM
Vijd
[
3
]
=
{
v0d
[
0
]
*
qivec0
[
0
]
+
v0d
[
1
]
*
qivec0
[
1
]
+
v0d
[
2
]
*
qivec0
[
2
],
v1d
[
0
]
*
qivec1
[
0
]
+
v1d
[
1
]
*
qivec1
[
1
],
v1d
[
0
]
*
qivec2
[
0
]
+
v1d
[
1
]
*
qivec2
[
1
]
};
RealOpenMM
Vijp
[
3
]
=
{
v0p
[
0
]
*
qivec0
[
0
]
+
v0p
[
1
]
*
qivec0
[
1
]
+
v0p
[
2
]
*
qivec0
[
2
],
v1p
[
0
]
*
qivec1
[
0
]
+
v1p
[
1
]
*
qivec1
[
1
],
v1p
[
0
]
*
qivec2
[
0
]
+
v1p
[
1
]
*
qivec2
[
1
]
};
RealOpenMM
Vjid
[
3
]
=
{
v0d
[
0
]
*
qjvec0
[
0
]
+
v0d
[
1
]
*
qjvec0
[
1
]
+
v0d
[
2
]
*
qjvec0
[
2
],
v1d
[
0
]
*
qjvec1
[
0
]
+
v1d
[
1
]
*
qjvec1
[
1
],
v1d
[
0
]
*
qjvec2
[
0
]
+
v1d
[
1
]
*
qjvec2
[
1
]
};
RealOpenMM
Vjip
[
3
]
=
{
v0p
[
0
]
*
qjvec0
[
0
]
+
v0p
[
1
]
*
qjvec0
[
1
]
+
v0p
[
2
]
*
qjvec0
[
2
],
v1p
[
0
]
*
qjvec1
[
0
]
+
v1p
[
1
]
*
qjvec1
[
1
],
v1p
[
0
]
*
qjvec2
[
0
]
+
v1p
[
1
]
*
qjvec2
[
1
]
};
RealOpenMM
dir
=
particleI
.
dipole
.
dot
(
deltaR
);
// Rotate the forces and torques back to the lab frame
for
(
int
ii
=
0
;
ii
<
3
;
ii
++
)
{
RealOpenMM
VijpVal
=
0.0
;
RealOpenMM
VijdVal
=
0.0
;
RealOpenMM
VjipVal
=
0.0
;
RealOpenMM
VjidVal
=
0.0
;
for
(
int
jj
=
0
;
jj
<
3
;
jj
++
)
{
VijdVal
+=
fieldRotationMatrix
[
ii
][
jj
]
*
Vijd
[
jj
];
VijpVal
+=
fieldRotationMatrix
[
ii
][
jj
]
*
Vijp
[
jj
];
VjidVal
+=
fieldRotationMatrix
[
ii
][
jj
]
*
Vjid
[
jj
];
VjipVal
+=
fieldRotationMatrix
[
ii
][
jj
]
*
Vjip
[
jj
];
}
_fixedMultipoleField
[
iIndex
][
ii
]
+=
VijdVal
;
_fixedMultipoleField
[
jIndex
][
ii
]
+=
VjidVal
;
_fixedMultipoleFieldPolar
[
iIndex
][
ii
]
+=
VijpVal
;
_fixedMultipoleFieldPolar
[
jIndex
][
ii
]
+=
VjipVal
;
}
RealVec
qxI
=
RealVec
(
particleI
.
quadrupole
[
QXX
],
particleI
.
quadrupole
[
QXY
],
particleI
.
quadrupole
[
QXZ
]);
RealVec
qyI
=
RealVec
(
particleI
.
quadrupole
[
QXY
],
particleI
.
quadrupole
[
QYY
],
particleI
.
quadrupole
[
QYZ
]);
RealVec
qzI
=
RealVec
(
particleI
.
quadrupole
[
QXZ
],
particleI
.
quadrupole
[
QYZ
],
particleI
.
quadrupole
[
QZZ
]);
RealVec
qi
=
RealVec
(
qxI
.
dot
(
deltaR
),
qyI
.
dot
(
deltaR
),
qzI
.
dot
(
deltaR
));
RealOpenMM
qir
=
qi
.
dot
(
deltaR
);
RealOpenMM
djr
=
particleJ
.
dipole
.
dot
(
deltaR
);
RealVec
qxJ
=
RealVec
(
particleJ
.
quadrupole
[
QXX
],
particleJ
.
quadrupole
[
QXY
],
particleJ
.
quadrupole
[
QXZ
]);
RealVec
qyJ
=
RealVec
(
particleJ
.
quadrupole
[
QXY
],
particleJ
.
quadrupole
[
QYY
],
particleJ
.
quadrupole
[
QYZ
]);
RealVec
qzJ
=
RealVec
(
particleJ
.
quadrupole
[
QXZ
],
particleJ
.
quadrupole
[
QYZ
],
particleJ
.
quadrupole
[
QZZ
]);
RealVec
qj
=
RealVec
(
qxJ
.
dot
(
deltaR
),
qyJ
.
dot
(
deltaR
),
qzJ
.
dot
(
deltaR
));
RealOpenMM
qjr
=
qj
.
dot
(
deltaR
);
RealVec
fim
=
qj
*
(
2.0
*
bn2
)
-
particleJ
.
dipole
*
bn1
-
deltaR
*
(
bn1
*
particleJ
.
charge
-
bn2
*
djr
+
bn3
*
qjr
);
RealVec
fjm
=
qi
*
(
-
2.0
*
bn2
)
-
particleI
.
dipole
*
bn1
+
deltaR
*
(
bn1
*
particleI
.
charge
+
bn2
*
dir
+
bn3
*
qir
);
RealVec
fid
=
qj
*
(
2.0
*
drr5
)
-
particleJ
.
dipole
*
drr3
-
deltaR
*
(
drr3
*
particleJ
.
charge
-
drr5
*
djr
+
drr7
*
qjr
);
RealVec
fjd
=
qi
*
(
-
2.0
*
drr5
)
-
particleI
.
dipole
*
drr3
+
deltaR
*
(
drr3
*
particleI
.
charge
+
drr5
*
dir
+
drr7
*
qir
);
RealVec
fip
=
qj
*
(
2.0
*
prr5
)
-
particleJ
.
dipole
*
prr3
-
deltaR
*
(
prr3
*
particleJ
.
charge
-
prr5
*
djr
+
prr7
*
qjr
);
RealVec
fjp
=
qi
*
(
-
2.0
*
prr5
)
-
particleI
.
dipole
*
prr3
+
deltaR
*
(
prr3
*
particleI
.
charge
+
prr5
*
dir
+
prr7
*
qir
);
// increment the field at each site due to this interaction
_fixedMultipoleField
[
iIndex
]
+=
fim
-
fid
;
_fixedMultipoleField
[
jIndex
]
+=
fjm
-
fjd
;
_fixedMultipoleFieldPolar
[
iIndex
]
+=
fim
-
fip
;
_fixedMultipoleFieldPolar
[
jIndex
]
+=
fjm
-
fjp
;
}
void
AmoebaReferencePmeMultipoleForce
::
calculateFixedMultipoleField
(
const
vector
<
MultipoleParticleData
>&
particleData
)
...
...
@@ -5302,31 +5154,18 @@ void AmoebaReferencePmeMultipoleForce::transformMultipolesToFractionalCoordinate
// Transform the multipoles.
RealOpenMM
cartDipole
[
3
];
RealOpenMM
cartQuadrupole
[
6
];
_transformed
.
resize
(
particleData
.
size
());
double
quadScale
[]
=
{
1
,
2
,
2
,
1
,
2
,
1
};
for
(
int
i
=
0
;
i
<
(
int
)
particleData
.
size
();
i
++
)
{
// Form Cartesian multipoles on the fly, from the spherical harmonics
cartDipole
[
0
]
=
particleData
[
i
].
sphericalDipole
[
1
];
cartDipole
[
1
]
=
particleData
[
i
].
sphericalDipole
[
2
];
cartDipole
[
2
]
=
particleData
[
i
].
sphericalDipole
[
0
];
cartQuadrupole
[
0
]
=
(
sqrtThree
*
particleData
[
i
].
sphericalQuadrupole
[
3
]
-
particleData
[
i
].
sphericalQuadrupole
[
0
])
/
6.0
;
cartQuadrupole
[
1
]
=
sqrtOneThird
*
particleData
[
i
].
sphericalQuadrupole
[
4
]
/
2.0
;
cartQuadrupole
[
2
]
=
sqrtOneThird
*
particleData
[
i
].
sphericalQuadrupole
[
1
]
/
2.0
;
cartQuadrupole
[
3
]
=
-
(
sqrtThree
*
particleData
[
i
].
sphericalQuadrupole
[
3
]
+
particleData
[
i
].
sphericalQuadrupole
[
0
])
/
6.0
;
cartQuadrupole
[
4
]
=
sqrtOneThird
*
particleData
[
i
].
sphericalQuadrupole
[
2
]
/
2.0
;
cartQuadrupole
[
5
]
=
particleData
[
i
].
sphericalQuadrupole
[
0
]
/
3.0
;
_transformed
[
i
].
charge
=
particleData
[
i
].
charge
;
_transformed
[
i
].
dipole
=
Vec3
();
for
(
int
j
=
0
;
j
<
3
;
j
++
)
for
(
int
k
=
0
;
k
<
3
;
k
++
)
_transformed
[
i
].
dipole
[
j
]
+=
a
[
j
][
k
]
*
c
art
D
ipole
[
k
];
_transformed
[
i
].
dipole
[
j
]
+=
a
[
j
][
k
]
*
p
art
icleData
[
i
].
d
ipole
[
k
];
for
(
int
j
=
0
;
j
<
6
;
j
++
)
{
_transformed
[
i
].
quadrupole
[
j
]
=
0
;
for
(
int
k
=
0
;
k
<
6
;
k
++
)
_transformed
[
i
].
quadrupole
[
j
]
+=
quadScale
[
k
]
*
b
[
j
][
k
]
*
c
art
Q
uadrupole
[
k
];
_transformed
[
i
].
quadrupole
[
j
]
+=
quadScale
[
k
]
*
b
[
j
][
k
]
*
p
art
icleData
[
i
].
q
uadrupole
[
k
];
}
}
}
...
...
@@ -5834,18 +5673,17 @@ RealOpenMM AmoebaReferencePmeMultipoleForce::computeReciprocalSpaceFixedMultipol
multipole
[
0
]
=
particleData
[
i
].
charge
;
// Form Cartesian multipoles on the fly, from the spherical harmonics
multipole
[
1
]
=
particleData
[
i
].
sphericalDipole
[
1
];
multipole
[
2
]
=
particleData
[
i
].
sphericalDipole
[
2
];
multipole
[
3
]
=
particleData
[
i
].
sphericalDipole
[
0
];
multipole
[
1
]
=
particleData
[
i
].
dipole
[
0
];
multipole
[
2
]
=
particleData
[
i
].
dipole
[
1
];
multipole
[
3
]
=
particleData
[
i
].
dipole
[
2
];
multipole
[
4
]
=
(
sqrtThree
*
particleData
[
i
].
sphericalQuadrupole
[
3
]
-
particleData
[
i
].
sphericalQuadrupole
[
0
])
/
6.0
;
multipole
[
5
]
=
-
(
sqrtThree
*
particleData
[
i
].
sphericalQuadrupole
[
3
]
+
particleData
[
i
].
sphericalQuadrupole
[
0
])
/
6.0
;
multipole
[
6
]
=
particleData
[
i
].
sphericalQ
uadrupole
[
0
]
/
3.0
;
multipole
[
4
]
=
particleData
[
i
].
quadrupole
[
QXX
]
;
multipole
[
5
]
=
particleData
[
i
].
quadrupole
[
QYY
]
;
multipole
[
6
]
=
particleData
[
i
].
q
uadrupole
[
QZZ
]
;
multipole
[
7
]
=
sqrtOneThird
*
particleData
[
i
].
sphericalQ
uadrupole
[
4
]
;
multipole
[
8
]
=
sqrtOneThird
*
particleData
[
i
].
sphericalQ
uadrupole
[
1
]
;
multipole
[
9
]
=
sqrtOneThird
*
particleData
[
i
].
sphericalQ
uadrupole
[
2
]
;
multipole
[
7
]
=
particleData
[
i
].
q
uadrupole
[
QXY
]
*
2.0
;
multipole
[
8
]
=
particleData
[
i
].
q
uadrupole
[
QXZ
]
*
2.0
;
multipole
[
9
]
=
particleData
[
i
].
q
uadrupole
[
QYZ
]
*
2.0
;
const
RealOpenMM
*
phi
=
&
cphi
[
10
*
i
];
torques
[
i
][
0
]
+=
_electric
*
(
multipole
[
3
]
*
phi
[
2
]
-
multipole
[
2
]
*
phi
[
3
]
...
...
@@ -5925,18 +5763,12 @@ RealOpenMM AmoebaReferencePmeMultipoleForce::computeReciprocalSpaceInducedDipole
multipole
[
2
]
=
particleData
[
i
].
dipole
[
1
];
multipole
[
3
]
=
particleData
[
i
].
dipole
[
2
];
// Form Cartesian multipoles on the fly, from the spherical harmonics
multipole
[
1
]
=
particleData
[
i
].
sphericalDipole
[
1
];
multipole
[
2
]
=
particleData
[
i
].
sphericalDipole
[
2
];
multipole
[
3
]
=
particleData
[
i
].
sphericalDipole
[
0
];
multipole
[
4
]
=
(
sqrtThree
*
particleData
[
i
].
sphericalQuadrupole
[
3
]
-
particleData
[
i
].
sphericalQuadrupole
[
0
])
/
6.0
;
multipole
[
5
]
=
-
(
sqrtThree
*
particleData
[
i
].
sphericalQuadrupole
[
3
]
+
particleData
[
i
].
sphericalQuadrupole
[
0
])
/
6.0
;
multipole
[
6
]
=
particleData
[
i
].
sphericalQuadrupole
[
0
]
/
3.0
;
multipole
[
7
]
=
sqrtOneThird
*
particleData
[
i
].
sphericalQuadrupole
[
4
];
multipole
[
8
]
=
sqrtOneThird
*
particleData
[
i
].
sphericalQuadrupole
[
1
];
multipole
[
9
]
=
sqrtOneThird
*
particleData
[
i
].
sphericalQuadrupole
[
2
];
multipole
[
4
]
=
particleData
[
i
].
quadrupole
[
QXX
];
multipole
[
5
]
=
particleData
[
i
].
quadrupole
[
QYY
];
multipole
[
6
]
=
particleData
[
i
].
quadrupole
[
QZZ
];
multipole
[
7
]
=
particleData
[
i
].
quadrupole
[
QXY
]
*
2.0
;
multipole
[
8
]
=
particleData
[
i
].
quadrupole
[
QXZ
]
*
2.0
;
multipole
[
9
]
=
particleData
[
i
].
quadrupole
[
QYZ
]
*
2.0
;
const
RealOpenMM
*
phi
=
&
cphi
[
10
*
i
];
torques
[
iIndex
][
0
]
+=
0.5
*
_electric
*
(
multipole
[
3
]
*
phi
[
2
]
-
multipole
[
2
]
*
phi
[
3
]
...
...
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