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
604881dc
Commit
604881dc
authored
Sep 05, 2014
by
peastman
Browse files
Merge pull request #604 from peastman/many
Created CustomManyParticleForce
parents
f2eb95d0
1515e2bc
Changes
50
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
2672 additions
and
300 deletions
+2672
-300
docs-source/usersguide/application.rst
docs-source/usersguide/application.rst
+55
-0
docs-source/usersguide/theory.rst
docs-source/usersguide/theory.rst
+48
-0
olla/include/openmm/kernels.h
olla/include/openmm/kernels.h
+41
-0
openmmapi/include/OpenMM.h
openmmapi/include/OpenMM.h
+1
-0
openmmapi/include/openmm/CustomManyParticleForce.h
openmmapi/include/openmm/CustomManyParticleForce.h
+558
-0
openmmapi/include/openmm/internal/CustomManyParticleForceImpl.h
...api/include/openmm/internal/CustomManyParticleForceImpl.h
+109
-0
openmmapi/include/openmm/internal/vectorize_neon.h
openmmapi/include/openmm/internal/vectorize_neon.h
+6
-0
openmmapi/include/openmm/internal/vectorize_pnacl.h
openmmapi/include/openmm/internal/vectorize_pnacl.h
+6
-0
openmmapi/include/openmm/internal/vectorize_sse.h
openmmapi/include/openmm/internal/vectorize_sse.h
+305
-299
openmmapi/src/CustomManyParticleForce.cpp
openmmapi/src/CustomManyParticleForce.cpp
+224
-0
openmmapi/src/CustomManyParticleForceImpl.cpp
openmmapi/src/CustomManyParticleForceImpl.cpp
+333
-0
platforms/cpu/include/CompiledExpressionSet.h
platforms/cpu/include/CompiledExpressionSet.h
+71
-0
platforms/cpu/include/CpuCustomManyParticleForce.h
platforms/cpu/include/CpuCustomManyParticleForce.h
+223
-0
platforms/cpu/include/CpuKernels.h
platforms/cpu/include/CpuKernels.h
+43
-0
platforms/cpu/src/CompiledExpressionSet.cpp
platforms/cpu/src/CompiledExpressionSet.cpp
+56
-0
platforms/cpu/src/CpuCustomManyParticleForce.cpp
platforms/cpu/src/CpuCustomManyParticleForce.cpp
+521
-0
platforms/cpu/src/CpuKernelFactory.cpp
platforms/cpu/src/CpuKernelFactory.cpp
+2
-0
platforms/cpu/src/CpuKernels.cpp
platforms/cpu/src/CpuKernels.cpp
+66
-0
platforms/cpu/src/CpuPlatform.cpp
platforms/cpu/src/CpuPlatform.cpp
+1
-0
platforms/cpu/src/CpuSETTLE.cpp
platforms/cpu/src/CpuSETTLE.cpp
+3
-1
No files found.
docs-source/usersguide/application.rst
View file @
604881dc
...
@@ -2400,6 +2400,61 @@ must include an attribute called :code:`radius`\ .
...
@@ -2400,6 +2400,61 @@ must include an attribute called :code:`radius`\ .
CustomGBForce
also
allows
you
to
define
tabulated
functions
.
See
section
CustomGBForce
also
allows
you
to
define
tabulated
functions
.
See
section
:
ref
:`
tabulated
-
functions
`
for
details
.
:
ref
:`
tabulated
-
functions
`
for
details
.
<
CustomManyParticleForce
>
=========================
To
add
a
CustomManyParticleForce
to
the
System
,
include
a
tag
that
looks
like
this
:
..
code
-
block
::
xml
<
CustomManyParticleForce
particlesPerSet
=
"3"
permutationMode
=
"UniqueCentralParticle"
bondCutoff
=
"3"
energy
=
"scale*(distance(p1,p2)-r1)*(distance(p1,p3)-r1)"
>
<
GlobalParameter
name
=
"scale"
defaultValue
=
"1"
/>
<
PerParticleParameter
name
=
"r"
/>
<
TypeFilter
index
=
"0"
types
=
"1,2"
/>
<
Atom
type
=
"0"
r
=
"0.31"
filterType
=
"0"
/>
<
Atom
type
=
"1"
r
=
"0.25"
filterType
=
"0"
/>
<
Atom
type
=
"2"
r
=
"0.33"
filterType
=
"1"
/>
...
</
CustomManyParticleForce
>
The
energy
expression
for
the
CustomManyParticleForce
is
specified
by
the
:
code
:`
energy
`
attribute
.
This
is
a
mathematical
expression
that
gives
the
energy
of
each
pairwise
interaction
as
a
function
of
various
particle
coordinates
,
distances
,
and
angles
.
See
the
API
documentation
for
details
.
:
code
:`
particlesPerSet
`
specifies
the
number
of
particles
involved
in
the
interaction
and
:
code
:`
permutationMode
`
specifies
the
permutation
mode
.
The
expression
may
depend
on
an
arbitrary
list
of
global
or
per
-
atom
parameters
.
Use
a
:
code
:`<
GlobalParameter
>`
tag
to
define
a
global
parameter
,
and
a
:
code
:`<
PerAtomParameter
>`
tag
to
define
a
per
-
atom
parameter
.
Exclusions
are
created
automatically
based
on
the
:
code
:`
bondCutoff
`
attribute
.
After
setting
the
nonbonded
parameters
for
all
atoms
,
the
force
field
calls
:
code
:`
createExclusionsFromBonds
()`
on
the
CustomManyParticleForce
,
passing
in
this
value
as
its
argument
.
To
avoid
creating
exclusions
,
set
:
code
:`
bondCutoff
`
to
0.
Type
filters
may
be
specified
with
a
:
code
:`<
TypeFilter
>`
tag
.
The
:
code
:`
index
`
attribute
specifies
the
index
of
the
particle
to
apply
the
filter
to
,
and
:
code
:`
types
`
is
a
comma
separated
list
of
allowed
types
.
Each
:
code
:`<
Atom
>`
tag
specifies
the
parameters
for
one
atom
type
(
specified
with
the
:
code
:`
type
`
attribute
)
or
atom
class
(
specified
with
the
:
code
:`
class
`
attribute
).
It
is
fine
to
mix
these
two
methods
,
having
some
tags
specify
a
type
and
others
specify
a
class
.
However
you
do
it
,
you
must
make
sure
that
a
unique
set
of
parameters
is
defined
for
every
atom
type
.
In
addition
,
each
:
code
:`<
Atom
>`
tag
must
include
the
:
code
:`
filterType
`
attribute
,
which
specifies
the
atom
type
for
use
in
type
filters
.
The
remaining
attributes
are
the
values
to
use
for
the
per
-
atom
parameters
.
All
per
-
atom
parameters
must
be
specified
for
every
:
code
:`<
Atom
>`
tag
,
and
the
attribute
name
must
match
the
name
of
the
parameter
.
For
instance
,
if
there
is
a
per
-
atom
parameter
with
the
name
“
radius
”
,
then
every
:
code
:`<
Atom
>`
tag
must
include
an
attribute
called
:
code
:`
radius
`\
.
CustomManyParticleForce
also
allows
you
to
define
tabulated
functions
.
See
section
:
ref
:`
tabulated
-
functions
`
for
details
.
Writing
Custom
Expressions
Writing
Custom
Expressions
==========================
==========================
...
...
docs-source/usersguide/theory.rst
View file @
604881dc
...
@@ -828,6 +828,54 @@ Parameters may be specified in two ways:
...
@@ -828,6 +828,54 @@ Parameters may be specified in two ways:
* Per-bond parameters are defined by specifying a value for each bond.
* Per-bond parameters are defined by specifying a value for each bond.
CustomManyParticleForce
***********************
CustomManyParticleForce is similar to CustomNonbondedForce in that it represents
a custom nonbonded interaction between particles, but it allows the interaction
to depend on more than two particles. This allows it to represent a wide range
of non-pairwise interactions. It is defined by specifying the number of
particles :math:`N` involved in the interaction and how the energy depends on
their positions. More specifically, it takes a user specified energy function
.. math::
E=f(\{x_i\},\{r_i\},\{\theta_i\},\{\phi_i\})
that may depend on an arbitrary set of positions {\ :math:`x_i`\ }, distances
{\ :math:`r_i`\ }, angles {\ :math:`\theta_i`\ }, and dihedral angles
{\ :math:`\phi_i`\ } from a particular set of :math:`N` particles.
Each distance, angle, or dihedral is defined by specifying a sequence of
particles chosen from among the particles in the set. A distance
variable is defined by two particles, and equals the distance between them. An
angle variable is defined by three particles, and equals the angle between them.
A dihedral variable is defined by four particles, and equals the angle between
the first and last particles about the axis formed by the middle two particles.
It is equal to zero when the first and last particles are on the same side of
the axis.
In addition to depending on positions, distances, angles, and dihedrals, the
energy may also depend on an arbitrary set of user defined parameters.
Parameters may be specified in two ways:
* Global parameters have a single, fixed value.
* Per-particle parameters are defined by specifying a value for each particle.
The energy function is evaluated one or more times for every unique set of
:math:`N` particles in the system. The exact number of times depends on the
*permutation mode*\ . A set of :math:`N` particles has :math:`N!` possible
permutations. In :code:`SinglePermutation` mode, the function is evaluated
for a single arbitrarily chosen one of those permutations. In
:code:`UniqueCentralParticle` mode, the function is evaluated for :math:`N` of
those permutations, once with each particle as the "central particle".
The number of times the energy function is evaluated can be further restricted
by specifying *type filters*\ . Each particle may have a "type" assigned to it,
and then each of the :math:`N` particles involved in an interaction may be
restricted to only a specified set of types. This provides a great deal of
flexibility in controlling which particles interact with each other.
CustomGBForce
CustomGBForce
*************
*************
...
...
olla/include/openmm/kernels.h
View file @
604881dc
...
@@ -44,6 +44,7 @@
...
@@ -44,6 +44,7 @@
#include "openmm/CustomHbondForce.h"
#include "openmm/CustomHbondForce.h"
#include "openmm/CustomIntegrator.h"
#include "openmm/CustomIntegrator.h"
#include "openmm/CustomNonbondedForce.h"
#include "openmm/CustomNonbondedForce.h"
#include "openmm/CustomManyParticleForce.h"
#include "openmm/CustomTorsionForce.h"
#include "openmm/CustomTorsionForce.h"
#include "openmm/GBSAOBCForce.h"
#include "openmm/GBSAOBCForce.h"
#include "openmm/GBVIForce.h"
#include "openmm/GBVIForce.h"
...
@@ -826,6 +827,46 @@ public:
...
@@ -826,6 +827,46 @@ public:
virtual
void
copyParametersToContext
(
ContextImpl
&
context
,
const
CustomCompoundBondForce
&
force
)
=
0
;
virtual
void
copyParametersToContext
(
ContextImpl
&
context
,
const
CustomCompoundBondForce
&
force
)
=
0
;
};
};
/**
* This kernel is invoked by CustomManyParticleForce to calculate the forces acting on the system and the energy of the system.
*/
class
CalcCustomManyParticleForceKernel
:
public
KernelImpl
{
public:
enum
NonbondedMethod
{
NoCutoff
=
0
,
CutoffNonPeriodic
=
1
,
CutoffPeriodic
=
2
};
static
std
::
string
Name
()
{
return
"CalcCustomManyParticleForce"
;
}
CalcCustomManyParticleForceKernel
(
std
::
string
name
,
const
Platform
&
platform
)
:
KernelImpl
(
name
,
platform
)
{
}
/**
* Initialize the kernel.
*
* @param system the System this kernel will be applied to
* @param force the CustomManyParticleForce this kernel will be used for
*/
virtual
void
initialize
(
const
System
&
system
,
const
CustomManyParticleForce
&
force
)
=
0
;
/**
* 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
*/
virtual
double
execute
(
ContextImpl
&
context
,
bool
includeForces
,
bool
includeEnergy
)
=
0
;
/**
* Copy changed parameters over to a context.
*
* @param context the context to copy parameters to
* @param force the CustomManyParticleForce to copy the parameters from
*/
virtual
void
copyParametersToContext
(
ContextImpl
&
context
,
const
CustomManyParticleForce
&
force
)
=
0
;
};
/**
/**
* This kernel is invoked by VerletIntegrator to take one time step.
* This kernel is invoked by VerletIntegrator to take one time step.
*/
*/
...
...
openmmapi/include/OpenMM.h
View file @
604881dc
...
@@ -44,6 +44,7 @@
...
@@ -44,6 +44,7 @@
#include "openmm/CustomGBForce.h"
#include "openmm/CustomGBForce.h"
#include "openmm/CustomHbondForce.h"
#include "openmm/CustomHbondForce.h"
#include "openmm/CustomIntegrator.h"
#include "openmm/CustomIntegrator.h"
#include "openmm/CustomManyParticleForce.h"
#include "openmm/CustomNonbondedForce.h"
#include "openmm/CustomNonbondedForce.h"
#include "openmm/Force.h"
#include "openmm/Force.h"
#include "openmm/GBSAOBCForce.h"
#include "openmm/GBSAOBCForce.h"
...
...
openmmapi/include/openmm/CustomManyParticleForce.h
0 → 100644
View file @
604881dc
#ifndef OPENMM_CUSTOMTHREEBODYFORCE_H_
#define OPENMM_CUSTOMTHREEBODYFORCE_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) 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. *
* -------------------------------------------------------------------------- */
#include "Force.h"
#include "TabulatedFunction.h"
#include "internal/windowsExport.h"
#include <set>
#include <string>
#include <vector>
namespace
OpenMM
{
/**
* This class supports a wide variety of nonbonded N-particle interactions, where N is user specified. The
* interaction energy is determined by an arbitrary, user specified algebraic expression that is evaluated for
* every possible set of N particles in the system. It may depend on the positions of the individual particles,
* the distances between pairs of particles, the angles formed by sets of three particles, and the dihedral
* angles formed by sets of four particles.
*
* Be aware that the cost of evaluating an N-particle interaction increases very rapidly with N. Values larger
* than N=3 are rarely used.
*
* We refer to a set of particles for which the energy is being evaluated as p1, p2, p3, etc. The energy expression
* may depend on the following variables and functions:
*
* <ul>
* <li>x1, y1, z1, x2, y2, z2, etc.: The x, y, and z coordinates of the particle positions. For example, x1
* is the x coordinate of particle p1, and y3 is the y coordinate of particle p3.</li>
* <li>distance(p1, p2): the distance between particles p1 and p2 (where "p1" and "p2" may be replaced by the names
* of whichever particles you want to calculate the distance between).</li>
* <li>angle(p1, p2, p3): the angle formed by the three specified particles.</li>
* <li>dihedral(p1, p2, p3, p4): the dihedral angle formed by the four specified particles.</li>
* <li>arbitrary global and per-particle parameters that you define.</li>
* </ul>
*
* To use this class, create a CustomManyParticleForce object, passing an algebraic expression to the constructor
* that defines the interaction energy of each set of particles. Then call addPerParticleParameter() to define per-particle
* parameters, and addGlobalParameter() to define global parameters. The values of per-particle parameters are specified as
* part of the system definition, while values of global parameters may be modified during a simulation by calling Context::setParameter().
*
* Next, call addParticle() once for each particle in the System to set the values of its per-particle parameters.
* The number of particles for which you set parameters must be exactly equal to the number of particles in the
* System, or else an exception will be thrown when you try to create a Context. After a particle has been added,
* you can modify its parameters by calling setParticleParameters(). This will have no effect on Contexts that already exist
* unless you call updateParametersInContext().
*
* Multi-particle interactions can be very expensive to evaluate, so they are usually used with a cutoff distance. The exact
* interpretation of the cutoff depends on the permutation mode, as discussed below.
*
* CustomManyParticleForce also lets you specify "exclusions", particular pairs of particles whose interactions should be
* omitted from force and energy calculations. This is most often used for particles that are bonded to each other.
* If you specify a pair of particles as an exclusion, <i>all</i> sets that include those two particles will be omitted.
*
* As an example, the following code creates a CustomManyParticleForce that implements an Axilrod-Teller potential. This
* is an interaction between three particles that depends on all three distances and angles formed by the particles.
*
* <tt><pre>CustomManyParticleForce* force = new CustomManyParticleForce(3,
* "C*(1+3*cos(theta1)*cos(theta2)*cos(theta3))/(r12*r13*r23)^3;"
* "theta1=angle(p1,p2,p3); theta2=angle(p2,p3,p1); theta3=angle(p3,p1,p2);"
* "r12=distance(p1,p2); r13=distance(p1,p3); r23=distance(p2,p3)");
* force->setPermutationMode(CustomManyParticleForce::SinglePermutation);
* </pre></tt>
*
* This force depends on one parameter, C. The following code defines it as a global parameter:
*
* <tt><pre>
* force->addGlobalParameter("C", 1.0);
* </pre></tt>
*
* Notice that the expression is symmetric with respect to the particles. It only depends on the products
* cos(theta1)*cos(theta2)*cos(theta3) and r12*r13*r23, both of which are unchanged if the labels p1, p2, and p3 are permuted.
* This is required because we specified SinglePermutation as the permutation mode. (This is the default, so we did not
* really need to set it, but doing so makes the example clearer.) In this mode, the expression is only evaluated once for
* each set of particles. No guarantee is made about which particle will be identified as p1, p2, etc. Therefore, the
* energy <i>must</i> be symmetric with respect to exchange of particles. Otherwise, the results would be undefined because
* permuting the labels would change the energy.
*
* Not all many-particle interactions work this way. Another common pattern is for the expression to describe an interaction
* between one central particle and other nearby particles. An example of this is the 3-particle piece of the Stillinger-Weber
* potential:
*
* <tt><pre>CustomManyParticleForce* force = new CustomManyParticleForce(3,
* "L*eps*(cos(theta1)+1/3)^2*exp(sigma*gamma/(r12-a*sigma))*exp(sigma*gamma/(r13-a*sigma));"
"r12 = distance(p1,p2); r13 = distance(p1,p3); theta1 = angle(p3,p1,p2)");
* force->setPermutationMode(CustomManyParticleForce::UniqueCentralParticle);
* </pre></tt>
*
* When the permutation mode is set to UniqueCentralParticle, particle p1 is treated as the central particle. For a set of
* N particles, the expression is evaluated N times, once with each particle as p1. The expression can therefore treat
* p1 differently from the other particles. Notice that it is still symmetric with respect to p2 and p3, however. There
* is no guarantee about how those labels will be assigned to particles.
*
* Distance cutoffs are applied in different ways depending on the permutation mode. In SinglePermutation mode, every particle
* in the set must be within the cutoff distance of every other particle. If <i>any</i> two particles are further apart than
* the cutoff distance, the interaction is skipped. In UniqueCentralParticle mode, each particle must be within the cutoff
* distance of the central particle, but not necessarily of all the other particles. The cutoff may therefore exclude a subset
* of the permutations of a set of particles.
*
* Another common situation is that some particles are fundamentally different from others, causing the expression to be
* inherently non-symmetric. An example would be a water model that involves three particles, two of which <i>must</i> be
* hydrogen and one of which <i>must</i> be oxygen. Cases like this can be implemented using particle types.
*
* A particle type is an integer that you specify when you call addParticle(). (If you omit the argument, it defaults
* to 0.) For the water model, you could specify 0 for all oxygen atoms and 1 for all hydrogen atoms. You can then
* call setTypeFilter() to specify the list of allowed types for each of the N particles involved in an interaction:
*
* <tt><pre>
* set<int> oxygenTypes, hydrogenTypes;
* oxygenTypes.insert(0);
* hydrogenTypes.insert(1);
* force->setTypeFilter(0, oxygenTypes);
* force->setTypeFilter(1, hydrogenTypes);
* force->setTypeFilter(2, hydrogenTypes);
* </pre></tt>
*
* This specifies that of the three particles in an interaction, p1 must be oxygen while p2 and p3 must be hydrogen.
* The energy expression will only be evaluated for triplets of particles that satisfy those requirements. It will
* still only be evaluated once for each triplet, so it must still be symmetric with respect to p2 and p3.
*
* Expressions may involve the operators + (add), - (subtract), * (multiply), / (divide), and ^ (power), and the following
* functions: sqrt, exp, log, sin, cos, sec, csc, tan, cot, asin, acos, atan, sinh, cosh, tanh, erf, erfc, min, max, abs, step, delta. All trigonometric functions
* are defined in radians, and log is the natural logarithm. step(x) = 0 if x is less than 0, 1 otherwise. delta(x) = 1 if x is 0, 0 otherwise.
* The names of per-particle parameters have the suffix "1", "2", etc. appended to them to indicate the values for the multiple interacting particles.
* For example, if you define a per-particle parameter called "charge", then the variable "charge2" is the charge of particle p2.
* As seen above, the expression may also involve intermediate quantities that are defined following the main expression, using ";" as a separator.
*
* In addition, you can call addTabulatedFunction() to define a new function based on tabulated values. You specify the function by
* creating a TabulatedFunction object. That function can then appear in the expression.
*/
class
OPENMM_EXPORT
CustomManyParticleForce
:
public
Force
{
public:
/**
* This is an enumeration of the different methods that may be used for handling long range nonbonded forces.
*/
enum
NonbondedMethod
{
/**
* No cutoff is applied to nonbonded interactions. The full set of interactions is computed exactly.
* This necessarily means that periodic boundary conditions cannot be used. This is the default.
*/
NoCutoff
=
0
,
/**
* Interactions are ignored if any two particles are further apart than the cutoff distance.
*/
CutoffNonPeriodic
=
1
,
/**
* Periodic boundary conditions are used, so that each particle interacts only with the nearest periodic copy of
* each other particle. Interactions are ignored if any two particles are further apart than the cutoff distance.
*/
CutoffPeriodic
=
2
,
};
/**
* This is an enumeration of the different modes for selecting which permutations of a set of particles to evaluate the
* interaction for.
*/
enum
PermutationMode
{
/**
* For any set of particles, the interaction is evaluated only once for a single permutation of the particles.
* There is no guarantee about which permutation will be used (aside from the requirement to satisfy type filters),
* so the expression must be symmetric. If cutoffs are used, then every particle in the set must be within the
* cutoff distance of every other particle.
*/
SinglePermutation
=
0
,
/**
* The interaction is treated as an interaction between one central particle (p1) and various other nearby particles
* (p2, p3, ...). For a set of N particles it will be evaluated N times, once with each particle as p1. The expression
* must be symmetric with respect to the other particles, but may treat p1 differently. If cutoffs are used, then
* every particle must be within the cutoff distance of p1.
*/
UniqueCentralParticle
=
1
};
/**
* Create a CustomManyParticleForce.
*
* @param particlesPerSet the number of particles in each set for which the energy is evaluated
* @param energy an algebraic expression giving the interaction energy of each triplet as a function
* of particle positions, inter-particle distances, angles, and any global and per-particle parameters
*/
explicit
CustomManyParticleForce
(
int
particlesPerSet
,
const
std
::
string
&
energy
);
~
CustomManyParticleForce
();
/**
* Get the number of particles in each set for which the energy is evaluated
*/
int
getNumParticlesPerSet
()
const
{
return
particlesPerSet
;
}
/**
* Get the number of particles for which force field parameters have been defined.
*/
int
getNumParticles
()
const
{
return
particles
.
size
();
}
/**
* Get the number of particle pairs whose interactions should be excluded.
*/
int
getNumExclusions
()
const
{
return
exclusions
.
size
();
}
/**
* Get the number of per-particle parameters that the interaction depends on.
*/
int
getNumPerParticleParameters
()
const
{
return
particleParameters
.
size
();
}
/**
* Get the number of global parameters that the interaction depends on.
*/
int
getNumGlobalParameters
()
const
{
return
globalParameters
.
size
();
}
/**
* Get the number of tabulated functions that have been defined.
*/
int
getNumTabulatedFunctions
()
const
{
return
functions
.
size
();
}
/**
* Get the algebraic expression that gives the interaction energy of each bond
*/
const
std
::
string
&
getEnergyFunction
()
const
;
/**
* Set the algebraic expression that gives the interaction energy of each bond
*/
void
setEnergyFunction
(
const
std
::
string
&
energy
);
/**
* Get the method used for handling long range nonbonded interactions.
*/
NonbondedMethod
getNonbondedMethod
()
const
;
/**
* Set the method used for handling long range nonbonded interactions.
*/
void
setNonbondedMethod
(
NonbondedMethod
method
);
/**
* Get the mode that selects which permutations of a set of particles to evaluate the interaction for.
*/
PermutationMode
getPermutationMode
()
const
;
/**
* Set the mode that selects which permutations of a set of particles to evaluate the interaction for.
*/
void
setPermutationMode
(
PermutationMode
mode
);
/**
* Get the cutoff distance (in nm) being used for nonbonded interactions. If the NonbondedMethod in use
* is NoCutoff, this value will have no effect.
*
* @return the cutoff distance, measured in nm
*/
double
getCutoffDistance
()
const
;
/**
* Set the cutoff distance (in nm) being used for nonbonded interactions. If the NonbondedMethod in use
* is NoCutoff, this value will have no effect.
*
* @param distance the cutoff distance, measured in nm
*/
void
setCutoffDistance
(
double
distance
);
/**
* Add a new per-particle parameter that the interaction may depend on.
*
* @param name the name of the parameter
* @return the index of the parameter that was added
*/
int
addPerParticleParameter
(
const
std
::
string
&
name
);
/**
* Get the name of a per-particle parameter.
*
* @param index the index of the parameter for which to get the name
* @return the parameter name
*/
const
std
::
string
&
getPerParticleParameterName
(
int
index
)
const
;
/**
* Set the name of a per-particle parameter.
*
* @param index the index of the parameter for which to set the name
* @param name the name of the parameter
*/
void
setPerParticleParameterName
(
int
index
,
const
std
::
string
&
name
);
/**
* Add a new global parameter that the interaction may depend on.
*
* @param name the name of the parameter
* @param defaultValue the default value of the parameter
* @return the index of the parameter that was added
*/
int
addGlobalParameter
(
const
std
::
string
&
name
,
double
defaultValue
);
/**
* Get the name of a global parameter.
*
* @param index the index of the parameter for which to get the name
* @return the parameter name
*/
const
std
::
string
&
getGlobalParameterName
(
int
index
)
const
;
/**
* Set the name of a global parameter.
*
* @param index the index of the parameter for which to set the name
* @param name the name of the parameter
*/
void
setGlobalParameterName
(
int
index
,
const
std
::
string
&
name
);
/**
* Get the default value of a global parameter.
*
* @param index the index of the parameter for which to get the default value
* @return the parameter default value
*/
double
getGlobalParameterDefaultValue
(
int
index
)
const
;
/**
* Set the default value of a global parameter.
*
* @param index the index of the parameter for which to set the default value
* @param name the default value of the parameter
*/
void
setGlobalParameterDefaultValue
(
int
index
,
double
defaultValue
);
/**
* Add the nonbonded force parameters for a particle. This should be called once for each particle
* in the System. When it is called for the i'th time, it specifies the parameters for the i'th particle.
*
* @param parameters the list of parameters for the new particle
* @param type the type of the new particle
* @return the index of the particle that was added
*/
int
addParticle
(
const
std
::
vector
<
double
>&
parameters
,
int
type
=
0
);
/**
* Get the nonbonded force parameters for a particle.
*
* @param index the index of the particle for which to get parameters
* @param parameters the list of parameters for the specified particle
* @param type the type of the specified particle
*/
void
getParticleParameters
(
int
index
,
std
::
vector
<
double
>&
parameters
,
int
&
type
)
const
;
/**
* Set the nonbonded force parameters for a particle.
*
* @param index the index of the particle for which to set parameters
* @param parameters the list of parameters for the specified particle
* @param type the type of the specified particle
*/
void
setParticleParameters
(
int
index
,
const
std
::
vector
<
double
>&
parameters
,
int
type
);
/**
* Add a particle pair to the list of interactions that should be excluded.
*
* In many cases, you can use createExclusionsFromBonds() rather than adding each exclusion explicitly.
*
* @param particle1 the index of the first particle in the pair
* @param particle2 the index of the second particle in the pair
* @return the index of the exclusion that was added
*/
int
addExclusion
(
int
particle1
,
int
particle2
);
/**
* Get the particles in a pair whose interaction should be excluded.
*
* @param index the index of the exclusion for which to get particle indices
* @param particle1 the index of the first particle in the pair
* @param particle2 the index of the second particle in the pair
*/
void
getExclusionParticles
(
int
index
,
int
&
particle1
,
int
&
particle2
)
const
;
/**
* Set the particles in a pair whose interaction should be excluded.
*
* @param index the index of the exclusion for which to set particle indices
* @param particle1 the index of the first particle in the pair
* @param particle2 the index of the second particle in the pair
*/
void
setExclusionParticles
(
int
index
,
int
particle1
,
int
particle2
);
/**
* Identify exclusions based on the molecular topology. Particles which are separated by up to a specified number of
* bonds are added as exclusions.
*
* @param bonds the set of bonds based on which to construct exclusions. Each element specifies the indices of
* two particles that are bonded to each other.
* @param bondCutoff pairs of particles that are separated by this many bonds or fewer are added to the list of exclusions
*/
void
createExclusionsFromBonds
(
const
std
::
vector
<
std
::
pair
<
int
,
int
>
>&
bonds
,
int
bondCutoff
);
/**
* Get the allowed particle types for one of the particles involved in the interaction.
* If this an empty set (the default), no filter is applied and all interactions are evaluated
* regardless of the type of the specified particle.
*
* @param index the index of the particle within the interaction (between 0 and getNumParticlesPerSet())
* @param types the allowed types for the specified particle
*/
void
getTypeFilter
(
int
index
,
std
::
set
<
int
>&
types
)
const
;
/**
* Set the allowed particle types for one of the particles involved in the interaction.
* If this an empty set (the default), no filter is applied and all interactions are evaluated
* regardless of the type of the specified particle.
*
* @param index the index of the particle within the interaction (between 0 and getNumParticlesPerSet())
* @param types the allowed types for the specified particle
*/
void
setTypeFilter
(
int
index
,
const
std
::
set
<
int
>&
types
);
/**
* Add a tabulated function that may appear in the energy expression.
*
* @param name the name of the function as it appears in expressions
* @param function a TabulatedFunction object defining the function. The TabulatedFunction
* should have been created on the heap with the "new" operator. The
* Force takes over ownership of it, and deletes it when the Force itself is deleted.
* @return the index of the function that was added
*/
int
addTabulatedFunction
(
const
std
::
string
&
name
,
TabulatedFunction
*
function
);
/**
* Get a const reference to a tabulated function that may appear in the energy expression.
*
* @param index the index of the function to get
* @return the TabulatedFunction object defining the function
*/
const
TabulatedFunction
&
getTabulatedFunction
(
int
index
)
const
;
/**
* Get a reference to a tabulated function that may appear in the energy expression.
*
* @param index the index of the function to get
* @return the TabulatedFunction object defining the function
*/
TabulatedFunction
&
getTabulatedFunction
(
int
index
);
/**
* Get the name of a tabulated function that may appear in the energy expression.
*
* @param index the index of the function to get
* @return the name of the function as it appears in expressions
*/
const
std
::
string
&
getTabulatedFunctionName
(
int
index
)
const
;
/**
* Update the per-particle parameters in a Context to match those stored in this Force object. This method provides
* an efficient method to update certain parameters in an existing Context without needing to reinitialize it.
* Simply call setParticleParameters() to modify this object's parameters, then call updateParametersInContext()
* to copy them over to the Context.
*
* This method has several limitations. The only information it updates is the values of per-particle parameters.
* All other aspects of the Force (the energy function, nonbonded method, cutoff distance, etc.) are unaffected and can
* only be changed by reinitializing the Context. Also, this method cannot be used to add new particles, only to change
* the parameters of existing ones.
*/
void
updateParametersInContext
(
Context
&
context
);
protected:
ForceImpl
*
createImpl
()
const
;
private:
class
ParticleInfo
;
class
ParticleParameterInfo
;
class
GlobalParameterInfo
;
class
ExclusionInfo
;
class
FunctionInfo
;
int
particlesPerSet
;
NonbondedMethod
nonbondedMethod
;
PermutationMode
permutationMode
;
double
cutoffDistance
;
std
::
string
energyExpression
;
std
::
vector
<
ParticleParameterInfo
>
particleParameters
;
std
::
vector
<
GlobalParameterInfo
>
globalParameters
;
std
::
vector
<
ParticleInfo
>
particles
;
std
::
vector
<
ExclusionInfo
>
exclusions
;
std
::
vector
<
FunctionInfo
>
functions
;
std
::
vector
<
std
::
set
<
int
>
>
typeFilters
;
};
/**
* This is an internal class used to record information about a particle.
* @private
*/
class
CustomManyParticleForce
::
ParticleInfo
{
public:
std
::
vector
<
double
>
parameters
;
int
type
;
ParticleInfo
()
{
}
ParticleInfo
(
const
std
::
vector
<
double
>&
parameters
,
int
type
)
:
parameters
(
parameters
),
type
(
type
)
{
}
};
/**
* This is an internal class used to record information about a per-particle parameter.
* @private
*/
class
CustomManyParticleForce
::
ParticleParameterInfo
{
public:
std
::
string
name
;
ParticleParameterInfo
()
{
}
ParticleParameterInfo
(
const
std
::
string
&
name
)
:
name
(
name
)
{
}
};
/**
* This is an internal class used to record information about a global parameter.
* @private
*/
class
CustomManyParticleForce
::
GlobalParameterInfo
{
public:
std
::
string
name
;
double
defaultValue
;
GlobalParameterInfo
()
{
}
GlobalParameterInfo
(
const
std
::
string
&
name
,
double
defaultValue
)
:
name
(
name
),
defaultValue
(
defaultValue
)
{
}
};
/**
* This is an internal class used to record information about an exclusion.
* @private
*/
class
CustomManyParticleForce
::
ExclusionInfo
{
public:
int
particle1
,
particle2
;
ExclusionInfo
()
{
particle1
=
particle2
=
-
1
;
}
ExclusionInfo
(
int
particle1
,
int
particle2
)
:
particle1
(
particle1
),
particle2
(
particle2
)
{
}
};
/**
* This is an internal class used to record information about a tabulated function.
* @private
*/
class
CustomManyParticleForce
::
FunctionInfo
{
public:
std
::
string
name
;
TabulatedFunction
*
function
;
FunctionInfo
()
{
}
FunctionInfo
(
const
std
::
string
&
name
,
TabulatedFunction
*
function
)
:
name
(
name
),
function
(
function
)
{
}
};
}
// namespace OpenMM
#endif
/*OPENMM_CUSTOMTHREEBODYFORCE_H_*/
openmmapi/include/openmm/internal/CustomManyParticleForceImpl.h
0 → 100644
View file @
604881dc
#ifndef OPENMM_CUSTOMMANYPARTICLEFORCEIMPL_H_
#define OPENMM_CUSTOMMANYPARTICLEFORCEIMPL_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) 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. *
* -------------------------------------------------------------------------- */
#include "ForceImpl.h"
#include "openmm/CustomManyParticleForce.h"
#include "openmm/Kernel.h"
#include "lepton/CustomFunction.h"
#include "lepton/ExpressionTreeNode.h"
#include "lepton/ParsedExpression.h"
#include <utility>
#include <map>
#include <string>
namespace
OpenMM
{
/**
* This is the internal implementation of CustomManyParticleForce.
*/
class
OPENMM_EXPORT
CustomManyParticleForceImpl
:
public
ForceImpl
{
public:
CustomManyParticleForceImpl
(
const
CustomManyParticleForce
&
owner
);
~
CustomManyParticleForceImpl
();
void
initialize
(
ContextImpl
&
context
);
const
CustomManyParticleForce
&
getOwner
()
const
{
return
owner
;
}
void
updateContextState
(
ContextImpl
&
context
)
{
// This force field doesn't update the state directly.
}
double
calcForcesAndEnergy
(
ContextImpl
&
context
,
bool
includeForces
,
bool
includeEnergy
,
int
groups
);
std
::
map
<
std
::
string
,
double
>
getDefaultParameters
();
std
::
vector
<
std
::
string
>
getKernelNames
();
void
updateParametersInContext
(
ContextImpl
&
context
);
/**
* This is a utility routine that parses the energy expression, identifies the angles and dihedrals
* in it, and replaces them with variables.
*
* @param force the CustomManyParticleForce to process
* @param functions definitions of custom function that may appear in the expression
* @param distances on exit, this will contain an entry for each distance used in the expression. The key is the name
* of the corresponding variable, and the value is the list of particle indices.
* @param angles on exit, this will contain an entry for each angle used in the expression. The key is the name
* of the corresponding variable, and the value is the list of particle indices.
* @param dihedrals on exit, this will contain an entry for each dihedral used in the expression. The key is the name
* of the corresponding variable, and the value is the list of particle indices.
* @return a Parsed expression for the energy
*/
static
Lepton
::
ParsedExpression
prepareExpression
(
const
CustomManyParticleForce
&
force
,
const
std
::
map
<
std
::
string
,
Lepton
::
CustomFunction
*>&
functions
,
std
::
map
<
std
::
string
,
std
::
vector
<
int
>
>&
distances
,
std
::
map
<
std
::
string
,
std
::
vector
<
int
>
>&
angles
,
std
::
map
<
std
::
string
,
std
::
vector
<
int
>
>&
dihedrals
);
/**
* Analyze the type filters for a force and build a set of arrays that can be used for reordering the
* particles in an interaction.
*
* @param force the CustomManyParticleForce to process
* @param numTypes on exit, the number of unique particle types
* @param particleTypes on exit, this contains a type code for each particle. These codes are <i>not</i> necessarily the
* same as the types assigned by the force. They are guaranteed to be successive integers starting from 0,
* whereas the force may have used arbitrary integers.
* @param orderIndex on exit, this contains a lookup table for selecting the particle order for an interaction.
* orderIndex[t1+numTypes*t2+numTypes*numTypes*t3+...] is the index of the order to use, where t1, t2, etc. are the type codes
* of the particles involved in the interaction. If this equals -1, the interaction should be omitted.
* @param particleOrder on exit, particleOrder[i][j] tells which particle to use as the j'th particle, where i is the value found in orderIndex.
*/
static
void
buildFilterArrays
(
const
CustomManyParticleForce
&
force
,
int
&
numTypes
,
std
::
vector
<
int
>&
particleTypes
,
std
::
vector
<
int
>&
orderIndex
,
std
::
vector
<
std
::
vector
<
int
>
>&
particleOrder
);
private:
class
FunctionPlaceholder
;
static
Lepton
::
ExpressionTreeNode
replaceFunctions
(
const
Lepton
::
ExpressionTreeNode
&
node
,
std
::
map
<
std
::
string
,
int
>
atoms
,
std
::
map
<
std
::
string
,
std
::
vector
<
int
>
>&
distances
,
std
::
map
<
std
::
string
,
std
::
vector
<
int
>
>&
angles
,
std
::
map
<
std
::
string
,
std
::
vector
<
int
>
>&
dihedrals
);
static
void
generatePermutations
(
std
::
vector
<
int
>&
values
,
int
numFixed
,
std
::
vector
<
std
::
vector
<
int
>
>&
result
);
const
CustomManyParticleForce
&
owner
;
Kernel
kernel
;
};
}
// namespace OpenMM
#endif
/*OPENMM_CUSTOMMANYPARTICLEFORCEIMPL_H_*/
openmmapi/include/openmm/internal/vectorize_neon.h
View file @
604881dc
...
@@ -268,6 +268,12 @@ static inline float dot4(const fvec4& v1, const fvec4& v2) {
...
@@ -268,6 +268,12 @@ static inline float dot4(const fvec4& v1, const fvec4& v2) {
return
vgetq_lane_f32
(
result
,
0
)
+
vgetq_lane_f32
(
result
,
1
)
+
vgetq_lane_f32
(
result
,
2
)
+
vgetq_lane_f32
(
result
,
3
);
return
vgetq_lane_f32
(
result
,
0
)
+
vgetq_lane_f32
(
result
,
1
)
+
vgetq_lane_f32
(
result
,
2
)
+
vgetq_lane_f32
(
result
,
3
);
}
}
static
inline
fvec4
cross
(
const
fvec4
&
v1
,
const
fvec4
&
v2
)
{
return
fvec4
(
v1
[
1
]
*
v2
[
2
]
-
v1
[
2
]
*
v2
[
1
],
v1
[
2
]
*
v2
[
0
]
-
v1
[
0
]
*
v2
[
2
],
v1
[
0
]
*
v2
[
1
]
-
v1
[
1
]
*
v2
[
0
],
0
);
}
static
inline
void
transpose
(
fvec4
&
v1
,
fvec4
&
v2
,
fvec4
&
v3
,
fvec4
&
v4
)
{
static
inline
void
transpose
(
fvec4
&
v1
,
fvec4
&
v2
,
fvec4
&
v3
,
fvec4
&
v4
)
{
float32x4x2_t
t1
=
vuzpq_f32
(
v1
,
v3
);
float32x4x2_t
t1
=
vuzpq_f32
(
v1
,
v3
);
float32x4x2_t
t2
=
vuzpq_f32
(
v2
,
v4
);
float32x4x2_t
t2
=
vuzpq_f32
(
v2
,
v4
);
...
...
openmmapi/include/openmm/internal/vectorize_pnacl.h
View file @
604881dc
...
@@ -255,6 +255,12 @@ static inline float dot4(const fvec4& v1, const fvec4& v2) {
...
@@ -255,6 +255,12 @@ static inline float dot4(const fvec4& v1, const fvec4& v2) {
return
r
[
0
]
+
r
[
1
]
+
r
[
2
]
+
r
[
3
];
return
r
[
0
]
+
r
[
1
]
+
r
[
2
]
+
r
[
3
];
}
}
static
inline
fvec4
cross
(
const
fvec4
&
v1
,
const
fvec4
&
v2
)
{
__m128
temp
=
v2
.
val
*
__builtin_shufflevector
(
v1
.
val
,
v1
.
val
,
2
,
0
,
1
,
3
)
-
v1
.
val
*
__builtin_shufflevector
(
v2
.
val
,
v2
.
val
,
2
,
0
,
1
,
3
);
return
__builtin_shufflevector
(
temp
,
temp
,
2
,
0
,
1
,
3
);
}
static
inline
void
transpose
(
fvec4
&
v1
,
fvec4
&
v2
,
fvec4
&
v3
,
fvec4
&
v4
)
{
static
inline
void
transpose
(
fvec4
&
v1
,
fvec4
&
v2
,
fvec4
&
v3
,
fvec4
&
v4
)
{
__m128
a1
=
__builtin_shufflevector
(
v1
.
val
,
v2
.
val
,
0
,
4
,
2
,
6
);
__m128
a1
=
__builtin_shufflevector
(
v1
.
val
,
v2
.
val
,
0
,
4
,
2
,
6
);
__m128
a2
=
__builtin_shufflevector
(
v1
.
val
,
v2
.
val
,
1
,
5
,
3
,
7
);
__m128
a2
=
__builtin_shufflevector
(
v1
.
val
,
v2
.
val
,
1
,
5
,
3
,
7
);
...
...
openmmapi/include/openmm/internal/vectorize_sse.h
View file @
604881dc
#ifndef OPENMM_VECTORIZE_SSE_H_
#ifndef OPENMM_VECTORIZE_SSE_H_
#define OPENMM_VECTORIZE_SSE_H_
#define OPENMM_VECTORIZE_SSE_H_
/* -------------------------------------------------------------------------- *
/* -------------------------------------------------------------------------- *
* OpenMM *
* OpenMM *
* -------------------------------------------------------------------------- *
* -------------------------------------------------------------------------- *
* This is part of the OpenMM molecular simulation toolkit originating from *
* This is part of the OpenMM molecular simulation toolkit originating from *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Simbios, the NIH National Center for Physics-Based Simulation of *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Biological Structures at Stanford, funded under the NIH Roadmap for *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* Medical Research, grant U54 GM072970. See https://simtk.org. *
* *
* *
* Portions copyright (c) 2013 Stanford University and the Authors. *
* Portions copyright (c) 2013 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Authors: Peter Eastman *
* Contributors: *
* Contributors: *
* *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* 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: *
* Software is furnished to do so, subject to the following conditions: *
* *
* *
* The above copyright notice and this permission notice shall be included in *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* all copies or substantial portions of the Software. *
* *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* 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 *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
* -------------------------------------------------------------------------- */
#include <smmintrin.h>
#include <smmintrin.h>
#include "hardware.h"
#include "hardware.h"
// This file defines classes and functions to simplify vectorizing code with SSE.
// This file defines classes and functions to simplify vectorizing code with SSE.
/**
/**
* Determine whether ivec4 and fvec4 are supported on this processor.
* Determine whether ivec4 and fvec4 are supported on this processor.
*/
*/
static
bool
isVec4Supported
()
{
static
bool
isVec4Supported
()
{
int
cpuInfo
[
4
];
int
cpuInfo
[
4
];
cpuid
(
cpuInfo
,
0
);
cpuid
(
cpuInfo
,
0
);
if
(
cpuInfo
[
0
]
>=
1
)
{
if
(
cpuInfo
[
0
]
>=
1
)
{
cpuid
(
cpuInfo
,
1
);
cpuid
(
cpuInfo
,
1
);
return
((
cpuInfo
[
2
]
&
((
int
)
1
<<
19
))
!=
0
);
return
((
cpuInfo
[
2
]
&
((
int
)
1
<<
19
))
!=
0
);
}
}
return
false
;
return
false
;
}
}
class
ivec4
;
class
ivec4
;
/**
/**
* A four element vector of floats.
* A four element vector of floats.
*/
*/
class
fvec4
{
class
fvec4
{
public:
public:
__m128
val
;
__m128
val
;
fvec4
()
{}
fvec4
()
{}
fvec4
(
float
v
)
:
val
(
_mm_set1_ps
(
v
))
{}
fvec4
(
float
v
)
:
val
(
_mm_set1_ps
(
v
))
{}
fvec4
(
float
v1
,
float
v2
,
float
v3
,
float
v4
)
:
val
(
_mm_set_ps
(
v4
,
v3
,
v2
,
v1
))
{}
fvec4
(
float
v1
,
float
v2
,
float
v3
,
float
v4
)
:
val
(
_mm_set_ps
(
v4
,
v3
,
v2
,
v1
))
{}
fvec4
(
__m128
v
)
:
val
(
v
)
{}
fvec4
(
__m128
v
)
:
val
(
v
)
{}
fvec4
(
const
float
*
v
)
:
val
(
_mm_loadu_ps
(
v
))
{}
fvec4
(
const
float
*
v
)
:
val
(
_mm_loadu_ps
(
v
))
{}
operator
__m128
()
const
{
operator
__m128
()
const
{
return
val
;
return
val
;
}
}
float
operator
[](
int
i
)
const
{
float
operator
[](
int
i
)
const
{
float
result
[
4
];
float
result
[
4
];
store
(
result
);
store
(
result
);
return
result
[
i
];
return
result
[
i
];
}
}
void
store
(
float
*
v
)
const
{
void
store
(
float
*
v
)
const
{
_mm_storeu_ps
(
v
,
val
);
_mm_storeu_ps
(
v
,
val
);
}
}
fvec4
operator
+
(
const
fvec4
&
other
)
const
{
fvec4
operator
+
(
const
fvec4
&
other
)
const
{
return
_mm_add_ps
(
val
,
other
);
return
_mm_add_ps
(
val
,
other
);
}
}
fvec4
operator
-
(
const
fvec4
&
other
)
const
{
fvec4
operator
-
(
const
fvec4
&
other
)
const
{
return
_mm_sub_ps
(
val
,
other
);
return
_mm_sub_ps
(
val
,
other
);
}
}
fvec4
operator
*
(
const
fvec4
&
other
)
const
{
fvec4
operator
*
(
const
fvec4
&
other
)
const
{
return
_mm_mul_ps
(
val
,
other
);
return
_mm_mul_ps
(
val
,
other
);
}
}
fvec4
operator
/
(
const
fvec4
&
other
)
const
{
fvec4
operator
/
(
const
fvec4
&
other
)
const
{
return
_mm_div_ps
(
val
,
other
);
return
_mm_div_ps
(
val
,
other
);
}
}
void
operator
+=
(
const
fvec4
&
other
)
{
void
operator
+=
(
const
fvec4
&
other
)
{
val
=
_mm_add_ps
(
val
,
other
);
val
=
_mm_add_ps
(
val
,
other
);
}
}
void
operator
-=
(
const
fvec4
&
other
)
{
void
operator
-=
(
const
fvec4
&
other
)
{
val
=
_mm_sub_ps
(
val
,
other
);
val
=
_mm_sub_ps
(
val
,
other
);
}
}
void
operator
*=
(
const
fvec4
&
other
)
{
void
operator
*=
(
const
fvec4
&
other
)
{
val
=
_mm_mul_ps
(
val
,
other
);
val
=
_mm_mul_ps
(
val
,
other
);
}
}
void
operator
/=
(
const
fvec4
&
other
)
{
void
operator
/=
(
const
fvec4
&
other
)
{
val
=
_mm_div_ps
(
val
,
other
);
val
=
_mm_div_ps
(
val
,
other
);
}
}
fvec4
operator
-
()
const
{
fvec4
operator
-
()
const
{
return
_mm_sub_ps
(
_mm_set1_ps
(
0.0
f
),
val
);
return
_mm_sub_ps
(
_mm_set1_ps
(
0.0
f
),
val
);
}
}
fvec4
operator
&
(
const
fvec4
&
other
)
const
{
fvec4
operator
&
(
const
fvec4
&
other
)
const
{
return
_mm_and_ps
(
val
,
other
);
return
_mm_and_ps
(
val
,
other
);
}
}
fvec4
operator
|
(
const
fvec4
&
other
)
const
{
fvec4
operator
|
(
const
fvec4
&
other
)
const
{
return
_mm_or_ps
(
val
,
other
);
return
_mm_or_ps
(
val
,
other
);
}
}
fvec4
operator
==
(
const
fvec4
&
other
)
const
{
fvec4
operator
==
(
const
fvec4
&
other
)
const
{
return
_mm_cmpeq_ps
(
val
,
other
);
return
_mm_cmpeq_ps
(
val
,
other
);
}
}
fvec4
operator
!=
(
const
fvec4
&
other
)
const
{
fvec4
operator
!=
(
const
fvec4
&
other
)
const
{
return
_mm_cmpneq_ps
(
val
,
other
);
return
_mm_cmpneq_ps
(
val
,
other
);
}
}
fvec4
operator
>
(
const
fvec4
&
other
)
const
{
fvec4
operator
>
(
const
fvec4
&
other
)
const
{
return
_mm_cmpgt_ps
(
val
,
other
);
return
_mm_cmpgt_ps
(
val
,
other
);
}
}
fvec4
operator
<
(
const
fvec4
&
other
)
const
{
fvec4
operator
<
(
const
fvec4
&
other
)
const
{
return
_mm_cmplt_ps
(
val
,
other
);
return
_mm_cmplt_ps
(
val
,
other
);
}
}
fvec4
operator
>=
(
const
fvec4
&
other
)
const
{
fvec4
operator
>=
(
const
fvec4
&
other
)
const
{
return
_mm_cmpge_ps
(
val
,
other
);
return
_mm_cmpge_ps
(
val
,
other
);
}
}
fvec4
operator
<=
(
const
fvec4
&
other
)
const
{
fvec4
operator
<=
(
const
fvec4
&
other
)
const
{
return
_mm_cmple_ps
(
val
,
other
);
return
_mm_cmple_ps
(
val
,
other
);
}
}
operator
ivec4
()
const
;
operator
ivec4
()
const
;
};
};
/**
/**
* A four element vector of ints.
* A four element vector of ints.
*/
*/
class
ivec4
{
class
ivec4
{
public:
public:
__m128i
val
;
__m128i
val
;
ivec4
()
{}
ivec4
()
{}
ivec4
(
int
v
)
:
val
(
_mm_set1_epi32
(
v
))
{}
ivec4
(
int
v
)
:
val
(
_mm_set1_epi32
(
v
))
{}
ivec4
(
int
v1
,
int
v2
,
int
v3
,
int
v4
)
:
val
(
_mm_set_epi32
(
v4
,
v3
,
v2
,
v1
))
{}
ivec4
(
int
v1
,
int
v2
,
int
v3
,
int
v4
)
:
val
(
_mm_set_epi32
(
v4
,
v3
,
v2
,
v1
))
{}
ivec4
(
__m128i
v
)
:
val
(
v
)
{}
ivec4
(
__m128i
v
)
:
val
(
v
)
{}
ivec4
(
const
int
*
v
)
:
val
(
_mm_loadu_si128
((
const
__m128i
*
)
v
))
{}
ivec4
(
const
int
*
v
)
:
val
(
_mm_loadu_si128
((
const
__m128i
*
)
v
))
{}
operator
__m128i
()
const
{
operator
__m128i
()
const
{
return
val
;
return
val
;
}
}
int
operator
[](
int
i
)
const
{
int
operator
[](
int
i
)
const
{
int
result
[
4
];
int
result
[
4
];
store
(
result
);
store
(
result
);
return
result
[
i
];
return
result
[
i
];
}
}
void
store
(
int
*
v
)
const
{
void
store
(
int
*
v
)
const
{
_mm_storeu_si128
((
__m128i
*
)
v
,
val
);
_mm_storeu_si128
((
__m128i
*
)
v
,
val
);
}
}
ivec4
operator
+
(
const
ivec4
&
other
)
const
{
ivec4
operator
+
(
const
ivec4
&
other
)
const
{
return
_mm_add_epi32
(
val
,
other
);
return
_mm_add_epi32
(
val
,
other
);
}
}
ivec4
operator
-
(
const
ivec4
&
other
)
const
{
ivec4
operator
-
(
const
ivec4
&
other
)
const
{
return
_mm_sub_epi32
(
val
,
other
);
return
_mm_sub_epi32
(
val
,
other
);
}
}
ivec4
operator
*
(
const
ivec4
&
other
)
const
{
ivec4
operator
*
(
const
ivec4
&
other
)
const
{
return
_mm_mullo_epi32
(
val
,
other
);
return
_mm_mullo_epi32
(
val
,
other
);
}
}
void
operator
+=
(
const
ivec4
&
other
)
{
void
operator
+=
(
const
ivec4
&
other
)
{
val
=
_mm_add_epi32
(
val
,
other
);
val
=
_mm_add_epi32
(
val
,
other
);
}
}
void
operator
-=
(
const
ivec4
&
other
)
{
void
operator
-=
(
const
ivec4
&
other
)
{
val
=
_mm_sub_epi32
(
val
,
other
);
val
=
_mm_sub_epi32
(
val
,
other
);
}
}
void
operator
*=
(
const
ivec4
&
other
)
{
void
operator
*=
(
const
ivec4
&
other
)
{
val
=
_mm_mullo_epi32
(
val
,
other
);
val
=
_mm_mullo_epi32
(
val
,
other
);
}
}
ivec4
operator
-
()
const
{
ivec4
operator
-
()
const
{
return
_mm_sub_epi32
(
_mm_set1_epi32
(
0
),
val
);
return
_mm_sub_epi32
(
_mm_set1_epi32
(
0
),
val
);
}
}
ivec4
operator
&
(
const
ivec4
&
other
)
const
{
ivec4
operator
&
(
const
ivec4
&
other
)
const
{
return
_mm_and_si128
(
val
,
other
);
return
_mm_and_si128
(
val
,
other
);
}
}
ivec4
operator
|
(
const
ivec4
&
other
)
const
{
ivec4
operator
|
(
const
ivec4
&
other
)
const
{
return
_mm_or_si128
(
val
,
other
);
return
_mm_or_si128
(
val
,
other
);
}
}
ivec4
operator
==
(
const
ivec4
&
other
)
const
{
ivec4
operator
==
(
const
ivec4
&
other
)
const
{
return
_mm_cmpeq_epi32
(
val
,
other
);
return
_mm_cmpeq_epi32
(
val
,
other
);
}
}
ivec4
operator
!=
(
const
ivec4
&
other
)
const
{
ivec4
operator
!=
(
const
ivec4
&
other
)
const
{
return
_mm_xor_si128
(
*
this
==
other
,
_mm_set1_epi32
(
0xFFFFFFFF
));
return
_mm_xor_si128
(
*
this
==
other
,
_mm_set1_epi32
(
0xFFFFFFFF
));
}
}
ivec4
operator
>
(
const
ivec4
&
other
)
const
{
ivec4
operator
>
(
const
ivec4
&
other
)
const
{
return
_mm_cmpgt_epi32
(
val
,
other
);
return
_mm_cmpgt_epi32
(
val
,
other
);
}
}
ivec4
operator
<
(
const
ivec4
&
other
)
const
{
ivec4
operator
<
(
const
ivec4
&
other
)
const
{
return
_mm_cmplt_epi32
(
val
,
other
);
return
_mm_cmplt_epi32
(
val
,
other
);
}
}
ivec4
operator
>=
(
const
ivec4
&
other
)
const
{
ivec4
operator
>=
(
const
ivec4
&
other
)
const
{
return
_mm_xor_si128
(
_mm_cmplt_epi32
(
val
,
other
),
_mm_set1_epi32
(
0xFFFFFFFF
));
return
_mm_xor_si128
(
_mm_cmplt_epi32
(
val
,
other
),
_mm_set1_epi32
(
0xFFFFFFFF
));
}
}
ivec4
operator
<=
(
const
ivec4
&
other
)
const
{
ivec4
operator
<=
(
const
ivec4
&
other
)
const
{
return
_mm_xor_si128
(
_mm_cmpgt_epi32
(
val
,
other
),
_mm_set1_epi32
(
0xFFFFFFFF
));
return
_mm_xor_si128
(
_mm_cmpgt_epi32
(
val
,
other
),
_mm_set1_epi32
(
0xFFFFFFFF
));
}
}
operator
fvec4
()
const
;
operator
fvec4
()
const
;
};
};
// Conversion operators.
// Conversion operators.
inline
fvec4
::
operator
ivec4
()
const
{
inline
fvec4
::
operator
ivec4
()
const
{
return
_mm_cvttps_epi32
(
val
);
return
_mm_cvttps_epi32
(
val
);
}
}
inline
ivec4
::
operator
fvec4
()
const
{
inline
ivec4
::
operator
fvec4
()
const
{
return
_mm_cvtepi32_ps
(
val
);
return
_mm_cvtepi32_ps
(
val
);
}
}
// Functions that operate on fvec4s.
// Functions that operate on fvec4s.
static
inline
fvec4
floor
(
const
fvec4
&
v
)
{
static
inline
fvec4
floor
(
const
fvec4
&
v
)
{
return
fvec4
(
_mm_floor_ps
(
v
.
val
));
return
fvec4
(
_mm_floor_ps
(
v
.
val
));
}
}
static
inline
fvec4
ceil
(
const
fvec4
&
v
)
{
static
inline
fvec4
ceil
(
const
fvec4
&
v
)
{
return
fvec4
(
_mm_ceil_ps
(
v
.
val
));
return
fvec4
(
_mm_ceil_ps
(
v
.
val
));
}
}
static
inline
fvec4
round
(
const
fvec4
&
v
)
{
static
inline
fvec4
round
(
const
fvec4
&
v
)
{
return
fvec4
(
_mm_round_ps
(
v
.
val
,
_MM_FROUND_TO_NEAREST_INT
));
return
fvec4
(
_mm_round_ps
(
v
.
val
,
_MM_FROUND_TO_NEAREST_INT
));
}
}
static
inline
fvec4
min
(
const
fvec4
&
v1
,
const
fvec4
&
v2
)
{
static
inline
fvec4
min
(
const
fvec4
&
v1
,
const
fvec4
&
v2
)
{
return
fvec4
(
_mm_min_ps
(
v1
.
val
,
v2
.
val
));
return
fvec4
(
_mm_min_ps
(
v1
.
val
,
v2
.
val
));
}
}
static
inline
fvec4
max
(
const
fvec4
&
v1
,
const
fvec4
&
v2
)
{
static
inline
fvec4
max
(
const
fvec4
&
v1
,
const
fvec4
&
v2
)
{
return
fvec4
(
_mm_max_ps
(
v1
.
val
,
v2
.
val
));
return
fvec4
(
_mm_max_ps
(
v1
.
val
,
v2
.
val
));
}
}
static
inline
fvec4
abs
(
const
fvec4
&
v
)
{
static
inline
fvec4
abs
(
const
fvec4
&
v
)
{
static
const
__m128
mask
=
_mm_castsi128_ps
(
_mm_set1_epi32
(
0x7FFFFFFF
));
static
const
__m128
mask
=
_mm_castsi128_ps
(
_mm_set1_epi32
(
0x7FFFFFFF
));
return
fvec4
(
_mm_and_ps
(
v
.
val
,
mask
));
return
fvec4
(
_mm_and_ps
(
v
.
val
,
mask
));
}
}
static
inline
fvec4
sqrt
(
const
fvec4
&
v
)
{
static
inline
fvec4
sqrt
(
const
fvec4
&
v
)
{
return
fvec4
(
_mm_sqrt_ps
(
v
.
val
));
return
fvec4
(
_mm_sqrt_ps
(
v
.
val
));
}
}
static
inline
float
dot3
(
const
fvec4
&
v1
,
const
fvec4
&
v2
)
{
static
inline
float
dot3
(
const
fvec4
&
v1
,
const
fvec4
&
v2
)
{
return
_mm_cvtss_f32
(
_mm_dp_ps
(
v1
,
v2
,
0x71
));
return
_mm_cvtss_f32
(
_mm_dp_ps
(
v1
,
v2
,
0x71
));
}
}
static
inline
float
dot4
(
const
fvec4
&
v1
,
const
fvec4
&
v2
)
{
static
inline
float
dot4
(
const
fvec4
&
v1
,
const
fvec4
&
v2
)
{
return
_mm_cvtss_f32
(
_mm_dp_ps
(
v1
,
v2
,
0xF1
));
return
_mm_cvtss_f32
(
_mm_dp_ps
(
v1
,
v2
,
0xF1
));
}
}
static
inline
void
transpose
(
fvec4
&
v1
,
fvec4
&
v2
,
fvec4
&
v3
,
fvec4
&
v4
)
{
static
inline
fvec4
cross
(
const
fvec4
&
v1
,
const
fvec4
&
v2
)
{
_MM_TRANSPOSE4_PS
(
v1
,
v2
,
v3
,
v4
);
fvec4
temp
=
fvec4
(
_mm_mul_ps
(
v1
,
_mm_shuffle_ps
(
v2
,
v2
,
_MM_SHUFFLE
(
3
,
0
,
2
,
1
))))
-
}
fvec4
(
_mm_mul_ps
(
v2
,
_mm_shuffle_ps
(
v1
,
v1
,
_MM_SHUFFLE
(
3
,
0
,
2
,
1
))));
return
_mm_shuffle_ps
(
temp
,
temp
,
_MM_SHUFFLE
(
3
,
0
,
2
,
1
));
// Functions that operate on ivec4s.
}
static
inline
ivec4
min
(
const
ivec4
&
v1
,
const
ivec4
&
v2
)
{
static
inline
void
transpose
(
fvec4
&
v1
,
fvec4
&
v2
,
fvec4
&
v3
,
fvec4
&
v4
)
{
return
ivec4
(
_mm_min_epi32
(
v1
.
val
,
v2
.
val
));
_MM_TRANSPOSE4_PS
(
v1
,
v2
,
v3
,
v4
);
}
}
static
inline
ivec4
max
(
const
ivec4
&
v1
,
const
ivec4
&
v2
)
{
// Functions that operate on ivec4s.
return
ivec4
(
_mm_max_epi32
(
v1
.
val
,
v2
.
val
));
}
static
inline
ivec4
min
(
const
ivec4
&
v1
,
const
ivec4
&
v2
)
{
return
ivec4
(
_mm_min_epi32
(
v1
.
val
,
v2
.
val
));
static
inline
ivec4
abs
(
const
ivec4
&
v
)
{
}
return
ivec4
(
_mm_abs_epi32
(
v
.
val
));
}
static
inline
ivec4
max
(
const
ivec4
&
v1
,
const
ivec4
&
v2
)
{
return
ivec4
(
_mm_max_epi32
(
v1
.
val
,
v2
.
val
));
static
inline
bool
any
(
const
ivec4
&
v
)
{
}
return
!
_mm_test_all_zeros
(
v
,
_mm_set1_epi32
(
0xFFFFFFFF
));
}
static
inline
ivec4
abs
(
const
ivec4
&
v
)
{
return
ivec4
(
_mm_abs_epi32
(
v
.
val
));
// Mathematical operators involving a scalar and a vector.
}
static
inline
fvec4
operator
+
(
float
v1
,
const
fvec4
&
v2
)
{
static
inline
bool
any
(
const
ivec4
&
v
)
{
return
fvec4
(
v1
)
+
v2
;
return
!
_mm_test_all_zeros
(
v
,
_mm_set1_epi32
(
0xFFFFFFFF
));
}
}
static
inline
fvec4
operator
-
(
float
v1
,
const
fvec4
&
v2
)
{
// Mathematical operators involving a scalar and a vector.
return
fvec4
(
v1
)
-
v2
;
}
static
inline
fvec4
operator
+
(
float
v1
,
const
fvec4
&
v2
)
{
return
fvec4
(
v1
)
+
v2
;
static
inline
fvec4
operator
*
(
float
v1
,
const
fvec4
&
v2
)
{
}
return
fvec4
(
v1
)
*
v2
;
}
static
inline
fvec4
operator
-
(
float
v1
,
const
fvec4
&
v2
)
{
return
fvec4
(
v1
)
-
v2
;
static
inline
fvec4
operator
/
(
float
v1
,
const
fvec4
&
v2
)
{
}
return
fvec4
(
v1
)
/
v2
;
}
static
inline
fvec4
operator
*
(
float
v1
,
const
fvec4
&
v2
)
{
return
fvec4
(
v1
)
*
v2
;
// Operations for blending fvec4s based on an ivec4.
}
static
inline
fvec4
blend
(
const
fvec4
&
v1
,
const
fvec4
&
v2
,
const
ivec4
&
mask
)
{
static
inline
fvec4
operator
/
(
float
v1
,
const
fvec4
&
v2
)
{
return
fvec4
(
_mm_blendv_ps
(
v1
.
val
,
v2
.
val
,
_mm_castsi128_ps
(
mask
.
val
)));
return
fvec4
(
v1
)
/
v2
;
}
}
#endif
/*OPENMM_VECTORIZE_SSE_H_*/
// Operations for blending fvec4s based on an ivec4.
static
inline
fvec4
blend
(
const
fvec4
&
v1
,
const
fvec4
&
v2
,
const
ivec4
&
mask
)
{
return
fvec4
(
_mm_blendv_ps
(
v1
.
val
,
v2
.
val
,
_mm_castsi128_ps
(
mask
.
val
)));
}
#endif
/*OPENMM_VECTORIZE_SSE_H_*/
openmmapi/src/CustomManyParticleForce.cpp
0 → 100644
View file @
604881dc
/* -------------------------------------------------------------------------- *
* 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. *
* -------------------------------------------------------------------------- */
#include "openmm/Force.h"
#include "openmm/OpenMMException.h"
#include "openmm/CustomManyParticleForce.h"
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/internal/CustomManyParticleForceImpl.h"
#include <cmath>
#include <map>
#include <set>
#include <sstream>
#include <utility>
using
namespace
OpenMM
;
using
namespace
std
;
CustomManyParticleForce
::
CustomManyParticleForce
(
int
particlesPerSet
,
const
string
&
energy
)
:
particlesPerSet
(
particlesPerSet
),
energyExpression
(
energy
),
nonbondedMethod
(
NoCutoff
),
permutationMode
(
SinglePermutation
),
cutoffDistance
(
1.0
),
typeFilters
(
particlesPerSet
)
{
}
CustomManyParticleForce
::~
CustomManyParticleForce
()
{
for
(
int
i
=
0
;
i
<
(
int
)
functions
.
size
();
i
++
)
delete
functions
[
i
].
function
;
}
const
string
&
CustomManyParticleForce
::
getEnergyFunction
()
const
{
return
energyExpression
;
}
void
CustomManyParticleForce
::
setEnergyFunction
(
const
string
&
energy
)
{
energyExpression
=
energy
;
}
CustomManyParticleForce
::
NonbondedMethod
CustomManyParticleForce
::
getNonbondedMethod
()
const
{
return
nonbondedMethod
;
}
void
CustomManyParticleForce
::
setNonbondedMethod
(
NonbondedMethod
method
)
{
nonbondedMethod
=
method
;
}
CustomManyParticleForce
::
PermutationMode
CustomManyParticleForce
::
getPermutationMode
()
const
{
return
permutationMode
;
}
void
CustomManyParticleForce
::
setPermutationMode
(
PermutationMode
mode
)
{
permutationMode
=
mode
;
}
double
CustomManyParticleForce
::
getCutoffDistance
()
const
{
return
cutoffDistance
;
}
void
CustomManyParticleForce
::
setCutoffDistance
(
double
distance
)
{
cutoffDistance
=
distance
;
}
int
CustomManyParticleForce
::
addPerParticleParameter
(
const
string
&
name
)
{
particleParameters
.
push_back
(
ParticleParameterInfo
(
name
));
return
particleParameters
.
size
()
-
1
;
}
const
string
&
CustomManyParticleForce
::
getPerParticleParameterName
(
int
index
)
const
{
ASSERT_VALID_INDEX
(
index
,
particleParameters
);
return
particleParameters
[
index
].
name
;
}
void
CustomManyParticleForce
::
setPerParticleParameterName
(
int
index
,
const
string
&
name
)
{
ASSERT_VALID_INDEX
(
index
,
particleParameters
);
particleParameters
[
index
].
name
=
name
;
}
int
CustomManyParticleForce
::
addGlobalParameter
(
const
string
&
name
,
double
defaultValue
)
{
globalParameters
.
push_back
(
GlobalParameterInfo
(
name
,
defaultValue
));
return
globalParameters
.
size
()
-
1
;
}
const
string
&
CustomManyParticleForce
::
getGlobalParameterName
(
int
index
)
const
{
ASSERT_VALID_INDEX
(
index
,
globalParameters
);
return
globalParameters
[
index
].
name
;
}
void
CustomManyParticleForce
::
setGlobalParameterName
(
int
index
,
const
string
&
name
)
{
ASSERT_VALID_INDEX
(
index
,
globalParameters
);
globalParameters
[
index
].
name
=
name
;
}
double
CustomManyParticleForce
::
getGlobalParameterDefaultValue
(
int
index
)
const
{
ASSERT_VALID_INDEX
(
index
,
globalParameters
);
return
globalParameters
[
index
].
defaultValue
;
}
void
CustomManyParticleForce
::
setGlobalParameterDefaultValue
(
int
index
,
double
defaultValue
)
{
ASSERT_VALID_INDEX
(
index
,
globalParameters
);
globalParameters
[
index
].
defaultValue
=
defaultValue
;
}
int
CustomManyParticleForce
::
addParticle
(
const
vector
<
double
>&
parameters
,
int
type
)
{
particles
.
push_back
(
ParticleInfo
(
parameters
,
type
));
return
particles
.
size
()
-
1
;
}
void
CustomManyParticleForce
::
getParticleParameters
(
int
index
,
vector
<
double
>&
parameters
,
int
&
type
)
const
{
ASSERT_VALID_INDEX
(
index
,
particles
);
parameters
=
particles
[
index
].
parameters
;
type
=
particles
[
index
].
type
;
}
void
CustomManyParticleForce
::
setParticleParameters
(
int
index
,
const
vector
<
double
>&
parameters
,
int
type
)
{
ASSERT_VALID_INDEX
(
index
,
particles
);
particles
[
index
].
parameters
=
parameters
;
particles
[
index
].
type
=
type
;
}
int
CustomManyParticleForce
::
addExclusion
(
int
particle1
,
int
particle2
)
{
exclusions
.
push_back
(
ExclusionInfo
(
particle1
,
particle2
));
return
exclusions
.
size
()
-
1
;
}
void
CustomManyParticleForce
::
getExclusionParticles
(
int
index
,
int
&
particle1
,
int
&
particle2
)
const
{
ASSERT_VALID_INDEX
(
index
,
exclusions
);
particle1
=
exclusions
[
index
].
particle1
;
particle2
=
exclusions
[
index
].
particle2
;
}
void
CustomManyParticleForce
::
setExclusionParticles
(
int
index
,
int
particle1
,
int
particle2
)
{
ASSERT_VALID_INDEX
(
index
,
exclusions
);
exclusions
[
index
].
particle1
=
particle1
;
exclusions
[
index
].
particle2
=
particle2
;
}
void
CustomManyParticleForce
::
createExclusionsFromBonds
(
const
vector
<
pair
<
int
,
int
>
>&
bonds
,
int
bondCutoff
)
{
if
(
bondCutoff
<
1
)
return
;
vector
<
set
<
int
>
>
exclusions
(
particles
.
size
());
vector
<
set
<
int
>
>
bonded12
(
exclusions
.
size
());
for
(
int
i
=
0
;
i
<
(
int
)
bonds
.
size
();
++
i
)
{
int
p1
=
bonds
[
i
].
first
;
int
p2
=
bonds
[
i
].
second
;
exclusions
[
p1
].
insert
(
p2
);
exclusions
[
p2
].
insert
(
p1
);
bonded12
[
p1
].
insert
(
p2
);
bonded12
[
p2
].
insert
(
p1
);
}
for
(
int
level
=
0
;
level
<
bondCutoff
-
1
;
level
++
)
{
vector
<
set
<
int
>
>
currentExclusions
=
exclusions
;
for
(
int
i
=
0
;
i
<
(
int
)
particles
.
size
();
i
++
)
{
for
(
set
<
int
>::
const_iterator
iter
=
currentExclusions
[
i
].
begin
();
iter
!=
currentExclusions
[
i
].
end
();
++
iter
)
exclusions
[
*
iter
].
insert
(
bonded12
[
i
].
begin
(),
bonded12
[
i
].
end
());
}
}
for
(
int
i
=
0
;
i
<
(
int
)
exclusions
.
size
();
++
i
)
for
(
set
<
int
>::
const_iterator
iter
=
exclusions
[
i
].
begin
();
iter
!=
exclusions
[
i
].
end
();
++
iter
)
if
(
*
iter
<
i
)
addExclusion
(
*
iter
,
i
);
}
void
CustomManyParticleForce
::
getTypeFilter
(
int
index
,
set
<
int
>&
types
)
const
{
if
(
index
<
0
||
index
>=
particlesPerSet
)
throw
OpenMMException
(
"CustomManyParticleForce: index to getTypeFilter out of range"
);
types
=
typeFilters
[
index
];
}
void
CustomManyParticleForce
::
setTypeFilter
(
int
index
,
const
set
<
int
>&
types
)
{
if
(
index
<
0
||
index
>=
particlesPerSet
)
throw
OpenMMException
(
"CustomManyParticleForce: index to setTypeFilter out of range"
);
typeFilters
[
index
]
=
types
;
}
int
CustomManyParticleForce
::
addTabulatedFunction
(
const
string
&
name
,
TabulatedFunction
*
function
)
{
functions
.
push_back
(
FunctionInfo
(
name
,
function
));
return
functions
.
size
()
-
1
;
}
const
TabulatedFunction
&
CustomManyParticleForce
::
getTabulatedFunction
(
int
index
)
const
{
ASSERT_VALID_INDEX
(
index
,
functions
);
return
*
functions
[
index
].
function
;
}
TabulatedFunction
&
CustomManyParticleForce
::
getTabulatedFunction
(
int
index
)
{
ASSERT_VALID_INDEX
(
index
,
functions
);
return
*
functions
[
index
].
function
;
}
const
string
&
CustomManyParticleForce
::
getTabulatedFunctionName
(
int
index
)
const
{
ASSERT_VALID_INDEX
(
index
,
functions
);
return
functions
[
index
].
name
;
}
ForceImpl
*
CustomManyParticleForce
::
createImpl
()
const
{
return
new
CustomManyParticleForceImpl
(
*
this
);
}
void
CustomManyParticleForce
::
updateParametersInContext
(
Context
&
context
)
{
dynamic_cast
<
CustomManyParticleForceImpl
&>
(
getImplInContext
(
context
)).
updateParametersInContext
(
getContextImpl
(
context
));
}
openmmapi/src/CustomManyParticleForceImpl.cpp
0 → 100644
View file @
604881dc
/* -------------------------------------------------------------------------- *
* 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. *
* -------------------------------------------------------------------------- */
#include "openmm/OpenMMException.h"
#include "openmm/internal/ContextImpl.h"
#include "openmm/internal/CustomManyParticleForceImpl.h"
#include "openmm/kernels.h"
#include "lepton/Operation.h"
#include "lepton/Parser.h"
#include <sstream>
using
namespace
OpenMM
;
using
Lepton
::
CustomFunction
;
using
Lepton
::
ExpressionTreeNode
;
using
Lepton
::
Operation
;
using
Lepton
::
ParsedExpression
;
using
std
::
map
;
using
std
::
pair
;
using
std
::
vector
;
using
std
::
set
;
using
std
::
string
;
using
std
::
stringstream
;
/**
* This class serves as a placeholder for angles and dihedrals in expressions.
*/
class
CustomManyParticleForceImpl
::
FunctionPlaceholder
:
public
CustomFunction
{
public:
int
numArguments
;
FunctionPlaceholder
(
int
numArguments
)
:
numArguments
(
numArguments
)
{
}
int
getNumArguments
()
const
{
return
numArguments
;
}
double
evaluate
(
const
double
*
arguments
)
const
{
return
0.0
;
}
double
evaluateDerivative
(
const
double
*
arguments
,
const
int
*
derivOrder
)
const
{
return
0.0
;
}
CustomFunction
*
clone
()
const
{
return
new
FunctionPlaceholder
(
numArguments
);
}
};
CustomManyParticleForceImpl
::
CustomManyParticleForceImpl
(
const
CustomManyParticleForce
&
owner
)
:
owner
(
owner
)
{
}
CustomManyParticleForceImpl
::~
CustomManyParticleForceImpl
()
{
}
void
CustomManyParticleForceImpl
::
initialize
(
ContextImpl
&
context
)
{
kernel
=
context
.
getPlatform
().
createKernel
(
CalcCustomManyParticleForceKernel
::
Name
(),
context
);
// Check for errors in the specification of parameters and exclusions.
const
System
&
system
=
context
.
getSystem
();
if
(
owner
.
getNumParticles
()
!=
system
.
getNumParticles
())
throw
OpenMMException
(
"CustomManyParticleForce must have exactly as many particles as the System it belongs to."
);
vector
<
set
<
int
>
>
exclusions
(
owner
.
getNumParticles
());
vector
<
double
>
parameters
;
int
type
;
int
numParameters
=
owner
.
getNumPerParticleParameters
();
for
(
int
i
=
0
;
i
<
owner
.
getNumParticles
();
i
++
)
{
owner
.
getParticleParameters
(
i
,
parameters
,
type
);
if
(
parameters
.
size
()
!=
numParameters
)
{
stringstream
msg
;
msg
<<
"CustomManyParticleForce: Wrong number of parameters for particle "
;
msg
<<
i
;
throw
OpenMMException
(
msg
.
str
());
}
}
for
(
int
i
=
0
;
i
<
owner
.
getNumExclusions
();
i
++
)
{
int
particle1
,
particle2
;
owner
.
getExclusionParticles
(
i
,
particle1
,
particle2
);
if
(
particle1
<
0
||
particle1
>=
owner
.
getNumParticles
())
{
stringstream
msg
;
msg
<<
"CustomManyParticleForce: Illegal particle index for an exclusion: "
;
msg
<<
particle1
;
throw
OpenMMException
(
msg
.
str
());
}
if
(
particle2
<
0
||
particle2
>=
owner
.
getNumParticles
())
{
stringstream
msg
;
msg
<<
"CustomManyParticleForce: Illegal particle index for an exclusion: "
;
msg
<<
particle2
;
throw
OpenMMException
(
msg
.
str
());
}
if
(
exclusions
[
particle1
].
count
(
particle2
)
>
0
||
exclusions
[
particle2
].
count
(
particle1
)
>
0
)
{
stringstream
msg
;
msg
<<
"CustomManyParticleForce: Multiple exclusions are specified for particles "
;
msg
<<
particle1
;
msg
<<
" and "
;
msg
<<
particle2
;
throw
OpenMMException
(
msg
.
str
());
}
exclusions
[
particle1
].
insert
(
particle2
);
exclusions
[
particle2
].
insert
(
particle1
);
}
if
(
owner
.
getNonbondedMethod
()
==
CustomManyParticleForce
::
CutoffPeriodic
)
{
Vec3
boxVectors
[
3
];
system
.
getDefaultPeriodicBoxVectors
(
boxVectors
[
0
],
boxVectors
[
1
],
boxVectors
[
2
]);
double
cutoff
=
owner
.
getCutoffDistance
();
if
(
cutoff
>
0.5
*
boxVectors
[
0
][
0
]
||
cutoff
>
0.5
*
boxVectors
[
1
][
1
]
||
cutoff
>
0.5
*
boxVectors
[
2
][
2
])
throw
OpenMMException
(
"CustomManyParticleForce: The cutoff distance cannot be greater than half the periodic box size."
);
}
kernel
.
getAs
<
CalcCustomManyParticleForceKernel
>
().
initialize
(
context
.
getSystem
(),
owner
);
}
double
CustomManyParticleForceImpl
::
calcForcesAndEnergy
(
ContextImpl
&
context
,
bool
includeForces
,
bool
includeEnergy
,
int
groups
)
{
if
((
groups
&
(
1
<<
owner
.
getForceGroup
()))
!=
0
)
return
kernel
.
getAs
<
CalcCustomManyParticleForceKernel
>
().
execute
(
context
,
includeForces
,
includeEnergy
);
return
0.0
;
}
vector
<
string
>
CustomManyParticleForceImpl
::
getKernelNames
()
{
vector
<
string
>
names
;
names
.
push_back
(
CalcCustomManyParticleForceKernel
::
Name
());
return
names
;
}
map
<
string
,
double
>
CustomManyParticleForceImpl
::
getDefaultParameters
()
{
map
<
string
,
double
>
parameters
;
for
(
int
i
=
0
;
i
<
owner
.
getNumGlobalParameters
();
i
++
)
parameters
[
owner
.
getGlobalParameterName
(
i
)]
=
owner
.
getGlobalParameterDefaultValue
(
i
);
return
parameters
;
}
ParsedExpression
CustomManyParticleForceImpl
::
prepareExpression
(
const
CustomManyParticleForce
&
force
,
const
map
<
string
,
CustomFunction
*>&
customFunctions
,
map
<
string
,
vector
<
int
>
>&
distances
,
map
<
string
,
vector
<
int
>
>&
angles
,
map
<
string
,
vector
<
int
>
>&
dihedrals
)
{
CustomManyParticleForceImpl
::
FunctionPlaceholder
custom
(
1
);
CustomManyParticleForceImpl
::
FunctionPlaceholder
distance
(
2
);
CustomManyParticleForceImpl
::
FunctionPlaceholder
angle
(
3
);
CustomManyParticleForceImpl
::
FunctionPlaceholder
dihedral
(
4
);
map
<
string
,
CustomFunction
*>
functions
=
customFunctions
;
functions
[
"distance"
]
=
&
distance
;
functions
[
"angle"
]
=
&
angle
;
functions
[
"dihedral"
]
=
&
dihedral
;
ParsedExpression
expression
=
Lepton
::
Parser
::
parse
(
force
.
getEnergyFunction
(),
functions
);
map
<
string
,
int
>
atoms
;
for
(
int
i
=
0
;
i
<
force
.
getNumParticlesPerSet
();
i
++
)
{
stringstream
name
;
name
<<
'p'
<<
(
i
+
1
);
atoms
[
name
.
str
()]
=
i
;
}
return
ParsedExpression
(
replaceFunctions
(
expression
.
getRootNode
(),
atoms
,
distances
,
angles
,
dihedrals
)).
optimize
();
}
ExpressionTreeNode
CustomManyParticleForceImpl
::
replaceFunctions
(
const
ExpressionTreeNode
&
node
,
map
<
string
,
int
>
atoms
,
map
<
string
,
vector
<
int
>
>&
distances
,
map
<
string
,
vector
<
int
>
>&
angles
,
map
<
string
,
vector
<
int
>
>&
dihedrals
)
{
const
Operation
&
op
=
node
.
getOperation
();
if
(
op
.
getId
()
!=
Operation
::
CUSTOM
||
(
op
.
getName
()
!=
"distance"
&&
op
.
getName
()
!=
"angle"
&&
op
.
getName
()
!=
"dihedral"
))
{
// This is not an angle or dihedral, so process its children.
vector
<
ExpressionTreeNode
>
children
;
for
(
int
i
=
0
;
i
<
(
int
)
node
.
getChildren
().
size
();
i
++
)
children
.
push_back
(
replaceFunctions
(
node
.
getChildren
()[
i
],
atoms
,
distances
,
angles
,
dihedrals
));
return
ExpressionTreeNode
(
op
.
clone
(),
children
);
}
const
Operation
::
Custom
&
custom
=
static_cast
<
const
Operation
::
Custom
&>
(
op
);
// Identify the atoms this term is based on.
int
numArgs
=
custom
.
getNumArguments
();
vector
<
int
>
indices
(
numArgs
);
for
(
int
i
=
0
;
i
<
numArgs
;
i
++
)
{
map
<
string
,
int
>::
const_iterator
iter
=
atoms
.
find
(
node
.
getChildren
()[
i
].
getOperation
().
getName
());
if
(
iter
==
atoms
.
end
())
throw
OpenMMException
(
"CustomManyParticleForce: Unknown particle '"
+
node
.
getChildren
()[
i
].
getOperation
().
getName
()
+
"'"
);
indices
[
i
]
=
iter
->
second
;
}
// Select a name for the variable and add it to the appropriate map.
stringstream
variable
;
if
(
numArgs
==
2
)
variable
<<
"distance"
;
else
if
(
numArgs
==
3
)
variable
<<
"angle"
;
else
variable
<<
"dihedral"
;
for
(
int
i
=
0
;
i
<
numArgs
;
i
++
)
variable
<<
indices
[
i
];
string
name
=
variable
.
str
();
if
(
numArgs
==
2
)
distances
[
name
]
=
indices
;
else
if
(
numArgs
==
3
)
angles
[
name
]
=
indices
;
else
dihedrals
[
name
]
=
indices
;
// Return a new node that represents it as a simple variable.
return
ExpressionTreeNode
(
new
Operation
::
Variable
(
name
));
}
void
CustomManyParticleForceImpl
::
updateParametersInContext
(
ContextImpl
&
context
)
{
kernel
.
getAs
<
CalcCustomManyParticleForceKernel
>
().
copyParametersToContext
(
context
,
owner
);
}
void
CustomManyParticleForceImpl
::
buildFilterArrays
(
const
CustomManyParticleForce
&
force
,
int
&
numTypes
,
vector
<
int
>&
particleTypes
,
vector
<
int
>&
orderIndex
,
vector
<
vector
<
int
>
>&
particleOrder
)
{
// Build a canonical list of type codes.
int
numParticles
=
force
.
getNumParticles
();
int
numParticlesPerSet
=
force
.
getNumParticlesPerSet
();
particleTypes
.
resize
(
numParticles
);
map
<
int
,
int
>
typeMap
;
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
{
vector
<
double
>
params
;
int
type
;
force
.
getParticleParameters
(
i
,
params
,
type
);
map
<
int
,
int
>::
const_iterator
element
=
typeMap
.
find
(
type
);
if
(
element
==
typeMap
.
end
())
{
int
newType
=
typeMap
.
size
();
typeMap
[
type
]
=
newType
;
particleTypes
[
i
]
=
newType
;
}
else
particleTypes
[
i
]
=
element
->
second
;
}
numTypes
=
typeMap
.
size
();
int
numIndices
=
1
;
for
(
int
i
=
0
;
i
<
numParticlesPerSet
;
i
++
)
numIndices
*=
numTypes
;
orderIndex
.
resize
(
numIndices
,
0
);
// Find the allowed type codes for each particle in an interaction.
vector
<
set
<
int
>
>
allowedTypes
(
numParticlesPerSet
);
bool
anyFilters
=
false
;
for
(
int
i
=
0
;
i
<
numParticlesPerSet
;
i
++
)
{
set
<
int
>
types
;
force
.
getTypeFilter
(
i
,
types
);
if
(
types
.
size
()
==
0
)
for
(
int
j
=
0
;
j
<
numTypes
;
j
++
)
allowedTypes
[
i
].
insert
(
j
);
else
{
for
(
set
<
int
>::
const_iterator
iter
=
types
.
begin
();
iter
!=
types
.
end
();
++
iter
)
if
(
typeMap
.
find
(
*
iter
)
!=
typeMap
.
end
())
allowedTypes
[
i
].
insert
(
typeMap
[
*
iter
]);
if
(
allowedTypes
[
i
].
size
()
<
numTypes
)
anyFilters
=
true
;
}
}
// If there are no filters, reordering is unnecessary.
if
(
!
anyFilters
)
{
particleOrder
.
resize
(
1
);
particleOrder
[
0
].
resize
(
numParticlesPerSet
);
for
(
int
i
=
0
;
i
<
numParticlesPerSet
;
i
++
)
particleOrder
[
0
][
i
]
=
i
;
return
;
}
// Build a list of every possible permutation of the particles.
particleOrder
.
clear
();
vector
<
int
>
values
;
for
(
int
i
=
0
;
i
<
numParticlesPerSet
;
i
++
)
values
.
push_back
(
i
);
generatePermutations
(
values
,
force
.
getPermutationMode
()
==
CustomManyParticleForce
::
SinglePermutation
?
0
:
1
,
particleOrder
);
int
numOrders
=
particleOrder
.
size
();
// Now we need to loop over every possible sequence of type codes, and for each one figure out which order to use.
for
(
int
i
=
0
;
i
<
numIndices
;
i
++
)
{
vector
<
int
>
types
(
numParticlesPerSet
);
int
temp
=
i
;
for
(
int
j
=
0
;
j
<
numParticlesPerSet
;
j
++
)
{
types
[
j
]
=
temp
%
numTypes
;
temp
/=
numTypes
;
}
// Loop over possible orders until we find one that matches the filters.
int
order
=
-
1
;
for
(
int
j
=
0
;
j
<
numOrders
&&
order
==
-
1
;
j
++
)
{
bool
matches
=
true
;
for
(
int
k
=
0
;
k
<
numParticlesPerSet
&&
matches
;
k
++
)
if
(
allowedTypes
[
k
].
find
(
types
[
particleOrder
[
j
][
k
]])
==
allowedTypes
[
k
].
end
())
matches
=
false
;
if
(
matches
)
order
=
j
;
}
orderIndex
[
i
]
=
order
;
}
}
void
CustomManyParticleForceImpl
::
generatePermutations
(
vector
<
int
>&
values
,
int
numFixed
,
vector
<
vector
<
int
>
>&
result
)
{
int
numValues
=
values
.
size
();
if
(
numFixed
==
numValues
)
{
result
.
push_back
(
values
);
return
;
}
for
(
int
i
=
numFixed
;
i
<
numValues
;
i
++
)
{
int
v1
=
values
[
numFixed
];
int
v2
=
values
[
i
];
values
[
numFixed
]
=
v2
;
values
[
i
]
=
v1
;
generatePermutations
(
values
,
numFixed
+
1
,
result
);
values
[
numFixed
]
=
v1
;
values
[
i
]
=
v2
;
}
}
\ No newline at end of file
platforms/cpu/include/CompiledExpressionSet.h
0 → 100644
View file @
604881dc
#ifndef OPENMM_COMPILEDEXPRESSIONSET_H_
#define OPENMM_COMPILEDEXPRESSIONSET_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) 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. *
* -------------------------------------------------------------------------- */
#include "lepton/CompiledExpression.h"
#include "windowsExportCpu.h"
#include <string>
#include <vector>
namespace
OpenMM
{
/**
* This class simplifies the management of a set of related CompiledExpressions that share variables.
*/
class
OPENMM_EXPORT_CPU
CompiledExpressionSet
{
public:
CompiledExpressionSet
();
/**
* Add a CompiledExpression to the set.
*/
void
registerExpression
(
Lepton
::
CompiledExpression
&
expression
);
/**
* Get the index of a particular variable.
*/
int
getVariableIndex
(
const
std
::
string
&
name
);
/**
* Set the value of a variable on every CompiledExpression.
*
* @param index the index of the variable, as returned by getVariableIndex()
* @param value the value to set it to
*/
void
setVariable
(
int
index
,
double
value
);
private:
std
::
vector
<
Lepton
::
CompiledExpression
*>
expressions
;
std
::
vector
<
std
::
string
>
variables
;
std
::
vector
<
std
::
vector
<
double
*>
>
variableReferences
;
};
}
// namespace OpenMM
#endif
/*OPENMM_COMPILEDEXPRESSIONSET_H_*/
platforms/cpu/include/CpuCustomManyParticleForce.h
0 → 100644
View file @
604881dc
/* 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_MANY_PARTICLE_FORCE_H__
#define OPENMM_CPU_CUSTOM_MANY_PARTICLE_FORCE_H__
#include "ReferenceForce.h"
#include "ReferenceBondIxn.h"
#include "CompiledExpressionSet.h"
#include "CpuNeighborList.h"
#include "openmm/CustomManyParticleForce.h"
#include "openmm/internal/ThreadPool.h"
#include "openmm/internal/vectorize.h"
#include "lepton/CompiledExpression.h"
#include "lepton/ParsedExpression.h"
#include <map>
#include <set>
#include <utility>
#include <vector>
namespace
OpenMM
{
class
CpuCustomManyParticleForce
{
private:
class
ParticleTermInfo
;
class
DistanceTermInfo
;
class
AngleTermInfo
;
class
DihedralTermInfo
;
class
ComputeForceTask
;
class
ThreadData
;
int
numParticles
,
numParticlesPerSet
,
numPerParticleParameters
,
numTypes
;
bool
useCutoff
,
usePeriodic
,
centralParticleMode
;
RealOpenMM
cutoffDistance
;
RealOpenMM
periodicBoxSize
[
3
];
CpuNeighborList
*
neighborList
;
ThreadPool
&
threads
;
std
::
vector
<
std
::
set
<
int
>
>
exclusions
;
std
::
vector
<
int
>
particleTypes
;
std
::
vector
<
int
>
orderIndex
;
std
::
vector
<
std
::
vector
<
int
>
>
particleOrder
;
std
::
vector
<
std
::
vector
<
int
>
>
particleNeighbors
;
std
::
vector
<
ThreadData
*>
threadData
;
// The following variables are used to make information accessible to the individual threads.
float
*
posq
;
RealOpenMM
**
particleParameters
;
const
std
::
map
<
std
::
string
,
double
>*
globalParameters
;
std
::
vector
<
AlignedArray
<
float
>
>*
threadForce
;
bool
includeForces
,
includeEnergy
;
void
*
atomicCounter
;
/**
* This routine contains the code executed by each thread.
*/
void
threadComputeForce
(
ThreadPool
&
threads
,
int
threadIndex
);
/**
* This is called recursively to loop over all possible combination of a set of particles and evaluate the
* interaction for each one.
*/
void
loopOverInteractions
(
std
::
vector
<
int
>&
availableParticles
,
std
::
vector
<
int
>&
particleSet
,
int
loopIndex
,
int
startIndex
,
RealOpenMM
**
particleParameters
,
float
*
forces
,
ThreadData
&
data
,
const
fvec4
&
boxSize
,
const
fvec4
&
invBoxSize
);
/**---------------------------------------------------------------------------------------
Calculate custom interaction for one set of particles
@param particleSet the indices of the particles
@param posq atom coordinates in float format
@param particleParameters particle parameter values (particleParameters[particleIndex][parameterIndex])
@param forces force array (forces added)
@param totalEnergy total energy
--------------------------------------------------------------------------------------- */
/**
* Calculate the interaction for one set of particles
*
* @param particleSet the indices of the particles
* @param particleParameters particle parameter values (particleParameters[particleIndex][parameterIndex])
* @param data information and workspace for the current thread
* @param boxSize the size of the periodic box
* @param invBoxSize the inverse size of the periodic box
*/
void
calculateOneIxn
(
std
::
vector
<
int
>&
particleSet
,
RealOpenMM
**
particleParameters
,
float
*
forces
,
ThreadData
&
data
,
const
fvec4
&
boxSize
,
const
fvec4
&
invBoxSize
);
/**
* Compute the displacement and squared distance between two points, optionally using
* periodic boundary conditions.
*/
void
computeDelta
(
const
fvec4
&
posI
,
const
fvec4
&
posJ
,
fvec4
&
deltaR
,
float
&
r2
,
const
fvec4
&
boxSize
,
const
fvec4
&
invBoxSize
)
const
;
static
float
computeAngle
(
const
fvec4
&
vi
,
const
fvec4
&
vj
,
float
v2i
,
float
v2j
,
float
sign
);
static
float
getDihedralAngleBetweenThreeVectors
(
const
fvec4
&
v1
,
const
fvec4
&
v2
,
const
fvec4
&
v3
,
fvec4
&
cross1
,
fvec4
&
cross2
,
const
fvec4
&
signVector
);
public:
/**
* Create a new CpuCustomManyParticleForce.
*
* @param force the CustomManyParticleForce to create it for
* @param threads the thread pool to use
*/
CpuCustomManyParticleForce
(
const
OpenMM
::
CustomManyParticleForce
&
force
,
ThreadPool
&
threads
);
~
CpuCustomManyParticleForce
();
/**
* Set the force to use a cutoff.
*
* @param distance the cutoff distance
*/
void
setUseCutoff
(
RealOpenMM
distance
);
/**
* 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 the interaction.
*
* @param posq atom coordinates in float format
* @param particleParameters particle parameter values (particleParameters[particleIndex][parameterIndex])
* @param globalParameters the values of global parameters
* @param threadForce the collection of arrays for each thread to add forces to
* @param includeForce whether to compute forces
* @param includeEnergy whether to compute energy
* @param energy the total energy is added to this
*/
void
calculateIxn
(
AlignedArray
<
float
>&
posq
,
RealOpenMM
**
particleParameters
,
const
std
::
map
<
std
::
string
,
double
>&
globalParameters
,
std
::
vector
<
AlignedArray
<
float
>
>&
threadForce
,
bool
includeForces
,
bool
includeEnergy
,
double
&
energy
);
};
class
CpuCustomManyParticleForce
::
ParticleTermInfo
{
public:
std
::
string
name
;
int
atom
,
component
,
variableIndex
;
Lepton
::
CompiledExpression
forceExpression
;
ParticleTermInfo
(
const
std
::
string
&
name
,
int
atom
,
int
component
,
const
Lepton
::
CompiledExpression
&
forceExpression
,
ThreadData
&
data
);
};
class
CpuCustomManyParticleForce
::
DistanceTermInfo
{
public:
std
::
string
name
;
int
p1
,
p2
,
variableIndex
;
Lepton
::
CompiledExpression
forceExpression
;
int
delta
;
float
deltaSign
;
DistanceTermInfo
(
const
std
::
string
&
name
,
const
std
::
vector
<
int
>&
atoms
,
const
Lepton
::
CompiledExpression
&
forceExpression
,
ThreadData
&
data
);
};
class
CpuCustomManyParticleForce
::
AngleTermInfo
{
public:
std
::
string
name
;
int
p1
,
p2
,
p3
,
variableIndex
;
Lepton
::
CompiledExpression
forceExpression
;
int
delta1
,
delta2
;
float
delta1Sign
,
delta2Sign
;
AngleTermInfo
(
const
std
::
string
&
name
,
const
std
::
vector
<
int
>&
atoms
,
const
Lepton
::
CompiledExpression
&
forceExpression
,
ThreadData
&
data
);
};
class
CpuCustomManyParticleForce
::
DihedralTermInfo
{
public:
std
::
string
name
;
int
p1
,
p2
,
p3
,
p4
,
variableIndex
;
Lepton
::
CompiledExpression
forceExpression
;
int
delta1
,
delta2
,
delta3
;
DihedralTermInfo
(
const
std
::
string
&
name
,
const
std
::
vector
<
int
>&
atoms
,
const
Lepton
::
CompiledExpression
&
forceExpression
,
ThreadData
&
data
);
};
class
CpuCustomManyParticleForce
::
ThreadData
{
public:
CompiledExpressionSet
expressionSet
;
Lepton
::
CompiledExpression
energyExpression
;
std
::
vector
<
std
::
vector
<
int
>
>
particleParamIndices
;
std
::
vector
<
int
>
permutedParticles
;
std
::
vector
<
std
::
pair
<
int
,
int
>
>
deltaPairs
;
std
::
vector
<
ParticleTermInfo
>
particleTerms
;
std
::
vector
<
DistanceTermInfo
>
distanceTerms
;
std
::
vector
<
AngleTermInfo
>
angleTerms
;
std
::
vector
<
DihedralTermInfo
>
dihedralTerms
;
AlignedArray
<
fvec4
>
delta
,
cross1
,
cross2
;
std
::
vector
<
float
>
normDelta
;
std
::
vector
<
float
>
norm2Delta
;
AlignedArray
<
fvec4
>
f
;
double
energy
;
ThreadData
(
const
CustomManyParticleForce
&
force
,
Lepton
::
ParsedExpression
&
energyExpr
,
std
::
map
<
std
::
string
,
std
::
vector
<
int
>
>&
distances
,
std
::
map
<
std
::
string
,
std
::
vector
<
int
>
>&
angles
,
std
::
map
<
std
::
string
,
std
::
vector
<
int
>
>&
dihedrals
);
/**
* Request a pair of particles whose distance or displacement vector is needed in the computation.
*/
void
requestDeltaPair
(
int
p1
,
int
p2
,
int
&
pairIndex
,
float
&
pairSign
,
bool
allowReversed
);
};
}
// namespace OpenMM
#endif // OPENMM_CPU_CUSTOM_MANY_PARTICLE_FORCE_H__
platforms/cpu/include/CpuKernels.h
View file @
604881dc
...
@@ -33,6 +33,7 @@
...
@@ -33,6 +33,7 @@
* -------------------------------------------------------------------------- */
* -------------------------------------------------------------------------- */
#include "CpuBondForce.h"
#include "CpuBondForce.h"
#include "CpuCustomManyParticleForce.h"
#include "CpuCustomNonbondedForce.h"
#include "CpuCustomNonbondedForce.h"
#include "CpuGBSAOBCForce.h"
#include "CpuGBSAOBCForce.h"
#include "CpuLangevinDynamics.h"
#include "CpuLangevinDynamics.h"
...
@@ -302,6 +303,48 @@ private:
...
@@ -302,6 +303,48 @@ private:
CpuGBSAOBCForce
obc
;
CpuGBSAOBCForce
obc
;
};
};
/**
* This kernel is invoked by CustomManyParticleForce to calculate the forces acting on the system and the energy of the system.
*/
class
CpuCalcCustomManyParticleForceKernel
:
public
CalcCustomManyParticleForceKernel
{
public:
CpuCalcCustomManyParticleForceKernel
(
std
::
string
name
,
const
Platform
&
platform
,
CpuPlatform
::
PlatformData
&
data
)
:
CalcCustomManyParticleForceKernel
(
name
,
platform
),
data
(
data
),
ixn
(
NULL
)
{
}
~
CpuCalcCustomManyParticleForceKernel
();
/**
* Initialize the kernel.
*
* @param system the System this kernel will be applied to
* @param force the CustomManyParticleForce this kernel will be used for
*/
void
initialize
(
const
System
&
system
,
const
CustomManyParticleForce
&
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 CustomManyParticleForce to copy the parameters from
*/
void
copyParametersToContext
(
ContextImpl
&
context
,
const
CustomManyParticleForce
&
force
);
private:
CpuPlatform
::
PlatformData
&
data
;
int
numParticles
;
RealOpenMM
cutoffDistance
;
RealOpenMM
**
particleParamArray
;
CpuCustomManyParticleForce
*
ixn
;
std
::
vector
<
std
::
string
>
globalParameterNames
;
NonbondedMethod
nonbondedMethod
;
};
/**
/**
* This kernel is invoked by LangevinIntegrator to take one time step.
* This kernel is invoked by LangevinIntegrator to take one time step.
*/
*/
...
...
platforms/cpu/src/CompiledExpressionSet.cpp
0 → 100644
View file @
604881dc
/* Portions copyright (c) 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 "CompiledExpressionSet.h"
using
namespace
OpenMM
;
using
namespace
Lepton
;
using
namespace
std
;
CompiledExpressionSet
::
CompiledExpressionSet
()
{
}
void
CompiledExpressionSet
::
registerExpression
(
Lepton
::
CompiledExpression
&
expression
)
{
expressions
.
push_back
(
&
expression
);
for
(
int
i
=
0
;
i
<
(
int
)
variables
.
size
();
i
++
)
if
(
expression
.
getVariables
().
find
(
variables
[
i
])
!=
expression
.
getVariables
().
end
())
variableReferences
[
i
].
push_back
(
&
expression
.
getVariableReference
(
variables
[
i
]));
}
int
CompiledExpressionSet
::
getVariableIndex
(
const
std
::
string
&
name
)
{
for
(
int
i
=
0
;
i
<
(
int
)
variables
.
size
();
i
++
)
if
(
variables
[
i
]
==
name
)
return
i
;
int
index
=
variables
.
size
();
variables
.
push_back
(
name
);
variableReferences
.
push_back
(
vector
<
double
*>
());
for
(
int
i
=
0
;
i
<
(
int
)
expressions
.
size
();
i
++
)
if
(
expressions
[
i
]
->
getVariables
().
find
(
name
)
!=
expressions
[
i
]
->
getVariables
().
end
())
variableReferences
[
index
].
push_back
(
&
expressions
[
i
]
->
getVariableReference
(
name
));
return
index
;
}
void
CompiledExpressionSet
::
setVariable
(
int
index
,
double
value
)
{
for
(
int
i
=
0
;
i
<
(
int
)
variableReferences
[
index
].
size
();
i
++
)
*
variableReferences
[
index
][
i
]
=
value
;
}
platforms/cpu/src/CpuCustomManyParticleForce.cpp
0 → 100644
View file @
604881dc
/* 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 <utility>
#include "SimTKOpenMMCommon.h"
#include "SimTKOpenMMLog.h"
#include "SimTKOpenMMUtilities.h"
#include "ReferenceForce.h"
#include "CpuCustomManyParticleForce.h"
#include "ReferenceTabulatedFunction.h"
#include "openmm/internal/CustomManyParticleForceImpl.h"
#include "lepton/CustomFunction.h"
#include "gmx_atomic.h"
using
namespace
OpenMM
;
using
namespace
std
;
class
CpuCustomManyParticleForce
::
ComputeForceTask
:
public
ThreadPool
::
Task
{
public:
ComputeForceTask
(
CpuCustomManyParticleForce
&
owner
)
:
owner
(
owner
)
{
}
void
execute
(
ThreadPool
&
threads
,
int
threadIndex
)
{
owner
.
threadComputeForce
(
threads
,
threadIndex
);
}
CpuCustomManyParticleForce
&
owner
;
};
CpuCustomManyParticleForce
::
CpuCustomManyParticleForce
(
const
CustomManyParticleForce
&
force
,
ThreadPool
&
threads
)
:
threads
(
threads
),
useCutoff
(
false
),
usePeriodic
(
false
),
neighborList
(
NULL
)
{
numParticles
=
force
.
getNumParticles
();
numParticlesPerSet
=
force
.
getNumParticlesPerSet
();
numPerParticleParameters
=
force
.
getNumPerParticleParameters
();
centralParticleMode
=
(
force
.
getPermutationMode
()
==
CustomManyParticleForce
::
UniqueCentralParticle
);
// Create custom functions for the tabulated functions.
map
<
string
,
Lepton
::
CustomFunction
*>
functions
;
for
(
int
i
=
0
;
i
<
(
int
)
force
.
getNumTabulatedFunctions
();
i
++
)
functions
[
force
.
getTabulatedFunctionName
(
i
)]
=
createReferenceTabulatedFunction
(
force
.
getTabulatedFunction
(
i
));
// Parse the expression and create the objects used to calculate the interaction.
map
<
string
,
vector
<
int
>
>
distances
;
map
<
string
,
vector
<
int
>
>
angles
;
map
<
string
,
vector
<
int
>
>
dihedrals
;
Lepton
::
ParsedExpression
energyExpr
=
CustomManyParticleForceImpl
::
prepareExpression
(
force
,
functions
,
distances
,
angles
,
dihedrals
);
for
(
int
i
=
0
;
i
<
threads
.
getNumThreads
();
i
++
)
threadData
.
push_back
(
new
ThreadData
(
force
,
energyExpr
,
distances
,
angles
,
dihedrals
));
if
(
force
.
getNonbondedMethod
()
!=
CustomManyParticleForce
::
NoCutoff
)
setUseCutoff
(
force
.
getCutoffDistance
());
// Delete the custom functions.
for
(
map
<
string
,
Lepton
::
CustomFunction
*>::
iterator
iter
=
functions
.
begin
();
iter
!=
functions
.
end
();
iter
++
)
delete
iter
->
second
;
// Record exclusions.
exclusions
.
resize
(
force
.
getNumParticles
());
for
(
int
i
=
0
;
i
<
(
int
)
force
.
getNumExclusions
();
i
++
)
{
int
p1
,
p2
;
force
.
getExclusionParticles
(
i
,
p1
,
p2
);
exclusions
[
p1
].
insert
(
p2
);
exclusions
[
p2
].
insert
(
p1
);
}
// Record information about type filters.
CustomManyParticleForceImpl
::
buildFilterArrays
(
force
,
numTypes
,
particleTypes
,
orderIndex
,
particleOrder
);
}
CpuCustomManyParticleForce
::~
CpuCustomManyParticleForce
()
{
if
(
neighborList
!=
NULL
)
delete
neighborList
;
for
(
int
i
=
0
;
i
<
(
int
)
threadData
.
size
();
i
++
)
delete
threadData
[
i
];
}
void
CpuCustomManyParticleForce
::
calculateIxn
(
AlignedArray
<
float
>&
posq
,
RealOpenMM
**
particleParameters
,
const
map
<
string
,
double
>&
globalParameters
,
vector
<
AlignedArray
<
float
>
>&
threadForce
,
bool
includeForces
,
bool
includeEnergy
,
double
&
energy
)
{
// Record the parameters for the threads.
this
->
posq
=
&
posq
[
0
];
this
->
particleParameters
=
particleParameters
;
this
->
globalParameters
=
&
globalParameters
;
this
->
threadForce
=
&
threadForce
;
this
->
includeForces
=
includeForces
;
this
->
includeEnergy
=
includeEnergy
;
gmx_atomic_t
counter
;
gmx_atomic_set
(
&
counter
,
0
);
this
->
atomicCounter
=
&
counter
;
if
(
useCutoff
)
{
// Construct a neighbor list. We use CpuNeighborList to do this, but then copy the result
// into a new data structure. This is needed because in UniqueCentralParticle mode, the
// the neighbor list needs to include symmetric pairs.
particleNeighbors
.
resize
(
numParticles
);
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
particleNeighbors
[
i
].
clear
();
float
boxSizeFloat
[]
=
{(
float
)
periodicBoxSize
[
0
],
(
float
)
periodicBoxSize
[
1
],
(
float
)
periodicBoxSize
[
2
]};
neighborList
->
computeNeighborList
(
numParticles
,
posq
,
exclusions
,
boxSizeFloat
,
usePeriodic
,
cutoffDistance
,
threads
);
for
(
int
blockIndex
=
0
;
blockIndex
<
neighborList
->
getNumBlocks
();
blockIndex
++
)
{
const
vector
<
int
>&
neighbors
=
neighborList
->
getBlockNeighbors
(
blockIndex
);
const
vector
<
char
>&
exclusions
=
neighborList
->
getBlockExclusions
(
blockIndex
);
int
numNeighbors
=
neighbors
.
size
();
for
(
int
i
=
0
;
i
<
4
;
i
++
)
{
int
p1
=
neighborList
->
getSortedAtoms
()[
4
*
blockIndex
+
i
];
for
(
int
j
=
0
;
j
<
numNeighbors
;
j
++
)
{
if
((
exclusions
[
j
]
&
(
1
<<
i
))
==
0
)
{
int
p2
=
neighbors
[
j
];
particleNeighbors
[
p1
].
push_back
(
p2
);
if
(
centralParticleMode
)
particleNeighbors
[
p2
].
push_back
(
p1
);
}
}
}
}
}
// Signal the threads to start running and wait for them to finish.
ComputeForceTask
task
(
*
this
);
threads
.
execute
(
task
);
threads
.
waitForThreads
();
// Combine the energies from all the threads.
if
(
includeEnergy
)
{
int
numThreads
=
threads
.
getNumThreads
();
for
(
int
i
=
0
;
i
<
numThreads
;
i
++
)
energy
+=
threadData
[
i
]
->
energy
;
}
}
void
CpuCustomManyParticleForce
::
threadComputeForce
(
ThreadPool
&
threads
,
int
threadIndex
)
{
vector
<
int
>
particleIndices
(
numParticlesPerSet
);
fvec4
boxSize
(
periodicBoxSize
[
0
],
periodicBoxSize
[
1
],
periodicBoxSize
[
2
],
0
);
fvec4
invBoxSize
((
1
/
periodicBoxSize
[
0
]),
(
1
/
periodicBoxSize
[
1
]),
(
1
/
periodicBoxSize
[
2
]),
0
);
float
*
forces
=
&
(
*
threadForce
)[
threadIndex
][
0
];
ThreadData
&
data
=
*
threadData
[
threadIndex
];
data
.
energy
=
0
;
for
(
map
<
string
,
double
>::
const_iterator
iter
=
globalParameters
->
begin
();
iter
!=
globalParameters
->
end
();
++
iter
)
data
.
expressionSet
.
setVariable
(
data
.
expressionSet
.
getVariableIndex
(
iter
->
first
),
iter
->
second
);
if
(
useCutoff
)
{
// Loop over interactions from the neighbor list.
while
(
true
)
{
int
i
=
gmx_atomic_fetch_add
(
reinterpret_cast
<
gmx_atomic_t
*>
(
atomicCounter
),
1
);
if
(
i
>=
numParticles
)
break
;
particleIndices
[
0
]
=
i
;
loopOverInteractions
(
particleNeighbors
[
i
],
particleIndices
,
1
,
0
,
particleParameters
,
forces
,
data
,
boxSize
,
invBoxSize
);
}
}
else
{
// Loop over all possible sets of particles.
vector
<
int
>
particles
(
numParticles
);
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
particles
[
i
]
=
i
;
while
(
true
)
{
int
i
=
gmx_atomic_fetch_add
(
reinterpret_cast
<
gmx_atomic_t
*>
(
atomicCounter
),
1
);
if
(
i
>=
numParticles
)
break
;
particleIndices
[
0
]
=
i
;
int
startIndex
=
(
centralParticleMode
?
0
:
i
+
1
);
loopOverInteractions
(
particles
,
particleIndices
,
1
,
startIndex
,
particleParameters
,
forces
,
data
,
boxSize
,
invBoxSize
);
}
}
}
void
CpuCustomManyParticleForce
::
setUseCutoff
(
RealOpenMM
distance
)
{
useCutoff
=
true
;
cutoffDistance
=
distance
;
if
(
neighborList
==
NULL
)
neighborList
=
new
CpuNeighborList
(
4
);
}
void
CpuCustomManyParticleForce
::
setPeriodic
(
RealVec
&
boxSize
)
{
assert
(
useCutoff
);
assert
(
boxSize
[
0
]
>=
2.0
*
cutoffDistance
);
assert
(
boxSize
[
1
]
>=
2.0
*
cutoffDistance
);
assert
(
boxSize
[
2
]
>=
2.0
*
cutoffDistance
);
usePeriodic
=
true
;
periodicBoxSize
[
0
]
=
boxSize
[
0
];
periodicBoxSize
[
1
]
=
boxSize
[
1
];
periodicBoxSize
[
2
]
=
boxSize
[
2
];
}
void
CpuCustomManyParticleForce
::
loopOverInteractions
(
vector
<
int
>&
availableParticles
,
vector
<
int
>&
particleSet
,
int
loopIndex
,
int
startIndex
,
RealOpenMM
**
particleParameters
,
float
*
forces
,
ThreadData
&
data
,
const
fvec4
&
boxSize
,
const
fvec4
&
invBoxSize
)
{
int
numParticles
=
availableParticles
.
size
();
double
cutoff2
=
cutoffDistance
*
cutoffDistance
;
int
checkRange
=
(
centralParticleMode
?
1
:
loopIndex
);
for
(
int
i
=
startIndex
;
i
<
numParticles
;
i
++
)
{
int
particle
=
availableParticles
[
i
];
// Check whether this particle can actually participate in interactions with the others found so far.
bool
include
=
true
;
if
(
useCutoff
)
{
fvec4
deltaR
;
fvec4
pos1
(
posq
+
4
*
particle
);
float
r2
;
for
(
int
j
=
0
;
j
<
checkRange
&&
include
;
j
++
)
{
fvec4
pos2
(
posq
+
4
*
particleSet
[
j
]);
computeDelta
(
pos1
,
pos2
,
deltaR
,
r2
,
boxSize
,
invBoxSize
);
include
&=
(
r2
<
cutoff2
);
}
}
for
(
int
j
=
0
;
j
<
loopIndex
&&
include
;
j
++
)
include
&=
(
exclusions
[
particle
].
find
(
particleSet
[
j
])
==
exclusions
[
particle
].
end
());
if
(
include
)
{
if
(
loopIndex
>
0
&&
availableParticles
[
i
]
==
particleSet
[
0
])
continue
;
particleSet
[
loopIndex
]
=
availableParticles
[
i
];
if
(
loopIndex
==
numParticlesPerSet
-
1
)
calculateOneIxn
(
particleSet
,
particleParameters
,
forces
,
data
,
boxSize
,
invBoxSize
);
else
loopOverInteractions
(
availableParticles
,
particleSet
,
loopIndex
+
1
,
i
+
1
,
particleParameters
,
forces
,
data
,
boxSize
,
invBoxSize
);
}
}
}
void
CpuCustomManyParticleForce
::
calculateOneIxn
(
vector
<
int
>&
particleSet
,
RealOpenMM
**
particleParameters
,
float
*
forces
,
ThreadData
&
data
,
const
fvec4
&
boxSize
,
const
fvec4
&
invBoxSize
)
{
// Select the ordering to use for the particles.
vector
<
int
>&
permutedParticles
=
data
.
permutedParticles
;
if
(
particleOrder
.
size
()
==
1
)
{
// There are no filters, so we don't need to worry about ordering.
permutedParticles
=
particleSet
;
}
else
{
int
index
=
0
;
for
(
int
i
=
numParticlesPerSet
-
1
;
i
>=
0
;
i
--
)
index
=
particleTypes
[
particleSet
[
i
]]
+
numTypes
*
index
;
int
order
=
orderIndex
[
index
];
if
(
order
==
-
1
)
return
;
for
(
int
i
=
0
;
i
<
numParticlesPerSet
;
i
++
)
permutedParticles
[
i
]
=
particleSet
[
particleOrder
[
order
][
i
]];
}
// Record per-particle parameters.
CompiledExpressionSet
&
expressionSet
=
data
.
expressionSet
;
for
(
int
i
=
0
;
i
<
numParticlesPerSet
;
i
++
)
for
(
int
j
=
0
;
j
<
numPerParticleParameters
;
j
++
)
expressionSet
.
setVariable
(
data
.
particleParamIndices
[
i
][
j
],
particleParameters
[
permutedParticles
[
i
]][
j
]);
// Compute inter-particle deltas.
int
numDeltas
=
data
.
deltaPairs
.
size
();
AlignedArray
<
fvec4
>&
delta
=
data
.
delta
;
AlignedArray
<
fvec4
>&
cross1
=
data
.
cross1
;
AlignedArray
<
fvec4
>&
cross2
=
data
.
cross2
;
vector
<
float
>&
normDelta
=
data
.
normDelta
;
vector
<
float
>&
norm2Delta
=
data
.
norm2Delta
;
for
(
int
i
=
0
;
i
<
numDeltas
;
i
++
)
{
int
p1
=
permutedParticles
[
data
.
deltaPairs
[
i
].
first
];
int
p2
=
permutedParticles
[
data
.
deltaPairs
[
i
].
second
];
computeDelta
(
fvec4
(
posq
+
4
*
p1
),
fvec4
(
posq
+
4
*
p2
),
delta
[
i
],
norm2Delta
[
i
],
boxSize
,
invBoxSize
);
normDelta
[
i
]
=
sqrtf
(
norm2Delta
[
i
]);
}
// Compute all of the variables the energy can depend on.
for
(
int
i
=
0
;
i
<
(
int
)
data
.
particleTerms
.
size
();
i
++
)
{
const
ParticleTermInfo
&
term
=
data
.
particleTerms
[
i
];
expressionSet
.
setVariable
(
term
.
variableIndex
,
posq
[
4
*
permutedParticles
[
term
.
atom
]
+
term
.
component
]);
}
for
(
int
i
=
0
;
i
<
(
int
)
data
.
distanceTerms
.
size
();
i
++
)
{
const
DistanceTermInfo
&
term
=
data
.
distanceTerms
[
i
];
expressionSet
.
setVariable
(
term
.
variableIndex
,
normDelta
[
term
.
delta
]);
}
for
(
int
i
=
0
;
i
<
(
int
)
data
.
angleTerms
.
size
();
i
++
)
{
const
AngleTermInfo
&
term
=
data
.
angleTerms
[
i
];
expressionSet
.
setVariable
(
term
.
variableIndex
,
computeAngle
(
delta
[
term
.
delta1
],
delta
[
term
.
delta2
],
norm2Delta
[
term
.
delta1
],
norm2Delta
[
term
.
delta2
],
term
.
delta1Sign
*
term
.
delta2Sign
));
}
for
(
int
i
=
0
;
i
<
(
int
)
data
.
dihedralTerms
.
size
();
i
++
)
{
const
DihedralTermInfo
&
term
=
data
.
dihedralTerms
[
i
];
expressionSet
.
setVariable
(
term
.
variableIndex
,
getDihedralAngleBetweenThreeVectors
(
delta
[
term
.
delta1
],
delta
[
term
.
delta2
],
delta
[
term
.
delta3
],
cross1
[
i
],
cross2
[
i
],
delta
[
term
.
delta1
]));
}
if
(
includeForces
)
{
// Apply forces based on individual particle coordinates.
AlignedArray
<
fvec4
>&
f
=
data
.
f
;
for
(
int
i
=
0
;
i
<
numParticlesPerSet
;
i
++
)
f
[
i
]
=
fvec4
(
0.0
f
);
for
(
int
i
=
0
;
i
<
(
int
)
data
.
particleTerms
.
size
();
i
++
)
{
const
ParticleTermInfo
&
term
=
data
.
particleTerms
[
i
];
float
temp
[
4
];
f
[
term
.
atom
].
store
(
temp
);
temp
[
term
.
component
]
-=
term
.
forceExpression
.
evaluate
();
f
[
term
.
atom
]
=
fvec4
(
temp
);
}
// Apply forces based on distances.
for
(
int
i
=
0
;
i
<
(
int
)
data
.
distanceTerms
.
size
();
i
++
)
{
const
DistanceTermInfo
&
term
=
data
.
distanceTerms
[
i
];
float
dEdR
=
(
float
)
(
term
.
forceExpression
.
evaluate
()
*
term
.
deltaSign
/
(
normDelta
[
term
.
delta
]));
fvec4
force
=
-
dEdR
*
delta
[
term
.
delta
];
f
[
term
.
p1
]
-=
force
;
f
[
term
.
p2
]
+=
force
;
}
// Apply forces based on angles.
for
(
int
i
=
0
;
i
<
(
int
)
data
.
angleTerms
.
size
();
i
++
)
{
const
AngleTermInfo
&
term
=
data
.
angleTerms
[
i
];
float
dEdTheta
=
(
float
)
term
.
forceExpression
.
evaluate
();
fvec4
thetaCross
=
cross
(
delta
[
term
.
delta1
],
delta
[
term
.
delta2
]);
float
lengthThetaCross
=
sqrtf
(
dot3
(
thetaCross
,
thetaCross
));
if
(
lengthThetaCross
<
1.0e-6
f
)
lengthThetaCross
=
1.0e-6
f
;
float
termA
=
dEdTheta
*
term
.
delta2Sign
/
(
norm2Delta
[
term
.
delta1
]
*
lengthThetaCross
);
float
termC
=
-
dEdTheta
*
term
.
delta1Sign
/
(
norm2Delta
[
term
.
delta2
]
*
lengthThetaCross
);
fvec4
deltaCross1
=
cross
(
delta
[
term
.
delta1
],
thetaCross
);
fvec4
deltaCross2
=
cross
(
delta
[
term
.
delta2
],
thetaCross
);
fvec4
force1
=
termA
*
deltaCross1
;
fvec4
force3
=
termC
*
deltaCross2
;
fvec4
force2
=
-
(
force1
+
force3
);
f
[
term
.
p1
]
+=
force1
;
f
[
term
.
p2
]
+=
force2
;
f
[
term
.
p3
]
+=
force3
;
}
// Apply forces based on dihedrals.
for
(
int
i
=
0
;
i
<
(
int
)
data
.
dihedralTerms
.
size
();
i
++
)
{
const
DihedralTermInfo
&
term
=
data
.
dihedralTerms
[
i
];
float
dEdTheta
=
(
float
)
term
.
forceExpression
.
evaluate
();
float
normCross1
=
dot3
(
cross1
[
i
],
cross1
[
i
]);
float
normBC
=
normDelta
[
term
.
delta2
];
float
forceFactors
[
4
];
forceFactors
[
0
]
=
(
-
dEdTheta
*
normBC
)
/
normCross1
;
float
normCross2
=
dot3
(
cross2
[
i
],
cross2
[
i
]);
forceFactors
[
3
]
=
(
dEdTheta
*
normBC
)
/
normCross2
;
forceFactors
[
1
]
=
dot3
(
delta
[
term
.
delta1
],
delta
[
term
.
delta2
]);
forceFactors
[
1
]
/=
norm2Delta
[
term
.
delta2
];
forceFactors
[
2
]
=
dot3
(
delta
[
term
.
delta3
],
delta
[
term
.
delta2
]);
forceFactors
[
2
]
/=
norm2Delta
[
term
.
delta2
];
fvec4
force1
=
forceFactors
[
0
]
*
cross1
[
i
];
fvec4
force4
=
forceFactors
[
3
]
*
cross2
[
i
];
fvec4
s
=
forceFactors
[
1
]
*
force1
-
forceFactors
[
2
]
*
force4
;
f
[
term
.
p1
]
+=
force1
;
f
[
term
.
p2
]
-=
force1
-
s
;
f
[
term
.
p3
]
-=
force4
+
s
;
f
[
term
.
p4
]
+=
force4
;
}
// Store the forces.
for
(
int
i
=
0
;
i
<
numParticlesPerSet
;
i
++
)
{
int
index
=
permutedParticles
[
i
];
(
fvec4
(
forces
+
4
*
index
)
+
f
[
i
]).
store
(
forces
+
4
*
index
);
}
}
// Add the energy
if
(
includeEnergy
)
data
.
energy
+=
data
.
energyExpression
.
evaluate
();
}
void
CpuCustomManyParticleForce
::
computeDelta
(
const
fvec4
&
posI
,
const
fvec4
&
posJ
,
fvec4
&
deltaR
,
float
&
r2
,
const
fvec4
&
boxSize
,
const
fvec4
&
invBoxSize
)
const
{
deltaR
=
posJ
-
posI
;
if
(
usePeriodic
)
{
fvec4
base
=
round
(
deltaR
*
invBoxSize
)
*
boxSize
;
deltaR
=
deltaR
-
base
;
}
r2
=
dot3
(
deltaR
,
deltaR
);
}
float
CpuCustomManyParticleForce
::
computeAngle
(
const
fvec4
&
vi
,
const
fvec4
&
vj
,
float
v2i
,
float
v2j
,
float
sign
)
{
float
dot
=
dot3
(
vi
,
vj
)
*
sign
;
float
cosine
=
dot
/
sqrtf
(
v2i
*
v2j
);
if
(
cosine
>
0.99
f
||
cosine
<
-
0.99
f
)
{
// We're close to the singularity in acos(), so take the cross product and use asin() instead.
fvec4
cross12
=
cross
(
vi
,
vj
);
float
scale
=
v2i
*
v2j
;
float
angle
=
asinf
(
sqrtf
(
dot3
(
cross12
,
cross12
)
/
scale
));
if
(
cosine
<
0.0
f
)
angle
=
(
float
)
(
M_PI
-
angle
);
return
angle
;
}
return
acosf
(
cosine
);
}
float
CpuCustomManyParticleForce
::
getDihedralAngleBetweenThreeVectors
(
const
fvec4
&
v1
,
const
fvec4
&
v2
,
const
fvec4
&
v3
,
fvec4
&
cross1
,
fvec4
&
cross2
,
const
fvec4
&
signVector
)
{
cross1
=
cross
(
v1
,
v2
);
cross2
=
cross
(
v2
,
v3
);
float
angle
=
computeAngle
(
cross1
,
cross2
,
dot3
(
cross1
,
cross1
),
dot3
(
cross2
,
cross2
),
1.0
f
);
float
dotProduct
=
dot3
(
signVector
,
cross2
);
if
(
dotProduct
<
0
)
angle
=
-
angle
;
return
angle
;
}
CpuCustomManyParticleForce
::
ParticleTermInfo
::
ParticleTermInfo
(
const
string
&
name
,
int
atom
,
int
component
,
const
Lepton
::
CompiledExpression
&
forceExpression
,
ThreadData
&
data
)
:
name
(
name
),
atom
(
atom
),
component
(
component
),
forceExpression
(
forceExpression
)
{
variableIndex
=
data
.
expressionSet
.
getVariableIndex
(
name
);
}
CpuCustomManyParticleForce
::
DistanceTermInfo
::
DistanceTermInfo
(
const
string
&
name
,
const
vector
<
int
>&
atoms
,
const
Lepton
::
CompiledExpression
&
forceExpression
,
ThreadData
&
data
)
:
name
(
name
),
p1
(
atoms
[
0
]),
p2
(
atoms
[
1
]),
forceExpression
(
forceExpression
)
{
variableIndex
=
data
.
expressionSet
.
getVariableIndex
(
name
);
data
.
requestDeltaPair
(
p1
,
p2
,
delta
,
deltaSign
,
true
);
}
CpuCustomManyParticleForce
::
AngleTermInfo
::
AngleTermInfo
(
const
string
&
name
,
const
vector
<
int
>&
atoms
,
const
Lepton
::
CompiledExpression
&
forceExpression
,
ThreadData
&
data
)
:
name
(
name
),
p1
(
atoms
[
0
]),
p2
(
atoms
[
1
]),
p3
(
atoms
[
2
]),
forceExpression
(
forceExpression
)
{
variableIndex
=
data
.
expressionSet
.
getVariableIndex
(
name
);
data
.
requestDeltaPair
(
p1
,
p2
,
delta1
,
delta1Sign
,
true
);
data
.
requestDeltaPair
(
p3
,
p2
,
delta2
,
delta2Sign
,
true
);
}
CpuCustomManyParticleForce
::
DihedralTermInfo
::
DihedralTermInfo
(
const
string
&
name
,
const
vector
<
int
>&
atoms
,
const
Lepton
::
CompiledExpression
&
forceExpression
,
ThreadData
&
data
)
:
name
(
name
),
p1
(
atoms
[
0
]),
p2
(
atoms
[
1
]),
p3
(
atoms
[
2
]),
p4
(
atoms
[
3
]),
forceExpression
(
forceExpression
)
{
variableIndex
=
data
.
expressionSet
.
getVariableIndex
(
name
);
float
sign
;
data
.
requestDeltaPair
(
p2
,
p1
,
delta1
,
sign
,
false
);
data
.
requestDeltaPair
(
p2
,
p3
,
delta2
,
sign
,
false
);
data
.
requestDeltaPair
(
p4
,
p3
,
delta3
,
sign
,
false
);
}
CpuCustomManyParticleForce
::
ThreadData
::
ThreadData
(
const
CustomManyParticleForce
&
force
,
Lepton
::
ParsedExpression
&
energyExpr
,
map
<
string
,
vector
<
int
>
>&
distances
,
map
<
string
,
vector
<
int
>
>&
angles
,
map
<
string
,
vector
<
int
>
>&
dihedrals
)
{
int
numParticlesPerSet
=
force
.
getNumParticlesPerSet
();
int
numPerParticleParameters
=
force
.
getNumPerParticleParameters
();
particleParamIndices
.
resize
(
numParticlesPerSet
);
permutedParticles
.
resize
(
numParticlesPerSet
);
f
.
resize
(
numParticlesPerSet
);
energyExpression
=
energyExpr
.
createCompiledExpression
();
expressionSet
.
registerExpression
(
energyExpression
);
// Differentiate the energy to get expressions for the force.
for
(
int
i
=
0
;
i
<
numParticlesPerSet
;
i
++
)
{
stringstream
xname
,
yname
,
zname
;
xname
<<
'x'
<<
(
i
+
1
);
yname
<<
'y'
<<
(
i
+
1
);
zname
<<
'z'
<<
(
i
+
1
);
particleTerms
.
push_back
(
CpuCustomManyParticleForce
::
ParticleTermInfo
(
xname
.
str
(),
i
,
0
,
energyExpr
.
differentiate
(
xname
.
str
()).
optimize
().
createCompiledExpression
(),
*
this
));
particleTerms
.
push_back
(
CpuCustomManyParticleForce
::
ParticleTermInfo
(
yname
.
str
(),
i
,
1
,
energyExpr
.
differentiate
(
yname
.
str
()).
optimize
().
createCompiledExpression
(),
*
this
));
particleTerms
.
push_back
(
CpuCustomManyParticleForce
::
ParticleTermInfo
(
zname
.
str
(),
i
,
2
,
energyExpr
.
differentiate
(
zname
.
str
()).
optimize
().
createCompiledExpression
(),
*
this
));
for
(
int
j
=
0
;
j
<
numPerParticleParameters
;
j
++
)
{
stringstream
paramname
;
paramname
<<
force
.
getPerParticleParameterName
(
j
)
<<
(
i
+
1
);
particleParamIndices
[
i
].
push_back
(
expressionSet
.
getVariableIndex
(
paramname
.
str
()));
}
}
for
(
map
<
string
,
vector
<
int
>
>::
const_iterator
iter
=
dihedrals
.
begin
();
iter
!=
dihedrals
.
end
();
++
iter
)
dihedralTerms
.
push_back
(
CpuCustomManyParticleForce
::
DihedralTermInfo
(
iter
->
first
,
iter
->
second
,
energyExpr
.
differentiate
(
iter
->
first
).
optimize
().
createCompiledExpression
(),
*
this
));
for
(
map
<
string
,
vector
<
int
>
>::
const_iterator
iter
=
distances
.
begin
();
iter
!=
distances
.
end
();
++
iter
)
distanceTerms
.
push_back
(
CpuCustomManyParticleForce
::
DistanceTermInfo
(
iter
->
first
,
iter
->
second
,
energyExpr
.
differentiate
(
iter
->
first
).
optimize
().
createCompiledExpression
(),
*
this
));
for
(
map
<
string
,
vector
<
int
>
>::
const_iterator
iter
=
angles
.
begin
();
iter
!=
angles
.
end
();
++
iter
)
angleTerms
.
push_back
(
CpuCustomManyParticleForce
::
AngleTermInfo
(
iter
->
first
,
iter
->
second
,
energyExpr
.
differentiate
(
iter
->
first
).
optimize
().
createCompiledExpression
(),
*
this
));
for
(
int
i
=
0
;
i
<
particleTerms
.
size
();
i
++
)
expressionSet
.
registerExpression
(
particleTerms
[
i
].
forceExpression
);
for
(
int
i
=
0
;
i
<
distanceTerms
.
size
();
i
++
)
expressionSet
.
registerExpression
(
distanceTerms
[
i
].
forceExpression
);
for
(
int
i
=
0
;
i
<
angleTerms
.
size
();
i
++
)
expressionSet
.
registerExpression
(
angleTerms
[
i
].
forceExpression
);
for
(
int
i
=
0
;
i
<
dihedralTerms
.
size
();
i
++
)
expressionSet
.
registerExpression
(
dihedralTerms
[
i
].
forceExpression
);
int
numDeltas
=
deltaPairs
.
size
();
delta
.
resize
(
numDeltas
);
normDelta
.
resize
(
numDeltas
);
norm2Delta
.
resize
(
numDeltas
);
cross1
.
resize
(
numDeltas
);
cross2
.
resize
(
numDeltas
);
}
void
CpuCustomManyParticleForce
::
ThreadData
::
requestDeltaPair
(
int
p1
,
int
p2
,
int
&
pairIndex
,
float
&
pairSign
,
bool
allowReversed
)
{
for
(
int
i
=
0
;
i
<
(
int
)
deltaPairs
.
size
();
i
++
)
{
if
(
deltaPairs
[
i
].
first
==
p1
&&
deltaPairs
[
i
].
second
==
p2
)
{
pairIndex
=
i
;
pairSign
=
1
;
return
;
}
if
(
deltaPairs
[
i
].
first
==
p2
&&
deltaPairs
[
i
].
second
==
p1
&&
allowReversed
)
{
pairIndex
=
i
;
pairSign
=
-
1
;
return
;
}
}
pairIndex
=
deltaPairs
.
size
();
pairSign
=
1
;
deltaPairs
.
push_back
(
make_pair
(
p1
,
p2
));
}
platforms/cpu/src/CpuKernelFactory.cpp
View file @
604881dc
...
@@ -49,6 +49,8 @@ KernelImpl* CpuKernelFactory::createKernelImpl(std::string name, const Platform&
...
@@ -49,6 +49,8 @@ KernelImpl* CpuKernelFactory::createKernelImpl(std::string name, const Platform&
return
new
CpuCalcNonbondedForceKernel
(
name
,
platform
,
data
);
return
new
CpuCalcNonbondedForceKernel
(
name
,
platform
,
data
);
if
(
name
==
CalcCustomNonbondedForceKernel
::
Name
())
if
(
name
==
CalcCustomNonbondedForceKernel
::
Name
())
return
new
CpuCalcCustomNonbondedForceKernel
(
name
,
platform
,
data
);
return
new
CpuCalcCustomNonbondedForceKernel
(
name
,
platform
,
data
);
if
(
name
==
CalcCustomManyParticleForceKernel
::
Name
())
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
==
IntegrateLangevinStepKernel
::
Name
())
if
(
name
==
IntegrateLangevinStepKernel
::
Name
())
...
...
platforms/cpu/src/CpuKernels.cpp
View file @
604881dc
...
@@ -835,6 +835,72 @@ void CpuCalcGBSAOBCForceKernel::copyParametersToContext(ContextImpl& context, co
...
@@ -835,6 +835,72 @@ void CpuCalcGBSAOBCForceKernel::copyParametersToContext(ContextImpl& context, co
obc
.
setParticleParameters
(
particleParams
);
obc
.
setParticleParameters
(
particleParams
);
}
}
CpuCalcCustomManyParticleForceKernel
::~
CpuCalcCustomManyParticleForceKernel
()
{
if
(
particleParamArray
!=
NULL
)
{
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
delete
[]
particleParamArray
[
i
];
delete
[]
particleParamArray
;
}
if
(
ixn
!=
NULL
)
delete
ixn
;
}
void
CpuCalcCustomManyParticleForceKernel
::
initialize
(
const
System
&
system
,
const
CustomManyParticleForce
&
force
)
{
// Build the arrays.
numParticles
=
system
.
getNumParticles
();
int
numParticleParameters
=
force
.
getNumPerParticleParameters
();
particleParamArray
=
new
double
*
[
numParticles
];
for
(
int
i
=
0
;
i
<
numParticles
;
i
++
)
particleParamArray
[
i
]
=
new
double
[
numParticleParameters
];
for
(
int
i
=
0
;
i
<
numParticles
;
++
i
)
{
vector
<
double
>
parameters
;
int
type
;
force
.
getParticleParameters
(
i
,
parameters
,
type
);
for
(
int
j
=
0
;
j
<
numParticleParameters
;
j
++
)
particleParamArray
[
i
][
j
]
=
parameters
[
j
];
}
for
(
int
i
=
0
;
i
<
force
.
getNumGlobalParameters
();
i
++
)
globalParameterNames
.
push_back
(
force
.
getGlobalParameterName
(
i
));
ixn
=
new
CpuCustomManyParticleForce
(
force
,
data
.
threads
);
nonbondedMethod
=
CalcCustomManyParticleForceKernel
::
NonbondedMethod
(
force
.
getNonbondedMethod
());
cutoffDistance
=
force
.
getCutoffDistance
();
}
double
CpuCalcCustomManyParticleForceKernel
::
execute
(
ContextImpl
&
context
,
bool
includeForces
,
bool
includeEnergy
)
{
map
<
string
,
double
>
globalParameters
;
for
(
int
i
=
0
;
i
<
(
int
)
globalParameterNames
.
size
();
i
++
)
globalParameters
[
globalParameterNames
[
i
]]
=
context
.
getParameter
(
globalParameterNames
[
i
]);
if
(
nonbondedMethod
==
CutoffPeriodic
)
{
RealVec
&
box
=
extractBoxSize
(
context
);
double
minAllowedSize
=
2
*
cutoffDistance
;
if
(
box
[
0
]
<
minAllowedSize
||
box
[
1
]
<
minAllowedSize
||
box
[
2
]
<
minAllowedSize
)
throw
OpenMMException
(
"The periodic box size has decreased to less than twice the nonbonded cutoff."
);
ixn
->
setPeriodic
(
box
);
}
double
energy
=
0
;
ixn
->
calculateIxn
(
data
.
posq
,
particleParamArray
,
globalParameters
,
data
.
threadForce
,
includeForces
,
includeEnergy
,
energy
);
return
energy
;
}
void
CpuCalcCustomManyParticleForceKernel
::
copyParametersToContext
(
ContextImpl
&
context
,
const
CustomManyParticleForce
&
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
;
int
type
;
force
.
getParticleParameters
(
i
,
parameters
,
type
);
for
(
int
j
=
0
;
j
<
numParameters
;
j
++
)
particleParamArray
[
i
][
j
]
=
static_cast
<
RealOpenMM
>
(
parameters
[
j
]);
}
}
CpuIntegrateLangevinStepKernel
::~
CpuIntegrateLangevinStepKernel
()
{
CpuIntegrateLangevinStepKernel
::~
CpuIntegrateLangevinStepKernel
()
{
if
(
dynamics
)
if
(
dynamics
)
delete
dynamics
;
delete
dynamics
;
...
...
platforms/cpu/src/CpuPlatform.cpp
View file @
604881dc
...
@@ -65,6 +65,7 @@ CpuPlatform::CpuPlatform() {
...
@@ -65,6 +65,7 @@ CpuPlatform::CpuPlatform() {
registerKernelFactory
(
CalcRBTorsionForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcRBTorsionForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcNonbondedForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcNonbondedForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcCustomNonbondedForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcCustomNonbondedForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcCustomManyParticleForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcGBSAOBCForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcGBSAOBCForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
IntegrateLangevinStepKernel
::
Name
(),
factory
);
registerKernelFactory
(
IntegrateLangevinStepKernel
::
Name
(),
factory
);
platformProperties
.
push_back
(
CpuThreads
());
platformProperties
.
push_back
(
CpuThreads
());
...
...
platforms/cpu/src/CpuSETTLE.cpp
View file @
604881dc
...
@@ -59,7 +59,9 @@ public:
...
@@ -59,7 +59,9 @@ public:
inverseMasses
(
inverseMasses
),
tolerance
(
tolerance
),
threadSettle
(
threadSettle
)
{
inverseMasses
(
inverseMasses
),
tolerance
(
tolerance
),
threadSettle
(
threadSettle
)
{
}
}
void
execute
(
ThreadPool
&
threads
,
int
threadIndex
)
{
void
execute
(
ThreadPool
&
threads
,
int
threadIndex
)
{
threadSettle
[
threadIndex
]
->
applyToVelocities
(
atomCoordinates
,
velocities
,
inverseMasses
,
tolerance
);
if
(
threadIndex
<
threadSettle
.
size
())
{
threadSettle
[
threadIndex
]
->
applyToVelocities
(
atomCoordinates
,
velocities
,
inverseMasses
,
tolerance
);
}
}
}
vector
<
OpenMM
::
RealVec
>&
atomCoordinates
;
vector
<
OpenMM
::
RealVec
>&
atomCoordinates
;
vector
<
OpenMM
::
RealVec
>&
velocities
;
vector
<
OpenMM
::
RealVec
>&
velocities
;
...
...
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