# Python modules documentation¶

## SeeK-path¶

This module contains the main functions to get a path and an explicit path.

seekpath.getpaths.get_explicit_from_implicit(seekpath_output, reference_distance)[source]

Given the output of get_path by seekpath, compute an “explicit” path, i.e. instead of just giving the endpoints and their coordinates, compute a full list of kpoints

Parameters: seekpath_output – a dictionary, the output of seekpath.get_path reference_distance – a reference target distance between neighboring k-points in the path, in units of 1/ang. The actual value will be as close as possible to this value, to have an integer number of points in each path.
seekpath.getpaths.get_explicit_k_path(structure, with_time_reversal=True, reference_distance=0.025, recipe='hpkot', threshold=1e-07, symprec=1e-05, angle_tolerance=-1.0)[source]

Return the kpoint path for band structure (in scaled and absolute coordinates), given a crystal structure, using the paths proposed in the various publications (see description of the ‘recipe’ input parameter). Note that the k-path typically refers to a different unit cell (e.g., the primitive one with some transformation matrix to comply with the conventions in the case of the HPKOT paper). So, one should use the crystal cell provided in output for all calculations, rather than the input ‘structure’.

If you use this module, please cite the paper of the corresponding recipe (see parameter below).

Parameters: structure – The crystal structure for which we want to obtain the suggested path. It should be a tuple in the format accepted by spglib: (cell, positions, numbers), where (if N is the number of atoms): cell is a $$3 \times 3$$ list of floats (cell[0] is the first lattice vector, …) positions is a $$N \times 3$$ list of floats with the atomic coordinates in scaled coordinates (i.e., w.r.t. the cell vectors) numbers is a length-$$N$$ list with integers identifying uniquely the atoms in the cell (e.g., the Z number of the atom, but any other positive non-zero integer will work - e.g. if you want to distinguish two Carbon atoms, you can set one number to 6 and the other to 1006) with_time_reversal – if False, and the group has no inversion symmetry, additional lines are returned. reference_distance – a reference target distance between neighboring k-points in the path, in units of 1/ang. The actual value will be as close as possible to this value, to have an integer number of points in each path. recipe – choose the reference publication that defines the special points and paths. Currently, the following value is implemented: hpkot: HPKOT paper: Y. Hinuma, G. Pizzi, Y. Kumagai, F. Oba, I. Tanaka, Band structure diagram paths based on crystallography, Comp. Mat. Sci. 128, 140 (2017). DOI: 10.1016/j.commatsci.2016.10.015 threshold – the threshold to use to verify if we are in and edge case (e.g., a tetragonal cell, but a==c). For instance, in the tI lattice, if abs(a-c) < threshold, a EdgeCaseWarning is issued. Note that depending on the bravais lattice, the meaning of the threshold is different (angle, length, …) symprec – the symmetry precision used internally by SPGLIB angle_tolerance – the angle_tolerance used internally by SPGLIB

Changed in version 1.8: The key segments has been renamed explicit_segments for consistency.

Returns: a dictionary with a number of keys. They are the same as get_path, plus a few ones: explicit_kpoints_abs: List of the kpoints along the specific path in absolute (Cartesian) coordinates. The two endpoints are always included, independently of the length. explicit_kpoints_rel: List of the kpoints along the specific path in relative (fractional) coordinates (same length as explicit_kpoints_abs). explicit_kpoints_labels: list of strings with kpoints labels. It has the same length as explicit_kpoints_abs and explicit_kpoints_rel. Empty if the point is not a special point. explicit_kpoints_linearcoord: array of floats, giving the coordinate at which to plot the corresponding point. explicit_segments: a list of length-2 tuples, with the start and end index of each segment. Note! The indices are supposed to be used as follows: the labels for the i-th segment are given by:segment_indices = explicit_segments[i] segment_labels = explicit_kpoints_labels[slice(*segment_indices)]  This means, in particular, that if you want the label of the start and end points, you should do: start_label = explicit_kpoints_labels[segment_indices[0]] stop_label = explicit_kpoints_labels[segment_indices[1]-1]  (note the minus one!) Also, note that if explicit_segments[i-1][1] == explicit_segments[i][0] + 1 it means that the point was calculated only once, and it belongs to both paths. Instead, if explicit_segments[i-1][1] == explicit_segments[i][0], then this is a ‘break’ point in the path (e.g., explicit_segments[i-1][1] is the X point, and explicit_segments[i][0] is the R point, and typically in a graphical representation they are shown at the same coordinate, with a label R|X).
seekpath.getpaths.get_path(structure, with_time_reversal=True, recipe='hpkot', threshold=1e-07, symprec=1e-05, angle_tolerance=-1.0)[source]

Return the kpoint path information for band structure given a crystal structure, using the paths from the chosen recipe/reference.

If you use this module, please cite the paper of the corresponding recipe (see parameter below).

Parameters: structure – The crystal structure for which we want to obtain the suggested path. It should be a tuple in the format accepted by spglib: (cell, positions, numbers), where (if N is the number of atoms): cell is a $$3 \times 3$$ list of floats (cell[0] is the first lattice vector, …) positions is a $$N \times 3$$ list of floats with the atomic coordinates in scaled coordinates (i.e., w.r.t. the cell vectors) numbers is a length-$$N$$ list with integers identifying uniquely the atoms in the cell (e.g., the Z number of the atom, but any other positive non-zero integer will work - e.g. if you want to distinguish two Carbon atoms, you can set one number to 6 and the other to 1006) with_time_reversal – if False, and the group has no inversion symmetry, additional lines are returned as described in the HPKOT paper. recipe – choose the reference publication that defines the special points and paths. Currently, the following value is implemented: hpkot: HPKOT paper: Y. Hinuma, G. Pizzi, Y. Kumagai, F. Oba, I. Tanaka, Band structure diagram paths based on crystallography, Comp. Mat. Sci. 128, 140 (2017). DOI: 10.1016/j.commatsci.2016.10.015 threshold – the threshold to use to verify if we are in and edge case (e.g., a tetragonal cell, but a==c). For instance, in the tI lattice, if abs(a-c) < threshold, a EdgeCaseWarning is issued. Note that depending on the bravais lattice, the meaning of the threshold is different (angle, length, …) symprec – the symmetry precision used internally by SPGLIB angle_tolerance – the angle_tolerance used internally by SPGLIB a dictionary with the following keys: point_coords: a dictionary with label -> float coordinates path: a list of length-2 tuples, with the labels of the starting and ending point of each label section has_inversion_symmetry: True or False, depending on whether the input crystal structure has inversion symmetry or not. augmented_path: if True, it means that the path was augmented with the $$-k$$ points (this happens if both has_inversion_symmetry is False, and the user set with_time_reversal=False in the input) bravais_lattice: the Bravais lattice string (like cP, tI, …) bravais_lattice_extended: the specific case used to define labels and coordinates (like cP1, tI2, …) cont_lattice: three real-space vectors for the crystallographic conventional cell (conv_lattice[0,:] is the first vector) conv_positions: fractional coordinates of atoms in the crystallographic conventional cell conv_types: list of integer types of the atoms in the crystallographic conventional cell (typically, the atomic numbers) primitive_lattice: three real-space vectors for the crystallographic primitive cell (primitive_lattice[0,:] is the first vector) primitive_positions: fractional coordinates of atoms in the crystallographic primitive cell primitive_types: list of integer types of the atoms in the crystallographic primitive cell (typically, the atomic numbers) reciprocal_primitive_lattice: reciprocal-cell vectors for the primitive cell (vectors are rows: reciprocal_primitive_lattice[0,:] is the first vector) primitive_transformation_matrix: the transformation matrix $$P$$ between the conventional and the primitive cell inverse_primitive_transformation_matrix: the inverse of the matrix $$P$$ (the determinant is integer and gives the ratio in volume between the conventional and primitive cells) volume_original_wrt_conv: volume ratio of the user-provided cell with respect to the the crystallographic conventional cell volume_original_wrt_prim: volume ratio of the user-provided cell with respect to the the crystalloraphic primitive cell An EdgeCaseWarning is issued for edge cases (e.g. if a==b==c for orthorhombic systems). In this case, still one of the valid cases is picked.

## The HPKOT module¶

The seekpath.hpkot module contains routines to get automatically the path in a 3D Brillouin zone to plot band structures according to the HPKOT paper (see references below).

Author: Giovanni Pizzi, EPFL

Note

the list of point coordinates and example POSCAR files in the band_path_data subfolder have been provided by Yoyo Hinuma, Kyoto University, Japan. The POSCARs have been retrieved from the Materials Project (http://materialsproject.org).

exception seekpath.hpkot.EdgeCaseWarning[source]

A warning issued when the cell is an edge case (e.g. orthorhombic symmetry, but a==b==c.

exception seekpath.hpkot.SymmetryDetectionError[source]

Error raised if spglib could not detect the symmetry.

seekpath.hpkot.get_path(structure, with_time_reversal=True, threshold=1e-07, symprec=1e-05, angle_tolerance=-1.0)[source]

Return the kpoint path information for band structure given a crystal structure, using the paths from the chosen recipe/reference.

If you use this module, please cite the paper of the corresponding recipe (see parameter below).

Parameters: structure – The crystal structure for which we want to obtain the suggested path. It should be a tuple in the format accepted by spglib: (cell, positions, numbers), where (if N is the number of atoms): cell is a $$3 \times 3$$ list of floats (cell[0] is the first lattice vector, …) positions is a $$N \times 3$$ list of floats with the atomic coordinates in scaled coordinates (i.e., w.r.t. the cell vectors) numbers is a length-$$N$$ list with integers identifying uniquely the atoms in the cell (e.g., the Z number of the atom, but any other positive non-zero integer will work - e.g. if you want to distinguish two Carbon atoms, you can set one number to 6 and the other to 1006) with_time_reversal – if False, and the group has no inversion symmetry, additional lines are returned as described in the HPKOT paper. recipe – choose the reference publication that defines the special points and paths. Currently, the following value is implemented: hpkot: HPKOT paper: Y. Hinuma, G. Pizzi, Y. Kumagai, F. Oba, I. Tanaka, Band structure diagram paths based on crystallography, Comp. Mat. Sci. 128, 140 (2017). DOI: 10.1016/j.commatsci.2016.10.015 threshold – the threshold to use to verify if we are in and edge case (e.g., a tetragonal cell, but a==c). For instance, in the tI lattice, if abs(a-c) < threshold, a EdgeCaseWarning is issued. Note that depending on the bravais lattice, the meaning of the threshold is different (angle, length, …) symprec – the symmetry precision used internally by SPGLIB angle_tolerance – the angle_tolerance used internally by SPGLIB a dictionary with the following keys: point_coords: a dictionary with label -> float coordinates path: a list of length-2 tuples, with the labels of the starting and ending point of each label section has_inversion_symmetry: True or False, depending on whether the input crystal structure has inversion symmetry or not. augmented_path: if True, it means that the path was augmented with the $$-k$$ points (this happens if both has_inversion_symmetry is False, and the user set with_time_reversal=False in the input) bravais_lattice: the Bravais lattice string (like cP, tI, …) bravais_lattice_extended: the specific case used to define labels and coordinates (like cP1, tI2, …) cont_lattice: three real-space vectors for the crystallographic conventional cell (conv_lattice[0,:] is the first vector) conv_positions: fractional coordinates of atoms in the crystallographic conventional cell conv_types: list of integer types of the atoms in the crystallographic conventional cell (typically, the atomic numbers) primitive_lattice: three real-space vectors for the crystallographic primitive cell (primitive_lattice[0,:] is the first vector) primitive_positions: fractional coordinates of atoms in the crystallographic primitive cell primitive_types: list of integer types of the atoms in the crystallographic primitive cell (typically, the atomic numbers) reciprocal_primitive_lattice: reciprocal-cell vectors for the primitive cell (vectors are rows: reciprocal_primitive_lattice[0,:] is the first vector) primitive_transformation_matrix: the transformation matrix $$P$$ between the conventional and the primitive cell inverse_primitive_transformation_matrix: the inverse of the matrix $$P$$ (the determinant is integer and gives the ratio in volume between the conventional and primitive cells) volume_original_wrt_conv: volume ratio of the user-provided cell with respect to the the crystallographic conventional cell volume_original_wrt_prim: volume ratio of the user-provided cell with respect to the the crystallographic primitive cell An EdgeCaseWarning is issued for edge cases (e.g. if a==b==c for orthorhombic systems). In this case, still one of the valid cases is picked.
seekpath.hpkot.spg_mapping.get_P_matrix(bravais_lattice)[source]

Return a tuple of length 2 with the P matrix and its inverse:

(P, invP)


with $$invP = P^{-1}$$.

These $$P$$ matrices are obtained from Table 3 of the HPKOT paper.

The P matrix is a $$3\times 3$$ matrix is the matrix that converts the lattice vectors from crystallographic conventional $$(a,b,c)$$ to crystallographic primitive $$(a_P, b_P, c_P)$$ as follows: $$(a_P, b_P, c_P) = (a,b,c) P$$

The change of (real space) coordinate triples follows instead: $$(x_P, y_P, z_P)^T = (P^{-1}) (x,y,z)^T$$

Note

the $$invP = P^{-1}$$ matrix is always integer (with values only $$-1, 0, 1$$) while $$P$$ is rational (non-integer values can be $$\pm \frac 1 2$$ and $$\pm \frac 1 3$$).

seekpath.hpkot.spg_mapping.get_crystal_family(number)[source]

Given a spacegroup number, returns a string to identify its crystal family (triclinic, monoclinic, …).

Parameters: number – the spacegroup number, from 1 to 230
seekpath.hpkot.spg_mapping.get_primitive(structure, bravais_lattice, wrap_to_zero_one=False)[source]

Return the primitive cell from a conventional crystallographic cell.

Note: the input structure MUST be already standardized by spglib! structure – should be a tuple of the form (lattice, positions, types) and it MUST be already a conventional crystallographic cell (i.e. as returned by spglib with the std_ prefix). bravais_lattice – a string with the information of the Bravais lattice of the input structure. wrap_to_zero_one – if True, wrap the scaled coordinates to the $$[0,1[$$ interval. Otherwise, the scaled coordinates will not be changed and can be outside of the $$[0,1[$$ range; the advantage is that the Cartesian coordinates of each atom returned in the primitive cell will match with one of the atoms in the input structure if this variable is False. a tuple of length three: the first element is the primitive structure, also in the format (lattice, positions, types); the second is a tuple with the (P, invP) matrices as returned by get_P_matrix(); the third is an array with the mapping from the atoms in the conventional cell to the atoms in the primitive cell (e.g. if the conventional cell has four atoms and twice the volume than the primitive, and the first and third atoms in the conventional map to the first of the primitive, while the second and the fourth map to the second of the primitive, this array will be $$[0,1,0,1]$$).
seekpath.hpkot.spg_mapping.get_spgroup_data()[source]

Return a dictionary that has the spacegroup number as key, and a tuple as value, with content:

(crystal family letter, centering, has_inversion).


It loads if from a table in the source code for efficiency.

seekpath.hpkot.spg_mapping.get_spgroup_data_realtime()[source]

Return a dictionary that has the spacegroup number as key, and a tuple as value, with content:

(crystal family letter, centering, has_inversion),


got in real time using spglib methods.

seekpath.hpkot.spg_mapping.pgnum_from_pgint(pgint)[source]

Return the number of the pointgroup (from 1 to 32) from the international pointgroup name.

seekpath.hpkot.spg_mapping.pointgroup_has_inversion(number)[source]

Return True if the pointgroup with given number has inversion, False otherwise.

Parameters: number – The integer number of the pointgroup, from 1 to 32.
seekpath.hpkot.tools.check_spglib_version()[source]

Check the SPGLIB version and raise a ValueError if the version is older than 1.9.4.

Also raises an warning if the user has a version of SPGLIB that is older than 1.13, because before then there were some bugs (e.g. wrong treatment of oI, see e.g. issue )

Return the spglib module.

seekpath.hpkot.tools.eval_expr(expr, a, b, c, cosalpha, cosbeta, cosgamma, kparam)[source]

Given a string expression as a function of the parameters a, b, c (lengths of the cell lattice vectors) and cosalpha, cosbeta, cosgamma (the cosines of the three angles between lattice vectors) returns the numerical value of the expression.

Parameters: a – length of the first lattice vector b – length of the second lattice vector c – length of the third lattice vector cosalpha – cosine of the $$\alpha$$ angle (between lattice vectors 2 and 3) cosbeta – cosine of the $$\beta$$ angle (between lattice vectors 1 and 3) cosgamma – cosine of the $$\gamma$$ angle (between lattice vectors 1 and 2) kparam – a dictionary that associates the value to expressions as a function of the a, b, c, cosalpha, cosbeta, cosgamma parameters the value of the expression for the given values of the cell parameters

Note

To evaluate expressions, I hardcode a table of existing expressions in the DB rather than parsing the string (to avoid additional dependencies and avoid the use of eval).

seekpath.hpkot.tools.eval_expr_simple(expr, kparam)[source]

To evaluate expressions tha only require kparams and not a, b, c, …

seekpath.hpkot.tools.extend_kparam(kparam)[source]

Extend the list of kparam with also expressions like $$1-x$$, …

Parameters: kparam – a dictionary where the key is the expression as a string and the value is the numerical value a similar dictionary, extended with simple expressions
seekpath.hpkot.tools.get_cell_params(cell)[source]

Return (a,b,c,cosalpha,cosbeta,cosgamma) given a $$3\times 3$$ cell

Note

Rows are vectors: v1 = cell[0], v2 = cell[1], v3 = cell[3]

seekpath.hpkot.tools.get_path_data(ext_bravais)[source]

Given an extended Bravais symbol among those defined in the HPKOT paper (only first three characters, like cF1), return the points and the suggested path.

Parameters: ext_bravais – a string among the allowed etended Bravais lattices defined in HPKOT. a tuple (kparam_def, points_def, path) where the first element is the list with the definition of the k-point parameters, the second is the dictionary with the definition of the k-points, and the third is the list with the suggested paths.

Note

kparam_def has to be a list and not a dictionary because the order matters (later k-parameters can be defined in terms of previous ones)

seekpath.hpkot.tools.get_real_cell_from_reciprocal_rows(reciprocal_space_rows)[source]

Given the cell in reciprocal space (3x3 matrix, G vectors as rows, return the real-space cell where again the R vectors are rows, i.e. satisfying dot(real_space_cell, reciprocal_space_cell.T) = $$2 \pi I$$, where $$I$$ is the $$3\times 3$$ identity matrix.

Note

This is actually the same as get_reciprocal_cell_rows().

Returns: the $$3\times 3$$ list of real lattice vectors where each row is one vector.
seekpath.hpkot.tools.get_reciprocal_cell_rows(real_space_cell)[source]

Given the cell in real space (3x3 matrix, vectors as rows, return the reciprocal-space cell where again the G vectors are rows, i.e. satisfying dot(real_space_cell, reciprocal_space_cell.T) = $$2 \pi I$$, where $$I$$ is the $$3\times 3$$ identity matrix.

Returns: the $$3\times 3$$ list of reciprocal lattice vectors where each row is one vector.

## Legacy AiiDA wrappers¶

seekpath.aiidawrappers.get_explicit_k_path(structure, with_time_reversal=True, reference_distance=0.025, recipe='hpkot', threshold=1e-07)[source]

Return the kpoint path for band structure (in scaled and absolute coordinates), given a crystal structure, using the paths proposed in the various publications (see description of the ‘recipe’ input parameter). The parameters are the same as get get_explicit_k_path in __init__, but here all structures are input and returned as AiiDA structures rather than tuples, and similarly k-points-related information as a AiiDA KpointsData class.

Deprecated since version 1.8: Use the methods in AiiDA instead.

Parameters: structure – The AiiDA StructureData for which we want to obtain the suggested path. with_time_reversal – if False, and the group has no inversion symmetry, additional lines are returned. reference_distance – a reference target distance between neighboring k-points in the path, in units of 1/ang. The actual value will be as close as possible to this value, to have an integer number of points in each path. recipe – choose the reference publication that defines the special points and paths. Currently, the following value is implemented: ‘hpkot’: HPKOT paper: Y. Hinuma, G. Pizzi, Y. Kumagai, F. Oba, I. Tanaka, Band structure diagram paths based on crystallography, Comp. Mat. Sci. 128, 140 (2017). DOI: 10.1016/j.commatsci.2016.10.015 threshold – the threshold to use to verify if we are in and edge case (e.g., a tetragonal cell, but a==c). For instance, in the tI lattice, if abs(a-c) < threshold, a EdgeCaseWarning is issued. Note that depending on the bravais lattice, the meaning of the threshold is different (angle, length, …) a dictionary with the following keys: has_inversion_symmetry: True or False, depending on whether the input crystal structure has inversion symmetry or not. augmented_path: if True, it means that the path was augmented with the -k points (this happens if both has_inversion_symmetry is False, and the user set with_time_reversal=False in the input) primitive_structure: the StructureData for the primitive cell reciprocal_primitive_lattice: reciprocal-cell vectors for the primitive cell (vectors are rows: reciprocal_primitive_lattice[0,:] is the first vector) volume_original_wrt_prim: volume ratio of the user-provided cell with respect to the the crystallographic primitive cell explicit_kpoints: An AiiDA KPointsData object (without weights) with the kpoints and the respective labels. For each segment, the two endpoints are always included, independently of the length. explicit_kpoints_linearcoord: array of floats, giving the coordinate at which to plot the corresponding point. segments: a list of length-2 tuples, with the start and end index of each segment. Note! The indices are supposed to be used as follows: the labels for the i-th segment are given by: segment_indices = segments[i] segment_points = explicit_kpoints.get_kpoints[slice(*segment_indices)]  This means, in particular, that if you want the label of the start and end points, you should do: start_point = explicit_kpoints.get_kpoints[segment_indices[0]] stop_point = explicit_kpoints.get_kpoints[segment_indices[1]-1]  (note the minus one!) Also, note that if segments[i-1][1] == segments[i][0] + 1 it means that the point was calculated only once, and it belongs to both paths. Instead, if segments[i-1][1] == segments[i][0], then this is a ‘break’ point in the path (e.g., segments[i-1][1] is the X point, and segments[i][0] is the R point, and typically in a graphical representation they are shown at the same coordinate, with a label “R|X”).
seekpath.aiidawrappers.get_path(structure, with_time_reversal=True, reference_distance=0.025, recipe='hpkot', threshold=1e-07)[source]

Return the kpoint path information for band structure given a crystal structure, using the paths from the chosen recipe/reference. The parameters are the same as get get_path in __init__, but here all structures are input and returned as AiiDA structures rather than tuples.

If you use this module, please cite the paper of the corresponding recipe (see parameter below).

Deprecated since version 1.8: Use the methods in AiiDA instead.

param structure:
The crystal structure for which we want to obtain the suggested path. It should be an AiiDA StructureData object.
param with_time_reversal:
if False, and the group has no inversion symmetry, additional lines are returned as described in the HPKOT paper.
param recipe:choose the reference publication that defines the special points and paths. Currently, the following value is implemented: ‘hpkot’: HPKOT paper: Y. Hinuma, G. Pizzi, Y. Kumagai, F. Oba, I. Tanaka, Band structure diagram paths based on crystallography, Comp. Mat. Sci. 128, 140 (2017). DOI: 10.1016/j.commatsci.2016.10.015
Parameters:threshold
the threshold to use to verify if we are in
and edge case (e.g., a tetragonal cell, but a==c). For instance, in the tI lattice, if abs(a-c) < threshold, a EdgeCaseWarning is issued. Note that depending on the bravais lattice, the meaning of the threshold is different (angle, length, …)
return: a dictionary with the following keys: point_coords: a dictionary with label -> float coordinates path: a list of length-2 tuples, with the labels of the starting and ending point of each label section has_inversion_symmetry: True or False, depending on whether the input crystal structure has inversion symmetry or not. augmented_path: if True, it means that the path was augmented with the -k points (this happens if both has_inversion_symmetry is False, and the user set with_time_reversal=False in the input) bravais_lattice: the Bravais lattice string (like ‘cP’, ‘tI’, …) bravais_lattice_extended: the specific case used to define labels and coordinates (like ‘cP1’, ‘tI2’, …) conv_structure: AiiDA StructureData for the crystallographic conventional cell primitive_structure: AiiDA StructureData for the crystallographic primitive cell reciprocal_primitive_lattice: reciprocal-cell vectors for the primitive cell (vectors are rows: reciprocal_primitive_lattice[0,:] is the first vector) primitive_transformation_matrix: the transformation matrix P between the conventional and the primitive cell inverse_primitive_transformation_matrix: the inverse of the matrix P (the determinant is integer and gives the ratio in volume between the conventional and primitive cells) volume_original_wrt_conv: volume ratio of the user-provided cell with respect to the the crystallographic conventional cell volume_original_wrt_prim: volume ratio of the user-provided cell with respect to the the crystallographic primitive cell An EdgeCaseWarning is issued for edge cases (e.g. if a==b==c for orthorhombic systems). In this case, still one of the valid cases is picked.