From fb716974bc6ac624f9d7a4acdd9081b3f94fcbfc Mon Sep 17 00:00:00 2001 From: "\"Serguei Sokol\"" Date: Thu, 16 May 2024 15:36:18 +0200 Subject: [PATCH 01/10] Implement the allclose_modulo as suggested by Serguei. --- src/pyFAI/test/test_utils_mathutil.py | 7 ++++++- src/pyFAI/utils/mathutil.py | 13 ++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/pyFAI/test/test_utils_mathutil.py b/src/pyFAI/test/test_utils_mathutil.py index 4624be7c0..260eebace 100644 --- a/src/pyFAI/test/test_utils_mathutil.py +++ b/src/pyFAI/test/test_utils_mathutil.py @@ -32,7 +32,7 @@ __contact__ = "Jerome.Kieffer@ESRF.eu" __license__ = "MIT" __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France" -__date__ = "20/02/2024" +__date__ = "16/05/2024" import unittest import numpy @@ -157,6 +157,11 @@ def test_is_far_from_group_cython(self): res = is_far_from_group_cython(pt, pts, dst2) self.assertEqual(ref, res, "cython implementation matches *is_far_from_group*") + def test_allclose_mod(self): + from ..utils.mathutil import allclose_mod + self.assertTrue(allclose_mod(numpy.atan2(+1e-10, -1), numpy.atan2(-1e-10, -1)),"angles matches modulo 2pi") + + def suite(): loader = unittest.defaultTestLoader.loadTestsFromTestCase testsuite = unittest.TestSuite() diff --git a/src/pyFAI/utils/mathutil.py b/src/pyFAI/utils/mathutil.py index 4c3aa943f..80fb520a5 100644 --- a/src/pyFAI/utils/mathutil.py +++ b/src/pyFAI/utils/mathutil.py @@ -34,7 +34,7 @@ __contact__ = "Jerome.Kieffer@ESRF.eu" __license__ = "MIT" __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France" -__date__ = "20/02/2024" +__date__ = "16/05/2024" __status__ = "production" import logging @@ -394,6 +394,7 @@ def unBinning(*args, **kwargs): return unbinning(*args, **kwargs) + def shift_fft(input_img, shift_val, method="fft"): """Do shift using FFTs @@ -928,3 +929,13 @@ def interp_filter(ary, out=None): out[mask_invalid] = numpy.interp(x[mask_invalid], x[mask_valid], ary[mask_valid], left=first, right=last) return out + + +def allclose_mod(a, b, modulo=2*numpy.pi, rtol=1.e-5, atol=1.e-8, equal_nan=False): + """Returns True if the two arrays a & b are equal within the given + tolerance modulo `modulo`; False otherwise. + + Thanks to "Serguei Sokol" + """ + di = numpy.minimum((a-b)%modulo, (b-a)%modulo) + return numpy.allclose(modulo*0.5, (di+modulo*0.5), ) From 774c77f110039235bf9a1eb6dbd76b7eba9a3e55 Mon Sep 17 00:00:00 2001 From: Jerome Kieffer Date: Thu, 16 May 2024 15:39:32 +0200 Subject: [PATCH 02/10] Fix test by going via complex numbers complicated but short in code --- src/pyFAI/test/test_geometry.py | 107 ++++++++++++++++++-------------- 1 file changed, 60 insertions(+), 47 deletions(-) diff --git a/src/pyFAI/test/test_geometry.py b/src/pyFAI/test/test_geometry.py index 8b986fc04..cc2a6b78f 100644 --- a/src/pyFAI/test/test_geometry.py +++ b/src/pyFAI/test/test_geometry.py @@ -34,7 +34,7 @@ __contact__ = "Jerome.Kieffer@ESRF.eu" __license__ = "MIT" __copyright__ = "European Synchrotron Radiation Facility, Grenoble, France" -__date__ = "07/05/2024" +__date__ = "16/05/2024" import unittest import random @@ -627,52 +627,65 @@ def test_array_from_unit_chi_center(self): self.assertTrue(179 < r4.max() < 180, "Orientation 4 upperrange matches") def test_array_from_unit_tth_corner(self): - r1 = self.ai1.array_from_unit(unit="2th_deg", typ="corner") - r2 = self.ai2.array_from_unit(unit="2th_deg", typ="corner") - r3 = self.ai3.array_from_unit(unit="2th_deg", typ="corner") - r4 = self.ai4.array_from_unit(unit="2th_deg", typ="corner") + r1 = self.ai1.array_from_unit(unit="2th_rad", typ="corner") + r2 = self.ai2.array_from_unit(unit="2th_rad", typ="corner") + r3 = self.ai3.array_from_unit(unit="2th_rad", typ="corner") + r4 = self.ai4.array_from_unit(unit="2th_rad", typ="corner") + + tth1 = r1[..., 0] + tth2 = r2[..., 0] + tth3 = r3[..., 0] + tth4 = r4[..., 0] + + chi1 = r1[..., 0] + chi2 = r2[..., 0] + chi3 = r3[..., 0] + chi4 = r4[..., 0] + + + sin_chi1 = numpy.sin(r1[..., 1]) + sin_chi2 = numpy.sin(r2[..., 1]) + sin_chi3 = numpy.sin(r3[..., 1]) + sin_chi4 = numpy.sin(r4[..., 1]) + + cos_chi1 = numpy.cos(r1[..., 1]) + cos_chi2 = numpy.cos(r2[..., 1]) + cos_chi3 = numpy.cos(r3[..., 1]) + cos_chi4 = numpy.cos(r4[..., 1]) + + # Here we use complex numbers + z1 = tth1*cos_chi1 + tth1*sin_chi1 *1j + z2 = tth2*cos_chi2 + tth2*sin_chi2 *1j + z3 = tth3*cos_chi3 + tth3*sin_chi3 *1j + z4 = tth4*cos_chi4 + tth4*sin_chi4 *1j + + # the mean is not sensitive to 2pi discontinuity in azimuthal direction + z1 = z1.mean(axis=-1) + z2 = z2.mean(axis=-1) + z3 = z3.mean(axis=-1) + z4 = z4.mean(axis=-1) + + self.assertFalse(numpy.allclose(z1, z2), "orientation 1,2 differ") + self.assertFalse(numpy.allclose(z1, z3), "orientation 1,3 differ") + self.assertFalse(numpy.allclose(z1, z3), "orientation 1,3 differ") + self.assertFalse(numpy.allclose(z1, z4), "orientation 1,4 differ") + self.assertFalse(numpy.allclose(z2, z3), "orientation 2,3 differ") + self.assertFalse(numpy.allclose(z2, z4), "orientation 2,4 differ") + self.assertFalse(numpy.allclose(z3, z4), "orientation 3,4 differ") + + #Check that the tranformation is OK. This is with complex number thus dense & complicated ! + self.assertTrue(numpy.allclose(z1, -numpy.fliplr(z2.conj())), "orientation 1,2 flipped") + self.assertTrue(numpy.allclose(z1, -z3[-1::-1, -1::-1]), "orientation 1,3 inversed") + self.assertTrue(numpy.allclose(z1, numpy.flipud(z4.conj())), "orientation 1,4 flipped") + self.assertTrue(numpy.allclose(z2, numpy.flipud(z3.conj())), "orientation 2,3 flipped") + self.assertTrue(numpy.allclose(z2, -z4[-1::-1, -1::-1]), "orientation 2,4 inversion") + self.assertTrue(numpy.allclose(z3, -numpy.fliplr(z4.conj())), "orientation 3,4 flipped") - tth1 = r1[..., 0].mean(axis=-1) - chi1 = r1[..., 1].mean(axis=-1) / numpy.pi - tth2 = r2[..., 0].mean(axis=-1) - chi2 = r2[..., 1].mean(axis=-1) / numpy.pi - tth3 = r3[..., 0].mean(axis=-1) - chi3 = r3[..., 1].mean(axis=-1) / numpy.pi - tth4 = r4[..., 0].mean(axis=-1) - chi4 = r4[..., 1].mean(axis=-1) / numpy.pi - - self.assertFalse(numpy.allclose(tth1, tth2), "orientation 1,2 differ tth") - self.assertFalse(numpy.allclose(chi1, chi2), "orientation 1,2 differ chi") - self.assertFalse(numpy.allclose(tth1, tth3), "orientation 1,3 differ tth") - self.assertFalse(numpy.allclose(chi1, chi3), "orientation 1,3 differ chi") - self.assertFalse(numpy.allclose(tth1, tth4), "orientation 1,4 differ tth") - self.assertFalse(numpy.allclose(chi1, chi4), "orientation 1,4 differ chi") - - self.assertTrue(numpy.allclose(tth1, numpy.fliplr(tth2)), "orientation 1,2 flipped match tth") - self.assertTrue(numpy.allclose(tth1, numpy.flipud(tth4)), "orientation 1,4 flipped match tth") - self.assertTrue(numpy.allclose(tth2, numpy.flipud(tth3)), "orientation 2,3 flipped match tth") - self.assertTrue(numpy.allclose(chi2, -numpy.flipud(chi3)), "orientation 2,3 flipped match chi") - self.assertTrue(numpy.allclose(tth1, tth3[-1::-1, -1::-1]), "orientation 1,3 inversion match tth") - self.assertTrue(numpy.allclose(tth2, tth4[-1::-1, -1::-1]), "orientation 2,4 inversion match tth") - - # Something fishy on mac-arm64 where this test fails ... correct on all other platforms ! - if platform.system() == "Darwin" and platform.machine()=="arm64": - def angular_distance(a, b, modulo): - return numpy.minimum((a-b)%modulo,(b-a)%modulo) - self.assertLess(angular_distance(chi1 + 1, -numpy.fliplr(chi2), 1).mean(), 0.0001, "orientation 1,2 flipped match chi") - self.assertLess(angular_distance(chi1, -numpy.flipud(chi4), 1).mean(), 0.0001, "orientation 1,4 flipped match chi") - self.assertLess(angular_distance(chi1+1, chi3[-1::-1, -1::-1], 1).mean(), 0.0001, "orientation 1,3 inversion match chi") - self.assertLess(angular_distance(chi2 + 1, chi4[-1::-1, -1::-1], 1).mean(), 0.0001, "orientation 2,4 inversion match chi") - else: - self.assertTrue(numpy.allclose(chi1 + 1, -numpy.fliplr(chi2), atol=0.0001), "orientation 1,2 flipped match chi") - self.assertTrue(numpy.allclose(chi1, -numpy.flipud(chi4)), "orientation 1,4 flipped match chi") - self.assertTrue(numpy.allclose(chi1 + 1, chi3[-1::-1, -1::-1], atol=0.0001), "orientation 1,3 inversion match chi") - self.assertTrue(numpy.allclose(chi2 + 1, chi4[-1::-1, -1::-1]), "orientation 2,4 inversion match chi") def test_chi(self): orient = {} for i in range(1, 5): - ai = geometry.Geometry.sload({"detector":"pilatus100k", "detector_config":{"orientation":i}, + ai = geometry.Geometry.sload({"detector":"Imxpad S10", "detector_config":{"orientation":i}, "poni1":0.01, "poni2":0.01, "wavelength":1e-10}) chi_c = ai.center_array(unit="chi_rad") / numpy.pi @@ -701,18 +714,18 @@ class TestOrientation2(unittest.TestCase): @classmethod def setUpClass(cls) -> None: super(TestOrientation2, cls).setUpClass() - p = detector_factory("Pilatus100k") + p = detector_factory("pilatus100k") c = p.get_pixel_corners() d1 = c[..., 1].max() d2 = c[..., 2].max() cls.ai1 = geometry.Geometry.sload({"poni1":3 * d1 / 4, "poni2":3 * d2 / 4, "wavelength":1e-10, - "detector":"pilatus100k", "detector_config":{"orientation":1}}) + "detector":p, "detector_config":{"orientation":1}}) cls.ai2 = geometry.Geometry.sload({"poni1":3 * d1 / 4, "poni2":d2 / 4, "wavelength":1e-10, - "detector":"pilatus100k", "detector_config":{"orientation":2}}) + "detector":p, "detector_config":{"orientation":2}}) cls.ai3 = geometry.Geometry.sload({"poni1":d1 / 4, "poni2":d2 / 4, "wavelength":1e-10, - "detector":"pilatus100k", "detector_config":{"orientation":3}}) + "detector":p, "detector_config":{"orientation":3}}) cls.ai4 = geometry.Geometry.sload({"poni1":d1 / 4, "poni2":3 * d2 / 4, "wavelength":1e-10, - "detector":"pilatus100k", "detector_config":{"orientation":4}}) + "detector":p, "detector_config":{"orientation":4}}) @classmethod def tearDownClass(cls) -> None: From 1a4d02e522651efd889cf3105c8d34578b0f920b Mon Sep 17 00:00:00 2001 From: Jerome Kieffer Date: Thu, 16 May 2024 16:03:07 +0200 Subject: [PATCH 03/10] Tune some tests --- src/pyFAI/test/test_geometry.py | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/pyFAI/test/test_geometry.py b/src/pyFAI/test/test_geometry.py index cc2a6b78f..2e77a1222 100644 --- a/src/pyFAI/test/test_geometry.py +++ b/src/pyFAI/test/test_geometry.py @@ -683,29 +683,33 @@ def test_array_from_unit_tth_corner(self): def test_chi(self): + epsilon = 6e-3 orient = {} for i in range(1, 5): ai = geometry.Geometry.sload({"detector":"Imxpad S10", "detector_config":{"orientation":i}, - "poni1":0.01, "poni2":0.01, - "wavelength":1e-10}) + "poni1":0.005, "poni2":0.005, "wavelength":1e-10}) chi_c = ai.center_array(unit="chi_rad") / numpy.pi - chi_m = ai.corner_array(unit="chi_rad")[..., 0].mean(axis=-1) / numpy.pi + corners = ai.corner_array(unit="r_mm") + corners_rad = corners[..., 0] + corners_ang = corners[..., 1] + z = corners_rad*numpy.cos(corners_ang) + corners_rad*numpy.sin(corners_ang)*1j + chi_m = numpy.angle(z.mean(axis=-1)) / numpy.pi orient[i] = {"ai": ai, "chi_c": chi_c, "chi_m": chi_m} for o, orien in orient.items(): - self.assertLess(numpy.median(abs(orien["chi_m"] - orien["chi_c"])), 1e-7, f"Orientation {o} matches") + self.assertTrue(numpy.allclose(orien["chi_m"], orien["chi_c"]), f"Orientation {o} matches") ai = orien["ai"] - self.assertLess(numpy.median(ai.delta_array(unit="chi_rad")) / numpy.pi, 1e-3, f"Orientation {o} delta chi small #0") - self.assertLess(numpy.median(ai.deltaChi()) / numpy.pi, 1e-3, f"Orientation {o} delta chi small #1") + self.assertLess(numpy.median(ai.delta_array(unit="chi_rad")) / numpy.pi, epsilon, f"Orientation {o} delta chi small #0") + self.assertLess(numpy.median(ai.deltaChi()) / numpy.pi, epsilon, f"Orientation {o} delta chi small #1") ai.reset() - self.assertLess(numpy.median(ai.delta_array(unit="chi_rad")) / numpy.pi, 1e-3, f"Orientation {o} delta chi small #2") + self.assertLess(numpy.median(ai.delta_array(unit="chi_rad")) / numpy.pi, epsilon, f"Orientation {o} delta chi small #2") ai.reset() - self.assertLess(numpy.median(ai.deltaChi()) / numpy.pi, 1e-3, f"Orientation {o} delta chi small #3") + self.assertLess(numpy.median(ai.deltaChi()) / numpy.pi, epsilon, f"Orientation {o} delta chi small #3") ai.reset() chiArray = ai.chiArray() / numpy.pi chi_center = orien["chi_c"] - self.assertTrue(numpy.allclose(chiArray, chi_center, atol=1e-5), f"Orientation {o} chiArray == center_array(chi)") + self.assertTrue(numpy.allclose(chiArray, chi_center), f"Orientation {o} chiArray == center_array(chi)") class TestOrientation2(unittest.TestCase): @@ -719,13 +723,13 @@ def setUpClass(cls) -> None: d1 = c[..., 1].max() d2 = c[..., 2].max() cls.ai1 = geometry.Geometry.sload({"poni1":3 * d1 / 4, "poni2":3 * d2 / 4, "wavelength":1e-10, - "detector":p, "detector_config":{"orientation":1}}) + "detector":"pilatus100k", "detector_config":{"orientation":1}}) cls.ai2 = geometry.Geometry.sload({"poni1":3 * d1 / 4, "poni2":d2 / 4, "wavelength":1e-10, - "detector":p, "detector_config":{"orientation":2}}) + "detector":"pilatus100k", "detector_config":{"orientation":2}}) cls.ai3 = geometry.Geometry.sload({"poni1":d1 / 4, "poni2":d2 / 4, "wavelength":1e-10, - "detector":p, "detector_config":{"orientation":3}}) + "detector":"pilatus100k", "detector_config":{"orientation":3}}) cls.ai4 = geometry.Geometry.sload({"poni1":d1 / 4, "poni2":3 * d2 / 4, "wavelength":1e-10, - "detector":p, "detector_config":{"orientation":4}}) + "detector":"pilatus100k", "detector_config":{"orientation":4}}) @classmethod def tearDownClass(cls) -> None: From eb7b9097721b3c42dbe640eef01b26669865d326 Mon Sep 17 00:00:00 2001 From: Jerome Kieffer Date: Thu, 16 May 2024 16:18:24 +0200 Subject: [PATCH 04/10] minor fix --- src/pyFAI/test/test_geometry.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/pyFAI/test/test_geometry.py b/src/pyFAI/test/test_geometry.py index 2e77a1222..ba60bff24 100644 --- a/src/pyFAI/test/test_geometry.py +++ b/src/pyFAI/test/test_geometry.py @@ -4,7 +4,7 @@ # Project: Azimuthal integration # https://github.com/silx-kit/pyFAI # -# Copyright (C) 2015-2023 European Synchrotron Radiation Facility, Grenoble, France +# Copyright (C) 2015-2024 European Synchrotron Radiation Facility, Grenoble, France # # Principal author: Jérôme Kieffer (Jerome.Kieffer@ESRF.eu) # @@ -43,7 +43,6 @@ import itertools import logging import os.path -import platform from . import utilstest logger = logging.getLogger(__name__) @@ -54,6 +53,7 @@ from ..detectors import detector_factory from ..third_party import transformations from .utilstest import UtilsTest +from ..utils.mathutil import allclose_mod import fabio @@ -637,21 +637,21 @@ def test_array_from_unit_tth_corner(self): tth3 = r3[..., 0] tth4 = r4[..., 0] - chi1 = r1[..., 0] - chi2 = r2[..., 0] - chi3 = r3[..., 0] - chi4 = r4[..., 0] + chi1 = r1[..., 1] + chi2 = r2[..., 1] + chi3 = r3[..., 1] + chi4 = r4[..., 1] - sin_chi1 = numpy.sin(r1[..., 1]) - sin_chi2 = numpy.sin(r2[..., 1]) - sin_chi3 = numpy.sin(r3[..., 1]) - sin_chi4 = numpy.sin(r4[..., 1]) + sin_chi1 = numpy.sin(chi1) + sin_chi2 = numpy.sin(chi2) + sin_chi3 = numpy.sin(chi3) + sin_chi4 = numpy.sin(chi4) - cos_chi1 = numpy.cos(r1[..., 1]) - cos_chi2 = numpy.cos(r2[..., 1]) - cos_chi3 = numpy.cos(r3[..., 1]) - cos_chi4 = numpy.cos(r4[..., 1]) + cos_chi1 = numpy.cos(chi1) + cos_chi2 = numpy.cos(chi2) + cos_chi3 = numpy.cos(chi3) + cos_chi4 = numpy.cos(chi4) # Here we use complex numbers z1 = tth1*cos_chi1 + tth1*sin_chi1 *1j @@ -698,7 +698,7 @@ def test_chi(self): orient[i] = {"ai": ai, "chi_c": chi_c, "chi_m": chi_m} for o, orien in orient.items(): - self.assertTrue(numpy.allclose(orien["chi_m"], orien["chi_c"]), f"Orientation {o} matches") + self.assertTrue(allclose_mod(orien["chi_m"], orien["chi_c"], 2), f"Orientation {o} matches") ai = orien["ai"] self.assertLess(numpy.median(ai.delta_array(unit="chi_rad")) / numpy.pi, epsilon, f"Orientation {o} delta chi small #0") self.assertLess(numpy.median(ai.deltaChi()) / numpy.pi, epsilon, f"Orientation {o} delta chi small #1") @@ -709,7 +709,7 @@ def test_chi(self): ai.reset() chiArray = ai.chiArray() / numpy.pi chi_center = orien["chi_c"] - self.assertTrue(numpy.allclose(chiArray, chi_center), f"Orientation {o} chiArray == center_array(chi)") + self.assertTrue(allclose_mod(chiArray, chi_center), f"Orientation {o} chiArray == center_array(chi)") class TestOrientation2(unittest.TestCase): From 70e68d32ad1a51794b77bf251fc83d53ca159820 Mon Sep 17 00:00:00 2001 From: Jerome Kieffer Date: Thu, 16 May 2024 16:47:07 +0200 Subject: [PATCH 05/10] typo --- src/pyFAI/test/test_utils_mathutil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyFAI/test/test_utils_mathutil.py b/src/pyFAI/test/test_utils_mathutil.py index 260eebace..2ce3367ac 100644 --- a/src/pyFAI/test/test_utils_mathutil.py +++ b/src/pyFAI/test/test_utils_mathutil.py @@ -159,7 +159,7 @@ def test_is_far_from_group_cython(self): def test_allclose_mod(self): from ..utils.mathutil import allclose_mod - self.assertTrue(allclose_mod(numpy.atan2(+1e-10, -1), numpy.atan2(-1e-10, -1)),"angles matches modulo 2pi") + self.assertTrue(allclose_mod(numpy.arctan2(+1e-10, -1), numpy.atan2(-1e-10, -1)),"angles matches modulo 2pi") def suite(): From 796abaf868ce331b612916c96af93e2c8cbb7c08 Mon Sep 17 00:00:00 2001 From: Jerome Kieffer Date: Thu, 16 May 2024 17:02:53 +0200 Subject: [PATCH 06/10] propagate all param to allclose --- src/pyFAI/utils/mathutil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyFAI/utils/mathutil.py b/src/pyFAI/utils/mathutil.py index 80fb520a5..3cdbd5d16 100644 --- a/src/pyFAI/utils/mathutil.py +++ b/src/pyFAI/utils/mathutil.py @@ -938,4 +938,4 @@ def allclose_mod(a, b, modulo=2*numpy.pi, rtol=1.e-5, atol=1.e-8, equal_nan=Fals Thanks to "Serguei Sokol" """ di = numpy.minimum((a-b)%modulo, (b-a)%modulo) - return numpy.allclose(modulo*0.5, (di+modulo*0.5), ) + return numpy.allclose(modulo*0.5, (di+modulo*0.5), rtol=rtol, atol=atol, equal_nan=equal_nan) From 97d4831330fcd3e6fa5a424a185f746902afcadf Mon Sep 17 00:00:00 2001 From: Jerome Kieffer Date: Thu, 16 May 2024 17:04:10 +0200 Subject: [PATCH 07/10] update dates --- src/pyFAI/test/test_utils_mathutil.py | 2 +- src/pyFAI/utils/mathutil.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pyFAI/test/test_utils_mathutil.py b/src/pyFAI/test/test_utils_mathutil.py index 2ce3367ac..a834a4856 100644 --- a/src/pyFAI/test/test_utils_mathutil.py +++ b/src/pyFAI/test/test_utils_mathutil.py @@ -4,7 +4,7 @@ # Project: Azimuthal integration # https://github.com/silx-kit/pyFAI # -# Copyright (C) 2015-2021 European Synchrotron Radiation Facility, Grenoble, France +# Copyright (C) 2015-2024 European Synchrotron Radiation Facility, Grenoble, France # # Principal author: Jérôme Kieffer (Jerome.Kieffer@ESRF.eu) # diff --git a/src/pyFAI/utils/mathutil.py b/src/pyFAI/utils/mathutil.py index 3cdbd5d16..fce508f0b 100644 --- a/src/pyFAI/utils/mathutil.py +++ b/src/pyFAI/utils/mathutil.py @@ -4,7 +4,7 @@ # Project: Fast Azimuthal integration # https://github.com/silx-kit/pyFAI # -# Copyright (C) 2017-2018 European Synchrotron Radiation Facility, Grenoble, France +# Copyright (C) 2017-2024 European Synchrotron Radiation Facility, Grenoble, France # # Principal author: Jérôme Kieffer (Jerome.Kieffer@ESRF.eu) # From 1b25f20948ddda4e0b88c1043e293a68d541b4bf Mon Sep 17 00:00:00 2001 From: Jerome Kieffer Date: Thu, 16 May 2024 17:19:17 +0200 Subject: [PATCH 08/10] forgot half of it ! --- src/pyFAI/test/test_utils_mathutil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pyFAI/test/test_utils_mathutil.py b/src/pyFAI/test/test_utils_mathutil.py index a834a4856..6529aa7a7 100644 --- a/src/pyFAI/test/test_utils_mathutil.py +++ b/src/pyFAI/test/test_utils_mathutil.py @@ -159,7 +159,7 @@ def test_is_far_from_group_cython(self): def test_allclose_mod(self): from ..utils.mathutil import allclose_mod - self.assertTrue(allclose_mod(numpy.arctan2(+1e-10, -1), numpy.atan2(-1e-10, -1)),"angles matches modulo 2pi") + self.assertTrue(allclose_mod(numpy.arctan2(+1e-10, -1), numpy.arctan2(-1e-10, -1)),"angles matches modulo 2pi") def suite(): From b64d1a5a979db2f8eaa7faf0be236dbdc0695a10 Mon Sep 17 00:00:00 2001 From: Jerome Kieffer Date: Fri, 17 May 2024 10:16:00 +0200 Subject: [PATCH 09/10] Trim white-space --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 76fb5a8e0..04c239e1d 100644 --- a/README.rst +++ b/README.rst @@ -145,7 +145,7 @@ using apt-get these can be installed as:: MacOSX ------ -One needs to manually install a recent version of `Python` (>=3.7) prior to installing pyFAI. +One needs to manually install a recent version of `Python` (>=3.7) prior to installing pyFAI. Apple provides only an outdated version of Python 2.7 which is now incomatible. If you want to build pyFAI from sources, you will also need `Xcode` which is available from the Apple store. The compiled extension will use only one core due to the limitation of the compiler. From 6dab338a8df70db6d2b3476e776a40142a8dae13 Mon Sep 17 00:00:00 2001 From: Jerome Kieffer Date: Fri, 17 May 2024 13:14:52 +0200 Subject: [PATCH 10/10] use **kwargs --- src/pyFAI/utils/mathutil.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pyFAI/utils/mathutil.py b/src/pyFAI/utils/mathutil.py index fce508f0b..7bf4ed649 100644 --- a/src/pyFAI/utils/mathutil.py +++ b/src/pyFAI/utils/mathutil.py @@ -931,11 +931,11 @@ def interp_filter(ary, out=None): return out -def allclose_mod(a, b, modulo=2*numpy.pi, rtol=1.e-5, atol=1.e-8, equal_nan=False): +def allclose_mod(a, b, modulo=2*numpy.pi, **kwargs): """Returns True if the two arrays a & b are equal within the given tolerance modulo `modulo`; False otherwise. Thanks to "Serguei Sokol" """ di = numpy.minimum((a-b)%modulo, (b-a)%modulo) - return numpy.allclose(modulo*0.5, (di+modulo*0.5), rtol=rtol, atol=atol, equal_nan=equal_nan) + return numpy.allclose(modulo*0.5, (di+modulo*0.5), **kwargs)