pyextal.superspace.lattice

The (3+d)-dimensional superspace lattice.

A modulated crystal has no three-dimensional lattice, so its diffraction pattern cannot be indexed with three integers. What it does have is a Fourier module: every reflection sits at

S(H) = h a* + k b* + l c* + m1 q1 + … + md qd

for integers H = (h, k, l, m1, ..., md). The main reflections are the ones with every m zero; the rest are satellites, and the satellite order is sum(abs(m)). This module holds the lattice plus the modulation wave vectors and does that index arithmetic, which is item 1 of the superspace work: the transition from hkl to hkl m1 m2 m3.

Rank is the thing to get right

d q-vectors only give a (3+d)-dimensional description if they are independent modulo the main lattice – that is, if no integer combination sum(n_j q_j) other than the trivial one lands on a reciprocal lattice point. Otherwise some satellites coincide, the superspace group is wrong, and a refinement fits parameters the data cannot separate.

1T-TaS2 is the textbook case. Its charge-density wave is triple-q, with three symmetry-equivalent vectors at 120 degrees, and it is tempting to index it in (3+3)D with all three. But q1 + q2 + q3 = c* exactly – a reciprocal lattice vector – so the three span a rank-2 module and the correct description is (3+2)D, which is what Spijkerman and co-workers used. SuperspaceLattice. integer_relations() finds relations like that one, and the constructor warns when it finds any. Three q-vectors are fully supported; they simply have to be genuinely independent, and this is how you check.

Classes

SuperspaceLattice

A 3D lattice plus d modulation wave vectors.

Functions

cell_to_metric(cell)

Direct-space metric tensor from the six lattice parameters.

Module Contents

pyextal.superspace.lattice.cell_to_metric(cell)

Direct-space metric tensor from the six lattice parameters.

Parameters:

cell (array-like) – (a, b, c, alpha, beta, gamma) with lengths in Angstrom and angles in degrees.

Returns:

(3, 3) direct metric tensor G, so that a vector with fractional coordinates x has length sqrt(x @ G @ x).

Return type:

np.ndarray

class pyextal.superspace.lattice.SuperspaceLattice(cell, q, check_rank=True, tol=1e-06)

A 3D lattice plus d modulation wave vectors.

Variables:
  • cell (tuple) – The six lattice parameters of the basic (average) structure.

  • q (np.ndarray) – (d, 3) modulation wave vectors, in reciprocal lattice units of the basic structure.

  • d (int) – Number of modulation dimensions, 1 to 3.

  • gmx (np.ndarray) – (3, 3) direct metric tensor.

  • gmxr (np.ndarray) – (3, 3) reciprocal metric tensor.

MAX_D = 3
cell
q
gmx
gmxr
tol
_warn_on_rank()

Warn about a rank-deficient q set, distinguishing the two causes.

Commensurate q-vectors are rank-deficient too, but that is a legitimate thing to build – it is the approximant – so it gets its own, quieter message pointing at the supercell rather than telling the user they made a mistake.

property d

Number of modulation dimensions.

Type:

int

property dim

Total superspace dimension, 3 + d.

Type:

int

__repr__()
effective_hkl(H)

The 3D reciprocal-space index a superspace reflection actually sits at.

This is the whole point of the superspace description: a satellite is not at an integral position, so it cannot be named by three integers, but it is at a perfectly well defined place.

Parameters:

H (array-like) – (n, 3+d) integer superspace indices, or a single (3+d,) index.

Returns:

(n, 3) non-integral reciprocal indices (h, k, l) + sum_j m_j q_j, in units of the basic reciprocal cell.

Return type:

np.ndarray

Raises:

ValueError – If the last axis is not 3+d long.

g_magnitude(H)

Length of the scattering vector, inverse Angstrom.

Parameters:

H (array-like) – (n, 3+d) superspace indices.

Returns:

(n,) values of |S(H)|.

Return type:

np.ndarray

d_spacing(H)

Interplanar spacing 1/|S(H)| in Angstrom.

Parameters:

H (array-like) – (n, 3+d) superspace indices.

Returns:

(n,) spacings; inf for the direct beam.

Return type:

np.ndarray

static satellite_order(H)

Satellite order sum |m_j|; zero for a main reflection.

Parameters:

H (array-like) – (n, 3+d) superspace indices.

Returns:

(n,) integer orders.

Return type:

np.ndarray

is_main(H)

Whether each reflection is a main reflection.

Parameters:

H (array-like) – (n, 3+d) superspace indices.

Returns:

(n,) booleans.

Return type:

np.ndarray

integer_relations(max_n=6, tol=None)

Integer combinations of the q-vectors that land on the main lattice.

Each one found means two nominally distinct satellites fall at the same place, so the description carries a dimension the data does not. Searches n in a box of half-width max_n, taking the first of each +/- pair and skipping multiples of a relation already found.

Parameters:
  • max_n (int) – Half-width of the integer search box.

  • tol (float, optional) – Distance from a reciprocal lattice point, in reciprocal lattice units. The constructor’s tolerance when None.

Returns:

(n, g) pairs, n the (d,) integer coefficients and g the (3,) integer reciprocal lattice vector hit. Empty when the q-vectors are properly independent.

Return type:

list[tuple]

rationalise(max_denominator=256, tol=None)

Exact integer form of the q-vectors, when they are all rational.

Returns q_j = p_j / N with a single common denominator. This is what makes commensurability decidable rather than guessed at: a brute-force search for integer relations would have to reach n = 13 to notice that q = (3/13, 1/13, 1/3) is rational, and to n = 39 in three dimensions that is half a million candidates.

Parameters:
  • max_denominator (int) – Largest denominator to accept.

  • tol (float, optional) – How close the rational has to be; the constructor’s tolerance when None.

Returns:

(P, N) with P the (d, 3) integer numerators and N the common denominator, or None if any component is irrational to within tol.

Return type:

tuple or None

rank(tol=None)

Rank of the Fourier module beyond the three main dimensions.

Parameters:

tol (float, optional) – Relation tolerance; the constructor’s when None.

Returns:

The true number of independent modulation dimensions – d when the q-vectors are independent, 0 when they are all rational (a commensurate structure, which is a 3D supercell in disguise), and something between when only some directions are redundant.

Return type:

int

is_commensurate(tol=None)

Whether every q-vector is rational, so an exact 3D supercell exists.

Parameters:

tol (float, optional) – Rationality tolerance; the constructor’s when None.

Returns:

True when the modulation adds no incommensurate dimension.

Return type:

bool

supercell_matrix(max_denominator=64, tol=None)

The smallest 3D supercell in which every satellite is a main reflection.

For rational q-vectors the modulated structure is an ordinary periodic crystal with a larger cell, and that cell is the commensurate approximant – the one thing about a modulated structure the existing Bloch-wave engine can already handle, since it is plain 3D.

The rows of the returned matrix are the supercell’s direct lattice vectors in terms of the basic ones, so a reflection’s supercell index is M @ hkl and the volume ratio is |det M|. The rows are the three shortest independent integer vectors v with every v . q_j integral, which in a rank-3 lattice is guaranteed to be a basis.

Parameters:
  • max_denominator (int) – Largest denominator to consider when rationalising the q-vectors, and the half-width of the search.

  • tol (float, optional) – Rationality tolerance; the constructor’s when None.

Returns:

(3, 3) integer matrix, or None if the structure is genuinely incommensurate and no finite supercell exists.

Return type:

np.ndarray or None

_relation_text(n, g)

Human-readable form of one integer relation, for the warning.