Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ If you use this tool, please cite the following work:

- Y. Hinuma, G. Pizzi, Y. Kumagai, F. Oba, I. Tanaka, *Band structure diagram paths based on crystallography*, Comp. Mat. Sci. 128, 140 (2017) ([JOURNAL LINK](https://dx.doi.org/10.1016/j.commatsci.2016.10.015), [arXiv link](https://arxiv.org/abs/1602.06402)).
- You should also cite [spglib](https://atztogo.github.io/spglib/) that is an essential library used in the implementation: A. Togo, I. Tanaka, "Spglib: a software library for crystal symmetry search", arXiv:1808.01590 (2018) ([spglib arXiv link](https://arxiv.org/abs/1808.01590)).
- If you run `SeeK-path` with the optional `moyopy` backend (`backend='moyopy'`), you should cite [moyo](https://github.com/spglib/moyo) in place of spglib for the symmetry analysis: K. Shinohara, *moyo: A fast and robust crystal symmetry finder, written in Rust* (2026) ([figshare link](https://figshare.com/articles/software/moyo_A_fast_and_robust_crystal_symmetry_finder_written_in_Rust_/31081162), doi:10.6084/m9.figshare.31081162.v1).

## How to install and how to use

Expand Down
111 changes: 109 additions & 2 deletions docs/source/maindoc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ How to use
==========
The main interface of the code is the :py:func:`~seekpath.getpaths.get_path` python function::

seekpath.get_path(structure, with_time_reversal, recipe, threshold, symprec, angle_tolerance)
seekpath.get_path(structure, with_time_reversal, recipe, threshold, symprec, angle_tolerance, backend)

You need to pass a crystal structure, a boolean flag (``with_time_reversal``) to say if time-reversal symmetry is present or not, and optionally, a recipe (currently only the string ``hpkot`` is supported) and a numerical threshold.

Expand All @@ -59,7 +59,112 @@ where (if ``N`` is the number of atoms):

The output of the function is a dictionary containing, among other quantities, the k-vector coefficients, the suggested band path, whether the system has inversion symmetry, the crystallographic primitive lattice, the reciprocal primitive lattice.
A detailed description of all output information and their format can be found in the function docstring. (Note that the ``threshold`` is the one used by seekpath to identify
e.g. the order of axes in an orthorhombic cell; instead ``symprec`` and ``angle_tolerance`` are just passed to spglib).
e.g. the order of axes in an orthorhombic cell; instead ``symprec`` and ``angle_tolerance`` are just passed to the symmetry backend).

------------------
Symmetry backends
------------------

The symmetry analysis that standardizes the input structure is done by
`spglib`_ by default. Passing ``backend='moyopy'`` uses `moyopy`_ instead, a
Rust reimplementation of spglib::

seekpath.get_path(structure, backend='moyopy')

``moyopy`` is an optional dependency that requires Python >= 3.10, installed
with::

pip install seekpath[moyopy]

What agrees
~~~~~~~~~~~

:py:func:`~seekpath.getpaths.get_path` and
:py:func:`~seekpath.getpaths.get_explicit_k_path` give the **same** result with
either backend. For all 60 reference structures shipped with seekpath, with and
without time reversal, the Bravais lattice classification, the extended Bravais
symbol, the space group, the path, the k-point labels and their coordinates are
identical, and the primitive lattices agree to within 1e-10. This also holds
under random rotations and unimodular changes of the input basis, for
left-handed input bases, and for supercells. Only the atom positions in the
standardized cells can differ (case 4).

What can differ
~~~~~~~~~~~~~~~

Four cases are known. None of them makes one backend right and the other wrong,
but they are worth knowing about before switching an existing workflow.

**1. K-points in the basis of the original cell.**
:py:func:`~seekpath.getpaths.get_path_orig_cell` and
:py:func:`~seekpath.getpaths.get_explicit_k_path_orig_cell` express the k-points
in the basis of the *input* cell. That depends on which of the several
symmetry-equivalent alignments of the standardized cell the backend picked, and
the two libraries do not always pick the same one.

For 25 of the 60 reference structures the two backends give identical
k-points. For the other 35 the k-points differ by an integral operation in the
conventional basis, most often a 180 or 120 degree rotation, and the two paths
are symmetry-equivalent (allowing for time reversal) in every case: a band
structure computed along either is the same, but the numbers are not
identical. Code that compares ``get_path_orig_cell`` output against stored
k-points should therefore not switch backend without re-generating them.

**2. Very loose** ``symprec`` **, right at a symmetry-promotion threshold.**
Where a structure sits on the boundary between two space groups, the two
libraries cross that boundary at slightly different tolerances, because they
apply ``symprec`` to different measures of the atomic mismatch: ``moyopy``
promotes to the higher-symmetry group at the smaller tolerance of the two.
Displacing every atom of each reference structure by 0.02 Angstrom and raising
``symprec`` until the undistorted space group is recovered, ``spglib`` needs a
tolerance 1.1 to 2.0 times larger than ``moyopy`` does (median 1.7 over the 28
structures where both recover it). Away from such a boundary the two agree over
the whole practical range.
If a structure's space group changes when ``symprec`` is nudged, that is a sign
the tolerance is too loose to be meaningful, whichever backend is used.

**3. Triclinic cells with 90 degree reciprocal angles (** ``aP2`` **vs** ``aP3``
**).** A triclinic crystal sitting on a higher-symmetry lattice - a defect cell
or a substituted supercell, say - can be classified either way, because the test
that separates the two looks at the sign of a quantity that is exactly zero.
This is **not** a backend difference: the spglib backend alone returns both
answers for the same crystal supplied in different orientations. seekpath raises
:py:class:`~seekpath.hpkot.EdgeCaseWarning` when it happens, and that warning
should be taken seriously whichever backend is in use.

**4. Atom positions in the standardized cell.** The two libraries may choose
different, symmetry-equivalent origins, so ``conv_positions`` and
``primitive_positions`` can differ by a shift (and in atom order). This does not
affect the k-paths, which are origin-independent.

.. note:: For a supercell whose lattice has lower symmetry than the crystal
itself, ``moyopy`` logs a warning that it omitted some symmetry operations.
seekpath does not use these operations, so the warning does not affect its
results. It can be silenced with
``logging.getLogger('moyo').setLevel(logging.ERROR)``.

Performance
~~~~~~~~~~~

``moyopy`` is the faster of the two across the board. Measured through
:py:func:`~seekpath.getpaths.get_path` on rocksalt supercells, either perfect or
with every atom displaced slightly to break the supercell symmetry:

============================= ========== ==========
cell ``spglib`` ``moyopy``
============================= ========== ==========
128 atoms, low symmetry 2.7 ms 1.6 ms
432 atoms, low symmetry 17.8 ms 8.4 ms
1024 atoms, low symmetry 87.3 ms 34.4 ms
128 atoms, perfect supercell 9.0 ms 1.0 ms
432 atoms, perfect supercell 10.0 ms 2.8 ms
1024 atoms, perfect supercell 14.7 ms 11.3 ms
============================= ========== ==========

The speedup grows with the number of atoms for a low-symmetry cell, and shrinks
for a large perfect supercell, where ``spglib`` scales well because it reduces
to the primitive cell early.


----------------------------------------
K-point path for non-standard unit cells
Expand Down Expand Up @@ -127,6 +232,8 @@ https://aiida-core.readthedocs.io/en/latest/datatypes/kpoints.html
.. _JOURNAL LINK: https://dx.doi.org/10.1016/j.commatsci.2016.10.015
.. _arXiv link: https://arxiv.org/abs/1602.06402
.. _spglib: https://atztogo.github.io/spglib/

.. _moyopy: https://spglib.github.io/moyo/python/
.. _Materials Cloud: https://www.materialscloud.org/tools/seekpath/
.. _docker hub: https://hub.docker.com/r/giovannipizzi/seekpath/
.. _AiiDA: https://www.aiida.net
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,12 @@ Downloads = "https://github.com/materialscloud-org/seekpath/archive/v2.2.2.tar.g
bz = [
"scipy>=1",
]
moyopy = [
"moyopy>=0.21; python_version >= '3.10'",
]
dev = [
"black==23.3.0",
"moyopy>=0.21; python_version >= '3.10'",
"pre-commit~=3.5",
"prospector==1.11.0",
"pytest==7.3.1",
Expand Down
53 changes: 45 additions & 8 deletions seekpath/getpaths.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import numpy as np
import warnings
from . import SupercellWarning
from .hpkot import DEFAULT_BACKEND


def get_explicit_from_implicit(seekpath_output, reference_distance):
Expand Down Expand Up @@ -82,6 +83,7 @@ def get_path(
threshold=1.0e-7,
symprec=1e-05,
angle_tolerance=-1.0,
backend=DEFAULT_BACKEND,
):
r"""
Return the kpoint path information for band structure given a
Expand Down Expand Up @@ -125,9 +127,16 @@ def get_path(
Note that depending on the bravais lattice, the meaning of the
threshold is different (angle, length, ...)

:param symprec: the symmetry precision used internally by SPGLIB
:param symprec: the symmetry precision used internally by the symmetry backend

:param angle_tolerance: the angle_tolerance used internally by SPGLIB
:param angle_tolerance: the angle_tolerance used internally by the symmetry
backend

:param backend: the symmetry backend used to standardize the structure,
either ``'spglib'`` (the default) or ``'moyopy'``. The ``'moyopy'``
backend requires the optional ``moyopy`` dependency and is usually
faster; see the documentation for where the results of the
two backends can differ.


:return: a dictionary with the following
Expand Down Expand Up @@ -185,6 +194,7 @@ def get_path(
threshold=threshold,
symprec=symprec,
angle_tolerance=angle_tolerance,
backend=backend,
)

else:
Expand All @@ -203,6 +213,7 @@ def get_explicit_k_path(
threshold=1.0e-7,
symprec=1e-05,
angle_tolerance=-1.0,
backend=DEFAULT_BACKEND,
):
r"""
Return the kpoint path for band structure (in scaled and absolute
Expand Down Expand Up @@ -257,9 +268,16 @@ def get_explicit_k_path(
Note that depending on the bravais lattice, the meaning of the
threshold is different (angle, length, ...)

:param symprec: the symmetry precision used internally by SPGLIB
:param symprec: the symmetry precision used internally by the symmetry backend

:param angle_tolerance: the angle_tolerance used internally by the symmetry
backend

:param angle_tolerance: the angle_tolerance used internally by SPGLIB
:param backend: the symmetry backend used to standardize the structure,
either ``'spglib'`` (the default) or ``'moyopy'``. The ``'moyopy'``
backend requires the optional ``moyopy`` dependency and is usually
faster; see the documentation for where the results of the
two backends can differ.

.. versionchanged:: 1.8
The key ``segments`` has been renamed ``explicit_segments``
Expand Down Expand Up @@ -313,6 +331,7 @@ def get_explicit_k_path(
threshold=threshold,
symprec=symprec,
angle_tolerance=angle_tolerance,
backend=backend,
)

else:
Expand All @@ -336,6 +355,7 @@ def get_path_orig_cell(
threshold=1.0e-7,
symprec=1e-05,
angle_tolerance=-1.0,
backend=DEFAULT_BACKEND,
):
r"""
Return the kpoint path information for band structure given a
Expand Down Expand Up @@ -388,9 +408,16 @@ def get_path_orig_cell(
Note that depending on the bravais lattice, the meaning of the
threshold is different (angle, length, ...)

:param symprec: the symmetry precision used internally by SPGLIB
:param symprec: the symmetry precision used internally by the symmetry backend

:param angle_tolerance: the angle_tolerance used internally by SPGLIB
:param angle_tolerance: the angle_tolerance used internally by the symmetry
backend

:param backend: the symmetry backend used to standardize the structure,
either ``'spglib'`` (the default) or ``'moyopy'``. The ``'moyopy'``
backend requires the optional ``moyopy`` dependency and is usually
faster; see the documentation for where the results of the
two backends can differ.


:return: a dictionary with the following
Expand Down Expand Up @@ -420,6 +447,7 @@ def get_path_orig_cell(
symprec=symprec,
angle_tolerance=angle_tolerance,
recipe=recipe,
backend=backend,
)

# The volume ratio is negative for a left-handed input cell, so only its
Expand Down Expand Up @@ -480,6 +508,7 @@ def get_explicit_k_path_orig_cell(
threshold=1.0e-7,
symprec=1e-05,
angle_tolerance=-1.0,
backend=DEFAULT_BACKEND,
):
r"""
Return the kpoint path for band structure (in scaled and absolute
Expand Down Expand Up @@ -537,9 +566,16 @@ def get_explicit_k_path_orig_cell(
Note that depending on the bravais lattice, the meaning of the
threshold is different (angle, length, ...)

:param symprec: the symmetry precision used internally by SPGLIB
:param symprec: the symmetry precision used internally by the symmetry backend

:param angle_tolerance: the angle_tolerance used internally by the symmetry
backend

:param angle_tolerance: the angle_tolerance used internally by SPGLIB
:param backend: the symmetry backend used to standardize the structure,
either ``'spglib'`` (the default) or ``'moyopy'``. The ``'moyopy'``
backend requires the optional ``moyopy`` dependency and is usually
faster; see the documentation for where the results of the
two backends can differ.

.. versionchanged:: 1.8
The key ``segments`` has been renamed ``explicit_segments``
Expand Down Expand Up @@ -593,6 +629,7 @@ def get_explicit_k_path_orig_cell(
symprec=symprec,
angle_tolerance=angle_tolerance,
recipe=recipe,
backend=backend,
)

# Set reciprocal_primitive_lattice as the reciprocal lattice of the original
Expand Down
Loading
Loading