class TestSchnetPack:

    pos1 = Posinp.from_file(os.path.join(pos_folder, "N2.xyz"))
    model1 = os.path.join(model_folder, "ani1_N2_model")
    model2 = os.path.join(model_folder, "wacsf_model")
    model3 = os.path.join(model_folder, "H2O_model")
    calc1 = SchnetPackCalculator(model_dir=model1)
    calc2 = SchnetPackCalculator(model_dir=model2)
    calc3 = SchnetPackCalculator(model_dir=model3)
    job = Job(posinp=pos1, calculator=calc1)
    jobwacsf = Job(posinp=pos1, calculator=calc2)

    def test_only_energy(self):
        self.job.run("energy")
        assert np.array(-2979.6067) == self.job.results["energy"][0]
        new_job = deepcopy(self.job)
        new_job.calculator.units = {"energy": "hartree", "positions": "atomic"}
        new_job.run("energy")
        assert new_job.results["energy"][0] == np.array(-81079.228)
        self.job.results["energy"] = None

    def test_forces_from_deriv(self):
        assert self.job.calculator.available_properties == ["energy"]
        self.job.run("forces")
        ref_forces = np.array([[-0.0, -0.0, -0.31532133],
                               [-0.0, -0.0, 0.31532133]])
        assert np.isclose(self.job.results["forces"][0], ref_forces).all()
        new_job = deepcopy(self.job)
        new_job.calculator.units = {"energy": "hartree", "positions": "atomic"}
        new_job.run("forces")
        assert np.isclose(ref_forces * 51.42206334724,
                          new_job.results["forces"][0]).all()

    def test_forces_from_finite_difference(self):
        assert self.job.calculator.available_properties == ["energy"]
        self.job.run("forces", finite_difference=True)
        ref_forces = np.array([[-0.0, -0.0, -0.32416448],
                               [-0.0, -0.0, 0.32416448]])
        assert np.isclose(self.job.results["forces"][0], ref_forces).all()

    def test_wacsf(self):
        self.jobwacsf.run("energy")
        assert self.jobwacsf.results["energy"] is not None

    def test_bad_property(self):
        with pytest.raises(ValueError):
            self.job.run("dipole")

    def test_convert(self):
        pos_angstrom = Posinp.from_file(
            os.path.join(pos_folder, "H2O_unrelaxed.xyz"))
        pos_atomic = Posinp.from_file(
            os.path.join(pos_folder, "H2O_atomic.xyz"))
        job1 = Job(posinp=pos_angstrom, calculator=self.calc3)
        job2 = Job(posinp=pos_atomic, calculator=self.calc3)
        job1.run("energy")
        job2.run("energy")
        assert job1.results["energy"] == job2.results["energy"]
Example #2
0
 def __init__(self,
              model_dir,
              available_properties=None,
              device="cpu",
              **kwargs):
     Calculator.__init__(self, **kwargs)
     self.schnetpackcalculator = SchnetPackCalculator(
         model_dir=model_dir,
         available_properties=available_properties,
         device=device,
     )
     self.implemented_properties = self.schnetpackcalculator._get_available_properties(
     )
     if "energy" in self.implemented_properties and "forces" not in self.implemented_properties:
         self.implemented_properties.append("forces")
Example #3
0
class AseSpkCalculator(Calculator):
    def __init__(self,
                 model_dir,
                 available_properties=None,
                 device="cpu",
                 **kwargs):
        Calculator.__init__(self, **kwargs)
        self.schnetpackcalculator = SchnetPackCalculator(
            model_dir=model_dir,
            available_properties=available_properties,
            device=device,
        )
        self.implemented_properties = self.schnetpackcalculator._get_available_properties(
        )
        if "energy" in self.implemented_properties and "forces" not in self.implemented_properties:
            self.implemented_properties.append("forces")

    def calculate(self,
                  atoms=None,
                  properties=["energy"],
                  system_changes=all_changes):
        if self.calculation_required(atoms, properties):
            Calculator.calculate(self, atoms)
            posinp = Posinp.from_ase(atoms)

            job = Job(posinp=posinp, calculator=self.schnetpackcalculator)
            for prop in properties:
                job.run(prop)
            results = {}
            for prop, result in zip(job.results.keys(), job.results.values()):
                results[prop] = np.squeeze(result)
            self.results = results
Example #4
0
class TestGeopt:

    posN2 = Posinp.from_file(os.path.join(pos_folder, "N2_unrelaxed.xyz"))
    posH2O = Posinp.from_file(os.path.join(pos_folder, "H2O_unrelaxed.xyz"))
    calcN2 = SchnetPackCalculator(os.path.join(model_folder, "ani1_N2_model"))
    calcH2O = SchnetPackCalculator(os.path.join(model_folder, "H2O_model"))

    def test_N2(self, capsys):
        init = Job(posinp=self.posN2, calculator=self.calcN2)
        init.run("energy")
        assert init.results["energy"][0] == -2978.2354
        geo = Geopt(posinp=self.posN2, calculator=self.calcN2)
        geo.run(recenter=True, verbose=2)
        output = capsys.readouterr()
        assert 1.101 < geo.final_posinp.distance(0, 1) < 1.103
        assert np.isclose(
            geo.final_posinp.positions[0, 2],
            -geo.final_posinp.positions[1, 2],
            atol=1e-6,
        )
        assert output.out is not None
        final = Job(posinp=geo.final_posinp, calculator=self.calcN2)
        final.run("energy")
        assert final.results["energy"][0] == -2979.6070

    def test_H2O(self):
        init = Job(posinp=self.posH2O, calculator=self.calcH2O)
        init.run("energy")
        assert np.isclose(init.results["energy"][0], -2076.7576, atol=1e-4)
        geo = Geopt(posinp=self.posH2O, calculator=self.calcH2O)
        geo.run()
        assert 0.964 < geo.final_posinp.distance(0, 1) < 0.965
        assert (geo.final_posinp.distance(0, 1) -
                geo.final_posinp.distance(0, 2)) < 0.0001
        # TODO Check the angle
        final = Job(posinp=geo.final_posinp, calculator=self.calcH2O)
        final.run("energy")
        assert np.isclose(final.results["energy"][0], -2078.6301, atol=1e-4)

    def test_errors(self):
        with pytest.raises(ValueError):
            geo = Geopt(posinp=None, calculator=self.calcN2)

        with pytest.raises(TypeError):
            geo = Geopt(posinp=self.posN2, calculator=1)
Example #5
0
class TestPhononAutoGrad:

    posH2O = Posinp.from_file(os.path.join(pos_folder, "H2Orelaxed.xyz"))
    calc_ener = SchnetPackCalculator(os.path.join(model_folder, "H2O_model"))
    calc_for = SchnetPackCalculator(
        os.path.join(model_folder, "H2O_forces_model"))

    def test_ph_h2o_autograd_2nd_derivative(self):
        ph1 = Phonon(posinp=self.posH2O, calculator=self.calc_ener)
        ph1.run()
        ph1.energies.sort()
        assert np.allclose(ph1.energies[6:9], [1726, 3856, 3942], atol=1)

    def test_ph_h2o_autograd_1st_derivative(self):
        ph1 = Phonon(posinp=self.posH2O, calculator=self.calc_for)
        ph1.run()
        ph1.energies.sort()
        assert np.allclose(ph1.energies[6:9], [1589, 3703, 3812], atol=1)
 def __init__(self,
              model_dir,
              available_properties=None,
              device="cpu",
              md=False,
              dropout=False,
              **kwargs):
     r"""
     Parameters
     ----------
     model_dir : str
         Same as :class:`SchnetPackCalculator`.
     available_properties : str or list of str
         Same as :class:`SchnetPackCalculator`.
     device : str
         Same as :class:`SchnetPackCalculator`.
     md : bool
         Default is False. Should be set to True if the
         calculator is used for molecular dynamics.
     dropout : bool
         Same as :class:`SchnetPackCalculator`.
     units : dict
         Same as :class:`SchnetPackCalculator`.
     """
     Calculator.__init__(self, **kwargs)
     self.schnetpackcalculator = SchnetPackCalculator(
         model_dir=model_dir,
         available_properties=available_properties,
         device=device,
         md=md,
         dropout=dropout,
     )
     self.implemented_properties = (
         self.schnetpackcalculator._get_available_properties())
     if ("energy" in self.implemented_properties
             and "forces" not in self.implemented_properties):
         self.implemented_properties.append("forces")
def get_orthonormal_basis(modes=None, model=None, posinp=None, write=False):
    if modes:
        with h5py.File(modes, "r") as f:
            normal_modes = f["modes"][:]
            orthonormal_basis = gramschmidt(normal_modes)
    else:
        calculator = SchnetPackCalculator(model)
        posinp = Posinp.from_file(posinp)
        ph = Phonon(posinp=posinp, calculator=calculator)
        ph.run()

        normal_modes = ph.normal_modes.copy()
        orthonormal_basis = gramschmidt(normal_modes)
    if write:
        fx = h5py.File("orthonormal_basis.h5", "w")
        fx.create_dataset("basis", data=orthonormal_basis)
        fx.close()
    return orthonormal_basis
Example #8
0
class TestGrapheneAngles:

    graphene2_name = os.path.join(pos_folder, "gra2.xyz")
    pos_2at = Posinp.from_file(graphene2_name)

    graphene4_name = os.path.join(pos_folder, "gra4_red.xyz")
    pos_4at_red = Posinp.from_file(graphene4_name)

    calc = SchnetPackCalculator(os.path.join(model_folder, "H2O_model"))

    def test_same_result(self):
        j1 = Job(posinp=self.pos_2at, calculator=self.calc)
        j1.run("energy")
        e1 = j1.results["energy"]

        j2 = Job(posinp=self.pos_4at_red, calculator=self.calc)
        j2.run("energy")
        e2 = j2.results["energy"]

        pos_4at = deepcopy(self.pos_4at_red)
        pos_4at.convert_units("angstroem")
        j3 = Job(posinp=pos_4at, calculator=self.calc)
        j3.run("energy")
        e3 = j3.results["energy"]

        assert e2 == e3
        assert np.isclose(e2, 2 * e1, atol=0.0002)

    def test_cell_with_angles(self):
        assert np.isclose(
            self.pos_2at.cell.array,
            np.array([[2.46, 0.0, 0.0], [0.0, 0.0, 0.0],
                      [1.23, 0.0, 2.13042249]]),
        ).all()

    def test_verify_values(self):

        assert np.isclose(self.pos_2at.angles, np.array([90.0, 60.0,
                                                         90.0])).all()
        assert self.pos_4at_red.orthorhombic
        assert not self.pos_2at.orthorhombic
        assert np.isclose(self.pos_2at.cell.lengths(),
                          np.array([2.46, 0.0, 2.46])).all()
Example #9
0
class TestPhononFinite:

    posN2 = Posinp.from_file(os.path.join(pos_folder, "N2_unrelaxed.xyz"))
    calcN2 = SchnetPackCalculator(os.path.join(model_folder, "myN2_model"))

    def test_ph_N2(self):
        ph1 = Phonon(posinp=self.posN2,
                     calculator=self.calcN2,
                     finite_difference=True)
        ph1.run(batch_size=1)
        assert np.isclose(ph1.energies.max(), 2339.53, atol=0.01)
        assert all(
            np.abs(np.delete(ph1.energies, np.argmax(ph1.energies))) < 30)

        ph2 = Phonon(
            posinp=ph1._ground_state,
            calculator=ph1.calculator,
            relax=False,
            finite_difference=True,
            translation_amplitudes=0.03,
        )
        ph2.run()
        assert np.allclose(ph1.energies, ph2.energies)

        ph3 = Phonon(
            posinp=self.posN2,
            calculator=self.calcN2,
            finite_difference=True,
            relax=False,
        )
        ph3.run()
        assert not np.allclose(ph3.energies, ph1.energies, atol=100)

    def test_phonon_posinp_error(self):
        with pytest.raises(TypeError):
            ph = Phonon(posinp=None, calculator=self.calcN2)

    def test_phonon_calc_error(self):
        with pytest.raises(TypeError):
            ph = Phonon(posinp=self.posN2, calculator=None)
def get_normal_modes(posinp, model, device="cpu", rotate=False):
    calculator = SchnetPackCalculator(model, device=device)
    posinp = Posinp.from_file(posinp)
    ph = Phonon(posinp=posinp, calculator=calculator)
    ph.run()

    if rotate:
        ndim = 3 * len(posinp)
        final_modes = np.zeros((ndim, ndim))

        idx = np.arange(ndim)
        for i in range(ndim):
            init = ph.normal_modes[:, i]
            final = np.empty_like(init)
            final[np.where(idx % 3 == 0)[0]] = init[np.where(idx % 3 == 0)[0]]
            final[np.where(idx % 3 == 1)[0]] = init[np.where(idx % 3 == 2)[0]]
            final[np.where(idx %
                           3 == 2)[0]] = -1.0 * init[np.where(idx % 3 == 1)[0]]
            final_modes[:, i] = final
        return ph.energies, final_modes

    else:
        return ph.energies, ph.normal_modes
class AseSpkCalculator(Calculator):
    r"""
    Wrapper :class:`Calculator` class around the :class:`SchnetPackCalculator`
    class to use directly inside ASE funtions.
    """
    def __init__(self,
                 model_dir,
                 available_properties=None,
                 device="cpu",
                 md=False,
                 dropout=False,
                 **kwargs):
        r"""
        Parameters
        ----------
        model_dir : str
            Same as :class:`SchnetPackCalculator`.
        available_properties : str or list of str
            Same as :class:`SchnetPackCalculator`.
        device : str
            Same as :class:`SchnetPackCalculator`.
        md : bool
            Default is False. Should be set to True if the
            calculator is used for molecular dynamics.
        dropout : bool
            Same as :class:`SchnetPackCalculator`.
        units : dict
            Same as :class:`SchnetPackCalculator`.
        """
        Calculator.__init__(self, **kwargs)
        self.schnetpackcalculator = SchnetPackCalculator(
            model_dir=model_dir,
            available_properties=available_properties,
            device=device,
            md=md,
            dropout=dropout,
        )
        self.implemented_properties = (
            self.schnetpackcalculator._get_available_properties())
        if ("energy" in self.implemented_properties
                and "forces" not in self.implemented_properties):
            self.implemented_properties.append("forces")

    def calculate(self,
                  atoms=None,
                  properties=["energy"],
                  system_changes=all_changes):
        r"""
        This method will be called by ASE functions.
        """
        if self.calculation_required(atoms, properties):
            from mlcalcdriver.base.posinp import Posinp

            Calculator.calculate(self, atoms)
            posinp = Posinp.from_ase(atoms)

            from mlcalcdriver.base.job import Job

            job = Job(posinp=posinp, calculator=self.schnetpackcalculator)
            for prop in properties:
                job.run(prop)
            results = {}
            for prop, result in zip(job.results.keys(), job.results.values()):
                results[prop] = np.squeeze(result)
            self.results = results
def get_normal_modes(posinp, model, device="cpu"):
    calculator = SchnetPackCalculator(model, device=device)
    posinp = Posinp.from_file(posinp)
    ph = Phonon(posinp=posinp, calculator=calculator)
    ph.run()
    return ph.energies, ph.normal_modes