def __init__(self, motionlist=None): """Initialises MultiMotion. Args: fixcom: An optional boolean which decides whether the centre of mass motion will be constrained or not. Defaults to False. """ dself = dd(self) dself.dt = depend_value(name="dt", func=self.get_totdt) self.mlist = motionlist for m in self.mlist: dd(m).dt.add_dependant(dself.dt) a = ( # noqa self.dt ) # DON'T ASK WHY BUT IF YOU DON'T DO THAT WEAKREFS TO SELF.DT WILL BE INVALIDATED self.fixatoms = set(self.mlist[0].fixatoms) for m in self.mlist: self.fixatoms = self.fixatoms.intersection(m.fixatoms) self.fixatoms = list(self.fixatoms) self.fixcom = True # fixcom is true only if all movers are fixed for m in self.mlist: self.fixcom = self.fixcom and m.fixcom
def __init__( self, mode, syslist, fflist, outputs, prng, smotion=None, step=0, tsteps=1000, ttime=0, threads=False, ): """Initialises Simulation class. Args: mode: What kind of simulation is this syslist: A list of system objects fflist: A list of forcefield objects prng: A random number object. smotion: A "super-motion" class specifying what to do with different system replicas outputs: A list of output objects. step: An optional integer giving the current simulation time step. Defaults to 0. tsteps: An optional integer giving the total number of steps. Defaults to 1000. ttime: The simulation running time. Used on restart, to keep a cumulative total. """ info(" # Initializing simulation object ", verbosity.low) self.prng = prng self.mode = mode self.threading = threads dself = dd(self) self.syslist = syslist for s in syslist: s.prng = self.prng # bind the system's prng to self prng s.init.init_stage1(s) # TODO - does this have any meaning now that we introduce the smotion class? if self.mode == "md" and len(syslist) > 1: warning("Multiple systems will evolve independently in a '" + self.mode + "' simulation.") self.fflist = {} for f in fflist: self.fflist[f.name] = f self.outtemplate = outputs dself.step = depend_value(name="step", value=step) self.tsteps = tsteps self.ttime = ttime self.smotion = smotion self.chk = None self.rollback = True
def __init__(self, mode, syslist, fflist, outputs, prng, paratemp, step=0, tsteps=1000, ttime=0): """Initialises Simulation class. Args: mode: What kind of simulation is this syslist: A list of system objects fflist: A list of forcefield objects prng: A random number object. paratemp: A parallel tempering helper class. outputs: A list of output objects. step: An optional integer giving the current simulation time step. Defaults to 0. tsteps: An optional integer giving the total number of steps. Defaults to 1000. ttime: The simulation running time. Used on restart, to keep a cumulative total. """ info(" # Initializing simulation object ", verbosity.low) self.prng = prng self.mode = mode self.syslist = syslist for s in syslist: s.prng = self.prng # bind the system's prng to self prng s.init.init_stage1(s) if self.mode == "md" and len(syslist) > 1: warning("Multiple systems will evolve independently in a '" + self.mode + "' simulation.") self.fflist = {} for f in fflist: self.fflist[f.name] = f self.outtemplate = outputs dset(self, "step", depend_value(name="step", value=step)) self.tsteps = tsteps self.ttime = ttime self.paratemp = paratemp self.chk = None self.rollback = True
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) dset(self, "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 None: 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() else: self.integrator = DummyIntegrator() self.fixcom = fixcom if fixatoms is None: self.fixatoms = np.zeros(0, int) else: self.fixatoms = fixatoms
def __init__(self, fixcom=False, fixatoms=None): """Initialises Motion object. Args: fixcom: An optional boolean which decides whether the centre of mass motion will be constrained or not. Defaults to False. fixatoms: A list of atoms that should be held fixed to their initial positions. """ dset(self, "dt", depend_value(name="dt", value=0.0)) self.fixcom = fixcom if fixatoms is None: self.fixatoms = np.zeros(0, int) else: self.fixatoms = fixatoms
def __init__(self, mode, syslist, fflist, outputs, prng, smotion=None, step=0, tsteps=1000, ttime=0, threads=False): """Initialises Simulation class. Args: mode: What kind of simulation is this syslist: A list of system objects fflist: A list of forcefield objects prng: A random number object. smotion: A "super-motion" class specifying what to do with different system replicas outputs: A list of output objects. step: An optional integer giving the current simulation time step. Defaults to 0. tsteps: An optional integer giving the total number of steps. Defaults to 1000. ttime: The simulation running time. Used on restart, to keep a cumulative total. """ info(" # Initializing simulation object ", verbosity.low) self.prng = prng self.mode = mode self.threading = threads dself = dd(self) self.syslist = syslist for s in syslist: s.prng = self.prng # bind the system's prng to self prng s.init.init_stage1(s) #! TODO - does this have any meaning now that we introduce the smotion class? if self.mode == "md" and len(syslist) > 1: warning("Multiple systems will evolve independently in a '" + self.mode + "' simulation.") self.fflist = {} for f in fflist: self.fflist[f.name] = f self.outtemplate = outputs dself.step = depend_value(name="step", value=step) self.tsteps = tsteps self.ttime = ttime self.smotion = smotion self.chk = None self.rollback = True
def __init__(self, fixcom=False, fixatoms=None): """Initialises Motion object. Args: fixcom: An optional boolean which decides whether the centre of mass motion will be constrained or not. Defaults to False. fixatoms: A list of atoms that should be held fixed to their initial positions. """ dself = dd(self) dself.dt = depend_value(name="dt", value=0.0) self.fixcom = fixcom if fixatoms is None: self.fixatoms = np.zeros(0, int) else: self.fixatoms = fixatoms self.beads = self.cell = self.forces = self.prng = self.nm = None
def __init__(self, motionlist=None): """Initialises MultiMotion. Args: fixcom: An optional boolean which decides whether the centre of mass motion will be constrained or not. Defaults to False. """ dself = dd(self) dself.dt = depend_value(name="dt", func=self.get_totdt) self.mlist = motionlist for m in self.mlist: dd(m).dt.add_dependant(dself.dt) print dd(m).dt._dependants a = self.dt # DON'T ASK WHY BUT IF YOU DON'T DO THAT WEAKREFS TO SELF.DT WILL BE INVALIDATED self.fixatoms = set(self.mlist[0].fixatoms) for m in self.mlist: self.fixatoms = self.fixatoms.intersection(m.fixatoms) self.fixatoms = list(self.fixatoms) self.fixcom = True # fixcom is true only if all movers are fixed for m in self.mlist: self.fixcom = self.fixcom and m.fixcom
def __init__(self, mode, geop, nstep, a0, ncell, nvac, nsi, nmg, neval, diffusion_barrier_al, diffusion_prefactor_al, diffusion_barrier_mg, diffusion_prefactor_mg, diffusion_barrier_si, diffusion_prefactor_si, idx=[], tottime=0, ecache_file="", qcache_file="", 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. """ # This will generate a lattice model based on a primitive FCC cell. the lattice is represented in three ways: # 1. as a string in which each lattice site is identified by a letter # 2. by a list of the lattice sites in 3D space, in 1-1 mapping with the letters # 3. by a list of the atoms, whose lattice position is indicated by an integer self.nstep = nstep self.ncell = ncell self.nvac = nvac self.nsi = nsi self.nmg = nmg self.nsites = self.ncell**3 self.natoms = self.nsites - self.nvac self.neval = neval self.diffusion_barrier_al = diffusion_barrier_al self.diffusion_prefactor_al = diffusion_prefactor_al if diffusion_barrier_mg > 0: self.diffusion_barrier_mg = diffusion_barrier_mg else: self.diffusion_barrier_mg = diffusion_barrier_al if diffusion_barrier_si > 0: self.diffusion_barrier_si = diffusion_barrier_si else: self.diffusion_barrier_si = diffusion_barrier_al if diffusion_prefactor_mg > 0: self.diffusion_prefactor_mg = diffusion_prefactor_mg else: self.diffusion_prefactor_mg = diffusion_prefactor_al if diffusion_prefactor_si > 0: self.diffusion_prefactor_si = diffusion_prefactor_si else: self.diffusion_prefactor_si = diffusion_prefactor_al self.barriers = { "A": self.diffusion_barrier_al, "M": self.diffusion_barrier_mg, "S": self.diffusion_barrier_si } self.prefactors = { "A": self.diffusion_prefactor_al, "M": self.diffusion_prefactor_mg, "S": self.diffusion_prefactor_si } self.a0 = a0 cell = np.zeros((3, 3)) cell[0] = [ 0.7071067811865475, 0.35355339059327373, 0.35355339059327373 ] cell[1] = [0., 0.6123724356957945, 0.20412414523193154] cell[2] = [0., 0., 0.5773502691896258] self.scell = self.a0 * cell self.dcell = Cell() self.dcell.h = self.scell * self.ncell print "LATTICE PARAM ", self.a0 # this is the list of lattice sites, in 3D coordinates ix, iy, iz = np.meshgrid(range(self.ncell), range(self.ncell), range(self.ncell), indexing='ij') self.sites = np.dot( np.asarray([ix.flatten(), iy.flatten(), iz.flatten()]).T, self.scell.T) print len(self.sites), self.nsites, "###" # now we build list of nearest neighbors (fcc-lattice hardcoded!) self.neigh = np.zeros((self.nsites, 12), int) nneigh = np.zeros(self.nsites, int) # could be done in a more analytic way but whatever, I'm too lazy a02 = 1.01 * 0.5 * self.a0**2 # perhaps 1.01 it is not enough, must check! for i in xrange( self.nsites): # determines the connectivity of the lattice rij = self.sites.copy().flatten() for j in xrange(self.nsites): rij[3 * j:3 * j + 3] -= self.sites[i] self.dcell.array_pbc(rij) rij.shape = (self.nsites, 3) for j in xrange(i): if np.dot(rij[j], rij[j]) < a02: # found nearest neighbor self.neigh[i, nneigh[i]] = j self.neigh[j, nneigh[j]] = i nneigh[i] += 1 nneigh[j] += 1 self.idx = idx # the KMC step is variable and so it cannot be stored as proper timing dd(self).dt = depend_value(name="dt", value=0.0) self.fixatoms = np.asarray([]) self.fixcom = True self.geop = [None] * self.neval # geop should not trigger exit if there is early convergence, but just carry on. # we hard-code this option to avoid early-termination that would be hard to debug for a user geop["exit_on_convergence"] = False for i in xrange(self.neval): # geometry optimizer should not have *any* hystory dependence self.geop[i] = GeopMotion( fixcom=fixcom, fixatoms=fixatoms, **geop ) #mode="cg", ls_options={"tolerance": 1, "iter": 20, "step": 1e-3, "adaptive": 0.0}, tolerances={"energy": 1e-7, "force": 1e-2, "position": 1e-4}, ) #!TODO: set the geop parameters properly # dictionary of previous energy evaluations - kind of tricky to use this with the omaker thingie self.ecache_file = ecache_file self.qcache_file = qcache_file try: ff = open(self.ecache_file, "rb") self.ecache = pickle.load(ff) ff.close() ff = open(self.qcache_file, "rb") self.qcache = pickle.load(ff) ff.close() print "Loaded %d cached energies" % (len(self.ecache)) except: print "Couldn't load cache files " + self.ecache_file + "," + self.qcache_file + " - resetting" self.ecache = {} self.qcache = {} self.ncache = len(self.ecache) self.ncache_stored = self.ncache # no TS evaluation implemented yet self.tscache = {} self.tottime = tottime
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) # Binds integrators self.integrator.bind(self) # n times the temperature (for path integral partition function) dset( self, "ntemp", depend_value(name='ntemp', func=self.get_ntemp, dependencies=[dget(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. deppipe(self, "ntemp", self.thermostat, "temp") deppipe(self, "dt", self.thermostat, "dt") # the free ring polymer propagator is called in the inner loop, so propagation time should be redefined accordingly. if self.enstype == "mts": self.inmts = 1 for mk in self.nmts: self.inmts *= mk dset( self, "deltat", depend_value(name="deltat", func=(lambda: self.dt / self.inmts), dependencies=[dget(self, "dt")])) deppipe(self, "deltat", 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) deppipe(self, "ntemp", self.barostat, "temp") deppipe(self, "dt", self.barostat, "dt") deppipe(self.ensemble, "pext", self.barostat, "pext") deppipe(self.ensemble, "stressext", self.barostat, "stressext") self.barostat.bind(beads, nm, cell, bforce, prng=prng, fixdof=fixdof) self.ensemble.add_econs(dget(self.thermostat, "ethermo")) self.ensemble.add_econs(dget(self.barostat, "ebaro")) #!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": print "STRESS:", np.trace(self.ensemble.stressext) if np.trace(self.ensemble.stressext) < 0: raise ValueError( "Negative or unspecified stress for a constant-s integrator" )