Skip to content

Commit

Permalink
Merge pull request #80 from ericpre/pyodide_install
Browse files Browse the repository at this point in the history
Make `numexpr` an optional dependency to allow installation in pyodide
  • Loading branch information
jlaehne authored Sep 11, 2024
2 parents 800b740 + 7775257 commit ee31d0a
Show file tree
Hide file tree
Showing 10 changed files with 99 additions and 15 deletions.
11 changes: 10 additions & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,22 @@ jobs:
os: [ubuntu, windows, macos]
PYTHON_VERSION: ['3.9', '3.11']
LABEL: ['']
PIP_SELECTOR: ['[tests, speed]']
include:
- os: ubuntu
PYTHON_VERSION: '3.8'
PIP_SELECTOR: '[tests, speed]'
- os: ubuntu
PYTHON_VERSION: '3.10'
PIP_SELECTOR: '[tests, speed]'
- os: ubuntu
PYTHON_VERSION: '3.12'
PIP_SELECTOR: '[tests, speed]'
# test minimum requirement
- os: ubuntu
PYTHON_VERSION: '3.9'
LABEL: '-minimum'
PIP_SELECTOR: '[tests]'

steps:
- uses: actions/checkout@v4
Expand Down Expand Up @@ -52,7 +61,7 @@ jobs:
- name: Install
run: |
pip install -e .[tests]
pip install -e '.${{ matrix.PIP_SELECTOR }}'
- name: Pip list
run: |
Expand Down
13 changes: 7 additions & 6 deletions doc/user_guide/eels.rst
Original file line number Diff line number Diff line change
Expand Up @@ -394,16 +394,17 @@ edge functionalities:

.. _eels.fine_structure:

Fine structure analysis
^^^^^^^^^^^^^^^^^^^^^^^
Fine structure analysis using a spline function
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The fine structure of an EELS ionization edge manifests as distinct features within
the first few tens of eVs energy. It is due to variations in the electron's energy
loss probability caused by the interactions with the material's electronic structure.
It offers insights into the material's electronic properties, bonding, and local environments.
Therefore, we cannot model them from first-principles because i) the material is usually unknown
ii) HyperSpy only supports Hydrogenic and Hartree-Slater EELS core-loss models. Instead, the
:py:class:`~.components.EELSCLEdge` component includes features
ii) HyperSpy supports Hydrogenic, Hartree-Slater EELS, DFT and Dirac core-loss models, which don't
include modeling of the fine structure - see :ref:`eels.GOS` and :class:`~.components.EELSCLEdge`
for more information. Instead, the :py:class:`~.components.EELSCLEdge` component includes features
for EELS fine structure modelling and analysis using functions to mimic the fine structure
features. The most basic consists in modelling
the fine structure of ionization edges using a spline function. You can activate this feature
Expand Down Expand Up @@ -483,8 +484,8 @@ structure width. It is possible to suspend this feature by calling
To resume it use
:py:meth:`~.models.EELSModel.suspend_auto_fine_structure_width`

Fine structure analysis
"""""""""""""""""""""""
Fine structure analysis using Gaussian functions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Fine structure analysis consists on measuring different features of the fine structure
(e.g., peak position, area, ...). Often, these features can be related to the ionized atom environment.
Expand Down
28 changes: 28 additions & 0 deletions doc/user_guide/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,35 @@ and install it using (requires ``pip``):
Required dependencies will be installed automatically.

Optional dependencies
---------------------

Optional dependencies can be installed using the
`extras <https://packaging.python.org/en/latest/specifications/dependency-specifiers/#extras>`_.
To install all optional dependencies:

.. code-block:: bash
pip install exspy[all]
The list of *extras*:

+------------------+-----------------------------+------------------------------------------------------------+
| Extra | Dependencies | Usage |
+==================+=============================+============================================================+
| ``speed`` | ``numexpr`` | To speed up fitting with components supporting ``numexpr`` |
+------------------+-----------------------------+------------------------------------------------------------+
| ``gui-jupyter`` | ``hyperspy_gui_ipywidgets`` | To use the ``ipywidgets`` user interface |
+------------------+-----------------------------+------------------------------------------------------------+
| ``gui-traitsui`` | ``hyperspy_gui_traitsui`` | To use the ``qt`` user interface |
+------------------+-----------------------------+------------------------------------------------------------+

And for development, the following *extras* are available (see ``pyproject.toml`` for more information):

- tests
- doc
- dev

Updating the package
====================

Expand Down
36 changes: 36 additions & 0 deletions exspy/_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
# Copyright 2007-2024 The eXSpy developers
#
# This file is part of eXSpy.
#
# eXSpy is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# eXSpy is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with eXSpy. If not, see <https://www.gnu.org/licenses/#GPL>.

import importlib
import logging

_logger = logging.getLogger(__name__)


def parse_component_module(module):
"""Check if numexpr is installed, if not fall back to numpy"""
if module == "numexpr":
numexpr_spec = importlib.util.find_spec("numexpr")
if numexpr_spec is None:
module = "numpy"
_logger.warning(
"Numexpr is not installed, falling back to numpy, "
"which is slower to calculate model."
)

return module
4 changes: 3 additions & 1 deletion exspy/components/eels_double_power_law.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
from hyperspy.docstrings.parameters import FUNCTION_ND_DOCSTRING
import hyperspy.api as hs

from exspy._utils import parse_component_module


class DoublePowerLaw(hs.model.components1D.Expression):
r"""Double power law component for EELS spectra.
Expand Down Expand Up @@ -87,7 +89,7 @@ def __init__(
left_cutoff=left_cutoff,
position="origin",
autodoc=False,
module=module,
module=parse_component_module(module),
compute_gradients=compute_gradients,
linear_parameter_list=["A"],
check_parameter_linearity=False,
Expand Down
4 changes: 3 additions & 1 deletion exspy/components/pes_see.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

import hyperspy.api as hs

from exspy._utils import parse_component_module


_logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -77,7 +79,7 @@ def __init__(
Phi=Phi,
B=B,
position="Phi",
module=module,
module=parse_component_module(module),
autodoc=False,
compute_gradients=compute_gradients,
linear_parameter_list=["A"],
Expand Down
4 changes: 3 additions & 1 deletion exspy/components/volume_plasmon_drude.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

import hyperspy.api as hs

from exspy._utils import parse_component_module


class VolumePlasmonDrude(hs.model.components1D.Expression):
r"""
Expand Down Expand Up @@ -72,7 +74,7 @@ def __init__(
plasmon_energy=plasmon_energy,
fwhm=fwhm,
position="plasmon_energy",
module=module,
module=parse_component_module(module),
autodoc=False,
compute_gradients=compute_gradients,
linear_parameter_list=["intensity"],
Expand Down
6 changes: 4 additions & 2 deletions exspy/tests/components/test_double_power_law.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ def test_function():
g.origin.value = 1
g.shift.value = 2
g.ratio.value = 2
assert np.isinf(g.function(1))
assert np.isinf(g.function(3))
if g._module == "numexpr":
# numpy raises a ZeroDivisionError
assert np.isinf(g.function(1))
assert np.isinf(g.function(3))
assert g.function(-1) == 0
assert g.function(0) == 0
assert g.function(2) == 9
Expand Down
7 changes: 4 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ dependencies = [
"dask[array]",
"hyperspy>=2.0rc0",
"matplotlib",
"numexpr",
"numpy",
"pint",
"pooch",
Expand Down Expand Up @@ -74,17 +73,19 @@ file = "LICENSE"
# unpin when sphinxcontrib-towncrier support more recent version to towncrier
"towncrier<24",
]
"speed" = ["numexpr"]
"tests" = [
"pytest >= 5.0",
"pytest-mpl",
"pytest-cov >= 2.8.1",
"pytest-xdist",
"setuptools-scm",
]
"dev" = ["black"]
"dev" = ["ruff"]
"all" = [
"exspy[gui-jupyter]",
"exspy[gui-traitsui]"
"exspy[gui-traitsui]",
"exspy[speed]"
]

[project.urls]
Expand Down
1 change: 1 addition & 0 deletions upcoming_changes/80.enhancements.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Make ``numexpr`` an optional dependency to allow installation in pyodide.

0 comments on commit ee31d0a

Please sign in to comment.