Giter VIP home page Giter VIP logo

Comments (2)

t-young31 avatar t-young31 commented on May 24, 2024

Absolutely one could – we haven't directly (rather used autodE for doing QM PESs and then single pointing with other wrappers).

Update (cc: @roitberg ): Below is a sample method implementation and example that seems to work reasonably, just for a 1D O-H stretch PES in water. It uses the newly "stable" autodE constrained optimisations, so please let me know when you find bugs.. I've already found one (#178), so the below won't yet work.

import ase
import torchani
import numpy as np
import multiprocessing as mp

import autode as ade
from autode.values import Gradient, PotentialEnergy
from autode.wrappers.keywords import KeywordsSet
from autode.calculations.types import CalculationType as ct
from autode.wrappers.methods import Method
from autode.pes import UnRelaxedPES1D, RelaxedPESnD
from autode.utils import work_in


# Need a low-level method to be available for good initial hessians
assert ade.methods.XTB().is_available or ade.methods.MOPAC().is_available


class ANI(Method):

    def __init__(self, ase_calculator, *args, **kwargs):
        super(ANI, self).__init__(*args, **kwargs)
        self.ase_calculator = ase_calculator

    def execute(self,
                calc: "CalculationExecutor"
                ) -> None:
        """Run the evaluation"""
        ase_atoms = self._ase_atoms_from_molecule_in(calc)

        calc.molecule.energy = PotentialEnergy(
            ase_atoms.get_potential_energy(), units="eV"
        ).to("Ha")
        calc.molecule.gradient = Gradient(
            -ase_atoms.get_forces(), units="eV Å^-1"
        ).to("Ha Å^-1")

    @property
    def uses_external_io(self) -> bool:
        return False

    def __repr__(self):
        return "ANI"

    def implements(self,
                   calculation_type: "autode.calculations.types.CalculationType") -> bool:
        return calculation_type in (ct.energy, ct.gradient)

    def _ase_atoms_from_molecule_in(self, calc: "CalculationExecutor"):
        """Get a set of ASE atoms with a set calculator"""

        atoms = ase.Atoms(symbols=calc.molecule.atomic_symbols,
                          positions=calc.molecule.coordinates)
        atoms.set_calculator(self.ase_calculator)

        return atoms


def plot_1d_unrelaxed():

    pes = UnRelaxedPES1D(h2o, rs={(0, 1): np.linspace(0.8, 1.5, num=20)})
    pes.calculate(method=ani)

    # matplotlib.use('TkAgg')   # <- I need to set this :shrug
    pes.plot("h2o_1d_unrelaxed.pdf")
    print(pes.relative_energies)


@work_in("relaxed_pes")
def plot_1d_relaxed():

    pes = RelaxedPESnD(h2o, rs={(0, 1): np.linspace(0.8, 1.5, num=20)})
    pes.calculate(method=ani)

    # matplotlib.use('TkAgg')   # <- I need to set this :shrug
    pes.plot("h2o_1d_relaxed.pdf")
    print(pes.relative_energies)


if __name__ == '__main__':

    # Parallelism doesn't work..
    ade.Config.n_cores = 1
    mp.set_start_method("spawn", force=True)

    h2o = ade.Molecule(smiles="O")

    ani = ANI(
        name="ANI",
        ase_calculator=torchani.models.ANI1ccx().ase(),
        keywords_set=KeywordsSet(),
        doi_list=[],
    )

    # h2o.single_point(method=ani)
    # h2o.optimise(method=ani)
    # print(h2o.energy)

    # plot_1d_unrelaxed()
    plot_1d_relaxed()

Wrapped as an external method Would allow to cache energy and gradients – probably not required
import os.path
from typing import List
import matplotlib
import multiprocessing as mp

import numpy as np

import autode as ade
from autode.hessians import Hessian
from autode.values import Coordinates, Gradient, PotentialEnergy
from autode.wrappers.keywords import OptKeywords, SinglePointKeywords, KeywordsSet
from autode.opt.optimisers.base import BaseOptimiser
from autode.wrappers.methods import ExternalMethod
from autode.exceptions import NotImplementedInMethod
from autode.pes import UnRelaxedPES1D, RelaxedPESnD

import ase
from ase.optimize import BFGS
from ase.constraints import FixBondLengths

import torchani


class ANI(ExternalMethod):

    def __init__(self, ase_calculator, *args, **kwargs):
        super(ANI, self).__init__(*args, **kwargs)
        self.ase_calculator = ase_calculator

    def execute(self, calc: "CalculationExecutor") -> None:

        if isinstance(calc.input.keywords, OptKeywords):
            self._execute_optimisation(calc)
        elif isinstance(calc.input.keywords, SinglePointKeywords):
            pass  # calculated in _energy_from
        else:
            raise NotImplementedError

        open("out", "w").close()
        return None

    def _execute_optimisation(self, calc: "CalculationExecutor") -> None:
        """Execute an optimisation on the atoms"""

        ase_atoms = self._ase_atoms_from_molecule_in(calc)

        if calc.molecule.constraints.distance is not None:
            constraints = calc.molecule.constraints.distance
            print(list(constraints.values()))
            ase_atoms.set_constraint(FixBondLengths(
                pairs=list(constraints.keys()),
                bondlengths=list(constraints.values()),
                tolerance=1E-6
            ))

        opt = BFGS(ase_atoms)
        opt.run(fmax=1E-4)
        print("Optimisation done!")

        calc.molecule.coordinates = ase_atoms.positions

        return None

    def _ase_atoms_from_molecule_in(self, calc: "CalculationExecutor"):
        """Get a set of ASE atoms with a set calculator"""

        atoms = ase.Atoms(symbols=calc.molecule.atomic_symbols,
                          positions=calc.molecule.coordinates)
        atoms.set_calculator(self.ase_calculator)

        return atoms

    def implements(self,
                   calculation_type: "autode.calculations.types.CalculationType") -> bool:
        return True  # TODO: be more granular than this

    def hessian_from(self,
                     calc: "autode.calculations.executors.CalculationExecutor") -> Hessian:
        raise NotImplementedInMethod

    def terminated_normally_in(self, calc: "CalculationExecutor") -> bool:
        return True

    class Optimiser(BaseOptimiser):
        """A not very realistic optimiser"""

        @property
        def converged(self) -> bool:
            return True

        @property
        def last_energy_change(self) -> PotentialEnergy:
            return PotentialEnergy(0)

    def optimiser_from(self,
                       calc: "CalculationExecutor") -> "autode.opt.optimisers.base.BaseOptimiser":
        return self.Optimiser()

    def _energy_from(self, calc: "CalculationExecutor") -> PotentialEnergy:
        ase_atoms = self._ase_atoms_from_molecule_in(calc)
        return PotentialEnergy(ase_atoms.get_potential_energy(), units="eV")

    def gradient_from(self, calc: "CalculationExecutor") -> Gradient:
        ase_atoms = self._ase_atoms_from_molecule_in(calc)
        return Gradient(-ase_atoms.get_forces(), units="eV Å^-1")

    def coordinates_from(self, calc: "CalculationExecutor") -> Coordinates:
        return calc.molecule.coordinates

    def partial_charges_from(self, calc: "CalculationExecutor") -> List[float]:
        raise NotImplementedInMethod

    def version_in(self, calc: "CalculationExecutor") -> str:
        pass

    @staticmethod
    def input_filename_for(calc: "CalculationExecutor") -> str:
        return "in"

    @staticmethod
    def output_filename_for(calc: "CalculationExecutor") -> str:
        if os.path.exists("out"):
            os.remove("out")
        return "out"

    def generate_input_for(self, calc: "CalculationExecutor") -> None:
        return open("in", "w").close()

    def __repr__(self):
        return "ANI"


def plot_1d_unrelaxed():

    pes = UnRelaxedPES1D(h2o, rs={(0, 1): np.linspace(0.8, 1.5, num=20)})
    pes.calculate(method=ani)

    # matplotlib.use('TkAgg')   # <- I need to set this :shrug
    pes.plot("h2o_1d_unrelaxed.pdf")
    print(pes.relative_energies)


def plot_1d_relaxed():

    pes = RelaxedPESnD(h2o, rs={(0, 1): np.linspace(0.8, 1.5, num=20)})
    pes.calculate(method=ani)

    # ASE opt doesn't respect the fixed bond lengths?!
    print(pes.relative_energies)


if __name__ == '__main__':

    # Parallelism doesn't work..
    ade.Config.n_cores = 1
    mp.set_start_method("spawn", force=True)

    h2o = ade.Molecule(smiles="O")

    ani = ANI(
        ase_calculator=torchani.models.ANI1ccx().ase(),
        executable_name="python",
        keywords_set=KeywordsSet(),
        doi_list=[],
        implicit_solvation_type=None
    )

    # plot_1d_unrelaxed()
    plot_1d_relaxed()

from autode.

t-young31 avatar t-young31 commented on May 24, 2024

v1.3.1 has just been released so the above should now work – please reopen this issue if it doesn't (or anything's unclear/I can be of any more use etc.)

from autode.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.