Interface to Spglib#

Wulfric relies on spglib in all its functions that need any information about the crystal's (cell + atoms) symmetry.

>>> import numpy as np
>>> cell = np.array([
...     [0.000000, 4.744935, 0.000000],
...     [3.553350, 0.000000, 0.000000],
...     [0.000000, 0.000000, 8.760497],
... ])
>>> atoms = {
...     "names": ["Cr1", "Br1", "S1", "Cr2", "Br2", "S2"],
...     "positions": np.array([
...         [0.000000, -0.500000,  0.882382],
...         [0.000000, 0.000000,  0.677322],
...         [-0.500000, -0.500000,  0.935321],
...         [0.500000, 0.000000,  0.117618],
...         [0.500000, 0.500000,  0.322678],
...         [0.000000, 0.000000,  0.064679],
...     ]),
... }

As Wulfric is primarily designed as a set of well-defined functions, we face the problem of multiple calls to spglib, when the user wants more than one property.

For example, if the user wants to know both conventional and primitive cells, they can be computed as

>>> import wulfric
>>> conv_cell, conv_atoms = wulfric.crystal.get_conventional(cell, atoms)
>>> prim_cell, prim_atoms = wulfric.crystal.get_primitive(cell, atoms)

However, the conventional cell is required to compute the primitive cell, therefore the function wulfric.crystal.get_conventional() is called twice - once by the user and once within wulfric.crystal.get_primitive().

To solve this problem of executing the code twice (or at least of calling spglib twice, which might be expensive), we isolate the interaction of Wulfric with spglib into a single function wulfric.get_spglib_data(). Then, the same code as above can be rewritten as

>>> import wulfric
>>> spglib_data = wulfric.get_spglib_data(cell, atoms)
>>> conv_cell, conv_atoms = wulfric.crystal.get_conventional(cell, atoms, spglib_data=spglib_data)
>>> prim_cell, prim_atoms = wulfric.crystal.get_primitive(cell, atoms, spglib_data=spglib_data)

In that way spglib is called only once and the data are re-used.

All functions that accept cell and atoms and rely on spglib have optional argument spglib_data that can be passed to them.

Moreover, spglib_data object by itself (which is an inventory of data stored as an instance of the dataclass wulfric.SpglibData) can be used by the user to access additional information derived from spglib:

# Fancy dot syntax
>>> spglib_data.space_group_number
59
>>> spglib_data.crystal_family
'o'
>>> spglib_data.centring_type
'P'

All properties of spglib_data are documented in wulfric.get_spglib_data().