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
199feca2
"...ssh:/git@developer.sourcefind.cn:2222/tsoc/openmm.git" did not exist on "00d8068fbebc22aec1e2a08af82c62d2098cc89e"
Commit
199feca2
authored
Jul 10, 2015
by
peastman
Browse files
Created CustomIntegratorUtilities
parent
0f21cca7
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
373 additions
and
0 deletions
+373
-0
openmmapi/include/openmm/internal/CustomIntegratorUtilities.h
...mmapi/include/openmm/internal/CustomIntegratorUtilities.h
+88
-0
openmmapi/src/CustomIntegrator.cpp
openmmapi/src/CustomIntegrator.cpp
+21
-0
openmmapi/src/CustomIntegratorUtilities.cpp
openmmapi/src/CustomIntegratorUtilities.cpp
+264
-0
No files found.
openmmapi/include/openmm/internal/CustomIntegratorUtilities.h
0 → 100644
View file @
199feca2
#ifndef OPENMM_CUSTOMINTEGRATORUTILITIES_H_
#define OPENMM_CUSTOMINTEGRATORUTILITIES_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) 2015 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/CustomIntegrator.h"
#include "openmm/internal/ContextImpl.h"
#include "lepton/ParsedExpression.h"
#include <map>
#include <vector>
namespace
OpenMM
{
class
System
;
/**
* This class defines a set of utility functions that are useful in implementing CustomIntegrator.
*/
class
OPENMM_EXPORT
CustomIntegratorUtilities
{
public:
enum
Comparison
{
EQUAL
=
0
,
LESS_THAN
=
1
,
GREATER_THAN
=
2
,
NOT_EQUAL
=
3
,
LESS_THAN_OR_EQUAL
=
4
,
GREATER_THAN_OR_EQUAL
=
5
};
/**
* Parse the expression for the condition of an "if" or "while" block, and split it into
* a left hand side, right hand side, and comparison operator.
*/
static
void
parseCondition
(
const
std
::
string
&
expression
,
std
::
string
&
lhs
,
std
::
string
&
rhs
,
Comparison
&
comparison
);
/**
* Analyze the sequence of steps in a CustomIntegrator. For each step:
*
* 1. Parse all expressions involved in the step, and identify the comparison operator (for conditional steps).
* 2. Determine whether the step causes previously computed forces and energies to become invalid.
* 3. Determine whether the step itself needs forces and/or energies.
* 4. Decide whether forces and energies should both be computed at that step (because
* it is more efficient to compute both at once, even if one won't be needed
* until a later step).
* 5. Identify what force group each step needs forces and/or energies for.
*/
static
void
analyzeComputations
(
const
ContextImpl
&
context
,
const
CustomIntegrator
&
integrator
,
std
::
vector
<
std
::
vector
<
Lepton
::
ParsedExpression
>
>&
expressions
,
std
::
vector
<
Comparison
>&
comparisons
,
std
::
vector
<
bool
>&
invalidatesForces
,
std
::
vector
<
bool
>&
needsForces
,
std
::
vector
<
bool
>&
needsEnergy
,
std
::
vector
<
bool
>&
computeBoth
,
std
::
vector
<
int
>&
forceGroup
);
/**
* Determine whether an expression involves a particular variable.
*/
static
bool
usesVariable
(
const
Lepton
::
ParsedExpression
&
expression
,
const
std
::
string
&
variable
);
private:
static
bool
usesVariable
(
const
Lepton
::
ExpressionTreeNode
&
node
,
const
std
::
string
&
variable
);
static
void
enumeratePaths
(
int
firstStep
,
std
::
vector
<
int
>
steps
,
std
::
vector
<
int
>
jumps
,
const
std
::
vector
<
int
>&
blockEnd
,
const
std
::
vector
<
CustomIntegrator
::
ComputationType
>&
stepType
,
const
std
::
vector
<
bool
>&
needsForces
,
const
std
::
vector
<
bool
>&
needsEnergy
,
const
std
::
vector
<
bool
>&
invalidatesForces
,
const
std
::
vector
<
int
>&
forceGroup
,
std
::
vector
<
bool
>&
computeBoth
);
static
void
analyzeForceComputationsForPath
(
std
::
vector
<
int
>&
steps
,
const
std
::
vector
<
bool
>&
needsForces
,
const
std
::
vector
<
bool
>&
needsEnergy
,
const
std
::
vector
<
bool
>&
invalidatesForces
,
const
std
::
vector
<
int
>&
forceGroup
,
std
::
vector
<
bool
>&
computeBoth
);
};
}
// namespace OpenMM
#endif
/*OPENMM_CUSTOMINTEGRATORUTILITIES_H_*/
openmmapi/src/CustomIntegrator.cpp
View file @
199feca2
...
@@ -245,6 +245,27 @@ int CustomIntegrator::addUpdateContextState() {
...
@@ -245,6 +245,27 @@ int CustomIntegrator::addUpdateContextState() {
return
computations
.
size
()
-
1
;
return
computations
.
size
()
-
1
;
}
}
int
CustomIntegrator
::
beginIfBlock
(
const
string
&
expression
)
{
if
(
owner
!=
NULL
)
throw
OpenMMException
(
"The integrator cannot be modified after it is bound to a context"
);
computations
.
push_back
(
ComputationInfo
(
BeginIfBlock
,
""
,
expression
));
return
computations
.
size
()
-
1
;
}
int
CustomIntegrator
::
beginWhileBlock
(
const
string
&
expression
)
{
if
(
owner
!=
NULL
)
throw
OpenMMException
(
"The integrator cannot be modified after it is bound to a context"
);
computations
.
push_back
(
ComputationInfo
(
BeginWhileBlock
,
""
,
expression
));
return
computations
.
size
()
-
1
;
}
int
CustomIntegrator
::
endBlock
()
{
if
(
owner
!=
NULL
)
throw
OpenMMException
(
"The integrator cannot be modified after it is bound to a context"
);
computations
.
push_back
(
ComputationInfo
(
EndBlock
,
""
,
""
));
return
computations
.
size
()
-
1
;
}
void
CustomIntegrator
::
getComputationStep
(
int
index
,
ComputationType
&
type
,
string
&
variable
,
string
&
expression
)
const
{
void
CustomIntegrator
::
getComputationStep
(
int
index
,
ComputationType
&
type
,
string
&
variable
,
string
&
expression
)
const
{
ASSERT_VALID_INDEX
(
index
,
computations
);
ASSERT_VALID_INDEX
(
index
,
computations
);
type
=
computations
[
index
].
type
;
type
=
computations
[
index
].
type
;
...
...
openmmapi/src/CustomIntegratorUtilities.cpp
0 → 100644
View file @
199feca2
/* -------------------------------------------------------------------------- *
* 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) 2015 Stanford University and the Authors. *
* Authors: Peter Eastman *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "openmm/internal/CustomIntegratorUtilities.h"
#include "openmm/OpenMMException.h"
#include "openmm/internal/ForceImpl.h"
#include "lepton/Operation.h"
#include "lepton/Parser.h"
#include <set>
#include <sstream>
using
namespace
OpenMM
;
using
namespace
std
;
void
CustomIntegratorUtilities
::
parseCondition
(
const
string
&
expression
,
string
&
lhs
,
string
&
rhs
,
Comparison
&
comparison
)
{
string
operators
[]
=
{
"="
,
"<"
,
">"
,
"!="
,
"<="
,
">="
};
for
(
int
i
=
5
;
i
>=
0
;
i
--
)
{
int
index
=
expression
.
find
(
operators
[
i
]);
if
(
index
!=
string
::
npos
)
{
lhs
=
expression
.
substr
(
0
,
index
);
rhs
=
expression
.
substr
(
index
+
operators
[
i
].
size
());
comparison
=
Comparison
(
i
);
return
;
}
}
throw
OpenMMException
(
"No comparison operator found in condition: "
+
expression
);
}
bool
CustomIntegratorUtilities
::
usesVariable
(
const
Lepton
::
ExpressionTreeNode
&
node
,
const
string
&
variable
)
{
const
Lepton
::
Operation
&
op
=
node
.
getOperation
();
if
(
op
.
getId
()
==
Lepton
::
Operation
::
VARIABLE
&&
op
.
getName
()
==
variable
)
return
true
;
for
(
int
i
=
0
;
i
<
(
int
)
node
.
getChildren
().
size
();
i
++
)
if
(
usesVariable
(
node
.
getChildren
()[
i
],
variable
))
return
true
;
return
false
;
}
bool
CustomIntegratorUtilities
::
usesVariable
(
const
Lepton
::
ParsedExpression
&
expression
,
const
string
&
variable
)
{
return
usesVariable
(
expression
.
getRootNode
(),
variable
);
}
void
CustomIntegratorUtilities
::
analyzeComputations
(
const
ContextImpl
&
context
,
const
CustomIntegrator
&
integrator
,
vector
<
vector
<
Lepton
::
ParsedExpression
>
>&
expressions
,
vector
<
Comparison
>&
comparisons
,
vector
<
bool
>&
invalidatesForces
,
vector
<
bool
>&
needsForces
,
vector
<
bool
>&
needsEnergy
,
vector
<
bool
>&
computeBoth
,
vector
<
int
>&
forceGroup
)
{
int
numSteps
=
integrator
.
getNumComputations
();
expressions
.
resize
(
numSteps
);
comparisons
.
resize
(
numSteps
);
invalidatesForces
.
resize
(
numSteps
,
false
);
needsForces
.
resize
(
numSteps
,
false
);
needsEnergy
.
resize
(
numSteps
,
false
);
computeBoth
.
resize
(
numSteps
,
false
);
forceGroup
.
resize
(
numSteps
,
-
2
);
vector
<
CustomIntegrator
::
ComputationType
>
stepType
(
numSteps
);
vector
<
string
>
stepVariable
(
numSteps
);
// Parse the expressions.
for
(
int
step
=
0
;
step
<
numSteps
;
step
++
)
{
string
expression
;
integrator
.
getComputationStep
(
step
,
stepType
[
step
],
stepVariable
[
step
],
expression
);
if
(
stepType
[
step
]
==
CustomIntegrator
::
BeginIfBlock
||
stepType
[
step
]
==
CustomIntegrator
::
BeginWhileBlock
)
{
// This step involves a condition.
string
lhs
,
rhs
;
parseCondition
(
expression
,
lhs
,
rhs
,
comparisons
[
step
]);
expressions
[
step
].
push_back
(
Lepton
::
Parser
::
parse
(
lhs
).
optimize
());
expressions
[
step
].
push_back
(
Lepton
::
Parser
::
parse
(
rhs
).
optimize
());
}
else
if
(
expression
.
size
()
>
0
)
expressions
[
step
].
push_back
(
Lepton
::
Parser
::
parse
(
expression
).
optimize
());
}
// Identify which steps invalidate the forces.
set
<
string
>
affectsForce
;
affectsForce
.
insert
(
"x"
);
for
(
vector
<
ForceImpl
*>::
const_iterator
iter
=
context
.
getForceImpls
().
begin
();
iter
!=
context
.
getForceImpls
().
end
();
++
iter
)
{
const
map
<
string
,
double
>
params
=
(
*
iter
)
->
getDefaultParameters
();
for
(
map
<
string
,
double
>::
const_iterator
param
=
params
.
begin
();
param
!=
params
.
end
();
++
param
)
affectsForce
.
insert
(
param
->
first
);
}
for
(
int
i
=
0
;
i
<
numSteps
;
i
++
)
invalidatesForces
[
i
]
=
(
stepType
[
i
]
==
CustomIntegrator
::
ConstrainPositions
||
affectsForce
.
find
(
stepVariable
[
i
])
!=
affectsForce
.
end
());
// Make a list of which steps require valid forces or energy to be known.
vector
<
string
>
forceGroupName
;
vector
<
string
>
energyGroupName
;
for
(
int
i
=
0
;
i
<
32
;
i
++
)
{
stringstream
fname
;
fname
<<
"f"
<<
i
;
forceGroupName
.
push_back
(
fname
.
str
());
stringstream
ename
;
ename
<<
"energy"
<<
i
;
energyGroupName
.
push_back
(
ename
.
str
());
}
for
(
int
step
=
0
;
step
<
numSteps
;
step
++
)
{
for
(
int
expr
=
0
;
expr
<
expressions
[
step
].
size
();
expr
++
)
{
if
(
usesVariable
(
expressions
[
step
][
expr
],
"f"
))
{
needsForces
[
step
]
=
true
;
forceGroup
[
step
]
=
-
1
;
}
if
(
usesVariable
(
expressions
[
step
][
expr
],
"energy"
))
{
needsEnergy
[
step
]
=
true
;
forceGroup
[
step
]
=
-
1
;
}
for
(
int
i
=
0
;
i
<
32
;
i
++
)
{
if
(
usesVariable
(
expressions
[
step
][
expr
],
forceGroupName
[
i
]))
{
if
(
forceGroup
[
step
]
!=
-
2
)
throw
OpenMMException
(
"A single computation step cannot depend on multiple force groups"
);
needsForces
[
step
]
=
true
;
forceGroup
[
step
]
=
1
<<
i
;
}
if
(
usesVariable
(
expressions
[
step
][
expr
],
energyGroupName
[
i
]))
{
if
(
forceGroup
[
step
]
!=
-
2
)
throw
OpenMMException
(
"A single computation step cannot depend on multiple force groups"
);
needsEnergy
[
step
]
=
true
;
forceGroup
[
step
]
=
1
<<
i
;
}
}
}
}
// Find the end point of each block.
vector
<
int
>
blockStart
;
vector
<
int
>
blockEnd
(
numSteps
);
for
(
int
step
=
0
;
step
<
numSteps
;
step
++
)
{
if
(
stepType
[
step
]
==
CustomIntegrator
::
BeginIfBlock
||
stepType
[
step
]
==
CustomIntegrator
::
BeginWhileBlock
)
blockStart
.
push_back
(
step
);
else
if
(
stepType
[
step
]
==
CustomIntegrator
::
EndBlock
)
{
if
(
blockStart
.
size
()
==
0
)
{
stringstream
error
(
"CustomIntegrator: Unexpected end of block at computation "
);
error
<<
step
;
throw
OpenMMException
(
error
.
str
());
}
blockEnd
[
blockStart
.
back
()]
=
step
;
blockStart
.
pop_back
();
}
}
if
(
blockStart
.
size
()
>
0
)
throw
OpenMMException
(
"CustomIntegrator: Missing EndBlock"
);
// If a step requires either forces or energy, and a later step will require the other one, it's most efficient
// to compute both at the same time. Figure out whether we should do that. In principle it's easy: step through
// the sequence of computations and see if the other one is used before the next time they get invalidated.
// Unfortunately, flow control makes this much more complicated, because there are many possible paths to
// consider.
//
// The cost of computing both when we really only needed one is much less than the cost of computing only one,
// then later finding we need to compute the other separately. So we always err on the side of computing both.
// If there is any possible path that would lead to us needing it, go ahead and compute it.
//
// So we need to enumerate all possible paths. For each "if" block, there are two possibilities: execute it
// or don't. For each "while" block there are three possibilities: don't execute it; execute it and then
// continue on; or execute it and then jump back to the beginning. I'm assuming the number of blocks will
// always remain small. Otherwise, this could become very expensive!
vector
<
int
>
jumps
(
numSteps
,
-
1
);
vector
<
int
>
stepsInPath
;
enumeratePaths
(
0
,
stepsInPath
,
jumps
,
blockEnd
,
stepType
,
needsForces
,
needsEnergy
,
invalidatesForces
,
forceGroup
,
computeBoth
);
}
void
CustomIntegratorUtilities
::
enumeratePaths
(
int
firstStep
,
vector
<
int
>
steps
,
vector
<
int
>
jumps
,
const
vector
<
int
>&
blockEnd
,
const
vector
<
CustomIntegrator
::
ComputationType
>&
stepType
,
const
vector
<
bool
>&
needsForces
,
const
vector
<
bool
>&
needsEnergy
,
const
vector
<
bool
>&
invalidatesForces
,
const
vector
<
int
>&
forceGroup
,
vector
<
bool
>&
computeBoth
)
{
int
step
=
firstStep
;
int
numSteps
=
stepType
.
size
();
while
(
step
<
numSteps
)
{
steps
.
push_back
(
step
);
if
(
jumps
[
step
]
>
0
)
{
// Follow the jump and remove it from the list.
int
nextStep
=
jumps
[
step
];
jumps
[
step
]
=
-
1
;
step
=
nextStep
;
}
else
if
(
stepType
[
step
]
==
CustomIntegrator
::
BeginIfBlock
)
{
// Consider skipping the block.
enumeratePaths
(
blockEnd
[
step
]
+
1
,
steps
,
jumps
,
blockEnd
,
stepType
,
needsForces
,
needsEnergy
,
invalidatesForces
,
forceGroup
,
computeBoth
);
// Continue on to execute the block.
step
++
;
}
else
if
(
stepType
[
step
]
==
CustomIntegrator
::
BeginWhileBlock
&&
jumps
[
step
]
!=
-
2
)
{
// Consider skipping the block.
enumeratePaths
(
blockEnd
[
step
]
+
1
,
steps
,
jumps
,
blockEnd
,
stepType
,
needsForces
,
needsEnergy
,
invalidatesForces
,
forceGroup
,
computeBoth
);
// Consider executing the block once.
enumeratePaths
(
step
+
1
,
steps
,
jumps
,
blockEnd
,
stepType
,
needsForces
,
needsEnergy
,
invalidatesForces
,
forceGroup
,
computeBoth
);
// Continue on to execute the block twice.
jumps
[
step
]
=
-
2
;
// Mark this "while" block as already processed.
jumps
[
blockEnd
[
step
]]
=
step
;
step
++
;
}
else
step
++
;
}
analyzeForceComputationsForPath
(
steps
,
needsForces
,
needsEnergy
,
invalidatesForces
,
forceGroup
,
computeBoth
);
}
void
CustomIntegratorUtilities
::
analyzeForceComputationsForPath
(
vector
<
int
>&
steps
,
const
vector
<
bool
>&
needsForces
,
const
vector
<
bool
>&
needsEnergy
,
const
vector
<
bool
>&
invalidatesForces
,
const
vector
<
int
>&
forceGroup
,
vector
<
bool
>&
computeBoth
)
{
vector
<
int
>
candidatePoints
;
int
currentGroup
=
-
1
;
for
(
int
i
=
0
;
i
<
(
int
)
steps
.
size
();
i
++
)
{
int
step
=
steps
[
i
];
if
(
invalidatesForces
[
step
]
||
((
needsForces
[
step
]
||
needsEnergy
[
step
])
&&
forceGroup
[
step
]
!=
currentGroup
))
{
// Forces and energies are invalidated at this step, or it changes to a different force group,
// so anything from this point on won't affect what we do at earlier steps.
candidatePoints
.
clear
();
}
if
(
needsForces
[
step
]
||
needsEnergy
[
step
])
{
// See if this step affects what we do at earlier points.
for
(
int
j
=
0
;
j
<
(
int
)
candidatePoints
.
size
();
j
++
)
{
int
candidate
=
candidatePoints
[
j
];
if
((
needsForces
[
candidate
]
&&
needsEnergy
[
step
])
||
(
needsEnergy
[
candidate
]
&&
needsForces
[
step
]))
computeBoth
[
candidate
]
=
true
;
}
// Add this to the list of candidates that might be affected by later steps.
candidatePoints
.
push_back
(
step
);
currentGroup
=
forceGroup
[
step
];
}
}
}
\ No newline at end of file
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