wulfric.niggli#
- wulfric.niggli(a=1, b=1, c=1, alpha=90, beta=90, gamma=90, eps_rel=0.0001, verbose=False, return_cell=False, max_iter=10000)[source]#
Computes Niggli matrix form.
- Parameters:
- afloat, default 1
Length of the \(\boldsymbol{a_1}\) vector.
- bfloat, default 1
Length of the \(\boldsymbol{a_2}\) vector.
- cfloat, default 1
Length of the \(\boldsymbol{a_3}\) vector.
- alphafloat, default 90
Angle between vectors \(\boldsymbol{a_2}\) and \(\boldsymbol{a_3}\). In degrees.
- betafloat, default 90
Angle between vectors \(\boldsymbol{a_1}\) and \(\boldsymbol{a_3}\). In degrees.
- gammafloat, default 90
Angle between vectors \(\boldsymbol{a_1}\) and \(\boldsymbol{a_2}\). In degrees.
- eps_relfloat, default 1e-5
Relative epsilon as defined in [2].
- verbosebool, default False
Whether to print the steps of an algorithm.
- return_cellbool, default False
Whether to return cell parameters instead of Niggli matrix form.
- max_iterint, default 100000
Maximum number of iterations.
- Returns:
- result(3,2) numpy.ndarray or (6,) tuple of floats
Niggli matrix form as defined in [1]:
\[\begin{split}\begin{pmatrix} A & B & C \\ \xi/2 & \eta/2 & \zeta/2 \end{pmatrix}\end{split}\]If return_cell == True, then returns Niggli cell parameters: (a, b, c, alpha, beta, gamma).
- Raises:
- ValueError
If the niggli cell is not found in
max_iter
iterations.- ValueError
If the provided cell`s volume is zero.
Notes
The parameters are defined as follows:
\[\begin{split}A & = a^2 \\ B & = b^2 \\ C & = c^2 \\ \xi & = 2bc \cos(\alpha) \\ \eta & = 2ac \cos(\beta) \\ \zeta & = 2ab \cos(\gamma)\end{split}\]Steps of an algorithm from original paper [1]:
\(A > B\) or (\(A = B\) and \(|\xi| > |\eta|\)), then swap \((A, \xi) \leftrightarrow (B,\eta)\).
\(B > C\) or (\(B = C\) and \(|\eta| > |\zeta|\)), then swap \((B, \eta) \leftrightarrow (C,\zeta)\) and go to 1.
If \(\xi \eta \zeta > 0\), then put \((|\xi|, |\eta|, |\zeta|) \rightarrow (\xi, \eta, \zeta)\).
If \(\xi \eta \zeta \leq 0\), then put \((-|\xi|, -|\eta|, -|\zeta|) \rightarrow (\xi, \eta, \zeta)\).
If \(|\xi| > B\) or (\(\xi = B\) and \(2\eta < \zeta\)) or (\(\xi = -B\) and \(\zeta < 0\)), then apply the following transformation:
\[\begin{split}C & = B + C - \xi \,\text{sign}(\xi) \\ \eta & = \eta - \zeta \,\text{sign}(\xi) \\ \xi & = \xi - 2B \,\text{sign}(\xi)\end{split}\]and go to 1.
If \(|\eta| > A\) or (\(\eta = A\) and \(2\xi < \zeta\)) or (\(\eta = -A\) and \(\zeta < 0\)), then apply the following transformation:
\[\begin{split}C & = A + C - \eta \,\text{sign}(\eta) \\ \xi & = \xi - \zeta \,\text{sign}(\eta) \\ \eta & = \eta - 2A \,\text{sign}(\eta)\end{split}\]and go to 1.
If \(|\zeta| > A\) or (\(\zeta = A\) and \(2\xi < \eta\)) or (\(\zeta = -A\) and \(\eta < 0\)), then apply the following transformation:
\[\begin{split}B & = A + B - \zeta \,\text{sign}(\zeta) \\ \xi & = \xi - \eta \,\text{sign}(\zeta) \\ \zeta & = \zeta - 2A \,\text{sign}(\zeta)\end{split}\]and go to 1.
If \(\xi + \eta + \zeta + A + B < 0\) or (\(\xi + \eta + \zeta + A + B = 0\) and \(2(A + \eta) + \zeta > 0\)), then apply the following transformation:
\[\begin{split}C & = A + B + C + \xi + \eta + \zeta \\ \xi & = 2B + \xi + \zeta \\ \eta & = 2A + \eta + \zeta\end{split}\]and go to 1.
References
[1] (1,2,3)Křivý, I. and Gruber, B., 1976. A unified algorithm for determining the reduced (Niggli) cell. Acta Crystallographica Section A: Crystal Physics, Diffraction, Theoretical and General Crystallography, 32(2), pp.297-298.
[2]Grosse-Kunstleve, R.W., Sauter, N.K. and Adams, P.D., 2004. Numerically stable algorithms for the computation of reduced unit cells. Acta Crystallographica Section A: Foundations of Crystallography, 60(1), pp.1-6.
Examples
Example from [1] (parameters are reproducing \(A=9\), \(B=27\), \(C=4\), \(\xi\) = -5, \(\eta\) = -4, \(\zeta = -22\)):
>>> import wulfric as wulf >>> from wulfric.constants import TODEGREES >>> from math import acos, sqrt >>> a = 3 >>> b = sqrt(27) >>> c = 2 >>> print(f"{a} {b:.3f} {c}") 3 5.196 2 >>> alpha = acos(-5 / 2 / b / c) * TODEGREES >>> beta = acos(-4 / 2 / a / c) * TODEGREES >>> gamma = acos(-22 / 2 / a / b) * TODEGREES >>> print(f"{alpha:.2f} {beta:.2f} {gamma:.2f}") 103.92 109.47 134.88 >>> niggli_matrix_form = wulf.niggli(a, b, c, alpha, beta, gamma, verbose=True) A B C xi eta zeta start: 9.0000 27.0000 4.0000 -5.0000 -4.0000 -22.0000 2 appl. to 9.0000 27.0000 4.0000 -5.0000 -4.0000 -22.0000 1 appl. to 9.0000 4.0000 27.0000 -5.0000 -22.0000 -4.0000 4 appl. to 4.0000 9.0000 27.0000 -22.0000 -5.0000 -4.0000 5 appl. to 4.0000 9.0000 27.0000 -22.0000 -5.0000 -4.0000 4 appl. to 4.0000 9.0000 14.0000 -4.0000 -9.0000 -4.0000 6 appl. to 4.0000 9.0000 14.0000 -4.0000 -9.0000 -4.0000 4 appl. to 4.0000 9.0000 9.0000 -8.0000 -1.0000 -4.0000 7 appl. to 4.0000 9.0000 9.0000 -8.0000 -1.0000 -4.0000 3 appl. to 4.0000 9.0000 9.0000 -9.0000 -1.0000 4.0000 5 appl. to 4.0000 9.0000 9.0000 9.0000 1.0000 4.0000 3 appl. to 4.0000 9.0000 9.0000 -9.0000 -3.0000 4.0000 result: 4.0000 9.0000 9.0000 9.0000 3.0000 4.0000 >>> niggli_matrix_form array([[4. , 9. , 9. ], [4.5, 1.5, 2. ]])