Commit a993d7ab authored by Peter Eastman's avatar Peter Eastman
Browse files

Merge remote-tracking branch 'origin/master' into charmm

parents fd76052f fcba92a6
language: cpp language: c
compiler:
- clang
before_install: install:
- sudo apt-get update -qq - source tools/ci/install.sh
- sudo apt-get install -qq libpcre3 libpcre3-dev gromacs - export PYTHONUNBUFFERED=true
- sudo apt-get install -qq swig doxygen llvm-3.3
- sudo apt-get install -qq python-numpy python-scipy python-nose
- export ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolizer-3.3
script: script:
- cmake -DCMAKE_INSTALL_PREFIX=$HOME/OpenMM . - export CC="clang++"
- make - source deactivate
- make install - conda install --yes conda-build
- sudo make PythonInstall - # Build the conda package, testing build before packaging.
- # run all of the tests - conda build tools/conda-recipe
- ctest -V - # Install the conda package locally.
- # get a list of all of the failed tests into this stupid ctest format - source activate $python
- python -c 'fn = "Testing/Temporary/LastTestsFailed.log"; import os; os.path.exists(fn) or exit(0); l = [line.split(":")[0] for line in open(fn)]; triplets = zip(l, l, [","]*len(l)); print "".join(",".join(t) for t in triplets)' > FailedTests.log - conda install $HOME/miniconda/conda-bld/linux-64/openmm-dev-*
- # rerun all of the failed tests - conda list -e
- if [ -s FailedTests.log ]; then ctest -V -I FailedTests.log; fi; - # Run the Python tests.
- # run the python tests too - pushd .
- cd python/tests - cd wrappers/python/tests
- nosetests -vv - nosetests -vv --processes=-1 --process-timeout=200
- popd
env:
global:
# encrypted BINSTAR_TOKEN for push of dev package to binstar
- secure: Qz3pEYXXFnNQ/WK+15ad4cdbLJvzgCIZRwKD9fLiS3CDO2ldAQWxzaz8RQOwqbFtZUWu7lQpr+GukNJz5p0w18QEto+BxLYG9aW5mjoc+F2vCjyWFjkwnJ/Z/3uBKTcr5x9Y7HKaPGivaJ4BNACifjt7cCpeVJzV6u2+bBgSoHc=
matrix:
- python=2.7 CONDA_PY=27
#- python=3.3 CONDA_PY=33
after_success:
- echo "after_success"
- source tools/ci/after_success.sh
...@@ -61,6 +61,11 @@ ELSE(WIN32) ...@@ -61,6 +61,11 @@ ELSE(WIN32)
ENDIF(NOT OPENMM_INSTALL_PREFIX) ENDIF(NOT OPENMM_INSTALL_PREFIX)
ENDIF(WIN32) ENDIF(WIN32)
# Include CPU-Features for Android
IF (ANDROID)
INCLUDE_DIRECTORIES(${ANDROID_NDK}/sources/cpufeatures)
ENDIF (ANDROID)
# It seems that on linux and mac, everything is trying to be installed in /usr/local/openmm # It seems that on linux and mac, everything is trying to be installed in /usr/local/openmm
# But if every install target is prefixed with /openmm/, on Windows the install files # But if every install target is prefixed with /openmm/, on Windows the install files
# end up in C:/Program Files/OpenMM/openmm/ which is ugly. # end up in C:/Program Files/OpenMM/openmm/ which is ugly.
...@@ -87,9 +92,11 @@ IF(WIN32) ...@@ -87,9 +92,11 @@ IF(WIN32)
SET(PTHREADS_LIB pthreadVC2) SET(PTHREADS_LIB pthreadVC2)
SET(PTHREADS_LIB_STATIC pthreadVC2_static_mt) SET(PTHREADS_LIB_STATIC pthreadVC2_static_mt)
ELSE(WIN32) ELSE(WIN32)
SET(PTHREADS_LIB pthread) IF (NOT ANDROID)
# in linux, even in static builds we link against the dynamic object (since its tied to libc versions) SET(PTHREADS_LIB pthread)
SET(PTHREADS_LIB_STATIC pthread) # in linux, even in static builds we link against the dynamic object (since its tied to libc versions)
SET(PTHREADS_LIB_STATIC pthread)
ENDIF (NOT ANDROID)
ENDIF(WIN32) ENDIF(WIN32)
# The build system will set ARCH64 for 64 bit builds, which require # The build system will set ARCH64 for 64 bit builds, which require
...@@ -121,11 +128,11 @@ IF (APPLE) ...@@ -121,11 +128,11 @@ IF (APPLE)
SET (CMAKE_INSTALL_NAME_DIR "@rpath") SET (CMAKE_INSTALL_NAME_DIR "@rpath")
SET(EXTRA_COMPILE_FLAGS "-msse2 -stdlib=libc++") SET(EXTRA_COMPILE_FLAGS "-msse2 -stdlib=libc++")
ELSE (APPLE) ELSE (APPLE)
IF (MSVC) IF (MSVC OR ANDROID)
SET(EXTRA_COMPILE_FLAGS) SET(EXTRA_COMPILE_FLAGS)
ELSE (MSVC) ELSE (MSVC OR ANDROID)
SET(EXTRA_COMPILE_FLAGS "-msse2") SET(EXTRA_COMPILE_FLAGS "-msse2")
ENDIF (MSVC) ENDIF (MSVC OR ANDROID)
ENDIF (APPLE) ENDIF (APPLE)
IF(UNIX AND NOT CMAKE_BUILD_TYPE) IF(UNIX AND NOT CMAKE_BUILD_TYPE)
...@@ -137,8 +144,13 @@ IF (NOT CMAKE_CXX_FLAGS_DEBUG) ...@@ -137,8 +144,13 @@ IF (NOT CMAKE_CXX_FLAGS_DEBUG)
ENDIF (NOT CMAKE_CXX_FLAGS_DEBUG) ENDIF (NOT CMAKE_CXX_FLAGS_DEBUG)
IF (NOT CMAKE_CXX_FLAGS_RELEASE) IF (NOT CMAKE_CXX_FLAGS_RELEASE)
SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING IF (ANDROID)
"To use when CMAKE_BUILD_TYPE=Release" FORCE) SET(CMAKE_CXX_FLAGS_RELEASE "-mfloat-abi=softfp -march=armv7-a -mfpu=neon -funsafe-math-optimizations -O3 -DNDEBUG" CACHE STRING
"To use when CMAKE_BUILD_TYPE=Release" FORCE)
ELSE (ANDROID)
SET(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING
"To use when CMAKE_BUILD_TYPE=Release" FORCE)
ENDIF (ANDROID)
ENDIF (NOT CMAKE_CXX_FLAGS_RELEASE) ENDIF (NOT CMAKE_CXX_FLAGS_RELEASE)
...@@ -252,7 +264,11 @@ FOREACH(subdir ${OPENMM_SOURCE_SUBDIRS}) ...@@ -252,7 +264,11 @@ FOREACH(subdir ${OPENMM_SOURCE_SUBDIRS})
## OpenMM was previously installed there. ## OpenMM was previously installed there.
INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/${subdir}/include) INCLUDE_DIRECTORIES(BEFORE ${CMAKE_CURRENT_SOURCE_DIR}/${subdir}/include)
ENDFOREACH(subdir) ENDFOREACH(subdir)
SET_SOURCE_FILES_PROPERTIES(${CMAKE_SOURCE_DIR}/libraries/sfmt/src/SFMT.cpp PROPERTIES COMPILE_FLAGS "-DHAVE_SSE2=1") IF (ANDROID)
SET_SOURCE_FILES_PROPERTIES(${CMAKE_SOURCE_DIR}/libraries/sfmt/src/SFMT.cpp PROPERTIES COMPILE_FLAGS "-UHAVE_SSE2")
ELSE (ANDROID)
SET_SOURCE_FILES_PROPERTIES(${CMAKE_SOURCE_DIR}/libraries/sfmt/src/SFMT.cpp PROPERTIES COMPILE_FLAGS "-DHAVE_SSE2=1")
ENDIF(ANDROID)
# If API wrappers are being generated, and add them to the build. # If API wrappers are being generated, and add them to the build.
SET(OPENMM_BUILD_C_AND_FORTRAN_WRAPPERS ON CACHE BOOL "Build wrappers for C and Fortran") SET(OPENMM_BUILD_C_AND_FORTRAN_WRAPPERS ON CACHE BOOL "Build wrappers for C and Fortran")
...@@ -287,13 +303,17 @@ ENDIF(OPENMM_BUILD_C_AND_FORTRAN_WRAPPERS) ...@@ -287,13 +303,17 @@ ENDIF(OPENMM_BUILD_C_AND_FORTRAN_WRAPPERS)
# On Linux need to link to libdl # On Linux need to link to libdl
FIND_LIBRARY(DL_LIBRARY dl) FIND_LIBRARY(DL_LIBRARY dl)
IF(DL_LIBRARY) IF(DL_LIBRARY)
TARGET_LINK_LIBRARIES(${SHARED_TARGET} ${DL_LIBRARY} ${PTHREADS_LIB}) TARGET_LINK_LIBRARIES(${SHARED_TARGET} ${DL_LIBRARY} ${PTHREADS_LIB})
IF(OPENMM_BUILD_STATIC_LIB) IF(OPENMM_BUILD_STATIC_LIB)
TARGET_LINK_LIBRARIES(${STATIC_TARGET} ${DL_LIBRARY} ${PTHREADS_LIB}) TARGET_LINK_LIBRARIES(${STATIC_TARGET} ${DL_LIBRARY} ${PTHREADS_LIB})
ENDIF(OPENMM_BUILD_STATIC_LIB) ENDIF(OPENMM_BUILD_STATIC_LIB)
MARK_AS_ADVANCED(DL_LIBRARY) MARK_AS_ADVANCED(DL_LIBRARY)
ELSE(DL_LIBRARY) ELSE(DL_LIBRARY)
TARGET_LINK_LIBRARIES(${SHARED_TARGET} ${PTHREADS_LIB}) IF (ANDROID)
TARGET_LINK_LIBRARIES(${SHARED_TARGET} ${PTHREADS_LIB} cpufeatures)
ELSE (ANDROID)
TARGET_LINK_LIBRARIES(${SHARED_TARGET} ${PTHREADS_LIB})
ENDIF (ANDROID)
ENDIF(DL_LIBRARY) ENDIF(DL_LIBRARY)
ADD_SUBDIRECTORY(platforms/reference/tests) ADD_SUBDIRECTORY(platforms/reference/tests)
......
...@@ -2187,6 +2187,49 @@ second atom has class OS and the third has class P: ...@@ -2187,6 +2187,49 @@ second atom has class OS and the third has class P:
<Proper class1="" class2="OS" class3="P" class4="" per="3" phase="0.0" k="0.66944"/> <Proper class1="" class2="OS" class3="P" class4="" per="3" phase="0.0" k="0.66944"/>
<CustomNonbondedForce>
===============
To add a CustomNonbondedForce to the System, include a tag that looks like this:
.. code-block:: xml
<CustomNonbondedForce energy="scale*epsilon1*epsilon2*((sigma1+sigma2)/r)^12" bondCutoff="3">
<GlobalParameter name="scale" defaultValue="1"/>
<PerParticleParameter name="sigma"/>
<PerParticleParameter name="epsilon"/>
<Atom type="0" sigma="0.3249" epsilon="0.7112"/>
<Atom type="1" sigma="0.1069" epsilon="0.0656"/>
<Atom type="2" sigma="0.3399" epsilon="0.4577"/>
...
</CustomNonbondedForce>
The energy expression for the CustomNonbondedForce is specified by the
:code:`energy` attribute. This is a mathematical expression that gives the
energy of each pairwise interaction as a function of the distance *r*\ . It
also may depend on an arbitrary list of global or per-particle parameters. Use
a :code:`<GlobalParameter>` tag to define a global parameter, and a
:code:`<PerParticleParameter>` tag to define a per-particle 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 CustomNonbondedForce, passing in this
value as its argument. To avoid creating exclusions, set :code:`bondCutoff` to 0.
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.
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`\ .
CustomNonbondedForce also allows you to define tabulated functions. See section
:ref:`tabulated-functions` for details.
<CustomGBForce> <CustomGBForce>
=============== ===============
...@@ -2244,30 +2287,8 @@ attribute name must match the name of the parameter. For instance, if there is ...@@ -2244,30 +2287,8 @@ 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 a per-atom parameter with the name radius, then every :code:`<Atom>` tag
must include an attribute called :code:`radius`\ . must include an attribute called :code:`radius`\ .
CustomGBForce also allows you to define tabulated functions. To define a CustomGBForce also allows you to define tabulated functions. See section
function, include a :code:`<Function>` tag inside the :ref:`tabulated-functions` for details.
:code:`<CustomGBForce>` tag:
.. code-block:: xml
<Function name="myfn" min="-5" max="5">
0.983674857694 -0.980096396266 -0.975743130031 -0.970451936613 -0.964027580076
-0.956237458128 -0.946806012846 -0.935409070603 -0.921668554406 -0.905148253645
-0.885351648202 -0.861723159313 -0.833654607012 -0.800499021761 -0.761594155956
-0.716297870199 -0.664036770268 -0.604367777117 -0.537049566998 -0.46211715726
-0.379948962255 -0.291312612452 -0.197375320225 -0.099667994625 0.0
0.099667994625 0.197375320225 0.291312612452 0.379948962255 0.46211715726
0.537049566998 0.604367777117 0.664036770268 0.716297870199 0.761594155956
0.800499021761 0.833654607012 0.861723159313 0.885351648202 0.905148253645
0.921668554406 0.935409070603 0.946806012846 0.956237458128 0.964027580076
0.970451936613 0.975743130031 0.980096396266 0.983674857694 0.986614298151
0.989027402201
</Function>
The tags attributes define the name of the function and the range of values for
which it is defined. The tabulated values are listed inside the body of the
tag, with successive values separated by white space. Again, see the API
documentation for more details.
Writing Custom Expressions Writing Custom Expressions
========================== ==========================
...@@ -2304,6 +2325,55 @@ is exactly equivalent to ...@@ -2304,6 +2325,55 @@ is exactly equivalent to
The definition of an intermediate value may itself involve other intermediate The definition of an intermediate value may itself involve other intermediate
values. All uses of a value must appear *before* that values definition. values. All uses of a value must appear *before* that values definition.
.. _tabulated-functions:
TabulatedFunctions
==================
Some forces, such as CustomNonbondedForce and CustomGBForce, allow you to define
tabulated functions. To define a function, include a :code:`<Function>` tag inside the
:code:`<CustomNonbondedForce>` or :code:`<CustomGBForce>` tag:
.. code-block:: xml
<Function name="myfn" type="Continuous1D" min="-5" max="5">
0.983674857694 -0.980096396266 -0.975743130031 -0.970451936613 -0.964027580076
-0.956237458128 -0.946806012846 -0.935409070603 -0.921668554406 -0.905148253645
-0.885351648202 -0.861723159313 -0.833654607012 -0.800499021761 -0.761594155956
-0.716297870199 -0.664036770268 -0.604367777117 -0.537049566998 -0.46211715726
-0.379948962255 -0.291312612452 -0.197375320225 -0.099667994625 0.0
0.099667994625 0.197375320225 0.291312612452 0.379948962255 0.46211715726
0.537049566998 0.604367777117 0.664036770268 0.716297870199 0.761594155956
0.800499021761 0.833654607012 0.861723159313 0.885351648202 0.905148253645
0.921668554406 0.935409070603 0.946806012846 0.956237458128 0.964027580076
0.970451936613 0.975743130031 0.980096396266 0.983674857694 0.986614298151
0.989027402201
</Function>
The tags attributes define the name of the function, the type of function, and
the range of values for which it is defined. The required set of attributed
depends on the function type:
.. tabularcolumns:: |l|L|
============ =======================================================
Type Required Attributes
============ =======================================================
Continuous1D min, max
Continuous2D xmin, ymin, xmax, ymax, xsize, ysize
Continuous3D xmin, ymin, zmin, xmax, ymax, zmax, xsize, ysize, zsize
Discrete1D
Discrete2D xsize, ysize
Discrete3D xsize, ysize, zsize
============ =======================================================
The "min" and "max" attributes define the range of the independent variables for
a continuous function. The "size" attributes define the size of the table along
each axis. The tabulated values are listed inside the body of the tag, with
successive values separated by white space. See the API documentation for more
details.
Using Multiple Files Using Multiple Files
******************** ********************
......
...@@ -84,13 +84,13 @@ void CompiledExpression::compileExpression(const ExpressionTreeNode& node, vecto ...@@ -84,13 +84,13 @@ void CompiledExpression::compileExpression(const ExpressionTreeNode& node, vecto
// Process this node. // Process this node.
if (node.getOperation().getId() == Operation::VARIABLE) { if (node.getOperation().getId() == Operation::VARIABLE) {
variableIndices[node.getOperation().getName()] = workspace.size(); variableIndices[node.getOperation().getName()] = (int) workspace.size();
variableNames.insert(node.getOperation().getName()); variableNames.insert(node.getOperation().getName());
} }
else { else {
int stepIndex = arguments.size(); int stepIndex = (int) arguments.size();
arguments.push_back(vector<int>()); arguments.push_back(vector<int>());
target.push_back(workspace.size()); target.push_back((int) workspace.size());
operation.push_back(node.getOperation().clone()); operation.push_back(node.getOperation().clone());
if (args.size() == 0) if (args.size() == 0)
arguments[stepIndex].push_back(0); // The value won't actually be used. We just need something there. arguments[stepIndex].push_back(0); // The value won't actually be used. We just need something there.
......
...@@ -71,13 +71,13 @@ ExpressionProgram& ExpressionProgram::operator=(const ExpressionProgram& program ...@@ -71,13 +71,13 @@ ExpressionProgram& ExpressionProgram::operator=(const ExpressionProgram& program
} }
void ExpressionProgram::buildProgram(const ExpressionTreeNode& node) { void ExpressionProgram::buildProgram(const ExpressionTreeNode& node) {
for (int i = node.getChildren().size()-1; i >= 0; i--) for (int i = (int) node.getChildren().size()-1; i >= 0; i--)
buildProgram(node.getChildren()[i]); buildProgram(node.getChildren()[i]);
operations.push_back(node.getOperation().clone()); operations.push_back(node.getOperation().clone());
} }
int ExpressionProgram::getNumOperations() const { int ExpressionProgram::getNumOperations() const {
return operations.size(); return (int) operations.size();
} }
const Operation& ExpressionProgram::getOperation(int index) const { const Operation& ExpressionProgram::getOperation(int index) const {
......
...@@ -60,7 +60,7 @@ double ParsedExpression::evaluate(const map<string, double>& variables) const { ...@@ -60,7 +60,7 @@ double ParsedExpression::evaluate(const map<string, double>& variables) const {
} }
double ParsedExpression::evaluate(const ExpressionTreeNode& node, const map<string, double>& variables) { double ParsedExpression::evaluate(const ExpressionTreeNode& node, const map<string, double>& variables) {
int numArgs = node.getChildren().size(); int numArgs = (int) node.getChildren().size();
vector<double> args(max(numArgs, 1)); vector<double> args(max(numArgs, 1));
for (int i = 0; i < numArgs; i++) for (int i = 0; i < numArgs; i++)
args[i] = evaluate(node.getChildren()[i], variables); args[i] = evaluate(node.getChildren()[i], variables);
...@@ -269,7 +269,15 @@ ExpressionTreeNode ParsedExpression::substituteSimplerExpression(const Expressio ...@@ -269,7 +269,15 @@ ExpressionTreeNode ParsedExpression::substituteSimplerExpression(const Expressio
return ExpressionTreeNode(new Operation::Constant(dynamic_cast<const Operation::MultiplyConstant*>(&node.getOperation())->getValue()*getConstantValue(children[0]))); return ExpressionTreeNode(new Operation::Constant(dynamic_cast<const Operation::MultiplyConstant*>(&node.getOperation())->getValue()*getConstantValue(children[0])));
if (children[0].getOperation().getId() == Operation::NEGATE) // Combine a multiply and a negate into a single multiply if (children[0].getOperation().getId() == Operation::NEGATE) // Combine a multiply and a negate into a single multiply
return ExpressionTreeNode(new Operation::MultiplyConstant(-dynamic_cast<const Operation::MultiplyConstant*>(&node.getOperation())->getValue()), children[0].getChildren()[0]); return ExpressionTreeNode(new Operation::MultiplyConstant(-dynamic_cast<const Operation::MultiplyConstant*>(&node.getOperation())->getValue()), children[0].getChildren()[0]);
break;
} }
default:
{
// If operation ID is not one of the above,
// we don't substitute a simpler expression.
break;
}
} }
return ExpressionTreeNode(node.getOperation().clone(), children); return ExpressionTreeNode(node.getOperation().clone(), children);
} }
......
...@@ -70,7 +70,7 @@ string Parser::trim(const string& expression) { ...@@ -70,7 +70,7 @@ string Parser::trim(const string& expression) {
int start, end; int start, end;
for (start = 0; start < (int) expression.size() && isspace(expression[start]); start++) for (start = 0; start < (int) expression.size() && isspace(expression[start]); start++)
; ;
for (end = expression.size()-1; end > start && isspace(expression[end]); end--) for (end = (int) expression.size()-1; end > start && isspace(expression[end]); end--)
; ;
if (start == end && isspace(expression[end])) if (start == end && isspace(expression[end]))
return ""; return "";
...@@ -140,7 +140,7 @@ vector<ParseToken> Parser::tokenize(const string& expression) { ...@@ -140,7 +140,7 @@ vector<ParseToken> Parser::tokenize(const string& expression) {
ParseToken token = getNextToken(expression, pos); ParseToken token = getNextToken(expression, pos);
if (token.getType() != ParseToken::Whitespace) if (token.getType() != ParseToken::Whitespace)
tokens.push_back(token); tokens.push_back(token);
pos += token.getText().size(); pos += (int) token.getText().size();
} }
return tokens; return tokens;
} }
...@@ -257,7 +257,7 @@ ExpressionTreeNode Parser::parsePrecedence(const vector<ParseToken>& tokens, int ...@@ -257,7 +257,7 @@ ExpressionTreeNode Parser::parsePrecedence(const vector<ParseToken>& tokens, int
while (pos < (int) tokens.size() && tokens[pos].getType() == ParseToken::Operator) { while (pos < (int) tokens.size() && tokens[pos].getType() == ParseToken::Operator) {
token = tokens[pos]; token = tokens[pos];
int opIndex = Operators.find(token.getText()); int opIndex = (int) Operators.find(token.getText());
int opPrecedence = Precedence[opIndex]; int opPrecedence = Precedence[opIndex];
if (opPrecedence < precedence) if (opPrecedence < precedence)
return result; return result;
......
...@@ -343,6 +343,8 @@ public: ...@@ -343,6 +343,8 @@ public:
void setParticleParameters(int index, const std::vector<double>& parameters); void setParticleParameters(int index, const std::vector<double>& parameters);
/** /**
* Add a particle pair to the list of interactions that should be excluded. * 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 particle1 the index of the first particle in the pair
* @param particle2 the index of the second particle in the pair * @param particle2 the index of the second particle in the pair
...@@ -365,6 +367,15 @@ public: ...@@ -365,6 +367,15 @@ public:
* @param particle2 the index of the second particle in the pair * @param particle2 the index of the second particle in the pair
*/ */
void setExclusionParticles(int index, int particle1, int particle2); 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);
/** /**
* Add a tabulated function that may appear in the energy expression. * Add a tabulated function that may appear in the energy expression.
* *
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* 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) 2008-2013 Stanford University and the Authors. * * Portions copyright (c) 2008-2014 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -67,7 +67,6 @@ public: ...@@ -67,7 +67,6 @@ public:
*/ */
static double calcLongRangeCorrection(const CustomNonbondedForce& force, const Context& context); static double calcLongRangeCorrection(const CustomNonbondedForce& force, const Context& context);
private: private:
class TabulatedFunction;
static double integrateInteraction(Lepton::CompiledExpression& expression, const std::vector<double>& params1, const std::vector<double>& params2, static double integrateInteraction(Lepton::CompiledExpression& expression, const std::vector<double>& params1, const std::vector<double>& params2,
const CustomNonbondedForce& force, const Context& context); const CustomNonbondedForce& force, const Context& context);
const CustomNonbondedForce& owner; const CustomNonbondedForce& owner;
......
...@@ -47,8 +47,12 @@ ...@@ -47,8 +47,12 @@
#define NOMINMAX #define NOMINMAX
#include <windows.h> #include <windows.h>
#else #else
#include <dlfcn.h> #ifdef __ANDROID__
#include <unistd.h> #include <cpu-features.h>
#else
#include <dlfcn.h>
#include <unistd.h>
#endif
#endif #endif
#endif #endif
...@@ -70,11 +74,15 @@ static int getNumProcessors() { ...@@ -70,11 +74,15 @@ static int getNumProcessors() {
ncpu = 1; ncpu = 1;
return ncpu; return ncpu;
#else #else
long nProcessorsOnline = sysconf(_SC_NPROCESSORS_ONLN); #ifdef __ANDROID__
if (nProcessorsOnline == -1) return android_getCpuCount();
return 1; #else
else long nProcessorsOnline = sysconf(_SC_NPROCESSORS_ONLN);
return (int) nProcessorsOnline; if (nProcessorsOnline == -1)
return 1;
else
return (int) nProcessorsOnline;
#endif
#endif #endif
#endif #endif
} }
...@@ -85,30 +93,32 @@ static int getNumProcessors() { ...@@ -85,30 +93,32 @@ static int getNumProcessors() {
#ifdef _WIN32 #ifdef _WIN32
#define cpuid __cpuid #define cpuid __cpuid
#else #else
static void cpuid(int cpuInfo[4], int infoType){ #ifndef __ANDROID__
#ifdef __LP64__ static void cpuid(int cpuInfo[4], int infoType){
__asm__ __volatile__ ( #ifdef __LP64__
"cpuid": __asm__ __volatile__ (
"=a" (cpuInfo[0]), "cpuid":
"=b" (cpuInfo[1]), "=a" (cpuInfo[0]),
"=c" (cpuInfo[2]), "=b" (cpuInfo[1]),
"=d" (cpuInfo[3]) : "=c" (cpuInfo[2]),
"a" (infoType) "=d" (cpuInfo[3]) :
); "a" (infoType)
#else );
__asm__ __volatile__ ( #else
"pushl %%ebx\n" __asm__ __volatile__ (
"cpuid\n" "pushl %%ebx\n"
"movl %%ebx, %1\n" "cpuid\n"
"popl %%ebx\n" : "movl %%ebx, %1\n"
"=a" (cpuInfo[0]), "popl %%ebx\n" :
"=r" (cpuInfo[1]), "=a" (cpuInfo[0]),
"=c" (cpuInfo[2]), "=r" (cpuInfo[1]),
"=d" (cpuInfo[3]) : "=c" (cpuInfo[2]),
"a" (infoType) "=d" (cpuInfo[3]) :
); "a" (infoType)
#endif );
} #endif
}
#endif
#endif #endif
#endif // OPENMM_HARDWARE_H_ #endif // OPENMM_HARDWARE_H_
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* 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) 2014 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -31,256 +31,11 @@ ...@@ -31,256 +31,11 @@
* 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> #if defined(__ANDROID__)
#include "vectorize_neon.h"
#else
// This file defines classes and functions to simplify vectorizing code with SSE. #include "vectorize_sse.h"
#endif
class ivec4;
/**
* A four element vector of floats.
*/
class fvec4 {
public:
__m128 val;
fvec4() {}
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(__m128 v) : val(v) {}
fvec4(const float* v) : val(_mm_loadu_ps(v)) {}
operator __m128() const {
return val;
}
float operator[](int i) const {
float result[4];
store(result);
return result[i];
}
void store(float* v) const {
_mm_storeu_ps(v, val);
}
fvec4 operator+(const fvec4& other) const {
return _mm_add_ps(val, other);
}
fvec4 operator-(const fvec4& other) const {
return _mm_sub_ps(val, other);
}
fvec4 operator*(const fvec4& other) const {
return _mm_mul_ps(val, other);
}
fvec4 operator/(const fvec4& other) const {
return _mm_div_ps(val, other);
}
void operator+=(const fvec4& other) {
val = _mm_add_ps(val, other);
}
void operator-=(const fvec4& other) {
val = _mm_sub_ps(val, other);
}
void operator*=(const fvec4& other) {
val = _mm_mul_ps(val, other);
}
void operator/=(const fvec4& other) {
val = _mm_div_ps(val, other);
}
fvec4 operator-() const {
return _mm_sub_ps(_mm_set1_ps(0.0f), val);
}
fvec4 operator&(const fvec4& other) const {
return _mm_and_ps(val, other);
}
fvec4 operator|(const fvec4& other) const {
return _mm_or_ps(val, other);
}
fvec4 operator==(const fvec4& other) const {
return _mm_cmpeq_ps(val, other);
}
fvec4 operator!=(const fvec4& other) const {
return _mm_cmpneq_ps(val, other);
}
fvec4 operator>(const fvec4& other) const {
return _mm_cmpgt_ps(val, other);
}
fvec4 operator<(const fvec4& other) const {
return _mm_cmplt_ps(val, other);
}
fvec4 operator>=(const fvec4& other) const {
return _mm_cmpge_ps(val, other);
}
fvec4 operator<=(const fvec4& other) const {
return _mm_cmple_ps(val, other);
}
operator ivec4() const;
};
/**
* A four element vector of ints.
*/
class ivec4 {
public:
__m128i val;
ivec4() {}
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(__m128i v) : val(v) {}
ivec4(const int* v) : val(_mm_loadu_si128((const __m128i*) v)) {}
operator __m128i() const {
return val;
}
int operator[](int i) const {
int result[4];
store(result);
return result[i];
}
void store(int* v) const {
_mm_storeu_si128((__m128i*) v, val);
}
ivec4 operator+(const ivec4& other) const {
return _mm_add_epi32(val, other);
}
ivec4 operator-(const ivec4& other) const {
return _mm_sub_epi32(val, other);
}
ivec4 operator*(const ivec4& other) const {
return _mm_mul_epi32(val, other);
}
void operator+=(const ivec4& other) {
val = _mm_add_epi32(val, other);
}
void operator-=(const ivec4& other) {
val = _mm_sub_epi32(val, other);
}
void operator*=(const ivec4& other) {
val = _mm_mul_epi32(val, other);
}
ivec4 operator-() const {
return _mm_sub_epi32(_mm_set1_epi32(0), val);
}
ivec4 operator&(const ivec4& other) const {
return _mm_and_si128(val, other);
}
ivec4 operator|(const ivec4& other) const {
return _mm_or_si128(val, other);
}
ivec4 operator==(const ivec4& other) const {
return _mm_cmpeq_epi32(val, other);
}
ivec4 operator!=(const ivec4& other) const {
return _mm_xor_si128(*this==other, _mm_set1_epi32(0xFFFFFFFF));
}
ivec4 operator>(const ivec4& other) const {
return _mm_cmpgt_epi32(val, other);
}
ivec4 operator<(const ivec4& other) const {
return _mm_cmplt_epi32(val, other);
}
ivec4 operator>=(const ivec4& other) const {
return _mm_xor_si128(_mm_cmplt_epi32(val, other), _mm_set1_epi32(0xFFFFFFFF));
}
ivec4 operator<=(const ivec4& other) const {
return _mm_xor_si128(_mm_cmpgt_epi32(val, other), _mm_set1_epi32(0xFFFFFFFF));
}
operator fvec4() const;
};
// Conversion operators.
inline fvec4::operator ivec4() const {
return _mm_cvttps_epi32(val);
}
inline ivec4::operator fvec4() const {
return _mm_cvtepi32_ps(val);
}
// Functions that operate on fvec4s.
static inline fvec4 floor(const fvec4& v) {
return fvec4(_mm_floor_ps(v.val));
}
static inline fvec4 ceil(const fvec4& v) {
return fvec4(_mm_ceil_ps(v.val));
}
static inline fvec4 round(const fvec4& v) {
return fvec4(_mm_round_ps(v.val, _MM_FROUND_TO_NEAREST_INT));
}
static inline fvec4 min(const fvec4& v1, const fvec4& v2) {
return fvec4(_mm_min_ps(v1.val, v2.val));
}
static inline fvec4 max(const fvec4& v1, const fvec4& v2) {
return fvec4(_mm_max_ps(v1.val, v2.val));
}
static inline fvec4 abs(const fvec4& v) {
static const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF));
return fvec4(_mm_and_ps(v.val, mask));
}
static inline fvec4 sqrt(const fvec4& v) {
return fvec4(_mm_sqrt_ps(v.val));
}
static inline float dot3(const fvec4& v1, const fvec4& v2) {
return _mm_cvtss_f32(_mm_dp_ps(v1, v2, 0x71));
}
static inline float dot4(const fvec4& v1, const fvec4& v2) {
return _mm_cvtss_f32(_mm_dp_ps(v1, v2, 0xF1));
}
static inline void transpose(fvec4& v1, fvec4& v2, fvec4& v3, fvec4& v4) {
_MM_TRANSPOSE4_PS(v1, v2, v3, v4);
}
// Functions that operate on ivec4s.
static inline ivec4 min(const ivec4& v1, const ivec4& v2) {
return ivec4(_mm_min_epi32(v1.val, v2.val));
}
static inline ivec4 max(const ivec4& v1, const ivec4& v2) {
return ivec4(_mm_max_epi32(v1.val, v2.val));
}
static inline ivec4 abs(const ivec4& v) {
return ivec4(_mm_abs_epi32(v.val));
}
static inline bool any(const ivec4& v) {
return !_mm_test_all_zeros(v, _mm_set1_epi32(0xFFFFFFFF));
}
// Mathematical operators involving a scalar and a vector.
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) {
return fvec4(_mm_blendv_ps(v1.val, v2.val, _mm_castsi128_ps(mask.val)));
}
#endif /*OPENMM_VECTORIZE_H_*/ #endif /*OPENMM_VECTORIZE_H_*/
#ifndef OPENMM_VECTORIZE_NEON_H_
#define OPENMM_VECTORIZE_NEON_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) 2013-2014 Stanford University and the Authors. *
* Authors: Mateus Lima, 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 <cpu-features.h>
#include <arm_neon.h>
#include <cmath>
typedef int int32_t;
// This file defines classes and functions to simplify vectorizing code with NEON.
class ivec4;
/**
* A four element vector of floats.
*/
class fvec4 {
public:
float32x4_t val;
fvec4() {}
fvec4(float v) : val(vdupq_n_f32(v)) {}
fvec4(float v1, float v2, float v3, float v4) {
float v[] = {v1, v2, v3, v4};
val = vld1q_f32(v);
}
fvec4(float32x4_t v) : val(v) {}
fvec4(const float* v) : val(vld1q_f32(v)) {}
operator float32x4_t() const {
return val;
}
float operator[](int i) const {
switch (i) {
case 0:
return vgetq_lane_f32(val, 0);
case 1:
return vgetq_lane_f32(val, 1);
case 2:
return vgetq_lane_f32(val, 2);
case 3:
return vgetq_lane_f32(val, 3);
}
return 0.0f;
}
void store(float* v) const {
vst1q_f32(v, val);
}
fvec4 operator+(const fvec4& other) const {
return vaddq_f32(val, other);
}
fvec4 operator-(const fvec4& other) const {
return vsubq_f32(val, other);
}
fvec4 operator*(const fvec4& other) const {
return vmulq_f32(val, other);
}
fvec4 operator/(const fvec4& other) const {
// NEON does not have a divide float-point operator, so we get the reciprocal and multiply.
float32x4_t reciprocal = vrecpeq_f32(other);
reciprocal = vmulq_f32(vrecpsq_f32(other, reciprocal), reciprocal);
reciprocal = vmulq_f32(vrecpsq_f32(other, reciprocal), reciprocal);
fvec4 result = vmulq_f32(val,reciprocal);
return result;
}
void operator+=(const fvec4& other) {
val = vaddq_f32(val, other);
}
void operator-=(const fvec4& other) {
val = vsubq_f32(val, other);
}
void operator*=(const fvec4& other) {
val = vmulq_f32(val, other);
}
void operator/=(const fvec4& other) {
val = *this/other;
}
fvec4 operator-() const {
return vnegq_f32(val);
}
fvec4 operator&(const fvec4& other) const {
return vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(val), vreinterpretq_u32_f32(other)));
}
fvec4 operator|(const fvec4& other) const {
return vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(val), vreinterpretq_u32_f32(other)));
}
fvec4 operator==(const fvec4& other) const {
return vcvtq_f32_s32(vreinterpretq_s32_u32(vceqq_f32(val, other)));
}
fvec4 operator!=(const fvec4& other) const {
return vcvtq_f32_s32(vreinterpretq_s32_u32(vmvnq_u32(vceqq_f32(val, other)))); // not(equals(val, other))
}
fvec4 operator>(const fvec4& other) const {
return vcvtq_f32_s32(vreinterpretq_s32_u32(vcgtq_f32(val, other)));
}
fvec4 operator<(const fvec4& other) const {
return vcvtq_f32_s32(vreinterpretq_s32_u32(vcltq_f32(val, other)));
}
fvec4 operator>=(const fvec4& other) const {
return vcvtq_f32_s32(vreinterpretq_s32_u32(vcgeq_f32(val, other)));
}
fvec4 operator<=(const fvec4& other) const {
return vcvtq_f32_s32(vreinterpretq_s32_u32(vcleq_f32(val, other)));
}
operator ivec4() const;
};
/**
* A four element vector of ints.
*/
class ivec4 {
public:
int32x4_t val;
ivec4() {}
ivec4(int v) : val(vdupq_n_s32(v)) {}
ivec4(int v1, int v2, int v3, int v4) {
int v[] = {v1, v2, v3, v4};
val = vld1q_s32(v);
}
ivec4(int32x4_t v) : val(v) {}
ivec4(const int* v) : val(vld1q_s32(v)) {}
operator int32x4_t() const {
return val;
}
int operator[](int i) const {
switch (i) {
case 0:
return vgetq_lane_s32(val, 0);
case 1:
return vgetq_lane_s32(val, 1);
case 2:
return vgetq_lane_s32(val, 2);
case 3:
return vgetq_lane_s32(val, 3);
}
return 0;
}
void store(int* v) const {
vst1q_s32(v, val);
}
ivec4 operator+(const ivec4& other) const {
return vaddq_s32(val, other);
}
ivec4 operator-(const ivec4& other) const {
return vsubq_s32(val, other);
}
ivec4 operator*(const ivec4& other) const {
return vmulq_s32(val, other);
}
void operator+=(const ivec4& other) {
val = vaddq_s32(val, other);
}
void operator-=(const ivec4& other) {
val = vsubq_s32(val, other);
}
void operator*=(const ivec4& other) {
val = vmulq_s32(val, other);
}
ivec4 operator-() const {
return vnegq_s32(val);
}
ivec4 operator&(const ivec4& other) const {
return vandq_s32(val, other);
}
ivec4 operator|(const ivec4& other) const {
return vorrq_s32(val, other);
}
ivec4 operator==(const ivec4& other) const {
return vreinterpretq_s32_u32(vceqq_s32(val, other));
}
ivec4 operator!=(const ivec4& other) const {
return vreinterpretq_s32_u32(vmvnq_u32(vceqq_s32(val, other))); // not(equal(val, other))
}
ivec4 operator>(const ivec4& other) const {
return vreinterpretq_s32_u32(vcgtq_s32(val, other));
}
ivec4 operator<(const ivec4& other) const {
return vreinterpretq_s32_u32(vcltq_s32(val, other));
}
ivec4 operator>=(const ivec4& other) const {
return vreinterpretq_s32_u32(vcgeq_s32(val, other));
}
ivec4 operator<=(const ivec4& other) const {
return vreinterpretq_s32_u32(vcleq_s32(val, other));
}
operator fvec4() const;
};
// Conversion operators.
inline fvec4::operator ivec4() const {
return ivec4(vcvtq_s32_f32(val));
}
inline ivec4::operator fvec4() const {
return fvec4(vcvtq_f32_s32(val));
}
// Functions that operate on fvec4s.
static inline fvec4 min(const fvec4& v1, const fvec4& v2) {
return vminq_f32(v1, v2);
}
static inline fvec4 max(const fvec4& v1, const fvec4& v2) {
return vmaxq_f32(v1, v2);
}
static inline fvec4 abs(const fvec4& v) {
return vabsq_f32(v);
}
static inline fvec4 sqrt(const fvec4& v) {
float32x4_t recipSqrt = vrsqrteq_f32(v);
recipSqrt = vmulq_f32(recipSqrt, vrsqrtsq_f32(vmulq_f32(recipSqrt, v), recipSqrt));
recipSqrt = vmulq_f32(recipSqrt, vrsqrtsq_f32(vmulq_f32(recipSqrt, v), recipSqrt));
return vmulq_f32(v, recipSqrt);
}
static inline float dot3(const fvec4& v1, const fvec4& v2) {
fvec4 result = v1*v2;
return vgetq_lane_f32(result, 0) + vgetq_lane_f32(result, 1) + vgetq_lane_f32(result, 2);
}
static inline float dot4(const fvec4& v1, const fvec4& v2) {
fvec4 result = v1*v2;
return vgetq_lane_f32(result, 0) + vgetq_lane_f32(result, 1) + vgetq_lane_f32(result, 2) + vgetq_lane_f32(result,3);
}
static inline void transpose(fvec4& v1, fvec4& v2, fvec4& v3, fvec4& v4) {
float32x4x2_t t1 = vuzpq_f32(v1, v3);
float32x4x2_t t2 = vuzpq_f32(v2, v4);
float32x4x2_t t3 = vtrnq_f32(t1.val[0], t2.val[0]);
float32x4x2_t t4 = vtrnq_f32(t1.val[1], t2.val[1]);
v1 = t3.val[0];
v2 = t4.val[0];
v3 = t3.val[1];
v4 = t4.val[1];
}
// Functions that operate on ivec4s.
static inline ivec4 min(const ivec4& v1, const ivec4& v2) {
return vminq_s32(v1, v2);
}
static inline ivec4 max(const ivec4& v1, const ivec4& v2) {
return vmaxq_s32(v1, v2);
}
static inline ivec4 abs(const ivec4& v) {
return vabdq_s32(v, ivec4(0));
}
static inline bool any(const ivec4& v) {
return (vgetq_lane_s32(v, 0) != 0 || vgetq_lane_s32(v, 1) != 0 || vgetq_lane_s32(v, 2) != 0 || vgetq_lane_s32(v, 3) != 0);
}
// Mathematical operators involving a scalar and a vector.
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) {
return vbslq_f32(vreinterpretq_u32_s32(mask), v2, v1);
}
// These are at the end since they involve other functions defined above.
static inline fvec4 round(const fvec4& v) {
fvec4 shift(0x1.0p23f);
fvec4 absResult = (abs(v)+shift)-shift;
return blend(v, absResult, ivec4(0x7FFFFFFF));
}
static inline fvec4 floor(const fvec4& v) {
fvec4 rounded = round(v);
return rounded + blend(0.0f, -1.0f, rounded>v);
}
static inline fvec4 ceil(const fvec4& v) {
fvec4 rounded = round(v);
return rounded + blend(0.0f, 1.0f, rounded<v);
}
#endif /*OPENMM_VECTORIZE_NEON_H_*/
#ifndef OPENMM_VECTORIZE_SSE_H_
#define OPENMM_VECTORIZE_SSE_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) 2013 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 <smmintrin.h>
// This file defines classes and functions to simplify vectorizing code with SSE.
class ivec4;
/**
* A four element vector of floats.
*/
class fvec4 {
public:
__m128 val;
fvec4() {}
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(__m128 v) : val(v) {}
fvec4(const float* v) : val(_mm_loadu_ps(v)) {}
operator __m128() const {
return val;
}
float operator[](int i) const {
float result[4];
store(result);
return result[i];
}
void store(float* v) const {
_mm_storeu_ps(v, val);
}
fvec4 operator+(const fvec4& other) const {
return _mm_add_ps(val, other);
}
fvec4 operator-(const fvec4& other) const {
return _mm_sub_ps(val, other);
}
fvec4 operator*(const fvec4& other) const {
return _mm_mul_ps(val, other);
}
fvec4 operator/(const fvec4& other) const {
return _mm_div_ps(val, other);
}
void operator+=(const fvec4& other) {
val = _mm_add_ps(val, other);
}
void operator-=(const fvec4& other) {
val = _mm_sub_ps(val, other);
}
void operator*=(const fvec4& other) {
val = _mm_mul_ps(val, other);
}
void operator/=(const fvec4& other) {
val = _mm_div_ps(val, other);
}
fvec4 operator-() const {
return _mm_sub_ps(_mm_set1_ps(0.0f), val);
}
fvec4 operator&(const fvec4& other) const {
return _mm_and_ps(val, other);
}
fvec4 operator|(const fvec4& other) const {
return _mm_or_ps(val, other);
}
fvec4 operator==(const fvec4& other) const {
return _mm_cmpeq_ps(val, other);
}
fvec4 operator!=(const fvec4& other) const {
return _mm_cmpneq_ps(val, other);
}
fvec4 operator>(const fvec4& other) const {
return _mm_cmpgt_ps(val, other);
}
fvec4 operator<(const fvec4& other) const {
return _mm_cmplt_ps(val, other);
}
fvec4 operator>=(const fvec4& other) const {
return _mm_cmpge_ps(val, other);
}
fvec4 operator<=(const fvec4& other) const {
return _mm_cmple_ps(val, other);
}
operator ivec4() const;
};
/**
* A four element vector of ints.
*/
class ivec4 {
public:
__m128i val;
ivec4() {}
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(__m128i v) : val(v) {}
ivec4(const int* v) : val(_mm_loadu_si128((const __m128i*) v)) {}
operator __m128i() const {
return val;
}
int operator[](int i) const {
int result[4];
store(result);
return result[i];
}
void store(int* v) const {
_mm_storeu_si128((__m128i*) v, val);
}
ivec4 operator+(const ivec4& other) const {
return _mm_add_epi32(val, other);
}
ivec4 operator-(const ivec4& other) const {
return _mm_sub_epi32(val, other);
}
ivec4 operator*(const ivec4& other) const {
return _mm_mul_epi32(val, other);
}
void operator+=(const ivec4& other) {
val = _mm_add_epi32(val, other);
}
void operator-=(const ivec4& other) {
val = _mm_sub_epi32(val, other);
}
void operator*=(const ivec4& other) {
val = _mm_mul_epi32(val, other);
}
ivec4 operator-() const {
return _mm_sub_epi32(_mm_set1_epi32(0), val);
}
ivec4 operator&(const ivec4& other) const {
return _mm_and_si128(val, other);
}
ivec4 operator|(const ivec4& other) const {
return _mm_or_si128(val, other);
}
ivec4 operator==(const ivec4& other) const {
return _mm_cmpeq_epi32(val, other);
}
ivec4 operator!=(const ivec4& other) const {
return _mm_xor_si128(*this==other, _mm_set1_epi32(0xFFFFFFFF));
}
ivec4 operator>(const ivec4& other) const {
return _mm_cmpgt_epi32(val, other);
}
ivec4 operator<(const ivec4& other) const {
return _mm_cmplt_epi32(val, other);
}
ivec4 operator>=(const ivec4& other) const {
return _mm_xor_si128(_mm_cmplt_epi32(val, other), _mm_set1_epi32(0xFFFFFFFF));
}
ivec4 operator<=(const ivec4& other) const {
return _mm_xor_si128(_mm_cmpgt_epi32(val, other), _mm_set1_epi32(0xFFFFFFFF));
}
operator fvec4() const;
};
// Conversion operators.
inline fvec4::operator ivec4() const {
return _mm_cvttps_epi32(val);
}
inline ivec4::operator fvec4() const {
return _mm_cvtepi32_ps(val);
}
// Functions that operate on fvec4s.
static inline fvec4 floor(const fvec4& v) {
return fvec4(_mm_floor_ps(v.val));
}
static inline fvec4 ceil(const fvec4& v) {
return fvec4(_mm_ceil_ps(v.val));
}
static inline fvec4 round(const fvec4& v) {
return fvec4(_mm_round_ps(v.val, _MM_FROUND_TO_NEAREST_INT));
}
static inline fvec4 min(const fvec4& v1, const fvec4& v2) {
return fvec4(_mm_min_ps(v1.val, v2.val));
}
static inline fvec4 max(const fvec4& v1, const fvec4& v2) {
return fvec4(_mm_max_ps(v1.val, v2.val));
}
static inline fvec4 abs(const fvec4& v) {
static const __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF));
return fvec4(_mm_and_ps(v.val, mask));
}
static inline fvec4 sqrt(const fvec4& v) {
return fvec4(_mm_sqrt_ps(v.val));
}
static inline float dot3(const fvec4& v1, const fvec4& v2) {
return _mm_cvtss_f32(_mm_dp_ps(v1, v2, 0x71));
}
static inline float dot4(const fvec4& v1, const fvec4& v2) {
return _mm_cvtss_f32(_mm_dp_ps(v1, v2, 0xF1));
}
static inline void transpose(fvec4& v1, fvec4& v2, fvec4& v3, fvec4& v4) {
_MM_TRANSPOSE4_PS(v1, v2, v3, v4);
}
// Functions that operate on ivec4s.
static inline ivec4 min(const ivec4& v1, const ivec4& v2) {
return ivec4(_mm_min_epi32(v1.val, v2.val));
}
static inline ivec4 max(const ivec4& v1, const ivec4& v2) {
return ivec4(_mm_max_epi32(v1.val, v2.val));
}
static inline ivec4 abs(const ivec4& v) {
return ivec4(_mm_abs_epi32(v.val));
}
static inline bool any(const ivec4& v) {
return !_mm_test_all_zeros(v, _mm_set1_epi32(0xFFFFFFFF));
}
// Mathematical operators involving a scalar and a vector.
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) {
return fvec4(_mm_blendv_ps(v1.val, v2.val, _mm_castsi128_ps(mask.val)));
}
#endif /*OPENMM_VECTORIZE_SSE_H_*/
...@@ -174,6 +174,33 @@ void CustomNonbondedForce::setExclusionParticles(int index, int particle1, int p ...@@ -174,6 +174,33 @@ void CustomNonbondedForce::setExclusionParticles(int index, int particle1, int p
exclusions[index].particle1 = particle1; exclusions[index].particle1 = particle1;
exclusions[index].particle2 = particle2; exclusions[index].particle2 = particle2;
} }
void CustomNonbondedForce::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);
}
int CustomNonbondedForce::addTabulatedFunction(const std::string& name, TabulatedFunction* function) { int CustomNonbondedForce::addTabulatedFunction(const std::string& name, TabulatedFunction* function) {
functions.push_back(FunctionInfo(name, function)); functions.push_back(FunctionInfo(name, function));
return functions.size()-1; return functions.size()-1;
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* 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) 2008-2013 Stanford University and the Authors. * * Portions copyright (c) 2008-2014 Stanford University and the Authors. *
* Authors: Peter Eastman * * Authors: Peter Eastman *
* Contributors: * * Contributors: *
* * * *
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
#include "openmm/internal/CustomNonbondedForceImpl.h" #include "openmm/internal/CustomNonbondedForceImpl.h"
#include "openmm/internal/SplineFitter.h" #include "openmm/internal/SplineFitter.h"
#include "openmm/kernels.h" #include "openmm/kernels.h"
#include "lepton/CustomFunction.h" #include "ReferenceTabulatedFunction.h"
#include "lepton/ParsedExpression.h" #include "lepton/ParsedExpression.h"
#include "lepton/Parser.h" #include "lepton/Parser.h"
#include <cmath> #include <cmath>
...@@ -137,38 +137,6 @@ void CustomNonbondedForceImpl::updateParametersInContext(ContextImpl& context) { ...@@ -137,38 +137,6 @@ void CustomNonbondedForceImpl::updateParametersInContext(ContextImpl& context) {
kernel.getAs<CalcCustomNonbondedForceKernel>().copyParametersToContext(context, owner); kernel.getAs<CalcCustomNonbondedForceKernel>().copyParametersToContext(context, owner);
} }
class CustomNonbondedForceImpl::TabulatedFunction : public Lepton::CustomFunction {
public:
TabulatedFunction(double min, double max, const vector<double>& values) :
min(min), max(max), values(values) {
int numValues = values.size();
x.resize(numValues);
for (int i = 0; i < numValues; i++)
x[i] = min+i*(max-min)/(numValues-1);
SplineFitter::createNaturalSpline(x, values, derivs);
}
int getNumArguments() const {
return 1;
}
double evaluate(const double* arguments) const {
double t = arguments[0];
if (t < min || t > max)
return 0.0;
return SplineFitter::evaluateSpline(x, values, derivs, t);
}
double evaluateDerivative(const double* arguments, const int* derivOrder) const {
double t = arguments[0];
if (t < min || t > max)
return 0.0;
return SplineFitter::evaluateSplineDerivative(x, values, derivs, t);
}
CustomFunction* clone() const {
return new TabulatedFunction(min, max, values);
}
double min, max;
vector<double> x, values, derivs;
};
double CustomNonbondedForceImpl::calcLongRangeCorrection(const CustomNonbondedForce& force, const Context& context) { double CustomNonbondedForceImpl::calcLongRangeCorrection(const CustomNonbondedForce& force, const Context& context) {
if (force.getNonbondedMethod() == CustomNonbondedForce::NoCutoff || force.getNonbondedMethod() == CustomNonbondedForce::CutoffNonPeriodic) if (force.getNonbondedMethod() == CustomNonbondedForce::NoCutoff || force.getNonbondedMethod() == CustomNonbondedForce::CutoffNonPeriodic)
return 0.0; return 0.0;
...@@ -176,13 +144,8 @@ double CustomNonbondedForceImpl::calcLongRangeCorrection(const CustomNonbondedFo ...@@ -176,13 +144,8 @@ double CustomNonbondedForceImpl::calcLongRangeCorrection(const CustomNonbondedFo
// Parse the energy expression. // Parse the energy expression.
map<string, Lepton::CustomFunction*> functions; map<string, Lepton::CustomFunction*> functions;
for (int i = 0; i < force.getNumFunctions(); i++) { for (int i = 0; i < force.getNumFunctions(); i++)
string name; functions[force.getTabulatedFunctionName(i)] = createReferenceTabulatedFunction(force.getTabulatedFunction(i));
vector<double> values;
double min, max;
force.getFunctionParameters(i, name, values, min, max);
functions[name] = new TabulatedFunction(min, max, values);
}
Lepton::CompiledExpression expression = Lepton::Parser::parse(force.getEnergyFunction(), functions).createCompiledExpression(); Lepton::CompiledExpression expression = Lepton::Parser::parse(force.getEnergyFunction(), functions).createCompiledExpression();
// Identify all particle classes (defined by parameters), and record the class of each particle. // Identify all particle classes (defined by parameters), and record the class of each particle.
......
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
* USE OR OTHER DEALINGS IN THE SOFTWARE. * * USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */ * -------------------------------------------------------------------------- */
#include <stdexcept>
#if defined(_WIN32) || defined(__CYGWIN__) #if defined(_WIN32) || defined(__CYGWIN__)
#include <windows.h> #include <windows.h>
static HCRYPTPROV hCryptProv = 0; static HCRYPTPROV hCryptProv = 0;
...@@ -38,28 +37,31 @@ static HCRYPTPROV hCryptProv = 0; ...@@ -38,28 +37,31 @@ static HCRYPTPROV hCryptProv = 0;
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#endif #endif
#include "openmm/OpenMMException.h"
#include "openmm/internal/OSRngSeed.h" #include "openmm/internal/OSRngSeed.h"
using OpenMM::OpenMMException;
int osrngseed(void) { int osrngseed(void) {
int value; int value;
#if defined(_WIN32) || defined(__CYGWIN__) #if defined(_WIN32) || defined(__CYGWIN__)
if (!::CryptAcquireContextW(&hCryptProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) { if (!::CryptAcquireContextW(&hCryptProv, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
throw std::runtime_error("Failed to initialize Windows random API (CryptoGen)"); throw OpenMMException("Failed to initialize Windows random API (CryptoGen)");
} }
if (!CryptGenRandom(hCryptProv, sizeof(int), (BYTE*) &value)) { if (!CryptGenRandom(hCryptProv, sizeof(int), (BYTE*) &value)) {
::CryptReleaseContext(hCryptProv, 0); ::CryptReleaseContext(hCryptProv, 0);
throw std::runtime_error("Failed to get random numbers"); throw OpenMMException("Failed to get random numbers");
} }
if (!::CryptReleaseContext(hCryptProv, 0)) { if (!::CryptReleaseContext(hCryptProv, 0)) {
throw std::runtime_error("Failed to release Windows random API context"); throw OpenMMException("Failed to release Windows random API context");
} }
#else #else
int m_fd = open("/dev/urandom", O_RDONLY); int m_fd = open("/dev/urandom", O_RDONLY);
if (m_fd == -1) { if (m_fd == -1) {
throw std::runtime_error("Failed to open /dev/urandom"); throw OpenMMException("Failed to open /dev/urandom");
} }
if (read(m_fd, &value, sizeof(int)) != sizeof(int)) { if (read(m_fd, &value, sizeof(int)) != sizeof(int)) {
throw std::runtime_error("Failed to read bytes from /dev/urandom"); throw OpenMMException("Failed to read bytes from /dev/urandom");
} }
close(m_fd); close(m_fd);
#endif #endif
......
FOREACH(file ${SOURCE_FILES}) FOREACH(file ${SOURCE_FILES})
IF (file MATCHES ".*Vec8.*") IF (file MATCHES ".*Vec8.*")
IF (MSVC) IF (MSVC)
SET_SOURCE_FILES_PROPERTIES(${file} PROPERTIES COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} /arch:AVX /D__AVX__") SET_SOURCE_FILES_PROPERTIES(${file} PROPERTIES COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} /arch:AVX /D__AVX__")
ELSE (MSVC) ELSE (MSVC)
SET_SOURCE_FILES_PROPERTIES(${file} PROPERTIES COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -msse4.1 -mavx") IF (NOT ANDROID)
ENDIF (MSVC) SET_SOURCE_FILES_PROPERTIES(${file} PROPERTIES COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -msse4.1 -mavx")
ENDIF (NOT ANDROID)
ENDIF (MSVC)
ELSE (file MATCHES ".*Vec8.*") ELSE (file MATCHES ".*Vec8.*")
IF (NOT MSVC) IF (NOT MSVC)
SET_SOURCE_FILES_PROPERTIES(${file} PROPERTIES COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -msse4.1") IF (NOT ANDROID)
ENDIF (NOT MSVC) SET_SOURCE_FILES_PROPERTIES(${file} PROPERTIES COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -msse4.1")
ENDIF (NOT ANDROID)
ENDIF (NOT MSVC)
ENDIF (file MATCHES ".*Vec8.*") ENDIF (file MATCHES ".*Vec8.*")
ENDFOREACH(file) ENDFOREACH(file)
ADD_LIBRARY(${SHARED_TARGET} SHARED ${SOURCE_FILES} ${SOURCE_INCLUDE_FILES} ${API_ABS_INCLUDE_FILES}) ADD_LIBRARY(${SHARED_TARGET} SHARED ${SOURCE_FILES} ${SOURCE_INCLUDE_FILES} ${API_ABS_INCLUDE_FILES})
......
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
#include <set> #include <set>
#include <map> #include <map>
#include <cmath> #include <cmath>
#include <smmintrin.h>
using namespace std; using namespace std;
......
...@@ -103,7 +103,7 @@ void CpuNonbondedForceVec4::calculateBlockIxn(int blockIndex, float* forces, dou ...@@ -103,7 +103,7 @@ void CpuNonbondedForceVec4::calculateBlockIxn(int blockIndex, float* forces, dou
dEdR = epsSig6*(12.0f*sig6 - 6.0f); dEdR = epsSig6*(12.0f*sig6 - 6.0f);
energy = epsSig6*(sig6-1.0f); energy = epsSig6*(sig6-1.0f);
if (useSwitch) { if (useSwitch) {
fvec4 t = (r>switchingDistance) & ((r-switchingDistance)*invSwitchingInterval); fvec4 t = blend(0.0f, (r-switchingDistance)*invSwitchingInterval, r>switchingDistance);
fvec4 switchValue = 1+t*t*t*(-10.0f+t*(15.0f-t*6.0f)); fvec4 switchValue = 1+t*t*t*(-10.0f+t*(15.0f-t*6.0f));
fvec4 switchDeriv = t*t*(-30.0f+t*(60.0f-t*30.0f))*invSwitchingInterval; fvec4 switchDeriv = t*t*(-30.0f+t*(60.0f-t*30.0f))*invSwitchingInterval;
dEdR = switchValue*dEdR - energy*switchDeriv*r; dEdR = switchValue*dEdR - energy*switchDeriv*r;
...@@ -214,7 +214,7 @@ void CpuNonbondedForceVec4::calculateBlockEwaldIxn(int blockIndex, float* forces ...@@ -214,7 +214,7 @@ void CpuNonbondedForceVec4::calculateBlockEwaldIxn(int blockIndex, float* forces
dEdR = epsSig6*(12.0f*sig6 - 6.0f); dEdR = epsSig6*(12.0f*sig6 - 6.0f);
energy = epsSig6*(sig6-1.0f); energy = epsSig6*(sig6-1.0f);
if (useSwitch) { if (useSwitch) {
fvec4 t = (r>switchingDistance) & ((r-switchingDistance)*invSwitchingInterval); fvec4 t = blend(0.0f, (r-switchingDistance)*invSwitchingInterval, r>switchingDistance);
fvec4 switchValue = 1+t*t*t*(-10.0f+t*(15.0f-t*6.0f)); fvec4 switchValue = 1+t*t*t*(-10.0f+t*(15.0f-t*6.0f));
fvec4 switchDeriv = t*t*(-30.0f+t*(60.0f-t*30.0f))*invSwitchingInterval; fvec4 switchDeriv = t*t*(-30.0f+t*(60.0f-t*30.0f))*invSwitchingInterval;
dEdR = switchValue*dEdR - energy*switchDeriv*r; dEdR = switchValue*dEdR - energy*switchDeriv*r;
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include "ReferenceConstraints.h" #include "ReferenceConstraints.h"
#include "openmm/internal/hardware.h" #include "openmm/internal/hardware.h"
#include <sstream> #include <sstream>
#include <stdlib.h>
using namespace OpenMM; using namespace OpenMM;
using namespace std; using namespace std;
...@@ -93,15 +94,20 @@ bool CpuPlatform::supportsDoublePrecision() const { ...@@ -93,15 +94,20 @@ bool CpuPlatform::supportsDoublePrecision() const {
} }
bool CpuPlatform::isProcessorSupported() { bool CpuPlatform::isProcessorSupported() {
// Make sure the CPU supports SSE 4.1. // Make sure the CPU supports SSE 4.1 or NEON.
int cpuInfo[4]; #ifdef __ANDROID__
cpuid(cpuInfo, 0); uint64_t features = android_getCpuFeatures();
if (cpuInfo[0] >= 1) { return (features & ANDROID_CPU_ARM_FEATURE_NEON) != 0;
cpuid(cpuInfo, 1); #else
return ((cpuInfo[2] & ((int) 1 << 19)) != 0); int cpuInfo[4];
} cpuid(cpuInfo, 0);
return false; if (cpuInfo[0] >= 1) {
cpuid(cpuInfo, 1);
return ((cpuInfo[2] & ((int) 1 << 19)) != 0);
}
return false;
#endif
} }
void CpuPlatform::contextCreated(ContextImpl& context, const map<string, string>& properties) const { void CpuPlatform::contextCreated(ContextImpl& context, const map<string, string>& properties) const {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment