Skip to content
Merged
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
21 changes: 19 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,25 @@ jobs:
- name: Run unit tests
run: pytest -v .

build_docs:
needs: build
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

- name: Install doc dependencies
run: pip install .[doc]
run: |
python -m pip install --upgrade pip setuptools wheel
pip install .[doc]

- name: Build documentation
run: sphinx-build ./doc ./build
run: sphinx-build ./doc ./build
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
__pycache__/
*.so

# Temporary files
/conversion_examples/*/*new*

# Distribution / packaging
/build/
/dist/
*.egg-info/
.eggs/
/doc/_generated
/doc/_static/example_nxxas_data.h5
/doc/_static/*.h5
45 changes: 44 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1 +1,44 @@
<a href="https://gitlab.esrf.fr/workflow/ewoksadmin/ewoksci/-/blob/main/CONTRIBUTING.md" target="_blank">CONTRIBUTING.md</a>
## Getting started

Requirements are listed in `setup.cfg` and can be installed with

```bash
pip install [--user] .[dev]
```

## Make a contribution

Before making a merge request make sure the following is done on your branch

1. Update HDF5 repository examples
2. Linting
3. Testing

### Update HDF5 repository examples

To be sure all HDF5 files are compliant with the latest standard

```bash
pip install -e .[dev]
./converted/generate.sh
```

### Linting

The configuration for [black](https://black.readthedocs.io/en/stable/) and [flake8](https://flake8.pycqa.org/en/latest/index.html) can be modified in `setup.cfg`.

Comment lines with `# noqa: E123` to ignore certain linting errors.

### Testing

Tests make use [pytest](https://docs.pytest.org/en/stable/index.html) and can be run as follows

```bash
pytest .
```

Testing an installed project is done like this

```bash
pytest --pyargs <project_name>
```
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# pynxxas
Library for reading and writing XAS data in NeXus format.

An example HDF5 file can be found [here](https://myhdf5.hdfgroup.org/view?url=https%3A%2F%2Fpynxxas.readthedocs.io%2Fen%2Flatest%2F_static%2Fexample_nxxas_data.h5)
An example HDF5 file can be found [here](https://myhdf5.hdfgroup.org/view?url=https%3A%2F%2Fpynxxas.readthedocs.io%2Fen%2Flatest%2F_static%2Fgeneric.h5)

<p align="center">
<a href="https://pynxxas.readthedocs.io" alt="Documentation">
Expand All @@ -12,6 +12,6 @@ An example HDF5 file can be found [here](https://myhdf5.hdfgroup.org/view?url=ht
<img src="https://img.shields.io/badge/license-MIT-blue" /></a>
<a href="https://github.com/psf/black" alt="Code Style">
<img src="https://img.shields.io/badge/code%20style-black-000000.svg" /></a>
<a href="https://myhdf5.hdfgroup.org/view?url=https%3A%2F%2Fpynxxas.readthedocs.io%2Fen%2Flatest%2F_static%2Fexample_nxxas_data.h5" alt="NeXus">
<a href="https://myhdf5.hdfgroup.org/view?url=https%3A%2F%2Fpynxxas.readthedocs.io%2Fen%2Flatest%2F_static%2Fgeneric.h5" alt="NeXus">
<img src="https://raw.githubusercontent.com/nexusformat/wiki/master/public/favicon.ico" /></a>
</p>
114 changes: 114 additions & 0 deletions conversion_examples/BlissMultiModal/make_xas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
from pathlib import Path

import h5py
import numpy
Copy link
Contributor

@mretegan mretegan Jan 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They recommend to import as import numpy as np. Not critical, though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import numpy as np
import pandas as pd
...

I'm not a favor for the same reason I'm not in favor of single letter variable names.


THIS_DIRECTORY = Path(__file__).parent


def bliss2nexus(nxentry_in, expressions, metadata, nxroot_out, entry_name):
root = create_nxclass(nxroot_out, entry_name, "NXentry")
nxroot_out.attrs["default"] = entry_name

inst = create_nxclass(root, "instrument", "NXinstrument")

source = create_nxclass(inst, "source", "NXsource")
source["type"] = "Synchrotron X-ray Source"
source["probe"] = "x-ray"

monochromator = create_nxclass(inst, "monochromator", "NXmonochromator")
nxinstrument_input = nxentry_in["instrument"]
dset = nxinstrument_input[metadata["energy"]]["data"]
monochromator["energy"] = dset[()]
energy_units = dset.attrs.get("units", "keV")
monochromator.attrs["units"] = energy_units

for name, expression in expressions.items():
subroot = create_nxclass(root, name, "NXsubentry", default="plot")
root.attrs["default"] = name
subroot["definition"] = "NXxas"

mode = expression["mode"]
subroot["mode"] = mode

subroot["energy"] = h5py.SoftLink(monochromator["energy"].name)

if mode == "transmission":
I0 = nxinstrument_input[expression["I0"]]["data"][()]
It = nxinstrument_input[expression["It"]]["data"][()]
subroot["intensity"] = numpy.log(I0 / It)
elif mode == "fluorescence":
I0 = nxinstrument_input[expression["I0"]]["data"][()]
mca = nxinstrument_input[expression["mca"]]
Ifluo = mca[expression["Ifluo"]][()]
Lt = mca[expression["Lt"]][()]
subroot["intensity"] = numpy.log(Ifluo / (I0 * Lt))
else:
raise NotImplementedError(mode)

element = create_nxclass(subroot, "element", "NXelement")
element["symbol"] = metadata["element"]

edge = create_nxclass(subroot, "edge", "NXedge")
edge["name"] = metadata["edge"]

plot = create_nxclass(
subroot, "plot", "NXdata", signal="intensity", axes="energy"
)
plot["title"] = expression.get("title", name)
plot["energy"] = h5py.SoftLink(subroot["energy"].name)
plot["intensity"] = h5py.SoftLink(subroot["intensity"].name)
plot["energy"].attrs["long_name"] = f"Energy ({energy_units})"
plot["intensity"].attrs["long_name"] = "Normalized mu(E)"


def create_nxclass(root, name, nx_class, **attrs):
"""Create NeXus class instance with attributes."""
child = root.create_group(name, track_order=True)
child.attrs["NX_class"] = nx_class
for name, value in attrs.items():
child.attrs[name] = value
return child


def main(output_filename):
with h5py.File(output_filename, "w", track_order=True) as nxroot_out:

input_filename = THIS_DIRECTORY / "test_Assolution_Mauro_0001.h5"

expressions = {
"itrans": {
"mode": "transmission",
"I0": "p201_1_bkg_sub",
"It": "p201_3_bkg_sub",
"title": "Transmission",
},
"iref": {
"mode": "transmission",
"I0": "p201_3_bkg_sub",
"It": "p201_5_bkg_sub",
"title": "Standard",
},
}
for mca_nr in range(16):
expressions[f"fluo{mca_nr}"] = {
"mode": "fluorescence",
"I0": "p201_1_bkg_sub",
"mca": f"xmapd16_det{mca_nr}",
"Ifluo": "roi1",
"Lt": "live_time", # effective measurement time
"title": f"Fluorescence #{mca_nr}",
}
metadata = {"element": "As", "edge": "K", "energy": "energy_enc"}

with h5py.File(input_filename, "r") as nxroot_in:
for entry_name in nxroot_in:
if entry_name.endswith(".1"):
nxentry_in = nxroot_in[entry_name]
bliss2nexus(
nxentry_in, expressions, metadata, nxroot_out, entry_name
)


if __name__ == "__main__":
main(THIS_DIRECTORY / ".." / ".." / "nxxas_examples" / f"{THIS_DIRECTORY.name}.h5")
Binary file not shown.
Loading
Loading