Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F70482077
ensembles.py
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Sun, Jul 7, 02:20
Size
19 KB
Mime Type
text/x-python
Expires
Tue, Jul 9, 02:20 (2 d)
Engine
blob
Format
Raw Data
Handle
18849437
Attached To
rLAMMPS lammps
ensembles.py
View Options
"""Contains the classes that deal with the different dynamics required in
different types of ensembles.
Copyright (C) 2013, Joshua More and Michele Ceriotti
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http.//www.gnu.org/licenses/>.
Holds the algorithms required for normal mode propagators, and the objects to
do the constant temperature and pressure algorithms. Also calculates the
appropriate conserved energy quantity for the ensemble of choice.
Classes:
Ensemble: Base ensemble class with generic methods and attributes.
NVEEnsemble: Deals with constant energy dynamics.
NVTEnsemble: Deals with constant temperature dynamics.
NPTEnsemble: Deals with constant pressure dynamics.
ReplayEnsemble: Takes a trajectory, and simply sets the atom positions to
match it, rather than doing dynamics. In this way new properties can
be calculated on an old simulation, without having to rerun it from
scratch.
"""
__all__
=
[
'Ensemble'
,
'NVEEnsemble'
,
'NVTEnsemble'
,
'NPTEnsemble'
,
'ReplayEnsemble'
]
import
numpy
as
np
import
time
from
ipi.utils.depend
import
*
from
ipi.utils
import
units
from
ipi.utils.softexit
import
softexit
from
ipi.utils.io.io_xyz
import
read_xyz
from
ipi.utils.io.io_pdb
import
read_pdb
from
ipi.utils.io.io_xml
import
xml_parse_file
from
ipi.utils.units
import
Constants
,
unit_to_internal
from
ipi.inputs.thermostats
import
InputThermo
from
ipi.inputs.barostats
import
InputBaro
from
ipi.engine.thermostats
import
*
from
ipi.engine.barostats
import
*
class
Ensemble
(
dobject
):
"""Base ensemble class.
Gives the standard methods and attributes needed in all the
ensemble classes.
Attributes:
beads: A beads object giving the atoms positions.
cell: A cell object giving the system box.
forces: A forces object giving the virial and the forces acting on
each bead.
prng: A random number generator object.
nm: An object which does the normal modes transformation.
fixcom: A boolean which decides whether the centre of mass
motion will be constrained or not.
Depend objects:
econs: The conserved energy quantity appropriate to the given
ensemble. Depends on the various energy terms which make it up,
which are different depending on the ensemble.
temp: The system temperature.
dt: The timestep for the algorithms.
ntemp: The simulation temperature. Will be nbeads times higher than
the system temperature as PIMD calculations are done at this
effective classical temperature.
"""
def
__init__
(
self
,
dt
,
temp
,
fixcom
=
False
):
"""Initialises Ensemble.
Args:
dt: The timestep of the simulation algorithms.
temp: The temperature.
fixcom: An optional boolean which decides whether the centre of mass
motion will be constrained or not. Defaults to False.
"""
dset
(
self
,
"econs"
,
depend_value
(
name
=
'econs'
,
func
=
self
.
get_econs
))
dset
(
self
,
"temp"
,
depend_value
(
name
=
'temp'
,
value
=
temp
))
dset
(
self
,
"dt"
,
depend_value
(
name
=
'dt'
,
value
=
dt
))
self
.
fixcom
=
fixcom
def
bind
(
self
,
beads
,
nm
,
cell
,
bforce
,
prng
):
"""Binds beads, cell, bforce and prng to the ensemble.
This takes a beads object, a cell object, a forcefield object and a
random number generator object and makes them members of the ensemble.
It also then creates the objects that will hold the data needed in the
ensemble algorithms and the dependency network. Note that the conserved
quantity is defined in the init, but as each ensemble has a different
conserved quantity the dependencies are defined in bind.
Args:
beads: The beads object from whcih the bead positions are taken.
nm: A normal modes object used to do the normal modes transformation.
cell: The cell object from which the system box is taken.
bforce: The forcefield object from which the force and virial are
taken.
prng: The random number generator object which controls random number
generation.
"""
# store local references to the different bits of the simulation
self
.
beads
=
beads
self
.
cell
=
cell
self
.
forces
=
bforce
self
.
prng
=
prng
self
.
nm
=
nm
# n times the temperature
dset
(
self
,
"ntemp"
,
depend_value
(
name
=
'ntemp'
,
func
=
self
.
get_ntemp
,
dependencies
=
[
dget
(
self
,
"temp"
)]))
# dependencies of the conserved quantity
dget
(
self
,
"econs"
)
.
add_dependency
(
dget
(
self
.
beads
,
"kin"
))
dget
(
self
,
"econs"
)
.
add_dependency
(
dget
(
self
.
forces
,
"pot"
))
dget
(
self
,
"econs"
)
.
add_dependency
(
dget
(
self
.
beads
,
"vpath"
))
def
get_ntemp
(
self
):
"""Returns the PI simulation temperature (P times the physical T)."""
return
self
.
temp
*
self
.
beads
.
nbeads
def
pstep
(
self
):
"""Dummy momenta propagator which does nothing."""
pass
def
qcstep
(
self
):
"""Dummy centroid position propagator which does nothing."""
pass
def
step
(
self
):
"""Dummy simulation time step which does nothing."""
pass
def
get_econs
(
self
):
"""Calculates the conserved energy quantity for constant energy
ensembles.
"""
return
self
.
beads
.
vpath
*
self
.
nm
.
omegan2
+
self
.
nm
.
kin
+
self
.
forces
.
pot
class
NVEEnsemble
(
Ensemble
):
"""Ensemble object for constant energy simulations.
Has the relevant conserved quantity and normal mode propagator for the
constant energy ensemble. Note that a temperature of some kind must be
defined so that the spring potential can be calculated.
Attributes:
ptime: The time taken in updating the velocities.
qtime: The time taken in updating the positions.
ttime: The time taken in applying the thermostat steps.
Depend objects:
econs: Conserved energy quantity. Depends on the bead kinetic and
potential energy, and the spring potential energy.
"""
def
__init__
(
self
,
dt
,
temp
,
fixcom
=
False
):
"""Initialises NVEEnsemble.
Args:
dt: The simulation timestep.
temp: The system temperature.
fixcom: An optional boolean which decides whether the centre of mass
motion will be constrained or not. Defaults to False.
"""
super
(
NVEEnsemble
,
self
)
.
__init__
(
dt
=
dt
,
temp
=
temp
,
fixcom
=
fixcom
)
def
rmcom
(
self
):
"""This removes the centre of mass contribution to the kinetic energy.
Calculates the centre of mass momenta, then removes the mass weighted
contribution from each atom. If the ensemble defines a thermostat, then
the contribution to the conserved quantity due to this subtraction is
added to the thermostat heat energy, as it is assumed that the centre of
mass motion is due to the thermostat.
If there is a choice of thermostats, the thermostat
connected to the centroid is chosen.
"""
if
(
self
.
fixcom
):
pcom
=
np
.
zeros
(
3
,
float
);
na3
=
self
.
beads
.
natoms
*
3
nb
=
self
.
beads
.
nbeads
p
=
depstrip
(
self
.
beads
.
p
)
m
=
depstrip
(
self
.
beads
.
m3
)[:,
0
:
na3
:
3
]
M
=
self
.
beads
[
0
]
.
M
for
i
in
range
(
3
):
pcom
[
i
]
=
p
[:,
i
:
na3
:
3
]
.
sum
()
if
hasattr
(
self
,
"thermostat"
):
if
hasattr
(
self
.
thermostat
,
"_thermos"
):
self
.
thermostat
.
_thermos
[
0
]
.
ethermo
+=
np
.
dot
(
pcom
,
pcom
)
/
(
2.0
*
M
*
nb
)
else
:
self
.
thermostat
.
ethermo
+=
np
.
dot
(
pcom
,
pcom
)
/
(
2.0
*
M
*
nb
)
# subtracts COM _velocity_
pcom
*=
1.0
/
(
nb
*
M
)
for
i
in
range
(
3
):
self
.
beads
.
p
[:,
i
:
na3
:
3
]
-=
m
*
pcom
[
i
]
def
pstep
(
self
):
"""Velocity Verlet momenta propagator."""
self
.
beads
.
p
+=
depstrip
(
self
.
forces
.
f
)
*
(
self
.
dt
*
0.5
)
def
qcstep
(
self
):
"""Velocity Verlet centroid position propagator."""
self
.
nm
.
qnm
[
0
,:]
+=
depstrip
(
self
.
nm
.
pnm
)[
0
,:]
/
depstrip
(
self
.
beads
.
m3
)[
0
]
*
self
.
dt
def
step
(
self
):
"""Does one simulation time step."""
self
.
ptime
=
-
time
.
time
()
self
.
pstep
()
self
.
ptime
+=
time
.
time
()
self
.
qtime
=
-
time
.
time
()
self
.
qcstep
()
self
.
nm
.
free_qstep
()
self
.
qtime
+=
time
.
time
()
self
.
ptime
-=
time
.
time
()
self
.
pstep
()
self
.
ptime
+=
time
.
time
()
self
.
ttime
=
-
time
.
time
()
self
.
rmcom
()
self
.
ttime
+=
time
.
time
()
class
NVTEnsemble
(
NVEEnsemble
):
"""Ensemble object for constant temperature simulations.
Has the relevant conserved quantity and normal mode propagator for the
constant temperature ensemble. Contains a thermostat object containing the
algorithms to keep the temperature constant.
Attributes:
thermostat: A thermostat object to keep the temperature constant.
Depend objects:
econs: Conserved energy quantity. Depends on the bead kinetic and
potential energy, the spring potential energy and the heat
transferred to the thermostat.
"""
def
__init__
(
self
,
dt
,
temp
,
thermostat
=
None
,
fixcom
=
False
):
"""Initialises NVTEnsemble.
Args:
dt: The simulation timestep.
temp: The system temperature.
thermostat: A thermostat object to keep the temperature constant.
Defaults to Thermostat()
fixcom: An optional boolean which decides whether the centre of mass
motion will be constrained or not. Defaults to False.
"""
super
(
NVTEnsemble
,
self
)
.
__init__
(
dt
=
dt
,
temp
=
temp
,
fixcom
=
fixcom
)
if
thermostat
is
None
:
self
.
thermostat
=
Thermostat
()
else
:
self
.
thermostat
=
thermostat
def
bind
(
self
,
beads
,
nm
,
cell
,
bforce
,
prng
):
"""Binds beads, cell, bforce and prng to the ensemble.
This takes a beads object, a cell object, a forcefield object and a
random number generator object and makes them members of the ensemble.
It also then creates the objects that will hold the data needed in the
ensemble algorithms and the dependency network. Also note that the
thermostat timestep and temperature are defined relative to the system
temperature, and the the thermostat temperature is held at the
higher simulation temperature, as is appropriate.
Args:
beads: The beads object from whcih the bead positions are taken.
nm: A normal modes object used to do the normal modes transformation.
cell: The cell object from which the system box is taken.
bforce: The forcefield object from which the force and virial are
taken.
prng: The random number generator object which controls random number
generation.
"""
super
(
NVTEnsemble
,
self
)
.
bind
(
beads
,
nm
,
cell
,
bforce
,
prng
)
fixdof
=
None
if
self
.
fixcom
:
fixdof
=
3
# first makes sure that the thermostat has the correct temperature, then proceed with binding it.
deppipe
(
self
,
"ntemp"
,
self
.
thermostat
,
"temp"
)
deppipe
(
self
,
"dt"
,
self
.
thermostat
,
"dt"
)
#decides whether the thermostat will work in the normal mode or
#the bead representation.
if
isinstance
(
self
.
thermostat
,
ThermoNMGLE
)
or
isinstance
(
self
.
thermostat
,
ThermoNMGLEG
)
or
isinstance
(
self
.
thermostat
,
ThermoPILE_L
)
or
isinstance
(
self
.
thermostat
,
ThermoPILE_G
):
self
.
thermostat
.
bind
(
nm
=
self
.
nm
,
prng
=
prng
,
fixdof
=
fixdof
)
else
:
self
.
thermostat
.
bind
(
beads
=
self
.
beads
,
prng
=
prng
,
fixdof
=
fixdof
)
dget
(
self
,
"econs"
)
.
add_dependency
(
dget
(
self
.
thermostat
,
"ethermo"
))
def
step
(
self
):
"""Does one simulation time step."""
self
.
ttime
=
-
time
.
time
()
self
.
thermostat
.
step
()
self
.
rmcom
()
self
.
ttime
+=
time
.
time
()
self
.
ptime
=
-
time
.
time
()
self
.
pstep
()
self
.
ptime
+=
time
.
time
()
self
.
qtime
=
-
time
.
time
()
self
.
qcstep
()
self
.
nm
.
free_qstep
()
self
.
qtime
+=
time
.
time
()
self
.
ptime
-=
time
.
time
()
self
.
pstep
()
self
.
ptime
+=
time
.
time
()
self
.
ttime
-=
time
.
time
()
self
.
thermostat
.
step
()
self
.
rmcom
()
self
.
ttime
+=
time
.
time
()
def
get_econs
(
self
):
"""Calculates the conserved energy quantity for constant temperature
ensemble.
"""
return
NVEEnsemble
.
get_econs
(
self
)
+
self
.
thermostat
.
ethermo
class
NPTEnsemble
(
NVTEnsemble
):
"""Ensemble object for constant pressure simulations.
Has the relevant conserved quantity and normal mode propagator for the
constant pressure ensemble. Contains a thermostat object containing the
algorithms to keep the temperature constant, and a barostat to keep the
pressure constant.
Attributes:
barostat: A barostat object to keep the pressure constant.
Depend objects:
econs: Conserved energy quantity. Depends on the bead and cell kinetic
and potential energy, the spring potential energy, the heat
transferred to the beads and cell thermostat, the temperature and
the cell volume.
pext: External pressure.
"""
def
__init__
(
self
,
dt
,
temp
,
pext
,
thermostat
=
None
,
barostat
=
None
,
fixcom
=
False
):
"""Initialises NPTEnsemble.
Args:
dt: The simulation timestep.
temp: The system temperature.
pext: The external pressure.
thermostat: A thermostat object to keep the temperature constant.
Defaults to Thermostat().
barostat: A barostat object to keep the pressure constant.
Defaults to Barostat().
fixcom: An optional boolean which decides whether the centre of mass
motion will be constrained or not. Defaults to False.
"""
super
(
NPTEnsemble
,
self
)
.
__init__
(
dt
,
temp
,
thermostat
,
fixcom
=
fixcom
)
if
barostat
==
None
:
self
.
barostat
=
Barostat
()
else
:
self
.
barostat
=
barostat
dset
(
self
,
"pext"
,
depend_value
(
name
=
'pext'
))
if
not
pext
is
None
:
self
.
pext
=
pext
else
:
self
.
pext
=
0.0
def
bind
(
self
,
beads
,
nm
,
cell
,
bforce
,
prng
):
"""Binds beads, cell, bforce and prng to the ensemble.
This takes a beads object, a cell object, a forcefield object and a
random number generator object and makes them members of the ensemble.
It also then creates the objects that will hold the data needed in the
ensemble algorithms and the dependency network. Also note that the cell
thermostat timesteps and temperatures are defined relative to the system
temperature, and the the thermostat temperatures are held at the
higher simulation temperature, as is appropriate.
Args:
beads: The beads object from whcih the bead positions are taken.
nm: A normal modes object used to do the normal modes transformation.
cell: The cell object from which the system box is taken.
bforce: The forcefield object from which the force and virial are
taken.
prng: The random number generator object which controls random number
generation.
"""
fixdof
=
None
if
self
.
fixcom
:
fixdof
=
3
super
(
NPTEnsemble
,
self
)
.
bind
(
beads
,
nm
,
cell
,
bforce
,
prng
)
self
.
barostat
.
bind
(
beads
,
nm
,
cell
,
bforce
,
prng
=
prng
,
fixdof
=
fixdof
)
deppipe
(
self
,
"ntemp"
,
self
.
barostat
,
"temp"
)
deppipe
(
self
,
"dt"
,
self
.
barostat
,
"dt"
)
deppipe
(
self
,
"pext"
,
self
.
barostat
,
"pext"
)
dget
(
self
,
"econs"
)
.
add_dependency
(
dget
(
self
.
barostat
,
"ebaro"
))
def
get_econs
(
self
):
"""Calculates the conserved energy quantity for the constant pressure
ensemble.
"""
return
NVTEnsemble
.
get_econs
(
self
)
+
self
.
barostat
.
ebaro
def
step
(
self
):
"""NPT time step.
Note that the barostat only propagates the centroid coordinates. If this
approximation is made a centroid virial pressure and stress estimator can
be defined, so this gives the best statistical convergence. This is
allowed as the normal mode propagation is approximately unaffected
by volume fluctuations as long as the system box is much larger than
the radius of gyration of the ring polymers.
"""
self
.
ttime
=
-
time
.
time
()
self
.
thermostat
.
step
()
self
.
barostat
.
thermostat
.
step
()
self
.
rmcom
()
self
.
ttime
+=
time
.
time
()
self
.
ptime
=
-
time
.
time
()
self
.
barostat
.
pstep
()
self
.
ptime
+=
time
.
time
()
self
.
qtime
=
-
time
.
time
()
self
.
barostat
.
qcstep
()
self
.
nm
.
free_qstep
()
self
.
qtime
+=
time
.
time
()
self
.
ptime
-=
time
.
time
()
self
.
barostat
.
pstep
()
self
.
ptime
+=
time
.
time
()
self
.
ttime
-=
time
.
time
()
self
.
barostat
.
thermostat
.
step
()
self
.
thermostat
.
step
()
self
.
rmcom
()
self
.
ttime
+=
time
.
time
()
class
ReplayEnsemble
(
Ensemble
):
"""Ensemble object that just loads snapshots from an external file in sequence.
Has the relevant conserved quantity and normal mode propagator for the
constant energy ensemble. Note that a temperature of some kind must be
defined so that the spring potential can be calculated.
Attributes:
intraj: The input trajectory file.
ptime: The time taken in updating the velocities.
qtime: The time taken in updating the positions.
ttime: The time taken in applying the thermostat steps.
Depend objects:
econs: Conserved energy quantity. Depends on the bead kinetic and
potential energy, and the spring potential energy.
"""
def
__init__
(
self
,
dt
,
temp
,
fixcom
=
False
,
intraj
=
None
):
"""Initialises ReplayEnsemble.
Args:
dt: The simulation timestep.
temp: The system temperature.
fixcom: An optional boolean which decides whether the centre of mass
motion will be constrained or not. Defaults to False.
intraj: The input trajectory file.
"""
super
(
ReplayEnsemble
,
self
)
.
__init__
(
dt
=
dt
,
temp
=
temp
,
fixcom
=
fixcom
)
if
intraj
==
None
:
raise
ValueError
(
"Must provide an initialized InitFile object to read trajectory from"
)
self
.
intraj
=
intraj
if
intraj
.
mode
==
"manual"
:
raise
ValueError
(
"Replay can only read from PDB or XYZ files -- or a single frame from a CHK file"
)
self
.
rfile
=
open
(
self
.
intraj
.
value
,
"r"
)
def
step
(
self
):
"""Does one simulation time step."""
self
.
ptime
=
self
.
ttime
=
0
self
.
qtime
=
-
time
.
time
()
try
:
if
(
self
.
intraj
.
mode
==
"xyz"
):
for
b
in
self
.
beads
:
myatoms
=
read_xyz
(
self
.
rfile
)
myatoms
.
q
*=
unit_to_internal
(
"length"
,
self
.
intraj
.
units
,
1.0
)
b
.
q
[:]
=
myatoms
.
q
elif
(
self
.
intraj
.
mode
==
"pdb"
):
for
b
in
self
.
beads
:
myatoms
,
mycell
=
read_pdb
(
self
.
rfile
)
myatoms
.
q
*=
unit_to_internal
(
"length"
,
self
.
intraj
.
units
,
1.0
)
mycell
.
h
*=
unit_to_internal
(
"length"
,
self
.
intraj
.
units
,
1.0
)
b
.
q
[:]
=
myatoms
.
q
self
.
cell
.
h
[:]
=
mycell
.
h
elif
(
self
.
intraj
.
mode
==
"chk"
or
self
.
intraj
.
mode
==
"checkpoint"
):
# reads configuration from a checkpoint file
xmlchk
=
xml_parse_file
(
self
.
rfile
)
# Parses the file.
from
ipi.inputs.simulation
import
InputSimulation
simchk
=
InputSimulation
()
simchk
.
parse
(
xmlchk
.
fields
[
0
][
1
])
mycell
=
simchk
.
cell
.
fetch
()
mybeads
=
simchk
.
beads
.
fetch
()
self
.
cell
.
h
[:]
=
mycell
.
h
self
.
beads
.
q
[:]
=
mybeads
.
q
softexit
.
trigger
(
" # Read single checkpoint"
)
except
EOFError
:
softexit
.
trigger
(
" # Finished reading re-run trajectory"
)
self
.
qtime
+=
time
.
time
()
Event Timeline
Log In to Comment