Comments (2)
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 requiredimport 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.
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)
- Using autodE in Interactive python shell causes unusual change in units HOT 7
- Coordinating solvent molecules: THF and LDA HOT 1
- Division and multiplication of `autode.values.Value` creates wrong units
- Constraints are ignored by xTB for Molecule().optimise() HOT 1
- Add different levels of logging? HOT 1
- RFO should update the Hessian
- DIC iterated back-transform possible bug HOT 3
- Clarification / Advice flag `with_complexes` HOT 3
- Implementation IRC Scan HOT 2
- NWChem "driver" arguments within autodE HOT 4
- SVD did not converge: #143 (cont, supposedly fixed by #151) HOT 5
- Issue with SMILES builder HOT 1
- Mismatch in atom ordering if user overrides conformer generation method HOT 1
- Rename autode.opt.coordinates.primitive.Distance and use values for optimisers HOT 2
- NEB should throw an exception if number of images is less than 3
- autode.exceptions.NoConformers(xtb and orca) HOT 5
- Customization of input blocks ORCA HOT 4
- Q-Chem Memory Allocation HOT 3
- Q-Chem TS optimisation nearly converged error HOT 1
- Implement multi-step generic reactions HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from autode.