pyextal.superspace.lattice ========================== .. py:module:: pyextal.superspace.lattice .. autoapi-nested-parse:: 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. :meth:`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 ------- .. autoapisummary:: pyextal.superspace.lattice.SuperspaceLattice Functions --------- .. autoapisummary:: pyextal.superspace.lattice.cell_to_metric Module Contents --------------- .. py:function:: cell_to_metric(cell) Direct-space metric tensor from the six lattice parameters. :param cell: ``(a, b, c, alpha, beta, gamma)`` with lengths in Angstrom and angles in degrees. :type cell: array-like :returns: (3, 3) direct metric tensor ``G``, so that a vector with fractional coordinates ``x`` has length ``sqrt(x @ G @ x)``. :rtype: np.ndarray .. py:class:: SuperspaceLattice(cell, q, check_rank=True, tol=1e-06) A 3D lattice plus ``d`` modulation wave vectors. :ivar cell: The six lattice parameters of the *basic* (average) structure. :vartype cell: tuple :ivar q: (d, 3) modulation wave vectors, in reciprocal lattice units of the basic structure. :vartype q: np.ndarray :ivar d: Number of modulation dimensions, 1 to 3. :vartype d: int :ivar gmx: (3, 3) direct metric tensor. :vartype gmx: np.ndarray :ivar gmxr: (3, 3) reciprocal metric tensor. :vartype gmxr: np.ndarray .. py:attribute:: MAX_D :value: 3 .. py:attribute:: cell .. py:attribute:: q .. py:attribute:: gmx .. py:attribute:: gmxr .. py:attribute:: tol .. py:method:: _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. .. py:property:: d Number of modulation dimensions. :type: int .. py:property:: dim Total superspace dimension, ``3 + d``. :type: int .. py:method:: __repr__() .. py:method:: 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. :param H: (n, 3+d) integer superspace indices, or a single (3+d,) index. :type H: array-like :returns: (n, 3) *non-integral* reciprocal indices ``(h, k, l) + sum_j m_j q_j``, in units of the basic reciprocal cell. :rtype: np.ndarray :raises ValueError: If the last axis is not 3+d long. .. py:method:: g_magnitude(H) Length of the scattering vector, inverse Angstrom. :param H: (n, 3+d) superspace indices. :type H: array-like :returns: (n,) values of ``|S(H)|``. :rtype: np.ndarray .. py:method:: d_spacing(H) Interplanar spacing ``1/|S(H)|`` in Angstrom. :param H: (n, 3+d) superspace indices. :type H: array-like :returns: (n,) spacings; ``inf`` for the direct beam. :rtype: np.ndarray .. py:method:: satellite_order(H) :staticmethod: Satellite order ``sum |m_j|``; zero for a main reflection. :param H: (n, 3+d) superspace indices. :type H: array-like :returns: (n,) integer orders. :rtype: np.ndarray .. py:method:: is_main(H) Whether each reflection is a main reflection. :param H: (n, 3+d) superspace indices. :type H: array-like :returns: (n,) booleans. :rtype: np.ndarray .. py:method:: 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. :param max_n: Half-width of the integer search box. :type max_n: int :param tol: Distance from a reciprocal lattice point, in reciprocal lattice units. The constructor's tolerance when None. :type tol: float, optional :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. :rtype: list[tuple] .. py:method:: 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. :param max_denominator: Largest denominator to accept. :type max_denominator: int :param tol: How close the rational has to be; the constructor's tolerance when None. :type tol: float, optional :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`. :rtype: tuple or None .. py:method:: rank(tol=None) Rank of the Fourier module beyond the three main dimensions. :param tol: Relation tolerance; the constructor's when None. :type tol: float, optional :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. :rtype: int .. py:method:: is_commensurate(tol=None) Whether every q-vector is rational, so an exact 3D supercell exists. :param tol: Rationality tolerance; the constructor's when None. :type tol: float, optional :returns: True when the modulation adds no incommensurate dimension. :rtype: bool .. py:method:: 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. :param max_denominator: Largest denominator to consider when rationalising the q-vectors, and the half-width of the search. :type max_denominator: int :param tol: Rationality tolerance; the constructor's when None. :type tol: float, optional :returns: (3, 3) integer matrix, or None if the structure is genuinely incommensurate and no finite supercell exists. :rtype: np.ndarray or None .. py:method:: _relation_text(n, g) Human-readable form of one integer relation, for the warning.