Skip to content

Calculation-based API

All calculations are run using the core Calculation object.

Manually initializing it allows for careful setup of the options that should be passed to xtb or crest on the command line, but is somewhat time-consuming.

For convenience, therefore, various class methods are made available that construct appropriate Calculation objects for specific runtypes, with method names corresponding to the respective xtb or crest runtypes.

easyxtb.Calculation

Calculation(program: Program, runtype: str | None = None, runtype_args: list | None = None, options: dict | None = None, command: list | None = None, input_geometry: Geometry | None = None, calc_dir: PathLike | None = None)

A convenience object to prepare, launch, and hold the results of calculations.

options are the flags passed to xtb or crest and should be given without preceding minuses, as the appropriate number will be added automatically. To use a flag that takes no argument, set the value to True. Flags with values of False or None will not be passed.

Geometry objects passed as items in runtype_args or command or as values in options will be saved as XYZ files and the path to the file will be put in the command in its place.

Note that any contents of calc_dir will be removed when the calculation begins.

Source code in easyxtb/calc.py
def __init__(
    self,
    program: Program,
    runtype: str | None = None,
    runtype_args: list | None = None,
    options: dict | None = None,
    command: list | None = None,
    input_geometry: Geometry | None = None,
    calc_dir: os.PathLike | None = None,
):
    """A convenience object to prepare, launch, and hold the results of
    calculations.

    `options` are the flags passed to `xtb` or `crest` and should be given
    without preceding minuses, as the appropriate number will be added
    automatically.
    To use a flag that takes no argument, set the value to `True`.
    Flags with values of `False` or `None` will not be passed.

    `Geometry` objects passed as items in `runtype_args` or `command` or as values
    in `options` will be saved as XYZ files and the path to the file will be put in
    the command in its place.

    Note that any contents of `calc_dir` will be removed when the calculation
    begins.
    """
    self.program = program
    if runtype:
        self.runtype = runtype
    elif options:
        # Runtype not specified but options were passed, so default runtype (single
        # point) is being requested
        self.runtype = None
    elif command:
        # User has passed full command themselves
        first_flag = command.split()[0].lstrip("-")
        if first_flag in self.program.runtypes:
            self.runtype = first_flag
    else:
        # Just a simple single point with no special options or flags or anything
        self.runtype = None
    self.runtype_args = runtype_args if runtype_args else []
    self.options = options if options else {}
    self.command = command
    self.input_geometry = input_geometry
    self.calc_dir = Path(calc_dir) if calc_dir else TEMP_DIR
    logger.info(f"New Calculation created for runtype {self.runtype} with {self.program.name}")

easyxtb.Calculation.preview_command

preview_command()

Return the command that will be used to run xtb or crest based on the current attributes of the Calculation.

Source code in easyxtb/calc.py
def preview_command(self):
    """Return the command that will be used to run xtb or crest based on the current
    attributes of the `Calculation`."""
    if self.command:
        # If arguments were passed by the user, use them as is
        command = self.command
    elif self.program.name == "crest":
        # CREST parses command line input in a slightly different way to xtb
        command = self._build_crest_command(self.input_geometry)
    else:
        command = self._build_xtb_command(self.input_geometry)
    return command

easyxtb.Calculation.run

run()

Run calculation with xtb or crest, storing the output, the saved output file, and the parsed energy, as well as the subprocess object.

Source code in easyxtb/calc.py
def run(self):
    """Run calculation with xtb or crest, storing the output, the saved output file,
    and the parsed energy, as well as the `subprocess` object."""

    logger.debug(f"Calculation of runtype {self.runtype} has been asked to run")
    logger.debug(f"The calculation will be run in the following directory: {self.calc_dir}")

    # Make sure directory nominated for calculation exists and is empty
    if self.calc_dir.exists():
        for x in self.calc_dir.iterdir():
            if x.is_file():
                x.unlink()
            elif x.is_dir():
                rmtree(x)
    else:
        self.calc_dir.mkdir(parents=True)

    # Save geometry to file
    geom_file = self.calc_dir / "input.xyz"
    logger.debug(f"Saving input geometry to {geom_file}")
    self.input_geometry.write_xyz(geom_file)

    self.output_file = geom_file.with_name("output.out")

    # Build command line args
    if self.command:
        # If arguments were passed by the user, use them as is
        command = self.command
    elif self.program.name == "crest":
        # CREST parses command line input in a slightly different way to xtb
        command = self._build_crest_command(geom_file)
    else:
        command = self._build_xtb_command(geom_file)
    # Replace any Geometry objects with paths to files
    aux_count = 0
    for i, arg in enumerate(command):
        if isinstance(arg, Geometry):
            aux_count += 1
            aux_file = arg.write_xyz(self.calc_dir / f"aux{aux_count}.xyz")
            command[i] = aux_file
    # Sanitize everything to strings
    command = [x if isinstance(x, str) else str(x) for x in command]
    logger.debug(f"Calculation will be run with the command: {' '.join(command)}")

    # Run xtb or crest from command line
    logger.debug(
        f"Running calculation in new subprocess using {self.calc_dir} as the working directory..."
    )
    subproc = subprocess.run(command, capture_output=True, encoding="utf-8", cwd=self.calc_dir)
    logger.debug("...calculation complete.")

    # Store output
    self.output = subproc.stdout
    # Also save it to file
    with open(self.output_file, "w", encoding="utf-8") as f:
        f.write(self.output)
        logger.debug(f"Calculation output saved to {self.output_file}")

    # Store the subprocess.CompletedProcess object too
    self.subproc = subproc

    # Do all post-calculation processing according to which program was run
    if self.program.name == "crest":
        self.process_crest()
    else:
        self.process_xtb()

easyxtb.Calculation.sp classmethod

sp(input_geometry: Geometry, solvation: str | None = None, method: int | None = None, n_proc: int | None = None, molden: bool = False, options: dict | None = None)

Construct a Calculation for an xtb single-point energy calculation.

If molden is True, a print-out of the molecular orbitals in Molden format will be requested.

Parameters:

  • input_geometry (Geometry) –
  • solvation (str | None, default: None ) –

    Sets the implicit solvent via the --alpb command line option.

  • method (int | None, default: None ) –

    Sets the parameterization of GFN-xTB to use via the --gfn command line option.

  • n_proc (int | None, default: None ) –

    Indicates the number of parallel threads the program should use via the -P command line option.

  • molden (bool, default: False ) –

    Whether to request a Molden-format MO print-out.

  • options (dict | None, default: None ) –

    Further command line options (see Calculation).

Source code in easyxtb/calc.py
@classmethod
def sp(
    cls,
    input_geometry: Geometry,
    solvation: str | None = None,
    method: int | None = None,
    n_proc: int | None = None,
    molden: bool = False,
    options: dict | None = None,
):
    """Construct a Calculation for an `xtb` single-point energy calculation.

    If `molden` is `True`, a print-out of the molecular orbitals in Molden format
    will be requested.

    Parameters
    ----------
    input_geometry
    solvation
        Sets the implicit solvent via the `--alpb` command line option.
    method
        Sets the parameterization of GFN-xTB to use via the `--gfn` command line
        option.
    n_proc
        Indicates the number of parallel threads the program should use via the `-P`
        command line option.
    molden
        Whether to request a Molden-format MO print-out.
    options
        Further command line options (see `Calculation`).
    """

    options = options if options else {}
    return cls(
        program=XTB,
        input_geometry=input_geometry,
        options={
            "gfn": method if method else config["method"],
            "alpb": solvation if solvation else config["solvent"],
            "P": n_proc if n_proc else config["n_proc"],
            "molden": molden,
        }
        | options,
    )

easyxtb.Calculation.opt classmethod

opt(input_geometry: Geometry, level: str | None = None, solvation: str | None = None, method: int | None = None, n_proc: int | None = None, options: dict | None = None)

Construct a Calculation for an xtb geometry optimization.

Corresponds to the --opt runtype.

Parameters:

  • input_geometry (Geometry) –
  • level (str | None, default: None ) –

    Sets the optimization level.

  • solvation (str | None, default: None ) –

    Sets the implicit solvent via the --alpb command line option.

  • method (int | None, default: None ) –

    Sets the parameterization of GFN-xTB to use via the --gfn command line option.

  • n_proc (int | None, default: None ) –

    Indicates the number of parallel threads the program should use via the -P command line option.

  • options (dict | None, default: None ) –

    Further command line options (see Calculation).

Source code in easyxtb/calc.py
@classmethod
def opt(
    cls,
    input_geometry: Geometry,
    level: str | None = None,
    solvation: str | None = None,
    method: int | None = None,
    n_proc: int | None = None,
    options: dict | None = None,
):
    """Construct a Calculation for an `xtb` geometry optimization.

    Corresponds to the `--opt` runtype.

    Parameters
    ----------
    input_geometry
    level
        Sets the optimization level.
    solvation
        Sets the implicit solvent via the `--alpb` command line option.
    method
        Sets the parameterization of GFN-xTB to use via the `--gfn` command line
        option.
    n_proc
        Indicates the number of parallel threads the program should use via the `-P`
        command line option.
    options
        Further command line options (see `Calculation`).
    """

    options = options if options else {}
    return cls(
        program=XTB,
        input_geometry=input_geometry,
        runtype="opt",
        runtype_args=[level] if level else [config["opt_lvl"]],
        options={
            "gfn": method if method else config["method"],
            "alpb": solvation if solvation else config["solvent"],
            "P": n_proc if n_proc else config["n_proc"],
        }
        | options,
    )

easyxtb.Calculation.hess classmethod

hess(input_geometry: Geometry, solvation: str | None = None, method: int | None = None, n_proc: int | None = None, options: dict | None = None)

Construct a Calculation for an xtb vibrational frequency calculation.

Corresponds to the --hess runtype.

Source code in easyxtb/calc.py
@classmethod
def hess(
    cls,
    input_geometry: Geometry,
    solvation: str | None = None,
    method: int | None = None,
    n_proc: int | None = None,
    options: dict | None = None,
):
    """Construct a Calculation for an `xtb` vibrational frequency calculation.

    Corresponds to the `--hess` runtype.
    """

    options = options if options else {}
    return cls(
        program=XTB,
        input_geometry=input_geometry,
        runtype="hess",
        options={
            "gfn": method if method else config["method"],
            "alpb": solvation if solvation else config["solvent"],
            "P": n_proc if n_proc else config["n_proc"],
        }
        | options,
    )

easyxtb.Calculation.ohess classmethod

ohess(input_geometry: Geometry, level: str | None = None, solvation: str | None = None, method: int | None = None, n_proc: int | None = None, options: dict | None = None)

Construct a Calculation for a combined geometry optimization and frequency calculation with xtb.

Corresponds to the --ohess runtype.

Source code in easyxtb/calc.py
@classmethod
def ohess(
    cls,
    input_geometry: Geometry,
    level: str | None = None,
    solvation: str | None = None,
    method: int | None = None,
    n_proc: int | None = None,
    options: dict | None = None,
):
    """Construct a Calculation for a combined geometry optimization and frequency
    calculation with `xtb`.

    Corresponds to the `--ohess` runtype.
    """

    options = options if options else {}
    options = {
        "gfn": method if method else config["method"],
        "alpb": solvation if solvation else config["solvent"],
        "P": n_proc if n_proc else config["n_proc"],
    } | options
    return cls(
        program=XTB,
        input_geometry=input_geometry,
        runtype="ohess",
        runtype_args=[level] if level else [config["opt_lvl"]],
        options=options,
    )

easyxtb.Calculation.v3 classmethod

v3(input_geometry: Geometry, solvation: str | None = None, method: int | None = None, ewin: int | float = 6, hess: bool = False, n_proc: int | None = None, options: dict | None = None)

Construct a Calculation for a conformer ensemble generation with crest.

Corresponds to the default --v3 runtype.

All conformers within ewin kcal/mol are kept. If hess=True, vibrational frequencies are calculated and the conformers reordered by Gibbs energy.

Source code in easyxtb/calc.py
@classmethod
def v3(
    cls,
    input_geometry: Geometry,
    solvation: str | None = None,
    method: int | None = None,
    ewin: int | float = 6,
    hess: bool = False,
    n_proc: int | None = None,
    options: dict | None = None,
):
    """Construct a Calculation for a conformer ensemble generation with `crest`.

    Corresponds to the default `--v3` runtype.

    All conformers within `ewin` kcal/mol are kept.
    If hess=True, vibrational frequencies are calculated and the conformers reordered by Gibbs energy.
    """
    method_flag = f"gfn{method}" if method else f'gfn{config["method"]}'
    options = options if options else {}
    return cls(
        program=CREST,
        input_geometry=input_geometry,
        runtype="v3",
        options={
            "xnam": XTB.path,
            method_flag: True,
            "alpb": solvation if solvation else config["solvent"],
            "ewin": ewin,
            "prop": "hess" if hess else False,
            "T": n_proc if n_proc else config["n_proc"],
        }
        | options,
    )

easyxtb.Calculation.tautomerize classmethod

tautomerize(input_geometry: Geometry, solvation: str | None = None, method: int | None = None, n_proc: int | None = None, options: dict | None = None)

Sample prototropic tautomers and return set of tautomer Geometries and energies.

The returned tautomers are ordered from lowest to highest energy.

Source code in easyxtb/calc.py
@classmethod
def tautomerize(
    cls,
    input_geometry: Geometry,
    solvation: str | None = None,
    method: int | None = None,
    n_proc: int | None = None,
    options: dict | None = None,
):
    """Sample prototropic tautomers and return set of tautomer Geometries and energies.

    The returned tautomers are ordered from lowest to highest energy.
    """
    method_flag = f"gfn{method}" if method else f'gfn{config["method"]}'
    options = options if options else {}
    return cls(
        program=CREST,
        input_geometry=input_geometry,
        runtype="tautomerize",
        options={
            "xnam": XTB.path,
            method_flag: True,
            "alpb": solvation if solvation else config["solvent"],
            "T": n_proc if n_proc else config["n_proc"],
        }
        | options,
    )

easyxtb.Calculation.protonate classmethod

protonate(input_geometry: Geometry, solvation: str | None = None, method: int | None = None, n_proc: int | None = None, options: dict | None = None)

Screen possible protonation sites and return set of tautomer Geometries and energies.

The returned tautomers are ordered from lowest to highest energy.

Source code in easyxtb/calc.py
@classmethod
def protonate(
    cls,
    input_geometry: Geometry,
    solvation: str | None = None,
    method: int | None = None,
    n_proc: int | None = None,
    options: dict | None = None,
):
    """Screen possible protonation sites and return set of tautomer Geometries and energies.

    The returned tautomers are ordered from lowest to highest energy.
    """
    method_flag = f"gfn{method}" if method else f'gfn{config["method"]}'
    options = options if options else {}
    return cls(
        program=CREST,
        input_geometry=input_geometry,
        runtype="protonate",
        options={
            "xnam": XTB.path,
            method_flag: True,
            "alpb": solvation if solvation else config["solvent"],
            "T": n_proc if n_proc else config["n_proc"],
        }
        | options,
    )

easyxtb.Calculation.deprotonate classmethod

deprotonate(input_geometry: Geometry, solvation: str | None = None, method: int | None = None, n_proc: int | None = None, options: dict | None = None)

Screen possible deprotonation sites and return set of tautomer Geometries and energies.

The returned tautomers are ordered from lowest to highest energy.

Source code in easyxtb/calc.py
@classmethod
def deprotonate(
    cls,
    input_geometry: Geometry,
    solvation: str | None = None,
    method: int | None = None,
    n_proc: int | None = None,
    options: dict | None = None,
):
    """Screen possible deprotonation sites and return set of tautomer Geometries and energies.

    The returned tautomers are ordered from lowest to highest energy.
    """
    method_flag = f"gfn{method}" if method else f'gfn{config["method"]}'
    options = options if options else {}
    return cls(
        program=CREST,
        input_geometry=input_geometry,
        runtype="deprotonate",
        options={
            "xnam": XTB.path,
            method_flag: True,
            "alpb": solvation if solvation else config["solvent"],
            "T": n_proc if n_proc else config["n_proc"],
        }
        | options,
    )

easyxtb.Calculation.qcg classmethod

qcg(solute_geometry: Geometry, solvent_geometry: Geometry, nsolv: int, method: int | None = None, n_proc: int | None = None, options: dict | None = None)

Grow a solvent shell around a solute for a total of nsolv solvent molecules.

Note that non-zero charge and spin on the solvent Geometry will not be passed to CREST.

Source code in easyxtb/calc.py
@classmethod
def qcg(
    cls,
    solute_geometry: Geometry,
    solvent_geometry: Geometry,
    nsolv: int,
    method: int | None = None,
    n_proc: int | None = None,
    options: dict | None = None,
):
    """Grow a solvent shell around a solute for a total of `nsolv` solvent molecules.

    Note that non-zero charge and spin on the solvent `Geometry` will not be passed to
    CREST.
    """
    method_flag = f"gfn{method}" if method else f'gfn{config["method"]}'
    options = options if options else {}
    return cls(
        program=CREST,
        input_geometry=solute_geometry,
        runtype="qcg",
        runtype_args=[solvent_geometry],
        options={
            "grow": True,
            "nsolv": nsolv,
            "xnam": XTB.path,
            method_flag: True,
            "T": n_proc if n_proc else config["n_proc"],
        }
        | options,
    )