Python API#

Python API of the dftd4 program package

Library interface#

Wrapper around the C-API of the dftd4 shared library. It provides the definition the basic interface to the library for most further integration in other Python frameworks.

The classes defined here allow a more Pythonic usage of the API object provided by the library in actual workflows than the low-level access provided in the CFFI generated wrappers.

Structure#

class dftd4.interface.Structure(numbers, positions, charge=None, lattice=None, periodic=None)[source]#

Represents a wrapped structure object in dftd4. The molecular structure data object has a fixed number of atoms and immutable atomic identifiers

Example

>>> from dftd4.interface import Structure
>>> import numpy as np
>>> mol = Structure(
...     positions=np.array([
...         [+0.00000000000000, +0.00000000000000, -0.73578586109551],
...         [+1.44183152868459, +0.00000000000000, +0.36789293054775],
...         [-1.44183152868459, +0.00000000000000, +0.36789293054775],
...     ]),
...     numbers = np.array([8, 1, 1]),
... )
>>> len(mol)
3
Raises:

ValueError – on invalid input, like incorrect shape / type of the passed arrays

update(positions, lattice=None)[source]#

Update coordinates and lattice parameters, both provided in atomic units (Bohr). The lattice update is optional also for periodic structures.

Generally, only the cartesian coordinates and the lattice parameters can be updated, every other modification, regarding total charge, total spin, boundary condition, atomic types or number of atoms requires the complete reconstruction of the object.

Raises:

ValueError – on invalid input, like incorrect shape / type of the passed arrays

DispersionModel#

class dftd4.interface.DispersionModel(numbers, positions, charge=None, lattice=None, periodic=None, **kwargs)[source]#

Representation of a dispersion model to evaluate C6 coefficients. The model is coupled to the molecular structure it has been created from and cannot be transfered to another molecular structure without recreating it.

Example

>>> from dftd4.interface import DispersionModel
>>> import numpy as np
>>> disp = DispersionModel(
...     positions=np.array([  # Coordinates in Bohr
...         [+0.00000000000000, +0.00000000000000, -0.73578586109551],
...         [+1.44183152868459, +0.00000000000000, +0.36789293054775],
...         [-1.44183152868459, +0.00000000000000, +0.36789293054775],
...     ]),
...     numbers = np.array([8, 1, 1]),
... )
>>> disp.get_properties()["polarizibilities"]
array([6.74893641, 1.33914933, 1.33914933])
Raises:
  • ValueError – on incorrect inputs to for the structure data

  • RuntimeError – in case of an error in library

get_dispersion(param, grad)[source]#

Perform actual evaluation of the dispersion correction.

Example

>>> from dftd4.interface import DampingParam, DispersionModel
>>> import numpy as np
>>> numbers = np.array([1, 1, 6, 5, 1, 15, 8, 17, 13, 15, 5, 1, 9, 15, 1, 15])
>>> positions = np.array([  # Coordinates in Bohr
...     [+2.79274810283778, +3.82998228828316, -2.79287054959216],
...     [-1.43447454186833, +0.43418729987882, +5.53854345129809],
...     [-3.26268343665218, -2.50644032426151, -1.56631149351046],
...     [+2.14548759959147, -0.88798018953965, -2.24592534506187],
...     [-4.30233097423181, -3.93631518670031, -0.48930754109119],
...     [+0.06107643564880, -3.82467931731366, -2.22333344469482],
...     [+0.41168550401858, +0.58105573172764, +5.56854609916143],
...     [+4.41363836635653, +3.92515871809283, +2.57961724984000],
...     [+1.33707758998700, +1.40194471661647, +1.97530004949523],
...     [+3.08342709834868, +1.72520024666801, -4.42666116106828],
...     [-3.02346932078505, +0.04438199934191, -0.27636197425010],
...     [+1.11508390868455, -0.97617412809198, +6.25462847718180],
...     [+0.61938955433011, +2.17903547389232, -6.21279842416963],
...     [-2.67491681346835, +3.00175899761859, +1.05038813614845],
...     [-4.13181080289514, -2.34226739863660, -3.44356159392859],
...     [+2.85007173009739, -2.64884892757600, +0.71010806424206],
... ])
>>> model = DispersionModel(numbers, positions)
>>> res = model.get_dispersion(DampingParam(method="scan"), grad=False)
>>> res.get("energy")  # Results in atomic units
-0.005328888532435093
Raises:

RuntimeError – in case the calculation fails in the library

get_pairwise_dispersion(param)[source]#

Evaluate pairwise representation of the dispersion energy

>>> from dftd4.interface import DispersionModel, DampingParam
>>> import numpy as np
>>> disp = DispersionModel(
...     numbers=np.array([7, 7, 1, 1, 1, 1, 1, 1]),
...     positions=np.array([
...         [-2.983345508575, -0.088082052767, +0.000000000000],
...         [+2.983345508575, +0.088082052767, +0.000000000000],
...         [-4.079203605652, +0.257751166821, +1.529856562614],
...         [-1.605268001556, +1.243804812431, +0.000000000000],
...         [-4.079203605652, +0.257751166821, -1.529856562614],
...         [+4.079203605652, -0.257751166821, -1.529856562614],
...         [+1.605268001556, -1.243804812431, +0.000000000000],
...         [+4.079203605652, -0.257751166821, +1.529856562614],
...     ]),
... )
>>> res = disp.get_pairwise_dispersion(DampingParam(method="tpss"))
>>> res["additive pairwise energy"].sum()
-0.0023605238432524104
>>> res["non-additive pairwise energy"].sum()
8.794562567135391e-08
get_properties()[source]#

Evaluate dispersion related properties, like polarizibilities and C6 coefficients. Will also return the coordination numbers and partial charges used to derive the polarizibilities. Only the static polarizibility is return at the moment.

Example

>>> from dftd4.interface import DispersionModel
>>> import numpy as np
>>> disp = DispersionModel(
...     numbers=np.array([16, 16, 16, 16, 16, 16, 16, 16]),
...     positions=np.array([
...         [-4.15128787379191, +1.71951973863958, -0.93066267097296],
...         [-4.15128787379191, -1.71951973863958, +0.93066267097296],
...         [-1.71951973863958, -4.15128787379191, -0.93066267097296],
...         [+1.71951973863958, -4.15128787379191, +0.93066267097296],
...         [+4.15128787379191, -1.71951973863958, -0.93066267097296],
...         [+4.15128787379191, +1.71951973863958, +0.93066267097296],
...         [+1.71951973863958, +4.15128787379191, -0.93066267097296],
...         [-1.71951973863958, +4.15128787379191, +0.93066267097296],
...     ]),
... )
>>> res = disp.get_properties()
>>> res.get("coordination numbers")
array([1.96273847, 1.96273847, 1.96273847, 1.96273847, 1.96273847,
       1.96273847, 1.96273847, 1.96273847])
>>> res.get("polarizibilities").sum()
158.748605606818

DampingParam#

class dftd4.interface.DampingParam(**kwargs)[source]#

Rational damping function for DFT-D4.

The damping parameters contained in the object are immutable. To change the parametrization, a new object must be created. Furthermore, the object is opaque to the user and the contained data cannot be accessed directly.

There are two main ways provided to generate a new damping parameter object:

  1. a method name is passed to the constructor, the library will load the required data from the dftd4 shared library.

  2. all required parameters are passed to the constructor and the library will generate an object from the given parameters.

Note

Mixing of the two methods is not allowed to avoid partial initialization of any created objects. Users who need full control over the creation of the object should use the second method.

Raises:
  • TypeError – incorrect input values provided to constructor

  • RuntimeError – failed to construct damping parameter object in API

static load_param(method, atm=True)[source]#

Create damping function API object from internal library storage by searching for the provided method name. The method name is case insensitive and hyphens are ignored. In case the method name is unknown an exception is raised.

Example

>>> from dftd4.interface import DampingParam
>>> param = DampingParam(method="pbe", atm=True)
Raises:

RuntimeError – failed to construct damping parameter object in API

static new_param(*, s6=1.0, s8, s9=1.0, a1, a2, alp=16.0)[source]#

Create damping function API object from user provided parameters. This object represent a rational damping function and requires at least the ‘s8’, ‘a1’, and ‘a2’ parameters as input. Additonally, the parameters ‘s6’, ‘s9’, and ‘alp’ can be overwritten. The user provided damping parameters will be used unchecked.

Example

>>> from dftd4.interface import DampingParam
>>> param = DampingParam(s6=0.6400, s8=1.16888646, a1=0.44154604, a2=4.73114642)
Raises:

RuntimeError – failed to construct damping parameter object in API