Skip to content

Commit

Permalink
Rename gp3 to gxtb (#103)
Browse files Browse the repository at this point in the history
* rename GP3-xTB to g-xTB in all files

Signed-off-by: Marcel Müller <[email protected]>

* rename files accordingly

Signed-off-by: Marcel Müller <[email protected]>

---------

Signed-off-by: Marcel Müller <[email protected]>
  • Loading branch information
marcelmbn authored Jan 13, 2025
1 parent c2087b2 commit ebb756d
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 60 deletions.
24 changes: 14 additions & 10 deletions src/mindlessgen/generator/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
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, GXTB, get_gxtb_path
from ..molecules import iterative_optimization, postprocess_mol
from ..prog import ConfigManager

Expand Down Expand Up @@ -45,12 +45,16 @@ def generator(config: ConfigManager) -> tuple[list[Molecule] | None, int]:
config.refine.engine,
config,
get_xtb_path,
get_orca_path, # GP3 cannot be used anyway
get_orca_path, # g-xTB cannot be used anyway
)

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_gxtb_path,
)
else:
postprocess_engine = None
Expand Down Expand Up @@ -266,7 +270,7 @@ def setup_engines(
cfg: ConfigManager,
xtb_path_func: Callable,
orca_path_func: Callable,
gp3_path_func: Callable | None = None,
gxtb_path_func: Callable | None = None,
):
"""
Set up the required engine.
Expand All @@ -287,12 +291,12 @@ def setup_engines(
except ImportError as e:
raise ImportError("orca not found.") from e
return ORCA(path, cfg.orca)
elif engine_type == "gp3":
if gp3_path_func is None:
raise ImportError("No callable function for determining the gp3 path.")
path = gp3_path_func()
elif engine_type == "gxtb":
if gxtb_path_func is None:
raise ImportError("No callable function for determining the g-xTB path.")
path = gxtb_path_func()
if not path:
raise ImportError("'gp3' binary could not be found.")
return GP3(path)
raise ImportError("'gxtb' binary could not be found.")
return GXTB(path)
else:
raise NotImplementedError("Engine not implemented.")
2 changes: 1 addition & 1 deletion src/mindlessgen/prog/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,7 @@ 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"]:
if engine not in ["xtb", "orca", "gxtb"]:
raise ValueError("Postprocess engine can only be xtb or orca.")
self._engine = engine

Expand Down
6 changes: 3 additions & 3 deletions src/mindlessgen/qm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
from .base import QMMethod
from .xtb import XTB, get_xtb_path
from .orca import ORCA, get_orca_path
from .gp3 import GP3, get_gp3_path
from .gxtb import GXTB, get_gxtb_path

__all__ = [
"XTB",
"get_xtb_path",
"QMMethod",
"ORCA",
"get_orca_path",
"GP3",
"get_gp3_path",
"GXTB",
"get_gxtb_path",
]
92 changes: 46 additions & 46 deletions src/mindlessgen/qm/gp3.py → src/mindlessgen/qm/gxtb.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
This module contains all interactions with the GP3-xTB binary
This module contains all interactions with the g-xTB binary
for next-gen tight-binding calculations.
"""

Expand All @@ -12,34 +12,34 @@
from .base import QMMethod


class GP3(QMMethod):
class GXTB(QMMethod):
"""
This class handles all interaction with the GP3 external dependency.
This class handles all interaction with the g-xTB external dependency.
"""

def __init__(self, path: str | Path) -> None:
"""
Initialize the GP3 class.
Initialize the GXTB class.
"""
if isinstance(path, str):
self.path: Path = Path(path).resolve()
elif isinstance(path, Path):
self.path = path
else:
raise TypeError("gp3_path should be a string or a Path object.")
raise TypeError("gxtb_path should be a string or a Path object.")

def singlepoint(self, molecule: Molecule, verbosity: int = 1) -> str:
"""
Perform a single-point calculation using GP3-xTB.
Perform a single-point calculation using g-xTB.
"""

# Create a unique temporary directory using TemporaryDirectory context manager
with TemporaryDirectory(prefix="gp3_") as temp_dir:
with TemporaryDirectory(prefix="gxtb_") as temp_dir:
temp_path = Path(temp_dir).resolve()
# write the molecule to a temporary file
molecule.write_xyz_to_file(str(temp_path / "molecule.xyz"))

# run gp3
# run g-xTB
arguments = [
"-c",
"molecule.xyz",
Expand All @@ -53,19 +53,19 @@ def singlepoint(self, molecule: Molecule, verbosity: int = 1) -> str:
f.write(str(molecule.uhf))

if verbosity > 2:
print(f"Running command: gp3 {' '.join(arguments)}")
print(f"Running command: gxtb {' '.join(arguments)}")

gp3_log_out, gp3_log_err, return_code = self._run(
gxtb_log_out, gxtb_log_err, return_code = self._run(
temp_path=temp_path, arguments=arguments
)
if verbosity > 2:
print(gp3_log_out)
print(gxtb_log_out)
if return_code != 0:
raise RuntimeError(
f"GP3-xTB failed with return code {return_code}:\n{gp3_log_err}"
f"g-xTB failed with return code {return_code}:\n{gxtb_log_err}"
)

return gp3_log_out
return gxtb_log_out

def check_gap(
self, molecule: Molecule, threshold: float = 0.5, verbosity: int = 1
Expand All @@ -83,13 +83,13 @@ def check_gap(

# Perform a single point calculation
try:
gp3_out = self.singlepoint(molecule)
gxtb_out = self.singlepoint(molecule)
except RuntimeError as e:
raise RuntimeError("Single point calculation failed.") from e

# Parse the output to get the gap
hlgap = None
for line in gp3_out.split("\n"):
for line in gxtb_out.split("\n"):
if "gap (eV)" in line and "dE" not in line:
# check if "alpha->alpha" is present in the same line
# then, the line looks as follows:
Expand All @@ -102,79 +102,79 @@ def check_gap(
hlgap = float(line.split()[3])
break
if hlgap is None:
raise ValueError("GP3-xTB gap not determined.")
raise ValueError("g-xTB gap not determined.")

if verbosity > 1:
print(f"GP3-xTB HOMO-LUMO gap: {hlgap:5f}")
print(f"g-xTB HOMO-LUMO gap: {hlgap:5f}")

return hlgap > threshold

def optimize(
self, molecule: Molecule, max_cycles: int | None = None, verbosity: int = 1
) -> Molecule:
"""
Optimize a molecule using GP3-xTB.
Optimize a molecule using g-xTB.
"""
raise NotImplementedError("Optimization is not yet implemented for GP3-xTB.")
raise NotImplementedError("Optimization is not yet implemented for g-xTB.")

def _run(self, temp_path: Path, arguments: list[str]) -> tuple[str, str, int]:
"""
Run GP3-xTB with the given arguments.
Run g-xTB with the given arguments.
Arguments:
arguments (list[str]): The arguments to pass to GP3-xTB.
arguments (list[str]): The arguments to pass to g-xTB.
Returns:
tuple[str, str, int]: The output of the GP3-xTB calculation (stdout and stderr)
tuple[str, str, int]: The output of the g-xTB calculation (stdout and stderr)
and the return code
"""
try:
gp3_out = sp.run(
gxtb_out = sp.run(
[str(self.path)] + arguments,
cwd=temp_path,
capture_output=True,
check=True,
)
# get the output of the GP3-xTB calculation (of both stdout and stderr)
gp3_log_out = gp3_out.stdout.decode("utf8")
gp3_log_err = gp3_out.stderr.decode("utf8")
# get the output of the g-xTB calculation (of both stdout and stderr)
gxtb_log_out = gxtb_out.stdout.decode("utf8")
gxtb_log_err = gxtb_out.stderr.decode("utf8")
if (
"no SCF convergence" in gp3_log_out
or "nuclear repulsion" not in gp3_log_out
"no SCF convergence" in gxtb_log_out
or "nuclear repulsion" not in gxtb_log_out
):
raise sp.CalledProcessError(
1,
str(self.path),
gp3_log_out.encode("utf8"),
gp3_log_err.encode("utf8"),
gxtb_log_out.encode("utf8"),
gxtb_log_err.encode("utf8"),
)
return gp3_log_out, gp3_log_err, 0
return gxtb_log_out, gxtb_log_err, 0
except sp.CalledProcessError as e:
gp3_log_out = e.stdout.decode("utf8")
gp3_log_err = e.stderr.decode("utf8")
return gp3_log_out, gp3_log_err, e.returncode
gxtb_log_out = e.stdout.decode("utf8")
gxtb_log_err = e.stderr.decode("utf8")
return gxtb_log_out, gxtb_log_err, e.returncode


# TODO: 1. Convert this to a @staticmethod of Class GP3
# TODO: 1. Convert this to a @staticmethod of Class GXTB
# 2. Rename to `get_method` or similar to enable an abstract interface
# 3. Add the renamed method to the ABC `QMMethod`
# 4. In `main.py`: Remove the passing of the path finder functions as arguments
# and remove the boiler plate code to make it more general.
def get_gp3_path(binary_name: str | Path | None = None) -> Path:
def get_gxtb_path(binary_name: str | Path | None = None) -> Path:
"""
Get the path to the GP3 binary based on different possible names
Get the path to the g-xTB binary based on different possible names
that are searched for in the PATH.
"""
default_gp3_names: list[str | Path] = ["gp3", "gp3_dev"]
default_gxtb_names: list[str | Path] = ["gxtb", "gxtb_dev"]
# put binary name at the beginning of the lixt to prioritize it
if binary_name is not None:
binary_names = [binary_name] + default_gp3_names
binary_names = [binary_name] + default_gxtb_names
else:
binary_names = default_gp3_names
# Get gp3 path from 'which gp3' command
binary_names = default_gxtb_names
# Get g-xTB path from 'which gxtb' command
for binpath in binary_names:
which_gp3 = shutil.which(binpath)
if which_gp3:
gp3_path = Path(which_gp3).resolve()
return gp3_path
raise ImportError("'gp3' binary could not be found.")
which_gxtb = shutil.which(binpath)
if which_gxtb:
gxtb_path = Path(which_gxtb).resolve()
return gxtb_path
raise ImportError("'gxtb' binary could not be found.")

0 comments on commit ebb756d

Please sign in to comment.