示例#1
0
    def __init__(self, timestep, mode="md", nsamples=0, stride=1, screen=0.0, nbeads=-1, 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.
        """

        self.mode = mode
        self.nsamples = nsamples
        self.stride = stride
        self.nbeads = nbeads
        self.screen = screen

        dself = dd(self)

        # the planetary step just computes constrained-centroid properties so it
        # should not advance the timer
        dself.dt = depend_value(name="dt", value=0.0)
        #dset(self, "dt", depend_value(name="dt", value = 0.0) )
        self.fixatoms = np.asarray([])
        self.fixcom = True

        # nvt-cc means contstant-temperature with constrained centroid
        # this basically is a motion class that will be used to make the
        # centroid propagation at each time step
        self.ccdyn = Dynamics(timestep, mode="nvt-cc", thermostat=thermostat, nmts=nmts, fixcom=fixcom, fixatoms=fixatoms)
示例#2
0
    def fetch(self):
        """Creates a motion calculator object.

        Returns:
           An ensemble object of the appropriate mode and with the appropriate
           objects given the attributes of the InputEnsemble object.
        """

        super(InputMotionBase, self).fetch()

        if self.mode.fetch() == "replay":
            sc = Replay(fixcom=self.fixcom.fetch(), fixatoms=self.fixatoms.fetch(), intraj=self.file.fetch())
        elif self.mode.fetch() == "minimize":
            sc = GeopMotion(fixcom=self.fixcom.fetch(), fixatoms=self.fixatoms.fetch(), **self.optimizer.fetch())
        elif self.mode.fetch() == "neb":
            sc = NEBMover(fixcom=self.fixcom.fetch(), fixatoms=self.fixatoms.fetch(), **self.neb_optimizer.fetch())
        elif self.mode.fetch() == "dynamics":
            sc = Dynamics(fixcom=self.fixcom.fetch(), fixatoms=self.fixatoms.fetch(), **self.dynamics.fetch())
        elif self.mode.fetch() == "vibrations":
            sc = DynMatrixMover(fixcom=self.fixcom.fetch(), fixatoms=self.fixatoms.fetch(), **self.vibrations.fetch())
        elif self.mode.fetch() == "alchemy":
            sc = AlchemyMC(fixcom=self.fixcom.fetch(), fixatoms=self.fixatoms.fetch(), **self.alchemy.fetch())
        elif self.mode.fetch() == "instanton":
            sc = InstantonMotion(fixcom=self.fixcom.fetch(), fixatoms=self.fixatoms.fetch(), **self.instanton.fetch())
        elif self.mode.fetch() == "t_ramp":
            sc = TemperatureRamp(**self.t_ramp.fetch())
        elif self.mode.fetch() == "p_ramp":
            sc = PressureRamp(**self.p_ramp.fetch())
        else:
            sc = Motion()
            # raise ValueError("'" + self.mode.fetch() + "' is not a supported motion calculation mode.")

        return sc
示例#3
0
    def fetch(self):
        """Creates a motion calculator object.

      Returns:
         An ensemble object of the appropriate mode and with the appropriate
         objects given the attributes of the InputEnsemble object.
      """

        super(InputMotion, self).fetch()

        if self.mode.fetch() == "replay":
            sc = Replay(fixcom=False, fixatoms=None, intraj=self.file.fetch())
        elif self.mode.fetch() == "minimize":
            sc = GeopMover(fixcom=False,
                           fixatoms=None,
                           **self.optimizer.fetch())
        elif self.mode.fetch() == "neb":
            sc = NEBMover(fixcom=False,
                          fixatoms=None,
                          **self.neb_optimizer.fetch())
        elif self.mode.fetch() == "dynamics":
            sc = Dynamics(fixcom=self.fixcom.fetch(),
                          fixatoms=self.fixatoms.fetch(),
                          **self.dynamics.fetch())
        else:
            sc = Motion()
            #raise ValueError("'" + self.mode.fetch() + "' is not a supported motion calculation mode.")

        return sc
示例#4
0
文件: planetary.py 项目: i-pi/i-pi
class Planetary(Motion):
    """Evaluation of the matrices needed in a planetary model by
    centroid-constrained MD. Basically uses a nested motion class
    to perform several constrained evaluation steps every time
    Planetary.step is called, accumulating averages of the
    covariance and of the frequency matrices.

    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="md",
        nsamples=0,
        stride=1,
        screen=0.0,
        nbeads=-1,
        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.
        """

        self.mode = mode
        self.nsamples = nsamples
        self.stride = stride
        self.nbeads = nbeads
        self.screen = screen

        dself = dd(self)

        # the planetary step just computes constrained-centroid properties so it
        # should not advance the timer
        dself.dt = depend_value(name="dt", value=0.0)
        # dset(self, "dt", depend_value(name="dt", value = 0.0) )
        self.fixatoms = np.asarray([])
        self.fixcom = True

        # nvt-cc means contstant-temperature with constrained centroid
        # this basically is a motion class that will be used to make the
        # centroid propagation at each time step
        self.ccdyn = Dynamics(
            timestep,
            mode="nvt-cc",
            thermostat=thermostat,
            nmts=nmts,
            fixcom=fixcom,
            fixatoms=fixatoms,
        )

    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 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.
        """

        if self.nbeads < 0:
            self.nbeads = beads.nbeads
        self.prng = prng
        self.basebeads = beads
        self.basenm = nm

        # copies of all of the helper classes that are needed to bind the ccdyn object
        self.dbeads = beads.copy(nbeads=self.nbeads)
        self.dcell = cell.copy()
        self.dforces = bforce.copy(self.dbeads, self.dcell)

        # options for NM propagation - hardcoded frequencies unless using a GLE thermo
        # for which frequencies matter
        if isinstance(self.ccdyn.thermostat, (ThermoGLE, ThermoNMGLE, ThermoNMGLEG)):
            self.dnm = nm.copy()
            self.dnm.mode = "rpmd"
        else:
            self.dnm = nm.copy(
                freqs=nm.omegak[1]
                * self.nbeads
                * np.sin(np.pi / self.nbeads)
                * np.ones(self.nbeads - 1)
                / (beads.nbeads * np.sin(np.pi / beads.nbeads))
            )
            self.dnm.mode = "manual"

        self.dnm.bind(ens, self, beads=self.dbeads, forces=self.dforces)
        self.dnm.qnm[:] = (
            nm.qnm[: self.nbeads] * np.sqrt(self.nbeads) / np.sqrt(beads.nbeads)
        )
        self.dens = ens.copy()
        self.dbias = ens.bias.copy(self.dbeads, self.dcell)
        self.dens.bind(
            self.dbeads, self.dnm, self.dcell, self.dforces, self.dbias, omaker
        )

        self.natoms = self.dbeads.natoms
        natoms3 = self.dbeads.natoms * 3
        self.omega2 = np.zeros((natoms3, natoms3), float)

        # initializes counters
        self.tmc = 0
        self.tmtx = 0
        self.tsave = 0
        self.neval = 0

        # finally, binds the ccdyn object
        self.ccdyn.bind(
            self.dens, self.dbeads, self.dnm, self.dcell, self.dforces, prng, omaker
        )

        self.omaker = omaker
        self.fomega2 = omaker.get_output("omega2")

    def increment(self, dnm):

        # accumulates an estimate of the frequency matrix
        sm3 = dstrip(self.dbeads.sm3)
        qms = dstrip(dnm.qnm) * sm3
        fms = dstrip(dnm.fnm) / sm3
        fms[0, :] = 0
        qms[0, :] = 0
        qms *= (dnm.omegak**2)[:, np.newaxis]

        self.omega2 += np.tensordot(fms, fms, axes=(0, 0))
        qffq = np.tensordot(fms, qms, axes=(0, 0))
        qffq = qffq + qffq.T
        qffq *= 0.5
        self.omega2 -= qffq

    def matrix_screen(self):
        """Computes a screening matrix to avoid the impact of
        noisy elements of the covariance and frequency matrices for
        far-away atoms"""

        q = np.array(self.dbeads[0].q).reshape(self.natoms, 3)
        sij = q[:, np.newaxis, :] - q
        sij = sij.transpose().reshape(3, self.natoms**2)
        # find minimum distances between atoms (rigorous for cubic cell)
        sij = np.matmul(self.dcell.ih, sij)
        sij -= np.around(sij)
        sij = np.matmul(self.dcell.h, sij)
        sij = sij.reshape(3, self.natoms, self.natoms).transpose()
        # take square magnitudes of distances
        sij = np.sum(sij * sij, axis=2)
        # screen with Heaviside step function
        sij = (sij < self.screen**2).astype(float)
        # sij = np.exp(-sij / (self.screen**2))
        # acount for 3 dimensions
        sij = np.concatenate((sij, sij, sij), axis=0)
        sij = np.concatenate((sij, sij, sij), axis=1)
        sij = sij.reshape(-1).reshape(-1, self.natoms).transpose()
        sij = sij.reshape(-1).reshape(-1, 3 * self.natoms).transpose()
        return sij

    def save_matrix(self, matrix):
        """Writes the compressed, sparse frequency matrix to a netstring encoded file"""

        sparse.save_npz(
            self.fomega2, matrix, saver=netstring_encoded_savez, compressed=True
        )

    def step(self, step=None):

        if step is not None and step % self.stride != 0:
            return

        # Initialize positions to the actual positions, possibly with contraction

        self.dnm.qnm[:] = (
            self.basenm.qnm[: self.nbeads]
            * np.sqrt(self.nbeads)
            / np.sqrt(self.basebeads.nbeads)
        )

        # Randomized momenta
        self.dnm.pnm = (
            self.prng.gvec((self.dbeads.nbeads, 3 * self.dbeads.natoms))
            * np.sqrt(self.dnm.dynm3)
            * np.sqrt(self.dens.temp * self.dbeads.nbeads * Constants.kb)
        )
        self.dnm.pnm[0] = 0.0

        # Resets the frequency matrix
        self.omega2[:] = 0.0

        self.tmtx -= time.time()
        self.increment(self.dnm)
        self.tmtx += time.time()

        # sample by constrained-centroid dynamics
        for istep in range(self.nsamples):
            self.tmc -= time.time()
            self.ccdyn.step(step)
            self.tmc += time.time()
            self.tmtx -= time.time()
            self.increment(self.dnm)
            self.tmtx += time.time()

        self.neval += 1

        self.omega2 /= (
            self.dbeads.nbeads
            * self.dens.temp
            * (self.nsamples + 1)
            * (self.dbeads.nbeads - 1)
        )
        self.tsave -= time.time()

        if self.screen > 0.0:
            scr = self.matrix_screen()
            self.omega2 *= scr

        # ensure perfect symmetry
        self.omega2[:] = 0.5 * (self.omega2 + self.omega2.transpose())
        # only save lower triangular part
        self.omega2[:] = np.tril(self.omega2)

        # save as a sparse matrix in half precision
        save_omega2 = sparse.csc_matrix(self.omega2.astype(np.float16))

        # save the frequency matrix to the PLANETARY file
        self.save_matrix(save_omega2)

        self.tsave += time.time()
        info(
            "@ PLANETARY MODEL Average timing: %f s, %f s, %f s\n"
            % (self.tmc / self.neval, self.tmtx / self.neval, self.tsave / self.neval),
            verbosity.high,
        )
示例#5
0
    def fetch(self):
        """Creates a motion calculator object.

        Returns:
           An ensemble object of the appropriate mode and with the appropriate
           objects given the attributes of the InputEnsemble object.
        """

        super(InputMotionBase, self).fetch()

        if self.mode.fetch() == "replay":
            sc = Replay(
                fixcom=self.fixcom.fetch(),
                fixatoms=self.fixatoms.fetch(),
                intraj=self.file.fetch(),
            )
        elif self.mode.fetch() == "minimize":
            sc = GeopMotion(fixcom=self.fixcom.fetch(),
                            fixatoms=self.fixatoms.fetch(),
                            **self.optimizer.fetch())
        elif self.mode.fetch() == "neb":

            raise ValueError(
                "The nudged elastic band calculation has been temporarily disabled until further bug-fixes."
            )
        #            sc = NEBMover(
        #                fixcom=self.fixcom.fetch(),
        #                fixatoms=self.fixatoms.fetch(),
        #                **self.neb_optimizer.fetch()
        #            )
        elif self.mode.fetch() == "dynamics":
            sc = Dynamics(fixcom=self.fixcom.fetch(),
                          fixatoms=self.fixatoms.fetch(),
                          **self.dynamics.fetch())
        elif self.mode.fetch() == "constrained_dynamics":
            sc = ConstrainedDynamics(fixcom=self.fixcom.fetch(),
                                     fixatoms=self.fixatoms.fetch(),
                                     **self.constrained_dynamics.fetch())
        elif self.mode.fetch() == "vibrations":
            sc = DynMatrixMover(fixcom=self.fixcom.fetch(),
                                fixatoms=self.fixatoms.fetch(),
                                **self.vibrations.fetch())
        elif self.mode.fetch() == "normalmodes":
            sc = NormalModeMover(fixcom=self.fixcom.fetch(),
                                 fixatoms=self.fixatoms.fetch(),
                                 **self.normalmodes.fetch())
        elif self.mode.fetch() == "scp":
            sc = SCPhononsMover(fixcom=self.fixcom.fetch(),
                                fixatoms=self.fixatoms.fetch(),
                                **self.scp.fetch())
        elif self.mode.fetch() == "alchemy":
            sc = AlchemyMC(fixcom=self.fixcom.fetch(),
                           fixatoms=self.fixatoms.fetch(),
                           **self.alchemy.fetch())
        elif self.mode.fetch() == "atomswap":
            sc = AtomSwap(fixcom=self.fixcom.fetch(),
                          fixatoms=self.fixatoms.fetch(),
                          **self.atomswap.fetch())
        elif self.mode.fetch() == "instanton":
            sc = InstantonMotion(fixcom=self.fixcom.fetch(),
                                 fixatoms=self.fixatoms.fetch(),
                                 **self.instanton.fetch())
        elif self.mode.fetch() == "planetary":
            sc = Planetary(fixcom=self.fixcom.fetch(),
                           fixatoms=self.fixatoms.fetch(),
                           **self.planetary.fetch())
        elif self.mode.fetch() == "t_ramp":
            sc = TemperatureRamp(**self.t_ramp.fetch())
        elif self.mode.fetch() == "p_ramp":
            sc = PressureRamp(**self.p_ramp.fetch())
        elif self.mode.fetch() == "al-kmc":
            sc = AlKMC(fixcom=self.fixcom.fetch(),
                       fixatoms=self.fixatoms.fetch(),
                       **self.al6xxx_kmc.fetch())
        else:
            sc = Motion()
            # raise ValueError("'" + self.mode.fetch() + "' is not a supported motion calculation mode.")

        return sc