Source code for atomate2.turbomole.sets.core

"""Module defining core atomate2-turbomole input set generators."""

from __future__ import annotations

import json
from dataclasses import dataclass, field

import numpy as np
from pymatgen.core import Molecule, Structure
from turbomoleio.core.control import cpc
from turbomoleio.core.molecule import MoleculeSystem
from turbomoleio.core.periodic import PeriodicSystem

from atomate2.turbomole.sets.base import (
    BaseTurbomoleInputGenerator,
    DefineInputSet,
    TurbomoleInputSet,
)
from atomate2.turbomole.utils import get_define_parameters


[docs] @dataclass class TurbomoleDefineInputGenerator(BaseTurbomoleInputGenerator): """A class to generate Turbomole input sets.""" define_template: str | None = None define_parameters: dict = field(default_factory=dict) user_define_parameters_settings: dict = field(default_factory=dict) user_datagroups_settings: dict = field(default_factory=dict) use_system_charge: bool = True use_system_multiplicity: bool = False
[docs] def get_input_set( self, system: MoleculeSystem | PeriodicSystem | Molecule | Structure, charge=None, unpaired_electrons=None, ) -> DefineInputSet: """ Generate a DefineInputSet object. Parameters ---------- system either a pymatgen Molecule or Structure or a turbomoleio MoleculeSystem or PeriodicSystem. charge charge of the system. unpaired_electrons number of unpaired electrons. Returns ------- a DefineInputSet object TODO: can we use pydantic to make sure system is of the correct kind? """ # Define the system if isinstance(system, Molecule): system = MoleculeSystem(system) elif isinstance(system, Structure): system = PeriodicSystem(system) elif not isinstance( # pragma: no branch (trivial) system, (MoleculeSystem, PeriodicSystem) ): raise RuntimeError( 'The "molecule_or_structure" input should be a pymatgen ' "Molecule/Structure or a turbomoleio MoleculeSystem/PeriodicSystem." ) # Get the define parameters dp = get_define_parameters(self.define_template, self.define_parameters) if unpaired_electrons is not None: dp["unpaired_electrons"] = unpaired_electrons elif self.use_system_multiplicity: # pragma: no branch (trivial) raise NotImplementedError( "multiplicity from the system not yet implemented." ) if charge is not None: dp["charge"] = charge elif dp.get("charge", None) is None and self.use_system_charge: dp["charge"] = system._molecule_or_structure.charge # Charges should be integers if dp.get("charge", None) is not None: int_charge = int(np.around(dp["charge"])) if not np.isclose(int_charge, dp["charge"]): raise ValueError("Charge is not close to an integer.") dp["charge"] = int_charge # The exchange-correlation functional should be set outside of define as it # does not know about libxc functionals func = dp.pop("functional", None) return DefineInputSet( inputs={ "coord": system.to_coord_string(), "define_parameters.json": json.dumps(dp), "datagroups.json": json.dumps(self.user_datagroups_settings), }, xc_func=func, datagroups=self.user_datagroups_settings, define_parameters=dp, system=system, )
[docs] @dataclass class TurbomoleInputGenerator(BaseTurbomoleInputGenerator): """A class to generate Turbomole input sets."""
[docs] def get_input_set(self, prev_output=None) -> TurbomoleInputSet: """ Generate a TurbomoleInputSet object. TODO: what kind of file is prev_output? """ if prev_output is not None: cpc(".", control_dir=prev_output) return TurbomoleInputSet()
[docs] @dataclass class DscfInputGenerator(TurbomoleInputGenerator): """A class to generate Turbomole input sets."""
[docs] def get_input_set(self, prev_output=None) -> TurbomoleInputSet: """ Generate a TurbomoleInputSet object. TODO: what kind of file is prev_output? """ if prev_output is not None: cpc(".", control_dir=prev_output) return TurbomoleInputSet()