def __init__(self, timestep, mode="nve", thermostat=None, barostat=None, fixcom=False, fixatoms=None, nmts=None): """Initialises a "dynamics" motion object. Args: dt: The timestep of the simulation algorithms. fixcom: An optional boolean which decides whether the centre of mass motion will be constrained or not. Defaults to False. """ super(Dynamics, self).__init__(fixcom=fixcom, fixatoms=fixatoms) dself = dd(self) dself.dt = depend_value(name='dt', value=timestep) if thermostat is None: self.thermostat = Thermostat() else: self.thermostat = thermostat if barostat is None: self.barostat = Barostat() else: self.barostat = barostat if nmts is np.zeros(0, int): self.nmts = np.asarray([1], int) elif nmts is None or len(nmts) == 0: self.nmts = np.asarray([1], int) else: self.nmts = np.asarray(nmts) self.enstype = mode if self.enstype == "nve": self.integrator = NVEIntegrator() elif self.enstype == "nvt": self.integrator = NVTIntegrator() elif self.enstype == "npt": self.integrator = NPTIntegrator() elif self.enstype == "nst": self.integrator = NSTIntegrator() elif self.enstype == "mts": self.integrator = MTSIntegrator() elif self.enstype == "sc": self.integrator = SCIntegrator() else: self.integrator = DummyIntegrator() self.fixcom = fixcom if fixatoms is None: self.fixatoms = np.zeros(0, int) else: self.fixatoms = fixatoms
def __init__(self, timestep, mode="nve", splitting="obabo", thermostat=None, barostat=None, fixcom=False, fixatoms=None, nmts=None): """Initialises a "dynamics" motion object. Args: dt: The timestep of the simulation algorithms. fixcom: An optional boolean which decides whether the centre of mass motion will be constrained or not. Defaults to False. """ super(Dynamics, self).__init__(fixcom=fixcom, fixatoms=fixatoms) dself = dd(self) # initialize time step. this is the master time step that covers a full time step dd(self).dt = depend_value(name='dt', value=timestep) if thermostat is None: self.thermostat = Thermostat() else: self.thermostat = thermostat if nmts is None or len(nmts) == 0: dd(self).nmts = depend_array(name="nmts", value=np.asarray([1], int)) else: dd(self).nmts = depend_array(name="nmts", value=np.asarray(nmts, int)) if barostat is None: self.barostat = Barostat() else: self.barostat = barostat self.enstype = mode if self.enstype == "nve": self.integrator = NVEIntegrator() elif self.enstype == "nvt": self.integrator = NVTIntegrator() elif self.enstype == "nvt-cc": self.integrator = NVTCCIntegrator() elif self.enstype == "npt": self.integrator = NPTIntegrator() elif self.enstype == "nst": self.integrator = NSTIntegrator() elif self.enstype == "sc": self.integrator = SCIntegrator() elif self.enstype == "scnpt": self.integrator = SCNPTIntegrator() else: self.integrator = DummyIntegrator() # splitting mode for the integrators dd(self).splitting = depend_value(name='splitting', value=splitting) # constraints self.fixcom = fixcom if fixatoms is None: self.fixatoms = np.zeros(0, int) else: self.fixatoms = fixatoms
def __init__(self, timestep, mode="nve", splitting="obabo", thermostat=None, barostat=None, fixcom=False, fixatoms=None, nmts=None): """Initialises a "dynamics" motion object. Args: dt: The timestep of the simulation algorithms. fixcom: An optional boolean which decides whether the centre of mass motion will be constrained or not. Defaults to False. """ super(Dynamics, self).__init__(fixcom=fixcom, fixatoms=fixatoms) dself = dd(self) # initialize time step. this is the master time step that covers a full time step dd(self).dt = depend_value(name='dt', value=timestep) if thermostat is None: self.thermostat = Thermostat() else: self.thermostat = thermostat if nmts is None or len(nmts) == 0: dd(self).nmts = depend_array(name="nmts", value=np.asarray([1], int)) else: dd(self).nmts = depend_array(name="nmts", value=np.asarray(nmts, int)) if barostat is None: self.barostat = Barostat() else: self.barostat = barostat self.enstype = mode if self.enstype == "nve": self.integrator = NVEIntegrator() elif self.enstype == "nvt": self.integrator = NVTIntegrator() elif self.enstype == "npt": self.integrator = NPTIntegrator() elif self.enstype == "nst": self.integrator = NSTIntegrator() elif self.enstype == "sc": self.integrator = SCIntegrator() elif self.enstype == "scnpt": self.integrator = SCNPTIntegrator() else: self.integrator = DummyIntegrator() # splitting mode for the integrators dd(self).splitting = depend_value(name='splitting', value=splitting) # constraints self.fixcom = fixcom if fixatoms is None: self.fixatoms = np.zeros(0, int) else: self.fixatoms = fixatoms
class Dynamics(Motion): """self (path integral) molecular dynamics class. Gives the standard methods and attributes needed in all the dynamics 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. 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.he 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, timestep, mode="nve", thermostat=None, barostat=None, fixcom=False, fixatoms=None, nmts=None): """Initialises a "dynamics" motion object. Args: dt: The timestep of the simulation algorithms. fixcom: An optional boolean which decides whether the centre of mass motion will be constrained or not. Defaults to False. """ super(Dynamics, self).__init__(fixcom=fixcom, fixatoms=fixatoms) dself = dd(self) dself.dt = depend_value(name='dt', value=timestep) if thermostat is None: self.thermostat = Thermostat() else: self.thermostat = thermostat if barostat is None: self.barostat = Barostat() else: self.barostat = barostat if nmts is np.zeros(0, int): self.nmts = np.asarray([1], int) elif nmts is None or len(nmts) == 0: self.nmts = np.asarray([1], int) else: self.nmts = np.asarray(nmts) self.enstype = mode if self.enstype == "nve": self.integrator = NVEIntegrator() elif self.enstype == "nvt": self.integrator = NVTIntegrator() elif self.enstype == "npt": self.integrator = NPTIntegrator() elif self.enstype == "nst": self.integrator = NSTIntegrator() elif self.enstype == "mts": self.integrator = MTSIntegrator() elif self.enstype == "sc": self.integrator = SCIntegrator() else: self.integrator = DummyIntegrator() self.fixcom = fixcom if fixatoms is None: self.fixatoms = np.zeros(0, int) else: self.fixatoms = fixatoms def bind(self, ens, beads, nm, cell, bforce, prng): """Binds ensemble beads, cell, bforce, and prng to the dynamics. 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. """ super(Dynamics, self).bind(ens, beads, nm, cell, bforce, prng) dself = dd(self) # Checks if the number of mts levels is equal to the dimensionality of the mts weights. if (len(self.nmts) != self.forces.nmtslevels): raise ValueError("The number of mts levels for the integrator does not agree with the mts_weights of the force components.") # Binds integrators self.integrator.bind(self) dself = dd(self) # n times the temperature (for path integral partition function) dself.ntemp = depend_value(name='ntemp', func=self.get_ntemp, dependencies=[dd(self.ensemble).temp]) self.integrator.pconstraints() fixdof = len(self.fixatoms) * 3 * self.beads.nbeads if self.fixcom: fixdof += 3 # first makes sure that the thermostat has the correct temperature, then proceed with binding it. dpipe(dself.ntemp, dd(self.thermostat).temp) dpipe(dself.dt, dd(self.thermostat).dt) # the free ring polymer propagator is called in the inner loop, so propagation time should be redefined accordingly. self.inmts = 1 for mk in self.nmts: self.inmts *= mk dself.deltat = depend_value(name="deltat", func=(lambda: self.dt / self.inmts), dependencies=[dself.dt]) dpipe(dself.deltat, dd(self.nm).dt) # depending on the kind, the thermostat might work in the normal mode or the bead representation. self.thermostat.bind(beads=self.beads, nm=self.nm, prng=prng, fixdof=fixdof) dbarostat = dd(self.barostat) dpipe(dself.ntemp, dbarostat.temp) dpipe(dself.dt, dbarostat.dt) dpipe(dd(self.ensemble).pext, dbarostat.pext) dpipe(dd(self.ensemble).stressext, dbarostat.stressext) #!TODO the barostat should also be connected to the bias stress self.barostat.bind(beads, nm, cell, bforce, prng=prng, fixdof=fixdof, bias=ens.bias) self.ensemble.add_econs(dd(self.thermostat).ethermo) self.ensemble.add_econs(dd(self.barostat).ebaro) # adds potential and kinetic energy for the barostat to the ensemble self.ensemble.add_xlpot(dd(self.barostat).pot) self.ensemble.add_xlkin(dd(self.barostat).kin) #!TODO THOROUGH CLEAN-UP AND CHECK # if self.enstype in ["nvt", "npt", "nst"]: if self.enstype == "nvt" or self.enstype == "npt" or self.enstype == "nst": if self.ensemble.temp < 0: raise ValueError("Negative or unspecified temperature for a constant-T integrator") if self.enstype == "npt": if type(self.barostat) is Barostat: raise ValueError("The barostat and its mode have to be specified for constant-p integrators") if self.ensemble.pext < 0: raise ValueError("Negative or unspecified pressure for a constant-p integrator") elif self.enstype == "nst": if np.trace(self.ensemble.stressext) < 0: raise ValueError("Negative or unspecified stress for a constant-s integrator") def get_ntemp(self): """Returns the PI simulation temperature (P times the physical T).""" return self.ensemble.temp * self.beads.nbeads def step(self, step=None): self.integrator.step(step)
def __init__( self, timestep, mode="nve", splitting="obabo", thermostat=None, barostat=None, fixcom=False, fixatoms=None, nmts=None, nsteps_geo=1, nsteps_o=1, constraint_list=[], csolver=None, ): """Initialises a "dynamics" motion object. Args: dt: The timestep of the simulation algorithms. fixcom: An optional boolean which decides whether the centre of mass motion will be constrained or not. Defaults to False. """ super(Dynamics, self).__init__(fixcom=fixcom, fixatoms=fixatoms) dd(self).dt = depend_value(name="dt", value=timestep) if thermostat is None: self.thermostat = Thermostat() else: self.thermostat = thermostat if nmts is None or len(nmts) == 0: dd(self).nmts = depend_array(name="nmts", value=np.asarray([1], int)) else: dd(self).nmts = depend_array(name="nmts", value=np.asarray(nmts, int)) if barostat is None: self.barostat = Barostat() else: self.barostat = barostat self.enstype = mode if self.enstype == "nve": self.integrator = NVEConstrainedIntegrator() elif self.enstype == "nvt": self.integrator = NVTConstrainedIntegrator() else: ValueError( "{:s} is not a valid ensemble for constrained dynamics".format( self.enstype)) # splitting mode for the integrators dd(self).splitting = depend_value(name="splitting", value=splitting) # The list of constraints coming from the input is an actual list of independent # constraints, and should be treated as such if constraint_list is not None: self.constraint_list = constraint_list has_eckart = False for constr in self.constraint_list: if isinstance(constr, ConstraintList): for c in constr.constraint_list: if isinstance(c, ConstraintList): raise ValueError( "Cannot have nested constraint lists!") elif isinstance(c, EckartConstraint): has_eckart = True else: if isinstance(constr, EckartConstraint): has_eckart = True self.fixcom = fixcom # If only some of the molecules have Eckart enforced, this will clash # with fixing the overall CoM; if *all* the molecules have Eckart # enforced, then cell CoM already fixed; in either case, raise # an error if fixcom is True and any of the constraints are Eckart. if self.fixcom and has_eckart: raise ValueError( "Cannot simultaneously fix cell CoM and enforce Eckart constraints!" ) if fixatoms is None: self.fixatoms = np.zeros(0, int) else: self.fixatoms = fixatoms if len(self.fixatoms) > 0: raise ValueError("Cannot fix atoms together with constrained MD") if csolver is None: self.csolver = ConstraintSolver(self.constraint_list, tolerance=0.0001, maxit=10000, norm_order=2) else: if csolver["norm_order"] == -1: norm_order = float("inf") else: norm_order = csolver["norm_order"] self.csolver = ConstraintSolver( self.constraint_list, tolerance=csolver["tolerance"], maxit=csolver["maxit"], norm_order=norm_order, ) # parameters of the geodesic integrator. will probably never need # to be changed dynamically, so for the moment we don't consider them depend objects self.nsteps_geo = nsteps_geo self.nsteps_o = nsteps_o
class Dynamics(Motion): """self (path integral) molecular dynamics class. Gives the standard methods and attributes needed in all the dynamics 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. 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.he 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, timestep, mode="nve", splitting="obabo", thermostat=None, barostat=None, fixcom=False, fixatoms=None, nmts=None): """Initialises a "dynamics" motion object. Args: dt: The timestep of the simulation algorithms. fixcom: An optional boolean which decides whether the centre of mass motion will be constrained or not. Defaults to False. """ super(Dynamics, self).__init__(fixcom=fixcom, fixatoms=fixatoms) dself = dd(self) # initialize time step. this is the master time step that covers a full time step dd(self).dt = depend_value(name='dt', value=timestep) if thermostat is None: self.thermostat = Thermostat() else: self.thermostat = thermostat if nmts is None or len(nmts) == 0: dd(self).nmts = depend_array(name="nmts", value=np.asarray([1], int)) else: dd(self).nmts = depend_array(name="nmts", value=np.asarray(nmts, int)) if barostat is None: self.barostat = Barostat() else: self.barostat = barostat self.enstype = mode if self.enstype == "nve": self.integrator = NVEIntegrator() elif self.enstype == "nvt": self.integrator = NVTIntegrator() elif self.enstype == "npt": self.integrator = NPTIntegrator() elif self.enstype == "nst": self.integrator = NSTIntegrator() elif self.enstype == "sc": self.integrator = SCIntegrator() elif self.enstype == "scnpt": self.integrator = SCNPTIntegrator() else: self.integrator = DummyIntegrator() # splitting mode for the integrators dd(self).splitting = depend_value(name='splitting', value=splitting) # constraints self.fixcom = fixcom if fixatoms is None: self.fixatoms = np.zeros(0, int) else: self.fixatoms = fixatoms def bind(self, ens, beads, nm, cell, bforce, prng): """Binds ensemble beads, cell, bforce, and prng to the dynamics. 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. """ super(Dynamics, self).bind(ens, beads, nm, cell, bforce, prng) # Checks if the number of mts levels is equal to the dimensionality of the mts weights. if (len(self.nmts) != self.forces.nmtslevels): raise ValueError("The number of mts levels for the integrator does not agree with the mts_weights of the force components.") # Strips off depend machinery for easier referencing. dself = dd(self) dthrm = dd(self.thermostat) dbaro = dd(self.barostat) dnm = dd(self.nm) dens = dd(self.ensemble) # n times the temperature (for path integral partition function) dself.ntemp = depend_value(name='ntemp', func=self.get_ntemp, dependencies=[dens.temp]) # fixed degrees of freedom count fixdof = len(self.fixatoms) * 3 * self.beads.nbeads if self.fixcom: fixdof += 3 # first makes sure that the thermostat has the correct temperature and timestep, then proceeds with binding it. dpipe(dself.ntemp, dthrm.temp) # depending on the kind, the thermostat might work in the normal mode or the bead representation. self.thermostat.bind(beads=self.beads, nm=self.nm, prng=prng, fixdof=fixdof) # first makes sure that the barostat has the correct stress andf timestep, then proceeds with binding it. dpipe(dself.ntemp, dbaro.temp) dpipe(dens.pext, dbaro.pext) dpipe(dens.stressext, dbaro.stressext) self.barostat.bind(beads, nm, cell, bforce, prng=prng, fixdof=fixdof, nmts=len(self.nmts)) # now that the timesteps are decided, we proceed to bind the integrator. self.integrator.bind(self) self.ensemble.add_econs(dthrm.ethermo) self.ensemble.add_econs(dbaro.ebaro) # adds the potential, kinetic enrgy and the cell jacobian to the ensemble self.ensemble.add_xlpot(dbaro.pot) self.ensemble.add_xlpot(dbaro.cell_jacobian) self.ensemble.add_xlkin(dbaro.kin) # applies constraints immediately after initialization. self.integrator.pconstraints() #!TODO THOROUGH CLEAN-UP AND CHECK if self.enstype == "nvt" or self.enstype == "npt" or self.enstype == "nst": if self.ensemble.temp < 0: raise ValueError("Negative or unspecified temperature for a constant-T integrator") if self.enstype == "npt": if type(self.barostat) is Barostat: raise ValueError("The barostat and its mode have to be specified for constant-p integrators") if self.ensemble.pext < 0: raise ValueError("Negative or unspecified pressure for a constant-p integrator") elif self.enstype == "nst": if np.trace(self.ensemble.stressext) < 0: raise ValueError("Negative or unspecified stress for a constant-s integrator") def get_ntemp(self): """Returns the PI simulation temperature (P times the physical T).""" return self.ensemble.temp * self.beads.nbeads def step(self, step=None): self.integrator.step(step)
def __init__( self, timestep, mode="nve", splitting="obabo", thermostat=None, barostat=None, fixcom=False, fixatoms=None, nmts=None, ): """Initialises a "dynamics" motion object. Args: dt: The timestep of the simulation algorithms. fixcom: An optional boolean which decides whether the centre of mass motion will be constrained or not. Defaults to False. """ super(Dynamics, self).__init__(fixcom=fixcom, fixatoms=fixatoms) dself = dd(self) # noqa # initialize time step. this is the master time step that covers a full time step dd(self).dt = depend_value(name="dt", value=timestep) if thermostat is None: self.thermostat = Thermostat() else: if ( thermostat.__class__.__name__ is ("ThermoPILE_G" or "ThermoNMGLEG ") ) and (len(fixatoms) > 0): softexit.trigger( "!! Sorry, fixed atoms and global thermostat on the centroid not supported. Use a local thermostat. !!" ) self.thermostat = thermostat if nmts is None or len(nmts) == 0: dd(self).nmts = depend_array(name="nmts", value=np.asarray([1], int)) else: dd(self).nmts = depend_array(name="nmts", value=np.asarray(nmts, int)) if barostat is None: self.barostat = Barostat() else: self.barostat = barostat self.enstype = mode if self.enstype == "nve": self.integrator = NVEIntegrator() elif self.enstype == "nvt": self.integrator = NVTIntegrator() elif self.enstype == "nvt-cc": self.integrator = NVTCCIntegrator() elif self.enstype == "npt": self.integrator = NPTIntegrator() elif self.enstype == "nst": self.integrator = NSTIntegrator() elif self.enstype == "sc": self.integrator = SCIntegrator() elif self.enstype == "scnpt": self.integrator = SCNPTIntegrator() else: self.integrator = DummyIntegrator() # splitting mode for the integrators dd(self).splitting = depend_value(name="splitting", value=splitting) # constraints self.fixcom = fixcom if fixatoms is None: self.fixatoms = np.zeros(0, int) else: self.fixatoms = fixatoms
class Dynamics(Motion): """self (path integral) molecular dynamics class. Gives the standard methods and attributes needed in all the dynamics 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. 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.he 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, timestep, mode="nve", splitting="obabo", thermostat=None, barostat=None, fixcom=False, fixatoms=None, nmts=None, ): """Initialises a "dynamics" motion object. Args: dt: The timestep of the simulation algorithms. fixcom: An optional boolean which decides whether the centre of mass motion will be constrained or not. Defaults to False. """ super(Dynamics, self).__init__(fixcom=fixcom, fixatoms=fixatoms) dself = dd(self) # noqa # initialize time step. this is the master time step that covers a full time step dd(self).dt = depend_value(name="dt", value=timestep) if thermostat is None: self.thermostat = Thermostat() else: if ( thermostat.__class__.__name__ is ("ThermoPILE_G" or "ThermoNMGLEG ") ) and (len(fixatoms) > 0): softexit.trigger( "!! Sorry, fixed atoms and global thermostat on the centroid not supported. Use a local thermostat. !!" ) self.thermostat = thermostat if nmts is None or len(nmts) == 0: dd(self).nmts = depend_array(name="nmts", value=np.asarray([1], int)) else: dd(self).nmts = depend_array(name="nmts", value=np.asarray(nmts, int)) if barostat is None: self.barostat = Barostat() else: self.barostat = barostat self.enstype = mode if self.enstype == "nve": self.integrator = NVEIntegrator() elif self.enstype == "nvt": self.integrator = NVTIntegrator() elif self.enstype == "nvt-cc": self.integrator = NVTCCIntegrator() elif self.enstype == "npt": self.integrator = NPTIntegrator() elif self.enstype == "nst": self.integrator = NSTIntegrator() elif self.enstype == "sc": self.integrator = SCIntegrator() elif self.enstype == "scnpt": self.integrator = SCNPTIntegrator() else: self.integrator = DummyIntegrator() # splitting mode for the integrators dd(self).splitting = depend_value(name="splitting", value=splitting) # constraints self.fixcom = fixcom if fixatoms is None: self.fixatoms = np.zeros(0, int) else: self.fixatoms = fixatoms def get_fixdof(self): """Calculate the number of fixed degrees of freedom, required for temperature and pressure calculations. """ fixdof = len(self.fixatoms) * 3 * self.beads.nbeads if self.fixcom: fixdof += 3 return fixdof def bind(self, ens, beads, nm, cell, bforce, prng, omaker): """Binds ensemble beads, cell, bforce, and prng to the dynamics. 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 which 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(Dynamics, self).bind(ens, beads, nm, cell, bforce, prng, omaker) # Checks if the number of mts levels is equal to the dimensionality of the mts weights. if len(self.nmts) != self.forces.nmtslevels: raise ValueError( "The number of mts levels for the integrator does not agree with the mts_weights of the force components." ) # Strips off depend machinery for easier referencing. dself = dd(self) dthrm = dd(self.thermostat) dbaro = dd(self.barostat) dnm = dd(self.nm) # noqa dens = dd(self.ensemble) # n times the temperature (for path integral partition function) dself.ntemp = depend_value( name="ntemp", func=self.get_ntemp, dependencies=[dens.temp] ) # fixed degrees of freedom count fixdof = self.get_fixdof() # first makes sure that the thermostat has the correct temperature and timestep, then proceeds with binding it. dpipe(dself.ntemp, dthrm.temp) # depending on the kind, the thermostat might work in the normal mode or the bead representation. self.thermostat.bind(beads=self.beads, nm=self.nm, prng=prng, fixdof=fixdof) # first makes sure that the barostat has the correct stress and timestep, then proceeds with binding it. dpipe(dself.ntemp, dbaro.temp) dpipe(dens.pext, dbaro.pext) dpipe(dens.stressext, dbaro.stressext) self.barostat.bind( beads, nm, cell, bforce, bias=self.ensemble.bias, prng=prng, fixdof=fixdof, nmts=len(self.nmts), ) # now that the timesteps are decided, we proceed to bind the integrator. self.integrator.bind(self) self.ensemble.add_econs(dthrm.ethermo) self.ensemble.add_econs(dbaro.ebaro) # adds the potential, kinetic energy and the cell Jacobian to the ensemble self.ensemble.add_xlpot(dbaro.pot) self.ensemble.add_xlpot(dbaro.cell_jacobian) self.ensemble.add_xlkin(dbaro.kin) # applies constraints immediately after initialization. self.integrator.pconstraints() # TODO THOROUGH CLEAN-UP AND CHECK if ( self.enstype == "nvt" or self.enstype == "nvt-cc" or self.enstype == "npt" or self.enstype == "nst" ): if self.ensemble.temp < 0: raise ValueError( "Negative or unspecified temperature for a constant-T integrator" ) if self.enstype == "npt": if type(self.barostat) is Barostat: raise ValueError( "The barostat and its mode have to be specified for constant-p integrators" ) if np.allclose(self.ensemble.pext, -12345): raise ValueError("Unspecified pressure for a constant-p integrator") elif self.enstype == "nst": if np.allclose(self.ensemble.stressext.diagonal(), -12345): raise ValueError("Unspecified stress for a constant-s integrator") def get_ntemp(self): """Returns the PI simulation temperature (P times the physical T).""" return self.ensemble.temp * self.beads.nbeads def step(self, step=None): """Advances the dynamics by one time step""" self.integrator.step(step) self.ensemble.time += self.dt # increments internal time