Source code for dxtb._src.calculators.config.integral
# This file is part of dxtb.
#
# SPDX-Identifier: Apache-2.0
# Copyright (C) 2024 Grimme Group
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
Integral configuration.
"""
from __future__ import annotations
from dxtb._src.constants import defaults, labels
from dxtb._src.typing import Literal
__all__ = ["ConfigIntegrals"]
[docs]
class ConfigIntegrals:
"""
Configuration for the integrals.
All configuration options are represented as integers. String options are
converted to integers in the constructor.
"""
cutoff: float
"""
Real-space cutoff (in Bohr) for integral evaluation for PyTorch.
The ``libint`` driver ignores this option.
"""
driver: int
"""Type of integral driver."""
level: int
"""
Indicator for integrals to compute.
- 0: None
- 1: overlap
- 2: +core Hamiltonian
- 3: +dipole
- 4: +quadrupole
"""
uplo: Literal["n", "l", "u"]
"""Integral mode for PyTorch integral calculation."""
def __init__(
self,
*,
level: int = defaults.INTLEVEL,
cutoff: float = defaults.INTCUTOFF,
driver: str | int = defaults.INTDRIVER,
uplo: str = defaults.INTUPLO,
) -> None:
self.cutoff = cutoff
if not isinstance(level, int):
raise TypeError(
f"The received integral level (`{level}`) is not an integer, "
f"but {type(level)}."
)
self.level = level
if uplo not in ("n", "N", "u", "U", "l", "L"):
raise ValueError(f"Unknown option for `uplo` chosen: '{uplo}'.")
self.uplo = uplo.casefold() # type: ignore
if isinstance(driver, str):
if driver.casefold() in labels.INTDRIVER_LIBCINT_STRS:
# pylint: disable=import-outside-toplevel
from dxtb._src.exlibs.available import has_libcint
# The default input is an integer. So, if we receive a string
# here, we need to assume that the libcint driver was
# explicitly requested and we need to check if the libcint
# interface is available.
if has_libcint is False:
raise ValueError(
"The integral driver seems to be have been set "
f"explicitly to '{driver}'. However, the libcint "
"interface is not installed."
)
self.driver = labels.INTDRIVER_LIBCINT
elif driver.casefold() in labels.INTDRIVER_ANALYTICAL_STRS:
self.driver = labels.INTDRIVER_ANALYTICAL
elif driver.casefold() in labels.INTDRIVER_AUTOGRAD_STRS:
self.driver = labels.INTDRIVER_AUTOGRAD
elif driver.casefold() in labels.INTDRIVER_LEGACY_STRS:
self.driver = labels.INTDRIVER_LEGACY
else:
raise ValueError(f"Unknown integral driver '{driver}'.")
elif isinstance(driver, int):
if driver not in (
labels.INTDRIVER_LIBCINT,
labels.INTDRIVER_ANALYTICAL,
labels.INTDRIVER_AUTOGRAD,
labels.INTDRIVER_LEGACY,
):
raise ValueError(f"Unknown integral driver '{driver}'.")
if driver == labels.INTDRIVER_LIBCINT:
# pylint: disable=import-outside-toplevel
from dxtb._src.exlibs.available import has_libcint
# If we receive the default integer here, we issue a warning
# and fall back to the PyTorch driver.
if has_libcint is False:
from dxtb import OutputHandler
OutputHandler.warn(
"The libcint interface is not installed. "
"Falling back to the analytical driver."
)
driver = labels.INTDRIVER_ANALYTICAL
self.driver = driver
else:
raise TypeError(
"The driver must be of type 'int' or 'str', but "
f"'{type(driver)}' was given."
)
def __str__(self) -> str: # pragma: no cover
return (
f"ConfigIntegrals(level={self.level}, cutoff={self.cutoff}, "
f"driver={self.driver}, uplo={self.uplo})"
)
def __repr__(self) -> str: # pragma: no cover
return str(self)