PowerSpectrum

class featomic.utils.PowerSpectrum(calculator_1: CalculatorBase, calculator_2: CalculatorBase | None = None, types: List[int] | None = None)

Bases: Module

General power spectrum of one or of two calculators.

If calculator_2 is provided, the invariants \(p_{nl}\) are generated by taking quadratic combinations of calculator_1’s spherical expansion \(\rho_{nlm}\) and calculator_2’s spherical expansion \(\nu_{nlm}\) according to Bartók et. al.

\[p_{nl} = \rho_{nlm}^\dagger \cdot \nu_{nlm}\]

where we use the Einstein summation convention. If gradients are present the invariants of those are constructed as

\[\nabla p_{nl} = \nabla \rho_{nlm}^\dagger \cdot \nu_{nlm} + \rho_{nlm}^\dagger \cdot \nabla \nu_{nlm}\]

Note

Currently only supports gradients with respect to positions.

If calculator_2=None invariants are generated by combining the coefficients of the spherical expansion of calculator_1. The spherical expansions given as input can only be featomic.SphericalExpansion or featomic.LodeSphericalExpansion.

Parameters:
  • calculator_1 – first calculator

  • calculator_1 – second calculator

  • types – List of "neighbor_type" to use in the properties of the output. This option might be useful when running the calculation on subset of a whole dataset and trying to join along the sample dimension after the calculation. If None, blocks are filled with "neighbor_type" found in the systems.

Raises:

Example

As an example we calculate the power spectrum for a short range (sr) spherical expansion and a long-range (lr) LODE spherical expansion for a NaCl crystal.

>>> import featomic
>>> import ase

Construct the NaCl crystal

>>> atoms = ase.Atoms(
...     symbols="NaCl",
...     positions=[[0, 0, 0], [0.5, 0.5, 0.5]],
...     pbc=True,
...     cell=[1, 1, 1],
... )

Define the hyper parameters for the short-range spherical expansion

>>> sr_hypers = {
...     "cutoff": {
...         "radius": 1.0,
...         "smoothing": {"type": "ShiftedCosine", "width": 0.5},
...     },
...     "density": {
...         "type": "Gaussian",
...         "width": 0.3,
...     },
...     "basis": {
...         "type": "TensorProduct",
...         "max_angular": 2,
...         "radial": {"type": "Gto", "max_radial": 5},
...     },
... }

Define the hyper parameters for the long-range LODE spherical expansion from the hyper parameters of the short-range spherical expansion

>>> lr_hypers = {
...     "density": {
...         "type": "SmearedPowerLaw",
...         "smearing": 0.3,
...         "exponent": 1,
...     },
...     "basis": {
...         "type": "TensorProduct",
...         "max_angular": 2,
...         "radial": {"type": "Gto", "max_radial": 5, "radius": 1.0},
...     },
... }

Construct the calculators

>>> sr_calculator = featomic.SphericalExpansion(**sr_hypers)
>>> lr_calculator = featomic.LodeSphericalExpansion(**lr_hypers)

Construct the power spectrum calculators and compute the spherical expansion

>>> calculator = featomic.utils.PowerSpectrum(sr_calculator, lr_calculator)
>>> power_spectrum = calculator.compute(atoms)

The resulting invariants are stored as metatensor.TensorMap as for any other calculator

>>> power_spectrum.keys
Labels(
    center_type
        11
        17
)
>>> power_spectrum[0]
TensorBlock
    samples (1): ['system', 'atom']
    components (): []
    properties (432): ['l', 'neighbor_1_type', 'n_1', 'neighbor_2_type', 'n_2']
    gradients: None

See also

If you are interested in the SOAP power spectrum you can the use the faster featomic.SoapPowerSpectrum.

Initialize internal Module state, shared by both nn.Module and ScriptModule.

property name

Name of this calculator.

compute(systems: IntoSystem | List[IntoSystem], gradients: List[str] | None = None, use_native_system: bool = True) TensorMap

Runs a calculation with this calculator on the given systems.

See featomic.calculators.CalculatorBase.compute() for details on the parameters.

Raises:

NotImplementedError – If a spherical expansions contains a gradient with respect to an unknwon parameter.

forward(systems: IntoSystem | List[IntoSystem], gradients: List[str] | None = None, use_native_system: bool = True) TensorMap

Calls the PowerSpectrum.compute() function.

This is intended for torch.nn.Module compatibility, and should be ignored in pure Python mode.