Skip to content
Draft
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: 9 additions & 12 deletions src/pyFAI/geometry/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
__contact__ = "Jerome.Kieffer@ESRF.eu"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
__date__ = "04/12/2025"
__date__ = "10/12/2025"
__status__ = "production"
__docformat__ = "restructuredtext"

Expand Down Expand Up @@ -2176,22 +2176,19 @@ def make_headers(self, type_="list"):
f2d = self.getFit2D()
res = [
"== pyFAI calibration ==",
"Distance Sample to Detector: %s m" % self.dist,
"PONI: %.3e, %.3e m" % (self.poni1, self.poni2),
"Rotations: %.6f %.6f %.6f rad" % (self.rot1, self.rot2, self.rot3),
f"Distance Sample to Detector: {self.dist} m",
f"PONI: {self.poni1:.3e}, {self.poni2:.3e} m",
f"Rotations: {self.rot1:.6f} {self.rot2:.6f} {self.rot3:.6f} rad",
"",
"== Fit2d calibration ==",
"Distance Sample-beamCenter: %.3f mm" % f2d["directDist"],
"Center: x=%.3f, y=%.3f pix" % (f2d["centerX"], f2d["centerY"]),
"Tilt: %.3f deg TiltPlanRot: %.3f deg"
% (f2d["tilt"], f2d["tiltPlanRotation"]),
f"Distance Sample-beamCenter: {f2d.directDist:.3f} mm",
f"Center: x={f2d.centerX:.3f}, y={f2d.centerY:.3f} pix",
f"Tilt: {f2d.tilt:.3f} deg TiltPlanRot: {f2d.tiltPlanRotation:.3f} deg",
"",
str(self.detector),
" Detector has a mask: %s " % (self.detector.mask is not None),
" Detector has a dark current: %s "
% (self.detector.darkcurrent is not None),
" detector has a flat field: %s "
% (self.detector.flatfield is not None),
f" Detector has a dark current: {self.detector.darkcurrent is not None}",
f" Detector has a flat field: {self.detector.flatfield is not None}",
"",
]

Expand Down
4 changes: 3 additions & 1 deletion src/pyFAI/gui/IntegrationDialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
__contact__ = "Jerome.Kieffer@ESRF.eu"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
__date__ = "08/12/2025"
__date__ = "10/12/2025"
__status__ = "development"

import logging
Expand Down Expand Up @@ -227,6 +227,8 @@ def createObserver(self, qtSafe=True):

class IntegrationDialog(qt.QWidget):
"""Dialog to configure an azimuthal integration.

TODO: this is not a Dialog !!!
"""

batchProcessRequested = qt.Signal()
Expand Down
71 changes: 41 additions & 30 deletions src/pyFAI/gui/widgets/WorkerConfigurator.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
__contact__ = "Jerome.Kieffer@ESRF.eu"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
__date__ = "05/12/2025"
__date__ = "10/12/2025"
__status__ = "production"

import logging
Expand Down Expand Up @@ -75,6 +75,9 @@ class WorkerConfigurator(qt.QWidget):
"""Frame displaying integration configuration which can be used as input
param of the ~`pyFAI.worker.Worker`.
"""
INTEGRATOR_METHODS = {"integrate/average": "integrate1d_ng",
"sigma-clip": "sigma_clip_ng",
"median-filter": "medfilt1d_ng"}

def __init__(self, parent=None):
qt.QWidget.__init__(self, parent)
Expand Down Expand Up @@ -140,24 +143,24 @@ def __init__(self, parent=None):
self.radial_unit.setShortNameDisplay(True)
self.radial_unit.model().changed.connect(self.__radialUnitUpdated)
self.__radialUnitUpdated()

# Fiber integration parameters
fiber_units = [v for v in RADIAL_UNITS.values() if isinstance(v, UnitFiber)]
self.ip_unit.setUnits(fiber_units)
self.ip_unit.model().setValue(RADIAL_UNITS["qip_nm^-1"])

self.oop_unit.setUnits(fiber_units)
self.oop_unit.model().setValue(RADIAL_UNITS["qoop_nm^-1"])

self.nbpt_ip.setValidator(npt_validator)
self.nbpt_oop.setValidator(npt_validator)

so_validator = qt.QIntValidator()
so_validator.setBottom(1)
so_validator.setTop(8)
self.sample_orientation.setValidator(so_validator)
#

doubleOrEmptyValidator = validators.AdvancedDoubleValidator(self)
doubleOrEmptyValidator.setAllowEmpty(True)
self.normalization_factor.setValidator(doubleOrEmptyValidator)
Expand All @@ -168,17 +171,17 @@ def __init__(self, parent=None):
self.error_model.addItem(text, value)
self.error_model.setCurrentIndex(0)

for value in ["integrate",
"sigma_clip_ng",
"medfilt_ng"
]:
text = value
for text, value in self.INTEGRATOR_METHODS.items():
self.integrator_name.addItem(text, value)
self.integrator_name.setCurrentIndex(0)
self.sigmaclip_threshold.setValidator(qt.QDoubleValidator(0.0, 100.0, 1))
self.sigmaclip_threshold.setText("5.0")
self.sigmaclip_maxiter.setValidator(qt.QIntValidator(0, 100))
self.sigmaclip_maxiter.setText("5")
self.medfilt_lower.setValidator(qt.QDoubleValidator(0.0, 100.0, 1))
self.medfilt_upper.setValidator(qt.QDoubleValidator(0.0, 100.0, 1))
self.medfilt_upper.setText("50.0")
self.medfilt_lower.setText("50.0")

self.__configureDisabledStates()

Expand Down Expand Up @@ -222,11 +225,13 @@ def __updateDisabledStates(self):
self.oop_range_max.setEnabled(enabled)
enabled = self.do_1d_integration.isChecked()
self.vertical_integration.setEnabled(enabled)

self.normalization_factor.setEnabled(self.do_normalization.isChecked())
self.monitor_name.setEnabled(self.do_normalization.isChecked())
self.sigmaclip_threshold.setEnabled(self.integrator_name.currentText() == "sigma_clip_ng")
self.sigmaclip_maxiter.setEnabled(self.integrator_name.currentText() == "sigma_clip_ng")
self.sigmaclip_threshold.setEnabled(self.integrator_name.currentText() == "sigma-clip")
self.sigmaclip_maxiter.setEnabled(self.integrator_name.currentText() == "sigma-clip")
self.medfilt_lower.setEnabled(self.integrator_name.currentText() == "median-filter")
self.medfilt_upper.setEnabled(self.integrator_name.currentText() == "median-filter")

def __unitChanged(self):
unit = self.wavelengthUnit.getUnit()
Expand Down Expand Up @@ -265,21 +270,21 @@ def __getAzimuthalNbpt(self):
if value == "":
return None
return int(value)

def __getInPlaneNbpt(self):
# Only for WorkerFiberConfig
value = str(self.nbpt_ip.text()).strip()
if value == "":
return None
return int(value)

def __getOutOfPlaneNbpt(self):
# Only for WorkerFiberConfig
value = str(self.nbpt_oop.text()).strip()
if value == "":
return None
return int(value)

def getPoni(self):
poni = {"wavelength": self.__geometryModel.wavelength().value(),
"dist": self.__geometryModel.distance().value(),
Expand All @@ -297,13 +302,13 @@ def getPoni(self):

def getPoniDict(self):
return self.getPoni().as_dict()

def _getIntegrationActiveTab(self) -> int:
# tab_index = 0 -> Azimuthal integration
# tab_index = 1 -> Fiber integration
tab_index = int(self.tabWidget.currentIndex())
return tab_index

def getWorkerConfigGeneric(self):
"""Read the configuration of the plugin and returns it as a WorkerConfig / WorkerFiberConfig instance

Expand Down Expand Up @@ -387,11 +392,17 @@ def splitFiles(filenames):
value = str(value)
wc.monitor_name = value

if self.integrator_name.currentText() == "sigma_clip_ng":
if self.integrator_name.currentText() == "sigma-clip":
wc.nbpt_azim = 1
wc.integrator_method = "sigma_clip_ng"
wc.extra_options = {"thres": float(self.sigmaclip_threshold.text()),
"max_iter": float(self.sigmaclip_maxiter.text()),
"max_iter": int(self.sigmaclip_maxiter.text()),
}
elif self.integrator_name.currentText() == "median-filter":
wc.nbpt_azim = 1
wc.integrator_method = "medfilt1d_ng"
wc.extra_options = {"percentile":(float(self.medfilt_lower.text()),
float(self.medfilt_upper.text())),
}
return wc

Expand Down Expand Up @@ -448,7 +459,7 @@ def splitFiles(filenames):
if self.do_oop_range.isChecked():
wc.oop_range = [self._float("oop_range_min", -numpy.inf),
self._float("oop_range_max", numpy.inf)]

wc.vertical_integration = self.vertical_integration.isChecked()
wc.integration_1d = self.do_1d_integration.isChecked()

Expand Down Expand Up @@ -492,7 +503,7 @@ def getConfig(self):
:return: dict with all information
"""
return self.getWorkerConfig().as_dict()

def setConfig(self, dico):
"""Setup the widget from its description

Expand All @@ -508,7 +519,7 @@ def setConfig(self, dico):
self.tabWidget.setCurrentIndex(1)
else:
raise ValueError(f"{integrator_class} is not a valid Integrator class")

def setWorkerConfig(self, wc):
"""Setup the widget from its description

Expand Down Expand Up @@ -571,7 +582,7 @@ def normalizeFiles(filenames):
self.polarization_factor.setValue(wc.polarization_factor)
elif isinstance(wc.polarization_factor, (tuple, list)):
self.polarization_factor.setValue(wc.polarization_factor[0])

if type(wc) is integration_config.WorkerConfig:
self.nbpt_rad.setText(str_(wc.nbpt_rad))
self.nbpt_azim.setText(str_(wc.nbpt_azim))
Expand All @@ -597,25 +608,25 @@ def normalizeFiles(filenames):
self.vertical_integration.setChecked(wc.vertical_integration)
self.do_1d_integration.setChecked(wc.integration_1d)
unit_ip = parse_fiber_unit(**wc.unit_ip)

# In UnitSelector, searching the unit is made with 'is' not '==', not valid for FiberUnit (which are copies)
for index in range(self.ip_unit.count()):
item = self.ip_unit.itemData(index)
if item == unit_ip:
if item == unit_ip:
self.ip_unit.setCurrentIndex(index)
break

unit_oop = parse_fiber_unit(**wc.unit_oop)
for index in range(self.oop_unit.count()):
item = self.oop_unit.itemData(index)
if item == unit_oop:
if item == unit_oop:
self.oop_unit.setCurrentIndex(index)
break

self.incident_angle_deg.setText(f"{numpy.rad2deg(unit_ip.incident_angle):.2f}")
self.tilt_angle_deg.setText(f"{numpy.rad2deg(unit_ip.tilt_angle):.2f}")
self.sample_orientation.setText(str(unit_ip.sample_orientation))

self.do_solid_angle.setChecked(bool(wc.correct_solid_angle))
self.do_dummy.setChecked(wc.do_dummy)
self.do_dark.setChecked(wc.do_dark)
Expand Down Expand Up @@ -664,7 +675,7 @@ def normalizeFiles(filenames):
self.sigmaclip_maxiter.setText(str(extra_options.get("max_iter", 5)))

self.__updateDisabledStates()

def getOpenFileName(self, title):
"""Display a dialog to select a filename and return it.

Expand Down
Loading