def calculate(self,
               atoms=None,
               properties=['energy'],
               system_changes=all_changes):
     LennardJones.calculate(self, atoms, properties, system_changes)
     if 'forces' in self.results:
         self.results['forces'] += 1e-4 * self.rng.normal(
             size=self.results['forces'].shape, )
     if 'stress' in self.results:
         self.results['stress'] += 1e-4 * self.rng.normal(
             size=self.results['stress'].shape, )
Exemple #2
0
    def calculate(self, atoms=None,
                  properties=['energy'],
                  system_changes=all_changes):
        LennardJones.calculate(self, atoms, properties, system_changes)

        natoms = len(self.atoms)

        epsilon = self.parameters.epsilon
        sigma = self.parameters.sigma
        k = self.parameters.k
        r0 = self.parameters.r0
        rc = self.parameters.rc
        if rc is None:
            rc = 3 * r0

        energy = 0.0
        forces = np.zeros((natoms, 3))
        stress = np.zeros((3, 3))

        tags = self.atoms.get_tags()
        for tag in np.unique(tags):
            # Adding (intramolecular) harmonic potential part
            indices = np.where(tags == tag)[0]
            assert len(indices) == 2
            a1, a2 = indices
            d = self.atoms.get_distance(a1, a2, mic=True, vector=True)
            r = np.linalg.norm(d)
            energy += 0.5 * k * (r - r0) ** 2
            f = -k * (r - r0) * d
            forces[a1] -= f
            forces[a2] += f
            stress += np.dot(np.array([f]).T, np.array([d]))

            # Substracting intramolecular LJ part
            r2 = r ** 2
            c6 = (sigma**2 / r2)**3
            c12 = c6 ** 2
            energy += -4 * epsilon * (c12 - c6).sum()
            f = (24 * epsilon * (2 * c12 - c6) / r2) * d
            forces[a1] -= -f
            forces[a2] += -f
            stress += -np.dot(np.array([f]).T, np.array([d]))

        if 'stress' in properties:
            stress += stress.T.copy()
            stress *= -0.5 / self.atoms.get_volume()
            self.results['stress'] += stress.flat[[0, 4, 8, 5, 2, 1]]

        self.results['energy'] += energy
        self.results['free_energy'] += energy
        self.results['forces'] += forces
def example():
    from ase.calculators.lj import LennardJones
    from theforce.util.flake import Hex
    from ase.io.trajectory import Trajectory
    from ase.optimize import BFGSLineSearch
    from ase.io import Trajectory

    # initial state + dft calculator
    ini_atoms = TorchAtoms(positions=Hex().array(), cutoff=3.0)
    dftcalc = LennardJones()
    ini_atoms.set_calculator(dftcalc)
    BFGSLineSearch(ini_atoms).run(fmax=0.01)
    vel = np.random.uniform(-1., 1., size=ini_atoms.positions.shape) * 1.
    vel -= vel.mean(axis=0)
    ini_atoms.set_velocities(vel)

    # use a pretrained model by writing it to the checkpoint
    # (alternatively set, for example, itrain=10*[5] in mlmd)
    pre = """GaussianProcessPotential([PairKernel(RBF(signal=3.2251566545458794, lengthscale=tensor([0.1040])),
    0, 0, factor=PolyCut(3.0, n=2))], White(signal=0.1064043798026091, requires_grad=True))""".replace(
        '\n', '')
    with open('gp.chp', 'w') as chp:
        chp.write(pre)

    # run(md)
    mlmd(ini_atoms,
         3.0,
         0.5,
         0.03,
         tolerance=0.18,
         max_steps=100,
         soap=False,
         itrain=10 * [3],
         retrain_every=5,
         retrain=5)

    # recalculate all with the actual calculator and compare
    traj = Trajectory('md.traj')
    energies = []
    forces = []
    dum = 0
    for atoms in traj:
        dum += 1
        e = atoms.get_potential_energy()
        f = atoms.get_forces()
        dftcalc.calculate(atoms)
        ee = dftcalc.results['energy']
        ff = dftcalc.results['forces']
        energies += [(e, ee)]
        forces += [(f.reshape(-1), ff.reshape(-1))]

    import pylab as plt
    get_ipython().run_line_magic('matplotlib', 'inline')
    fig, axes = plt.subplots(1, 2, figsize=(8, 3))
    axes[0].scatter(*zip(*energies))
    axes[0].set_xlabel('ml')
    axes[0].set_ylabel('dft')
    a, b = (np.concatenate(v) for v in zip(*forces))
    axes[1].scatter(a, b)
    axes[1].set_xlabel('ml')
    axes[1].set_ylabel('dft')
    fig.tight_layout()
    fig.text(0.2, 0.8, 'energy')
    fig.text(0.7, 0.8, 'forces')