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
7e72bafb
Unverified
Commit
7e72bafb
authored
Dec 21, 2019
by
Zheng GONG
Committed by
GitHub
Dec 21, 2019
Browse files
Merge pull request #3 from openmm/master
Update from upstream
parents
83b8ea75
f6431a42
Changes
81
Show whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
2354 additions
and
62 deletions
+2354
-62
libraries/lepton/include/lepton/ParsedExpression.h
libraries/lepton/include/lepton/ParsedExpression.h
+1
-0
libraries/lepton/src/ParsedExpression.cpp
libraries/lepton/src/ParsedExpression.cpp
+76
-58
olla/include/openmm/kernels.h
olla/include/openmm/kernels.h
+89
-0
openmmapi/include/OpenMM.h
openmmapi/include/OpenMM.h
+2
-0
openmmapi/include/openmm/NoseHooverChain.h
openmmapi/include/openmm/NoseHooverChain.h
+266
-0
openmmapi/include/openmm/NoseHooverIntegrator.h
openmmapi/include/openmm/NoseHooverIntegrator.h
+279
-0
openmmapi/src/ContextImpl.cpp
openmmapi/src/ContextImpl.cpp
+4
-0
openmmapi/src/NoseHooverChain.cpp
openmmapi/src/NoseHooverChain.cpp
+61
-0
openmmapi/src/NoseHooverIntegrator.cpp
openmmapi/src/NoseHooverIntegrator.cpp
+356
-0
platforms/cuda/include/CudaIntegrationUtilities.h
platforms/cuda/include/CudaIntegrationUtilities.h
+8
-0
platforms/cuda/include/CudaKernels.h
platforms/cuda/include/CudaKernels.h
+103
-0
platforms/cuda/src/CudaIntegrationUtilities.cpp
platforms/cuda/src/CudaIntegrationUtilities.cpp
+44
-1
platforms/cuda/src/CudaKernelFactory.cpp
platforms/cuda/src/CudaKernelFactory.cpp
+4
-0
platforms/cuda/src/CudaKernels.cpp
platforms/cuda/src/CudaKernels.cpp
+465
-2
platforms/cuda/src/CudaPlatform.cpp
platforms/cuda/src/CudaPlatform.cpp
+2
-0
platforms/cuda/src/kernels/noseHooverChain.cu
platforms/cuda/src/kernels/noseHooverChain.cu
+172
-0
platforms/cuda/src/kernels/utilities.cu
platforms/cuda/src/kernels/utilities.cu
+1
-1
platforms/cuda/src/kernels/velocityVerlet.cu
platforms/cuda/src/kernels/velocityVerlet.cu
+349
-0
platforms/cuda/tests/TestCudaNoseHooverIntegrator.cpp
platforms/cuda/tests/TestCudaNoseHooverIntegrator.cpp
+36
-0
platforms/cuda/tests/TestCudaNoseHooverThermostat.cpp
platforms/cuda/tests/TestCudaNoseHooverThermostat.cpp
+36
-0
No files found.
libraries/lepton/include/lepton/ParsedExpression.h
View file @
7e72bafb
...
...
@@ -116,6 +116,7 @@ private:
static
ExpressionTreeNode
precalculateConstantSubexpressions
(
const
ExpressionTreeNode
&
node
);
static
ExpressionTreeNode
substituteSimplerExpression
(
const
ExpressionTreeNode
&
node
);
static
ExpressionTreeNode
differentiate
(
const
ExpressionTreeNode
&
node
,
const
std
::
string
&
variable
);
static
bool
isConstant
(
const
ExpressionTreeNode
&
node
);
static
double
getConstantValue
(
const
ExpressionTreeNode
&
node
);
static
ExpressionTreeNode
renameNodeVariables
(
const
ExpressionTreeNode
&
node
,
const
std
::
map
<
std
::
string
,
std
::
string
>&
replacements
);
ExpressionTreeNode
rootNode
;
...
...
libraries/lepton/src/ParsedExpression.cpp
View file @
7e72bafb
...
...
@@ -121,19 +121,33 @@ ExpressionTreeNode ParsedExpression::substituteSimplerExpression(const Expressio
vector
<
ExpressionTreeNode
>
children
(
node
.
getChildren
().
size
());
for
(
int
i
=
0
;
i
<
(
int
)
children
.
size
();
i
++
)
children
[
i
]
=
substituteSimplerExpression
(
node
.
getChildren
()[
i
]);
// Collect some info on constant expressions in children
bool
first_const
=
children
.
size
()
>
0
&&
isConstant
(
children
[
0
]);
// is first child constant?
bool
second_const
=
children
.
size
()
>
1
&&
isConstant
(
children
[
1
]);
;
// is second child constant?
double
first
,
second
;
// if yes, value of first and second child
if
(
first_const
)
first
=
getConstantValue
(
children
[
0
]);
if
(
second_const
)
second
=
getConstantValue
(
children
[
1
]);
switch
(
node
.
getOperation
().
getId
())
{
case
Operation
::
ADD
:
{
double
first
=
getConstantValue
(
children
[
0
]);
double
second
=
getConstantValue
(
children
[
1
]);
if
(
first
==
0.0
)
// Add 0
if
(
first_const
)
{
if
(
first
==
0.0
)
{
// Add 0
return
children
[
1
];
if
(
second
==
0.0
)
// Add 0
return
children
[
0
];
if
(
first
==
first
)
// Add a constant
}
else
{
// Add a constant
return
ExpressionTreeNode
(
new
Operation
::
AddConstant
(
first
),
children
[
1
]);
if
(
second
==
second
)
// Add a constant
}
}
if
(
second_const
)
{
if
(
second
==
0.0
)
{
// Add 0
return
children
[
0
];
}
else
{
// Add a constant
return
ExpressionTreeNode
(
new
Operation
::
AddConstant
(
second
),
children
[
0
]);
}
}
if
(
children
[
1
].
getOperation
().
getId
()
==
Operation
::
NEGATE
)
// a+(-b) = a-b
return
ExpressionTreeNode
(
new
Operation
::
Subtract
(),
children
[
0
],
children
[
1
].
getChildren
()[
0
]);
if
(
children
[
0
].
getOperation
().
getId
()
==
Operation
::
NEGATE
)
// (-a)+b = b-a
...
...
@@ -144,34 +158,35 @@ ExpressionTreeNode ParsedExpression::substituteSimplerExpression(const Expressio
{
if
(
children
[
0
]
==
children
[
1
])
return
ExpressionTreeNode
(
new
Operation
::
Constant
(
0.0
));
// Subtracting anything from itself is 0
double
first
=
getConstantValue
(
children
[
0
]);
if
(
first_const
)
{
if
(
first
==
0.0
)
// Subtract from 0
return
ExpressionTreeNode
(
new
Operation
::
Negate
(),
children
[
1
]);
double
second
=
getConstantValue
(
children
[
1
]);
if
(
second
==
0.0
)
// Subtract 0
}
if
(
second_const
)
{
if
(
second
==
0.0
)
{
// Subtract 0
return
children
[
0
];
if
(
second
==
second
)
// Subtract a constant
}
else
{
// Subtract a constant
return
ExpressionTreeNode
(
new
Operation
::
AddConstant
(
-
second
),
children
[
0
]);
}
}
if
(
children
[
1
].
getOperation
().
getId
()
==
Operation
::
NEGATE
)
// a-(-b) = a+b
return
ExpressionTreeNode
(
new
Operation
::
Add
(),
children
[
0
],
children
[
1
].
getChildren
()[
0
]);
break
;
}
case
Operation
::
MULTIPLY
:
{
double
first
=
getConstantValue
(
children
[
0
]);
double
second
=
getConstantValue
(
children
[
1
]);
if
(
first
==
0.0
||
second
==
0.0
)
// Multiply by 0
if
((
first_const
&&
first
==
0.0
)
||
(
second_const
&&
second
==
0.0
))
// Multiply by 0
return
ExpressionTreeNode
(
new
Operation
::
Constant
(
0.0
));
if
(
first
==
1.0
)
// Multiply by 1
if
(
first
_const
&&
first
==
1.0
)
// Multiply by 1
return
children
[
1
];
if
(
second
==
1.0
)
// Multiply by 1
if
(
second
_const
&&
second
==
1.0
)
// Multiply by 1
return
children
[
0
];
if
(
children
[
0
].
getOperation
().
getId
()
==
Operation
::
CONSTANT
)
{
// Multiply by a constant
if
(
first_const
)
{
// Multiply by a constant
if
(
children
[
1
].
getOperation
().
getId
()
==
Operation
::
MULTIPLY_CONSTANT
)
// Combine two multiplies into a single one
return
ExpressionTreeNode
(
new
Operation
::
MultiplyConstant
(
first
*
dynamic_cast
<
const
Operation
::
MultiplyConstant
*>
(
&
children
[
1
].
getOperation
())
->
getValue
()),
children
[
1
].
getChildren
()[
0
]);
return
ExpressionTreeNode
(
new
Operation
::
MultiplyConstant
(
first
),
children
[
1
]);
}
if
(
children
[
1
].
getOperation
().
getId
()
==
Operation
::
CONSTANT
)
{
// Multiply by a constant
if
(
second_const
)
{
// Multiply by a constant
if
(
children
[
0
].
getOperation
().
getId
()
==
Operation
::
MULTIPLY_CONSTANT
)
// Combine two multiplies into a single one
return
ExpressionTreeNode
(
new
Operation
::
MultiplyConstant
(
second
*
dynamic_cast
<
const
Operation
::
MultiplyConstant
*>
(
&
children
[
0
].
getOperation
())
->
getValue
()),
children
[
0
].
getChildren
()[
0
]);
return
ExpressionTreeNode
(
new
Operation
::
MultiplyConstant
(
second
),
children
[
0
]);
...
...
@@ -202,18 +217,16 @@ ExpressionTreeNode ParsedExpression::substituteSimplerExpression(const Expressio
{
if
(
children
[
0
]
==
children
[
1
])
return
ExpressionTreeNode
(
new
Operation
::
Constant
(
1.0
));
// Dividing anything from itself is 0
double
numerator
=
getConstantValue
(
children
[
0
]);
if
(
numerator
==
0.0
)
// 0 divided by something
if
(
first_const
&&
first
==
0.0
)
// 0 divided by something
return
ExpressionTreeNode
(
new
Operation
::
Constant
(
0.0
));
if
(
numerator
==
1.0
)
// 1 divided by something
if
(
first_const
&&
first
==
1.0
)
// 1 divided by something
return
ExpressionTreeNode
(
new
Operation
::
Reciprocal
(),
children
[
1
]);
double
denominator
=
getConstantValue
(
children
[
1
]);
if
(
denominator
==
1.0
)
// Divide by 1
if
(
second_const
&&
second
==
1.0
)
// Divide by 1
return
children
[
0
];
if
(
children
[
1
].
getOperation
().
getId
()
==
Operation
::
CONSTANT
)
{
if
(
second_const
)
{
if
(
children
[
0
].
getOperation
().
getId
()
==
Operation
::
MULTIPLY_CONSTANT
)
// Combine a multiply and a divide into one multiply
return
ExpressionTreeNode
(
new
Operation
::
MultiplyConstant
(
dynamic_cast
<
const
Operation
::
MultiplyConstant
*>
(
&
children
[
0
].
getOperation
())
->
getValue
()
/
denominator
),
children
[
0
].
getChildren
()[
0
]);
return
ExpressionTreeNode
(
new
Operation
::
MultiplyConstant
(
1.0
/
denominator
),
children
[
0
]);
// Replace a divide with a multiply
return
ExpressionTreeNode
(
new
Operation
::
MultiplyConstant
(
dynamic_cast
<
const
Operation
::
MultiplyConstant
*>
(
&
children
[
0
].
getOperation
())
->
getValue
()
/
second
),
children
[
0
].
getChildren
()[
0
]);
return
ExpressionTreeNode
(
new
Operation
::
MultiplyConstant
(
1.0
/
second
),
children
[
0
]);
// Replace a divide with a multiply
}
if
(
children
[
0
].
getOperation
().
getId
()
==
Operation
::
NEGATE
&&
children
[
1
].
getOperation
().
getId
()
==
Operation
::
NEGATE
)
// The two negations cancel
return
ExpressionTreeNode
(
new
Operation
::
Divide
(),
children
[
0
].
getChildren
()[
0
],
children
[
1
].
getChildren
()[
0
]);
...
...
@@ -229,34 +242,34 @@ ExpressionTreeNode ParsedExpression::substituteSimplerExpression(const Expressio
}
case
Operation
::
POWER
:
{
double
base
=
getConstantValue
(
children
[
0
]);
if
(
base
==
0.0
)
// 0 to any power is 0
if
(
first_const
&&
first
==
0.0
)
// 0 to any power is 0
return
ExpressionTreeNode
(
new
Operation
::
Constant
(
0.0
));
if
(
base
==
1.0
)
// 1 to any power is 1
if
(
first_const
&&
first
==
1.0
)
// 1 to any power is 1
return
ExpressionTreeNode
(
new
Operation
::
Constant
(
1.0
));
double
exponent
=
getConstantValue
(
children
[
1
]);
if
(
exponent
==
0.0
)
// x^0 = 1
if
(
second_const
)
{
// Constant exponent
if
(
second
==
0.0
)
// x^0 = 1
return
ExpressionTreeNode
(
new
Operation
::
Constant
(
1.0
));
if
(
exponent
==
1.0
)
// x^1 = x
if
(
second
==
1.0
)
// x^1 = x
return
children
[
0
];
if
(
exponent
==
-
1.0
)
// x^-1 = recip(x)
if
(
second
==
-
1.0
)
// x^-1 = recip(x)
return
ExpressionTreeNode
(
new
Operation
::
Reciprocal
(),
children
[
0
]);
if
(
exponent
==
2.0
)
// x^2 = square(x)
if
(
second
==
2.0
)
// x^2 = square(x)
return
ExpressionTreeNode
(
new
Operation
::
Square
(),
children
[
0
]);
if
(
exponent
==
3.0
)
// x^3 = cube(x)
if
(
second
==
3.0
)
// x^3 = cube(x)
return
ExpressionTreeNode
(
new
Operation
::
Cube
(),
children
[
0
]);
if
(
exponent
==
0.5
)
// x^0.5 = sqrt(x)
if
(
second
==
0.5
)
// x^0.5 = sqrt(x)
return
ExpressionTreeNode
(
new
Operation
::
Sqrt
(),
children
[
0
]);
if
(
exponent
==
exponent
)
// Constant power
return
ExpressionTreeNode
(
new
Operation
::
PowerConstant
(
exponent
),
children
[
0
]);
// Constant power
return
ExpressionTreeNode
(
new
Operation
::
PowerConstant
(
second
),
children
[
0
]);
}
break
;
}
case
Operation
::
NEGATE
:
{
if
(
children
[
0
].
getOperation
().
getId
()
==
Operation
::
MULTIPLY_CONSTANT
)
// Combine a multiply and a negate into a single multiply
return
ExpressionTreeNode
(
new
Operation
::
MultiplyConstant
(
-
dynamic_cast
<
const
Operation
::
MultiplyConstant
*>
(
&
children
[
0
].
getOperation
())
->
getValue
()),
children
[
0
].
getChildren
()[
0
]);
if
(
children
[
0
].
getOperation
().
getId
()
==
Operation
::
CONSTANT
)
// Negate a constant
return
ExpressionTreeNode
(
new
Operation
::
Constant
(
-
getConstantValue
(
children
[
0
])
));
if
(
first_const
)
// Negate a constant
return
ExpressionTreeNode
(
new
Operation
::
Constant
(
-
first
));
if
(
children
[
0
].
getOperation
().
getId
()
==
Operation
::
NEGATE
)
// The two negations cancel
return
children
[
0
].
getChildren
()[
0
];
break
;
...
...
@@ -265,7 +278,7 @@ ExpressionTreeNode ParsedExpression::substituteSimplerExpression(const Expressio
{
if
(
children
[
0
].
getOperation
().
getId
()
==
Operation
::
MULTIPLY_CONSTANT
)
// Combine two multiplies into a single one
return
ExpressionTreeNode
(
new
Operation
::
MultiplyConstant
(
dynamic_cast
<
const
Operation
::
MultiplyConstant
*>
(
&
node
.
getOperation
())
->
getValue
()
*
dynamic_cast
<
const
Operation
::
MultiplyConstant
*>
(
&
children
[
0
].
getOperation
())
->
getValue
()),
children
[
0
].
getChildren
()[
0
]);
if
(
children
[
0
].
getOperation
().
getId
()
==
Operation
::
CONSTANT
)
// Multiply two constants
if
(
first_const
)
// Multiply two constants
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
return
ExpressionTreeNode
(
new
Operation
::
MultiplyConstant
(
-
dynamic_cast
<
const
Operation
::
MultiplyConstant
*>
(
&
node
.
getOperation
())
->
getValue
()),
children
[
0
].
getChildren
()[
0
]);
...
...
@@ -303,10 +316,15 @@ ExpressionTreeNode ParsedExpression::differentiate(const ExpressionTreeNode& nod
return
node
.
getOperation
().
differentiate
(
node
.
getChildren
(),
childDerivs
,
variable
);
}
bool
ParsedExpression
::
isConstant
(
const
ExpressionTreeNode
&
node
)
{
return
(
node
.
getOperation
().
getId
()
==
Operation
::
CONSTANT
);
}
double
ParsedExpression
::
getConstantValue
(
const
ExpressionTreeNode
&
node
)
{
if
(
node
.
getOperation
().
getId
()
==
Operation
::
CONSTANT
)
if
(
node
.
getOperation
().
getId
()
!=
Operation
::
CONSTANT
)
{
throw
Exception
(
"getConstantValue called on a non-constant ExpressionNode"
);
}
return
dynamic_cast
<
const
Operation
::
Constant
&>
(
node
.
getOperation
()).
getValue
();
return
numeric_limits
<
double
>::
quiet_NaN
();
}
ExpressionProgram
ParsedExpression
::
createProgram
()
const
{
...
...
olla/include/openmm/kernels.h
View file @
7e72bafb
...
...
@@ -64,6 +64,8 @@
#include "openmm/VariableLangevinIntegrator.h"
#include "openmm/VariableVerletIntegrator.h"
#include "openmm/VerletIntegrator.h"
#include "openmm/NoseHooverIntegrator.h"
#include "openmm/NoseHooverChain.h"
#include <iosfwd>
#include <set>
#include <string>
...
...
@@ -1058,6 +1060,41 @@ public:
virtual
double
computeKineticEnergy
(
ContextImpl
&
context
,
const
VerletIntegrator
&
integrator
)
=
0
;
};
/**
* This kernel is invoked by NoseHooverIntegrator to take one time step.
*/
class
IntegrateVelocityVerletStepKernel
:
public
KernelImpl
{
public:
static
std
::
string
Name
()
{
return
"IntegrateVelocityVerletStep"
;
}
IntegrateVelocityVerletStepKernel
(
std
::
string
name
,
const
Platform
&
platform
)
:
KernelImpl
(
name
,
platform
)
{
}
/**
* Initialize the kernel.
*
* @param system the System this kernel will be applied to
* @param integrator the NoseHooverIntegrator this kernel will be used for
*/
virtual
void
initialize
(
const
System
&
system
,
const
NoseHooverIntegrator
&
integrator
)
=
0
;
/**
* Execute the kernel.
*
* @param context the context in which to execute this kernel
* @param integrator the NoseHooverIntegrator this kernel is being used for
* @param forcesAreValid a reference to the parent integrator's boolean for keeping
* track of the validity of the current forces.
*/
virtual
void
execute
(
ContextImpl
&
context
,
const
NoseHooverIntegrator
&
integrator
,
bool
&
forcesAreValid
)
=
0
;
/**
* Compute the kinetic energy.
*
* @param context the context in which to execute this kernel
* @param integrator the NoseHooverIntegrator this kernel is being used for
*/
virtual
double
computeKineticEnergy
(
ContextImpl
&
context
,
const
NoseHooverIntegrator
&
integrator
)
=
0
;
};
/**
* This kernel is invoked by LangevinIntegrator to take one time step.
*/
...
...
@@ -1327,6 +1364,58 @@ public:
virtual
void
execute
(
ContextImpl
&
context
)
=
0
;
};
/**
* This kernel is invoked by NoseHooverChainThermostat at the beginning and end of each time step
* to update the Nose-Hoover chain.
*/
class
NoseHooverChainKernel
:
public
KernelImpl
{
public:
static
std
::
string
Name
()
{
return
"NoseHooverChain"
;
}
NoseHooverChainKernel
(
std
::
string
name
,
const
Platform
&
platform
)
:
KernelImpl
(
name
,
platform
)
{
}
/**
* Initialize the kernel.
*/
virtual
void
initialize
()
=
0
;
/**
* Execute the kernel that propagates the Nose Hoover chain and determines the velocity scale factor.
*
* @param context the context in which to execute this kernel
* @param noseHooverChain the object describing the chain to be propagated.
* @param kineticEnergy the {center of mass, relative} kineticEnergies of the particles being thermostated by this chain.
* @param timeStep the time step used by the integrator.
* @return the velocity scale factor to apply to the particles associated with this heat bath.
*/
virtual
std
::
pair
<
double
,
double
>
propagateChain
(
ContextImpl
&
context
,
const
NoseHooverChain
&
noseHooverChain
,
std
::
pair
<
double
,
double
>
kineticEnergy
,
double
timeStep
)
=
0
;
/**
* Execute the kernal that computes the total (kinetic + potential) heat bath energy.
*
* @param context the context in which to execute this kernel
* @param noseHooverChain the chain whose energy is to be determined.
* @return the total heat bath energy.
*/
virtual
double
computeHeatBathEnergy
(
ContextImpl
&
context
,
const
NoseHooverChain
&
noseHooverChain
)
=
0
;
/**
* Execute the kernel that computes the kinetic energy for a subset of atoms,
* or the relative kinetic energy of Drude particles with respect to their parent atoms
*
* @param context the context in which to execute this kernel
* @param noseHooverChain the chain whose energy is to be determined.
* @param downloadValue whether the computed value should be downloaded and returned.
*/
virtual
std
::
pair
<
double
,
double
>
computeMaskedKineticEnergy
(
ContextImpl
&
context
,
const
NoseHooverChain
&
noseHooverChain
,
bool
downloadValue
)
=
0
;
/**
* Execute the kernel that scales the velocities of particles associated with a nose hoover chain
*
* @param context the context in which to execute this kernel
* @param noseHooverChain the chain whose energy is to be determined.
* @param scaleFactor the multiplicative factor by which {absolute, relative} velocities are scaled.
*/
virtual
void
scaleVelocities
(
ContextImpl
&
context
,
const
NoseHooverChain
&
noseHooverChain
,
std
::
pair
<
double
,
double
>
scaleFactor
)
=
0
;
};
/**
* This kernel is invoked by MonteCarloBarostat to adjust the periodic box volume
*/
...
...
openmmapi/include/OpenMM.h
View file @
7e72bafb
...
...
@@ -75,6 +75,8 @@
#include "openmm/VariableVerletIntegrator.h"
#include "openmm/Vec3.h"
#include "openmm/VerletIntegrator.h"
#include "openmm/NoseHooverIntegrator.h"
#include "openmm/NoseHooverChain.h"
#include "openmm/VirtualSite.h"
#include "openmm/Platform.h"
#include "openmm/serialization/XmlSerializer.h"
...
...
openmmapi/include/openmm/NoseHooverChain.h
0 → 100644
View file @
7e72bafb
#ifndef OPENMM_NOSEHOOVERCHAIN_H_
#define OPENMM_NOSEHOOVERCHAIN_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) 2019 Stanford University and the Authors. *
* Authors: Andreas Krämer and Andrew C. Simmonett *
* 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 <string>
#include <vector>
#include "openmm/OpenMMException.h"
#include "internal/windowsExport.h"
namespace
OpenMM
{
/**
* This class defines a chain of Nose-Hoover particles to be used as a heat bath to
* scale the velocities of a collection of particles subject to thermostating. The
* heat bath is propagated using the multi time step approach detailed in
*
* G. J. Martyna, M. E. Tuckerman, D. J. Tobias and M. L. Klein, Mol. Phys. 87, 1117 (1996).
*
* where the total number of timesteps used to propagate the chain in each step is
* the number of MTS steps multiplied by the number of terms in the Yoshida-Suzuki decomposition.
*
* Two types of NHC may be created. The first is a simple thermostat that couples with a given subset
* of the atoms within a system, controling their absolute motion. The second is more elaborate and
* can thermostat tethered pairs of atoms and in this case two thermostats are created: one that controls
* the absolute center of mass velocity of each pair and another that controls their motion relative to
* one another.
*/
class
OPENMM_EXPORT
NoseHooverChain
{
public:
/**
* Create a NoseHooverChain.
*
* @param temperature the temperature of the heat bath for absolute motion (in Kelvin)
* @param collisionFrequency the collision frequency for absolute motion (in 1/ps)
* @param relativeTemperature the temperature of the heat bath for relative motion(in Kelvin).
* This is only used if the list of thermostated pairs is not empty.
* @param relativeCollisionFrequency the collision frequency for relative motion(in 1/ps).
* This is only used if the list of thermostated pairs is not empty.
* @param numDOFs the number of degrees of freedom in the particles that
* interact with this chain
* @param chainLength the length of (number of particles in) this heat bath
* @param numMTS the number of multi time steps used to propagate this chain
* @param numYoshidaSuzuki the number of Yoshida Suzuki steps used to propagate this chain (1, 3, or 5).
* @param chainID the chain id used to distinguish this Nose-Hoover chain from others that may
* be used to control a different set of particles, e.g. for Drude oscillators
* @param thermostatedAtoms the list of atoms to be handled by this thermostat
* @param thermostatedPairs the list of connected pairs to be thermostated; their absolute center of mass motion will
* be thermostated independently from their motion relative to one another.
*/
NoseHooverChain
(
double
temperature
,
double
relativeTemperature
,
double
collisionFrequency
,
double
relativeCollisionFrequency
,
int
numDOFs
,
int
chainLength
,
int
numMTS
,
int
numYoshidaSuzuki
,
int
chainID
,
const
std
::
vector
<
int
>&
thermostatedAtoms
,
const
std
::
vector
<
std
::
pair
<
int
,
int
>
>
&
thermostatedPairs
);
/**
* Get the temperature of the heat bath for treating absolute particle motion (in Kelvin).
*
* @return the temperature of the heat bath, measured in Kelvin.
*/
double
getTemperature
()
const
{
return
temp
;
}
/**
* Set the temperature of the heat bath for treating absolute particle motion.
* This will affect any new Contexts you create, but not ones that already exist.
*
* @param temperature the temperature of the heat bath (in Kelvin)
*/
void
setTemperature
(
double
temperature
)
{
temp
=
temperature
;
}
/**
* Get the temperature of the heat bath for treating relative particle motion (in Kelvin).
*
* @return the temperature of the heat bath, measured in Kelvin.
*/
double
getRelativeTemperature
()
const
{
return
relativeTemp
;
}
/**
* Set the temperature of the heat bath for treating relative motion if this thermostat has
* been set up to treat connected pairs of atoms. This will affect any new Contexts you create,
* but not ones that already exist.
*
* @param temperature the temperature of the heat bath for relative motion (in Kelvin)
*/
void
setRelativeTemperature
(
double
temperature
)
{
relativeTemp
=
temperature
;
}
/**
* Get the collision frequency for treating absolute particle motion (in 1/ps).
*
* @return the collision frequency, measured in 1/ps.
*/
double
getCollisionFrequency
()
const
{
return
freq
;
}
/**
* Set the collision frequency for treating absolute particle motion.
* This will affect any new Contexts you create, but not those that already exist.
*
* @param frequency the collision frequency (in 1/ps)
*/
void
setCollisionFrequency
(
double
frequency
)
{
freq
=
frequency
;
}
/**
* Get the collision frequency for treating relative particle motion (in 1/ps).
*
* @return the collision frequency, measured in 1/ps.
*/
double
getRelativeCollisionFrequency
()
const
{
return
relativeFreq
;
}
/**
* Set the collision frequency for treating relative particle motion if this thermostat has
* been set up to handle connected pairs of atoms. This will affect any new Contexts you create,
* but not those that already exist.
*
* @param frequency the collision frequency (in 1/ps)
*/
void
setRelativeCollisionFrequency
(
double
frequency
)
{
relativeFreq
=
frequency
;
}
/**
* Get the number of degrees of freedom in the particles controled by this heat bath.
*
* @return the number of degrees of freedom.
*/
int
getNumDegreesOfFreedom
()
const
{
return
numDOFs
;
}
/**
* Set the number of degrees of freedom in the particles controled by this heat bath.
* This will affect any new Contexts you create, but not those that already exist.
*
* @param numDOF the number of degrees of freedom.
*/
void
setNumDegreesOfFreedom
(
int
numDOF
)
{
numDOFs
=
numDOF
;
}
/**
* Get the chain length of this heat bath.
*
* @return the chain length.
*/
int
getChainLength
()
const
{
return
chainLength
;
}
/**
* Get the number of steps used in the multi time step propagation.
*
* @returns the number of multi time steps.
*/
int
getNumMultiTimeSteps
()
const
{
return
numMTS
;
}
/**
* Get the number of steps used in the Yoshida-Suzuki decomposition for
* multi time step propagation.
*
* @returns the number of multi time steps in the Yoshida-Suzuki decomposition.
*/
int
getNumYoshidaSuzukiTimeSteps
()
const
{
return
numYS
;
}
/**
* Get the chain id used to identify this chain
*
* @returns the chain id
*/
int
getChainID
()
const
{
return
chainID
;
}
/**
* Get the atom ids of all atoms that are thermostated
*
* @returns ids of all atoms that are being handled by this thermostat
*/
const
std
::
vector
<
int
>&
getThermostatedAtoms
()
const
{
return
thermostatedAtoms
;
}
/**
* Set list of atoms that are handled by this thermostat
*
* @param atomIDs
*/
void
setThermostatedAtoms
(
const
std
::
vector
<
int
>&
atomIDs
){
thermostatedAtoms
=
atomIDs
;
}
/**
* Get the list of any connected pairs to be handled by this thermostat.
* If this is a regular thermostat, returns an empty vector.
*
* @returns list of connected pairs.
*/
const
std
::
vector
<
std
::
pair
<
int
,
int
>
>&
getThermostatedPairs
()
const
{
return
thermostatedPairs
;
}
/**
* In case this thermostat handles the kinetic energy of Drude particles
* set the atom IDs of all parent atoms.
*
* @param pairIDs the list of connected pairs to thermostat.
*/
void
setThermostatedPairs
(
const
std
::
vector
<
std
::
pair
<
int
,
int
>
>&
pairIDs
){
thermostatedPairs
=
pairIDs
;
}
/**
* Get the weights used in the Yoshida Suzuki multi time step decomposition (dimensionless)
*
* @returns the weights for the Yoshida-Suzuki integration
*/
std
::
vector
<
double
>
getYoshidaSuzukiWeights
()
const
;
/**
* Returns whether or not this force makes use of periodic boundary
* conditions.
*
* @returns true if force uses PBC and false otherwise
*/
bool
usesPeriodicBoundaryConditions
()
const
{
return
false
;
}
private:
double
temp
,
freq
,
relativeTemp
,
relativeFreq
;
int
numDOFs
,
chainLength
,
numMTS
,
numYS
;
// The suffix used to distinguish NH chains, e.g. for Drude particles vs. regular particles.
int
chainID
;
std
::
vector
<
int
>
thermostatedAtoms
;
std
::
vector
<
std
::
pair
<
int
,
int
>>
thermostatedPairs
;
};
}
// namespace OpenMM
#endif
/*OPENMM_NOSEHOOVERCHAIN_H_*/
openmmapi/include/openmm/NoseHooverIntegrator.h
0 → 100644
View file @
7e72bafb
#ifndef OPENMM_NOSEHOOVERINTEGRATOR_H_
#define OPENMM_NOSEHOOVERINTEGRATOR_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) 2019 Stanford University and the Authors. *
* Authors: Andreas Krämer and Andrew C. Simmonett *
* 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 "Integrator.h"
#include "openmm/State.h"
#include "openmm/Kernel.h"
#include "NoseHooverChain.h"
#include "internal/windowsExport.h"
#include <tuple>
namespace
OpenMM
{
class
System
;
/**
* This is an Integrator which simulates a System using one or more Nose Hoover chain
* thermostats, using the velocity Verlet propagation algorithm.
*/
class
OPENMM_EXPORT
NoseHooverIntegrator
:
public
Integrator
{
public:
/**
* Create a NoseHooverIntegrator. This version creates a bare velocity Verlet integrator
* with no thermostats; any thermostats should be added by calling addThermostat.
*
* @param stepSize the step size with which to integrate the system (in picoseconds)
*/
explicit
NoseHooverIntegrator
(
double
stepSize
);
/**
* Create a NoseHooverIntegrator.
*
* @param temperature the target temperature for the system (in Kelvin).
* @param collisionFrequency the frequency of the interaction with the heat bath (in inverse picoseconds).
* @param stepSize the step size with which to integrate the system (in picoseconds)
* @param chainLength the number of beads in the Nose-Hoover chain.
* @param numMTS the number of step in the multiple time step chain propagation algorithm.
* @param numYoshidaSuzuki the number of terms in the Yoshida-Suzuki multi time step decomposition
* used in the chain propagation algorithm (must be 1, 3, or 5).
*/
explicit
NoseHooverIntegrator
(
double
temperature
,
double
collisionFrequency
,
double
stepSize
,
int
chainLength
=
3
,
int
numMTS
=
3
,
int
numYoshidaSuzuki
=
3
);
virtual
~
NoseHooverIntegrator
();
/**
* Advance a simulation through time by taking a series of time steps.
*
* @param steps the number of time steps to take
*/
void
step
(
int
steps
);
/**
* Add a simple Nose-Hoover Chain thermostat to control the temperature of the full system
*
* @param temperature the target temperature for the system.
* @param collisionFrequency the frequency of the interaction with the heat bath (in 1/ps).
* @param chainLength the number of beads in the Nose-Hoover chain
* @param numMTS the number of step in the multiple time step chain propagation algorithm.
* @param numYoshidaSuzuki the number of terms in the Yoshida-Suzuki multi time step decomposition
* used in the chain propagation algorithm (must be 1, 3, or 5).
*/
int
addThermostat
(
double
temperature
,
double
collisionFrequency
,
int
chainLength
,
int
numMTS
,
int
numYoshidaSuzuki
);
/**
* Add a Nose-Hoover Chain thermostat to control the temperature of a collection of atoms and/or pairs of
* connected atoms within the full system. A list of atoms defining the atoms to be thermostated is
* provided and the thermostat will only control members of that list. Additionally a list of pairs of
* connected atoms may be provided; in this case both the center of mass absolute motion of each pair is
* controlled as well as their motion relative to each other, which is independently thermostated.
* If both the list of thermostated particles and thermostated pairs are empty all particles will be thermostated.
*
* @param thermostatedParticles list of particle ids to be thermostated.
* @param thermostatedPairs a list of pairs of connected atoms whose absolute center of mass motion
* and motion relative to one another will be independently thermostated.
* @param temperature the target temperature for each pair's absolute of center of mass motion.
* @param collisionFrequency the frequency of the interaction with the heat bath for the
* pairs' center of mass motion (in 1/ps).
* @param relativeTemperature the target temperature for each pair's relative motion.
* @param relativeCollisionFrequency the frequency of the interaction with the heat bath for the
* pairs' relative motion (in 1/ps).
* @param chainLength the number of beads in the Nose-Hoover chain.
* @param numMTS the number of step in the multiple time step chain propagation algorithm.
* @param numYoshidaSuzuki the number of terms in the Yoshida-Suzuki multi time step decomposition
* used in the chain propagation algorithm (must be 1, 3, or 5).
*/
int
addSubsystemThermostat
(
const
std
::
vector
<
int
>&
thermostatedParticles
,
const
std
::
vector
<
std
::
pair
<
int
,
int
>
>&
thermostatedPairs
,
double
temperature
,
double
collisionFrequency
,
double
relativeTemperature
,
double
relativeCollisionFrequency
,
int
chainLength
=
3
,
int
numMTS
=
3
,
int
numYoshidaSuzuki
=
3
);
/**
* Get the temperature of the i-th chain for controling absolute particle motion (in Kelvin).
*
* @param chainID the index of the Nose-Hoover chain thermostat (default=0).
*
* @return the temperature.
*/
double
getTemperature
(
int
chainID
=
0
)
const
;
/**
* set the (absolute motion) temperature of the i-th chain.
*
* @param temperature the temperature for the Nose-Hoover chain thermostat (in Kelvin).
* @param chainID The id of the Nose-Hoover chain thermostat for which the temperature is set (default=0).
*/
void
setTemperature
(
double
temperature
,
int
chainID
=
0
);
/**
* Get the temperature of the i-th chain for controling pairs' relative particle motion (in Kelvin).
*
* @param chainID the index of the Nose-Hoover chain thermostat (default=0).
*
* @return the temperature.
*/
double
getRelativeTemperature
(
int
chainID
=
0
)
const
;
/**
* set the (relative pair motion) temperature of the i-th chain.
*
* @param temperature the temperature for the Nose-Hoover chain thermostat (in Kelvin).
* @param chainID The id of the Nose-Hoover chain thermostat for which the temperature is set (default=0).
*/
void
setRelativeTemperature
(
double
temperature
,
int
chainID
=
0
);
/**
* Get the collision frequency for absolute motion of the i-th chain (in 1/picosecond).
*
* @param chainID the index of the Nose-Hoover chain thermostat (default=0).
*
* @return the collision frequency.
*/
double
getCollisionFrequency
(
int
chainID
=
0
)
const
;
/**
* Set the collision frequency for absolute motion of the i-th chain.
*
* @param frequency the collision frequency in picosecond.
* @param chainID the index of the Nose-Hoover chain thermostat (default=0).
*/
void
setCollisionFrequency
(
double
frequency
,
int
chainID
=
0
);
/**
* Get the collision frequency for pairs' relative motion of the i-th chain (in 1/picosecond).
*
* @param chainID the index of the Nose-Hoover chain thermostat (default=0).
*
* @return the collision frequency.
*/
double
getRelativeCollisionFrequency
(
int
chainID
=
0
)
const
;
/**
* Set the collision frequency for pairs' relative motion of the i-th chain.
*
* @param frequency the collision frequency in picosecond.
* @param chainID the index of the Nose-Hoover chain thermostat (default=0).
*/
void
setRelativeCollisionFrequency
(
double
frequency
,
int
chainID
=
0
);
/**
* Compute the total (potential + kinetic) heat bath energy for all heat baths
* associated with this integrator, at the current time.
*/
double
computeHeatBathEnergy
();
/**
* Get the number of Nose-Hoover chains registered with this integrator.
*/
int
getNumThermostats
()
const
{
return
noseHooverChains
.
size
();
}
/**
* Get the NoseHooverChain thermostat
*
* @param chainID the index of the Nose-Hoover chain thermostat (default=0).
*/
const
NoseHooverChain
&
getThermostat
(
int
chainID
=
0
)
const
;
/**
* This will be called by the Context when the user modifies aspects of the context state, such
* as positions, velocities, or parameters. This gives the Integrator a chance to discard cached
* information. This is <i>only</i> called when the user modifies information using methods of the Context
* object. It is <i>not</i> called when a ForceImpl object modifies state information in its updateContextState()
* method (unless the ForceImpl calls a Context method to perform the modification).
*
* @param changed this specifies what aspect of the Context was changed
*/
virtual
void
stateChanged
(
State
::
DataType
changed
)
{
if
(
State
::
Positions
==
changed
)
forcesAreValid
=
false
;
}
/**
* Return false, if this integrator was set up with the 'default constructor' that thermostats the whole system,
* true otherwise. Required for serialization.
*/
bool
hasSubsystemThermostats
()
const
{
return
hasSubsystemThermostats_
;
}
/**
* Gets the maximum distance (in nm) that a connected pair may stray from each other. If zero, there are no
* constraints on the intra-pair separation.
*/
double
getMaximumPairDistance
()
const
{
return
maxPairDistance_
;
}
/**
* Sets the maximum distance (in nm) that a connected pair may stray from each other, implemented using a hard
* wall. If set to zero, the hard wall constraint is omited and the pairs are free to be separated by any distance.
*/
void
setMaximumPairDistance
(
double
distance
)
{
maxPairDistance_
=
distance
;
}
/**
* Get a list of all individual atoms (i.e. not involved in a connected Drude-like pair) in the system.
*/
const
std
::
vector
<
int
>
&
getAllThermostatedIndividualParticles
()
const
{
return
allAtoms
;
}
/**
* Get a list of all connected Drude-like pairs, and their target relative temperature, in the system.
*/
const
std
::
vector
<
std
::
tuple
<
int
,
int
,
double
>>
&
getAllThermostatedPairs
()
const
{
return
allPairs
;
}
protected:
/**
* Advance any Nose-Hoover chains associated with this integrator and determine
* scale factor for the velocities.
*
* @param kineticEnergy the {absolute, relative} kinetic energies of the system that the chain is thermostating
* @param chainID id of the Nose-Hoover-Chain
* @return the scale factor to be applied to the velocities of the particles thermostated by the chain.
*/
std
::
pair
<
double
,
double
>
propagateChain
(
std
::
pair
<
double
,
double
>
kineticEnergy
,
int
chainID
=
0
);
/**
* This will be called by the Context when it is created. It informs the Integrator
* of what context it will be integrating, and gives it a chance to do any necessary initialization.
* It will also get called again if the application calls reinitialize() on the Context.
*/
void
initialize
(
ContextImpl
&
context
);
/**
* Goes through the list of thermostats, sets the number of DOFs, and checks for errors in the thermostats.
*/
void
initializeThermostats
(
const
System
&
system
);
/**
* This will be called by the Context when it is destroyed to let the Integrator do any necessary
* cleanup. It will also get called again if the application calls reinitialize() on the Context.
*/
void
cleanup
();
/**
* Get the names of all Kernels used by this Integrator.
*/
std
::
vector
<
std
::
string
>
getKernelNames
();
/**
* Compute the kinetic energy of the system at the current time.
*/
virtual
double
computeKineticEnergy
();
std
::
vector
<
NoseHooverChain
>
noseHooverChains
;
std
::
vector
<
int
>
allAtoms
;
std
::
vector
<
std
::
tuple
<
int
,
int
,
double
>>
allPairs
;
bool
forcesAreValid
;
Kernel
vvKernel
,
nhcKernel
;
bool
hasSubsystemThermostats_
;
double
maxPairDistance_
;
};
}
// namespace OpenMM
#endif
/*OPENMM_NOSEHOOVERINTEGRATOR_H_*/
openmmapi/src/ContextImpl.cpp
View file @
7e72bafb
...
...
@@ -481,6 +481,10 @@ void ContextImpl::loadCheckpoint(istream& stream) {
}
updateStateDataKernel
.
getAs
<
UpdateStateDataKernel
>
().
loadCheckpoint
(
*
this
,
stream
);
hasSetPositions
=
true
;
integrator
.
stateChanged
(
State
::
Positions
);
integrator
.
stateChanged
(
State
::
Velocities
);
integrator
.
stateChanged
(
State
::
Parameters
);
integrator
.
stateChanged
(
State
::
Energy
);
}
void
ContextImpl
::
systemChanged
()
{
...
...
openmmapi/src/NoseHooverChain.cpp
0 → 100644
View file @
7e72bafb
/* -------------------------------------------------------------------------- *
* 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) 2019 Stanford University and the Authors. *
* Authors: Andreas Krämer and Andrew C. Simmonett *
* 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/NoseHooverChain.h"
#include "openmm/OpenMMException.h"
using
namespace
OpenMM
;
NoseHooverChain
::
NoseHooverChain
(
double
temperature
,
double
relativeTemperature
,
double
collisionFrequency
,
double
relativeCollisionFrequency
,
int
numDOFs_
,
int
chainLength_
,
int
numMTS_
,
int
numYoshidaSuzuki
,
int
chainID_
,
const
std
::
vector
<
int
>&
thermostatedAtoms
,
const
std
::
vector
<
std
::
pair
<
int
,
int
>
>
&
thermostatedPairs
)
:
temp
(
temperature
),
relativeTemp
(
relativeTemperature
),
freq
(
collisionFrequency
),
relativeFreq
(
relativeCollisionFrequency
),
numDOFs
(
numDOFs_
),
chainLength
(
chainLength_
),
numMTS
(
numMTS_
),
numYS
(
numYoshidaSuzuki
),
chainID
(
chainID_
),
thermostatedAtoms
(
thermostatedAtoms
),
thermostatedPairs
(
thermostatedPairs
)
{}
std
::
vector
<
double
>
NoseHooverChain
::
getYoshidaSuzukiWeights
()
const
{
switch
(
numYS
)
{
case
1
:
return
{
1
};
case
3
:
return
{
0.828981543588751
,
-
0.657963087177502
,
0.828981543588751
};
case
5
:
return
{
0.2967324292201065
,
0.2967324292201065
,
-
0.186929716880426
,
0.2967324292201065
,
0.2967324292201065
};
default:
throw
OpenMMException
(
"The number of Yoshida-Suzuki weights must be 1,3, or 5."
);
}
}
openmmapi/src/NoseHooverIntegrator.cpp
0 → 100644
View file @
7e72bafb
/* -------------------------------------------------------------------------- *
* 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) 2019 Stanford University and the Authors. *
* Authors: Andreas Krämer and Andrew C. Simmonett *
* 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/NoseHooverIntegrator.h"
#include "openmm/Context.h"
#include "openmm/Force.h"
#include "openmm/System.h"
#include "openmm/NoseHooverChain.h"
#include "openmm/OpenMMException.h"
#include "openmm/CMMotionRemover.h"
#include "openmm/internal/ContextImpl.h"
#include "openmm/internal/AssertionUtilities.h"
#include "openmm/kernels.h"
#include <iostream>
#include <string>
#include <algorithm>
using
namespace
OpenMM
;
using
std
::
string
;
using
std
::
vector
;
NoseHooverIntegrator
::
NoseHooverIntegrator
(
double
stepSize
)
:
forcesAreValid
(
false
),
hasSubsystemThermostats_
(
true
)
{
setStepSize
(
stepSize
);
setConstraintTolerance
(
1e-5
);
setMaximumPairDistance
(
0.0
);
}
NoseHooverIntegrator
::
NoseHooverIntegrator
(
double
temperature
,
double
collisionFrequency
,
double
stepSize
,
int
chainLength
,
int
numMTS
,
int
numYoshidaSuzuki
)
:
forcesAreValid
(
false
),
hasSubsystemThermostats_
(
false
)
{
setStepSize
(
stepSize
);
setConstraintTolerance
(
1e-5
);
setMaximumPairDistance
(
0.0
);
addThermostat
(
temperature
,
collisionFrequency
,
chainLength
,
numMTS
,
numYoshidaSuzuki
);
}
NoseHooverIntegrator
::~
NoseHooverIntegrator
()
{}
std
::
pair
<
double
,
double
>
NoseHooverIntegrator
::
propagateChain
(
std
::
pair
<
double
,
double
>
kineticEnergy
,
int
chainID
)
{
return
nhcKernel
.
getAs
<
NoseHooverChainKernel
>
().
propagateChain
(
*
context
,
noseHooverChains
.
at
(
chainID
),
kineticEnergy
,
getStepSize
());
}
int
NoseHooverIntegrator
::
addThermostat
(
double
temperature
,
double
collisionFrequency
,
int
chainLength
,
int
numMTS
,
int
numYoshidaSuzuki
)
{
hasSubsystemThermostats_
=
false
;
return
addSubsystemThermostat
(
std
::
vector
<
int
>
(),
std
::
vector
<
std
::
pair
<
int
,
int
>>
(),
temperature
,
collisionFrequency
,
temperature
,
collisionFrequency
,
chainLength
,
numMTS
,
numYoshidaSuzuki
);
}
int
NoseHooverIntegrator
::
addSubsystemThermostat
(
const
std
::
vector
<
int
>&
thermostatedParticles
,
const
std
::
vector
<
std
::
pair
<
int
,
int
>
>
&
thermostatedPairs
,
double
temperature
,
double
collisionFrequency
,
double
relativeTemperature
,
double
relativeCollisionFrequency
,
int
chainLength
,
int
numMTS
,
int
numYoshidaSuzuki
)
{
int
chainID
=
noseHooverChains
.
size
();
// check if one thermostat already applies to all atoms or pairs
if
(
(
chainID
>
0
)
&&
(
noseHooverChains
[
0
].
getThermostatedAtoms
().
size
()
*
noseHooverChains
[
0
].
getThermostatedPairs
().
size
()
==
0
)
)
{
throw
OpenMMException
(
"Cannot add thermostat, since one of the thermostats already in the integrator applies to all particles. "
"To manually add thermostats, use the constructor that takes only the "
"step size as an input argument."
);
}
int
nDOF
=
0
;
// is set in initializeThermostats()
noseHooverChains
.
emplace_back
(
temperature
,
relativeTemperature
,
collisionFrequency
,
relativeCollisionFrequency
,
nDOF
,
chainLength
,
numMTS
,
numYoshidaSuzuki
,
chainID
,
thermostatedParticles
,
thermostatedPairs
);
return
chainID
;
}
const
NoseHooverChain
&
NoseHooverIntegrator
::
getThermostat
(
int
chainID
)
const
{
ASSERT_VALID_INDEX
(
chainID
,
noseHooverChains
);
return
noseHooverChains
[
chainID
];
}
void
NoseHooverIntegrator
::
initializeThermostats
(
const
System
&
system
)
{
allAtoms
.
clear
();
allPairs
.
clear
();
std
::
set
<
int
>
allAtomsSet
;
for
(
int
atom
=
0
;
atom
<
system
.
getNumParticles
();
++
atom
)
allAtomsSet
.
insert
(
atom
);
for
(
auto
&
thermostat
:
noseHooverChains
)
{
const
auto
&
thermostatedParticles
=
thermostat
.
getThermostatedAtoms
();
const
auto
&
thermostatedPairs
=
thermostat
.
getThermostatedPairs
();
for
(
auto
&
pair
:
thermostatedPairs
)
{
allAtomsSet
.
erase
(
pair
.
first
);
allAtomsSet
.
erase
(
pair
.
second
);
allPairs
.
emplace_back
(
pair
.
first
,
pair
.
second
,
thermostat
.
getRelativeTemperature
());
}
// figure out the number of DOFs
int
nDOF
=
3
*
(
thermostatedParticles
.
size
()
+
thermostatedPairs
.
size
());
for
(
int
constraintNum
=
0
;
constraintNum
<
system
.
getNumConstraints
();
constraintNum
++
)
{
int
particle1
,
particle2
;
double
distance
;
system
.
getConstraintParameters
(
constraintNum
,
particle1
,
particle2
,
distance
);
bool
particle1_in_thermostatedParticles
=
((
std
::
find
(
thermostatedParticles
.
begin
(),
thermostatedParticles
.
end
(),
particle1
)
!=
thermostatedParticles
.
end
()))
||
(
std
::
find_if
(
thermostatedPairs
.
begin
(),
thermostatedPairs
.
end
(),
[
&
particle1
](
const
std
::
pair
<
int
,
int
>&
pair
){
return
pair
.
first
==
particle1
||
pair
.
second
==
particle1
;})
!=
thermostatedPairs
.
end
());
bool
particle2_in_thermostatedParticles
=
((
std
::
find
(
thermostatedParticles
.
begin
(),
thermostatedParticles
.
end
(),
particle2
)
!=
thermostatedParticles
.
end
()))
||
(
std
::
find_if
(
thermostatedPairs
.
begin
(),
thermostatedPairs
.
end
(),
[
&
particle2
](
const
std
::
pair
<
int
,
int
>&
pair
){
return
pair
.
first
==
particle2
||
pair
.
second
==
particle2
;})
!=
thermostatedPairs
.
end
());
if
((
system
.
getParticleMass
(
particle1
)
>
0
)
&&
(
system
.
getParticleMass
(
particle2
)
>
0
)){
if
((
particle1_in_thermostatedParticles
&&
!
particle2_in_thermostatedParticles
)
||
(
!
particle1_in_thermostatedParticles
&&
particle2_in_thermostatedParticles
)){
throw
OpenMMException
(
"Cannot add only one of particles "
+
std
::
to_string
(
particle1
)
+
" and "
+
std
::
to_string
(
particle2
)
+
" to NoseHooverChain, because they are connected by a constraint."
);
}
if
(
particle1_in_thermostatedParticles
&&
particle2_in_thermostatedParticles
){
nDOF
-=
1
;
}
}
}
// remove 3 degrees of freedom from thermostats that act on absolute motions
int
numForces
=
system
.
getNumForces
();
if
(
thermostatedPairs
.
size
()
==
0
){
for
(
int
forceNum
=
0
;
forceNum
<
numForces
;
++
forceNum
)
{
if
(
dynamic_cast
<
const
CMMotionRemover
*>
(
&
system
.
getForce
(
forceNum
)))
nDOF
-=
3
;
}
}
// set number of DoFs for chain
thermostat
.
setNumDegreesOfFreedom
(
nDOF
);
}
for
(
int
chain1
=
0
;
chain1
<
noseHooverChains
.
size
();
++
chain1
){
const
auto
&
nhc
=
noseHooverChains
[
chain1
];
// make sure that thermostats do not overlap
for
(
int
chain2
=
0
;
chain2
<
chain1
;
++
chain2
){
const
auto
&
other_nhc
=
noseHooverChains
[
chain2
];
for
(
auto
&
particle
:
nhc
.
getThermostatedAtoms
()){
bool
isParticleInOtherChain
=
(
std
::
find
(
other_nhc
.
getThermostatedAtoms
().
begin
(),
other_nhc
.
getThermostatedAtoms
().
end
(),
particle
)
!=
other_nhc
.
getThermostatedAtoms
().
end
())
||
(
std
::
find_if
(
other_nhc
.
getThermostatedPairs
().
begin
(),
other_nhc
.
getThermostatedPairs
().
end
(),
[
&
particle
](
const
std
::
pair
<
int
,
int
>&
pair
){
return
pair
.
first
==
particle
||
pair
.
second
==
particle
;})
!=
other_nhc
.
getThermostatedPairs
().
end
());
if
(
isParticleInOtherChain
){
throw
OpenMMException
(
"Found particle "
+
std
::
to_string
(
particle
)
+
"in a different NoseHooverChain, "
"but particles can only be thermostated by one thermostat."
);
}
}
for
(
auto
&
pair
:
nhc
.
getThermostatedPairs
()){
bool
isParticleInOtherChain
=
(
std
::
find
(
other_nhc
.
getThermostatedAtoms
().
begin
(),
other_nhc
.
getThermostatedAtoms
().
end
(),
pair
.
first
)
!=
other_nhc
.
getThermostatedAtoms
().
end
())
||
(
std
::
find
(
other_nhc
.
getThermostatedAtoms
().
begin
(),
other_nhc
.
getThermostatedAtoms
().
end
(),
pair
.
second
)
!=
other_nhc
.
getThermostatedAtoms
().
end
())
||
(
std
::
find_if
(
other_nhc
.
getThermostatedPairs
().
begin
(),
other_nhc
.
getThermostatedPairs
().
end
(),
[
&
pair
](
const
std
::
pair
<
int
,
int
>&
other_pair
){
return
pair
.
first
==
other_pair
.
first
||
pair
.
first
==
other_pair
.
second
||
pair
.
second
==
other_pair
.
first
||
pair
.
second
==
other_pair
.
second
;})
!=
other_nhc
.
getThermostatedPairs
().
end
());
if
(
isParticleInOtherChain
){
throw
OpenMMException
(
"Found pair "
+
std
::
to_string
(
pair
.
first
)
+
","
+
std
::
to_string
(
pair
.
second
)
+
" in a different NoseHooverChain, "
"but particles can only be thermostated by one thermostat."
);
}
}
}
// make sure that massless particles are not thermostated
for
(
auto
particle
:
nhc
.
getThermostatedAtoms
()){
double
mass
=
system
.
getParticleMass
(
particle
);
if
(
mass
==
0.0
)
{
throw
OpenMMException
(
"Found a particle with no mass ("
+
std
::
to_string
(
particle
)
+
") in a thermostat. Massless particles cannot be thermostated."
);
}
}
}
for
(
const
auto
&
atom
:
allAtomsSet
)
allAtoms
.
push_back
(
atom
);
}
double
NoseHooverIntegrator
::
getTemperature
(
int
chainID
)
const
{
ASSERT_VALID_INDEX
(
chainID
,
noseHooverChains
);
return
noseHooverChains
[
chainID
].
getTemperature
();
}
void
NoseHooverIntegrator
::
setTemperature
(
double
temperature
,
int
chainID
){
ASSERT_VALID_INDEX
(
chainID
,
noseHooverChains
);
noseHooverChains
[
chainID
].
setTemperature
(
temperature
);
}
double
NoseHooverIntegrator
::
getRelativeTemperature
(
int
chainID
)
const
{
ASSERT_VALID_INDEX
(
chainID
,
noseHooverChains
);
return
noseHooverChains
[
chainID
].
getRelativeTemperature
();
}
void
NoseHooverIntegrator
::
setRelativeTemperature
(
double
temperature
,
int
chainID
){
ASSERT_VALID_INDEX
(
chainID
,
noseHooverChains
);
noseHooverChains
[
chainID
].
setRelativeTemperature
(
temperature
);
}
double
NoseHooverIntegrator
::
getCollisionFrequency
(
int
chainID
)
const
{
ASSERT_VALID_INDEX
(
chainID
,
noseHooverChains
);
return
noseHooverChains
[
chainID
].
getCollisionFrequency
();
}
void
NoseHooverIntegrator
::
setCollisionFrequency
(
double
frequency
,
int
chainID
){
ASSERT_VALID_INDEX
(
chainID
,
noseHooverChains
);
noseHooverChains
[
chainID
].
setCollisionFrequency
(
frequency
);
}
double
NoseHooverIntegrator
::
getRelativeCollisionFrequency
(
int
chainID
)
const
{
ASSERT_VALID_INDEX
(
chainID
,
noseHooverChains
);
return
noseHooverChains
[
chainID
].
getRelativeCollisionFrequency
();
}
void
NoseHooverIntegrator
::
setRelativeCollisionFrequency
(
double
frequency
,
int
chainID
){
ASSERT_VALID_INDEX
(
chainID
,
noseHooverChains
);
noseHooverChains
[
chainID
].
setRelativeCollisionFrequency
(
frequency
);
}
double
NoseHooverIntegrator
::
computeKineticEnergy
()
{
double
kE
=
0.0
;
if
(
noseHooverChains
.
size
()
>
0
)
{
for
(
const
auto
&
nhc
:
noseHooverChains
){
kE
+=
nhcKernel
.
getAs
<
NoseHooverChainKernel
>
().
computeMaskedKineticEnergy
(
*
context
,
nhc
,
true
).
first
;
}
}
else
{
kE
=
vvKernel
.
getAs
<
IntegrateVelocityVerletStepKernel
>
().
computeKineticEnergy
(
*
context
,
*
this
);
}
return
kE
;
}
double
NoseHooverIntegrator
::
computeHeatBathEnergy
()
{
double
energy
=
0
;
for
(
auto
&
nhc
:
noseHooverChains
)
{
if
(
context
&&
(
nhc
.
getNumDegreesOfFreedom
()
>
0
))
{
energy
+=
nhcKernel
.
getAs
<
NoseHooverChainKernel
>
().
computeHeatBathEnergy
(
*
context
,
nhc
);
}
}
return
energy
;
}
void
NoseHooverIntegrator
::
initialize
(
ContextImpl
&
contextRef
)
{
if
(
owner
!=
NULL
&&
&
contextRef
.
getOwner
()
!=
owner
)
throw
OpenMMException
(
"This Integrator is already bound to a context"
);
context
=
&
contextRef
;
const
System
&
system
=
context
->
getSystem
();
owner
=
&
contextRef
.
getOwner
();
vvKernel
=
context
->
getPlatform
().
createKernel
(
IntegrateVelocityVerletStepKernel
::
Name
(),
contextRef
);
vvKernel
.
getAs
<
IntegrateVelocityVerletStepKernel
>
().
initialize
(
contextRef
.
getSystem
(),
*
this
);
nhcKernel
=
context
->
getPlatform
().
createKernel
(
NoseHooverChainKernel
::
Name
(),
contextRef
);
nhcKernel
.
getAs
<
NoseHooverChainKernel
>
().
initialize
();
forcesAreValid
=
false
;
// check for drude particles and build the Nose-Hoover Chains
for
(
auto
&
thermostat
:
noseHooverChains
){
// if there are no thermostated particles or pairs in the lists this is a regular thermostat for the whole (non-Drude) system
if
(
(
thermostat
.
getThermostatedAtoms
().
size
()
==
0
)
&&
(
thermostat
.
getThermostatedPairs
().
size
()
==
0
)
){
std
::
vector
<
int
>
thermostatedParticles
;
for
(
int
particle
=
0
;
particle
<
system
.
getNumParticles
();
++
particle
)
{
double
mass
=
system
.
getParticleMass
(
particle
);
if
(
(
mass
>
0
)
&&
(
mass
<
0.8
)
){
std
::
cout
<<
"Warning: Found particles with mass between 0.0 and 0.8 dalton. Did you mean to make a DrudeNoseHooverIntegrator instead? "
"The thermostat you are about to use will not treat these particles as Drude particles!"
<<
std
::
endl
;
}
if
(
system
.
getParticleMass
(
particle
)
>
0
)
{
thermostatedParticles
.
push_back
(
particle
);
}
}
thermostat
.
setThermostatedAtoms
(
thermostatedParticles
);
}
}
initializeThermostats
(
system
);
}
void
NoseHooverIntegrator
::
cleanup
()
{
vvKernel
=
Kernel
();
nhcKernel
=
Kernel
();
}
vector
<
string
>
NoseHooverIntegrator
::
getKernelNames
()
{
std
::
vector
<
std
::
string
>
names
;
names
.
push_back
(
NoseHooverChainKernel
::
Name
());
names
.
push_back
(
IntegrateVelocityVerletStepKernel
::
Name
());
return
names
;
}
void
NoseHooverIntegrator
::
step
(
int
steps
)
{
if
(
context
==
NULL
)
throw
OpenMMException
(
"This Integrator is not bound to a context!"
);
std
::
pair
<
double
,
double
>
scale
,
kineticEnergy
;
for
(
int
i
=
0
;
i
<
steps
;
++
i
)
{
context
->
updateContextState
();
for
(
auto
&
nhc
:
noseHooverChains
)
{
kineticEnergy
=
nhcKernel
.
getAs
<
NoseHooverChainKernel
>
().
computeMaskedKineticEnergy
(
*
context
,
nhc
,
false
);
scale
=
nhcKernel
.
getAs
<
NoseHooverChainKernel
>
().
propagateChain
(
*
context
,
nhc
,
kineticEnergy
,
getStepSize
());
nhcKernel
.
getAs
<
NoseHooverChainKernel
>
().
scaleVelocities
(
*
context
,
nhc
,
scale
);
}
vvKernel
.
getAs
<
IntegrateVelocityVerletStepKernel
>
().
execute
(
*
context
,
*
this
,
forcesAreValid
);
for
(
auto
&
nhc
:
noseHooverChains
)
{
kineticEnergy
=
nhcKernel
.
getAs
<
NoseHooverChainKernel
>
().
computeMaskedKineticEnergy
(
*
context
,
nhc
,
false
);
scale
=
nhcKernel
.
getAs
<
NoseHooverChainKernel
>
().
propagateChain
(
*
context
,
nhc
,
kineticEnergy
,
getStepSize
());
nhcKernel
.
getAs
<
NoseHooverChainKernel
>
().
scaleVelocities
(
*
context
,
nhc
,
scale
);
}
}
}
platforms/cuda/include/CudaIntegrationUtilities.h
View file @
7e72bafb
...
...
@@ -30,6 +30,7 @@
#include "openmm/System.h"
#include "CudaContext.h"
#include "windowsExportCuda.h"
#include <map>
#include <iosfwd>
namespace
OpenMM
{
...
...
@@ -120,6 +121,12 @@ public:
* @param timeShift the amount by which to shift the velocities in time
*/
double
computeKineticEnergy
(
double
timeShift
);
/**
* Get the data structure that holds the state of all Nose-Hoover chains
*
* @return vector of chain states
*/
std
::
map
<
int
,
CudaArray
>&
getNoseHooverChainState
();
private:
void
applyConstraints
(
bool
constrainVelocities
,
double
tol
);
CudaContext
&
context
;
...
...
@@ -168,6 +175,7 @@ private:
double2
lastStepSize
;
struct
ShakeCluster
;
struct
ConstraintOrderer
;
std
::
map
<
int
,
CudaArray
>
noseHooverChainState
;
};
}
// namespace OpenMM
...
...
platforms/cuda/include/CudaKernels.h
View file @
7e72bafb
...
...
@@ -1366,6 +1366,44 @@ private:
CUfunction
kernel1
,
kernel2
;
};
/*
* This kernel is invoked by NoseHooverIntegrator to take one time step.
*/
class
CudaIntegrateVelocityVerletStepKernel
:
public
IntegrateVelocityVerletStepKernel
{
public:
CudaIntegrateVelocityVerletStepKernel
(
std
::
string
name
,
const
Platform
&
platform
,
CudaContext
&
cu
)
:
IntegrateVelocityVerletStepKernel
(
name
,
platform
),
cu
(
cu
)
{
}
~
CudaIntegrateVelocityVerletStepKernel
()
{}
/**
* Initialize the kernel.
*
* @param system the System this kernel will be applied to
* @param integrator the NoseHooverIntegrator this kernel will be used for
*/
void
initialize
(
const
System
&
system
,
const
NoseHooverIntegrator
&
integrator
);
/**
* Execute the kernel.
*
* @param context the context in which to execute this kernel
* @param integrator the VerletIntegrator this kernel is being used for
* @param forcesAreValid a reference to the parent integrator's boolean for keeping
* track of the validity of the current forces.
*/
void
execute
(
ContextImpl
&
context
,
const
NoseHooverIntegrator
&
integrator
,
bool
&
forcesAreValid
);
/**
* Compute the kinetic energy.
*
* @param context the context in which to execute this kernel
* @param integrator the NoseHooverIntegrator this kernel is being used for
*/
double
computeKineticEnergy
(
ContextImpl
&
context
,
const
NoseHooverIntegrator
&
integrator
);
private:
CudaContext
&
cu
;
float
prevMaxPairDistance
;
CudaArray
maxPairDistanceBuffer
,
pairListBuffer
,
atomListBuffer
,
pairTemperatureBuffer
;
CUfunction
kernel1
,
kernel2
,
kernel3
,
kernelHardWall
;
};
/**
* This kernel is invoked by LangevinIntegrator to take one time step.
*/
...
...
@@ -1716,6 +1754,71 @@ private:
CUfunction
kernel
;
};
/**
* This kernel is invoked by NoseHooverChain at the start of each time step to adjust the thermostat
* and update the associated particle velocities.
*/
class
CudaNoseHooverChainKernel
:
public
NoseHooverChainKernel
{
public:
CudaNoseHooverChainKernel
(
std
::
string
name
,
const
Platform
&
platform
,
CudaContext
&
cu
)
:
NoseHooverChainKernel
(
name
,
platform
),
cu
(
cu
)
{
}
~
CudaNoseHooverChainKernel
()
{}
/**
* Initialize the kernel.
*/
virtual
void
initialize
();
/**
* Execute the kernel that propagates the Nose Hoover chain and determines the velocity scale factor.
*
* @param context the context in which to execute this kernel
* @param noseHooverChain the object describing the chain to be propagated.
* @param kineticEnergies the {absolute, relative} kineticEnergy of the particles being thermostated by this chain.
* @param timeStep the time step used by the integrator.
* @return the {absolute, relative} velocity scale factor to apply to the particles associated with this heat bath.
*/
virtual
std
::
pair
<
double
,
double
>
propagateChain
(
ContextImpl
&
context
,
const
NoseHooverChain
&
nhc
,
std
::
pair
<
double
,
double
>
kineticEnergies
,
double
timeStep
);
/**
* Execute the kernal that computes the total (kinetic + potential) heat bath energy.
*
* @param context the context in which to execute this kernel
* @param noseHooverChain the chain whose energy is to be determined.
* @return the total heat bath energy.
*/
virtual
double
computeHeatBathEnergy
(
ContextImpl
&
context
,
const
NoseHooverChain
&
nhc
);
/**
* Execute the kernel that computes the kinetic energy for a subset of atoms,
* or the relative kinetic energy of Drude particles with respect to their parent atoms
*
* @param context the context in which to execute this kernel
* @param noseHooverChain the chain whose energy is to be determined.
* @param downloadValue whether the computed value should be downloaded and returned.
*
*/
virtual
std
::
pair
<
double
,
double
>
computeMaskedKineticEnergy
(
ContextImpl
&
context
,
const
NoseHooverChain
&
noseHooverChain
,
bool
downloadValue
);
/**
* Execute the kernel that scales the velocities of particles associated with a nose hoover chain
*
* @param context the context in which to execute this kernel
* @param noseHooverChain the chain whose energy is to be determined.
* @param scaleFactors the {absolute, relative} multiplicative factor by which velocities are scaled.
*/
virtual
void
scaleVelocities
(
ContextImpl
&
context
,
const
NoseHooverChain
&
noseHooverChain
,
std
::
pair
<
double
,
double
>
scaleFactors
);
private:
int
sumWorkGroupSize
;
CudaContext
&
cu
;
CudaArray
energyBuffer
,
scaleFactorBuffer
,
kineticEnergyBuffer
,
chainMasses
,
chainForces
,
heatBathEnergy
;
std
::
map
<
int
,
CudaArray
>
atomlists
,
pairlists
;
std
::
map
<
int
,
CUfunction
>
propagateKernels
;
CUfunction
reduceEnergyKernel
;
CUfunction
computeHeatBathEnergyKernel
;
CUfunction
computeAtomsKineticEnergyKernel
;
CUfunction
computePairsKineticEnergyKernel
;
CUfunction
scaleAtomsVelocitiesKernel
;
CUfunction
scalePairsVelocitiesKernel
;
};
/**
* This kernel is invoked by MonteCarloBarostat to adjust the periodic box volume
*/
...
...
platforms/cuda/src/CudaIntegrationUtilities.cpp
View file @
7e72bafb
...
...
@@ -707,6 +707,24 @@ int CudaIntegrationUtilities::prepareRandomNumbers(int numValues) {
}
void
CudaIntegrationUtilities
::
createCheckpoint
(
ostream
&
stream
)
{
size_t
numChains
=
noseHooverChainState
.
size
();
bool
useDouble
=
context
.
getUseDoublePrecision
()
||
context
.
getUseMixedPrecision
();
stream
.
write
((
char
*
)
&
numChains
,
sizeof
(
size_t
));
for
(
auto
&
chainState
:
noseHooverChainState
){
int
chainID
=
chainState
.
first
;
size_t
chainLength
=
chainState
.
second
.
getSize
();
stream
.
write
((
char
*
)
&
chainID
,
sizeof
(
int
));
stream
.
write
((
char
*
)
&
chainLength
,
sizeof
(
size_t
));
if
(
useDouble
)
{
vector
<
double2
>
stateVec
;
chainState
.
second
.
download
(
stateVec
);
stream
.
write
((
char
*
)
stateVec
.
data
(),
sizeof
(
double2
)
*
chainLength
);
}
else
{
vector
<
float2
>
stateVec
;
chainState
.
second
.
download
(
stateVec
);
stream
.
write
((
char
*
)
stateVec
.
data
(),
sizeof
(
float2
)
*
chainLength
);
}
}
if
(
!
random
.
isInitialized
())
return
;
stream
.
write
((
char
*
)
&
randomPos
,
sizeof
(
int
));
...
...
@@ -719,6 +737,28 @@ void CudaIntegrationUtilities::createCheckpoint(ostream& stream) {
}
void
CudaIntegrationUtilities
::
loadCheckpoint
(
istream
&
stream
)
{
size_t
numChains
,
chainLength
;
bool
useDouble
=
context
.
getUseDoublePrecision
()
||
context
.
getUseMixedPrecision
();
stream
.
read
((
char
*
)
&
numChains
,
sizeof
(
size_t
));
noseHooverChainState
.
clear
();
for
(
size_t
i
=
0
;
i
<
numChains
;
i
++
){
int
chainID
;
stream
.
read
((
char
*
)
&
chainID
,
sizeof
(
int
));
stream
.
read
((
char
*
)
&
chainLength
,
sizeof
(
size_t
));
if
(
useDouble
)
{
noseHooverChainState
[
chainID
]
=
CudaArray
();
noseHooverChainState
[
chainID
].
initialize
<
double2
>
(
context
,
chainLength
,
"chainState"
+
std
::
to_string
(
chainID
));
std
::
vector
<
double2
>
stateVec
(
chainLength
);
stream
.
read
((
char
*
)
&
stateVec
[
0
],
sizeof
(
double2
)
*
chainLength
);
noseHooverChainState
[
chainID
].
upload
(
stateVec
);
}
else
{
noseHooverChainState
[
chainID
]
=
CudaArray
();
noseHooverChainState
[
chainID
].
initialize
<
float2
>
(
context
,
chainLength
,
"chainState"
+
std
::
to_string
(
chainID
));
std
::
vector
<
float2
>
stateVec
(
chainLength
);
stream
.
read
((
char
*
)
&
stateVec
[
0
],
sizeof
(
float2
)
*
chainLength
);
noseHooverChainState
[
chainID
].
upload
(
stateVec
);
}
}
if
(
!
random
.
isInitialized
())
return
;
stream
.
read
((
char
*
)
&
randomPos
,
sizeof
(
int
));
...
...
@@ -768,10 +808,13 @@ double CudaIntegrationUtilities::computeKineticEnergy(double timeShift) {
energy
+=
(
v
.
x
*
v
.
x
+
v
.
y
*
v
.
y
+
v
.
z
*
v
.
z
)
/
v
.
w
;
}
}
// Restore the velocities.
if
(
timeShift
!=
0
)
posDelta
.
copyTo
(
context
.
getVelm
());
return
0.5
*
energy
;
}
std
::
map
<
int
,
CudaArray
>&
CudaIntegrationUtilities
::
getNoseHooverChainState
(){
return
noseHooverChainState
;
};
platforms/cuda/src/CudaKernelFactory.cpp
View file @
7e72bafb
...
...
@@ -132,6 +132,10 @@ KernelImpl* CudaKernelFactory::createKernelImpl(std::string name, const Platform
return
new
CudaIntegrateCustomStepKernel
(
name
,
platform
,
cu
);
if
(
name
==
ApplyAndersenThermostatKernel
::
Name
())
return
new
CudaApplyAndersenThermostatKernel
(
name
,
platform
,
cu
);
if
(
name
==
NoseHooverChainKernel
::
Name
())
return
new
CudaNoseHooverChainKernel
(
name
,
platform
,
cu
);
if
(
name
==
IntegrateVelocityVerletStepKernel
::
Name
())
return
new
CudaIntegrateVelocityVerletStepKernel
(
name
,
platform
,
cu
);
if
(
name
==
ApplyMonteCarloBarostatKernel
::
Name
())
return
new
CudaApplyMonteCarloBarostatKernel
(
name
,
platform
,
cu
);
if
(
name
==
RemoveCMMotionKernel
::
Name
())
...
...
platforms/cuda/src/CudaKernels.cpp
View file @
7e72bafb
...
...
@@ -56,6 +56,7 @@
#include <cmath>
#include <iterator>
#include <set>
#include <assert.h>
using namespace OpenMM;
using namespace std;
...
...
@@ -386,7 +387,7 @@ void CudaUpdateStateDataKernel::setPeriodicBoxVectors(ContextImpl& context, cons
void CudaUpdateStateDataKernel::createCheckpoint(ContextImpl& context, ostream& stream) {
cu.setAsCurrent();
int
version
=
2
;
int version =
3
;
stream.write((char*) &version, sizeof(int));
int precision = (cu.getUseDoublePrecision() ? 2 : cu.getUseMixedPrecision() ? 1 : 0);
stream.write((char*) &precision, sizeof(int));
...
...
@@ -418,7 +419,7 @@ void CudaUpdateStateDataKernel::loadCheckpoint(ContextImpl& context, istream& st
cu.setAsCurrent();
int version;
stream.read((char*) &version, sizeof(int));
if
(
version
!=
2
)
if (version !=
3
)
throw OpenMMException("Checkpoint was created with a different version of OpenMM");
int precision;
stream.read((char*) &precision, sizeof(int));
...
...
@@ -7075,6 +7076,119 @@ double CudaIntegrateVerletStepKernel::computeKineticEnergy(ContextImpl& context,
return cu.getIntegrationUtilities().computeKineticEnergy(0.5*integrator.getStepSize());
}
void CudaIntegrateVelocityVerletStepKernel::initialize(const System& system, const NoseHooverIntegrator& integrator) {
cu.getPlatformData().initializeContexts(system);
cu.setAsCurrent();
map<string, string> defines;
defines["BOLTZ"] = cu.doubleToString(BOLTZ);
CUmodule module = cu.createModule(CudaKernelSources::velocityVerlet, defines, "");
kernel1 = cu.getKernel(module, "integrateVelocityVerletPart1");
kernel2 = cu.getKernel(module, "integrateVelocityVerletPart2");
kernel3 = cu.getKernel(module, "integrateVelocityVerletPart3");
kernelHardWall = cu.getKernel(module, "integrateVelocityVerletHardWall");
prevMaxPairDistance = -1.0;
maxPairDistanceBuffer.initialize<float>(cu, 1, "maxPairDistanceBuffer");
}
void CudaIntegrateVelocityVerletStepKernel::execute(ContextImpl& context, const NoseHooverIntegrator& integrator, bool &forcesAreValid) {
cu.setAsCurrent();
CudaIntegrationUtilities& integration = cu.getIntegrationUtilities();
int paddedNumAtoms = cu.getPaddedNumAtoms();
double dt = integrator.getStepSize();
cu.getIntegrationUtilities().setNextStepSize(dt);
if( !forcesAreValid ) context.calcForcesAndEnergy(true, false);
const auto& atomList = integrator.getAllThermostatedIndividualParticles();
const auto& pairList = integrator.getAllThermostatedPairs();
int numAtoms = atomList.size();
int numPairs = pairList.size();
int numParticles = numAtoms + 2*numPairs;
float maxPairDistance = integrator.getMaximumPairDistance();
// Make sure atom and pair metadata is uploaded and has the correct dimensions
if (prevMaxPairDistance != maxPairDistance) {
std::vector<float> tmp(1, maxPairDistance);
maxPairDistanceBuffer.upload(tmp);
prevMaxPairDistance = maxPairDistance;
}
if (numAtoms !=0 && (!atomListBuffer.isInitialized() || atomListBuffer.getSize() != numAtoms)) {
if(atomListBuffer.isInitialized()) {
atomListBuffer.resize(atomList.size());
} else {
atomListBuffer.initialize<int>(cu, atomList.size(), "atomListBuffer");
}
atomListBuffer.upload(atomList);
}
if (numPairs !=0 && (!pairListBuffer.isInitialized() || pairListBuffer.getSize() != numPairs)) {
if (pairListBuffer.isInitialized()) {
pairListBuffer.resize(pairList.size());
pairTemperatureBuffer.resize(pairList.size());
} else {
pairListBuffer.initialize<int2>(cu, pairList.size(), "pairListBuffer");
pairTemperatureBuffer.initialize<float>(cu, pairList.size(), "pairTemperatureBuffer");
}
std::vector<int2> tmp;
std::vector<float> tmp2;
for(const auto &pair : pairList) {
tmp.push_back(make_int2(std::get<0>(pair), std::get<1>(pair)));
tmp2.push_back(std::get<2>(pair));
}
pairListBuffer.upload(tmp);
pairTemperatureBuffer.upload(tmp2);
}
//// Call the first integration kernel.
CUdeviceptr posCorrection = (cu.getUseMixedPrecision() ? cu.getPosqCorrection().getDevicePointer() : 0);
void* args1[] = {&numAtoms, &numPairs, &paddedNumAtoms, &cu.getIntegrationUtilities().getStepSize().getDevicePointer(), &cu.getPosq().getDevicePointer(), &posCorrection,
&cu.getVelm().getDevicePointer(), &cu.getForce().getDevicePointer(), &integration.getPosDelta().getDevicePointer(),
&atomListBuffer.getDevicePointer(), &pairListBuffer.getDevicePointer()};
cu.executeKernel(kernel1, args1, std::max(numAtoms,numPairs), 128);
//// Apply constraints.
integration.applyConstraints(integrator.getConstraintTolerance());
//// Call the second integration kernel.
void* args2[] = {&numParticles, &cu.getIntegrationUtilities().getStepSize().getDevicePointer(), &cu.getPosq().getDevicePointer(), &posCorrection,
&cu.getVelm().getDevicePointer(), &integration.getPosDelta().getDevicePointer()};
cu.executeKernel(kernel2, args2, numParticles, 128);
if (numPairs > 0) {
//// Enforce hard wall constraint
void* argsHardWall[] = {&numPairs, &maxPairDistanceBuffer.getDevicePointer(),
&cu.getIntegrationUtilities().getStepSize().getDevicePointer(), &cu.getPosq().getDevicePointer(), &posCorrection,
&cu.getVelm().getDevicePointer(), &pairListBuffer.getDevicePointer(),
&pairTemperatureBuffer.getDevicePointer()};
cu.executeKernel(kernelHardWall, argsHardWall, numPairs, 128);
}
integration.computeVirtualSites();
//// Update forces
context.calcForcesAndEnergy(true, false);
forcesAreValid = true;
//// Call the third integration kernel.
void* args3[] = {&numAtoms, &numPairs, &paddedNumAtoms, &cu.getIntegrationUtilities().getStepSize().getDevicePointer(), &cu.getPosq().getDevicePointer(), &posCorrection,
&cu.getVelm().getDevicePointer(), &cu.getForce().getDevicePointer(), &integration.getPosDelta().getDevicePointer(),
&atomListBuffer.getDevicePointer(), &pairListBuffer.getDevicePointer()};
cu.executeKernel(kernel3, args3, std::max(numAtoms,numPairs), 128);
// TODO: Figure out if this is really needed. The constraint velocities are accounted for
// in a finite difference sense in the step 3 kernel, when the velocities are updated.
integration.applyVelocityConstraints(integrator.getConstraintTolerance());
//// Update the time and step count.
cu.setTime(cu.getTime()+dt);
cu.setStepCount(cu.getStepCount()+1);
cu.reorderAtoms();
}
double CudaIntegrateVelocityVerletStepKernel::computeKineticEnergy(ContextImpl& context, const NoseHooverIntegrator& integrator) {
return cu.getIntegrationUtilities().computeKineticEnergy(0);
}
void CudaIntegrateLangevinStepKernel::initialize(const System& system, const LangevinIntegrator& integrator) {
cu.getPlatformData().initializeContexts(system);
cu.setAsCurrent();
...
...
@@ -8364,6 +8478,355 @@ void CudaApplyAndersenThermostatKernel::execute(ContextImpl& context) {
cu.executeKernel(kernel, args, cu.getNumAtoms());
}
void CudaNoseHooverChainKernel::initialize() {
cu.setAsCurrent();
bool useDouble = cu.getUseDoublePrecision() || cu.getUseMixedPrecision();
map<string, string> defines;
sumWorkGroupSize = 512;
defines["WORK_GROUP_SIZE"] = cu.intToString(sumWorkGroupSize);
defines["MIXEDEXP"] = useDouble ? "exp" : "expf";
defines["BEGIN_YS_LOOP"] = "for(const real & ys : {1}) {";
defines["END_YS_LOOP"] = "}";
CUmodule module = cu.createModule(CudaKernelSources::noseHooverChain, defines, "-std=c++11");
propagateKernels[1] = cu.getKernel(module, "propagateNoseHooverChain");
defines["BEGIN_YS_LOOP"] = "for(const real & ys : {0.828981543588751, -0.657963087177502, 0.828981543588751}){";
module = cu.createModule(CudaKernelSources::noseHooverChain, defines, "-std=c++11");
propagateKernels[3] = cu.getKernel(module, "propagateNoseHooverChain");
defines["BEGIN_YS_LOOP"] = "for(const real & ys : {0.2967324292201065, 0.2967324292201065, -0.186929716880426, 0.2967324292201065, 0.2967324292201065}){";
module = cu.createModule(CudaKernelSources::noseHooverChain, defines, "-std=c++11");
propagateKernels[5] = cu.getKernel(module, "propagateNoseHooverChain");
module = cu.createModule(CudaKernelSources::noseHooverChain, defines, "-std=c++11");
reduceEnergyKernel = cu.getKernel(module, "reduceEnergyPair");
computeHeatBathEnergyKernel = cu.getKernel(module, "computeHeatBathEnergy");
computeAtomsKineticEnergyKernel = cu.getKernel(module, "computeAtomsKineticEnergy");
computePairsKineticEnergyKernel = cu.getKernel(module, "computePairsKineticEnergy");
scaleAtomsVelocitiesKernel = cu.getKernel(module, "scaleAtomsVelocities");
scalePairsVelocitiesKernel = cu.getKernel(module, "scalePairsVelocities");
int energyBufferSize = cu.getEnergyBuffer().getSize();
if (cu.getUseDoublePrecision() || cu.getUseMixedPrecision()) {
energyBuffer.initialize<double2>(cu, energyBufferSize, "energyBuffer");
} else {
energyBuffer.initialize<float2>(cu, energyBufferSize, "energyBuffer");
}
}
std::pair<double, double> CudaNoseHooverChainKernel::propagateChain(ContextImpl& context, const NoseHooverChain &nhc, std::pair<double, double> kineticEnergies, double timeStep) {
cu.setAsCurrent();
bool useDouble = cu.getUseDoublePrecision() || cu.getUseMixedPrecision();
int chainID = nhc.getChainID();
int nAtoms = nhc.getThermostatedAtoms().size();
int nPairs = nhc.getThermostatedPairs().size();
int chainLength = nhc.getChainLength();
int numYS = nhc.getNumYoshidaSuzukiTimeSteps();
int numMTS = nhc.getNumMultiTimeSteps();
int numDOFs = nhc.getNumDegreesOfFreedom();
double temperature = nhc.getTemperature();
double frequency = nhc.getCollisionFrequency();
double relativeTemperature = nhc.getRelativeTemperature();
double relativeFrequency = nhc.getRelativeCollisionFrequency();
if (numYS != 1 && numYS != 3 && numYS != 5) {
throw OpenMMException("Number of Yoshida Suzuki time steps has to be 1, 3, or 5.");
}
auto & chainState = cu.getIntegrationUtilities().getNoseHooverChainState();
if (!scaleFactorBuffer.isInitialized() ||scaleFactorBuffer.getSize() == 0) {
if(useDouble){
std::vector<double2> zeros{{0,0}};
if (scaleFactorBuffer.isInitialized()) {
scaleFactorBuffer.resize(1);
} else {
scaleFactorBuffer.initialize<double2>(cu, 1, "scaleFactorBuffer");
}
scaleFactorBuffer.upload(zeros);
} else {
std::vector<float2> zeros{{0,0}};
if (scaleFactorBuffer.isInitialized()) {
scaleFactorBuffer.resize(1);
} else {
scaleFactorBuffer.initialize<float2>(cu, 1, "scaleFactorBuffer");
}
scaleFactorBuffer.upload(zeros);
}
}
std::vector<double> zeros(chainLength,0);
if (!chainForces.isInitialized() || !chainMasses.isInitialized() ){
if(useDouble){
if (chainForces.isInitialized()) {
chainMasses.resize(chainLength);
chainForces.resize(chainLength);
} else {
chainMasses.initialize<double>(cu, chainLength, "chainMasses");
chainForces.initialize<double>(cu, chainLength, "chainForces");
}
chainMasses.upload(zeros);
chainForces.upload(zeros);
} else {
if (chainForces.isInitialized()) {
chainMasses.resize(chainLength);
chainForces.resize(chainLength);
} else {
chainMasses.initialize<float>(cu, chainLength, "chainMasses");
chainForces.initialize<float>(cu, chainLength, "chainForces");
}
chainMasses.upload(zeros);
chainForces.upload(zeros);
}
}
if (chainForces.getSize() < chainLength) chainMasses.resize(chainLength);
if (chainMasses.getSize() < chainLength) chainMasses.resize(chainLength);
float timeStepFloat = (float) timeStep;
// N.B. We ignore the incoming kineticEnergy and grab it from the device buffer instead
if (nAtoms) {
if (!chainState.count(2*chainID)) chainState[2*chainID] = CudaArray();
if (chainState.at(2*chainID).getSize() != chainLength) {
// We need to upload the CUDA array
if(useDouble){
if (chainState.at(2*chainID).isInitialized()) {
chainState.at(2*chainID).resize(chainLength);
} else {
chainState.at(2*chainID).initialize<double2>(cu, chainLength, "chainState" + std::to_string(2*chainID));
}
std::vector<double2> zeros(chainLength, make_double2(0, 0));
chainState.at(2*chainID).upload(zeros.data());
} else {
if (chainState.at(2*chainID).isInitialized()) {
chainState.at(2*chainID).resize(chainLength);
} else {
chainState.at(2*chainID).initialize<float2>(cu, chainLength, "chainState" + std::to_string(2*chainID));
}
std::vector<float2> zeros(chainLength, make_float2(0, 0));
chainState.at(2*chainID).upload(zeros.data());
}
}
int chainType = 0;
double kT = BOLTZ * temperature;
float kTfloat = (float) kT;
float frequencyFloat = (float) frequency;
void *args[] = {
&chainState[2*chainID].getDevicePointer(),
&kineticEnergyBuffer.getDevicePointer(),
&scaleFactorBuffer.getDevicePointer(),
&chainMasses.getDevicePointer(),
&chainForces.getDevicePointer(),
&chainType, &chainLength, &numMTS, &numDOFs,
&timeStepFloat,
useDouble ? (void*) &kT : (void*) &kTfloat,
&frequencyFloat
};
cu.executeKernel(propagateKernels[numYS], args, 1, 1);
}
if (nPairs) {
if (!chainState.count(2*chainID+1)) chainState[2*chainID+1] = CudaArray();
if (chainState.at(2*chainID+1).getSize() != chainLength) {
// We need to upload the CUDA array
if(useDouble){
if (chainState.at(2*chainID+1).isInitialized()) {
chainState.at(2*chainID+1).resize(chainLength);
} else {
chainState.at(2*chainID+1).initialize<double2>(cu, chainLength, "chainState" + std::to_string(2*chainID+1));
}
std::vector<double2> zeros(chainLength, make_double2(0, 0));
chainState.at(2*chainID+1).upload(zeros.data());
} else {
if (chainState.at(2*chainID+1).isInitialized()) {
chainState.at(2*chainID+1).resize(chainLength);
} else {
chainState.at(2*chainID+1).initialize<float2>(cu, chainLength, "chainState" + std::to_string(2*chainID+1));
}
std::vector<float2> zeros(chainLength, make_float2(0, 0));
chainState.at(2*chainID+1).upload(zeros.data());
}
}
int chainType = 1;
double kT = BOLTZ * relativeTemperature;
int ndf = 3*nPairs;
float kTfloat = (float) kT;
float frequencyFloat = (float) relativeFrequency;
void *args[] = {
&chainState[2*chainID+1].getDevicePointer(),
&kineticEnergyBuffer.getDevicePointer(),
&scaleFactorBuffer.getDevicePointer(),
&chainMasses.getDevicePointer(),
&chainForces.getDevicePointer(),
&chainType, &chainLength, &numMTS, &ndf,
&timeStepFloat,
useDouble ? (void*) &kT : (void*) &kTfloat,
&frequencyFloat
};
cu.executeKernel(propagateKernels[numYS], args, 1, 1);
}
return {0, 0};
}
double CudaNoseHooverChainKernel::computeHeatBathEnergy(ContextImpl& context, const NoseHooverChain &nhc) {
cu.setAsCurrent();
bool useDouble = cu.getUseDoublePrecision() || cu.getUseMixedPrecision();
int chainID = nhc.getChainID();
int chainLength = nhc.getChainLength();
auto & chainState = cu.getIntegrationUtilities().getNoseHooverChainState();
bool absChainIsValid = chainState.count(2*chainID) != 0 &&
chainState[2*chainID].isInitialized() &&
chainState[2*chainID].getSize() == chainLength;
bool relChainIsValid = chainState.count(2*chainID+1) != 0 &&
chainState[2*chainID+1].isInitialized() &&
chainState[2*chainID+1].getSize() == chainLength;
if (!absChainIsValid && !relChainIsValid) return 0.0;
if (!heatBathEnergy.isInitialized() || heatBathEnergy.getSize() == 0) {
if(useDouble){
std::vector<double> one(1);
heatBathEnergy.initialize<double>(cu, 1, "heatBathEnergy");
heatBathEnergy.upload(one);
} else {
std::vector<float> one(1);
heatBathEnergy.initialize<float>(cu, 1, "heatBathEnergy");
heatBathEnergy.upload(one);
}
}
cu.clearBuffer(heatBathEnergy);
if (absChainIsValid) {
int numDOFs = nhc.getNumDegreesOfFreedom();
double temperature = nhc.getTemperature();
double frequency = nhc.getCollisionFrequency();
double kT = BOLTZ * temperature;
float kTfloat = (float) kT;
float frequencyFloat = (float) frequency;
void * args[] = {&heatBathEnergy.getDevicePointer(), &chainLength, &numDOFs,
useDouble ? (void*) &kT : (void*) & kTfloat,
&frequencyFloat, &chainState[2*chainID].getDevicePointer()};
cu.executeKernel(computeHeatBathEnergyKernel, args, 1, 1);
}
if (relChainIsValid) {
int numDOFs = 3 * nhc.getThermostatedPairs().size();
double temperature = nhc.getRelativeTemperature();
double frequency = nhc.getRelativeCollisionFrequency();
double kT = BOLTZ * temperature;
float kTfloat = (float) kT;
float frequencyFloat = (float) frequency;
void * args[] = {&heatBathEnergy.getDevicePointer(), &chainLength, &numDOFs,
useDouble ? (void*) &kT : (void*) & kTfloat,
&frequencyFloat, &chainState[2*chainID+1].getDevicePointer()};
cu.executeKernel(computeHeatBathEnergyKernel, args, 1, 1);
}
void * pinnedBuffer = cu.getPinnedBuffer();
heatBathEnergy.download(pinnedBuffer);
if (useDouble){
return *((double*) pinnedBuffer);
} else {
return *((float*) pinnedBuffer);
}
}
std::pair<double, double> CudaNoseHooverChainKernel::computeMaskedKineticEnergy(ContextImpl& context, const NoseHooverChain &nhc, bool downloadValue) {
cu.setAsCurrent();
bool useDouble = cu.getUseDoublePrecision() || cu.getUseMixedPrecision();
int chainID = nhc.getChainID();
const auto & nhcAtoms = nhc.getThermostatedAtoms();
const auto & nhcPairs = nhc.getThermostatedPairs();
auto nAtoms = nhcAtoms.size();
auto nPairs = nhcPairs.size();
if (nAtoms) {
if (!atomlists.count(chainID)) {
// We need to upload the CUDA array
atomlists[chainID] = CudaArray();
atomlists[chainID].initialize<int>(cu, nAtoms, "atomlist" + std::to_string(chainID));
atomlists[chainID].upload(nhcAtoms);
}
if (atomlists[chainID].getSize() != nAtoms) {
throw OpenMMException("Number of atoms changed. Cannot be handled by the same Nose-Hoover thermostat.");
}
}
if (nPairs) {
if (!pairlists.count(chainID)) {
// We need to upload the CUDA array
pairlists[chainID] = CudaArray();
pairlists[chainID].initialize<int2>(cu, nPairs, "pairlist" + std::to_string(chainID));
std::vector<int2> int2vec;
for(const auto &p : nhcPairs) int2vec.push_back(make_int2(p.first, p.second));
pairlists[chainID].upload(int2vec);
}
if (pairlists[chainID].getSize() != nPairs) {
throw OpenMMException("Number of thermostated pairs changed. Cannot be handled by the same Nose-Hoover thermostat.");
}
}
if (!kineticEnergyBuffer.isInitialized() || kineticEnergyBuffer.getSize() == 0) {
if(useDouble){
std::vector<double2> zeros{{0,0}};
kineticEnergyBuffer.initialize<double2>(cu, 1, "kineticEnergyBuffer");
kineticEnergyBuffer.upload(zeros);
} else {
std::vector<float2> zeros{{0,0}};
kineticEnergyBuffer.initialize<float2>(cu, 1, "kineticEnergyBuffer");
kineticEnergyBuffer.upload(zeros);
}
}
cu.clearBuffer(energyBuffer);
if (nAtoms) {
void *args[] = {&energyBuffer.getDevicePointer(),&nAtoms, &cu.getVelm().getDevicePointer(), &atomlists[chainID].getDevicePointer()};
cu.executeKernel(computeAtomsKineticEnergyKernel, args, nAtoms);
}
if (nPairs) {
void *args[] = {&energyBuffer.getDevicePointer(),&nPairs, &cu.getVelm().getDevicePointer(), &pairlists[chainID].getDevicePointer()};
cu.executeKernel(computePairsKineticEnergyKernel, args, nPairs);
}
//taken from CudaContext::reduceEnergy(); the final kinetic energy will live in the kineticEnergy buffer
int bufferSize = energyBuffer.getSize();
void* args2[] = {&energyBuffer.getDevicePointer(), &kineticEnergyBuffer.getDevicePointer(), &bufferSize, &sumWorkGroupSize};
cu.executeKernel(reduceEnergyKernel, args2, sumWorkGroupSize, sumWorkGroupSize, sumWorkGroupSize*energyBuffer.getElementSize());
std::pair<double, double> KEs = {0, 0};
if (downloadValue) {
void * pinnedBuffer = cu.getPinnedBuffer();
kineticEnergyBuffer.download(pinnedBuffer);
KEs.first = useDouble ? *((double*) pinnedBuffer) : *((float*) pinnedBuffer);
KEs.second = useDouble ? *((double*) pinnedBuffer + 1) : *((float*) pinnedBuffer + 1);
}
return KEs;
}
void CudaNoseHooverChainKernel::scaleVelocities(ContextImpl& context, const NoseHooverChain &nhc, std::pair<double, double> scaleFactor) {
// For now we assume that the atoms and pairs info is valid, because compute{Atoms|Pairs}KineticEnergy must have been
// called before this kernel. If that ever ceases to be true, some sanity checks are needed here.
cu.setAsCurrent();
int chainID = nhc.getChainID();
auto nAtoms = nhc.getThermostatedAtoms().size();
auto nPairs = nhc.getThermostatedPairs().size();
if(nAtoms) {
void *args[] = {&scaleFactorBuffer.getDevicePointer(),
&nAtoms, &cu.getVelm().getDevicePointer(), &atomlists[chainID].getDevicePointer()};
cu.executeKernel(scaleAtomsVelocitiesKernel, args, nAtoms);
}
if(nPairs) {
void *args[] = {&scaleFactorBuffer.getDevicePointer(),
&nPairs, &cu.getVelm().getDevicePointer(), &pairlists[chainID].getDevicePointer()};
cu.executeKernel(scalePairsVelocitiesKernel, args, nPairs);
}
}
void CudaApplyMonteCarloBarostatKernel::initialize(const System& system, const Force& thermostat) {
cu.setAsCurrent();
savedPositions.initialize(cu, cu.getPaddedNumAtoms(), cu.getUseDoublePrecision() ? sizeof(double4) : sizeof(float4), "savedPositions");
...
...
platforms/cuda/src/CudaPlatform.cpp
View file @
7e72bafb
...
...
@@ -96,6 +96,7 @@ CudaPlatform::CudaPlatform() {
registerKernelFactory
(
CalcCustomManyParticleForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
CalcGayBerneForceKernel
::
Name
(),
factory
);
registerKernelFactory
(
IntegrateVerletStepKernel
::
Name
(),
factory
);
registerKernelFactory
(
IntegrateVelocityVerletStepKernel
::
Name
(),
factory
);
registerKernelFactory
(
IntegrateLangevinStepKernel
::
Name
(),
factory
);
registerKernelFactory
(
IntegrateBAOABStepKernel
::
Name
(),
factory
);
registerKernelFactory
(
IntegrateBrownianStepKernel
::
Name
(),
factory
);
...
...
@@ -103,6 +104,7 @@ CudaPlatform::CudaPlatform() {
registerKernelFactory
(
IntegrateVariableLangevinStepKernel
::
Name
(),
factory
);
registerKernelFactory
(
IntegrateCustomStepKernel
::
Name
(),
factory
);
registerKernelFactory
(
ApplyAndersenThermostatKernel
::
Name
(),
factory
);
registerKernelFactory
(
NoseHooverChainKernel
::
Name
(),
factory
);
registerKernelFactory
(
ApplyMonteCarloBarostatKernel
::
Name
(),
factory
);
registerKernelFactory
(
RemoveCMMotionKernel
::
Name
(),
factory
);
platformProperties
.
push_back
(
CudaDeviceIndex
());
...
...
platforms/cuda/src/kernels/noseHooverChain.cu
0 → 100644
View file @
7e72bafb
#include <initializer_list>
extern
"C"
__global__
void
propagateNoseHooverChain
(
mixed2
*
__restrict__
chainData
,
const
mixed2
*
__restrict__
energySum
,
mixed2
*
__restrict__
scaleFactor
,
mixed
*
__restrict__
chainMasses
,
mixed
*
__restrict__
chainForces
,
int
chainType
,
int
chainLength
,
int
numMTS
,
int
numDOFs
,
float
timeStep
,
mixed
kT
,
float
frequency
){
const
mixed
&
kineticEnergy
=
chainType
?
energySum
[
0
].
y
:
energySum
[
0
].
x
;
mixed
&
scale
=
chainType
?
scaleFactor
[
0
].
y
:
scaleFactor
[
0
].
x
;
scale
=
(
mixed
)
1
;
if
(
kineticEnergy
<
1e-8
)
return
;
for
(
int
bead
=
0
;
bead
<
chainLength
;
++
bead
)
chainMasses
[
bead
]
=
kT
/
(
frequency
*
frequency
);
chainMasses
[
0
]
*=
numDOFs
;
mixed
KE2
=
2.0
f
*
kineticEnergy
;
mixed
timeOverMTS
=
timeStep
/
numMTS
;
chainForces
[
0
]
=
(
KE2
-
numDOFs
*
kT
)
/
chainMasses
[
0
];
for
(
int
bead
=
0
;
bead
<
chainLength
-
1
;
++
bead
)
{
chainForces
[
bead
+
1
]
=
(
chainMasses
[
bead
]
*
chainData
[
bead
].
y
*
chainData
[
bead
].
y
-
kT
)
/
chainMasses
[
bead
+
1
];
}
for
(
int
mts
=
0
;
mts
<
numMTS
;
++
mts
)
{
BEGIN_YS_LOOP
mixed
wdt
=
ys
*
timeOverMTS
;
chainData
[
chainLength
-
1
].
y
+=
0.25
f
*
wdt
*
chainForces
[
chainLength
-
1
];
for
(
int
bead
=
chainLength
-
2
;
bead
>=
0
;
--
bead
)
{
mixed
aa
=
MIXEDEXP
(
-
0.125
f
*
wdt
*
chainData
[
bead
+
1
].
y
);
chainData
[
bead
].
y
=
aa
*
(
chainData
[
bead
].
y
*
aa
+
0.25
f
*
wdt
*
chainForces
[
bead
]);
}
// update particle velocities
mixed
aa
=
MIXEDEXP
(
-
0.5
f
*
wdt
*
chainData
[
0
].
y
);
scale
*=
aa
;
// update the thermostat positions
for
(
int
bead
=
0
;
bead
<
chainLength
;
++
bead
)
{
chainData
[
bead
].
x
+=
0.5
f
*
chainData
[
bead
].
y
*
wdt
;
}
// update the forces
chainForces
[
0
]
=
(
scale
*
scale
*
KE2
-
numDOFs
*
kT
)
/
chainMasses
[
0
];
// update thermostat velocities
for
(
int
bead
=
0
;
bead
<
chainLength
-
1
;
++
bead
)
{
mixed
aa
=
MIXEDEXP
(
-
0.125
f
*
wdt
*
chainData
[
bead
+
1
].
y
);
chainData
[
bead
].
y
=
aa
*
(
aa
*
chainData
[
bead
].
y
+
0.25
f
*
wdt
*
chainForces
[
bead
]);
chainForces
[
bead
+
1
]
=
(
chainMasses
[
bead
]
*
chainData
[
bead
].
y
*
chainData
[
bead
].
y
-
kT
)
/
chainMasses
[
bead
+
1
];
}
chainData
[
chainLength
-
1
].
y
+=
0.25
f
*
wdt
*
chainForces
[
chainLength
-
1
];
END_YS_LOOP
}
// MTS loop
}
/**
* Compute total (potential + kinetic) energy of the Nose-Hoover beads
*/
extern
"C"
__global__
void
computeHeatBathEnergy
(
mixed
*
__restrict__
heatBathEnergy
,
int
chainLength
,
int
numDOFs
,
mixed
kT
,
float
frequency
,
const
mixed2
*
__restrict__
chainData
){
// Note that this is always incremented; make sure it's zeroed properly before the first call
mixed
&
energy
=
heatBathEnergy
[
0
];
for
(
int
i
=
0
;
i
<
chainLength
;
++
i
)
{
mixed
prefac
=
i
?
1
:
numDOFs
;
mixed
mass
=
prefac
*
kT
/
(
frequency
*
frequency
);
mixed
velocity
=
chainData
[
i
].
y
;
// The kinetic energy of this bead
energy
+=
0.5
f
*
mass
*
velocity
*
velocity
;
// The potential energy of this bead
mixed
position
=
chainData
[
i
].
x
;
energy
+=
prefac
*
kT
*
position
;
}
}
extern
"C"
__global__
void
computeAtomsKineticEnergy
(
mixed2
*
__restrict__
energyBuffer
,
int
numAtoms
,
const
mixed4
*
__restrict__
velm
,
const
int
*
__restrict__
atoms
){
mixed2
energy
=
make_mixed2
(
0
,
0
);
//energy = 1; return;
for
(
int
index
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
index
<
numAtoms
;
index
+=
blockDim
.
x
*
gridDim
.
x
)
{
int
atom
=
atoms
[
index
];
mixed4
v
=
velm
[
atom
];
mixed
mass
=
v
.
w
==
0
?
0
:
1
/
v
.
w
;
energy
.
x
+=
0.5
f
*
mass
*
(
v
.
x
*
v
.
x
+
v
.
y
*
v
.
y
+
v
.
z
*
v
.
z
);
}
energyBuffer
[
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
]
=
energy
;
}
extern
"C"
__global__
void
computePairsKineticEnergy
(
mixed2
*
__restrict__
energyBuffer
,
int
numPairs
,
const
mixed4
*
__restrict__
velm
,
const
int2
*
__restrict__
pairs
){
mixed2
energy
=
make_mixed2
(
0
,
0
);
for
(
int
index
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
index
<
numPairs
;
index
+=
blockDim
.
x
*
gridDim
.
x
)
{
int2
pair
=
pairs
[
index
];
int
atom1
=
pair
.
x
;
int
atom2
=
pair
.
y
;
mixed4
v1
=
velm
[
atom1
];
mixed4
v2
=
velm
[
atom2
];
mixed
m1
=
v1
.
w
==
0
?
0
:
1
/
v1
.
w
;
mixed
m2
=
v2
.
w
==
0
?
0
:
1
/
v2
.
w
;
mixed4
cv
;
cv
.
x
=
(
m1
*
v1
.
x
+
m2
*
v2
.
x
)
/
(
m1
+
m2
);
cv
.
y
=
(
m1
*
v1
.
y
+
m2
*
v2
.
y
)
/
(
m1
+
m2
);
cv
.
z
=
(
m1
*
v1
.
z
+
m2
*
v2
.
z
)
/
(
m1
+
m2
);
mixed4
rv
;
rv
.
x
=
v2
.
x
-
v1
.
x
;
rv
.
y
=
v2
.
y
-
v1
.
y
;
rv
.
z
=
v2
.
z
-
v1
.
z
;
energy
.
x
+=
0.5
f
*
(
m1
+
m2
)
*
(
cv
.
x
*
cv
.
x
+
cv
.
y
*
cv
.
y
+
cv
.
z
*
cv
.
z
);
energy
.
y
+=
0.5
f
*
(
m1
*
m2
/
(
m1
+
m2
))
*
(
rv
.
x
*
rv
.
x
+
rv
.
y
*
rv
.
y
+
rv
.
z
*
rv
.
z
);
}
// The atoms version of this has been called already, so accumulate instead of assigning here
energyBuffer
[
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
].
x
+=
energy
.
x
;
energyBuffer
[
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
].
y
+=
energy
.
y
;
}
extern
"C"
__global__
void
scaleAtomsVelocities
(
mixed2
*
__restrict__
scaleFactor
,
int
numAtoms
,
mixed4
*
__restrict__
velm
,
const
int
*
__restrict__
atoms
){
const
mixed
&
scale
=
scaleFactor
[
0
].
x
;
for
(
int
index
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
index
<
numAtoms
;
index
+=
blockDim
.
x
*
gridDim
.
x
)
{
int
atom
=
atoms
[
index
];
mixed4
&
v
=
velm
[
atom
];
v
.
x
*=
scale
;
v
.
y
*=
scale
;
v
.
z
*=
scale
;
}
}
extern
"C"
__global__
void
scalePairsVelocities
(
mixed2
*
__restrict__
scaleFactor
,
int
numPairs
,
mixed4
*
__restrict__
velm
,
const
int2
*
__restrict__
pairs
){
const
mixed
&
absScale
=
scaleFactor
[
0
].
x
;
const
mixed
&
relScale
=
scaleFactor
[
0
].
y
;
for
(
int
index
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
index
<
numPairs
;
index
+=
blockDim
.
x
*
gridDim
.
x
)
{
int
atom1
=
pairs
[
index
].
x
;
int
atom2
=
pairs
[
index
].
y
;
mixed4
v1
=
velm
[
atom1
];
mixed4
v2
=
velm
[
atom2
];
mixed
m1
=
v1
.
w
==
0
?
0
:
1
/
v1
.
w
;
mixed
m2
=
v2
.
w
==
0
?
0
:
1
/
v2
.
w
;
mixed4
cv
;
cv
.
x
=
(
m1
*
v1
.
x
+
m2
*
v2
.
x
)
/
(
m1
+
m2
);
cv
.
y
=
(
m1
*
v1
.
y
+
m2
*
v2
.
y
)
/
(
m1
+
m2
);
cv
.
z
=
(
m1
*
v1
.
z
+
m2
*
v2
.
z
)
/
(
m1
+
m2
);
mixed4
rv
;
rv
.
x
=
v2
.
x
-
v1
.
x
;
rv
.
y
=
v2
.
y
-
v1
.
y
;
rv
.
z
=
v2
.
z
-
v1
.
z
;
v1
.
x
=
absScale
*
cv
.
x
-
relScale
*
rv
.
x
*
m2
/
(
m1
+
m2
);
v1
.
y
=
absScale
*
cv
.
y
-
relScale
*
rv
.
y
*
m2
/
(
m1
+
m2
);
v1
.
z
=
absScale
*
cv
.
z
-
relScale
*
rv
.
z
*
m2
/
(
m1
+
m2
);
v2
.
x
=
absScale
*
cv
.
x
+
relScale
*
rv
.
x
*
m1
/
(
m1
+
m2
);
v2
.
y
=
absScale
*
cv
.
y
+
relScale
*
rv
.
y
*
m1
/
(
m1
+
m2
);
v2
.
z
=
absScale
*
cv
.
z
+
relScale
*
rv
.
z
*
m1
/
(
m1
+
m2
);
velm
[
atom1
]
=
v1
;
velm
[
atom2
]
=
v2
;
}
}
/**
* Sum the energy buffer containing a pair of energies stored as mixed2. This is copied from utilities.cu with small modifications
*/
extern
"C"
__global__
void
reduceEnergyPair
(
const
mixed2
*
__restrict__
energyBuffer
,
mixed2
*
__restrict__
result
,
int
bufferSize
,
int
workGroupSize
)
{
__shared__
mixed2
tempBuffer
[
WORK_GROUP_SIZE
];
const
unsigned
int
thread
=
threadIdx
.
x
;
mixed2
sum
=
make_mixed2
(
0
,
0
);
for
(
unsigned
int
idx
=
thread
;
idx
<
bufferSize
;
idx
+=
blockDim
.
x
)
{
sum
.
x
+=
energyBuffer
[
idx
].
x
;
sum
.
y
+=
energyBuffer
[
idx
].
y
;
}
tempBuffer
[
thread
]
=
sum
;
for
(
int
i
=
1
;
i
<
workGroupSize
;
i
*=
2
)
{
__syncthreads
();
if
(
thread
%
(
i
*
2
)
==
0
&&
thread
+
i
<
workGroupSize
)
{
tempBuffer
[
thread
].
x
+=
tempBuffer
[
thread
+
i
].
x
;
tempBuffer
[
thread
].
y
+=
tempBuffer
[
thread
+
i
].
y
;
}
}
if
(
thread
==
0
)
*
result
=
tempBuffer
[
0
];
}
platforms/cuda/src/kernels/utilities.cu
View file @
7e72bafb
platforms/cuda/src/kernels/velocityVerlet.cu
0 → 100644
View file @
7e72bafb
/**
* Perform the first step of Velocity Verlet integration.
*
* update displacements (posDelta) and velocities (velm)
*/
extern
"C"
__global__
void
integrateVelocityVerletPart1
(
int
numAtoms
,
int
numPairs
,
int
paddedNumAtoms
,
const
mixed2
*
__restrict__
dt
,
const
real4
*
__restrict__
posq
,
const
real4
*
__restrict__
posqCorrection
,
mixed4
*
__restrict__
velm
,
const
long
long
*
__restrict__
force
,
mixed4
*
__restrict__
posDelta
,
const
int
*
__restrict__
atomList
,
const
int2
*
__restrict__
pairList
)
{
const
mixed2
stepSize
=
dt
[
0
];
const
mixed
dtPos
=
stepSize
.
y
;
const
mixed
dtVel
=
0.5
f
*
(
stepSize
.
x
+
stepSize
.
y
);
const
mixed
scale
=
0.5
f
*
dtVel
/
(
mixed
)
0x100000000
;
for
(
int
index
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
index
<
numAtoms
;
index
+=
blockDim
.
x
*
gridDim
.
x
)
{
int
atom
=
atomList
[
index
];
mixed4
velocity
=
velm
[
atom
];
if
(
velocity
.
w
!=
0.0
)
{
#ifdef USE_MIXED_PRECISION
real4
pos1
=
posq
[
atom
];
real4
pos2
=
posqCorrection
[
atom
];
mixed4
pos
=
make_mixed4
(
pos1
.
x
+
(
mixed
)
pos2
.
x
,
pos1
.
y
+
(
mixed
)
pos2
.
y
,
pos1
.
z
+
(
mixed
)
pos2
.
z
,
pos1
.
w
);
#else
real4
pos
=
posq
[
atom
];
#endif
velocity
.
x
+=
scale
*
force
[
atom
]
*
velocity
.
w
;
velocity
.
y
+=
scale
*
force
[
atom
+
paddedNumAtoms
]
*
velocity
.
w
;
velocity
.
z
+=
scale
*
force
[
atom
+
paddedNumAtoms
*
2
]
*
velocity
.
w
;
pos
.
x
=
velocity
.
x
*
dtPos
;
pos
.
y
=
velocity
.
y
*
dtPos
;
pos
.
z
=
velocity
.
z
*
dtPos
;
posDelta
[
atom
]
=
pos
;
velm
[
atom
]
=
velocity
;
}
}
for
(
int
index
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
index
<
numPairs
;
index
+=
blockDim
.
x
*
gridDim
.
x
)
{
int
atom1
=
pairList
[
index
].
x
;
int
atom2
=
pairList
[
index
].
y
;
mixed4
v1
=
velm
[
atom1
];
mixed4
v2
=
velm
[
atom2
];
mixed
m1
=
v1
.
w
==
0.0
f
?
0.0
f
:
1.0
f
/
v1
.
w
;
mixed
m2
=
v2
.
w
==
0.0
f
?
0.0
f
:
1.0
f
/
v2
.
w
;
mixed
mass1fract
=
m1
/
(
m1
+
m2
);
mixed
mass2fract
=
m2
/
(
m1
+
m2
);
mixed
invRedMass
=
(
m1
*
m2
!=
0.0
f
)
?
(
m1
+
m2
)
/
(
m1
*
m2
)
:
0.0
f
;
mixed
invTotMass
=
(
m1
+
m2
!=
0.0
f
)
?
1.0
f
/
(
m1
+
m2
)
:
0.0
f
;
mixed3
comVel
;
comVel
.
x
=
v1
.
x
*
mass1fract
+
v2
.
x
*
mass2fract
;
comVel
.
y
=
v1
.
y
*
mass1fract
+
v2
.
y
*
mass2fract
;
comVel
.
z
=
v1
.
z
*
mass1fract
+
v2
.
z
*
mass2fract
;
mixed3
relVel
;
relVel
.
x
=
v2
.
x
-
v1
.
x
;
relVel
.
y
=
v2
.
y
-
v1
.
y
;
relVel
.
z
=
v2
.
z
-
v1
.
z
;
//
mixed3
comFrc
;
comFrc
.
x
=
force
[
atom1
]
+
force
[
atom2
];
comFrc
.
y
=
force
[
atom1
+
paddedNumAtoms
]
+
force
[
atom2
+
paddedNumAtoms
];
comFrc
.
z
=
force
[
atom1
+
paddedNumAtoms
*
2
]
+
force
[
atom2
+
paddedNumAtoms
*
2
];
mixed3
relFrc
;
relFrc
.
x
=
mass1fract
*
force
[
atom2
]
-
mass2fract
*
force
[
atom1
];
relFrc
.
y
=
mass1fract
*
force
[
atom2
+
paddedNumAtoms
]
-
mass2fract
*
force
[
atom1
+
paddedNumAtoms
];
relFrc
.
z
=
mass1fract
*
force
[
atom2
+
paddedNumAtoms
*
2
]
-
mass2fract
*
force
[
atom1
+
paddedNumAtoms
*
2
];
comVel
.
x
+=
comFrc
.
x
*
scale
*
invTotMass
;
comVel
.
y
+=
comFrc
.
y
*
scale
*
invTotMass
;
comVel
.
z
+=
comFrc
.
z
*
scale
*
invTotMass
;
relVel
.
x
+=
relFrc
.
x
*
scale
*
invRedMass
;
relVel
.
y
+=
relFrc
.
y
*
scale
*
invRedMass
;
relVel
.
z
+=
relFrc
.
z
*
scale
*
invRedMass
;
#ifdef USE_MIXED_PRECISION
real4
posv1
=
posq
[
atom1
];
real4
posv2
=
posq
[
atom2
];
real4
posc1
=
posqCorrection
[
atom1
];
real4
posc2
=
posqCorrection
[
atom2
];
mixed4
pos1
=
make_mixed4
(
posv1
.
x
+
(
mixed
)
posc1
.
x
,
posv1
.
y
+
(
mixed
)
posc1
.
y
,
posv1
.
z
+
(
mixed
)
posc1
.
z
,
posv1
.
w
);
mixed4
pos2
=
make_mixed4
(
posv2
.
x
+
(
mixed
)
posc2
.
x
,
posv2
.
y
+
(
mixed
)
posc2
.
y
,
posv2
.
z
+
(
mixed
)
posc2
.
z
,
posv2
.
w
);
#else
real4
pos1
=
posq
[
atom1
];
real4
pos2
=
posq
[
atom2
];
#endif
if
(
v1
.
w
!=
0.0
f
)
{
v1
.
x
=
comVel
.
x
-
relVel
.
x
*
mass2fract
;
v1
.
y
=
comVel
.
y
-
relVel
.
y
*
mass2fract
;
v1
.
z
=
comVel
.
z
-
relVel
.
z
*
mass2fract
;
pos1
.
x
=
v1
.
x
*
dtPos
;
pos1
.
y
=
v1
.
y
*
dtPos
;
pos1
.
z
=
v1
.
z
*
dtPos
;
posDelta
[
atom1
]
=
pos1
;
velm
[
atom1
]
=
v1
;
}
if
(
v2
.
w
!=
0.0
f
)
{
v2
.
x
=
comVel
.
x
+
relVel
.
x
*
mass1fract
;
v2
.
y
=
comVel
.
y
+
relVel
.
y
*
mass1fract
;
v2
.
z
=
comVel
.
z
+
relVel
.
z
*
mass1fract
;
pos2
.
x
=
v2
.
x
*
dtPos
;
pos2
.
y
=
v2
.
y
*
dtPos
;
pos2
.
z
=
v2
.
z
*
dtPos
;
posDelta
[
atom2
]
=
pos2
;
velm
[
atom2
]
=
v2
;
}
}
}
/**
* Perform the second step of Velocity Verlet integration.
*
* apply displacements to positions (posq) after constraints have been enforced
*/
extern
"C"
__global__
void
integrateVelocityVerletPart2
(
int
numAtoms
,
mixed2
*
__restrict__
dt
,
real4
*
__restrict__
posq
,
real4
*
__restrict__
posqCorrection
,
mixed4
*
__restrict__
velm
,
const
mixed4
*
__restrict__
posDelta
)
{
mixed2
stepSize
=
dt
[
0
];
int
index
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
if
(
index
==
0
)
dt
[
0
].
x
=
stepSize
.
y
;
for
(;
index
<
numAtoms
;
index
+=
blockDim
.
x
*
gridDim
.
x
)
{
mixed4
velocity
=
velm
[
index
];
if
(
velocity
.
w
!=
0.0
)
{
#ifdef USE_MIXED_PRECISION
real4
pos1
=
posq
[
index
];
real4
pos2
=
posqCorrection
[
index
];
mixed4
pos
=
make_mixed4
(
pos1
.
x
+
(
mixed
)
pos2
.
x
,
pos1
.
y
+
(
mixed
)
pos2
.
y
,
pos1
.
z
+
(
mixed
)
pos2
.
z
,
pos1
.
w
);
#else
real4
pos
=
posq
[
index
];
#endif
mixed4
delta
=
posDelta
[
index
];
pos
.
x
+=
delta
.
x
;
pos
.
y
+=
delta
.
y
;
pos
.
z
+=
delta
.
z
;
#ifdef USE_MIXED_PRECISION
posq
[
index
]
=
make_real4
((
real
)
pos
.
x
,
(
real
)
pos
.
y
,
(
real
)
pos
.
z
,
(
real
)
pos
.
w
);
posqCorrection
[
index
]
=
make_real4
(
pos
.
x
-
(
real
)
pos
.
x
,
pos
.
y
-
(
real
)
pos
.
y
,
pos
.
z
-
(
real
)
pos
.
z
,
0
);
#else
posq
[
index
]
=
pos
;
#endif
}
}
}
/**
* Perform the third step of Velocity Verlet integration.
*
* modify the velocities (velm) after the force update
*/
extern
"C"
__global__
void
integrateVelocityVerletPart3
(
int
numAtoms
,
int
numPairs
,
int
paddedNumAtoms
,
mixed2
*
__restrict__
dt
,
real4
*
__restrict__
posq
,
real4
*
__restrict__
posqCorrection
,
mixed4
*
__restrict__
velm
,
const
long
long
*
__restrict__
force
,
const
mixed4
*
__restrict__
posDelta
,
const
int
*
__restrict__
atomList
,
const
int2
*
__restrict__
pairList
)
{
mixed2
stepSize
=
dt
[
0
];
#if __CUDA_ARCH__ >= 130
double
oneOverDt
=
1.0
/
stepSize
.
y
;
#else
float
oneOverDt
=
1.0
f
/
stepSize
.
y
;
float
correction
=
(
1.0
f
-
oneOverDt
*
stepSize
.
y
)
/
stepSize
.
y
;
#endif
const
mixed
dtVel
=
0.5
f
*
(
stepSize
.
x
+
stepSize
.
y
);
const
mixed
scale
=
0.5
f
*
dtVel
/
(
mixed
)
0x100000000
;
int
index
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
if
(
index
==
0
)
dt
[
0
].
x
=
stepSize
.
y
;
for
(
int
index
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
index
<
numAtoms
;
index
+=
blockDim
.
x
*
gridDim
.
x
)
{
int
atom
=
atomList
[
index
];
mixed4
velocity
=
velm
[
atom
];
if
(
velocity
.
w
!=
0.0
)
{
mixed4
deltaXconstrained
=
posDelta
[
atom
];
velocity
.
x
+=
scale
*
force
[
atom
]
*
velocity
.
w
+
(
deltaXconstrained
.
x
-
velocity
.
x
*
stepSize
.
y
)
*
oneOverDt
;
velocity
.
y
+=
scale
*
force
[
atom
+
paddedNumAtoms
]
*
velocity
.
w
+
(
deltaXconstrained
.
y
-
velocity
.
y
*
stepSize
.
y
)
*
oneOverDt
;
velocity
.
z
+=
scale
*
force
[
atom
+
paddedNumAtoms
*
2
]
*
velocity
.
w
+
(
deltaXconstrained
.
z
-
velocity
.
z
*
stepSize
.
y
)
*
oneOverDt
;
#if __CUDA_ARCH__ < 130
velocity
.
x
+=
(
deltaXconstrained
.
x
-
velocity
.
x
*
stepSize
.
y
)
*
correction
;
velocity
.
y
+=
(
deltaXconstrained
.
y
-
velocity
.
y
*
stepSize
.
y
)
*
correction
;
velocity
.
z
+=
(
deltaXconstrained
.
z
-
velocity
.
z
*
stepSize
.
y
)
*
correction
;
#endif
velm
[
atom
]
=
velocity
;
}
}
for
(
int
index
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
index
<
numPairs
;
index
+=
blockDim
.
x
*
gridDim
.
x
)
{
int
atom1
=
pairList
[
index
].
x
;
int
atom2
=
pairList
[
index
].
y
;
mixed4
v1
=
velm
[
atom1
];
mixed4
v2
=
velm
[
atom2
];
mixed
m1
=
v1
.
w
==
0.0
f
?
0.0
f
:
1.0
f
/
v1
.
w
;
mixed
m2
=
v2
.
w
==
0.0
f
?
0.0
f
:
1.0
f
/
v2
.
w
;
mixed
mass1fract
=
m1
/
(
m1
+
m2
);
mixed
mass2fract
=
m2
/
(
m1
+
m2
);
mixed
invRedMass
=
(
m1
*
m2
!=
0.0
f
)
?
(
m1
+
m2
)
/
(
m1
*
m2
)
:
0.0
f
;
mixed
invTotMass
=
(
m1
+
m2
!=
0.0
f
)
?
1.0
f
/
(
m1
+
m2
)
:
0.0
f
;
mixed3
comVel
;
comVel
.
x
=
v1
.
x
*
mass1fract
+
v2
.
x
*
mass2fract
;
comVel
.
y
=
v1
.
y
*
mass1fract
+
v2
.
y
*
mass2fract
;
comVel
.
z
=
v1
.
z
*
mass1fract
+
v2
.
z
*
mass2fract
;
mixed3
relVel
;
relVel
.
x
=
v2
.
x
-
v1
.
x
;
relVel
.
y
=
v2
.
y
-
v1
.
y
;
relVel
.
z
=
v2
.
z
-
v1
.
z
;
//
mixed3
comFrc
;
comFrc
.
x
=
force
[
atom1
]
+
force
[
atom2
];
comFrc
.
y
=
force
[
atom1
+
paddedNumAtoms
]
+
force
[
atom2
+
paddedNumAtoms
];
comFrc
.
z
=
force
[
atom1
+
paddedNumAtoms
*
2
]
+
force
[
atom2
+
paddedNumAtoms
*
2
];
mixed3
relFrc
;
relFrc
.
x
=
mass1fract
*
force
[
atom2
]
-
mass2fract
*
force
[
atom1
];
relFrc
.
y
=
mass1fract
*
force
[
atom2
+
paddedNumAtoms
]
-
mass2fract
*
force
[
atom1
+
paddedNumAtoms
];
relFrc
.
z
=
mass1fract
*
force
[
atom2
+
paddedNumAtoms
*
2
]
-
mass2fract
*
force
[
atom1
+
paddedNumAtoms
*
2
];
comVel
.
x
+=
comFrc
.
x
*
scale
*
invTotMass
;
comVel
.
y
+=
comFrc
.
y
*
scale
*
invTotMass
;
comVel
.
z
+=
comFrc
.
z
*
scale
*
invTotMass
;
relVel
.
x
+=
relFrc
.
x
*
scale
*
invRedMass
;
relVel
.
y
+=
relFrc
.
y
*
scale
*
invRedMass
;
relVel
.
z
+=
relFrc
.
z
*
scale
*
invRedMass
;
if
(
v1
.
w
!=
0.0
f
)
{
mixed4
deltaXconstrained
=
posDelta
[
atom1
];
v1
.
x
=
comVel
.
x
-
relVel
.
x
*
mass2fract
+
(
deltaXconstrained
.
x
-
v1
.
x
*
stepSize
.
y
)
*
oneOverDt
;
v1
.
y
=
comVel
.
y
-
relVel
.
y
*
mass2fract
+
(
deltaXconstrained
.
y
-
v1
.
y
*
stepSize
.
y
)
*
oneOverDt
;
v1
.
z
=
comVel
.
z
-
relVel
.
z
*
mass2fract
+
(
deltaXconstrained
.
z
-
v1
.
z
*
stepSize
.
y
)
*
oneOverDt
;
#if __CUDA_ARCH__ < 130
v1
.
x
+=
(
deltaXconstrained
.
x
-
v1
.
x
*
stepSize
.
y
)
*
correction
;
v1
.
y
+=
(
deltaXconstrained
.
y
-
v1
.
y
*
stepSize
.
y
)
*
correction
;
v1
.
z
+=
(
deltaXconstrained
.
z
-
v1
.
z
*
stepSize
.
y
)
*
correction
;
#endif
velm
[
atom1
]
=
v1
;
}
if
(
v2
.
w
!=
0.0
f
)
{
mixed4
deltaXconstrained
=
posDelta
[
atom2
];
v2
.
x
=
comVel
.
x
+
relVel
.
x
*
mass1fract
+
(
deltaXconstrained
.
x
-
v2
.
x
*
stepSize
.
y
)
*
oneOverDt
;
v2
.
y
=
comVel
.
y
+
relVel
.
y
*
mass1fract
+
(
deltaXconstrained
.
y
-
v2
.
y
*
stepSize
.
y
)
*
oneOverDt
;
v2
.
z
=
comVel
.
z
+
relVel
.
z
*
mass1fract
+
(
deltaXconstrained
.
z
-
v2
.
z
*
stepSize
.
y
)
*
oneOverDt
;
#if __CUDA_ARCH__ < 130
v2
.
x
+=
(
deltaXconstrained
.
x
-
v2
.
x
*
stepSize
.
y
)
*
correction
;
v2
.
y
+=
(
deltaXconstrained
.
y
-
v2
.
y
*
stepSize
.
y
)
*
correction
;
v2
.
z
+=
(
deltaXconstrained
.
z
-
v2
.
z
*
stepSize
.
y
)
*
correction
;
#endif
velm
[
atom2
]
=
v2
;
}
}
}
/**
* Apply the hard wall constraint
*/
extern
"C"
__global__
void
integrateVelocityVerletHardWall
(
int
numPairs
,
const
float
*
__restrict__
maxPairDistance
,
mixed2
*
__restrict__
dt
,
real4
*
__restrict__
posq
,
real4
*
__restrict__
posqCorrection
,
mixed4
*
__restrict__
velm
,
const
int2
*
__restrict__
pairList
,
const
float
*
__restrict__
pairTemperature
)
{
mixed
dtPos
=
dt
[
0
].
y
;
mixed
maxDelta
=
(
mixed
)
maxPairDistance
[
0
];
// Apply hard wall constraints.
if
(
maxDelta
>
0
)
{
for
(
int
index
=
blockIdx
.
x
*
blockDim
.
x
+
threadIdx
.
x
;
index
<
numPairs
;
index
+=
blockDim
.
x
*
gridDim
.
x
)
{
const
mixed
hardWallScale
=
sqrt
(
((
mixed
)
pairTemperature
[
index
])
*
((
mixed
)
BOLTZ
));
int2
atom
=
make_int2
(
pairList
[
index
].
x
,
pairList
[
index
].
y
);
#ifdef USE_MIXED_PRECISION
real4
posv1
=
posq
[
atom
.
x
];
real4
posc1
=
posqCorrection
[
atom
.
x
];
mixed4
pos1
=
make_mixed4
(
posv1
.
x
+
(
mixed
)
posc1
.
x
,
posv1
.
y
+
(
mixed
)
posc1
.
y
,
posv1
.
z
+
(
mixed
)
posc1
.
z
,
posv1
.
w
);
real4
posv2
=
posq
[
atom
.
y
];
real4
posc2
=
posqCorrection
[
atom
.
y
];
mixed4
pos2
=
make_mixed4
(
posv2
.
x
+
(
mixed
)
posc2
.
x
,
posv2
.
y
+
(
mixed
)
posc2
.
y
,
posv2
.
z
+
(
mixed
)
posc2
.
z
,
posv2
.
w
);
#else
real4
pos1
=
posq
[
atom
.
x
];
real4
pos2
=
posq
[
atom
.
y
];
#endif
mixed3
delta
=
make_mixed3
(
mixed
(
pos1
.
x
-
pos2
.
x
),
mixed
(
pos1
.
y
-
pos2
.
y
),
mixed
(
pos1
.
z
-
pos2
.
z
)
);
mixed
r
=
sqrt
(
delta
.
x
*
delta
.
x
+
delta
.
y
*
delta
.
y
+
delta
.
z
*
delta
.
z
);
mixed
rInv
=
1
/
r
;
if
(
rInv
*
maxDelta
<
1.0
)
{
// The constraint has been violated, so make the inter-particle distance "bounce"
// off the hard wall.
mixed3
bondDir
=
make_mixed3
(
delta
.
x
*
rInv
,
delta
.
y
*
rInv
,
delta
.
z
*
rInv
);
mixed3
vel1
=
make_mixed3
(
velm
[
atom
.
x
].
x
,
velm
[
atom
.
x
].
y
,
velm
[
atom
.
x
].
z
);
mixed3
vel2
=
make_mixed3
(
velm
[
atom
.
y
].
x
,
velm
[
atom
.
y
].
y
,
velm
[
atom
.
y
].
z
);
mixed
m1
=
velm
[
atom
.
x
].
w
!=
0.0
?
1.0
/
velm
[
atom
.
x
].
w
:
0.0
;
mixed
m2
=
velm
[
atom
.
y
].
w
!=
0.0
?
1.0
/
velm
[
atom
.
y
].
w
:
0.0
;
mixed
invTotMass
=
(
m1
+
m2
!=
0.0
)
?
1.0
/
(
m1
+
m2
)
:
0.0
;
mixed
deltaR
=
r
-
maxDelta
;
mixed
deltaT
=
dtPos
;
mixed
dt
=
dtPos
;
mixed
dotvr1
=
vel1
.
x
*
bondDir
.
x
+
vel1
.
y
*
bondDir
.
y
+
vel1
.
z
*
bondDir
.
z
;
mixed3
vb1
=
make_mixed3
(
bondDir
.
x
*
dotvr1
,
bondDir
.
y
*
dotvr1
,
bondDir
.
z
*
dotvr1
);
mixed3
vp1
=
make_mixed3
(
vel1
.
x
-
vb1
.
x
,
vel1
.
y
-
vb1
.
y
,
vel1
.
z
-
vb1
.
z
);
if
(
m2
==
0
)
{
// The parent particle is massless, so move only the Drude particle.
if
(
dotvr1
!=
0.0
)
deltaT
=
deltaR
/
fabs
(
dotvr1
);
if
(
deltaT
>
dtPos
)
deltaT
=
dtPos
;
dotvr1
=
-
dotvr1
*
hardWallScale
/
(
fabs
(
dotvr1
)
*
sqrt
(
m1
));
mixed
dr
=
-
deltaR
+
deltaT
*
dotvr1
;
pos1
.
x
+=
bondDir
.
x
*
dr
;
pos1
.
y
+=
bondDir
.
y
*
dr
;
pos1
.
z
+=
bondDir
.
z
*
dr
;
velm
[
atom
.
x
]
=
make_mixed4
(
vp1
.
x
+
bondDir
.
x
*
dotvr1
,
vp1
.
y
+
bondDir
.
y
*
dotvr1
,
vp1
.
z
+
bondDir
.
z
*
dotvr1
,
velm
[
atom
.
x
].
w
);
#ifdef USE_MIXED_PRECISION
posq
[
atom
.
x
]
=
make_real4
((
real
)
pos1
.
x
,
(
real
)
pos1
.
y
,
(
real
)
pos1
.
z
,
(
real
)
pos1
.
w
);
posqCorrection
[
atom
.
x
]
=
make_real4
(
pos1
.
x
-
(
real
)
pos1
.
x
,
pos1
.
y
-
(
real
)
pos1
.
y
,
pos1
.
z
-
(
real
)
pos1
.
z
,
0
);
#else
posq
[
atom
.
x
]
=
pos1
;
#endif
}
else
{
// Move both particles.
mixed
dotvr2
=
vel2
.
x
*
bondDir
.
x
+
vel2
.
y
*
bondDir
.
y
+
vel2
.
z
*
bondDir
.
z
;
mixed3
vb2
=
make_mixed3
(
bondDir
.
x
*
dotvr2
,
bondDir
.
y
*
dotvr2
,
bondDir
.
z
*
dotvr2
);
mixed3
vp2
=
make_mixed3
(
vel2
.
x
-
vb2
.
x
,
vel2
.
y
-
vb2
.
y
,
vel2
.
z
-
vb2
.
z
);
mixed
vbCMass
=
(
m1
*
dotvr1
+
m2
*
dotvr2
)
*
invTotMass
;
dotvr1
-=
vbCMass
;
dotvr2
-=
vbCMass
;
if
(
dotvr1
!=
dotvr2
)
deltaT
=
deltaR
/
fabs
(
dotvr1
-
dotvr2
);
if
(
deltaT
>
dt
)
deltaT
=
dt
;
mixed
vBond
=
hardWallScale
/
sqrt
(
m1
);
dotvr1
=
-
dotvr1
*
vBond
*
m2
*
invTotMass
/
fabs
(
dotvr1
);
dotvr2
=
-
dotvr2
*
vBond
*
m1
*
invTotMass
/
fabs
(
dotvr2
);
mixed
dr1
=
-
deltaR
*
m2
*
invTotMass
+
deltaT
*
dotvr1
;
mixed
dr2
=
deltaR
*
m1
*
invTotMass
+
deltaT
*
dotvr2
;
dotvr1
+=
vbCMass
;
dotvr2
+=
vbCMass
;
pos1
.
x
+=
bondDir
.
x
*
dr1
;
pos1
.
y
+=
bondDir
.
y
*
dr1
;
pos1
.
z
+=
bondDir
.
z
*
dr1
;
pos2
.
x
+=
bondDir
.
x
*
dr2
;
pos2
.
y
+=
bondDir
.
y
*
dr2
;
pos2
.
z
+=
bondDir
.
z
*
dr2
;
velm
[
atom
.
x
]
=
make_mixed4
(
vp1
.
x
+
bondDir
.
x
*
dotvr1
,
vp1
.
y
+
bondDir
.
y
*
dotvr1
,
vp1
.
z
+
bondDir
.
z
*
dotvr1
,
velm
[
atom
.
x
].
w
);
velm
[
atom
.
y
]
=
make_mixed4
(
vp2
.
x
+
bondDir
.
x
*
dotvr2
,
vp2
.
y
+
bondDir
.
y
*
dotvr2
,
vp2
.
z
+
bondDir
.
z
*
dotvr2
,
velm
[
atom
.
y
].
w
);
#ifdef USE_MIXED_PRECISION
posq
[
atom
.
x
]
=
make_real4
((
real
)
pos1
.
x
,
(
real
)
pos1
.
y
,
(
real
)
pos1
.
z
,
(
real
)
pos1
.
w
);
posq
[
atom
.
y
]
=
make_real4
((
real
)
pos2
.
x
,
(
real
)
pos2
.
y
,
(
real
)
pos2
.
z
,
(
real
)
pos2
.
w
);
posqCorrection
[
atom
.
x
]
=
make_real4
(
pos1
.
x
-
(
real
)
pos1
.
x
,
pos1
.
y
-
(
real
)
pos1
.
y
,
pos1
.
z
-
(
real
)
pos1
.
z
,
0
);
posqCorrection
[
atom
.
y
]
=
make_real4
(
pos2
.
x
-
(
real
)
pos2
.
x
,
pos2
.
y
-
(
real
)
pos2
.
y
,
pos2
.
z
-
(
real
)
pos2
.
z
,
0
);
#else
posq
[
atom
.
x
]
=
pos1
;
posq
[
atom
.
y
]
=
pos2
;
#endif
}
}
}
}
/* end of hard wall constraint part */
}
platforms/cuda/tests/TestCudaNoseHooverIntegrator.cpp
0 → 100644
View file @
7e72bafb
/* -------------------------------------------------------------------------- *
* 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) 2019 Stanford University and the Authors. *
* Authors: Andreas Krämer and Andrew C. Simmmonett *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "CudaTests.h"
#include "TestNoseHooverIntegrator.h"
void
runPlatformTests
()
{
}
platforms/cuda/tests/TestCudaNoseHooverThermostat.cpp
0 → 100644
View file @
7e72bafb
/* -------------------------------------------------------------------------- *
* 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) 2019 Stanford University and the Authors. *
* Authors: Andreas Krämer and Andrew C. Simmonett *
* Contributors: *
* *
* Permission is hereby granted, free of charge, to any person obtaining a *
* copy of this software and associated documentation files (the "Software"), *
* to deal in the Software without restriction, including without limitation *
* the rights to use, copy, modify, merge, publish, distribute, sublicense, *
* and/or sell copies of the Software, and to permit persons to whom the *
* Software is furnished to do so, subject to the following conditions: *
* *
* The above copyright notice and this permission notice shall be included in *
* all copies or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
* THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE *
* USE OR OTHER DEALINGS IN THE SOFTWARE. *
* -------------------------------------------------------------------------- */
#include "CudaTests.h"
#include "TestNoseHooverThermostat.h"
void
runPlatformTests
()
{
}
Prev
1
2
3
4
5
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