1 """Contains the classes that deal with the different dynamics required in
2 different types of ensembles.
4 Copyright (C) 2013, Joshua More and Michele Ceriotti
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http.//www.gnu.org/licenses/>.
20 Holds the algorithms required for normal mode propagators, and the objects to
21 do the constant temperature and pressure algorithms. Also calculates the
22 appropriate conserved energy quantity for the ensemble of choice.
25 Ensemble: Base ensemble class with generic methods and attributes.
26 NVEEnsemble: Deals with constant energy dynamics.
27 NVTEnsemble: Deals with constant temperature dynamics.
28 NPTEnsemble: Deals with constant pressure dynamics.
29 ReplayEnsemble: Takes a trajectory, and simply sets the atom positions to
30 match it, rather than doing dynamics. In this way new properties can
31 be calculated on an old simulation, without having to rerun it from
35 __all__
= ['Ensemble', 'NVEEnsemble', 'NVTEnsemble', 'NPTEnsemble', 'ReplayEnsemble']
40 from ipi
.utils
.depend
import *
41 from ipi
.utils
import units
42 from ipi
.utils
.softexit
import softexit
43 from ipi
.utils
.io
.io_xyz
import read_xyz
44 from ipi
.utils
.io
.io_pdb
import read_pdb
45 from ipi
.utils
.io
.io_xml
import xml_parse_file
46 from ipi
.utils
.units
import Constants
, unit_to_internal
47 from ipi
.inputs
.thermostats
import InputThermo
48 from ipi
.inputs
.barostats
import InputBaro
49 from ipi
.engine
.thermostats
import *
50 from ipi
.engine
.barostats
import *
53 class Ensemble(dobject
):
54 """Base ensemble class.
56 Gives the standard methods and attributes needed in all the
60 beads: A beads object giving the atoms positions.
61 cell: A cell object giving the system box.
62 forces: A forces object giving the virial and the forces acting on
64 prng: A random number generator object.
65 nm: An object which does the normal modes transformation.
66 fixcom: A boolean which decides whether the centre of mass
67 motion will be constrained or not.
70 econs: The conserved energy quantity appropriate to the given
71 ensemble. Depends on the various energy terms which make it up,
72 which are different depending on the ensemble.
73 temp: The system temperature.
74 dt: The timestep for the algorithms.
75 ntemp: The simulation temperature. Will be nbeads times higher than
76 the system temperature as PIMD calculations are done at this
77 effective classical temperature.
80 def __init__(self
, dt
, temp
, fixcom
=False):
81 """Initialises Ensemble.
84 dt: The timestep of the simulation algorithms.
85 temp: The temperature.
86 fixcom: An optional boolean which decides whether the centre of mass
87 motion will be constrained or not. Defaults to False.
90 dset(self
, "econs", depend_value(name
='econs', func
=self
.get_econs
))
91 dset(self
, "temp", depend_value(name
='temp', value
=temp
))
92 dset(self
, "dt", depend_value(name
='dt', value
=dt
))
96 def bind(self
, beads
, nm
, cell
, bforce
, prng
):
97 """Binds beads, cell, bforce and prng to the ensemble.
99 This takes a beads object, a cell object, a forcefield object and a
100 random number generator object and makes them members of the ensemble.
101 It also then creates the objects that will hold the data needed in the
102 ensemble algorithms and the dependency network. Note that the conserved
103 quantity is defined in the init, but as each ensemble has a different
104 conserved quantity the dependencies are defined in bind.
107 beads: The beads object from whcih the bead positions are taken.
108 nm: A normal modes object used to do the normal modes transformation.
109 cell: The cell object from which the system box is taken.
110 bforce: The forcefield object from which the force and virial are
112 prng: The random number generator object which controls random number
116 # store local references to the different bits of the simulation
123 # n times the temperature
124 dset(self
,"ntemp", depend_value(name
='ntemp',func
=self
.get_ntemp
,
125 dependencies
=[dget(self
,"temp")]))
127 # dependencies of the conserved quantity
128 dget(self
,"econs").add_dependency(dget(self
.beads
, "kin"))
129 dget(self
,"econs").add_dependency(dget(self
.forces
, "pot"))
130 dget(self
,"econs").add_dependency(dget(self
.beads
, "vpath"))
134 """Returns the PI simulation temperature (P times the physical T)."""
136 return self
.temp
*self
.beads
.nbeads
140 """Dummy momenta propagator which does nothing."""
145 """Dummy centroid position propagator which does nothing."""
150 """Dummy simulation time step which does nothing."""
155 """Calculates the conserved energy quantity for constant energy
159 return self
.beads
.vpath
*self
.nm
.omegan2
+ self
.nm
.kin
+ self
.forces
.pot
162 class NVEEnsemble(Ensemble
):
163 """Ensemble object for constant energy simulations.
165 Has the relevant conserved quantity and normal mode propagator for the
166 constant energy ensemble. Note that a temperature of some kind must be
167 defined so that the spring potential can be calculated.
170 ptime: The time taken in updating the velocities.
171 qtime: The time taken in updating the positions.
172 ttime: The time taken in applying the thermostat steps.
175 econs: Conserved energy quantity. Depends on the bead kinetic and
176 potential energy, and the spring potential energy.
179 def __init__(self
, dt
, temp
, fixcom
=False):
180 """Initialises NVEEnsemble.
183 dt: The simulation timestep.
184 temp: The system temperature.
185 fixcom: An optional boolean which decides whether the centre of mass
186 motion will be constrained or not. Defaults to False.
189 super(NVEEnsemble
,self
).__init
__(dt
=dt
,temp
=temp
, fixcom
=fixcom
)
192 """This removes the centre of mass contribution to the kinetic energy.
194 Calculates the centre of mass momenta, then removes the mass weighted
195 contribution from each atom. If the ensemble defines a thermostat, then
196 the contribution to the conserved quantity due to this subtraction is
197 added to the thermostat heat energy, as it is assumed that the centre of
198 mass motion is due to the thermostat.
200 If there is a choice of thermostats, the thermostat
201 connected to the centroid is chosen.
205 pcom
= np
.zeros(3,float);
207 na3
= self
.beads
.natoms
*3
208 nb
= self
.beads
.nbeads
209 p
= depstrip(self
.beads
.p
)
210 m
= depstrip(self
.beads
.m3
)[:,0:na3
:3]
214 pcom
[i
] = p
[:,i
:na3
:3].sum()
216 if hasattr(self
,"thermostat"):
217 if hasattr(self
.thermostat
, "_thermos"):
218 self
.thermostat
._thermos
[0].ethermo
+= np
.dot(pcom
,pcom
)/(2.0*M
*nb
)
220 self
.thermostat
.ethermo
+= np
.dot(pcom
,pcom
)/(2.0*M
*nb
)
222 # subtracts COM _velocity_
225 self
.beads
.p
[:,i
:na3
:3] -= m
*pcom
[i
]
228 """Velocity Verlet momenta propagator."""
230 self
.beads
.p
+= depstrip(self
.forces
.f
)*(self
.dt
*0.5)
233 """Velocity Verlet centroid position propagator."""
235 self
.nm
.qnm
[0,:] += depstrip(self
.nm
.pnm
)[0,:]/depstrip(self
.beads
.m3
)[0]*self
.dt
238 """Does one simulation time step."""
240 self
.ptime
= -time
.time()
242 self
.ptime
+= time
.time()
244 self
.qtime
= -time
.time()
248 self
.qtime
+= time
.time()
250 self
.ptime
-= time
.time()
252 self
.ptime
+= time
.time()
254 self
.ttime
= -time
.time()
256 self
.ttime
+= time
.time()
259 class NVTEnsemble(NVEEnsemble
):
260 """Ensemble object for constant temperature simulations.
262 Has the relevant conserved quantity and normal mode propagator for the
263 constant temperature ensemble. Contains a thermostat object containing the
264 algorithms to keep the temperature constant.
267 thermostat: A thermostat object to keep the temperature constant.
270 econs: Conserved energy quantity. Depends on the bead kinetic and
271 potential energy, the spring potential energy and the heat
272 transferred to the thermostat.
275 def __init__(self
, dt
, temp
, thermostat
=None, fixcom
=False):
276 """Initialises NVTEnsemble.
279 dt: The simulation timestep.
280 temp: The system temperature.
281 thermostat: A thermostat object to keep the temperature constant.
282 Defaults to Thermostat()
283 fixcom: An optional boolean which decides whether the centre of mass
284 motion will be constrained or not. Defaults to False.
287 super(NVTEnsemble
,self
).__init
__(dt
=dt
,temp
=temp
, fixcom
=fixcom
)
289 if thermostat
is None:
290 self
.thermostat
= Thermostat()
292 self
.thermostat
= thermostat
294 def bind(self
, beads
, nm
, cell
, bforce
, prng
):
295 """Binds beads, cell, bforce and prng to the ensemble.
297 This takes a beads object, a cell object, a forcefield object and a
298 random number generator object and makes them members of the ensemble.
299 It also then creates the objects that will hold the data needed in the
300 ensemble algorithms and the dependency network. Also note that the
301 thermostat timestep and temperature are defined relative to the system
302 temperature, and the the thermostat temperature is held at the
303 higher simulation temperature, as is appropriate.
306 beads: The beads object from whcih the bead positions are taken.
307 nm: A normal modes object used to do the normal modes transformation.
308 cell: The cell object from which the system box is taken.
309 bforce: The forcefield object from which the force and virial are
311 prng: The random number generator object which controls random number
315 super(NVTEnsemble
,self
).bind(beads
, nm
, cell
, bforce
, prng
)
320 # first makes sure that the thermostat has the correct temperature, then proceed with binding it.
321 deppipe(self
,"ntemp", self
.thermostat
,"temp")
322 deppipe(self
,"dt", self
.thermostat
, "dt")
324 #decides whether the thermostat will work in the normal mode or
325 #the bead representation.
326 if isinstance(self
.thermostat
,ThermoNMGLE
) or isinstance(self
.thermostat
,ThermoNMGLEG
) or isinstance(self
.thermostat
,ThermoPILE_L
) or isinstance(self
.thermostat
,ThermoPILE_G
):
327 self
.thermostat
.bind(nm
=self
.nm
,prng
=prng
,fixdof
=fixdof
)
329 self
.thermostat
.bind(beads
=self
.beads
,prng
=prng
, fixdof
=fixdof
)
331 dget(self
,"econs").add_dependency(dget(self
.thermostat
, "ethermo"))
334 """Does one simulation time step."""
336 self
.ttime
= -time
.time()
337 self
.thermostat
.step()
339 self
.ttime
+= time
.time()
341 self
.ptime
= -time
.time()
343 self
.ptime
+= time
.time()
345 self
.qtime
= -time
.time()
348 self
.qtime
+= time
.time()
350 self
.ptime
-= time
.time()
352 self
.ptime
+= time
.time()
354 self
.ttime
-= time
.time()
355 self
.thermostat
.step()
357 self
.ttime
+= time
.time()
360 """Calculates the conserved energy quantity for constant temperature
364 return NVEEnsemble
.get_econs(self
) + self
.thermostat
.ethermo
367 class NPTEnsemble(NVTEnsemble
):
368 """Ensemble object for constant pressure simulations.
370 Has the relevant conserved quantity and normal mode propagator for the
371 constant pressure ensemble. Contains a thermostat object containing the
372 algorithms to keep the temperature constant, and a barostat to keep the
376 barostat: A barostat object to keep the pressure constant.
379 econs: Conserved energy quantity. Depends on the bead and cell kinetic
380 and potential energy, the spring potential energy, the heat
381 transferred to the beads and cell thermostat, the temperature and
383 pext: External pressure.
386 def __init__(self
, dt
, temp
, pext
, thermostat
=None, barostat
=None, fixcom
=False):
387 """Initialises NPTEnsemble.
390 dt: The simulation timestep.
391 temp: The system temperature.
392 pext: The external pressure.
393 thermostat: A thermostat object to keep the temperature constant.
394 Defaults to Thermostat().
395 barostat: A barostat object to keep the pressure constant.
396 Defaults to Barostat().
397 fixcom: An optional boolean which decides whether the centre of mass
398 motion will be constrained or not. Defaults to False.
401 super(NPTEnsemble
,self
).__init
__(dt
, temp
, thermostat
, fixcom
=fixcom
)
403 self
.barostat
= Barostat()
405 self
.barostat
= barostat
407 dset(self
,"pext",depend_value(name
='pext'))
410 else: self
.pext
= 0.0
413 def bind(self
, beads
, nm
, cell
, bforce
, prng
):
414 """Binds beads, cell, bforce and prng to the ensemble.
416 This takes a beads object, a cell object, a forcefield object and a
417 random number generator object and makes them members of the ensemble.
418 It also then creates the objects that will hold the data needed in the
419 ensemble algorithms and the dependency network. Also note that the cell
420 thermostat timesteps and temperatures are defined relative to the system
421 temperature, and the the thermostat temperatures are held at the
422 higher simulation temperature, as is appropriate.
425 beads: The beads object from whcih the bead positions are taken.
426 nm: A normal modes object used to do the normal modes transformation.
427 cell: The cell object from which the system box is taken.
428 bforce: The forcefield object from which the force and virial are
430 prng: The random number generator object which controls random number
439 super(NPTEnsemble
,self
).bind(beads
, nm
, cell
, bforce
, prng
)
440 self
.barostat
.bind(beads
, nm
, cell
, bforce
, prng
=prng
, fixdof
=fixdof
)
443 deppipe(self
,"ntemp", self
.barostat
, "temp")
444 deppipe(self
,"dt", self
.barostat
, "dt")
445 deppipe(self
,"pext", self
.barostat
, "pext")
446 dget(self
,"econs").add_dependency(dget(self
.barostat
, "ebaro"))
449 """Calculates the conserved energy quantity for the constant pressure
453 return NVTEnsemble
.get_econs(self
) + self
.barostat
.ebaro
458 Note that the barostat only propagates the centroid coordinates. If this
459 approximation is made a centroid virial pressure and stress estimator can
460 be defined, so this gives the best statistical convergence. This is
461 allowed as the normal mode propagation is approximately unaffected
462 by volume fluctuations as long as the system box is much larger than
463 the radius of gyration of the ring polymers.
466 self
.ttime
= -time
.time()
467 self
.thermostat
.step()
468 self
.barostat
.thermostat
.step()
470 self
.ttime
+= time
.time()
472 self
.ptime
= -time
.time()
473 self
.barostat
.pstep()
474 self
.ptime
+= time
.time()
476 self
.qtime
= -time
.time()
477 self
.barostat
.qcstep()
479 self
.qtime
+= time
.time()
481 self
.ptime
-= time
.time()
482 self
.barostat
.pstep()
483 self
.ptime
+= time
.time()
485 self
.ttime
-= time
.time()
486 self
.barostat
.thermostat
.step()
487 self
.thermostat
.step()
489 self
.ttime
+= time
.time()
492 class ReplayEnsemble(Ensemble
):
493 """Ensemble object that just loads snapshots from an external file in sequence.
495 Has the relevant conserved quantity and normal mode propagator for the
496 constant energy ensemble. Note that a temperature of some kind must be
497 defined so that the spring potential can be calculated.
500 intraj: The input trajectory file.
501 ptime: The time taken in updating the velocities.
502 qtime: The time taken in updating the positions.
503 ttime: The time taken in applying the thermostat steps.
506 econs: Conserved energy quantity. Depends on the bead kinetic and
507 potential energy, and the spring potential energy.
510 def __init__(self
, dt
, temp
, fixcom
=False, intraj
=None):
511 """Initialises ReplayEnsemble.
514 dt: The simulation timestep.
515 temp: The system temperature.
516 fixcom: An optional boolean which decides whether the centre of mass
517 motion will be constrained or not. Defaults to False.
518 intraj: The input trajectory file.
521 super(ReplayEnsemble
,self
).__init
__(dt
=dt
,temp
=temp
,fixcom
=fixcom
)
523 raise ValueError("Must provide an initialized InitFile object to read trajectory from")
525 if intraj
.mode
== "manual":
526 raise ValueError("Replay can only read from PDB or XYZ files -- or a single frame from a CHK file")
527 self
.rfile
= open(self
.intraj
.value
,"r")
530 """Does one simulation time step."""
532 self
.ptime
= self
.ttime
= 0
533 self
.qtime
= -time
.time()
536 if (self
.intraj
.mode
== "xyz"):
538 myatoms
= read_xyz(self
.rfile
)
539 myatoms
.q
*= unit_to_internal("length",self
.intraj
.units
,1.0)
541 elif (self
.intraj
.mode
== "pdb"):
543 myatoms
, mycell
= read_pdb(self
.rfile
)
544 myatoms
.q
*= unit_to_internal("length",self
.intraj
.units
,1.0)
545 mycell
.h
*= unit_to_internal("length",self
.intraj
.units
,1.0)
547 self
.cell
.h
[:] = mycell
.h
548 elif (self
.intraj
.mode
== "chk" or self
.intraj
.mode
== "checkpoint"):
549 # reads configuration from a checkpoint file
550 xmlchk
= xml_parse_file(self
.rfile
) # Parses the file.
552 from ipi
.inputs
.simulation
import InputSimulation
553 simchk
= InputSimulation()
554 simchk
.parse(xmlchk
.fields
[0][1])
555 mycell
= simchk
.cell
.fetch()
556 mybeads
= simchk
.beads
.fetch()
557 self
.cell
.h
[:] = mycell
.h
558 self
.beads
.q
[:] = mybeads
.q
559 softexit
.trigger(" # Read single checkpoint")
561 softexit
.trigger(" # Finished reading re-run trajectory")
563 self
.qtime
+= time
.time()