-
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 #2419 from kif/diffmap
Diffmap
- Loading branch information
Showing
16 changed files
with
286 additions
and
223 deletions.
There are no files selected for viewing
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 |
---|---|---|
|
@@ -33,7 +33,7 @@ | |
__contact__ = "[email protected]" | ||
__license__ = "MIT" | ||
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France" | ||
__date__ = "14/02/2025" | ||
__date__ = "17/02/2025" | ||
__satus__ = "production" | ||
|
||
import sys | ||
|
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 |
---|---|---|
|
@@ -31,7 +31,7 @@ | |
__contact__ = "[email protected]" | ||
__license__ = "MIT" | ||
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France" | ||
__date__ = "27/01/2025" | ||
__date__ = "19/02/2025" | ||
__status__ = "development" | ||
__docformat__ = 'restructuredtext' | ||
|
||
|
@@ -53,6 +53,7 @@ | |
from . import version as PyFAI_VERSION, date as PyFAI_DATE | ||
from .integrator.load_engines import PREFERED_METHODS_2D, PREFERED_METHODS_1D | ||
from .io import Nexus, get_isotime, h5py | ||
from .io.integration_config import WorkerConfig | ||
from .worker import Worker | ||
from .utils.decorators import deprecated, deprecated_warning | ||
|
||
|
@@ -380,10 +381,13 @@ def parse(self, sysargv=None, with_config=False): | |
def configure_worker(self, dico=None): | ||
"""Configure the worker from the dictionary | ||
:param dico: dictionary with the configuration | ||
:param dico: dictionary/WorkerConfig with the configuration | ||
:return: worker | ||
""" | ||
if isinstance(dico, dict): | ||
dico = WorkerConfig.from_dict(dico) | ||
self.worker.set_config(dico or self.poni) | ||
self.init_shape(dico.shape) | ||
|
||
def makeHDF5(self, rewrite=False): | ||
""" | ||
|
@@ -439,7 +443,6 @@ def makeHDF5(self, rewrite=False): | |
process_grp["offset"] = self.offset | ||
config = nxs.new_class(process_grp, "configuration", "NXnote") | ||
config["type"] = "text/json" | ||
self.init_shape() | ||
worker_config = self.worker.get_config() | ||
config["data"] = json.dumps(worker_config, indent=2, separators=(",\r\n", ": ")) | ||
|
||
|
@@ -497,20 +500,25 @@ def makeHDF5(self, rewrite=False): | |
self.dataset.attrs["title"] = self.nxdata_grp["map"].attrs["title"] = str(self) | ||
self.nxs = nxs | ||
|
||
def init_shape(self): | ||
def init_shape(self, shape=None): | ||
"""Initialize the worker with the proper input shape | ||
:param shape: enforce the shape to initialize to | ||
:return: shape of the individual frames | ||
""" | ||
# if shape of detector undefined: reading the first image to guess it | ||
if self.ai.detector.shape: | ||
shape = self.ai.detector.shape | ||
else: | ||
former_shape = self.worker.ai.detector.shape | ||
try: | ||
with fabio.open(self.inputfiles[0]) as fimg: | ||
shape = fimg.data.shape | ||
self.worker.ai.shape = shape | ||
self.worker._shape = shape | ||
self.worker.output = "raw" | ||
new_shape = fimg.data.shape | ||
except: | ||
new_shape = None | ||
shape = new_shape or shape or former_shape | ||
self.worker.ai.shape = shape | ||
self.worker._shape = shape | ||
print(f"reconfigure worker with shape {shape}") | ||
self.worker.reconfig(shape, sync=True) | ||
self.worker.output = "raw" #after reconfig ! | ||
self.worker.safe = False | ||
return shape | ||
|
||
def init_ai(self): | ||
|
@@ -522,17 +530,12 @@ def init_ai(self): | |
self.configure_worker(self.poni) | ||
if not self.nxdata_grp: | ||
self.makeHDF5(rewrite=False) | ||
shape = self.init_shape() | ||
data = numpy.empty(shape, dtype=numpy.float32) | ||
logger.info(f"Initialization of the Azimuthal Integrator using method {self.method}") | ||
# enforce initialization of azimuthal integrator | ||
print(self.ai) | ||
res = self.worker.process(data) | ||
tth = res.radial | ||
if self.dataset is None: | ||
self.makeHDF5() | ||
logger.info(f"Detector shape: {self.ai.detector.shape} mask shape {self.ai.detector.mask.shape}") | ||
tth = self.worker.radial | ||
|
||
if res.sigma is not None: | ||
if self.worker.propagate_uncertainties: | ||
self.dataset_error = self.nxdata_grp.create_dataset("errors", | ||
shape=self.dataset.shape, | ||
dtype="float32", | ||
|
@@ -542,16 +545,16 @@ def init_ai(self): | |
space = self.unit.space | ||
unit = str(self.unit)[len(space) + 1:] | ||
if space not in self.nxdata_grp: | ||
self.nxdata_grp[space] = tth | ||
self.nxdata_grp[space].attrs["unit"] = unit | ||
self.nxdata_grp[space].attrs["long_name"] = self.unit.label | ||
self.nxdata_grp[space].attrs["interpretation"] = "scalar" | ||
tthds = self.nxdata_grp.create_dataset(space, data=tth) | ||
tthds.attrs["unit"] = unit | ||
tthds.attrs["long_name"] = self.unit.label | ||
tthds.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 | ||
azimds = self.nxdata_grp.create_dataset("azimuthal", data=self.worker.azimuthal) | ||
azimds.attrs["unit"] = "deg" | ||
azimds.attrs["interpretation"] = "scalar" | ||
azimds.attrs["axes"] = 1 | ||
azim = self.worker.azimuthal | ||
self.nxdata_grp[space].attrs["axes"] = 2 | ||
else: | ||
self.nxdata_grp[space].attrs["axes"] = 1 | ||
|
@@ -672,10 +675,9 @@ def process(self): | |
self.makeHDF5() | ||
self.init_ai() | ||
t0 = -time.perf_counter() | ||
print(self.inputfiles) | ||
for f in self.inputfiles: | ||
self.process_one_file(f) | ||
t0 -= time.perf_counter() | ||
t0 += time.perf_counter() | ||
cnt = max(self._idx, 0) + 1 | ||
print(f"Execution time for {cnt} frames: {t0:.3f} s; " | ||
f"Average execution time: {1000. * t0 / cnt:.1f} ms/img") | ||
|
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 |
---|---|---|
|
@@ -40,7 +40,7 @@ | |
__contact__ = "[email protected]" | ||
__license__ = "MIT" | ||
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France" | ||
__date__ = "31/01/2025" | ||
__date__ = "19/02/2025" | ||
__status__ = "production" | ||
__docformat__ = 'restructuredtext' | ||
|
||
|
@@ -1357,24 +1357,32 @@ def load(self, filename): | |
""" | ||
Load the refined parameters from a file. | ||
:param filename: name of the file to load. Can also be a JSON string with a dict or dict | ||
:type filename: string | ||
:param filename: name of the file to load. Can also be a JSON string with a dict or dict or geometry | ||
:type filename: string with filename or JSON-serialized dict (i.e. string) or a dictionary or Geometry instance. | ||
:return: itself with updated parameters | ||
""" | ||
try: | ||
if os.path.exists(filename): | ||
with open(filename) as f: | ||
dico = json.load(f) | ||
else: | ||
dico = json.loads(filename) | ||
except Exception: | ||
logger.info("Unable to parse %s as JSON file, defaulting to PoniParser", filename) | ||
poni = None | ||
if isinstance(filename, ponifile.PoniFile): | ||
poni = filename | ||
elif isinstance(filename, (dict, Geometry)): | ||
poni = ponifile.PoniFile(data=filename) | ||
elif isinstance(filename, str): | ||
try: | ||
if os.path.exists(filename): | ||
with open(filename) as f: | ||
dico = json.load(f) | ||
else: | ||
dico = json.loads(filename) | ||
except Exception: | ||
logger.info("Unable to parse %s as JSON file, defaulting to PoniParser", filename) | ||
poni = ponifile.PoniFile(data=filename) | ||
else: | ||
config = integration_config.ConfigurationReader(dico) | ||
poni = config.pop_ponifile() | ||
else: | ||
config = integration_config.ConfigurationReader(dico) | ||
poni = config.pop_ponifile() | ||
self._init_from_poni(poni) | ||
|
||
logger.error("Unable to initialize geometry from %s", filename) | ||
if poni: | ||
self._init_from_poni(poni) | ||
return self | ||
|
||
read = load | ||
|
@@ -1891,6 +1899,9 @@ def polarization(self, shape=None, factor=None, axis_offset=0, with_checksum=Fal | |
if isinstance(factor, PolarizationDescription): | ||
desc = factor | ||
factor, axis_offset = desc | ||
elif isinstance(factor, list) and len(factor)==2: | ||
desc = PolarizationDescription(*factor) | ||
factor, axis_offset = desc | ||
else: | ||
factor = float(factor) | ||
axis_offset = float(axis_offset) | ||
|
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 |
---|---|---|
|
@@ -31,7 +31,7 @@ | |
__contact__ = "[email protected]" | ||
__license__ = "MIT" | ||
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France" | ||
__date__ = "27/01/2025" | ||
__date__ = "03/02/2025" | ||
__status__ = "development" | ||
__docformat__ = 'restructuredtext' | ||
|
||
|
@@ -155,7 +155,7 @@ class DiffMapWidget(qt.QWidget): | |
def __init__(self): | ||
qt.QWidget.__init__(self) | ||
|
||
self.integration_config = {} | ||
self.integration_config = None | ||
self.list_dataset = ListDataSet() # Contains all datasets to be treated. | ||
|
||
try: | ||
|
@@ -526,16 +526,15 @@ def process(self, config=None): | |
last_processed_file = None | ||
with self.processing_sem: | ||
config = self.dump() | ||
config_ai = config.get("ai", {}) | ||
config_ai = config_ai.copy() | ||
config_ai = self.integration_config | ||
diffmap_kwargs = {} | ||
|
||
diffmap_kwargs["nbpt_rad"] = config_ai.get("nbpt_rad") | ||
diffmap_kwargs["nbpt_rad"] = config_ai.nbpt_rad | ||
for key in ["nbpt_fast", "nbpt_slow"]: | ||
if key in config: | ||
diffmap_kwargs[key] = config[key] | ||
if config_ai.get("do_2D"): | ||
diffmap_kwargs["nbpt_azim"] = config_ai.get("nbpt_azim", 1) | ||
if config_ai.do_2D: | ||
diffmap_kwargs["nbpt_azim"] = config_ai.nbpt_azim | ||
|
||
diffmap = DiffMap(**diffmap_kwargs) | ||
diffmap.inputfiles = [i.path for i in self.list_dataset] # in case generic detector without shape | ||
|
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 |
---|---|---|
|
@@ -33,7 +33,7 @@ | |
__contact__ = "[email protected]" | ||
__license__ = "MIT" | ||
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France" | ||
__date__ = "27/01/2025" | ||
__date__ = "31/01/2025" | ||
__status__ = "development" | ||
|
||
from typing import Tuple | ||
|
@@ -62,7 +62,7 @@ | |
from .widgets.MapPlotWidget import MapPlotWidget | ||
from .widgets.TitleWidget import TitleWidget | ||
from ...io.integration_config import WorkerConfig | ||
|
||
logger = logging.getLogger(__name__) | ||
|
||
class MainWindow(qt.QMainWindow): | ||
sigFileChanged = qt.Signal(str) | ||
|
@@ -175,26 +175,24 @@ def initData(self, | |
try: | ||
image_grp = h5file[path] | ||
except KeyError: | ||
error_msg = f"Cannot access diffraction images at {path}: no such path." | ||
logging.warning(error_msg) | ||
status_bar = self.statusBar() | ||
if status_bar: | ||
status_bar.showMessage(error_msg) | ||
self.warning(f"Cannot access diffraction images at {path}: no such path.") | ||
else: | ||
if not isinstance(image_grp, h5py.Group): | ||
error_msg = f"Cannot access diffraction images at {path}: not a group." | ||
logging.warning(error_msg) | ||
status_bar = self.statusBar() | ||
if status_bar: | ||
status_bar.showMessage(error_msg) | ||
else: | ||
if isinstance(image_grp, h5py.Group): | ||
lst = [] | ||
for key in image_grp: | ||
if key.startswith(base) and isinstance(image_grp[key], h5py.Dataset): | ||
lst.append(key) | ||
try: | ||
ds = image_grp[key] | ||
except KeyError: | ||
self.warning(f"Cannot access diffraction images at {path}/{key}: not a valid dataset.") | ||
else: | ||
if key.startswith(base) and isinstance(ds, h5py.Dataset): | ||
lst.append(key) | ||
|
||
lst.sort() | ||
for key in lst: | ||
self._dataset_paths[posixpath.join(path, key)] = len(image_grp[key]) | ||
else: | ||
self.warning(f"Cannot access diffraction images at {path}: not a group.") | ||
|
||
self._radial_matrix = compute_radial_values(self.worker_config) | ||
self._delta_radial_over_2 = delta_radial / 2 | ||
|
@@ -252,20 +250,20 @@ def displayImageAtIndices(self, indices: ImageIndices): | |
nxprocess = h5file[self._nxprocess_path] | ||
map_shape = get_dataset(nxprocess, "result/intensity").shape | ||
image_index = row * map_shape[1] + col + self._offset | ||
for dataset_path, size in self._dataset_paths.items(): | ||
if image_index < size: | ||
break | ||
else: | ||
image_index -= size | ||
if self._dataset_paths: | ||
for dataset_path, size in self._dataset_paths.items(): | ||
if image_index < size: | ||
break | ||
else: | ||
image_index -= size | ||
else: | ||
self.warning(f"No diffraction data images found in {self._file_name}") | ||
return | ||
try: | ||
image_dset = get_dataset(h5file, dataset_path) | ||
except KeyError: | ||
image_link = h5file.get(dataset_path, getlink=True) | ||
error_msg = f"Cannot access diffraction images at {image_link}" | ||
logging.warning(error_msg) | ||
status_bar = self.statusBar() | ||
if status_bar: | ||
status_bar.showMessage(error_msg) | ||
self.warning(f"Cannot access diffraction images at {image_link}") | ||
return | ||
|
||
if image_index >= len(image_dset): | ||
|
@@ -464,3 +462,13 @@ def setNewBackgroundCurve(self, x: float, y: float): | |
def clearPoints(self): | ||
for indices in self._fixed_indices.copy(): | ||
self.removeMapPoint(indices=indices) | ||
|
||
def warning(self, error_msg): | ||
"""Log a warning both in the terminal and in the status bar if possible | ||
:param error_msg: string with the message | ||
""" | ||
logger.warning(error_msg) | ||
status_bar = self.statusBar() | ||
if status_bar: | ||
status_bar.showMessage(error_msg) |
Oops, something went wrong.