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
e5b7f0b3
"plugins/vscode:/vscode.git/clone" did not exist on "72bd8a83aed9e7ef017444eab676cf8f73e6c222"
Commit
e5b7f0b3
authored
Aug 02, 2012
by
Peter Eastman
Browse files
Continuing to convert AmoebaMultipoleForce
parent
155fe172
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
1673 additions
and
29 deletions
+1673
-29
plugins/amoeba/platforms/cuda2/src/AmoebaCudaKernels.cpp
plugins/amoeba/platforms/cuda2/src/AmoebaCudaKernels.cpp
+10
-2
plugins/amoeba/platforms/cuda2/src/AmoebaCudaKernels.h
plugins/amoeba/platforms/cuda2/src/AmoebaCudaKernels.h
+2
-1
plugins/amoeba/platforms/cuda2/src/kernels/electrostaticPairForce.cu
...eba/platforms/cuda2/src/kernels/electrostaticPairForce.cu
+2
-2
plugins/amoeba/platforms/cuda2/src/kernels/multipoleElectrostatics.cu
...ba/platforms/cuda2/src/kernels/multipoleElectrostatics.cu
+11
-11
plugins/amoeba/platforms/cuda2/src/kernels/multipoleFixedField.cu
...amoeba/platforms/cuda2/src/kernels/multipoleFixedField.cu
+1
-1
plugins/amoeba/platforms/cuda2/src/kernels/multipoles.cu
plugins/amoeba/platforms/cuda2/src/kernels/multipoles.cu
+229
-12
plugins/amoeba/platforms/cuda2/tests/TestCudaAmoebaMultipoleForce.cpp
...ba/platforms/cuda2/tests/TestCudaAmoebaMultipoleForce.cpp
+1418
-0
No files found.
plugins/amoeba/platforms/cuda2/src/AmoebaCudaKernels.cpp
View file @
e5b7f0b3
...
@@ -866,7 +866,7 @@ private:
...
@@ -866,7 +866,7 @@ private:
CudaCalcAmoebaMultipoleForceKernel
::
CudaCalcAmoebaMultipoleForceKernel
(
std
::
string
name
,
const
Platform
&
platform
,
CudaContext
&
cu
,
System
&
system
)
:
CudaCalcAmoebaMultipoleForceKernel
::
CudaCalcAmoebaMultipoleForceKernel
(
std
::
string
name
,
const
Platform
&
platform
,
CudaContext
&
cu
,
System
&
system
)
:
CalcAmoebaMultipoleForceKernel
(
name
,
platform
),
cu
(
cu
),
system
(
system
),
hasInitializedScaleFactors
(
false
),
CalcAmoebaMultipoleForceKernel
(
name
,
platform
),
cu
(
cu
),
system
(
system
),
hasInitializedScaleFactors
(
false
),
multipoleParticles
(
NULL
),
molecularDipoles
(
NULL
),
molecularQuadrupoles
(
NULL
),
multipoleParticles
(
NULL
),
molecularDipoles
(
NULL
),
molecularQuadrupoles
(
NULL
),
labFrameDipoles
(
NULL
),
labFrameQuadrupoles
(
NULL
),
field
(
NULL
),
fieldPolar
(
NULL
),
dampingAndThole
(
NULL
),
labFrameDipoles
(
NULL
),
labFrameQuadrupoles
(
NULL
),
field
(
NULL
),
fieldPolar
(
NULL
),
torque
(
NULL
),
dampingAndThole
(
NULL
),
inducedDipole
(
NULL
),
inducedDipolePolar
(
NULL
),
currentEpsilon
(
NULL
),
polarizability
(
NULL
),
covalentFlags
(
NULL
),
polarizationGroupFlags
(
NULL
),
inducedDipole
(
NULL
),
inducedDipolePolar
(
NULL
),
currentEpsilon
(
NULL
),
polarizability
(
NULL
),
covalentFlags
(
NULL
),
polarizationGroupFlags
(
NULL
),
pmeGrid
(
NULL
)
{
pmeGrid
(
NULL
)
{
}
}
...
@@ -887,6 +887,8 @@ CudaCalcAmoebaMultipoleForceKernel::~CudaCalcAmoebaMultipoleForceKernel() {
...
@@ -887,6 +887,8 @@ CudaCalcAmoebaMultipoleForceKernel::~CudaCalcAmoebaMultipoleForceKernel() {
delete
field
;
delete
field
;
if
(
fieldPolar
!=
NULL
)
if
(
fieldPolar
!=
NULL
)
delete
fieldPolar
;
delete
fieldPolar
;
if
(
torque
!=
NULL
)
delete
torque
;
if
(
dampingAndThole
!=
NULL
)
if
(
dampingAndThole
!=
NULL
)
delete
dampingAndThole
;
delete
dampingAndThole
;
if
(
inducedDipole
!=
NULL
)
if
(
inducedDipole
!=
NULL
)
...
@@ -966,10 +968,12 @@ void CudaCalcAmoebaMultipoleForceKernel::initialize(const System& system, const
...
@@ -966,10 +968,12 @@ void CudaCalcAmoebaMultipoleForceKernel::initialize(const System& system, const
labFrameQuadrupoles
=
new
CudaArray
(
cu
,
5
*
paddedNumAtoms
,
elementSize
,
"labFrameQuadrupoles"
);
labFrameQuadrupoles
=
new
CudaArray
(
cu
,
5
*
paddedNumAtoms
,
elementSize
,
"labFrameQuadrupoles"
);
field
=
new
CudaArray
(
cu
,
3
*
paddedNumAtoms
,
sizeof
(
long
long
),
"field"
);
field
=
new
CudaArray
(
cu
,
3
*
paddedNumAtoms
,
sizeof
(
long
long
),
"field"
);
fieldPolar
=
new
CudaArray
(
cu
,
3
*
paddedNumAtoms
,
sizeof
(
long
long
),
"fieldPolar"
);
fieldPolar
=
new
CudaArray
(
cu
,
3
*
paddedNumAtoms
,
sizeof
(
long
long
),
"fieldPolar"
);
torque
=
new
CudaArray
(
cu
,
3
*
paddedNumAtoms
,
sizeof
(
long
long
),
"torque"
);
inducedDipole
=
new
CudaArray
(
cu
,
3
*
paddedNumAtoms
,
elementSize
,
"inducedDipole"
);
inducedDipole
=
new
CudaArray
(
cu
,
3
*
paddedNumAtoms
,
elementSize
,
"inducedDipole"
);
inducedDipolePolar
=
new
CudaArray
(
cu
,
3
*
paddedNumAtoms
,
elementSize
,
"inducedDipolePolar"
);
inducedDipolePolar
=
new
CudaArray
(
cu
,
3
*
paddedNumAtoms
,
elementSize
,
"inducedDipolePolar"
);
cu
.
addAutoclearBuffer
(
*
field
);
cu
.
addAutoclearBuffer
(
*
field
);
cu
.
addAutoclearBuffer
(
*
fieldPolar
);
cu
.
addAutoclearBuffer
(
*
fieldPolar
);
cu
.
addAutoclearBuffer
(
*
torque
);
// Record which atoms should be flagged as exclusions based on covalent groups, and determine
// Record which atoms should be flagged as exclusions based on covalent groups, and determine
// the values for the covalent group flags.
// the values for the covalent group flags.
...
@@ -1025,6 +1029,7 @@ void CudaCalcAmoebaMultipoleForceKernel::initialize(const System& system, const
...
@@ -1025,6 +1029,7 @@ void CudaCalcAmoebaMultipoleForceKernel::initialize(const System& system, const
CUmodule
module
=
cu
.
createModule
(
CudaKernelSources
::
vectorOps
+
CudaAmoebaKernelSources
::
multipoles
,
defines
);
CUmodule
module
=
cu
.
createModule
(
CudaKernelSources
::
vectorOps
+
CudaAmoebaKernelSources
::
multipoles
,
defines
);
computeMomentsKernel
=
cu
.
getKernel
(
module
,
"computeLabFrameMoments"
);
computeMomentsKernel
=
cu
.
getKernel
(
module
,
"computeLabFrameMoments"
);
recordInducedDipolesKernel
=
cu
.
getKernel
(
module
,
"recordInducedDipoles"
);
recordInducedDipolesKernel
=
cu
.
getKernel
(
module
,
"recordInducedDipoles"
);
mapTorqueKernel
=
cu
.
getKernel
(
module
,
"mapTorqueToForce"
);
module
=
cu
.
createModule
(
CudaKernelSources
::
vectorOps
+
CudaAmoebaKernelSources
::
multipoleFixedField
,
defines
);
module
=
cu
.
createModule
(
CudaKernelSources
::
vectorOps
+
CudaAmoebaKernelSources
::
multipoleFixedField
,
defines
);
computeFixedFieldKernel
=
cu
.
getKernel
(
module
,
"computeFixedField"
);
computeFixedFieldKernel
=
cu
.
getKernel
(
module
,
"computeFixedField"
);
stringstream
electrostaticsSource
;
stringstream
electrostaticsSource
;
...
@@ -1437,12 +1442,15 @@ double CudaCalcAmoebaMultipoleForceKernel::execute(ContextImpl& context, bool in
...
@@ -1437,12 +1442,15 @@ double CudaCalcAmoebaMultipoleForceKernel::execute(ContextImpl& context, bool in
// Compute electrostatic force.
// Compute electrostatic force.
void
*
electrostaticsArgs
[]
=
{
&
cu
.
getForce
().
getDevicePointer
(),
&
cu
.
getEnergyBuffer
().
getDevicePointer
(),
void
*
electrostaticsArgs
[]
=
{
&
cu
.
getForce
().
getDevicePointer
(),
&
torque
->
getDevicePointer
(),
&
cu
.
getEnergyBuffer
().
getDevicePointer
(),
&
cu
.
getPosq
().
getDevicePointer
(),
&
nb
.
getExclusionIndices
().
getDevicePointer
(),
&
nb
.
getExclusionRowIndices
().
getDevicePointer
(),
&
cu
.
getPosq
().
getDevicePointer
(),
&
nb
.
getExclusionIndices
().
getDevicePointer
(),
&
nb
.
getExclusionRowIndices
().
getDevicePointer
(),
&
covalentFlags
->
getDevicePointer
(),
&
polarizationGroupFlags
->
getDevicePointer
(),
&
startTileIndex
,
&
numTileIndices
,
&
covalentFlags
->
getDevicePointer
(),
&
polarizationGroupFlags
->
getDevicePointer
(),
&
startTileIndex
,
&
numTileIndices
,
&
labFrameDipoles
->
getDevicePointer
(),
&
labFrameQuadrupoles
->
getDevicePointer
(),
&
inducedDipole
->
getDevicePointer
(),
&
labFrameDipoles
->
getDevicePointer
(),
&
labFrameQuadrupoles
->
getDevicePointer
(),
&
inducedDipole
->
getDevicePointer
(),
&
inducedDipolePolar
->
getDevicePointer
(),
&
dampingAndThole
->
getDevicePointer
()};
&
inducedDipolePolar
->
getDevicePointer
(),
&
dampingAndThole
->
getDevicePointer
()};
cu
.
executeKernel
(
electrostaticsKernel
,
electrostaticsArgs
,
numForceThreadBlocks
*
forceThreadBlockSize
,
forceThreadBlockSize
);
cu
.
executeKernel
(
electrostaticsKernel
,
electrostaticsArgs
,
numForceThreadBlocks
*
forceThreadBlockSize
,
forceThreadBlockSize
);
void
*
mapTorqueArgs
[]
=
{
&
cu
.
getForce
().
getDevicePointer
(),
&
torque
->
getDevicePointer
(),
&
cu
.
getPosq
().
getDevicePointer
(),
&
multipoleParticles
->
getDevicePointer
()};
cu
.
executeKernel
(
mapTorqueKernel
,
mapTorqueArgs
,
cu
.
getNumAtoms
());
}
}
return
0.0
;
return
0.0
;
}
}
...
...
plugins/amoeba/platforms/cuda2/src/AmoebaCudaKernels.h
View file @
e5b7f0b3
...
@@ -388,6 +388,7 @@ private:
...
@@ -388,6 +388,7 @@ private:
CudaArray
*
labFrameQuadrupoles
;
CudaArray
*
labFrameQuadrupoles
;
CudaArray
*
field
;
CudaArray
*
field
;
CudaArray
*
fieldPolar
;
CudaArray
*
fieldPolar
;
CudaArray
*
torque
;
CudaArray
*
dampingAndThole
;
CudaArray
*
dampingAndThole
;
CudaArray
*
inducedDipole
;
CudaArray
*
inducedDipole
;
CudaArray
*
inducedDipolePolar
;
CudaArray
*
inducedDipolePolar
;
...
@@ -412,7 +413,7 @@ private:
...
@@ -412,7 +413,7 @@ private:
CudaArray
*
pmeAtomGridIndex
;
CudaArray
*
pmeAtomGridIndex
;
CudaSort
*
sort
;
CudaSort
*
sort
;
cufftHandle
fft
;
cufftHandle
fft
;
CUfunction
computeMomentsKernel
,
recordInducedDipolesKernel
,
computeFixedFieldKernel
,
electrostaticsKernel
;
CUfunction
computeMomentsKernel
,
recordInducedDipolesKernel
,
computeFixedFieldKernel
,
electrostaticsKernel
,
mapTorqueKernel
;
};
};
/**
/**
...
...
plugins/amoeba/platforms/cuda2/src/kernels/electrostaticPairForce.cu
View file @
e5b7f0b3
...
@@ -92,12 +92,12 @@ __device__ void computeOneInteractionT3(AtomData& atom1, volatile AtomData& atom
...
@@ -92,12 +92,12 @@ __device__ void computeOneInteractionT3(AtomData& atom1, volatile AtomData& atom
real
dsc7
=
rr7
*
scale7
*
dScale
;
real
dsc7
=
rr7
*
scale7
*
dScale
;
real
psc7
=
rr7
*
scale7
*
pScale
;
real
psc7
=
rr7
*
scale7
*
pScale
;
real
atom2quadrupoleZZ
=
1
-
atom2
.
quadrupoleXX
-
atom2
.
quadrupoleYY
;
real
atom2quadrupoleZZ
=
-
(
atom2
.
quadrupoleXX
+
atom2
.
quadrupoleYY
)
;
real
qJr_0
=
atom2
.
quadrupoleXX
*
xr
+
atom2
.
quadrupoleXY
*
yr
+
atom2
.
quadrupoleXZ
*
zr
;
real
qJr_0
=
atom2
.
quadrupoleXX
*
xr
+
atom2
.
quadrupoleXY
*
yr
+
atom2
.
quadrupoleXZ
*
zr
;
real
qJr_1
=
atom2
.
quadrupoleXY
*
xr
+
atom2
.
quadrupoleYY
*
yr
+
atom2
.
quadrupoleYZ
*
zr
;
real
qJr_1
=
atom2
.
quadrupoleXY
*
xr
+
atom2
.
quadrupoleYY
*
yr
+
atom2
.
quadrupoleYZ
*
zr
;
real
qJr_2
=
atom2
.
quadrupoleXZ
*
xr
+
atom2
.
quadrupoleYZ
*
yr
+
atom2quadrupoleZZ
*
zr
;
real
qJr_2
=
atom2
.
quadrupoleXZ
*
xr
+
atom2
.
quadrupoleYZ
*
yr
+
atom2quadrupoleZZ
*
zr
;
real
atom1quadrupoleZZ
=
1
-
atom1
.
quadrupoleXX
-
atom1
.
quadrupoleYY
;
real
atom1quadrupoleZZ
=
-
(
atom1
.
quadrupoleXX
+
atom1
.
quadrupoleYY
)
;
real
qIr_0
=
atom1
.
quadrupoleXX
*
xr
+
atom1
.
quadrupoleXY
*
yr
+
atom1
.
quadrupoleXZ
*
zr
;
real
qIr_0
=
atom1
.
quadrupoleXX
*
xr
+
atom1
.
quadrupoleXY
*
yr
+
atom1
.
quadrupoleXZ
*
zr
;
real
qIr_1
=
atom1
.
quadrupoleXY
*
xr
+
atom1
.
quadrupoleYY
*
yr
+
atom1
.
quadrupoleYZ
*
zr
;
real
qIr_1
=
atom1
.
quadrupoleXY
*
xr
+
atom1
.
quadrupoleYY
*
yr
+
atom1
.
quadrupoleYZ
*
zr
;
real
qIr_2
=
atom1
.
quadrupoleXZ
*
xr
+
atom1
.
quadrupoleYZ
*
yr
+
atom1quadrupoleZZ
*
zr
;
real
qIr_2
=
atom1
.
quadrupoleXZ
*
xr
+
atom1
.
quadrupoleYZ
*
yr
+
atom1quadrupoleZZ
*
zr
;
...
...
plugins/amoeba/platforms/cuda2/src/kernels/multipoleElectrostatics.cu
View file @
e5b7f0b3
...
@@ -56,7 +56,7 @@ __device__ float computePScaleFactor(uint2 covalent, unsigned int polarizationGr
...
@@ -56,7 +56,7 @@ __device__ float computePScaleFactor(uint2 covalent, unsigned int polarizationGr
* Compute electrostatic interactions.
* Compute electrostatic interactions.
*/
*/
extern
"C"
__global__
void
computeElectrostatics
(
extern
"C"
__global__
void
computeElectrostatics
(
unsigned
long
long
*
__restrict__
forceBuffers
,
real
*
__restrict__
energyBuffer
,
unsigned
long
long
*
__restrict__
forceBuffers
,
unsigned
long
long
*
__restrict__
torqueBuffers
,
real
*
__restrict__
energyBuffer
,
const
real4
*
__restrict__
posq
,
const
unsigned
int
*
__restrict__
exclusionIndices
,
const
unsigned
int
*
__restrict__
exclusionRowIndices
,
const
real4
*
__restrict__
posq
,
const
unsigned
int
*
__restrict__
exclusionIndices
,
const
unsigned
int
*
__restrict__
exclusionRowIndices
,
const
uint2
*
__restrict__
covalentFlags
,
const
unsigned
int
*
__restrict__
polarizationGroupFlags
,
unsigned
int
startTileIndex
,
unsigned
int
numTileIndices
,
const
uint2
*
__restrict__
covalentFlags
,
const
unsigned
int
*
__restrict__
polarizationGroupFlags
,
unsigned
int
startTileIndex
,
unsigned
int
numTileIndices
,
#ifdef USE_CUTOFF
#ifdef USE_CUTOFF
...
@@ -183,9 +183,9 @@ extern "C" __global__ void computeElectrostatics(
...
@@ -183,9 +183,9 @@ extern "C" __global__ void computeElectrostatics(
polarizationGroup
>>=
1
;
polarizationGroup
>>=
1
;
}
}
data
.
force
*=
ENERGY_SCALE_FACTOR
;
data
.
force
*=
ENERGY_SCALE_FACTOR
;
atomicAdd
(
&
f
or
c
eBuffers
[
atom1
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
data
.
force
.
x
*
0xFFFFFFFF
)));
atomicAdd
(
&
t
or
qu
eBuffers
[
atom1
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
data
.
force
.
x
*
0xFFFFFFFF
)));
atomicAdd
(
&
f
or
c
eBuffers
[
atom1
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
data
.
force
.
y
*
0xFFFFFFFF
)));
atomicAdd
(
&
t
or
qu
eBuffers
[
atom1
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
data
.
force
.
y
*
0xFFFFFFFF
)));
atomicAdd
(
&
f
or
c
eBuffers
[
atom1
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
data
.
force
.
z
*
0xFFFFFFFF
)));
atomicAdd
(
&
t
or
qu
eBuffers
[
atom1
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
data
.
force
.
z
*
0xFFFFFFFF
)));
}
}
else
{
else
{
// This is an off-diagonal tile.
// This is an off-diagonal tile.
...
@@ -338,18 +338,18 @@ extern "C" __global__ void computeElectrostatics(
...
@@ -338,18 +338,18 @@ extern "C" __global__ void computeElectrostatics(
localData
[
threadIdx
.
x
].
force
*=
ENERGY_SCALE_FACTOR
;
localData
[
threadIdx
.
x
].
force
*=
ENERGY_SCALE_FACTOR
;
if
(
pos
<
end
)
{
if
(
pos
<
end
)
{
unsigned
int
offset
=
x
*
TILE_SIZE
+
tgx
;
unsigned
int
offset
=
x
*
TILE_SIZE
+
tgx
;
atomicAdd
(
&
f
or
c
eBuffers
[
offset
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
data
.
force
.
x
*
0xFFFFFFFF
)));
atomicAdd
(
&
t
or
qu
eBuffers
[
offset
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
data
.
force
.
x
*
0xFFFFFFFF
)));
atomicAdd
(
&
f
or
c
eBuffers
[
offset
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
data
.
force
.
y
*
0xFFFFFFFF
)));
atomicAdd
(
&
t
or
qu
eBuffers
[
offset
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
data
.
force
.
y
*
0xFFFFFFFF
)));
atomicAdd
(
&
f
or
c
eBuffers
[
offset
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
data
.
force
.
z
*
0xFFFFFFFF
)));
atomicAdd
(
&
t
or
qu
eBuffers
[
offset
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
data
.
force
.
z
*
0xFFFFFFFF
)));
offset
=
y
*
TILE_SIZE
+
tgx
;
offset
=
y
*
TILE_SIZE
+
tgx
;
atomicAdd
(
&
f
or
c
eBuffers
[
offset
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
localData
[
threadIdx
.
x
].
force
.
x
*
0xFFFFFFFF
)));
atomicAdd
(
&
t
or
qu
eBuffers
[
offset
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
localData
[
threadIdx
.
x
].
force
.
x
*
0xFFFFFFFF
)));
atomicAdd
(
&
f
or
c
eBuffers
[
offset
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
localData
[
threadIdx
.
x
].
force
.
y
*
0xFFFFFFFF
)));
atomicAdd
(
&
t
or
qu
eBuffers
[
offset
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
localData
[
threadIdx
.
x
].
force
.
y
*
0xFFFFFFFF
)));
atomicAdd
(
&
f
or
c
eBuffers
[
offset
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
localData
[
threadIdx
.
x
].
force
.
z
*
0xFFFFFFFF
)));
atomicAdd
(
&
t
or
qu
eBuffers
[
offset
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
localData
[
threadIdx
.
x
].
force
.
z
*
0xFFFFFFFF
)));
}
}
}
}
}
}
}
}
pos
++
;
pos
++
;
}
while
(
pos
<
end
);
}
while
(
pos
<
end
);
energyBuffer
[
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
]
+=
energy
;
energyBuffer
[
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
]
+=
energy
*
ENERGY_SCALE_FACTOR
;
}
}
plugins/amoeba/platforms/cuda2/src/kernels/multipoleFixedField.cu
View file @
e5b7f0b3
...
@@ -19,7 +19,7 @@ inline __device__ void loadAtomData(AtomData& data, int atom, const real4* __res
...
@@ -19,7 +19,7 @@ inline __device__ void loadAtomData(AtomData& data, int atom, const real4* __res
data
.
quadrupoleXZ
=
labFrameQuadrupole
[
atom
*
5
+
2
];
data
.
quadrupoleXZ
=
labFrameQuadrupole
[
atom
*
5
+
2
];
data
.
quadrupoleYY
=
labFrameQuadrupole
[
atom
*
5
+
3
];
data
.
quadrupoleYY
=
labFrameQuadrupole
[
atom
*
5
+
3
];
data
.
quadrupoleYZ
=
labFrameQuadrupole
[
atom
*
5
+
4
];
data
.
quadrupoleYZ
=
labFrameQuadrupole
[
atom
*
5
+
4
];
data
.
quadrupoleZZ
=
1
-
data
.
quadrupoleXX
-
data
.
quadrupoleYY
;
data
.
quadrupoleZZ
=
-
(
data
.
quadrupoleXX
+
data
.
quadrupoleYY
)
;
float2
temp
=
dampingAndThole
[
atom
];
float2
temp
=
dampingAndThole
[
atom
];
data
.
damp
=
temp
.
x
;
data
.
damp
=
temp
.
x
;
data
.
thole
=
temp
.
y
;
data
.
thole
=
temp
.
y
;
...
...
plugins/amoeba/platforms/cuda2/src/kernels/multipoles.cu
View file @
e5b7f0b3
...
@@ -170,27 +170,27 @@ extern "C" __global__ void computeLabFrameMoments(real4* __restrict__ posq, int4
...
@@ -170,27 +170,27 @@ extern "C" __global__ void computeLabFrameMoments(real4* __restrict__ posq, int4
real
mPoleXZ
=
molecularQuadrupoles
[
offset
+
2
];
real
mPoleXZ
=
molecularQuadrupoles
[
offset
+
2
];
real
mPoleYY
=
molecularQuadrupoles
[
offset
+
3
];
real
mPoleYY
=
molecularQuadrupoles
[
offset
+
3
];
real
mPoleYZ
=
molecularQuadrupoles
[
offset
+
4
];
real
mPoleYZ
=
molecularQuadrupoles
[
offset
+
4
];
real
mPoleZZ
=
1
-
mPoleXX
-
mPoleYY
;
real
mPoleZZ
=
-
(
mPoleXX
+
mPoleYY
)
;
if
(
reverse
)
{
if
(
reverse
)
{
mPoleXY
*=
-
1
;
mPoleXY
*=
-
1
;
mPoleYZ
*=
-
1
;
mPoleYZ
*=
-
1
;
}
}
labFrameQuadrupoles
[
offset
]
=
vectorX
.
x
*
(
vectorX
.
x
*
mPoleXX
+
vectorY
.
x
*
mPoleXY
+
vectorZ
.
x
*
mPoleXZ
)
;
labFrameQuadrupoles
[
offset
]
=
vectorX
.
x
*
(
vectorX
.
x
*
mPoleXX
+
vectorY
.
x
*
mPoleXY
+
vectorZ
.
x
*
mPoleXZ
)
+
vectorY
.
x
*
(
vectorX
.
x
*
mPoleXY
+
vectorY
.
x
*
mPoleYY
+
vectorZ
.
x
*
mPoleYZ
)
;
+
vectorY
.
x
*
(
vectorX
.
x
*
mPoleXY
+
vectorY
.
x
*
mPoleYY
+
vectorZ
.
x
*
mPoleYZ
)
+
vectorZ
.
x
*
(
vectorX
.
x
*
mPoleXZ
+
vectorY
.
x
*
mPoleYZ
+
vectorZ
.
x
*
mPoleZZ
);
+
vectorZ
.
x
*
(
vectorX
.
x
*
mPoleXZ
+
vectorY
.
x
*
mPoleYZ
+
vectorZ
.
x
*
mPoleZZ
);
labFrameQuadrupoles
[
offset
+
1
]
=
vectorX
.
x
*
(
vectorX
.
y
*
mPoleXX
+
vectorY
.
y
*
mPoleXY
+
vectorZ
.
y
*
mPoleXZ
)
;
labFrameQuadrupoles
[
offset
+
1
]
=
vectorX
.
x
*
(
vectorX
.
y
*
mPoleXX
+
vectorY
.
y
*
mPoleXY
+
vectorZ
.
y
*
mPoleXZ
)
+
vectorY
.
x
*
(
vectorX
.
y
*
mPoleXY
+
vectorY
.
y
*
mPoleYY
+
vectorZ
.
y
*
mPoleYZ
)
;
+
vectorY
.
x
*
(
vectorX
.
y
*
mPoleXY
+
vectorY
.
y
*
mPoleYY
+
vectorZ
.
y
*
mPoleYZ
)
+
vectorZ
.
x
*
(
vectorX
.
y
*
mPoleXZ
+
vectorY
.
y
*
mPoleYZ
+
vectorZ
.
y
*
mPoleZZ
);
+
vectorZ
.
x
*
(
vectorX
.
y
*
mPoleXZ
+
vectorY
.
y
*
mPoleYZ
+
vectorZ
.
y
*
mPoleZZ
);
labFrameQuadrupoles
[
offset
+
2
]
=
vectorX
.
x
*
(
vectorX
.
z
*
mPoleXX
+
vectorY
.
z
*
mPoleXY
+
vectorZ
.
z
*
mPoleXZ
)
;
labFrameQuadrupoles
[
offset
+
2
]
=
vectorX
.
x
*
(
vectorX
.
z
*
mPoleXX
+
vectorY
.
z
*
mPoleXY
+
vectorZ
.
z
*
mPoleXZ
)
+
vectorY
.
x
*
(
vectorX
.
z
*
mPoleXY
+
vectorY
.
z
*
mPoleYY
+
vectorZ
.
z
*
mPoleYZ
)
;
+
vectorY
.
x
*
(
vectorX
.
z
*
mPoleXY
+
vectorY
.
z
*
mPoleYY
+
vectorZ
.
z
*
mPoleYZ
)
+
vectorZ
.
x
*
(
vectorX
.
z
*
mPoleXZ
+
vectorY
.
z
*
mPoleYZ
+
vectorZ
.
z
*
mPoleZZ
);
+
vectorZ
.
x
*
(
vectorX
.
z
*
mPoleXZ
+
vectorY
.
z
*
mPoleYZ
+
vectorZ
.
z
*
mPoleZZ
);
labFrameQuadrupoles
[
offset
+
3
]
=
vectorX
.
y
*
(
vectorX
.
y
*
mPoleXX
+
vectorY
.
y
*
mPoleXY
+
vectorZ
.
y
*
mPoleXZ
)
;
labFrameQuadrupoles
[
offset
+
3
]
=
vectorX
.
y
*
(
vectorX
.
y
*
mPoleXX
+
vectorY
.
y
*
mPoleXY
+
vectorZ
.
y
*
mPoleXZ
)
+
vectorY
.
y
*
(
vectorX
.
y
*
mPoleXY
+
vectorY
.
y
*
mPoleYY
+
vectorZ
.
y
*
mPoleYZ
)
;
+
vectorY
.
y
*
(
vectorX
.
y
*
mPoleXY
+
vectorY
.
y
*
mPoleYY
+
vectorZ
.
y
*
mPoleYZ
)
+
vectorZ
.
y
*
(
vectorX
.
y
*
mPoleXZ
+
vectorY
.
y
*
mPoleYZ
+
vectorZ
.
y
*
mPoleZZ
);
+
vectorZ
.
y
*
(
vectorX
.
y
*
mPoleXZ
+
vectorY
.
y
*
mPoleYZ
+
vectorZ
.
y
*
mPoleZZ
);
labFrameQuadrupoles
[
offset
+
4
]
=
vectorX
.
y
*
(
vectorX
.
z
*
mPoleXX
+
vectorY
.
z
*
mPoleXY
+
vectorZ
.
z
*
mPoleXZ
)
;
labFrameQuadrupoles
[
offset
+
4
]
=
vectorX
.
y
*
(
vectorX
.
z
*
mPoleXX
+
vectorY
.
z
*
mPoleXY
+
vectorZ
.
z
*
mPoleXZ
)
+
vectorY
.
y
*
(
vectorX
.
z
*
mPoleXY
+
vectorY
.
z
*
mPoleYY
+
vectorZ
.
z
*
mPoleYZ
)
;
+
vectorY
.
y
*
(
vectorX
.
z
*
mPoleXY
+
vectorY
.
z
*
mPoleYY
+
vectorZ
.
z
*
mPoleYZ
)
+
vectorZ
.
y
*
(
vectorX
.
z
*
mPoleXZ
+
vectorY
.
z
*
mPoleYZ
+
vectorZ
.
z
*
mPoleZZ
);
+
vectorZ
.
y
*
(
vectorX
.
z
*
mPoleXZ
+
vectorY
.
z
*
mPoleYZ
+
vectorZ
.
z
*
mPoleZZ
);
}
}
}
}
...
@@ -208,3 +208,220 @@ extern "C" __global__ void recordInducedDipoles(const long long* __restrict__ fi
...
@@ -208,3 +208,220 @@ extern "C" __global__ void recordInducedDipoles(const long long* __restrict__ fi
inducedDipolePolar
[
3
*
atom
+
2
]
=
scale
*
fieldPolarBuffers
[
atom
+
PADDED_NUM_ATOMS
*
2
];
inducedDipolePolar
[
3
*
atom
+
2
]
=
scale
*
fieldPolarBuffers
[
atom
+
PADDED_NUM_ATOMS
*
2
];
}
}
}
}
/**
* Convert a real4 to a real3 by removing its last element.
*/
inline
__device__
real3
trim
(
real4
v
)
{
return
make_real3
(
v
.
x
,
v
.
y
,
v
.
z
);
}
/**
* Normalize a vector and return what its magnitude was.
*/
inline
__device__
real
normVector
(
real3
&
v
)
{
real
n
=
SQRT
(
dot
(
v
,
v
));
v
*=
(
n
>
0
?
RECIP
(
n
)
:
0
);
return
n
;
}
extern
"C"
__global__
void
mapTorqueToForce
(
unsigned
long
long
*
__restrict__
forceBuffers
,
const
long
long
*
__restrict__
torqueBuffers
,
const
real4
*
__restrict__
posq
,
const
int4
*
__restrict__
multipoleParticles
)
{
const
int
U
=
0
;
const
int
V
=
1
;
const
int
W
=
2
;
const
int
R
=
3
;
const
int
S
=
4
;
const
int
UV
=
5
;
const
int
UW
=
6
;
const
int
VW
=
7
;
const
int
UR
=
8
;
const
int
US
=
9
;
const
int
VS
=
10
;
const
int
WS
=
11
;
const
int
LastVectorIndex
=
12
;
const
int
X
=
0
;
const
int
Y
=
1
;
const
int
Z
=
2
;
const
int
I
=
3
;
const
real
torqueScale
=
RECIP
((
double
)
0xFFFFFFFF
);
real3
forces
[
4
];
real
norms
[
LastVectorIndex
];
real3
vector
[
LastVectorIndex
];
real
angles
[
LastVectorIndex
][
2
];
for
(
int
atom
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
atom
<
NUM_ATOMS
;
atom
+=
gridDim
.
x
*
blockDim
.
x
)
{
int4
particles
=
multipoleParticles
[
atom
];
int
axisAtom
=
particles
.
z
;
int
axisType
=
particles
.
w
;
// NoAxisType
if
(
axisType
<
5
&&
particles
.
z
>=
0
)
{
real3
atomPos
=
trim
(
posq
[
atom
]);
vector
[
U
]
=
atomPos
-
trim
(
posq
[
axisAtom
]);
norms
[
U
]
=
normVector
(
vector
[
U
]);
if
(
axisType
!=
4
&&
particles
.
x
>=
0
)
vector
[
V
]
=
atomPos
-
trim
(
posq
[
particles
.
x
]);
else
vector
[
V
]
=
make_real3
(
0.1
f
);
norms
[
V
]
=
normVector
(
vector
[
V
]);
// W = UxV
if
(
axisType
<
2
||
axisType
>
3
)
vector
[
W
]
=
cross
(
vector
[
U
],
vector
[
V
]);
else
vector
[
W
]
=
atomPos
-
trim
(
posq
[
particles
.
y
]);
norms
[
W
]
=
normVector
(
vector
[
W
]);
vector
[
UV
]
=
cross
(
vector
[
V
],
vector
[
U
]);
vector
[
UW
]
=
cross
(
vector
[
W
],
vector
[
U
]);
vector
[
VW
]
=
cross
(
vector
[
W
],
vector
[
V
]);
norms
[
UV
]
=
normVector
(
vector
[
UV
]);
norms
[
UW
]
=
normVector
(
vector
[
UW
]);
norms
[
VW
]
=
normVector
(
vector
[
VW
]);
angles
[
UV
][
0
]
=
dot
(
vector
[
U
],
vector
[
V
]);
angles
[
UV
][
1
]
=
SQRT
(
1
-
angles
[
UV
][
0
]
*
angles
[
UV
][
0
]);
angles
[
UW
][
0
]
=
dot
(
vector
[
U
],
vector
[
W
]);
angles
[
UW
][
1
]
=
SQRT
(
1
-
angles
[
UW
][
0
]
*
angles
[
UW
][
0
]);
angles
[
VW
][
0
]
=
dot
(
vector
[
V
],
vector
[
W
]);
angles
[
VW
][
1
]
=
SQRT
(
1
-
angles
[
VW
][
0
]
*
angles
[
VW
][
0
]);
real
dphi
[
3
];
real3
torque
=
make_real3
(
torqueScale
*
torqueBuffers
[
atom
],
torqueScale
*
torqueBuffers
[
atom
+
PADDED_NUM_ATOMS
],
torqueScale
*
torqueBuffers
[
atom
+
PADDED_NUM_ATOMS
*
2
]);
dphi
[
U
]
=
-
dot
(
vector
[
U
],
torque
);
dphi
[
V
]
=
-
dot
(
vector
[
V
],
torque
);
dphi
[
W
]
=
-
dot
(
vector
[
W
],
torque
);
// z-then-x and bisector
if
(
axisType
==
0
||
axisType
==
1
)
{
real
factor1
=
dphi
[
V
]
/
(
norms
[
U
]
*
angles
[
UV
][
1
]);
real
factor2
=
dphi
[
W
]
/
(
norms
[
U
]);
real
factor3
=
-
dphi
[
U
]
/
(
norms
[
V
]
*
angles
[
UV
][
1
]);
real
factor4
=
0
;
if
(
axisType
==
1
)
{
factor2
*=
0.5
f
;
factor4
=
0.5
f
*
dphi
[
W
]
/
(
norms
[
V
]);
}
forces
[
Z
]
=
vector
[
UV
]
*
factor1
+
factor2
*
vector
[
UW
];
forces
[
X
]
=
vector
[
UV
]
*
factor3
+
factor4
*
vector
[
VW
];
forces
[
I
]
=
-
(
forces
[
X
]
+
forces
[
Z
]);
forces
[
Y
]
=
make_real3
(
0
);
}
else
if
(
axisType
==
2
)
{
// z-bisect
vector
[
R
]
=
vector
[
V
]
+
vector
[
W
];
vector
[
S
]
=
cross
(
vector
[
U
],
vector
[
R
]);
norms
[
R
]
=
normVector
(
vector
[
R
]);
norms
[
S
]
=
normVector
(
vector
[
S
]);
vector
[
UR
]
=
cross
(
vector
[
R
],
vector
[
U
]);
vector
[
US
]
=
cross
(
vector
[
S
],
vector
[
U
]);
vector
[
VS
]
=
cross
(
vector
[
S
],
vector
[
V
]);
vector
[
WS
]
=
cross
(
vector
[
S
],
vector
[
W
]);
norms
[
UR
]
=
normVector
(
vector
[
UR
]);
norms
[
US
]
=
normVector
(
vector
[
US
]);
norms
[
VS
]
=
normVector
(
vector
[
VS
]);
norms
[
WS
]
=
normVector
(
vector
[
WS
]);
angles
[
UR
][
0
]
=
dot
(
vector
[
U
],
vector
[
R
]);
angles
[
UR
][
1
]
=
SQRT
(
1
-
angles
[
UR
][
0
]
*
angles
[
UR
][
0
]);
angles
[
US
][
0
]
=
dot
(
vector
[
U
],
vector
[
S
]);
angles
[
US
][
1
]
=
SQRT
(
1
-
angles
[
US
][
0
]
*
angles
[
US
][
0
]);
angles
[
VS
][
0
]
=
dot
(
vector
[
V
],
vector
[
S
]);
angles
[
VS
][
1
]
=
SQRT
(
1
-
angles
[
VS
][
0
]
*
angles
[
VS
][
0
]);
angles
[
WS
][
0
]
=
dot
(
vector
[
W
],
vector
[
S
]);
angles
[
WS
][
1
]
=
SQRT
(
1
-
angles
[
WS
][
0
]
*
angles
[
WS
][
0
]);
real3
t1
=
vector
[
V
]
-
vector
[
S
]
*
angles
[
VS
][
0
];
real3
t2
=
vector
[
W
]
-
vector
[
S
]
*
angles
[
WS
][
0
];
normVector
(
t1
);
normVector
(
t2
);
real
ut1cos
=
dot
(
vector
[
U
],
t1
);
real
ut1sin
=
SQRT
(
1
-
ut1cos
*
ut1cos
);
real
ut2cos
=
dot
(
vector
[
U
],
t2
);
real
ut2sin
=
SQRT
(
1
-
ut2cos
*
ut2cos
);
real
dphiR
=
-
dot
(
vector
[
R
],
torque
);
real
dphiS
=
-
dot
(
vector
[
S
],
torque
);
real
factor1
=
dphiR
/
(
norms
[
U
]
*
angles
[
UR
][
1
]);
real
factor2
=
dphiS
/
(
norms
[
U
]);
real
factor3
=
dphi
[
U
]
/
(
norms
[
V
]
*
(
ut1sin
+
ut2sin
));
real
factor4
=
dphi
[
U
]
/
(
norms
[
W
]
*
(
ut1sin
+
ut2sin
));
forces
[
Z
]
=
vector
[
UR
]
*
factor1
+
factor2
*
vector
[
US
];
forces
[
X
]
=
(
angles
[
VS
][
1
]
*
vector
[
S
]
-
angles
[
VS
][
0
]
*
t1
)
*
factor3
;
forces
[
Y
]
=
(
angles
[
WS
][
1
]
*
vector
[
S
]
-
angles
[
WS
][
0
]
*
t2
)
*
factor4
;
forces
[
I
]
=
-
(
forces
[
X
]
+
forces
[
Y
]
+
forces
[
Z
]);
}
else
if
(
axisType
==
3
)
{
// 3-fold
forces
[
Z
]
=
(
vector
[
UW
]
*
dphi
[
W
]
/
(
norms
[
U
]
*
angles
[
UW
][
1
])
+
vector
[
UV
]
*
dphi
[
V
]
/
(
norms
[
U
]
*
angles
[
UV
][
1
])
-
vector
[
UW
]
*
dphi
[
U
]
/
(
norms
[
U
]
*
angles
[
UW
][
1
])
-
vector
[
UV
]
*
dphi
[
U
]
/
(
norms
[
U
]
*
angles
[
UV
][
1
]))
/
3
;
forces
[
X
]
=
(
vector
[
VW
]
*
dphi
[
W
]
/
(
norms
[
V
]
*
angles
[
VW
][
1
])
-
vector
[
UV
]
*
dphi
[
U
]
/
(
norms
[
V
]
*
angles
[
UV
][
1
])
-
vector
[
VW
]
*
dphi
[
V
]
/
(
norms
[
V
]
*
angles
[
VW
][
1
])
+
vector
[
UV
]
*
dphi
[
V
]
/
(
norms
[
V
]
*
angles
[
UV
][
1
]))
/
3
;
forces
[
Y
]
=
(
-
vector
[
UW
]
*
dphi
[
U
]
/
(
norms
[
W
]
*
angles
[
UW
][
1
])
-
vector
[
VW
]
*
dphi
[
V
]
/
(
norms
[
W
]
*
angles
[
VW
][
1
])
+
vector
[
UW
]
*
dphi
[
W
]
/
(
norms
[
W
]
*
angles
[
UW
][
1
])
+
vector
[
VW
]
*
dphi
[
W
]
/
(
norms
[
W
]
*
angles
[
VW
][
1
]))
/
3
;
forces
[
I
]
=
-
(
forces
[
X
]
+
forces
[
Y
]
+
forces
[
Z
]);
}
else
if
(
axisType
==
4
)
{
// z-only
forces
[
Z
]
=
vector
[
UV
]
*
dphi
[
V
]
/
(
norms
[
U
]
*
angles
[
UV
][
1
]);
forces
[
X
]
=
make_float3
(
0
);
forces
[
Y
]
=
make_float3
(
0
);
forces
[
I
]
=
-
forces
[
Z
];
}
else
{
forces
[
Z
]
=
make_float3
(
0
);
forces
[
X
]
=
make_float3
(
0
);
forces
[
Y
]
=
make_float3
(
0
);
forces
[
I
]
=
make_float3
(
0
);
}
// Store results
atomicAdd
(
&
forceBuffers
[
particles
.
z
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
forces
[
Z
].
x
*
0xFFFFFFFF
)));
atomicAdd
(
&
forceBuffers
[
particles
.
z
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
forces
[
Z
].
y
*
0xFFFFFFFF
)));
atomicAdd
(
&
forceBuffers
[
particles
.
z
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
forces
[
Z
].
z
*
0xFFFFFFFF
)));
if
(
axisType
!=
4
)
{
atomicAdd
(
&
forceBuffers
[
particles
.
x
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
forces
[
X
].
x
*
0xFFFFFFFF
)));
atomicAdd
(
&
forceBuffers
[
particles
.
x
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
forces
[
X
].
y
*
0xFFFFFFFF
)));
atomicAdd
(
&
forceBuffers
[
particles
.
x
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
forces
[
X
].
z
*
0xFFFFFFFF
)));
}
if
((
axisType
==
2
||
axisType
==
3
)
&&
particles
.
y
>
-
1
)
{
atomicAdd
(
&
forceBuffers
[
particles
.
y
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
forces
[
Y
].
x
*
0xFFFFFFFF
)));
atomicAdd
(
&
forceBuffers
[
particles
.
y
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
forces
[
Y
].
y
*
0xFFFFFFFF
)));
atomicAdd
(
&
forceBuffers
[
particles
.
y
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
forces
[
Y
].
z
*
0xFFFFFFFF
)));
}
atomicAdd
(
&
forceBuffers
[
atom
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
forces
[
I
].
x
*
0xFFFFFFFF
)));
atomicAdd
(
&
forceBuffers
[
atom
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
forces
[
I
].
y
*
0xFFFFFFFF
)));
atomicAdd
(
&
forceBuffers
[
atom
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
forces
[
I
].
z
*
0xFFFFFFFF
)));
}
}
}
plugins/amoeba/platforms/cuda2/tests/TestCudaAmoebaMultipoleForce.cpp
0 → 100644
View file @
e5b7f0b3
/* -------------------------------------------------------------------------- *
* OpenMMAmoeba *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2008 Stanford University and the Authors. *
* Authors: Mark Friedrichs *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
/**
* This tests the CUDA implementation of CudaAmoebaMultipoleForce.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "OpenMMAmoeba.h"
#include "AmoebaTinkerParameterFile.h"
#include "openmm/System.h"
#include "openmm/AmoebaMultipoleForce.h"
#include "openmm/LangevinIntegrator.h"
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <stdio.h>
#define ASSERT_EQUAL_TOL_MOD(expected, found, tol, testname) {double _scale_ = std::abs(expected) > 1.0 ? std::abs(expected) : 1.0; if (!(std::abs((expected)-(found))/_scale_ <= (tol))) {std::stringstream details; details << testname << " Expected "<<(expected)<<", found "<<(found); throwException(__FILE__, __LINE__, details.str());}};
#define ASSERT_EQUAL_VEC_MOD(expected, found, tol,testname) {ASSERT_EQUAL_TOL_MOD((expected)[0], (found)[0], (tol),(testname)); ASSERT_EQUAL_TOL_MOD((expected)[1], (found)[1], (tol),(testname)); ASSERT_EQUAL_TOL_MOD((expected)[2], (found)[2], (tol),(testname));};
using
namespace
OpenMM
;
const
double
TOL
=
1e-4
;
// setup for 2 ammonia molecules
static
void
setupAndGetForcesEnergyMultipoleAmmonia
(
AmoebaMultipoleForce
::
AmoebaNonbondedMethod
nonbondedMethod
,
AmoebaMultipoleForce
::
AmoebaPolarizationType
polarizationType
,
double
cutoff
,
int
inputPmeGridDimension
,
std
::
vector
<
Vec3
>&
forces
,
double
&
energy
,
FILE
*
log
){
// beginning of Multipole setup
System
system
;
// box
double
boxDimension
=
0.6
;
Vec3
a
(
boxDimension
,
0.0
,
0.0
);
Vec3
b
(
0.0
,
boxDimension
,
0.0
);
Vec3
c
(
0.0
,
0.0
,
boxDimension
);
system
.
setDefaultPeriodicBoxVectors
(
a
,
b
,
c
);
AmoebaMultipoleForce
*
amoebaMultipoleForce
=
new
AmoebaMultipoleForce
();;
int
numberOfParticles
=
8
;
amoebaMultipoleForce
->
setNonbondedMethod
(
nonbondedMethod
);
amoebaMultipoleForce
->
setPolarizationType
(
polarizationType
);
amoebaMultipoleForce
->
setCutoffDistance
(
cutoff
);
amoebaMultipoleForce
->
setMutualInducedTargetEpsilon
(
1.0e-06
);
amoebaMultipoleForce
->
setMutualInducedMaxIterations
(
500
);
amoebaMultipoleForce
->
setAEwald
(
1.4024714e+01
);
amoebaMultipoleForce
->
setEwaldErrorTolerance
(
1.0e-04
);
std
::
vector
<
int
>
pmeGridDimension
(
3
);
pmeGridDimension
[
0
]
=
pmeGridDimension
[
1
]
=
pmeGridDimension
[
2
]
=
inputPmeGridDimension
;
amoebaMultipoleForce
->
setPmeGridDimensions
(
pmeGridDimension
);
std
::
vector
<
double
>
nitrogenMolecularDipole
(
3
);
std
::
vector
<
double
>
nitrogenMolecularQuadrupole
(
9
);
nitrogenMolecularDipole
[
0
]
=
8.3832254e-03
;
nitrogenMolecularDipole
[
1
]
=
0.0000000e+00
;
nitrogenMolecularDipole
[
2
]
=
3.4232474e-03
;
nitrogenMolecularQuadrupole
[
0
]
=
-
4.0406249e-04
;
nitrogenMolecularQuadrupole
[
1
]
=
0.0000000e+00
;
nitrogenMolecularQuadrupole
[
2
]
=
-
2.6883671e-04
;
nitrogenMolecularQuadrupole
[
3
]
=
0.0000000e+00
;
nitrogenMolecularQuadrupole
[
4
]
=
2.5463927e-04
;
nitrogenMolecularQuadrupole
[
5
]
=
0.0000000e+00
;
nitrogenMolecularQuadrupole
[
6
]
=
-
2.6883671e-04
;
nitrogenMolecularQuadrupole
[
7
]
=
0.0000000e+00
;
nitrogenMolecularQuadrupole
[
8
]
=
1.4942322e-04
;
// first N
system
.
addParticle
(
1.4007000e+01
);
amoebaMultipoleForce
->
addParticle
(
-
5.7960000e-01
,
nitrogenMolecularDipole
,
nitrogenMolecularQuadrupole
,
2
,
1
,
2
,
3
,
3.9000000e-01
,
3.1996314e-01
,
1.0730000e-03
);
// 3 H attached to first N
std
::
vector
<
double
>
hydrogenMolecularDipole
(
3
);
std
::
vector
<
double
>
hydrogenMolecularQuadrupole
(
9
);
hydrogenMolecularDipole
[
0
]
=
-
1.7388763e-03
;
hydrogenMolecularDipole
[
1
]
=
0.0000000e+00
;
hydrogenMolecularDipole
[
2
]
=
-
4.6837475e-03
;
hydrogenMolecularQuadrupole
[
0
]
=
-
4.4253841e-05
;
hydrogenMolecularQuadrupole
[
1
]
=
0.0000000e+00
;
hydrogenMolecularQuadrupole
[
2
]
=
1.5429571e-05
;
hydrogenMolecularQuadrupole
[
3
]
=
0.0000000e+00
;
hydrogenMolecularQuadrupole
[
4
]
=
4.1798924e-05
;
hydrogenMolecularQuadrupole
[
5
]
=
0.0000000e+00
;
hydrogenMolecularQuadrupole
[
6
]
=
1.5429571e-05
;
hydrogenMolecularQuadrupole
[
7
]
=
0.0000000e+00
;
hydrogenMolecularQuadrupole
[
8
]
=
2.4549167e-06
;
system
.
addParticle
(
1.0080000e+00
);
system
.
addParticle
(
1.0080000e+00
);
system
.
addParticle
(
1.0080000e+00
);
amoebaMultipoleForce
->
addParticle
(
1.9320000e-01
,
hydrogenMolecularDipole
,
hydrogenMolecularQuadrupole
,
2
,
0
,
2
,
3
,
3.9000000e-01
,
2.8135002e-01
,
4.9600000e-04
);
amoebaMultipoleForce
->
addParticle
(
1.9320000e-01
,
hydrogenMolecularDipole
,
hydrogenMolecularQuadrupole
,
2
,
0
,
1
,
3
,
3.9000000e-01
,
2.8135002e-01
,
4.9600000e-04
);
amoebaMultipoleForce
->
addParticle
(
1.9320000e-01
,
hydrogenMolecularDipole
,
hydrogenMolecularQuadrupole
,
2
,
0
,
1
,
2
,
3.9000000e-01
,
2.8135002e-01
,
4.9600000e-04
);
// second N
system
.
addParticle
(
1.4007000e+01
);
amoebaMultipoleForce
->
addParticle
(
-
5.7960000e-01
,
nitrogenMolecularDipole
,
nitrogenMolecularQuadrupole
,
2
,
5
,
6
,
7
,
3.9000000e-01
,
3.1996314e-01
,
1.0730000e-03
);
// 3 H attached to second N
system
.
addParticle
(
1.0080000e+00
);
system
.
addParticle
(
1.0080000e+00
);
system
.
addParticle
(
1.0080000e+00
);
amoebaMultipoleForce
->
addParticle
(
1.9320000e-01
,
hydrogenMolecularDipole
,
hydrogenMolecularQuadrupole
,
2
,
4
,
6
,
7
,
3.9000000e-01
,
2.8135002e-01
,
4.9600000e-04
);
amoebaMultipoleForce
->
addParticle
(
1.9320000e-01
,
hydrogenMolecularDipole
,
hydrogenMolecularQuadrupole
,
2
,
4
,
5
,
7
,
3.9000000e-01
,
2.8135002e-01
,
4.9600000e-04
);
amoebaMultipoleForce
->
addParticle
(
1.9320000e-01
,
hydrogenMolecularDipole
,
hydrogenMolecularQuadrupole
,
2
,
4
,
5
,
6
,
3.9000000e-01
,
2.8135002e-01
,
4.9600000e-04
);
// covalent maps
std
::
vector
<
int
>
covalentMap
;
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
1
);
covalentMap
.
push_back
(
2
);
covalentMap
.
push_back
(
3
);
amoebaMultipoleForce
->
setCovalentMap
(
0
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
0
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
0
);
covalentMap
.
push_back
(
1
);
covalentMap
.
push_back
(
2
);
covalentMap
.
push_back
(
3
);
amoebaMultipoleForce
->
setCovalentMap
(
0
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
4
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
0
);
amoebaMultipoleForce
->
setCovalentMap
(
1
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
0
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
2
);
covalentMap
.
push_back
(
3
);
amoebaMultipoleForce
->
setCovalentMap
(
1
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
1
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
0
);
covalentMap
.
push_back
(
1
);
covalentMap
.
push_back
(
2
);
covalentMap
.
push_back
(
3
);
amoebaMultipoleForce
->
setCovalentMap
(
1
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
4
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
0
);
amoebaMultipoleForce
->
setCovalentMap
(
2
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
0
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
1
);
covalentMap
.
push_back
(
3
);
amoebaMultipoleForce
->
setCovalentMap
(
2
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
1
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
0
);
covalentMap
.
push_back
(
1
);
covalentMap
.
push_back
(
2
);
covalentMap
.
push_back
(
3
);
amoebaMultipoleForce
->
setCovalentMap
(
2
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
4
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
0
);
amoebaMultipoleForce
->
setCovalentMap
(
3
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
0
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
1
);
covalentMap
.
push_back
(
2
);
amoebaMultipoleForce
->
setCovalentMap
(
3
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
1
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
0
);
covalentMap
.
push_back
(
1
);
covalentMap
.
push_back
(
2
);
covalentMap
.
push_back
(
3
);
amoebaMultipoleForce
->
setCovalentMap
(
3
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
4
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
5
);
covalentMap
.
push_back
(
6
);
covalentMap
.
push_back
(
7
);
amoebaMultipoleForce
->
setCovalentMap
(
4
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
0
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
4
);
covalentMap
.
push_back
(
5
);
covalentMap
.
push_back
(
6
);
covalentMap
.
push_back
(
7
);
amoebaMultipoleForce
->
setCovalentMap
(
4
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
4
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
4
);
amoebaMultipoleForce
->
setCovalentMap
(
5
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
0
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
6
);
covalentMap
.
push_back
(
7
);
amoebaMultipoleForce
->
setCovalentMap
(
5
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
1
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
4
);
covalentMap
.
push_back
(
5
);
covalentMap
.
push_back
(
6
);
covalentMap
.
push_back
(
7
);
amoebaMultipoleForce
->
setCovalentMap
(
5
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
4
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
4
);
amoebaMultipoleForce
->
setCovalentMap
(
6
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
0
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
5
);
covalentMap
.
push_back
(
7
);
amoebaMultipoleForce
->
setCovalentMap
(
6
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
1
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
4
);
covalentMap
.
push_back
(
5
);
covalentMap
.
push_back
(
6
);
covalentMap
.
push_back
(
7
);
amoebaMultipoleForce
->
setCovalentMap
(
6
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
4
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
4
);
amoebaMultipoleForce
->
setCovalentMap
(
7
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
0
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
5
);
covalentMap
.
push_back
(
6
);
amoebaMultipoleForce
->
setCovalentMap
(
7
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
1
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
4
);
covalentMap
.
push_back
(
5
);
covalentMap
.
push_back
(
6
);
covalentMap
.
push_back
(
7
);
amoebaMultipoleForce
->
setCovalentMap
(
7
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
4
),
covalentMap
);
// 1-2 bonds needed
AmoebaHarmonicBondForce
*
amoebaHarmonicBondForce
=
new
AmoebaHarmonicBondForce
();
// addBond: particle1, particle2, length, quadraticK
amoebaHarmonicBondForce
->
addBond
(
0
,
1
,
0.0000000e+00
,
0.0000000e+00
);
amoebaHarmonicBondForce
->
addBond
(
0
,
2
,
0.0000000e+00
,
0.0000000e+00
);
amoebaHarmonicBondForce
->
addBond
(
0
,
3
,
0.0000000e+00
,
0.0000000e+00
);
amoebaHarmonicBondForce
->
addBond
(
4
,
5
,
0.0000000e+00
,
0.0000000e+00
);
amoebaHarmonicBondForce
->
addBond
(
4
,
6
,
0.0000000e+00
,
0.0000000e+00
);
amoebaHarmonicBondForce
->
addBond
(
4
,
7
,
0.0000000e+00
,
0.0000000e+00
);
amoebaHarmonicBondForce
->
setAmoebaGlobalHarmonicBondCubic
(
-
2.5500000e+01
);
amoebaHarmonicBondForce
->
setAmoebaGlobalHarmonicBondQuartic
(
3.7931250e+02
);
system
.
addForce
(
amoebaHarmonicBondForce
);
std
::
vector
<
Vec3
>
positions
(
numberOfParticles
);
positions
[
0
]
=
Vec3
(
1.5927280e-01
,
1.7000000e-06
,
1.6491000e-03
);
positions
[
1
]
=
Vec3
(
2.0805540e-01
,
-
8.1258800e-02
,
3.7282500e-02
);
positions
[
2
]
=
Vec3
(
2.0843610e-01
,
8.0953200e-02
,
3.7462200e-02
);
positions
[
3
]
=
Vec3
(
1.7280780e-01
,
2.0730000e-04
,
-
9.8741700e-02
);
positions
[
4
]
=
Vec3
(
-
1.6743680e-01
,
1.5900000e-05
,
-
6.6149000e-03
);
positions
[
5
]
=
Vec3
(
-
2.0428260e-01
,
8.1071500e-02
,
4.1343900e-02
);
positions
[
6
]
=
Vec3
(
-
6.7308300e-02
,
1.2800000e-05
,
1.0623300e-02
);
positions
[
7
]
=
Vec3
(
-
2.0426290e-01
,
-
8.1231400e-02
,
4.1033500e-02
);
system
.
addForce
(
amoebaMultipoleForce
);
std
::
string
platformName
;
platformName
=
"CUDA"
;
LangevinIntegrator
integrator
(
0.0
,
0.1
,
0.01
);
Context
context
(
system
,
integrator
,
Platform
::
getPlatformByName
(
platformName
)
);
context
.
setPositions
(
positions
);
State
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
forces
=
state
.
getForces
();
energy
=
state
.
getPotentialEnergy
();
}
// compare forces and energies
static
void
compareForcesEnergy
(
std
::
string
&
testName
,
double
expectedEnergy
,
double
energy
,
std
::
vector
<
Vec3
>&
expectedForces
,
std
::
vector
<
Vec3
>&
forces
,
double
tolerance
,
FILE
*
log
)
{
//#define AMOEBA_DEBUG
#ifdef AMOEBA_DEBUG
if
(
log
){
double
conversion
=
1.0
/
4.184
;
double
energyAbsDiff
=
fabs
(
expectedEnergy
-
energy
);
double
energyRelDiff
=
2.0
*
energyAbsDiff
/
(
fabs
(
expectedEnergy
)
+
fabs
(
energy
)
+
1.0e-08
);
(
void
)
fprintf
(
log
,
"%s: expected energy=%14.7e %14.7e absDiff=%15.7e relDiff=%15.7e
\n
"
,
testName
.
c_str
(),
conversion
*
expectedEnergy
,
conversion
*
energy
,
conversion
*
energyAbsDiff
,
conversion
*
energyRelDiff
);
if
(
conversion
!=
1.0
)
conversion
*=
-
0.1
;
for
(
unsigned
int
ii
=
0
;
ii
<
forces
.
size
();
ii
++
){
double
expectedNorm
=
sqrt
(
expectedForces
[
ii
][
0
]
*
expectedForces
[
ii
][
0
]
+
expectedForces
[
ii
][
1
]
*
expectedForces
[
ii
][
1
]
+
expectedForces
[
ii
][
2
]
*
expectedForces
[
ii
][
2
]
);
double
norm
=
sqrt
(
forces
[
ii
][
0
]
*
forces
[
ii
][
0
]
+
forces
[
ii
][
1
]
*
forces
[
ii
][
1
]
+
forces
[
ii
][
2
]
*
forces
[
ii
][
2
]
);
double
absDiff
=
fabs
(
norm
-
expectedNorm
);
double
relDiff
=
2.0
*
absDiff
/
(
fabs
(
norm
)
+
fabs
(
expectedNorm
)
+
1.0e-08
);
(
void
)
fprintf
(
log
,
"%6u %15.7e %15.7e [%14.7e %14.7e %14.7e] [%14.7e %14.7e %14.7e]
\n
"
,
ii
,
conversion
*
absDiff
,
conversion
*
relDiff
,
conversion
*
expectedForces
[
ii
][
0
],
conversion
*
expectedForces
[
ii
][
1
],
conversion
*
expectedForces
[
ii
][
2
],
conversion
*
forces
[
ii
][
0
],
conversion
*
forces
[
ii
][
1
],
conversion
*
forces
[
ii
][
2
],
conversion
*
expectedNorm
,
conversion
*
norm
);
}
(
void
)
fflush
(
log
);
conversion
=
1.0
;
(
void
)
fprintf
(
log
,
"
\n
%s: expected energy=%14.7e %14.7e no conversion
\n
"
,
testName
.
c_str
(),
conversion
*
expectedEnergy
,
conversion
*
energy
);
if
(
conversion
!=
1.0
)
conversion
=
-
1.0
;
for
(
unsigned
int
ii
=
0
;
ii
<
forces
.
size
();
ii
++
){
(
void
)
fprintf
(
log
,
"%6u [%14.7e %14.7e %14.7e] [%14.7e %14.7e %14.7e]
\n
"
,
ii
,
conversion
*
expectedForces
[
ii
][
0
],
conversion
*
expectedForces
[
ii
][
1
],
conversion
*
expectedForces
[
ii
][
2
],
conversion
*
forces
[
ii
][
0
],
conversion
*
forces
[
ii
][
1
],
conversion
*
forces
[
ii
][
2
]
);
}
(
void
)
fflush
(
log
);
}
#endif
for
(
unsigned
int
ii
=
0
;
ii
<
forces
.
size
();
ii
++
){
ASSERT_EQUAL_VEC_MOD
(
expectedForces
[
ii
],
forces
[
ii
],
tolerance
,
testName
);
}
ASSERT_EQUAL_TOL_MOD
(
expectedEnergy
,
energy
,
tolerance
,
testName
);
}
// compare relative differences in force norms and energies
static
void
compareForceNormsEnergy
(
std
::
string
&
testName
,
double
expectedEnergy
,
double
energy
,
std
::
vector
<
Vec3
>&
expectedForces
,
const
std
::
vector
<
Vec3
>&
forces
,
double
tolerance
,
FILE
*
log
)
{
//#define AMOEBA_DEBUG
#ifdef AMOEBA_DEBUG
if
(
log
){
double
conversion
=
1.0
/
4.184
;
double
energyAbsDiff
=
fabs
(
expectedEnergy
-
energy
);
double
energyRelDiff
=
2.0
*
energyAbsDiff
/
(
fabs
(
expectedEnergy
)
+
fabs
(
energy
)
+
1.0e-08
);
(
void
)
fprintf
(
log
,
"%s: expected energy=%14.7e %14.7e absDiff=%15.7e relDiff=%15.7e
\n
"
,
testName
.
c_str
(),
conversion
*
expectedEnergy
,
conversion
*
energy
,
conversion
*
energyAbsDiff
,
conversion
*
energyRelDiff
);
if
(
conversion
!=
1.0
)
conversion
*=
-
0.1
;
for
(
unsigned
int
ii
=
0
;
ii
<
forces
.
size
();
ii
++
){
double
expectedNorm
=
sqrt
(
expectedForces
[
ii
][
0
]
*
expectedForces
[
ii
][
0
]
+
expectedForces
[
ii
][
1
]
*
expectedForces
[
ii
][
1
]
+
expectedForces
[
ii
][
2
]
*
expectedForces
[
ii
][
2
]
);
double
norm
=
sqrt
(
forces
[
ii
][
0
]
*
forces
[
ii
][
0
]
+
forces
[
ii
][
1
]
*
forces
[
ii
][
1
]
+
forces
[
ii
][
2
]
*
forces
[
ii
][
2
]
);
double
absDiff
=
fabs
(
(
norm
-
expectedNorm
)
);
double
relDiff
=
2.0
*
absDiff
/
(
fabs
(
norm
)
+
fabs
(
expectedNorm
)
+
1.0e-08
);
(
void
)
fprintf
(
log
,
"%6u %15.7e %15.7e [%14.7e %14.7e %14.7e] [%14.7e %14.7e %14.7e] %15.7e %15.7e
\n
"
,
ii
,
fabs
(
conversion
)
*
absDiff
,
relDiff
,
conversion
*
expectedForces
[
ii
][
0
],
conversion
*
expectedForces
[
ii
][
1
],
conversion
*
expectedForces
[
ii
][
2
],
conversion
*
forces
[
ii
][
0
],
conversion
*
forces
[
ii
][
1
],
conversion
*
forces
[
ii
][
2
],
fabs
(
conversion
)
*
expectedNorm
,
fabs
(
conversion
)
*
norm
);
}
(
void
)
fflush
(
log
);
conversion
=
1.0
;
(
void
)
fprintf
(
log
,
"
\n
%s: expected energy=%14.7e %14.7e no conversion
\n
"
,
testName
.
c_str
(),
conversion
*
expectedEnergy
,
conversion
*
energy
);
if
(
conversion
!=
1.0
)
conversion
=
-
1.0
;
for
(
unsigned
int
ii
=
0
;
ii
<
forces
.
size
();
ii
++
){
(
void
)
fprintf
(
log
,
"%6u [%14.7e %14.7e %14.7e] [%14.7e %14.7e %14.7e]
\n
"
,
ii
,
conversion
*
expectedForces
[
ii
][
0
],
conversion
*
expectedForces
[
ii
][
1
],
conversion
*
expectedForces
[
ii
][
2
],
conversion
*
forces
[
ii
][
0
],
conversion
*
forces
[
ii
][
1
],
conversion
*
forces
[
ii
][
2
]
);
}
(
void
)
fflush
(
log
);
}
#endif
for
(
unsigned
int
ii
=
0
;
ii
<
forces
.
size
();
ii
++
){
double
expectedNorm
=
sqrt
(
expectedForces
[
ii
][
0
]
*
expectedForces
[
ii
][
0
]
+
expectedForces
[
ii
][
1
]
*
expectedForces
[
ii
][
1
]
+
expectedForces
[
ii
][
2
]
*
expectedForces
[
ii
][
2
]
);
double
norm
=
sqrt
(
forces
[
ii
][
0
]
*
forces
[
ii
][
0
]
+
forces
[
ii
][
1
]
*
forces
[
ii
][
1
]
+
forces
[
ii
][
2
]
*
forces
[
ii
][
2
]
);
double
absDiff
=
fabs
(
norm
-
expectedNorm
);
double
relDiff
=
2.0
*
absDiff
/
(
fabs
(
norm
)
+
fabs
(
expectedNorm
)
+
1.0e-08
);
if
(
relDiff
>
tolerance
&&
absDiff
>
0.001
){
std
::
stringstream
details
;
details
<<
testName
<<
"Relative difference in norms "
<<
relDiff
<<
" larger than allowed tolerance at particle="
<<
ii
;
details
<<
": norms="
<<
norm
<<
" expected norm="
<<
expectedNorm
;
throwException
(
__FILE__
,
__LINE__
,
details
.
str
());
}
}
double
energyAbsDiff
=
fabs
(
expectedEnergy
-
energy
);
double
energyRelDiff
=
2.0
*
energyAbsDiff
/
(
fabs
(
expectedEnergy
)
+
fabs
(
energy
)
+
1.0e-08
);
if
(
energyRelDiff
>
tolerance
){
std
::
stringstream
details
;
details
<<
testName
<<
"Relative difference in energies "
<<
energyRelDiff
<<
" larger than allowed tolerance."
;
details
<<
"Energies="
<<
energy
<<
" expected energy="
<<
expectedEnergy
;
throwException
(
__FILE__
,
__LINE__
,
details
.
str
());
}
}
// test multipole direct polarization for system comprised of two ammonia molecules; no cutoff
static
void
testMultipoleAmmoniaDirectPolarization
(
FILE
*
log
)
{
std
::
string
testName
=
"testMultipoleAmmoniaDirectPolarization"
;
int
numberOfParticles
=
8
;
int
inputPmeGridDimension
=
0
;
double
cutoff
=
9000000.0
;
std
::
vector
<
Vec3
>
forces
;
double
energy
;
setupAndGetForcesEnergyMultipoleAmmonia
(
AmoebaMultipoleForce
::
NoCutoff
,
AmoebaMultipoleForce
::
Direct
,
cutoff
,
inputPmeGridDimension
,
forces
,
energy
,
log
);
std
::
vector
<
Vec3
>
expectedForces
(
numberOfParticles
);
double
expectedEnergy
=
-
1.7428832e+01
;
expectedForces
[
0
]
=
Vec3
(
-
3.5574000e+02
,
-
7.3919340e+00
,
3.8989934e+01
);
expectedForces
[
1
]
=
Vec3
(
3.0368045e+01
,
-
8.7325694e+00
,
6.9731151e+00
);
expectedForces
[
2
]
=
Vec3
(
3.2358980e+01
,
1.0234924e+01
,
4.7203694e-01
);
expectedForces
[
3
]
=
Vec3
(
2.1439022e+01
,
5.8998414e+00
,
-
3.8355239e+01
);
expectedForces
[
4
]
=
Vec3
(
-
1.8052760e+02
,
-
1.0618455e+00
,
-
7.0030146e+01
);
expectedForces
[
5
]
=
Vec3
(
4.2411304e+01
,
-
1.6569222e+01
,
1.9047581e+00
);
expectedForces
[
6
]
=
Vec3
(
3.6823677e+02
,
7.7839986e-01
,
5.8404590e+01
);
expectedForces
[
7
]
=
Vec3
(
4.1453480e+01
,
1.6842405e+01
,
1.6409513e+00
);
double
tolerance
=
1.0e-04
;
compareForcesEnergy
(
testName
,
expectedEnergy
,
energy
,
expectedForces
,
forces
,
tolerance
,
log
);
}
// test multipole mutual polarization for system comprised of two ammonia molecules; no cutoff
static
void
testMultipoleAmmoniaMutualPolarization
(
FILE
*
log
)
{
std
::
string
testName
=
"testMultipoleAmmoniaMutualPolarization"
;
int
numberOfParticles
=
8
;
int
inputPmeGridDimension
=
0
;
double
cutoff
=
9000000.0
;
std
::
vector
<
Vec3
>
forces
;
double
energy
;
setupAndGetForcesEnergyMultipoleAmmonia
(
AmoebaMultipoleForce
::
NoCutoff
,
AmoebaMultipoleForce
::
Mutual
,
cutoff
,
inputPmeGridDimension
,
forces
,
energy
,
log
);
std
::
vector
<
Vec3
>
expectedForces
(
numberOfParticles
);
double
expectedEnergy
=
-
1.7790449e+01
;
expectedForces
[
0
]
=
Vec3
(
-
3.7523158e+02
,
-
7.9806295e+00
,
3.7464051e+01
);
expectedForces
[
1
]
=
Vec3
(
3.1352410e+01
,
-
9.4055551e+00
,
8.5230415e+00
);
expectedForces
[
2
]
=
Vec3
(
3.3504923e+01
,
1.1029935e+01
,
1.5052263e+00
);
expectedForces
[
3
]
=
Vec3
(
2.3295507e+01
,
6.3698827e+00
,
-
4.0403553e+01
);
expectedForces
[
4
]
=
Vec3
(
-
1.9379275e+02
,
-
1.0903937e+00
,
-
7.3461740e+01
);
expectedForces
[
5
]
=
Vec3
(
4.3278067e+01
,
-
1.6906589e+01
,
1.5721909e+00
);
expectedForces
[
6
]
=
Vec3
(
3.9529983e+02
,
7.9661172e-01
,
6.3499055e+01
);
expectedForces
[
7
]
=
Vec3
(
4.2293601e+01
,
1.7186738e+01
,
1.3017270e+00
);
double
tolerance
=
1.0e-04
;
compareForcesEnergy
(
testName
,
expectedEnergy
,
energy
,
expectedForces
,
forces
,
tolerance
,
log
);
}
// setup for box of 4 water molecules -- used to test PME
static
void
setupAndGetForcesEnergyMultipoleWater
(
AmoebaMultipoleForce
::
AmoebaNonbondedMethod
nonbondedMethod
,
AmoebaMultipoleForce
::
AmoebaPolarizationType
polarizationType
,
double
cutoff
,
int
inputPmeGridDimension
,
std
::
vector
<
Vec3
>&
forces
,
double
&
energy
,
FILE
*
log
){
// beginning of Multipole setup
System
system
;
// box dimensions
double
boxDimension
=
1.8643
;
Vec3
a
(
boxDimension
,
0.0
,
0.0
);
Vec3
b
(
0.0
,
boxDimension
,
0.0
);
Vec3
c
(
0.0
,
0.0
,
boxDimension
);
system
.
setDefaultPeriodicBoxVectors
(
a
,
b
,
c
);
AmoebaMultipoleForce
*
amoebaMultipoleForce
=
new
AmoebaMultipoleForce
();;
int
numberOfParticles
=
12
;
amoebaMultipoleForce
->
setNonbondedMethod
(
nonbondedMethod
);
amoebaMultipoleForce
->
setPolarizationType
(
polarizationType
);
amoebaMultipoleForce
->
setCutoffDistance
(
cutoff
);
amoebaMultipoleForce
->
setMutualInducedTargetEpsilon
(
1.0e-06
);
amoebaMultipoleForce
->
setMutualInducedMaxIterations
(
500
);
amoebaMultipoleForce
->
setAEwald
(
5.4459052e+00
);
amoebaMultipoleForce
->
setEwaldErrorTolerance
(
1.0e-04
);
std
::
vector
<
int
>
pmeGridDimension
(
3
);
pmeGridDimension
[
0
]
=
pmeGridDimension
[
1
]
=
pmeGridDimension
[
2
]
=
inputPmeGridDimension
;
amoebaMultipoleForce
->
setPmeGridDimensions
(
pmeGridDimension
);
for
(
unsigned
int
jj
=
0
;
jj
<
numberOfParticles
;
jj
+=
3
){
system
.
addParticle
(
1.5995000e+01
);
system
.
addParticle
(
1.0080000e+00
);
system
.
addParticle
(
1.0080000e+00
);
}
std
::
vector
<
double
>
oxygenMolecularDipole
(
3
);
std
::
vector
<
double
>
oxygenMolecularQuadrupole
(
9
);
oxygenMolecularDipole
[
0
]
=
0.0000000e+00
;
oxygenMolecularDipole
[
1
]
=
0.0000000e+00
;
oxygenMolecularDipole
[
2
]
=
7.5561214e-03
;
oxygenMolecularQuadrupole
[
0
]
=
3.5403072e-04
;
oxygenMolecularQuadrupole
[
1
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
2
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
3
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
4
]
=
-
3.9025708e-04
;
oxygenMolecularQuadrupole
[
5
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
6
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
7
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
8
]
=
3.6226356e-05
;
std
::
vector
<
double
>
hydrogenMolecularDipole
(
3
);
std
::
vector
<
double
>
hydrogenMolecularQuadrupole
(
9
);
hydrogenMolecularDipole
[
0
]
=
-
2.0420949e-03
;
hydrogenMolecularDipole
[
1
]
=
0.0000000e+00
;
hydrogenMolecularDipole
[
2
]
=
-
3.0787530e-03
;
hydrogenMolecularQuadrupole
[
0
]
=
-
3.4284825e-05
;
hydrogenMolecularQuadrupole
[
1
]
=
0.0000000e+00
;
hydrogenMolecularQuadrupole
[
2
]
=
-
1.8948597e-06
;
hydrogenMolecularQuadrupole
[
3
]
=
0.0000000e+00
;
hydrogenMolecularQuadrupole
[
4
]
=
-
1.0024088e-04
;
hydrogenMolecularQuadrupole
[
5
]
=
0.0000000e+00
;
hydrogenMolecularQuadrupole
[
6
]
=
-
1.8948597e-06
;
hydrogenMolecularQuadrupole
[
7
]
=
0.0000000e+00
;
hydrogenMolecularQuadrupole
[
8
]
=
1.3452570e-04
;
for
(
unsigned
int
jj
=
0
;
jj
<
numberOfParticles
;
jj
+=
3
){
amoebaMultipoleForce
->
addParticle
(
-
5.1966000e-01
,
oxygenMolecularDipole
,
oxygenMolecularQuadrupole
,
1
,
jj
+
1
,
jj
+
2
,
-
1
,
3.9000000e-01
,
3.0698765e-01
,
8.3700000e-04
);
amoebaMultipoleForce
->
addParticle
(
2.5983000e-01
,
hydrogenMolecularDipole
,
hydrogenMolecularQuadrupole
,
0
,
jj
,
jj
+
2
,
-
1
,
3.9000000e-01
,
2.8135002e-01
,
4.9600000e-04
);
amoebaMultipoleForce
->
addParticle
(
2.5983000e-01
,
hydrogenMolecularDipole
,
hydrogenMolecularQuadrupole
,
0
,
jj
,
jj
+
1
,
-
1
,
3.9000000e-01
,
2.8135002e-01
,
4.9600000e-04
);
}
// CovalentMaps
std
::
vector
<
int
>
covalentMap
;
for
(
unsigned
int
jj
=
0
;
jj
<
numberOfParticles
;
jj
+=
3
){
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
jj
+
1
);
covalentMap
.
push_back
(
jj
+
2
);
amoebaMultipoleForce
->
setCovalentMap
(
jj
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
0
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
jj
);
covalentMap
.
push_back
(
jj
+
1
);
covalentMap
.
push_back
(
jj
+
2
);
amoebaMultipoleForce
->
setCovalentMap
(
jj
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
4
),
covalentMap
);
amoebaMultipoleForce
->
setCovalentMap
(
jj
+
1
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
4
),
covalentMap
);
amoebaMultipoleForce
->
setCovalentMap
(
jj
+
2
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
4
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
jj
);
amoebaMultipoleForce
->
setCovalentMap
(
jj
+
1
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
0
),
covalentMap
);
amoebaMultipoleForce
->
setCovalentMap
(
jj
+
2
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
0
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
jj
+
2
);
amoebaMultipoleForce
->
setCovalentMap
(
jj
+
1
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
1
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
jj
+
1
);
amoebaMultipoleForce
->
setCovalentMap
(
jj
+
2
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
1
),
covalentMap
);
}
// 1-2 bonds needed
AmoebaHarmonicBondForce
*
amoebaHarmonicBondForce
=
new
AmoebaHarmonicBondForce
();
// addBond: particle1, particle2, length, quadraticK
for
(
unsigned
int
jj
=
0
;
jj
<
numberOfParticles
;
jj
+=
3
){
amoebaHarmonicBondForce
->
addBond
(
jj
,
jj
+
1
,
0.0000000e+00
,
0.0000000e+00
);
amoebaHarmonicBondForce
->
addBond
(
jj
,
jj
+
2
,
0.0000000e+00
,
0.0000000e+00
);
}
amoebaHarmonicBondForce
->
setAmoebaGlobalHarmonicBondCubic
(
-
2.5500000e+01
);
amoebaHarmonicBondForce
->
setAmoebaGlobalHarmonicBondQuartic
(
3.7931250e+02
);
system
.
addForce
(
amoebaHarmonicBondForce
);
std
::
vector
<
Vec3
>
positions
(
numberOfParticles
);
positions
[
0
]
=
Vec3
(
-
8.7387270e-01
,
5.3220410e-01
,
7.4214000e-03
);
positions
[
1
]
=
Vec3
(
-
9.6050090e-01
,
5.1173410e-01
,
-
2.2202700e-02
);
positions
[
2
]
=
Vec3
(
-
8.5985900e-01
,
4.9658230e-01
,
1.0283390e-01
);
positions
[
3
]
=
Vec3
(
9.1767100e-02
,
-
7.8956650e-01
,
4.3804200e-01
);
positions
[
4
]
=
Vec3
(
1.2333420e-01
,
-
7.0267430e-01
,
4.2611550e-01
);
positions
[
5
]
=
Vec3
(
1.7267090e-01
,
-
8.2320810e-01
,
4.8124750e-01
);
positions
[
6
]
=
Vec3
(
8.6290110e-01
,
6.2153500e-02
,
4.1280850e-01
);
positions
[
7
]
=
Vec3
(
8.6385200e-01
,
1.2684730e-01
,
3.3887060e-01
);
positions
[
8
]
=
Vec3
(
9.5063550e-01
,
5.3173300e-02
,
4.4799160e-01
);
positions
[
9
]
=
Vec3
(
5.0844930e-01
,
2.8684740e-01
,
-
6.9293750e-01
);
positions
[
10
]
=
Vec3
(
6.0459330e-01
,
3.0620510e-01
,
-
7.0100130e-01
);
positions
[
11
]
=
Vec3
(
5.0590640e-01
,
1.8880920e-01
,
-
6.8813470e-01
);
system
.
addForce
(
amoebaMultipoleForce
);
std
::
string
platformName
;
platformName
=
"CUDA"
;
LangevinIntegrator
integrator
(
0.0
,
0.1
,
0.01
);
Context
context
(
system
,
integrator
,
Platform
::
getPlatformByName
(
platformName
)
);
context
.
setPositions
(
positions
);
State
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
forces
=
state
.
getForces
();
energy
=
state
.
getPotentialEnergy
();
}
// test multipole direct polarization using PME for box of water
static
void
testMultipoleWaterPMEDirectPolarization
(
FILE
*
log
)
{
std
::
string
testName
=
"testMultipoleWaterDirectPolarization"
;
int
numberOfParticles
=
12
;
int
inputPmeGridDimension
=
20
;
double
cutoff
=
0.70
;
std
::
vector
<
Vec3
>
forces
;
double
energy
;
setupAndGetForcesEnergyMultipoleWater
(
AmoebaMultipoleForce
::
PME
,
AmoebaMultipoleForce
::
Direct
,
cutoff
,
inputPmeGridDimension
,
forces
,
energy
,
log
);
std
::
vector
<
Vec3
>
expectedForces
(
numberOfParticles
);
double
expectedEnergy
=
6.4585115e-01
;
expectedForces
[
0
]
=
Vec3
(
-
1.2396731e+00
,
-
2.4231698e+01
,
8.3348523e+00
);
expectedForces
[
1
]
=
Vec3
(
-
3.3737276e+00
,
9.9304523e+00
,
-
6.3917827e+00
);
expectedForces
[
2
]
=
Vec3
(
4.4062247e+00
,
1.9518971e+01
,
-
4.6552873e+00
);
expectedForces
[
3
]
=
Vec3
(
-
1.3128824e+00
,
-
1.2887339e+00
,
-
1.4473147e+00
);
expectedForces
[
4
]
=
Vec3
(
2.1137034e+00
,
3.9457973e-01
,
2.9269129e-01
);
expectedForces
[
5
]
=
Vec3
(
1.0271174e+00
,
1.2039367e+00
,
1.2112214e+00
);
expectedForces
[
6
]
=
Vec3
(
-
3.2082903e+00
,
1.4979371e+01
,
-
1.0274832e+00
);
expectedForces
[
7
]
=
Vec3
(
-
1.1880320e+00
,
-
1.5177166e+01
,
2.5525509e+00
);
expectedForces
[
8
]
=
Vec3
(
4.3607105e+00
,
-
7.0253274e+00
,
2.9522580e-01
);
expectedForces
[
9
]
=
Vec3
(
-
3.0175134e+00
,
1.3607102e+00
,
6.6883370e+00
);
expectedForces
[
10
]
=
Vec3
(
9.2036949e-01
,
-
1.4717629e+00
,
-
3.3362339e+00
);
expectedForces
[
11
]
=
Vec3
(
1.2523841e+00
,
-
1.9794292e+00
,
-
3.4670129e+00
);
double
tolerance
=
1.0e-03
;
compareForcesEnergy
(
testName
,
expectedEnergy
,
energy
,
expectedForces
,
forces
,
tolerance
,
log
);
}
// test multipole mutual polarization using PME for box of water
static
void
testMultipoleWaterPMEMutualPolarization
(
FILE
*
log
)
{
std
::
string
testName
=
"testMultipoleWaterMutualPolarization"
;
int
numberOfParticles
=
12
;
int
inputPmeGridDimension
=
20
;
double
cutoff
=
0.70
;
std
::
vector
<
Vec3
>
forces
;
double
energy
;
setupAndGetForcesEnergyMultipoleWater
(
AmoebaMultipoleForce
::
PME
,
AmoebaMultipoleForce
::
Mutual
,
cutoff
,
inputPmeGridDimension
,
forces
,
energy
,
log
);
std
::
vector
<
Vec3
>
expectedForces
(
numberOfParticles
);
double
expectedEnergy
=
6.5029855e-01
;
expectedForces
[
0
]
=
Vec3
(
-
1.2367386e+00
,
-
2.4197036e+01
,
8.3256759e+00
);
expectedForces
[
1
]
=
Vec3
(
-
3.3825187e+00
,
9.9387618e+00
,
-
6.4200475e+00
);
expectedForces
[
2
]
=
Vec3
(
4.4108644e+00
,
1.9486127e+01
,
-
4.6530661e+00
);
expectedForces
[
3
]
=
Vec3
(
-
1.3129168e+00
,
-
1.2947383e+00
,
-
1.4438198e+00
);
expectedForces
[
4
]
=
Vec3
(
2.1144837e+00
,
3.9590305e-01
,
2.9040889e-01
);
expectedForces
[
5
]
=
Vec3
(
1.0287222e+00
,
1.2100201e+00
,
1.2103068e+00
);
expectedForces
[
6
]
=
Vec3
(
-
3.2017550e+00
,
1.4995985e+01
,
-
1.1036504e+00
);
expectedForces
[
7
]
=
Vec3
(
-
1.2065398e+00
,
-
1.5192899e+01
,
2.6233368e+00
);
expectedForces
[
8
]
=
Vec3
(
4.3698604e+00
,
-
7.0550315e+00
,
3.4204565e-01
);
expectedForces
[
9
]
=
Vec3
(
-
3.0082825e+00
,
1.3575082e+00
,
6.6901032e+00
);
expectedForces
[
10
]
=
Vec3
(
9.1775539e-01
,
-
1.4651882e+00
,
-
3.3322516e+00
);
expectedForces
[
11
]
=
Vec3
(
1.2467701e+00
,
-
1.9832979e+00
,
-
3.4684052e+00
);
double
tolerance
=
1.0e-03
;
compareForcesEnergy
(
testName
,
expectedEnergy
,
energy
,
expectedForces
,
forces
,
tolerance
,
log
);
}
// check validation of traceless/symmetric quadrupole tensor
static
void
testQuadrupoleValidation
(
FILE
*
log
){
std
::
string
testName
=
"checkQuadrupoleValidation"
;
int
numberOfParticles
=
12
;
int
pmeGridDimension
=
20
;
double
cutoff
=
0.70
;
// beginning of Multipole setup
System
system
;
double
boxDimension
=
1.8643
;
Vec3
a
(
boxDimension
,
0.0
,
0.0
);
Vec3
b
(
0.0
,
boxDimension
,
0.0
);
Vec3
c
(
0.0
,
0.0
,
boxDimension
);
system
.
setDefaultPeriodicBoxVectors
(
a
,
b
,
c
);
AmoebaMultipoleForce
*
amoebaMultipoleForce
=
new
AmoebaMultipoleForce
();;
std
::
vector
<
Vec3
>
expectedForces
(
numberOfParticles
);
amoebaMultipoleForce
->
setNonbondedMethod
(
AmoebaMultipoleForce
::
PME
);
amoebaMultipoleForce
->
setPolarizationType
(
AmoebaMultipoleForce
::
Direct
);
amoebaMultipoleForce
->
setCutoffDistance
(
0.7
);
amoebaMultipoleForce
->
setMutualInducedTargetEpsilon
(
1.0e-06
);
amoebaMultipoleForce
->
setMutualInducedMaxIterations
(
500
);
amoebaMultipoleForce
->
setAEwald
(
5.4459052e+00
);
amoebaMultipoleForce
->
setEwaldErrorTolerance
(
1.0e-04
);
std
::
vector
<
int
>
pmeGridDimensions
(
3
);
pmeGridDimensions
[
0
]
=
pmeGridDimensions
[
1
]
=
pmeGridDimensions
[
2
]
=
pmeGridDimension
;
amoebaMultipoleForce
->
setPmeGridDimensions
(
pmeGridDimensions
);
for
(
unsigned
int
jj
=
0
;
jj
<
numberOfParticles
;
jj
+=
3
){
system
.
addParticle
(
1.5995000e+01
);
system
.
addParticle
(
1.0080000e+00
);
system
.
addParticle
(
1.0080000e+00
);
}
std
::
vector
<
double
>
oxygenMolecularDipole
(
3
);
std
::
vector
<
double
>
oxygenMolecularQuadrupole
(
9
);
oxygenMolecularDipole
[
0
]
=
0.0000000e+00
;
oxygenMolecularDipole
[
1
]
=
0.0000000e+00
;
oxygenMolecularDipole
[
2
]
=
7.5561214e-03
;
oxygenMolecularQuadrupole
[
0
]
=
3.5403072e-04
;
oxygenMolecularQuadrupole
[
1
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
2
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
3
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
4
]
=
-
3.9025708e-04
;
oxygenMolecularQuadrupole
[
5
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
6
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
7
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
8
]
=
3.6226356e-05
;
std
::
vector
<
double
>
hydrogenMolecularDipole
(
3
);
std
::
vector
<
double
>
hydrogenMolecularQuadrupole
(
9
);
hydrogenMolecularDipole
[
0
]
=
-
2.0420949e-03
;
hydrogenMolecularDipole
[
1
]
=
0.0000000e+00
;
hydrogenMolecularDipole
[
2
]
=
-
3.0787530e-03
;
hydrogenMolecularQuadrupole
[
0
]
=
-
3.4284825e-05
;
hydrogenMolecularQuadrupole
[
1
]
=
0.0000000e+00
;
hydrogenMolecularQuadrupole
[
2
]
=
-
1.8948597e-06
;
hydrogenMolecularQuadrupole
[
3
]
=
0.0000000e+00
;
hydrogenMolecularQuadrupole
[
4
]
=
-
1.0024088e-04
;
hydrogenMolecularQuadrupole
[
5
]
=
0.0000000e+00
;
hydrogenMolecularQuadrupole
[
6
]
=
-
1.8948597e-06
;
hydrogenMolecularQuadrupole
[
7
]
=
0.0000000e+00
;
hydrogenMolecularQuadrupole
[
8
]
=
1.3452570e-04
;
for
(
unsigned
int
jj
=
0
;
jj
<
numberOfParticles
;
jj
+=
3
){
amoebaMultipoleForce
->
addParticle
(
-
5.1966000e-01
,
oxygenMolecularDipole
,
oxygenMolecularQuadrupole
,
1
,
jj
+
1
,
jj
+
2
,
-
1
,
3.9000000e-01
,
3.0698765e-01
,
8.3700000e-04
);
amoebaMultipoleForce
->
addParticle
(
2.5983000e-01
,
hydrogenMolecularDipole
,
hydrogenMolecularQuadrupole
,
0
,
jj
,
jj
+
2
,
-
1
,
3.9000000e-01
,
2.8135002e-01
,
4.9600000e-04
);
amoebaMultipoleForce
->
addParticle
(
2.5983000e-01
,
hydrogenMolecularDipole
,
hydrogenMolecularQuadrupole
,
0
,
jj
,
jj
+
1
,
-
1
,
3.9000000e-01
,
2.8135002e-01
,
4.9600000e-04
);
}
// CovalentMaps
/*
std::vector< int > covalentMap;
for( unsigned int jj = 0; jj < numberOfParticles; jj += 3 ){
covalentMap.resize(0);
covalentMap.push_back( jj+1 );
covalentMap.push_back( jj+2 );
amoebaMultipoleForce->setCovalentMap( jj, static_cast<OpenMM::AmoebaMultipoleForce::CovalentType>(0), covalentMap );
covalentMap.resize(0);
covalentMap.push_back( jj );
covalentMap.push_back( jj+1 );
covalentMap.push_back( jj+2 );
amoebaMultipoleForce->setCovalentMap( jj, static_cast<OpenMM::AmoebaMultipoleForce::CovalentType>(4), covalentMap );
amoebaMultipoleForce->setCovalentMap( jj+1, static_cast<OpenMM::AmoebaMultipoleForce::CovalentType>(4), covalentMap );
amoebaMultipoleForce->setCovalentMap( jj+2, static_cast<OpenMM::AmoebaMultipoleForce::CovalentType>(4), covalentMap );
covalentMap.resize(0);
covalentMap.push_back( jj );
amoebaMultipoleForce->setCovalentMap( jj+1, static_cast<OpenMM::AmoebaMultipoleForce::CovalentType>(0), covalentMap );
amoebaMultipoleForce->setCovalentMap( jj+2, static_cast<OpenMM::AmoebaMultipoleForce::CovalentType>(0), covalentMap );
covalentMap.resize(0);
covalentMap.push_back( jj+2 );
amoebaMultipoleForce->setCovalentMap( jj+1, static_cast<OpenMM::AmoebaMultipoleForce::CovalentType>(1), covalentMap );
covalentMap.resize(0);
covalentMap.push_back( jj+1 );
amoebaMultipoleForce->setCovalentMap( jj+2, static_cast<OpenMM::AmoebaMultipoleForce::CovalentType>(1), covalentMap );
}
*/
AmoebaHarmonicBondForce
*
amoebaHarmonicBondForce
=
new
AmoebaHarmonicBondForce
();
// addBond: particle1, particle2, length, quadraticK
for
(
unsigned
int
jj
=
0
;
jj
<
numberOfParticles
;
jj
+=
3
){
amoebaHarmonicBondForce
->
addBond
(
jj
,
jj
+
1
,
0.0000000e+00
,
0.0000000e+00
);
amoebaHarmonicBondForce
->
addBond
(
jj
,
jj
+
2
,
0.0000000e+00
,
0.0000000e+00
);
}
amoebaHarmonicBondForce
->
setAmoebaGlobalHarmonicBondCubic
(
-
2.5500000e+01
);
amoebaHarmonicBondForce
->
setAmoebaGlobalHarmonicBondQuartic
(
3.7931250e+02
);
system
.
addForce
(
amoebaHarmonicBondForce
);
std
::
vector
<
Vec3
>
positions
(
numberOfParticles
);
positions
[
0
]
=
Vec3
(
-
8.7387270e-01
,
5.3220410e-01
,
7.4214000e-03
);
positions
[
1
]
=
Vec3
(
-
9.6050090e-01
,
5.1173410e-01
,
-
2.2202700e-02
);
positions
[
2
]
=
Vec3
(
-
8.5985900e-01
,
4.9658230e-01
,
1.0283390e-01
);
positions
[
3
]
=
Vec3
(
9.1767100e-02
,
-
7.8956650e-01
,
4.3804200e-01
);
positions
[
4
]
=
Vec3
(
1.2333420e-01
,
-
7.0267430e-01
,
4.2611550e-01
);
positions
[
5
]
=
Vec3
(
1.7267090e-01
,
-
8.2320810e-01
,
4.8124750e-01
);
positions
[
6
]
=
Vec3
(
8.6290110e-01
,
6.2153500e-02
,
4.1280850e-01
);
positions
[
7
]
=
Vec3
(
8.6385200e-01
,
1.2684730e-01
,
3.3887060e-01
);
positions
[
8
]
=
Vec3
(
9.5063550e-01
,
5.3173300e-02
,
4.4799160e-01
);
positions
[
9
]
=
Vec3
(
5.0844930e-01
,
2.8684740e-01
,
-
6.9293750e-01
);
positions
[
10
]
=
Vec3
(
6.0459330e-01
,
3.0620510e-01
,
-
7.0100130e-01
);
positions
[
11
]
=
Vec3
(
5.0590640e-01
,
1.8880920e-01
,
-
6.8813470e-01
);
system
.
addForce
(
amoebaMultipoleForce
);
std
::
string
platformName
;
platformName
=
"CUDA"
;
LangevinIntegrator
integrator
(
0.0
,
0.1
,
0.01
);
Context
context
(
system
,
integrator
,
Platform
::
getPlatformByName
(
platformName
)
);
context
.
setPositions
(
positions
);
// traceless quadrupole
try
{
oxygenMolecularQuadrupole
[
4
]
+=
0.1
;
amoebaMultipoleForce
->
setMultipoleParameters
(
0
,
-
5.1966000e-01
,
oxygenMolecularDipole
,
oxygenMolecularQuadrupole
,
1
,
1
,
2
,
-
1
,
3.9000000e-01
,
3.0698765e-01
,
8.3700000e-04
);
State
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
std
::
stringstream
buffer
;
buffer
<<
"Exception not thrown for quadrupole tensor w/ nonzero trace."
;
throw
OpenMMException
(
buffer
.
str
());
}
catch
(
const
std
::
exception
&
e
)
{
}
oxygenMolecularQuadrupole
[
4
]
-=
0.1
;
// symmetric quadrupole
// XY and YX components
try
{
oxygenMolecularQuadrupole
[
1
]
+=
0.1
;
amoebaMultipoleForce
->
setMultipoleParameters
(
0
,
-
5.1966000e-01
,
oxygenMolecularDipole
,
oxygenMolecularQuadrupole
,
1
,
1
,
2
,
-
1
,
3.9000000e-01
,
3.0698765e-01
,
8.3700000e-04
);
State
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
std
::
stringstream
buffer
;
buffer
<<
"Exception not thrown for quadrupole tensor w/ nonzero trace."
;
throw
OpenMMException
(
buffer
.
str
());
}
catch
(
const
std
::
exception
&
e
)
{
}
oxygenMolecularQuadrupole
[
1
]
-=
0.1
;
// XZ and ZX components
try
{
oxygenMolecularQuadrupole
[
2
]
+=
0.1
;
amoebaMultipoleForce
->
setMultipoleParameters
(
0
,
-
5.1966000e-01
,
oxygenMolecularDipole
,
oxygenMolecularQuadrupole
,
1
,
1
,
2
,
-
1
,
3.9000000e-01
,
3.0698765e-01
,
8.3700000e-04
);
State
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
std
::
stringstream
buffer
;
buffer
<<
"Exception not thrown for quadrupole tensor w/ nonzero trace."
;
throw
OpenMMException
(
buffer
.
str
());
}
catch
(
const
std
::
exception
&
e
)
{
}
oxygenMolecularQuadrupole
[
2
]
-=
0.1
;
// YZ and ZY components
try
{
oxygenMolecularQuadrupole
[
5
]
+=
0.1
;
amoebaMultipoleForce
->
setMultipoleParameters
(
0
,
-
5.1966000e-01
,
oxygenMolecularDipole
,
oxygenMolecularQuadrupole
,
1
,
1
,
2
,
-
1
,
3.9000000e-01
,
3.0698765e-01
,
8.3700000e-04
);
State
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
std
::
stringstream
buffer
;
buffer
<<
"Exception not thrown for quadrupole tensor w/ nonzero trace."
;
throw
OpenMMException
(
buffer
.
str
());
}
catch
(
const
std
::
exception
&
e
)
{
}
oxygenMolecularQuadrupole
[
5
]
-=
0.1
;
}
// setup for box of 2 water molecules and 3 ions
// this method does too much; I tried passing the context ptr back to
// the tests methods, but the tests would seg fault w/ a bad_alloc error
static
void
setupAndGetForcesEnergyMultipoleIonsAndWater
(
AmoebaMultipoleForce
::
AmoebaNonbondedMethod
nonbondedMethod
,
AmoebaMultipoleForce
::
AmoebaPolarizationType
polarizationType
,
double
cutoff
,
int
inputPmeGridDimension
,
std
::
string
testName
,
std
::
vector
<
Vec3
>&
forces
,
double
&
energy
,
std
::
vector
<
double
>&
outputMultipoleMoments
,
std
::
vector
<
Vec3
>&
inputGrid
,
std
::
vector
<
double
>&
outputGridPotential
,
FILE
*
log
){
// beginning of Multipole setup
System
system
;
// box dimensions
double
boxDimensions
[
3
]
=
{
6.7538
,
7.2977
,
7.4897
};
Vec3
a
(
boxDimensions
[
0
],
0.0
,
0.0
);
Vec3
b
(
0.0
,
boxDimensions
[
1
],
0.0
);
Vec3
c
(
0.0
,
0.0
,
boxDimensions
[
2
]
);
system
.
setDefaultPeriodicBoxVectors
(
a
,
b
,
c
);
AmoebaMultipoleForce
*
amoebaMultipoleForce
=
new
AmoebaMultipoleForce
();;
int
numberOfParticles
=
8
;
int
numberOfWaters
=
2
;
int
numberOfIons
=
numberOfParticles
-
numberOfWaters
*
3
;
amoebaMultipoleForce
->
setNonbondedMethod
(
nonbondedMethod
);
amoebaMultipoleForce
->
setPolarizationType
(
polarizationType
);
amoebaMultipoleForce
->
setCutoffDistance
(
cutoff
);
amoebaMultipoleForce
->
setMutualInducedTargetEpsilon
(
1.0e-06
);
amoebaMultipoleForce
->
setMutualInducedMaxIterations
(
500
);
amoebaMultipoleForce
->
setAEwald
(
5.4459052e+00
);
amoebaMultipoleForce
->
setEwaldErrorTolerance
(
1.0e-05
);
std
::
vector
<
int
>
pmeGridDimension
(
3
);
pmeGridDimension
[
0
]
=
pmeGridDimension
[
1
]
=
pmeGridDimension
[
2
]
=
inputPmeGridDimension
;
amoebaMultipoleForce
->
setPmeGridDimensions
(
pmeGridDimension
);
// 2 ions
system
.
addParticle
(
3.5453000e+01
);
system
.
addParticle
(
2.2990000e+01
);
std
::
vector
<
double
>
ionDipole
(
3
);
std
::
vector
<
double
>
ionQuadrupole
(
9
);
ionDipole
[
0
]
=
0.0000000e+00
;
ionDipole
[
1
]
=
0.0000000e+00
;
ionDipole
[
2
]
=
0.0000000e+00
;
ionQuadrupole
[
0
]
=
0.0000000e+00
;
ionQuadrupole
[
1
]
=
0.0000000e+00
;
ionQuadrupole
[
2
]
=
0.0000000e+00
;
ionQuadrupole
[
3
]
=
0.0000000e+00
;
ionQuadrupole
[
4
]
=
0.0000000e+00
;
ionQuadrupole
[
5
]
=
0.0000000e+00
;
ionQuadrupole
[
6
]
=
0.0000000e+00
;
ionQuadrupole
[
7
]
=
0.0000000e+00
;
ionQuadrupole
[
8
]
=
0.0000000e+00
;
amoebaMultipoleForce
->
addParticle
(
-
1.0000000e+00
,
ionDipole
,
ionQuadrupole
,
5
,
-
1
,
-
1
,
-
1
,
3.9000000e-01
,
3.9842202e-01
,
4.0000000e-03
);
amoebaMultipoleForce
->
addParticle
(
1.0000000e+00
,
ionDipole
,
ionQuadrupole
,
5
,
-
1
,
-
1
,
-
1
,
3.9000000e-01
,
2.2209062e-01
,
1.2000000e-04
);
// waters
for
(
unsigned
int
jj
=
2
;
jj
<
numberOfParticles
;
jj
+=
3
){
system
.
addParticle
(
1.5999000e+01
);
system
.
addParticle
(
1.0080000e+00
);
system
.
addParticle
(
1.0080000e+00
);
}
std
::
vector
<
double
>
oxygenMolecularDipole
(
3
);
std
::
vector
<
double
>
oxygenMolecularQuadrupole
(
9
);
oxygenMolecularDipole
[
0
]
=
0.0000000e+00
;
oxygenMolecularDipole
[
1
]
=
0.0000000e+00
;
oxygenMolecularDipole
[
2
]
=
7.5561214e-03
;
oxygenMolecularQuadrupole
[
0
]
=
3.5403072e-04
;
oxygenMolecularQuadrupole
[
1
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
2
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
3
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
4
]
=
-
3.9025708e-04
;
oxygenMolecularQuadrupole
[
5
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
6
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
7
]
=
0.0000000e+00
;
oxygenMolecularQuadrupole
[
8
]
=
3.6226356e-05
;
std
::
vector
<
double
>
hydrogenMolecularDipole
(
3
);
std
::
vector
<
double
>
hydrogenMolecularQuadrupole
(
9
);
hydrogenMolecularDipole
[
0
]
=
-
2.0420949e-03
;
hydrogenMolecularDipole
[
1
]
=
0.0000000e+00
;
hydrogenMolecularDipole
[
2
]
=
-
3.0787530e-03
;
hydrogenMolecularQuadrupole
[
0
]
=
-
3.4284825e-05
;
hydrogenMolecularQuadrupole
[
1
]
=
0.0000000e+00
;
hydrogenMolecularQuadrupole
[
2
]
=
-
1.8948597e-06
;
hydrogenMolecularQuadrupole
[
3
]
=
0.0000000e+00
;
hydrogenMolecularQuadrupole
[
4
]
=
-
1.0024088e-04
;
hydrogenMolecularQuadrupole
[
5
]
=
0.0000000e+00
;
hydrogenMolecularQuadrupole
[
6
]
=
-
1.8948597e-06
;
hydrogenMolecularQuadrupole
[
7
]
=
0.0000000e+00
;
hydrogenMolecularQuadrupole
[
8
]
=
1.3452570e-04
;
for
(
unsigned
int
jj
=
2
;
jj
<
numberOfParticles
;
jj
+=
3
){
amoebaMultipoleForce
->
addParticle
(
-
5.1966000e-01
,
oxygenMolecularDipole
,
oxygenMolecularQuadrupole
,
1
,
jj
+
1
,
jj
+
2
,
-
1
,
3.9000000e-01
,
3.0698765e-01
,
8.3700000e-04
);
amoebaMultipoleForce
->
addParticle
(
2.5983000e-01
,
hydrogenMolecularDipole
,
hydrogenMolecularQuadrupole
,
0
,
jj
,
jj
+
2
,
-
1
,
3.9000000e-01
,
2.8135002e-01
,
4.9600000e-04
);
amoebaMultipoleForce
->
addParticle
(
2.5983000e-01
,
hydrogenMolecularDipole
,
hydrogenMolecularQuadrupole
,
0
,
jj
,
jj
+
1
,
-
1
,
3.9000000e-01
,
2.8135002e-01
,
4.9600000e-04
);
}
// CovalentMaps
std
::
vector
<
int
>
covalentMap
;
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
0
);
amoebaMultipoleForce
->
setCovalentMap
(
0
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
4
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
1
);
amoebaMultipoleForce
->
setCovalentMap
(
1
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
4
),
covalentMap
);
for
(
unsigned
int
jj
=
2
;
jj
<
numberOfParticles
;
jj
+=
3
){
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
jj
+
1
);
covalentMap
.
push_back
(
jj
+
2
);
amoebaMultipoleForce
->
setCovalentMap
(
jj
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
0
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
jj
);
covalentMap
.
push_back
(
jj
+
1
);
covalentMap
.
push_back
(
jj
+
2
);
amoebaMultipoleForce
->
setCovalentMap
(
jj
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
4
),
covalentMap
);
amoebaMultipoleForce
->
setCovalentMap
(
jj
+
1
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
4
),
covalentMap
);
amoebaMultipoleForce
->
setCovalentMap
(
jj
+
2
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
4
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
jj
);
amoebaMultipoleForce
->
setCovalentMap
(
jj
+
1
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
0
),
covalentMap
);
amoebaMultipoleForce
->
setCovalentMap
(
jj
+
2
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
0
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
jj
+
2
);
amoebaMultipoleForce
->
setCovalentMap
(
jj
+
1
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
1
),
covalentMap
);
covalentMap
.
resize
(
0
);
covalentMap
.
push_back
(
jj
+
1
);
amoebaMultipoleForce
->
setCovalentMap
(
jj
+
2
,
static_cast
<
OpenMM
::
AmoebaMultipoleForce
::
CovalentType
>
(
1
),
covalentMap
);
}
// 1-2 bonds needed
AmoebaHarmonicBondForce
*
amoebaHarmonicBondForce
=
new
AmoebaHarmonicBondForce
();
// addBond: particle1, particle2, length, quadraticK
for
(
unsigned
int
jj
=
2
;
jj
<
numberOfParticles
;
jj
+=
3
){
amoebaHarmonicBondForce
->
addBond
(
jj
,
jj
+
1
,
0.0000000e+00
,
0.0000000e+00
);
amoebaHarmonicBondForce
->
addBond
(
jj
,
jj
+
2
,
0.0000000e+00
,
0.0000000e+00
);
}
amoebaHarmonicBondForce
->
setAmoebaGlobalHarmonicBondCubic
(
-
2.5500000e+01
);
amoebaHarmonicBondForce
->
setAmoebaGlobalHarmonicBondQuartic
(
3.7931250e+02
);
system
.
addForce
(
amoebaHarmonicBondForce
);
std
::
vector
<
Vec3
>
positions
(
numberOfParticles
);
positions
[
0
]
=
Vec3
(
-
1.4364000e+00
,
-
1.2848000e+00
,
5.1940000e-01
);
positions
[
1
]
=
Vec3
(
-
3.2644000e+00
,
2.3620000e+00
,
1.3643000e+00
);
positions
[
2
]
=
Vec3
(
-
2.3780000e+00
,
1.8976000e+00
,
-
1.5921000e+00
);
positions
[
3
]
=
Vec3
(
-
2.3485183e+00
,
1.8296632e+00
,
-
1.5310146e+00
);
positions
[
4
]
=
Vec3
(
-
2.3784362e+00
,
1.8623910e+00
,
-
1.6814092e+00
);
positions
[
5
]
=
Vec3
(
-
2.1821000e+00
,
-
1.0808000e+00
,
2.9547000e+00
);
positions
[
6
]
=
Vec3
(
-
2.1198155e+00
,
-
1.0925202e+00
,
2.8825940e+00
);
positions
[
7
]
=
Vec3
(
-
2.1537255e+00
,
-
1.0076218e+00
,
3.0099797e+00
);
system
.
addForce
(
amoebaMultipoleForce
);
std
::
string
platformName
;
platformName
=
"CUDA"
;
LangevinIntegrator
integrator
(
0.0
,
0.1
,
0.01
);
Context
context
=
Context
(
system
,
integrator
,
Platform
::
getPlatformByName
(
platformName
)
);
context
.
setPositions
(
positions
);
if
(
testName
==
"testSystemMultipoleMoments"
){
Vec3
origin
(
0.0
,
0.0
,
0.0
);
amoebaMultipoleForce
->
getSystemMultipoleMoments
(
origin
,
context
,
outputMultipoleMoments
);
}
else
if
(
testName
==
"testMultipoleGridPotential"
){
amoebaMultipoleForce
->
getElectrostaticPotential
(
inputGrid
,
context
,
outputGridPotential
);
}
else
{
State
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
forces
=
state
.
getForces
();
energy
=
state
.
getPotentialEnergy
();
}
return
;
}
// test multipole mutual polarization using PME for system comprised of 2 ions and 2 waters
static
void
testMultipoleIonsAndWaterPMEDirectPolarization
(
FILE
*
log
)
{
std
::
string
testName
=
"testMultipoleIonsAndWaterDirectPolarization"
;
int
numberOfParticles
=
8
;
int
inputPmeGridDimension
=
64
;
double
cutoff
=
0.70
;
std
::
vector
<
Vec3
>
forces
;
double
energy
;
std
::
vector
<
double
>
outputMultipoleMoments
;
std
::
vector
<
Vec3
>
inputGrid
;
std
::
vector
<
double
>
outputGridPotential
;
setupAndGetForcesEnergyMultipoleIonsAndWater
(
AmoebaMultipoleForce
::
PME
,
AmoebaMultipoleForce
::
Direct
,
cutoff
,
inputPmeGridDimension
,
testName
,
forces
,
energy
,
outputMultipoleMoments
,
inputGrid
,
outputGridPotential
,
log
);
std
::
vector
<
Vec3
>
expectedForces
(
numberOfParticles
);
double
expectedEnergy
=
-
4.6859568e+01
;
expectedForces
[
0
]
=
Vec3
(
-
9.1266563e+00
,
1.5193632e+01
,
-
4.0047974e+00
);
expectedForces
[
1
]
=
Vec3
(
-
1.0497973e+00
,
1.4622548e+01
,
1.1789324e+01
);
expectedForces
[
2
]
=
Vec3
(
-
3.2564644e+00
,
6.5325105e+00
,
-
2.9698616e+00
);
expectedForces
[
3
]
=
Vec3
(
3.0687040e+00
,
-
8.4253665e-01
,
-
3.4081010e+00
);
expectedForces
[
4
]
=
Vec3
(
1.1407201e+00
,
-
3.1491550e+00
,
-
1.1326031e+00
);
expectedForces
[
5
]
=
Vec3
(
-
6.1046529e+00
,
9.5686061e-01
,
1.1506333e-01
);
expectedForces
[
6
]
=
Vec3
(
1.9275403e+00
,
-
5.6007439e-01
,
-
4.8387346e+00
);
expectedForces
[
7
]
=
Vec3
(
4.0644209e+00
,
-
3.3666305e+00
,
-
1.7022384e+00
);
double
tolerance
=
5.0e-04
;
compareForceNormsEnergy
(
testName
,
expectedEnergy
,
energy
,
expectedForces
,
forces
,
tolerance
,
log
);
}
// test multipole mutual polarization using PME for system comprised of 2 ions and 2 waters
static
void
testMultipoleIonsAndWaterPMEMutualPolarization
(
FILE
*
log
)
{
std
::
string
testName
=
"testMultipoleIonsAndWaterMutualPolarization"
;
int
numberOfParticles
=
8
;
int
inputPmeGridDimension
=
64
;
double
cutoff
=
0.70
;
std
::
vector
<
Vec3
>
forces
;
double
energy
;
std
::
vector
<
double
>
outputMultipoleMoments
;
std
::
vector
<
Vec3
>
inputGrid
;
std
::
vector
<
double
>
outputGridPotential
;
setupAndGetForcesEnergyMultipoleIonsAndWater
(
AmoebaMultipoleForce
::
PME
,
AmoebaMultipoleForce
::
Mutual
,
cutoff
,
inputPmeGridDimension
,
testName
,
forces
,
energy
,
outputMultipoleMoments
,
inputGrid
,
outputGridPotential
,
log
);
std
::
vector
<
Vec3
>
expectedForces
(
numberOfParticles
);
double
expectedEnergy
=
-
4.6859424e+01
;
expectedForces
[
0
]
=
Vec3
(
-
9.1272358e+00
,
1.5191516e+01
,
-
4.0058826e+00
);
expectedForces
[
1
]
=
Vec3
(
-
1.0497156e+00
,
1.4622425e+01
,
1.1789420e+01
);
expectedForces
[
2
]
=
Vec3
(
-
3.2560478e+00
,
6.5289712e+00
,
-
2.9779483e+00
);
expectedForces
[
3
]
=
Vec3
(
3.0672153e+00
,
-
8.4407797e-01
,
-
3.4094884e+00
);
expectedForces
[
4
]
=
Vec3
(
1.1382586e+00
,
-
3.1512949e+00
,
-
1.1387028e+00
);
expectedForces
[
5
]
=
Vec3
(
-
6.1050295e+00
,
9.5345692e-01
,
1.1488832e-01
);
expectedForces
[
6
]
=
Vec3
(
1.9319945e+00
,
-
5.5747599e-01
,
-
4.8469044e+00
);
expectedForces
[
7
]
=
Vec3
(
4.0622614e+00
,
-
3.3687594e+00
,
-
1.6986575e+00
);
//double tolerance = 1.0e-03;
//compareForcesEnergy( testName, expectedEnergy, energy, expectedForces, forces, tolerance, log );
double
tolerance
=
5.0e-04
;
compareForceNormsEnergy
(
testName
,
expectedEnergy
,
energy
,
expectedForces
,
forces
,
tolerance
,
log
);
}
// test computation of system multipole moments
static
void
testSystemMultipoleMoments
(
FILE
*
log
)
{
std
::
string
testName
=
"testSystemMultipoleMoments"
;
int
numberOfParticles
=
8
;
int
inputPmeGridDimension
=
64
;
double
cutoff
=
0.70
;
std
::
vector
<
Vec3
>
forces
;
double
energy
;
std
::
vector
<
double
>
outputMultipoleMoments
;
std
::
vector
<
Vec3
>
inputGrid
;
std
::
vector
<
double
>
outputGridPotential
;
setupAndGetForcesEnergyMultipoleIonsAndWater
(
AmoebaMultipoleForce
::
PME
,
AmoebaMultipoleForce
::
Mutual
,
cutoff
,
inputPmeGridDimension
,
testName
,
forces
,
energy
,
outputMultipoleMoments
,
inputGrid
,
outputGridPotential
,
log
);
std
::
vector
<
double
>
tinkerMoments
(
13
);
tinkerMoments
[
0
]
=
0.0000000e+00
;
tinkerMoments
[
1
]
=
-
8.5884599e+00
;
tinkerMoments
[
2
]
=
1.7447506e+01
;
tinkerMoments
[
3
]
=
3.9868461e+00
;
tinkerMoments
[
4
]
=
-
2.7977319e+00
;
tinkerMoments
[
5
]
=
-
7.8694903e+00
;
tinkerMoments
[
6
]
=
-
2.6429049e+00
;
tinkerMoments
[
7
]
=
-
7.8694903e+00
;
tinkerMoments
[
8
]
=
7.4048693e+00
;
tinkerMoments
[
9
]
=
6.7152875e+00
;
tinkerMoments
[
10
]
=
-
2.6429049e+00
;
tinkerMoments
[
11
]
=
6.7152875e+00
;
tinkerMoments
[
12
]
=
-
4.6071374e+00
;
double
tolerance
=
1.0e-04
;
for
(
unsigned
int
ii
=
0
;
ii
<
tinkerMoments
.
size
();
ii
++
){
double
difference
=
fabs
(
outputMultipoleMoments
[
ii
]
-
tinkerMoments
[
ii
]
);
//fprintf( stderr, "%2d %15.7e %15.7e %15.7e %15.7e\n", ii, difference, difference/fabs(tinkerMoments[ii]), outputMultipoleMonents[ii], tinkerMoments[ii] );
if
(
difference
>
tolerance
){
std
::
stringstream
details
;
details
<<
testName
<<
"Multipole moment "
<<
ii
<<
" does not agree w/ TINKER computed moments: OpenMM="
<<
outputMultipoleMoments
[
ii
];
details
<<
" TINKER="
<<
tinkerMoments
[
ii
]
<<
" difference="
<<
difference
;
throwException
(
__FILE__
,
__LINE__
,
details
.
str
());
}
}
}
// test computation of multipole potential on a grid
static
void
testMultipoleGridPotential
(
FILE
*
log
)
{
std
::
string
testName
=
"testMultipoleGridPotential"
;
int
numberOfParticles
=
8
;
int
inputPmeGridDimension
=
64
;
double
cutoff
=
0.70
;
std
::
vector
<
Vec3
>
forces
;
double
energy
;
std
::
vector
<
double
>
outputMultipoleMoments
;
// initialize grid
int
gridSize
=
27
;
std
::
vector
<
Vec3
>
inputGrid
(
gridSize
);
inputGrid
[
0
]
=
Vec3
(
-
3.2894000e+00
,
-
1.3098000e+00
,
-
1.7064092e+00
);
inputGrid
[
1
]
=
Vec3
(
-
3.2894000e+00
,
-
1.3098000e+00
,
6.3928525e-01
);
inputGrid
[
2
]
=
Vec3
(
-
3.2894000e+00
,
-
1.3098000e+00
,
2.9849797e+00
);
inputGrid
[
3
]
=
Vec3
(
-
3.2894000e+00
,
5.1360000e-01
,
-
1.7064092e+00
);
inputGrid
[
4
]
=
Vec3
(
-
3.2894000e+00
,
5.1360000e-01
,
6.3928525e-01
);
inputGrid
[
5
]
=
Vec3
(
-
3.2894000e+00
,
5.1360000e-01
,
2.9849797e+00
);
inputGrid
[
6
]
=
Vec3
(
-
3.2894000e+00
,
2.3370000e+00
,
-
1.7064092e+00
);
inputGrid
[
7
]
=
Vec3
(
-
3.2894000e+00
,
2.3370000e+00
,
6.3928525e-01
);
inputGrid
[
8
]
=
Vec3
(
-
3.2894000e+00
,
2.3370000e+00
,
2.9849797e+00
);
inputGrid
[
9
]
=
Vec3
(
-
2.3754000e+00
,
-
1.3098000e+00
,
-
1.7064092e+00
);
inputGrid
[
10
]
=
Vec3
(
-
2.3754000e+00
,
-
1.3098000e+00
,
6.3928525e-01
);
inputGrid
[
11
]
=
Vec3
(
-
2.3754000e+00
,
-
1.3098000e+00
,
2.9849797e+00
);
inputGrid
[
12
]
=
Vec3
(
-
2.3754000e+00
,
5.1360000e-01
,
-
1.7064092e+00
);
inputGrid
[
13
]
=
Vec3
(
-
2.3754000e+00
,
5.1360000e-01
,
6.3928525e-01
);
inputGrid
[
14
]
=
Vec3
(
-
2.3754000e+00
,
5.1360000e-01
,
2.9849797e+00
);
inputGrid
[
15
]
=
Vec3
(
-
2.3754000e+00
,
2.3370000e+00
,
-
1.7064092e+00
);
inputGrid
[
16
]
=
Vec3
(
-
2.3754000e+00
,
2.3370000e+00
,
6.3928525e-01
);
inputGrid
[
17
]
=
Vec3
(
-
2.3754000e+00
,
2.3370000e+00
,
2.9849797e+00
);
inputGrid
[
18
]
=
Vec3
(
-
1.4614000e+00
,
-
1.3098000e+00
,
-
1.7064092e+00
);
inputGrid
[
19
]
=
Vec3
(
-
1.4614000e+00
,
-
1.3098000e+00
,
6.3928525e-01
);
inputGrid
[
20
]
=
Vec3
(
-
1.4614000e+00
,
-
1.3098000e+00
,
2.9849797e+00
);
inputGrid
[
21
]
=
Vec3
(
-
1.4614000e+00
,
5.1360000e-01
,
-
1.7064092e+00
);
inputGrid
[
22
]
=
Vec3
(
-
1.4614000e+00
,
5.1360000e-01
,
6.3928525e-01
);
inputGrid
[
23
]
=
Vec3
(
-
1.4614000e+00
,
5.1360000e-01
,
2.9849797e+00
);
inputGrid
[
24
]
=
Vec3
(
-
1.4614000e+00
,
2.3370000e+00
,
-
1.7064092e+00
);
inputGrid
[
25
]
=
Vec3
(
-
1.4614000e+00
,
2.3370000e+00
,
6.3928525e-01
);
inputGrid
[
26
]
=
Vec3
(
-
1.4614000e+00
,
2.3370000e+00
,
2.9849797e+00
);
std
::
vector
<
double
>
outputGridPotential
;
setupAndGetForcesEnergyMultipoleIonsAndWater
(
AmoebaMultipoleForce
::
PME
,
AmoebaMultipoleForce
::
Mutual
,
cutoff
,
inputPmeGridDimension
,
testName
,
forces
,
energy
,
outputMultipoleMoments
,
inputGrid
,
outputGridPotential
,
log
);
// TINKER computed grid values
std
::
vector
<
double
>
tinkerGridPotential
(
gridSize
);
tinkerGridPotential
[
0
]
=
-
1.8587681e+01
;
tinkerGridPotential
[
1
]
=
-
3.7731481e+01
;
tinkerGridPotential
[
2
]
=
-
1.4093518e+01
;
tinkerGridPotential
[
3
]
=
-
8.6733284e-01
;
tinkerGridPotential
[
4
]
=
1.6378362e+01
;
tinkerGridPotential
[
5
]
=
1.7545816e+01
;
tinkerGridPotential
[
6
]
=
1.2115085e+01
;
tinkerGridPotential
[
7
]
=
1.5693689e+02
;
tinkerGridPotential
[
8
]
=
5.6517394e+01
;
tinkerGridPotential
[
9
]
=
-
2.8489173e+01
;
tinkerGridPotential
[
10
]
=
-
1.1037348e+02
;
tinkerGridPotential
[
11
]
=
-
7.1050586e+01
;
tinkerGridPotential
[
12
]
=
-
5.9901289e+00
;
tinkerGridPotential
[
13
]
=
-
4.0533846e+00
;
tinkerGridPotential
[
14
]
=
1.0506199e+01
;
tinkerGridPotential
[
15
]
=
-
8.6421838e+00
;
tinkerGridPotential
[
16
]
=
8.3729402e+01
;
tinkerGridPotential
[
17
]
=
4.4286652e+01
;
tinkerGridPotential
[
18
]
=
-
3.4746066e+01
;
tinkerGridPotential
[
19
]
=
-
1.0763056e+03
;
tinkerGridPotential
[
20
]
=
-
2.0034673e+01
;
tinkerGridPotential
[
21
]
=
-
1.2131063e+01
;
tinkerGridPotential
[
22
]
=
-
2.4662346e+01
;
tinkerGridPotential
[
23
]
=
1.4630799e+00
;
tinkerGridPotential
[
24
]
=
5.1623298e+00
;
tinkerGridPotential
[
25
]
=
3.3114482e+01
;
tinkerGridPotential
[
26
]
=
2.5828622e+01
;
double
tolerance
=
1.0e-04
;
for
(
unsigned
int
ii
=
0
;
ii
<
gridSize
;
ii
++
){
double
difference
=
fabs
(
outputGridPotential
[
ii
]
-
tinkerGridPotential
[
ii
]
);
//fprintf( stderr, "%2d %15.7e %15.7e %15.7e %15.7e\n", ii, difference, difference/fabs(tinkerGridPotential[ii]), outputGridPotential[ii], tinkerGridPotential[ii] );
if
(
difference
>
tolerance
){
std
::
stringstream
details
;
details
<<
testName
<<
"Multipole moment "
<<
ii
<<
" does not agree w/ TINKER computed moments: OpenMM="
<<
outputGridPotential
[
ii
];
details
<<
" TINKER="
<<
tinkerGridPotential
[
ii
]
<<
" difference="
<<
difference
;
throwException
(
__FILE__
,
__LINE__
,
details
.
str
());
}
}
}
int
main
(
int
numberOfArguments
,
char
*
argv
[]
)
{
try
{
std
::
cout
<<
"TestCudaAmoebaMultipoleForce running test..."
<<
std
::
endl
;
registerAmoebaCudaKernelFactories
();
FILE
*
log
=
NULL
;
// tests using two ammonia molecules
// test direct polarization, no cutoff
testMultipoleAmmoniaDirectPolarization
(
log
);
// test mutual polarization, no cutoff
// testMultipoleAmmoniaMutualPolarization( log );
//
// // test multipole direct & mutual polarization using PME
//
// testMultipoleWaterPMEDirectPolarization( log );
// testMultipoleWaterPMEMutualPolarization( log );
//
// // check validation of traceless/symmetric quadrupole tensor
//
// testQuadrupoleValidation( log );
//
// // system w/ 2 ions and 2 water molecules
//
// testMultipoleIonsAndWaterPMEMutualPolarization( log );
// testMultipoleIonsAndWaterPMEDirectPolarization( log );
//
// // test computation of system multipole moments
//
// testSystemMultipoleMoments( log );
//
// // test computation of grid potential
//
// testMultipoleGridPotential( log );
}
catch
(
const
std
::
exception
&
e
)
{
std
::
cout
<<
"exception: "
<<
e
.
what
()
<<
std
::
endl
;
std
::
cout
<<
"FAIL - ERROR. Test failed."
<<
std
::
endl
;
return
1
;
}
std
::
cout
<<
"Done"
<<
std
::
endl
;
return
0
;
}
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