diff --git a/sasdata/quantities/constants.py b/sasdata/quantities/constants.py index ea260e24e..b2a17c236 100644 --- a/sasdata/quantities/constants.py +++ b/sasdata/quantities/constants.py @@ -1,4 +1,10 @@ import math +# Common Pi-related values Pi = math.pi TwoPi = 2 * math.pi +PiOverTwo = Pi / 2 + +# Infinite values +Inf = math.inf +NegInf = -math.inf diff --git a/sasdata/quantities/quantity.py b/sasdata/quantities/quantity.py index 08e0be6fe..e38dc2eaa 100644 --- a/sasdata/quantities/quantity.py +++ b/sasdata/quantities/quantity.py @@ -5,7 +5,7 @@ import h5py import numpy as np -from numpy._typing import ArrayLike +from numpy.typing import ArrayLike from sasdata.quantities import units from sasdata.quantities.numerical_encoding import numerical_decode, numerical_encode diff --git a/sasdata/slicing/slicer_demo.py b/sasdata/slicing/slicer_demo.py index 5626ded4d..b8ff0224e 100644 --- a/sasdata/slicing/slicer_demo.py +++ b/sasdata/slicing/slicer_demo.py @@ -4,7 +4,7 @@ import numpy as np from sasdata.slicing.meshes.voronoi_mesh import voronoi_mesh -from sasdata.slicing.slicers.AnularSector import AnularSector +from sasdata.slicing.slicers.AnnularSector import AnnularSector if __name__ == "__main__": q_range = 1.5 @@ -41,7 +41,7 @@ def lobe_test_function(x, y): phi0 = np.pi/2 - size phi1 = np.pi/2 + size - rebinner = AnularSector(q0, q1, phi0, phi1) + rebinner = AnnularSector(q0, q1, phi0, phi1) data_order_neg1.append(rebinner.sum(x, y, random_lobe_data, order=-1)) data_order_0.append(rebinner.sum(x, y, random_lobe_data, order=0)) @@ -94,7 +94,7 @@ def ring_test_function(x, y): phi0 = np.pi/2 - size phi1 = np.pi/2 + size - rebinner = AnularSector(q0, q1, phi0, phi1) + rebinner = AnnularSector(q0, q1, phi0, phi1) data_order_neg1.append(rebinner.average(x, y, grid_ring_data, order=-1)) data_order_0.append(rebinner.average(x, y, grid_ring_data, order=0)) diff --git a/sasdata/slicing/slicers/Annular.py b/sasdata/slicing/slicers/Annular.py new file mode 100644 index 000000000..1d349120f --- /dev/null +++ b/sasdata/slicing/slicers/Annular.py @@ -0,0 +1,23 @@ +from sasdata.quantities.constants import TwoPi +from sasdata.quantities.quantity import Quantity +from sasdata.quantities.units import per_angstrom +from sasdata.slicing.slicers.AnnularSector import AnnularSector, QuantityType + + +class Annular(AnnularSector): + """ Annual averaging, using the wedge as a basis. """ + def __init__(self, q0: QuantityType, q1: QuantityType, points_per_degree: int=2): + super().__init__(q0, q1, 0.0, TwoPi, points_per_degree) + + +def main(): + """ Just show a random example""" + a_float = Annular(1, 2) + q0 = Quantity(1, per_angstrom) + q1 = Quantity(2, per_angstrom) + a_quant = Annular(q0, q1) + assert a_float.bin_mesh.n_cells == a_quant.bin_mesh.n_cells + + +if __name__ == "__main__": + main() diff --git a/sasdata/slicing/slicers/AnnularSector.py b/sasdata/slicing/slicers/AnnularSector.py new file mode 100644 index 000000000..6fc565bf7 --- /dev/null +++ b/sasdata/slicing/slicers/AnnularSector.py @@ -0,0 +1,66 @@ +import numpy as np + +from sasdata.quantities.quantity import Quantity +from sasdata.quantities.units import per_angstrom, radians +from sasdata.slicing.meshes.mesh import Mesh +from sasdata.slicing.rebinning import Rebinner + +QuantityType = Quantity | float + + +class AnnularSector(Rebinner): + """ A single annular sector (wedge sum)""" + def __init__(self, q0: QuantityType, q1: QuantityType, phi0: QuantityType, + phi1: QuantityType, points_per_degree: int=2): + super().__init__() + + # Ensure all values are scaled to the proper units + self._q0 = q0.to_units_of(per_angstrom) if isinstance(q0, Quantity) else Quantity(q0, per_angstrom) + self._q1 = q1.to_units_of(per_angstrom) if isinstance(q1, Quantity) else Quantity(q1, per_angstrom) + self._phi0 = phi0.to_units_of(radians) if isinstance(phi0, Quantity) else Quantity(phi0, radians) + self._phi1 = phi1.to_units_of(radians) if isinstance(phi1, Quantity) else Quantity(phi1, radians) + + self.points_per_degree = points_per_degree + + @property + def q0(self): + return self._q0.value + + @property + def q1(self): + return self._q1.value + + @property + def phi0(self): + return self._phi0.value + + @property + def phi1(self): + return self._phi1.value + + def _bin_mesh(self) -> Mesh: + + n_points = np.max([int(1 + 180*self.points_per_degree*(self.phi1 - self.phi0) / np.pi), 2]) + + angles = np.linspace(self.phi0, self.phi1, n_points) + + row1 = self.q0 * np.array([np.cos(angles), np.sin(angles)]) + row2 = self.q1 * np.array([np.cos(angles), np.sin(angles)])[:, ::-1] + + points = np.concatenate((row1, row2), axis=1).T + + cells = [[i for i in range(2*n_points)]] + + return Mesh(points=points, cells=cells) + + def _bin_coordinates(self) -> np.ndarray: + return np.array([], dtype=float) + + +def main(): + """ Just show a random example""" + AnnularSector(1, 2, 1, 2).bin_mesh.show() + + +if __name__ == "__main__": + main() diff --git a/sasdata/slicing/slicers/AnularSector.py b/sasdata/slicing/slicers/AnularSector.py deleted file mode 100644 index 56ed5f262..000000000 --- a/sasdata/slicing/slicers/AnularSector.py +++ /dev/null @@ -1,44 +0,0 @@ -import numpy as np - -from sasdata.slicing.meshes.mesh import Mesh -from sasdata.slicing.rebinning import Rebinner - - -class AnularSector(Rebinner): - """ A single annular sector (wedge sum)""" - def __init__(self, q0: float, q1: float, phi0: float, phi1: float, points_per_degree: int=2): - super().__init__() - - self.q0 = q0 - self.q1 = q1 - self.phi0 = phi0 - self.phi1 = phi1 - - self.points_per_degree = points_per_degree - - def _bin_mesh(self) -> Mesh: - - n_points = np.max([int(1 + 180*self.points_per_degree*(self.phi1 - self.phi0) / np.pi), 2]) - - angles = np.linspace(self.phi0, self.phi1, n_points) - - row1 = self.q0 * np.array([np.cos(angles), np.sin(angles)]) - row2 = self.q1 * np.array([np.cos(angles), np.sin(angles)])[:, ::-1] - - points = np.concatenate((row1, row2), axis=1).T - - cells = [[i for i in range(2*n_points)]] - - return Mesh(points=points, cells=cells) - - def _bin_coordinates(self) -> np.ndarray: - return np.array([], dtype=float) - - -def main(): - """ Just show a random example""" - AnularSector(1, 2, 1, 2).bin_mesh.show() - - -if __name__ == "__main__": - main() diff --git a/sasdata/slicing/slicers/Sector.py b/sasdata/slicing/slicers/Sector.py new file mode 100644 index 000000000..4483af611 --- /dev/null +++ b/sasdata/slicing/slicers/Sector.py @@ -0,0 +1,20 @@ +from sasdata.quantities.constants import Inf, NegInf, PiOverTwo +from sasdata.slicing.slicers.AnnularSector import AnnularSector + + +class Sector(AnnularSector): + """ Annual averaging, using the wedge as a basis. """ + def __init__(self, phi0: float, phi1: float, points_per_degree: int=2): + super().__init__(NegInf, Inf, phi0, phi1, points_per_degree) + + +def main(): + """ Just show a random example""" + sector = Sector(0, PiOverTwo) + sector.q0 = -3 + sector.q1 = 3 + sector.bin_mesh.show() + + +if __name__ == "__main__": + main()