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
a468fa3a
Commit
a468fa3a
authored
Aug 09, 2016
by
peastman
Committed by
GitHub
Aug 09, 2016
Browse files
Merge pull request #1553 from peastman/gayberne
Implemented Gay-Berne ellipsoids
parents
c1843f54
ebf0ca29
Changes
41
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
2719 additions
and
5 deletions
+2719
-5
platforms/cuda/src/kernels/gayBerne.cu
platforms/cuda/src/kernels/gayBerne.cu
+538
-0
platforms/cuda/tests/TestCudaGayBerneForce.cpp
platforms/cuda/tests/TestCudaGayBerneForce.cpp
+36
-0
platforms/opencl/include/OpenCLKernels.h
platforms/opencl/include/OpenCLKernels.h
+66
-0
platforms/opencl/src/OpenCLKernelFactory.cpp
platforms/opencl/src/OpenCLKernelFactory.cpp
+3
-1
platforms/opencl/src/OpenCLKernels.cpp
platforms/opencl/src/OpenCLKernels.cpp
+417
-0
platforms/opencl/src/OpenCLPlatform.cpp
platforms/opencl/src/OpenCLPlatform.cpp
+1
-0
platforms/opencl/src/kernels/gayBerne.cl
platforms/opencl/src/kernels/gayBerne.cl
+543
-0
platforms/opencl/tests/TestOpenCLGayBerneForce.cpp
platforms/opencl/tests/TestOpenCLGayBerneForce.cpp
+36
-0
platforms/reference/include/ReferenceGayBerneForce.h
platforms/reference/include/ReferenceGayBerneForce.h
+135
-0
platforms/reference/include/ReferenceKernels.h
platforms/reference/include/ReferenceKernels.h
+35
-0
platforms/reference/src/ReferenceKernelFactory.cpp
platforms/reference/src/ReferenceKernelFactory.cpp
+3
-3
platforms/reference/src/ReferenceKernels.cpp
platforms/reference/src/ReferenceKernels.cpp
+20
-0
platforms/reference/src/ReferencePlatform.cpp
platforms/reference/src/ReferencePlatform.cpp
+1
-0
platforms/reference/src/SimTKReference/ReferenceGayBerneForce.cpp
...s/reference/src/SimTKReference/ReferenceGayBerneForce.cpp
+318
-0
platforms/reference/tests/TestReferenceGayBerneForce.cpp
platforms/reference/tests/TestReferenceGayBerneForce.cpp
+36
-0
serialization/include/openmm/serialization/GayBerneForceProxy.h
...ization/include/openmm/serialization/GayBerneForceProxy.h
+53
-0
serialization/src/GayBerneForceProxy.cpp
serialization/src/GayBerneForceProxy.cpp
+98
-0
serialization/src/SerializationProxyRegistration.cpp
serialization/src/SerializationProxyRegistration.cpp
+4
-1
serialization/tests/TestSerializeGayBerneForce.cpp
serialization/tests/TestSerializeGayBerneForce.cpp
+112
-0
tests/TestGayBerneForce.h
tests/TestGayBerneForce.h
+264
-0
No files found.
platforms/cuda/src/kernels/gayBerne.cu
0 → 100644
View file @
a468fa3a
#define TILE_SIZE 32
#define NEIGHBOR_BLOCK_SIZE 32
/**
* Calculate the ellipsoid coordinate frames and associated matrices.
*/
extern
"C"
__global__
void
computeEllipsoidFrames
(
int
numParticles
,
const
real4
*
__restrict__
posq
,
int2
*
const
__restrict__
axisParticleIndices
,
const
float4
*
__restrict__
sigParams
,
const
float4
*
__restrict__
scale
,
real
*
__restrict__
aMatrix
,
real
*
__restrict__
bMatrix
,
real
*
__restrict__
gMatrix
,
const
int
*
sortedParticles
)
{
for
(
int
sortedIndex
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
sortedIndex
<
numParticles
;
sortedIndex
+=
blockDim
.
x
*
gridDim
.
x
)
{
// Compute the local coordinate system of the ellipsoid;
int
originalIndex
=
sortedParticles
[
sortedIndex
];
real3
pos
=
trimTo3
(
posq
[
originalIndex
]);
int2
axisParticles
=
axisParticleIndices
[
originalIndex
];
real3
xdir
,
ydir
,
zdir
;
if
(
axisParticles
.
x
==
-
1
)
{
xdir
=
make_real3
(
1
,
0
,
0
);
ydir
=
make_real3
(
0
,
1
,
0
);
}
else
{
xdir
=
pos
-
trimTo3
(
posq
[
axisParticles
.
x
]);
xdir
=
normalize
(
xdir
);
if
(
axisParticles
.
y
==
-
1
)
{
if
(
xdir
.
y
>
-
0.5
f
&&
xdir
.
y
<
0.5
f
)
ydir
=
make_real3
(
0
,
1
,
0
);
else
ydir
=
make_real3
(
1
,
0
,
0
);
}
else
ydir
=
pos
-
trimTo3
(
posq
[
axisParticles
.
y
]);
ydir
-=
xdir
*
dot
(
xdir
,
ydir
);
ydir
=
normalize
(
ydir
);
}
zdir
=
cross
(
xdir
,
ydir
);
// Compute matrices we will need later.
real
(
*
a
)[
3
]
=
(
real
(
*
)[
3
])
(
aMatrix
+
sortedIndex
*
9
);
real
(
*
b
)[
3
]
=
(
real
(
*
)[
3
])
(
bMatrix
+
sortedIndex
*
9
);
real
(
*
g
)[
3
]
=
(
real
(
*
)[
3
])
(
gMatrix
+
sortedIndex
*
9
);
a
[
0
][
0
]
=
xdir
.
x
;
a
[
0
][
1
]
=
xdir
.
y
;
a
[
0
][
2
]
=
xdir
.
z
;
a
[
1
][
0
]
=
ydir
.
x
;
a
[
1
][
1
]
=
ydir
.
y
;
a
[
1
][
2
]
=
ydir
.
z
;
a
[
2
][
0
]
=
zdir
.
x
;
a
[
2
][
1
]
=
zdir
.
y
;
a
[
2
][
2
]
=
zdir
.
z
;
float4
sig
=
sigParams
[
originalIndex
];
float3
r2
=
make_float3
(
sig
.
y
,
sig
.
z
,
sig
.
w
);
float3
e2
=
trimTo3
(
scale
[
originalIndex
]);
for
(
int
i
=
0
;
i
<
3
;
i
++
)
for
(
int
j
=
0
;
j
<
3
;
j
++
)
{
b
[
i
][
j
]
=
a
[
0
][
i
]
*
e2
.
x
*
a
[
0
][
j
]
+
a
[
1
][
i
]
*
e2
.
y
*
a
[
1
][
j
]
+
a
[
2
][
i
]
*
e2
.
z
*
a
[
2
][
j
];
g
[
i
][
j
]
=
a
[
0
][
i
]
*
r2
.
x
*
a
[
0
][
j
]
+
a
[
1
][
i
]
*
r2
.
y
*
a
[
1
][
j
]
+
a
[
2
][
i
]
*
r2
.
z
*
a
[
2
][
j
];
}
}
}
/**
* Find a bounding box for the atoms in each block.
*/
extern
"C"
__global__
void
findBlockBounds
(
int
numAtoms
,
real4
periodicBoxSize
,
real4
invPeriodicBoxSize
,
real4
periodicBoxVecX
,
real4
periodicBoxVecY
,
real4
periodicBoxVecZ
,
const
int
*
sortedAtoms
,
const
real4
*
__restrict__
posq
,
real4
*
__restrict__
sortedPos
,
real4
*
__restrict__
blockCenter
,
real4
*
__restrict__
blockBoundingBox
,
int
*
__restrict__
neighborBlockCount
)
{
int
index
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
int
base
=
index
*
TILE_SIZE
;
while
(
base
<
numAtoms
)
{
real4
pos
=
posq
[
sortedAtoms
[
base
]];
sortedPos
[
base
]
=
pos
;
#ifdef USE_PERIODIC
APPLY_PERIODIC_TO_POS
(
pos
)
#endif
real4
minPos
=
pos
;
real4
maxPos
=
pos
;
int
last
=
min
(
base
+
TILE_SIZE
,
numAtoms
);
for
(
int
i
=
base
+
1
;
i
<
last
;
i
++
)
{
pos
=
posq
[
sortedAtoms
[
i
]];
sortedPos
[
i
]
=
pos
;
#ifdef USE_PERIODIC
real4
center
=
0.5
f
*
(
maxPos
+
minPos
);
APPLY_PERIODIC_TO_POS_WITH_CENTER
(
pos
,
center
)
#endif
minPos
=
make_real4
(
min
(
minPos
.
x
,
pos
.
x
),
min
(
minPos
.
y
,
pos
.
y
),
min
(
minPos
.
z
,
pos
.
z
),
0
);
maxPos
=
make_real4
(
max
(
maxPos
.
x
,
pos
.
x
),
max
(
maxPos
.
y
,
pos
.
y
),
max
(
maxPos
.
z
,
pos
.
z
),
0
);
}
real4
blockSize
=
0.5
f
*
(
maxPos
-
minPos
);
blockBoundingBox
[
index
]
=
blockSize
;
blockCenter
[
index
]
=
0.5
f
*
(
maxPos
+
minPos
);
index
+=
blockDim
.
x
*
gridDim
.
x
;
base
=
index
*
TILE_SIZE
;
}
if
(
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
==
0
)
*
neighborBlockCount
=
0
;
}
/**
* This is called by findNeighbors() to write a block to the neighbor list.
*/
__device__
void
storeNeighbors
(
int
atom1
,
int
*
neighborBuffer
,
int
numAtomsInBuffer
,
int
maxNeighborBlocks
,
int
*
__restrict__
neighbors
,
int
*
__restrict__
neighborIndex
,
int
*
__restrict__
neighborBlockCount
)
{
int
blockIndex
=
atomicAdd
(
neighborBlockCount
,
1
);
if
(
blockIndex
>=
maxNeighborBlocks
)
return
;
// We don't have enough room for the neighbor list.
neighborIndex
[
blockIndex
]
=
atom1
;
int
baseIndex
=
blockIndex
*
NEIGHBOR_BLOCK_SIZE
;
for
(
int
i
=
0
;
i
<
numAtomsInBuffer
;
i
++
)
neighbors
[
baseIndex
+
i
]
=
neighborBuffer
[
i
];
for
(
int
i
=
numAtomsInBuffer
;
i
<
NEIGHBOR_BLOCK_SIZE
;
i
++
)
neighbors
[
baseIndex
+
i
]
=
-
1
;
}
/**
* Build a list of neighbors for each atom.
*/
extern
"C"
__global__
void
findNeighbors
(
int
numAtoms
,
int
maxNeighborBlocks
,
real4
periodicBoxSize
,
real4
invPeriodicBoxSize
,
real4
periodicBoxVecX
,
real4
periodicBoxVecY
,
real4
periodicBoxVecZ
,
real4
*
__restrict__
sortedPos
,
real4
*
__restrict__
blockCenter
,
real4
*
__restrict__
blockBoundingBox
,
int
*
__restrict__
neighbors
,
int
*
__restrict__
neighborIndex
,
int
*
__restrict__
neighborBlockCount
,
const
int
*
__restrict__
exclusions
,
const
int
*
__restrict__
exclusionStartIndex
)
{
const
int
numBlocks
=
(
numAtoms
+
TILE_SIZE
-
1
)
/
TILE_SIZE
;
int
neighborBuffer
[
NEIGHBOR_BLOCK_SIZE
];
for
(
int
atom1
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
atom1
<
numAtoms
;
atom1
+=
blockDim
.
x
*
gridDim
.
x
)
{
int
nextExclusion
=
exclusionStartIndex
[
atom1
];
int
lastExclusion
=
exclusionStartIndex
[
atom1
+
1
];
real4
pos
=
sortedPos
[
atom1
];
int
nextBufferIndex
=
0
;
// Loop over atom blocks and compute the distance of this atom from each one's bounding box.
for
(
int
block
=
(
atom1
+
1
)
/
TILE_SIZE
;
block
<
numBlocks
;
block
++
)
{
real4
center
=
blockCenter
[
block
];
real4
blockSize
=
blockBoundingBox
[
block
];
real4
blockDelta
=
center
-
pos
;
#ifdef USE_PERIODIC
APPLY_PERIODIC_TO_DELTA
(
blockDelta
)
#endif
blockDelta
.
x
=
max
((
real
)
0
,
fabs
(
blockDelta
.
x
)
-
blockSize
.
x
);
blockDelta
.
y
=
max
((
real
)
0
,
fabs
(
blockDelta
.
y
)
-
blockSize
.
y
);
blockDelta
.
z
=
max
((
real
)
0
,
fabs
(
blockDelta
.
z
)
-
blockSize
.
z
);
if
(
blockDelta
.
x
*
blockDelta
.
x
+
blockDelta
.
y
*
blockDelta
.
y
+
blockDelta
.
z
*
blockDelta
.
z
>=
CUTOFF_SQUARED
)
continue
;
// Loop over atoms within this block.
int
first
=
max
(
block
*
TILE_SIZE
,
atom1
+
1
);
int
last
=
min
((
block
+
1
)
*
TILE_SIZE
,
numAtoms
);
for
(
int
atom2
=
first
;
atom2
<
last
;
atom2
++
)
{
// Skip over excluded interactions.
if
(
nextExclusion
<
lastExclusion
&&
exclusions
[
nextExclusion
]
>=
atom2
)
{
nextExclusion
++
;
continue
;
}
real4
delta
=
pos
-
sortedPos
[
atom2
];
#ifdef USE_PERIODIC
APPLY_PERIODIC_TO_DELTA
(
delta
)
#endif
real
r2
=
delta
.
x
*
delta
.
x
+
delta
.
y
*
delta
.
y
+
delta
.
z
*
delta
.
z
;
if
(
r2
<
CUTOFF_SQUARED
)
{
neighborBuffer
[
nextBufferIndex
++
]
=
atom2
;
if
(
nextBufferIndex
==
NEIGHBOR_BLOCK_SIZE
)
{
storeNeighbors
(
atom1
,
neighborBuffer
,
nextBufferIndex
,
maxNeighborBlocks
,
neighbors
,
neighborIndex
,
neighborBlockCount
);
nextBufferIndex
=
0
;
}
}
}
}
if
(
nextBufferIndex
>
0
)
storeNeighbors
(
atom1
,
neighborBuffer
,
nextBufferIndex
,
maxNeighborBlocks
,
neighbors
,
neighborIndex
,
neighborBlockCount
);
}
}
typedef
struct
{
float4
sig
;
float2
eps
;
real3
pos
;
real
a
[
3
][
3
],
b
[
3
][
3
],
g
[
3
][
3
];
}
AtomData
;
__device__
void
loadAtomData
(
AtomData
*
data
,
int
sortedIndex
,
int
originalIndex
,
const
real4
*
__restrict__
pos
,
const
float4
*
__restrict__
sigParams
,
const
float2
*
__restrict__
epsParams
,
const
real
*
__restrict__
aMatrix
,
const
real
*
__restrict__
bMatrix
,
const
real
*
__restrict__
gMatrix
)
{
data
->
sig
=
sigParams
[
originalIndex
];
data
->
eps
=
epsParams
[
originalIndex
];
data
->
pos
=
trimTo3
(
pos
[
sortedIndex
]);
for
(
int
i
=
0
;
i
<
3
;
i
++
)
for
(
int
j
=
0
;
j
<
3
;
j
++
)
{
int
k
=
9
*
sortedIndex
+
3
*
i
+
j
;
data
->
a
[
i
][
j
]
=
aMatrix
[
k
];
data
->
b
[
i
][
j
]
=
bMatrix
[
k
];
data
->
g
[
i
][
j
]
=
gMatrix
[
k
];
}
}
inline
__device__
real3
matrixVectorProduct
(
real
(
*
m
)[
3
],
real3
v
)
{
return
make_real3
(
m
[
0
][
0
]
*
v
.
x
+
m
[
0
][
1
]
*
v
.
y
+
m
[
0
][
2
]
*
v
.
z
,
m
[
1
][
0
]
*
v
.
x
+
m
[
1
][
1
]
*
v
.
y
+
m
[
1
][
2
]
*
v
.
z
,
m
[
2
][
0
]
*
v
.
x
+
m
[
2
][
1
]
*
v
.
y
+
m
[
2
][
2
]
*
v
.
z
);
}
inline
__device__
real3
vectorMatrixProduct
(
real3
v
,
real
(
*
m
)[
3
])
{
return
make_real3
(
m
[
0
][
0
]
*
v
.
x
+
m
[
1
][
0
]
*
v
.
y
+
m
[
2
][
0
]
*
v
.
z
,
m
[
0
][
1
]
*
v
.
x
+
m
[
1
][
1
]
*
v
.
y
+
m
[
2
][
1
]
*
v
.
z
,
m
[
0
][
2
]
*
v
.
x
+
m
[
1
][
2
]
*
v
.
y
+
m
[
2
][
2
]
*
v
.
z
);
}
inline
__device__
void
matrixSum
(
real
(
*
result
)[
3
],
real
(
*
a
)[
3
],
real
(
*
b
)[
3
])
{
result
[
0
][
0
]
=
a
[
0
][
0
]
+
b
[
0
][
0
];
result
[
0
][
1
]
=
a
[
0
][
1
]
+
b
[
0
][
1
];
result
[
0
][
2
]
=
a
[
0
][
2
]
+
b
[
0
][
2
];
result
[
1
][
0
]
=
a
[
1
][
0
]
+
b
[
1
][
0
];
result
[
1
][
1
]
=
a
[
1
][
1
]
+
b
[
1
][
1
];
result
[
1
][
2
]
=
a
[
1
][
2
]
+
b
[
1
][
2
];
result
[
2
][
0
]
=
a
[
2
][
0
]
+
b
[
2
][
0
];
result
[
2
][
1
]
=
a
[
2
][
1
]
+
b
[
2
][
1
];
result
[
2
][
2
]
=
a
[
2
][
2
]
+
b
[
2
][
2
];
}
inline
__device__
real
determinant
(
real
(
*
m
)[
3
])
{
return
(
m
[
0
][
0
]
*
m
[
1
][
1
]
*
m
[
2
][
2
]
+
m
[
0
][
1
]
*
m
[
1
][
2
]
*
m
[
2
][
0
]
+
m
[
0
][
2
]
*
m
[
1
][
0
]
*
m
[
2
][
1
]
-
m
[
0
][
0
]
*
m
[
1
][
2
]
*
m
[
2
][
1
]
-
m
[
0
][
1
]
*
m
[
1
][
0
]
*
m
[
2
][
2
]
-
m
[
0
][
2
]
*
m
[
1
][
1
]
*
m
[
2
][
0
]);
}
inline
__device__
void
matrixInverse
(
real
(
*
result
)[
3
],
real
(
*
m
)[
3
])
{
real
invDet
=
RECIP
(
determinant
(
m
));
result
[
0
][
0
]
=
invDet
*
(
m
[
1
][
1
]
*
m
[
2
][
2
]
-
m
[
1
][
2
]
*
m
[
2
][
1
]);
result
[
1
][
0
]
=
-
invDet
*
(
m
[
1
][
0
]
*
m
[
2
][
2
]
-
m
[
1
][
2
]
*
m
[
2
][
0
]);
result
[
2
][
0
]
=
invDet
*
(
m
[
1
][
0
]
*
m
[
2
][
1
]
-
m
[
1
][
1
]
*
m
[
2
][
0
]);
result
[
0
][
1
]
=
-
invDet
*
(
m
[
0
][
1
]
*
m
[
2
][
2
]
-
m
[
0
][
2
]
*
m
[
2
][
1
]);
result
[
1
][
1
]
=
invDet
*
(
m
[
0
][
0
]
*
m
[
2
][
2
]
-
m
[
0
][
2
]
*
m
[
2
][
0
]);
result
[
2
][
1
]
=
-
invDet
*
(
m
[
0
][
0
]
*
m
[
2
][
1
]
-
m
[
0
][
1
]
*
m
[
2
][
0
]);
result
[
0
][
2
]
=
invDet
*
(
m
[
0
][
1
]
*
m
[
1
][
2
]
-
m
[
0
][
2
]
*
m
[
1
][
1
]);
result
[
1
][
2
]
=
-
invDet
*
(
m
[
0
][
0
]
*
m
[
1
][
2
]
-
m
[
0
][
2
]
*
m
[
1
][
0
]);
result
[
2
][
2
]
=
invDet
*
(
m
[
0
][
0
]
*
m
[
1
][
1
]
-
m
[
0
][
1
]
*
m
[
1
][
0
]);
}
__device__
void
computeOneInteraction
(
AtomData
*
data1
,
AtomData
*
data2
,
real
sigma
,
real
epsilon
,
real3
dr
,
real
r2
,
real3
*
force1
,
real3
*
force2
,
real3
*
torque1
,
real3
*
torque2
,
mixed
*
totalEnergy
)
{
real
rInv
=
RSQRT
(
r2
);
real
r
=
r2
*
rInv
;
real3
drUnit
=
dr
*
rInv
;
// Compute the switching function.
real
switchValue
=
1
,
switchDeriv
=
0
;
#if USE_SWITCH
if
(
r
>
SWITCH_CUTOFF
)
{
real
x
=
r
-
SWITCH_CUTOFF
;
switchValue
=
1
+
x
*
x
*
x
*
(
SWITCH_C3
+
x
*
(
SWITCH_C4
+
x
*
SWITCH_C5
));
switchDeriv
=
x
*
x
*
(
3
*
SWITCH_C3
+
x
*
(
4
*
SWITCH_C4
+
x
*
5
*
SWITCH_C5
));
}
#endif
// Compute vectors and matrices we'll be needing.
real
B12
[
3
][
3
],
G12
[
3
][
3
],
B12inv
[
3
][
3
],
G12inv
[
3
][
3
];
matrixSum
(
B12
,
data1
->
b
,
data2
->
b
);
matrixSum
(
G12
,
data1
->
g
,
data2
->
g
);
matrixInverse
(
B12inv
,
B12
);
matrixInverse
(
G12inv
,
G12
);
real
detG12
=
determinant
(
G12
);
// Estimate the distance between the ellipsoids and compute the first terms needed for the energy.
real
sigma12
=
1
/
SQRT
(
0.5
f
*
dot
(
drUnit
,
matrixVectorProduct
(
G12inv
,
drUnit
)));
real
h12
=
r
-
sigma12
;
real
rho
=
sigma
/
(
h12
+
sigma
);
real
rho2
=
rho
*
rho
;
real
rho6
=
rho2
*
rho2
*
rho2
;
real
u
=
4
*
epsilon
*
(
rho6
*
rho6
-
rho6
);
real
eta
=
SQRT
(
2
*
data1
->
eps
.
y
*
data2
->
eps
.
y
/
detG12
);
real
chi
=
2
*
dot
(
drUnit
,
matrixVectorProduct
(
B12inv
,
drUnit
));
chi
*=
chi
;
real
energy
=
u
*
eta
*
chi
;
// Compute the terms needed for the force.
real3
kappa
=
matrixVectorProduct
(
G12inv
,
dr
);
real3
iota
=
matrixVectorProduct
(
B12inv
,
dr
);
real
rInv2
=
rInv
*
rInv
;
real
dUSLJdr
=
24
*
epsilon
*
(
2
*
rho6
-
1
)
*
rho6
*
rho
/
sigma
;
real
temp
=
0.5
f
*
sigma12
*
sigma12
*
sigma12
*
rInv2
;
real3
dudr
=
(
drUnit
+
(
kappa
-
drUnit
*
dot
(
kappa
,
drUnit
))
*
temp
)
*
dUSLJdr
;
real3
dchidr
=
(
iota
-
drUnit
*
dot
(
iota
,
drUnit
))
*
(
-
8
*
rInv2
*
SQRT
(
chi
));
real3
force
=
(
dchidr
*
u
+
dudr
*
chi
)
*
(
eta
*
switchValue
)
-
drUnit
*
(
energy
*
switchDeriv
);
*
force1
+=
force
;
*
force2
-=
force
;
// Compute the terms needed for the torque.
for
(
int
j
=
0
;
j
<
2
;
j
++
)
{
real
(
*
a
)[
3
]
=
(
j
==
0
?
data1
->
a
:
data2
->
a
);
real
(
*
b
)[
3
]
=
(
j
==
0
?
data1
->
b
:
data2
->
b
);
real
(
*
g
)[
3
]
=
(
j
==
0
?
data1
->
g
:
data2
->
g
);
float4
sig
=
(
j
==
0
?
data1
->
sig
:
data2
->
sig
);
real3
dudq
=
cross
(
vectorMatrixProduct
(
kappa
,
g
),
kappa
*
(
temp
*
dUSLJdr
));
real3
dchidq
=
cross
(
vectorMatrixProduct
(
iota
,
b
),
iota
)
*
(
-
4
*
rInv2
);
real3
scale
=
make_real3
(
sig
.
y
,
sig
.
z
,
sig
.
w
)
*
(
-
0.5
f
*
eta
/
detG12
);
real
d
[
3
][
3
];
d
[
0
][
0
]
=
scale
.
x
*
(
2
*
a
[
0
][
0
]
*
(
G12
[
1
][
1
]
*
G12
[
2
][
2
]
-
G12
[
1
][
2
]
*
G12
[
2
][
1
])
+
a
[
0
][
2
]
*
(
G12
[
1
][
2
]
*
G12
[
0
][
1
]
+
G12
[
1
][
0
]
*
G12
[
2
][
1
]
-
G12
[
1
][
1
]
*
(
G12
[
0
][
2
]
+
G12
[
2
][
0
]))
+
a
[
0
][
1
]
*
(
G12
[
0
][
2
]
*
G12
[
2
][
1
]
+
G12
[
2
][
0
]
*
G12
[
1
][
2
]
-
G12
[
2
][
2
]
*
(
G12
[
0
][
1
]
+
G12
[
1
][
0
])));
d
[
0
][
1
]
=
scale
.
x
*
(
a
[
0
][
0
]
*
(
G12
[
0
][
2
]
*
G12
[
2
][
1
]
+
G12
[
2
][
0
]
*
G12
[
1
][
2
]
-
G12
[
2
][
2
]
*
(
G12
[
0
][
1
]
+
G12
[
1
][
0
]))
+
2
*
a
[
0
][
1
]
*
(
G12
[
0
][
0
]
*
G12
[
2
][
2
]
-
G12
[
2
][
0
]
*
G12
[
0
][
2
])
+
a
[
0
][
2
]
*
(
G12
[
1
][
0
]
*
G12
[
0
][
2
]
+
G12
[
2
][
0
]
*
G12
[
0
][
1
]
-
G12
[
0
][
0
]
*
(
G12
[
1
][
2
]
+
G12
[
2
][
1
])));
d
[
0
][
2
]
=
scale
.
x
*
(
a
[
0
][
0
]
*
(
G12
[
0
][
1
]
*
G12
[
1
][
2
]
+
G12
[
1
][
0
]
*
G12
[
2
][
1
]
-
G12
[
1
][
1
]
*
(
G12
[
0
][
2
]
+
G12
[
2
][
0
]))
+
a
[
0
][
1
]
*
(
G12
[
1
][
0
]
*
G12
[
0
][
2
]
+
G12
[
2
][
0
]
*
G12
[
0
][
1
]
-
G12
[
0
][
0
]
*
(
G12
[
1
][
2
]
+
G12
[
2
][
1
]))
+
2
*
a
[
0
][
2
]
*
(
G12
[
1
][
1
]
*
G12
[
0
][
0
]
-
G12
[
1
][
0
]
*
G12
[
0
][
1
]));
d
[
1
][
0
]
=
scale
.
y
*
(
2
*
a
[
1
][
0
]
*
(
G12
[
1
][
1
]
*
G12
[
2
][
2
]
-
G12
[
1
][
2
]
*
G12
[
2
][
1
])
+
a
[
1
][
1
]
*
(
G12
[
0
][
2
]
*
G12
[
2
][
1
]
+
G12
[
2
][
0
]
*
G12
[
1
][
2
]
-
G12
[
2
][
2
]
*
(
G12
[
0
][
1
]
+
G12
[
1
][
0
]))
+
a
[
1
][
2
]
*
(
G12
[
1
][
2
]
*
G12
[
0
][
1
]
+
G12
[
1
][
0
]
*
G12
[
2
][
1
]
-
G12
[
1
][
1
]
*
(
G12
[
0
][
2
]
+
G12
[
2
][
0
])));
d
[
1
][
1
]
=
scale
.
y
*
(
a
[
1
][
0
]
*
(
G12
[
0
][
2
]
*
G12
[
2
][
1
]
+
G12
[
2
][
0
]
*
G12
[
1
][
2
]
-
G12
[
2
][
2
]
*
(
G12
[
0
][
1
]
+
G12
[
1
][
0
]))
+
2
*
a
[
1
][
1
]
*
(
G12
[
2
][
2
]
*
G12
[
0
][
0
]
-
G12
[
2
][
0
]
*
G12
[
0
][
2
])
+
a
[
1
][
2
]
*
(
G12
[
1
][
0
]
*
G12
[
0
][
2
]
+
G12
[
0
][
1
]
*
G12
[
2
][
0
]
-
G12
[
0
][
0
]
*
(
G12
[
1
][
2
]
+
G12
[
2
][
1
])));
d
[
1
][
2
]
=
scale
.
y
*
(
a
[
1
][
0
]
*
(
G12
[
0
][
1
]
*
G12
[
1
][
2
]
+
G12
[
1
][
0
]
*
G12
[
2
][
1
]
-
G12
[
1
][
1
]
*
(
G12
[
0
][
2
]
+
G12
[
2
][
0
]))
+
a
[
1
][
1
]
*
(
G12
[
1
][
0
]
*
G12
[
0
][
2
]
+
G12
[
0
][
1
]
*
G12
[
2
][
0
]
-
G12
[
0
][
0
]
*
(
G12
[
1
][
2
]
+
G12
[
2
][
1
]))
+
2
*
a
[
1
][
2
]
*
(
G12
[
1
][
1
]
*
G12
[
0
][
0
]
-
G12
[
1
][
0
]
*
G12
[
0
][
1
]));
d
[
2
][
0
]
=
scale
.
z
*
(
2
*
a
[
2
][
0
]
*
(
G12
[
1
][
1
]
*
G12
[
2
][
2
]
-
G12
[
2
][
1
]
*
G12
[
1
][
2
])
+
a
[
2
][
1
]
*
(
G12
[
0
][
2
]
*
G12
[
2
][
1
]
+
G12
[
1
][
2
]
*
G12
[
2
][
0
]
-
G12
[
2
][
2
]
*
(
G12
[
0
][
1
]
+
G12
[
1
][
0
]))
+
a
[
2
][
2
]
*
(
G12
[
0
][
1
]
*
G12
[
1
][
2
]
+
G12
[
2
][
1
]
*
G12
[
1
][
0
]
-
G12
[
1
][
1
]
*
(
G12
[
0
][
2
]
+
G12
[
2
][
0
])));
d
[
2
][
1
]
=
scale
.
z
*
(
a
[
2
][
0
]
*
(
G12
[
0
][
2
]
*
G12
[
2
][
1
]
+
G12
[
1
][
2
]
*
G12
[
2
][
0
]
-
G12
[
2
][
2
]
*
(
G12
[
0
][
1
]
+
G12
[
1
][
0
]))
+
2
*
a
[
2
][
1
]
*
(
G12
[
0
][
0
]
*
G12
[
2
][
2
]
-
G12
[
0
][
2
]
*
G12
[
2
][
0
])
+
a
[
2
][
2
]
*
(
G12
[
1
][
0
]
*
G12
[
0
][
2
]
+
G12
[
0
][
1
]
*
G12
[
2
][
0
]
-
G12
[
0
][
0
]
*
(
G12
[
1
][
2
]
+
G12
[
2
][
1
])));
d
[
2
][
2
]
=
scale
.
z
*
(
a
[
2
][
0
]
*
(
G12
[
0
][
1
]
*
G12
[
1
][
2
]
+
G12
[
2
][
1
]
*
G12
[
1
][
0
]
-
G12
[
1
][
1
]
*
(
G12
[
0
][
2
]
+
G12
[
2
][
0
]))
+
a
[
2
][
1
]
*
(
G12
[
1
][
0
]
*
G12
[
0
][
2
]
+
G12
[
2
][
0
]
*
G12
[
0
][
1
]
-
G12
[
0
][
0
]
*
(
G12
[
1
][
2
]
+
G12
[
2
][
1
]))
+
2
*
a
[
2
][
2
]
*
(
G12
[
1
][
1
]
*
G12
[
0
][
0
]
-
G12
[
1
][
0
]
*
G12
[
0
][
1
]));
real3
detadq
=
make_real3
(
0
);
for
(
int
i
=
0
;
i
<
3
;
i
++
)
detadq
+=
cross
(
make_real3
(
a
[
i
][
0
],
a
[
i
][
1
],
a
[
i
][
2
]),
make_real3
(
d
[
i
][
0
],
d
[
i
][
1
],
d
[
i
][
2
]));
real3
torque
=
(
dchidq
*
(
u
*
eta
)
+
detadq
*
(
u
*
chi
)
+
dudq
*
(
eta
*
chi
))
*
switchValue
;
*
(
j
==
0
?
torque1
:
torque2
)
-=
torque
;
}
*
totalEnergy
+=
switchValue
*
energy
;
}
/**
* Compute the interactions.
*/
extern
"C"
__global__
void
computeForce
(
unsigned
long
long
*
__restrict__
forceBuffers
,
unsigned
long
long
*
__restrict__
torqueBuffers
,
int
numAtoms
,
int
numExceptions
,
mixed
*
__restrict__
energyBuffer
,
const
real4
*
__restrict__
pos
,
const
float4
*
__restrict__
sigParams
,
const
float2
*
__restrict__
epsParams
,
const
int
*
__restrict__
sortedAtoms
,
const
real
*
__restrict__
aMatrix
,
const
real
*
__restrict__
bMatrix
,
const
real
*
__restrict__
gMatrix
,
const
int
*
__restrict__
exclusions
,
const
int
*
__restrict__
exclusionStartIndex
,
const
int4
*
__restrict__
exceptionParticles
,
const
float2
*
__restrict__
exceptionParams
#ifdef USE_CUTOFF
,
int
maxNeighborBlocks
,
int
*
__restrict__
neighbors
,
int
*
__restrict__
neighborIndex
,
int
*
__restrict__
neighborBlockCount
,
real4
periodicBoxSize
,
real4
invPeriodicBoxSize
,
real4
periodicBoxVecX
,
real4
periodicBoxVecY
,
real4
periodicBoxVecZ
#endif
)
{
const
unsigned
int
warp
=
(
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
)
/
TILE_SIZE
;
mixed
energy
=
0
;
#ifdef USE_CUTOFF
const
int
numBlocks
=
*
neighborBlockCount
;
if
(
numBlocks
>
maxNeighborBlocks
)
return
;
// There wasn't enough memory for the neighbor list.
for
(
int
block
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
block
<
numBlocks
;
block
+=
blockDim
.
x
*
gridDim
.
x
)
{
// Load parameters for atom1.
int
atom1
=
neighborIndex
[
block
];
int
index1
=
sortedAtoms
[
atom1
];
AtomData
data1
;
loadAtomData
(
&
data1
,
atom1
,
index1
,
pos
,
sigParams
,
epsParams
,
aMatrix
,
bMatrix
,
gMatrix
);
real3
force1
=
make_real3
(
0
);
real3
torque1
=
make_real3
(
0
);
for
(
int
indexInBlock
=
0
;
indexInBlock
<
NEIGHBOR_BLOCK_SIZE
;
indexInBlock
++
)
{
// Load parameters for atom2.
int
atom2
=
neighbors
[
NEIGHBOR_BLOCK_SIZE
*
block
+
indexInBlock
];
if
(
atom2
==
-
1
)
continue
;
int
index2
=
sortedAtoms
[
atom2
];
AtomData
data2
;
loadAtomData
(
&
data2
,
atom2
,
index2
,
pos
,
sigParams
,
epsParams
,
aMatrix
,
bMatrix
,
gMatrix
);
real3
force2
=
make_real3
(
0
);
real3
torque2
=
make_real3
(
0
);
// Compute the interaction.
real3
delta
=
data1
.
pos
-
data2
.
pos
;
#ifdef USE_PERIODIC
APPLY_PERIODIC_TO_DELTA
(
delta
)
#endif
real
r2
=
delta
.
x
*
delta
.
x
+
delta
.
y
*
delta
.
y
+
delta
.
z
*
delta
.
z
;
real
sigma
=
data1
.
sig
.
x
+
data2
.
sig
.
x
;
real
epsilon
=
data1
.
eps
.
x
*
data2
.
eps
.
x
;
computeOneInteraction
(
&
data1
,
&
data2
,
sigma
,
epsilon
,
delta
,
r2
,
&
force1
,
&
force2
,
&
torque1
,
&
torque2
,
&
energy
);
atomicAdd
(
&
forceBuffers
[
index2
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force2
.
x
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
index2
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force2
.
y
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
index2
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force2
.
z
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index2
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque2
.
x
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index2
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque2
.
y
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index2
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque2
.
z
*
0x100000000
)));
}
atomicAdd
(
&
forceBuffers
[
index1
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force1
.
x
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
index1
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force1
.
y
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
index1
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force1
.
z
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index1
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque1
.
x
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index1
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque1
.
y
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index1
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque1
.
z
*
0x100000000
)));
}
#else
for
(
int
atom1
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
atom1
<
numAtoms
;
atom1
+=
blockDim
.
x
*
gridDim
.
x
)
{
// Load parameters for atom1.
int
index1
=
sortedAtoms
[
atom1
];
AtomData
data1
;
loadAtomData
(
&
data1
,
atom1
,
index1
,
pos
,
sigParams
,
epsParams
,
aMatrix
,
bMatrix
,
gMatrix
);
real3
force1
=
make_real3
(
0
);
real3
torque1
=
make_real3
(
0
);
int
nextExclusion
=
exclusionStartIndex
[
atom1
];
int
lastExclusion
=
exclusionStartIndex
[
atom1
+
1
];
for
(
int
atom2
=
atom1
+
1
;
atom2
<
numAtoms
;
atom2
++
)
{
// Skip over excluded interactions.
if
(
nextExclusion
<
lastExclusion
&&
exclusions
[
nextExclusion
]
==
atom2
)
{
nextExclusion
++
;
continue
;
}
// Load parameters for atom2.
int
index2
=
sortedAtoms
[
atom2
];
AtomData
data2
;
loadAtomData
(
&
data2
,
atom2
,
index2
,
pos
,
sigParams
,
epsParams
,
aMatrix
,
bMatrix
,
gMatrix
);
real3
force2
=
make_real3
(
0
);
real3
torque2
=
make_real3
(
0
);
// Compute the interaction.
real3
delta
=
data1
.
pos
-
data2
.
pos
;
real
r2
=
delta
.
x
*
delta
.
x
+
delta
.
y
*
delta
.
y
+
delta
.
z
*
delta
.
z
;
real
sigma
=
data1
.
sig
.
x
+
data2
.
sig
.
x
;
real
epsilon
=
data1
.
eps
.
x
*
data2
.
eps
.
x
;
computeOneInteraction
(
&
data1
,
&
data2
,
sigma
,
epsilon
,
delta
,
r2
,
&
force1
,
&
force2
,
&
torque1
,
&
torque2
,
&
energy
);
atomicAdd
(
&
forceBuffers
[
index2
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force2
.
x
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
index2
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force2
.
y
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
index2
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force2
.
z
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index2
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque2
.
x
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index2
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque2
.
y
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index2
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque2
.
z
*
0x100000000
)));
}
atomicAdd
(
&
forceBuffers
[
index1
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force1
.
x
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
index1
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force1
.
y
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
index1
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force1
.
z
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index1
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque1
.
x
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index1
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque1
.
y
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index1
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque1
.
z
*
0x100000000
)));
}
#endif
// Now compute exceptions.
for
(
int
index
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
index
<
numExceptions
;
index
+=
blockDim
.
x
*
gridDim
.
x
)
{
int4
atomIndices
=
exceptionParticles
[
index
];
float2
params
=
exceptionParams
[
index
];
int
index1
=
atomIndices
.
x
,
index2
=
atomIndices
.
y
;
int
atom1
=
atomIndices
.
z
,
atom2
=
atomIndices
.
w
;
AtomData
data1
,
data2
;
loadAtomData
(
&
data1
,
atom1
,
index1
,
pos
,
sigParams
,
epsParams
,
aMatrix
,
bMatrix
,
gMatrix
);
loadAtomData
(
&
data2
,
atom2
,
index2
,
pos
,
sigParams
,
epsParams
,
aMatrix
,
bMatrix
,
gMatrix
);
real3
force1
=
make_real3
(
0
),
force2
=
make_real3
(
0
);
real3
torque1
=
make_real3
(
0
),
torque2
=
make_real3
(
0
);
real3
delta
=
data1
.
pos
-
data2
.
pos
;
real
r2
=
delta
.
x
*
delta
.
x
+
delta
.
y
*
delta
.
y
+
delta
.
z
*
delta
.
z
;
#ifdef USE_CUTOFF
if
(
r2
<
CUTOFF_SQUARED
)
{
#endif
computeOneInteraction
(
&
data1
,
&
data2
,
params
.
x
,
params
.
y
,
delta
,
r2
,
&
force1
,
&
force2
,
&
torque1
,
&
torque2
,
&
energy
);
atomicAdd
(
&
forceBuffers
[
index1
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force1
.
x
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
index1
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force1
.
y
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
index1
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force1
.
z
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
index2
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force2
.
x
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
index2
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force2
.
y
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
index2
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force2
.
z
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index1
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque1
.
x
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index1
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque1
.
y
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index1
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque1
.
z
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index2
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque2
.
x
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index2
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque2
.
y
*
0x100000000
)));
atomicAdd
(
&
torqueBuffers
[
index2
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
torque2
.
z
*
0x100000000
)));
#ifdef USE_CUTOFF
}
#endif
}
energyBuffer
[
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
]
+=
energy
;
}
/**
* Convert the torques to forces on the connected particles.
*/
extern
"C"
__global__
void
applyTorques
(
unsigned
long
long
*
__restrict__
forceBuffers
,
long
long
*
__restrict__
torqueBuffers
,
int
numParticles
,
const
real4
*
__restrict__
posq
,
int2
*
const
__restrict__
axisParticleIndices
,
const
int
*
sortedParticles
)
{
const
unsigned
int
warp
=
(
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
)
/
TILE_SIZE
;
for
(
int
sortedIndex
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
sortedIndex
<
numParticles
;
sortedIndex
+=
blockDim
.
x
*
gridDim
.
x
)
{
int
originalIndex
=
sortedParticles
[
sortedIndex
];
real3
pos
=
trimTo3
(
posq
[
originalIndex
]);
int2
axisParticles
=
axisParticleIndices
[
originalIndex
];
if
(
axisParticles
.
x
!=
-
1
)
{
// Load the torque.
real
scale
=
1
/
(
real
)
0x100000000
;
real3
torque
=
make_real3
(
scale
*
torqueBuffers
[
originalIndex
],
scale
*
torqueBuffers
[
originalIndex
+
PADDED_NUM_ATOMS
],
scale
*
torqueBuffers
[
originalIndex
+
2
*
PADDED_NUM_ATOMS
]);
real3
force
=
make_real3
(
0
),
xforce
=
make_real3
(
0
),
yforce
=
make_real3
(
0
);
// Apply a force to the x particle.
real3
dx
=
trimTo3
(
posq
[
axisParticles
.
x
])
-
pos
;
real
dx2
=
dot
(
dx
,
dx
);
real3
f
=
cross
(
torque
,
dx
)
/
dx2
;
xforce
+=
f
;
force
-=
f
;
if
(
axisParticles
.
y
!=
-
1
)
{
// Apply a force to the y particle. This is based on the component of the torque
// that was not already applied to the x particle.
real3
dy
=
trimTo3
(
posq
[
axisParticles
.
y
])
-
pos
;
real
dy2
=
dot
(
dy
,
dy
);
real3
torque2
=
dx
*
dot
(
torque
,
dx
)
/
dx2
;
f
=
cross
(
torque2
,
dy
)
/
dy2
;
yforce
+=
f
;
force
-=
f
;
}
atomicAdd
(
&
forceBuffers
[
originalIndex
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force
.
x
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
originalIndex
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force
.
y
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
originalIndex
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
force
.
z
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
axisParticles
.
x
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
xforce
.
x
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
axisParticles
.
x
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
xforce
.
y
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
axisParticles
.
x
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
xforce
.
z
*
0x100000000
)));
if
(
axisParticles
.
y
!=
-
1
)
{
atomicAdd
(
&
forceBuffers
[
axisParticles
.
y
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
yforce
.
x
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
axisParticles
.
y
+
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
yforce
.
y
*
0x100000000
)));
atomicAdd
(
&
forceBuffers
[
axisParticles
.
y
+
2
*
PADDED_NUM_ATOMS
],
static_cast
<
unsigned
long
long
>
((
long
long
)
(
yforce
.
z
*
0x100000000
)));
}
}
}
}
platforms/cuda/tests/TestCudaGayBerneForce.cpp
0 → 100644
View file @
a468fa3a
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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) 2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* 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. *
* -------------------------------------------------------------------------- */
#include "CudaTests.h"
#include "TestGayBerneForce.h"
void
runPlatformTests
()
{
}
platforms/opencl/include/OpenCLKernels.h
View file @
a468fa3a
...
...
@@ -1084,6 +1084,72 @@ private:
cl
::
Kernel
forceKernel
,
blockBoundsKernel
,
neighborsKernel
,
startIndicesKernel
,
copyPairsKernel
;
};
/**
* This kernel is invoked by GayBerneForce to calculate the forces acting on the system.
*/
class
OpenCLCalcGayBerneForceKernel
:
public
CalcGayBerneForceKernel
{
public:
OpenCLCalcGayBerneForceKernel
(
std
::
string
name
,
const
Platform
&
platform
,
OpenCLContext
&
cl
)
:
CalcGayBerneForceKernel
(
name
,
platform
),
cl
(
cl
),
hasInitializedKernels
(
false
),
sortedParticles
(
NULL
),
axisParticleIndices
(
NULL
),
sigParams
(
NULL
),
epsParams
(
NULL
),
scale
(
NULL
),
exceptionParticles
(
NULL
),
exceptionParams
(
NULL
),
aMatrix
(
NULL
),
bMatrix
(
NULL
),
gMatrix
(
NULL
),
exclusions
(
NULL
),
exclusionStartIndex
(
NULL
),
blockCenter
(
NULL
),
blockBoundingBox
(
NULL
),
neighbors
(
NULL
),
neighborIndex
(
NULL
),
neighborBlockCount
(
NULL
),
sortedPos
(
NULL
),
torque
(
NULL
)
{
}
~
OpenCLCalcGayBerneForceKernel
();
/**
* Initialize the kernel.
*
* @param system the System this kernel will be applied to
* @param force the GayBerneForce this kernel will be used for
*/
void
initialize
(
const
System
&
system
,
const
GayBerneForce
&
force
);
/**
* Execute the kernel to calculate the forces and/or energy.
*
* @param context the context in which to execute this kernel
* @param includeForces true if forces should be calculated
* @return the potential energy due to the force
*/
double
execute
(
ContextImpl
&
context
,
bool
includeForces
,
bool
includeEnergy
);
/**
* Copy changed parameters over to a context.
*
* @param context the context to copy parameters to
* @param force the GayBerneForce to copy the parameters from
*/
void
copyParametersToContext
(
ContextImpl
&
context
,
const
GayBerneForce
&
force
);
private:
class
ReorderListener
;
void
sortAtoms
();
OpenCLContext
&
cl
;
bool
hasInitializedKernels
;
int
numRealParticles
,
maxNeighborBlocks
;
GayBerneForce
::
NonbondedMethod
nonbondedMethod
;
OpenCLArray
*
sortedParticles
;
OpenCLArray
*
axisParticleIndices
;
OpenCLArray
*
sigParams
;
OpenCLArray
*
epsParams
;
OpenCLArray
*
scale
;
OpenCLArray
*
exceptionParticles
;
OpenCLArray
*
exceptionParams
;
OpenCLArray
*
aMatrix
;
OpenCLArray
*
bMatrix
;
OpenCLArray
*
gMatrix
;
OpenCLArray
*
exclusions
;
OpenCLArray
*
exclusionStartIndex
;
OpenCLArray
*
blockCenter
;
OpenCLArray
*
blockBoundingBox
;
OpenCLArray
*
neighbors
;
OpenCLArray
*
neighborIndex
;
OpenCLArray
*
neighborBlockCount
;
OpenCLArray
*
sortedPos
;
OpenCLArray
*
torque
;
std
::
vector
<
bool
>
isRealParticle
;
std
::
vector
<
std
::
pair
<
int
,
int
>
>
exceptionAtoms
;
std
::
vector
<
std
::
pair
<
int
,
int
>
>
excludedPairs
;
cl
::
Kernel
framesKernel
,
blockBoundsKernel
,
neighborsKernel
,
forceKernel
,
torqueKernel
;
};
/**
* This kernel is invoked by VerletIntegrator to take one time step.
*/
...
...
platforms/opencl/src/OpenCLKernelFactory.cpp
View file @
a468fa3a
...
...
@@ -6,7 +6,7 @@
* 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.
*
* Portions copyright (c) 2008
-2016
Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
...
...
@@ -108,6 +108,8 @@ KernelImpl* OpenCLKernelFactory::createKernelImpl(std::string name, const Platfo
return
new
OpenCLCalcCustomCompoundBondForceKernel
(
name
,
platform
,
cl
,
context
.
getSystem
());
if
(
name
==
CalcCustomManyParticleForceKernel
::
Name
())
return
new
OpenCLCalcCustomManyParticleForceKernel
(
name
,
platform
,
cl
,
context
.
getSystem
());
if
(
name
==
CalcGayBerneForceKernel
::
Name
())
return
new
OpenCLCalcGayBerneForceKernel
(
name
,
platform
,
cl
);
if
(
name
==
IntegrateVerletStepKernel
::
Name
())
return
new
OpenCLIntegrateVerletStepKernel
(
name
,
platform
,
cl
);
if
(
name
==
IntegrateLangevinStepKernel
::
Name
())
...
...
platforms/opencl/src/OpenCLKernels.cpp
View file @
a468fa3a
...
...
@@ -6208,6 +6208,423 @@ void OpenCLCalcCustomManyParticleForceKernel::copyParametersToContext(ContextImp
cl.invalidateMolecules();
}
class OpenCLGayBerneForceInfo : public OpenCLForceInfo {
public:
OpenCLGayBerneForceInfo(int requiredBuffers, const GayBerneForce& force) : OpenCLForceInfo(requiredBuffers), force(force) {
}
bool areParticlesIdentical(int particle1, int particle2) {
int xparticle1, yparticle1;
double sigma1, epsilon1, sx1, sy1, sz1, ex1, ey1, ez1;
int xparticle2, yparticle2;
double sigma2, epsilon2, sx2, sy2, sz2, ex2, ey2, ez2;
force.getParticleParameters(particle1, sigma1, epsilon1, xparticle1, yparticle1, sx1, sy1, sz1, ex1, ey1, ez1);
force.getParticleParameters(particle2, sigma2, epsilon2, xparticle2, yparticle2, sx2, sy2, sz2, ex2, ey2, ez2);
return (sigma1 == sigma2 && epsilon1 == epsilon2 && sx1 == sx2 && sy1 == sy2 && sz1 == sz2 && ex1 == ex2 && ey1 == ey2 && ez1 == ez2);
}
int getNumParticleGroups() {
return force.getNumExceptions()+force.getNumParticles();
}
void getParticlesInGroup(int index, vector<int>& particles) {
if (index < force.getNumExceptions()) {
int particle1, particle2;
double sigma, epsilon;
force.getExceptionParameters(index, particle1, particle2, sigma, epsilon);
particles.resize(2);
particles[0] = particle1;
particles[1] = particle2;
}
else {
int particle = index-force.getNumExceptions();
int xparticle, yparticle;
double sigma, epsilon, sx, sy, sz, ex, ey, ez;
force.getParticleParameters(particle, sigma, epsilon, xparticle, yparticle, sx, sy, sz, ex, ey, ez);
particles.clear();
particles.push_back(particle);
if (xparticle > -1)
particles.push_back(xparticle);
if (yparticle > -1)
particles.push_back(yparticle);
}
}
bool areGroupsIdentical(int group1, int group2) {
if (group1 < force.getNumExceptions() && group2 < force.getNumExceptions()) {
int particle1, particle2;
double sigma1, sigma2, epsilon1, epsilon2;
force.getExceptionParameters(group1, particle1, particle2, sigma1, epsilon1);
force.getExceptionParameters(group2, particle1, particle2, sigma2, epsilon2);
return (sigma1 == sigma2 && epsilon1 == epsilon2);
}
return true;
}
private:
const GayBerneForce& force;
};
class OpenCLCalcGayBerneForceKernel::ReorderListener : public OpenCLContext::ReorderListener {
public:
ReorderListener(OpenCLCalcGayBerneForceKernel& owner) : owner(owner) {
}
void execute() {
owner.sortAtoms();
}
private:
OpenCLCalcGayBerneForceKernel& owner;
};
OpenCLCalcGayBerneForceKernel::~OpenCLCalcGayBerneForceKernel() {
if (sortedParticles != NULL)
delete sortedParticles;
if (axisParticleIndices != NULL)
delete axisParticleIndices;
if (sigParams != NULL)
delete sigParams;
if (epsParams != NULL)
delete epsParams;
if (scale != NULL)
delete scale;
if (exceptionParticles != NULL)
delete exceptionParticles;
if (exceptionParams != NULL)
delete exceptionParams;
if (aMatrix != NULL)
delete aMatrix;
if (bMatrix != NULL)
delete bMatrix;
if (gMatrix != NULL)
delete gMatrix;
if (exclusions != NULL)
delete exclusions;
if (exclusionStartIndex != NULL)
delete exclusionStartIndex;
if (blockCenter != NULL)
delete blockCenter;
if (blockBoundingBox != NULL)
delete blockBoundingBox;
if (neighbors != NULL)
delete neighbors;
if (neighborIndex != NULL)
delete neighborIndex;
if (neighborBlockCount != NULL)
delete neighborBlockCount;
if (sortedPos != NULL)
delete sortedPos;
if (torque != NULL)
delete torque;
}
void OpenCLCalcGayBerneForceKernel::initialize(const System& system, const GayBerneForce& force) {
if (!cl.getSupports64BitGlobalAtomics())
throw OpenMMException("GayBerneForce requires a device that supports 64 bit atomic operations");
// Initialize interactions.
int numParticles = force.getNumParticles();
sigParams = OpenCLArray::create<mm_float4>(cl, cl.getPaddedNumAtoms(), "sigParams");
epsParams = OpenCLArray::create<mm_float2>(cl, cl.getPaddedNumAtoms(), "epsParams");
scale = OpenCLArray::create<mm_float4>(cl, cl.getPaddedNumAtoms(), "scale");
axisParticleIndices = OpenCLArray::create<mm_int2>(cl, cl.getPaddedNumAtoms(), "axisParticleIndices");
sortedParticles = OpenCLArray::create<cl_int>(cl, cl.getPaddedNumAtoms(), "sortedParticles");
aMatrix = OpenCLArray::create<cl_float>(cl, 9*cl.getPaddedNumAtoms(), "aMatrix");
bMatrix = OpenCLArray::create<cl_float>(cl, 9*cl.getPaddedNumAtoms(), "bMatrix");
gMatrix = OpenCLArray::create<cl_float>(cl, 9*cl.getPaddedNumAtoms(), "gMatrix");
vector<mm_float4> sigParamsVector(cl.getPaddedNumAtoms(), mm_float4(0, 0, 0, 0));
vector<mm_float2> epsParamsVector(cl.getPaddedNumAtoms(), mm_float2(0, 0));
vector<mm_float4> scaleVector(cl.getPaddedNumAtoms(), mm_float4(0, 0, 0, 0));
vector<mm_int2> axisParticleVector(cl.getPaddedNumAtoms(), mm_int2(0, 0));
isRealParticle.resize(cl.getPaddedNumAtoms());
for (int i = 0; i < numParticles; i++) {
int xparticle, yparticle;
double sigma, epsilon, sx, sy, sz, ex, ey, ez;
force.getParticleParameters(i, sigma, epsilon, xparticle, yparticle, sx, sy, sz, ex, ey, ez);
axisParticleVector[i] = mm_int2(xparticle, yparticle);
sigParamsVector[i] = mm_float4((float) (0.5*sigma), (float) (0.25*sx*sx), (float) (0.25*sy*sy), (float) (0.25*sz*sz));
epsParamsVector[i] = mm_float2((float) sqrt(epsilon), (float) (0.125*(sx*sy + sz*sz)*sqrt(sx*sy)));
scaleVector[i] = mm_float4((float) (1/sqrt(ex)), (float) (1/sqrt(ey)), (float) (1/sqrt(ez)), 0);
isRealParticle[i] = (epsilon != 0.0);
}
sigParams->upload(sigParamsVector);
epsParams->upload(epsParamsVector);
scale->upload(scaleVector);
axisParticleIndices->upload(axisParticleVector);
// Record exceptions and exclusions.
vector<mm_float2> exceptionParamsVec;
for (int i = 0; i < force.getNumExceptions(); i++) {
int particle1, particle2;
double sigma, epsilon;
force.getExceptionParameters(i, particle1, particle2, sigma, epsilon);
if (epsilon != 0.0) {
exceptionParamsVec.push_back(mm_float2((float) sigma, (float) epsilon));
exceptionAtoms.push_back(make_pair(particle1, particle2));
isRealParticle[particle1] = true;
isRealParticle[particle2] = true;
}
if (isRealParticle[particle1] && isRealParticle[particle2])
excludedPairs.push_back(pair<int, int>(particle1, particle2));
}
numRealParticles = 0;
for (int i = 0; i < isRealParticle.size(); i++)
if (isRealParticle[i])
numRealParticles++;
int numExceptions = exceptionParamsVec.size();
exclusions = OpenCLArray::create<cl_int>(cl, max(1, (int) excludedPairs.size()), "exclusions");
exclusionStartIndex = OpenCLArray::create<cl_int>(cl, numRealParticles+1, "exclusionStartIndex");
exceptionParticles = OpenCLArray::create<mm_int4>(cl, max(1, numExceptions), "exceptionParticles");
exceptionParams = OpenCLArray::create<mm_float2>(cl, max(1, numExceptions), "exceptionParams");
if (numExceptions > 0)
exceptionParams->upload(exceptionParamsVec);
// Create data structures used for the neighbor list.
int numAtomBlocks = (numRealParticles+31)/32;
int elementSize = (cl.getUseDoublePrecision() ? sizeof(cl_double) : sizeof(cl_float));
blockCenter = new OpenCLArray(cl, numAtomBlocks, 4*elementSize, "blockCenter");
blockBoundingBox = new OpenCLArray(cl, numAtomBlocks, 4*elementSize, "blockBoundingBox");
sortedPos = new OpenCLArray(cl, numRealParticles, 4*elementSize, "sortedPos");
maxNeighborBlocks = numRealParticles*2;
neighbors = OpenCLArray::create<cl_int>(cl, maxNeighborBlocks*32, "neighbors");
neighborIndex = OpenCLArray::create<cl_int>(cl, maxNeighborBlocks, "neighborIndex");
neighborBlockCount = OpenCLArray::create<cl_int>(cl, 1, "neighborBlockCount");
// Create array for accumulating torques.
torque = OpenCLArray::create<cl_long>(cl, 3*cl.getPaddedNumAtoms(), "torque");
cl.addAutoclearBuffer(*torque);
// Create the kernels.
nonbondedMethod = force.getNonbondedMethod();
bool useCutoff = (nonbondedMethod != GayBerneForce::NoCutoff);
bool usePeriodic = (nonbondedMethod == GayBerneForce::CutoffPeriodic);
map<string, string> defines;
defines["USE_SWITCH"] = (useCutoff && force.getUseSwitchingFunction() ? "1" : "0");
double cutoff = force.getCutoffDistance();
defines["CUTOFF_SQUARED"] = cl.doubleToString(cutoff*cutoff);
if (useCutoff) {
defines["USE_CUTOFF"] = 1;
if (usePeriodic)
defines["USE_PERIODIC"] = "1";
// Compute the switching coefficients.
if (force.getUseSwitchingFunction()) {
defines["SWITCH_CUTOFF"] = cl.doubleToString(force.getSwitchingDistance());
defines["SWITCH_C3"] = cl.doubleToString(10/pow(force.getSwitchingDistance()-cutoff, 3.0));
defines["SWITCH_C4"] = cl.doubleToString(15/pow(force.getSwitchingDistance()-cutoff, 4.0));
defines["SWITCH_C5"] = cl.doubleToString(6/pow(force.getSwitchingDistance()-cutoff, 5.0));
}
}
defines["PADDED_NUM_ATOMS"] = cl.intToString(cl.getPaddedNumAtoms());
cl::Program program = cl.createProgram(OpenCLKernelSources::gayBerne, defines);
framesKernel = cl::Kernel(program, "computeEllipsoidFrames");
blockBoundsKernel = cl::Kernel(program, "findBlockBounds");
neighborsKernel = cl::Kernel(program, "findNeighbors");
forceKernel = cl::Kernel(program, "computeForce");
torqueKernel = cl::Kernel(program, "applyTorques");
cl.addForce(new OpenCLGayBerneForceInfo(cl.getNonbondedUtilities().getNumForceBuffers(), force));
cl.addReorderListener(new ReorderListener(*this));
}
double OpenCLCalcGayBerneForceKernel::execute(ContextImpl& context, bool includeForces, bool includeEnergy) {
if (!hasInitializedKernels) {
hasInitializedKernels = true;
sortAtoms();
framesKernel.setArg<cl_int>(0, numRealParticles);
framesKernel.setArg<cl::Buffer>(1, cl.getPosq().getDeviceBuffer());
framesKernel.setArg<cl::Buffer>(2, axisParticleIndices->getDeviceBuffer());
framesKernel.setArg<cl::Buffer>(3, sigParams->getDeviceBuffer());
framesKernel.setArg<cl::Buffer>(4, scale->getDeviceBuffer());
framesKernel.setArg<cl::Buffer>(5, aMatrix->getDeviceBuffer());
framesKernel.setArg<cl::Buffer>(6, bMatrix->getDeviceBuffer());
framesKernel.setArg<cl::Buffer>(7, gMatrix->getDeviceBuffer());
framesKernel.setArg<cl::Buffer>(8, sortedParticles->getDeviceBuffer());
blockBoundsKernel.setArg<cl_int>(0, numRealParticles);
blockBoundsKernel.setArg<cl::Buffer>(6, sortedParticles->getDeviceBuffer());
blockBoundsKernel.setArg<cl::Buffer>(7, cl.getPosq().getDeviceBuffer());
blockBoundsKernel.setArg<cl::Buffer>(8, sortedPos->getDeviceBuffer());
blockBoundsKernel.setArg<cl::Buffer>(9, blockCenter->getDeviceBuffer());
blockBoundsKernel.setArg<cl::Buffer>(10, blockBoundingBox->getDeviceBuffer());
blockBoundsKernel.setArg<cl::Buffer>(11, neighborBlockCount->getDeviceBuffer());
neighborsKernel.setArg<cl_int>(0, numRealParticles);
neighborsKernel.setArg<cl_int>(1, maxNeighborBlocks);
neighborsKernel.setArg<cl::Buffer>(7, sortedPos->getDeviceBuffer());
neighborsKernel.setArg<cl::Buffer>(8, blockCenter->getDeviceBuffer());
neighborsKernel.setArg<cl::Buffer>(9, blockBoundingBox->getDeviceBuffer());
neighborsKernel.setArg<cl::Buffer>(10, neighbors->getDeviceBuffer());
neighborsKernel.setArg<cl::Buffer>(11, neighborIndex->getDeviceBuffer());
neighborsKernel.setArg<cl::Buffer>(12, neighborBlockCount->getDeviceBuffer());
neighborsKernel.setArg<cl::Buffer>(13, exclusions->getDeviceBuffer());
neighborsKernel.setArg<cl::Buffer>(14, exclusionStartIndex->getDeviceBuffer());
int index = 0;
forceKernel.setArg<cl::Buffer>(index++, cl.getLongForceBuffer().getDeviceBuffer());
forceKernel.setArg<cl::Buffer>(index++, torque->getDeviceBuffer());
forceKernel.setArg<cl_int>(index++, numRealParticles);
forceKernel.setArg<cl_int>(index++, exceptionAtoms.size());
forceKernel.setArg<cl::Buffer>(index++, cl.getEnergyBuffer().getDeviceBuffer());
forceKernel.setArg<cl::Buffer>(index++, sortedPos->getDeviceBuffer());
forceKernel.setArg<cl::Buffer>(index++, sigParams->getDeviceBuffer());
forceKernel.setArg<cl::Buffer>(index++, epsParams->getDeviceBuffer());
forceKernel.setArg<cl::Buffer>(index++, sortedParticles->getDeviceBuffer());
forceKernel.setArg<cl::Buffer>(index++, aMatrix->getDeviceBuffer());
forceKernel.setArg<cl::Buffer>(index++, bMatrix->getDeviceBuffer());
forceKernel.setArg<cl::Buffer>(index++, gMatrix->getDeviceBuffer());
forceKernel.setArg<cl::Buffer>(index++, exclusions->getDeviceBuffer());
forceKernel.setArg<cl::Buffer>(index++, exclusionStartIndex->getDeviceBuffer());
forceKernel.setArg<cl::Buffer>(index++, exceptionParticles->getDeviceBuffer());
forceKernel.setArg<cl::Buffer>(index++, exceptionParams->getDeviceBuffer());
if (nonbondedMethod != GayBerneForce::NoCutoff) {
forceKernel.setArg<cl_int>(index++, maxNeighborBlocks);
forceKernel.setArg<cl::Buffer>(index++, neighbors->getDeviceBuffer());
forceKernel.setArg<cl::Buffer>(index++, neighborIndex->getDeviceBuffer());
forceKernel.setArg<cl::Buffer>(index++, neighborBlockCount->getDeviceBuffer());
}
index = 0;
torqueKernel.setArg<cl::Buffer>(index++, cl.getLongForceBuffer().getDeviceBuffer());
torqueKernel.setArg<cl::Buffer>(index++, torque->getDeviceBuffer());
torqueKernel.setArg<cl_int>(index++, numRealParticles);
torqueKernel.setArg<cl::Buffer>(index++, cl.getPosq().getDeviceBuffer());
torqueKernel.setArg<cl::Buffer>(index++, axisParticleIndices->getDeviceBuffer());
torqueKernel.setArg<cl::Buffer>(index++, sortedParticles->getDeviceBuffer());
}
cl.executeKernel(framesKernel, numRealParticles);
setPeriodicBoxArgs(cl, blockBoundsKernel, 1);
cl.executeKernel(blockBoundsKernel, (numRealParticles+31)/32);
if (nonbondedMethod == GayBerneForce::NoCutoff) {
cl.executeKernel(forceKernel, cl.getNonbondedUtilities().getNumForceThreadBlocks()*cl.getNonbondedUtilities().getForceThreadBlockSize());
}
else {
while (true) {
setPeriodicBoxArgs(cl, neighborsKernel, 2);
cl.executeKernel(neighborsKernel, numRealParticles);
cl_int* count = (cl_int*) cl.getPinnedBuffer();
cl::Event event;
cl.getQueue().enqueueReadBuffer(neighborBlockCount->getDeviceBuffer(), CL_FALSE, 0, neighborBlockCount->getSize()*neighborBlockCount->getElementSize(), count, NULL, &event);
setPeriodicBoxArgs(cl, forceKernel, 20);
cl.executeKernel(forceKernel, cl.getNonbondedUtilities().getNumForceThreadBlocks()*cl.getNonbondedUtilities().getForceThreadBlockSize());
event.wait();
if (*count <= maxNeighborBlocks)
break;
// There wasn't enough room for the neighbor list, so we need to recreate it.
delete neighbors;
neighbors = NULL;
delete neighborIndex;
neighborIndex = NULL;
maxNeighborBlocks = (int) ceil((*count)*1.1);
neighbors = OpenCLArray::create<cl_int>(cl, maxNeighborBlocks*32, "neighbors");
neighborIndex = OpenCLArray::create<cl_int>(cl, maxNeighborBlocks, "neighborIndex");
neighborsKernel.setArg<cl::Buffer>(10, neighbors->getDeviceBuffer());
neighborsKernel.setArg<cl::Buffer>(11, neighborIndex->getDeviceBuffer());
forceKernel.setArg<cl::Buffer>(17, neighbors->getDeviceBuffer());
forceKernel.setArg<cl::Buffer>(18, neighborIndex->getDeviceBuffer());
}
}
cl.executeKernel(torqueKernel, numRealParticles);
return 0.0;
}
void OpenCLCalcGayBerneForceKernel::copyParametersToContext(ContextImpl& context, const GayBerneForce& force) {
// Make sure the new parameters are acceptable.
if (force.getNumParticles() != cl.getNumAtoms())
throw OpenMMException("updateParametersInContext: The number of particles has changed");
vector<int> exceptions;
for (int i = 0; i < force.getNumExceptions(); i++) {
int particle1, particle2;
double sigma, epsilon;
force.getExceptionParameters(i, particle1, particle2, sigma, epsilon);
if (exceptionAtoms.size() > exceptions.size() && make_pair(particle1, particle2) == exceptionAtoms[exceptions.size()])
exceptions.push_back(i);
else if (epsilon != 0.0)
throw OpenMMException("updateParametersInContext: The set of non-excluded exceptions has changed");
}
int numExceptions = exceptionAtoms.size();
// Record the per-particle parameters.
vector<mm_float4> sigParamsVector(cl.getPaddedNumAtoms(), mm_float4(0, 0, 0, 0));
vector<mm_float2> epsParamsVector(cl.getPaddedNumAtoms(), mm_float2(0, 0));
vector<mm_float4> scaleVector(cl.getPaddedNumAtoms(), mm_float4(0, 0, 0, 0));
for (int i = 0; i < force.getNumParticles(); i++) {
int xparticle, yparticle;
double sigma, epsilon, sx, sy, sz, ex, ey, ez;
force.getParticleParameters(i, sigma, epsilon, xparticle, yparticle, sx, sy, sz, ex, ey, ez);
sigParamsVector[i] = mm_float4((float) (0.5*sigma), (float) (0.25*sx*sx), (float) (0.25*sy*sy), (float) (0.25*sz*sz));
epsParamsVector[i] = mm_float2((float) sqrt(epsilon), (float) (0.125*(sx*sy + sz*sz)*sqrt(sx*sy)));
scaleVector[i] = mm_float4((float) (1/sqrt(ex)), (float) (1/sqrt(ey)), (float) (1/sqrt(ez)), 0);
if (epsilon != 0.0 && !isRealParticle[i])
throw OpenMMException("updateParametersInContext: The set of ignored particles (ones with epsilon=0) has changed");
}
sigParams->upload(sigParamsVector);
epsParams->upload(epsParamsVector);
scale->upload(scaleVector);
// Record the exceptions.
if (numExceptions > 0) {
vector<mm_float2> exceptionParamsVec(numExceptions);
for (int i = 0; i < numExceptions; i++) {
int atom1, atom2;
double sigma, epsilon;
force.getExceptionParameters(exceptions[i], atom1, atom2, sigma, epsilon);
exceptionParamsVec[i] = mm_float2((float) sigma, (float) epsilon);
}
exceptionParams->upload(exceptionParamsVec);
}
cl.invalidateMolecules();
sortAtoms();
}
void OpenCLCalcGayBerneForceKernel::sortAtoms() {
// Sort the list of atoms by type to avoid thread divergence. This is executed every time
// the atoms are reordered.
int nextIndex = 0;
vector<cl_int> particles(cl.getPaddedNumAtoms(), 0);
const vector<int>& order = cl.getAtomIndex();
vector<int> inverseOrder(order.size(), -1);
for (int i = 0; i < cl.getNumAtoms(); i++) {
int atom = order[i];
if (isRealParticle[atom]) {
inverseOrder[atom] = nextIndex;
particles[nextIndex++] = atom;
}
}
sortedParticles->upload(particles);
// Update the list of exception particles.
int numExceptions = exceptionAtoms.size();
if (numExceptions > 0) {
vector<mm_int4> exceptionParticlesVec(numExceptions);
for (int i = 0; i < numExceptions; i++)
exceptionParticlesVec[i] = mm_int4(exceptionAtoms[i].first, exceptionAtoms[i].second, inverseOrder[exceptionAtoms[i].first], inverseOrder[exceptionAtoms[i].second]);
exceptionParticles->upload(exceptionParticlesVec);
}
// Rebuild the list of exclusions.
vector<vector<int> > excludedAtoms(numRealParticles);
for (int i = 0; i < excludedPairs.size(); i++) {
int first = inverseOrder[min(excludedPairs[i].first, excludedPairs[i].second)];
int second = inverseOrder[max(excludedPairs[i].first, excludedPairs[i].second)];
excludedAtoms[first].push_back(second);
}
int index = 0;
vector<int> exclusionVec(exclusions->getSize());
vector<int> startIndexVec(exclusionStartIndex->getSize());
for (int i = 0; i < numRealParticles; i++) {
startIndexVec[i] = index;
for (int j = 0; j < excludedAtoms[i].size(); j++)
exclusionVec[index++] = excludedAtoms[i][j];
}
startIndexVec[numRealParticles] = index;
exclusions->upload(exclusionVec);
exclusionStartIndex->upload(startIndexVec);
}
OpenCLIntegrateVerletStepKernel::~OpenCLIntegrateVerletStepKernel() {
}
...
...
platforms/opencl/src/OpenCLPlatform.cpp
View file @
a468fa3a
...
...
@@ -83,6 +83,7 @@ OpenCLPlatform::OpenCLPlatform() {
registerKernelFactory
(
CalcCustomCentroidBondForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcCustomCompoundBondForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcCustomManyParticleForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcGayBerneForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
IntegrateVerletStepKernel
::
Name
(),
factory
);
registerKernelFactory
(
IntegrateLangevinStepKernel
::
Name
(),
factory
);
registerKernelFactory
(
IntegrateBrownianStepKernel
::
Name
(),
factory
);
...
...
platforms/opencl/src/kernels/gayBerne.cl
0 → 100644
View file @
a468fa3a
#
pragma
OPENCL
EXTENSION
cl_khr_global_int32_base_atomics
:
enable
#
pragma
OPENCL
EXTENSION
cl_khr_int64_base_atomics
:
enable
#
define
TILE_SIZE
32
#
define
NEIGHBOR_BLOCK_SIZE
32
/**
*
Calculate
the
ellipsoid
coordinate
frames
and
associated
matrices.
*/
__kernel
void
computeEllipsoidFrames
(
int
numParticles,
__global
const
real4*
restrict
posq,
__global
int2*
const
restrict
axisParticleIndices,
__global
const
float4*
restrict
sigParams,
__global
const
float4*
restrict
scale,
__global
real*
restrict
aMatrix,
__global
real*
restrict
bMatrix,
__global
real*
restrict
gMatrix,
__global
const
int*
sortedParticles
)
{
for
(
int
sortedIndex
=
get_global_id
(
0
)
; sortedIndex < numParticles; sortedIndex += get_global_size(0)) {
//
Compute
the
local
coordinate
system
of
the
ellipsoid
;
int
originalIndex
=
sortedParticles[sortedIndex]
;
real3
pos
=
posq[originalIndex].xyz
;
int2
axisParticles
=
axisParticleIndices[originalIndex]
;
real3
xdir,
ydir,
zdir
;
if
(
axisParticles.x
==
-1
)
{
xdir
=
(
real3
)
(
1
,
0
,
0
)
;
ydir
=
(
real3
)
(
0
,
1
,
0
)
;
}
else
{
xdir
=
pos-posq[axisParticles.x].xyz
;
xdir
=
normalize
(
xdir
)
;
if
(
axisParticles.y
==
-1
)
{
if
(
xdir.y
>
-0.5f
&&
xdir.y
<
0.5f
)
ydir
=
(
real3
)
(
0
,
1
,
0
)
;
else
ydir
=
(
real3
)
(
1
,
0
,
0
)
;
}
else
ydir
=
pos-posq[axisParticles.y].xyz
;
ydir
-=
xdir*dot
(
xdir,
ydir
)
;
ydir
=
normalize
(
ydir
)
;
}
zdir
=
cross
(
xdir,
ydir
)
;
//
Compute
matrices
we
will
need
later.
__global
real
(
*a
)
[3]
=
(
__global
real
(
*
)
[3]
)
(
aMatrix+sortedIndex*9
)
;
__global
real
(
*b
)
[3]
=
(
__global
real
(
*
)
[3]
)
(
bMatrix+sortedIndex*9
)
;
__global
real
(
*g
)
[3]
=
(
__global
real
(
*
)
[3]
)
(
gMatrix+sortedIndex*9
)
;
a[0][0]
=
xdir.x
;
a[0][1]
=
xdir.y
;
a[0][2]
=
xdir.z
;
a[1][0]
=
ydir.x
;
a[1][1]
=
ydir.y
;
a[1][2]
=
ydir.z
;
a[2][0]
=
zdir.x
;
a[2][1]
=
zdir.y
;
a[2][2]
=
zdir.z
;
float4
sig
=
sigParams[originalIndex]
;
float3
r2
=
sig.yzw
;
float3
e2
=
scale[originalIndex].xyz
;
for
(
int
i
=
0
; i < 3; i++)
for
(
int
j
=
0
; j < 3; j++) {
b[i][j]
=
a[0][i]*e2.x*a[0][j]
+
a[1][i]*e2.y*a[1][j]
+
a[2][i]*e2.z*a[2][j]
;
g[i][j]
=
a[0][i]*r2.x*a[0][j]
+
a[1][i]*r2.y*a[1][j]
+
a[2][i]*r2.z*a[2][j]
;
}
}
}
/**
*
Find
a
bounding
box
for
the
atoms
in
each
block.
*/
__kernel
void
findBlockBounds
(
int
numAtoms,
real4
periodicBoxSize,
real4
invPeriodicBoxSize,
real4
periodicBoxVecX,
real4
periodicBoxVecY,
real4
periodicBoxVecZ,
__global
const
int*
sortedAtoms,
__global
const
real4*
restrict
posq,
__global
real4*
restrict
sortedPos,
__global
real4*
restrict
blockCenter,
__global
real4*
restrict
blockBoundingBox,
__global
int*
restrict
neighborBlockCount
)
{
int
index
=
get_global_id
(
0
)
;
int
base
=
index*TILE_SIZE
;
while
(
base
<
numAtoms
)
{
real4
pos
=
posq[sortedAtoms[base]]
;
sortedPos[base]
=
pos
;
#
ifdef
USE_PERIODIC
APPLY_PERIODIC_TO_POS
(
pos
)
#
endif
real4
minPos
=
pos
;
real4
maxPos
=
pos
;
int
last
=
min
(
base+TILE_SIZE,
numAtoms
)
;
for
(
int
i
=
base+1
; i < last; i++) {
pos
=
posq[sortedAtoms[i]]
;
sortedPos[i]
=
pos
;
#
ifdef
USE_PERIODIC
real4
center
=
0.5f*
(
maxPos+minPos
)
;
APPLY_PERIODIC_TO_POS_WITH_CENTER
(
pos,
center
)
#
endif
minPos
=
min
(
minPos,
pos
)
;
maxPos
=
max
(
maxPos,
pos
)
;
}
real4
blockSize
=
0.5f*
(
maxPos-minPos
)
;
blockBoundingBox[index]
=
blockSize
;
blockCenter[index]
=
0.5f*
(
maxPos+minPos
)
;
index
+=
get_global_size
(
0
)
;
base
=
index*TILE_SIZE
;
}
if
(
get_global_id
(
0
)
==
0
)
*neighborBlockCount
=
0
;
}
/**
*
This
is
called
by
findNeighbors
()
to
write
a
block
to
the
neighbor
list.
*/
void
storeNeighbors
(
int
atom1,
int*
neighborBuffer,
int
numAtomsInBuffer,
int
maxNeighborBlocks,
__global
int*
restrict
neighbors,
__global
int*
restrict
neighborIndex,
__global
int*
restrict
neighborBlockCount
)
{
int
blockIndex
=
atom_add
(
neighborBlockCount,
1
)
;
if
(
blockIndex
>=
maxNeighborBlocks
)
return
; // We don't have enough room for the neighbor list.
neighborIndex[blockIndex]
=
atom1
;
int
baseIndex
=
blockIndex*NEIGHBOR_BLOCK_SIZE
;
for
(
int
i
=
0
; i < numAtomsInBuffer; i++)
neighbors[baseIndex+i]
=
neighborBuffer[i]
;
for
(
int
i
=
numAtomsInBuffer
; i < NEIGHBOR_BLOCK_SIZE; i++)
neighbors[baseIndex+i]
=
-1
;
}
/**
*
Build
a
list
of
neighbors
for
each
atom.
*/
__kernel
void
findNeighbors
(
int
numAtoms,
int
maxNeighborBlocks,
real4
periodicBoxSize,
real4
invPeriodicBoxSize,
real4
periodicBoxVecX,
real4
periodicBoxVecY,
real4
periodicBoxVecZ,
__global
real4*
restrict
sortedPos,
__global
real4*
restrict
blockCenter,
__global
real4*
restrict
blockBoundingBox,
__global
int*
restrict
neighbors,
__global
int*
restrict
neighborIndex,
__global
int*
restrict
neighborBlockCount,
__global
const
int*
restrict
exclusions,
__global
const
int*
restrict
exclusionStartIndex
)
{
const
int
numBlocks
=
(
numAtoms+TILE_SIZE-1
)
/TILE_SIZE
;
int
neighborBuffer[NEIGHBOR_BLOCK_SIZE]
;
for
(
int
atom1
=
get_global_id
(
0
)
; atom1 < numAtoms; atom1 += get_global_size(0)) {
int
nextExclusion
=
exclusionStartIndex[atom1]
;
int
lastExclusion
=
exclusionStartIndex[atom1+1]
;
real4
pos
=
sortedPos[atom1]
;
int
nextBufferIndex
=
0
;
//
Loop
over
atom
blocks
and
compute
the
distance
of
this
atom
from
each
one
's
bounding
box.
for
(
int
block
=
(
atom1+1
)
/TILE_SIZE
; block < numBlocks; block++) {
real4
center
=
blockCenter[block]
;
real4
blockSize
=
blockBoundingBox[block]
;
real4
blockDelta
=
center-pos
;
#
ifdef
USE_PERIODIC
APPLY_PERIODIC_TO_DELTA
(
blockDelta
)
#
endif
blockDelta.x
=
max
((
real
)
0
,
fabs
(
blockDelta.x
)
-blockSize.x
)
;
blockDelta.y
=
max
((
real
)
0
,
fabs
(
blockDelta.y
)
-blockSize.y
)
;
blockDelta.z
=
max
((
real
)
0
,
fabs
(
blockDelta.z
)
-blockSize.z
)
;
if
(
blockDelta.x*blockDelta.x+blockDelta.y*blockDelta.y+blockDelta.z*blockDelta.z
>=
CUTOFF_SQUARED
)
continue
;
//
Loop
over
atoms
within
this
block.
int
first
=
max
(
block*TILE_SIZE,
atom1+1
)
;
int
last
=
min
((
block+1
)
*TILE_SIZE,
numAtoms
)
;
for
(
int
atom2
=
first
; atom2 < last; atom2++) {
//
Skip
over
excluded
interactions.
if
(
nextExclusion
<
lastExclusion
&&
exclusions[nextExclusion]
>=
atom2
)
{
nextExclusion++
;
continue
;
}
real4
delta
=
pos-sortedPos[atom2]
;
#
ifdef
USE_PERIODIC
APPLY_PERIODIC_TO_DELTA
(
delta
)
#
endif
real
r2
=
delta.x*delta.x
+
delta.y*delta.y
+
delta.z*delta.z
;
if
(
r2
<
CUTOFF_SQUARED
)
{
neighborBuffer[nextBufferIndex++]
=
atom2
;
if
(
nextBufferIndex
==
NEIGHBOR_BLOCK_SIZE
)
{
storeNeighbors
(
atom1,
neighborBuffer,
nextBufferIndex,
maxNeighborBlocks,
neighbors,
neighborIndex,
neighborBlockCount
)
;
nextBufferIndex
=
0
;
}
}
}
}
if
(
nextBufferIndex
>
0
)
storeNeighbors
(
atom1,
neighborBuffer,
nextBufferIndex,
maxNeighborBlocks,
neighbors,
neighborIndex,
neighborBlockCount
)
;
}
}
typedef
struct
{
float4
sig
;
float2
eps
;
real3
pos
;
real
a[3][3],
b[3][3],
g[3][3]
;
}
AtomData
;
void
loadAtomData
(
AtomData*
data,
int
sortedIndex,
int
originalIndex,
__global
const
real4*
restrict
pos,
__global
const
float4*
restrict
sigParams,
__global
const
float2*
restrict
epsParams,
__global
const
real*
restrict
aMatrix,
__global
const
real*
restrict
bMatrix,
__global
const
real*
restrict
gMatrix
)
{
data->sig
=
sigParams[originalIndex]
;
data->eps
=
epsParams[originalIndex]
;
data->pos
=
pos[sortedIndex].xyz
;
for
(
int
i
=
0
; i < 3; i++)
for
(
int
j
=
0
; j < 3; j++) {
int
k
=
9*sortedIndex+3*i+j
;
data->a[i][j]
=
aMatrix[k]
;
data->b[i][j]
=
bMatrix[k]
;
data->g[i][j]
=
gMatrix[k]
;
}
}
real3
matrixVectorProduct
(
real
(
*m
)
[3],
real3
v
)
{
return
(
real3
)
(
m[0][0]*v.x
+
m[0][1]*v.y
+
m[0][2]*v.z,
m[1][0]*v.x
+
m[1][1]*v.y
+
m[1][2]*v.z,
m[2][0]*v.x
+
m[2][1]*v.y
+
m[2][2]*v.z
)
;
}
real3
vectorMatrixProduct
(
real3
v,
real
(
*m
)
[3]
)
{
return
(
real3
)
(
m[0][0]*v.x
+
m[1][0]*v.y
+
m[2][0]*v.z,
m[0][1]*v.x
+
m[1][1]*v.y
+
m[2][1]*v.z,
m[0][2]*v.x
+
m[1][2]*v.y
+
m[2][2]*v.z
)
;
}
void
matrixSum
(
real
(
*result
)
[3],
real
(
*a
)
[3],
real
(
*b
)
[3]
)
{
result[0][0]
=
a[0][0]+b[0][0]
;
result[0][1]
=
a[0][1]+b[0][1]
;
result[0][2]
=
a[0][2]+b[0][2]
;
result[1][0]
=
a[1][0]+b[1][0]
;
result[1][1]
=
a[1][1]+b[1][1]
;
result[1][2]
=
a[1][2]+b[1][2]
;
result[2][0]
=
a[2][0]+b[2][0]
;
result[2][1]
=
a[2][1]+b[2][1]
;
result[2][2]
=
a[2][2]+b[2][2]
;
}
real
determinant
(
real
(
*m
)
[3]
)
{
return
(
m[0][0]*m[1][1]*m[2][2]
+
m[0][1]*m[1][2]*m[2][0]
+
m[0][2]*m[1][0]*m[2][1]
-
m[0][0]*m[1][2]*m[2][1]
-
m[0][1]*m[1][0]*m[2][2]
-
m[0][2]*m[1][1]*m[2][0]
)
;
}
void
matrixInverse
(
real
(
*result
)
[3],
real
(
*m
)
[3]
)
{
real
invDet
=
RECIP
(
determinant
(
m
))
;
result[0][0]
=
invDet*
(
m[1][1]*m[2][2]
-
m[1][2]*m[2][1]
)
;
result[1][0]
=
-invDet*
(
m[1][0]*m[2][2]
-
m[1][2]*m[2][0]
)
;
result[2][0]
=
invDet*
(
m[1][0]*m[2][1]
-
m[1][1]*m[2][0]
)
;
result[0][1]
=
-invDet*
(
m[0][1]*m[2][2]
-
m[0][2]*m[2][1]
)
;
result[1][1]
=
invDet*
(
m[0][0]*m[2][2]
-
m[0][2]*m[2][0]
)
;
result[2][1]
=
-invDet*
(
m[0][0]*m[2][1]
-
m[0][1]*m[2][0]
)
;
result[0][2]
=
invDet*
(
m[0][1]*m[1][2]
-
m[0][2]*m[1][1]
)
;
result[1][2]
=
-invDet*
(
m[0][0]*m[1][2]
-
m[0][2]*m[1][0]
)
;
result[2][2]
=
invDet*
(
m[0][0]*m[1][1]
-
m[0][1]*m[1][0]
)
;
}
void
computeOneInteraction
(
AtomData*
data1,
AtomData*
data2,
real
sigma,
real
epsilon,
real3
dr,
real
r2,
real3*
force1,
real3*
force2,
real3*
torque1,
real3*
torque2,
mixed
*totalEnergy
)
{
real
rInv
=
RSQRT
(
r2
)
;
real
r
=
r2*rInv
;
real3
drUnit
=
dr*rInv
;
//
Compute
the
switching
function.
real
switchValue
=
1
,
switchDeriv
=
0
;
#
if
USE_SWITCH
if
(
r
>
SWITCH_CUTOFF
)
{
real
x
=
r-SWITCH_CUTOFF
;
switchValue
=
1+x*x*x*
(
SWITCH_C3+x*
(
SWITCH_C4+x*SWITCH_C5
))
;
switchDeriv
=
x*x*
(
3*SWITCH_C3+x*
(
4*SWITCH_C4+x*5*SWITCH_C5
))
;
}
#
endif
//
Compute
vectors
and
matrices
we
'll
be
needing.
real
B12[3][3],
G12[3][3],
B12inv[3][3],
G12inv[3][3]
;
matrixSum
(
B12,
data1->b,
data2->b
)
;
matrixSum
(
G12,
data1->g,
data2->g
)
;
matrixInverse
(
B12inv,
B12
)
;
matrixInverse
(
G12inv,
G12
)
;
real
detG12
=
determinant
(
G12
)
;
//
Estimate
the
distance
between
the
ellipsoids
and
compute
the
first
terms
needed
for
the
energy.
real
sigma12
=
1/SQRT
(
0.5f*dot
(
drUnit,
matrixVectorProduct
(
G12inv,
drUnit
)))
;
real
h12
=
r
-
sigma12
;
real
rho
=
sigma/
(
h12+sigma
)
;
real
rho2
=
rho*rho
;
real
rho6
=
rho2*rho2*rho2
;
real
u
=
4*epsilon*
(
rho6*rho6-rho6
)
;
real
eta
=
SQRT
(
2*data1->eps.y*data2->eps.y/detG12
)
;
real
chi
=
2*dot
(
drUnit,
matrixVectorProduct
(
B12inv,
drUnit
))
;
chi
*=
chi
;
real
energy
=
u*eta*chi
;
//
Compute
the
terms
needed
for
the
force.
real3
kappa
=
matrixVectorProduct
(
G12inv,
dr
)
;
real3
iota
=
matrixVectorProduct
(
B12inv,
dr
)
;
real
rInv2
=
rInv*rInv
;
real
dUSLJdr
=
24*epsilon*
(
2*rho6-1
)
*rho6*
rho/sigma
;
real
temp
=
0.5f*sigma12*sigma12*sigma12*rInv2
;
real3
dudr
=
(
drUnit
+
(
kappa-drUnit*dot
(
kappa,
drUnit
))
*temp
)
*dUSLJdr
;
real3
dchidr
=
(
iota-drUnit*dot
(
iota,
drUnit
))
*
(
-8*rInv2*SQRT
(
chi
))
;
real3
force
=
(
dchidr*u
+
dudr*chi
)
*
(
eta*switchValue
)
-
drUnit*
(
energy*switchDeriv
)
;
*force1
+=
force
;
*force2
-=
force
;
//
Compute
the
terms
needed
for
the
torque.
for
(
int
j
=
0
; j < 2; j++) {
real
(
*a
)
[3]
=
(
j
==
0
?
data1->a
:
data2->a
)
;
real
(
*b
)
[3]
=
(
j
==
0
?
data1->b
:
data2->b
)
;
real
(
*g
)
[3]
=
(
j
==
0
?
data1->g
:
data2->g
)
;
float4
sig
=
(
j
==
0
?
data1->sig
:
data2->sig
)
;
real3
dudq
=
cross
(
vectorMatrixProduct
(
kappa,
g
)
,
kappa*
(
temp*dUSLJdr
))
;
real3
dchidq
=
cross
(
vectorMatrixProduct
(
iota,
b
)
,
iota
)
*
(
-4*rInv2
)
;
real3
scale
=
(
real3
)
(
sig.y,
sig.z,
sig.w
)
*
(
-0.5f*eta/detG12
)
;
real
d[3][3]
;
d[0][0]
=
scale.x*
(
2*a[0][0]*
(
G12[1][1]*G12[2][2]
-
G12[1][2]*G12[2][1]
)
+
a[0][2]*
(
G12[1][2]*G12[0][1]
+
G12[1][0]*G12[2][1]
-
G12[1][1]*
(
G12[0][2]
+
G12[2][0]
))
+
a[0][1]*
(
G12[0][2]*G12[2][1]
+
G12[2][0]*G12[1][2]
-
G12[2][2]*
(
G12[0][1]
+
G12[1][0]
)))
;
d[0][1]
=
scale.x*
(
a[0][0]*
(
G12[0][2]*G12[2][1]
+
G12[2][0]*G12[1][2]
-
G12[2][2]*
(
G12[0][1]
+
G12[1][0]
))
+
2*a[0][1]*
(
G12[0][0]*G12[2][2]
-
G12[2][0]*G12[0][2]
)
+
a[0][2]*
(
G12[1][0]*G12[0][2]
+
G12[2][0]*G12[0][1]
-
G12[0][0]*
(
G12[1][2]
+
G12[2][1]
)))
;
d[0][2]
=
scale.x*
(
a[0][0]*
(
G12[0][1]*G12[1][2]
+
G12[1][0]*G12[2][1]
-
G12[1][1]*
(
G12[0][2]
+
G12[2][0]
))
+
a[0][1]*
(
G12[1][0]*G12[0][2]
+
G12[2][0]*G12[0][1]
-
G12[0][0]*
(
G12[1][2]
+
G12[2][1]
))
+
2*a[0][2]*
(
G12[1][1]*G12[0][0]
-
G12[1][0]*G12[0][1]
))
;
d[1][0]
=
scale.y*
(
2*a[1][0]*
(
G12[1][1]*G12[2][2]
-
G12[1][2]*G12[2][1]
)
+
a[1][1]*
(
G12[0][2]*G12[2][1]
+
G12[2][0]*G12[1][2]
-
G12[2][2]*
(
G12[0][1]
+
G12[1][0]
))
+
a[1][2]*
(
G12[1][2]*G12[0][1]
+
G12[1][0]*G12[2][1]
-
G12[1][1]*
(
G12[0][2]
+
G12[2][0]
)))
;
d[1][1]
=
scale.y*
(
a[1][0]*
(
G12[0][2]*G12[2][1]
+
G12[2][0]*G12[1][2]
-
G12[2][2]*
(
G12[0][1]
+
G12[1][0]
))
+
2*a[1][1]*
(
G12[2][2]*G12[0][0]
-
G12[2][0]*G12[0][2]
)
+
a[1][2]*
(
G12[1][0]*G12[0][2]
+
G12[0][1]*G12[2][0]
-
G12[0][0]*
(
G12[1][2]
+
G12[2][1]
)))
;
d[1][2]
=
scale.y*
(
a[1][0]*
(
G12[0][1]*G12[1][2]
+
G12[1][0]*G12[2][1]
-
G12[1][1]*
(
G12[0][2]
+
G12[2][0]
))
+
a[1][1]*
(
G12[1][0]*G12[0][2]
+
G12[0][1]*G12[2][0]
-
G12[0][0]*
(
G12[1][2]
+
G12[2][1]
))
+
2*a[1][2]*
(
G12[1][1]*G12[0][0]
-
G12[1][0]*G12[0][1]
))
;
d[2][0]
=
scale.z*
(
2*a[2][0]*
(
G12[1][1]*G12[2][2]
-
G12[2][1]*G12[1][2]
)
+
a[2][1]*
(
G12[0][2]*G12[2][1]
+
G12[1][2]*G12[2][0]
-
G12[2][2]*
(
G12[0][1]
+
G12[1][0]
))
+
a[2][2]*
(
G12[0][1]*G12[1][2]
+
G12[2][1]*G12[1][0]
-
G12[1][1]*
(
G12[0][2]
+
G12[2][0]
)))
;
d[2][1]
=
scale.z*
(
a[2][0]*
(
G12[0][2]*G12[2][1]
+
G12[1][2]*G12[2][0]
-
G12[2][2]*
(
G12[0][1]
+
G12[1][0]
))
+
2*a[2][1]*
(
G12[0][0]*G12[2][2]
-
G12[0][2]*G12[2][0]
)
+
a[2][2]*
(
G12[1][0]*G12[0][2]
+
G12[0][1]*G12[2][0]
-
G12[0][0]*
(
G12[1][2]
+
G12[2][1]
)))
;
d[2][2]
=
scale.z*
(
a[2][0]*
(
G12[0][1]*G12[1][2]
+
G12[2][1]*G12[1][0]
-
G12[1][1]*
(
G12[0][2]
+
G12[2][0]
))
+
a[2][1]*
(
G12[1][0]*G12[0][2]
+
G12[2][0]*G12[0][1]
-
G12[0][0]*
(
G12[1][2]
+
G12[2][1]
))
+
2*a[2][2]*
(
G12[1][1]*G12[0][0]
-
G12[1][0]*G12[0][1]
))
;
real3
detadq
=
0
;
for
(
int
i
=
0
; i < 3; i++)
detadq
+=
cross
((
real3
)
(
a[i][0],
a[i][1],
a[i][2]
)
,
(
real3
)
(
d[i][0],
d[i][1],
d[i][2]
))
;
real3
torque
=
(
dchidq*
(
u*eta
)
+
detadq*
(
u*chi
)
+
dudq*
(
eta*chi
))
*switchValue
;
*
(
j
==
0
?
torque1
:
torque2
)
-=
torque
;
}
*totalEnergy
+=
switchValue*energy
;
}
/**
*
Compute
the
interactions.
*/
__kernel
void
computeForce
(
__global
long*
restrict
forceBuffers,
__global
long*
restrict
torqueBuffers,
int
numAtoms,
int
numExceptions,
__global
mixed*
restrict
energyBuffer,
__global
const
real4*
restrict
pos,
__global
const
float4*
restrict
sigParams,
__global
const
float2*
restrict
epsParams,
__global
const
int*
restrict
sortedAtoms,
__global
const
real*
restrict
aMatrix,
__global
const
real*
restrict
bMatrix,
__global
const
real*
restrict
gMatrix,
__global
const
int*
restrict
exclusions,
__global
const
int*
restrict
exclusionStartIndex,
__global
const
int4*
restrict
exceptionParticles,
__global
const
float2*
restrict
exceptionParams
#
ifdef
USE_CUTOFF
,
int
maxNeighborBlocks,
__global
int*
restrict
neighbors,
__global
int*
restrict
neighborIndex,
__global
int*
restrict
neighborBlockCount,
real4
periodicBoxSize,
real4
invPeriodicBoxSize,
real4
periodicBoxVecX,
real4
periodicBoxVecY,
real4
periodicBoxVecZ
#
endif
)
{
const
unsigned
int
warp
=
get_global_id
(
0
)
/TILE_SIZE
;
mixed
energy
=
0
;
#
ifdef
USE_CUTOFF
const
int
numBlocks
=
*neighborBlockCount
;
if
(
numBlocks
>
maxNeighborBlocks
)
return
; // There wasn't enough memory for the neighbor list.
for
(
int
block
=
get_global_id
(
0
)
; block < numBlocks; block += get_global_size(0)) {
//
Load
parameters
for
atom1.
int
atom1
=
neighborIndex[block]
;
int
index1
=
sortedAtoms[atom1]
;
AtomData
data1
;
loadAtomData
(
&data1,
atom1,
index1,
pos,
sigParams,
epsParams,
aMatrix,
bMatrix,
gMatrix
)
;
real3
force1
=
0.0f
;
real3
torque1
=
0.0f
;
for
(
int
indexInBlock
=
0
; indexInBlock < NEIGHBOR_BLOCK_SIZE; indexInBlock++) {
//
Load
parameters
for
atom2.
int
atom2
=
neighbors[NEIGHBOR_BLOCK_SIZE*block+indexInBlock]
;
if
(
atom2
==
-1
)
continue
;
int
index2
=
sortedAtoms[atom2]
;
AtomData
data2
;
loadAtomData
(
&data2,
atom2,
index2,
pos,
sigParams,
epsParams,
aMatrix,
bMatrix,
gMatrix
)
;
real3
force2
=
0.0f
;
real3
torque2
=
0.0f
;
//
Compute
the
interaction.
real3
delta
=
data1.pos-data2.pos
;
#
ifdef
USE_PERIODIC
APPLY_PERIODIC_TO_DELTA
(
delta
)
#
endif
real
r2
=
delta.x*delta.x
+
delta.y*delta.y
+
delta.z*delta.z
;
real
sigma
=
data1.sig.x+data2.sig.x
;
real
epsilon
=
data1.eps.x*data2.eps.x
;
computeOneInteraction
(
&data1,
&data2,
sigma,
epsilon,
delta,
r2,
&force1,
&force2,
&torque1,
&torque2,
&energy
)
;
atom_add
(
&forceBuffers[index2],
(
long
)
(
force2.x*0x100000000
))
;
atom_add
(
&forceBuffers[index2+PADDED_NUM_ATOMS],
(
long
)
(
force2.y*0x100000000
))
;
atom_add
(
&forceBuffers[index2+2*PADDED_NUM_ATOMS],
(
long
)
(
force2.z*0x100000000
))
;
atom_add
(
&torqueBuffers[index2],
(
long
)
(
torque2.x*0x100000000
))
;
atom_add
(
&torqueBuffers[index2+PADDED_NUM_ATOMS],
(
long
)
(
torque2.y*0x100000000
))
;
atom_add
(
&torqueBuffers[index2+2*PADDED_NUM_ATOMS],
(
long
)
(
torque2.z*0x100000000
))
;
}
atom_add
(
&forceBuffers[index1],
(
long
)
(
force1.x*0x100000000
))
;
atom_add
(
&forceBuffers[index1+PADDED_NUM_ATOMS],
(
long
)
(
force1.y*0x100000000
))
;
atom_add
(
&forceBuffers[index1+2*PADDED_NUM_ATOMS],
(
long
)
(
force1.z*0x100000000
))
;
atom_add
(
&torqueBuffers[index1],
(
long
)
(
torque1.x*0x100000000
))
;
atom_add
(
&torqueBuffers[index1+PADDED_NUM_ATOMS],
(
long
)
(
torque1.y*0x100000000
))
;
atom_add
(
&torqueBuffers[index1+2*PADDED_NUM_ATOMS],
(
long
)
(
torque1.z*0x100000000
))
;
}
#
else
for
(
int
atom1
=
get_global_id
(
0
)
; atom1 < numAtoms; atom1 += get_global_size(0)) {
//
Load
parameters
for
atom1.
int
index1
=
sortedAtoms[atom1]
;
AtomData
data1
;
loadAtomData
(
&data1,
atom1,
index1,
pos,
sigParams,
epsParams,
aMatrix,
bMatrix,
gMatrix
)
;
real3
force1
=
0.0f
;
real3
torque1
=
0.0f
;
int
nextExclusion
=
exclusionStartIndex[atom1]
;
int
lastExclusion
=
exclusionStartIndex[atom1+1]
;
for
(
int
atom2
=
atom1+1
; atom2 < numAtoms; atom2++) {
//
Skip
over
excluded
interactions.
if
(
nextExclusion
<
lastExclusion
&&
exclusions[nextExclusion]
==
atom2
)
{
nextExclusion++
;
continue
;
}
//
Load
parameters
for
atom2.
int
index2
=
sortedAtoms[atom2]
;
AtomData
data2
;
loadAtomData
(
&data2,
atom2,
index2,
pos,
sigParams,
epsParams,
aMatrix,
bMatrix,
gMatrix
)
;
real3
force2
=
0.0f
;
real3
torque2
=
0.0f
;
//
Compute
the
interaction.
real3
delta
=
data1.pos-data2.pos
;
real
r2
=
delta.x*delta.x
+
delta.y*delta.y
+
delta.z*delta.z
;
real
sigma
=
data1.sig.x+data2.sig.x
;
real
epsilon
=
data1.eps.x*data2.eps.x
;
computeOneInteraction
(
&data1,
&data2,
sigma,
epsilon,
delta,
r2,
&force1,
&force2,
&torque1,
&torque2,
&energy
)
;
atom_add
(
&forceBuffers[index2],
(
long
)
(
force2.x*0x100000000
))
;
atom_add
(
&forceBuffers[index2+PADDED_NUM_ATOMS],
(
long
)
(
force2.y*0x100000000
))
;
atom_add
(
&forceBuffers[index2+2*PADDED_NUM_ATOMS],
(
long
)
(
force2.z*0x100000000
))
;
atom_add
(
&torqueBuffers[index2],
(
long
)
(
torque2.x*0x100000000
))
;
atom_add
(
&torqueBuffers[index2+PADDED_NUM_ATOMS],
(
long
)
(
torque2.y*0x100000000
))
;
atom_add
(
&torqueBuffers[index2+2*PADDED_NUM_ATOMS],
(
long
)
(
torque2.z*0x100000000
))
;
}
atom_add
(
&forceBuffers[index1],
(
long
)
(
force1.x*0x100000000
))
;
atom_add
(
&forceBuffers[index1+PADDED_NUM_ATOMS],
(
long
)
(
force1.y*0x100000000
))
;
atom_add
(
&forceBuffers[index1+2*PADDED_NUM_ATOMS],
(
long
)
(
force1.z*0x100000000
))
;
atom_add
(
&torqueBuffers[index1],
(
long
)
(
torque1.x*0x100000000
))
;
atom_add
(
&torqueBuffers[index1+PADDED_NUM_ATOMS],
(
long
)
(
torque1.y*0x100000000
))
;
atom_add
(
&torqueBuffers[index1+2*PADDED_NUM_ATOMS],
(
long
)
(
torque1.z*0x100000000
))
;
}
#
endif
//
Now
compute
exceptions.
for
(
int
index
=
get_global_id
(
0
)
; index < numExceptions; index += get_global_size(0)) {
int4
atomIndices
=
exceptionParticles[index]
;
float2
params
=
exceptionParams[index]
;
int
index1
=
atomIndices.x,
index2
=
atomIndices.y
;
int
atom1
=
atomIndices.z,
atom2
=
atomIndices.w
;
AtomData
data1,
data2
;
loadAtomData
(
&data1,
atom1,
index1,
pos,
sigParams,
epsParams,
aMatrix,
bMatrix,
gMatrix
)
;
loadAtomData
(
&data2,
atom2,
index2,
pos,
sigParams,
epsParams,
aMatrix,
bMatrix,
gMatrix
)
;
real3
force1
=
0
,
force2
=
0
;
real3
torque1
=
0
,
torque2
=
0
;
real3
delta
=
data1.pos-data2.pos
;
real
r2
=
delta.x*delta.x
+
delta.y*delta.y
+
delta.z*delta.z
;
#
ifdef
USE_CUTOFF
if
(
r2
<
CUTOFF_SQUARED
)
{
#
endif
computeOneInteraction
(
&data1,
&data2,
params.x,
params.y,
delta,
r2,
&force1,
&force2,
&torque1,
&torque2,
&energy
)
;
atom_add
(
&forceBuffers[index1],
(
long
)
(
force1.x*0x100000000
))
;
atom_add
(
&forceBuffers[index1+PADDED_NUM_ATOMS],
(
long
)
(
force1.y*0x100000000
))
;
atom_add
(
&forceBuffers[index1+2*PADDED_NUM_ATOMS],
(
long
)
(
force1.z*0x100000000
))
;
atom_add
(
&forceBuffers[index2],
(
long
)
(
force2.x*0x100000000
))
;
atom_add
(
&forceBuffers[index2+PADDED_NUM_ATOMS],
(
long
)
(
force2.y*0x100000000
))
;
atom_add
(
&forceBuffers[index2+2*PADDED_NUM_ATOMS],
(
long
)
(
force2.z*0x100000000
))
;
atom_add
(
&torqueBuffers[index1],
(
long
)
(
torque1.x*0x100000000
))
;
atom_add
(
&torqueBuffers[index1+PADDED_NUM_ATOMS],
(
long
)
(
torque1.y*0x100000000
))
;
atom_add
(
&torqueBuffers[index1+2*PADDED_NUM_ATOMS],
(
long
)
(
torque1.z*0x100000000
))
;
atom_add
(
&torqueBuffers[index2],
(
long
)
(
torque2.x*0x100000000
))
;
atom_add
(
&torqueBuffers[index2+PADDED_NUM_ATOMS],
(
long
)
(
torque2.y*0x100000000
))
;
atom_add
(
&torqueBuffers[index2+2*PADDED_NUM_ATOMS],
(
long
)
(
torque2.z*0x100000000
))
;
#
ifdef
USE_CUTOFF
}
#
endif
}
energyBuffer[get_global_id
(
0
)
]
+=
energy
;
}
/**
*
Convert
the
torques
to
forces
on
the
connected
particles.
*/
__kernel
void
applyTorques
(
__global
long*
restrict
forceBuffers,
__global
long*
restrict
torqueBuffers,
int
numParticles,
__global
const
real4*
restrict
posq,
__global
int2*
const
restrict
axisParticleIndices,
__global
const
int*
sortedParticles
)
{
const
unsigned
int
warp
=
get_global_id
(
0
)
/TILE_SIZE
;
for
(
int
sortedIndex
=
get_global_id
(
0
)
; sortedIndex < numParticles; sortedIndex += get_global_size(0)) {
int
originalIndex
=
sortedParticles[sortedIndex]
;
real3
pos
=
posq[originalIndex].xyz
;
int2
axisParticles
=
axisParticleIndices[originalIndex]
;
if
(
axisParticles.x
!=
-1
)
{
//
Load
the
torque.
real
scale
=
1/
(
real
)
0x100000000
;
real3
torque
=
(
real3
)
(
scale*torqueBuffers[originalIndex],
scale*torqueBuffers[originalIndex+PADDED_NUM_ATOMS],
scale*torqueBuffers[originalIndex+2*PADDED_NUM_ATOMS]
)
;
real3
force
=
0
,
xforce
=
0
,
yforce
=
0
;
//
Apply
a
force
to
the
x
particle.
real3
dx
=
posq[axisParticles.x].xyz-pos
;
real
dx2
=
dot
(
dx,
dx
)
;
real3
f
=
cross
(
torque,
dx
)
/dx2
;
xforce
+=
f
;
force
-=
f
;
if
(
axisParticles.y
!=
-1
)
{
//
Apply
a
force
to
the
y
particle.
This
is
based
on
the
component
of
the
torque
//
that
was
not
already
applied
to
the
x
particle.
real3
dy
=
posq[axisParticles.y].xyz-pos
;
real
dy2
=
dot
(
dy,
dy
)
;
real3
torque2
=
dx*dot
(
torque,
dx
)
/dx2
;
f
=
cross
(
torque2,
dy
)
/dy2
;
yforce
+=
f
;
force
-=
f
;
}
atom_add
(
&forceBuffers[originalIndex],
(
long
)
(
force.x*0x100000000
))
;
atom_add
(
&forceBuffers[originalIndex+PADDED_NUM_ATOMS],
(
long
)
(
force.y*0x100000000
))
;
atom_add
(
&forceBuffers[originalIndex+2*PADDED_NUM_ATOMS],
(
long
)
(
force.z*0x100000000
))
;
atom_add
(
&forceBuffers[axisParticles.x],
(
long
)
(
xforce.x*0x100000000
))
;
atom_add
(
&forceBuffers[axisParticles.x+PADDED_NUM_ATOMS],
(
long
)
(
xforce.y*0x100000000
))
;
atom_add
(
&forceBuffers[axisParticles.x+2*PADDED_NUM_ATOMS],
(
long
)
(
xforce.z*0x100000000
))
;
if
(
axisParticles.y
!=
-1
)
{
atom_add
(
&forceBuffers[axisParticles.y],
(
long
)
(
yforce.x*0x100000000
))
;
atom_add
(
&forceBuffers[axisParticles.y+PADDED_NUM_ATOMS],
(
long
)
(
yforce.y*0x100000000
))
;
atom_add
(
&forceBuffers[axisParticles.y+2*PADDED_NUM_ATOMS],
(
long
)
(
yforce.z*0x100000000
))
;
}
}
}
}
platforms/opencl/tests/TestOpenCLGayBerneForce.cpp
0 → 100644
View file @
a468fa3a
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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) 2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* 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. *
* -------------------------------------------------------------------------- */
#include "OpenCLTests.h"
#include "TestGayBerneForce.h"
void
runPlatformTests
()
{
}
platforms/reference/include/ReferenceGayBerneForce.h
0 → 100644
View file @
a468fa3a
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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) 2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* 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. *
* -------------------------------------------------------------------------- */
#ifndef __ReferenceGayBerneForce_H__
#define __ReferenceGayBerneForce_H__
#include "openmm/GayBerneForce.h"
#include "RealVec.h"
#include <set>
#include <utility>
namespace
OpenMM
{
class
OPENMM_EXPORT
ReferenceGayBerneForce
{
public:
struct
Matrix
;
/**
* Constructor.
*/
ReferenceGayBerneForce
(
const
GayBerneForce
&
force
);
/**
* Compute the interaction.
*
* @param positions the positions of the atoms
* @param forces forces will be added to this vector
* @param boxVectors the periodic box vectors
* @return the energy of the interaction
*/
RealOpenMM
calculateForce
(
const
std
::
vector
<
RealVec
>&
positions
,
std
::
vector
<
RealVec
>&
forces
,
const
RealVec
*
boxVectors
);
private:
struct
ParticleInfo
;
struct
ExceptionInfo
;
std
::
vector
<
ParticleInfo
>
particles
;
std
::
vector
<
ExceptionInfo
>
exceptions
;
std
::
set
<
std
::
pair
<
int
,
int
>
>
exclusions
;
GayBerneForce
::
NonbondedMethod
nonbondedMethod
;
RealOpenMM
cutoffDistance
,
switchingDistance
;
bool
useSwitchingFunction
;
std
::
vector
<
RealOpenMM
>
s
;
std
::
vector
<
Matrix
>
A
,
B
,
G
;
void
computeEllipsoidFrames
(
const
std
::
vector
<
RealVec
>&
positions
);
void
applyTorques
(
const
std
::
vector
<
RealVec
>&
positions
,
std
::
vector
<
RealVec
>&
forces
,
const
std
::
vector
<
RealVec
>&
torques
);
RealOpenMM
computeOneInteraction
(
int
particle1
,
int
particle2
,
RealOpenMM
sigma
,
RealOpenMM
epsilon
,
const
std
::
vector
<
RealVec
>&
positions
,
std
::
vector
<
RealVec
>&
forces
,
std
::
vector
<
RealVec
>&
torques
,
const
RealVec
*
boxVectors
);
};
struct
ReferenceGayBerneForce
::
ParticleInfo
{
int
xparticle
,
yparticle
;
RealOpenMM
sigma
,
epsilon
,
rx
,
ry
,
rz
,
ex
,
ey
,
ez
;
};
struct
ReferenceGayBerneForce
::
ExceptionInfo
{
int
particle1
,
particle2
;
RealOpenMM
sigma
,
epsilon
;
};
struct
ReferenceGayBerneForce
::
Matrix
{
RealOpenMM
v
[
3
][
3
];
RealVec
operator
*
(
const
RealVec
&
r
)
{
return
RealVec
(
v
[
0
][
0
]
*
r
[
0
]
+
v
[
0
][
1
]
*
r
[
1
]
+
v
[
0
][
2
]
*
r
[
2
],
v
[
1
][
0
]
*
r
[
0
]
+
v
[
1
][
1
]
*
r
[
1
]
+
v
[
1
][
2
]
*
r
[
2
],
v
[
2
][
0
]
*
r
[
0
]
+
v
[
2
][
1
]
*
r
[
1
]
+
v
[
2
][
2
]
*
r
[
2
]);
}
Matrix
operator
+
(
const
Matrix
&
m
)
{
Matrix
result
;
for
(
int
i
=
0
;
i
<
3
;
i
++
)
for
(
int
j
=
0
;
j
<
3
;
j
++
)
result
.
v
[
i
][
j
]
=
v
[
i
][
j
]
+
m
.
v
[
i
][
j
];
return
result
;
}
RealOpenMM
determinant
()
{
return
(
v
[
0
][
0
]
*
v
[
1
][
1
]
*
v
[
2
][
2
]
+
v
[
0
][
1
]
*
v
[
1
][
2
]
*
v
[
2
][
0
]
+
v
[
0
][
2
]
*
v
[
1
][
0
]
*
v
[
2
][
1
]
-
v
[
0
][
0
]
*
v
[
1
][
2
]
*
v
[
2
][
1
]
-
v
[
0
][
1
]
*
v
[
1
][
0
]
*
v
[
2
][
2
]
-
v
[
0
][
2
]
*
v
[
1
][
1
]
*
v
[
2
][
0
]);
}
Matrix
inverse
()
{
RealOpenMM
invDet
=
1
/
determinant
();
Matrix
result
;
result
.
v
[
0
][
0
]
=
invDet
*
(
v
[
1
][
1
]
*
v
[
2
][
2
]
-
v
[
1
][
2
]
*
v
[
2
][
1
]);
result
.
v
[
1
][
0
]
=
-
invDet
*
(
v
[
1
][
0
]
*
v
[
2
][
2
]
-
v
[
1
][
2
]
*
v
[
2
][
0
]);
result
.
v
[
2
][
0
]
=
invDet
*
(
v
[
1
][
0
]
*
v
[
2
][
1
]
-
v
[
1
][
1
]
*
v
[
2
][
0
]);
result
.
v
[
0
][
1
]
=
-
invDet
*
(
v
[
0
][
1
]
*
v
[
2
][
2
]
-
v
[
0
][
2
]
*
v
[
2
][
1
]);
result
.
v
[
1
][
1
]
=
invDet
*
(
v
[
0
][
0
]
*
v
[
2
][
2
]
-
v
[
0
][
2
]
*
v
[
2
][
0
]);
result
.
v
[
2
][
1
]
=
-
invDet
*
(
v
[
0
][
0
]
*
v
[
2
][
1
]
-
v
[
0
][
1
]
*
v
[
2
][
0
]);
result
.
v
[
0
][
2
]
=
invDet
*
(
v
[
0
][
1
]
*
v
[
1
][
2
]
-
v
[
0
][
2
]
*
v
[
1
][
1
]);
result
.
v
[
1
][
2
]
=
-
invDet
*
(
v
[
0
][
0
]
*
v
[
1
][
2
]
-
v
[
0
][
2
]
*
v
[
1
][
0
]);
result
.
v
[
2
][
2
]
=
invDet
*
(
v
[
0
][
0
]
*
v
[
1
][
1
]
-
v
[
0
][
1
]
*
v
[
1
][
0
]);
return
result
;
}
};
static
RealVec
operator
*
(
const
RealVec
&
r
,
ReferenceGayBerneForce
::
Matrix
&
m
)
{
return
RealVec
(
m
.
v
[
0
][
0
]
*
r
[
0
]
+
m
.
v
[
1
][
0
]
*
r
[
1
]
+
m
.
v
[
2
][
0
]
*
r
[
2
],
m
.
v
[
0
][
1
]
*
r
[
0
]
+
m
.
v
[
1
][
1
]
*
r
[
1
]
+
m
.
v
[
2
][
1
]
*
r
[
2
],
m
.
v
[
0
][
2
]
*
r
[
0
]
+
m
.
v
[
1
][
2
]
*
r
[
1
]
+
m
.
v
[
2
][
2
]
*
r
[
2
]);
}
}
// namespace OpenMM
#endif // __ReferenceGayBerneForce_H__
platforms/reference/include/ReferenceKernels.h
View file @
a468fa3a
...
...
@@ -47,6 +47,7 @@ class ReferenceCustomCentroidBondIxn;
class
ReferenceCustomCompoundBondIxn
;
class
ReferenceCustomHbondIxn
;
class
ReferenceCustomManyParticleIxn
;
class
ReferenceGayBerneForce
;
class
ReferenceBrownianDynamics
;
class
ReferenceStochasticDynamics
;
class
ReferenceConstraintAlgorithm
;
...
...
@@ -962,6 +963,40 @@ private:
NonbondedMethod
nonbondedMethod
;
};
/**
* This kernel is invoked by GayBerneForce to calculate the forces acting on the system.
*/
class
ReferenceCalcGayBerneForceKernel
:
public
CalcGayBerneForceKernel
{
public:
ReferenceCalcGayBerneForceKernel
(
std
::
string
name
,
const
Platform
&
platform
)
:
CalcGayBerneForceKernel
(
name
,
platform
),
ixn
(
NULL
)
{
}
~
ReferenceCalcGayBerneForceKernel
();
/**
* Initialize the kernel.
*
* @param system the System this kernel will be applied to
* @param force the GayBerneForce this kernel will be used for
*/
void
initialize
(
const
System
&
system
,
const
GayBerneForce
&
force
);
/**
* Execute the kernel to calculate the forces and/or energy.
*
* @param context the context in which to execute this kernel
* @param includeForces true if forces should be calculated
* @return the potential energy due to the force
*/
double
execute
(
ContextImpl
&
context
,
bool
includeForces
,
bool
includeEnergy
);
/**
* Copy changed parameters over to a context.
*
* @param context the context to copy parameters to
* @param force the GayBerneForce to copy the parameters from
*/
void
copyParametersToContext
(
ContextImpl
&
context
,
const
GayBerneForce
&
force
);
private:
ReferenceGayBerneForce
*
ixn
;
};
/**
* This kernel is invoked by VerletIntegrator to take one time step.
*/
...
...
platforms/reference/src/ReferenceKernelFactory.cpp
View file @
a468fa3a
...
...
@@ -6,7 +6,7 @@
* 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.
*
* Portions copyright (c) 2008
-2016
Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
...
...
@@ -56,8 +56,6 @@ KernelImpl* ReferenceKernelFactory::createKernelImpl(std::string name, const Pla
return
new
ReferenceCalcCustomBondForceKernel
(
name
,
platform
);
if
(
name
==
CalcHarmonicAngleForceKernel
::
Name
())
return
new
ReferenceCalcHarmonicAngleForceKernel
(
name
,
platform
);
if
(
name
==
CalcHarmonicAngleForceKernel
::
Name
())
return
new
ReferenceCalcHarmonicAngleForceKernel
(
name
,
platform
);
if
(
name
==
CalcCustomAngleForceKernel
::
Name
())
return
new
ReferenceCalcCustomAngleForceKernel
(
name
,
platform
);
if
(
name
==
CalcPeriodicTorsionForceKernel
::
Name
())
...
...
@@ -82,6 +80,8 @@ KernelImpl* ReferenceKernelFactory::createKernelImpl(std::string name, const Pla
return
new
ReferenceCalcCustomCompoundBondForceKernel
(
name
,
platform
);
if
(
name
==
CalcCustomManyParticleForceKernel
::
Name
())
return
new
ReferenceCalcCustomManyParticleForceKernel
(
name
,
platform
);
if
(
name
==
CalcGayBerneForceKernel
::
Name
())
return
new
ReferenceCalcGayBerneForceKernel
(
name
,
platform
);
if
(
name
==
IntegrateVerletStepKernel
::
Name
())
return
new
ReferenceIntegrateVerletStepKernel
(
name
,
platform
,
data
);
if
(
name
==
IntegrateLangevinStepKernel
::
Name
())
...
...
platforms/reference/src/ReferenceKernels.cpp
View file @
a468fa3a
...
...
@@ -49,6 +49,7 @@
#include "ReferenceCustomNonbondedIxn.h"
#include "ReferenceCustomManyParticleIxn.h"
#include "ReferenceCustomTorsionIxn.h"
#include "ReferenceGayBerneForce.h"
#include "ReferenceHarmonicBondIxn.h"
#include "ReferenceLJCoulomb14.h"
#include "ReferenceLJCoulombIxn.h"
...
...
@@ -1973,6 +1974,25 @@ void ReferenceCalcCustomManyParticleForceKernel::copyParametersToContext(Context
}
}
ReferenceCalcGayBerneForceKernel
::~
ReferenceCalcGayBerneForceKernel
()
{
if
(
ixn
!=
NULL
)
delete
ixn
;
}
void
ReferenceCalcGayBerneForceKernel
::
initialize
(
const
System
&
system
,
const
GayBerneForce
&
force
)
{
ixn
=
new
ReferenceGayBerneForce
(
force
);
}
double
ReferenceCalcGayBerneForceKernel
::
execute
(
ContextImpl
&
context
,
bool
includeForces
,
bool
includeEnergy
)
{
return
ixn
->
calculateForce
(
extractPositions
(
context
),
extractForces
(
context
),
extractBoxVectors
(
context
));
}
void
ReferenceCalcGayBerneForceKernel
::
copyParametersToContext
(
ContextImpl
&
context
,
const
GayBerneForce
&
force
)
{
delete
ixn
;
ixn
=
NULL
;
ixn
=
new
ReferenceGayBerneForce
(
force
);
}
ReferenceIntegrateVerletStepKernel
::~
ReferenceIntegrateVerletStepKernel
()
{
if
(
dynamics
)
delete
dynamics
;
...
...
platforms/reference/src/ReferencePlatform.cpp
View file @
a468fa3a
...
...
@@ -65,6 +65,7 @@ ReferencePlatform::ReferencePlatform() {
registerKernelFactory
(
CalcCustomCentroidBondForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcCustomCompoundBondForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcCustomManyParticleForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcGayBerneForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
IntegrateVerletStepKernel
::
Name
(),
factory
);
registerKernelFactory
(
IntegrateLangevinStepKernel
::
Name
(),
factory
);
registerKernelFactory
(
IntegrateBrownianStepKernel
::
Name
(),
factory
);
...
...
platforms/reference/src/SimTKReference/ReferenceGayBerneForce.cpp
0 → 100644
View file @
a468fa3a
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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) 2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* 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. *
* -------------------------------------------------------------------------- */
#ifdef _MSC_VER
// Prevent Windows from defining macros that interfere with other code.
#define NOMINMAX
#endif
#include "ReferenceGayBerneForce.h"
#include "ReferenceForce.h"
#include "openmm/OpenMMException.h"
#include <algorithm>
#include <cmath>
using
namespace
OpenMM
;
using
namespace
std
;
ReferenceGayBerneForce
::
ReferenceGayBerneForce
(
const
GayBerneForce
&
force
)
{
// Record the force parameters.
int
numParticles
=
force
.
getNumParticles
();
particles
.
resize
(
numParticles
);
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
{
ParticleInfo
&
p
=
particles
[
i
];
double
sx
,
sy
,
sz
;
force
.
getParticleParameters
(
i
,
p
.
sigma
,
p
.
epsilon
,
p
.
xparticle
,
p
.
yparticle
,
sx
,
sy
,
sz
,
p
.
ex
,
p
.
ey
,
p
.
ez
);
p
.
rx
=
0.5
*
sx
;
p
.
ry
=
0.5
*
sy
;
p
.
rz
=
0.5
*
sz
;
}
int
numExceptions
=
force
.
getNumExceptions
();
exceptions
.
resize
(
numExceptions
);
for
(
int
i
=
0
;
i
<
numExceptions
;
i
++
)
{
ExceptionInfo
&
e
=
exceptions
[
i
];
force
.
getExceptionParameters
(
i
,
e
.
particle1
,
e
.
particle2
,
e
.
sigma
,
e
.
epsilon
);
exclusions
.
insert
(
make_pair
(
min
(
e
.
particle1
,
e
.
particle2
),
max
(
e
.
particle1
,
e
.
particle2
)));
}
nonbondedMethod
=
force
.
getNonbondedMethod
();
cutoffDistance
=
force
.
getCutoffDistance
();
switchingDistance
=
force
.
getSwitchingDistance
();
useSwitchingFunction
=
force
.
getUseSwitchingFunction
();
// Allocate workspace for calculations.
s
.
resize
(
numParticles
);
A
.
resize
(
numParticles
);
B
.
resize
(
numParticles
);
G
.
resize
(
numParticles
);
// We can precompute the shape factors.
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
{
ParticleInfo
&
p
=
particles
[
i
];
s
[
i
]
=
(
p
.
rx
*
p
.
ry
+
p
.
rz
*
p
.
rz
)
*
SQRT
(
p
.
rx
*
p
.
ry
);
}
}
RealOpenMM
ReferenceGayBerneForce
::
calculateForce
(
const
vector
<
RealVec
>&
positions
,
vector
<
RealVec
>&
forces
,
const
RealVec
*
boxVectors
)
{
if
(
nonbondedMethod
==
GayBerneForce
::
CutoffPeriodic
)
{
double
minAllowedSize
=
1.999999
*
cutoffDistance
;
if
(
boxVectors
[
0
][
0
]
<
minAllowedSize
||
boxVectors
[
1
][
1
]
<
minAllowedSize
||
boxVectors
[
2
][
2
]
<
minAllowedSize
)
throw
OpenMMException
(
"The periodic box size has decreased to less than twice the nonbonded cutoff."
);
}
// First find the orientations of the particles and compute the matrices we'll be needing.
computeEllipsoidFrames
(
positions
);
// Compute standard interactions.
RealOpenMM
energy
=
0
;
int
numParticles
=
particles
.
size
();
vector
<
RealVec
>
torques
(
numParticles
,
Vec3
());
for
(
int
i
=
1
;
i
<
numParticles
;
i
++
)
{
if
(
particles
[
i
].
epsilon
==
0.0
)
continue
;
for
(
int
j
=
0
;
j
<
i
;
j
++
)
{
if
(
particles
[
j
].
epsilon
==
0.0
)
continue
;
if
(
exclusions
.
find
(
make_pair
(
j
,
i
))
!=
exclusions
.
end
())
continue
;
// This interaction will be handled by an exception.
RealOpenMM
sigma
=
0.5
*
(
particles
[
i
].
sigma
+
particles
[
j
].
sigma
);
RealOpenMM
epsilon
=
SQRT
(
particles
[
i
].
epsilon
*
particles
[
j
].
epsilon
);
energy
+=
computeOneInteraction
(
i
,
j
,
sigma
,
epsilon
,
positions
,
forces
,
torques
,
boxVectors
);
}
}
// Compute exceptions.
int
numExceptions
=
exceptions
.
size
();
for
(
int
i
=
0
;
i
<
numExceptions
;
i
++
)
{
ExceptionInfo
&
e
=
exceptions
[
i
];
energy
+=
computeOneInteraction
(
e
.
particle1
,
e
.
particle2
,
e
.
sigma
,
e
.
epsilon
,
positions
,
forces
,
torques
,
boxVectors
);
}
// Apply torques.
applyTorques
(
positions
,
forces
,
torques
);
return
energy
;
}
void
ReferenceGayBerneForce
::
computeEllipsoidFrames
(
const
vector
<
RealVec
>&
positions
)
{
int
numParticles
=
particles
.
size
();
for
(
int
particle
=
0
;
particle
<
numParticles
;
particle
++
)
{
ParticleInfo
&
p
=
particles
[
particle
];
// Compute the local coordinate system of the ellipsoid;
RealVec
xdir
,
ydir
,
zdir
;
if
(
p
.
xparticle
==
-
1
)
{
xdir
=
RealVec
(
1
,
0
,
0
);
ydir
=
RealVec
(
0
,
1
,
0
);
}
else
{
xdir
=
positions
[
particle
]
-
positions
[
p
.
xparticle
];
xdir
/=
SQRT
(
xdir
.
dot
(
xdir
));
if
(
p
.
yparticle
==
-
1
)
{
if
(
xdir
[
1
]
>
-
0.5
&&
xdir
[
1
]
<
0.5
)
ydir
=
RealVec
(
0
,
1
,
0
);
else
ydir
=
RealVec
(
1
,
0
,
0
);
}
else
ydir
=
positions
[
particle
]
-
positions
[
p
.
yparticle
];
ydir
-=
xdir
*
(
xdir
.
dot
(
ydir
));
ydir
/=
SQRT
(
ydir
.
dot
(
ydir
));
}
zdir
=
xdir
.
cross
(
ydir
);
// Compute matrices we will need later.
RealOpenMM
(
&
a
)[
3
][
3
]
=
A
[
particle
].
v
;
RealOpenMM
(
&
b
)[
3
][
3
]
=
B
[
particle
].
v
;
RealOpenMM
(
&
g
)[
3
][
3
]
=
G
[
particle
].
v
;
a
[
0
][
0
]
=
xdir
[
0
];
a
[
0
][
1
]
=
xdir
[
1
];
a
[
0
][
2
]
=
xdir
[
2
];
a
[
1
][
0
]
=
ydir
[
0
];
a
[
1
][
1
]
=
ydir
[
1
];
a
[
1
][
2
]
=
ydir
[
2
];
a
[
2
][
0
]
=
zdir
[
0
];
a
[
2
][
1
]
=
zdir
[
1
];
a
[
2
][
2
]
=
zdir
[
2
];
RealVec
r2
(
p
.
rx
*
p
.
rx
,
p
.
ry
*
p
.
ry
,
p
.
rz
*
p
.
rz
);
RealVec
e2
(
1
/
sqrt
(
p
.
ex
),
1
/
sqrt
(
p
.
ey
),
1
/
sqrt
(
p
.
ez
));
for
(
int
i
=
0
;
i
<
3
;
i
++
)
for
(
int
j
=
0
;
j
<
3
;
j
++
)
{
b
[
i
][
j
]
=
0
;
g
[
i
][
j
]
=
0
;
for
(
int
k
=
0
;
k
<
3
;
k
++
)
{
b
[
i
][
j
]
+=
a
[
k
][
i
]
*
e2
[
k
]
*
a
[
k
][
j
];
g
[
i
][
j
]
+=
a
[
k
][
i
]
*
r2
[
k
]
*
a
[
k
][
j
];
}
}
}
}
void
ReferenceGayBerneForce
::
applyTorques
(
const
vector
<
RealVec
>&
positions
,
vector
<
RealVec
>&
forces
,
const
vector
<
RealVec
>&
torques
)
{
int
numParticles
=
particles
.
size
();
for
(
int
particle
=
0
;
particle
<
numParticles
;
particle
++
)
{
ParticleInfo
&
p
=
particles
[
particle
];
RealVec
pos
=
positions
[
particle
];
if
(
p
.
xparticle
!=
-
1
)
{
// Apply a force to the x particle.
RealVec
dx
=
positions
[
p
.
xparticle
]
-
pos
;
double
dx2
=
dx
.
dot
(
dx
);
RealVec
f
=
torques
[
particle
].
cross
(
dx
)
/
dx2
;
forces
[
p
.
xparticle
]
+=
f
;
forces
[
particle
]
-=
f
;
if
(
p
.
yparticle
!=
-
1
)
{
// Apply a force to the y particle. This is based on the component of the torque
// that was not already applied to the x particle.
RealVec
dy
=
positions
[
p
.
yparticle
]
-
pos
;
double
dy2
=
dy
.
dot
(
dy
);
RealVec
torque
=
dx
*
(
torques
[
particle
].
dot
(
dx
)
/
dx2
);
f
=
torque
.
cross
(
dy
)
/
dy2
;
forces
[
p
.
yparticle
]
+=
f
;
forces
[
particle
]
-=
f
;
}
}
}
}
RealOpenMM
ReferenceGayBerneForce
::
computeOneInteraction
(
int
particle1
,
int
particle2
,
RealOpenMM
sigma
,
RealOpenMM
epsilon
,
const
vector
<
RealVec
>&
positions
,
vector
<
RealVec
>&
forces
,
vector
<
RealVec
>&
torques
,
const
RealVec
*
boxVectors
)
{
// Compute the displacement and check against the cutoff.
RealOpenMM
deltaR
[
ReferenceForce
::
LastDeltaRIndex
];
if
(
nonbondedMethod
==
GayBerneForce
::
CutoffPeriodic
)
ReferenceForce
::
getDeltaRPeriodic
(
positions
[
particle2
],
positions
[
particle1
],
boxVectors
,
deltaR
);
else
ReferenceForce
::
getDeltaR
(
positions
[
particle2
],
positions
[
particle1
],
deltaR
);
RealOpenMM
r
=
deltaR
[
ReferenceForce
::
RIndex
];
if
(
nonbondedMethod
!=
GayBerneForce
::
NoCutoff
&&
r
>=
cutoffDistance
)
return
0
;
// Compute vectors and matrices we'll be needing.
RealOpenMM
rInv
=
1
/
r
;
RealVec
dr
(
deltaR
[
ReferenceForce
::
XIndex
],
deltaR
[
ReferenceForce
::
YIndex
],
deltaR
[
ReferenceForce
::
ZIndex
]);
RealVec
drUnit
=
dr
*
rInv
;
Matrix
B12
=
B
[
particle1
]
+
B
[
particle2
];
Matrix
G12
=
G
[
particle1
]
+
G
[
particle2
];
Matrix
B12inv
=
B12
.
inverse
();
Matrix
G12inv
=
G12
.
inverse
();
RealOpenMM
detG12
=
G12
.
determinant
();
// Compute the switching function.
RealOpenMM
switchValue
=
1
,
switchDeriv
=
0
;
if
(
useSwitchingFunction
&&
r
>
switchingDistance
)
{
RealOpenMM
t
=
(
r
-
switchingDistance
)
/
(
cutoffDistance
-
switchingDistance
);
switchValue
=
1
+
t
*
t
*
t
*
(
-
10
+
t
*
(
15
-
t
*
6
));
switchDeriv
=
t
*
t
*
(
-
30
+
t
*
(
60
-
t
*
30
))
/
(
cutoffDistance
-
switchingDistance
);
}
// Estimate the distance between the ellipsoids and compute the first terms needed for the energy.
RealOpenMM
sigma12
=
1
/
SQRT
(
0.5
*
drUnit
.
dot
(
G12inv
*
drUnit
));
RealOpenMM
h12
=
r
-
sigma12
;
RealOpenMM
rho
=
sigma
/
(
h12
+
sigma
);
RealOpenMM
rho2
=
rho
*
rho
;
RealOpenMM
rho6
=
rho2
*
rho2
*
rho2
;
RealOpenMM
u
=
4
*
epsilon
*
(
rho6
*
rho6
-
rho6
);
RealOpenMM
eta
=
SQRT
(
2
*
s
[
particle1
]
*
s
[
particle2
]
/
detG12
);
RealOpenMM
chi
=
2
*
drUnit
.
dot
(
B12inv
*
drUnit
);
chi
*=
chi
;
RealOpenMM
energy
=
u
*
eta
*
chi
;
// Compute the terms needed for the force.
RealVec
kappa
=
G12inv
*
dr
;
RealVec
iota
=
B12inv
*
dr
;
RealOpenMM
rInv2
=
rInv
*
rInv
;
RealOpenMM
dUSLJdr
=
24
*
epsilon
*
(
2
*
rho6
-
1
)
*
rho6
*
rho
/
sigma
;
RealOpenMM
temp
=
0.5
*
sigma12
*
sigma12
*
sigma12
*
rInv2
;
RealVec
dudr
=
(
drUnit
+
(
kappa
-
drUnit
*
kappa
.
dot
(
drUnit
))
*
temp
)
*
dUSLJdr
;
RealVec
dchidr
=
(
iota
-
drUnit
*
iota
.
dot
(
drUnit
))
*
(
-
8
*
rInv2
*
SQRT
(
chi
));
RealVec
force
=
(
dchidr
*
u
+
dudr
*
chi
)
*
(
eta
*
switchValue
)
-
drUnit
*
(
energy
*
switchDeriv
);
forces
[
particle1
]
+=
force
;
forces
[
particle2
]
-=
force
;
// Compute the terms needed for the torque.
for
(
int
j
=
0
;
j
<
2
;
j
++
)
{
int
particle
=
(
j
==
0
?
particle1
:
particle2
);
RealVec
dudq
=
(
kappa
*
G
[
particle
]).
cross
(
kappa
*
(
temp
*
dUSLJdr
));
RealVec
dchidq
=
(
iota
*
B
[
particle
]).
cross
(
iota
)
*
(
-
4
*
rInv2
);
RealOpenMM
(
&
g12
)[
3
][
3
]
=
G12
.
v
;
RealOpenMM
(
&
a
)[
3
][
3
]
=
A
[
particle
].
v
;
ParticleInfo
&
p
=
particles
[
particle
];
RealVec
scale
=
RealVec
(
p
.
rx
*
p
.
rx
,
p
.
ry
*
p
.
ry
,
p
.
rz
*
p
.
rz
)
*
(
-
0.5
*
eta
/
detG12
);
Matrix
D
;
RealOpenMM
(
&
d
)[
3
][
3
]
=
D
.
v
;
d
[
0
][
0
]
=
scale
[
0
]
*
(
2
*
a
[
0
][
0
]
*
(
g12
[
1
][
1
]
*
g12
[
2
][
2
]
-
g12
[
1
][
2
]
*
g12
[
2
][
1
])
+
a
[
0
][
2
]
*
(
g12
[
1
][
2
]
*
g12
[
0
][
1
]
+
g12
[
1
][
0
]
*
g12
[
2
][
1
]
-
g12
[
1
][
1
]
*
(
g12
[
0
][
2
]
+
g12
[
2
][
0
]))
+
a
[
0
][
1
]
*
(
g12
[
0
][
2
]
*
g12
[
2
][
1
]
+
g12
[
2
][
0
]
*
g12
[
1
][
2
]
-
g12
[
2
][
2
]
*
(
g12
[
0
][
1
]
+
g12
[
1
][
0
])));
d
[
0
][
1
]
=
scale
[
0
]
*
(
a
[
0
][
0
]
*
(
g12
[
0
][
2
]
*
g12
[
2
][
1
]
+
g12
[
2
][
0
]
*
g12
[
1
][
2
]
-
g12
[
2
][
2
]
*
(
g12
[
0
][
1
]
+
g12
[
1
][
0
]))
+
2
*
a
[
0
][
1
]
*
(
g12
[
0
][
0
]
*
g12
[
2
][
2
]
-
g12
[
2
][
0
]
*
g12
[
0
][
2
])
+
a
[
0
][
2
]
*
(
g12
[
1
][
0
]
*
g12
[
0
][
2
]
+
g12
[
2
][
0
]
*
g12
[
0
][
1
]
-
g12
[
0
][
0
]
*
(
g12
[
1
][
2
]
+
g12
[
2
][
1
])));
d
[
0
][
2
]
=
scale
[
0
]
*
(
a
[
0
][
0
]
*
(
g12
[
0
][
1
]
*
g12
[
1
][
2
]
+
g12
[
1
][
0
]
*
g12
[
2
][
1
]
-
g12
[
1
][
1
]
*
(
g12
[
0
][
2
]
+
g12
[
2
][
0
]))
+
a
[
0
][
1
]
*
(
g12
[
1
][
0
]
*
g12
[
0
][
2
]
+
g12
[
2
][
0
]
*
g12
[
0
][
1
]
-
g12
[
0
][
0
]
*
(
g12
[
1
][
2
]
+
g12
[
2
][
1
]))
+
2
*
a
[
0
][
2
]
*
(
g12
[
1
][
1
]
*
g12
[
0
][
0
]
-
g12
[
1
][
0
]
*
g12
[
0
][
1
]));
d
[
1
][
0
]
=
scale
[
1
]
*
(
2
*
a
[
1
][
0
]
*
(
g12
[
1
][
1
]
*
g12
[
2
][
2
]
-
g12
[
1
][
2
]
*
g12
[
2
][
1
])
+
a
[
1
][
1
]
*
(
g12
[
0
][
2
]
*
g12
[
2
][
1
]
+
g12
[
2
][
0
]
*
g12
[
1
][
2
]
-
g12
[
2
][
2
]
*
(
g12
[
0
][
1
]
+
g12
[
1
][
0
]))
+
a
[
1
][
2
]
*
(
g12
[
1
][
2
]
*
g12
[
0
][
1
]
+
g12
[
1
][
0
]
*
g12
[
2
][
1
]
-
g12
[
1
][
1
]
*
(
g12
[
0
][
2
]
+
g12
[
2
][
0
])));
d
[
1
][
1
]
=
scale
[
1
]
*
(
a
[
1
][
0
]
*
(
g12
[
0
][
2
]
*
g12
[
2
][
1
]
+
g12
[
2
][
0
]
*
g12
[
1
][
2
]
-
g12
[
2
][
2
]
*
(
g12
[
0
][
1
]
+
g12
[
1
][
0
]))
+
2
*
a
[
1
][
1
]
*
(
g12
[
2
][
2
]
*
g12
[
0
][
0
]
-
g12
[
2
][
0
]
*
g12
[
0
][
2
])
+
a
[
1
][
2
]
*
(
g12
[
1
][
0
]
*
g12
[
0
][
2
]
+
g12
[
0
][
1
]
*
g12
[
2
][
0
]
-
g12
[
0
][
0
]
*
(
g12
[
1
][
2
]
+
g12
[
2
][
1
])));
d
[
1
][
2
]
=
scale
[
1
]
*
(
a
[
1
][
0
]
*
(
g12
[
0
][
1
]
*
g12
[
1
][
2
]
+
g12
[
1
][
0
]
*
g12
[
2
][
1
]
-
g12
[
1
][
1
]
*
(
g12
[
0
][
2
]
+
g12
[
2
][
0
]))
+
a
[
1
][
1
]
*
(
g12
[
1
][
0
]
*
g12
[
0
][
2
]
+
g12
[
0
][
1
]
*
g12
[
2
][
0
]
-
g12
[
0
][
0
]
*
(
g12
[
1
][
2
]
+
g12
[
2
][
1
]))
+
2
*
a
[
1
][
2
]
*
(
g12
[
1
][
1
]
*
g12
[
0
][
0
]
-
g12
[
1
][
0
]
*
g12
[
0
][
1
]));
d
[
2
][
0
]
=
scale
[
2
]
*
(
2
*
a
[
2
][
0
]
*
(
g12
[
1
][
1
]
*
g12
[
2
][
2
]
-
g12
[
2
][
1
]
*
g12
[
1
][
2
])
+
a
[
2
][
1
]
*
(
g12
[
0
][
2
]
*
g12
[
2
][
1
]
+
g12
[
1
][
2
]
*
g12
[
2
][
0
]
-
g12
[
2
][
2
]
*
(
g12
[
0
][
1
]
+
g12
[
1
][
0
]))
+
a
[
2
][
2
]
*
(
g12
[
0
][
1
]
*
g12
[
1
][
2
]
+
g12
[
2
][
1
]
*
g12
[
1
][
0
]
-
g12
[
1
][
1
]
*
(
g12
[
0
][
2
]
+
g12
[
2
][
0
])));
d
[
2
][
1
]
=
scale
[
2
]
*
(
a
[
2
][
0
]
*
(
g12
[
0
][
2
]
*
g12
[
2
][
1
]
+
g12
[
1
][
2
]
*
g12
[
2
][
0
]
-
g12
[
2
][
2
]
*
(
g12
[
0
][
1
]
+
g12
[
1
][
0
]))
+
2
*
a
[
2
][
1
]
*
(
g12
[
0
][
0
]
*
g12
[
2
][
2
]
-
g12
[
0
][
2
]
*
g12
[
2
][
0
])
+
a
[
2
][
2
]
*
(
g12
[
1
][
0
]
*
g12
[
0
][
2
]
+
g12
[
0
][
1
]
*
g12
[
2
][
0
]
-
g12
[
0
][
0
]
*
(
g12
[
1
][
2
]
+
g12
[
2
][
1
])));
d
[
2
][
2
]
=
scale
[
2
]
*
(
a
[
2
][
0
]
*
(
g12
[
0
][
1
]
*
g12
[
1
][
2
]
+
g12
[
2
][
1
]
*
g12
[
1
][
0
]
-
g12
[
1
][
1
]
*
(
g12
[
0
][
2
]
+
g12
[
2
][
0
]))
+
a
[
2
][
1
]
*
(
g12
[
1
][
0
]
*
g12
[
0
][
2
]
+
g12
[
2
][
0
]
*
g12
[
0
][
1
]
-
g12
[
0
][
0
]
*
(
g12
[
1
][
2
]
+
g12
[
2
][
1
]))
+
2
*
a
[
2
][
2
]
*
(
g12
[
1
][
1
]
*
g12
[
0
][
0
]
-
g12
[
1
][
0
]
*
g12
[
0
][
1
]));
RealVec
detadq
;
for
(
int
i
=
0
;
i
<
3
;
i
++
)
detadq
+=
RealVec
(
a
[
i
][
0
],
a
[
i
][
1
],
a
[
i
][
2
]).
cross
(
RealVec
(
d
[
i
][
0
],
d
[
i
][
1
],
d
[
i
][
2
]));
RealVec
torque
=
(
dchidq
*
(
u
*
eta
)
+
detadq
*
(
u
*
chi
)
+
dudq
*
(
eta
*
chi
))
*
switchValue
;
torques
[
particle
]
-=
torque
;
}
return
switchValue
*
energy
;
}
platforms/reference/tests/TestReferenceGayBerneForce.cpp
0 → 100644
View file @
a468fa3a
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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) 2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* 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. *
* -------------------------------------------------------------------------- */
#include "ReferenceTests.h"
#include "TestGayBerneForce.h"
void
runPlatformTests
()
{
}
serialization/include/openmm/serialization/GayBerneForceProxy.h
0 → 100644
View file @
a468fa3a
#ifndef OPENMM_GAYBERNEFORCE_PROXY_H_
#define OPENMM_GAYBERNEFORCE_PROXY_H_
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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) 2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* 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. *
* -------------------------------------------------------------------------- */
#include "openmm/internal/windowsExport.h"
#include "openmm/serialization/SerializationProxy.h"
namespace
OpenMM
{
/**
* This is a proxy for serializing GayBerneForce objects.
*/
class
OPENMM_EXPORT
GayBerneForceProxy
:
public
SerializationProxy
{
public:
GayBerneForceProxy
();
void
serialize
(
const
void
*
object
,
SerializationNode
&
node
)
const
;
void
*
deserialize
(
const
SerializationNode
&
node
)
const
;
};
}
// namespace OpenMM
#endif
/*OPENMM_GAYBERNEFORCE_PROXY_H_*/
serialization/src/GayBerneForceProxy.cpp
0 → 100644
View file @
a468fa3a
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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) 2010-2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* 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. *
* -------------------------------------------------------------------------- */
#include "openmm/serialization/GayBerneForceProxy.h"
#include "openmm/serialization/SerializationNode.h"
#include "openmm/Force.h"
#include "openmm/GayBerneForce.h"
#include <sstream>
using
namespace
OpenMM
;
using
namespace
std
;
GayBerneForceProxy
::
GayBerneForceProxy
()
:
SerializationProxy
(
"GayBerneForce"
)
{
}
void
GayBerneForceProxy
::
serialize
(
const
void
*
object
,
SerializationNode
&
node
)
const
{
node
.
setIntProperty
(
"version"
,
1
);
const
GayBerneForce
&
force
=
*
reinterpret_cast
<
const
GayBerneForce
*>
(
object
);
node
.
setIntProperty
(
"forceGroup"
,
force
.
getForceGroup
());
node
.
setIntProperty
(
"method"
,
(
int
)
force
.
getNonbondedMethod
());
node
.
setDoubleProperty
(
"cutoff"
,
force
.
getCutoffDistance
());
node
.
setBoolProperty
(
"useSwitchingFunction"
,
force
.
getUseSwitchingFunction
());
node
.
setDoubleProperty
(
"switchingDistance"
,
force
.
getSwitchingDistance
());
SerializationNode
&
particles
=
node
.
createChildNode
(
"Particles"
);
for
(
int
i
=
0
;
i
<
force
.
getNumParticles
();
i
++
)
{
double
sigma
,
epsilon
,
sx
,
sy
,
sz
,
ex
,
ey
,
ez
;
int
xparticle
,
yparticle
;
force
.
getParticleParameters
(
i
,
sigma
,
epsilon
,
xparticle
,
yparticle
,
sx
,
sy
,
sz
,
ex
,
ey
,
ez
);
particles
.
createChildNode
(
"Particle"
).
setDoubleProperty
(
"sig"
,
sigma
).
setDoubleProperty
(
"eps"
,
epsilon
).
setDoubleProperty
(
"sx"
,
sx
)
.
setDoubleProperty
(
"sy"
,
sy
).
setDoubleProperty
(
"sz"
,
sz
).
setDoubleProperty
(
"ex"
,
ex
).
setDoubleProperty
(
"ey"
,
ey
).
setDoubleProperty
(
"ez"
,
ez
)
.
setIntProperty
(
"xparticle"
,
xparticle
).
setIntProperty
(
"yparticle"
,
yparticle
);
}
SerializationNode
&
exceptions
=
node
.
createChildNode
(
"Exceptions"
);
for
(
int
i
=
0
;
i
<
force
.
getNumExceptions
();
i
++
)
{
int
particle1
,
particle2
;
double
sigma
,
epsilon
;
force
.
getExceptionParameters
(
i
,
particle1
,
particle2
,
sigma
,
epsilon
);
exceptions
.
createChildNode
(
"Exception"
).
setIntProperty
(
"p1"
,
particle1
).
setIntProperty
(
"p2"
,
particle2
).
setDoubleProperty
(
"sig"
,
sigma
).
setDoubleProperty
(
"eps"
,
epsilon
);
}
}
void
*
GayBerneForceProxy
::
deserialize
(
const
SerializationNode
&
node
)
const
{
if
(
node
.
getIntProperty
(
"version"
)
!=
1
)
throw
OpenMMException
(
"Unsupported version number"
);
GayBerneForce
*
force
=
new
GayBerneForce
();
try
{
force
->
setForceGroup
(
node
.
getIntProperty
(
"forceGroup"
,
0
));
force
->
setNonbondedMethod
((
GayBerneForce
::
NonbondedMethod
)
node
.
getIntProperty
(
"method"
));
force
->
setCutoffDistance
(
node
.
getDoubleProperty
(
"cutoff"
));
force
->
setUseSwitchingFunction
(
node
.
getBoolProperty
(
"useSwitchingFunction"
,
false
));
force
->
setSwitchingDistance
(
node
.
getDoubleProperty
(
"switchingDistance"
,
-
1.0
));
const
SerializationNode
&
particles
=
node
.
getChildNode
(
"Particles"
);
for
(
int
i
=
0
;
i
<
(
int
)
particles
.
getChildren
().
size
();
i
++
)
{
const
SerializationNode
&
particle
=
particles
.
getChildren
()[
i
];
force
->
addParticle
(
particle
.
getDoubleProperty
(
"sig"
),
particle
.
getDoubleProperty
(
"eps"
),
particle
.
getIntProperty
(
"xparticle"
),
particle
.
getIntProperty
(
"yparticle"
),
particle
.
getDoubleProperty
(
"sx"
),
particle
.
getDoubleProperty
(
"sy"
),
particle
.
getDoubleProperty
(
"sz"
),
particle
.
getDoubleProperty
(
"ex"
),
particle
.
getDoubleProperty
(
"ey"
),
particle
.
getDoubleProperty
(
"ez"
));
}
const
SerializationNode
&
exceptions
=
node
.
getChildNode
(
"Exceptions"
);
for
(
int
i
=
0
;
i
<
(
int
)
exceptions
.
getChildren
().
size
();
i
++
)
{
const
SerializationNode
&
exception
=
exceptions
.
getChildren
()[
i
];
force
->
addException
(
exception
.
getIntProperty
(
"p1"
),
exception
.
getIntProperty
(
"p2"
),
exception
.
getDoubleProperty
(
"sig"
),
exception
.
getDoubleProperty
(
"eps"
));
}
}
catch
(...)
{
delete
force
;
throw
;
}
return
force
;
}
serialization/src/SerializationProxyRegistration.cpp
View file @
a468fa3a
...
...
@@ -6,7 +6,7 @@
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* Portions copyright (c) 2010-201
5
Stanford University and the Authors. *
* Portions copyright (c) 2010-201
6
Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
...
...
@@ -45,6 +45,7 @@
#include "openmm/CustomManyParticleForce.h"
#include "openmm/CustomNonbondedForce.h"
#include "openmm/CustomTorsionForce.h"
#include "openmm/GayBerneForce.h"
#include "openmm/GBSAOBCForce.h"
#include "openmm/HarmonicAngleForce.h"
#include "openmm/HarmonicBondForce.h"
...
...
@@ -78,6 +79,7 @@
#include "openmm/serialization/CustomManyParticleForceProxy.h"
#include "openmm/serialization/CustomNonbondedForceProxy.h"
#include "openmm/serialization/CustomTorsionForceProxy.h"
#include "openmm/serialization/GayBerneForceProxy.h"
#include "openmm/serialization/GBSAOBCForceProxy.h"
#include "openmm/serialization/HarmonicAngleForceProxy.h"
#include "openmm/serialization/HarmonicBondForceProxy.h"
...
...
@@ -132,6 +134,7 @@ extern "C" void registerSerializationProxies() {
SerializationProxy
::
registerProxy
(
typeid
(
Discrete1DFunction
),
new
Discrete1DFunctionProxy
());
SerializationProxy
::
registerProxy
(
typeid
(
Discrete2DFunction
),
new
Discrete2DFunctionProxy
());
SerializationProxy
::
registerProxy
(
typeid
(
Discrete3DFunction
),
new
Discrete3DFunctionProxy
());
SerializationProxy
::
registerProxy
(
typeid
(
GayBerneForce
),
new
GayBerneForceProxy
());
SerializationProxy
::
registerProxy
(
typeid
(
GBSAOBCForce
),
new
GBSAOBCForceProxy
());
SerializationProxy
::
registerProxy
(
typeid
(
HarmonicAngleForce
),
new
HarmonicAngleForceProxy
());
SerializationProxy
::
registerProxy
(
typeid
(
HarmonicBondForce
),
new
HarmonicBondForceProxy
());
...
...
serialization/tests/TestSerializeGayBerneForce.cpp
0 → 100644
View file @
a468fa3a
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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) 2010-2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* 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. *
* -------------------------------------------------------------------------- */
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/GayBerneForce.h"
#include "openmm/serialization/XmlSerializer.h"
#include <iostream>
#include <sstream>
using
namespace
OpenMM
;
using
namespace
std
;
void
testSerialization
()
{
// Create a Force.
GayBerneForce
force
;
force
.
setForceGroup
(
3
);
force
.
setNonbondedMethod
(
GayBerneForce
::
CutoffPeriodic
);
force
.
setSwitchingDistance
(
1.5
);
force
.
setUseSwitchingFunction
(
true
);
force
.
setCutoffDistance
(
2.0
);
force
.
addParticle
(
0.1
,
0.01
,
-
1
,
-
1
,
0.5
,
0.5
,
0.5
,
1.0
,
1.0
,
1.0
);
force
.
addParticle
(
0.2
,
0.02
,
-
1
,
-
1
,
0.7
,
0.7
,
0.7
,
1.2
,
1.2
,
1.2
);
force
.
addParticle
(
0.3
,
0.03
,
1
,
0
,
0.8
,
0.9
,
1.0
,
0.5
,
0.6
,
0.7
);
force
.
addException
(
0
,
1
,
0.5
,
0.1
);
force
.
addException
(
1
,
2
,
0.4
,
0.2
);
// Serialize and then deserialize it.
stringstream
buffer
;
XmlSerializer
::
serialize
<
GayBerneForce
>
(
&
force
,
"Force"
,
buffer
);
GayBerneForce
*
copy
=
XmlSerializer
::
deserialize
<
GayBerneForce
>
(
buffer
);
// Compare the two forces to see if they are identical.
GayBerneForce
&
force2
=
*
copy
;
ASSERT_EQUAL
(
force
.
getForceGroup
(),
force2
.
getForceGroup
());
ASSERT_EQUAL
(
force
.
getNonbondedMethod
(),
force2
.
getNonbondedMethod
());
ASSERT_EQUAL
(
force
.
getSwitchingDistance
(),
force2
.
getSwitchingDistance
());
ASSERT_EQUAL
(
force
.
getUseSwitchingFunction
(),
force2
.
getUseSwitchingFunction
());
ASSERT_EQUAL
(
force
.
getCutoffDistance
(),
force2
.
getCutoffDistance
());
ASSERT_EQUAL
(
force
.
getNumParticles
(),
force2
.
getNumParticles
());
for
(
int
i
=
0
;
i
<
force
.
getNumParticles
();
i
++
)
{
double
sigma1
,
epsilon1
,
sx1
,
sy1
,
sz1
,
ex1
,
ey1
,
ez1
;
double
sigma2
,
epsilon2
,
sx2
,
sy2
,
sz2
,
ex2
,
ey2
,
ez2
;
int
xparticle1
,
yparticle1
,
xparticle2
,
yparticle2
;
force
.
getParticleParameters
(
i
,
sigma1
,
epsilon1
,
xparticle1
,
yparticle1
,
sx1
,
sy1
,
sz1
,
ex1
,
ey1
,
ez1
);
force2
.
getParticleParameters
(
i
,
sigma2
,
epsilon2
,
xparticle2
,
yparticle2
,
sx2
,
sy2
,
sz2
,
ex2
,
ey2
,
ez2
);
ASSERT_EQUAL
(
sigma1
,
sigma2
);
ASSERT_EQUAL
(
epsilon1
,
epsilon2
);
ASSERT_EQUAL
(
xparticle1
,
xparticle1
);
ASSERT_EQUAL
(
xparticle2
,
xparticle2
);
ASSERT_EQUAL
(
sx1
,
sx2
);
ASSERT_EQUAL
(
sy1
,
sy2
);
ASSERT_EQUAL
(
sz1
,
sz2
);
ASSERT_EQUAL
(
ex1
,
ex2
);
ASSERT_EQUAL
(
ey1
,
ey2
);
ASSERT_EQUAL
(
ez1
,
ez2
);
}
ASSERT_EQUAL
(
force
.
getNumExceptions
(),
force2
.
getNumExceptions
());
for
(
int
i
=
0
;
i
<
force
.
getNumExceptions
();
i
++
)
{
int
a1
,
a2
,
b1
,
b2
;
double
sigma1
,
epsilon1
;
double
sigma2
,
epsilon2
;
force
.
getExceptionParameters
(
i
,
a1
,
b1
,
sigma1
,
epsilon1
);
force2
.
getExceptionParameters
(
i
,
a2
,
b2
,
sigma2
,
epsilon2
);
ASSERT_EQUAL
(
a1
,
a2
);
ASSERT_EQUAL
(
b1
,
b2
);
ASSERT_EQUAL
(
sigma1
,
sigma2
);
ASSERT_EQUAL
(
epsilon1
,
epsilon2
);
}
}
int
main
()
{
try
{
testSerialization
();
}
catch
(
const
exception
&
e
)
{
cout
<<
"exception: "
<<
e
.
what
()
<<
endl
;
return
1
;
}
cout
<<
"Done"
<<
endl
;
return
0
;
}
tests/TestGayBerneForce.h
0 → 100644
View file @
a468fa3a
/* -------------------------------------------------------------------------- *
* OpenMM *
* -------------------------------------------------------------------------- *
* 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) 2016 Stanford University and the Authors. *
* Authors: Peter Eastman *
* 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. *
* -------------------------------------------------------------------------- */
#ifdef WIN32
#define _USE_MATH_DEFINES // Needed to get M_PI
#endif
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/Context.h"
#include "openmm/GayBerneForce.h"
#include "openmm/NonbondedForce.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include "sfmt/SFMT.h"
#include <iostream>
#include <vector>
using
namespace
OpenMM
;
using
namespace
std
;
const
double
TOL
=
1e-5
;
void
testPointParticles
()
{
// For point particles, it should be identical to a standard Lennard-Jones force.
const
int
numParticles
=
10
;
const
double
sigma
=
0.5
;
const
double
epsilon
=
1.5
;
System
system
;
GayBerneForce
*
gb
=
new
GayBerneForce
();
NonbondedForce
*
nb
=
new
NonbondedForce
();
system
.
addForce
(
gb
);
system
.
addForce
(
nb
);
gb
->
setForceGroup
(
1
);
vector
<
Vec3
>
positions
;
OpenMM_SFMT
::
SFMT
sfmt
;
init_gen_rand
(
0
,
sfmt
);
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
{
system
.
addParticle
(
1.0
);
gb
->
addParticle
(
sigma
,
epsilon
,
-
1
,
-
1
,
sigma
,
sigma
,
sigma
,
1
,
1
,
1
);
nb
->
addParticle
(
0
,
sigma
,
epsilon
);
positions
.
push_back
(
Vec3
(
2.0
*
genrand_real2
(
sfmt
),
2.0
*
genrand_real2
(
sfmt
),
2.0
*
genrand_real2
(
sfmt
)));
}
VerletIntegrator
integ
(
0.001
);
// Compute forces and energy with each one and compare them.
Context
context
(
system
,
integ
,
platform
);
context
.
setPositions
(
positions
);
State
state1
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
,
false
,
1
);
State
state2
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
,
false
,
2
);
ASSERT_EQUAL_TOL
(
state1
.
getPotentialEnergy
(),
state2
.
getPotentialEnergy
(),
1e-5
);
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
ASSERT_EQUAL_VEC
(
state1
.
getForces
()[
i
],
state2
.
getForces
()[
i
],
1e-5
);
}
void
testEnergyScales
()
{
// Create two Lennard-Jones particles for which the energy scale factors vary.
const
double
sigma
=
0.5
;
const
double
epsilon
=
1.5
;
System
system
;
for
(
int
i
=
0
;
i
<
6
;
i
++
)
system
.
addParticle
(
1.0
);
GayBerneForce
*
gb
=
new
GayBerneForce
();
system
.
addForce
(
gb
);
gb
->
addParticle
(
sigma
,
epsilon
,
1
,
2
,
sigma
,
sigma
,
sigma
,
1.1
,
1.5
,
1.8
);
gb
->
addParticle
(
1
,
0
,
-
1
,
-
1
,
1
,
1
,
1
,
1
,
1
,
1
);
gb
->
addParticle
(
1
,
0
,
-
1
,
-
1
,
1
,
1
,
1
,
1
,
1
,
1
);
gb
->
addParticle
(
sigma
,
epsilon
,
4
,
5
,
sigma
,
sigma
,
sigma
,
1.2
,
1.6
,
1.7
);
gb
->
addParticle
(
1
,
0
,
-
1
,
-
1
,
1
,
1
,
1
,
1
,
1
,
1
);
gb
->
addParticle
(
1
,
0
,
-
1
,
-
1
,
1
,
1
,
1
,
1
,
1
,
1
);
vector
<
Vec3
>
positions
(
6
);
positions
[
0
]
=
Vec3
(
0
,
0
,
0
);
positions
[
1
]
=
Vec3
(
1
,
0
,
0
);
positions
[
2
]
=
Vec3
(
0
,
1
,
0
);
positions
[
3
]
=
Vec3
(
1
,
0
,
0
);
positions
[
4
]
=
Vec3
(
2
,
0
,
0
);
positions
[
5
]
=
Vec3
(
1
,
1
,
0
);
VerletIntegrator
integ
(
0.001
);
Context
context
(
system
,
integ
,
platform
);
context
.
setPositions
(
positions
);
// Depending on their relative orientations, the interaction should be equivalent
// to LJ with different values of epsilon.
double
expectedEnergy
=
4
*
epsilon
*
(
pow
(
sigma
,
12.0
)
-
pow
(
sigma
,
6.0
));
double
expectedForce
=
4
*
epsilon
*
(
12
*
pow
(
sigma
,
12.0
)
-
6
*
pow
(
sigma
,
6.0
));
double
expectedScale
=
pow
(
2.0
/
(
1
/
sqrt
(
1.1
)
+
1
/
sqrt
(
1.2
)),
2.0
);
State
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
ASSERT_EQUAL_TOL
(
expectedEnergy
*
expectedScale
,
state
.
getPotentialEnergy
(),
1e-5
);
ASSERT_EQUAL_VEC
(
Vec3
(
expectedForce
*
expectedScale
,
0
,
0
),
state
.
getForces
()[
3
],
1e-5
);
positions
[
3
]
=
Vec3
(
0
,
1
,
0
);
positions
[
4
]
=
Vec3
(
1
,
1
,
0
);
positions
[
5
]
=
Vec3
(
0
,
2
,
0
);
context
.
setPositions
(
positions
);
expectedScale
=
pow
(
2.0
/
(
1
/
sqrt
(
1.5
)
+
1
/
sqrt
(
1.6
)),
2.0
);
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
ASSERT_EQUAL_TOL
(
expectedEnergy
*
expectedScale
,
state
.
getPotentialEnergy
(),
1e-5
);
ASSERT_EQUAL_VEC
(
Vec3
(
0
,
expectedForce
*
expectedScale
,
0
),
state
.
getForces
()[
3
],
1e-5
);
positions
[
3
]
=
Vec3
(
0
,
1
,
0
);
positions
[
4
]
=
Vec3
(
1
,
1
,
0
);
positions
[
5
]
=
Vec3
(
0
,
1
,
1
);
context
.
setPositions
(
positions
);
expectedScale
=
pow
(
2.0
/
(
1
/
sqrt
(
1.5
)
+
1
/
sqrt
(
1.7
)),
2.0
);
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
ASSERT_EQUAL_TOL
(
expectedEnergy
*
expectedScale
,
state
.
getPotentialEnergy
(),
1e-5
);
ASSERT_EQUAL_VEC
(
Vec3
(
0
,
expectedForce
*
expectedScale
,
0
),
state
.
getForces
()[
3
],
1e-5
);
// Modify their parameters and see if the result is still correct.
double
newSigma
=
1.1
*
sigma
;
gb
->
setParticleParameters
(
0
,
newSigma
,
1.5
*
epsilon
,
1
,
2
,
newSigma
,
newSigma
,
newSigma
,
1.2
,
1.6
,
1.9
);
gb
->
setParticleParameters
(
3
,
newSigma
,
epsilon
,
4
,
5
,
newSigma
,
newSigma
,
newSigma
,
1.3
,
1.7
,
1.8
);
gb
->
updateParametersInContext
(
context
);
double
combinedEpsilon
=
sqrt
(
1.5
)
*
epsilon
;
expectedEnergy
=
4
*
combinedEpsilon
*
(
pow
(
newSigma
,
12.0
)
-
pow
(
newSigma
,
6.0
));
expectedForce
=
4
*
combinedEpsilon
*
(
12
*
pow
(
newSigma
,
12.0
)
-
6
*
pow
(
newSigma
,
6.0
));
expectedScale
=
pow
(
2.0
/
(
1
/
sqrt
(
1.6
)
+
1
/
sqrt
(
1.8
)),
2.0
);
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
ASSERT_EQUAL_TOL
(
expectedEnergy
*
expectedScale
,
state
.
getPotentialEnergy
(),
1e-5
);
ASSERT_EQUAL_VEC
(
Vec3
(
0
,
expectedForce
*
expectedScale
,
0
),
state
.
getForces
()[
3
],
1e-5
);
}
void
testEnergyConservation
()
{
// Create a box of ellipsoids and make sure a simulation conserves energy.
// That verifies that forces and energies are consistent.
const
double
boxSize
=
3.0
;
System
system
;
system
.
setDefaultPeriodicBoxVectors
(
Vec3
(
boxSize
,
0
,
0
),
Vec3
(
0
,
boxSize
,
0
),
Vec3
(
0
,
0
,
boxSize
));
GayBerneForce
*
gb
=
new
GayBerneForce
();
system
.
addForce
(
gb
);
gb
->
setNonbondedMethod
(
GayBerneForce
::
CutoffPeriodic
);
gb
->
setCutoffDistance
(
1.0
);
gb
->
setUseSwitchingFunction
(
true
);
gb
->
setSwitchingDistance
(
0.9
);
vector
<
Vec3
>
positions
;
for
(
int
x
=
0
;
x
<
3
;
x
++
)
{
for
(
int
y
=
0
;
y
<
3
;
y
++
)
{
for
(
int
z
=
0
;
z
<
3
;
z
++
)
{
int
first
=
system
.
getNumParticles
();
system
.
addParticle
(
10.0
);
system
.
addParticle
(
1.0
);
system
.
addParticle
(
1.0
);
gb
->
addParticle
(
0.2
,
10.0
,
first
+
1
,
first
+
2
,
0.2
,
0.25
,
0.3
,
0.9
,
1.0
,
1.1
);
gb
->
addParticle
(
1.0
,
0.0
,
-
1
,
-
1
,
1
,
1
,
1
,
1
,
1
,
1
);
gb
->
addParticle
(
1.0
,
0.0
,
-
1
,
-
1
,
1
,
1
,
1
,
1
,
1
,
1
);
positions
.
push_back
(
Vec3
(
x
,
y
,
z
));
positions
.
push_back
(
Vec3
(
x
+
0.1
,
y
,
z
));
positions
.
push_back
(
Vec3
(
x
,
y
+
0.1
,
z
));
system
.
addConstraint
(
first
,
first
+
1
,
0.1
);
system
.
addConstraint
(
first
,
first
+
2
,
0.1
);
system
.
addConstraint
(
first
+
1
,
first
+
2
,
0.1
*
sqrt
(
2.0
));
}
}
}
VerletIntegrator
integ
(
0.0005
);
Context
context
(
system
,
integ
,
platform
);
context
.
setPositions
(
positions
);
context
.
setVelocitiesToTemperature
(
300.0
);
double
initialEnergy
;
for
(
int
i
=
0
;
i
<
100
;
i
++
)
{
integ
.
step
(
5
);
State
state
=
context
.
getState
(
State
::
Energy
);
double
energy
=
state
.
getPotentialEnergy
()
+
state
.
getKineticEnergy
();
if
(
i
==
0
)
initialEnergy
=
energy
;
else
ASSERT_EQUAL_TOL
(
initialEnergy
,
energy
,
1e-4
);
}
}
void
testExceptions
()
{
// Create two Lennard-Jones particles for which the energy scale factors vary,
// then override their interaction with an exception.
const
double
sigma
=
0.5
;
const
double
epsilon
=
1.5
;
System
system
;
for
(
int
i
=
0
;
i
<
6
;
i
++
)
system
.
addParticle
(
1.0
);
GayBerneForce
*
gb
=
new
GayBerneForce
();
system
.
addForce
(
gb
);
gb
->
addParticle
(
sigma
,
epsilon
,
1
,
2
,
sigma
,
sigma
,
sigma
,
1.1
,
1.5
,
1.8
);
gb
->
addParticle
(
1
,
0
,
-
1
,
-
1
,
1
,
1
,
1
,
1
,
1
,
1
);
gb
->
addParticle
(
1
,
0
,
-
1
,
-
1
,
1
,
1
,
1
,
1
,
1
,
1
);
gb
->
addParticle
(
sigma
,
epsilon
,
4
,
5
,
sigma
,
sigma
,
sigma
,
1.2
,
1.6
,
1.7
);
gb
->
addParticle
(
1
,
0
,
-
1
,
-
1
,
1
,
1
,
1
,
1
,
1
,
1
);
gb
->
addParticle
(
1
,
0
,
-
1
,
-
1
,
1
,
1
,
1
,
1
,
1
,
1
);
gb
->
addException
(
0
,
3
,
sigma
,
3.5
*
epsilon
);
vector
<
Vec3
>
positions
(
6
);
positions
[
0
]
=
Vec3
(
0
,
0
,
0
);
positions
[
1
]
=
Vec3
(
1
,
0
,
0
);
positions
[
2
]
=
Vec3
(
0
,
1
,
0
);
positions
[
3
]
=
Vec3
(
1
,
0
,
0
);
positions
[
4
]
=
Vec3
(
2
,
0
,
0
);
positions
[
5
]
=
Vec3
(
1
,
1
,
0
);
VerletIntegrator
integ
(
0.001
);
Context
context
(
system
,
integ
,
platform
);
context
.
setPositions
(
positions
);
double
expectedEnergy
=
3.5
*
4
*
epsilon
*
(
pow
(
sigma
,
12.0
)
-
pow
(
sigma
,
6.0
));
double
expectedForce
=
3.5
*
4
*
epsilon
*
(
12
*
pow
(
sigma
,
12.0
)
-
6
*
pow
(
sigma
,
6.0
));
double
expectedScale
=
pow
(
2.0
/
(
1
/
sqrt
(
1.1
)
+
1
/
sqrt
(
1.2
)),
2.0
);
State
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
ASSERT_EQUAL_TOL
(
expectedEnergy
*
expectedScale
,
state
.
getPotentialEnergy
(),
1e-5
);
ASSERT_EQUAL_VEC
(
Vec3
(
expectedForce
*
expectedScale
,
0
,
0
),
state
.
getForces
()[
3
],
1e-5
);
// Modify the exception and see if the results are still correct.
gb
->
setExceptionParameters
(
0
,
0
,
3
,
sigma
,
3.1
*
epsilon
);
gb
->
updateParametersInContext
(
context
);
expectedEnergy
=
3.1
*
4
*
epsilon
*
(
pow
(
sigma
,
12.0
)
-
pow
(
sigma
,
6.0
));
expectedForce
=
3.1
*
4
*
epsilon
*
(
12
*
pow
(
sigma
,
12.0
)
-
6
*
pow
(
sigma
,
6.0
));
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
ASSERT_EQUAL_TOL
(
expectedEnergy
*
expectedScale
,
state
.
getPotentialEnergy
(),
1e-5
);
ASSERT_EQUAL_VEC
(
Vec3
(
expectedForce
*
expectedScale
,
0
,
0
),
state
.
getForces
()[
3
],
1e-5
);
}
void
runPlatformTests
();
int
main
(
int
argc
,
char
*
argv
[])
{
try
{
initializeTests
(
argc
,
argv
);
testPointParticles
();
testEnergyScales
();
testEnergyConservation
();
testExceptions
();
runPlatformTests
();
}
catch
(
const
exception
&
e
)
{
cout
<<
"exception: "
<<
e
.
what
()
<<
endl
;
return
1
;
}
cout
<<
"Done"
<<
endl
;
return
0
;
}
Prev
1
2
3
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment