From 797c8f6259c5bfdd7469411a0b6a0bb0dddcf36d Mon Sep 17 00:00:00 2001 From: Edgar Gutierrez Fernandez Date: Tue, 12 Nov 2024 13:33:27 +0100 Subject: [PATCH 1/9] first --- src/pyFAI/multi_geometry.py | 179 ++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) diff --git a/src/pyFAI/multi_geometry.py b/src/pyFAI/multi_geometry.py index daba12b6e..15efb5c30 100644 --- a/src/pyFAI/multi_geometry.py +++ b/src/pyFAI/multi_geometry.py @@ -48,6 +48,7 @@ import threading import numpy from .method_registry import IntegrationMethod +from .utils.decorators import deprecated_warning error = None @@ -342,3 +343,181 @@ def reset(self, collect_garbage=True): self.threadpool = ThreadPool(threadpoolsize) if collect_garbage: gc.collect() + + def integrate2d_grazing_incidence(self, lst_data, + npt_ip=1000, unit_ip=None, ip_range=None, + npt_oop=1000, unit_oop=None, oop_range=None, + incident_angle=None, tilt_angle=None, sample_orientation=None, + correctSolidAngle=True, + lst_mask=None, dummy=None, delta_dummy=None, + lst_variance=None, + polarization_factor=None, dark=None, lst_flat=None, + method=("no", "histogram", "cython"), + normalization_factor=1.0, **kwargs): + + """Performs 2D azimuthal integration of multiples frames, one for each geometry + + + """ + if "npt_horizontal" in kwargs: + deprecated_warning(type_=type(kwargs["npt_horizontal"]), name="npt_horizontal", replacement="npt_ip", since_version="2024.11/12") + npt_ip = kwargs["npt_horizontal"] + if "npt_vertical" in kwargs: + deprecated_warning(type_=type(kwargs["npt_vertical"]), name="npt_vertical", replacement="npt_oop", since_version="2024.11/12") + npt_oop = kwargs["npt_vertical"] + if "horizontal_unit" in kwargs: + deprecated_warning(type_=type(kwargs["horizontal_unit"]), name="horizontal_unit", replacement="unit_ip", since_version="2024.11/12") + unit_ip = kwargs["horizontal_unit"] + if "vertical_unit" in kwargs: + deprecated_warning(type_=type(kwargs["vertical_unit"]), name="vertical_unit", replacement="unit_oop", since_version="2024.11/12") + unit_oop = kwargs["vertical_unit"] + if "horizontal_unit_range" in kwargs: + deprecated_warning(type_=type(kwargs["horizontal_unit_range"]), name="horizontal_unit_range", replacement="ip_range", since_version="2024.11/12") + ip_range = kwargs["horizontal_unit_range"] + if "vertical_unit_range" in kwargs: + deprecated_warning(type_=type(kwargs["vertical_unit_range"]), name="vertical_unit_range", replacement="oop_range", since_version="2024.11/12") + oop_range = kwargs["vertical_unit_range"] + + for fi in self.ais: + unit_ip, unit_oop = fi.parse_units(unit_ip=unit_ip, unit_oop=unit_oop, + incident_angle=incident_angle, + tilt_angle=tilt_angle, + sample_orientation=sample_orientation) + + fi.reset_integrator(incident_angle=unit_ip.incident_angle, + tilt_angle=unit_ip.tilt_angle, + sample_orientation=unit_ip.sample_orientation) + + if (isinstance(method, (tuple, list)) and method[0] != "no") or (isinstance(method, IntegrationMethod) and method.split != "no"): + logger.warning(f"Method {method} is using a pixel-splitting scheme. GI integration should be use WITHOUT PIXEL-SPLITTING! The results could be wrong!") + + return self.integrate2d_fiber(lst_data=lst_data, npt_ip=npt_ip, npt_oop=npt_oop, + unit_ip=unit_ip, unit_oop=unit_oop, + ip_range=ip_range, + oop_range=oop_range, + sample_orientation=sample_orientation, + correctSolidAngle=correctSolidAngle, + lst_mask=lst_mask, dummy=dummy, delta_dummy=delta_dummy, + polarization_factor=polarization_factor, dark=dark, lst_flat=lst_flat, + method=method, + normalization_factor=normalization_factor, + ) + + def integrate2d_fiber(self, lst_data, + npt_ip=1000, unit_ip=None, ip_range=None, + npt_oop=1000, unit_oop=None, oop_range=None, + incident_angle=None, tilt_angle=None, sample_orientation=None, + correctSolidAngle=True, + lst_mask=None, dummy=None, delta_dummy=None, + lst_variance=None, + polarization_factor=None, dark=None, lst_flat=None, + method=("no", "histogram", "cython"), + normalization_factor=1.0, **kwargs): + + if "npt_horizontal" in kwargs: + deprecated_warning(type_=type(kwargs["npt_horizontal"]), name="npt_horizontal", replacement="npt_ip", since_version="2024.11/12") + npt_ip = kwargs["npt_horizontal"] + if "npt_vertical" in kwargs: + deprecated_warning(type_=type(kwargs["npt_vertical"]), name="npt_vertical", replacement="npt_oop", since_version="2024.11/12") + npt_oop = kwargs["npt_vertical"] + if "horizontal_unit" in kwargs: + deprecated_warning(type_=type(kwargs["horizontal_unit"]), name="horizontal_unit", replacement="unit_ip", since_version="2024.11/12") + unit_ip = kwargs["horizontal_unit"] + if "vertical_unit" in kwargs: + deprecated_warning(type_=type(kwargs["vertical_unit"]), name="vertical_unit", replacement="unit_oop", since_version="2024.11/12") + unit_oop = kwargs["vertical_unit"] + if "horizontal_unit_range" in kwargs: + deprecated_warning(type_=type(kwargs["horizontal_unit_range"]), name="horizontal_unit_range", replacement="ip_range", since_version="2024.11/12") + ip_range = kwargs["horizontal_unit_range"] + if "vertical_unit_range" in kwargs: + deprecated_warning(type_=type(kwargs["vertical_unit_range"]), name="vertical_unit_range", replacement="oop_range", since_version="2024.11/12") + oop_range = kwargs["vertical_unit_range"] + + for fi in self.ais: + unit_ip, unit_oop = fi.parse_units(unit_ip=unit_ip, unit_oop=unit_oop, + sample_orientation=sample_orientation) + + fi.reset_integrator(incident_angle=unit_ip.incident_angle, + tilt_angle=unit_ip.tilt_angle, + sample_orientation=unit_ip.sample_orientation) + + if (isinstance(method, (tuple, list)) and method[0] != "no") or (isinstance(method, IntegrationMethod) and method.split != "no"): + logger.warning(f"Method {method} is using a pixel-splitting scheme. GI integration should be use WITHOUT PIXEL-SPLITTING! The results could be wrong!") + + if len(lst_data) == 0: + raise RuntimeError("List of images cannot be empty") + if normalization_factor is None: + normalization_factor = [1.0] * len(self.ais) + elif not isinstance(normalization_factor, collections.abc.Iterable): + normalization_factor = [normalization_factor] * len(self.ais) + if lst_variance is None: + lst_variance = [None] * len(self.ais) + if lst_mask is None: + lst_mask = [None] * len(self.ais) + elif isinstance(lst_mask, numpy.ndarray): + lst_mask = [lst_mask] * len(self.ais) + if lst_flat is None: + lst_flat = [None] * len(self.ais) + elif isinstance(lst_flat, numpy.ndarray): + lst_flat = [lst_flat] * len(self.ais) + + method = IntegrationMethod.select_one_available(method, dim=2) + + signal = numpy.zeros((npt_oop, npt_ip), dtype=numpy.float64) + count = numpy.zeros_like(signal) + normalization = numpy.zeros_like(signal) + variance = None + if self.radial_range is None: + self.radial_range = self._guess_radial_range() + if self.azimuth_range is None: + self.azimuth_range = self._guess_azimuth_range() + def _integrate(args): + fi, data, monitor, var, mask, flat = args + return fi.integrate2d_fiber(data, + npt_ip=npt_ip, unit_ip=unit_ip, ip_range=ip_range, + npt_oop=npt_oop, unit_oop=unit_oop, oop_range=oop_range, + incident_angle=incident_angle, tilt_angle=tilt_angle, sample_orientation=sample_orientation, + correctSolidAngle=correctSolidAngle, + variance=var, + polarization_factor=polarization_factor, + method=method, safe=True, + dummy=dummy, delta_dummy=delta_dummy, + mask=mask, flat=flat, dark=dark, normalization_factor=monitor, **kwargs) + if self.threadpool is None: + results = map(_integrate, + zip(self.ais, lst_data, normalization_factor, lst_variance, lst_mask, lst_flat)) + else: + results = self.threadpool.map(_integrate, + zip(self.ais, lst_data, normalization_factor, lst_variance, lst_mask, lst_flat)) + for res, ai in zip(results, self.ais): + sac = (ai.pixel1 * ai.pixel2 / ai.dist ** 2) if correctSolidAngle else 1.0 + count += res.count + signal += res.sum_signal + normalization += res.sum_normalization * sac + if res.sigma is not None: + if variance is None: + variance = res.sum_variance.astype(numpy.float64) # explicit copy ! + else: + variance += res.sum_variance + + tiny = numpy.finfo("float32").tiny + norm = numpy.maximum(normalization, tiny) + invalid = count <= 0 + I = signal / norm + I[invalid] = self.empty + + if variance is not None: + sigma = numpy.sqrt(variance) / norm + sigma[invalid] = self.empty + result = Integrate2dResult(I, res.radial, res.azimuthal, sigma) + else: + result = Integrate2dResult(I, res.radial, res.azimuthal) + result._set_sum(signal) + result._set_compute_engine(res.compute_engine) + result._set_radial_unit(self.radial_unit) + result._set_azimuthal_unit(self.azimuth_unit) + result._set_sum_signal(signal) + result._set_sum_normalization(normalization) + result._set_sum_variance(variance) + result._set_count(count) + return result \ No newline at end of file From bd6e64e634e5b66bdd69c062b8cc8a44d03a02c4 Mon Sep 17 00:00:00 2001 From: Edgar Gutierrez Fernandez Date: Tue, 12 Nov 2024 13:43:05 +0100 Subject: [PATCH 2/9] ls_variance --- src/pyFAI/multi_geometry.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pyFAI/multi_geometry.py b/src/pyFAI/multi_geometry.py index 15efb5c30..5ddbd9f82 100644 --- a/src/pyFAI/multi_geometry.py +++ b/src/pyFAI/multi_geometry.py @@ -398,6 +398,7 @@ def integrate2d_grazing_incidence(self, lst_data, sample_orientation=sample_orientation, correctSolidAngle=correctSolidAngle, lst_mask=lst_mask, dummy=dummy, delta_dummy=delta_dummy, + lst_variance=lst_variance, polarization_factor=polarization_factor, dark=dark, lst_flat=lst_flat, method=method, normalization_factor=normalization_factor, From fba42c2f238fb9e20b4beb0fe89572832855e04e Mon Sep 17 00:00:00 2001 From: Edgar Gutierrez Fernandez Date: Tue, 12 Nov 2024 14:58:12 +0100 Subject: [PATCH 3/9] compatbility --- src/pyFAI/multi_geometry.py | 419 +++++++++++++++++++++++++++++++----- 1 file changed, 365 insertions(+), 54 deletions(-) diff --git a/src/pyFAI/multi_geometry.py b/src/pyFAI/multi_geometry.py index 5ddbd9f82..7956f4345 100644 --- a/src/pyFAI/multi_geometry.py +++ b/src/pyFAI/multi_geometry.py @@ -344,6 +344,154 @@ def reset(self, collect_garbage=True): if collect_garbage: gc.collect() + + def integrate2d_fiber(self, lst_data, + npt_ip=1000, unit_ip=None, ip_range=None, + npt_oop=1000, unit_oop=None, oop_range=None, + sample_orientation=None, + correctSolidAngle=True, + lst_mask=None, dummy=None, delta_dummy=None, + lst_variance=None, + polarization_factor=None, dark=None, lst_flat=None, + method=("no", "histogram", "cython"), + normalization_factor=1.0, **kwargs): + """Performs 2D azimuthal integration of multiples frames, one for each geometry, + It wraps the method integrate2d_fiber of pyFAI.integrator.fiber.FiberIntegrator + + :param lst_data: list of numpy array + :param int npt_ip: number of points to be used along the in-plane axis + :param pyFAI.units.UnitFiber/str unit_ip: unit to describe the in-plane axis. If not provided, it takes qip_nm^-1 + :param list ip_range: The lower and upper range of the in-plane unit. If not provided, range is simply (data.min(), data.max()). Values outside the range are ignored. Optional. + :param int npt_oop: number of points to be used along the out-of-plane axis + :param pyFAI.units.UnitFiber/str unit_oop: unit to describe the out-of-plane axis. If not provided, it takes qoop_nm^-1 + :param list oop_range: The lower and upper range of the out-of-plane unit. If not provided, range is simply (data.min(), data.max()). Values outside the range are ignored. Optional. + :param int sample_orientation: 1-4, four different orientation of the fiber axis regarding the detector main axis, from 1 to 4 is +90º + :param bool correctSolidAngle: correct for solid angle of each pixel if True + :param lst_mask: numpy.Array or list of numpy.array which mask the lst_data. + :param float dummy: value for dead/masked pixels + :param float delta_dummy: precision for dummy value + :param lst_variance: list of array containing the variance of the data. If not available, no error propagation is done + :type lst_variance: list of ndarray + :param float polarization_factor: polarization factor between -1 (vertical) and +1 (horizontal). + * 0 for circular polarization or random, + * None for no correction, + * True for using the former correction + :param ndarray dark: dark noise image + :param lst_flat: numpy.Array or list of numpy.array which flat the lst_data. + :param IntegrationMethod method: IntegrationMethod instance or 3-tuple with (splitting, algorithm, implementation) + :param float normalization_factor: Value of a normalization monitor + :return: regrouped intensity and unit arrays + :rtype: Integrate2dResult + """ + if "npt_horizontal" in kwargs: + deprecated_warning(type_=type(kwargs["npt_horizontal"]), name="npt_horizontal", replacement="npt_ip", since_version="2024.11/12") + npt_ip = kwargs["npt_horizontal"] + if "npt_vertical" in kwargs: + deprecated_warning(type_=type(kwargs["npt_vertical"]), name="npt_vertical", replacement="npt_oop", since_version="2024.11/12") + npt_oop = kwargs["npt_vertical"] + if "horizontal_unit" in kwargs: + deprecated_warning(type_=type(kwargs["horizontal_unit"]), name="horizontal_unit", replacement="unit_ip", since_version="2024.11/12") + unit_ip = kwargs["horizontal_unit"] + if "vertical_unit" in kwargs: + deprecated_warning(type_=type(kwargs["vertical_unit"]), name="vertical_unit", replacement="unit_oop", since_version="2024.11/12") + unit_oop = kwargs["vertical_unit"] + if "horizontal_unit_range" in kwargs: + deprecated_warning(type_=type(kwargs["horizontal_unit_range"]), name="horizontal_unit_range", replacement="ip_range", since_version="2024.11/12") + ip_range = kwargs["horizontal_unit_range"] + if "vertical_unit_range" in kwargs: + deprecated_warning(type_=type(kwargs["vertical_unit_range"]), name="vertical_unit_range", replacement="oop_range", since_version="2024.11/12") + oop_range = kwargs["vertical_unit_range"] + + for fi in self.ais: + unit_ip, unit_oop = fi.parse_units(unit_ip=unit_ip, unit_oop=unit_oop, + sample_orientation=sample_orientation) + + fi.reset_integrator(incident_angle=unit_ip.incident_angle, + tilt_angle=unit_ip.tilt_angle, + sample_orientation=unit_ip.sample_orientation) + + if (isinstance(method, (tuple, list)) and method[0] != "no") or (isinstance(method, IntegrationMethod) and method.split != "no"): + logger.warning(f"Method {method} is using a pixel-splitting scheme. GI integration should be use WITHOUT PIXEL-SPLITTING! The results could be wrong!") + + if len(lst_data) == 0: + raise RuntimeError("List of images cannot be empty") + if normalization_factor is None: + normalization_factor = [1.0] * len(self.ais) + elif not isinstance(normalization_factor, collections.abc.Iterable): + normalization_factor = [normalization_factor] * len(self.ais) + if lst_variance is None: + lst_variance = [None] * len(self.ais) + if lst_mask is None: + lst_mask = [None] * len(self.ais) + elif isinstance(lst_mask, numpy.ndarray): + lst_mask = [lst_mask] * len(self.ais) + if lst_flat is None: + lst_flat = [None] * len(self.ais) + elif isinstance(lst_flat, numpy.ndarray): + lst_flat = [lst_flat] * len(self.ais) + + method = IntegrationMethod.select_one_available(method, dim=2) + + signal = numpy.zeros((npt_oop, npt_ip), dtype=numpy.float64) + count = numpy.zeros_like(signal) + normalization = numpy.zeros_like(signal) + variance = None + + if self.radial_range is None: + self.radial_range = ip_range or self._guess_radial_range() + if self.azimuth_range is None: + self.azimuth_range = oop_range or self._guess_azimuth_range() + def _integrate(args): + fi, data, monitor, var, mask, flat = args + return fi.integrate2d_fiber(data, + npt_ip=npt_ip, unit_ip=unit_ip, ip_range=self.radial_range, + npt_oop=npt_oop, unit_oop=unit_oop, oop_range=self.azimuth_range, + sample_orientation=sample_orientation, + correctSolidAngle=correctSolidAngle, + variance=var, + polarization_factor=polarization_factor, + method=method, safe=True, + dummy=dummy, delta_dummy=delta_dummy, + mask=mask, flat=flat, dark=dark, normalization_factor=monitor, **kwargs) + if self.threadpool is None: + results = map(_integrate, + zip(self.ais, lst_data, normalization_factor, lst_variance, lst_mask, lst_flat)) + else: + results = self.threadpool.map(_integrate, + zip(self.ais, lst_data, normalization_factor, lst_variance, lst_mask, lst_flat)) + for res, ai in zip(results, self.ais): + sac = (ai.pixel1 * ai.pixel2 / ai.dist ** 2) if correctSolidAngle else 1.0 + count += res.count + signal += res.sum_signal + normalization += res.sum_normalization * sac + if res.sigma is not None: + if variance is None: + variance = res.sum_variance.astype(numpy.float64) # explicit copy ! + else: + variance += res.sum_variance + + tiny = numpy.finfo("float32").tiny + norm = numpy.maximum(normalization, tiny) + invalid = count <= 0 + I = signal / norm + I[invalid] = self.empty + + if variance is not None: + sigma = numpy.sqrt(variance) / norm + sigma[invalid] = self.empty + result = Integrate2dResult(I, res.radial, res.azimuthal, sigma) + else: + result = Integrate2dResult(I, res.radial, res.azimuthal) + result._set_sum(signal) + result._set_compute_engine(res.compute_engine) + result._set_radial_unit(self.radial_unit) + result._set_azimuthal_unit(self.azimuth_unit) + result._set_sum_signal(signal) + result._set_sum_normalization(normalization) + result._set_sum_variance(variance) + result._set_count(count) + return result + def integrate2d_grazing_incidence(self, lst_data, npt_ip=1000, unit_ip=None, ip_range=None, npt_oop=1000, unit_oop=None, oop_range=None, @@ -354,11 +502,37 @@ def integrate2d_grazing_incidence(self, lst_data, polarization_factor=None, dark=None, lst_flat=None, method=("no", "histogram", "cython"), normalization_factor=1.0, **kwargs): - - """Performs 2D azimuthal integration of multiples frames, one for each geometry - + """Performs 2D azimuthal integration of multiples frames, one for each geometry, + It wraps the method integrate2d_grazing_incidence of pyFAI.integrator.fiber.FiberIntegrator + :param lst_data: list of numpy array + :param int npt_ip: number of points to be used along the in-plane axis + :param pyFAI.units.UnitFiber/str unit_ip: unit to describe the in-plane axis. If not provided, it takes qip_nm^-1 + :param list ip_range: The lower and upper range of the in-plane unit. If not provided, range is simply (data.min(), data.max()). Values outside the range are ignored. Optional. + :param int npt_oop: number of points to be used along the out-of-plane axis + :param pyFAI.units.UnitFiber/str unit_oop: unit to describe the out-of-plane axis. If not provided, it takes qoop_nm^-1 + :param list oop_range: The lower and upper range of the out-of-plane unit. If not provided, range is simply (data.min(), data.max()). Values outside the range are ignored. Optional. + :param incident_angle: tilting of the sample towards the beam (analog to rot2): in radians + :param tilt_angle: tilting of the sample orthogonal to the beam direction (analog to rot3): in radians + :param int sample_orientation: 1-4, four different orientation of the fiber axis regarding the detector main axis, from 1 to 4 is +90º + :param bool correctSolidAngle: correct for solid angle of each pixel if True + :param lst_mask: numpy.Array or list of numpy.array which mask the lst_data. + :param float dummy: value for dead/masked pixels + :param float delta_dummy: precision for dummy value + :param lst_variance: list of array containing the variance of the data. If not available, no error propagation is done + :type lst_variance: list of ndarray + :param float polarization_factor: polarization factor between -1 (vertical) and +1 (horizontal). + * 0 for circular polarization or random, + * None for no correction, + * True for using the former correction + :param ndarray dark: dark noise image + :param lst_flat: numpy.Array or list of numpy.array which flat the lst_data. + :param IntegrationMethod method: IntegrationMethod instance or 3-tuple with (splitting, algorithm, implementation) + :param float normalization_factor: Value of a normalization monitor + :return: regrouped intensity and unit arrays + :rtype: Integrate2dResult """ + if "npt_horizontal" in kwargs: deprecated_warning(type_=type(kwargs["npt_horizontal"]), name="npt_horizontal", replacement="npt_ip", since_version="2024.11/12") npt_ip = kwargs["npt_horizontal"] @@ -402,37 +576,73 @@ def integrate2d_grazing_incidence(self, lst_data, polarization_factor=polarization_factor, dark=dark, lst_flat=lst_flat, method=method, normalization_factor=normalization_factor, - ) + ) - def integrate2d_fiber(self, lst_data, + def integrate1d_fiber(self, lst_data, npt_ip=1000, unit_ip=None, ip_range=None, npt_oop=1000, unit_oop=None, oop_range=None, - incident_angle=None, tilt_angle=None, sample_orientation=None, + sample_orientation=None, correctSolidAngle=True, + vertical_integration = True, lst_mask=None, dummy=None, delta_dummy=None, lst_variance=None, polarization_factor=None, dark=None, lst_flat=None, method=("no", "histogram", "cython"), normalization_factor=1.0, **kwargs): - - if "npt_horizontal" in kwargs: - deprecated_warning(type_=type(kwargs["npt_horizontal"]), name="npt_horizontal", replacement="npt_ip", since_version="2024.11/12") - npt_ip = kwargs["npt_horizontal"] - if "npt_vertical" in kwargs: - deprecated_warning(type_=type(kwargs["npt_vertical"]), name="npt_vertical", replacement="npt_oop", since_version="2024.11/12") - npt_oop = kwargs["npt_vertical"] - if "horizontal_unit" in kwargs: - deprecated_warning(type_=type(kwargs["horizontal_unit"]), name="horizontal_unit", replacement="unit_ip", since_version="2024.11/12") - unit_ip = kwargs["horizontal_unit"] - if "vertical_unit" in kwargs: - deprecated_warning(type_=type(kwargs["vertical_unit"]), name="vertical_unit", replacement="unit_oop", since_version="2024.11/12") - unit_oop = kwargs["vertical_unit"] - if "horizontal_unit_range" in kwargs: - deprecated_warning(type_=type(kwargs["horizontal_unit_range"]), name="horizontal_unit_range", replacement="ip_range", since_version="2024.11/12") - ip_range = kwargs["horizontal_unit_range"] - if "vertical_unit_range" in kwargs: - deprecated_warning(type_=type(kwargs["vertical_unit_range"]), name="vertical_unit_range", replacement="oop_range", since_version="2024.11/12") - oop_range = kwargs["vertical_unit_range"] + """Performs 1D fiber integration of multiples frames, one for each geometry, + It wraps the method integrate_fiber of pyFAI.integrator.fiber.FiberIntegrator + + :param lst_data: list of numpy array + :param int npt_ip: number of points to be used along the in-plane axis + :param pyFAI.units.UnitFiber/str unit_ip: unit to describe the in-plane axis. If not provided, it takes qip_nm^-1 + :param list ip_range: The lower and upper range of the in-plane unit. If not provided, range is simply (data.min(), data.max()). Values outside the range are ignored. Optional. + :param int npt_oop: number of points to be used along the out-of-plane axis + :param pyFAI.units.UnitFiber/str unit_oop: unit to describe the out-of-plane axis. If not provided, it takes qoop_nm^-1 + :param list oop_range: The lower and upper range of the out-of-plane unit. If not provided, range is simply (data.min(), data.max()). Values outside the range are ignored. Optional. + :param int sample_orientation: 1-4, four different orientation of the fiber axis regarding the detector main axis, from 1 to 4 is +90º + :param bool vertical_integration: If True, integrates along unit_ip; if False, integrates along unit_oop + :param bool correctSolidAngle: correct for solid angle of each pixel if True + :param lst_mask: numpy.Array or list of numpy.array which mask the lst_data. + :param float dummy: value for dead/masked pixels + :param float delta_dummy: precision for dummy value + :param lst_variance: list of array containing the variance of the data. If not available, no error propagation is done + :type lst_variance: list of ndarray + :param float polarization_factor: polarization factor between -1 (vertical) and +1 (horizontal). + * 0 for circular polarization or random, + * None for no correction, + * True for using the former correction + :param ndarray dark: dark noise image + :param lst_flat: numpy.Array or list of numpy.array which flat the lst_data. + :param IntegrationMethod method: IntegrationMethod instance or 3-tuple with (splitting, algorithm, implementation) + :param float normalization_factor: Value of a normalization monitor + :return: chi bins center positions and regrouped intensity + :rtype: Integrate1dResult + """ + + if "npt_output" in kwargs: + deprecated_warning(type_=type(kwargs["npt_output"]), name="npt_output", replacement=("npt_oop, npt_ip, vertical_integration instead"), since_version="2024.11/12") + npt_oop = kwargs["npt_output"] + vertical_integration = True + if "npt_integrated" in kwargs: + deprecated_warning(type_=type(kwargs["npt_integrated"]), name="npt_integrated", replacement=("npt_oop, npt_ip, vertical_integration instead"), since_version="2024.11/12") + npt_ip = kwargs["npt_integrated"] + vertical_integration = True + if "output_unit" in kwargs: + deprecated_warning(type_=type(kwargs["output_unit"]), name="output_unit", replacement=("unit_oop, unit_ip, vertical_integration instead"), since_version="2024.11/12") + unit_oop = kwargs["output_unit"] + vertical_integration = True + if "integrated_unit" in kwargs: + deprecated_warning(type_=type(kwargs["integrated_unit"]), name="integrated_unit", replacement=("unit_oop, unit_ip, vertical_integration instead"), since_version="2024.11/12") + unit_ip = kwargs["integrated_unit"] + vertical_integration = True + if "output_unit_range" in kwargs: + deprecated_warning(type_=type(kwargs["output_unit_range"]), name="output_unit_range", replacement=("oop_range, ip_range, vertical_integration instead"), since_version="2024.11/12") + oop_range = kwargs["output_unit_range"] + vertical_integration = True + if "integrated_unit_range" in kwargs: + deprecated_warning(type_=type(kwargs["integrated_unit_range"]), name="integrated_unit_range", replacement=("oop_range, ip_range, vertical_integration instead"), since_version="2024.11/12") + ip_range = kwargs["integrated_unit_range"] + vertical_integration = True for fi in self.ais: unit_ip, unit_oop = fi.parse_units(unit_ip=unit_ip, unit_oop=unit_oop, @@ -445,6 +655,23 @@ def integrate2d_fiber(self, lst_data, if (isinstance(method, (tuple, list)) and method[0] != "no") or (isinstance(method, IntegrationMethod) and method.split != "no"): logger.warning(f"Method {method} is using a pixel-splitting scheme. GI integration should be use WITHOUT PIXEL-SPLITTING! The results could be wrong!") + + if vertical_integration and npt_oop is None: + raise RuntimeError("npt_oop (out-of-plane bins) is needed to do the integration") + elif not vertical_integration and npt_ip is None: + raise RuntimeError("npt_ip (in-plane bins) is needed to do the integration") + + npt_oop = npt_oop or 500 + npt_ip = npt_ip or 500 + + npt_output = npt_oop + self.radial_unit = unit_oop + self.radial_range = oop_range or self._guess_radial_range() + self.azimuth_unit = unit_ip + self.azimuth_range = ip_range or self._guess_azimuth_range() + + method = IntegrationMethod.select_one_available(method, dim=1) + if len(lst_data) == 0: raise RuntimeError("List of images cannot be empty") if normalization_factor is None: @@ -461,64 +688,148 @@ def integrate2d_fiber(self, lst_data, lst_flat = [None] * len(self.ais) elif isinstance(lst_flat, numpy.ndarray): lst_flat = [lst_flat] * len(self.ais) - - method = IntegrationMethod.select_one_available(method, dim=2) - - signal = numpy.zeros((npt_oop, npt_ip), dtype=numpy.float64) - count = numpy.zeros_like(signal) + signal = numpy.zeros(npt_output, dtype=numpy.float64) normalization = numpy.zeros_like(signal) + count = numpy.zeros_like(signal) variance = None - if self.radial_range is None: - self.radial_range = self._guess_radial_range() - if self.azimuth_range is None: - self.azimuth_range = self._guess_azimuth_range() + def _integrate(args): fi, data, monitor, var, mask, flat = args - return fi.integrate2d_fiber(data, - npt_ip=npt_ip, unit_ip=unit_ip, ip_range=ip_range, - npt_oop=npt_oop, unit_oop=unit_oop, oop_range=oop_range, - incident_angle=incident_angle, tilt_angle=tilt_angle, sample_orientation=sample_orientation, - correctSolidAngle=correctSolidAngle, - variance=var, - polarization_factor=polarization_factor, - method=method, safe=True, - dummy=dummy, delta_dummy=delta_dummy, - mask=mask, flat=flat, dark=dark, normalization_factor=monitor, **kwargs) + return fi.integrate_fiber(data=data, + npt_oop=npt_oop, unit_oop=unit_oop, oop_range=self.radial_range, + npt_ip=npt_ip, unit_ip=unit_ip, ip_range=self.azimuth_range, + vertical_integration=vertical_integration, + sample_orientation=sample_orientation, + correctSolidAngle=correctSolidAngle, + mask=mask, dummy=dummy, delta_dummy=delta_dummy, + polarization_factor=polarization_factor, dark=dark, flat=flat, + method=("no", "histogram", "cython"), + normalization_factor=monitor, + variance=var, + ) if self.threadpool is None: results = map(_integrate, zip(self.ais, lst_data, normalization_factor, lst_variance, lst_mask, lst_flat)) else: results = self.threadpool.map(_integrate, - zip(self.ais, lst_data, normalization_factor, lst_variance, lst_mask, lst_flat)) + zip(self.ais, lst_data, normalization_factor, lst_variance, lst_mask, lst_flat)) for res, ai in zip(results, self.ais): sac = (ai.pixel1 * ai.pixel2 / ai.dist ** 2) if correctSolidAngle else 1.0 count += res.count - signal += res.sum_signal normalization += res.sum_normalization * sac + signal += res.sum_signal if res.sigma is not None: if variance is None: - variance = res.sum_variance.astype(numpy.float64) # explicit copy ! + variance = res.sum_variance.astype(dtype=numpy.float64) # explicit copy else: variance += res.sum_variance tiny = numpy.finfo("float32").tiny norm = numpy.maximum(normalization, tiny) - invalid = count <= 0 + invalid = count <= 0.0 I = signal / norm I[invalid] = self.empty if variance is not None: sigma = numpy.sqrt(variance) / norm sigma[invalid] = self.empty - result = Integrate2dResult(I, res.radial, res.azimuthal, sigma) + result = Integrate1dResult(res.radial, I, sigma) else: - result = Integrate2dResult(I, res.radial, res.azimuthal) - result._set_sum(signal) + result = Integrate1dResult(res.radial, I) result._set_compute_engine(res.compute_engine) - result._set_radial_unit(self.radial_unit) - result._set_azimuthal_unit(self.azimuth_unit) + result._set_unit(self.radial_unit) result._set_sum_signal(signal) result._set_sum_normalization(normalization) result._set_sum_variance(variance) result._set_count(count) - return result \ No newline at end of file + return result + + def integrate1d_grazing_incidence(self, lst_data, + npt_ip=1000, unit_ip=None, ip_range=None, + npt_oop=1000, unit_oop=None, oop_range=None, + incident_angle=None, tilt_angle=None, sample_orientation=None, + vertical_integration = True, + correctSolidAngle=True, + lst_mask=None, dummy=None, delta_dummy=None, + lst_variance=None, + polarization_factor=None, dark=None, lst_flat=None, + method=("no", "histogram", "cython"), + normalization_factor=1.0, **kwargs): + """Performs 1D fiber integration of multiples frames, one for each geometry, + It wraps the method integrate_grazing_incidence of pyFAI.integrator.fiber.FiberIntegrator + + :param lst_data: list of numpy array + :param int npt_ip: number of points to be used along the in-plane axis + :param pyFAI.units.UnitFiber/str unit_ip: unit to describe the in-plane axis. If not provided, it takes qip_nm^-1 + :param list ip_range: The lower and upper range of the in-plane unit. If not provided, range is simply (data.min(), data.max()). Values outside the range are ignored. Optional. + :param int npt_oop: number of points to be used along the out-of-plane axis + :param pyFAI.units.UnitFiber/str unit_oop: unit to describe the out-of-plane axis. If not provided, it takes qoop_nm^-1 + :param list oop_range: The lower and upper range of the out-of-plane unit. If not provided, range is simply (data.min(), data.max()). Values outside the range are ignored. Optional. + :param incident_angle: tilting of the sample towards the beam (analog to rot2): in radians + :param tilt_angle: tilting of the sample orthogonal to the beam direction (analog to rot3): in radians + :param int sample_orientation: 1-4, four different orientation of the fiber axis regarding the detector main axis, from 1 to 4 is +90º + :param bool vertical_integration: If True, integrates along unit_ip; if False, integrates along unit_oop + :param bool correctSolidAngle: correct for solid angle of each pixel if True + :param lst_mask: numpy.Array or list of numpy.array which mask the lst_data. + :param float dummy: value for dead/masked pixels + :param float delta_dummy: precision for dummy value + :param lst_variance: list of array containing the variance of the data. If not available, no error propagation is done + :type lst_variance: list of ndarray + :param float polarization_factor: polarization factor between -1 (vertical) and +1 (horizontal). + * 0 for circular polarization or random, + * None for no correction, + * True for using the former correction + :param ndarray dark: dark noise image + :param lst_flat: numpy.Array or list of numpy.array which flat the lst_data. + :param IntegrationMethod method: IntegrationMethod instance or 3-tuple with (splitting, algorithm, implementation) + :param float normalization_factor: Value of a normalization monitor + :return: chi bins center positions and regrouped intensity + :rtype: Integrate1dResult + """ + if "npt_output" in kwargs: + deprecated_warning(type_=type(kwargs["npt_output"]), name="npt_output", replacement=("npt_oop, npt_ip, vertical_integration instead"), since_version="2024.11/12") + npt_oop = kwargs["npt_output"] + vertical_integration = True + if "npt_integrated" in kwargs: + deprecated_warning(type_=type(kwargs["npt_integrated"]), name="npt_integrated", replacement=("npt_oop, npt_ip, vertical_integration instead"), since_version="2024.11/12") + npt_ip = kwargs["npt_integrated"] + vertical_integration = True + if "output_unit" in kwargs: + deprecated_warning(type_=type(kwargs["output_unit"]), name="output_unit", replacement=("unit_oop, unit_ip, vertical_integration instead"), since_version="2024.11/12") + unit_oop = kwargs["output_unit"] + vertical_integration = True + if "integrated_unit" in kwargs: + deprecated_warning(type_=type(kwargs["integrated_unit"]), name="integrated_unit", replacement=("unit_oop, unit_ip, vertical_integration instead"), since_version="2024.11/12") + unit_ip = kwargs["integrated_unit"] + vertical_integration = True + if "output_unit_range" in kwargs: + deprecated_warning(type_=type(kwargs["output_unit_range"]), name="output_unit_range", replacement=("oop_range, ip_range, vertical_integration instead"), since_version="2024.11/12") + oop_range = kwargs["output_unit_range"] + vertical_integration = True + if "integrated_unit_range" in kwargs: + deprecated_warning(type_=type(kwargs["integrated_unit_range"]), name="integrated_unit_range", replacement=("oop_range, ip_range, vertical_integration instead"), since_version="2024.11/12") + ip_range = kwargs["integrated_unit_range"] + vertical_integration = True + + for fi in self.ais: + unit_ip, unit_oop = fi.parse_units(unit_ip=unit_ip, unit_oop=unit_oop, + incident_angle=incident_angle, + tilt_angle=tilt_angle, + sample_orientation=sample_orientation) + + fi.reset_integrator(incident_angle=unit_ip.incident_angle, + tilt_angle=unit_ip.tilt_angle, + sample_orientation=unit_ip.sample_orientation) + + return self.integrate1d_fiber(lst_data=lst_data, + npt_oop=npt_oop, unit_oop=unit_oop, oop_range=oop_range, + npt_ip=npt_ip, unit_ip=unit_ip, ip_range=ip_range, + vertical_integration=vertical_integration, + sample_orientation=sample_orientation, + correctSolidAngle=correctSolidAngle, + lst_mask=lst_mask, dummy=dummy, delta_dummy=delta_dummy, + lst_variance=lst_variance, + polarization_factor=polarization_factor, dark=dark, lst_flat=lst_flat, + method=method, + normalization_factor=normalization_factor, + ) \ No newline at end of file From 421a45d603338c4137be9baff1f6c10be8fcfcc3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 12 Nov 2024 13:59:30 +0000 Subject: [PATCH 4/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/pyFAI/multi_geometry.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/pyFAI/multi_geometry.py b/src/pyFAI/multi_geometry.py index 7956f4345..aae7072f9 100644 --- a/src/pyFAI/multi_geometry.py +++ b/src/pyFAI/multi_geometry.py @@ -355,7 +355,7 @@ def integrate2d_fiber(self, lst_data, polarization_factor=None, dark=None, lst_flat=None, method=("no", "histogram", "cython"), normalization_factor=1.0, **kwargs): - """Performs 2D azimuthal integration of multiples frames, one for each geometry, + """Performs 2D azimuthal integration of multiples frames, one for each geometry, It wraps the method integrate2d_fiber of pyFAI.integrator.fiber.FiberIntegrator :param lst_data: list of numpy array @@ -492,7 +492,7 @@ def _integrate(args): result._set_count(count) return result - def integrate2d_grazing_incidence(self, lst_data, + def integrate2d_grazing_incidence(self, lst_data, npt_ip=1000, unit_ip=None, ip_range=None, npt_oop=1000, unit_oop=None, oop_range=None, incident_angle=None, tilt_angle=None, sample_orientation=None, @@ -502,7 +502,7 @@ def integrate2d_grazing_incidence(self, lst_data, polarization_factor=None, dark=None, lst_flat=None, method=("no", "histogram", "cython"), normalization_factor=1.0, **kwargs): - """Performs 2D azimuthal integration of multiples frames, one for each geometry, + """Performs 2D azimuthal integration of multiples frames, one for each geometry, It wraps the method integrate2d_grazing_incidence of pyFAI.integrator.fiber.FiberIntegrator :param lst_data: list of numpy array @@ -576,9 +576,9 @@ def integrate2d_grazing_incidence(self, lst_data, polarization_factor=polarization_factor, dark=dark, lst_flat=lst_flat, method=method, normalization_factor=normalization_factor, - ) + ) - def integrate1d_fiber(self, lst_data, + def integrate1d_fiber(self, lst_data, npt_ip=1000, unit_ip=None, ip_range=None, npt_oop=1000, unit_oop=None, oop_range=None, sample_orientation=None, @@ -589,7 +589,7 @@ def integrate1d_fiber(self, lst_data, polarization_factor=None, dark=None, lst_flat=None, method=("no", "histogram", "cython"), normalization_factor=1.0, **kwargs): - """Performs 1D fiber integration of multiples frames, one for each geometry, + """Performs 1D fiber integration of multiples frames, one for each geometry, It wraps the method integrate_fiber of pyFAI.integrator.fiber.FiberIntegrator :param lst_data: list of numpy array @@ -668,7 +668,7 @@ def integrate1d_fiber(self, lst_data, self.radial_unit = unit_oop self.radial_range = oop_range or self._guess_radial_range() self.azimuth_unit = unit_ip - self.azimuth_range = ip_range or self._guess_azimuth_range() + self.azimuth_range = ip_range or self._guess_azimuth_range() method = IntegrationMethod.select_one_available(method, dim=1) @@ -743,8 +743,8 @@ def _integrate(args): result._set_sum_variance(variance) result._set_count(count) return result - - def integrate1d_grazing_incidence(self, lst_data, + + def integrate1d_grazing_incidence(self, lst_data, npt_ip=1000, unit_ip=None, ip_range=None, npt_oop=1000, unit_oop=None, oop_range=None, incident_angle=None, tilt_angle=None, sample_orientation=None, @@ -755,7 +755,7 @@ def integrate1d_grazing_incidence(self, lst_data, polarization_factor=None, dark=None, lst_flat=None, method=("no", "histogram", "cython"), normalization_factor=1.0, **kwargs): - """Performs 1D fiber integration of multiples frames, one for each geometry, + """Performs 1D fiber integration of multiples frames, one for each geometry, It wraps the method integrate_grazing_incidence of pyFAI.integrator.fiber.FiberIntegrator :param lst_data: list of numpy array @@ -832,4 +832,4 @@ def integrate1d_grazing_incidence(self, lst_data, polarization_factor=polarization_factor, dark=dark, lst_flat=lst_flat, method=method, normalization_factor=normalization_factor, - ) \ No newline at end of file + ) From d43600a6dc37f6e8b8350f22bd48ccafb8f1f9f6 Mon Sep 17 00:00:00 2001 From: Edgar Gutierrez Fernandez Date: Thu, 14 Nov 2024 16:47:56 +0100 Subject: [PATCH 5/9] clean --- src/pyFAI/multi_geometry.py | 156 ++++++++++++------------------------ 1 file changed, 53 insertions(+), 103 deletions(-) diff --git a/src/pyFAI/multi_geometry.py b/src/pyFAI/multi_geometry.py index 7956f4345..122fe1b40 100644 --- a/src/pyFAI/multi_geometry.py +++ b/src/pyFAI/multi_geometry.py @@ -49,6 +49,9 @@ import numpy from .method_registry import IntegrationMethod from .utils.decorators import deprecated_warning +from .integrator.fiber import get_deprecated_params_1d +from .integrator.fiber import get_deprecated_params_2d +from .integrator.fiber import parse_fiber_unit error = None @@ -383,29 +386,20 @@ def integrate2d_fiber(self, lst_data, :return: regrouped intensity and unit arrays :rtype: Integrate2dResult """ - if "npt_horizontal" in kwargs: - deprecated_warning(type_=type(kwargs["npt_horizontal"]), name="npt_horizontal", replacement="npt_ip", since_version="2024.11/12") - npt_ip = kwargs["npt_horizontal"] - if "npt_vertical" in kwargs: - deprecated_warning(type_=type(kwargs["npt_vertical"]), name="npt_vertical", replacement="npt_oop", since_version="2024.11/12") - npt_oop = kwargs["npt_vertical"] - if "horizontal_unit" in kwargs: - deprecated_warning(type_=type(kwargs["horizontal_unit"]), name="horizontal_unit", replacement="unit_ip", since_version="2024.11/12") - unit_ip = kwargs["horizontal_unit"] - if "vertical_unit" in kwargs: - deprecated_warning(type_=type(kwargs["vertical_unit"]), name="vertical_unit", replacement="unit_oop", since_version="2024.11/12") - unit_oop = kwargs["vertical_unit"] - if "horizontal_unit_range" in kwargs: - deprecated_warning(type_=type(kwargs["horizontal_unit_range"]), name="horizontal_unit_range", replacement="ip_range", since_version="2024.11/12") - ip_range = kwargs["horizontal_unit_range"] - if "vertical_unit_range" in kwargs: - deprecated_warning(type_=type(kwargs["vertical_unit_range"]), name="vertical_unit_range", replacement="oop_range", since_version="2024.11/12") - oop_range = kwargs["vertical_unit_range"] + deprecated_params = get_deprecated_params_2d(**kwargs) + npt_oop = deprecated_params.get('npt_oop', None) or npt_oop + npt_ip = deprecated_params.get('npt_ip', None) or npt_ip + unit_oop = deprecated_params.get('unit_oop', None) or unit_oop + unit_ip = deprecated_params.get('unit_ip', None) or unit_ip + oop_range = deprecated_params.get('oop_range', None) or oop_range + ip_range = deprecated_params.get('ip_range', None) or ip_range + + unit_ip = unit_ip or 'qip_nm^-1' + unit_oop = unit_oop or 'qoop_nm^-1' + unit_ip = parse_fiber_unit(unit=unit_ip, sample_orientation=sample_orientation) + unit_oop = parse_fiber_unit(unit=unit_oop, sample_orientation=unit_ip.sample_orientation) for fi in self.ais: - unit_ip, unit_oop = fi.parse_units(unit_ip=unit_ip, unit_oop=unit_oop, - sample_orientation=sample_orientation) - fi.reset_integrator(incident_angle=unit_ip.incident_angle, tilt_angle=unit_ip.tilt_angle, sample_orientation=unit_ip.sample_orientation) @@ -532,32 +526,20 @@ def integrate2d_grazing_incidence(self, lst_data, :return: regrouped intensity and unit arrays :rtype: Integrate2dResult """ - - if "npt_horizontal" in kwargs: - deprecated_warning(type_=type(kwargs["npt_horizontal"]), name="npt_horizontal", replacement="npt_ip", since_version="2024.11/12") - npt_ip = kwargs["npt_horizontal"] - if "npt_vertical" in kwargs: - deprecated_warning(type_=type(kwargs["npt_vertical"]), name="npt_vertical", replacement="npt_oop", since_version="2024.11/12") - npt_oop = kwargs["npt_vertical"] - if "horizontal_unit" in kwargs: - deprecated_warning(type_=type(kwargs["horizontal_unit"]), name="horizontal_unit", replacement="unit_ip", since_version="2024.11/12") - unit_ip = kwargs["horizontal_unit"] - if "vertical_unit" in kwargs: - deprecated_warning(type_=type(kwargs["vertical_unit"]), name="vertical_unit", replacement="unit_oop", since_version="2024.11/12") - unit_oop = kwargs["vertical_unit"] - if "horizontal_unit_range" in kwargs: - deprecated_warning(type_=type(kwargs["horizontal_unit_range"]), name="horizontal_unit_range", replacement="ip_range", since_version="2024.11/12") - ip_range = kwargs["horizontal_unit_range"] - if "vertical_unit_range" in kwargs: - deprecated_warning(type_=type(kwargs["vertical_unit_range"]), name="vertical_unit_range", replacement="oop_range", since_version="2024.11/12") - oop_range = kwargs["vertical_unit_range"] + deprecated_params = get_deprecated_params_2d(**kwargs) + npt_oop = deprecated_params.get('npt_oop', None) or npt_oop + npt_ip = deprecated_params.get('npt_ip', None) or npt_ip + unit_oop = deprecated_params.get('unit_oop', None) or unit_oop + unit_ip = deprecated_params.get('unit_ip', None) or unit_ip + oop_range = deprecated_params.get('oop_range', None) or oop_range + ip_range = deprecated_params.get('ip_range', None) or ip_range + + unit_ip = unit_ip or 'qip_nm^-1' + unit_oop = unit_oop or 'qoop_nm^-1' + unit_ip = parse_fiber_unit(unit=unit_ip, incident_angle=incident_angle, tilt_angle=tilt_angle, sample_orientation=sample_orientation) + unit_oop = parse_fiber_unit(unit=unit_oop, incident_angle=unit_ip.incident_angle, tilt_angle=unit_ip.tilt_angle, sample_orientation=unit_ip.sample_orientation) for fi in self.ais: - unit_ip, unit_oop = fi.parse_units(unit_ip=unit_ip, unit_oop=unit_oop, - incident_angle=incident_angle, - tilt_angle=tilt_angle, - sample_orientation=sample_orientation) - fi.reset_integrator(incident_angle=unit_ip.incident_angle, tilt_angle=unit_ip.tilt_angle, sample_orientation=unit_ip.sample_orientation) @@ -618,36 +600,21 @@ def integrate1d_fiber(self, lst_data, :return: chi bins center positions and regrouped intensity :rtype: Integrate1dResult """ - - if "npt_output" in kwargs: - deprecated_warning(type_=type(kwargs["npt_output"]), name="npt_output", replacement=("npt_oop, npt_ip, vertical_integration instead"), since_version="2024.11/12") - npt_oop = kwargs["npt_output"] - vertical_integration = True - if "npt_integrated" in kwargs: - deprecated_warning(type_=type(kwargs["npt_integrated"]), name="npt_integrated", replacement=("npt_oop, npt_ip, vertical_integration instead"), since_version="2024.11/12") - npt_ip = kwargs["npt_integrated"] - vertical_integration = True - if "output_unit" in kwargs: - deprecated_warning(type_=type(kwargs["output_unit"]), name="output_unit", replacement=("unit_oop, unit_ip, vertical_integration instead"), since_version="2024.11/12") - unit_oop = kwargs["output_unit"] - vertical_integration = True - if "integrated_unit" in kwargs: - deprecated_warning(type_=type(kwargs["integrated_unit"]), name="integrated_unit", replacement=("unit_oop, unit_ip, vertical_integration instead"), since_version="2024.11/12") - unit_ip = kwargs["integrated_unit"] - vertical_integration = True - if "output_unit_range" in kwargs: - deprecated_warning(type_=type(kwargs["output_unit_range"]), name="output_unit_range", replacement=("oop_range, ip_range, vertical_integration instead"), since_version="2024.11/12") - oop_range = kwargs["output_unit_range"] - vertical_integration = True - if "integrated_unit_range" in kwargs: - deprecated_warning(type_=type(kwargs["integrated_unit_range"]), name="integrated_unit_range", replacement=("oop_range, ip_range, vertical_integration instead"), since_version="2024.11/12") - ip_range = kwargs["integrated_unit_range"] - vertical_integration = True + deprecated_params = get_deprecated_params_1d(**kwargs) + npt_oop = deprecated_params.get('npt_oop', None) or npt_oop + npt_ip = deprecated_params.get('npt_ip', None) or npt_ip + unit_oop = deprecated_params.get('unit_oop', None) or unit_oop + unit_ip = deprecated_params.get('unit_ip', None) or unit_ip + oop_range = deprecated_params.get('oop_range', None) or oop_range + ip_range = deprecated_params.get('ip_range', None) or ip_range + vertical_integration = deprecated_params.get('vertical_integration', None) or vertical_integration + + unit_ip = unit_ip or 'qip_nm^-1' + unit_oop = unit_oop or 'qoop_nm^-1' + unit_ip = parse_fiber_unit(unit=unit_ip, sample_orientation=sample_orientation) + unit_oop = parse_fiber_unit(unit=unit_oop, sample_orientation=unit_ip.sample_orientation) for fi in self.ais: - unit_ip, unit_oop = fi.parse_units(unit_ip=unit_ip, unit_oop=unit_oop, - sample_orientation=sample_orientation) - fi.reset_integrator(incident_angle=unit_ip.incident_angle, tilt_angle=unit_ip.tilt_angle, sample_orientation=unit_ip.sample_orientation) @@ -655,7 +622,6 @@ def integrate1d_fiber(self, lst_data, if (isinstance(method, (tuple, list)) and method[0] != "no") or (isinstance(method, IntegrationMethod) and method.split != "no"): logger.warning(f"Method {method} is using a pixel-splitting scheme. GI integration should be use WITHOUT PIXEL-SPLITTING! The results could be wrong!") - if vertical_integration and npt_oop is None: raise RuntimeError("npt_oop (out-of-plane bins) is needed to do the integration") elif not vertical_integration and npt_ip is None: @@ -786,37 +752,21 @@ def integrate1d_grazing_incidence(self, lst_data, :return: chi bins center positions and regrouped intensity :rtype: Integrate1dResult """ - if "npt_output" in kwargs: - deprecated_warning(type_=type(kwargs["npt_output"]), name="npt_output", replacement=("npt_oop, npt_ip, vertical_integration instead"), since_version="2024.11/12") - npt_oop = kwargs["npt_output"] - vertical_integration = True - if "npt_integrated" in kwargs: - deprecated_warning(type_=type(kwargs["npt_integrated"]), name="npt_integrated", replacement=("npt_oop, npt_ip, vertical_integration instead"), since_version="2024.11/12") - npt_ip = kwargs["npt_integrated"] - vertical_integration = True - if "output_unit" in kwargs: - deprecated_warning(type_=type(kwargs["output_unit"]), name="output_unit", replacement=("unit_oop, unit_ip, vertical_integration instead"), since_version="2024.11/12") - unit_oop = kwargs["output_unit"] - vertical_integration = True - if "integrated_unit" in kwargs: - deprecated_warning(type_=type(kwargs["integrated_unit"]), name="integrated_unit", replacement=("unit_oop, unit_ip, vertical_integration instead"), since_version="2024.11/12") - unit_ip = kwargs["integrated_unit"] - vertical_integration = True - if "output_unit_range" in kwargs: - deprecated_warning(type_=type(kwargs["output_unit_range"]), name="output_unit_range", replacement=("oop_range, ip_range, vertical_integration instead"), since_version="2024.11/12") - oop_range = kwargs["output_unit_range"] - vertical_integration = True - if "integrated_unit_range" in kwargs: - deprecated_warning(type_=type(kwargs["integrated_unit_range"]), name="integrated_unit_range", replacement=("oop_range, ip_range, vertical_integration instead"), since_version="2024.11/12") - ip_range = kwargs["integrated_unit_range"] - vertical_integration = True + deprecated_params = get_deprecated_params_1d(**kwargs) + npt_oop = deprecated_params.get('npt_oop', None) or npt_oop + npt_ip = deprecated_params.get('npt_ip', None) or npt_ip + unit_oop = deprecated_params.get('unit_oop', None) or unit_oop + unit_ip = deprecated_params.get('unit_ip', None) or unit_ip + oop_range = deprecated_params.get('oop_range', None) or oop_range + ip_range = deprecated_params.get('ip_range', None) or ip_range + vertical_integration = deprecated_params.get('vertical_integration', None) or vertical_integration + + unit_ip = unit_ip or 'qip_nm^-1' + unit_oop = unit_oop or 'qoop_nm^-1' + unit_ip = parse_fiber_unit(unit=unit_ip, incident_angle=incident_angle, tilt_angle=tilt_angle, sample_orientation=sample_orientation) + unit_oop = parse_fiber_unit(unit=unit_oop, incident_angle=unit_ip.incident_angle, tilt_angle=unit_ip.tilt_angle, sample_orientation=unit_ip.sample_orientation) for fi in self.ais: - unit_ip, unit_oop = fi.parse_units(unit_ip=unit_ip, unit_oop=unit_oop, - incident_angle=incident_angle, - tilt_angle=tilt_angle, - sample_orientation=sample_orientation) - fi.reset_integrator(incident_angle=unit_ip.incident_angle, tilt_angle=unit_ip.tilt_angle, sample_orientation=unit_ip.sample_orientation) From ebfd0020df33082b68c096482b5b804a3646bbdd Mon Sep 17 00:00:00 2001 From: edgar1993a Date: Fri, 6 Dec 2024 10:35:25 +0100 Subject: [PATCH 6/9] new class MultiGeometryFiber --- src/pyFAI/multi_geometry.py | 482 ++++++++++++++---------------------- 1 file changed, 189 insertions(+), 293 deletions(-) diff --git a/src/pyFAI/multi_geometry.py b/src/pyFAI/multi_geometry.py index a9e5ebbd7..cdcef908c 100644 --- a/src/pyFAI/multi_geometry.py +++ b/src/pyFAI/multi_geometry.py @@ -40,6 +40,7 @@ import logging logger = logging.getLogger(__name__) from .integrator.azimuthal import AzimuthalIntegrator +from .integrator.fiber import FiberIntegrator from .containers import Integrate1dResult from .containers import Integrate2dResult from . import units @@ -347,28 +348,110 @@ def reset(self, collect_garbage=True): if collect_garbage: gc.collect() +class MultiGeometryFiber(object): + """This is a Fiber integrator containing multiple geometries, + for example when the detector is on a goniometer arm + """ - def integrate2d_fiber(self, lst_data, - npt_ip=1000, unit_ip=None, ip_range=None, - npt_oop=1000, unit_oop=None, oop_range=None, - sample_orientation=None, + def __init__(self, fis, unit=("qip_nm^-1", "qoop_nm^-1"), + ip_range=None, oop_range=None, + incident_angle=None, tilt_angle=None, sample_orientation=None, + wavelength=None, empty=0.0, chi_disc=180, + threadpoolsize=cpu_count()): + """ + Constructor of the multi-geometry integrator + + :param ais: list of azimuthal integrators + :param ip_range: (2-tuple) in-plane range for integration + :param oop_range: (2-tuple) out-of-plane range for integration + :param incident_angle: tilting of the sample towards the beam (analog to rot2): in radians + :param tilt_angle: tilting of the sample orthogonal to the beam direction (analog to rot3): in radians + :param int sample_orientation: 1-4, four different orientation of the fiber axis regarding the detector main axis, from 1 to 4 is +90º + :param empty: value for empty pixels + :param chi_disc: if 0, set the chi_discontinuity at 0, else π + :param threadpoolsize: By default, use a thread-pool to parallelize histogram/CSC integrator over as many threads as cores, + set to False/0 to serialize + """ + self._sem = threading.Semaphore() + self.abolute_solid_angle = None + self.fis = [fi if isinstance(fi, FiberIntegrator) + else FiberIntegrator.sload(fi) + for fi in fis] + self.wavelength = None + self.threadpool = ThreadPool(min(len(self.fis), threadpoolsize)) if threadpoolsize>0 else None + if wavelength: + self.set_wavelength(wavelength) + if isinstance(unit, (tuple, list)) and len(unit) == 2: + self.ip_unit = units.parse_fiber_unit(unit=unit[0], + incident_angle=incident_angle, + tilt_angle=tilt_angle, + sample_orientation=sample_orientation, + ) + self.oop_unit = units.parse_fiber_unit(unit=unit[1], + incident_angle=self.ip_unit.incident_angle, + tilt_angle=self.ip_unit.tilt_angle, + sample_orientation=self.ip_unit.sample_orientation, + ) + else: + self.ip_unit = units.parse_fiber_unit(unit=unit, + incident_angle=incident_angle, + tilt_angle=tilt_angle, + sample_orientation=sample_orientation, + ) + self.oop_unit = units.parse_fiber_unit(unit="qoop_nm^-1", + incident_angle=self.ip_unit.incident_angle, + tilt_angle=self.ip_unit.tilt_angle, + sample_orientation=self.ip_unit.sample_orientation, + ) + + self.unit = (self.ip_unit, self.oop_unit) + self.ip_range = ip_range + self.oop_range = oop_range + self.abolute_solid_angle = None + self.empty = empty + if chi_disc == 0: + for fi in self.fis: + fi.setChiDiscAtZero() + elif chi_disc == 180: + for fi in self.fis: + fi.setChiDiscAtPi() + else: + logger.warning("Unable to set the Chi discontinuity at %s", chi_disc) + + def __del__(self): + if self.threadpool and self.threadpool._state == "RUN": + self.threadpool.close() + + def __repr__(self, *args, **kwargs): + return "MultiGeometry integrator with %s geometries on %s radial range (%s) and %s azimuthal range (deg)" % \ + (len(self.fis), self.ip_range, self.unit, self.oop_range) + + def _guess_inplane_range(self): + logger.info(f"Calculating the in-plane range of MultiGeometry...") + ip = numpy.array([fi.array_from_unit(unit=self.ip_unit) for fi in self.fis]) + return (ip.min(), ip.max()) + + def _guess_outofplane_range(self): + logger.info(f"Calculating the out-of-plane range of MultiGeometry...") + oop = numpy.array([fi.array_from_unit(unit=self.oop_unit) for fi in self.fis]) + return (oop.min(), oop.max()) + + def integrate_fiber(self, lst_data, + npt_ip=1000, npt_oop=1000, correctSolidAngle=True, + vertical_integration = True, lst_mask=None, dummy=None, delta_dummy=None, lst_variance=None, polarization_factor=None, dark=None, lst_flat=None, method=("no", "histogram", "cython"), normalization_factor=1.0, **kwargs): - """Performs 2D azimuthal integration of multiples frames, one for each geometry, - It wraps the method integrate2d_fiber of pyFAI.integrator.fiber.FiberIntegrator + """Performs 1D fiber integration of multiples frames, one for each geometry, + It wraps the method integrate_fiber of pyFAI.integrator.fiber.FiberIntegrator :param lst_data: list of numpy array :param int npt_ip: number of points to be used along the in-plane axis - :param pyFAI.units.UnitFiber/str unit_ip: unit to describe the in-plane axis. If not provided, it takes qip_nm^-1 - :param list ip_range: The lower and upper range of the in-plane unit. If not provided, range is simply (data.min(), data.max()). Values outside the range are ignored. Optional. :param int npt_oop: number of points to be used along the out-of-plane axis - :param pyFAI.units.UnitFiber/str unit_oop: unit to describe the out-of-plane axis. If not provided, it takes qoop_nm^-1 - :param list oop_range: The lower and upper range of the out-of-plane unit. If not provided, range is simply (data.min(), data.max()). Values outside the range are ignored. Optional. - :param int sample_orientation: 1-4, four different orientation of the fiber axis regarding the detector main axis, from 1 to 4 is +90º + :param bool vertical_integration: If True, integrates along unit_ip; if False, integrates along unit_oop :param bool correctSolidAngle: correct for solid angle of each pixel if True :param lst_mask: numpy.Array or list of numpy.array which mask the lst_data. :param float dummy: value for dead/masked pixels @@ -383,121 +466,110 @@ def integrate2d_fiber(self, lst_data, :param lst_flat: numpy.Array or list of numpy.array which flat the lst_data. :param IntegrationMethod method: IntegrationMethod instance or 3-tuple with (splitting, algorithm, implementation) :param float normalization_factor: Value of a normalization monitor - :return: regrouped intensity and unit arrays - :rtype: Integrate2dResult + :return: chi bins center positions and regrouped intensity + :rtype: Integrate1dResult """ - deprecated_params = get_deprecated_params_2d(**kwargs) - npt_oop = deprecated_params.get('npt_oop', None) or npt_oop - npt_ip = deprecated_params.get('npt_ip', None) or npt_ip - unit_oop = deprecated_params.get('unit_oop', None) or unit_oop - unit_ip = deprecated_params.get('unit_ip', None) or unit_ip - oop_range = deprecated_params.get('oop_range', None) or oop_range - ip_range = deprecated_params.get('ip_range', None) or ip_range - - unit_ip = unit_ip or 'qip_nm^-1' - unit_oop = unit_oop or 'qoop_nm^-1' - unit_ip = parse_fiber_unit(unit=unit_ip, sample_orientation=sample_orientation) - unit_oop = parse_fiber_unit(unit=unit_oop, sample_orientation=unit_ip.sample_orientation) - - for fi in self.ais: - fi.reset_integrator(incident_angle=unit_ip.incident_angle, - tilt_angle=unit_ip.tilt_angle, - sample_orientation=unit_ip.sample_orientation) - if (isinstance(method, (tuple, list)) and method[0] != "no") or (isinstance(method, IntegrationMethod) and method.split != "no"): logger.warning(f"Method {method} is using a pixel-splitting scheme. GI integration should be use WITHOUT PIXEL-SPLITTING! The results could be wrong!") + if vertical_integration and npt_oop is None: + raise RuntimeError("npt_oop (out-of-plane bins) is needed to do the integration") + elif not vertical_integration and npt_ip is None: + raise RuntimeError("npt_ip (in-plane bins) is needed to do the integration") + + if self.ip_range is None: + self.ip_range = self.ip_range or self._guess_inplane_range() + if self.oop_range is None: + self.oop_range = self.oop_range or self._guess_outofplane_range() + if len(lst_data) == 0: raise RuntimeError("List of images cannot be empty") if normalization_factor is None: - normalization_factor = [1.0] * len(self.ais) + normalization_factor = [1.0] * len(self.fis) elif not isinstance(normalization_factor, collections.abc.Iterable): - normalization_factor = [normalization_factor] * len(self.ais) + normalization_factor = [normalization_factor] * len(self.fis) if lst_variance is None: - lst_variance = [None] * len(self.ais) + lst_variance = [None] * len(self.fis) if lst_mask is None: - lst_mask = [None] * len(self.ais) + lst_mask = [None] * len(self.fis) elif isinstance(lst_mask, numpy.ndarray): - lst_mask = [lst_mask] * len(self.ais) + lst_mask = [lst_mask] * len(self.fis) if lst_flat is None: - lst_flat = [None] * len(self.ais) + lst_flat = [None] * len(self.fis) elif isinstance(lst_flat, numpy.ndarray): - lst_flat = [lst_flat] * len(self.ais) - - method = IntegrationMethod.select_one_available(method, dim=2) + lst_flat = [lst_flat] * len(self.fis) - signal = numpy.zeros((npt_oop, npt_ip), dtype=numpy.float64) - count = numpy.zeros_like(signal) + method = IntegrationMethod.select_one_available(method, dim=1) + signal = numpy.zeros(npt_oop, dtype=numpy.float64) normalization = numpy.zeros_like(signal) + count = numpy.zeros_like(signal) variance = None - if self.radial_range is None: - self.radial_range = ip_range or self._guess_radial_range() - if self.azimuth_range is None: - self.azimuth_range = oop_range or self._guess_azimuth_range() def _integrate(args): fi, data, monitor, var, mask, flat = args - return fi.integrate2d_fiber(data, - npt_ip=npt_ip, unit_ip=unit_ip, ip_range=self.radial_range, - npt_oop=npt_oop, unit_oop=unit_oop, oop_range=self.azimuth_range, - sample_orientation=sample_orientation, - correctSolidAngle=correctSolidAngle, - variance=var, - polarization_factor=polarization_factor, - method=method, safe=True, - dummy=dummy, delta_dummy=delta_dummy, - mask=mask, flat=flat, dark=dark, normalization_factor=monitor, **kwargs) + return fi.integrate_fiber(data=data, + npt_oop=npt_oop, unit_oop=self.oop_unit, oop_range=self.ip_range, + npt_ip=npt_ip, unit_ip=self.ip_unit, ip_range=self.oop_range, + vertical_integration=vertical_integration, + correctSolidAngle=correctSolidAngle, + mask=mask, dummy=dummy, delta_dummy=delta_dummy, + polarization_factor=polarization_factor, dark=dark, flat=flat, + method=("no", "histogram", "cython"), + normalization_factor=monitor, + variance=var, + ) if self.threadpool is None: results = map(_integrate, - zip(self.ais, lst_data, normalization_factor, lst_variance, lst_mask, lst_flat)) + zip(self.fis, lst_data, normalization_factor, lst_variance, lst_mask, lst_flat)) else: results = self.threadpool.map(_integrate, - zip(self.ais, lst_data, normalization_factor, lst_variance, lst_mask, lst_flat)) - for res, ai in zip(results, self.ais): - sac = (ai.pixel1 * ai.pixel2 / ai.dist ** 2) if correctSolidAngle else 1.0 + zip(self.fis, lst_data, normalization_factor, lst_variance, lst_mask, lst_flat)) + for res, fi in zip(results, self.fis): + sac = (fi.pixel1 * fi.pixel2 / fi.dist ** 2) if correctSolidAngle else 1.0 count += res.count - signal += res.sum_signal normalization += res.sum_normalization * sac + signal += res.sum_signal if res.sigma is not None: if variance is None: - variance = res.sum_variance.astype(numpy.float64) # explicit copy ! + variance = res.sum_variance.astype(dtype=numpy.float64) # explicit copy else: variance += res.sum_variance tiny = numpy.finfo("float32").tiny norm = numpy.maximum(normalization, tiny) - invalid = count <= 0 + invalid = count <= 0.0 I = signal / norm I[invalid] = self.empty if variance is not None: sigma = numpy.sqrt(variance) / norm sigma[invalid] = self.empty - result = Integrate2dResult(I, res.radial, res.azimuthal, sigma) + result = Integrate1dResult(res.radial, I, sigma) else: - result = Integrate2dResult(I, res.radial, res.azimuthal) - result._set_sum(signal) + result = Integrate1dResult(res.radial, I) result._set_compute_engine(res.compute_engine) - result._set_radial_unit(self.radial_unit) - result._set_azimuthal_unit(self.azimuth_unit) + result._set_unit(self.ip_unit) result._set_sum_signal(signal) result._set_sum_normalization(normalization) result._set_sum_variance(variance) result._set_count(count) return result - def integrate2d_grazing_incidence(self, lst_data, - npt_ip=1000, unit_ip=None, ip_range=None, - npt_oop=1000, unit_oop=None, oop_range=None, - incident_angle=None, tilt_angle=None, sample_orientation=None, - correctSolidAngle=True, - lst_mask=None, dummy=None, delta_dummy=None, - lst_variance=None, - polarization_factor=None, dark=None, lst_flat=None, - method=("no", "histogram", "cython"), - normalization_factor=1.0, **kwargs): + integrate_grazing_incidence = integrate_fiber + integrate1d_grazing_incidence = integrate_grazing_incidence + integrate1d_fiber = integrate_fiber + integrate1d = integrate1d_fiber + + def integrate2d_fiber(self, lst_data, + npt_ip=1000, npt_oop=1000, + correctSolidAngle=True, + lst_mask=None, dummy=None, delta_dummy=None, + lst_variance=None, + polarization_factor=None, dark=None, lst_flat=None, + method=("no", "histogram", "cython"), + normalization_factor=1.0, **kwargs): """Performs 2D azimuthal integration of multiples frames, one for each geometry, - It wraps the method integrate2d_grazing_incidence of pyFAI.integrator.fiber.FiberIntegrator + It wraps the method integrate2d_fiber of pyFAI.integrator.fiber.FiberIntegrator :param lst_data: list of numpy array :param int npt_ip: number of points to be used along the in-plane axis @@ -506,8 +578,6 @@ def integrate2d_grazing_incidence(self, lst_data, :param int npt_oop: number of points to be used along the out-of-plane axis :param pyFAI.units.UnitFiber/str unit_oop: unit to describe the out-of-plane axis. If not provided, it takes qoop_nm^-1 :param list oop_range: The lower and upper range of the out-of-plane unit. If not provided, range is simply (data.min(), data.max()). Values outside the range are ignored. Optional. - :param incident_angle: tilting of the sample towards the beam (analog to rot2): in radians - :param tilt_angle: tilting of the sample orthogonal to the beam direction (analog to rot3): in radians :param int sample_orientation: 1-4, four different orientation of the fiber axis regarding the detector main axis, from 1 to 4 is +90º :param bool correctSolidAngle: correct for solid angle of each pixel if True :param lst_mask: numpy.Array or list of numpy.array which mask the lst_data. @@ -526,260 +596,86 @@ def integrate2d_grazing_incidence(self, lst_data, :return: regrouped intensity and unit arrays :rtype: Integrate2dResult """ - deprecated_params = get_deprecated_params_2d(**kwargs) - npt_oop = deprecated_params.get('npt_oop', None) or npt_oop - npt_ip = deprecated_params.get('npt_ip', None) or npt_ip - unit_oop = deprecated_params.get('unit_oop', None) or unit_oop - unit_ip = deprecated_params.get('unit_ip', None) or unit_ip - oop_range = deprecated_params.get('oop_range', None) or oop_range - ip_range = deprecated_params.get('ip_range', None) or ip_range - - unit_ip = unit_ip or 'qip_nm^-1' - unit_oop = unit_oop or 'qoop_nm^-1' - unit_ip = parse_fiber_unit(unit=unit_ip, incident_angle=incident_angle, tilt_angle=tilt_angle, sample_orientation=sample_orientation) - unit_oop = parse_fiber_unit(unit=unit_oop, incident_angle=unit_ip.incident_angle, tilt_angle=unit_ip.tilt_angle, sample_orientation=unit_ip.sample_orientation) - - for fi in self.ais: - fi.reset_integrator(incident_angle=unit_ip.incident_angle, - tilt_angle=unit_ip.tilt_angle, - sample_orientation=unit_ip.sample_orientation) - - if (isinstance(method, (tuple, list)) and method[0] != "no") or (isinstance(method, IntegrationMethod) and method.split != "no"): - logger.warning(f"Method {method} is using a pixel-splitting scheme. GI integration should be use WITHOUT PIXEL-SPLITTING! The results could be wrong!") - - return self.integrate2d_fiber(lst_data=lst_data, npt_ip=npt_ip, npt_oop=npt_oop, - unit_ip=unit_ip, unit_oop=unit_oop, - ip_range=ip_range, - oop_range=oop_range, - sample_orientation=sample_orientation, - correctSolidAngle=correctSolidAngle, - lst_mask=lst_mask, dummy=dummy, delta_dummy=delta_dummy, - lst_variance=lst_variance, - polarization_factor=polarization_factor, dark=dark, lst_flat=lst_flat, - method=method, - normalization_factor=normalization_factor, - ) - - def integrate1d_fiber(self, lst_data, - npt_ip=1000, unit_ip=None, ip_range=None, - npt_oop=1000, unit_oop=None, oop_range=None, - sample_orientation=None, - correctSolidAngle=True, - vertical_integration = True, - lst_mask=None, dummy=None, delta_dummy=None, - lst_variance=None, - polarization_factor=None, dark=None, lst_flat=None, - method=("no", "histogram", "cython"), - normalization_factor=1.0, **kwargs): - """Performs 1D fiber integration of multiples frames, one for each geometry, - It wraps the method integrate_fiber of pyFAI.integrator.fiber.FiberIntegrator - - :param lst_data: list of numpy array - :param int npt_ip: number of points to be used along the in-plane axis - :param pyFAI.units.UnitFiber/str unit_ip: unit to describe the in-plane axis. If not provided, it takes qip_nm^-1 - :param list ip_range: The lower and upper range of the in-plane unit. If not provided, range is simply (data.min(), data.max()). Values outside the range are ignored. Optional. - :param int npt_oop: number of points to be used along the out-of-plane axis - :param pyFAI.units.UnitFiber/str unit_oop: unit to describe the out-of-plane axis. If not provided, it takes qoop_nm^-1 - :param list oop_range: The lower and upper range of the out-of-plane unit. If not provided, range is simply (data.min(), data.max()). Values outside the range are ignored. Optional. - :param int sample_orientation: 1-4, four different orientation of the fiber axis regarding the detector main axis, from 1 to 4 is +90º - :param bool vertical_integration: If True, integrates along unit_ip; if False, integrates along unit_oop - :param bool correctSolidAngle: correct for solid angle of each pixel if True - :param lst_mask: numpy.Array or list of numpy.array which mask the lst_data. - :param float dummy: value for dead/masked pixels - :param float delta_dummy: precision for dummy value - :param lst_variance: list of array containing the variance of the data. If not available, no error propagation is done - :type lst_variance: list of ndarray - :param float polarization_factor: polarization factor between -1 (vertical) and +1 (horizontal). - * 0 for circular polarization or random, - * None for no correction, - * True for using the former correction - :param ndarray dark: dark noise image - :param lst_flat: numpy.Array or list of numpy.array which flat the lst_data. - :param IntegrationMethod method: IntegrationMethod instance or 3-tuple with (splitting, algorithm, implementation) - :param float normalization_factor: Value of a normalization monitor - :return: chi bins center positions and regrouped intensity - :rtype: Integrate1dResult - """ - deprecated_params = get_deprecated_params_1d(**kwargs) - npt_oop = deprecated_params.get('npt_oop', None) or npt_oop - npt_ip = deprecated_params.get('npt_ip', None) or npt_ip - unit_oop = deprecated_params.get('unit_oop', None) or unit_oop - unit_ip = deprecated_params.get('unit_ip', None) or unit_ip - oop_range = deprecated_params.get('oop_range', None) or oop_range - ip_range = deprecated_params.get('ip_range', None) or ip_range - vertical_integration = deprecated_params.get('vertical_integration', None) or vertical_integration - - unit_ip = unit_ip or 'qip_nm^-1' - unit_oop = unit_oop or 'qoop_nm^-1' - unit_ip = parse_fiber_unit(unit=unit_ip, sample_orientation=sample_orientation) - unit_oop = parse_fiber_unit(unit=unit_oop, sample_orientation=unit_ip.sample_orientation) - - for fi in self.ais: - fi.reset_integrator(incident_angle=unit_ip.incident_angle, - tilt_angle=unit_ip.tilt_angle, - sample_orientation=unit_ip.sample_orientation) - if (isinstance(method, (tuple, list)) and method[0] != "no") or (isinstance(method, IntegrationMethod) and method.split != "no"): logger.warning(f"Method {method} is using a pixel-splitting scheme. GI integration should be use WITHOUT PIXEL-SPLITTING! The results could be wrong!") - if vertical_integration and npt_oop is None: - raise RuntimeError("npt_oop (out-of-plane bins) is needed to do the integration") - elif not vertical_integration and npt_ip is None: - raise RuntimeError("npt_ip (in-plane bins) is needed to do the integration") - - npt_oop = npt_oop or 500 - npt_ip = npt_ip or 500 - - npt_output = npt_oop - self.radial_unit = unit_oop - self.radial_range = oop_range or self._guess_radial_range() - self.azimuth_unit = unit_ip - self.azimuth_range = ip_range or self._guess_azimuth_range() - - method = IntegrationMethod.select_one_available(method, dim=1) - if len(lst_data) == 0: raise RuntimeError("List of images cannot be empty") if normalization_factor is None: - normalization_factor = [1.0] * len(self.ais) + normalization_factor = [1.0] * len(self.fis) elif not isinstance(normalization_factor, collections.abc.Iterable): - normalization_factor = [normalization_factor] * len(self.ais) + normalization_factor = [normalization_factor] * len(self.fis) if lst_variance is None: - lst_variance = [None] * len(self.ais) + lst_variance = [None] * len(self.fis) if lst_mask is None: - lst_mask = [None] * len(self.ais) + lst_mask = [None] * len(self.fis) elif isinstance(lst_mask, numpy.ndarray): - lst_mask = [lst_mask] * len(self.ais) + lst_mask = [lst_mask] * len(self.fis) if lst_flat is None: - lst_flat = [None] * len(self.ais) + lst_flat = [None] * len(self.fis) elif isinstance(lst_flat, numpy.ndarray): - lst_flat = [lst_flat] * len(self.ais) - signal = numpy.zeros(npt_output, dtype=numpy.float64) - normalization = numpy.zeros_like(signal) + lst_flat = [lst_flat] * len(self.fis) + + method = IntegrationMethod.select_one_available(method, dim=2) + signal = numpy.zeros((npt_oop, npt_ip), dtype=numpy.float64) count = numpy.zeros_like(signal) + normalization = numpy.zeros_like(signal) variance = None + if self.ip_range is None: + self.ip_range = self.ip_range or self._guess_inplane_range() + if self.oop_range is None: + self.oop_range = self.oop_range or self._guess_outofplane_range() + def _integrate(args): fi, data, monitor, var, mask, flat = args - return fi.integrate_fiber(data=data, - npt_oop=npt_oop, unit_oop=unit_oop, oop_range=self.radial_range, - npt_ip=npt_ip, unit_ip=unit_ip, ip_range=self.azimuth_range, - vertical_integration=vertical_integration, - sample_orientation=sample_orientation, - correctSolidAngle=correctSolidAngle, - mask=mask, dummy=dummy, delta_dummy=delta_dummy, - polarization_factor=polarization_factor, dark=dark, flat=flat, - method=("no", "histogram", "cython"), - normalization_factor=monitor, - variance=var, - ) + return fi.integrate2d_fiber(data, + npt_ip=npt_ip, unit_ip=self.ip_unit, ip_range=self.ip_range, + npt_oop=npt_oop, unit_oop=self.oop_unit, oop_range=self.oop_range, + correctSolidAngle=correctSolidAngle, + variance=var, + polarization_factor=polarization_factor, + method=method, safe=True, + dummy=dummy, delta_dummy=delta_dummy, + mask=mask, flat=flat, dark=dark, normalization_factor=monitor, **kwargs) if self.threadpool is None: results = map(_integrate, - zip(self.ais, lst_data, normalization_factor, lst_variance, lst_mask, lst_flat)) + zip(self.fis, lst_data, normalization_factor, lst_variance, lst_mask, lst_flat)) else: results = self.threadpool.map(_integrate, - zip(self.ais, lst_data, normalization_factor, lst_variance, lst_mask, lst_flat)) - for res, ai in zip(results, self.ais): + zip(self.fis, lst_data, normalization_factor, lst_variance, lst_mask, lst_flat)) + for res, ai in zip(results, self.fis): sac = (ai.pixel1 * ai.pixel2 / ai.dist ** 2) if correctSolidAngle else 1.0 count += res.count - normalization += res.sum_normalization * sac signal += res.sum_signal + normalization += res.sum_normalization * sac if res.sigma is not None: if variance is None: - variance = res.sum_variance.astype(dtype=numpy.float64) # explicit copy + variance = res.sum_variance.astype(numpy.float64) # explicit copy ! else: variance += res.sum_variance tiny = numpy.finfo("float32").tiny norm = numpy.maximum(normalization, tiny) - invalid = count <= 0.0 + invalid = count <= 0 I = signal / norm I[invalid] = self.empty if variance is not None: sigma = numpy.sqrt(variance) / norm sigma[invalid] = self.empty - result = Integrate1dResult(res.radial, I, sigma) + result = Integrate2dResult(I, res.radial, res.azimuthal, sigma) else: - result = Integrate1dResult(res.radial, I) + result = Integrate2dResult(I, res.radial, res.azimuthal) + result._set_sum(signal) result._set_compute_engine(res.compute_engine) - result._set_unit(self.radial_unit) + result._set_radial_unit(self.ip_unit) + result._set_azimuthal_unit(self.oop_unit) result._set_sum_signal(signal) result._set_sum_normalization(normalization) result._set_sum_variance(variance) result._set_count(count) return result - def integrate1d_grazing_incidence(self, lst_data, - npt_ip=1000, unit_ip=None, ip_range=None, - npt_oop=1000, unit_oop=None, oop_range=None, - incident_angle=None, tilt_angle=None, sample_orientation=None, - vertical_integration = True, - correctSolidAngle=True, - lst_mask=None, dummy=None, delta_dummy=None, - lst_variance=None, - polarization_factor=None, dark=None, lst_flat=None, - method=("no", "histogram", "cython"), - normalization_factor=1.0, **kwargs): - """Performs 1D fiber integration of multiples frames, one for each geometry, - It wraps the method integrate_grazing_incidence of pyFAI.integrator.fiber.FiberIntegrator - - :param lst_data: list of numpy array - :param int npt_ip: number of points to be used along the in-plane axis - :param pyFAI.units.UnitFiber/str unit_ip: unit to describe the in-plane axis. If not provided, it takes qip_nm^-1 - :param list ip_range: The lower and upper range of the in-plane unit. If not provided, range is simply (data.min(), data.max()). Values outside the range are ignored. Optional. - :param int npt_oop: number of points to be used along the out-of-plane axis - :param pyFAI.units.UnitFiber/str unit_oop: unit to describe the out-of-plane axis. If not provided, it takes qoop_nm^-1 - :param list oop_range: The lower and upper range of the out-of-plane unit. If not provided, range is simply (data.min(), data.max()). Values outside the range are ignored. Optional. - :param incident_angle: tilting of the sample towards the beam (analog to rot2): in radians - :param tilt_angle: tilting of the sample orthogonal to the beam direction (analog to rot3): in radians - :param int sample_orientation: 1-4, four different orientation of the fiber axis regarding the detector main axis, from 1 to 4 is +90º - :param bool vertical_integration: If True, integrates along unit_ip; if False, integrates along unit_oop - :param bool correctSolidAngle: correct for solid angle of each pixel if True - :param lst_mask: numpy.Array or list of numpy.array which mask the lst_data. - :param float dummy: value for dead/masked pixels - :param float delta_dummy: precision for dummy value - :param lst_variance: list of array containing the variance of the data. If not available, no error propagation is done - :type lst_variance: list of ndarray - :param float polarization_factor: polarization factor between -1 (vertical) and +1 (horizontal). - * 0 for circular polarization or random, - * None for no correction, - * True for using the former correction - :param ndarray dark: dark noise image - :param lst_flat: numpy.Array or list of numpy.array which flat the lst_data. - :param IntegrationMethod method: IntegrationMethod instance or 3-tuple with (splitting, algorithm, implementation) - :param float normalization_factor: Value of a normalization monitor - :return: chi bins center positions and regrouped intensity - :rtype: Integrate1dResult - """ - deprecated_params = get_deprecated_params_1d(**kwargs) - npt_oop = deprecated_params.get('npt_oop', None) or npt_oop - npt_ip = deprecated_params.get('npt_ip', None) or npt_ip - unit_oop = deprecated_params.get('unit_oop', None) or unit_oop - unit_ip = deprecated_params.get('unit_ip', None) or unit_ip - oop_range = deprecated_params.get('oop_range', None) or oop_range - ip_range = deprecated_params.get('ip_range', None) or ip_range - vertical_integration = deprecated_params.get('vertical_integration', None) or vertical_integration - - unit_ip = unit_ip or 'qip_nm^-1' - unit_oop = unit_oop or 'qoop_nm^-1' - unit_ip = parse_fiber_unit(unit=unit_ip, incident_angle=incident_angle, tilt_angle=tilt_angle, sample_orientation=sample_orientation) - unit_oop = parse_fiber_unit(unit=unit_oop, incident_angle=unit_ip.incident_angle, tilt_angle=unit_ip.tilt_angle, sample_orientation=unit_ip.sample_orientation) - - for fi in self.ais: - fi.reset_integrator(incident_angle=unit_ip.incident_angle, - tilt_angle=unit_ip.tilt_angle, - sample_orientation=unit_ip.sample_orientation) - - return self.integrate1d_fiber(lst_data=lst_data, - npt_oop=npt_oop, unit_oop=unit_oop, oop_range=oop_range, - npt_ip=npt_ip, unit_ip=unit_ip, ip_range=ip_range, - vertical_integration=vertical_integration, - sample_orientation=sample_orientation, - correctSolidAngle=correctSolidAngle, - lst_mask=lst_mask, dummy=dummy, delta_dummy=delta_dummy, - lst_variance=lst_variance, - polarization_factor=polarization_factor, dark=dark, lst_flat=lst_flat, - method=method, - normalization_factor=normalization_factor, - ) + integrate2d_grazing_incidence = integrate2d_fiber + integrate2d = integrate2d_fiber \ No newline at end of file From 9301810e01dc866d89bb4af1326e8e0dbc0187fc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 6 Dec 2024 09:35:52 +0000 Subject: [PATCH 7/9] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/pyFAI/multi_geometry.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/pyFAI/multi_geometry.py b/src/pyFAI/multi_geometry.py index cdcef908c..c715dde34 100644 --- a/src/pyFAI/multi_geometry.py +++ b/src/pyFAI/multi_geometry.py @@ -403,7 +403,7 @@ def __init__(self, fis, unit=("qip_nm^-1", "qoop_nm^-1"), tilt_angle=self.ip_unit.tilt_angle, sample_orientation=self.ip_unit.sample_orientation, ) - + self.unit = (self.ip_unit, self.oop_unit) self.ip_range = ip_range self.oop_range = oop_range @@ -435,9 +435,9 @@ def _guess_outofplane_range(self): logger.info(f"Calculating the out-of-plane range of MultiGeometry...") oop = numpy.array([fi.array_from_unit(unit=self.oop_unit) for fi in self.fis]) return (oop.min(), oop.max()) - + def integrate_fiber(self, lst_data, - npt_ip=1000, npt_oop=1000, + npt_ip=1000, npt_oop=1000, correctSolidAngle=True, vertical_integration = True, lst_mask=None, dummy=None, delta_dummy=None, @@ -499,7 +499,7 @@ def integrate_fiber(self, lst_data, elif isinstance(lst_flat, numpy.ndarray): lst_flat = [lst_flat] * len(self.fis) - method = IntegrationMethod.select_one_available(method, dim=1) + method = IntegrationMethod.select_one_available(method, dim=1) signal = numpy.zeros(npt_oop, dtype=numpy.float64) normalization = numpy.zeros_like(signal) count = numpy.zeros_like(signal) @@ -561,7 +561,7 @@ def _integrate(args): integrate1d = integrate1d_fiber def integrate2d_fiber(self, lst_data, - npt_ip=1000, npt_oop=1000, + npt_ip=1000, npt_oop=1000, correctSolidAngle=True, lst_mask=None, dummy=None, delta_dummy=None, lst_variance=None, @@ -678,4 +678,4 @@ def _integrate(args): return result integrate2d_grazing_incidence = integrate2d_fiber - integrate2d = integrate2d_fiber \ No newline at end of file + integrate2d = integrate2d_fiber From a0bddbccb86f98dafb7d521e209c7c102a4aea45 Mon Sep 17 00:00:00 2001 From: edgar1993a Date: Fri, 6 Dec 2024 10:36:41 +0100 Subject: [PATCH 8/9] clean --- src/pyFAI/multi_geometry.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/pyFAI/multi_geometry.py b/src/pyFAI/multi_geometry.py index cdcef908c..fcb6d3d6c 100644 --- a/src/pyFAI/multi_geometry.py +++ b/src/pyFAI/multi_geometry.py @@ -49,10 +49,6 @@ import threading import numpy from .method_registry import IntegrationMethod -from .utils.decorators import deprecated_warning -from .integrator.fiber import get_deprecated_params_1d -from .integrator.fiber import get_deprecated_params_2d -from .integrator.fiber import parse_fiber_unit error = None From ac9836f418bb8654553356017b54f49e3665e08f Mon Sep 17 00:00:00 2001 From: edgar1993a Date: Thu, 30 Jan 2025 11:09:52 +0100 Subject: [PATCH 9/9] fix error in units --- src/pyFAI/multi_geometry.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/pyFAI/multi_geometry.py b/src/pyFAI/multi_geometry.py index b7420a134..48a248773 100644 --- a/src/pyFAI/multi_geometry.py +++ b/src/pyFAI/multi_geometry.py @@ -504,8 +504,8 @@ def integrate_fiber(self, lst_data, def _integrate(args): fi, data, monitor, var, mask, flat = args return fi.integrate_fiber(data=data, - npt_oop=npt_oop, unit_oop=self.oop_unit, oop_range=self.ip_range, - npt_ip=npt_ip, unit_ip=self.ip_unit, ip_range=self.oop_range, + npt_oop=npt_oop, unit_oop=self.oop_unit, oop_range=self.oop_range, + npt_ip=npt_ip, unit_ip=self.ip_unit, ip_range=self.ip_range, vertical_integration=vertical_integration, correctSolidAngle=correctSolidAngle, mask=mask, dummy=dummy, delta_dummy=delta_dummy, @@ -536,7 +536,6 @@ def _integrate(args): invalid = count <= 0.0 I = signal / norm I[invalid] = self.empty - if variance is not None: sigma = numpy.sqrt(variance) / norm sigma[invalid] = self.empty @@ -544,7 +543,13 @@ def _integrate(args): else: result = Integrate1dResult(res.radial, I) result._set_compute_engine(res.compute_engine) - result._set_unit(self.ip_unit) + + if vertical_integration: + output_unit = self.oop_unit + else: + output_unit = self.ip_unit + + result._set_unit(output_unit) result._set_sum_signal(signal) result._set_sum_normalization(normalization) result._set_sum_variance(variance)