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
468a8a5c
"vscode:/vscode.git/clone" did not exist on "505824d6dee165ca3d1d3c488e9b9e4ba9213ad7"
Commit
468a8a5c
authored
Oct 06, 2014
by
peastman
Browse files
Began creating CPU version of CustomGBForce
parent
77e33f17
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
1374 additions
and
0 deletions
+1374
-0
platforms/cpu/include/CpuCustomGBForce.h
platforms/cpu/include/CpuCustomGBForce.h
+263
-0
platforms/cpu/include/CpuKernels.h
platforms/cpu/include/CpuKernels.h
+53
-0
platforms/cpu/src/CpuCustomGBForce.cpp
platforms/cpu/src/CpuCustomGBForce.cpp
+420
-0
platforms/cpu/src/CpuKernelFactory.cpp
platforms/cpu/src/CpuKernelFactory.cpp
+2
-0
platforms/cpu/src/CpuKernels.cpp
platforms/cpu/src/CpuKernels.cpp
+156
-0
platforms/cpu/src/CpuPlatform.cpp
platforms/cpu/src/CpuPlatform.cpp
+1
-0
platforms/cpu/tests/TestCpuCustomGBForce.cpp
platforms/cpu/tests/TestCpuCustomGBForce.cpp
+479
-0
No files found.
platforms/cpu/include/CpuCustomGBForce.h
0 → 100644
View file @
468a8a5c
/* Portions copyright (c) 2009-2014 Stanford University and Simbios.
* Contributors: Peter Eastman
*
* 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 OPENMM_CPU_CUSTOM_GB_FORCE_H__
#define OPENMM_CPU_CUSTOM_GB_FORCE_H__
#include "ReferenceNeighborList.h"
#include "CompiledExpressionSet.h"
#include "lepton/CompiledExpression.h"
#include "openmm/CustomGBForce.h"
#include <map>
#include <set>
#include <vector>
class
CpuCustomGBForce
{
private:
bool
cutoff
;
bool
periodic
;
const
OpenMM
::
NeighborList
*
neighborList
;
RealOpenMM
periodicBoxSize
[
3
];
RealOpenMM
cutoffDistance
;
OpenMM
::
CompiledExpressionSet
expressionSet
;
std
::
vector
<
Lepton
::
CompiledExpression
>
valueExpressions
;
std
::
vector
<
std
::
vector
<
Lepton
::
CompiledExpression
>
>
valueDerivExpressions
;
std
::
vector
<
std
::
vector
<
Lepton
::
CompiledExpression
>
>
valueGradientExpressions
;
std
::
vector
<
std
::
string
>
valueNames
;
std
::
vector
<
int
>
valueIndex
;
std
::
vector
<
OpenMM
::
CustomGBForce
::
ComputationType
>
valueTypes
;
std
::
vector
<
Lepton
::
CompiledExpression
>
energyExpressions
;
std
::
vector
<
std
::
vector
<
Lepton
::
CompiledExpression
>
>
energyDerivExpressions
;
std
::
vector
<
std
::
vector
<
Lepton
::
CompiledExpression
>
>
energyGradientExpressions
;
std
::
vector
<
std
::
string
>
paramNames
;
std
::
vector
<
int
>
paramIndex
;
std
::
vector
<
OpenMM
::
CustomGBForce
::
ComputationType
>
energyTypes
;
std
::
vector
<
std
::
string
>
particleParamNames
;
std
::
vector
<
std
::
string
>
particleValueNames
;
std
::
vector
<
int
>
particleParamIndex
;
std
::
vector
<
int
>
particleValueIndex
;
int
xindex
,
yindex
,
zindex
,
rindex
;
/**
* Calculate a computed value of type SingleParticle
*
* @param index the index of the value to compute
* @param numAtoms number of atoms
* @param atomCoordinates atom coordinates
* @param values the vector to store computed values into
* @param globalParameters the values of global parameters
* @param atomParameters atomParameters[atomIndex][paramterIndex]
*/
void
calculateSingleParticleValue
(
int
index
,
int
numAtoms
,
std
::
vector
<
OpenMM
::
RealVec
>&
atomCoordinates
,
std
::
vector
<
std
::
vector
<
RealOpenMM
>
>&
values
,
const
std
::
map
<
std
::
string
,
double
>&
globalParameters
,
RealOpenMM
**
atomParameters
);
/**
* Calculate a computed value that is based on particle pairs
*
* @param index the index of the value to compute
* @param numAtoms number of atoms
* @param atomCoordinates atom coordinates
* @param atomParameters atomParameters[atomIndex][paramterIndex]
* @param values the vector to store computed values into
* @param globalParameters the values of global parameters
* @param exclusions exclusions[i] is the set of excluded indices for atom i
* @param useExclusions specifies whether to use exclusions
*/
void
calculateParticlePairValue
(
int
index
,
int
numAtoms
,
std
::
vector
<
OpenMM
::
RealVec
>&
atomCoordinates
,
RealOpenMM
**
atomParameters
,
std
::
vector
<
std
::
vector
<
RealOpenMM
>
>&
values
,
const
std
::
map
<
std
::
string
,
double
>&
globalParameters
,
const
std
::
vector
<
std
::
set
<
int
>
>&
exclusions
,
bool
useExclusions
);
/**
* Evaluate a single atom pair as part of calculating a computed value
*
* @param index the index of the value to compute
* @param atom1 the index of the first atom in the pair
* @param atom2 the index of the second atom in the pair
* @param atomCoordinates atom coordinates
* @param atomParameters atomParameters[atomIndex][paramterIndex]
* @param globalParameters the values of global parameters
* @param values the vector to store computed values into
*/
void
calculateOnePairValue
(
int
index
,
int
atom1
,
int
atom2
,
std
::
vector
<
OpenMM
::
RealVec
>&
atomCoordinates
,
RealOpenMM
**
atomParameters
,
const
std
::
map
<
std
::
string
,
double
>&
globalParameters
,
std
::
vector
<
std
::
vector
<
RealOpenMM
>
>&
values
);
/**
* Calculate an energy term of type SingleParticle
*
* @param index the index of the value to compute
* @param numAtoms number of atoms
* @param atomCoordinates atom coordinates
* @param values the vector containing computed values
* @param globalParameters the values of global parameters
* @param atomParameters atomParameters[atomIndex][paramterIndex]
* @param forces forces on atoms are added to this
* @param totalEnergy the energy contribution is added to this
* @param dEdV the derivative of energy with respect to computed values is stored in this
*/
void
calculateSingleParticleEnergyTerm
(
int
index
,
int
numAtoms
,
std
::
vector
<
OpenMM
::
RealVec
>&
atomCoordinates
,
const
std
::
vector
<
std
::
vector
<
RealOpenMM
>
>&
values
,
const
std
::
map
<
std
::
string
,
double
>&
globalParameters
,
RealOpenMM
**
atomParameters
,
std
::
vector
<
OpenMM
::
RealVec
>&
forces
,
RealOpenMM
*
totalEnergy
,
std
::
vector
<
std
::
vector
<
RealOpenMM
>
>&
dEdV
);
/**
* Calculate an energy term that is based on particle pairs
*
* @param index the index of the term to compute
* @param numAtoms number of atoms
* @param atomCoordinates atom coordinates
* @param atomParameters atomParameters[atomIndex][paramterIndex]
* @param values the vector containing computed values
* @param globalParameters the values of global parameters
* @param exclusions exclusions[i] is the set of excluded indices for atom i
* @param useExclusions specifies whether to use exclusions
* @param forces forces on atoms are added to this
* @param totalEnergy the energy contribution is added to this
* @param dEdV the derivative of energy with respect to computed values is stored in this
*/
void
calculateParticlePairEnergyTerm
(
int
index
,
int
numAtoms
,
std
::
vector
<
OpenMM
::
RealVec
>&
atomCoordinates
,
RealOpenMM
**
atomParameters
,
const
std
::
vector
<
std
::
vector
<
RealOpenMM
>
>&
values
,
const
std
::
map
<
std
::
string
,
double
>&
globalParameters
,
const
std
::
vector
<
std
::
set
<
int
>
>&
exclusions
,
bool
useExclusions
,
std
::
vector
<
OpenMM
::
RealVec
>&
forces
,
RealOpenMM
*
totalEnergy
,
std
::
vector
<
std
::
vector
<
RealOpenMM
>
>&
dEdV
);
/**
* Evaluate a single atom pair as part of calculating an energy term
*
* @param index the index of the term to compute
* @param atom1 the index of the first atom in the pair
* @param atom2 the index of the second atom in the pair
* @param atomCoordinates atom coordinates
* @param atomParameters atomParameters[atomIndex][paramterIndex]
* @param globalParameters the values of global parameters
* @param values the vector containing computed values
* @param forces forces on atoms are added to this
* @param totalEnergy the energy contribution is added to this
* @param dEdV the derivative of energy with respect to computed values is stored in this
*/
void
calculateOnePairEnergyTerm
(
int
index
,
int
atom1
,
int
atom2
,
std
::
vector
<
OpenMM
::
RealVec
>&
atomCoordinates
,
RealOpenMM
**
atomParameters
,
const
std
::
map
<
std
::
string
,
double
>&
globalParameters
,
const
std
::
vector
<
std
::
vector
<
RealOpenMM
>
>&
values
,
std
::
vector
<
OpenMM
::
RealVec
>&
forces
,
RealOpenMM
*
totalEnergy
,
std
::
vector
<
std
::
vector
<
RealOpenMM
>
>&
dEdV
);
/**
* Apply the chain rule to compute forces on atoms
*
* @param numAtoms number of atoms
* @param atomCoordinates atom coordinates
* @param atomParameters atomParameters[atomIndex][paramterIndex]
* @param values the vector containing computed values
* @param globalParameters the values of global parameters
* @param exclusions exclusions[i] is the set of excluded indices for atom i
* @param forces forces on atoms are added to this
* @param dEdV the derivative of energy with respect to computed values is stored in this
*/
void
calculateChainRuleForces
(
int
numAtoms
,
std
::
vector
<
OpenMM
::
RealVec
>&
atomCoordinates
,
RealOpenMM
**
atomParameters
,
const
std
::
vector
<
std
::
vector
<
RealOpenMM
>
>&
values
,
const
std
::
map
<
std
::
string
,
double
>&
globalParameters
,
const
std
::
vector
<
std
::
set
<
int
>
>&
exclusions
,
std
::
vector
<
OpenMM
::
RealVec
>&
forces
,
std
::
vector
<
std
::
vector
<
RealOpenMM
>
>&
dEdV
);
/**
* Evaluate a single atom pair as part of applying the chain rule
*
* @param atom1 the index of the first atom in the pair
* @param atom2 the index of the second atom in the pair
* @param atomCoordinates atom coordinates
* @param atomParameters atomParameters[atomIndex][paramterIndex]
* @param globalParameters the values of global parameters
* @param values the vector containing computed values
* @param forces forces on atoms are added to this
* @param dEdV the derivative of energy with respect to computed values is stored in this
* @param isExcluded specifies whether this is an excluded pair
*/
void
calculateOnePairChainRule
(
int
atom1
,
int
atom2
,
std
::
vector
<
OpenMM
::
RealVec
>&
atomCoordinates
,
RealOpenMM
**
atomParameters
,
const
std
::
map
<
std
::
string
,
double
>&
globalParameters
,
const
std
::
vector
<
std
::
vector
<
RealOpenMM
>
>&
values
,
std
::
vector
<
OpenMM
::
RealVec
>&
forces
,
std
::
vector
<
std
::
vector
<
RealOpenMM
>
>&
dEdV
,
bool
isExcluded
);
public:
/**
* Construct a new CpuCustomGBForce.
*/
CpuCustomGBForce
(
const
std
::
vector
<
Lepton
::
CompiledExpression
>&
valueExpressions
,
const
std
::
vector
<
std
::
vector
<
Lepton
::
CompiledExpression
>
>
valueDerivExpressions
,
const
std
::
vector
<
std
::
vector
<
Lepton
::
CompiledExpression
>
>
valueGradientExpressions
,
const
std
::
vector
<
std
::
string
>&
valueNames
,
const
std
::
vector
<
OpenMM
::
CustomGBForce
::
ComputationType
>&
valueTypes
,
const
std
::
vector
<
Lepton
::
CompiledExpression
>&
energyExpressions
,
const
std
::
vector
<
std
::
vector
<
Lepton
::
CompiledExpression
>
>
energyDerivExpressions
,
const
std
::
vector
<
std
::
vector
<
Lepton
::
CompiledExpression
>
>
energyGradientExpressions
,
const
std
::
vector
<
OpenMM
::
CustomGBForce
::
ComputationType
>&
energyTypes
,
const
std
::
vector
<
std
::
string
>&
parameterNames
);
~
CpuCustomGBForce
();
/**
* Set the force to use a cutoff.
*
* @param distance the cutoff distance
* @param neighbors the neighbor list to use
*/
void
setUseCutoff
(
RealOpenMM
distance
,
const
OpenMM
::
NeighborList
&
neighbors
);
/**
* Set the force to use periodic boundary conditions. This requires that a cutoff has
* already been set, and the smallest side of the periodic box is at least twice the cutoff
* distance.
*
* @param boxSize the X, Y, and Z widths of the periodic box
*/
void
setPeriodic
(
OpenMM
::
RealVec
&
boxSize
);
/**
* Calculate custom GB ixn
*
* @param numberOfAtoms number of atoms
* @param atomCoordinates atom coordinates
* @param atomParameters atomParameters[atomIndex][paramterIndex]
* @param exclusions exclusions[i] is the set of excluded indices for atom i
* @param globalParameters the values of global parameters
* @param forces force array (forces added)
* @param totalEnergy total energy
*/
void
calculateIxn
(
int
numberOfAtoms
,
std
::
vector
<
OpenMM
::
RealVec
>&
atomCoordinates
,
RealOpenMM
**
atomParameters
,
const
std
::
vector
<
std
::
set
<
int
>
>&
exclusions
,
std
::
map
<
std
::
string
,
double
>&
globalParameters
,
std
::
vector
<
OpenMM
::
RealVec
>&
forces
,
RealOpenMM
*
totalEnergy
);
};
#endif // OPENMM_CPU_CUSTOM_GB_FORCE_H__
platforms/cpu/include/CpuKernels.h
View file @
468a8a5c
...
@@ -33,6 +33,7 @@
...
@@ -33,6 +33,7 @@
* -------------------------------------------------------------------------- */
* -------------------------------------------------------------------------- */
#include "CpuBondForce.h"
#include "CpuBondForce.h"
#include "CpuCustomGBForce.h"
#include "CpuCustomManyParticleForce.h"
#include "CpuCustomManyParticleForce.h"
#include "CpuCustomNonbondedForce.h"
#include "CpuCustomNonbondedForce.h"
#include "CpuGBSAOBCForce.h"
#include "CpuGBSAOBCForce.h"
...
@@ -303,6 +304,58 @@ private:
...
@@ -303,6 +304,58 @@ private:
CpuGBSAOBCForce
obc
;
CpuGBSAOBCForce
obc
;
};
};
/**
* This kernel is invoked by CustomGBForce to calculate the forces acting on the system.
*/
class
CpuCalcCustomGBForceKernel
:
public
CalcCustomGBForceKernel
{
public:
CpuCalcCustomGBForceKernel
(
std
::
string
name
,
const
Platform
&
platform
,
CpuPlatform
::
PlatformData
&
data
)
:
CalcCustomGBForceKernel
(
name
,
platform
),
data
(
data
)
{
}
~
CpuCalcCustomGBForceKernel
();
/**
* Initialize the kernel.
*
* @param system the System this kernel will be applied to
* @param force the CustomGBForce this kernel will be used for
*/
void
initialize
(
const
System
&
system
,
const
CustomGBForce
&
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
* @param includeEnergy true if the energy 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 CustomGBForce to copy the parameters from
*/
void
copyParametersToContext
(
ContextImpl
&
context
,
const
CustomGBForce
&
force
);
private:
CpuPlatform
::
PlatformData
&
data
;
int
numParticles
;
bool
isPeriodic
;
RealOpenMM
**
particleParamArray
;
RealOpenMM
nonbondedCutoff
;
std
::
vector
<
std
::
set
<
int
>
>
exclusions
;
std
::
vector
<
std
::
string
>
particleParameterNames
,
globalParameterNames
,
valueNames
;
std
::
vector
<
Lepton
::
CompiledExpression
>
valueExpressions
;
std
::
vector
<
std
::
vector
<
Lepton
::
CompiledExpression
>
>
valueDerivExpressions
;
std
::
vector
<
std
::
vector
<
Lepton
::
CompiledExpression
>
>
valueGradientExpressions
;
std
::
vector
<
OpenMM
::
CustomGBForce
::
ComputationType
>
valueTypes
;
std
::
vector
<
Lepton
::
CompiledExpression
>
energyExpressions
;
std
::
vector
<
std
::
vector
<
Lepton
::
CompiledExpression
>
>
energyDerivExpressions
;
std
::
vector
<
std
::
vector
<
Lepton
::
CompiledExpression
>
>
energyGradientExpressions
;
std
::
vector
<
OpenMM
::
CustomGBForce
::
ComputationType
>
energyTypes
;
NonbondedMethod
nonbondedMethod
;
NeighborList
*
neighborList
;
};
/**
/**
* This kernel is invoked by CustomManyParticleForce to calculate the forces acting on the system and the energy of the system.
* This kernel is invoked by CustomManyParticleForce to calculate the forces acting on the system and the energy of the system.
*/
*/
...
...
platforms/cpu/src/CpuCustomGBForce.cpp
0 → 100644
View file @
468a8a5c
/* Portions copyright (c) 2009-2014 Stanford University and Simbios.
* Contributors: Peter Eastman
*
* 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 <string.h>
#include <sstream>
#include "SimTKOpenMMCommon.h"
#include "SimTKOpenMMLog.h"
#include "SimTKOpenMMUtilities.h"
#include "ReferenceForce.h"
#include "CpuCustomGBForce.h"
using
std
::
map
;
using
std
::
set
;
using
std
::
string
;
using
std
::
stringstream
;
using
std
::
vector
;
using
OpenMM
::
RealVec
;
CpuCustomGBForce
::
CpuCustomGBForce
(
const
vector
<
Lepton
::
CompiledExpression
>&
valueExpressions
,
const
vector
<
vector
<
Lepton
::
CompiledExpression
>
>
valueDerivExpressions
,
const
vector
<
vector
<
Lepton
::
CompiledExpression
>
>
valueGradientExpressions
,
const
vector
<
string
>&
valueNames
,
const
vector
<
OpenMM
::
CustomGBForce
::
ComputationType
>&
valueTypes
,
const
vector
<
Lepton
::
CompiledExpression
>&
energyExpressions
,
const
vector
<
vector
<
Lepton
::
CompiledExpression
>
>
energyDerivExpressions
,
const
vector
<
vector
<
Lepton
::
CompiledExpression
>
>
energyGradientExpressions
,
const
vector
<
OpenMM
::
CustomGBForce
::
ComputationType
>&
energyTypes
,
const
vector
<
string
>&
parameterNames
)
:
cutoff
(
false
),
periodic
(
false
),
valueExpressions
(
valueExpressions
),
valueDerivExpressions
(
valueDerivExpressions
),
valueGradientExpressions
(
valueGradientExpressions
),
valueNames
(
valueNames
),
valueTypes
(
valueTypes
),
energyExpressions
(
energyExpressions
),
energyDerivExpressions
(
energyDerivExpressions
),
energyGradientExpressions
(
energyGradientExpressions
),
energyTypes
(
energyTypes
),
paramNames
(
parameterNames
)
{
for
(
int
i
=
0
;
i
<
(
int
)
valueExpressions
.
size
();
i
++
)
expressionSet
.
registerExpression
(
this
->
valueExpressions
[
i
]);
for
(
int
i
=
0
;
i
<
(
int
)
valueDerivExpressions
.
size
();
i
++
)
for
(
int
j
=
0
;
j
<
(
int
)
valueDerivExpressions
[
i
].
size
();
j
++
)
expressionSet
.
registerExpression
(
this
->
valueDerivExpressions
[
i
][
j
]);
for
(
int
i
=
0
;
i
<
(
int
)
valueGradientExpressions
.
size
();
i
++
)
for
(
int
j
=
0
;
j
<
(
int
)
valueGradientExpressions
[
i
].
size
();
j
++
)
expressionSet
.
registerExpression
(
this
->
valueGradientExpressions
[
i
][
j
]);
for
(
int
i
=
0
;
i
<
(
int
)
energyExpressions
.
size
();
i
++
)
expressionSet
.
registerExpression
(
this
->
energyExpressions
[
i
]);
for
(
int
i
=
0
;
i
<
(
int
)
energyDerivExpressions
.
size
();
i
++
)
for
(
int
j
=
0
;
j
<
(
int
)
energyDerivExpressions
[
i
].
size
();
j
++
)
expressionSet
.
registerExpression
(
this
->
energyDerivExpressions
[
i
][
j
]);
for
(
int
i
=
0
;
i
<
(
int
)
energyGradientExpressions
.
size
();
i
++
)
for
(
int
j
=
0
;
j
<
(
int
)
energyGradientExpressions
[
i
].
size
();
j
++
)
expressionSet
.
registerExpression
(
this
->
energyGradientExpressions
[
i
][
j
]);
xindex
=
expressionSet
.
getVariableIndex
(
"x"
);
yindex
=
expressionSet
.
getVariableIndex
(
"y"
);
zindex
=
expressionSet
.
getVariableIndex
(
"z"
);
rindex
=
expressionSet
.
getVariableIndex
(
"r"
);
for
(
int
i
=
0
;
i
<
(
int
)
paramNames
.
size
();
i
++
)
{
paramIndex
.
push_back
(
expressionSet
.
getVariableIndex
(
paramNames
[
i
]));
for
(
int
j
=
1
;
j
<
3
;
j
++
)
{
stringstream
name
;
name
<<
paramNames
[
i
]
<<
j
;
particleParamNames
.
push_back
(
name
.
str
());
particleParamIndex
.
push_back
(
expressionSet
.
getVariableIndex
(
name
.
str
()));
}
}
for
(
int
i
=
0
;
i
<
(
int
)
valueNames
.
size
();
i
++
)
{
valueIndex
.
push_back
(
expressionSet
.
getVariableIndex
(
valueNames
[
i
]));
for
(
int
j
=
1
;
j
<
3
;
j
++
)
{
stringstream
name
;
name
<<
valueNames
[
i
]
<<
j
;
particleValueNames
.
push_back
(
name
.
str
());
particleValueIndex
.
push_back
(
expressionSet
.
getVariableIndex
(
name
.
str
()));
}
}
}
CpuCustomGBForce
::~
CpuCustomGBForce
()
{
}
void
CpuCustomGBForce
::
setUseCutoff
(
RealOpenMM
distance
,
const
OpenMM
::
NeighborList
&
neighbors
)
{
cutoff
=
true
;
cutoffDistance
=
distance
;
neighborList
=
&
neighbors
;
}
void
CpuCustomGBForce
::
setPeriodic
(
RealVec
&
boxSize
)
{
if
(
cutoff
)
{
assert
(
boxSize
[
0
]
>=
2.0
*
cutoffDistance
);
assert
(
boxSize
[
1
]
>=
2.0
*
cutoffDistance
);
assert
(
boxSize
[
2
]
>=
2.0
*
cutoffDistance
);
}
periodic
=
true
;
periodicBoxSize
[
0
]
=
boxSize
[
0
];
periodicBoxSize
[
1
]
=
boxSize
[
1
];
periodicBoxSize
[
2
]
=
boxSize
[
2
];
}
void
CpuCustomGBForce
::
calculateIxn
(
int
numberOfAtoms
,
vector
<
RealVec
>&
atomCoordinates
,
RealOpenMM
**
atomParameters
,
const
vector
<
set
<
int
>
>&
exclusions
,
map
<
string
,
double
>&
globalParameters
,
vector
<
RealVec
>&
forces
,
RealOpenMM
*
totalEnergy
)
{
for
(
map
<
string
,
double
>::
const_iterator
iter
=
globalParameters
.
begin
();
iter
!=
globalParameters
.
end
();
++
iter
)
expressionSet
.
setVariable
(
expressionSet
.
getVariableIndex
(
iter
->
first
),
iter
->
second
);
// First calculate the computed values.
int
numValues
=
valueTypes
.
size
();
vector
<
vector
<
RealOpenMM
>
>
values
(
numValues
);
for
(
int
valueIndex
=
0
;
valueIndex
<
numValues
;
valueIndex
++
)
{
if
(
valueTypes
[
valueIndex
]
==
OpenMM
::
CustomGBForce
::
SingleParticle
)
calculateSingleParticleValue
(
valueIndex
,
numberOfAtoms
,
atomCoordinates
,
values
,
globalParameters
,
atomParameters
);
else
if
(
valueTypes
[
valueIndex
]
==
OpenMM
::
CustomGBForce
::
ParticlePair
)
calculateParticlePairValue
(
valueIndex
,
numberOfAtoms
,
atomCoordinates
,
atomParameters
,
values
,
globalParameters
,
exclusions
,
true
);
else
calculateParticlePairValue
(
valueIndex
,
numberOfAtoms
,
atomCoordinates
,
atomParameters
,
values
,
globalParameters
,
exclusions
,
false
);
}
// Now calculate the energy and its derivatives.
vector
<
vector
<
RealOpenMM
>
>
dEdV
(
numValues
,
vector
<
RealOpenMM
>
(
numberOfAtoms
,
(
RealOpenMM
)
0
));
for
(
int
termIndex
=
0
;
termIndex
<
(
int
)
energyExpressions
.
size
();
termIndex
++
)
{
if
(
energyTypes
[
termIndex
]
==
OpenMM
::
CustomGBForce
::
SingleParticle
)
calculateSingleParticleEnergyTerm
(
termIndex
,
numberOfAtoms
,
atomCoordinates
,
values
,
globalParameters
,
atomParameters
,
forces
,
totalEnergy
,
dEdV
);
else
if
(
energyTypes
[
termIndex
]
==
OpenMM
::
CustomGBForce
::
ParticlePair
)
calculateParticlePairEnergyTerm
(
termIndex
,
numberOfAtoms
,
atomCoordinates
,
atomParameters
,
values
,
globalParameters
,
exclusions
,
true
,
forces
,
totalEnergy
,
dEdV
);
else
calculateParticlePairEnergyTerm
(
termIndex
,
numberOfAtoms
,
atomCoordinates
,
atomParameters
,
values
,
globalParameters
,
exclusions
,
false
,
forces
,
totalEnergy
,
dEdV
);
}
// Apply the chain rule to evaluate forces.
calculateChainRuleForces
(
numberOfAtoms
,
atomCoordinates
,
atomParameters
,
values
,
globalParameters
,
exclusions
,
forces
,
dEdV
);
}
void
CpuCustomGBForce
::
calculateSingleParticleValue
(
int
index
,
int
numAtoms
,
vector
<
RealVec
>&
atomCoordinates
,
vector
<
vector
<
RealOpenMM
>
>&
values
,
const
map
<
string
,
double
>&
globalParameters
,
RealOpenMM
**
atomParameters
)
{
values
[
index
].
resize
(
numAtoms
);
for
(
int
i
=
0
;
i
<
numAtoms
;
i
++
)
{
expressionSet
.
setVariable
(
xindex
,
atomCoordinates
[
i
][
0
]);
expressionSet
.
setVariable
(
yindex
,
atomCoordinates
[
i
][
1
]);
expressionSet
.
setVariable
(
zindex
,
atomCoordinates
[
i
][
2
]);
for
(
int
j
=
0
;
j
<
(
int
)
paramNames
.
size
();
j
++
)
expressionSet
.
setVariable
(
paramIndex
[
j
],
atomParameters
[
i
][
j
]);
for
(
int
j
=
0
;
j
<
index
;
j
++
)
expressionSet
.
setVariable
(
valueIndex
[
j
],
values
[
j
][
i
]);
values
[
index
][
i
]
=
(
RealOpenMM
)
valueExpressions
[
index
].
evaluate
();
}
}
void
CpuCustomGBForce
::
calculateParticlePairValue
(
int
index
,
int
numAtoms
,
vector
<
RealVec
>&
atomCoordinates
,
RealOpenMM
**
atomParameters
,
vector
<
vector
<
RealOpenMM
>
>&
values
,
const
map
<
string
,
double
>&
globalParameters
,
const
vector
<
set
<
int
>
>&
exclusions
,
bool
useExclusions
)
{
values
[
index
].
resize
(
numAtoms
);
for
(
int
i
=
0
;
i
<
numAtoms
;
i
++
)
values
[
index
][
i
]
=
(
RealOpenMM
)
0.0
;
if
(
cutoff
)
{
// Loop over all pairs in the neighbor list.
for
(
int
i
=
0
;
i
<
(
int
)
neighborList
->
size
();
i
++
)
{
OpenMM
::
AtomPair
pair
=
(
*
neighborList
)[
i
];
if
(
useExclusions
&&
exclusions
[
pair
.
first
].
find
(
pair
.
second
)
!=
exclusions
[
pair
.
first
].
end
())
continue
;
calculateOnePairValue
(
index
,
pair
.
first
,
pair
.
second
,
atomCoordinates
,
atomParameters
,
globalParameters
,
values
);
calculateOnePairValue
(
index
,
pair
.
second
,
pair
.
first
,
atomCoordinates
,
atomParameters
,
globalParameters
,
values
);
}
}
else
{
// Perform an O(N^2) loop over all atom pairs.
for
(
int
i
=
0
;
i
<
numAtoms
;
i
++
)
{
for
(
int
j
=
i
+
1
;
j
<
numAtoms
;
j
++
)
{
if
(
useExclusions
&&
exclusions
[
i
].
find
(
j
)
!=
exclusions
[
i
].
end
())
continue
;
calculateOnePairValue
(
index
,
i
,
j
,
atomCoordinates
,
atomParameters
,
globalParameters
,
values
);
calculateOnePairValue
(
index
,
j
,
i
,
atomCoordinates
,
atomParameters
,
globalParameters
,
values
);
}
}
}
}
void
CpuCustomGBForce
::
calculateOnePairValue
(
int
index
,
int
atom1
,
int
atom2
,
vector
<
RealVec
>&
atomCoordinates
,
RealOpenMM
**
atomParameters
,
const
map
<
string
,
double
>&
globalParameters
,
vector
<
vector
<
RealOpenMM
>
>&
values
)
{
RealOpenMM
deltaR
[
ReferenceForce
::
LastDeltaRIndex
];
if
(
periodic
)
ReferenceForce
::
getDeltaRPeriodic
(
atomCoordinates
[
atom2
],
atomCoordinates
[
atom1
],
periodicBoxSize
,
deltaR
);
else
ReferenceForce
::
getDeltaR
(
atomCoordinates
[
atom2
],
atomCoordinates
[
atom1
],
deltaR
);
RealOpenMM
r
=
deltaR
[
ReferenceForce
::
RIndex
];
if
(
cutoff
&&
r
>=
cutoffDistance
)
return
;
for
(
int
i
=
0
;
i
<
(
int
)
paramNames
.
size
();
i
++
)
{
expressionSet
.
setVariable
(
particleParamIndex
[
i
*
2
],
atomParameters
[
atom1
][
i
]);
expressionSet
.
setVariable
(
particleParamIndex
[
i
*
2
+
1
],
atomParameters
[
atom2
][
i
]);
}
expressionSet
.
setVariable
(
rindex
,
r
);
for
(
int
i
=
0
;
i
<
index
;
i
++
)
{
expressionSet
.
setVariable
(
particleValueIndex
[
i
*
2
],
values
[
i
][
atom1
]);
expressionSet
.
setVariable
(
particleValueIndex
[
i
*
2
+
1
],
values
[
i
][
atom2
]);
}
values
[
index
][
atom1
]
+=
(
RealOpenMM
)
valueExpressions
[
index
].
evaluate
();
}
void
CpuCustomGBForce
::
calculateSingleParticleEnergyTerm
(
int
index
,
int
numAtoms
,
vector
<
RealVec
>&
atomCoordinates
,
const
vector
<
vector
<
RealOpenMM
>
>&
values
,
const
map
<
string
,
double
>&
globalParameters
,
RealOpenMM
**
atomParameters
,
vector
<
RealVec
>&
forces
,
RealOpenMM
*
totalEnergy
,
vector
<
vector
<
RealOpenMM
>
>&
dEdV
)
{
for
(
int
i
=
0
;
i
<
numAtoms
;
i
++
)
{
expressionSet
.
setVariable
(
xindex
,
atomCoordinates
[
i
][
0
]);
expressionSet
.
setVariable
(
yindex
,
atomCoordinates
[
i
][
1
]);
expressionSet
.
setVariable
(
zindex
,
atomCoordinates
[
i
][
2
]);
for
(
int
j
=
0
;
j
<
(
int
)
paramNames
.
size
();
j
++
)
expressionSet
.
setVariable
(
paramIndex
[
j
],
atomParameters
[
i
][
j
]);
for
(
int
j
=
0
;
j
<
(
int
)
valueNames
.
size
();
j
++
)
expressionSet
.
setVariable
(
valueIndex
[
j
],
values
[
j
][
i
]);
if
(
totalEnergy
!=
NULL
)
*
totalEnergy
+=
(
RealOpenMM
)
energyExpressions
[
index
].
evaluate
();
for
(
int
j
=
0
;
j
<
(
int
)
valueNames
.
size
();
j
++
)
dEdV
[
j
][
i
]
+=
(
RealOpenMM
)
energyDerivExpressions
[
index
][
j
].
evaluate
();
forces
[
i
][
0
]
-=
(
RealOpenMM
)
energyGradientExpressions
[
index
][
0
].
evaluate
();
forces
[
i
][
1
]
-=
(
RealOpenMM
)
energyGradientExpressions
[
index
][
1
].
evaluate
();
forces
[
i
][
2
]
-=
(
RealOpenMM
)
energyGradientExpressions
[
index
][
2
].
evaluate
();
}
}
void
CpuCustomGBForce
::
calculateParticlePairEnergyTerm
(
int
index
,
int
numAtoms
,
vector
<
RealVec
>&
atomCoordinates
,
RealOpenMM
**
atomParameters
,
const
vector
<
vector
<
RealOpenMM
>
>&
values
,
const
map
<
string
,
double
>&
globalParameters
,
const
vector
<
set
<
int
>
>&
exclusions
,
bool
useExclusions
,
vector
<
RealVec
>&
forces
,
RealOpenMM
*
totalEnergy
,
vector
<
vector
<
RealOpenMM
>
>&
dEdV
)
{
if
(
cutoff
)
{
// Loop over all pairs in the neighbor list.
for
(
int
i
=
0
;
i
<
(
int
)
neighborList
->
size
();
i
++
)
{
OpenMM
::
AtomPair
pair
=
(
*
neighborList
)[
i
];
if
(
useExclusions
&&
exclusions
[
pair
.
first
].
find
(
pair
.
second
)
!=
exclusions
[
pair
.
first
].
end
())
continue
;
calculateOnePairEnergyTerm
(
index
,
pair
.
first
,
pair
.
second
,
atomCoordinates
,
atomParameters
,
globalParameters
,
values
,
forces
,
totalEnergy
,
dEdV
);
}
}
else
{
// Perform an O(N^2) loop over all atom pairs.
for
(
int
i
=
0
;
i
<
numAtoms
;
i
++
)
{
for
(
int
j
=
i
+
1
;
j
<
numAtoms
;
j
++
)
{
if
(
useExclusions
&&
exclusions
[
i
].
find
(
j
)
!=
exclusions
[
i
].
end
())
continue
;
calculateOnePairEnergyTerm
(
index
,
i
,
j
,
atomCoordinates
,
atomParameters
,
globalParameters
,
values
,
forces
,
totalEnergy
,
dEdV
);
}
}
}
}
void
CpuCustomGBForce
::
calculateOnePairEnergyTerm
(
int
index
,
int
atom1
,
int
atom2
,
vector
<
RealVec
>&
atomCoordinates
,
RealOpenMM
**
atomParameters
,
const
map
<
string
,
double
>&
globalParameters
,
const
vector
<
vector
<
RealOpenMM
>
>&
values
,
vector
<
RealVec
>&
forces
,
RealOpenMM
*
totalEnergy
,
vector
<
vector
<
RealOpenMM
>
>&
dEdV
)
{
// Compute the displacement.
RealOpenMM
deltaR
[
ReferenceForce
::
LastDeltaRIndex
];
if
(
periodic
)
ReferenceForce
::
getDeltaRPeriodic
(
atomCoordinates
[
atom2
],
atomCoordinates
[
atom1
],
periodicBoxSize
,
deltaR
);
else
ReferenceForce
::
getDeltaR
(
atomCoordinates
[
atom2
],
atomCoordinates
[
atom1
],
deltaR
);
RealOpenMM
r
=
deltaR
[
ReferenceForce
::
RIndex
];
if
(
cutoff
&&
r
>=
cutoffDistance
)
return
;
// Record variables for evaluating expressions.
for
(
int
i
=
0
;
i
<
(
int
)
paramNames
.
size
();
i
++
)
{
expressionSet
.
setVariable
(
particleParamIndex
[
i
*
2
],
atomParameters
[
atom1
][
i
]);
expressionSet
.
setVariable
(
particleParamIndex
[
i
*
2
+
1
],
atomParameters
[
atom2
][
i
]);
}
expressionSet
.
setVariable
(
rindex
,
r
);
for
(
int
i
=
0
;
i
<
(
int
)
valueNames
.
size
();
i
++
)
{
expressionSet
.
setVariable
(
particleValueIndex
[
i
*
2
],
values
[
i
][
atom1
]);
expressionSet
.
setVariable
(
particleValueIndex
[
i
*
2
+
1
],
values
[
i
][
atom2
]);
}
// Evaluate the energy and its derivatives.
if
(
totalEnergy
!=
NULL
)
*
totalEnergy
+=
(
RealOpenMM
)
energyExpressions
[
index
].
evaluate
();
RealOpenMM
dEdR
=
(
RealOpenMM
)
energyDerivExpressions
[
index
][
0
].
evaluate
();
dEdR
*=
1
/
r
;
for
(
int
i
=
0
;
i
<
3
;
i
++
)
{
forces
[
atom1
][
i
]
-=
dEdR
*
deltaR
[
i
];
forces
[
atom2
][
i
]
+=
dEdR
*
deltaR
[
i
];
}
for
(
int
i
=
0
;
i
<
(
int
)
valueNames
.
size
();
i
++
)
{
dEdV
[
i
][
atom1
]
+=
(
RealOpenMM
)
energyDerivExpressions
[
index
][
2
*
i
+
1
].
evaluate
();
dEdV
[
i
][
atom2
]
+=
(
RealOpenMM
)
energyDerivExpressions
[
index
][
2
*
i
+
2
].
evaluate
();
}
}
void
CpuCustomGBForce
::
calculateChainRuleForces
(
int
numAtoms
,
vector
<
RealVec
>&
atomCoordinates
,
RealOpenMM
**
atomParameters
,
const
vector
<
vector
<
RealOpenMM
>
>&
values
,
const
map
<
string
,
double
>&
globalParameters
,
const
vector
<
set
<
int
>
>&
exclusions
,
vector
<
RealVec
>&
forces
,
vector
<
vector
<
RealOpenMM
>
>&
dEdV
)
{
if
(
cutoff
)
{
// Loop over all pairs in the neighbor list.
for
(
int
i
=
0
;
i
<
(
int
)
neighborList
->
size
();
i
++
)
{
OpenMM
::
AtomPair
pair
=
(
*
neighborList
)[
i
];
bool
isExcluded
=
(
exclusions
[
pair
.
first
].
find
(
pair
.
second
)
!=
exclusions
[
pair
.
first
].
end
());
calculateOnePairChainRule
(
pair
.
first
,
pair
.
second
,
atomCoordinates
,
atomParameters
,
globalParameters
,
values
,
forces
,
dEdV
,
isExcluded
);
calculateOnePairChainRule
(
pair
.
second
,
pair
.
first
,
atomCoordinates
,
atomParameters
,
globalParameters
,
values
,
forces
,
dEdV
,
isExcluded
);
}
}
else
{
// Perform an O(N^2) loop over all atom pairs.
for
(
int
i
=
0
;
i
<
numAtoms
;
i
++
)
{
for
(
int
j
=
i
+
1
;
j
<
numAtoms
;
j
++
)
{
bool
isExcluded
=
(
exclusions
[
i
].
find
(
j
)
!=
exclusions
[
i
].
end
());
calculateOnePairChainRule
(
i
,
j
,
atomCoordinates
,
atomParameters
,
globalParameters
,
values
,
forces
,
dEdV
,
isExcluded
);
calculateOnePairChainRule
(
j
,
i
,
atomCoordinates
,
atomParameters
,
globalParameters
,
values
,
forces
,
dEdV
,
isExcluded
);
}
}
}
// Compute chain rule terms for computed values that depend explicitly on particle coordinates.
for
(
int
i
=
0
;
i
<
numAtoms
;
i
++
)
{
expressionSet
.
setVariable
(
xindex
,
atomCoordinates
[
i
][
0
]);
expressionSet
.
setVariable
(
yindex
,
atomCoordinates
[
i
][
1
]);
expressionSet
.
setVariable
(
zindex
,
atomCoordinates
[
i
][
2
]);
vector
<
RealOpenMM
>
dVdX
(
valueDerivExpressions
.
size
(),
0.0
);
vector
<
RealOpenMM
>
dVdY
(
valueDerivExpressions
.
size
(),
0.0
);
vector
<
RealOpenMM
>
dVdZ
(
valueDerivExpressions
.
size
(),
0.0
);
for
(
int
j
=
0
;
j
<
(
int
)
paramNames
.
size
();
j
++
)
expressionSet
.
setVariable
(
paramIndex
[
j
],
atomParameters
[
i
][
j
]);
for
(
int
j
=
1
;
j
<
(
int
)
valueNames
.
size
();
j
++
)
{
expressionSet
.
setVariable
(
valueIndex
[
j
-
1
],
values
[
j
-
1
][
i
]);
for
(
int
k
=
1
;
k
<
j
;
k
++
)
{
RealOpenMM
dVdV
=
(
RealOpenMM
)
valueDerivExpressions
[
j
][
k
].
evaluate
();
dVdX
[
j
]
+=
dVdV
*
dVdX
[
k
];
dVdY
[
j
]
+=
dVdV
*
dVdY
[
k
];
dVdZ
[
j
]
+=
dVdV
*
dVdZ
[
k
];
}
dVdX
[
j
]
+=
(
RealOpenMM
)
valueGradientExpressions
[
j
][
0
].
evaluate
();
dVdY
[
j
]
+=
(
RealOpenMM
)
valueGradientExpressions
[
j
][
1
].
evaluate
();
dVdZ
[
j
]
+=
(
RealOpenMM
)
valueGradientExpressions
[
j
][
2
].
evaluate
();
forces
[
i
][
0
]
-=
dEdV
[
j
][
i
]
*
dVdX
[
j
];
forces
[
i
][
1
]
-=
dEdV
[
j
][
i
]
*
dVdY
[
j
];
forces
[
i
][
2
]
-=
dEdV
[
j
][
i
]
*
dVdZ
[
j
];
}
}
}
void
CpuCustomGBForce
::
calculateOnePairChainRule
(
int
atom1
,
int
atom2
,
vector
<
RealVec
>&
atomCoordinates
,
RealOpenMM
**
atomParameters
,
const
map
<
string
,
double
>&
globalParameters
,
const
vector
<
vector
<
RealOpenMM
>
>&
values
,
vector
<
RealVec
>&
forces
,
vector
<
vector
<
RealOpenMM
>
>&
dEdV
,
bool
isExcluded
)
{
// Compute the displacement.
RealOpenMM
deltaR
[
ReferenceForce
::
LastDeltaRIndex
];
if
(
periodic
)
ReferenceForce
::
getDeltaRPeriodic
(
atomCoordinates
[
atom2
],
atomCoordinates
[
atom1
],
periodicBoxSize
,
deltaR
);
else
ReferenceForce
::
getDeltaR
(
atomCoordinates
[
atom2
],
atomCoordinates
[
atom1
],
deltaR
);
RealOpenMM
r
=
deltaR
[
ReferenceForce
::
RIndex
];
if
(
cutoff
&&
r
>=
cutoffDistance
)
return
;
// Record variables for evaluating expressions.
for
(
int
i
=
0
;
i
<
(
int
)
paramNames
.
size
();
i
++
)
{
expressionSet
.
setVariable
(
particleParamIndex
[
i
*
2
],
atomParameters
[
atom1
][
i
]);
expressionSet
.
setVariable
(
particleParamIndex
[
i
*
2
+
1
],
atomParameters
[
atom2
][
i
]);
}
expressionSet
.
setVariable
(
rindex
,
r
);
expressionSet
.
setVariable
(
particleValueIndex
[
0
],
values
[
0
][
atom1
]);
expressionSet
.
setVariable
(
particleValueIndex
[
1
],
values
[
0
][
atom2
]);
// Evaluate the derivative of each parameter with respect to position and apply forces.
RealOpenMM
rinv
=
1
/
r
;
deltaR
[
0
]
*=
rinv
;
deltaR
[
1
]
*=
rinv
;
deltaR
[
2
]
*=
rinv
;
vector
<
RealOpenMM
>
dVdR1
(
valueDerivExpressions
.
size
(),
0.0
);
vector
<
RealOpenMM
>
dVdR2
(
valueDerivExpressions
.
size
(),
0.0
);
if
(
!
isExcluded
||
valueTypes
[
0
]
!=
OpenMM
::
CustomGBForce
::
ParticlePair
)
{
dVdR1
[
0
]
=
(
RealOpenMM
)
valueDerivExpressions
[
0
][
0
].
evaluate
();
dVdR2
[
0
]
=
-
dVdR1
[
0
];
for
(
int
i
=
0
;
i
<
3
;
i
++
)
{
forces
[
atom1
][
i
]
-=
dEdV
[
0
][
atom1
]
*
dVdR1
[
0
]
*
deltaR
[
i
];
forces
[
atom2
][
i
]
-=
dEdV
[
0
][
atom1
]
*
dVdR2
[
0
]
*
deltaR
[
i
];
}
}
for
(
int
i
=
0
;
i
<
(
int
)
paramNames
.
size
();
i
++
)
expressionSet
.
setVariable
(
paramIndex
[
i
],
atomParameters
[
atom1
][
i
]);
expressionSet
.
setVariable
(
valueIndex
[
0
],
values
[
0
][
atom1
]);
for
(
int
i
=
1
;
i
<
(
int
)
valueNames
.
size
();
i
++
)
{
expressionSet
.
setVariable
(
valueIndex
[
i
],
values
[
i
][
atom1
]);
expressionSet
.
setVariable
(
xindex
,
atomCoordinates
[
atom1
][
0
]);
expressionSet
.
setVariable
(
yindex
,
atomCoordinates
[
atom1
][
1
]);
expressionSet
.
setVariable
(
zindex
,
atomCoordinates
[
atom1
][
2
]);
for
(
int
j
=
0
;
j
<
i
;
j
++
)
{
RealOpenMM
dVdV
=
(
RealOpenMM
)
valueDerivExpressions
[
i
][
j
].
evaluate
();
dVdR1
[
i
]
+=
dVdV
*
dVdR1
[
j
];
dVdR2
[
i
]
+=
dVdV
*
dVdR2
[
j
];
}
for
(
int
k
=
0
;
k
<
3
;
k
++
)
{
forces
[
atom1
][
k
]
-=
dEdV
[
i
][
atom1
]
*
dVdR1
[
i
]
*
deltaR
[
k
];
forces
[
atom2
][
k
]
-=
dEdV
[
i
][
atom1
]
*
dVdR2
[
i
]
*
deltaR
[
k
];
}
}
}
platforms/cpu/src/CpuKernelFactory.cpp
View file @
468a8a5c
...
@@ -53,6 +53,8 @@ KernelImpl* CpuKernelFactory::createKernelImpl(std::string name, const Platform&
...
@@ -53,6 +53,8 @@ KernelImpl* CpuKernelFactory::createKernelImpl(std::string name, const Platform&
return
new
CpuCalcCustomManyParticleForceKernel
(
name
,
platform
,
data
);
return
new
CpuCalcCustomManyParticleForceKernel
(
name
,
platform
,
data
);
if
(
name
==
CalcGBSAOBCForceKernel
::
Name
())
if
(
name
==
CalcGBSAOBCForceKernel
::
Name
())
return
new
CpuCalcGBSAOBCForceKernel
(
name
,
platform
,
data
);
return
new
CpuCalcGBSAOBCForceKernel
(
name
,
platform
,
data
);
if
(
name
==
CalcCustomGBForceKernel
::
Name
())
return
new
CpuCalcCustomGBForceKernel
(
name
,
platform
,
data
);
if
(
name
==
IntegrateLangevinStepKernel
::
Name
())
if
(
name
==
IntegrateLangevinStepKernel
::
Name
())
return
new
CpuIntegrateLangevinStepKernel
(
name
,
platform
,
data
);
return
new
CpuIntegrateLangevinStepKernel
(
name
,
platform
,
data
);
throw
OpenMMException
((
std
::
string
(
"Tried to create kernel with illegal kernel name '"
)
+
name
+
"'"
).
c_str
());
throw
OpenMMException
((
std
::
string
(
"Tried to create kernel with illegal kernel name '"
)
+
name
+
"'"
).
c_str
());
...
...
platforms/cpu/src/CpuKernels.cpp
View file @
468a8a5c
...
@@ -835,6 +835,162 @@ void CpuCalcGBSAOBCForceKernel::copyParametersToContext(ContextImpl& context, co
...
@@ -835,6 +835,162 @@ void CpuCalcGBSAOBCForceKernel::copyParametersToContext(ContextImpl& context, co
obc
.
setParticleParameters
(
particleParams
);
obc
.
setParticleParameters
(
particleParams
);
}
}
CpuCalcCustomGBForceKernel
::~
CpuCalcCustomGBForceKernel
()
{
if
(
particleParamArray
!=
NULL
)
{
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
delete
[]
particleParamArray
[
i
];
delete
[]
particleParamArray
;
}
if
(
neighborList
!=
NULL
)
delete
neighborList
;
}
void
CpuCalcCustomGBForceKernel
::
initialize
(
const
System
&
system
,
const
CustomGBForce
&
force
)
{
if
(
force
.
getNumComputedValues
()
>
0
)
{
string
name
,
expression
;
CustomGBForce
::
ComputationType
type
;
force
.
getComputedValueParameters
(
0
,
name
,
expression
,
type
);
if
(
type
==
CustomGBForce
::
SingleParticle
)
throw
OpenMMException
(
"CpuPlatform requires that the first computed value for a CustomGBForce be of type ParticlePair or ParticlePairNoExclusions."
);
for
(
int
i
=
1
;
i
<
force
.
getNumComputedValues
();
i
++
)
{
force
.
getComputedValueParameters
(
i
,
name
,
expression
,
type
);
if
(
type
!=
CustomGBForce
::
SingleParticle
)
throw
OpenMMException
(
"CpuPlatform requires that a CustomGBForce only have one computed value of type ParticlePair or ParticlePairNoExclusions."
);
}
}
// Record the exclusions.
numParticles
=
force
.
getNumParticles
();
exclusions
.
resize
(
numParticles
);
for
(
int
i
=
0
;
i
<
force
.
getNumExclusions
();
i
++
)
{
int
particle1
,
particle2
;
force
.
getExclusionParticles
(
i
,
particle1
,
particle2
);
exclusions
[
particle1
].
insert
(
particle2
);
exclusions
[
particle2
].
insert
(
particle1
);
}
// Build the arrays.
int
numPerParticleParameters
=
force
.
getNumPerParticleParameters
();
particleParamArray
=
new
double
*
[
numParticles
];
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
particleParamArray
[
i
]
=
new
double
[
numPerParticleParameters
];
for
(
int
i
=
0
;
i
<
numParticles
;
++
i
)
{
vector
<
double
>
parameters
;
force
.
getParticleParameters
(
i
,
parameters
);
for
(
int
j
=
0
;
j
<
numPerParticleParameters
;
j
++
)
particleParamArray
[
i
][
j
]
=
static_cast
<
RealOpenMM
>
(
parameters
[
j
]);
}
for
(
int
i
=
0
;
i
<
numPerParticleParameters
;
i
++
)
particleParameterNames
.
push_back
(
force
.
getPerParticleParameterName
(
i
));
for
(
int
i
=
0
;
i
<
force
.
getNumGlobalParameters
();
i
++
)
globalParameterNames
.
push_back
(
force
.
getGlobalParameterName
(
i
));
nonbondedMethod
=
CalcCustomGBForceKernel
::
NonbondedMethod
(
force
.
getNonbondedMethod
());
nonbondedCutoff
=
(
RealOpenMM
)
force
.
getCutoffDistance
();
if
(
nonbondedMethod
==
NoCutoff
)
neighborList
=
NULL
;
else
neighborList
=
new
NeighborList
();
// Create custom functions for the tabulated functions.
map
<
string
,
Lepton
::
CustomFunction
*>
functions
;
for
(
int
i
=
0
;
i
<
force
.
getNumFunctions
();
i
++
)
functions
[
force
.
getTabulatedFunctionName
(
i
)]
=
createReferenceTabulatedFunction
(
force
.
getTabulatedFunction
(
i
));
// Parse the expressions for computed values.
valueDerivExpressions
.
resize
(
force
.
getNumComputedValues
());
valueGradientExpressions
.
resize
(
force
.
getNumComputedValues
());
for
(
int
i
=
0
;
i
<
force
.
getNumComputedValues
();
i
++
)
{
string
name
,
expression
;
CustomGBForce
::
ComputationType
type
;
force
.
getComputedValueParameters
(
i
,
name
,
expression
,
type
);
Lepton
::
ParsedExpression
ex
=
Lepton
::
Parser
::
parse
(
expression
,
functions
).
optimize
();
valueExpressions
.
push_back
(
ex
.
createCompiledExpression
());
valueTypes
.
push_back
(
type
);
valueNames
.
push_back
(
name
);
if
(
i
==
0
)
valueDerivExpressions
[
i
].
push_back
(
ex
.
differentiate
(
"r"
).
createCompiledExpression
());
else
{
valueGradientExpressions
[
i
].
push_back
(
ex
.
differentiate
(
"x"
).
createCompiledExpression
());
valueGradientExpressions
[
i
].
push_back
(
ex
.
differentiate
(
"y"
).
createCompiledExpression
());
valueGradientExpressions
[
i
].
push_back
(
ex
.
differentiate
(
"z"
).
createCompiledExpression
());
for
(
int
j
=
0
;
j
<
i
;
j
++
)
valueDerivExpressions
[
i
].
push_back
(
ex
.
differentiate
(
valueNames
[
j
]).
createCompiledExpression
());
}
}
// Parse the expressions for energy terms.
energyDerivExpressions
.
resize
(
force
.
getNumEnergyTerms
());
energyGradientExpressions
.
resize
(
force
.
getNumEnergyTerms
());
for
(
int
i
=
0
;
i
<
force
.
getNumEnergyTerms
();
i
++
)
{
string
expression
;
CustomGBForce
::
ComputationType
type
;
force
.
getEnergyTermParameters
(
i
,
expression
,
type
);
Lepton
::
ParsedExpression
ex
=
Lepton
::
Parser
::
parse
(
expression
,
functions
).
optimize
();
energyExpressions
.
push_back
(
ex
.
createCompiledExpression
());
energyTypes
.
push_back
(
type
);
if
(
type
!=
CustomGBForce
::
SingleParticle
)
energyDerivExpressions
[
i
].
push_back
(
ex
.
differentiate
(
"r"
).
createCompiledExpression
());
for
(
int
j
=
0
;
j
<
force
.
getNumComputedValues
();
j
++
)
{
if
(
type
==
CustomGBForce
::
SingleParticle
)
{
energyDerivExpressions
[
i
].
push_back
(
ex
.
differentiate
(
valueNames
[
j
]).
createCompiledExpression
());
energyGradientExpressions
[
i
].
push_back
(
ex
.
differentiate
(
"x"
).
createCompiledExpression
());
energyGradientExpressions
[
i
].
push_back
(
ex
.
differentiate
(
"y"
).
createCompiledExpression
());
energyGradientExpressions
[
i
].
push_back
(
ex
.
differentiate
(
"z"
).
createCompiledExpression
());
}
else
{
energyDerivExpressions
[
i
].
push_back
(
ex
.
differentiate
(
valueNames
[
j
]
+
"1"
).
createCompiledExpression
());
energyDerivExpressions
[
i
].
push_back
(
ex
.
differentiate
(
valueNames
[
j
]
+
"2"
).
createCompiledExpression
());
}
}
}
// Delete the custom functions.
for
(
map
<
string
,
Lepton
::
CustomFunction
*>::
iterator
iter
=
functions
.
begin
();
iter
!=
functions
.
end
();
iter
++
)
delete
iter
->
second
;
}
double
CpuCalcCustomGBForceKernel
::
execute
(
ContextImpl
&
context
,
bool
includeForces
,
bool
includeEnergy
)
{
vector
<
RealVec
>&
posData
=
extractPositions
(
context
);
vector
<
RealVec
>&
forceData
=
extractForces
(
context
);
RealOpenMM
energy
=
0
;
CpuCustomGBForce
ixn
(
valueExpressions
,
valueDerivExpressions
,
valueGradientExpressions
,
valueNames
,
valueTypes
,
energyExpressions
,
energyDerivExpressions
,
energyGradientExpressions
,
energyTypes
,
particleParameterNames
);
bool
periodic
=
(
nonbondedMethod
==
CutoffPeriodic
);
if
(
periodic
)
ixn
.
setPeriodic
(
extractBoxSize
(
context
));
if
(
nonbondedMethod
!=
NoCutoff
)
{
computeNeighborListVoxelHash
(
*
neighborList
,
numParticles
,
posData
,
exclusions
,
extractBoxSize
(
context
),
periodic
,
nonbondedCutoff
,
0.0
);
ixn
.
setUseCutoff
(
nonbondedCutoff
,
*
neighborList
);
}
map
<
string
,
double
>
globalParameters
;
for
(
int
i
=
0
;
i
<
(
int
)
globalParameterNames
.
size
();
i
++
)
globalParameters
[
globalParameterNames
[
i
]]
=
context
.
getParameter
(
globalParameterNames
[
i
]);
ixn
.
calculateIxn
(
numParticles
,
posData
,
particleParamArray
,
exclusions
,
globalParameters
,
forceData
,
includeEnergy
?
&
energy
:
NULL
);
return
energy
;
}
void
CpuCalcCustomGBForceKernel
::
copyParametersToContext
(
ContextImpl
&
context
,
const
CustomGBForce
&
force
)
{
if
(
numParticles
!=
force
.
getNumParticles
())
throw
OpenMMException
(
"updateParametersInContext: The number of particles has changed"
);
// Record the values.
int
numParameters
=
force
.
getNumPerParticleParameters
();
vector
<
double
>
params
;
for
(
int
i
=
0
;
i
<
numParticles
;
++
i
)
{
vector
<
double
>
parameters
;
force
.
getParticleParameters
(
i
,
parameters
);
for
(
int
j
=
0
;
j
<
numParameters
;
j
++
)
particleParamArray
[
i
][
j
]
=
static_cast
<
RealOpenMM
>
(
parameters
[
j
]);
}
}
CpuCalcCustomManyParticleForceKernel
::~
CpuCalcCustomManyParticleForceKernel
()
{
CpuCalcCustomManyParticleForceKernel
::~
CpuCalcCustomManyParticleForceKernel
()
{
if
(
particleParamArray
!=
NULL
)
{
if
(
particleParamArray
!=
NULL
)
{
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
...
...
platforms/cpu/src/CpuPlatform.cpp
View file @
468a8a5c
...
@@ -67,6 +67,7 @@ CpuPlatform::CpuPlatform() {
...
@@ -67,6 +67,7 @@ CpuPlatform::CpuPlatform() {
registerKernelFactory
(
CalcCustomNonbondedForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcCustomNonbondedForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcCustomManyParticleForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcCustomManyParticleForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcGBSAOBCForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcGBSAOBCForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcCustomGBForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
IntegrateLangevinStepKernel
::
Name
(),
factory
);
registerKernelFactory
(
IntegrateLangevinStepKernel
::
Name
(),
factory
);
platformProperties
.
push_back
(
CpuThreads
());
platformProperties
.
push_back
(
CpuThreads
());
int
threads
=
getNumProcessors
();
int
threads
=
getNumProcessors
();
...
...
platforms/cpu/tests/TestCpuCustomGBForce.cpp
0 → 100644
View file @
468a8a5c
/* -------------------------------------------------------------------------- *
* 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) 2008-2014 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. *
* -------------------------------------------------------------------------- */
/**
* This tests all the different force terms in the reference implementation of CustomGBForce.
*/
#include "openmm/internal/AssertionUtilities.h"
#include "sfmt/SFMT.h"
#include "openmm/Context.h"
#include "CpuPlatform.h"
#include "openmm/CustomGBForce.h"
#include "openmm/GBSAOBCForce.h"
#include "openmm/GBVIForce.h"
#include "openmm/OpenMMException.h"
#include "openmm/System.h"
#include "openmm/VerletIntegrator.h"
#include <iostream>
#include <vector>
#include <algorithm>
using
namespace
OpenMM
;
using
namespace
std
;
const
double
TOL
=
1e-5
;
void
testOBC
(
GBSAOBCForce
::
NonbondedMethod
obcMethod
,
CustomGBForce
::
NonbondedMethod
customMethod
)
{
const
int
numMolecules
=
70
;
const
int
numParticles
=
numMolecules
*
2
;
const
double
boxSize
=
10.0
;
const
double
cutoff
=
2.0
;
CpuPlatform
platform
;
// Create two systems: one with a GBSAOBCForce, and one using a CustomGBForce to implement the same interaction.
System
standardSystem
;
System
customSystem
;
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
{
standardSystem
.
addParticle
(
1.0
);
customSystem
.
addParticle
(
1.0
);
}
standardSystem
.
setDefaultPeriodicBoxVectors
(
Vec3
(
boxSize
,
0.0
,
0.0
),
Vec3
(
0.0
,
boxSize
,
0.0
),
Vec3
(
0.0
,
0.0
,
boxSize
));
customSystem
.
setDefaultPeriodicBoxVectors
(
Vec3
(
boxSize
,
0.0
,
0.0
),
Vec3
(
0.0
,
boxSize
,
0.0
),
Vec3
(
0.0
,
0.0
,
boxSize
));
GBSAOBCForce
*
obc
=
new
GBSAOBCForce
();
CustomGBForce
*
custom
=
new
CustomGBForce
();
obc
->
setCutoffDistance
(
cutoff
);
custom
->
setCutoffDistance
(
cutoff
);
custom
->
addPerParticleParameter
(
"q"
);
custom
->
addPerParticleParameter
(
"radius"
);
custom
->
addPerParticleParameter
(
"scale"
);
custom
->
addGlobalParameter
(
"solventDielectric"
,
obc
->
getSolventDielectric
());
custom
->
addGlobalParameter
(
"soluteDielectric"
,
obc
->
getSoluteDielectric
());
custom
->
addComputedValue
(
"I"
,
"step(r+sr2-or1)*0.5*(1/L-1/U+0.25*(1/U^2-1/L^2)*(r-sr2*sr2/r)+0.5*log(L/U)/r+C);"
"U=r+sr2;"
"C=2*(1/or1-1/L)*step(sr2-r-or1);"
"L=max(or1, D);"
"D=abs(r-sr2);"
"sr2 = scale2*or2;"
"or1 = radius1-0.009; or2 = radius2-0.009"
,
CustomGBForce
::
ParticlePairNoExclusions
);
custom
->
addComputedValue
(
"B"
,
"1/(1/or-tanh(1*psi-0.8*psi^2+4.85*psi^3)/radius);"
"psi=I*or; or=radius-0.009"
,
CustomGBForce
::
SingleParticle
);
custom
->
addEnergyTerm
(
"28.3919551*(radius+0.14)^2*(radius/B)^6-0.5*138.935485*(1/soluteDielectric-1/solventDielectric)*q^2/B"
,
CustomGBForce
::
SingleParticle
);
string
invCutoffString
=
""
;
if
(
obcMethod
!=
GBSAOBCForce
::
NoCutoff
)
{
stringstream
s
;
s
<<
(
1.0
/
cutoff
);
invCutoffString
=
s
.
str
();
}
custom
->
addEnergyTerm
(
"138.935485*(1/soluteDielectric-1/solventDielectric)*q1*q2*("
+
invCutoffString
+
"-1/f);"
"f=sqrt(r^2+B1*B2*exp(-r^2/(4*B1*B2)))"
,
CustomGBForce
::
ParticlePairNoExclusions
);
vector
<
Vec3
>
positions
(
numParticles
);
vector
<
Vec3
>
velocities
(
numParticles
);
OpenMM_SFMT
::
SFMT
sfmt
;
init_gen_rand
(
0
,
sfmt
);
vector
<
double
>
params
(
3
);
for
(
int
i
=
0
;
i
<
numMolecules
;
i
++
)
{
if
(
i
<
numMolecules
/
2
)
{
obc
->
addParticle
(
1.0
,
0.2
,
0.5
);
params
[
0
]
=
1.0
;
params
[
1
]
=
0.2
;
params
[
2
]
=
0.5
;
custom
->
addParticle
(
params
);
obc
->
addParticle
(
-
1.0
,
0.1
,
0.5
);
params
[
0
]
=
-
1.0
;
params
[
1
]
=
0.1
;
custom
->
addParticle
(
params
);
}
else
{
obc
->
addParticle
(
1.0
,
0.2
,
0.8
);
params
[
0
]
=
1.0
;
params
[
1
]
=
0.2
;
params
[
2
]
=
0.8
;
custom
->
addParticle
(
params
);
obc
->
addParticle
(
-
1.0
,
0.1
,
0.8
);
params
[
0
]
=
-
1.0
;
params
[
1
]
=
0.1
;
custom
->
addParticle
(
params
);
}
positions
[
2
*
i
]
=
Vec3
(
boxSize
*
genrand_real2
(
sfmt
),
boxSize
*
genrand_real2
(
sfmt
),
boxSize
*
genrand_real2
(
sfmt
));
positions
[
2
*
i
+
1
]
=
Vec3
(
positions
[
2
*
i
][
0
]
+
1.0
,
positions
[
2
*
i
][
1
],
positions
[
2
*
i
][
2
]);
velocities
[
2
*
i
]
=
Vec3
(
genrand_real2
(
sfmt
),
genrand_real2
(
sfmt
),
genrand_real2
(
sfmt
));
velocities
[
2
*
i
+
1
]
=
Vec3
(
genrand_real2
(
sfmt
),
genrand_real2
(
sfmt
),
genrand_real2
(
sfmt
));
}
obc
->
setNonbondedMethod
(
obcMethod
);
custom
->
setNonbondedMethod
(
customMethod
);
standardSystem
.
addForce
(
obc
);
customSystem
.
addForce
(
custom
);
VerletIntegrator
integrator1
(
0.01
);
VerletIntegrator
integrator2
(
0.01
);
Context
context1
(
standardSystem
,
integrator1
,
platform
);
context1
.
setPositions
(
positions
);
context1
.
setVelocities
(
velocities
);
State
state1
=
context1
.
getState
(
State
::
Forces
|
State
::
Energy
);
Context
context2
(
customSystem
,
integrator2
,
platform
);
context2
.
setPositions
(
positions
);
context2
.
setVelocities
(
velocities
);
State
state2
=
context2
.
getState
(
State
::
Forces
|
State
::
Energy
);
ASSERT_EQUAL_TOL
(
state1
.
getPotentialEnergy
(),
state2
.
getPotentialEnergy
(),
1e-4
);
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
{
ASSERT_EQUAL_VEC
(
state1
.
getForces
()[
i
],
state2
.
getForces
()[
i
],
1e-4
);
}
// Try changing the particle parameters and make sure it's still correct.
for
(
int
i
=
0
;
i
<
numMolecules
/
2
;
i
++
)
{
obc
->
setParticleParameters
(
2
*
i
,
1.1
,
0.3
,
0.6
);
params
[
0
]
=
1.1
;
params
[
1
]
=
0.3
;
params
[
2
]
=
0.6
;
custom
->
setParticleParameters
(
2
*
i
,
params
);
obc
->
setParticleParameters
(
2
*
i
+
1
,
-
1.1
,
0.2
,
0.4
);
params
[
0
]
=
-
1.1
;
params
[
1
]
=
0.2
;
params
[
2
]
=
0.4
;
custom
->
setParticleParameters
(
2
*
i
+
1
,
params
);
}
obc
->
updateParametersInContext
(
context1
);
custom
->
updateParametersInContext
(
context2
);
state1
=
context1
.
getState
(
State
::
Forces
|
State
::
Energy
);
state2
=
context2
.
getState
(
State
::
Forces
|
State
::
Energy
);
ASSERT_EQUAL_TOL
(
state1
.
getPotentialEnergy
(),
state2
.
getPotentialEnergy
(),
1e-4
);
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
{
ASSERT_EQUAL_VEC
(
state1
.
getForces
()[
i
],
state2
.
getForces
()[
i
],
1e-4
);
}
}
void
testMembrane
()
{
const
int
numMolecules
=
70
;
const
int
numParticles
=
numMolecules
*
2
;
const
double
boxSize
=
10.0
;
CpuPlatform
platform
;
// Create a system with an implicit membrane.
System
system
;
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
{
system
.
addParticle
(
1.0
);
}
system
.
setDefaultPeriodicBoxVectors
(
Vec3
(
boxSize
,
0.0
,
0.0
),
Vec3
(
0.0
,
boxSize
,
0.0
),
Vec3
(
0.0
,
0.0
,
boxSize
));
CustomGBForce
*
custom
=
new
CustomGBForce
();
custom
->
setCutoffDistance
(
2.0
);
custom
->
addPerParticleParameter
(
"q"
);
custom
->
addPerParticleParameter
(
"radius"
);
custom
->
addPerParticleParameter
(
"scale"
);
custom
->
addGlobalParameter
(
"thickness"
,
3
);
custom
->
addGlobalParameter
(
"solventDielectric"
,
78.3
);
custom
->
addGlobalParameter
(
"soluteDielectric"
,
1
);
custom
->
addComputedValue
(
"Imol"
,
"step(r+sr2-or1)*0.5*(1/L-1/U+0.25*(1/U^2-1/L^2)*(r-sr2*sr2/r)+0.5*log(L/U)/r+C);"
"U=r+sr2;"
"C=2*(1/or1-1/L)*step(sr2-r-or1);"
"L=max(or1, D);"
"D=abs(r-sr2);"
"sr2 = scale2*or2;"
"or1 = radius1-0.009; or2 = radius2-0.009"
,
CustomGBForce
::
ParticlePairNoExclusions
);
custom
->
addComputedValue
(
"Imem"
,
"(1/radius+2*log(2)/thickness)/(1+exp(7.2*(abs(z)+radius-0.5*thickness)))"
,
CustomGBForce
::
SingleParticle
);
custom
->
addComputedValue
(
"B"
,
"1/(1/or-tanh(1*psi-0.8*psi^2+4.85*psi^3)/radius);"
"psi=max(Imol,Imem)*or; or=radius-0.009"
,
CustomGBForce
::
SingleParticle
);
custom
->
addEnergyTerm
(
"28.3919551*(radius+0.14)^2*(radius/B)^6-0.5*138.935456*(1/soluteDielectric-1/solventDielectric)*q^2/B"
,
CustomGBForce
::
SingleParticle
);
custom
->
addEnergyTerm
(
"-138.935456*(1/soluteDielectric-1/solventDielectric)*q1*q2/f;"
"f=sqrt(r^2+B1*B2*exp(-r^2/(4*B1*B2)))"
,
CustomGBForce
::
ParticlePairNoExclusions
);
vector
<
Vec3
>
positions
(
numParticles
);
vector
<
Vec3
>
velocities
(
numParticles
);
OpenMM_SFMT
::
SFMT
sfmt
;
init_gen_rand
(
0
,
sfmt
);
vector
<
double
>
params
(
3
);
for
(
int
i
=
0
;
i
<
numMolecules
;
i
++
)
{
if
(
i
<
numMolecules
/
2
)
{
params
[
0
]
=
1.0
;
params
[
1
]
=
0.2
;
params
[
2
]
=
0.5
;
custom
->
addParticle
(
params
);
params
[
0
]
=
-
1.0
;
params
[
1
]
=
0.1
;
custom
->
addParticle
(
params
);
}
else
{
params
[
0
]
=
1.0
;
params
[
1
]
=
0.2
;
params
[
2
]
=
0.8
;
custom
->
addParticle
(
params
);
params
[
0
]
=
-
1.0
;
params
[
1
]
=
0.1
;
custom
->
addParticle
(
params
);
}
positions
[
2
*
i
]
=
Vec3
(
boxSize
*
genrand_real2
(
sfmt
),
boxSize
*
genrand_real2
(
sfmt
),
boxSize
*
genrand_real2
(
sfmt
));
positions
[
2
*
i
+
1
]
=
Vec3
(
positions
[
2
*
i
][
0
]
+
1.0
,
positions
[
2
*
i
][
1
],
positions
[
2
*
i
][
2
]);
velocities
[
2
*
i
]
=
Vec3
(
genrand_real2
(
sfmt
),
genrand_real2
(
sfmt
),
genrand_real2
(
sfmt
));
velocities
[
2
*
i
+
1
]
=
Vec3
(
genrand_real2
(
sfmt
),
genrand_real2
(
sfmt
),
genrand_real2
(
sfmt
));
}
system
.
addForce
(
custom
);
VerletIntegrator
integrator
(
0.01
);
Context
context
(
system
,
integrator
,
platform
);
context
.
setPositions
(
positions
);
context
.
setVelocities
(
velocities
);
State
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
const
vector
<
Vec3
>&
forces
=
state
.
getForces
();
// Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount.
double
norm
=
0.0
;
for
(
int
i
=
0
;
i
<
(
int
)
forces
.
size
();
++
i
)
norm
+=
forces
[
i
].
dot
(
forces
[
i
]);
norm
=
std
::
sqrt
(
norm
);
const
double
stepSize
=
1e-2
;
double
step
=
0.5
*
stepSize
/
norm
;
vector
<
Vec3
>
positions2
(
numParticles
),
positions3
(
numParticles
);
for
(
int
i
=
0
;
i
<
(
int
)
positions
.
size
();
++
i
)
{
Vec3
p
=
positions
[
i
];
Vec3
f
=
forces
[
i
];
positions2
[
i
]
=
Vec3
(
p
[
0
]
-
f
[
0
]
*
step
,
p
[
1
]
-
f
[
1
]
*
step
,
p
[
2
]
-
f
[
2
]
*
step
);
positions3
[
i
]
=
Vec3
(
p
[
0
]
+
f
[
0
]
*
step
,
p
[
1
]
+
f
[
1
]
*
step
,
p
[
2
]
+
f
[
2
]
*
step
);
}
context
.
setPositions
(
positions2
);
State
state2
=
context
.
getState
(
State
::
Energy
);
context
.
setPositions
(
positions3
);
State
state3
=
context
.
getState
(
State
::
Energy
);
ASSERT_EQUAL_TOL
(
norm
,
(
state2
.
getPotentialEnergy
()
-
state3
.
getPotentialEnergy
())
/
stepSize
,
1e-3
);
}
void
testTabulatedFunction
()
{
CpuPlatform
platform
;
System
system
;
system
.
addParticle
(
1.0
);
system
.
addParticle
(
1.0
);
VerletIntegrator
integrator
(
0.01
);
CustomGBForce
*
force
=
new
CustomGBForce
();
force
->
addComputedValue
(
"a"
,
"0"
,
CustomGBForce
::
ParticlePair
);
force
->
addEnergyTerm
(
"fn(r)+1"
,
CustomGBForce
::
ParticlePair
);
force
->
addParticle
(
vector
<
double
>
());
force
->
addParticle
(
vector
<
double
>
());
vector
<
double
>
table
;
for
(
int
i
=
0
;
i
<
21
;
i
++
)
table
.
push_back
(
std
::
sin
(
0.25
*
i
));
force
->
addTabulatedFunction
(
"fn"
,
new
Continuous1DFunction
(
table
,
1.0
,
6.0
));
system
.
addForce
(
force
);
Context
context
(
system
,
integrator
,
platform
);
vector
<
Vec3
>
positions
(
2
);
positions
[
0
]
=
Vec3
(
0
,
0
,
0
);
for
(
int
i
=
1
;
i
<
30
;
i
++
)
{
double
x
=
(
7.0
/
30.0
)
*
i
;
positions
[
1
]
=
Vec3
(
x
,
0
,
0
);
context
.
setPositions
(
positions
);
State
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
const
vector
<
Vec3
>&
forces
=
state
.
getForces
();
double
force
=
(
x
<
1.0
||
x
>
6.0
?
0.0
:
-
std
::
cos
(
x
-
1.0
));
double
energy
=
(
x
<
1.0
||
x
>
6.0
?
0.0
:
std
::
sin
(
x
-
1.0
))
+
1.0
;
ASSERT_EQUAL_VEC
(
Vec3
(
-
force
,
0
,
0
),
forces
[
0
],
0.1
);
ASSERT_EQUAL_VEC
(
Vec3
(
force
,
0
,
0
),
forces
[
1
],
0.1
);
ASSERT_EQUAL_TOL
(
energy
,
state
.
getPotentialEnergy
(),
0.02
);
}
}
void
testMultipleChainRules
()
{
CpuPlatform
platform
;
System
system
;
system
.
addParticle
(
1.0
);
system
.
addParticle
(
1.0
);
VerletIntegrator
integrator
(
0.01
);
CustomGBForce
*
force
=
new
CustomGBForce
();
force
->
addComputedValue
(
"a"
,
"2*r"
,
CustomGBForce
::
ParticlePair
);
force
->
addComputedValue
(
"b"
,
"a+1"
,
CustomGBForce
::
SingleParticle
);
force
->
addComputedValue
(
"c"
,
"2*b+a"
,
CustomGBForce
::
SingleParticle
);
force
->
addEnergyTerm
(
"0.1*a+1*b+10*c"
,
CustomGBForce
::
SingleParticle
);
// 0.1*(2*r) + 2*r+1 + 10*(3*a+2) = 0.2*r + 2*r+1 + 40*r+20+20*r = 62.2*r+21
force
->
addParticle
(
vector
<
double
>
());
force
->
addParticle
(
vector
<
double
>
());
system
.
addForce
(
force
);
Context
context
(
system
,
integrator
,
platform
);
vector
<
Vec3
>
positions
(
2
);
positions
[
0
]
=
Vec3
(
0
,
0
,
0
);
for
(
int
i
=
1
;
i
<
5
;
i
++
)
{
positions
[
1
]
=
Vec3
(
i
,
0
,
0
);
context
.
setPositions
(
positions
);
State
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
const
vector
<
Vec3
>&
forces
=
state
.
getForces
();
ASSERT_EQUAL_VEC
(
Vec3
(
124.4
,
0
,
0
),
forces
[
0
],
1e-4
);
ASSERT_EQUAL_VEC
(
Vec3
(
-
124.4
,
0
,
0
),
forces
[
1
],
1e-4
);
ASSERT_EQUAL_TOL
(
2
*
(
62.2
*
i
+
21
),
state
.
getPotentialEnergy
(),
0.02
);
}
}
void
testPositionDependence
()
{
CpuPlatform
platform
;
System
system
;
system
.
addParticle
(
1.0
);
system
.
addParticle
(
1.0
);
VerletIntegrator
integrator
(
0.01
);
CustomGBForce
*
force
=
new
CustomGBForce
();
force
->
addComputedValue
(
"a"
,
"r"
,
CustomGBForce
::
ParticlePair
);
force
->
addComputedValue
(
"b"
,
"a+x*y"
,
CustomGBForce
::
SingleParticle
);
force
->
addEnergyTerm
(
"b*z"
,
CustomGBForce
::
SingleParticle
);
force
->
addEnergyTerm
(
"b1+b2"
,
CustomGBForce
::
ParticlePair
);
// = 2*r+x1*y1+x2*y2
force
->
addParticle
(
vector
<
double
>
());
force
->
addParticle
(
vector
<
double
>
());
system
.
addForce
(
force
);
Context
context
(
system
,
integrator
,
platform
);
vector
<
Vec3
>
positions
(
2
);
vector
<
Vec3
>
forces
(
2
);
OpenMM_SFMT
::
SFMT
sfmt
;
init_gen_rand
(
0
,
sfmt
);
for
(
int
i
=
0
;
i
<
5
;
i
++
)
{
positions
[
0
]
=
Vec3
(
genrand_real2
(
sfmt
),
genrand_real2
(
sfmt
),
genrand_real2
(
sfmt
));
positions
[
1
]
=
Vec3
(
genrand_real2
(
sfmt
),
genrand_real2
(
sfmt
),
genrand_real2
(
sfmt
));
context
.
setPositions
(
positions
);
State
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
const
vector
<
Vec3
>&
forces
=
state
.
getForces
();
Vec3
delta
=
positions
[
0
]
-
positions
[
1
];
double
r
=
sqrt
(
delta
.
dot
(
delta
));
double
energy
=
2
*
r
+
positions
[
0
][
0
]
*
positions
[
0
][
1
]
+
positions
[
1
][
0
]
*
positions
[
1
][
1
];
for
(
int
j
=
0
;
j
<
2
;
j
++
)
energy
+=
positions
[
j
][
2
]
*
(
r
+
positions
[
j
][
0
]
*
positions
[
j
][
1
]);
Vec3
force1
(
-
(
1
+
positions
[
0
][
2
])
*
delta
[
0
]
/
r
-
(
1
+
positions
[
0
][
2
])
*
positions
[
0
][
1
]
-
(
1
+
positions
[
1
][
2
])
*
delta
[
0
]
/
r
,
-
(
1
+
positions
[
0
][
2
])
*
delta
[
1
]
/
r
-
(
1
+
positions
[
0
][
2
])
*
positions
[
0
][
0
]
-
(
1
+
positions
[
1
][
2
])
*
delta
[
1
]
/
r
,
-
(
1
+
positions
[
0
][
2
])
*
delta
[
2
]
/
r
-
(
r
+
positions
[
0
][
0
]
*
positions
[
0
][
1
])
-
(
1
+
positions
[
1
][
2
])
*
delta
[
2
]
/
r
);
Vec3
force2
((
1
+
positions
[
0
][
2
])
*
delta
[
0
]
/
r
+
(
1
+
positions
[
1
][
2
])
*
delta
[
0
]
/
r
-
(
1
+
positions
[
1
][
2
])
*
positions
[
1
][
1
],
(
1
+
positions
[
0
][
2
])
*
delta
[
1
]
/
r
+
(
1
+
positions
[
1
][
2
])
*
delta
[
1
]
/
r
-
(
1
+
positions
[
1
][
2
])
*
positions
[
1
][
0
],
(
1
+
positions
[
0
][
2
])
*
delta
[
2
]
/
r
+
(
1
+
positions
[
1
][
2
])
*
delta
[
2
]
/
r
-
(
r
+
positions
[
1
][
0
]
*
positions
[
1
][
1
]));
ASSERT_EQUAL_VEC
(
force1
,
forces
[
0
],
1e-4
);
ASSERT_EQUAL_VEC
(
force2
,
forces
[
1
],
1e-4
);
ASSERT_EQUAL_TOL
(
energy
,
state
.
getPotentialEnergy
(),
0.02
);
// Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount.
double
norm
=
0.0
;
for
(
int
i
=
0
;
i
<
(
int
)
forces
.
size
();
++
i
)
norm
+=
forces
[
i
].
dot
(
forces
[
i
]);
norm
=
std
::
sqrt
(
norm
);
const
double
stepSize
=
1e-3
;
double
step
=
0.5
*
stepSize
/
norm
;
vector
<
Vec3
>
positions2
(
2
),
positions3
(
2
);
for
(
int
i
=
0
;
i
<
(
int
)
positions
.
size
();
++
i
)
{
Vec3
p
=
positions
[
i
];
Vec3
f
=
forces
[
i
];
positions2
[
i
]
=
Vec3
(
p
[
0
]
-
f
[
0
]
*
step
,
p
[
1
]
-
f
[
1
]
*
step
,
p
[
2
]
-
f
[
2
]
*
step
);
positions3
[
i
]
=
Vec3
(
p
[
0
]
+
f
[
0
]
*
step
,
p
[
1
]
+
f
[
1
]
*
step
,
p
[
2
]
+
f
[
2
]
*
step
);
}
context
.
setPositions
(
positions2
);
State
state2
=
context
.
getState
(
State
::
Energy
);
context
.
setPositions
(
positions3
);
State
state3
=
context
.
getState
(
State
::
Energy
);
ASSERT_EQUAL_TOL
(
norm
,
(
state2
.
getPotentialEnergy
()
-
state3
.
getPotentialEnergy
())
/
stepSize
,
1e-3
);
}
}
void
testExclusions
()
{
CpuPlatform
platform
;
for
(
int
i
=
3
;
i
<
4
;
i
++
)
{
System
system
;
system
.
addParticle
(
1.0
);
system
.
addParticle
(
1.0
);
VerletIntegrator
integrator
(
0.01
);
CustomGBForce
*
force
=
new
CustomGBForce
();
force
->
addComputedValue
(
"a"
,
"r"
,
i
<
2
?
CustomGBForce
::
ParticlePair
:
CustomGBForce
::
ParticlePairNoExclusions
);
force
->
addEnergyTerm
(
"a"
,
CustomGBForce
::
SingleParticle
);
force
->
addEnergyTerm
(
"(1+a1+a2)*r"
,
i
%
2
==
0
?
CustomGBForce
::
ParticlePair
:
CustomGBForce
::
ParticlePairNoExclusions
);
force
->
addParticle
(
vector
<
double
>
());
force
->
addParticle
(
vector
<
double
>
());
force
->
addExclusion
(
0
,
1
);
system
.
addForce
(
force
);
Context
context
(
system
,
integrator
,
platform
);
vector
<
Vec3
>
positions
(
2
);
positions
[
0
]
=
Vec3
(
0
,
0
,
0
);
positions
[
1
]
=
Vec3
(
1
,
0
,
0
);
context
.
setPositions
(
positions
);
State
state
=
context
.
getState
(
State
::
Forces
|
State
::
Energy
);
const
vector
<
Vec3
>&
forces
=
state
.
getForces
();
double
f
,
energy
;
switch
(
i
)
{
case
0
:
// e = 0
f
=
0
;
energy
=
0
;
break
;
case
1
:
// e = r
f
=
1
;
energy
=
1
;
break
;
case
2
:
// e = 2r
f
=
2
;
energy
=
2
;
break
;
case
3
:
// e = 3r + 2r^2
f
=
7
;
energy
=
5
;
break
;
default:
ASSERT
(
false
);
}
ASSERT_EQUAL_VEC
(
Vec3
(
f
,
0
,
0
),
forces
[
0
],
1e-4
);
ASSERT_EQUAL_VEC
(
Vec3
(
-
f
,
0
,
0
),
forces
[
1
],
1e-4
);
ASSERT_EQUAL_TOL
(
energy
,
state
.
getPotentialEnergy
(),
1e-4
);
// Take a small step in the direction of the energy gradient and see whether the potential energy changes by the expected amount.
double
norm
=
0.0
;
for
(
int
i
=
0
;
i
<
(
int
)
forces
.
size
();
++
i
)
norm
+=
forces
[
i
].
dot
(
forces
[
i
]);
norm
=
std
::
sqrt
(
norm
);
const
double
stepSize
=
1e-3
;
double
step
=
stepSize
/
norm
;
for
(
int
i
=
0
;
i
<
(
int
)
positions
.
size
();
++
i
)
{
Vec3
p
=
positions
[
i
];
Vec3
f
=
forces
[
i
];
positions
[
i
]
=
Vec3
(
p
[
0
]
-
f
[
0
]
*
step
,
p
[
1
]
-
f
[
1
]
*
step
,
p
[
2
]
-
f
[
2
]
*
step
);
}
context
.
setPositions
(
positions
);
State
state2
=
context
.
getState
(
State
::
Energy
);
ASSERT_EQUAL_TOL
(
norm
,
(
state2
.
getPotentialEnergy
()
-
state
.
getPotentialEnergy
())
/
stepSize
,
1e-3
*
abs
(
state
.
getPotentialEnergy
()));
}
}
int
main
()
{
try
{
testOBC
(
GBSAOBCForce
::
NoCutoff
,
CustomGBForce
::
NoCutoff
);
testOBC
(
GBSAOBCForce
::
CutoffNonPeriodic
,
CustomGBForce
::
CutoffNonPeriodic
);
testOBC
(
GBSAOBCForce
::
CutoffPeriodic
,
CustomGBForce
::
CutoffPeriodic
);
testMembrane
();
testTabulatedFunction
();
testMultipleChainRules
();
testPositionDependence
();
testExclusions
();
}
catch
(
const
exception
&
e
)
{
cout
<<
"exception: "
<<
e
.
what
()
<<
endl
;
return
1
;
}
cout
<<
"Done"
<<
endl
;
return
0
;
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment