Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
bc0c037
Add BSD-3 Clause license for use in select components
hakonanes Jun 13, 2026
f1a2ca7
Add an optional dependency on ebsdsim
hakonanes Jun 13, 2026
d611203
Depend on patched ebsdsim until it is available from PyPI
hakonanes Jun 13, 2026
875459c
Make licenseheaders respect new BSD 3-Clause license headers
hakonanes Jun 13, 2026
d1a7ec6
Relicense constant handling to BSD
hakonanes Jun 13, 2026
9ce481d
Add reader for master patterns from ebsdsim
hakonanes Jun 13, 2026
086a616
Test new ebsdsim master pattern reader
hakonanes Jun 13, 2026
0ae4c77
Fix handling of phase returned from readers
hakonanes Jun 13, 2026
475f753
Use pytest setup_method instead of Python class for properties
hakonanes Jun 13, 2026
e2a33be
Add simple note in IO docs about ebsdsim reader
hakonanes Jun 13, 2026
2ad897d
Mention new reader in changelog
hakonanes Jun 13, 2026
c0f70b4
Fix again the phase parsing from readers
hakonanes Jun 13, 2026
49bfcd9
Also depend on custom branch for ebsdsim in [all]
hakonanes Jun 13, 2026
ac3f567
Guard ebsdsim import in fixture function
hakonanes Jun 13, 2026
efa0807
Update changelog
hakonanes Jun 13, 2026
b4b6868
Exclude PR template from pre-commit
hakonanes Jun 13, 2026
33511b9
Remind PR reviewer that they must consider licensing now that we have…
hakonanes Jun 13, 2026
3870721
Add note about licensing considerations in contributor guide
hakonanes Jun 13, 2026
b7c4251
Add ebsdsim master pattern file reader to the public API
hakonanes Jun 13, 2026
10948eb
Add the module docstrings in the right place
hakonanes Jun 13, 2026
54052cc
Add gpu pytest marker
hakonanes Jun 13, 2026
92a9799
Mark ebsdsim tests as requiring GPU found by wgpu
hakonanes Jun 13, 2026
8813e12
Run ebsdsim tests on macOS only
hakonanes Jun 13, 2026
08c8519
Fix pytest 9.1 errors
hakonanes Jun 13, 2026
6c91fb6
Add ebsdsim, EMSphinxEBSD, and ReciPro to related software
hakonanes Jun 13, 2026
50d1201
Fix energy axis offset
hakonanes Jun 14, 2026
02e3453
Remove dependency on custom ebsdsim branch
hakonanes Jun 14, 2026
50d9b5b
Mention that ebsdsim is unavailable from conda-forge
hakonanes Jun 14, 2026
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 .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#### For reviewers
<!-- Don't remove the checklist below. -->
- [ ] Files with a BSD 3-Clause license do not import from GPLv3+ software.
- [ ] The PR title is short, concise, and will make sense 1 year later.
- [ ] New functions are imported in corresponding `__init__.py`.
- [ ] New features, API changes, and deprecations are mentioned in the unreleased
Expand Down
10 changes: 9 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ jobs:
if: ${{ contains(matrix.LABEL, 'minimum_requirement') == false && matrix.os == 'macos-latest' }}
shell: bash
run: |
pip install "pyebsdindex[gpu]" pyvista
pip install ipywidgets IPython "pooch>=1.3.0" psygnal "pyebsdindex[gpu]>=0.3.9.2,!=0.3.10" pyvista

- name: Display Python, pip and package versions
run: |
Expand Down Expand Up @@ -134,6 +134,14 @@ jobs:
run: |
pytest ${{ env.PYTEST_ARGS }}

- name: Run GPU tests on macOS
if: ${{ matrix.os == 'macos-latest' }}
run: |
# TODO: Replace with patched version once it's released
pip install "ebsdsim @ git+https://github.com/hakonanes/ebsdsim@fix-1-multiprocessing-start-method-with-script"

pytest ${{ env.PYTEST_ARGS }} -m gpu --gpu

- name: Generate line coverage
run: |
coverage report --show-missing
Expand Down
3 changes: 3 additions & 0 deletions .license_bsd.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Copyright ${years} the ${projectname} developers

SPDX-License-Identifier: BSD-3-Clause
8 changes: 8 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
## along with kikuchipy. If not, see <http://www.gnu.org/licenses/>.
##

exclude: ^\.github/pull_request_template.md

repos:
# https://docs.astral.sh/ruff/configuration
- repo: https://github.com/astral-sh/ruff-pre-commit
Expand All @@ -35,6 +37,12 @@ repos:
rev: v0.8.8
hooks:
- id: licenseheaders
name: licenseheaders (BSD-3-Clause)
files: ^src/kikuchipy/(_constants\.py|io/plugins/ebsdsim_master_pattern/)
args: ["-t", ".license_bsd.tmpl", "-cy", "-n", "kikuchipy", "-f"]
- id: licenseheaders
name: licenseheaders (GPL-3.0-or-later)
exclude: ^src/kikuchipy/(_constants\.py|io/plugins/ebsdsim_master_pattern/)
args: ["-t", ".license.tmpl", "-cy", "-n", "kikuchipy", "-f"]

# https://pre-commit.ci/#configuration
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ Added
(`#796 <https://github.com/pyxem/kikuchipy/pull/796>`_)
- Function to clear the kikuchipy data cache directory.
(`#796 <https://github.com/pyxem/kikuchipy/pull/796>`_)
- Optional dependency on the ebsdsim Python package.
(`#809 <https://github.com/pyxem/kikuchipy/pull/809>`_)
- Reader for master patterns generated by the ebsdsim Python package.
(`#809 <https://github.com/pyxem/kikuchipy/pull/809>`_)

Changed
-------
Expand Down
29 changes: 29 additions & 0 deletions LICENSE-BSD-3-Clause
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
BSD 3-Clause License

Copyright 2026 the kikuchipy developers

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
16 changes: 14 additions & 2 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,12 @@ library.
.. |zenodo_doi| image:: https://zenodo.org/badge/doi/10.5281/zenodo.3597646.svg
:target: https://doi.org/10.5281/zenodo.3597646

.. |GPLv3| image:: https://img.shields.io/github/license/pyxem/kikuchipy
.. |GPLv3| image:: https://img.shields.io/badge/license-GPLv3%2B-blue
:target: https://opensource.org/license/GPL-3.0

.. |BSD3| image:: https://img.shields.io/badge/license_(select_components)-BSD--3--Clause-blue
:target: https://opensource.org/license/BSD-3-Clause

.. |GH-discuss| image:: https://img.shields.io/badge/GitHub-Discussions-green?logo=github
:target: https://github.com/pyxem/kikuchipy/discussions

Expand All @@ -63,20 +66,28 @@ library.
+----------------------+------------------------------------------------+
| Citation | |arxiv_doi| |zenodo_doi| |
+----------------------+------------------------------------------------+
| License | |GPLv3| |
| License | |GPLv3| |BSD3| |
+----------------------+------------------------------------------------+
| Community | |GH-discuss| |
+----------------------+------------------------------------------------+
| Formatter | |black| |
+----------------------+------------------------------------------------+

kikuchipy is licensed under the `GNU General Public License v3+
<https://opensource.org/license/GPL-3.0>`__.
Select components are individually licensed under the `BSD 3-Clause License
<https://opensource.org/license/BSD-3-Clause>`__, allowing reuse *of those components
only* in both GPL and non-GPL projects.


Documentation
-------------

Refer to the `documentation <https://kikuchipy.org>`__ for detailed installation
instructions, a user guide, and the
`changelog <https://kikuchipy.org/en/stable/changelog.html>`__.


Installation
------------

Expand All @@ -95,6 +106,7 @@ You can also visit `PyPI <https://pypi.org/project/kikuchipy>`__,
Further details are available in the
`installation guide <https://kikuchipy.org/en/stable/user/installation.html>`__.


Citing kikuchipy
----------------

Expand Down
76 changes: 56 additions & 20 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import os
from pathlib import Path
import tempfile
from typing import Callable, Generator
from typing import Callable, Generator, Literal

import dask.array as da
from diffpy.structure import Atom, Lattice, Structure
Expand Down Expand Up @@ -65,18 +65,30 @@ def pytest_addoption(parser):
# Flags for optional markers. Markers requiring something (installed
# dependency, e.g.) should not have a flag to still run them.
parser.addoption(
"--weekly", action="store_true", help="Run tests that should run only weekly"
"--gpu",
action="store_true",
help="Run tests that should run only when wgpu has a GPU available",
)
parser.addoption(
"--weekly",
action="store_true",
help="Run tests that should run only weekly",
)


MARKERS = [
"gpu",
"weekly",
]


def pytest_runtest_setup(item):
# Skip certain tests when flag is missing:
# https://docs.pytest.org/en/stable/reference/reference.html#pytest.hookspec.pytest_runtest_setup
"""Skip certain tests when flag is missing:
https://docs.pytest.org/en/stable/reference/reference.html#pytest.hookspec.pytest_runtest_setup.

To run tests marked by this marker *only*, say, `gpu`, do
`pytest -m gpu --gpu`.
"""
for marker in MARKERS:
marker_str = f"--{marker}"
if marker in item.keywords and not item.config.getoption(
Expand Down Expand Up @@ -229,7 +241,7 @@ def dummy_background() -> Generator[np.ndarray, None, None]:
yield np.array([5, 4, 5, 4, 3, 4, 4, 4, 3], dtype=np.uint8).reshape((3, 3))


@pytest.fixture(params=[[(3, 3), (3, 3), False, np.float32]])
@pytest.fixture
def ebsd_with_axes_and_random_data(request) -> Generator[kp.signals.EBSD, None, None]:
"""EBSD signal with minimally defined axes and random data.

Expand All @@ -240,7 +252,10 @@ def ebsd_with_axes_and_random_data(request) -> Generator[kp.signals.EBSD, None,
lazy : bool
dtype : numpy.dtype
"""
nav_shape, sig_shape, lazy, dtype = request.param
nav_shape, sig_shape, lazy, dtype = getattr(
request, "param", [(3, 3), (3, 3), False, np.float32]
)

nav_ndim = len(nav_shape)
sig_ndim = len(sig_shape)
data_shape = nav_shape + sig_shape
Expand Down Expand Up @@ -287,12 +302,12 @@ def pc1() -> Generator[list[float], None, None]:
yield [0.4210, 0.7794, 0.5049]


@pytest.fixture(params=[[(1,), (60, 60)]])
@pytest.fixture
def detector(request, pc1) -> Generator[kp.detectors.EBSDDetector, None, None]:
"""An EBSD detector of a given shape with a number of PCs given by
a navigation shape.
"""
nav_shape, sig_shape = request.param
nav_shape, sig_shape = getattr(request, "param", [(1,), (60, 60)])
yield kp.detectors.EBSDDetector(
shape=sig_shape,
binning=8,
Expand Down Expand Up @@ -343,12 +358,12 @@ def _get_single_phase_xmap(
# ---------------------------- IO fixtures --------------------------- #


@pytest.fixture(params=["h5"])
@pytest.fixture
def save_path_hdf5(request, tmpdir) -> Generator[Path, None, None]:
"""Temporary file in a temporary directory for use when tests need
to write, and sometimes read again, a signal to, and from, a file.
"""
ext = request.param
ext = getattr(request, "param", "h5")
yield Path(tmpdir / f"patterns.{ext}")


Expand Down Expand Up @@ -379,7 +394,7 @@ def ni_small_axes_manager() -> Generator[dict, None, None]:
yield axes_manager


@pytest.fixture(params=[("_x{}y{}.tif", (3, 3))])
@pytest.fixture
def ebsd_directory(tmpdir, request) -> Generator[Path, None, None]:
"""Temporary directory with EBSD files as .tif, .png or .bmp files.

Expand All @@ -391,7 +406,7 @@ def ebsd_directory(tmpdir, request) -> Generator[Path, None, None]:
s = kp.data.nickel_ebsd_small()
s.unfold_navigation_space()

xy_pattern, nav_shape = request.param
xy_pattern, nav_shape = getattr(request, "param", ("_x{}y{}.tif", (3, 3)))
y, x = np.indices(nav_shape)
x = x.ravel()
y = y.ravel()
Expand Down Expand Up @@ -427,7 +442,7 @@ def edax_binary_path() -> Generator[Path, None, None]:
yield DATA_PATH / "edax_binary"


@pytest.fixture(params=[(1, (2, 3), (60, 60), "uint8", 2, False)])
@pytest.fixture
def edax_binary_file(tmpdir, request) -> Generator[TextIOWrapper, None, None]:
"""Create a dummy EDAX binary UP1/2 file.

Expand All @@ -444,7 +459,9 @@ def edax_binary_file(tmpdir, request) -> Generator[TextIOWrapper, None, None]:
is_hex : bool
"""
# Unpack parameters
up_ver, (ny, nx), (sy, sx), dtype, ver, is_hex = request.param
up_ver, (ny, nx), (sy, sx), dtype, ver, is_hex = getattr(
request, "param", (1, (2, 3), (60, 60), "uint8", 2, False)
)

if up_ver == 1:
fname = tmpdir.join("dummy_edax_file.up1")
Expand Down Expand Up @@ -497,7 +514,7 @@ def oxford_binary_path() -> Generator[Path, None, None]:
yield DATA_PATH / "oxford_binary"


@pytest.fixture(params=[((2, 3), (60, 60), np.uint8, 2, False, True)])
@pytest.fixture
def oxford_binary_file(tmpdir, request) -> Generator[TextIOWrapper, None, None]:
"""Create a dummy Oxford Instruments' binary .ebsp file.

Expand All @@ -514,7 +531,9 @@ def oxford_binary_file(tmpdir, request) -> Generator[TextIOWrapper, None, None]:
all_present : bool
"""
# Unpack parameters
(nr, nc), (sr, sc), dtype, ver, compressed, all_present = request.param
(nr, nc), (sr, sc), dtype, ver, compressed, all_present = getattr(
request, "param", ((2, 3), (60, 60), np.uint8, 2, False, True)
)

fname = tmpdir.join("dummy_oxford_file.ebsp")
f = open(fname, mode="w")
Expand Down Expand Up @@ -580,20 +599,37 @@ def oxford_binary_file(tmpdir, request) -> Generator[TextIOWrapper, None, None]:
yield f


@pytest.fixture(params=["7.0"])
@pytest.fixture
def oxford_h5ebsd_file(tmpdir, request) -> Generator[Path, None, None]:
"""Yield the file path to a temporary H5OINA file.

Parameters expected in `request`
-------------------------------
version : "6.0" or "7.0"
"""
version = request.param
version: Literal["6.0", "7.0"] = getattr(request, "param", "7.0")
fpath = tmpdir / "patterns.h5oina"
create_dummy_oxford_h5ebsd_file(fpath, version=version)
yield fpath


# -------------------------- ebsdsim formats ------------------------- #


@pytest.fixture(scope="session")
def ebsdsim_master_pattern_file(tmp_path_factory) -> Generator[Path, None, None]:
"""Minimal ebsdsim Ni master pattern .npz file, created once per
session.
"""
from kikuchipy.data._dummy_files.ebsdsim_master_pattern_npz import (
create_small_ebsdsim_npz_file,
)

fpath = tmp_path_factory.mktemp("ebsdsim") / "ni_master_pattern.npz"
create_small_ebsdsim_npz_file(fpath)
yield fpath


# -------------------------- EMsoft formats -------------------------- #


Expand Down Expand Up @@ -621,9 +657,9 @@ def emsoft_ebsd_master_pattern_metadata() -> Generator[dict, None, None]:
}


@pytest.fixture(params=[["hemisphere", "energy", "height", "width"]])
@pytest.fixture
def emsoft_ebsd_master_pattern_axes_manager(request) -> Generator[dict, None, None]:
axes = request.param
axes = getattr(request, "param", ["hemisphere", "energy", "height", "width"])
am = {
"hemisphere": {
"name": "hemisphere",
Expand Down
2 changes: 1 addition & 1 deletion doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ def _str_examples(self):
"gallery_dirs": "examples",
"reference_url": {"kikuchipy": None},
"run_stale_examples": False,
"show_memory": True,
"show_memory": False, # Takes too long time
}
autosummary_generate = True

Expand Down
14 changes: 8 additions & 6 deletions doc/dev/improving_performance.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ Improving performance
=====================

When we write code, it's important that we (1) get the correct result, (2) don't fill up
memory, and (3) that the computation doesn't take too long. To keep memory in check, we
should use `Dask <https://docs.dask.org/en/latest/>`__ wherever possible. To speed up
computations, we should use `Numba <https://numba.pydata.org/numba-doc/dev/>`__ wherever
possible.
memory, and (3) that the computation doesn't take too long.
To keep memory in check, we should use `Dask <https://docs.dask.org/en/latest/>`__
wherever possible.
To speed up computations, we should use `Numba
<https://numba.pydata.org/numba-doc/dev/>`__ wherever possible.

To check whether a change is an improvement or a regression, a benchmark should be
written. These are stored in the top directory ``kikuchipy/benchmarks``. Benchmarks are
run using `pytest-benchmark
written.
These are stored in the top directory ``kikuchipy/benchmarks``.
Benchmarks are run using `pytest-benchmark
<https://pytest-benchmark.readthedocs.io/en/stable/index.html>`__::

pytest --benchmark-only
Loading
Loading