-
Notifications
You must be signed in to change notification settings - Fork 97
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #2394 from kif/diffmap
Diffmap enhancements
- Loading branch information
Showing
13 changed files
with
524 additions
and
342 deletions.
There are no files selected for viewing
15 changes: 11 additions & 4 deletions
15
doc/source/usage/tutorial/ThickDetector/Parallax_model.ipynb
Large diffs are not rendered by default.
Oops, something went wrong.
371 changes: 194 additions & 177 deletions
371
doc/source/usage/tutorial/ThickDetector/deconvolution.ipynb
Large diffs are not rendered by default.
Oops, something went wrong.
72 changes: 44 additions & 28 deletions
72
doc/source/usage/tutorial/ThickDetector/goniometer_id28.ipynb
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ | |
# Project: Azimuthal integration | ||
# https://github.com/silx-kit/pyFAI | ||
# | ||
# Copyright (C) 2024-2024 European Synchrotron Radiation Facility, Grenoble, France | ||
# Copyright (C) 2024-2025 European Synchrotron Radiation Facility, Grenoble, France | ||
# | ||
# Principal author: Loïc Huder ([email protected]) | ||
# | ||
|
@@ -32,14 +32,14 @@ | |
__contact__ = "[email protected]" | ||
__license__ = "MIT" | ||
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France" | ||
__date__ = "27/09/2024" | ||
__date__ = "28/01/2025" | ||
__status__ = "development" | ||
|
||
from silx.gui import qt | ||
import sys | ||
import argparse | ||
|
||
from ..gui.pilx.MainWindow import MainWindow | ||
from .. import version as pyFAI_version, __date__ as pyFAI_date | ||
|
||
|
||
def main(args=None): | ||
|
@@ -51,6 +51,8 @@ def main(args=None): | |
parser.add_argument("-p", "--nxprocess", dest="nxprocess_path", | ||
help="inner path to the Nexus process with the integrated Data", | ||
default="/entry_0000/pyFAI",) | ||
version = f"pyFAI-diffmap-view version {pyFAI_version}: {pyFAI_date}" | ||
parser.add_argument("-V", "--version", action='version', version=version) | ||
|
||
options = parser.parse_args(args) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ | |
# Project: Azimuthal integration | ||
# https://github.com/silx-kit/pyFAI | ||
# | ||
# Copyright (C) 2015-2024 European Synchrotron Radiation Facility, Grenoble, France | ||
# Copyright (C) 2015-2025 European Synchrotron Radiation Facility, Grenoble, France | ||
# | ||
# Principal author: Jérôme Kieffer ([email protected]) | ||
# | ||
|
@@ -31,7 +31,7 @@ | |
__contact__ = "[email protected]" | ||
__license__ = "MIT" | ||
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France" | ||
__date__ = "19/12/2024" | ||
__date__ = "27/01/2025" | ||
__status__ = "development" | ||
__docformat__ = 'restructuredtext' | ||
|
||
|
@@ -47,6 +47,8 @@ | |
import fabio | ||
import json | ||
import __main__ as main | ||
from queue import Queue | ||
import threading | ||
from .opencl import ocl | ||
from . import version as PyFAI_VERSION, date as PyFAI_DATE | ||
from .integrator.load_engines import PREFERED_METHODS_2D, PREFERED_METHODS_1D | ||
|
@@ -113,7 +115,6 @@ def __init__(self, nbpt_fast=0, nbpt_slow=1, nbpt_rad=1000, nbpt_azim=None, | |
self.experiment_title = "Diffraction Mapping" | ||
self.slow_motor_range = None | ||
self.fast_motor_range = None | ||
# method is a property from worker | ||
|
||
def __repr__(self): | ||
return f"{self.experiment_title} experiment with nbpt_slow: {self.nbpt_slow} nbpt_fast: {self.nbpt_fast}, nbpt_diff: {self.nbpt_rad}" | ||
|
@@ -401,9 +402,9 @@ def makeHDF5(self, rewrite=False): | |
|
||
# create motor range if not yet existing ... | ||
if self.fast_motor_range is None: | ||
self.fast_motor_range=(0, self.nbpt_fast - 1) | ||
self.fast_motor_range = (0, self.nbpt_fast - 1) | ||
if self.slow_motor_range is None: | ||
self.slow_motor_range=(0, self.nbpt_slow - 1) | ||
self.slow_motor_range = (0, self.nbpt_slow - 1) | ||
|
||
nxs = Nexus(self.hdf5, mode="w", creator="pyFAI") | ||
self.entry_grp = entry_grp = nxs.new_entry(entry="entry", | ||
|
@@ -444,8 +445,12 @@ def makeHDF5(self, rewrite=False): | |
|
||
self.nxdata_grp = nxs.new_class(process_grp, "result", class_type="NXdata") | ||
entry_grp.attrs["default"] = self.nxdata_grp.name.split("/", 2)[2] | ||
self.nxdata_grp[self.slow_motor_name] = numpy.linspace(*self.slow_motor_range, self.nbpt_slow) | ||
self.nxdata_grp[self.fast_motor_name] = numpy.linspace(*self.fast_motor_range, self.nbpt_fast) | ||
slow_motor_ds = self.nxdata_grp.create_dataset("slow", data=numpy.linspace(*self.slow_motor_range, self.nbpt_slow)) | ||
slow_motor_ds.attrs["interpretation"] = "scalar" | ||
slow_motor_ds.attrs["long_name"] = self.slow_motor_name | ||
fast_motor_ds = self.nxdata_grp.create_dataset("fast", data=numpy.linspace(*self.fast_motor_range, self.nbpt_fast)) | ||
fast_motor_ds.attrs["interpretation"] = "scalar" | ||
fast_motor_ds.attrs["long_name"] = self.fast_motor_name | ||
|
||
if self.worker.do_2D(): | ||
self.dataset = self.nxdata_grp.create_dataset( | ||
|
@@ -456,14 +461,16 @@ def makeHDF5(self, rewrite=False): | |
maxshape=(None, None, self.nbpt_azim, self.nbpt_rad), | ||
fillvalue=numpy.nan) | ||
self.dataset.attrs["interpretation"] = "image" | ||
self.nxdata_grp.attrs["axes"] = [self.slow_motor_name, self.fast_motor_name, "azimuthal", self.unit.space] | ||
self.nxdata_grp.attrs["axes"] = ["azimuthal", self.unit.space, "slow", "fast"] | ||
# Build a transposed view to display the mapping experiment | ||
layout = h5py.VirtualLayout(shape=(self.nbpt_azim, self.nbpt_rad, self.nbpt_slow, self.nbpt_fast), dtype=self.dataset.dtype) | ||
source = h5py.VirtualSource(self.dataset) | ||
for i in range(self.nbpt_slow): | ||
for j in range(self.nbpt_fast): | ||
layout[:, :, i, j] = source[i, j] | ||
layout[:,:, i, j] = source[i, j] | ||
self.nxdata_grp.create_virtual_dataset('map', layout, fillvalue=numpy.nan).attrs["interpretation"] = "image" | ||
slow_motor_ds.attrs["axes"] = 3 | ||
fast_motor_ds.attrs["axes"] = 4 | ||
|
||
else: | ||
print(f"shape for dataset: {self.nbpt_slow}, {self.nbpt_fast}, {self.nbpt_rad}") | ||
|
@@ -475,18 +482,19 @@ def makeHDF5(self, rewrite=False): | |
maxshape=(None, None, self.nbpt_rad), | ||
fillvalue=numpy.nan) | ||
self.dataset.attrs["interpretation"] = "spectrum" | ||
self.nxdata_grp.attrs["axes"] = [self.slow_motor_name, self.fast_motor_name, self.unit.space] | ||
self.nxdata_grp.attrs["axes"] = [self.unit.space, "slow", "fast"] | ||
# Build a transposed view to display the mapping experiment | ||
layout = h5py.VirtualLayout(shape=(self.nbpt_rad, self.nbpt_slow, self.nbpt_fast), dtype=self.dataset.dtype) | ||
source = h5py.VirtualSource(self.dataset) | ||
for i in range(self.nbpt_slow): | ||
for j in range(self.nbpt_fast): | ||
layout[:, i, j] = source[i, j] | ||
self.nxdata_grp.create_virtual_dataset('map', layout, fillvalue=numpy.nan).attrs["interpretation"] = "image" | ||
slow_motor_ds.attrs["axes"] = 2 | ||
fast_motor_ds.attrs["axes"] = 3 | ||
|
||
self.nxdata_grp.attrs["signal"] = self.dataset.name.split("/")[-1] | ||
|
||
self.dataset.attrs["title"] = str(self) | ||
self.nxdata_grp.attrs["signal"] = 'map' | ||
self.dataset.attrs["title"] = self.nxdata_grp["map"].attrs["title"] = str(self) | ||
self.nxs = nxs | ||
|
||
def init_shape(self): | ||
|
@@ -532,19 +540,21 @@ def init_ai(self): | |
maxshape=(None,) + self.dataset.shape[1:]) | ||
self.dataset_error.attrs["interpretation"] = "image" if self.dataset.ndim == 4 else "spectrum" | ||
space = self.unit.space | ||
unit = str(self.unit)[len(space)+1:] | ||
unit = str(self.unit)[len(space) + 1:] | ||
if space not in self.nxdata_grp: | ||
self.nxdata_grp[space] = tth | ||
self.nxdata_grp[space].attrs["axes"] = 3 | ||
self.nxdata_grp[space].attrs["unit"] = unit | ||
self.nxdata_grp[space].attrs["long_name"] = self.unit.label | ||
self.nxdata_grp[space].attrs["interpretation"] = "scalar" | ||
if self.worker.do_2D(): | ||
self.nxdata_grp["azimuthal"] = res.azimuthal | ||
self.nxdata_grp["azimuthal"].attrs["unit"] = "deg" | ||
self.nxdata_grp["azimuthal"].attrs["interpretation"] = "scalar" | ||
self.nxdata_grp["azimuthal"].attrs["axes"] = 1 | ||
azim = res.azimuthal | ||
self.nxdata_grp[space].attrs["axes"] = 2 | ||
else: | ||
self.nxdata_grp[space].attrs["axes"] = 1 | ||
azim = None | ||
return tth, azim | ||
|
||
|
@@ -584,16 +594,16 @@ def get_pos(self, filename=None, idx=None): | |
def process_one_file(self, filename, callback=None): | ||
""" | ||
:param filename: name of the input filename | ||
:param idx: index of file | ||
:param callback: function to be called after every frame has been processed. | ||
:param indices: this is a slice object, frames in this file should have the given indices. | ||
:return: None | ||
""" | ||
if self.ai is None: | ||
self.configure_worker(self.poni) | ||
if self.dataset is None: | ||
self.makeHDF5() | ||
|
||
t = time.perf_counter() | ||
t = -time.perf_counter() | ||
with fabio.open(filename) as fimg: | ||
if "dataset" in dir(fimg): | ||
if isinstance(fimg.dataset, list): | ||
|
@@ -610,9 +620,9 @@ def process_one_file(self, filename, callback=None): | |
self.process_one_frame(fimg.data) | ||
if callable(callback): | ||
callback(filename, i + 1) | ||
t -= time.perf_counter() | ||
print(f"Processing {os.path.basename(filename):30s} took {-1000*t:6.1f}ms ({fimg.nframes} frames)") | ||
self.timing.append(-t) | ||
t += time.perf_counter() | ||
print(f"Processing {os.path.basename(filename):30s} took {1000*t:6.1f}ms ({fimg.nframes} frames)") | ||
self.timing.append(t) | ||
self.processed_file.append(filename) | ||
|
||
def set_hdf5_input_dataset(self, dataset): | ||
|
@@ -633,7 +643,7 @@ def set_hdf5_input_dataset(self, dataset): | |
measurement_grp = self.nxs.new_class(self.entry_grp, "measurement", "NXdata") | ||
here = os.path.dirname(os.path.abspath(self.nxs.filename)) | ||
there = os.path.abspath(dataset.file.filename) | ||
name = "images_%04i" % len(self.stored_input) | ||
name = f"images_{len(self.stored_input):04d}" | ||
measurement_grp[name] = h5py.ExternalLink(os.path.relpath(there, here), dataset.name) | ||
if "signal" not in measurement_grp.attrs: | ||
measurement_grp.attrs["signal"] = name | ||
|
@@ -661,14 +671,14 @@ def process(self): | |
if self.dataset is None: | ||
self.makeHDF5() | ||
self.init_ai() | ||
t0 = time.perf_counter() | ||
t0 = -time.perf_counter() | ||
print(self.inputfiles) | ||
for f in self.inputfiles: | ||
self.process_one_file(f) | ||
tot = time.perf_counter() - t0 | ||
t0 -= time.perf_counter() | ||
cnt = max(self._idx, 0) + 1 | ||
print(f"Execution time for {cnt} frames: {tot:.3f} s; " | ||
f"Average execution time: {1000. * tot / cnt:.1f} ms/img") | ||
print(f"Execution time for {cnt} frames: {t0:.3f} s; " | ||
f"Average execution time: {1000. * t0 / cnt:.1f} ms/img") | ||
self.nxs.close() | ||
|
||
def get_use_gpu(self): | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,7 +3,7 @@ | |
# Project: Azimuthal integration | ||
# https://github.com/silx-kit/pyFAI | ||
# | ||
# Copyright (C) 2015-2024 European Synchrotron Radiation Facility, Grenoble, France | ||
# Copyright (C) 2015-2025 European Synchrotron Radiation Facility, Grenoble, France | ||
# | ||
# Principal author: Jérôme Kieffer ([email protected]) | ||
# | ||
|
@@ -31,7 +31,7 @@ | |
__contact__ = "[email protected]" | ||
__license__ = "MIT" | ||
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France" | ||
__date__ = "20/06/2024" | ||
__date__ = "27/01/2025" | ||
__status__ = "development" | ||
__docformat__ = 'restructuredtext' | ||
|
||
|
@@ -53,7 +53,7 @@ | |
from ..diffmap import DiffMap | ||
from .utils.tree import ListDataSet, DataSet | ||
from .dialog import MessageBox | ||
|
||
from ..io.integration_config import WorkerConfig | ||
from .pilx import MainWindow as pilx_main | ||
logger = logging.getLogger(__name__) | ||
lognorm = colors.LogNorm() | ||
|
@@ -299,13 +299,13 @@ def configure_diffraction(self, *arg, **kwarg): | |
""" | ||
logger.info("in configure_diffraction") | ||
iw = IntegrateDialog(self) | ||
if self.integration_config: | ||
iw.widget.setConfig(self.integration_config) | ||
if self.integration_config is not None: | ||
iw.widget.setWorkerConfig(self.integration_config) | ||
while True: | ||
res = iw.exec_() | ||
if res == qt.QDialog.Accepted: | ||
self.integration_config = iw.widget.getConfig() | ||
if self.integration_config.get("nbpt_rad"): | ||
self.integration_config = iw.widget.getWorkerConfig() | ||
if self.integration_config.nbpt_rad: | ||
break | ||
else: | ||
qt.QMessageBox.about(self, "Unconsistent configuration", "Some essential parameters are missing ... Did you set the radial number of points ?") | ||
|
@@ -411,12 +411,14 @@ def scan_input_files(self): | |
self.numberOfFrames.setText(str(total_frames)) | ||
if shape: | ||
self.frameShape.setText(f"{shape[1]} x {shape[0]}") | ||
if self.integration_config is not None: | ||
self.integration_config.shape = shape | ||
return total_frames | ||
|
||
def get_config(self): | ||
"""Return a dict with the plugin configuration which is JSON-serializable | ||
""" | ||
res = {"ai": self.integration_config, | ||
res = {"ai": self.integration_config.as_dict(), | ||
"experiment_title": str_(self.experimentTitle.text()).strip(), | ||
"fast_motor_name": str_(self.fastMotorName.text()).strip(), | ||
"slow_motor_name": str_(self.slowMotorName.text()).strip(), | ||
|
@@ -441,7 +443,7 @@ def set_config(self, dico): | |
:param dico: dictionary | ||
""" | ||
self.integration_config = dico.get("ai", {}) | ||
self.integration_config = WorkerConfig.from_dict(dico.get("ai", {})) | ||
setup_data = {"experiment_title": self.experimentTitle.setText, | ||
"fast_motor_name": self.fastMotorName.setText, | ||
"slow_motor_name": self.slowMotorName.setText, | ||
|
@@ -452,8 +454,8 @@ def set_config(self, dico): | |
} | ||
|
||
deprecated_keys = { | ||
"fast_motor_points" : "nbpt_fast", | ||
"slow_motor_points" : "nbpt_slow", | ||
"fast_motor_points": "nbpt_fast", | ||
"slow_motor_points": "nbpt_slow", | ||
} | ||
|
||
for key in dico.keys(): | ||
|
Oops, something went wrong.