Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for Turbomole #101

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- support for `python-3.13`
- option to set a fixed molecular charge, while ensuring `uhf = 0`
- `element_composition` and `forbidden_elements` can now be directly set to a `dict` or `list`, respectively, via API access
- support for the qm program turbomole.
jonathan-schoeps marked this conversation as resolved.
Show resolved Hide resolved

### Breaking Changes
- Removal of the `dist_threshold` flag and in the `-toml` file.
Expand Down
12 changes: 11 additions & 1 deletion mindlessgen.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ hlgap = 0.5
debug = false

[postprocess]
# > Engine for the post-processing part. Options: 'xtb', 'orca'
# > Engine for the post-processing part. Options: 'xtb', 'orca', 'turbomole'
engine = "orca"
# > Optimize geometry in the post-processing part. If `false`, only a single-point is conducted. Options: <bool>
optimize = true
Expand Down Expand Up @@ -88,3 +88,13 @@ basis = "def2-SVP"
gridsize = 1
# > Maximum number of SCF cycles: Options: <int>
scf_cycles = 100

[turbomole]
# > Path to the turbomole executable. The names `ridft` and `jobex` are automatically searched for. Options: <str | Path>
turbomole_path = "/path/to/turbomole"
# > Functional/Method: Options: <str>
functional = "PBE"
# > Basis set: Options: <str>
basis = "def2-SVP"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tested if this combination works if you directly use this mindlessgen.toml? If yes, just resolve this question.

# > Maximum number of SCF cycles: Options: <int>
scf_cycles = 100
27 changes: 25 additions & 2 deletions src/mindlessgen/generator/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,16 @@
import warnings

from ..molecules import generate_random_molecule, Molecule
from ..qm import XTB, get_xtb_path, QMMethod, ORCA, get_orca_path, GP3, get_gp3_path
from ..qm import (
XTB,
get_xtb_path,
QMMethod,
ORCA,
get_orca_path,
GP3,
Turbomole,
get_turbomole_path,
)
from ..molecules import iterative_optimization, postprocess_mol
from ..prog import ConfigManager

Expand Down Expand Up @@ -46,11 +55,16 @@ def generator(config: ConfigManager) -> tuple[list[Molecule] | None, int]:
config,
get_xtb_path,
get_orca_path, # GP3 cannot be used anyway
get_turbomole_path,
)

if config.general.postprocess:
postprocess_engine: QMMethod | None = setup_engines(
config.postprocess.engine, config, get_xtb_path, get_orca_path, get_gp3_path
config.postprocess.engine,
config,
get_xtb_path,
get_orca_path,
get_turbomole_path,
)
else:
postprocess_engine = None
Expand Down Expand Up @@ -266,6 +280,7 @@ def setup_engines(
cfg: ConfigManager,
xtb_path_func: Callable,
orca_path_func: Callable,
turbomole_path_func: Callable,
gp3_path_func: Callable | None = None,
):
"""
Expand All @@ -287,6 +302,14 @@ def setup_engines(
except ImportError as e:
raise ImportError("orca not found.") from e
return ORCA(path, cfg.orca)
elif engine_type == "turbomole":
try:
path = turbomole_path_func(cfg.turbomole.turbomole_path)
if not path:
raise ImportError("turbomole not found.")
except ImportError as e:
raise ImportError("turbomole not found.") from e
return Turbomole(path, cfg.turbomole)
elif engine_type == "gp3":
if gp3_path_func is None:
raise ImportError("No callable function for determining the gp3 path.")
Expand Down
2 changes: 2 additions & 0 deletions src/mindlessgen/prog/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
GeneralConfig,
XTBConfig,
ORCAConfig,
TURBOMOLEConfig,
GenerateConfig,
RefineConfig,
PostProcessConfig,
Expand All @@ -17,6 +18,7 @@
"GeneralConfig",
"XTBConfig",
"ORCAConfig",
"TURBOMOLEConfig",
"GenerateConfig",
"RefineConfig",
"PostProcessConfig",
Expand Down
96 changes: 92 additions & 4 deletions src/mindlessgen/prog/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -656,8 +656,8 @@ def engine(self, engine: str):
"""
if not isinstance(engine, str):
raise TypeError("Refinement engine should be a string.")
if engine not in ["xtb", "orca"]:
raise ValueError("Refinement engine can only be xtb or orca.")
if engine not in ["xtb", "orca", "turbomole"]:
raise ValueError("Refinement engine can only be xtb, orca or turbomole.")
self._engine = engine

@property
Expand Down Expand Up @@ -723,8 +723,8 @@ def engine(self, engine: str):
"""
if not isinstance(engine, str):
raise TypeError("Postprocess engine should be a string.")
if engine not in ["xtb", "orca", "gp3"]:
raise ValueError("Postprocess engine can only be xtb or orca.")
if engine not in ["xtb", "orca", "gp3", "turbomole"]:
raise ValueError("Postprocess engine can only be xtb, orca or turbomole.")
self._engine = engine

@property
Expand Down Expand Up @@ -925,6 +925,87 @@ def scf_cycles(self, max_scf_cycles: int):
self._scf_cycles = max_scf_cycles


class TURBOMOLEConfig(BaseConfig):
"""
Configuration class for TURBOMOLE.
"""

def __init__(self: TURBOMOLEConfig) -> None:
self._turbomole_path: str | Path = "turbomole"
self._functional: str = "pbe"
self._basis: str = "def2-SVP"
self._scf_cycles: int = 100

def get_identifier(self) -> str:
return "turbomole"

@property
def turbomole_path(self):
"""
Get the turbomole path.
"""
return self._turbomole_path

@turbomole_path.setter
def turbomole_path(self, turbomole_path: str | Path):
"""
Set the turbomole path.
"""
if not isinstance(turbomole_path, str | Path):
raise TypeError("turbomole_path should be a string or Path.")
self._turbomole_path = turbomole_path

@property
def functional(self):
"""
Get the TURBOMOLE functional/method.
"""
return self._functional

@functional.setter
def functional(self, functional: str):
"""
Set the TURBOMOLE functional/method.
"""
if not isinstance(functional, str):
raise TypeError("Functional should be a string.")
self._functional = functional

@property
def basis(self):
"""
Get the TURBOMOLE basis set.
"""
return self._basis

@basis.setter
def basis(self, basis: str):
"""
Set the TURBOMOLE basis set.
"""
if not isinstance(basis, str):
raise TypeError("Basis should be a string.")
self._basis = basis

@property
def scf_cycles(self):
"""
Get the maximum number of SCF cycles.
"""
return self._scf_cycles

@scf_cycles.setter
def scf_cycles(self, max_scf_cycles: int):
"""
Set the maximum number of SCF cycles.
"""
if not isinstance(max_scf_cycles, int):
raise TypeError("Max SCF cycles should be an integer.")
if max_scf_cycles < 1:
raise ValueError("Max SCF cycles should be greater than 0.")
self._scf_cycles = max_scf_cycles


class ConfigManager:
"""
Overall configuration manager for the program.
Expand All @@ -937,6 +1018,7 @@ def __init__(self, config_file: str | Path | None = None):
self.general = GeneralConfig()
self.xtb = XTBConfig()
self.orca = ORCAConfig()
self.turbomole = TURBOMOLEConfig()
self.refine = RefineConfig()
self.postprocess = PostProcessConfig()
self.generate = GenerateConfig()
Expand Down Expand Up @@ -1026,6 +1108,9 @@ def load_from_toml(self, config_file: str | Path) -> None:
[orca]
orca_option = "opt"

[turbomole]
turbomole_option = "opt"

Arguments:
config_file (str): Path to the configuration file

Expand All @@ -1048,6 +1133,9 @@ def load_from_dict(self, config_dict: dict) -> None:
},
"orca": {
"orca_option": "opt"
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a simplified and exemplary structure only anyway. You can make this whole dictionary example also a bit shorter to save some lines of code (or comment, in this case).

"turbomole": {
"turbomole_option": "opt"
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/mindlessgen/qm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .xtb import XTB, get_xtb_path
from .orca import ORCA, get_orca_path
from .gp3 import GP3, get_gp3_path
from .tm import Turbomole, get_turbomole_path

__all__ = [
"XTB",
Expand All @@ -15,4 +16,6 @@
"get_orca_path",
"GP3",
"get_gp3_path",
"Turbomole",
"get_turbomole_path",
]
Loading
Loading