From 413fddeda019edd5341369f32c12747399495203 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Wed, 19 Mar 2025 23:30:09 +0100 Subject: [PATCH 01/51] Added methods for comparing beams and for printing out summary in the Beam class. --- abel/classes/beam.py | 129 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/abel/classes/beam.py b/abel/classes/beam.py index d1d72215..5ee240b0 100644 --- a/abel/classes/beam.py +++ b/abel/classes/beam.py @@ -231,6 +231,101 @@ def deltas(self, pz0=None): def ts(self): return self.zs()/SI.c + + def comp_beams(beam1, beam2, comp_location=False, rtol=1e-05, atol=1e-08): + """ + Compare the phase spaces of two beams. Chekcks if all arrays are element-wise equal within given tolerances. + + Parameters + ---------- + beam1, beam2 : ABEL ``Beam`` object + Beams to be compared + + comp_location: bool, optional + Flag for comparing the location of the beams. Default set to ``False``. + + rtol : float, optional + The relative tolerance parameter (see [1]_). Default set to 1e-5. + + rb_fit_obj : float, optional + The absolute tolerance parameter (see [1]_). Default set to 1e-8. + + + Returns + ---------- + ``None`` + + + References + ---------- + .. [1] ``numpy.allclose()`` https://numpy.org/doc/stable/reference/generated/numpy.allclose.html + """ + + if comp_location: + assert np.allclose(beam1.location, beam2.location, rtol, atol) + assert np.allclose(beam1.qs(), beam2.qs(), rtol, atol) + assert np.allclose(beam1.weightings(), beam2.weightings(), rtol, atol) + assert np.allclose(beam1.xs(), beam2.xs(), rtol, atol) + assert np.allclose(beam1.ys(), beam2.ys(), rtol, atol) + assert np.allclose(beam1.zs(), beam2.zs(), rtol, atol) + assert np.allclose(beam1.uxs(), beam2.uxs(), rtol, atol) + assert np.allclose(beam1.uys(), beam2.uys(), rtol, atol) + assert np.allclose(beam1.uzs(), beam2.uzs(), rtol, atol) + assert np.allclose(beam1.particle_mass, beam2.particle_mass, rtol, atol) + + + def comp_beam_params(beam1, beam2, comp_location=False): + """ + Compare the parameters of two beams to see if they are equal within given tolerances. + + Parameters + ---------- + beam1, beam2 : ABEL ``Beam`` object + Beams to be compared + + comp_location: bool, optional + Flag for comparing the location of the beams. Default set to ``False``. + + + Returns + ---------- + ``None`` + + + References + ---------- + .. [1] ``numpy.allclose()`` https://numpy.org/doc/stable/reference/generated/numpy.allclose.html + """ + + if comp_location: + assert np.allclose(beam1.location, beam2.location, rtol=0.0, atol=0.3) + assert np.allclose(beam1.particle_mass, beam2.particle_mass, rtol=1e-05, atol=1e-08) + assert np.allclose(beam1.total_particles(), beam2.total_particles(), rtol=1e-05, atol=1e-08) + assert np.allclose(beam1.charge(), beam2.charge(), rtol=1e-05, atol=1e-08) + assert np.allclose(beam1.energy(), beam2.energy(), rtol=0.0, atol=0.6e9) # Usually rather large discrepancy in energy. + assert np.allclose(beam1.energy_spread(), beam2.energy_spread(), rtol=0.0, atol=0.6e9) + assert np.allclose(beam1.rel_energy_spread(), beam2.rel_energy_spread(), rtol=0.0, atol=5e-4) + assert np.allclose(beam1.bunch_length(), beam2.bunch_length(), rtol=0.0, atol=1e-6) + assert np.allclose(beam1.beam_size_x(), beam2.beam_size_x(), rtol=0.0, atol=0.5e-6) + assert np.allclose(beam1.beam_size_y(), beam2.beam_size_y(), rtol=0.0, atol=0.05e-6) + assert np.allclose(beam1.geom_emittance_x(), beam2.geom_emittance_x(), rtol=1e-05, atol=1e-08) + assert np.allclose(beam1.geom_emittance_y(), beam2.geom_emittance_y(), rtol=1e-05, atol=1e-08) + assert np.allclose(beam1.norm_emittance_x(), beam2.norm_emittance_x(), rtol=0.0, atol=1e-6) + assert np.allclose(beam1.norm_emittance_y(), beam2.norm_emittance_y(), rtol=0.0, atol=0.5e-6) + assert np.allclose(beam1.peak_current(), beam2.peak_current(), rtol=0.0, atol=0.7e3) + assert np.allclose(beam1.beta_x(), beam2.beta_x(), rtol=0.0, atol=50e-3) + assert np.allclose(beam1.beta_y(), beam2.beta_y(), rtol=0.0, atol=50e-3) + assert np.allclose(beam1.gamma_x(), beam2.gamma_x(), rtol=0.0, atol=0.1) + assert np.allclose(beam1.gamma_y(), beam2.gamma_y(), rtol=0.0, atol=0.1) + assert np.allclose(beam1.z_offset(), beam2.z_offset(), rtol=0.0, atol=3e-6) + assert np.allclose(beam1.x_offset(), beam2.x_offset(), rtol=0.0, atol=3e-6) + assert np.allclose(beam1.y_offset(), beam2.y_offset(), rtol=0.0, atol=3e-6) + assert np.allclose(beam1.x_angle(), beam2.x_angle(), rtol=0.0, atol=3e-6) + assert np.allclose(beam1.y_angle(), beam2.y_angle(), rtol=0.0, atol=3e-6) + assert np.allclose(beam1.divergence_x(), beam2.divergence_x(), rtol=0.0, atol=0.2e-5) + assert np.allclose(beam1.divergence_y(), beam2.divergence_y(), rtol=0.0, atol=0.5e-6) + + # vector of transverse positions and angles: (x, x', y, y') def transverse_vector(self): vector = np.zeros((4,len(self))) @@ -1669,3 +1764,37 @@ def density_map_diags(self): extent_energ[2] = extent_energ[2]/1e9 # [GeV] extent_energ[3] = extent_energ[3]/1e9 # [GeV] self.distribution_plot_2D(arr1=zs, arr2=Es, weights=weights, hist_bins=hist_bins, hist_range=hist_range_energ, axes=axs[2][2], extent=extent_energ, vmin=None, vmax=None, colmap=cmap, xlab=xilab, ylab=energ_lab, clab=r'$\partial^2 N/\partial \xi \partial\mathcal{E}$ [$\mathrm{m}^{-1}$ $\mathrm{eV}^{-1}$]', origin='lower', interpolation='nearest') + + + # ================================================== + def print_summary(self): + + print('---------------------------------------------------') + print('Quantity \t\t\t\t Value') + print('---------------------------------------------------') + if hasattr(self, 'beam_name'): + print(f"Beam name:\t\t\t\t {self.beam_name :s}") + print(f"Number of macroparticles:\t\t {len(self) :d}") + print(f"Mean gamma:\t\t\t\t {self.gamma() :.3f}") + print(f"Mean energy [GeV]:\t\t\t {self.energy()/1e9 :.3f}") + print(f"rms energy spread [%]:\t\t\t {self.rel_energy_spread()*1e2 :.3f}\n") + + print(f"Location [m]:\t\t\t\t {self.location :.3f}") + print(f"x offset [um]:\t\t\t\t {self.x_offset()*1e6 :.3f}") + print(f"y offset [um]:\t\t\t\t {self.y_offset()*1e6 :.3f}") + print(f"z offset [um]:\t\t\t\t {self.z_offset()*1e6 :.3f}\n") + + print(f"x angular offset [urad]:\t\t {self.x_angle()*1e6 :.3f}") + print(f"y angular offset [urad]:\t\t {self.y_angle()*1e6 :.3f}\n") + + print(f"Normalised x emittance [mm mrad]:\t {self.norm_emittance_x()*1e6 :.3f}") + print(f"Normalised y emittance [mm mrad]:\t {self.norm_emittance_y()*1e6 :.3f}") + print(f"Angular momentum [mm mrad]:\t\t {self.angular_momentum()*1e6 :.3f}\n") + print(f"x beta function [mm]:\t\t\t {self.beta_x()*1e3 :.3f} \t\t") + print(f"y beta function [mm]:\t\t\t {self.beta_y()*1e3 :.3f} \t\t\n") + + print(f"x beam size [um]:\t\t\t {self.beam_size_x()*1e6 :.3f} \t\t\t") + print(f"y beam size [um]:\t\t\t {self.beam_size_y()*1e6 :.3f} \t\t\t") + print(f"rms beam length [um]:\t\t\t {self.bunch_length()*1e6 :.3f} \t\t") + print(f"Peak current [kA]:\t\t\t {self.peak_current()/1e3 :.3f} \t\t") + print('---------------------------------------------------') From fd58b691aa616ae2f39e74a1e70f884ad32a066c Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Wed, 19 Mar 2025 23:31:14 +0100 Subject: [PATCH 02/51] Added test for testing SourceBasic --- tests/test_source.py | 79 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 tests/test_source.py diff --git a/tests/test_source.py b/tests/test_source.py new file mode 100644 index 00000000..427910cf --- /dev/null +++ b/tests/test_source.py @@ -0,0 +1,79 @@ +""" +ABEL : Source class tests +======================================= + +This file is a part of ABEL. +Copyright 2022– C.A.Lindstrøm, B.Chen, O.G. Finnerud, +D. Kallvik, E. Hørlyk, K.N. Sjobak, E.Adli, University of Oslo + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" + +import pytest +from abel import * + +def test_SourceBasic2Beam(): + "Check that the generated ``Beam`` from a ``SourceBasic`` has the desired properties." + + np.random.seed(42) + + plasma_density = 6.0e+20 # [m^-3] + ramp_beta_mag = 5.0 + + main = SourceBasic() + main.bunch_length = 40.0e-06 # [m], rms. + main.num_particles = 10000 + main.charge = -e * 1.0e10 # [C] + + # Energy parameters + main.energy = 3e9 # [eV] + main.rel_energy_spread = 0.02 # Relative rms energy spread + + # Emittances + main.emit_nx, main.emit_ny = 90.0e-6, 0.32e-6 # [m rad], budget value + + # Beta functions + main.beta_x = beta_matched(plasma_density, main.energy) * ramp_beta_mag # [m] + main.beta_y = main.beta_x # [m] + + # Offsets + main.z_offset = 0.00e-6 # [m] + main.x_offset = 1.50e-6 # [m] + main.y_offset = -1.0e-6 # [m] + main.x_angle = -0.1e-6 # [rad] + main.y_angle = 0.7e-6 # [rad] + + # Other + main.symmetrize_6d = True + + # Track and check + beam = main.track() + + beam.print_summary() + + assert np.allclose(beam.particle_mass, SI.m_e, rtol=1e-05, atol=1e-08) + assert np.allclose(len(beam), main.num_particles, rtol=1e-05, atol=1e-08) + assert np.allclose(beam.charge(), main.charge, rtol=1e-05, atol=1e-08) + assert np.allclose(beam.energy(), main.energy, rtol=0.0, atol=0.1e9) + assert np.allclose(beam.rel_energy_spread(), main.rel_energy_spread, rtol=0.0, atol=0.005) + assert np.allclose(beam.bunch_length(), main.bunch_length, rtol=0.0, atol=2e-6) + assert np.allclose(beam.norm_emittance_x(), main.emit_nx, rtol=0.0, atol=1e-6) + assert np.allclose(beam.norm_emittance_y(), main.emit_ny, rtol=0.0, atol=0.05e-6) + assert np.allclose(beam.beta_x(), main.beta_x, rtol=0.0, atol=5e-3) + assert np.allclose(beam.beta_y(), main.beta_y, rtol=0.0, atol=5e-3) + assert np.allclose(beam.z_offset(), main.z_offset, rtol=0.0, atol=1e-8) + assert np.allclose(beam.x_offset(), main.x_offset, rtol=0.0, atol=1e-8) + assert np.allclose(beam.y_offset(), main.y_offset, rtol=0.0, atol=1e-8) + assert np.allclose(beam.x_angle(), main.x_angle, rtol=0.0, atol=1e-8) + assert np.allclose(beam.y_angle(), main.y_angle, rtol=0.0, atol=1e-8) \ No newline at end of file From e3ea280be6caff0ccbf059e15ef150f3c3f046d7 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Thu, 20 Mar 2025 15:40:11 +0100 Subject: [PATCH 03/51] Updates to test_sources.py --- pyproject.toml | 1 + tests/test_source.py | 79 ----------------- tests/test_sources.py | 194 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+), 79 deletions(-) delete mode 100644 tests/test_source.py create mode 100644 tests/test_sources.py diff --git a/pyproject.toml b/pyproject.toml index debde464..8fd3fb88 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -51,4 +51,5 @@ addopts = [ markers = [ "core: Test core functionality", "stageGeometry: Test stage geometry calculation functionality", + "sources: Test the various Source subclasses generate beams with desired properties", ] diff --git a/tests/test_source.py b/tests/test_source.py deleted file mode 100644 index 427910cf..00000000 --- a/tests/test_source.py +++ /dev/null @@ -1,79 +0,0 @@ -""" -ABEL : Source class tests -======================================= - -This file is a part of ABEL. -Copyright 2022– C.A.Lindstrøm, B.Chen, O.G. Finnerud, -D. Kallvik, E. Hørlyk, K.N. Sjobak, E.Adli, University of Oslo - -This program is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program. If not, see . -""" - -import pytest -from abel import * - -def test_SourceBasic2Beam(): - "Check that the generated ``Beam`` from a ``SourceBasic`` has the desired properties." - - np.random.seed(42) - - plasma_density = 6.0e+20 # [m^-3] - ramp_beta_mag = 5.0 - - main = SourceBasic() - main.bunch_length = 40.0e-06 # [m], rms. - main.num_particles = 10000 - main.charge = -e * 1.0e10 # [C] - - # Energy parameters - main.energy = 3e9 # [eV] - main.rel_energy_spread = 0.02 # Relative rms energy spread - - # Emittances - main.emit_nx, main.emit_ny = 90.0e-6, 0.32e-6 # [m rad], budget value - - # Beta functions - main.beta_x = beta_matched(plasma_density, main.energy) * ramp_beta_mag # [m] - main.beta_y = main.beta_x # [m] - - # Offsets - main.z_offset = 0.00e-6 # [m] - main.x_offset = 1.50e-6 # [m] - main.y_offset = -1.0e-6 # [m] - main.x_angle = -0.1e-6 # [rad] - main.y_angle = 0.7e-6 # [rad] - - # Other - main.symmetrize_6d = True - - # Track and check - beam = main.track() - - beam.print_summary() - - assert np.allclose(beam.particle_mass, SI.m_e, rtol=1e-05, atol=1e-08) - assert np.allclose(len(beam), main.num_particles, rtol=1e-05, atol=1e-08) - assert np.allclose(beam.charge(), main.charge, rtol=1e-05, atol=1e-08) - assert np.allclose(beam.energy(), main.energy, rtol=0.0, atol=0.1e9) - assert np.allclose(beam.rel_energy_spread(), main.rel_energy_spread, rtol=0.0, atol=0.005) - assert np.allclose(beam.bunch_length(), main.bunch_length, rtol=0.0, atol=2e-6) - assert np.allclose(beam.norm_emittance_x(), main.emit_nx, rtol=0.0, atol=1e-6) - assert np.allclose(beam.norm_emittance_y(), main.emit_ny, rtol=0.0, atol=0.05e-6) - assert np.allclose(beam.beta_x(), main.beta_x, rtol=0.0, atol=5e-3) - assert np.allclose(beam.beta_y(), main.beta_y, rtol=0.0, atol=5e-3) - assert np.allclose(beam.z_offset(), main.z_offset, rtol=0.0, atol=1e-8) - assert np.allclose(beam.x_offset(), main.x_offset, rtol=0.0, atol=1e-8) - assert np.allclose(beam.y_offset(), main.y_offset, rtol=0.0, atol=1e-8) - assert np.allclose(beam.x_angle(), main.x_angle, rtol=0.0, atol=1e-8) - assert np.allclose(beam.y_angle(), main.y_angle, rtol=0.0, atol=1e-8) \ No newline at end of file diff --git a/tests/test_sources.py b/tests/test_sources.py new file mode 100644 index 00000000..6100e71d --- /dev/null +++ b/tests/test_sources.py @@ -0,0 +1,194 @@ +""" +ABEL : Source class tests +======================================= + +This file is a part of ABEL. +Copyright 2022– C.A.Lindstrøm, B.Chen, O.G. Finnerud, +D. Kallvik, E. Hørlyk, K.N. Sjobak, E.Adli, University of Oslo + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" + +import pytest +from abel import * + +def check_beam_source_parameters(beam, source): + assert np.allclose(beam.particle_mass, SI.m_e, rtol=1e-05, atol=1e-08) + assert np.allclose(len(beam), source.num_particles, rtol=1e-05, atol=1e-08) + assert np.allclose(beam.charge(), source.charge, rtol=1e-05, atol=1e-08) + assert np.allclose(beam.energy(), source.energy, rtol=0.0, atol=0.1e9) + assert np.allclose(beam.rel_energy_spread(), source.rel_energy_spread, rtol=0.0, atol=0.005) + assert np.allclose(beam.norm_emittance_x(), source.emit_nx, rtol=0.01, atol=1e-6) + assert np.allclose(beam.norm_emittance_y(), source.emit_ny, rtol=0.01, atol=0.05e-6) + assert np.allclose(beam.beta_x(), source.beta_x, rtol=0.01, atol=5e-3) + assert np.allclose(beam.beta_y(), source.beta_y, rtol=0.01, atol=5e-3) + + if isinstance(source, SourceTrapezoid) or isinstance(source, SourceFlatTop): + assert np.allclose(beam.zs().max(), source.z_offset, rtol=0.01, atol=2e-6) + else: + assert np.allclose(beam.z_offset(), source.z_offset, rtol=0.0, atol=1e-8) + assert np.allclose(beam.x_offset(), source.x_offset, rtol=0.0, atol=1e-8) + assert np.allclose(beam.y_offset(), source.y_offset, rtol=0.0, atol=1e-8) + assert np.allclose(beam.x_angle(), source.x_angle, rtol=0.0, atol=1e-8) + assert np.allclose(beam.y_angle(), source.y_angle, rtol=0.0, atol=1e-8) + + if isinstance(source, SourceTrapezoid) or isinstance(source, SourceFlatTop): + assert np.allclose(beam.zs().max()-beam.zs().min(), source.bunch_length, rtol=0.01, atol=0.0) + else: + assert np.allclose(beam.bunch_length(), source.bunch_length, rtol=0.01, atol=2e-6) + + +@pytest.mark.sources +def test_SourceBasic2Beam(): + "Check that the generated ``Beam`` from a ``SourceBasic`` has the desired properties." + + np.random.seed(42) + + plasma_density = 6.0e+20 # [m^-3] + ramp_beta_mag = 5.0 + + source = SourceBasic() + source.bunch_length = 40.0e-06 # [m], rms. + source.num_particles = 10000 + source.charge = -e * 1.0e10 # [C] + + # Energy parameters + source.energy = 3e9 # [eV] + source.rel_energy_spread = 0.02 # Relative rms energy spread + + # Emittances + source.emit_nx, source.emit_ny = 90.0e-6, 0.32e-6 # [m rad], budget value + + # Beta functions + source.beta_x = beta_matched(plasma_density, source.energy) * ramp_beta_mag # [m] + source.beta_y = source.beta_x # [m] + + # Offsets + source.z_offset = 0.00e-6 # [m] + source.x_offset = 1.50e-6 # [m] + source.y_offset = -1.0e-6 # [m] + source.x_angle = -0.1e-6 # [rad] + source.y_angle = 0.7e-6 # [rad] + + # Other + source.symmetrize_6d = True + + # Track and check + beam = source.track() + beam.print_summary() + check_beam_source_parameters(beam, source) + + +@pytest.mark.sources +def test_SourceTrapezoid2Beam(): + "Check that the generated ``Beam`` from a ``SourceTrapezoid`` has the desired properties." + + np.random.seed(42) + + source = SourceTrapezoid() + source.bunch_length = 1050e-6 # [m], rms. + source.num_particles = 30000 + source.charge = -e * 5.0e10 # [C] + source.current_head = 0.1e3 # [A] + + # Energy parameters + source.energy = 4.0e9 # [eV] + source.rel_energy_spread = 0.01 # Relative rms energy spread + + # Emittances + source.emit_nx, source.emit_ny = 50e-6, 100e-6 # [m rad], budget value + + # Beta functions + source.beta_x, source.beta_y = 0.5, 0.5 # [m] + + # Offsets + source.z_offset = 1615e-6 # [m] + source.x_offset = 1.50e-6 # [m] + source.y_offset = -1.0e-6 # [m] + source.x_angle = -0.1e-6 # [rad] + source.y_angle = 0.7e-6 # [rad] + + # Other + source.symmetrize = True + #source.gaussian_blur = 50e-6 # [m], excluding blur makes it easier to control z_offset. + + # Track and check + beam = source.track() + beam.print_summary() + check_beam_source_parameters(beam, source) + + +@pytest.mark.sources +def test_SourceFlatopBeam(): + "Check that the generated ``Beam`` from a ``SourceFlatTop`` has the desired properties." + + np.random.seed(42) + + source = SourceFlatTop() + source.bunch_length = 1050e-6 # [m], rms. + source.num_particles = 30000 + source.charge = -e * 5.0e10 # [C] + + # Energy parameters + source.energy = 4.0e9 # [eV] + source.rel_energy_spread = 0.01 # Relative rms energy spread + + # Emittances + source.emit_nx, source.emit_ny = 50e-6, 100e-6 # [m rad], budget value + + # Beta functions + source.beta_x, source.beta_y = 0.5, 0.5 # [m] + + # Offsets + source.z_offset = 1615e-6 # [m] + source.x_offset = 1.50e-6 # [m] + source.y_offset = -1.0e-6 # [m] + source.x_angle = -0.1e-6 # [rad] + source.y_angle = 0.7e-6 # [rad] + + # Other + source.symmetrize = True + + # Track and check + beam = source.track() + beam.print_summary() + check_beam_source_parameters(beam, source) + + +@pytest.mark.sources +def test_SourceCapsule2Beam(): + "Check that ``SourceCapsule`` retuns returns the same ``Beam`` as the input ``Beam``." + + beam_file = 'tests/data/test_StagePrtclTransWakeInstability_beamline/test_baseline_linac/shot_000/beam_003_00048.558626.h5' + + source = SourceCapsule() + ref_beam = Beam.load(beam_file) + source.beam = ref_beam + beam = source.track() + Beam.comp_beams(beam, ref_beam) + + +@pytest.mark.sources +def test_SourceFromFile2Beam(): + "Check that ``SourceFromFile`` retuns returns the same ``Beam`` as the input ``Beam``." + + beam_file = 'tests/data/test_StagePrtclTransWakeInstability_beamline/test_baseline_linac/shot_000/beam_003_00048.558626.h5' + + source = SourceFromFile() + source.file = beam_file + beam = source.track() + ref_beam = Beam.load(beam_file) + Beam.comp_beams(beam, ref_beam) + + From ea6b68921c407c72ce77fc770d18d04308ef9326 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Thu, 20 Mar 2025 23:53:51 +0100 Subject: [PATCH 04/51] Added test_beam.py for testing the Beam class. --- tests/test_beam.py | 246 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 246 insertions(+) create mode 100644 tests/test_beam.py diff --git a/tests/test_beam.py b/tests/test_beam.py new file mode 100644 index 00000000..26af401b --- /dev/null +++ b/tests/test_beam.py @@ -0,0 +1,246 @@ +""" +ABEL : Beam class tests +======================================= + +This file is a part of ABEL. +Copyright 2022– C.A.Lindstrøm, B.Chen, O.G. Finnerud, +D. Kallvik, E. Hørlyk, K.N. Sjobak, E.Adli, University of Oslo + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +""" + +import pytest +from abel import * +import random + + +############# Basic tests ############# + +@pytest.mark.beam +def test_initialization(): + "Test if the ``Beam`` object initialises correctly." + beam = Beam(num_particles=1) + assert beam.num_bunches_in_train == 1 + assert beam.bunch_separation == 0.0 + assert beam.trackable_number == -1 + assert beam.stage_number == 0 + assert beam.location == 0 + + +@pytest.mark.beam +def test_set_phase_space(): + "Verify that the phase space is set correctly." + beam = Beam() + xs = np.random.rand(1000) + ys = np.random.rand(1000) + zs = np.random.rand(1000) + uxs = np.random.rand(1000) + uys = np.random.rand(1000) + uzs = np.random.rand(1000) + Q = -SI.e * 1.0e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + assert len(beam) == 1000 + assert np.allclose(beam.xs(), xs) + assert np.allclose(beam.ys(), ys) + assert np.allclose(beam.zs(), zs) + assert np.allclose(beam.uxs(), uxs) + assert np.allclose(beam.uys(), uys) + assert np.allclose(beam.uzs(), uzs) + assert np.allclose(beam.qs(), np.ones_like(xs)*Q/1000) + assert np.allclose(beam.charge(), Q) + assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/1000/(-SI.e)) + + +@pytest.mark.beam +def test_reset_phase_space(): + "Test reset_phase_space to ensure it initializes an 8xN zero matrix for the specified number of particles." + beam = Beam() + beam.reset_phase_space(10) + assert beam._Beam__phasespace.shape == (8, 10) + assert (beam._Beam__phasespace == 0).all() + + +@pytest.mark.beam +def test_delitem(): + "Test deleting macroparticles by indices or masks." + beam = Beam() + beam.reset_phase_space(5) + beam.__delitem__([0, 2]) + assert beam._Beam__phasespace.shape[1] == 3 # Two particles removed + + +@pytest.mark.beam +def test_remove_nans(): + "Verify that remove_nans removes particles with any NaN value." + beam = Beam() + beam.reset_phase_space(10) + beam._Beam__phasespace[0, 1] = float('nan') # Introduce NaN in one particle + beam._Beam__phasespace[0, 4] = float('nan') # Introduce NaN in one particle + beam._Beam__phasespace[1, 4] = float('nan') # Introduce NaN in one particle + beam._Beam__phasespace[1, 5] = float('nan') # Introduce NaN in one particle + beam._Beam__phasespace[5, 7] = float('nan') # Introduce NaN in one particle + beam.remove_nans() + assert len(beam) == 6 + + +@pytest.mark.beam +def test_add_beams(): + "Test the __add__ operator." + beam1 = Beam() + num_particles1 = 1021 + beam1.reset_phase_space(num_particles1) + beam2 = Beam() + num_particles2 = 42 + beam2.reset_phase_space(num_particles2) + beam3 = beam1 + beam2 + assert len(beam3) == num_particles1 + num_particles2 + + +@pytest.mark.beam +def test_iadd_beams(): + "Test the __iadd__ operator." + beam1 = Beam() + num_particles1 = 3044 + beam1.reset_phase_space(num_particles1) + beam2 = Beam() + num_particles2 = 4444 + beam2.reset_phase_space(num_particles2) + beam1 += beam2 + assert len(beam1) == num_particles1 + num_particles2 + + +@pytest.mark.beam +def test_getitem(): + "Test retrieving a single particle's data by index." + + beam = Beam() + xs = np.random.rand(1000) + ys = np.random.rand(1000) + zs = np.random.rand(1000) + Q = -SI.e * 1.0e10 + beam.set_phase_space(Q, xs, ys, zs) + random_integer = random.randint(0, 999) + particle = beam[random_integer] + assert particle.shape == (8,) + assert np.allclose(particle[0], xs[random_integer]) + assert np.allclose(particle[1], ys[random_integer]) + assert np.allclose(particle[2], zs[random_integer]) + + +@pytest.mark.beam +def test_len(): + "Verify that __len__ returns the correct number of particles." + random_integer = random.randint(0, 30000) + beam = Beam() + beam.reset_phase_space(random_integer) + assert len(beam) == random_integer + + +# @pytest.mark.beam +# def test_str(): +# "Test the __str__ method for correct formatting of beam properties." +# beam = Beam() +# beam.reset_phase_space(5) +# string_repr = str(beam) +# assert "Beam:" in string_repr +# assert "5 macroparticles" in string_repr + + +@pytest.mark.beam +def test_copy_particle_charge(): + + num_particles = 8051 + + beam1 = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = np.random.rand(num_particles) + Q = -SI.e * 1.0e10 + beam1.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + beam2 = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = np.random.rand(num_particles) + Q = -SI.e * 3.4e10 + ws = np.random.rand(num_particles)*Q/(-SI.e) + beam2.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs, weightings=ws) + median_charge = np.median(beam2._Beam__phasespace[6, :]) # Extract expected median charge + + beam1.copy_particle_charge(beam2) + assert (beam1._Beam__phasespace[6, :] == median_charge).all() # Verify charge is copied correctly + + +# def test_scale_charge(): +# "Test correct scaling of particle charges, scaling to a larger or smaller total charge. Edge case: scaling to zero charge." + +# beam = Beam() +# beam.set_phase_space(1e-9, [1.0, 2.0], [0.5, 1.5], [0.2, 0.3]) # Total charge = 1e-9 C +# original_charges = beam._Beam__phasespace[6, :].copy() + +# # Scale up charge +# beam.scale_charge(2e-9) # Scale to 2 nC +# scaled_charges = beam._Beam__phasespace[6, :] +# assert np.isclose(scaled_charges.sum(), 2e-9) # Check total charge +# assert np.allclose(scaled_charges / original_charges, 2.0) # Charges scaled proportionally + +# # Scale down charge +# beam.scale_charge(5e-10) # Scale to 0.5 nC +# scaled_charges = beam._Beam__phasespace[6, :] +# assert np.isclose(scaled_charges.sum(), 5e-10) + +# # Edge case: zero charge +# beam.scale_charge(0) +# scaled_charges = beam._Beam__phasespace[6, :] +# assert np.isclose(scaled_charges.sum(), 0) + + +# def test_scale_energy(): +# "Test correct scaling of particle energies, scaling to a higher or lower total energy. Edge case: scaling to zero energy." + +# beam = Beam() +# beam.set_phase_space(1e-9, [1.0, 2.0], [0.5, 1.5], [0.2, 0.3], Es=[1e6, 2e6]) # Initialize with energies in eV +# original_energies = beam._Beam__phasespace[5, :].copy() # Assuming energy stored in index 5 + +# # Scale up energy +# beam.scale_energy(4e6) # Scale total energy to 4 MeV +# scaled_energies = beam._Beam__phasespace[5, :] +# assert np.isclose(scaled_energies.sum(), 4e6) +# assert np.allclose(scaled_energies / original_energies, 2.0) # Energies scaled proportionally + +# # Scale down energy +# beam.scale_energy(1e6) # Scale total energy to 1 MeV +# scaled_energies = beam._Beam__phasespace[5, :] +# assert np.isclose(scaled_energies.sum(), 1e6) + +# # Edge case: zero energy +# try: +# beam.scale_energy(0) +# except ValueError as e: +# assert str(e) == "Energy cannot be scaled to zero" + + +############# Tests on bunch pattern ############# + + + + +############# ... ############# \ No newline at end of file From 0e7d7d9383d6edb14c22a09097e63e330ec25fb7 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Fri, 21 Mar 2025 00:51:02 +0100 Subject: [PATCH 05/51] Small change in Beam.copy_particle_charge() to handle one of the beams being empty. --- abel/classes/beam.py | 2 ++ tests/test_beam.py | 45 +++++++++++++++++++++++--------------------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/abel/classes/beam.py b/abel/classes/beam.py index 5ee240b0..80d87f9f 100644 --- a/abel/classes/beam.py +++ b/abel/classes/beam.py @@ -194,6 +194,8 @@ def weightings(self): # copy another beam's macroparticle charge def copy_particle_charge(self, beam): + if beam.__phasespace is None or self.__phasespace is None: + raise ValueError('One of the beams is empty.') self.set_qs(np.median(beam.qs())) def scale_charge(self, Q): diff --git a/tests/test_beam.py b/tests/test_beam.py index 26af401b..5577ae68 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -189,28 +189,31 @@ def test_copy_particle_charge(): assert (beam1._Beam__phasespace[6, :] == median_charge).all() # Verify charge is copied correctly -# def test_scale_charge(): -# "Test correct scaling of particle charges, scaling to a larger or smaller total charge. Edge case: scaling to zero charge." +def test_scale_charge(): + "Test correct scaling of particle charges, scaling to a larger or smaller total charge. Edge case: scaling to zero charge." -# beam = Beam() -# beam.set_phase_space(1e-9, [1.0, 2.0], [0.5, 1.5], [0.2, 0.3]) # Total charge = 1e-9 C -# original_charges = beam._Beam__phasespace[6, :].copy() - -# # Scale up charge -# beam.scale_charge(2e-9) # Scale to 2 nC -# scaled_charges = beam._Beam__phasespace[6, :] -# assert np.isclose(scaled_charges.sum(), 2e-9) # Check total charge -# assert np.allclose(scaled_charges / original_charges, 2.0) # Charges scaled proportionally - -# # Scale down charge -# beam.scale_charge(5e-10) # Scale to 0.5 nC -# scaled_charges = beam._Beam__phasespace[6, :] -# assert np.isclose(scaled_charges.sum(), 5e-10) - -# # Edge case: zero charge -# beam.scale_charge(0) -# scaled_charges = beam._Beam__phasespace[6, :] -# assert np.isclose(scaled_charges.sum(), 0) + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + Q = -SI.e * 1.0e10 + beam.set_phase_space(Q, xs, ys, zs) + original_charges = copy.deepcopy(beam.qs()) + + # Scale up charge + beam.scale_charge(-SI.e * 2.0e10) + scaled_charges = beam.qs() + assert np.isclose(scaled_charges.sum(), -SI.e * 2.0e10) # Check total charge + assert np.allclose(scaled_charges / original_charges, 2.0) # Charges scaled proportionally + + # Scale down charge + beam.scale_charge(-SI.e * 0.5e10) + assert np.isclose(scaled_charges.sum(), -SI.e * 0.5e10) + + # Edge case: zero charge + beam.scale_charge(0) + scaled_charges = beam.qs() + assert np.isclose(scaled_charges.sum(), 0) # def test_scale_energy(): From 9543833c1b1d0f1d672cafaad70e3f50ba03a1cd Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Fri, 21 Mar 2025 00:52:46 +0100 Subject: [PATCH 06/51] Added more tests in test_beam.py. --- tests/test_beam.py | 54 +++++++++++++++++++++++++++------------------- 1 file changed, 32 insertions(+), 22 deletions(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index 5577ae68..dd4992f0 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -193,6 +193,7 @@ def test_scale_charge(): "Test correct scaling of particle charges, scaling to a larger or smaller total charge. Edge case: scaling to zero charge." beam = Beam() + num_particles = 4352 xs = np.random.rand(num_particles) ys = np.random.rand(num_particles) zs = np.random.rand(num_particles) @@ -216,29 +217,38 @@ def test_scale_charge(): assert np.isclose(scaled_charges.sum(), 0) -# def test_scale_energy(): -# "Test correct scaling of particle energies, scaling to a higher or lower total energy. Edge case: scaling to zero energy." +def test_scale_energy(): + "Test correct scaling of particle energies, scaling to a higher or lower total energy. Edge case: scaling to zero energy." -# beam = Beam() -# beam.set_phase_space(1e-9, [1.0, 2.0], [0.5, 1.5], [0.2, 0.3], Es=[1e6, 2e6]) # Initialize with energies in eV -# original_energies = beam._Beam__phasespace[5, :].copy() # Assuming energy stored in index 5 - -# # Scale up energy -# beam.scale_energy(4e6) # Scale total energy to 4 MeV -# scaled_energies = beam._Beam__phasespace[5, :] -# assert np.isclose(scaled_energies.sum(), 4e6) -# assert np.allclose(scaled_energies / original_energies, 2.0) # Energies scaled proportionally - -# # Scale down energy -# beam.scale_energy(1e6) # Scale total energy to 1 MeV -# scaled_energies = beam._Beam__phasespace[5, :] -# assert np.isclose(scaled_energies.sum(), 1e6) - -# # Edge case: zero energy -# try: -# beam.scale_energy(0) -# except ValueError as e: -# assert str(e) == "Energy cannot be scaled to zero" + beam = Beam() + num_particles = 4352 + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + #Es = np.ones_like(num_particles) * 1e9 + Es = np.random.normal(1e9, 0.02*1e9, num_particles) + Q = -SI.e * 1.0e10 + beam.set_phase_space(Q, xs, ys, zs, Es=Es) + original_energies = copy.deepcopy(beam.Es()) + + # Scale up energy + beam.scale_energy(4e9) + scaled_energies = beam.Es() + scaled_mean_energy = weighted_mean(scaled_energies, beam.weightings()) + assert np.isclose(scaled_mean_energy, 4e9, rtol=0.01, atol=1e8) + assert np.allclose(scaled_energies / original_energies, 4.0, rtol=0.01, atol=0.1) # Energies scaled proportionally + + # Scale down energy + beam.scale_energy(1.7e8) + scaled_energies = beam.Es() + scaled_mean_energy = weighted_mean(scaled_energies, beam.weightings()) + assert np.isclose(scaled_mean_energy, 1.7e8, rtol=0.01, atol=1e8) + + # # Edge case: zero energy + # try: + # beam.scale_energy(0) + # except ValueError as e: + # assert str(e) == "Energy cannot be scaled to zero" ############# Tests on bunch pattern ############# From 5eae0e884c093c6882b065b49d9cc7eea8fc07b5 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Mon, 24 Mar 2025 16:01:54 +0100 Subject: [PATCH 07/51] Added Beam class initiation tests to test_beam.py and added another tag to pyproject.toml. --- pyproject.toml | 1 + tests/test_beam.py | 136 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 125 insertions(+), 12 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8fd3fb88..b346be53 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -52,4 +52,5 @@ markers = [ "core: Test core functionality", "stageGeometry: Test stage geometry calculation functionality", "sources: Test the various Source subclasses generate beams with desired properties", + "beam: Tests for the Beam class", ] diff --git a/tests/test_beam.py b/tests/test_beam.py index dd4992f0..44436355 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -42,25 +42,136 @@ def test_initialization(): def test_set_phase_space(): "Verify that the phase space is set correctly." beam = Beam() - xs = np.random.rand(1000) - ys = np.random.rand(1000) - zs = np.random.rand(1000) - uxs = np.random.rand(1000) - uys = np.random.rand(1000) - uzs = np.random.rand(1000) + num_particles = 10042 + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = np.random.rand(num_particles) Q = -SI.e * 1.0e10 beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) - assert len(beam) == 1000 + assert len(beam) == num_particles + assert np.isclose(beam.particle_mass, SI.m_e) assert np.allclose(beam.xs(), xs) assert np.allclose(beam.ys(), ys) assert np.allclose(beam.zs(), zs) assert np.allclose(beam.uxs(), uxs) assert np.allclose(beam.uys(), uys) assert np.allclose(beam.uzs(), uzs) - assert np.allclose(beam.qs(), np.ones_like(xs)*Q/1000) - assert np.allclose(beam.charge(), Q) - assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/1000/(-SI.e)) + assert np.allclose(beam.qs(), np.ones_like(xs)*Q/num_particles) + assert np.isclose(beam.charge(), Q) + assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/num_particles/(-SI.e)) + + assert np.allclose(beam.xps(), uxs/uzs) + assert np.allclose(beam.yps(), uys/uzs) + assert np.allclose(beam.pxs(), SI.m_e*uxs) + assert np.allclose(beam.pys(), SI.m_e*uys) + assert np.allclose(beam.pzs(), SI.m_e*uzs) + assert np.allclose(beam.Es(), np.sqrt((SI.m_e*uzs*SI.c)**2 + (SI.m_e*SI.c**2)**2)/SI.e ) + + +@pytest.mark.beam +def test_set_phase_space2(): + "Verify that the phase space is set correctly." + beam = Beam() + num_particles = 10042 + xs = np.random.normal(0.0, 2.0e-6, num_particles) + ys = np.random.normal(0.0, 1.0e-6, num_particles) + zs = np.random.normal(0.0, 50.0e-6, num_particles) + xps = np.random.normal(0.0, 1.5e-4, num_particles) + yps = np.random.normal(0.0, 1.0e-5, num_particles) + Es = np.random.normal(500e9, 0.02*500e9, num_particles) + Q = -SI.e * 1.0e10 + beam.set_phase_space(Q, xs, ys, zs, xps=xps, yps=yps, Es=Es) + + assert len(beam) == num_particles + assert np.isclose(beam.particle_mass, SI.m_e) + assert np.allclose(beam.xs(), xs) + assert np.allclose(beam.ys(), ys) + assert np.allclose(beam.zs(), zs) + assert np.allclose(beam.xps(), xps, rtol=1e-05, atol=1e-08) + assert np.allclose(beam.yps(), yps, rtol=1e-05, atol=1e-08) + assert np.allclose(beam.Es(), Es) + assert np.allclose(beam.qs(), np.ones_like(xs)*Q/num_particles) + assert np.isclose(beam.charge(), Q) + assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/num_particles/(-SI.e)) + + assert np.allclose(beam.uzs(), np.sqrt((Es*SI.e/SI.m_e/SI.c)**2 - SI.c**2) ) + assert np.allclose(beam.uxs(), xps*beam.uzs()) + assert np.allclose(beam.uys(), yps*beam.uzs()) + assert np.allclose(beam.pxs(), SI.m_e*xps*beam.uzs(), rtol=1e-05, atol=1e-25) + assert np.allclose(beam.pys(), SI.m_e*yps*beam.uzs(), rtol=1e-05, atol=1e-25) + assert np.allclose(beam.pzs(), SI.m_e*beam.uzs(), rtol=1e-05, atol=1e-19) + + +@pytest.mark.beam +def test_set_phase_space3(): + "Verify that the phase space is set correctly." + beam = Beam() + num_particles = 10042 + xs = np.random.normal(1.0, 2.4e-6, num_particles) + ys = np.random.normal(0.3, 1.1e-6, num_particles) + zs = np.random.normal(10.0, 42.0e-6, num_particles) + pxs = np.random.normal(0.0, 5.0e-22, num_particles) + pys = np.random.normal(0.0, 5.0e-23, num_particles) + pzs = np.random.normal(2.67e-16, 5.4e-18, num_particles) # Corresponds to 500 GeV. + Q = -SI.e * 1.0e10 + beam.set_phase_space(Q, xs, ys, zs, pxs=pxs, pys=pys, pzs=pzs) + + assert len(beam) == num_particles + assert np.isclose(beam.particle_mass, SI.m_e) + assert np.allclose(beam.xs(), xs) + assert np.allclose(beam.ys(), ys) + assert np.allclose(beam.zs(), zs) + assert np.allclose(beam.pxs(), pxs, rtol=1e-05, atol=1e-25) + assert np.allclose(beam.pys(), pys, rtol=1e-05, atol=1e-25) + assert np.allclose(beam.pzs(), pzs, rtol=1e-05, atol=1e-19) + assert np.allclose(beam.qs(), np.ones_like(xs)*Q/num_particles) + assert np.isclose(beam.charge(), Q) + assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/num_particles/(-SI.e)) + + assert np.allclose(beam.xps(), pxs/pzs) + assert np.allclose(beam.yps(), pys/pzs) + assert np.allclose(beam.uxs(), pxs/SI.m_e) + assert np.allclose(beam.uys(), pys/SI.m_e) + assert np.allclose(beam.uzs(), pzs/SI.m_e) + assert np.allclose(beam.Es(), np.sqrt((pzs*SI.c)**2 + (SI.m_e*SI.c**2)**2)/SI.e ) + + +@pytest.mark.beam +def test_set_phase_space4(): + "Verify that the phase space is set correctly." + beam = Beam() + num_particles = 10042 + xs = np.random.normal(0.0, 2.0e-6, num_particles) + ys = np.random.normal(0.0, 1.0e-6, num_particles) + zs = np.random.normal(0.0, 50.0e-6, num_particles) + uxs = np.random.normal(0.0, 250.0e6, num_particles) + yps = np.random.normal(0.0, 1.0e-5, num_particles) + pzs = np.random.normal(1.6e-18, 3.0e-20, num_particles) + Q = -SI.e * 1.0e10 + beam.set_phase_space(Q, xs, ys, zs, uxs=uxs, yps=yps, pzs=pzs) + + assert len(beam) == num_particles + assert np.isclose(beam.particle_mass, SI.m_e) + assert np.allclose(beam.xs(), xs) + assert np.allclose(beam.ys(), ys) + assert np.allclose(beam.zs(), zs) + assert np.allclose(beam.uxs(), uxs) + assert np.allclose(beam.yps(), yps) + assert np.allclose(beam.pzs(), pzs, rtol=1e-05, atol=1e-25) + assert np.allclose(beam.qs(), np.ones_like(xs)*Q/num_particles) + assert np.isclose(beam.charge(), Q) + assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/num_particles/(-SI.e)) + + assert np.allclose(beam.uzs(), pzs/SI.m_e) + assert np.allclose(beam.xps(), uxs/beam.uzs()) + assert np.allclose(beam.uys(), yps*beam.uzs()) + assert np.allclose(beam.pxs(), SI.m_e*uxs, rtol=1e-05, atol=1e-25) + assert np.allclose(beam.pys(), SI.m_e*yps*beam.uzs(), rtol=1e-05, atol=1e-25) + assert np.allclose(beam.Es(), np.sqrt((pzs*SI.c)**2 + (SI.m_e*SI.c**2)**2)/SI.e ) @pytest.mark.beam @@ -189,6 +300,7 @@ def test_copy_particle_charge(): assert (beam1._Beam__phasespace[6, :] == median_charge).all() # Verify charge is copied correctly +@pytest.mark.beam def test_scale_charge(): "Test correct scaling of particle charges, scaling to a larger or smaller total charge. Edge case: scaling to zero charge." @@ -217,6 +329,7 @@ def test_scale_charge(): assert np.isclose(scaled_charges.sum(), 0) +@pytest.mark.beam def test_scale_energy(): "Test correct scaling of particle energies, scaling to a higher or lower total energy. Edge case: scaling to zero energy." @@ -225,7 +338,6 @@ def test_scale_energy(): xs = np.random.rand(num_particles) ys = np.random.rand(num_particles) zs = np.random.rand(num_particles) - #Es = np.ones_like(num_particles) * 1e9 Es = np.random.normal(1e9, 0.02*1e9, num_particles) Q = -SI.e * 1.0e10 beam.set_phase_space(Q, xs, ys, zs, Es=Es) @@ -256,4 +368,4 @@ def test_scale_energy(): -############# ... ############# \ No newline at end of file +############# Tests of rotation methods ############# \ No newline at end of file From bcc9aa7a7a6824f03cbfc6c0c727b519ff89075d Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Mon, 24 Mar 2025 16:02:41 +0100 Subject: [PATCH 08/51] Edited __init__.py to add SourceCapsule. --- abel/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/abel/__init__.py b/abel/__init__.py index f5aaad51..553baebf 100644 --- a/abel/__init__.py +++ b/abel/__init__.py @@ -44,6 +44,7 @@ from .classes.source.impl.source_combiner import * from .classes.source.impl.source_from_file import * from .classes.source.impl.source_flattop import * +from .classes.source.impl.source_capsule import * from .classes.stage.impl.stage_basic import * from .classes.stage.impl.stage_nonlinear_1d import * from .classes.stage.impl.stage_hipace import * From 18887a3e936cd6d06f7892b1fa64ec3f7d56dbdc Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 25 Mar 2025 00:39:06 +0100 Subject: [PATCH 09/51] Added a function for setting up a SourceBasic in test_beam.py. Also added more subtests to the Beam initialisation tests. --- tests/test_beam.py | 81 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 69 insertions(+), 12 deletions(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index 44436355..260d0e3c 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -25,6 +25,34 @@ import random +def setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, bunch_length=40.0e-06, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0): + main = SourceBasic() + main.bunch_length = bunch_length # [m], rms. Standard value + main.num_particles = 10000 + main.charge = -e * 1.0e10 # [C] + + # Energy parameters + main.energy = energy # [eV], HALHF v2 last stage nominal input energy + main.rel_energy_spread = 0.02 # Relative rms energy spread + + # Emittances + main.emit_nx, main.emit_ny = 15e-6, 0.1e-6 # [m rad] + + # Beta functions + main.beta_x = beta_matched(plasma_density, main.energy) * ramp_beta_mag # [m] + main.beta_y = main.beta_x # [m] + + # Offsets + main.z_offset = z_offset # [m] + main.x_offset = x_offset # [m] + main.y_offset = y_offset # [m] + + # Other + main.symmetrize_6d = True + + return main + + ############# Basic tests ############# @pytest.mark.beam @@ -54,6 +82,8 @@ def test_set_phase_space(): assert len(beam) == num_particles assert np.isclose(beam.particle_mass, SI.m_e) + assert np.isclose(beam.charge(), Q) + assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/num_particles/(-SI.e)) assert np.allclose(beam.xs(), xs) assert np.allclose(beam.ys(), ys) assert np.allclose(beam.zs(), zs) @@ -61,8 +91,7 @@ def test_set_phase_space(): assert np.allclose(beam.uys(), uys) assert np.allclose(beam.uzs(), uzs) assert np.allclose(beam.qs(), np.ones_like(xs)*Q/num_particles) - assert np.isclose(beam.charge(), Q) - assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/num_particles/(-SI.e)) + assert np.allclose(beam.xps(), uxs/uzs) assert np.allclose(beam.yps(), uys/uzs) @@ -77,17 +106,34 @@ def test_set_phase_space2(): "Verify that the phase space is set correctly." beam = Beam() num_particles = 10042 - xs = np.random.normal(0.0, 2.0e-6, num_particles) - ys = np.random.normal(0.0, 1.0e-6, num_particles) - zs = np.random.normal(0.0, 50.0e-6, num_particles) - xps = np.random.normal(0.0, 1.5e-4, num_particles) - yps = np.random.normal(0.0, 1.0e-5, num_particles) + xs = np.random.normal(1.1, 2.0e-6, num_particles) + ys = np.random.normal(0.3, 1.0e-6, num_particles) + zs = np.random.normal(5.6, 50.0e-6, num_particles) + xps = np.random.normal(1.1e-5, 1.5e-7, num_particles) + yps = np.random.normal(3.2e-6, 1.0e-8, num_particles) Es = np.random.normal(500e9, 0.02*500e9, num_particles) + #weightings = # TODO: make an array for varying weightings Q = -SI.e * 1.0e10 beam.set_phase_space(Q, xs, ys, zs, xps=xps, yps=yps, Es=Es) assert len(beam) == num_particles assert np.isclose(beam.particle_mass, SI.m_e) + assert np.isclose(beam.charge(), Q) + assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/num_particles/(-SI.e)) + assert np.isclose(beam.energy(), 500e9, rtol=0.0001*500e9, atol=1e9) + assert np.isclose(beam.gamma(), 500e9*SI.e/SI.m_e/SI.c**2, rtol=0.0001*500e9*SI.e/SI.m_e/SI.c**2, atol=200) + assert np.isclose(beam.rel_energy_spread(), 0.02, rtol=0.001, atol=0.001) + assert np.isclose(beam.z_offset(), 5.6) + assert np.isclose(beam.x_offset(), 1.1) + assert np.isclose(beam.y_offset(), 0.3) + assert np.isclose(beam.bunch_length(), 50.0e-6, rtol=0.005, atol=0.03) + assert np.isclose(beam.beam_size_x(), 2.0e-6, rtol=0.005, atol=0.03) + assert np.isclose(beam.beam_size_y(), 1.0e-6, rtol=0.005, atol=0.03) + assert np.isclose(beam.x_angle(), 1.1e-5) + assert np.isclose(beam.y_angle(), 3.2e-6) + assert np.isclose(beam.divergence_x(), 1.5e-7) + assert np.isclose(beam.divergence_y(), 1.0e-8) + assert np.allclose(beam.xs(), xs) assert np.allclose(beam.ys(), ys) assert np.allclose(beam.zs(), zs) @@ -95,8 +141,6 @@ def test_set_phase_space2(): assert np.allclose(beam.yps(), yps, rtol=1e-05, atol=1e-08) assert np.allclose(beam.Es(), Es) assert np.allclose(beam.qs(), np.ones_like(xs)*Q/num_particles) - assert np.isclose(beam.charge(), Q) - assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/num_particles/(-SI.e)) assert np.allclose(beam.uzs(), np.sqrt((Es*SI.e/SI.m_e/SI.c)**2 - SI.c**2) ) assert np.allclose(beam.uxs(), xps*beam.uzs()) @@ -122,6 +166,8 @@ def test_set_phase_space3(): assert len(beam) == num_particles assert np.isclose(beam.particle_mass, SI.m_e) + assert np.isclose(beam.charge(), Q) + assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/num_particles/(-SI.e)) assert np.allclose(beam.xs(), xs) assert np.allclose(beam.ys(), ys) assert np.allclose(beam.zs(), zs) @@ -129,8 +175,6 @@ def test_set_phase_space3(): assert np.allclose(beam.pys(), pys, rtol=1e-05, atol=1e-25) assert np.allclose(beam.pzs(), pzs, rtol=1e-05, atol=1e-19) assert np.allclose(beam.qs(), np.ones_like(xs)*Q/num_particles) - assert np.isclose(beam.charge(), Q) - assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/num_particles/(-SI.e)) assert np.allclose(beam.xps(), pxs/pzs) assert np.allclose(beam.yps(), pys/pzs) @@ -368,4 +412,17 @@ def test_scale_energy(): -############# Tests of rotation methods ############# \ No newline at end of file +############# Tests of rotation methods ############# + +#def test_x_tilt_angle(): + +def test_rotate_coord_sys_3D(): + "Test correct rotation of beam coordinate system." + + source = setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0) + beam = source.track() + x_axis = np.array([0, 1, 0]) # Axis as an unit vector. Axis permutaton is zxy. + y_axis = np.array([0, 0, 1]) + + beam.rotate_coord_sys_3D(y_axis, np.pi/2, x_axis, 0.0, invert=False) # Rotate beam 90 degrees around the y-axis. + assert np.isclose(beam.x_tilt_angle(), np.pi/2) \ No newline at end of file From 1e4f5c0f793a68eb78d8e09f65625082c3519290 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 25 Mar 2025 01:45:21 +0100 Subject: [PATCH 10/51] Saving some tests for beam coordinate rotation. Work in progress... --- tests/test_beam.py | 52 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index 260d0e3c..a335791d 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -112,7 +112,7 @@ def test_set_phase_space2(): xps = np.random.normal(1.1e-5, 1.5e-7, num_particles) yps = np.random.normal(3.2e-6, 1.0e-8, num_particles) Es = np.random.normal(500e9, 0.02*500e9, num_particles) - #weightings = # TODO: make an array for varying weightings + #weightings = # TODO: make an array with varying weightings Q = -SI.e * 1.0e10 beam.set_phase_space(Q, xs, ys, zs, xps=xps, yps=yps, Es=Es) @@ -413,8 +413,51 @@ def test_scale_energy(): ############# Tests of rotation methods ############# +# def test_slice_centroids(): +# source = setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0) +# beam = source.track() +# beam_quant = beam.xs() # Use x positions as the beam quantity +# x_slices, z_centroids = beam.slice_centroids(beam_quant, bin_number=5) + +# # Check that the output shapes are correct +# assert x_slices.shape[0] == z_centroids.shape[0] +# assert len(x_slices) == 5 # Should match the number of bins + +# # Check that the centroids are within the expected range +# assert np.all(z_centroids >= 0) +# assert np.all(z_centroids <= 10) + + +def test_x_tilt_angle(): + "Test the retrieval of the beam tilt angle in the zx-plane." + source = setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0) + beam = source.track() + nominal_x_angle = random.uniform(-np.pi/2, np.pi/2) + beam.set_xs(beam.zs() * np.tan(nominal_x_angle)) # Add a tilt in x + x_angle = beam.x_tilt_angle() + assert np.isclose(x_angle, nominal_x_angle, rtol=1e-7, atol=1e-3) + + +def test_y_tilt_angle(): + "Test the retrieval of the beam tilt angle in the zy-plane." + source = setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0) + beam = source.track() + nominal_y_angle = random.uniform(-np.pi/2, np.pi/2) + beam.set_ys(beam.zs() * np.tan(nominal_y_angle)) # Add a tilt in x + y_angle = beam.y_tilt_angle() + assert np.isclose(y_angle, nominal_y_angle, rtol=1e-7, atol=1e-3) + + +def test_xy_rotate_coord_sys1(): + "Test correct rotation of beam coordinate system around the y-axis." + source = setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0) + beam = source.track() + old_beam = copy.deepcopy(beam) + nom_x_angle = random.uniform(-np.pi/2, np.pi/2) + beam.xy_rotate_coord_sys(x_angle=nom_x_angle, y_angle=None, invert=False) + assert np.allclose(beam.xs(), -old_beam.zs()*np.sin(nom_x_angle) + old_beam.xs()*np.cos(nom_x_angle), rtol=1e-7, atol=1e-13) + assert np.allclose(beam.zs(), old_beam.zs()*np.cos(nom_x_angle) + old_beam.xs()*np.sin(nom_x_angle), rtol=1e-7, atol=1e-13) -#def test_x_tilt_angle(): def test_rotate_coord_sys_3D(): "Test correct rotation of beam coordinate system." @@ -424,5 +467,6 @@ def test_rotate_coord_sys_3D(): x_axis = np.array([0, 1, 0]) # Axis as an unit vector. Axis permutaton is zxy. y_axis = np.array([0, 0, 1]) - beam.rotate_coord_sys_3D(y_axis, np.pi/2, x_axis, 0.0, invert=False) # Rotate beam 90 degrees around the y-axis. - assert np.isclose(beam.x_tilt_angle(), np.pi/2) \ No newline at end of file + nom_x_angle = random.uniform(-np.pi/2, np.pi/2) + beam.rotate_coord_sys_3D(y_axis, nom_x_angle, x_axis, 0.0, invert=False) # Rotate beam 90 degrees around the y-axis. + assert np.isclose(beam.x_tilt_angle(), nom_x_angle) \ No newline at end of file From 02a45a7046d313aed3337a2c001174a384687e37 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 25 Mar 2025 18:07:19 +0100 Subject: [PATCH 11/51] Added controls to the Beam class to ensure that energy, longitudinal proper velocity and momentum are above a given threshold. Also added controls for the number of particles, number of bunches in a train and bunch separation. --- abel/classes/beam.py | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/abel/classes/beam.py b/abel/classes/beam.py index 80d87f9f..d28759fa 100644 --- a/abel/classes/beam.py +++ b/abel/classes/beam.py @@ -5,7 +5,7 @@ from abel.CONFIG import CONFIG from types import SimpleNamespace import scipy.constants as SI -from abel.utilities.relativity import energy2proper_velocity, proper_velocity2energy, momentum2proper_velocity, proper_velocity2momentum, proper_velocity2gamma, energy2gamma, gamma2proper_velocity +from abel.utilities.relativity import energy2proper_velocity, proper_velocity2energy, momentum2proper_velocity, proper_velocity2momentum, proper_velocity2gamma, energy2gamma, gamma2momentum from abel.utilities.statistics import weighted_mean, weighted_std, weighted_cov from abel.utilities.plasma_physics import k_p, wave_breaking_field, beta_matched from abel.physics_models.hills_equation import evolve_hills_equation_analytic @@ -21,6 +21,14 @@ class Beam(): def __init__(self, phasespace=None, num_particles=1000, num_bunches_in_train=1, bunch_separation=0.0): + # check the inputs + if num_particles < 1: + raise ValueError('num_particles cannot be lower than 1.') + if num_bunches_in_train < 1: + raise ValueError('num_bunches_in_train cannot be lower than 1.') + if bunch_separation < 0.0: + raise ValueError('bunch_separation cannot be negative.') + # the phase space variable is private if phasespace is not None: self.__phasespace = phasespace @@ -38,6 +46,9 @@ def __init__(self, phasespace=None, num_particles=1000, num_bunches_in_train=1, # reset phase space def reset_phase_space(self, num_particles): + if num_particles < 1: + raise ValueError('num_particles cannot be lower than 1.') + self.__phasespace = np.zeros((8, num_particles)) # filter out macroparticles based on a mask (true means delete) @@ -62,13 +73,27 @@ def set_phase_space(self, Q, xs, ys, zs, uxs=None, uys=None, uzs=None, pxs=None, self.set_xs(xs) self.set_ys(ys) self.set_zs(zs) + + # minimum thresholds for energy, uz and pz + energy_thres = 100*particle_mass*SI.c**2/SI.e # [eV], 100 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=particle_mass) + pz_thres = gamma2momentum(energy2gamma(energy_thres, unit='eV', m=particle_mass)) # add momenta if uzs is None: + if pzs is not None: + if np.any(pzs < pz_thres): + raise ValueError('pzs contains values that are too small.') uzs = momentum2proper_velocity(pzs) + elif Es is not None: + if np.any(Es < energy_thres): + raise ValueError('Es contains values that are too small.') uzs = energy2proper_velocity(Es) + else: + if np.any(uzs < uz_thres): + raise ValueError('uzs contains values that are too small.') self.__phasespace[5,:] = uzs if uxs is None: @@ -175,6 +200,10 @@ def set_uxs(self, uxs): def set_uys(self, uys): self.__phasespace[4,:] = uys def set_uzs(self, uzs): + energy_thres = 100*self.particle_mass*SI.c**2/SI.e # [eV], 100 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=self.particle_mass) + if np.any(uzs < uz_thres): + raise ValueError('uzs contains values that are too small.') self.__phasespace[5,:] = uzs def set_xps(self, xps): @@ -182,6 +211,9 @@ def set_xps(self, xps): def set_yps(self, yps): self.set_uys(yps*self.uzs()) def set_Es(self, Es): + energy_thres = 100*self.particle_mass*SI.c**2/SI.e # [eV], 100 * particle rest energy. + if np.any(Es < energy_thres): + raise ValueError('Es contains values that are too small.') self.set_uzs(energy2proper_velocity(Es)) def set_qs(self, qs): @@ -423,7 +455,7 @@ def beam_alignment_angles(self): Parameters ---------- - ... + N/A Returns @@ -468,7 +500,7 @@ def beam_alignment_angles(self): # ================================================== def xy_rotate_coord_sys(self, x_angle=None, y_angle=None, invert=False): """ - Rotates the coordinate system of the beam first with x_angle around the y-axis then with y_angle around the x-axis. + Rotates the coordinate system of the beam first with ``x_angle`` around the y-axis then with ``y_angle`` around the x-axis. Parameters ---------- From 05610948b421b2b58e601b8790985c00a8cc27fc Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 25 Mar 2025 18:10:10 +0100 Subject: [PATCH 12/51] Edited tests in test_beam.py to meet the requirement of energy, longitudinal proper velocity and momentum being above a given threshold. Also some more edts on the rotation tests. --- tests/test_beam.py | 67 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 17 deletions(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index a335791d..c3070f66 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -27,7 +27,7 @@ def setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, bunch_length=40.0e-06, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0): main = SourceBasic() - main.bunch_length = bunch_length # [m], rms. Standard value + main.bunch_length = bunch_length # [m], rms. main.num_particles = 10000 main.charge = -e * 1.0e10 # [C] @@ -71,13 +71,17 @@ def test_set_phase_space(): "Verify that the phase space is set correctly." beam = Beam() num_particles = 10042 + Q = -SI.e * 1.0e10 xs = np.random.rand(num_particles) ys = np.random.rand(num_particles) zs = np.random.rand(num_particles) uxs = np.random.rand(num_particles) uys = np.random.rand(num_particles) - uzs = np.random.rand(num_particles) - Q = -SI.e * 1.0e10 + + energy_thres = 1001*SI.m_e*SI.c**2/SI.e # [eV], 1000 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + uzs = random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e)) + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) assert len(beam) == num_particles @@ -92,7 +96,6 @@ def test_set_phase_space(): assert np.allclose(beam.uzs(), uzs) assert np.allclose(beam.qs(), np.ones_like(xs)*Q/num_particles) - assert np.allclose(beam.xps(), uxs/uzs) assert np.allclose(beam.yps(), uys/uzs) assert np.allclose(beam.pxs(), SI.m_e*uxs) @@ -297,10 +300,10 @@ def test_getitem(): @pytest.mark.beam def test_len(): "Verify that __len__ returns the correct number of particles." - random_integer = random.randint(0, 30000) + num_particles = 30001 beam = Beam() - beam.reset_phase_space(random_integer) - assert len(beam) == random_integer + beam.reset_phase_space(num_particles) + assert len(beam) == num_particles # @pytest.mark.beam @@ -317,14 +320,16 @@ def test_len(): def test_copy_particle_charge(): num_particles = 8051 - + energy_thres = 1001*SI.m_e*SI.c**2/SI.e # [eV], 1000 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + beam1 = Beam() xs = np.random.rand(num_particles) ys = np.random.rand(num_particles) zs = np.random.rand(num_particles) uxs = np.random.rand(num_particles) uys = np.random.rand(num_particles) - uzs = np.random.rand(num_particles) + uzs = random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e)) Q = -SI.e * 1.0e10 beam1.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) @@ -334,7 +339,7 @@ def test_copy_particle_charge(): zs = np.random.rand(num_particles) uxs = np.random.rand(num_particles) uys = np.random.rand(num_particles) - uzs = np.random.rand(num_particles) + uzs = random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e)) Q = -SI.e * 3.4e10 ws = np.random.rand(num_particles)*Q/(-SI.e) beam2.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs, weightings=ws) @@ -412,7 +417,14 @@ def test_scale_energy(): -############# Tests of rotation methods ############# +############# Tests of coordinate rotation methods ############# +def passive_rotate_vector(vec, x_angle, yangle): + "Rotate a vector ``vec`` with three componets (along xyz) first with ``x_angle`` around the y-axis then with ``y_angle`` around the x-axis." + rotated_z_offset = main_beam.z_offset() * np.cos(test_x_angle)*np.cos(test_y_angle) + main_beam.x_offset() * np.sin(test_x_angle)*np.cos(test_y_angle) - main_beam.y_offset() * np.sin(test_y_angle) + rotated_x_offset = -main_beam.z_offset() * np.sin(test_x_angle) + main_beam.x_offset() * np.cos(test_x_angle) + rotated_y_offset = main_beam.z_offset() * np.cos(test_x_angle)*np.sin(test_y_angle) + main_beam.x_offset() * np.sin(test_x_angle)*np.sin(test_y_angle) + main_beam.y_offset() * np.cos(test_y_angle) + + # def test_slice_centroids(): # source = setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0) # beam = source.track() @@ -435,7 +447,9 @@ def test_x_tilt_angle(): nominal_x_angle = random.uniform(-np.pi/2, np.pi/2) beam.set_xs(beam.zs() * np.tan(nominal_x_angle)) # Add a tilt in x x_angle = beam.x_tilt_angle() + y_angle = beam.y_tilt_angle() assert np.isclose(x_angle, nominal_x_angle, rtol=1e-7, atol=1e-3) + assert np.isclose(y_angle, 0.0, rtol=1e-7, atol=1e-8) def test_y_tilt_angle(): @@ -443,25 +457,42 @@ def test_y_tilt_angle(): source = setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0) beam = source.track() nominal_y_angle = random.uniform(-np.pi/2, np.pi/2) - beam.set_ys(beam.zs() * np.tan(nominal_y_angle)) # Add a tilt in x + beam.set_ys(beam.zs() * np.tan(nominal_y_angle)) # Add a tilt in y + x_angle = beam.x_tilt_angle() y_angle = beam.y_tilt_angle() assert np.isclose(y_angle, nominal_y_angle, rtol=1e-7, atol=1e-3) + assert np.isclose(x_angle, 0.0, rtol=1e-7, atol=1e-8) + + +def test_beam_alignment_angles(): + "" +def test_add_pointing_tilts(): + "Test correct extraction of the beam pointing angles." def test_xy_rotate_coord_sys1(): "Test correct rotation of beam coordinate system around the y-axis." - source = setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0) + + start_x_angle = random.uniform(-np.pi/2, np.pi/2) # Define an initial tilt in x. + source = setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=start_x_angle, y_angle=0.0) beam = source.track() + + beam.add_pointing_tilts() # Add an initial tilt in x. old_beam = copy.deepcopy(beam) - nom_x_angle = random.uniform(-np.pi/2, np.pi/2) + nom_x_angle = random.uniform(-np.pi/2, np.pi/2) # TODO: rather have a loop over different angles. Do not use random angles. beam.xy_rotate_coord_sys(x_angle=nom_x_angle, y_angle=None, invert=False) - assert np.allclose(beam.xs(), -old_beam.zs()*np.sin(nom_x_angle) + old_beam.xs()*np.cos(nom_x_angle), rtol=1e-7, atol=1e-13) assert np.allclose(beam.zs(), old_beam.zs()*np.cos(nom_x_angle) + old_beam.xs()*np.sin(nom_x_angle), rtol=1e-7, atol=1e-13) + assert np.allclose(beam.xs(), -old_beam.zs()*np.sin(nom_x_angle) + old_beam.xs()*np.cos(nom_x_angle), rtol=1e-7, atol=1e-13) + assert np.allclose(beam.ys(), old_beam.ys(), rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uzs(), old_beam.uzs()*np.cos(nom_x_angle) + old_beam.uxs()*np.sin(nom_x_angle), rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uxs(), -old_beam.uzs()*np.sin(nom_x_angle) + old_beam.uxs()*np.cos(nom_x_angle), rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uys(), old_beam.uys(), rtol=1e-7, atol=1e-13) + assert np.isclose(beam.x_angle, np.arcsin(rotated_ux_offset/rotated_uz_offset)) + assert np.isclose(beam.x_tilt_angle(), ) def test_rotate_coord_sys_3D(): "Test correct rotation of beam coordinate system." - source = setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0) beam = source.track() x_axis = np.array([0, 1, 0]) # Axis as an unit vector. Axis permutaton is zxy. @@ -469,4 +500,6 @@ def test_rotate_coord_sys_3D(): nom_x_angle = random.uniform(-np.pi/2, np.pi/2) beam.rotate_coord_sys_3D(y_axis, nom_x_angle, x_axis, 0.0, invert=False) # Rotate beam 90 degrees around the y-axis. - assert np.isclose(beam.x_tilt_angle(), nom_x_angle) \ No newline at end of file + assert np.isclose(beam.x_tilt_angle(), nom_x_angle) + + # TODO: test un-rotate \ No newline at end of file From fcc2ce9ed879a5dcce4291138d9b8e5129080756 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Thu, 27 Mar 2025 00:57:46 +0100 Subject: [PATCH 13/51] Moved a chunk of code (the rotation part) further down in beam.py. Also minor edits on some docstrings. --- abel/classes/beam.py | 478 ++++++++++++++++++++++--------------------- 1 file changed, 245 insertions(+), 233 deletions(-) diff --git a/abel/classes/beam.py b/abel/classes/beam.py index d28759fa..d5d4f008 100644 --- a/abel/classes/beam.py +++ b/abel/classes/beam.py @@ -384,8 +384,238 @@ def norm_transverse_vector(self): vector[3,:] = self.uys()/SI.c return vector + + + ## BEAM STATISTICS + + def total_particles(self): + return int(np.nansum(self.weightings())) + + def charge(self): + return np.nansum(self.qs()) + + def abs_charge(self): + return abs(self.charge()) + + def charge_sign(self): + if self.charge() == 0: + return 1.0 + else: + return self.charge()/abs(self.charge()) + + def energy(self, clean=False): + return weighted_mean(self.Es(), self.weightings(), clean) + + def gamma(self, clean=False): + return weighted_mean(self.gammas(), self.weightings(), clean) + + def total_energy(self): + return SI.e * np.nansum(self.weightings()*self.Es()) + + def energy_spread(self, clean=False): + return weighted_std(self.Es(), self.weightings(), clean) + + def rel_energy_spread(self, clean=False): + return self.energy_spread(clean)/self.energy(clean) + + def z_offset(self, clean=False): + return weighted_mean(self.zs(), self.weightings(), clean) + + def bunch_length(self, clean=False): + return weighted_std(self.zs(), self.weightings(), clean) + + def x_offset(self, clean=False): + return weighted_mean(self.xs(), self.weightings(), clean) + + def beam_size_x(self, clean=False): + return weighted_std(self.xs(), self.weightings(), clean) + + def y_offset(self, clean=False): + return weighted_mean(self.ys(), self.weightings(), clean) + + def beam_size_y(self, clean=False): + return weighted_std(self.ys(), self.weightings(), clean) + + def x_angle(self, clean=False): + return weighted_mean(self.xps(), self.weightings(), clean) + + def divergence_x(self, clean=False): + return weighted_std(self.xps(), self.weightings(), clean) - ## Rotate the coordinate system of the beam + def y_angle(self, clean=False): + return weighted_mean(self.yps(), self.weightings(), clean) + + def divergence_y(self, clean=False): + return weighted_std(self.yps(), self.weightings(), clean) + + def ux_offset(self, clean=False): + return weighted_mean(self.uxs(), self.weightings(), clean) + + def uy_offset(self, clean=False): + return weighted_mean(self.uys(), self.weightings(), clean) + + def uz_offset(self, clean=False): + return weighted_mean(self.uzs(), self.weightings(), clean) + + + def geom_emittance_x(self, clean=False): + return np.sqrt(np.linalg.det(weighted_cov(self.xs(), self.xps(), self.weightings(), clean))) + + def geom_emittance_y(self, clean=False): + return np.sqrt(np.linalg.det(weighted_cov(self.ys(), self.yps(), self.weightings(), clean))) + + def norm_emittance_x(self, clean=False): + return np.sqrt(np.linalg.det(weighted_cov(self.xs(), self.uxs()/SI.c, self.weightings(), clean))) + + def norm_emittance_y(self, clean=False): + return np.sqrt(np.linalg.det(weighted_cov(self.ys(), self.uys()/SI.c, self.weightings(), clean))) + + def beta_x(self, clean=False): + covx = weighted_cov(self.xs(), self.xps(), self.weightings(), clean) + return covx[0,0]/np.sqrt(np.linalg.det(covx)) + + def beta_y(self, clean=False): + covy = weighted_cov(self.ys(), self.yps(), self.weightings(), clean) + return covy[0,0]/np.sqrt(np.linalg.det(covy)) + + def alpha_x(self, clean=False): + covx = weighted_cov(self.xs(), self.xps(), self.weightings(), clean) + return -covx[1,0]/np.sqrt(np.linalg.det(covx)) + + def alpha_y(self, clean=False): + covy = weighted_cov(self.ys(), self.yps(), self.weightings(), clean) + return -covy[1,0]/np.sqrt(np.linalg.det(covy)) + + def gamma_x(self, clean=False): + covx = weighted_cov(self.xs(), self.xps(), self.weightings(), clean) + return covx[1,1]/np.sqrt(np.linalg.det(covx)) + + def gamma_y(self, clean=False): + covy = weighted_cov(self.ys(), self.yps(), self.weightings(), clean) + return covy[1,1]/np.sqrt(np.linalg.det(covy)) + + def intrinsic_emittance(self): + covxy = np.cov(self.norm_transverse_vector(), aweights=self.weightings()) + return np.sqrt(np.sqrt(np.linalg.det(covxy))) + + def angular_momentum(self): + covxy = np.cov(self.norm_transverse_vector(), aweights=self.weightings()) + det_covxy_cross = np.linalg.det(covxy[2:4,0:2]) + return np.sign(covxy[3,0]-covxy[2,1])*np.sqrt(np.abs(det_covxy_cross)) + + def eigen_emittance_max(self): + return np.sqrt(self.norm_emittance_x()*self.norm_emittance_y()) + self.angular_momentum() + + def eigen_emittance_min(self): + return np.sqrt(self.norm_emittance_x()*self.norm_emittance_y()) - self.angular_momentum() + + def norm_amplitude_x(self, plasma_density=None, clean=False): + if plasma_density is not None: + beta_x = beta_matched(plasma_density, self.energy()) + alpha_x = 0 + else: + covx = weighted_cov(self.xs(), self.xps(), self.weightings(), clean) + emgx = np.sqrt(np.linalg.det(covx)) + beta_x = covx[0,0]/emgx + alpha_x = -covx[1,0]/emgx + return np.sqrt(self.gamma()/beta_x)*np.sqrt(self.x_offset()**2 + (self.x_offset()*alpha_x + self.x_angle()*beta_x)**2) + + def norm_amplitude_y(self, plasma_density=None, clean=False): + if plasma_density is not None: + beta_y = beta_matched(plasma_density, self.energy()) + alpha_y = 0 + else: + covy = weighted_cov(self.ys(), self.yps(), self.weightings(), clean) + emgy = np.sqrt(np.linalg.det(covy)) + beta_y = covy[0,0]/emgy + alpha_y = -covy[1,0]/emgy + return np.sqrt(self.gamma()/beta_y)*np.sqrt(self.y_offset()**2 + (self.y_offset()*alpha_y + self.y_angle()*beta_y)**2) + + def peak_density(self): # TODO: this is only valid for Gaussian beams. + return (self.charge()/SI.e)/(np.sqrt(2*SI.pi)**3*self.beam_size_x()*self.beam_size_y()*self.bunch_length()) + + def peak_current(self): + Is, _ = self.current_profile() + return max(abs(Is)) + + + ## BEAM HALO CLEANING (EXTREME OUTLIERS) + def remove_halo_particles(self, nsigma=20): + xfilter = np.abs(self.xs()-self.x_offset(clean=True)) > nsigma*self.beam_size_x(clean=True) + xpfilter = np.abs(self.xps()-self.x_angle(clean=True)) > nsigma*self.divergence_x(clean=True) + yfilter = np.abs(self.ys()-self.y_offset(clean=True)) > nsigma*self.beam_size_y(clean=True) + ypfilter = np.abs(self.yps()-self.y_angle(clean=True)) > nsigma*self.divergence_y(clean=True) + filter = np.logical_or(np.logical_or(xfilter, xpfilter), np.logical_or(yfilter, ypfilter)) + del self[filter] + + + ## BEAM PROJECTIONS + + def projected_density(self, fcn, bins=None): + if bins is None: + Nbins = int(np.sqrt(len(self)/2)) + bins = np.linspace(min(fcn()), max(fcn()), Nbins) + counts, edges = np.histogram(fcn(), weights=self.qs(), bins=bins) + ctrs = (edges[0:-1] + edges[1:])/2 + proj = counts/np.diff(edges) + return proj, ctrs + + def current_profile(self, bins=None): + return self.projected_density(self.ts, bins=bins) + + def longitudinal_num_density(self, bins=None): + dQdz, zs = self.projected_density(self.zs, bins=bins) + dNdz = dQdz / SI.e / self.charge_sign() + return dNdz, zs + + def energy_spectrum(self, bins=None): + return self.projected_density(self.Es, bins=bins) + + def rel_energy_spectrum(self, nom_energy=None, bins=None): + if nom_energy is None: + nom_energy = self.energy() + return self.projected_density(lambda: self.Es()/nom_energy-1, bins=bins) + + def transverse_profile_x(self, bins=None): + return self.projected_density(self.xs, bins=bins) + + def transverse_profile_y(self, bins=None): + return self.projected_density(self.ys, bins=bins) + + def transverse_profile_xp(self, bins=None): + return self.projected_density(self.xps, bins=bins) + + def transverse_profile_yp(self, bins=None): + return self.projected_density(self.yps, bins=bins) + + ## phase spaces + + def phase_space_density(self, hfcn, vfcn, hbins=None, vbins=None): + self.remove_nans() + if hbins is None: + hbins = round(np.sqrt(len(self))/2) + if vbins is None: + vbins = round(np.sqrt(len(self))/2) + counts, hedges, vedges = np.histogram2d(hfcn(), vfcn(), weights=self.qs(), bins=(hbins, vbins)) + hctrs = (hedges[0:-1] + hedges[1:])/2 + vctrs = (vedges[0:-1] + vedges[1:])/2 + density = (counts/np.diff(vedges)).T/np.diff(hedges) + + #dx = np.diff(hedges) + #dy = np.diff(vedges) + #bin_areas = dx[:, None] * dy[None, :] + #density = counts/bin_areas + #print(np.sum(density*np.diff(vedges)*np.diff(hedges))/self.charge()) + return density, hctrs, vctrs + + def density_lps(self, hbins=None, vbins=None): + return self.phase_space_density(self.zs, self.Es, hbins=hbins, vbins=vbins) + + def density_transverse(self, hbins=None, vbins=None): + return self.phase_space_density(self.xs, self.ys, hbins=hbins, vbins=vbins) + + +## Rotate the coordinate system of the beam # ================================================== def rotate_coord_sys_3D(self, axis1, angle1, axis2=np.array([0, 1, 0]), angle2=0.0, axis3=np.array([1, 0, 0]), angle3=0.0, invert=False): """ @@ -538,11 +768,11 @@ def add_pointing_tilts(self, align_x_angle=None, align_y_angle=None): Parameters ---------- - align_x_angle: [rad] float - Beam coordinates with in the zx-plane are rotated with this angle. + align_x_angle: [rad] float, optional + Beam coordinates in the zx-plane are rotated with this angle. If ``None``, will align the beam using its angular offset. - align_y_angle: [rad] float - Beam coordinates with in the zy-plane are rotated with this angle. Note that due to the right hand rule, a positive rotation angle in the zy-plane corresponds to rotation from z-axis towards negative y. I.e. the opposite sign convention of beam.yps(). + align_y_angle: [rad] float, optional + Beam coordinates in the zy-plane are rotated with this angle. Note that due to the right hand rule, a positive rotation angle in the zy-plane corresponds to rotation from z-axis towards negative y. I.e. the opposite sign convention of ``beam.yps()``. If ``None``, will align the beam using its angular offset. Returns @@ -654,7 +884,12 @@ def slice_centroids(self, beam_quant, bin_number=None, cut_off=None, make_plot=F # ================================================== + # def x_tilt_angle(self, clean=False): + # #return np.arcsin(self.ux_offset(clean=clean)/self.uz_offset(clean=clean)) + # return np.arcsin(self.x_offset(clean=clean)/self.z_offset(clean=clean)) + def x_tilt_angle(self, z_cutoff=None): + "Retrieve the tilt angle of the beam in the zx-plane. WARNING: becomes unreliable around > 1e-4 rad." if z_cutoff is None: z_cutoff = 1.5 * self.bunch_length() @@ -666,8 +901,12 @@ def x_tilt_angle(self, z_cutoff=None): return np.arctan(slope) - # ================================================== + # # ================================================== + # def y_tilt_angle(self, clean=False): + # return np.arcsin(self.uy_offset(clean=clean)/self.uz_offset(clean=clean)) + def y_tilt_angle(self, z_cutoff=None): + "Retrieve the tilt angle of the beam in the zy-plane. WARNING: becomes unreliable around > 1e-4 rad." if z_cutoff is None: z_cutoff = 1.5 * self.bunch_length() y_centroids, z_centroids = self.slice_centroids(self.ys(), cut_off=z_cutoff, make_plot=False) @@ -676,234 +915,7 @@ def y_tilt_angle(self, z_cutoff=None): slope, _ = np.polyfit(z_centroids, y_centroids, 1) return np.arctan(slope) - - - - ## BEAM STATISTICS - - def total_particles(self): - return int(np.nansum(self.weightings())) - - def charge(self): - return np.nansum(self.qs()) - - def abs_charge(self): - return abs(self.charge()) - - def charge_sign(self): - if self.charge() == 0: - return 1.0 - else: - return self.charge()/abs(self.charge()) - - def energy(self, clean=False): - return weighted_mean(self.Es(), self.weightings(), clean) - - def gamma(self, clean=False): - return weighted_mean(self.gammas(), self.weightings(), clean) - - def total_energy(self): - return SI.e * np.nansum(self.weightings()*self.Es()) - - def energy_spread(self, clean=False): - return weighted_std(self.Es(), self.weightings(), clean) - def rel_energy_spread(self, clean=False): - return self.energy_spread(clean)/self.energy(clean) - - def z_offset(self, clean=False): - return weighted_mean(self.zs(), self.weightings(), clean) - - def bunch_length(self, clean=False): - return weighted_std(self.zs(), self.weightings(), clean) - - def x_offset(self, clean=False): - return weighted_mean(self.xs(), self.weightings(), clean) - - def beam_size_x(self, clean=False): - return weighted_std(self.xs(), self.weightings(), clean) - - def y_offset(self, clean=False): - return weighted_mean(self.ys(), self.weightings(), clean) - - def beam_size_y(self, clean=False): - return weighted_std(self.ys(), self.weightings(), clean) - - def x_angle(self, clean=False): - return weighted_mean(self.xps(), self.weightings(), clean) - - def divergence_x(self, clean=False): - return weighted_std(self.xps(), self.weightings(), clean) - - def y_angle(self, clean=False): - return weighted_mean(self.yps(), self.weightings(), clean) - - def divergence_y(self, clean=False): - return weighted_std(self.yps(), self.weightings(), clean) - - def ux_offset(self, clean=False): - return weighted_mean(self.uxs(), self.weightings(), clean) - - def uy_offset(self, clean=False): - return weighted_mean(self.uys(), self.weightings(), clean) - - - def geom_emittance_x(self, clean=False): - return np.sqrt(np.linalg.det(weighted_cov(self.xs(), self.xps(), self.weightings(), clean))) - - def geom_emittance_y(self, clean=False): - return np.sqrt(np.linalg.det(weighted_cov(self.ys(), self.yps(), self.weightings(), clean))) - - def norm_emittance_x(self, clean=False): - return np.sqrt(np.linalg.det(weighted_cov(self.xs(), self.uxs()/SI.c, self.weightings(), clean))) - - def norm_emittance_y(self, clean=False): - return np.sqrt(np.linalg.det(weighted_cov(self.ys(), self.uys()/SI.c, self.weightings(), clean))) - - def beta_x(self, clean=False): - covx = weighted_cov(self.xs(), self.xps(), self.weightings(), clean) - return covx[0,0]/np.sqrt(np.linalg.det(covx)) - - def beta_y(self, clean=False): - covy = weighted_cov(self.ys(), self.yps(), self.weightings(), clean) - return covy[0,0]/np.sqrt(np.linalg.det(covy)) - - def alpha_x(self, clean=False): - covx = weighted_cov(self.xs(), self.xps(), self.weightings(), clean) - return -covx[1,0]/np.sqrt(np.linalg.det(covx)) - - def alpha_y(self, clean=False): - covy = weighted_cov(self.ys(), self.yps(), self.weightings(), clean) - return -covy[1,0]/np.sqrt(np.linalg.det(covy)) - - def gamma_x(self, clean=False): - covx = weighted_cov(self.xs(), self.xps(), self.weightings(), clean) - return covx[1,1]/np.sqrt(np.linalg.det(covx)) - - def gamma_y(self, clean=False): - covy = weighted_cov(self.ys(), self.yps(), self.weightings(), clean) - return covy[1,1]/np.sqrt(np.linalg.det(covy)) - - def intrinsic_emittance(self): - covxy = np.cov(self.norm_transverse_vector(), aweights=self.weightings()) - return np.sqrt(np.sqrt(np.linalg.det(covxy))) - - def angular_momentum(self): - covxy = np.cov(self.norm_transverse_vector(), aweights=self.weightings()) - det_covxy_cross = np.linalg.det(covxy[2:4,0:2]) - return np.sign(covxy[3,0]-covxy[2,1])*np.sqrt(np.abs(det_covxy_cross)) - - def eigen_emittance_max(self): - return np.sqrt(self.norm_emittance_x()*self.norm_emittance_y()) + self.angular_momentum() - - def eigen_emittance_min(self): - return np.sqrt(self.norm_emittance_x()*self.norm_emittance_y()) - self.angular_momentum() - - def norm_amplitude_x(self, plasma_density=None, clean=False): - if plasma_density is not None: - beta_x = beta_matched(plasma_density, self.energy()) - alpha_x = 0 - else: - covx = weighted_cov(self.xs(), self.xps(), self.weightings(), clean) - emgx = np.sqrt(np.linalg.det(covx)) - beta_x = covx[0,0]/emgx - alpha_x = -covx[1,0]/emgx - return np.sqrt(self.gamma()/beta_x)*np.sqrt(self.x_offset()**2 + (self.x_offset()*alpha_x + self.x_angle()*beta_x)**2) - - def norm_amplitude_y(self, plasma_density=None, clean=False): - if plasma_density is not None: - beta_y = beta_matched(plasma_density, self.energy()) - alpha_y = 0 - else: - covy = weighted_cov(self.ys(), self.yps(), self.weightings(), clean) - emgy = np.sqrt(np.linalg.det(covy)) - beta_y = covy[0,0]/emgy - alpha_y = -covy[1,0]/emgy - return np.sqrt(self.gamma()/beta_y)*np.sqrt(self.y_offset()**2 + (self.y_offset()*alpha_y + self.y_angle()*beta_y)**2) - - def peak_density(self): # TODO: this is only valid for Gaussian beams. - return (self.charge()/SI.e)/(np.sqrt(2*SI.pi)**3*self.beam_size_x()*self.beam_size_y()*self.bunch_length()) - - def peak_current(self): - Is, _ = self.current_profile() - return max(abs(Is)) - - - ## BEAM HALO CLEANING (EXTREME OUTLIERS) - def remove_halo_particles(self, nsigma=20): - xfilter = np.abs(self.xs()-self.x_offset(clean=True)) > nsigma*self.beam_size_x(clean=True) - xpfilter = np.abs(self.xps()-self.x_angle(clean=True)) > nsigma*self.divergence_x(clean=True) - yfilter = np.abs(self.ys()-self.y_offset(clean=True)) > nsigma*self.beam_size_y(clean=True) - ypfilter = np.abs(self.yps()-self.y_angle(clean=True)) > nsigma*self.divergence_y(clean=True) - filter = np.logical_or(np.logical_or(xfilter, xpfilter), np.logical_or(yfilter, ypfilter)) - del self[filter] - - - ## BEAM PROJECTIONS - - def projected_density(self, fcn, bins=None): - if bins is None: - Nbins = int(np.sqrt(len(self)/2)) - bins = np.linspace(min(fcn()), max(fcn()), Nbins) - counts, edges = np.histogram(fcn(), weights=self.qs(), bins=bins) - ctrs = (edges[0:-1] + edges[1:])/2 - proj = counts/np.diff(edges) - return proj, ctrs - - def current_profile(self, bins=None): - return self.projected_density(self.ts, bins=bins) - - def longitudinal_num_density(self, bins=None): - dQdz, zs = self.projected_density(self.zs, bins=bins) - dNdz = dQdz / SI.e / self.charge_sign() - return dNdz, zs - - def energy_spectrum(self, bins=None): - return self.projected_density(self.Es, bins=bins) - - def rel_energy_spectrum(self, nom_energy=None, bins=None): - if nom_energy is None: - nom_energy = self.energy() - return self.projected_density(lambda: self.Es()/nom_energy-1, bins=bins) - - def transverse_profile_x(self, bins=None): - return self.projected_density(self.xs, bins=bins) - - def transverse_profile_y(self, bins=None): - return self.projected_density(self.ys, bins=bins) - - def transverse_profile_xp(self, bins=None): - return self.projected_density(self.xps, bins=bins) - - def transverse_profile_yp(self, bins=None): - return self.projected_density(self.yps, bins=bins) - - ## phase spaces - - def phase_space_density(self, hfcn, vfcn, hbins=None, vbins=None): - self.remove_nans() - if hbins is None: - hbins = round(np.sqrt(len(self))/2) - if vbins is None: - vbins = round(np.sqrt(len(self))/2) - counts, hedges, vedges = np.histogram2d(hfcn(), vfcn(), weights=self.qs(), bins=(hbins, vbins)) - hctrs = (hedges[0:-1] + hedges[1:])/2 - vctrs = (vedges[0:-1] + vedges[1:])/2 - density = (counts/np.diff(vedges)).T/np.diff(hedges) - - #dx = np.diff(hedges) - #dy = np.diff(vedges) - #bin_areas = dx[:, None] * dy[None, :] - #density = counts/bin_areas - #print(np.sum(density*np.diff(vedges)*np.diff(hedges))/self.charge()) - return density, hctrs, vctrs - - def density_lps(self, hbins=None, vbins=None): - return self.phase_space_density(self.zs, self.Es, hbins=hbins, vbins=vbins) - - def density_transverse(self, hbins=None, vbins=None): - return self.phase_space_density(self.xs, self.ys, hbins=hbins, vbins=vbins) - # ================================================== # TODO: Currently does not reproduce the correct peak density for Gaussian beams unless the bin numbers are adjusted manually. From df96f88c25fc00f8cf413235b2c6bfd3553fefe3 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Thu, 27 Mar 2025 00:59:11 +0100 Subject: [PATCH 14/51] Added several major tests for the beam coordinate system rotations. --- tests/test_beam.py | 318 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 265 insertions(+), 53 deletions(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index c3070f66..10320657 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -25,32 +25,68 @@ import random -def setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, bunch_length=40.0e-06, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0): - main = SourceBasic() - main.bunch_length = bunch_length # [m], rms. - main.num_particles = 10000 - main.charge = -e * 1.0e10 # [C] +def setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, bunch_length=40.0e-06, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0): + source = SourceBasic() + source.bunch_length = bunch_length # [m], rms. + source.num_particles = 10000 + source.charge = -e * 1.0e10 # [C] # Energy parameters - main.energy = energy # [eV], HALHF v2 last stage nominal input energy - main.rel_energy_spread = 0.02 # Relative rms energy spread + source.energy = energy # [eV] + source.rel_energy_spread = 0.02 # Relative rms energy spread # Emittances - main.emit_nx, main.emit_ny = 15e-6, 0.1e-6 # [m rad] + source.emit_nx, source.emit_ny = 15e-6, 0.1e-6 # [m rad] # Beta functions - main.beta_x = beta_matched(plasma_density, main.energy) * ramp_beta_mag # [m] - main.beta_y = main.beta_x # [m] + source.beta_x = beta_matched(plasma_density, source.energy) * ramp_beta_mag # [m] + source.beta_y = source.beta_x # [m] # Offsets - main.z_offset = z_offset # [m] - main.x_offset = x_offset # [m] - main.y_offset = y_offset # [m] + source.z_offset = z_offset # [m] + source.x_offset = x_offset # [m] + source.y_offset = y_offset # [m] + source.x_angle = x_angle # [rad] + source.y_angle = y_angle # [rad] # Other - main.symmetrize_6d = True + source.symmetrize_6d = True - return main + return source + + +def setup_trapezoid_source(current_head=0.1e3, bunch_length=1050e-6, z_offset=1615e-6, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0, enable_xy_jitter=False, enable_xpyp_jitter=False): + source = SourceTrapezoid() + source.current_head = current_head # [A] + source.bunch_length = bunch_length # [m] + + source.num_particles = 30000 + source.charge = 5.0e10 * -SI.e # [C] + source.energy = 4.9e9 # [eV] + source.gaussian_blur = 50e-6 # [m] + source.rel_energy_spread = 0.01 + + source.emit_nx, source.emit_ny = 50e-6, 100e-6 # [m rad] + source.beta_x, source.beta_y = 0.5, 0.5 # [m] + + # Offsets + source.z_offset = z_offset # [m] + source.x_offset = x_offset # [m] + source.y_offset = y_offset # [m] + source.x_angle = x_angle # [rad] + source.y_angle = y_angle # [rad] + + if enable_xy_jitter: + source.jitter.x = 100e-9 # [m], std + source.jitter.y = 100e-9 # [m], std + + if enable_xpyp_jitter: + source.jitter.xp = 1.0e-6 # [rad], std + source.jitter.yp = 1.0e-6 # [rad], std + + source.symmetrize = True + + return source ############# Basic tests ############# @@ -415,18 +451,36 @@ def test_scale_energy(): ############# Tests on bunch pattern ############# +############# Tests for beam statistics ############# +# Need tests for beam parameter calculations such as offsets, emittance, beta functions, peak current + + +############# Tests for beam projections ############# +# ... + + ############# Tests of coordinate rotation methods ############# -def passive_rotate_vector(vec, x_angle, yangle): - "Rotate a vector ``vec`` with three componets (along xyz) first with ``x_angle`` around the y-axis then with ``y_angle`` around the x-axis." - rotated_z_offset = main_beam.z_offset() * np.cos(test_x_angle)*np.cos(test_y_angle) + main_beam.x_offset() * np.sin(test_x_angle)*np.cos(test_y_angle) - main_beam.y_offset() * np.sin(test_y_angle) - rotated_x_offset = -main_beam.z_offset() * np.sin(test_x_angle) + main_beam.x_offset() * np.cos(test_x_angle) - rotated_y_offset = main_beam.z_offset() * np.cos(test_x_angle)*np.sin(test_y_angle) + main_beam.x_offset() * np.sin(test_x_angle)*np.sin(test_y_angle) + main_beam.y_offset() * np.cos(test_y_angle) +def active_rotate_arrs(x_comps, y_comps, z_comps, x_angle, y_angle): + "Active rotation of ndarrays ``x_comps``, ``y_comps`` and ``z_comps`` containing the xyz-components of vectors such as position and proper velocity first with ``x_angle`` around the y-axis then with ``y_angle`` around the x-axis." + rotated_z_comps = z_comps * np.cos(x_angle)*np.cos(y_angle) - x_comps * np.sin(x_angle)*np.cos(y_angle) + y_comps * np.sin(y_angle) + rotated_x_comps = z_comps * np.sin(x_angle) + x_comps * np.cos(x_angle) + rotated_y_comps = -z_comps * np.cos(x_angle)*np.sin(y_angle) + x_comps * np.sin(x_angle)*np.sin(y_angle) + y_comps * np.cos(y_angle) + + return rotated_x_comps, rotated_y_comps, rotated_z_comps + +def passive_rotate_arrs(x_comps, y_comps, z_comps, x_angle, y_angle): + "Passive rotation of ndarrays ``x_comps``, ``y_comps`` and ``z_comps`` containing the xyz-components of vectors such as position and proper velocity first with ``x_angle`` around the y-axis then with ``y_angle`` around the x-axis." + rotated_z_comps = z_comps * np.cos(x_angle)*np.cos(y_angle) + x_comps * np.sin(x_angle)*np.cos(y_angle) - y_comps * np.sin(y_angle) + rotated_x_comps = -z_comps * np.sin(x_angle) + x_comps * np.cos(x_angle) + rotated_y_comps = z_comps * np.cos(x_angle)*np.sin(y_angle) + x_comps * np.sin(x_angle)*np.sin(y_angle) + y_comps * np.cos(y_angle) + + return rotated_x_comps, rotated_y_comps, rotated_z_comps # def test_slice_centroids(): -# source = setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0) +# source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0) # beam = source.track() # beam_quant = beam.xs() # Use x positions as the beam quantity # x_slices, z_centroids = beam.slice_centroids(beam_quant, bin_number=5) @@ -440,66 +494,224 @@ def passive_rotate_vector(vec, x_angle, yangle): # assert np.all(z_centroids <= 10) +@pytest.mark.beam def test_x_tilt_angle(): "Test the retrieval of the beam tilt angle in the zx-plane." - source = setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0) + source = setup_trapezoid_source(current_head=0.1e3, bunch_length=1050e-6, z_offset=1615e-6, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0, enable_xy_jitter=False, enable_xpyp_jitter=False) beam = source.track() - nominal_x_angle = random.uniform(-np.pi/2, np.pi/2) - beam.set_xs(beam.zs() * np.tan(nominal_x_angle)) # Add a tilt in x + nom_x_angle = -2.82e-8 # [rad] + + # Add tilt in x + rotated_xs, rotated_ys, rotated_zs = passive_rotate_arrs(beam.xs(), beam.ys(), beam.zs(), nom_x_angle, y_angle=0.0) + rotated_uxs, rotated_uys, rotated_uzs = passive_rotate_arrs(beam.uxs(), beam.uys(), beam.uzs(), nom_x_angle, y_angle=0.0) + beam.set_phase_space(beam.charge(), rotated_xs, rotated_ys, rotated_zs, rotated_uxs, rotated_uys, rotated_uzs) + + # Compare the angles x_angle = beam.x_tilt_angle() y_angle = beam.y_tilt_angle() - assert np.isclose(x_angle, nominal_x_angle, rtol=1e-7, atol=1e-3) + assert np.isclose(x_angle, -nom_x_angle, rtol=1e-3, atol=1e-8) assert np.isclose(y_angle, 0.0, rtol=1e-7, atol=1e-8) +@pytest.mark.beam def test_y_tilt_angle(): "Test the retrieval of the beam tilt angle in the zy-plane." - source = setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0) + source = setup_trapezoid_source(current_head=0.1e3, bunch_length=1050e-6, z_offset=1615e-6, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0, enable_xy_jitter=False, enable_xpyp_jitter=False) beam = source.track() - nominal_y_angle = random.uniform(-np.pi/2, np.pi/2) - beam.set_ys(beam.zs() * np.tan(nominal_y_angle)) # Add a tilt in y + nom_y_angle = 7.04e-9 # [rad] + + # Add tilt in y + rotated_xs, rotated_ys, rotated_zs = passive_rotate_arrs(beam.xs(), beam.ys(), beam.zs(), 0.0, y_angle=nom_y_angle) + rotated_uxs, rotated_uys, rotated_uzs = passive_rotate_arrs(beam.uxs(), beam.uys(), beam.uzs(), 0.0, y_angle=nom_y_angle) + beam.set_phase_space(beam.charge(), rotated_xs, rotated_ys, rotated_zs, rotated_uxs, rotated_uys, rotated_uzs) + + # Compare the angles x_angle = beam.x_tilt_angle() y_angle = beam.y_tilt_angle() - assert np.isclose(y_angle, nominal_y_angle, rtol=1e-7, atol=1e-3) + assert np.isclose(y_angle, nom_y_angle, rtol=1e-3, atol=1e-11) assert np.isclose(x_angle, 0.0, rtol=1e-7, atol=1e-8) +@pytest.mark.beam def test_beam_alignment_angles(): - "" + "Test ``Beam.beam_alignment_angles()``, which calculates the angles for rotation around the y- and x-axis to align the z-axis to the beam proper velocity." + + start_x_angle = 1.2e-7 # [rad], define an angle in the zx-plane. + start_y_angle = -2.3e-7 # [rad], define an angle in the zy-plane. + # Create a source with angular offsets, but not tilted in space + source = setup_trapezoid_source(current_head=0.1e3, bunch_length=1050e-6, z_offset=1615e-6, x_offset=0.0, y_offset=0.0, x_angle=start_x_angle, y_angle=start_y_angle, enable_xy_jitter=False, enable_xpyp_jitter=False) + + # Generate a beam + beam = source.track() + + # Get the angles + align_x_angle, align_y_angle = beam.beam_alignment_angles() + + # Compare to the chosen angular offsets + assert np.isclose(align_x_angle, start_x_angle, rtol=1e-5, atol=1e-13) + assert np.isclose(align_y_angle, start_y_angle, rtol=1e-5, atol=1e-13) + + + +@pytest.mark.beam def test_add_pointing_tilts(): - "Test correct extraction of the beam pointing angles." + "Test ``Beam.add_pointing_tilts()``, which uses active transformation to tilt the beam in the zx- and zy-planes." + + start_x_angle = -2.82328e-08 # [rad], define an angle in the zx-plane. + start_y_angle = 7.040999e-09 # [rad], define an angle in the zy-plane. + + # Create a source with angular offsets, but not tilted in space + source = setup_trapezoid_source(current_head=0.1e3, bunch_length=1050e-6, z_offset=1615e-6, x_offset=0.0, y_offset=0.0, x_angle=start_x_angle, y_angle=start_y_angle, enable_xy_jitter=False, enable_xpyp_jitter=False) + # Generate a beam + beam = source.track() + initial_beam = copy.deepcopy(beam) + + # Tilt the beam using its angular offset + beam.add_pointing_tilts() + + # Rotate the positions and proper velocities of all particles with written out formulas for comparison. Note the sign convention for y_angle. + rotated_xs, rotated_ys, rotated_zs = active_rotate_arrs(initial_beam.xs(), initial_beam.ys(), initial_beam.zs(), start_x_angle, -start_y_angle) + + # Examine the resulting beam + assert np.isclose(beam.x_angle(), start_x_angle, rtol=1e-3, atol=1e-11) + assert np.isclose(beam.y_angle(), start_y_angle, rtol=1e-3, atol=1e-11) + assert np.allclose(beam.uxs(), initial_beam.uxs(), rtol=1e-15, atol=0.0) # The proper velocities should not change. + assert np.allclose(beam.uys(), initial_beam.uys(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.uzs(), initial_beam.uzs(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.xs(), rotated_xs, rtol=1e-8, atol=0.0) + assert np.allclose(beam.ys(), rotated_ys, rtol=1e-8, atol=0.0) + assert np.allclose(beam.zs(), rotated_zs, rtol=1e-8, atol=0.0) + + +@pytest.mark.beam def test_xy_rotate_coord_sys1(): "Test correct rotation of beam coordinate system around the y-axis." - start_x_angle = random.uniform(-np.pi/2, np.pi/2) # Define an initial tilt in x. - source = setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=start_x_angle, y_angle=0.0) - beam = source.track() + np.random.seed(42) + + start_x_angle = 1e-7 # [rad], define an angle in the zx-plane. + + # Source with angular offset, but no tilt + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=start_x_angle, y_angle=0.0) + + nom_x_angles = np.concatenate((-np.logspace(-9, np.log10(0.11), 10), np.logspace(-9, -1, 10))) # [rad] + + for i in range(len(nom_x_angles)): + + beam = source.track() + beam.add_pointing_tilts() # Add an initial tilt in the zx-plane. + old_beam = copy.deepcopy(beam) + + nom_x_angle = nom_x_angles[i] + beam.xy_rotate_coord_sys(x_angle=nom_x_angle, y_angle=None, invert=False) + + # Rotate the positions and proper velocities of all particles with written out formulas for comparison + rotated_xs, rotated_ys, rotated_zs = passive_rotate_arrs(old_beam.xs(), old_beam.ys(), old_beam.zs(), nom_x_angle, y_angle=0.0) + rotated_uxs, rotated_uys, rotated_uzs = passive_rotate_arrs(old_beam.uxs(), old_beam.uys(), old_beam.uzs(), nom_x_angle, y_angle=0.0) + rotated_ux_offset, rotated_uy_offset, rotated_uz_offset = passive_rotate_arrs(old_beam.ux_offset(), old_beam.uy_offset(), old_beam.uz_offset(), nom_x_angle, y_angle=0.0) + + # Compare the rotated arrays + assert np.allclose(beam.zs(), rotated_zs, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.xs(), rotated_xs, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.ys(), rotated_ys, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uzs(), rotated_uzs, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uxs(), rotated_uxs, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uys(), rotated_uys, rtol=1e-7, atol=1e-13) + assert np.isclose(beam.x_angle(), np.arcsin(rotated_ux_offset/rotated_uz_offset), rtol=np.abs(beam.x_angle())*1e-3, atol=np.abs(beam.x_angle())*2e-3) + assert np.isclose(beam.y_angle(), np.arcsin(rotated_uy_offset/rotated_uz_offset), rtol=1e-7, atol=1e-13) + + # print(nom_x_angle, beam.x_tilt_angle(), np.arcsin(rotated_ux_offset/rotated_uz_offset)) + # assert np.isclose(beam.x_tilt_angle(), np.arcsin(rotated_ux_offset/rotated_uz_offset), rtol=np.abs(beam.x_angle())*1e-3, atol=np.abs(beam.x_angle())*2e-3) + # assert np.isclose(beam.y_tilt_angle(), np.arcsin(rotated_uy_offset/rotated_uz_offset), rtol=1e-7, atol=1e-13) + + +@pytest.mark.beam +def test_xy_rotate_coord_sys2(): + "Test correct rotation of beam coordinate system around the y-axis." + + np.random.seed(42) + + start_y_angle = 1e-6 # [rad], define an angle in the zy-plane. + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=start_y_angle) - beam.add_pointing_tilts() # Add an initial tilt in x. - old_beam = copy.deepcopy(beam) - nom_x_angle = random.uniform(-np.pi/2, np.pi/2) # TODO: rather have a loop over different angles. Do not use random angles. - beam.xy_rotate_coord_sys(x_angle=nom_x_angle, y_angle=None, invert=False) - assert np.allclose(beam.zs(), old_beam.zs()*np.cos(nom_x_angle) + old_beam.xs()*np.sin(nom_x_angle), rtol=1e-7, atol=1e-13) - assert np.allclose(beam.xs(), -old_beam.zs()*np.sin(nom_x_angle) + old_beam.xs()*np.cos(nom_x_angle), rtol=1e-7, atol=1e-13) - assert np.allclose(beam.ys(), old_beam.ys(), rtol=1e-7, atol=1e-13) - assert np.allclose(beam.uzs(), old_beam.uzs()*np.cos(nom_x_angle) + old_beam.uxs()*np.sin(nom_x_angle), rtol=1e-7, atol=1e-13) - assert np.allclose(beam.uxs(), -old_beam.uzs()*np.sin(nom_x_angle) + old_beam.uxs()*np.cos(nom_x_angle), rtol=1e-7, atol=1e-13) - assert np.allclose(beam.uys(), old_beam.uys(), rtol=1e-7, atol=1e-13) - assert np.isclose(beam.x_angle, np.arcsin(rotated_ux_offset/rotated_uz_offset)) - assert np.isclose(beam.x_tilt_angle(), ) + nom_y_angles = np.concatenate((-np.logspace(-9, np.log10(0.11), 10), np.logspace(-9, -1, 10))) # [rad] + + for i in range(len(nom_y_angles)): + + beam = source.track() + beam.add_pointing_tilts() # Add an initial tilt in the zy-plane. + old_beam = copy.deepcopy(beam) + + nom_y_angle = nom_y_angles[i] + beam.xy_rotate_coord_sys(x_angle=None, y_angle=nom_y_angle, invert=False) + + # Roatate the positions and proper velocities of all particles with written out formulas for comparison + rotated_xs, rotated_ys, rotated_zs = passive_rotate_arrs(old_beam.xs(), old_beam.ys(), old_beam.zs(), 0.0, y_angle=nom_y_angle) + rotated_uxs, rotated_uys, rotated_uzs = passive_rotate_arrs(old_beam.uxs(), old_beam.uys(), old_beam.uzs(), 0.0, y_angle=nom_y_angle) + rotated_ux_offset, rotated_uy_offset, rotated_uz_offset = passive_rotate_arrs(old_beam.ux_offset(), old_beam.uy_offset(), old_beam.uz_offset(), 0.0, y_angle=nom_y_angle) + + # Compare the rotated arrays + assert np.allclose(beam.zs(), rotated_zs, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.xs(), rotated_xs, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.ys(), rotated_ys, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uzs(), rotated_uzs, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uxs(), rotated_uxs, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uys(), rotated_uys, rtol=1e-7, atol=1e-13) + assert np.isclose(beam.x_angle(), np.arcsin(rotated_ux_offset/rotated_uz_offset), rtol=1e-7, atol=1e-13) + assert np.isclose(beam.y_angle(), np.arcsin(rotated_uy_offset/rotated_uz_offset), rtol=np.abs(nom_y_angle)*1e-3, atol=np.abs(nom_y_angle)*2e-3) + # print(nom_y_angle, beam.y_tilt_angle(), np.arcsin(rotated_uy_offset/rotated_uz_offset)) + # assert np.isclose(beam.y_tilt_angle(), np.arcsin(rotated_uy_offset/rotated_uz_offset), rtol=np.abs(nom_y_angle)*1e-3, atol=np.abs(nom_y_angle)*2e-3) + # assert np.isclose(beam.x_tilt_angle(), np.arcsin(rotated_ux_offset/rotated_uz_offset), rtol=1e-7, atol=1e-13) + +@pytest.mark.beam def test_rotate_coord_sys_3D(): - "Test correct rotation of beam coordinate system." - source = setup_basic_main_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0) - beam = source.track() + "Test correct passive rotation of beam coordinate system." + + np.random.seed(42) + + start_x_angle = -2.82328e-08 # [rad], define an angle in the zx-plane. + start_y_angle = 7.040999e-09 # [rad], define an angle in the zy-plane. + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=start_x_angle, y_angle=start_y_angle) + + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0) + old_beam = source.track() + old_beam.add_pointing_tilts() # Add an initial tilt in the zy-plane. + #old_beam = copy.deepcopy(beam) + x_axis = np.array([0, 1, 0]) # Axis as an unit vector. Axis permutaton is zxy. y_axis = np.array([0, 0, 1]) - - nom_x_angle = random.uniform(-np.pi/2, np.pi/2) - beam.rotate_coord_sys_3D(y_axis, nom_x_angle, x_axis, 0.0, invert=False) # Rotate beam 90 degrees around the y-axis. - assert np.isclose(beam.x_tilt_angle(), nom_x_angle) + nom_x_angles = np.concatenate((-np.logspace(-9, np.log10(0.11), 10), np.logspace(-9, -1, 10))) # [rad] + nom_y_angles = np.concatenate((-np.logspace(-9, np.log10(0.11), 10), np.logspace(-9, -1, 10))) # [rad] + + for i in range(len(nom_x_angles)): + + beam = copy.deepcopy(old_beam) + + nom_x_angle = nom_x_angles[i] + nom_y_angle = nom_y_angles[i] + beam.rotate_coord_sys_3D(y_axis, nom_x_angle, x_axis, nom_y_angle, invert=False) + + # Roatate the positions and proper velocities of all particles with written out formulas for comparison + rotated_xs, rotated_ys, rotated_zs = passive_rotate_arrs(old_beam.xs(), old_beam.ys(), old_beam.zs(), nom_x_angle, nom_y_angle) + rotated_uxs, rotated_uys, rotated_uzs = passive_rotate_arrs(old_beam.uxs(), old_beam.uys(), old_beam.uzs(), nom_x_angle, nom_y_angle) + rotated_ux_offset, rotated_uy_offset, rotated_uz_offset = passive_rotate_arrs(old_beam.ux_offset(), old_beam.uy_offset(), old_beam.uz_offset(), nom_x_angle, nom_y_angle) + + # Compare the rotated arrays + assert np.allclose(beam.zs(), rotated_zs, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.xs(), rotated_xs, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.ys(), rotated_ys, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uzs(), rotated_uzs, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uxs(), rotated_uxs, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uys(), rotated_uys, rtol=1e-7, atol=1e-13) + assert np.isclose(beam.x_angle(), np.arcsin(rotated_ux_offset/rotated_uz_offset), rtol=np.abs(nom_x_angle)*1e-3, atol=np.abs(nom_x_angle)*2e-3) + assert np.isclose(beam.y_angle(), np.arcsin(rotated_uy_offset/rotated_uz_offset), rtol=np.abs(nom_y_angle)*1e-3, atol=np.abs(nom_y_angle)*2e-3) + + # nom_x_angle = random.uniform(-np.pi/2, np.pi/2) + # beam.rotate_coord_sys_3D(y_axis, nom_x_angle, x_axis, 0.0, invert=False) # Rotate beam 90 degrees around the y-axis. + # assert np.isclose(beam.x_tilt_angle(), nom_x_angle) # TODO: test un-rotate \ No newline at end of file From 00afa1fafd199a761dc3031c69abe23ed59e3853 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Thu, 27 Mar 2025 14:29:58 +0100 Subject: [PATCH 15/51] Updates to the rotation tets in test_beam.py. --- tests/test_beam.py | 132 ++++++++++++++++++++++++++++++++------------- 1 file changed, 95 insertions(+), 37 deletions(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index 10320657..136e1f0e 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -571,7 +571,7 @@ def test_add_pointing_tilts(): # Tilt the beam using its angular offset beam.add_pointing_tilts() - # Rotate the positions and proper velocities of all particles with written out formulas for comparison. Note the sign convention for y_angle. + # Rotate the positions of all particles with written out formulas for comparison. Note the sign convention for y_angle. rotated_xs, rotated_ys, rotated_zs = active_rotate_arrs(initial_beam.xs(), initial_beam.ys(), initial_beam.zs(), start_x_angle, -start_y_angle) # Examine the resulting beam @@ -622,10 +622,6 @@ def test_xy_rotate_coord_sys1(): assert np.isclose(beam.x_angle(), np.arcsin(rotated_ux_offset/rotated_uz_offset), rtol=np.abs(beam.x_angle())*1e-3, atol=np.abs(beam.x_angle())*2e-3) assert np.isclose(beam.y_angle(), np.arcsin(rotated_uy_offset/rotated_uz_offset), rtol=1e-7, atol=1e-13) - # print(nom_x_angle, beam.x_tilt_angle(), np.arcsin(rotated_ux_offset/rotated_uz_offset)) - # assert np.isclose(beam.x_tilt_angle(), np.arcsin(rotated_ux_offset/rotated_uz_offset), rtol=np.abs(beam.x_angle())*1e-3, atol=np.abs(beam.x_angle())*2e-3) - # assert np.isclose(beam.y_tilt_angle(), np.arcsin(rotated_uy_offset/rotated_uz_offset), rtol=1e-7, atol=1e-13) - @pytest.mark.beam def test_xy_rotate_coord_sys2(): @@ -662,9 +658,63 @@ def test_xy_rotate_coord_sys2(): assert np.isclose(beam.x_angle(), np.arcsin(rotated_ux_offset/rotated_uz_offset), rtol=1e-7, atol=1e-13) assert np.isclose(beam.y_angle(), np.arcsin(rotated_uy_offset/rotated_uz_offset), rtol=np.abs(nom_y_angle)*1e-3, atol=np.abs(nom_y_angle)*2e-3) - # print(nom_y_angle, beam.y_tilt_angle(), np.arcsin(rotated_uy_offset/rotated_uz_offset)) - # assert np.isclose(beam.y_tilt_angle(), np.arcsin(rotated_uy_offset/rotated_uz_offset), rtol=np.abs(nom_y_angle)*1e-3, atol=np.abs(nom_y_angle)*2e-3) - # assert np.isclose(beam.x_tilt_angle(), np.arcsin(rotated_ux_offset/rotated_uz_offset), rtol=1e-7, atol=1e-13) + +@pytest.mark.beam +def test_xy_rotate_coord_sys3(): + "Test adding creating a tilted beam and then align the z-axis to the drive beam propagation axis using passive transformation to rotate the frame of the beam." + + np.random.seed(42) + + start_x_angle = -2.82328e-08 # [rad], define an angle in the zx-plane. + start_y_angle = 7.040999e-09 # [rad], define an angle in the zy-plane. + + # Create a source with angular offsets, but not tilted in space + source = setup_trapezoid_source(current_head=0.1e3, bunch_length=1050e-6, z_offset=1615e-6, x_offset=0.0, y_offset=0.0, x_angle=start_x_angle, y_angle=start_y_angle, enable_xy_jitter=False, enable_xpyp_jitter=False) + + # Generate a beam + beam = source.track() + initial_beam = copy.deepcopy(beam) # Has angular offsets, but not tilted in space + + # Tilt the beam using its angular offset + beam.add_pointing_tilts() + + # Rotate the positions of all particles with written out formulas for comparison. Note the sign convention for y_angle. + rotated_xs, rotated_ys, rotated_zs = active_rotate_arrs(initial_beam.xs(), initial_beam.ys(), initial_beam.zs(), start_x_angle, -start_y_angle) + + # Examine the tilted beam + assert np.isclose(beam.x_angle(), start_x_angle, rtol=1e-3, atol=1e-11) + assert np.isclose(beam.y_angle(), start_y_angle, rtol=1e-3, atol=1e-11) + assert np.allclose(beam.uxs(), initial_beam.uxs(), rtol=1e-15, atol=0.0) # The proper velocities should not change. + assert np.allclose(beam.uys(), initial_beam.uys(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.uzs(), initial_beam.uzs(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.xs(), rotated_xs, rtol=1e-8, atol=0.0) + assert np.allclose(beam.ys(), rotated_ys, rtol=1e-8, atol=0.0) + assert np.allclose(beam.zs(), rotated_zs, rtol=1e-8, atol=0.0) + + # Calculate the angles that will be used to rotate the beams' frame + rotation_angle_x, rotation_angle_y = beam.beam_alignment_angles() + rotation_angle_y = -rotation_angle_y # Minus due to right hand rule. + + assert np.isclose(rotation_angle_x, start_x_angle, rtol=1e-10, atol=0.0) + assert np.isclose(rotation_angle_y, -start_y_angle, rtol=1e-10, atol=0.0) + + + # Use passive transformation to rotate the frame of the beam + beam.xy_rotate_coord_sys(rotation_angle_x, rotation_angle_y) # Align the z-axis to the drive beam propagation. + + # Rotate the proper velocities of all particles with written out formulas for comparison. Note the sign convention for y_angle. + rotated_uxs, rotated_uys, rotated_uzs = passive_rotate_arrs(initial_beam.uxs(), initial_beam.uys(), initial_beam.uzs(), rotation_angle_x, rotation_angle_y) + + # Examine the aligned beam + assert beam.x_angle() < 1e-15 # The angular offsets should be very small + assert beam.y_angle() < 1e-15 + assert np.allclose(beam.uxs(), rotated_uxs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.uys(), rotated_uys, rtol=1e-15, atol=0.0) + assert np.allclose(beam.uzs(), rotated_uzs, rtol=1e-15, atol=0.0) + # The position arrays should have been rotated back to when the beam only had angular offsets, but not tilted in space + assert np.allclose(beam.xs(), initial_beam.xs(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.ys(), initial_beam.ys(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.zs(), initial_beam.zs(), rtol=1e-15, atol=0.0) @pytest.mark.beam @@ -680,38 +730,46 @@ def test_rotate_coord_sys_3D(): source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0) old_beam = source.track() old_beam.add_pointing_tilts() # Add an initial tilt in the zy-plane. - #old_beam = copy.deepcopy(beam) x_axis = np.array([0, 1, 0]) # Axis as an unit vector. Axis permutaton is zxy. y_axis = np.array([0, 0, 1]) - nom_x_angles = np.concatenate((-np.logspace(-9, np.log10(0.11), 10), np.logspace(-9, -1, 10))) # [rad] - nom_y_angles = np.concatenate((-np.logspace(-9, np.log10(0.11), 10), np.logspace(-9, -1, 10))) # [rad] + nom_x_angles = np.concatenate((-np.logspace(np.log10(0.11), -9, 10), np.logspace(-8.9, -1, 10))) # [rad] + nom_y_angles = np.concatenate((-np.logspace(np.log10(0.09), -8.1, 10), np.logspace(-9, -0.97, 10))) # [rad] for i in range(len(nom_x_angles)): + for j in range(len(nom_y_angles)): + + beam = copy.deepcopy(old_beam) + + nom_x_angle = nom_x_angles[i] + nom_y_angle = nom_y_angles[j] + beam.rotate_coord_sys_3D(y_axis, nom_x_angle, x_axis, nom_y_angle, invert=False) + + # Roatate the positions and proper velocities of all particles with written out formulas for comparison + rotated_xs, rotated_ys, rotated_zs = passive_rotate_arrs(old_beam.xs(), old_beam.ys(), old_beam.zs(), nom_x_angle, nom_y_angle) + rotated_uxs, rotated_uys, rotated_uzs = passive_rotate_arrs(old_beam.uxs(), old_beam.uys(), old_beam.uzs(), nom_x_angle, nom_y_angle) + rotated_ux_offset, rotated_uy_offset, rotated_uz_offset = passive_rotate_arrs(old_beam.ux_offset(), old_beam.uy_offset(), old_beam.uz_offset(), nom_x_angle, nom_y_angle) + + # Compare the rotated arrays + assert np.allclose(beam.zs(), rotated_zs, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.xs(), rotated_xs, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.ys(), rotated_ys, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uzs(), rotated_uzs, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uxs(), rotated_uxs, rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uys(), rotated_uys, rtol=1e-7, atol=1e-13) + assert np.isclose(beam.x_angle(), np.arcsin(rotated_ux_offset/rotated_uz_offset), rtol=np.abs(nom_x_angle)*1e-3, atol=np.abs(nom_x_angle)*2e-3) + assert np.isclose(beam.y_angle(), np.arcsin(rotated_uy_offset/rotated_uz_offset), rtol=np.abs(nom_y_angle)*1e-3, atol=np.abs(nom_y_angle)*2e-3) + + # Un-rotate + beam.rotate_coord_sys_3D(y_axis, nom_x_angle, x_axis, nom_y_angle, invert=True) + + # Compare the rotated arrays + assert np.allclose(beam.zs(), old_beam.zs(), rtol=1e-7, atol=1e-13) + assert np.allclose(beam.xs(), old_beam.xs(), rtol=1e-7, atol=1e-13) + assert np.allclose(beam.ys(), old_beam.ys(), rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uzs(), old_beam.uzs(), rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uxs(), old_beam.uxs(), rtol=1e-7, atol=1e-13) + assert np.allclose(beam.uys(), old_beam.uys(), rtol=1e-7, atol=1e-13) + assert np.isclose(beam.x_angle(), old_beam.x_angle(), rtol=1e-7, atol=1e-13) + assert np.isclose(beam.y_angle(), old_beam.y_angle(), rtol=1e-7, atol=1e-13) - beam = copy.deepcopy(old_beam) - - nom_x_angle = nom_x_angles[i] - nom_y_angle = nom_y_angles[i] - beam.rotate_coord_sys_3D(y_axis, nom_x_angle, x_axis, nom_y_angle, invert=False) - - # Roatate the positions and proper velocities of all particles with written out formulas for comparison - rotated_xs, rotated_ys, rotated_zs = passive_rotate_arrs(old_beam.xs(), old_beam.ys(), old_beam.zs(), nom_x_angle, nom_y_angle) - rotated_uxs, rotated_uys, rotated_uzs = passive_rotate_arrs(old_beam.uxs(), old_beam.uys(), old_beam.uzs(), nom_x_angle, nom_y_angle) - rotated_ux_offset, rotated_uy_offset, rotated_uz_offset = passive_rotate_arrs(old_beam.ux_offset(), old_beam.uy_offset(), old_beam.uz_offset(), nom_x_angle, nom_y_angle) - - # Compare the rotated arrays - assert np.allclose(beam.zs(), rotated_zs, rtol=1e-7, atol=1e-13) - assert np.allclose(beam.xs(), rotated_xs, rtol=1e-7, atol=1e-13) - assert np.allclose(beam.ys(), rotated_ys, rtol=1e-7, atol=1e-13) - assert np.allclose(beam.uzs(), rotated_uzs, rtol=1e-7, atol=1e-13) - assert np.allclose(beam.uxs(), rotated_uxs, rtol=1e-7, atol=1e-13) - assert np.allclose(beam.uys(), rotated_uys, rtol=1e-7, atol=1e-13) - assert np.isclose(beam.x_angle(), np.arcsin(rotated_ux_offset/rotated_uz_offset), rtol=np.abs(nom_x_angle)*1e-3, atol=np.abs(nom_x_angle)*2e-3) - assert np.isclose(beam.y_angle(), np.arcsin(rotated_uy_offset/rotated_uz_offset), rtol=np.abs(nom_y_angle)*1e-3, atol=np.abs(nom_y_angle)*2e-3) - - # nom_x_angle = random.uniform(-np.pi/2, np.pi/2) - # beam.rotate_coord_sys_3D(y_axis, nom_x_angle, x_axis, 0.0, invert=False) # Rotate beam 90 degrees around the y-axis. - # assert np.isclose(beam.x_tilt_angle(), nom_x_angle) - - # TODO: test un-rotate \ No newline at end of file From e9634d2d6e5c22b34284e4b00dfe70d63c1d67b7 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Fri, 28 Mar 2025 00:18:37 +0100 Subject: [PATCH 16/51] Changed proper_velocity2momentum() in relativity.py to calculate momentum directly as m*u. --- abel/utilities/relativity.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/abel/utilities/relativity.py b/abel/utilities/relativity.py index 057a2007..9ffe37dd 100644 --- a/abel/utilities/relativity.py +++ b/abel/utilities/relativity.py @@ -54,8 +54,10 @@ def proper_velocity2gamma(u): return np.sign(u) * np.sqrt(1+(u/SI.c)**2) # convert proper velocity to momentum [kg m/s] -def proper_velocity2momentum(u): - return gamma2momentum(proper_velocity2gamma(u)) +# def proper_velocity2momentum(u): +# return gamma2momentum(proper_velocity2gamma(u)) +def proper_velocity2momentum(u, m=SI.m_e): + return m*u # convert proper velocity to energy def proper_velocity2energy(u, unit=defaultUnitE, m=SI.m_e): From eb906047c1f91eb746d137e42e5ea50cca433556 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Fri, 28 Mar 2025 00:20:38 +0100 Subject: [PATCH 17/51] Changed pxs(), pys() and pzs() to reflect the changes done to proper_velocity2momentum() in relativity.py where the momentum is now calculated as m*u. --- abel/classes/beam.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/abel/classes/beam.py b/abel/classes/beam.py index d5d4f008..8a4baa2e 100644 --- a/abel/classes/beam.py +++ b/abel/classes/beam.py @@ -241,11 +241,11 @@ def rs(self): return np.sqrt(self.xs()**2 + self.ys()**2) def pxs(self): - return proper_velocity2momentum(self.uxs()) + return proper_velocity2momentum(self.uxs(), m=self.particle_mass) def pys(self): - return proper_velocity2momentum(self.uys()) + return proper_velocity2momentum(self.uys(), m=self.particle_mass) def pzs(self): - return proper_velocity2momentum(self.uzs()) + return proper_velocity2momentum(self.uzs(), m=self.particle_mass) def xps(self): return self.uxs()/self.uzs() From 95c808506180fc1cf476a66329a75adcadd5b30b Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Fri, 28 Mar 2025 00:23:07 +0100 Subject: [PATCH 18/51] Added more tolerances to phase space tests and added a large amount of tests for beam statistics. --- tests/test_beam.py | 352 +++++++++++++++++++++++++++++++++------------ 1 file changed, 262 insertions(+), 90 deletions(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index 136e1f0e..21231b99 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -22,6 +22,7 @@ import pytest from abel import * +from abel.utilities.beam_physics import generate_trace_space import random @@ -121,33 +122,38 @@ def test_set_phase_space(): beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) assert len(beam) == num_particles - assert np.isclose(beam.particle_mass, SI.m_e) - assert np.isclose(beam.charge(), Q) + assert np.isclose(beam.particle_mass, SI.m_e, rtol=1e-15, atol=0.0) + assert np.isclose(beam.charge(), Q, rtol=1e-15, atol=0.0) + assert np.isclose(beam.abs_charge(), np.abs(Q), rtol=1e-15, atol=0.0) + assert np.isclose(beam.total_particles(), 1.0e10, rtol=1e-15, atol=0.0) assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/num_particles/(-SI.e)) - assert np.allclose(beam.xs(), xs) - assert np.allclose(beam.ys(), ys) - assert np.allclose(beam.zs(), zs) - assert np.allclose(beam.uxs(), uxs) - assert np.allclose(beam.uys(), uys) - assert np.allclose(beam.uzs(), uzs) - assert np.allclose(beam.qs(), np.ones_like(xs)*Q/num_particles) - - assert np.allclose(beam.xps(), uxs/uzs) - assert np.allclose(beam.yps(), uys/uzs) - assert np.allclose(beam.pxs(), SI.m_e*uxs) - assert np.allclose(beam.pys(), SI.m_e*uys) - assert np.allclose(beam.pzs(), SI.m_e*uzs) - assert np.allclose(beam.Es(), np.sqrt((SI.m_e*uzs*SI.c)**2 + (SI.m_e*SI.c**2)**2)/SI.e ) + assert np.allclose(beam.xs(), xs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.ys(), ys, rtol=1e-15, atol=0.0) + assert np.allclose(beam.zs(), zs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.uxs(), uxs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.uys(), uys, rtol=1e-15, atol=0.0) + assert np.allclose(beam.uzs(), uzs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.qs(), np.ones_like(xs)*Q/num_particles, rtol=1e-15, atol=0.0) + + assert np.allclose(beam.xps(), uxs/uzs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.yps(), uys/uzs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.pxs(), SI.m_e*uxs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.pys(), SI.m_e*uys, rtol=1e-15, atol=0.0) + assert np.allclose(beam.pzs(), SI.m_e*uzs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.Es(), np.sqrt((SI.m_e*uzs*SI.c)**2 + (SI.m_e*SI.c**2)**2)/SI.e, rtol=1e-15, atol=0.0) @pytest.mark.beam def test_set_phase_space2(): "Verify that the phase space is set correctly." + + np.random.seed(42) + beam = Beam() - num_particles = 10042 - xs = np.random.normal(1.1, 2.0e-6, num_particles) - ys = np.random.normal(0.3, 1.0e-6, num_particles) - zs = np.random.normal(5.6, 50.0e-6, num_particles) + num_particles = 100042 + xs = np.random.normal(1.1e-6, 2.0e-6, num_particles) + ys = np.random.normal(0.3e-6, 1.0e-6, num_particles) + zs = np.random.normal(5.6e-6, 50.0e-6, num_particles) xps = np.random.normal(1.1e-5, 1.5e-7, num_particles) yps = np.random.normal(3.2e-6, 1.0e-8, num_particles) Es = np.random.normal(500e9, 0.02*500e9, num_particles) @@ -156,37 +162,40 @@ def test_set_phase_space2(): beam.set_phase_space(Q, xs, ys, zs, xps=xps, yps=yps, Es=Es) assert len(beam) == num_particles - assert np.isclose(beam.particle_mass, SI.m_e) - assert np.isclose(beam.charge(), Q) - assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/num_particles/(-SI.e)) - assert np.isclose(beam.energy(), 500e9, rtol=0.0001*500e9, atol=1e9) - assert np.isclose(beam.gamma(), 500e9*SI.e/SI.m_e/SI.c**2, rtol=0.0001*500e9*SI.e/SI.m_e/SI.c**2, atol=200) + assert np.isclose(beam.particle_mass, SI.m_e, rtol=1e-15, atol=0.0) + assert np.isclose(beam.charge(), Q, rtol=1e-15, atol=0.0) + assert np.isclose(beam.charge_sign(), -1, rtol=1e-15, atol=0.0) + assert np.isclose(beam.total_energy(), SI.e * np.nansum(beam.weightings()*beam.Es()), rtol=1e-15, atol=0.0) + assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/num_particles/(-SI.e), rtol=1e-15, atol=0.0) + + assert np.isclose(beam.energy(), 500e9, rtol=1e-4, atol=1e9) + assert np.isclose(beam.gamma(), 500e9*SI.e/SI.m_e/SI.c**2, rtol=1e-3, atol=200) assert np.isclose(beam.rel_energy_spread(), 0.02, rtol=0.001, atol=0.001) - assert np.isclose(beam.z_offset(), 5.6) - assert np.isclose(beam.x_offset(), 1.1) - assert np.isclose(beam.y_offset(), 0.3) - assert np.isclose(beam.bunch_length(), 50.0e-6, rtol=0.005, atol=0.03) + assert np.isclose(beam.z_offset(), 5.6e-6, rtol=0.3, atol=0.0) + assert np.isclose(beam.x_offset(), 1.1e-6, rtol=0.05, atol=0.0) + assert np.isclose(beam.y_offset(), 0.3e-6, rtol=0.03, atol=0.0) + assert np.isclose(beam.bunch_length(), 50.0e-6, rtol=1e-4, atol=0.00) assert np.isclose(beam.beam_size_x(), 2.0e-6, rtol=0.005, atol=0.03) assert np.isclose(beam.beam_size_y(), 1.0e-6, rtol=0.005, atol=0.03) - assert np.isclose(beam.x_angle(), 1.1e-5) - assert np.isclose(beam.y_angle(), 3.2e-6) - assert np.isclose(beam.divergence_x(), 1.5e-7) - assert np.isclose(beam.divergence_y(), 1.0e-8) - - assert np.allclose(beam.xs(), xs) - assert np.allclose(beam.ys(), ys) - assert np.allclose(beam.zs(), zs) - assert np.allclose(beam.xps(), xps, rtol=1e-05, atol=1e-08) - assert np.allclose(beam.yps(), yps, rtol=1e-05, atol=1e-08) - assert np.allclose(beam.Es(), Es) - assert np.allclose(beam.qs(), np.ones_like(xs)*Q/num_particles) - - assert np.allclose(beam.uzs(), np.sqrt((Es*SI.e/SI.m_e/SI.c)**2 - SI.c**2) ) - assert np.allclose(beam.uxs(), xps*beam.uzs()) - assert np.allclose(beam.uys(), yps*beam.uzs()) - assert np.allclose(beam.pxs(), SI.m_e*xps*beam.uzs(), rtol=1e-05, atol=1e-25) - assert np.allclose(beam.pys(), SI.m_e*yps*beam.uzs(), rtol=1e-05, atol=1e-25) - assert np.allclose(beam.pzs(), SI.m_e*beam.uzs(), rtol=1e-05, atol=1e-19) + assert np.isclose(beam.x_angle(), 1.1e-5, rtol=1e-5, atol=0.0) + assert np.isclose(beam.y_angle(), 3.2e-6, rtol=1e-4, atol=0.0) + assert np.isclose(beam.divergence_x(), 1.5e-7, rtol=1e-2, atol=0.0) + assert np.isclose(beam.divergence_y(), 1.0e-8, rtol=1e-2, atol=0.0) + + assert np.allclose(beam.xs(), xs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.ys(), ys, rtol=1e-15, atol=0.0) + assert np.allclose(beam.zs(), zs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.xps(), xps, rtol=1e-15, atol=0.0) + assert np.allclose(beam.yps(), yps, rtol=1e-15, atol=0.0) + assert np.allclose(beam.Es(), Es, rtol=1e-15, atol=0.0) + assert np.allclose(beam.qs(), np.ones_like(xs)*Q/num_particles, rtol=1e-15, atol=0.0) + + assert np.allclose(beam.uzs(), np.sqrt((Es*SI.e/SI.m_e/SI.c)**2 - SI.c**2), rtol=1e-15, atol=0.0) + assert np.allclose(beam.uxs(), xps*beam.uzs(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.uys(), yps*beam.uzs(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.pxs(), SI.m_e*xps*beam.uzs(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.pys(), SI.m_e*yps*beam.uzs(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.pzs(), SI.m_e*beam.uzs(), rtol=1e-15, atol=0.0) @pytest.mark.beam @@ -204,23 +213,23 @@ def test_set_phase_space3(): beam.set_phase_space(Q, xs, ys, zs, pxs=pxs, pys=pys, pzs=pzs) assert len(beam) == num_particles - assert np.isclose(beam.particle_mass, SI.m_e) - assert np.isclose(beam.charge(), Q) - assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/num_particles/(-SI.e)) - assert np.allclose(beam.xs(), xs) - assert np.allclose(beam.ys(), ys) - assert np.allclose(beam.zs(), zs) - assert np.allclose(beam.pxs(), pxs, rtol=1e-05, atol=1e-25) - assert np.allclose(beam.pys(), pys, rtol=1e-05, atol=1e-25) - assert np.allclose(beam.pzs(), pzs, rtol=1e-05, atol=1e-19) - assert np.allclose(beam.qs(), np.ones_like(xs)*Q/num_particles) - - assert np.allclose(beam.xps(), pxs/pzs) - assert np.allclose(beam.yps(), pys/pzs) - assert np.allclose(beam.uxs(), pxs/SI.m_e) - assert np.allclose(beam.uys(), pys/SI.m_e) - assert np.allclose(beam.uzs(), pzs/SI.m_e) - assert np.allclose(beam.Es(), np.sqrt((pzs*SI.c)**2 + (SI.m_e*SI.c**2)**2)/SI.e ) + assert np.isclose(beam.particle_mass, SI.m_e, rtol=1e-15, atol=0.0) + assert np.isclose(beam.charge(), Q, rtol=1e-15, atol=0.0) + assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/num_particles/(-SI.e), rtol=1e-15, atol=0.0) + assert np.allclose(beam.xs(), xs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.ys(), ys, rtol=1e-15, atol=0.0) + assert np.allclose(beam.zs(), zs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.pxs(), pxs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.pys(), pys, rtol=1e-15, atol=0.0) + assert np.allclose(beam.pzs(), pzs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.qs(), np.ones_like(xs)*Q/num_particles, rtol=1e-15, atol=0.0) + + assert np.allclose(beam.xps(), pxs/pzs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.yps(), pys/pzs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.uxs(), pxs/SI.m_e, rtol=1e-15, atol=0.0) + assert np.allclose(beam.uys(), pys/SI.m_e, rtol=1e-15, atol=0.0) + assert np.allclose(beam.uzs(), pzs/SI.m_e, rtol=1e-15, atol=0.0) + assert np.allclose(beam.Es(), np.sqrt((pzs*SI.c)**2 + (SI.m_e*SI.c**2)**2)/SI.e, rtol=1e-15, atol=0.0) @pytest.mark.beam @@ -239,22 +248,22 @@ def test_set_phase_space4(): assert len(beam) == num_particles assert np.isclose(beam.particle_mass, SI.m_e) - assert np.allclose(beam.xs(), xs) - assert np.allclose(beam.ys(), ys) - assert np.allclose(beam.zs(), zs) - assert np.allclose(beam.uxs(), uxs) - assert np.allclose(beam.yps(), yps) + assert np.allclose(beam.xs(), xs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.ys(), ys, rtol=1e-15, atol=0.0) + assert np.allclose(beam.zs(), zs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.uxs(), uxs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.yps(), yps, rtol=1e-15, atol=0.0) assert np.allclose(beam.pzs(), pzs, rtol=1e-05, atol=1e-25) - assert np.allclose(beam.qs(), np.ones_like(xs)*Q/num_particles) - assert np.isclose(beam.charge(), Q) - assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/num_particles/(-SI.e)) + assert np.allclose(beam.qs(), np.ones_like(xs)*Q/num_particles, rtol=1e-15, atol=0.0) + assert np.isclose(beam.charge(), Q, rtol=1e-15, atol=0.0) + assert np.allclose(beam.weightings(), np.ones_like(xs)*Q/num_particles/(-SI.e), rtol=1e-15, atol=0.0) - assert np.allclose(beam.uzs(), pzs/SI.m_e) - assert np.allclose(beam.xps(), uxs/beam.uzs()) - assert np.allclose(beam.uys(), yps*beam.uzs()) - assert np.allclose(beam.pxs(), SI.m_e*uxs, rtol=1e-05, atol=1e-25) - assert np.allclose(beam.pys(), SI.m_e*yps*beam.uzs(), rtol=1e-05, atol=1e-25) - assert np.allclose(beam.Es(), np.sqrt((pzs*SI.c)**2 + (SI.m_e*SI.c**2)**2)/SI.e ) + assert np.allclose(beam.uzs(), pzs/SI.m_e, rtol=1e-15, atol=0.0) + assert np.allclose(beam.xps(), uxs/beam.uzs(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.uys(), yps*beam.uzs(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.pxs(), SI.m_e*uxs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.pys(), SI.m_e*yps*beam.uzs(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.Es(), np.sqrt((pzs*SI.c)**2 + (SI.m_e*SI.c**2)**2)/SI.e, rtol=1e-15, atol=0.0) @pytest.mark.beam @@ -342,7 +351,7 @@ def test_len(): assert len(beam) == num_particles -# @pytest.mark.beam +# @pytest.mark.beam TODO # def test_str(): # "Test the __str__ method for correct formatting of beam properties." # beam = Beam() @@ -401,17 +410,17 @@ def test_scale_charge(): # Scale up charge beam.scale_charge(-SI.e * 2.0e10) scaled_charges = beam.qs() - assert np.isclose(scaled_charges.sum(), -SI.e * 2.0e10) # Check total charge - assert np.allclose(scaled_charges / original_charges, 2.0) # Charges scaled proportionally + assert np.isclose(scaled_charges.sum(), -SI.e * 2.0e10, rtol=1e-15, atol=0.0) # Check total charge + assert np.allclose(scaled_charges / original_charges, 2.0, rtol=1e-15, atol=0.0) # Charges scaled proportionally # Scale down charge beam.scale_charge(-SI.e * 0.5e10) - assert np.isclose(scaled_charges.sum(), -SI.e * 0.5e10) + assert np.isclose(scaled_charges.sum(), -SI.e * 0.5e10, rtol=1e-15, atol=0.0) # Edge case: zero charge beam.scale_charge(0) scaled_charges = beam.qs() - assert np.isclose(scaled_charges.sum(), 0) + assert np.isclose(scaled_charges.sum(), 0, rtol=1e-15, atol=0.0) @pytest.mark.beam @@ -441,11 +450,11 @@ def test_scale_energy(): scaled_mean_energy = weighted_mean(scaled_energies, beam.weightings()) assert np.isclose(scaled_mean_energy, 1.7e8, rtol=0.01, atol=1e8) - # # Edge case: zero energy - # try: - # beam.scale_energy(0) - # except ValueError as e: - # assert str(e) == "Energy cannot be scaled to zero" + # Edge case: zero energy + try: + beam.scale_energy(0) + except ValueError as err: + assert str(err) == 'Es contains values that are too small.' ############# Tests on bunch pattern ############# @@ -454,6 +463,170 @@ def test_scale_energy(): ############# Tests for beam statistics ############# # Need tests for beam parameter calculations such as offsets, emittance, beta functions, peak current +@pytest.mark.beam +def test_param_calcs_generate_trace_space(): + "Test the beam parameter calculations using a trace space generated with generate_trace_space()." + + np.random.seed(42) + + alpha_x = -0.239 + alpha_y = -0.171 + beta_x = 0.120 # [m] + beta_y = 0.120 # [m] + geo_emitt_x = 2.552865e-09 # [m rad] + geo_emitt_y = 1.750833e-11 # [m rad] + + # Generate trace spaces + xs, xps = generate_trace_space(geo_emitt_x, beta_x, alpha_x, 10011, symmetrize=False) + ys, yps = generate_trace_space(geo_emitt_y, beta_y, alpha_y, 10011, symmetrize=False) + zs = np.random.normal(loc=0.0, scale=40.0e-6, size=10011) + Es = np.random.normal(loc=3e9, scale=0.02*3e9, size=10011) + + beam = Beam() + beam.set_phase_space(xs=xs, ys=ys, zs=zs, xps=xps, yps=yps, Es=Es, Q=-e*1.0e10) + + # Examine the beam parameters + assert np.isclose(np.std(xs), np.sqrt(geo_emitt_x*beta_x), rtol=1e-2, atol=0.0) # Beam size + assert np.isclose(np.std(ys), np.sqrt(geo_emitt_y*beta_y), rtol=1e-2, atol=0.0) + assert np.isclose(np.std(Es), 0.02*3e9, rtol=0.01, atol=0.0) + assert np.isclose(np.std(zs), 50.0e-6, rtol=0.005, atol=0.03) + assert np.isclose(beam.beam_size_x(), np.sqrt(geo_emitt_x*beta_x), rtol=1e-2, atol=0.0) # Beam size + assert np.isclose(beam.beam_size_y(), np.sqrt(geo_emitt_y*beta_y), rtol=1e-2, atol=0.0) + assert np.isclose(beam.divergence_x(), np.sqrt(geo_emitt_x/beta_x), rtol=5e-2, atol=0.0) + assert np.isclose(beam.divergence_y(), np.sqrt(geo_emitt_y/beta_y), rtol=5e-2, atol=0.0) + assert np.isclose(beam.energy_spread(), 0.02*3e9, rtol=0.01, atol=0.0) + assert np.isclose(beam.bunch_length(), 50.0e-6, rtol=0.005, atol=0.03) + + assert np.isclose(beam.alpha_x(), alpha_x, rtol=6e-2, atol=0.0) + assert np.isclose(beam.alpha_y(), alpha_y, rtol=6e-2, atol=0.0) + assert np.isclose(beam.beta_x(), beta_x, rtol=2e-3, atol=0.0) + assert np.isclose(beam.beta_y(), beta_y, rtol=1.5e-2, atol=0.0) + assert np.isclose(beam.geom_emittance_x(), geo_emitt_x, rtol=1e-2, atol=0.0) + assert np.isclose(beam.geom_emittance_y(), geo_emitt_y, rtol=1e-2, atol=0.0) + assert np.isclose(beam.norm_emittance_x(), geo_emitt_x*beam.gamma(), rtol=1e-2, atol=0.0) + assert np.isclose(beam.norm_emittance_y(), geo_emitt_y*beam.gamma(), rtol=1e-2, atol=0.0) + + +@pytest.mark.beam +def test_param_calcs_generate_trace_space_xy(): + "Test the beam parameter calculations using a trace space generated with generate_trace_space_xy()." + + np.random.seed(42) + + alpha_x = -0.239 + alpha_y = -0.171 + beta_x = 0.120 # [m] + beta_y = 0.120 # [m] + geo_emitt_x = 2.552865e-09 # [m rad] + geo_emitt_y = 1.750833e-11 # [m rad] + num_particles = 200011 + + # Generate trace space + xs, xps, ys, yps = generate_trace_space_xy(geo_emitt_x, beta_x, alpha_x, geo_emitt_y, beta_y, alpha_y, num_particles, L=0, symmetrize=False) + zs = np.random.normal(loc=0.0, scale=40.0e-6, size=num_particles) + Es = np.random.normal(loc=3e9, scale=0.02*3e9, size=num_particles) + + beam = Beam() + beam.set_phase_space(xs=xs, ys=ys, zs=zs, xps=xps, yps=yps, Es=Es, Q=-e*1.0e10) + + # Examine the beam parameters + assert np.isclose(np.std(xs), np.sqrt(geo_emitt_x*beta_x), rtol=1e-2, atol=0.0) # Beam size + assert np.isclose(np.std(ys), np.sqrt(geo_emitt_y*beta_y), rtol=1e-2, atol=0.0) + assert np.isclose(np.std(Es), 0.02*3e9, rtol=0.005, atol=0.0) + assert np.isclose(np.std(zs), 50.0e-6, rtol=0.005, atol=0.03) + assert np.isclose(beam.beam_size_x(), np.sqrt(geo_emitt_x*beta_x), rtol=1e-3, atol=0.0) # Beam size + assert np.isclose(beam.beam_size_y(), np.sqrt(geo_emitt_y*beta_y), rtol=5e-3, atol=0.0) + assert np.isclose(beam.divergence_x(), np.sqrt(geo_emitt_x/beta_x), rtol=5e-2, atol=0.0) + assert np.isclose(beam.divergence_y(), np.sqrt(geo_emitt_y/beta_y), rtol=5e-2, atol=0.0) + assert np.isclose(beam.energy_spread(), 0.02*3e9, rtol=0.005, atol=0.0) + assert np.isclose(beam.bunch_length(), 50.0e-6, rtol=0.005, atol=0.03) + + assert np.isclose(beam.alpha_x(), alpha_x, rtol=1e-2, atol=0.0) + assert np.isclose(beam.alpha_y(), alpha_y, rtol=1e-2, atol=0.0) + assert np.isclose(beam.beta_x(), beta_x, rtol=1e-3, atol=0.0) + assert np.isclose(beam.beta_y(), beta_y, rtol=3e-3, atol=0.0) + assert np.isclose(beam.geom_emittance_x(), geo_emitt_x, rtol=1e-2, atol=0.0) + assert np.isclose(beam.geom_emittance_y(), geo_emitt_y, rtol=1e-2, atol=0.0) + assert np.isclose(beam.norm_emittance_x(), geo_emitt_x*beam.gamma(), rtol=1e-2, atol=0.0) + assert np.isclose(beam.norm_emittance_y(), geo_emitt_y*beam.gamma(), rtol=1e-2, atol=0.0) + + # Perform the same control with a symmetrised phase space + xs, xps, ys, yps = generate_trace_space_xy(geo_emitt_x, beta_x, alpha_x, geo_emitt_y, beta_y, alpha_y, num_particles, L=0, symmetrize=True) + num_tiling = 4 + num_particles_actual = round(num_particles/num_tiling) + zs = np.random.normal(loc=0.0, scale=40.0e-6, size=num_particles_actual) + Es = np.random.normal(loc=3e9, scale=0.02*3e9, size=num_particles_actual) + zs = np.tile(zs, num_tiling) + Es = np.tile(Es, num_tiling) + + beam = Beam() + beam.set_phase_space(xs=xs, ys=ys, zs=zs, xps=xps, yps=yps, Es=Es, Q=-e*1.0e10) + + assert np.isclose(np.std(xs), np.sqrt(geo_emitt_x*beta_x), rtol=1e-2, atol=0.0) # Beam size + assert np.isclose(np.std(ys), np.sqrt(geo_emitt_y*beta_y), rtol=5e-2, atol=0.0) + assert np.isclose(np.std(Es), 0.02*3e9, rtol=0.005, atol=0.0) + assert np.isclose(np.std(zs), 50.0e-6, rtol=0.005, atol=0.03) + assert np.isclose(beam.beam_size_x(), np.sqrt(geo_emitt_x*beta_x), rtol=1e-3, atol=0.0) # Beam size + assert np.isclose(beam.beam_size_y(), np.sqrt(geo_emitt_y*beta_y), rtol=5e-3, atol=0.0) + assert np.isclose(beam.divergence_x(), np.sqrt(geo_emitt_x/beta_x), rtol=5e-2, atol=0.0) + assert np.isclose(beam.divergence_y(), np.sqrt(geo_emitt_y/beta_y), rtol=5e-2, atol=0.0) + assert np.isclose(beam.energy_spread(), 0.02*3e9, rtol=0.01, atol=0.0) + assert np.isclose(beam.bunch_length(), 50.0e-6, rtol=0.005, atol=0.03) + + assert np.isclose(beam.alpha_x(), alpha_x, rtol=1e-2, atol=0.0) + assert np.isclose(beam.alpha_y(), alpha_y, rtol=4e-2, atol=0.0) + assert np.isclose(beam.beta_x(), beta_x, rtol=3e-3, atol=0.0) + assert np.isclose(beam.beta_y(), beta_y, rtol=5e-3, atol=0.0) + assert np.isclose(beam.geom_emittance_x(), geo_emitt_x, rtol=1e-2, atol=0.0) + assert np.isclose(beam.geom_emittance_y(), geo_emitt_y, rtol=1e-2, atol=0.0) + assert np.isclose(beam.norm_emittance_x(), geo_emitt_x*beam.gamma(), rtol=1e-2, atol=0.0) + assert np.isclose(beam.norm_emittance_y(), geo_emitt_y*beam.gamma(), rtol=1e-2, atol=0.0) + + +@pytest.mark.beam +def test_param_calcs_generate_symm_trace_space_xyz(): + "Test the beam parameter calculations using a trace space generated with generate_symm_trace_space_xyz()." + + np.random.seed(42) + + alpha_x = -0.239 + alpha_y = -0.171 + beta_x = 0.120 # [m] + beta_y = 0.120 # [m] + geo_emitt_x = 2.552865e-09 # [m rad] + geo_emitt_y = 1.750833e-11 # [m rad] + num_particles = 200011 + + # Generate trace space + xs, xps, ys, yps, zs, Es = generate_symm_trace_space_xyz(geo_emitt_x, beta_x, alpha_x, geo_emitt_y, beta_y, alpha_y, num_particles, bunch_length=50.0e-6, energy_spread=0.02*3e9, L=0) + Es += 3e9 # Add offset. + + beam = Beam() + beam.set_phase_space(xs=xs, ys=ys, zs=zs, xps=xps, yps=yps, Es=Es, Q=-e*1.0e10) + + # Examine the beam parameters + assert np.isclose(np.std(xs), np.sqrt(geo_emitt_x*beta_x), rtol=1e-2, atol=0.0) # Beam size + assert np.isclose(np.std(ys), np.sqrt(geo_emitt_y*beta_y), rtol=1e-2, atol=0.0) + assert np.isclose(np.std(Es), 0.02*3e9, rtol=0.005, atol=0.0) + assert np.isclose(np.std(zs), 50.0e-6, rtol=0.005, atol=0.03) + assert np.isclose(beam.beam_size_x(), np.sqrt(geo_emitt_x*beta_x), rtol=1e-3, atol=0.0) # Beam size + assert np.isclose(beam.beam_size_y(), np.sqrt(geo_emitt_y*beta_y), rtol=5e-3, atol=0.0) + assert np.isclose(beam.divergence_x(), np.sqrt(geo_emitt_x/beta_x), rtol=5e-2, atol=0.0) + assert np.isclose(beam.divergence_y(), np.sqrt(geo_emitt_y/beta_y), rtol=5e-2, atol=0.0) + assert np.isclose(beam.energy_spread(), 0.02*3e9, rtol=0.005, atol=0.0) + assert np.isclose(beam.bunch_length(), 50.0e-6, rtol=0.005, atol=0.03) + assert np.isclose(beam.peak_current(), -beam.charge()/(np.sqrt(2*np.pi)*beam.bunch_length())*SI.c, rtol=0.0, atol=3e2) + assert np.isclose(beam.peak_density(), beam.charge()/(SI.e*np.sqrt(2*np.pi)**3*beam.beam_size_x()*beam.beam_size_y()*beam.bunch_length()), rtol=1e-8, atol=0.0) + + assert np.isclose(beam.alpha_x(), alpha_x, rtol=3e-2, atol=0.0) + assert np.isclose(beam.alpha_y(), alpha_y, rtol=1e-2, atol=0.0) + assert np.isclose(beam.beta_x(), beta_x, rtol=3e-3, atol=0.0) + assert np.isclose(beam.beta_y(), beta_y, rtol=3e-3, atol=0.0) + assert np.isclose(beam.geom_emittance_x(), geo_emitt_x, rtol=1e-2, atol=0.0) + assert np.isclose(beam.geom_emittance_y(), geo_emitt_y, rtol=1e-2, atol=0.0) + assert np.isclose(beam.norm_emittance_x(), geo_emitt_x*beam.gamma(), rtol=1e-2, atol=0.0) + assert np.isclose(beam.norm_emittance_y(), geo_emitt_y*beam.gamma(), rtol=1e-2, atol=0.0) + ############# Tests for beam projections ############# # ... @@ -553,7 +726,6 @@ def test_beam_alignment_angles(): assert np.isclose(align_y_angle, start_y_angle, rtol=1e-5, atol=1e-13) - @pytest.mark.beam def test_add_pointing_tilts(): "Test ``Beam.add_pointing_tilts()``, which uses active transformation to tilt the beam in the zx- and zy-planes." From 94ab1fed9e56d152a1182febc6fcf7179e725701 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Fri, 28 Mar 2025 15:42:57 +0100 Subject: [PATCH 19/51] Added tests for beam projection methods in test_beam.py. --- tests/test_beam.py | 161 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 158 insertions(+), 3 deletions(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index 21231b99..e2932547 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -457,12 +457,13 @@ def test_scale_energy(): assert str(err) == 'Es contains values that are too small.' + ############# Tests on bunch pattern ############# +# TODO -############# Tests for beam statistics ############# -# Need tests for beam parameter calculations such as offsets, emittance, beta functions, peak current +############# Tests for beam statistics ############# @pytest.mark.beam def test_param_calcs_generate_trace_space(): "Test the beam parameter calculations using a trace space generated with generate_trace_space()." @@ -628,10 +629,139 @@ def test_param_calcs_generate_symm_trace_space_xyz(): assert np.isclose(beam.norm_emittance_y(), geo_emitt_y*beam.gamma(), rtol=1e-2, atol=0.0) + ############# Tests for beam projections ############# -# ... +@pytest.mark.beam +def test_current_profile(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=1.0e-6, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + + dIdt, ts = beam.current_profile() + assert np.isclose(np.max(np.abs(dIdt)), beam.peak_current(), rtol=1e-15, atol=0.0) + assert np.isclose(SI.c*ts.mean(), beam.z_offset(), rtol=1e-10, atol=0.0) + + Nbins = int(np.sqrt(len(beam)/2)) + bins = np.linspace(min(beam.ts()), max(beam.ts()), Nbins) + dIdt, ts = beam.current_profile(bins=bins) + assert np.isclose(np.max(np.abs(dIdt)), beam.peak_current(), rtol=1e-15, atol=0.0) + assert len(dIdt) == Nbins - 1 + assert len(ts) == Nbins - 1 + assert np.isclose(SI.c*ts.mean(), beam.z_offset(), rtol=1e-10, atol=0.0) +@pytest.mark.beam +def test_longitudinal_num_density(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=1.0e-6, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + dNdz, zs = beam.longitudinal_num_density() + assert np.isclose( np.sum( dNdz*np.diff(zs)[0] ), beam.total_particles(), rtol=1e-10, atol=0.0 ) + assert np.isclose(zs.mean(), beam.z_offset(), rtol=1e-10, atol=0.0) + + +@pytest.mark.beam +def test_energy_spectrum(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + dQdE, Es = beam.energy_spectrum() + assert np.isclose( np.sum( dQdE*np.diff(Es)[0] ), beam.charge(), rtol=1e-10, atol=0.0 ) + assert np.isclose( Es.mean(), beam.energy(), rtol=1e-10, atol=0.0 ) + + +@pytest.mark.beam +def test_rel_energy_spectrum(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + dQdE, rel_Es = beam.rel_energy_spectrum() + assert np.isclose( np.sum( dQdE*np.diff(rel_Es)[0] ), beam.charge(), rtol=1e-10, atol=0.0 ) + assert np.isclose( rel_Es.mean(), 0.0, rtol=0.0, atol=1e-10 ) + + +@pytest.mark.beam +def test_transverse_profile_x(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=1.0e-6, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + dQdx, xs = beam.transverse_profile_x() + assert np.isclose( np.sum( dQdx*np.diff(xs)[0] ), beam.charge(), rtol=1e-10, atol=0.0 ) + assert np.isclose( xs.mean(), beam.x_offset(), rtol=1e-10, atol=0.0 ) + + +@pytest.mark.beam +def test_transverse_profile_y(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=1.0e-6, x_angle=0.0, y_angle=0.0) + beam = source.track() + dQdy, ys = beam.transverse_profile_y() + assert np.isclose( np.sum( dQdy*np.diff(ys)[0] ), beam.charge(), rtol=1e-8, atol=0.0 ) + assert np.isclose( ys.mean(), beam.y_offset(), rtol=1e-10, atol=0.0 ) + + +@pytest.mark.beam +def test_transverse_profile_xp(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=1.0e-6, y_angle=0.0) + beam = source.track() + dQdxp, xps = beam.transverse_profile_xp() + assert np.isclose( np.sum( dQdxp*np.diff(xps)[0] ), beam.charge(), rtol=1e-10, atol=0.0 ) + assert np.isclose( xps.mean(), beam.x_angle(), rtol=1e-10, atol=0.0 ) + + +@pytest.mark.beam +def test_transverse_profile_yp(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=1.0e-6) + beam = source.track() + dQdyp, yps = beam.transverse_profile_yp() + assert np.isclose( np.sum( dQdyp*np.diff(yps)[0] ), beam.charge(), rtol=1e-10, atol=0.0 ) + assert np.isclose( yps.mean(), beam.y_angle(), rtol=1e-10, atol=0.0 ) + + +@pytest.mark.beam +def test_phase_space_density(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=1.2e-6, y_angle=0.3e-6) + beam = source.track() + density, xps, yps = beam.phase_space_density(beam.xps, beam.yps, hbins=None, vbins=None) + density_1d = np.sum(density*np.diff(xps)[0], axis=1) + assert np.isclose( np.sum(density_1d*np.diff(yps)[0]), beam.charge(), rtol=1e-10, atol=0.0 ) + assert np.isclose( xps.mean(), beam.x_angle(), rtol=1e-10, atol=0.0 ) + assert np.isclose( yps.mean(), beam.y_angle(), rtol=1e-10, atol=0.0 ) + + Nbins = int(np.sqrt(len(beam)/2)) + hbins = np.linspace(min(beam.xps()), max(beam.xps()), Nbins+1) + vbins = np.linspace(min(beam.yps()), max(beam.yps()), Nbins+2) + density, xps, yps = beam.phase_space_density(beam.xps, beam.yps, hbins, vbins) + density_1d = np.sum(density*np.diff(xps)[0], axis=1) + assert np.isclose( np.sum(density_1d*np.diff(yps)[0]), beam.charge(), rtol=1e-10, atol=0.0 ) + assert np.isclose( xps.mean(), beam.x_angle(), rtol=1e-10, atol=0.0 ) + assert np.isclose( yps.mean(), beam.y_angle(), rtol=1e-10, atol=0.0 ) + + +@pytest.mark.beam +def test_density_lps(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=1.0e-6, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + density, zs, Es = beam.density_lps(hbins=None, vbins=None) + density_1d = np.sum(density*np.diff(zs)[0], axis=1) + assert np.isclose( np.sum(density_1d*np.diff(Es)[0]), beam.charge(), rtol=1e-10, atol=0.0 ) + assert np.isclose( Es.mean(), beam.energy(), rtol=1e-10, atol=0.0 ) + assert np.isclose( zs.mean(), beam.z_offset(), rtol=1e-10, atol=0.0 ) + + Nbins = int(np.sqrt(len(beam)/2)) + hbins = np.linspace(min(beam.zs()), max(beam.zs()), Nbins+1) + vbins = np.linspace(min(beam.Es()), max(beam.Es()), Nbins+2) + density, zs, Es = beam.density_lps(hbins, vbins) + density_1d = np.sum(density*np.diff(zs)[0], axis=1) + assert np.isclose( np.sum(density_1d*np.diff(Es)[0]), beam.charge(), rtol=1e-10, atol=0.0 ) + assert np.isclose( Es.mean(), beam.energy(), rtol=1e-10, atol=0.0 ) + assert np.isclose( zs.mean(), beam.z_offset(), rtol=1e-10, atol=0.0 ) + + +@pytest.mark.beam +def test_density_transverse(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.2e-6, y_offset=3.3e-6, x_angle=0.0, y_angle=0.0) + beam = source.track() + density, xs, ys = beam.density_transverse() + density_1d = np.sum(density*np.diff(xs)[0], axis=1) + assert np.isclose( np.sum(density_1d*np.diff(ys)[0]), beam.charge(), rtol=1e-10, atol=0.0 ) + assert np.isclose( xs.mean(), beam.x_offset(), rtol=1e-10, atol=0.0 ) + assert np.isclose( ys.mean(), beam.y_offset(), rtol=1e-10, atol=0.0 ) + ############# Tests of coordinate rotation methods ############# @@ -643,6 +773,7 @@ def active_rotate_arrs(x_comps, y_comps, z_comps, x_angle, y_angle): return rotated_x_comps, rotated_y_comps, rotated_z_comps + def passive_rotate_arrs(x_comps, y_comps, z_comps, x_angle, y_angle): "Passive rotation of ndarrays ``x_comps``, ``y_comps`` and ``z_comps`` containing the xyz-components of vectors such as position and proper velocity first with ``x_angle`` around the y-axis then with ``y_angle`` around the x-axis." rotated_z_comps = z_comps * np.cos(x_angle)*np.cos(y_angle) + x_comps * np.sin(x_angle)*np.cos(y_angle) - y_comps * np.sin(y_angle) @@ -945,3 +1076,27 @@ def test_rotate_coord_sys_3D(): assert np.isclose(beam.x_angle(), old_beam.x_angle(), rtol=1e-7, atol=1e-13) assert np.isclose(beam.y_angle(), old_beam.y_angle(), rtol=1e-7, atol=1e-13) + + +############# Tests of in-house beam field calculation methods ############# +@pytest.mark.beam +def test_charge_density_3D(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=123.4e-6, x_offset=0.1e-6, y_offset=4.5e-6, x_angle=1.2e-6, y_angle=0.3e-6) + beam = source.track() + dQ_dzdxdy, zctrs, xctrs, yctrs, edges_z, edges_x, edges_y = beam.charge_density_3D(zbins=None, xbins=None, ybins=None) + + # Calculate volume of each bin + dz = np.diff(edges_z) + dx = np.diff(edges_x) + dy = np.diff(edges_y) + bin_volumes = dz[:, None, None] * dx[None, :, None] * dy[None, None, :] # The None indexing is used to add new axes to the differences arrays, allowing them to be broadcasted properly for division with counts. This ensures that each element of counts is divided by the corresponding bin volume (element-wise division). + + assert np.isclose(np.sum(dQ_dzdxdy*bin_volumes), beam.charge(), rtol=1e-15, atol=0.0) + assert np.isclose( xctrs.mean(), beam.x_offset(), rtol=1e-10, atol=0.0 ) + assert np.isclose( yctrs.mean(), beam.y_offset(), rtol=1e-10, atol=0.0 ) + assert np.isclose( zctrs.mean(), beam.z_offset(), rtol=1e-10, atol=0.0 ) + +# TODO: test Dirichlet_BC_system_matrix(), Ex_Ey_2D(), Ex_Ey() + + +############# Tests of plotting methods ############# \ No newline at end of file From 74c833294e7492389d81b9888fbeaa044aa628d6 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Fri, 28 Mar 2025 16:17:47 +0100 Subject: [PATCH 20/51] Minor change to Beam plotting methods and moved these further down in beam.py. --- abel/classes/beam.py | 158 ++++++++++++++++++++++--------------------- 1 file changed, 80 insertions(+), 78 deletions(-) diff --git a/abel/classes/beam.py b/abel/classes/beam.py index 8a4baa2e..5bf7aa10 100644 --- a/abel/classes/beam.py +++ b/abel/classes/beam.py @@ -1198,84 +1198,6 @@ def Ex_Ey(self, x_box_min, x_box_max, y_box_min, y_box_max, dx, dy, num_z_cells= - ## PLOTTING - def plot_current_profile(self): - dQdt, ts = self.current_profile() - - fig, ax = plt.subplots() - fig.set_figwidth(6) - fig.set_figheight(4) - ax.plot(ts*SI.c*1e6, -dQdt/1e3) - ax.set_xlabel('z (um)') - ax.set_ylabel('Beam current (kA)') - - def plot_lps(self): - dQdzdE, zs, Es = self.density_lps() - - fig, ax = plt.subplots() - fig.set_figwidth(8) - fig.set_figheight(5) - - p = ax.pcolor(zs*1e6, Es/1e9, -dQdzdE*1e15, cmap=CONFIG.default_cmap, shading='auto') - ax.set_xlabel('z (um)') - ax.set_ylabel('E (GeV)') - ax.set_title('Longitudinal phase space') - cb = fig.colorbar(p) - cb.ax.set_ylabel('Charge density (pC/um/GeV)') - - def plot_trace_space_x(self): - dQdxdxp, xs, xps = self.phase_space_density(self.xs, self.xps) - - fig, ax = plt.subplots() - fig.set_figwidth(8) - fig.set_figheight(5) - p = ax.pcolor(xs*1e6, xps*1e3, -dQdxdxp*1e3, cmap=CONFIG.default_cmap, shading='auto') - ax.set_xlabel('x (um)') - ax.set_ylabel('x'' (mrad)') - ax.set_title('Horizontal trace space') - cb = fig.colorbar(p) - cb.ax.set_ylabel('Charge density (pC/um/mrad)') - - def plot_trace_space_y(self): - dQdydyp, ys, yps = self.phase_space_density(self.ys, self.yps) - - fig, ax = plt.subplots() - fig.set_figwidth(8) - fig.set_figheight(5) - p = ax.pcolor(ys*1e6, yps*1e3, -dQdydyp*1e3, cmap=CONFIG.default_cmap, shading='auto') - ax.set_xlabel('y (um)') - ax.set_ylabel('y'' (mrad)') - ax.set_title('Vertical trace space') - cb = fig.colorbar(p) - cb.ax.set_ylabel('Charge density (pC/um/mrad)') - - def plot_transverse_profile(self): - dQdxdy, xs, ys = self.phase_space_density(self.xs, self.ys) - - fig, ax = plt.subplots() - fig.set_figwidth(8) - fig.set_figheight(5) - p = ax.pcolor(xs*1e6, ys*1e6, -dQdxdy, cmap=CONFIG.default_cmap, shading='auto') - #p = ax.imshow(-dQdxdy, extent=[xs.min()*1e6, xs.max()*1e6, ys.min()*1e6, ys.max()*1e6], - # origin='lower', cmap=CONFIG.default_cmap, aspect='auto') - ax.set_xlabel('x (um)') - ax.set_ylabel('y (um)') - ax.set_title('Transverse profile') - cb = fig.colorbar(p) - cb.ax.set_ylabel('Charge density (pC/um^2)') - - - def plot_bunch_pattern(self): - - fig, ax = plt.subplots() - fig.set_figwidth(6) - fig.set_figheight(4) - ax.plot(ts*SI.c*1e6, -dQdt/1e3) - ax.set_xlabel('z (um)') - ax.set_ylabel('Beam current (kA)') - - - ## CHANGE BEAM def accelerate(self, energy_gain=0, chirp=0, z_offset=0): @@ -1432,6 +1354,86 @@ def apply_betatron_motion(self, L, n0, deltaEs, x0_driver=0, y0_driver=0, radiat else: return Es_final + + + ## PLOTTING + def plot_current_profile(self): + dQdt, ts = self.current_profile() + + fig, ax = plt.subplots() + fig.set_figwidth(6) + fig.set_figheight(4) + ax.plot(ts*SI.c*1e6, np.abs(dQdt)/1e3) + ax.set_xlabel('z (um)') + ax.set_ylabel('Beam current (kA)') + + def plot_lps(self): + dQdzdE, zs, Es = self.density_lps() + + fig, ax = plt.subplots() + fig.set_figwidth(8) + fig.set_figheight(5) + + p = ax.pcolor(zs*1e6, Es/1e9, -dQdzdE*1e15, cmap=CONFIG.default_cmap, shading='auto') + ax.set_xlabel('z (um)') + ax.set_ylabel('E (GeV)') + ax.set_title('Longitudinal phase space') + cb = fig.colorbar(p) + cb.ax.set_ylabel('Charge density (pC/um/GeV)') + + def plot_trace_space_x(self): + dQdxdxp, xs, xps = self.phase_space_density(self.xs, self.xps) + + fig, ax = plt.subplots() + fig.set_figwidth(8) + fig.set_figheight(5) + p = ax.pcolor(xs*1e6, xps*1e3, -dQdxdxp*1e3, cmap=CONFIG.default_cmap, shading='auto') + ax.set_xlabel('x (um)') + ax.set_ylabel('x'' (mrad)') + ax.set_title('Horizontal trace space') + cb = fig.colorbar(p) + cb.ax.set_ylabel('Charge density (pC/um/mrad)') + + def plot_trace_space_y(self): + dQdydyp, ys, yps = self.phase_space_density(self.ys, self.yps) + + fig, ax = plt.subplots() + fig.set_figwidth(8) + fig.set_figheight(5) + p = ax.pcolor(ys*1e6, yps*1e3, -dQdydyp*1e3, cmap=CONFIG.default_cmap, shading='auto') + ax.set_xlabel('y (um)') + ax.set_ylabel('y'' (mrad)') + ax.set_title('Vertical trace space') + cb = fig.colorbar(p) + cb.ax.set_ylabel('Charge density (pC/um/mrad)') + + def plot_transverse_profile(self): + dQdxdy, xs, ys = self.phase_space_density(self.xs, self.ys) + + fig, ax = plt.subplots() + fig.set_figwidth(8) + fig.set_figheight(5) + p = ax.pcolor(xs*1e6, ys*1e6, -dQdxdy, cmap=CONFIG.default_cmap, shading='auto') + #p = ax.imshow(-dQdxdy, extent=[xs.min()*1e6, xs.max()*1e6, ys.min()*1e6, ys.max()*1e6], + # origin='lower', cmap=CONFIG.default_cmap, aspect='auto') + ax.set_xlabel('x (um)') + ax.set_ylabel('y (um)') + ax.set_title('Transverse profile') + cb = fig.colorbar(p) + cb.ax.set_ylabel('Charge density (pC/um^2)') + + + # TODO: unfinished! + # def plot_bunch_pattern(self): + + # fig, ax = plt.subplots() + # fig.set_figwidth(6) + # fig.set_figheight(4) + # ax.plot(ts*SI.c*1e6, np.abs(dQdt)/1e3) + # ax.set_xlabel('z (um)') + # ax.set_ylabel('Beam current (kA)') + + ## SAVE AND LOAD BEAM From 81cffabf99e5df38f2856bbe7fd336201d951be2 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Fri, 28 Mar 2025 16:20:39 +0100 Subject: [PATCH 21/51] Added tests for Beam plotting methods. --- tests/test_beam.py | 54 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 48 insertions(+), 6 deletions(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index e2932547..9dbf71ae 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -636,16 +636,18 @@ def test_current_profile(): source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=1.0e-6, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) beam = source.track() - dIdt, ts = beam.current_profile() - assert np.isclose(np.max(np.abs(dIdt)), beam.peak_current(), rtol=1e-15, atol=0.0) + dQdt, ts = beam.current_profile() + assert np.isclose(np.max(np.abs(dQdt)), beam.peak_current(), rtol=1e-15, atol=0.0) + assert np.isclose( np.sum( dQdt*np.diff(ts)[0] ), beam.charge(), rtol=1e-10, atol=0.0 ) assert np.isclose(SI.c*ts.mean(), beam.z_offset(), rtol=1e-10, atol=0.0) Nbins = int(np.sqrt(len(beam)/2)) bins = np.linspace(min(beam.ts()), max(beam.ts()), Nbins) - dIdt, ts = beam.current_profile(bins=bins) - assert np.isclose(np.max(np.abs(dIdt)), beam.peak_current(), rtol=1e-15, atol=0.0) - assert len(dIdt) == Nbins - 1 + dQdt, ts = beam.current_profile(bins=bins) + assert np.isclose(np.max(np.abs(dQdt)), beam.peak_current(), rtol=1e-15, atol=0.0) + assert len(dQdt) == Nbins - 1 assert len(ts) == Nbins - 1 + assert np.isclose( np.sum( dQdt*np.diff(ts)[0] ), beam.charge(), rtol=1e-10, atol=0.0 ) assert np.isclose(SI.c*ts.mean(), beam.z_offset(), rtol=1e-10, atol=0.0) @@ -1099,4 +1101,44 @@ def test_charge_density_3D(): # TODO: test Dirichlet_BC_system_matrix(), Ex_Ey_2D(), Ex_Ey() -############# Tests of plotting methods ############# \ No newline at end of file +############# Tests of plotting methods ############# +@pytest.mark.beam +def test_plot_current_profile(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + beam.plot_current_profile() + + +@pytest.mark.beam +def test_plot_lps(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + beam.plot_lps() + + +@pytest.mark.beam +def test_plot_trace_space_x(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + beam.plot_trace_space_x() + + +@pytest.mark.beam +def test_plot_trace_space_y(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + beam.plot_trace_space_y() + + +@pytest.mark.beam +def test_plot_transverse_profile(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + beam.plot_transverse_profile() + + +# @pytest.mark.beam +# def test_plot_bunch_pattern(): +# source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) +# beam = source.track() +# beam.plot_bunch_pattern() \ No newline at end of file From 602c6d0646fa219c71c3e49fca065437d8640710 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Fri, 28 Mar 2025 16:59:13 +0100 Subject: [PATCH 22/51] Added tests for Beam.accelerate(). --- tests/test_beam.py | 59 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/tests/test_beam.py b/tests/test_beam.py index 9dbf71ae..8e1905d6 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -1101,12 +1101,67 @@ def test_charge_density_3D(): # TODO: test Dirichlet_BC_system_matrix(), Ex_Ey_2D(), Ex_Ey() + +############# Tests of methods changing the beam ############# +@pytest.mark.beam +def test_accelerate_nominal(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + energy_gain = 1e9 # 1 GeV energy gain + chirp = 0 # No chirp + initial_Es = beam.Es() + + beam.accelerate(energy_gain=energy_gain, chirp=chirp) + expected_Es = initial_Es + energy_gain + + assert np.allclose(beam.Es(), expected_Es, rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_accelerate_negative(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + energy_gain = -beam.energy() # Energy decrease + chirp = 0 # No chirp + + # Suppress warnings + with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=RuntimeWarning) + + try: + beam.accelerate(energy_gain=energy_gain, chirp=chirp) + except ValueError as err: + assert str(err) == 'uzs contains values that are too small.' + + +@pytest.mark.beam +def test_accelerate_chirp(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + energy_gain = 1e9 # 1 GeV energy gain + chirp = 1e8 # Energy chirp dE/dz + zs = beam.zs() + initial_Es = beam.Es() + + expected_Es = energy_gain + initial_Es + np.sign(beam.qs()) * zs * chirp + beam.accelerate(energy_gain=energy_gain, chirp=chirp) + + assert np.allclose(beam.Es(), expected_Es, rtol=1e-15, atol=0.0) + + + + + + + + ############# Tests of plotting methods ############# @pytest.mark.beam def test_plot_current_profile(): source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) beam = source.track() beam.plot_current_profile() + plt.close() @pytest.mark.beam @@ -1114,6 +1169,7 @@ def test_plot_lps(): source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) beam = source.track() beam.plot_lps() + plt.close() @pytest.mark.beam @@ -1121,6 +1177,7 @@ def test_plot_trace_space_x(): source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) beam = source.track() beam.plot_trace_space_x() + plt.close() @pytest.mark.beam @@ -1128,6 +1185,7 @@ def test_plot_trace_space_y(): source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) beam = source.track() beam.plot_trace_space_y() + plt.close() @pytest.mark.beam @@ -1135,6 +1193,7 @@ def test_plot_transverse_profile(): source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) beam = source.track() beam.plot_transverse_profile() + plt.close() # @pytest.mark.beam From ef6c2b59557cf559d6f6b0ccd8340f26b8f54511 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Mon, 31 Mar 2025 16:20:32 +0200 Subject: [PATCH 23/51] Added controls to Beam.scale_norm_emittance_x() and Beam.scale_norm_emittance_y() to prevent negative emittances. --- abel/classes/beam.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/abel/classes/beam.py b/abel/classes/beam.py index 5bf7aa10..cc969db4 100644 --- a/abel/classes/beam.py +++ b/abel/classes/beam.py @@ -1220,11 +1220,15 @@ def scale_to_length(self, bunch_length): self.set_zs(zs_scaled) def scale_norm_emittance_x(self, norm_emit_nx): + if norm_emit_nx < 0: + raise ValueError('Normalised emittance cannot be negative.') scale_factor = norm_emit_nx/self.norm_emittance_x() self.set_xs(self.xs() * np.sqrt(scale_factor)) self.set_uxs(self.uxs() * np.sqrt(scale_factor)) def scale_norm_emittance_y(self, norm_emit_ny): + if norm_emit_ny < 0: + raise ValueError('Normalised emittance cannot be negative.') scale_factor = norm_emit_ny/self.norm_emittance_y() self.set_ys(self.ys() * np.sqrt(scale_factor)) self.set_uys(self.uys() * np.sqrt(scale_factor)) @@ -1433,7 +1437,7 @@ def plot_transverse_profile(self): # ax.set_xlabel('z (um)') # ax.set_ylabel('Beam current (kA)') - + ## SAVE AND LOAD BEAM From 1904545218adb951a712563fd9e3106eac7251ff Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Mon, 31 Mar 2025 16:22:13 +0200 Subject: [PATCH 24/51] Added a flag calc_evolution to StageBaisc and edited StageBasic.track() to enable using parameter evolution tracking when calling Beam.apply_betatron_motion(). --- abel/classes/stage/impl/stage_basic.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/abel/classes/stage/impl/stage_basic.py b/abel/classes/stage/impl/stage_basic.py index 58dec105..f44b3dec 100644 --- a/abel/classes/stage/impl/stage_basic.py +++ b/abel/classes/stage/impl/stage_basic.py @@ -9,11 +9,12 @@ class StageBasic(Stage): - def __init__(self, nom_accel_gradient=None, nom_energy_gain=None, plasma_density=None, driver_source=None, ramp_beta_mag=None, transformer_ratio=1): + def __init__(self, nom_accel_gradient=None, nom_energy_gain=None, plasma_density=None, driver_source=None, ramp_beta_mag=None, transformer_ratio=1, calc_evolution=False): super().__init__(nom_accel_gradient=nom_accel_gradient, nom_energy_gain=nom_energy_gain, plasma_density=plasma_density, driver_source=driver_source, ramp_beta_mag=ramp_beta_mag) self.transformer_ratio = transformer_ratio + self.calc_evolution = calc_evolution def track(self, beam_incoming, savedepth=0, runnable=None, verbose=False): @@ -85,7 +86,12 @@ def track(self, beam_incoming, savedepth=0, runnable=None, verbose=False): # ========== Betatron oscillations ========== - beam.apply_betatron_motion(self.length_flattop, self.plasma_density, self.nom_energy_gain_flattop, x0_driver=driver0.x_offset(), y0_driver=driver0.y_offset()) + deltaEs = np.full(len(beam.Es()), self.nom_energy_gain_flattop) + if self.calc_evolution: + _, evol = beam.apply_betatron_motion(self.length_flattop, self.plasma_density, deltaEs, x0_driver=driver0.x_offset(), y0_driver=driver0.y_offset(), calc_evolution=self.calc_evolution) + self.evolution.beam = evol + else: + beam.apply_betatron_motion(self.length_flattop, self.plasma_density, deltaEs, x0_driver=driver0.x_offset(), y0_driver=driver0.y_offset()) # ========== Accelerate beam with homogeneous energy gain ========== From a8c26e04c26f240e78d780d8df72252f5ab8b33f Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Mon, 31 Mar 2025 16:24:36 +0200 Subject: [PATCH 25/51] Added tests for the Beam methods compress(), scale_to_length(), scale_norm_emittance_x(), scale_norm_emittance_y() and apply_betatron_motion(). --- tests/test_beam.py | 232 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 230 insertions(+), 2 deletions(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index 8e1905d6..37f0156f 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -26,7 +26,7 @@ import random -def setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, bunch_length=40.0e-06, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0): +def setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, bunch_length=40.0e-06, energy=3e9, rel_energy_spread=0.02, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0): source = SourceBasic() source.bunch_length = bunch_length # [m], rms. source.num_particles = 10000 @@ -34,7 +34,7 @@ def setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, bunch_length=40 # Energy parameters source.energy = energy # [eV] - source.rel_energy_spread = 0.02 # Relative rms energy spread + source.rel_energy_spread = rel_energy_spread # Relative rms energy spread # Emittances source.emit_nx, source.emit_ny = 15e-6, 0.1e-6 # [m rad] @@ -1149,10 +1149,238 @@ def test_accelerate_chirp(): assert np.allclose(beam.Es(), expected_Es, rtol=1e-15, atol=0.0) +@pytest.mark.beam +def test_compress_nominal(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + + R_56 = 0.5**2*SI.c**2*np.sqrt(beam.energy()/10e9)**3/(3*beam.energy()**2) + initial_zs = beam.zs() + initial_Es = beam.Es() + + expected_zs = initial_zs + (1 - initial_Es / beam.energy()) * R_56 + beam.compress(R_56=R_56, nom_energy=beam.energy()) + + assert np.allclose(beam.zs(), expected_zs, rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_compress_null(): + + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + + R_56 = 0 # No compression + initial_zs = beam.zs() + + beam.compress(R_56=R_56, nom_energy=beam.energy()) + + # zs should remain unchanged + assert np.allclose(beam.zs(), initial_zs, rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_compress_uniform(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + R_56 = 0.5**2*SI.c**2*np.sqrt(beam.energy()/10e9)**3/(3*beam.energy()**2) + uniform_energy = np.full(len(beam.Es()), beam.energy()) + beam.set_Es(uniform_energy) + initial_zs = beam.zs() + beam.compress(R_56=R_56, nom_energy=beam.energy()) + + assert np.allclose(beam.zs(), initial_zs, rtol=1e-15, atol=0.0) +@pytest.mark.beam +def test_scale_to_length(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + + beam = source.track() + new_bunch_length = beam.bunch_length()/2 + zs_scaled = beam.z_offset() + (beam.zs()-beam.z_offset())*new_bunch_length/beam.bunch_length() + beam.scale_to_length(bunch_length=new_bunch_length) + assert np.allclose(beam.zs(), zs_scaled, rtol=1e-15, atol=0.0) + + beam = source.track() + new_bunch_length = beam.bunch_length()*5.354 + zs_scaled = beam.z_offset() + (beam.zs()-beam.z_offset())*new_bunch_length/beam.bunch_length() + beam.scale_to_length(bunch_length=new_bunch_length) + assert np.allclose(beam.zs(), zs_scaled, rtol=1e-15, atol=0.0) + + beam = source.track() + new_bunch_length = beam.bunch_length()*0 + beam.scale_to_length(bunch_length=new_bunch_length) + assert np.allclose(beam.zs(), beam.z_offset(), rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_scale_norm_emittance_x(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + + beam = source.track() + scale_factor = 15.16 + expct_emit_nx = scale_factor * beam.norm_emittance_x() + expected_xs = beam.xs() * np.sqrt(scale_factor) + expected_uxs = beam.uxs() * np.sqrt(scale_factor) + beam.scale_norm_emittance_x(scale_factor*beam.norm_emittance_x()) + assert np.allclose(beam.xs(), expected_xs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.uxs(), expected_uxs, rtol=1e-15, atol=0.0) + assert np.isclose(beam.norm_emittance_x(), expct_emit_nx, rtol=1e-15, atol=0.0) + + beam = source.track() + scale_factor = 0.5354 + expct_emit_nx = scale_factor * beam.norm_emittance_x() + expected_xs = beam.xs() * np.sqrt(scale_factor) + expected_uxs = beam.uxs() * np.sqrt(scale_factor) + beam.scale_norm_emittance_x(scale_factor*beam.norm_emittance_x()) + assert np.allclose(beam.xs(), expected_xs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.uxs(), expected_uxs, rtol=1e-15, atol=0.0) + assert np.isclose(beam.norm_emittance_x(), expct_emit_nx, rtol=1e-15, atol=0.0) + + beam = source.track() + scale_factor = 0.0 + expct_emit_nx = scale_factor * beam.norm_emittance_x() + expected_xs = beam.xs() * np.sqrt(scale_factor) + expected_uxs = beam.uxs() * np.sqrt(scale_factor) + beam.scale_norm_emittance_x(scale_factor*beam.norm_emittance_x()) + assert np.allclose(beam.xs(), expected_xs, rtol=1e-15, atol=0.0) + assert np.allclose(beam.uxs(), expected_uxs, rtol=1e-15, atol=0.0) + assert np.isclose(beam.norm_emittance_x(), expct_emit_nx, rtol=1e-15, atol=0.0) + + try: + beam.scale_norm_emittance_x(-8e-6) + except ValueError as err: + assert str(err) == 'Normalised emittance cannot be negative.' + + +@pytest.mark.beam +def test_scale_norm_emittance_y(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + + beam = source.track() + scale_factor = 15.16 + expct_emit_ny = scale_factor * beam.norm_emittance_y() + expected_ys = beam.ys() * np.sqrt(scale_factor) + expected_uys = beam.uys() * np.sqrt(scale_factor) + beam.scale_norm_emittance_y(scale_factor*beam.norm_emittance_y()) + assert np.allclose(beam.ys(), expected_ys, rtol=1e-15, atol=0.0) + assert np.allclose(beam.uys(), expected_uys, rtol=1e-15, atol=0.0) + assert np.isclose(beam.norm_emittance_y(), expct_emit_ny, rtol=1e-13, atol=0.0) + + beam = source.track() + scale_factor = 0.5354 + expct_emit_ny = scale_factor * beam.norm_emittance_y() + expected_ys = beam.ys() * np.sqrt(scale_factor) + expected_uys = beam.uys() * np.sqrt(scale_factor) + beam.scale_norm_emittance_y(scale_factor*beam.norm_emittance_y()) + assert np.allclose(beam.ys(), expected_ys, rtol=1e-15, atol=0.0) + assert np.allclose(beam.uys(), expected_uys, rtol=1e-15, atol=0.0) + assert np.isclose(beam.norm_emittance_y(), expct_emit_ny, rtol=1e-15, atol=0.0) + + beam = source.track() + scale_factor = 0.0 + expct_emit_ny = scale_factor * beam.norm_emittance_y() + expected_ys = beam.ys() * np.sqrt(scale_factor) + expected_uys = beam.uys() * np.sqrt(scale_factor) + beam.scale_norm_emittance_y(scale_factor*beam.norm_emittance_y()) + assert np.allclose(beam.ys(), expected_ys, rtol=1e-15, atol=0.0) + assert np.allclose(beam.uys(), expected_uys, rtol=1e-15, atol=0.0) + assert np.isclose(beam.norm_emittance_y(), expct_emit_ny, rtol=1e-15, atol=0.0) + + try: + beam.scale_norm_emittance_y(-8e-6) + except ValueError as err: + assert str(err) == 'Normalised emittance cannot be negative.' + + +# @pytest.mark.beam +# def test_apply_betatron_damping(): + + + + +# @pytest.mark.beam +# def test_magnify_beta_function(): +# # TODO + + +# @pytest.mark.beam +# def test_transport(): +# # TODO + + +# @pytest.mark.beam +# def test_flip_transverse_phase_spaces(): +# # TODO + + +@pytest.mark.beam +def test_apply_betatron_motion_emitt_pres(): + "Test of ``Beam.apply_betatron_motion()`` with no energy spread and radiation reaction so that the emittances are preserved." + + np.random.seed(42) + + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, rel_energy_spread=0.0, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + initial_beam = copy.deepcopy(beam) + deltaEs = np.full(len(beam.Es()), 1e9) # Homogeneous energy gain + + Es_final, evol = beam.apply_betatron_motion(L=1.0, n0=6.0e20, deltaEs=deltaEs, x0_driver=0, y0_driver=0, radiation_reaction=False, calc_evolution=True) + + assert np.allclose(Es_final.mean(), 4e9, rtol=1e-15, atol=0.0) + assert np.allclose(np.std(Es_final), 1e-20, rtol=0.0, atol=1e-19) + assert np.allclose(np.std(Es_final)/Es_final.mean(), 1e-20, rtol=0.0, atol=1e-19) + assert np.allclose(beam.charge(), initial_beam.charge(), rtol=1e-10, atol=0.0) + assert np.allclose(beam.z_offset(), initial_beam.z_offset(), rtol=1e-10, atol=0.0) + assert np.allclose(beam.bunch_length(), initial_beam.bunch_length(), rtol=1e-10, atol=0.0) + + assert np.allclose(Es_final.mean(), evol.energy[-1], rtol=1e-20, atol=0.0) + assert np.allclose(evol.energy_spread[-1], 1e-20, rtol=0.0, atol=1e-19) + assert np.allclose(beam.charge(), evol.charge[-1], rtol=1e-10, atol=0.0) + assert np.allclose(beam.norm_emittance_x(), evol.emit_nx[-1], rtol=0.0, atol=0.3e-5) + assert np.allclose(beam.norm_emittance_y(), evol.emit_ny[-1], rtol=0.0, atol=0.5e-5) + + # Emittance is preserved when the energy spread is 0 (homogenneoud energy gain) and radiation reaction disabled. + #assert np.isclose(beam.rel_energy_spread(), 1e-15, rtol=1e-10, atol=0.0) # Beam energies not updated after apply_betatron_motion(), so cannot check this. + assert np.allclose(beam.norm_emittance_x(), initial_beam.norm_emittance_x(), rtol=1e-8, atol=0.0) + assert np.allclose(beam.norm_emittance_y(), initial_beam.norm_emittance_y(), rtol=1e-8, atol=0.0) + assert np.allclose(evol.emit_nx[0], evol.emit_nx[-1], rtol=1e-8, atol=0.0) + assert np.allclose(evol.emit_ny[0], evol.emit_ny[-1], rtol=1e-8, atol=0.0) + + +@pytest.mark.beam +def test_apply_betatron_motion(): + "Test of ``Beam.apply_betatron_motion()`` with energy spread and radiation reaction." + + np.random.seed(42) + + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, rel_energy_spread=0.01, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + initial_beam = copy.deepcopy(beam) + deltaEs = np.full(len(beam.Es()), 1e9) # Homogeneous energy gain + + Es_final, evol = beam.apply_betatron_motion(L=1.0, n0=6.0e20, deltaEs=deltaEs, x0_driver=0, y0_driver=0, radiation_reaction=True, calc_evolution=True) + + assert np.allclose(Es_final.mean(), 4e9, rtol=1e-6, atol=0.0) + assert np.allclose(np.std(Es_final), 0.01*3e9, rtol=5e-3, atol=0.0) + #assert np.allclose(np.std(Es_final)/Es_final.mean(), 1e-20, rtol=0.0, atol=1e-19) + assert np.allclose(beam.charge(), initial_beam.charge(), rtol=1e-10, atol=0.0) + assert np.allclose(beam.z_offset(), initial_beam.z_offset(), rtol=1e-10, atol=0.0) + assert np.allclose(beam.bunch_length(), initial_beam.bunch_length(), rtol=1e-10, atol=0.0) + + assert np.allclose(Es_final.mean(), evol.energy[-1], rtol=1e-3, atol=0.0) + assert np.allclose(evol.energy_spread[-1], 0.01*3e9, rtol=5e-2, atol=0.0) + assert np.allclose(beam.charge(), evol.charge[-1], rtol=1e-10, atol=0.0) + assert np.allclose(beam.norm_emittance_x(), evol.emit_nx[-1], rtol=0.0, atol=0.3e-5) + assert np.allclose(beam.norm_emittance_y(), evol.emit_ny[-1], rtol=0.0, atol=0.5e-5) + + + #mag = np.sqrt(initial_beam.gamma()/energy2gamma(Es_final.mean())) # Magnification factor + #assert np.allclose(beam.beta_x(), initial_beam.beta_x()*mag, rtol=1e-15, atol=0.0) + ############# Tests of plotting methods ############# From 5362d2afbfe76e5fb382c24e328aaf9671a93ba6 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Mon, 31 Mar 2025 17:39:52 +0200 Subject: [PATCH 26/51] Added test_magnify_beta_function() to test_beam.py. --- tests/test_beam.py | 96 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 90 insertions(+), 6 deletions(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index 37f0156f..4258c4ad 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -520,7 +520,7 @@ def test_param_calcs_generate_trace_space_xy(): beta_y = 0.120 # [m] geo_emitt_x = 2.552865e-09 # [m rad] geo_emitt_y = 1.750833e-11 # [m rad] - num_particles = 200011 + num_particles = 200012 # Generate trace space xs, xps, ys, yps = generate_trace_space_xy(geo_emitt_x, beta_x, alpha_x, geo_emitt_y, beta_y, alpha_y, num_particles, L=0, symmetrize=False) @@ -531,6 +531,7 @@ def test_param_calcs_generate_trace_space_xy(): beam.set_phase_space(xs=xs, ys=ys, zs=zs, xps=xps, yps=yps, Es=Es, Q=-e*1.0e10) # Examine the beam parameters + assert len(beam) == num_particles assert np.isclose(np.std(xs), np.sqrt(geo_emitt_x*beta_x), rtol=1e-2, atol=0.0) # Beam size assert np.isclose(np.std(ys), np.sqrt(geo_emitt_y*beta_y), rtol=1e-2, atol=0.0) assert np.isclose(np.std(Es), 0.02*3e9, rtol=0.005, atol=0.0) @@ -543,7 +544,7 @@ def test_param_calcs_generate_trace_space_xy(): assert np.isclose(beam.bunch_length(), 50.0e-6, rtol=0.005, atol=0.03) assert np.isclose(beam.alpha_x(), alpha_x, rtol=1e-2, atol=0.0) - assert np.isclose(beam.alpha_y(), alpha_y, rtol=1e-2, atol=0.0) + assert np.isclose(beam.alpha_y(), alpha_y, rtol=2e-2, atol=0.0) assert np.isclose(beam.beta_x(), beta_x, rtol=1e-3, atol=0.0) assert np.isclose(beam.beta_y(), beta_y, rtol=3e-3, atol=0.0) assert np.isclose(beam.geom_emittance_x(), geo_emitt_x, rtol=1e-2, atol=0.0) @@ -563,6 +564,8 @@ def test_param_calcs_generate_trace_space_xy(): beam = Beam() beam.set_phase_space(xs=xs, ys=ys, zs=zs, xps=xps, yps=yps, Es=Es, Q=-e*1.0e10) + # Examine the beam parameters + assert len(beam) == num_particles assert np.isclose(np.std(xs), np.sqrt(geo_emitt_x*beta_x), rtol=1e-2, atol=0.0) # Beam size assert np.isclose(np.std(ys), np.sqrt(geo_emitt_y*beta_y), rtol=5e-2, atol=0.0) assert np.isclose(np.std(Es), 0.02*3e9, rtol=0.005, atol=0.0) @@ -596,7 +599,7 @@ def test_param_calcs_generate_symm_trace_space_xyz(): beta_y = 0.120 # [m] geo_emitt_x = 2.552865e-09 # [m rad] geo_emitt_y = 1.750833e-11 # [m rad] - num_particles = 200011 + num_particles = 200016 # Generate trace space xs, xps, ys, yps, zs, Es = generate_symm_trace_space_xyz(geo_emitt_x, beta_x, alpha_x, geo_emitt_y, beta_y, alpha_y, num_particles, bunch_length=50.0e-6, energy_spread=0.02*3e9, L=0) @@ -606,6 +609,7 @@ def test_param_calcs_generate_symm_trace_space_xyz(): beam.set_phase_space(xs=xs, ys=ys, zs=zs, xps=xps, yps=yps, Es=Es, Q=-e*1.0e10) # Examine the beam parameters + assert len(beam) == num_particles assert np.isclose(np.std(xs), np.sqrt(geo_emitt_x*beta_x), rtol=1e-2, atol=0.0) # Beam size assert np.isclose(np.std(ys), np.sqrt(geo_emitt_y*beta_y), rtol=1e-2, atol=0.0) assert np.isclose(np.std(Es), 0.02*3e9, rtol=0.005, atol=0.0) @@ -619,7 +623,7 @@ def test_param_calcs_generate_symm_trace_space_xyz(): assert np.isclose(beam.peak_current(), -beam.charge()/(np.sqrt(2*np.pi)*beam.bunch_length())*SI.c, rtol=0.0, atol=3e2) assert np.isclose(beam.peak_density(), beam.charge()/(SI.e*np.sqrt(2*np.pi)**3*beam.beam_size_x()*beam.beam_size_y()*beam.bunch_length()), rtol=1e-8, atol=0.0) - assert np.isclose(beam.alpha_x(), alpha_x, rtol=3e-2, atol=0.0) + assert np.isclose(beam.alpha_x(), alpha_x, rtol=5e-2, atol=0.0) assert np.isclose(beam.alpha_y(), alpha_y, rtol=1e-2, atol=0.0) assert np.isclose(beam.beta_x(), beta_x, rtol=3e-3, atol=0.0) assert np.isclose(beam.beta_y(), beta_y, rtol=3e-3, atol=0.0) @@ -1303,8 +1307,88 @@ def test_scale_norm_emittance_y(): # @pytest.mark.beam -# def test_magnify_beta_function(): -# # TODO +def test_magnify_beta_function(): + + np.random.seed(42) + + x_offset = 5.354e-6 + y_offset = 0.1516e-6 + ux_offset = 0.0 + uy_offset = 1583681.8243787317 + beta_mag = 5.0 # Magnify + + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=beta_mag, energy=3e9, rel_energy_spread=0.0, z_offset=0.0, y_offset=y_offset, x_offset=x_offset, x_angle=ux_offset, y_angle=uy_offset/energy2proper_velocity(3e9)) + beam = source.track() + initial_beam = copy.deepcopy(beam) + + beam.magnify_beta_function(beta_mag=beta_mag, axis_defining_beam=beam) + + # calculate beam (not beta) magnification + mag = np.sqrt(beta_mag) + + # Examine beam + assert len(beam) == len(initial_beam) + assert np.isclose(beam.particle_mass, SI.m_e, rtol=1e-15, atol=0.0) + assert np.isclose(beam.charge(), initial_beam.charge(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.charge_sign(), -1, rtol=1e-15, atol=0.0) + assert np.isclose(beam.total_energy(), initial_beam.total_energy(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.weightings(), initial_beam.weightings(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.energy(), initial_beam.energy(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.rel_energy_spread(), initial_beam.rel_energy_spread(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.z_offset(), initial_beam.z_offset(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.bunch_length(), initial_beam.bunch_length(), rtol=1e-15, atol=0.0) + + assert np.isclose(beam.x_offset(), x_offset, rtol=1e-15, atol=0.0) + assert np.isclose(beam.y_offset(), y_offset, rtol=1e-15, atol=0.0) + assert np.isclose(beam.beam_size_x(), initial_beam.beam_size_x()*mag, rtol=1e-15, atol=0.0) + assert np.isclose(beam.beam_size_y(), initial_beam.beam_size_y()*mag, rtol=1e-15, atol=0.0) + assert np.isclose(beam.x_angle(), ux_offset/energy2proper_velocity(3e9), rtol=1e-15, atol=0.0) + assert np.isclose(beam.y_angle(), uy_offset/energy2proper_velocity(3e9), rtol=1e-15, atol=0.0) + assert np.isclose(beam.divergence_x(), initial_beam.divergence_x()/mag, rtol=1e-15, atol=0.0) + assert np.isclose(beam.divergence_y(), initial_beam.divergence_y()/mag, rtol=1e-15, atol=0.0) + + assert np.allclose(beam.xs(), (initial_beam.xs()-initial_beam.x_offset())*mag + initial_beam.x_offset(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.ys(), (initial_beam.ys()-initial_beam.y_offset())*mag + initial_beam.y_offset(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.uxs(), (initial_beam.uxs()-initial_beam.ux_offset())/mag + initial_beam.ux_offset(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.uys(), (initial_beam.uys()-initial_beam.uy_offset())/mag + initial_beam.uy_offset(), rtol=1e-15, atol=0.0) + + + beta_mag = 1/beta_mag # De-magnify + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=beta_mag, energy=3e9, rel_energy_spread=0.0, z_offset=0.0, y_offset=y_offset, x_offset=x_offset, x_angle=ux_offset, y_angle=uy_offset/energy2proper_velocity(3e9)) + beam = source.track() + initial_beam = copy.deepcopy(beam) + + beam.magnify_beta_function(beta_mag=beta_mag, axis_defining_beam=beam) + + # calculate beam (not beta) magnification + mag = np.sqrt(beta_mag) + + # Examine beam + assert len(beam) == len(initial_beam) + assert np.isclose(beam.particle_mass, SI.m_e, rtol=1e-15, atol=0.0) + assert np.isclose(beam.charge(), initial_beam.charge(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.charge_sign(), -1, rtol=1e-15, atol=0.0) + assert np.isclose(beam.total_energy(), initial_beam.total_energy(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.weightings(), initial_beam.weightings(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.energy(), initial_beam.energy(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.rel_energy_spread(), initial_beam.rel_energy_spread(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.z_offset(), initial_beam.z_offset(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.bunch_length(), initial_beam.bunch_length(), rtol=1e-15, atol=0.0) + + assert np.isclose(beam.x_offset(), x_offset, rtol=1e-15, atol=0.0) + assert np.isclose(beam.y_offset(), y_offset, rtol=1e-15, atol=0.0) + assert np.isclose(beam.beam_size_x(), initial_beam.beam_size_x()*mag, rtol=1e-15, atol=0.0) + assert np.isclose(beam.beam_size_y(), initial_beam.beam_size_y()*mag, rtol=1e-15, atol=0.0) + assert np.isclose(beam.x_angle(), ux_offset/energy2proper_velocity(3e9), rtol=1e-15, atol=0.0) + assert np.isclose(beam.y_angle(), uy_offset/energy2proper_velocity(3e9), rtol=1e-15, atol=0.0) + assert np.isclose(beam.divergence_x(), initial_beam.divergence_x()/mag, rtol=1e-15, atol=0.0) + assert np.isclose(beam.divergence_y(), initial_beam.divergence_y()/mag, rtol=1e-15, atol=0.0) + + assert np.allclose(beam.xs(), (initial_beam.xs()-initial_beam.x_offset())*mag + initial_beam.x_offset(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.ys(), (initial_beam.ys()-initial_beam.y_offset())*mag + initial_beam.y_offset(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.uxs(), (initial_beam.uxs()-initial_beam.ux_offset())/mag + initial_beam.ux_offset(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.uys(), (initial_beam.uys()-initial_beam.uy_offset())/mag + initial_beam.uy_offset(), rtol=1e-15, atol=0.0) + # @pytest.mark.beam From 3b16ce56cf33c94646041b08aaf5355051828467 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 1 Apr 2025 00:39:02 +0200 Subject: [PATCH 27/51] Added test_apply_betatron_damping(), test_magnify_beta_function(), test_transport() and test_flip_transverse_phase_spaces(). --- tests/test_beam.py | 221 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 210 insertions(+), 11 deletions(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index 4258c4ad..22cf8255 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -1300,14 +1300,103 @@ def test_scale_norm_emittance_y(): assert str(err) == 'Normalised emittance cannot be negative.' -# @pytest.mark.beam -# def test_apply_betatron_damping(): - - +@pytest.mark.beam +def test_apply_betatron_damping(): + np.random.seed(42) -# @pytest.mark.beam + x_offset = 5.354e-6 + y_offset = 0.1516e-6 + ux_offset = 739215.7882185677 + uy_offset = 1583681.8243787317 + deltaE = 1.516e9 + + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=np.sqrt(3/4.516), energy=3e9, rel_energy_spread=0.0, z_offset=0.0, y_offset=y_offset, x_offset=x_offset, x_angle=ux_offset/energy2proper_velocity(3e9), y_angle=uy_offset/energy2proper_velocity(3e9)) + + beam = source.track() + initial_beam = copy.deepcopy(beam) + + # calculate beam (not beta) magnification + gammasBoosted = energy2gamma(abs(initial_beam.Es() + deltaE)) + beta_mag = np.sqrt(initial_beam.gammas()/gammasBoosted) + assert np.isclose(beta_mag.mean(), np.sqrt(3/4.516), rtol=1e-15, atol=0.0) + mag = np.sqrt(beta_mag) + + beam.apply_betatron_damping(deltaE, axis_defining_beam=beam) + + # Examine beam + assert len(beam) == len(initial_beam) + assert np.isclose(beam.particle_mass, SI.m_e, rtol=1e-15, atol=0.0) + assert np.isclose(beam.charge(), initial_beam.charge(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.charge_sign(), -1, rtol=1e-15, atol=0.0) + assert np.isclose(beam.total_energy(), initial_beam.total_energy(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.weightings(), initial_beam.weightings(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.energy(), initial_beam.energy(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.rel_energy_spread(), initial_beam.rel_energy_spread(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.z_offset(), initial_beam.z_offset(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.bunch_length(), initial_beam.bunch_length(), rtol=1e-15, atol=0.0) + + assert np.isclose(beam.x_offset(), x_offset, rtol=1e-15, atol=0.0) + assert np.isclose(beam.y_offset(), y_offset, rtol=1e-15, atol=0.0) + assert np.isclose(beam.beam_size_x(), initial_beam.beam_size_x()*mag.mean(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.beam_size_y(), initial_beam.beam_size_y()*mag.mean(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.x_angle(), ux_offset/energy2proper_velocity(3e9), rtol=1e-12, atol=0.0) + assert np.isclose(beam.y_angle(), uy_offset/energy2proper_velocity(3e9), rtol=1e-15, atol=0.0) + assert np.isclose(beam.divergence_x(), initial_beam.divergence_x()/mag.mean(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.divergence_y(), initial_beam.divergence_y()/mag.mean(), rtol=1e-15, atol=0.0) + + assert np.allclose(beam.xs(), (initial_beam.xs()-initial_beam.x_offset())*mag + initial_beam.x_offset(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.ys(), (initial_beam.ys()-initial_beam.y_offset())*mag + initial_beam.y_offset(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.uxs(), (initial_beam.uxs()-initial_beam.ux_offset())/mag + initial_beam.ux_offset(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.uys(), (initial_beam.uys()-initial_beam.uy_offset())/mag + initial_beam.uy_offset(), rtol=1e-15, atol=0.0) + + + # Test no energy change + deltaE = 0.0 + + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=1.0, energy=3e9, rel_energy_spread=0.01, z_offset=0.0, y_offset=y_offset, x_offset=x_offset, x_angle=ux_offset/energy2proper_velocity(3e9), y_angle=uy_offset/energy2proper_velocity(3e9)) + + beam = source.track() + initial_beam = copy.deepcopy(beam) + + # calculate beam (not beta) magnification + gammasBoosted = energy2gamma(abs(initial_beam.Es() + deltaE)) + beta_mag = np.sqrt(initial_beam.gammas()/gammasBoosted) + assert np.isclose(beta_mag.mean(), 1.0, rtol=1e-15, atol=0.0) + mag = np.sqrt(beta_mag) + + beam.apply_betatron_damping(deltaE, axis_defining_beam=beam) + + # Examine beam + assert len(beam) == len(initial_beam) + assert np.isclose(beam.particle_mass, SI.m_e, rtol=1e-15, atol=0.0) + assert np.isclose(beam.charge(), initial_beam.charge(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.charge_sign(), -1, rtol=1e-15, atol=0.0) + assert np.isclose(beam.total_energy(), initial_beam.total_energy(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.weightings(), initial_beam.weightings(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.energy(), initial_beam.energy(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.rel_energy_spread(), initial_beam.rel_energy_spread(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.z_offset(), initial_beam.z_offset(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.bunch_length(), initial_beam.bunch_length(), rtol=1e-15, atol=0.0) + + assert np.isclose(beam.x_offset(), x_offset, rtol=1e-15, atol=0.0) + assert np.isclose(beam.y_offset(), y_offset, rtol=1e-15, atol=0.0) + assert np.isclose(beam.beam_size_x(), initial_beam.beam_size_x()*mag.mean(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.beam_size_y(), initial_beam.beam_size_y()*mag.mean(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.x_angle(), ux_offset/energy2proper_velocity(3e9), rtol=1e-12, atol=0.0) + assert np.isclose(beam.y_angle(), uy_offset/energy2proper_velocity(3e9), rtol=1e-15, atol=0.0) + assert np.isclose(beam.divergence_x(), initial_beam.divergence_x()/mag.mean(), rtol=1e-15, atol=0.0) + assert np.isclose(beam.divergence_y(), initial_beam.divergence_y()/mag.mean(), rtol=1e-15, atol=0.0) + + assert np.allclose(beam.xs(), (initial_beam.xs()-initial_beam.x_offset())*mag + initial_beam.x_offset(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.ys(), (initial_beam.ys()-initial_beam.y_offset())*mag + initial_beam.y_offset(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.uxs(), (initial_beam.uxs()-initial_beam.ux_offset())/mag + initial_beam.ux_offset(), rtol=1e-15, atol=0.0) + assert np.allclose(beam.uys(), (initial_beam.uys()-initial_beam.uy_offset())/mag + initial_beam.uy_offset(), rtol=1e-15, atol=0.0) + + +@pytest.mark.beam def test_magnify_beta_function(): + "Tests for ``Beam.magnify_beta_function(beta_mag, axis_defining_beam=None)``, which magnifies beta functions (increases beam size, decreases divergence for beta_mag > 1.0)." np.random.seed(42) @@ -1390,15 +1479,125 @@ def test_magnify_beta_function(): assert np.allclose(beam.uys(), (initial_beam.uys()-initial_beam.uy_offset())/mag + initial_beam.uy_offset(), rtol=1e-15, atol=0.0) +@pytest.mark.beam +def test_transport(): + + x_offset = 0 # [m] + y_offset = 0 # [m] + x_angle = 0 # [rad] + y_angle = 0 # [rad] + L = 0 # [m] + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, rel_energy_spread=0.0, z_offset=0.0, y_offset=y_offset, x_offset=x_offset, x_angle=x_angle, y_angle=y_angle) + beam = source.track() + initial_beam = copy.deepcopy(beam) -# @pytest.mark.beam -# def test_transport(): -# # TODO + beam.transport(L) + assert np.allclose(beam.xs(), initial_beam.xs()+L*initial_beam.xps()) + assert np.allclose(beam.ys(), initial_beam.ys()+L*initial_beam.yps()) + + x_offset = 5.354e-6 # [m] + y_offset = 0.1516e-6 # [m] + x_angle = 6.6e-6 # [rad] + y_angle = 0.42e-6 # [rad] + L = 0.0 # [m] + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, rel_energy_spread=0.0, z_offset=0.0, y_offset=y_offset, x_offset=x_offset, x_angle=x_angle, y_angle=y_angle) + beam = source.track() + initial_beam = copy.deepcopy(beam) + beam.transport(L) + assert np.allclose(beam.xs(), initial_beam.xs()+L*initial_beam.xps()) + assert np.allclose(beam.ys(), initial_beam.ys()+L*initial_beam.yps()) + + x_offset = 5.354e-6 # [m] + y_offset = 0.1516e-6 # [m] + x_angle = 6.6e-6 # [rad] + y_angle = 0.42e-6 # [rad] + L = 7.8 # [m] + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, rel_energy_spread=0.0, z_offset=0.0, y_offset=y_offset, x_offset=x_offset, x_angle=x_angle, y_angle=y_angle) + beam = source.track() + initial_beam = copy.deepcopy(beam) + beam.transport(L) + assert np.allclose(beam.xs(), initial_beam.xs()+L*initial_beam.xps()) + assert np.allclose(beam.ys(), initial_beam.ys()+L*initial_beam.yps()) + + x_offset = -5.354e-6 # [m] + y_offset = 0.1516e-6 # [m] + x_angle = 6.6e-6 # [rad] + y_angle = -0.42e-6 # [rad] + L = 7.8 # [m] + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, rel_energy_spread=0.0, z_offset=0.0, y_offset=y_offset, x_offset=x_offset, x_angle=x_angle, y_angle=y_angle) + beam = source.track() + initial_beam = copy.deepcopy(beam) + beam.transport(L) + assert np.allclose(beam.xs(), initial_beam.xs()+L*initial_beam.xps()) + assert np.allclose(beam.ys(), initial_beam.ys()+L*initial_beam.yps()) + + x_offset = -5.354e-6 # [m] + y_offset = 0.1516e-6 # [m] + x_angle = 6.6e-6 # [rad] + y_angle = -0.42e-6 # [rad] + L = -7.8 # [m] + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, rel_energy_spread=0.0, z_offset=0.0, y_offset=y_offset, x_offset=x_offset, x_angle=x_angle, y_angle=y_angle) + beam = source.track() + initial_beam = copy.deepcopy(beam) + beam.transport(L) + assert np.allclose(beam.xs(), initial_beam.xs()+L*initial_beam.xps()) + assert np.allclose(beam.ys(), initial_beam.ys()+L*initial_beam.yps()) -# @pytest.mark.beam -# def test_flip_transverse_phase_spaces(): -# # TODO +@pytest.mark.beam +def test_flip_transverse_phase_spaces(): + + x_offset = 0 # [m] + y_offset = 0 # [m] + x_angle = 0 # [rad] + y_angle = 0 # [rad] + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, rel_energy_spread=0.0, z_offset=0.0, y_offset=y_offset, x_offset=x_offset, x_angle=x_angle, y_angle=y_angle) + beam = source.track() + initial_beam = copy.deepcopy(beam) + beam.flip_transverse_phase_spaces(flip_momenta=False, flip_positions=False) + assert np.allclose(beam.xs(), initial_beam.xs()) + assert np.allclose(beam.ys(), initial_beam.ys()) + assert np.allclose(beam.uxs(), initial_beam.uxs()) + assert np.allclose(beam.uys(), initial_beam.uys()) + + x_offset = -5.354e-6 # [m] + y_offset = 0.1516e-6 # [m] + x_angle = 6.6e-6 # [rad] + y_angle = -0.42e-6 # [rad] + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, rel_energy_spread=0.0, z_offset=0.0, y_offset=y_offset, x_offset=x_offset, x_angle=x_angle, y_angle=y_angle) + beam = source.track() + initial_beam = copy.deepcopy(beam) + beam.flip_transverse_phase_spaces(flip_momenta=True, flip_positions=False) + assert np.allclose(beam.xs(), initial_beam.xs()) + assert np.allclose(beam.ys(), initial_beam.ys()) + assert np.allclose(beam.uxs(), -initial_beam.uxs()) + assert np.allclose(beam.uys(), -initial_beam.uys()) + + x_offset = 5.354e-6 # [m] + y_offset = -0.1516e-6 # [m] + x_angle = -6.6e-6 # [rad] + y_angle = -0.42e-6 # [rad] + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, rel_energy_spread=0.0, z_offset=0.0, y_offset=y_offset, x_offset=x_offset, x_angle=x_angle, y_angle=y_angle) + beam = source.track() + initial_beam = copy.deepcopy(beam) + beam.flip_transverse_phase_spaces(flip_momenta=False, flip_positions=True) + assert np.allclose(beam.xs(), -initial_beam.xs()) + assert np.allclose(beam.ys(), -initial_beam.ys()) + assert np.allclose(beam.uxs(), initial_beam.uxs()) + assert np.allclose(beam.uys(), initial_beam.uys()) + + x_offset = 5.354e-6 # [m] + y_offset = 0.1516e-6 # [m] + x_angle = 6.6e-6 # [rad] + y_angle = 0.42e-6 # [rad] + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, rel_energy_spread=0.0, z_offset=0.0, y_offset=y_offset, x_offset=x_offset, x_angle=x_angle, y_angle=y_angle) + beam = source.track() + initial_beam = copy.deepcopy(beam) + beam.flip_transverse_phase_spaces(flip_momenta=True, flip_positions=True) + assert np.allclose(beam.xs(), -initial_beam.xs()) + assert np.allclose(beam.ys(), -initial_beam.ys()) + assert np.allclose(beam.uxs(), -initial_beam.uxs()) + assert np.allclose(beam.uys(), -initial_beam.uys()) @pytest.mark.beam From ccd580d57e36dac81d1751f7c887f0f3d50fb80e Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 1 Apr 2025 00:45:10 +0200 Subject: [PATCH 28/51] Minor changes in Beam.apply_betatron_damping() and Beam.flip_transverse_phase_spaces(). --- abel/classes/beam.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/abel/classes/beam.py b/abel/classes/beam.py index cc969db4..84b8c6c7 100644 --- a/abel/classes/beam.py +++ b/abel/classes/beam.py @@ -1234,13 +1234,13 @@ def scale_norm_emittance_y(self, norm_emit_ny): self.set_uys(self.uys() * np.sqrt(scale_factor)) # betatron damping (must be done before acceleration) - def apply_betatron_damping(self, deltaE): + def apply_betatron_damping(self, deltaE, axis_defining_beam=None): gammasBoosted = energy2gamma(abs(self.Es()+deltaE)) betamag = np.sqrt(self.gammas()/gammasBoosted) - self.magnify_beta_function(betamag) + self.magnify_beta_function(betamag, axis_defining_beam) - # magnify beta function (increase beam size, decrease divergence) + # magnify beta function (increase beam size, decrease divergence for beta_mag > 1.0) def magnify_beta_function(self, beta_mag, axis_defining_beam=None): # calculate beam (not beta) magnification @@ -1273,7 +1273,7 @@ def flip_transverse_phase_spaces(self, flip_momenta=True, flip_positions=False): if flip_momenta: self.set_uxs(-self.uxs()) self.set_uys(-self.uys()) - elif flip_positions: + if flip_positions: self.set_xs(-self.xs()) self.set_ys(-self.ys()) From 7e9b64b886728adeb656d849337a46ee9041a602 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 1 Apr 2025 01:32:05 +0200 Subject: [PATCH 29/51] Changes to the default relative tolerance and absolute tolerance of Beam.comp_beams(). --- abel/classes/beam.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/abel/classes/beam.py b/abel/classes/beam.py index 84b8c6c7..a8ad786e 100644 --- a/abel/classes/beam.py +++ b/abel/classes/beam.py @@ -266,7 +266,7 @@ def ts(self): return self.zs()/SI.c - def comp_beams(beam1, beam2, comp_location=False, rtol=1e-05, atol=1e-08): + def comp_beams(beam1, beam2, comp_location=False, rtol=1e-15, atol=0.0): """ Compare the phase spaces of two beams. Chekcks if all arrays are element-wise equal within given tolerances. @@ -279,10 +279,10 @@ def comp_beams(beam1, beam2, comp_location=False, rtol=1e-05, atol=1e-08): Flag for comparing the location of the beams. Default set to ``False``. rtol : float, optional - The relative tolerance parameter (see [1]_). Default set to 1e-5. + The relative tolerance parameter (see [1]_). Default set to 1e-15. rb_fit_obj : float, optional - The absolute tolerance parameter (see [1]_). Default set to 1e-8. + The absolute tolerance parameter (see [1]_). Default set to 0.0. Returns From 2437ed1837022ef797b07217830d318264704188 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 1 Apr 2025 01:32:59 +0200 Subject: [PATCH 30/51] Added test_save_load() to test_beam.py. --- tests/test_beam.py | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index 22cf8255..56881e1a 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -1711,4 +1711,27 @@ def test_plot_transverse_profile(): # def test_plot_bunch_pattern(): # source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) # beam = source.track() -# beam.plot_bunch_pattern() \ No newline at end of file +# beam.plot_bunch_pattern() + + + +############# Tests of saving and loading ############# +@pytest.mark.beam +def test_save_load(): + + import os + #from abel.classes.beam import comp_beams + + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, rel_energy_spread=0.01, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + + save_dir = 'tests' + os.sep + 'data' + os.sep + 'test_beam' + os.sep + if not os.path.exists(save_dir): + os.mkdir(save_dir) + filename = save_dir + os.sep + 'beam_test_save.h5' + + beam.save(filename=filename) + loaded_beam = Beam.load(filename=filename) + + Beam.comp_beams(beam, loaded_beam, rtol=1e-15, atol=0.0) + shutil.rmtree(save_dir) \ No newline at end of file From e04994dc8179031da70364fd05cc2d69586595f8 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 1 Apr 2025 12:10:11 +0200 Subject: [PATCH 31/51] Added beam reference file for tests. --- .../shot_000/beam_003_00048.558626.h5 | Bin 0 -> 1083528 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 tests/data/test_StagePrtclTransWakeInstability_beamline/test_baseline_linac/shot_000/beam_003_00048.558626.h5 diff --git a/tests/data/test_StagePrtclTransWakeInstability_beamline/test_baseline_linac/shot_000/beam_003_00048.558626.h5 b/tests/data/test_StagePrtclTransWakeInstability_beamline/test_baseline_linac/shot_000/beam_003_00048.558626.h5 new file mode 100644 index 0000000000000000000000000000000000000000..b9b28b154e015a41605e514f2da693737bf600bb GIT binary patch literal 1083528 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

&nyRp!I^+FP^^X)ZGU`c=prp(M5 z!iDqQ{YsOYH30=)vE(qvXM<%|?166GQv9S>pnQbrR+F*2-u*gP3SW+_ozkPTgscm% z7Pkvo;^WuicVBNcLTa9`0qf2g2D^kt@r|IYpBjfIc*7H5Q>MZumPS-nGDu^9OT z_qqQdT)wVV@0)vKG2eYYyLKTSO6|gmQaEB^!`tlwyUYS06`AHwh7g`}my(PH>36oX z|62Xjko0vQWjLkPZvz2FZ=V{x_klBe)emm0vq7e~o$Br`KDbHf@)`BIT)5=sK=;Eu z7Y;9ooUt~{MPtK@{*6t!xNrDx5L(ipV|cy)swEBIIFD`|u_#4GC7s}NmZhL;k};AZ zoPfWF+7-FA5@70|+P^kRG9JFCb!(GJG87HNRlTrN=q*~qxIOF?EGh-ttBU}LI*)_aqb%rW#rBJJ*#NRC@CFI?l2J)w3 zuADxSh7W~2|7#@qqco!ip=9ER6Zo!sR_}8P7`VJ2H?J~#a0O?^vQ6_QdIz~ zn-fdCRz~<$W>ZlCJU;k?k==ey#Rs%^H=gt&_c_0;uJb&(-~E$|g#t+b>Yb*bk0ztJ zs36+E{Z4xj_OUMWi@OG4{S`Tt$dVvX-$ZZLt`!6qLN~}H7n#CFk)!tydzpb5bA!yP ziy5YiitB!@Hbpt_@6Xh7Qeg89pYA`DIE)%yx&0?54(hf}^+7}mwzjl>c%hq%(`Ksg z6N&G8n2WhuR3{e>IPK|su0zgSk$#`>=}SPHdOSCndI^`MA8nt15k`7_ypNoI7lzc- zs^e3~lW^?(`mudPU;429fUbdR5`17Wwzr^51)j%)iM9u_FzY*af!*#5xJYTN&)boK zwn9fc-A`wM!MM>vj%^A$RTn*NbWMStpCV;T9}+P*dXC9tHW4fyT>edh2aqO-bxF4p zkZqiLP$3)?Dm`W#Qb^|P zx!RZA1!!wFTKcoM0B&hXEz=nNL8sf0i-)|2g*LaY;cHj0ikZHr{nrn}$462l^pjCa zlOs-Li!Bm-;DFBl|b&ycvQYp z3Et&5dGlE$2mD>HS_j^DhMBRKZ@3#=uy?jkZg|oK{tCY>qmXmZxz>E0nPQ38dMrak z`!%svzfgx`y%vaBxXrydcNs!wEyd?o)1fSFk|V=26CWsU>WlTt1mWpOPqx)`%wJcV zGGCexCu4SdD#{bC_6sXiJszU^65f6QoJl+q)B*?GJiMp7!}|}x;{sv)?7ewAx`twTx6ZQx<_=L z0<4zJbjl1ApxOBjzS}?{{O^M+H|HoA+@LujME0yAl_Rge`FrDoX1yp)FK-ascPhDx z>}7v%e)F^2EDdK*bG;l~Pr;o9^Sk5L5xp$z?!oI?Y4E1{>O=RsQaG^u=I*1Wa{RQ? zJhtOOIf(3j-?H^uDYgu%h;67!fDiG%&Z}xApf|5?08fk^{OM6HjfuC$ahZ3aFGm9) zaI|*bvpE18d{|HLevZJKeHYiXW+LF=&$%>z;?wwuiN8Ly*ueic9ni72EcDrP&f)u6@eH>lR}QNEIy=CA_18d82pK7R_v2H(l52 zc_b6A$k;eXi)Lc2C|3Sf&xRC6ePewg;sXu7Q0A~B4c4uVuu4EO?$1ektst0&sx`qv z5>mOqZ^Rfkr%%O`VP^8qDpY_cXWHZ?bMY_7z8`}vf%sy2@ZZOdKoEFW`~Bk};rLvv ztgILfLUyXS%I&vgz89_sl~uwKT#Vv%d>@auw=(P&V9bQq+(BYH_q(BApwEhsggf?) z^?RpsxRX57=M%!@y&1Oa;OgS>RP-LKWy(9A3KSvUQi<6VJg^w}^UBv0kf#51@99uF zUX}IaSJBCUi~!Yt^dsrOm#ezZTs4FE0#*O!canafu?FW2^i+sB@p8VGj*5~tOIvii zGr%=_<+N633Zw#ovc833b)ES zt!Zk3c)z*i{CsdYKDo8su04eCEak%Xmn@&f&0E$uTz{CrLk~&U9ly_l7<~t>Z8ODp zvHv(&p68-Q!kmHlmTc%vHNB2R2Q{48v~To%E*R9*zP$4+8gyQWw%xlChp>xDwyHV~ z+DmgEZ61ooIL#JT(E}c&FS6-VBZogoKMLmtk}sZnq0PuY?F;h5 zKNIQPA|N^X&Gtz52(+uJ{#-d0gvY6~)-1n+;B)JxH%e9-cy)_<{1Bc)z2c|EKReW* zQI>95s7D=?$Jx#)s3t!<5q zM?n3Z^rV``C}hy+60pBZcw|prhjR@_AfG_l;ypVBOpc7ua1vGoMbXWN)kIIiXzUg4 z-e^UXzZmUQ##4(&943=Fpc>vj*Wa+lQw!evP1#JL8sq-l5$}{rfCXXxf$S3rNI=D7 zx*R9Gr(4SXc@ZtI zD5UiF8lk(bKvvmN17NqYPuX?X2-NZF0|`4mvTwWT z2-{d!JNkAzp|QvK@>EU~Y@>$FzATKyhug;+8Hi8p-52$Q8yQjfbHLS$(jNucjP_3# znxk;}JvS3ea5O5)^K^dqiH3U&#c$b%ih-XmGont42F^8W`}aO6#_nSseT7owUfK1P za%njWuh@D&yu_Ffu0Pw^cxUpk%HUtJ*XJyF!BE2N#Sx60udjX?){7yjQIlT*iZQ_E zy+iN8WDv=(zGZ$CmkZ9Or#XeT=fYiwq(_%Sa>-t*{b2f*T(Z`!ndGv`M_ysi+Spfl zpi*2}cXT2TKc#jxvfJi^$0Y+_sRVc63Agm%jC9B4~SCocQ^?AKJr896#P+Z~q+6*|i zXg0C$R0ila-YE~ent`6eY#C!GDX>G`;`8)a8ipwkT-24Npyp>7?P2jQISoS3|&3SXQH;HUwY%kG(ey$0~XozDd#~ zLn_LYOhsf0DXdL0RU~67v&^#$ndf<)$t*G@R76@u#-tIEv2-#Uh1EHD7M|`QsBC-=FUL z;*Y2W!@q>rJn)NKA6`exc%lPIXZXMAyP_nsQs%j1?l||Pq)Q;|^CTL@{CnpaSNtTG zrBh@$6E!fn`)*y#Lz|i+e8t8y@yiz}Gov$kc#_(ZHvY;8KjHE=t8r3CJ3pO&D-vmp zf)q~R+(31FTOKR(94bKud%4A@VoUHkpY+Ew!X;Sq_uoOr_!6{rALoMyd!n&$+n#MKCk&NadG`W`8ld;8%i1Hc2A5Hv@?C?_a$6>Y3eo`C#&_l)FSNS*lVHe4^ zLkIQXInU+?@NhUBRSj+%v{VnryZ1hMyjMLEDO5yPS6wZ_VScL(Z_0~N<>H6c{Uyct zwh{9rqh}F%YvYz36BLYRsKTb{2feZ7t|P{Iuzn;@q~3h%UT+j5dc?`24Cd`0FEaA} zd==?kd6pEy6^Tx8bdJ8}iNrcI&GgM4*OA$i`r4cD+*n(r)yz938znIGhPYqL#uHvQ zG{#SQpu=}fZ{KJPM%f*W*XuiivHtXvLj@fkc=Cw3;YX-{vBPn)F;^mx0r&cc&n6Lg zIq}ao@Az>1(KG9QRaz)=U`mZUR1}IO=MCOYa=Rndo@zcxX~@42gd>?C56pIl%>Cvt zeqQ~4VimLI;@clui`s*8QCkfxgiB1sFU5IF*i@rXgM{;fp-L1s;j=jr5(WF+8hR!F z3rRte#{O+((8&KhKV4N}1oL!?E)YTyDLCDxfl<3T6_;(P-}I|F71}v_p6Bp^!R$k8&vKx@Pe_gmz} z5-Dy-O77B&HhdjvPfQB#|5Sty3*T^Sra(SXA?K{g_Ukz8=f2gMLMvo9NM8{eYL6u5 z4Z3)Wtnl#j$htjY_P9D*FJrpH3yBSUxNKJMg?~s`vM54+tv@`H2RJQ#Fqg74Ya-0s zi0yPQ^i(ND0(Jj5gQ82(r$1(=cAP53r=HbD{Ge4vC6SNoPjsrFkzmi8DpyqSMr|Ya zyM;=4Xx9d{i^qKN{i{Fbmf$*eh3Tm8C)hW2GTVG4@j9&A5#2XgyEhIMB{ABtD8qC4 z^CAU)3Q35m_QHYBVMn*;X{m<5Avc{eE8nvm9H9&I`~nuWK?B?4k}gMe6N=R z&wcOuZ2Vc6g=SfGUtTH7!kG**Em`APcwX9b$735Ol<9Eq_06;P$WCFap22fF{9$is z@}e-@=b-(2X8J;QTx*iAU|uLkV)3&M66}tbmW_= zFHWuQ$xL7k!pBcDr^&AdB0Uq243ne2D6K4l(ko$)lVh)q%0%1Z3sa)oS>)`I!$A7A z)F@kI?me!V>EMJy*nhrw)9!~?>|6y~EBw%}mMWdRU}wBbv?Ez0T^AkFcA1(`7R67E zS5J=9=;BSbH0{!a2%+m+woGcY~!v#Y(9KK+i)ZRB_5dG zxqQtAeK@JFqx>ZV)k(M(Y`q5c`F6PS?d1@B(YfWy`n7Om^m0OsMKuU1w|Rs{+j*i_ ze=03^CV-XJ@!de?Y)U2x~)z&loVT@hy$)afa^YW>rYaKL%yuiQ)*gLvzTeQD8ikQ<^v_2b5h%YWc{-;c0&{Nr zUfWR{g??Q5(zs<9?!*4^E=>KEiZ>2-DhSc1p`BiT?^7pJk$tYrG4>6PNa}};1fPv3 z78b}6N%r?dIZt1IZcKH+*;@8~0T!lccXld$rPO7VN`JpBuhSH7f2+A?!|O|!I89XR z9e{i&_nrB-31=at-I9!dU_XxPX|7d)fE-+rcWIt?I1shv_OYJaZ-V6N(oV_H8{r;m z_!CFykAimz>KOVX@ z5YPKdeD(|oMBiIZ4yBI=Aoj(^uF<>z%>P91kEysdQrS+OzIHYMy*vGZN4?t$TYFUA zmOqt&cGYznt2Gqh*nHD-R9K%~$7Y#0`?vtHuvks?rX`@Lk~YPHnn+X<#Y$~0PQaYn z?&`BQBJov~GGHV3IE;i(Sp^5%dX^x)`l*Yg^9 zzEP9YuU(giS0e_*3L$ z1z)0egrjFK;GSHR1mGmQ!zeDA8L%L`~3W_~8Amt6~C1azJ*Xp4#z0_mRWV^I_#7B!-8`AI%<5TdyPn2zmFjrpWd_=b?%V5fnCgDBudxXBHQpw+>xOMG3T#*zjxh2-(jn!AUao$a z2rb+C*2fREeLs9P40&LW!E=hWcMNeqC*u;|{-ZeP1pi`qgaI<~zD;M=EQ$E$-lq0! zgS_?kw?<80NyJhQ8*Po46H&0O=hw|niAbgI{jdIfOJrT}q+IP1Jny2Z-Ol~+3^Ef^ zYF^R?4;Qn%BOuQPk3xmjRA4M7)D+^2ykk*c0Bgk%aul9E1fwu;kQy4uR*z zl&So8A?Sy1uj+2KAe14?*}n<)SMbkXmkWoyB$sr1?maq{g6_V3_W6W*3jXG+pr+bj zh7qmsJHpHnb;&ygZXR;NJ!e@4By7#mp%xj=A;$CAnzHxR)6;%PlkP3&T_HalEo}e9 z`Liyn&r@#nZx6<_I>*yk9|t3&P*Y>-axC6f&$wXmJQnR6?_v#Da>pG{L7EZj>#CMS?8~;!)n9UW>Leo-B-gRu*h&A@#@V%^f zyzAhm$d~!?NLVDPGJabMHprWu-+7P{s;5;b`7*pOQN%J_0)x| z_SkIn>=BY|5(-1_>}qYJKZoK3VHK9V{pN^4naMn8#vIpG9N^t*6o7oh)OT!~f#(5V zmr%*lwBX2((hhvEpA-fY(QI%*|EJY*=r#BG7(HXi*_$Rvb~vrjmlbVjIsI(^vH8R5_r2la(D zLA0Q9XKskj3}ff@cfwre@Z9Zdh7zYa>e)Ce<3MkQxDTr>?TWsR(pcwQQX2|U@;R3} z-MT{D7Pn-2EAcwsuW`WsP*XnAN?M&hX>uLyPP~7>zbPLNGiwGMyl@?V=53XW^@>2A z;nGi4?!tPnmBGY3uLw*V5^llO6pmU-g)cqPibQ;pSL;88LVkdgQchtmVK^nmIO64r zNF4d(NXy)O1XAY?3+0-Pz@JN>_HOHr#4LMKj!C_aM8VQ2@4IY_a24Ny<2ejQXn$eq zYX);)bn(WI+~w`QScZ*@W<(nDX6c2~xBj(27C`4U(tY7I&Y;!`imujd$&l z*tGqNxK3+)MvmF7gWU$HN-$*`_t|5?y!ydsdjha4Wy2}s4VhV}pku@L+~ZKb30l0TxEv?@(i4nc;MOj0`{{c+)!JN%bhLh$zw+i)k$<9oPs z+4EE#>~pU$AQQS0iEnma-Qt-5`8Kz?={-vbM-9*H((&F1WNHwxw8RPDva@qOvSq$DU-29GW0vu zk2ZRv!a$YyO;>{P->TX8twZ6+LhbFiUROANA;0uM?tCzEjCvqF1J6-*(%zT9qo0Cb z2EvtfT?$Hc(z5(^F9rW~a8^_gJ%Nmi67Zf}Lu6OJT(0S!}I)IkAKHzqM^fAYhzMSb%uO?LlRgg3Ys_aJ6A4F>EF-PLeBqc|)vG0QG8XssK3BY}m5amrdGq?UbJ3Q( z@56U3vr)@q<=cXm*;t9?ypm<4aoo4SY;*#C|d8(ze-b8_WW22=brpz@$9`$g0wnHJj_7K)T#Rz&6whvMmm z@aJbmARk|PVgL0jY1px`uai0dAo_P&?e1{+A2M`X6TP~-=c&5nnyRCB{?4deC1)BFdmPhhbzRl6hodKgPr?09$ZCK z+LYKE@LYBm_4?EBKBaAQ`ZWBYV0ri)~skPVAR?r}%2zIq>vgx-8( zI20X^B_>a2QQ&#O-_E|OEbe6Nwkz?29D6d_JUGe6NJ<KXdX=!F;JW8>zJb_E@~v zd~|v_EfO*Ak1Om-jl?ZuiLH+uVV-8f)aG?lYgBoQ&MMT#8ml%LJ?0NKLp>jsGZ_qH z5#JNNUl;Dg;!c^NShn-A*x?OoO(>2< z;yIaop8H)YW~se@^%Lw%+F7LjbHO$R4~A#E{d;eNS#=D@lK$Bs0rjNJyDY}&?9|BR zm0L#GZT?Z<;NLJ*?m6LP@Fxua`!rrZIt%&IlP%WdK7`^EpZ#8Zu*$?=nt}>u!(pC~ zL+zcbvC#j!F?Y6@`y6^~)6jn?)fJsMRbJ$99m+|_iEuT$O{m{X+=X7d~`IuF!N5F`Zi)~(t{Y;<8MeEYy z{aTs%XlrH6IsGu0cXL3>IW#T@O=K>b|Jj?1t|vBDj&bK=F#)#AUmryy`}~Zix9#Dm z%r13aaV;7L;$I4})$KE5Ti zUY>;~rc;|2?0m4$#-M?k^F9a}JrmH5bwv?c*4N#AT(QAu`_?{KAKAoLG3#|B9@9Df zRQz2UgR4c?CArIDkiz^125zw^WE?blhh8EI_7&M7a&tKnPrT`DvtEuwVV>c9@1mXY z-j9^jLkBc)UZ-vZ<+3x9tr|2KQPDzGF&DlwTy#X=Vx<2$TyVrRDcQg7W;viA?WqTr z5*;wd>7Z5VZV#k>=jHLvL!M~g6;VOieh;il38D4m^~6=3HKMh5i_!2%ji*)yj64=5Tf}V_?r@RfhVCofl$lv}!?LuIcew;@ z@%1Nm)&E*yJ#EpInpe7!IIP4Yv}2P${*rz||3MgBFRwODKYo{tJ2q(W*MCe#2a~UE zy94*jzZ4|+6{$ueTHh%gY#fD+dPiaxjiQiR?!=TRLmb``=-cyYQygM9j?#Vs`;oG< ze*X~iGZ7b8o)i)PlZbM-`wk29CL@FNKZi@qLr~;teocP05Nyi1v&@9i7k}1XsqUpBJp7I^%JxDLT8~s5K243s$tBWvOdLb;yIny? zw)~Dq@%6pAZ$e>z#0!bKOa&fTV0)FgM1KG}a^ILCMJf>E^yaS2MR&BUH*L(<1oPt$ z3>!L?M`Cx@d;4UIB2mF`FOAd9C_Fj%A!Z!bA0^$2S7MEX`P2IUm=Ypk|G-D8E_rPU z$oqN!6MywAoT_OPr~&%{3m(bden3A9v2{f+zkZp8g7gaW9l9WIrsjQ5@sVuoexJ3{ z1KKZvn(TcGMk)A}Q3)fhNItd*{~-M$zW_Z={iEtwSb#6!UE8lQ=c9q)&gC6vH)Edg z!xlAG=a5)l+#Mop4+<>5U%XHE96oct{Qfk|i{Y#nZu<+@#cx+SiYdy$c=+hT&NjYa z#NG2fvZ68seRl4eb%*O-RLOI^H$MbB#?UXKimOHqdezPDxXY&y zKkN{Z*N64oo?Z~CQRm!w{H5@1(fmG!D1-{h4Iu>T!7d+E)tRxAnlw^LXl$bk9(SrLor{p+l}5A6_{51*kzgN z3N&NiboSU(1wIz1?RM-{1@d_v`#U7s679M*c|_~GC9d>by7cg^Gv<;)qaxleNX)=P zSZLN9N3JFuaq%(1UsrjaKkhU~G$Z{QW-Axa30dZ`^CE#L^jRgx#a{vVXd26#tbQBJ z(DmNm$Pwn^Xsy2#_T7lK4W@bQJ*wBs}|U)v2H zPlsmX9vPNnx8&21-yI>kw99GOXT?wFAmm5+n5QWb(h!HZc2nVsHLl2B5eXM_rrbeQEr`qliSa((` zo)tQr6NyE5A9fCXj6kPZUbgDM_%oGJrDAG43M-?dtB>cRP^i%>y8Rc5(PJ?$_rC_k z_#Yd$S-f2l?hj=(8n7-xmA(!ieHfB(uKc-Z2AH>OA2KssADD=*=V{H^g(jl>aJ#;z z@O$<4%A;&B@Aa2V)LmV}Vq|dU?`?gH5_Il&QFG3pK(ryg9i5#Cz#?u%4?MpFpbH0T z>FL>m@Y9EqCW#i8P_f+PQCp8o_^Ub{=TJ97IZvGE%B2w&tY-Fp%UFO+IlW5bqx!19q(Lky@E;}Fl^W7x5Kl%t9^%C zQ&0;Q5}L72!EVI|8BFh|U?HW=Lp#h<(AD=9qyFN$xXfoHucT2G5ksO@DW`Oi&=X%N z-T^giS2J2yqU3=_mgG9ljCo>#@M`7@aNq5lyi^d&J5MB`-23Q(ZnXDC~n;DZ}r2=Il{c-1m!p zx9ss;^RK6SpF=)l0fU%JCee7y(Q%fc5!lD?fwX9gbu>~9zV%J%Up#&Q%0^#k~BJpBug%T2F4In z%~hr4@I4rx=bTM{#~6a?SgU1E{Rl?!+PF(`Yboxh3q5X}S%&R8)-6IAN>QBAQ@5w7 zWyqHynLq1Q3alqlqGMBqeFQD#0)CICV2ihNcRW;6(Rtd@kN4hZ;p0lpqAN1#=(y+i zX6>0Qv?E-eQCm12qn8^)y3S;vZ(r4F9yFxl*)JoXjNv(T+2;ni+lm=jz@_SVG2}^7 zOB_Gl<(P;|yI#vwzd)3x(Gaq^*(5~LWl>2$qZ3HB>wv`v6<(Ez{sebw{c=&zNr&&}8Nn4{z0 z{dY#*m~-p7gqL6JQHoH>$@zcG;=Q7@U*#v1kDDI|W{Ntv07(k7v8t^r8yw@VCdC z=lKflP`?ICj<32sdiyQt`-9GM$b&B0;P{{%pYiWqpEE5*6vs(VP1{mjxbB~sqELa@ zew#UAg$mqiC|r`bRb-~s2@ zqZXBN=nwTwfYd!HTw*WANH-9LWM&Uki1$X}Z?E@vhbM<){T&7utHZ;Q$Ta2-9o9m1 zcC}|37M&4otw$N7rVC~qV-WsObrR;?%6wwDorW|sW+X$!(vZY~yduLxX;|X=-96u` zU|vpM(`WN1u?Qj2EeAScvDo@@>+SSZR4l?&#FGv41kb!%eVYz>Ub9UNn{VWzDZ;Am z1$ z;S_=bYD}g@l_ODQsefIeTqITvUV5=zDFO?On~U`PjKUYMoU?f78i7iMQd`TpqR}*a z5K9^4Yjup*j~v|r^JE+~C10;ap@`l}j&0(wU%4#nu5;O0I7D$JiqSV6Sv#HNJ(QD$ zc8V9Ii3X)(7v^ne!;7Mju9pg5*7YdtB=IX#gFgnvc$xbB5sJaTuVhGQ*5>00>ByA9 z{$f;okSdl_0(s<^B2>Je730ybUY4(neNp}JJqKnTUrZIrp8C4thiX%#wsNdO`)Vx2 z8T2jPj`1ip+KK z??tg*DB8T%yrDS{r-vaJ)(q+{Z zm~VGk+5Tx@Fn-~s`DhD_pKOZ*_lgDuqekxWpW?9Z`JNh?L+4<=aK{9!cQi@E#WJZg zyL-}b-ephbHc4yDz(b|;J|BqituZlG=;u%HycB%mZjIhHV&6w`Zm52r<-2Eleet85 zs46)|U!)!(EUo0|h6`9P6|&2^;@QA9{0#PMVDyri);9A-%f99+0*0<=zVe=bKzkC} z__S6o@ktUMq}#g2`Zyl(FAVM;ACAYD+Qg~jzLCgU!9V4uPbA*#mLNe_2l>4DB^IvS z3dd|xXD&^yr=ctX`8UotQqf9o*{Be0IzDG9Im=y@itAo3mw#CbK!vAhi!6TxzCYOW&-8vt2?IuW>L9N|%~1;^wR4|Z|HEo* z9(MU6T}>@|=&Hma`>+}vS9P>)uBpWrOph(@f%&D;G2N#(FUDX|YWKT`D>2Ayqv{Kx z196y>$3XQ%wFh9tyg#0X4jwMUb^9m?rK_yAK-LDY%x2(7rW#l z-bd%$sv@OJA(_ z-10!vY@wUV^%K!{iCqjbmlN@97DOhv5 z!EU)T8OJdD?OO7MaiQM7$9*u*v+DJ?wtyF*h_19NYI9d8elhojPpI!2t{yRw_~M$1 z=9|{DmAq21BS%ZJ)SeW~q_6+f{a^}uI(*i>tXu|FGW8wW%`1)WMKN+4{FcKy4By)O zypG|3h6(2FTIon3%-kHEPKUh86W44N3eoTpPufn|LL8hK>q8aJK#wxs?%Eocj>C3y zrT*KIfh{iN%{IiQqhmJtJVWE9qhLZi!>*lK6?C%x&qIccT-7%Pt zKV?8-7tFt4b~?)QEgEmVaeHv=cQj&3@zG41MA(rfMOtcY3#Q>v7l^7*LC5xF->x*> zimdJX-u@ZN#eNY%TF<4(S)w#^80P{dXeMCPU5RF0ZJy&)Mmc(Kok3C1(GJR0x zx1ciXyFOUr#f6EBcfF9>&tH?1#a@_k^YfFZcU(e>$*oFljTbO}<)w44<^uX$(Dq}~ zrb}2+hW#SlW?l4i<5fqf&&eM7cML7^9?mZeHAAx0ohy^tW_UhSnzwGh41WCGck*0v801L{?p`zwM~{`+ zybQ9#kldH5voWqPPiA4%P4h$qP9WUWgujL$r{<)ftYx?lkinzvq#A)zotd9BDn?>4 z)7bA*HSu`#rBY#qNF=(@@_RO0nz|zfHXiFAPtZPNCTt+ z(g10IG(Z|44Uh&%1Ec}c0BL|UKpG$okOoKtqyf?ZX@E398Xygj21o;>0nz|zfHXiF zAPtZPNCTt+(g10IG(Z|44Uh&%1Ec}c0BL|UKpG$okOoKtqyf?ZX@E398Xygj21o;> z0nz|zfHXiFAPtZPNCTt+(g10IG(Z|44Uh&%1Ec}c0BL|UKpG$okOoKtqyf?ZX@E39 z8Xygj21o;>0nz|zfHXiFAPtZPNCTt+(g10IG(Z|44Uh&%1Ec}c0BL|UKpG$okOoKt zqyf?ZX@E398Xygj21o;>0nz|zfHXiFAPtZPNCTt+(g10IG(Z|44Uh&%1Ec}c0BL|U zKpG$okOoKtqyf?ZX@E398Xygj21o;>0nz|z;QyBfXlWQ|X#exc|Ld>+fc?Kb(9-_* z0cN59*7Cnd2e1F<6&7A4n$7?9k}{3-HX7-5y8r$;dN}%@*Ei7p_Zw{fpZBBNu;Gf* zrvLsKUYh^;RR~%C=b!)ioxc@tZMW0N{nrou=e*e9H7{p7Pd$zQ=l}1&&yt2_;qIND zao^kWH2?Ga|Me#SFaA1z?&L{YnhiAT|Hq&IThRaUp4q4V=R^H3fxQ3w4`iQW_}>rw z&+Gr~?tg!Yj7S5d0nz|zfHXiF`2U81?%7a-wyjhmq_^1Hd>fV65zXfl5AieSbm4;# z3$H|cy!(toT>G81sxm|&Y%@jndO=L_&$9do{C9RU?*?ls;bQhp*bJDdM}PL06_wZ> zdDS5U;!_zbteUA5;_5_bLKM(pS*49RjY5Q}j%z4Etlu=p_xB$BzRHc+9N^aD-Q!zY zsKknC`jNe@RO0N~sni*ND$&?fVCoNSX>Rm0J%5NbUar1W2fk2hUCZR461g<8 zoSA#6#A%hK)8fGLKVxT;fX3DjTW=hgC*G;KwRQlr<$k+l^3N043tOx~9Qn_oKk6`* zIL7tz^)yh++-g--49?%XHu53xzOvvO38T&Uyj#;8*&}*-a&O@ojSd`jSGJ#m|Itg!n^}+BdcUD#6c`#;^>&Bixpr z-UAK`8M(X!o@`(&=>mU|0jcsaz^!3f(~&@}3s&C`0p08cV-Jl|2@$7?{*DnUVbkq0 zKlmTo@X2q4YCG_64Mhii6y}IHvCj}IFE02 z=SKs8wx6Sihu}Pa@+iv|0;S8FC4Cv7{!Bfe|Gt?@ywrC>xxihg)oQVd`*4A2j8ov0ml!BpVYmPUILnD zCp7(n&q1a6b4URADO5pr5vcHPm`?`SJ;Q!A1ImF;Yf78`TPnf(%^~SG@WkR5pWATU zI$>E{5YFS?&I|7xb*RJ{fnR7p#H#N%@mK(boYftsu26}dvoX8x1G^eN{`m`RIG_1& zhaLP}Whh@I3zX}-p7Tz?3YU!EDy;JaSC?he2Z+a3Dh&kY)`NRL3|t4EI$F>+a3Kz`2dxm75W}^0?5&5;&qxI%30~ifklWNI}Coj zOQaB~e|#V9OQH~}Uf+4bk|_i;M_#f$Q2or|ZM&Gk7e0GZ7JOl!;So{r*T+j2wh_oG z5mOWg?M-~6tl^3GP(Fx#69Pb9cB|1pK<3_|{T+Lu9t7vL>F%Qv?z*a9!Xa)Zm@fB0 z?DVFQt!9uyaOD4zSB3fzP`Fcu8~Pdd!)@J)K>Lj)h3o4SLikDX(E{N9KRuq-G|;{Y z|K52RxU{?5&e4`a$X4w8{sd^N%U~r5Z0S-ue;nA{+a|Ct7~0{N?In`H8&`k0IsxBP ze^2=bL49t$x9KYzv=8ryo#Q}dADt}W-SdQ{9IfyJi0}07+h*fVCGK?p=xPMAPM`Vi z?Lj3{U3b2J0`aSwxu*JjDlx~NL|g{`&6X-%0q*GjQ z*44p%z`TIJ2KvC|R3?`LlN91+eC4Z8Qxrl%LF_X(kh>3i?gO6u@YC4-I`q#aBFZL( z&<@?dYQYLT`esu@J{*^4jvap!Mx|wO2n=2W(&Ct1!}#M+j+Hc6mOF8`@xz@V{1 zNxz(+9cYVsJ_uYcdz_u;4CllBIBFx1p5}0f;=y@>VL|IeweUQlZG?E&grFZ#Q&AFu zxFu6c5spV0Kp2w zgMlp%lj;lq(=Q{-i?YDgtq~e#&@a;@eD6CBJeyIG>i-$a`^Smj{J^wZMnZJJu|Kq8 z7lG>)v%Y<_RASutnDi3xpi5oveqe3i?PsGvIc63+k5FhQ3{>^*0zLCB7kz*YLTqhz zz@y%p0n!UlKCU6D&M#D=@2Z9IS%`JKey^_qZ3P7OtxC@m#a6BSOTZiS&A3`-o)Fr7 z$YTr8_?6P``YZ}@E}hx)J8<%s<{QRr3gLLh!O8&`Bwif80`+J|z`Io&PAC^IrWmDw zQn3ng;cz@`&Nf5;4TVT4?y8~y_up7qiUd|>{5&lGnnJ8y;5=*s<&16Lx8prf4)^ao za?uiEQ+>0w1&Cj!Sd7Yn$EitYe>z}F*e&nzTne#)bM^frh{wiuRqLC>|DQFAz2WJp5#mOdA){)DH5wmiM<8gYE z@`56OwvoI}EkLP1kNt~*o)dMs8c@y}|8BS?-~zul@WlKo#4xv`qfMFzD0?p6KnGZO$!o<;2I@=OW@Wye&@N8}CHg^ovU>UF3l`uTR=JoqAk7MG zfiNSLIG(Qc`QvsfVY$)#hc(1^(o61d-2v^Di6E;woX4@_ddug4wC`HW)PVW5z7e0{ zJm2DB&0vO#RBoesN33I5H}ib3$liBw!w$r2ZK_eUlYD*ssV9N z_LYkfz)rVkz1R5Ryp3fxR0EY)C*HXNKMr+OuK{Z}sodg;0q+F|XE}iKLfi%O(Ny9{ z?R4Wf#3!?pIX;}D5}}KRdnELrp9wwVsRr@C4zaiHK+XouXKBZwKX~@(-cI1*>q%{q zz*mo>{{{l1;wVmAaM(Br$y+_~Q zhVdq+jlmv>Z!&RvzX0aim9$K{Qi+KGI=(Dm{X)=Gy&IJn$yaeo1*(UflK2DTpJxT5 zL_4s3)a=1^TPm^0G55w5_++Tdx2g~7p^~UhKk!)28MPYV{!NE;-TEoS&K(|I>z3fP z-PCro74$putQ?nt$8$s!7lCJTYy{5R!S#?Xf1*FIpEg)g6iBPuw?YAKt^aMl4?OyE zGRD7$@y_`4#i3&muPGQ^Q3s|ZZrw)#k5$w3Rg5R7gxS8x3_0L8ozWUA;G<-sik_EB zM6=9Xv*dyAXU`X%Pr%qQ-;tZZQG4e~TNtPAuw3P~lY;L^x9JV31~#~?=XuIl+%{$H56c*m~(0xuv}aEMLV!tEU7lM zlR_vwJiDn1_?)34+8^jL(jvU0i$c`%fBtt2`XdR?5#?{dg+7uCK31uU#YuR2f(himC?)qvdl$GKKZ;Pbw&FI_8z&-<6(@f`4~n`Dnd8NA;f zwr%Xt&VAN?KCT1&(Uv4k3+>;SYTC7}5TEd!zWvw-{EPbubpx-Sl-jn_mqN7N=nH%V zvHiy@aSqT9UjD*WwG&wSZC`L6(C-TSlWCw#X9w+7_`Xq$#;7}R!0~W4_PP(mOuT#+<+tEG^1E)_0hXIrh}{S3Udb2C z2d<6k*VhhHh$@|Z*JOeF7ie4N;QXCg-|6-PWnZxShcZI{!CwDuefvCN@pRwE-4HYC zc@}3t+~n_h$QRnAyzUy z9tC`=m3ZYe@Pl`D(<0OpNvpTVw_gDd0|oswz^!h7%iqIs|EJo&1d1ty`MV_9O~9ws zI~n7EC%+EKTLUNCI6Ehy9b|LS5h`W^e>Bs3Ujelr-7&NUCfZexJc534S=60g2sj)~ zr`iKtB-TENWmAYurf`duW+>;jpCZNYKzZI0{&>$_AWxw4ARHH4TC#oJ4daCJ)t+-b z(64G<`9udic}({#8&GM2Ys1=kDluas`b!&V@sJqm1rD=4wJ8OjQc!s*PRtVlx7<6A zs>~DY>EWdd5W9Wgz4;a5ii2ScWAHg|Oy$dn!{-*62x#$vct1X=LJ#pvshC$~^%Np9 zKUAL7zm3XXCp6r9s@Vqgv941;)=pl_yq#U!B&k)B$nbAwCgSXctnK(^BF4 ztQfmRSOIIBwtX7_?iR555C`<5xmlVz3+>uXpD)?K>9m&9#lZF|ca0U`N5!KF4~n3_ zN1;`hfGj@7Em1&04W*e=;D74p*7A)|4?q5nEN1}D=Lz_p1pW* zT()!x%6-b5u$DK(*&X|SD*~-v?e*>IhVm2dZP*J`VObII?4c5A@9p}i5L3UNJ>~V| zKks*}$OFi(KX)?(n4WVX+I$(>vzYOb$9WVY`e1BxDez=&uucPTe!BeW8u09z@yV11 zxNdN1Tt5%oj~?&YcN@ynK={{ghy}jIy_heC_S%r&+!NXfC4Xg(PKXtkRatw0veM_j zZTt)Gdz@EL0w`E{N%}0XJ@d@3N}yre4Y6HNzCVQM%eTY#ZJr}kVWkiKPRlFDcfi3b z{sx&a&QfR7OUAIf=EIN`cfmyU4+Vn30yNj^0&J|6eEbraYlpP*-73-!bFn36Wc z`WDNLH6;{+tD{EmH~4;i$=0z5Smir*kf#*B|H5!t6}Vr<`1aXTQ6NjNvPL=d+wwNf zbH^ag8I+`@JwPSYY%`7BfgkUS$O!@!r)SPr^T9Zit-PVakxKAr?P7fZJh$DI!^#Qz zyHi{*9U->qZ}DO{10J^SiaQ4s51q1gI87z?R-Z^rf_O&br>=JvTz}{UFxO_v`|iTavu#lR z9@5%d0&Ds@U7CUR75mrx$0@{6LvtS8JGkCF;P|iy;>)aur*bU2|3j}WQvwm-&qm8d z40u;;CXWpmqMP105f1Nv%*5^V0F3jG=iE60ME2K9&4IVS=~sFJ|IodR$*ZLhO$XIX zy?{3Bzl-{SzJ~7Qe85ea$}kNcHWp?#5MJ+u|L_1(K@bKsWu0uvkt zP(S(SgB$drKVo$_rv>pvo5|f(z|0IvMvoVa2YQLTAmIMM{ONL_g}mI2Y;W*Bb4Ql{ zDV%3hXizfnyYvFB7LY&tn+FYCcW)KlU8K`WB|0|MUJC<$T^kDA0^~DKGf)IFPPAz8 zgur-i`uL^};8&x=X;Q#2;f>}Cz(#)$(Of4AVO=}&pb5CVDrIO6RC?=va|Gxld^mNP z3&w2?$>p24VSG`|*5nv zhi0UJi398%vH8%BXdL=z3ViY*U84ZhH`x!C9CZ9JELC-!S|?3LRH z6zo&_K z9PS&8Yp1LOEqauO5}-cD&{H=4)`WJ#b!#XajJws-oiu%bluu$N4siVPsZW;e`{915 z`KQnqz}5ghlk?E-@OtuHa05yWRQzBGg6p9hswR(t{+F4JCxEXne&Bi!H1?3y_UMK3 zc}10168aDQYe{K_z<+fyHr&7`msux<1E8GP>1pHur#8)gG6D+uCMkVUpqp$h7 zPzl}STMf&=jeM_{&I7*-Q9S+v)l-{UBkxlPUpD7x=>D%&s);6h{Xlu-#~MP+4=tYk&@$Vf(1-mL8GGLlis zo@FH2DQIiBYp*L^+rIgOQk!Ry$6khs8MkKg~1(LF)v+n0EG7VZ2Y7o>;d zQU95^eMS(*sJ1K8Ct!cVA?4D6*pauxqtS7SAX~pk-U8pP2mIr_kNc}>UKI&L*gucC zp)RHr#Bpu{ILv+b=mr#Q-p5XPk}=)q2PEF74lkXv*t!_DDMBg zD`Xn^FmY41JvWlEK#%HkBe{G&%i16 zN^em&Tt5{`LL2f~;kY6_cNlU;eya$YyM6odz5xC0)J4}1$h*|VJFhZBrdUyie#pOQ zea24#>rSPe__`wM%7G8ttTA8HSOodcA)X}cdEtUTkFC{h>L6g=EF8BQhG`=Dy4q-$ zu&F<3at!rEqAX5Lc=2Z1h2L;=`P)T(cyhhARTO#3S@!#*Sui@)$m(n16k(m>qreUv zb0ymf*@OMsL{-xQbWn0_u7r>N&_XE5p^b(j~g?5Hn5t~Jjc2~kS zg@!A^$P-j|qNv;i7$5TX^W19`{FuK=NmBF?A8_j5;D_fa4+Z=@g#Dfl-+o_cJwJDa3MO?ZUX+I4 z%siSIYw-MQ!C_{z8g=H1Z=*SgPd}4*&;T!Vt8_Et=d5?coXOk;@$3xl8<1PNsUQh9@8`@upSo$W6W8b_Hk~j}diEMADP2l|v7AUbJ zZY65Ur_aFtX-ayo8!icKwYR{B%f2x*nV9E}oDw0zejv=?^o$UkAMQ-M36pJDZXbcV z9{;r@W1d#F`Pj1pX{#>3_@RpaTO~=)jd@(B^>o;oJE$A+lG$`yp`I~y^g|Wmg@sq; zyPi7m{GK;2_9+F=ddYA_ z6_x-Sr8KUSp-$1YGxlg!3-4cqHYf$E{oB}z&_+GTrOLZX5A})5Pm1ZFeubq63A~r+ z@?r~KVs9R4#yUCpeV_0SR4e2>nX8HZzEVKh1ro7*!v@vsx65D?a_(YS>;Bv(*A;c$D)EO7aL4Sqf1?ZfiPe72 z9{4s#g*&tg&jWpg-L6C8*kBV9_~OQGJ2%*Ivf@}M>If_Z+9Wx6)r~md6}%yy(exXN zOjU_F{z5--D&l&De2`n5ydnjLwxoJkz&kAVdi}@;3!guA4~OjxcWG2&Yrlt}(0gyvwkGbuvL`3hM*8%1Jd?_UDn52%J0o+TznjDt5l5AzdU(1kt%UWYrKGGBrd`MhIY7aJ5;X>6WEyV!K< zKo9bOtKF*}5=W6Y+_O@iMjYbOLFU1Ox^U<|H64tDPe(Y!c!IR_1 z0uQ6z|3_D^v^DynbVT}XSh5^TJqh36stdJ((}er>zYqHvV;NffyGrAsN8V6fuh?M@ernrREZKwn<87SgBe<}7m01Hy*{%Ei zfqQ0kuZP6pxreX74P&f>T0(CJJ|U(Exm6mEIH@ewX8Z9Jf!V?TMFG6X+%BvUI7P5> zRLFIQvu_->->YK3-sv7QWVrB+=*ta$X)q9qg|>$*T$hx}bjuUii4@1LhBt3|%p z=d$(}Qm$B;2Y*LCb!~hh0eS8B-Zi;&D9rZb79H~2)_sSi-pgP={Ef_j7kbJU{hW}- zbHxI_^A@srKkYW$kC{+UG=1U`h1Zk*O{3Zhg9Hh^ys*RB>igk9oEwOo1Rh*@;5jYpoECX6;!S=nQKHuTlrmV>SV?yuD0%@dM*3s;fXy$SE1g)Vv@ zOWCfWAFijReKbP<<2zl)-iiMA)>L8%`I_igHtKSie&CkP6X-qNCAD@A^@-o{3uomp z&ckmt`yh_Hd#~0KF6qjD-iJK&kiHj5t}W(?v7>in5a$ZcUKNJF_h-b!(4bEHA^JiI z9KS~WQJHp{V08N*`vNuYW9oe_G8NQe?^)zrfJWQm#Mb>Mgmud? zFWOmfn!s>#+HVCK?DWMMqdnK~=aHAFcS@~Y@;QonLn1?(XB^^@H)4-Nq0`fHRtx-o zNA$Uf+TedDNE=wXuwPacf_>}(T3@{1rNl0 zyipnOo`AkhBkZ0H(HexZ3|ABrSg;>Tu4|ltcA}xTzCi1o@#A-3&o(KeQXXEvyYj?Z zF80~7gxkf4UHvy?Nb@nzt$D7{Vf{*Cu(EN$dPSqIZ4(2}4g2g1MthU(C^yRxeoou0 zjuxEzV0*b~H+GA4l^jOBlH!(Aivj9>M`;i88RB`w(sqXo%r#Qe#YxUC!PSqDMo(i!dP3zyq|DELh-u0dY@^iK_kJG282vUwhaeH83<8wDbI4{;$eY69= zFLO0@c{}!H4W@MUP&7HfB@^ut3M5CrVLcLM{md)Lh5ml)bAUP&Wf05^N4pwJ@$CZ< z*oQ3rz0ekp=Mi$BP3;kHh!x%1ZNKsLUf~G(d*FvONpbY|KAs;m{}8{YUJeXH{G4ix zdXx(JYh?WmZFuBQQ-d8$bZu3Lfh_x)mAYGy2NWu>X18L#V^F_sfjG+SdIA7-F}nxBmmiwNpmYN(IKHXrV>~{B!N}n|o-F$rjU* z#XgKYDZnie>$cgEf~F|M69Ho$)H7J0#aqh`puTS!cme`L!nf*Ovf%Q41m{SCCX!FU@Ux?lEN~wOM&YjjmCTIw~zaI&TWI&z9HbbWv zDqB)2t$I!q*5ZX%-+E0G-rTP@B!TtnhewK_`~sDg-8|~u1KyR=3#fzM%{5d&%xJf- zBpYgdv&^r;ywptDS*mS=^+H)QCm1F~JwNdX(k7@en$6;Tg~$9kdT5+o$nFGh1|4io zgVN?|dm1{BPg;)X9PLEE{VyQ#F5>f3y-{gUAe6*B2Jge%sj-{}@_sRrG=>|2i;p*< zeTwwO4Xm?Y20b@z;9b5lx@b6NUr7`L->4}|Y9U`&7K%DU40TU19`=LB*h)^SLylPs zWsSQyZ+7Pec^!;4nAlST|3p3yW5@4xpxRZ@;Uo4D-ufYOkb^YIb5F4@3|OLq2bp}<%O>I9 zteKtuhf{?3Qj&~=cwSbmL}3!`hs%sd=Jwe zY#9`*F@0Ioi}{=7+Ncxi7YB|#9H~c~CG^_e0P$Lnu?{nG^-Rlx{XCHNWyjJ`8qT9; z_q?`7Y`W1E&VX^q5dCLu27c$1(>MV&&+WuzLweau6i*4LvrKVr{XCC(@9tuX3F5o0 zEXU>%TR#lWALqlrZ(|F24OP!;lF;*`ztNU$9EHollb*xoGlcr9P0MPxX9#9Y<8+$v zslX8L1B)5LDO>Xt9$aVUDw_M}(O;a1Sd&B$kFsCC@);)MIF&H!FxNja@D1Yk$?=Y+ zFhl(Cs9lJ_H=HXlYJ0i6FTK+qzcUUk4+*h?3ekZREN9;@LF6;>3$NWQX z5JLfZYF)*|(cV50da<7x>&ZaepEESrw;N75Eh4V0>+LuN2~PuMqME1h{Hy17B-Cu< zZrOcK6HHsRjIv2VSeFATw#EoFbXkmp-%#g>a6K|NW?;fp1# z*L;=#1EzLoMRFj25B81vx_f@M{~M0JvEuoPYK1-#d>!Svc@+u>MNs%2(jW(N>fisNiwt-Kup2Y<0OhGM4=chAp;GOj#%Tvq`B1>e7<2bi^^KOtR zG%&O;BAq}#@AK?PMQk!r7kGUddG|-~x( z5$<87J}3DEx4R`AOERZXROaWHV^FKHx?Olau>{l%Lnx2 zE@7QcEOiKjk7SdtQ>bD78d`a5f;dP!jAjn=@`#SjKqls6O{(nA@Ce~8PvE4(aD z;Q5eAoM$GaWV-xu9e#9446TQmB8h(4n1>XWM!q#-zcvw0_t^o`WmPuagChRo-_@6J zJ}>NG=6~>0?ME3c7#p;1qXTa}jkx_z9{bwfHL6_bZK#x|j(No|?j}1o3}<7L<$5+n zVC>`mei@cMd%$G|cltz0!k|vC->X3f{5yT(je8i+$GAo<-FIWJF;;WL6S^!j)VL1M zJq7QCLCzatIQ7|75~1@;CRUpbkUg z_sjX!Wz3r|RJ&dy<_il+U@^o#<2i?XG5URuT_EK;{JNpJKi zaXx`2C7&E#%W`fDr9d5&PLAjj;`R6e#%|ol(kCKOyZ6`q*A6E$?yo@o+}?lBP~R=# zaQ*dnk|1aEXF6hOl0fe<-fati*r!tXLYsSh8>a8^e9By$Uly(>?&a@=S2F*}Y{J5c zmJ&Ox1JBPS7%wX0I>igcX(5h07qgEZuF`D$dHEmqby;CYhhaJ6vA?$XcLfBAS$9~= z`sX1P_V2aq1)5{XcUdJ(4;Uk641Dik592i|9S&W_{K48Q+@g>39Q^aml!$K}oX9u< zC9S$2Q4C>SqLnd{A4Hz&vv=Ske8v-d#SZP~#tw_j+oH}z)%T_XZV_zTKR~{98dXnt zKg8u*L?`z9;^xsq&^Np8=s8Hu{GE@q3+FAia{L?d^VS3&l;=XOTQ43cLZTUF_D3-6 zwFZ~FC)SUtk5pAlzNyH0M6~w0z zvxlbGvLNrLsC7wT!0$iUTthU1ST$WKG7_;^$%b!an;rs+A)a|U^S+YgOwSl3(K!Y_^cN`E^) z7BR(`mYjVM=GjK;k4jKxXXjL7AfD%px;A7XwmqpEb_V@@Co4T|x8DcZ8E+TBs*rM( z9jspw2O1q4>9OyTROruz(fd1!&%v$s)xKf4lvI6R=|7x5c==Bu8h&xJ$sB{C_7>#+ z@V}BqgA}ZnH}f2%*|1)UFq3H1Lzj6?llxFy%}UV{d7Pw0(QMfT{N6Jpt0mCk?99qz zw2xny^b5s2T2psEx(oAcn3Pg^4{T>5$xemgV;&;wMA$EQt$N7qK}`JG_zPm=8_W+j z-~#p3L!!gT$Cef7N}Mx8O;FTC-Nt@kTtEx!Z&mH1yHNi9j{OU? zhxY|{yg@&hk?MU!2S?Xb8ScV@8znv!km&pA&lISG@$VJdrv&eXG>K)w&rg*&v*EAL zlY2r6cGpYmFNa`y+eemeX#Cr$#u~D<#I}6-g}jWB<>(e%tiLq+eFpWy?251Yh&6kx z&oSFf5vaR*vxsd`hpcC4UPhe5yP2B<|J&~*JjsRirde2-j2rjsgVqaQc%PQdYBz3T zV>kD1m?C(QzDu@*)m14(e%Sv=`A776A|7gA8xIr3JZpbF>i9|Q1K7(le4(7i*JCMY z4~|r`y0>?R5YoBiUoQE2$i{_43SSWo^AbQ$uX-?uClStIV`pbJWY z`#)cq`-AiI+Kh@7dtvUtq`d^r(SKr^rrJTA=+k9Wa2$1#?C!l+;GEx54mtEo)ZW=` zH#AWFkLJNNK~L(6vo3tc<7D#_9=c1&cR?OF<|KTuC>QhAsm>nhJmgXRHMb54@ zXd;%-iRXz8!hVIhWM&5D=qV_61WyrKX5D*c5v$JK_CBD5eA6qUG7>s(aD`lk$Ek#$ zBxAm$?cy-ZMV?bsp{nH$U+Vd+@184<@cmCm7kSY9^w|)$Cs@~O4l-GWq28gV{fzfpaw`4!P=Z0~52lvv!4;Rdrk3y0LXY10UDZ=v1flr$-G?2TU=MC2D zD|f=z5i6e1cwoPRdg^~pi$w70+;Q5wFyvm|tHbcBQFneR`r#m%?$Mu^xB8AL+x>$L zqt~{%Zed>Jzoo*hgXdvA!mswxD3P1!Tyh?_T4Ec;TX2%87b zKJ!UNJ~Lx+GzT#eO`i7@EdM_Eq4zz`1<-dyG{gNTlew?L>dw333? zBdR`ye4FrLbaVhQQ=PYkDdhN*=d{>`dUxzC6+XyAF=1@q%!sl`C#(+|xxxq1`W(c00$}aB^uPOxX>qjii z^+J2w1@&Y_2hShS_~qYpU95Y?GZU{U;LNkc5TA17c?VCuA^Cv*B(;3I4{=+p5`8bM zAKkBLRE9cqWLqB>?E9`^&;aEZ{b%fV<#;A$8jk!$keR(R0`u*Q_gXLEOO24ir_gId zvDTXz*Lgki2hAbmd9tt1NWr3oZk+|Rn_XWH)Xc_yTlH!xZx-&O(YeRDP=-9^@EYu! zdRcBtih1%*0On-)M#N#p80)Vwqn-!i`UtM!K3J_fz7k#6blFlN#&ue0{$D9)frU-TG1!Nx3T*t6p3|c>onK}=PWSE*g z^)SBTUuMihN6*9YC*hfUcbfq1+%4n3(29glI0N%ULHXA_86TXRj`JoHflsUQp9=a-5w29th!i1i>HHwG zBaZp@?f!<{&k^RmZ*Gx=rf~%EQF!))e8VNFX~GY8lfZ^EXusr|_zFIhJ33e%!u&2~R8yUx~_X#`u&exf0vcXE;v`?X@0Ey+ znE9jbBafVmlcSM0YcnywJ&E?(C?fPMWhOP9fe(^&rrOxcqJS(aw| zB^W?bCU~&`^PxrNJBHWTpI10KXh2%F7wJY&IfP@s=LtM_y|}n6CNe|l_T3jE4Y{2- zm@HtM6RBtx=BuS%ChjvZoIRIP6Z6&q6`5;$;oMkp2G#Nu;Q@=dz95uKnl&hc?mv8Q zc0)6&*@uc^n5SMpe^YxB<7CN6S*2Pp!p!dH3k_%9Qwa-VP4)0fFL|*m;=JWLP>IIPJ@PJ$^Y@rt& za}>e3$(s7Xl`qJ5&9uvtq3>zVLNVy{hssN@8~y+K9C!9N)J1ah{54@i;Voxl_~8R7 zu>(xDzH;129(9J>y4J0bUXZCr@;sh%{UBR3M7&+6V^WZSeNt1v^eAK&I<%FYh<&Vi zzTxiY^FDLQbGKb%liO4-BTrn`(Hs4ox8bTJml3b{ei%xbpSvRMf4*h)ZW- zPhS|nKHBpRdLLT~#rRBr?`w#B=k%WOs1oEu24ge!r{NuU6TY3Fk2aI;+X3!KaOsuO_mUqs-@It`!x@E`7n zb4A$~7vSu7r@y2bSU-Q!t$cieb0>HFU(_Nd+H|5JfrZ)A{7tjS=c|U~nC9?4JAR%` zfjk*cWLwZaeu5)-4WC02r%&luW}G2VmOK?a4==gyb-eD41S3x?l02LPFEDZV zuVLS`xZNt*g7~xSwC2nv@+jR@Vc9LrmtiCl#fbBL=20R zXITi#huE3N;8zxttCG0ijQy*`r*Oa3)Wm#Eq2E68ux*$gW)*Ws2s z{`r9VAmSxOC7<(f-yV&w0F0MfwUbu!cd$R{RL`(QYlcPRf+@|=$i zuCt=i*FpTbo@)Wa6~vx4Q%k+aa6LTiKV=`s>z&O0695e!)P&qRfx1|`-7L#t%-h~A zpLfqAkl(q)9FEvpem3NET6EXZ5`Vqg7srRp_Q+lidzKwatH>4WOUh?9mRoj6`$ zz3)vPJf4H+vI1QcN&ka$rPaTH0TQ%c=T>5ok~Ba^Lj8 z&vOkRowk5NH<_6n;q>(+O`U(3k4;~#HDjM6Uzy^iiTUUB0hN1Z&{k>a_&od}Hfd6g ze4=+hZErAq)#}2sEfuY9vPM70T zH_PAQ9G&XUM`L*L3Fn?i|n;X1Dv`5Ea82Rn#NTY4kYwc)CN6ioqy^&@~f#)B@ z*c?$t9nDDHYg-BPi--yvIpRg{&3~q-KZS^t>N`Bf`IO{6jyVB17dA&HE(5J3I$t#J z`glC<(nI7^)tjlju*;ilzW_WvpEauvKYnf=`+$DEnKr)f4Ei&#`wzM)#A3SqggIzg zt7k=KiTuFhjF1sL>n*Lc8}sGF^JqZ_7w8NBYe&bk3I5fgr z=a2Po=wjCbtVv|ok`2JTVJ@Vq3Q3Pjb)UocdE^B-KCgr>@`u0n;(I+VN>6AzAa3Q^ ziub~Grq@jw?}3!Z{z>=2#fF}ZNto;UD&!uRzqgg{ZXlkjrXU)Hhl?pT z4@6-!9}eB((Qa7l{HN4f%a<@&-QGVBlN_E`TiMO+l6)`b%0>xHd{#rr1^c{+}bfX!9BCqw;6W3-4-y(k9_<*>XEjTO* z@f!h&!+FTFu9Nm~Wx`+Yzk24d(YWX!{fO^`5N%XZNE+h zs6x?rT@BAoJcaYGJn=-n)8$so5C0TYkIkZ8m7G=RD%QjI7wNN=;8MhDbvk^(#$9i} z8*A%jQ~Kcff5cOeq(%^tLH-nBm8s|W?&nX+cR2cA!R>;b)rVH-KVI*SNkJCFT84j? zQv@ILLyLzH$MqB!hCjpj_cybpgPLs8JTG8P@y4F#kg4X=#inM|?^vbgR^W+`kCM(q z{X$dMLFj9*n<-g`d7o-6S|17oJ{8o2iwk50@=&hYD*k~6>P@ubx0ayw-S5L*(B?=c z2ahJ|7sX#$RVk(j`K9uTijXYk!3S2j$FSgVIgIfkC3h-(*4pSryH&?tGA`&VV_ODxQnoKz~r8NM}HNoBCo7MGo@Qz9+*^p~AivTEP@I z1Ko~1-f4wBGi7^PZex5#jND#U&UYI(!Xl;Ie+TgU(N8#2OT+D!9qmzl>@T>| zey}56SPIC!i+Su}hIV=#TzT>QgfrAOtui){vEqr&rvU>=A z^fKkU^#S|p+s>2^p>yy>B1 zlepn+RcW5^=Xl;^8+o=GmQwqO>A+Vfr_8A0&`z`OQnNYcgSN(vQuK#VPPLCupcdn1 zf(100I^@&Ii2c--aaarTf^7?XqddfcnxR|8kW!9>qpSqy14U{oQs9fr`!`A;;Un+Y zCa9lAVJtR_`jAF*Fh9&$d)A|cc~#C-{G$t;rD}_sG{Vm%sJ{4v@v+4aI1cAQ0#7FzA%5>E z7tQ#hwVhb?oc_a4{*C$ zOq>^r%kbJ-B2QB4{B?7;PLZ`8v3wC~Y4ty!L0+|4TEAI(9`je;IP)C>?ypLfMKk=} z*%`;9fO%!k>O=|zWd-~SWcN`blYrOxwczfbxu!Ugwl^zYH<%B9R_|=l!9%kd;ag~@@i>vj`vtEn5GuF?X|4Ul zH(-aJL)7m6J-m`Wc=z08--iZn0{&g4#>?p$#6;0o^9SLfYsu|bPwqaausvEQihaYP zR&EsHXi7uZ88~{jl~h6p>-FrrbEa^bPh*u$8_!dNHXG~^|Ht>X_=+FSu`PZq3H8P2 zNltMnUqF2Q>vfWkh~qOQYGyGXKWWnDW;4O(ArrZ8k0TcKu9mV!Ec)XMak&ucGnH4n z&kN)4&n-x2lj)4 zvqJ$tQD0PfLnIC3>7>*rp|eAYNgL(?GbbKp@@1S`99*Ph*foyrU@8=iffw6t>jF zdLm8sw+VTJ2wT$`UBt_d*9Fa?bD?UcJoYiw@)eQ0`}Lp27PKd!=132_EZWDWvu(%G zPsiRQ%T&VQ+T{Fps5bmH&PWz{;ODU`YuJ}uxxPwWkNt?4H@gE3Oo?OtLV)zCw;$}D zBYEZLV_F1>7PqY(W05BvTO4nI`9a1OTK_QbNWHu%vxIToC}m~=fBU}lSb(g)>^JAJ zj}tk0)%wH*ysqrbW;QI%xZvy_Iv2T(;MI6>2)!=sr@z zd2-3DK1p@trK{}{obVXUMaiR3ptp6B{Sxwkf#NMD{5=|brf>4_soY`vy=d>0qGeUV zd=f`Hs80`5MM4;_!(Za^ z){VYpnIafHDDu$=N_W)%OoMYN8sz~8G0&?tfAEH_b?)K*5Y#Q_ zu9)dVk^AA&o{-leo_Y%MEF=b8#5#ZZu|XO&_BC=E)?^xpAL@Vloelr)yG~+&aX6+v z{8&Q=^l$OgOHq>5eD1;=ouQwFdalMO)#|1ZVo+~EdDktK{>_kzjh?id4a0O$YpLFXi z7l0ut2e0TsgR_|rE+IeY$WrpEw8Q*pZaBGH_v3T5x)Olv!awRd6@zv;jWfrXFhBfh zKYZgjl&CFh+d&?&y>L{;8L{hge8fN(^}#LYIvdpE?=F#bv?1Py>f0RRSl<6AJGHQ% zer0Y%kNJ?>RN5~Y^P{=QsX8}!jwUYIQxNO22;HYf)X}!~)rJzmrh5Y^yXW&;$lf(1 zRO7y-JJ0-u$IXeadcnlSosvp8_8#lpUOZR6olF}?iu_og#c>c?pV|rSfThJ-`SG;) zdCj)d%QQImms2=Gf_TH}o|+>aUT@|4#GS24!db>pJDTlD!oVwSeq!jB?9SVOb|Qm| z=9Ad>_O1W3eG3nyKKF@cBMm$3ic3EX_MbQg7HvNev~&kM|K`y5n+jEhHTS*&sH zDwo}6U>Nm6s>OeV5u6)1$}o{-qSOwl+259-a5FU2Cq&=FjYfgO(p*T%)|bi{fQlLQ}E@(&nh#7 zN9MydqVVUlUoX_qj|^D0D}SJWxzmSrIUo+zw5(o+MuyZra=0%{PBVRT@cem zJfQyInI8Pbx@CPId1jgDOS4!w=ggjz2q}ds8A-9vTIRet?|m3`RkL&HdGJ!d%iabU z(9|!ifO=+ciba1E`d^L5crqFK+kO`Bh28IIsyvY7+n8_cOhbKhm&X9{U?u2Vbcl z3rc{t&zuv*((&A|KiA*s0AByy&xefkxF4T%Iv>K(0}@#t@R#Sox7t?dCy&;CiCbdd z-Nbx`53v*5Vw4+V>I_*gEe+&XCl3!#Q2X6#y<_2+qLxymo+=`^I%3VZvs^H zJy-A(=2dWNC*eA6sRyR=kt3h-QEVjHhkPoiZ;&2wr~86RFtk1NQMo-F_qqM@H*Xk6 zb@9Q)2#nVSnSXY0HqeUw(HQnAWkZwHFu*30=g>Iv0!4b?Xv7-F&N8mv!FB&{@YN#v zy@xs(7ppbKRqejWlh85v5?xFN*5|4<(@1z-@XiZbc!*X_<5Z7bU0evFOQ#prb+TOVyAa*!Mc$BU!Wi<`uV%j&OvgR zzAVss6)H{d4LtG@=RQ>2=Ud#d?%fWVTYiLjaZyN#-eb4!(s95D?GN&+fA4;-qjDqI zC;+ZiTPixjGxsCB-ofW@SRQeDVqNc#{dxonlRCc6h2aYnsisisp+xU>%xea<@e3}n zUF~JWXZY;cAYVGH`drdBtc3m3wKo2B==|MMz+V~9HJ=H{%OTFOd2(oPJ)Tp%8&#u+ zQL~GZ$6@MqVdq|$>FMy^9`j?DcG3G>m^ya(Y9$PO;oW``^JD&%*Gt8uv8V?Z3WeWD#^;U}KhV~} z@WWDHM^n(>-;eO_w#P~q1-mXI@Adf1mWezgkTAscEpi=RF~I!IG2ys-Ub}O|l{px3eTcu3-AlZ$U!4Re z*n0ERbvEc^;M~6ny(7H&%>yCNaQ6z-;{6il4xMWJ|0{&%%R!$skk?!jppCx|%N4DC zf?&=QlC5ayIyU9E#DzTOyx5HyZv6Q*nrml{ARmhw{qPHMUjFa6o9O>c!tj`{9->?_rE18Lgq=Pmrbi zO~P|HL(aID2IEX4*y$5b9nJ?)?U=0BqF;GE)_sqd=xKp~7Zfq#VgH+e&qayr+i4`C zU#;mf^&xhrmt0~5B#Azk%slsC7;Qz9tKR!8Ews>i8L z%_!7|-)Z{s!xXKi@^G}b5nYj-ox(YRBWy71zk7wU`De4su47oj3|1G=jUHD zejXdc^YXg=6z+~NpR!)yFSMuplet?*_#nNvp#sKR@SQjW4K4l?vtz=1W7zOJrwyMg zOFSPt3m;7exsJe+yFc72p|#jg0_l}3vFo@+~jvw@T9=>^58Ts3h z7VU%Z#)T}=OE7iyMJ^kRV0rZ~G64DfO?i({xZ=I2ZUYnDtp2V*9ZPSjSLjCr)_rM( zaHhJ#G8p}kZ}m)2HEYbC&yWp^5$SPp$oUzh~1!W543M zZm%((g4$2gJNERTZsM6TA%OVedk&WO^?2QiYC-;w7!MYjYc+^-+~wkH5OWdxN>G>J zd0J}!k)u%iRfk?qi+)ILmmL-Vf4KfFEYEF7kr&;GyvWLq>+aKKn)QD7`d^x0 zEmKFH{431u8W^uUdsR7eG491OG9@9WS-Vu@E7S#Fl+Db*L}{8= zyWjVACbn?jC|qb*ct%N&_f;Q#CV5yA>26ax9EH)s2sjvI<2=Up7 z{o(}{F!WkQHC(xzaed|XZarV-jV|JcQ7axH$g}hWvf1vzAcN+oE%4|}Nbqi5;Fwvg zyufR`u1Dd4WmsIGWMu#cQW)cUVe-+{`N-?Yk2OmfMU3(JwdFFw}kl%hK>q4;9AK9s67kC@}AhQucxtQWPZW;u}isjt7*QS`U@hZ(!yv(0;m zHgQ84^TIv0QEGThsfo!NTC$ju^FWqVIpSZ`IA22dK}QviY7)3FBTr`7Pp`b2r!T%M zsyZo#&+*YE`8aS&$31PBj31ucbi%-Zc*WdumHf4l&15k1vuK2eUHvLI*T4UO9!Yk0Bne zYkheF@wobvk2-HrpSwlzIsYBbTa?|SjLjy~)&LGW*{IzHS{BI+GSIX0(^cqR=8#j ze*G$#9)@^n>p zb{RfkG|sex#&7(G`SJep&R38Q)eIv_hU5ag)ZOf!Qv@^ykbe?L$zTkqArYM}FO-{SgjQ+`XZvwm(>`mQ78Ou>F=T& zjQr^8&qPJkeKMa~g(@T7ZxNYz6!T!*WI*DN96a|knpJZ{tpA0s<0>>z8>%_>4fAs? zvFH{2K8MtoVtWvW9@pa%fh(dujaB)W2gNxPxAX9QA_qN^Y%uO;B>jm#qWzCwH_-)c zjPKrvlaZJFM zw0&eooi@F~Z0#ldZmuH{294(52NglL8>Ql3JJBC*P?yYf;PX0r3R1ryURk}@FNFT} zi?rAGH(sy)T3GWRydLX*c~e{HeKUHM0eYUWsXSeZ>u<>{)egNT|J*f%q|bgZl*6`b zDvW$RICr~q?qL~B3aX_{fj7eTNVh?*>ioZ40yqaUuXfcC9(=756u^)9+Td>AKg50! zv#o*ZsNaO8zc{IZ{4(~nS2%3mo1%3Ot_CM0i_GBMfp|-s*DtIOeQ8sXaIdERp(x0- znk|`*b*+%2x@H5emK5Gnp-25A;sL8E{I1W^P1=lkszUa1H{9U+^joC`c~rK@3tz-4 z2Q5wil^|az{*~PbXUMM{I$4VQ*JPze3DaipGpuRhbF_PX5AN2(ZcC`T2*b3$-P5Pw zkg%E`1@5EM`8!9P;In=zF&8+^%~19f&YUTqy+(`m$KUn6A5=XTUh^3ShnHt%LXrHd zxrr25AMMxo&cZEAt_^KUTvtuC&Uc90wpe?tyzqG#x-j!bNLH=<-xzdM@;&hd>X`PN zXZVRc;e&zV%O9v?RQ??E8AKjJ{jjhR?JN;@IPM~ksxsL(uY~IpZZh}i0Itgh(RHsG zw39pQC^Kl{JkE=|Ud&Kh?~~s#_;9LjBO1;*@;^3V#Ca%@!-~uBc+bbY8<0e=u;vns z^mJQ3v5fsd!pNTSe|Vliu=K&--yWz z9<8TJV0<{mx9q^6>@eY;Qy3T8l$X*GM|Qtx&q=~_`2sD^GAP>3S(KTKx{r<#l>(d~ zp3~UmEMK)C>PFwq&G%p*w`U)%VJ!ATPwx=^?e6aseclY( zpxwjb!p6fu58C>GV|K08AQ;(g#ra}M7Z7ZAOA z6uwr?KY0u7BE<1E!|2~vpY3y;hn1u+lWHMzG_|cB{4Y(Mat7-c^DhnJV60bDXREGh zLI(B+)KjfT{L7+iz z_xvy?bN@;@wExZ+GKoCPk7|8|Q{9$4ozvL=?CH>0$2`$l?+}m&C&T(RO5u`rXA(CbKF3%5H&_=+OF#Kw z2+4c9M}ERT4x2Fsao893dP-G6wY>s5I#4s~eb_o&e;dQ}qz>mQJ7b6$Vek#*8+ve7 zV>@FMh8*_hx%3j>C*kqIUM~mrG4Bqjg2BzsgNg}=Gitz z%wF`J=``Y=R`x<;Jv{#=pZ&fGy~67BjrFk)SXt;WN6g3A{exE>&x_?tK1V|0Lro!m zP=2)WUKTvp&e$t{6aDd#<^(_7SWJjJ2i+v9GZ=4SpXvBOboadA&SZA2i3;xPZ+5vk z#8Q7ZzWBnBy!=OuGN>={^@Ze1qdueGo4FV9<7TD1JaDAs`>%$6??oUjCH<(FH~u=$*^y1@JZjp30pqzH1;xM|I#VNFoSrXljuZ+6RxM=;c92dmqy(} z1LM-8stn+TE~DoXtEiivuC)qX!+9)Ej|+i_<0q~c(jz`dWLbR65wADh_G$?Ez^}6D zxO(U??f4`C?IQuPVZ5Ta{wsrWWg-|KH?O(fMJ(?ZK*w|v`?55~ywX(6XA;gyPoSE& z&RQYrzl_D>vP4j*N%`3!G29>iuzU6R`_Gc^uR0*^_+}X7iule_+&cxVS2yq<(|E!m zPudH+-|JAbez^B3ocVd#;|k`9z?%zv@$j;L-B3Fmy;*!`046NAXKSnA^}prcc@3Yj zB%GkW0RNO()*!yqt{}2?3Hfo-V9E^4eJk;eTn+iX!M&4iP>VvRR*(bz^0CojS$IR( zQS||Q>edqTg&lPbuO6~;V$AmGvw^n z;`#-zxiI?jU&Q+Hvw`do=Ar4IYVG2v1Lg9BEaxI-W^LC9MSNDfbtW?c>u|daxp*Y< zZ9RwHG{i^G%M+9lhsh@Lwr}D(N6(+2+rqq+**M_`KPPZoHK6^Z_Z8EXOw`wId|DCC zLOz?26R?fgt$?lnGUAU$G&iDh@ciR__1rqNqjS0H0TTi&!*}DOpZ=%lzT>g_;y8ed zkdVEyS4O1BmYqCT3AWBRlv z@MuoEs!22U(~-zaK6#3Dda{J?ZxNp_pbqOp9KTdwKK&T^@=zkDz&{}TR=_C9d|%D)oQ{0zN%vHr%{} zJV9w!T=x*_rfNW@r5{03@Htm{*Y;CyNn8Qu}b_%45e#{+S7t75$z zy!+#lxslYY`f@}49YOd}f0UC2TC?WY%of_iwgwLetmdb}Z zImD^|{En3+VBV`#CU!It{lxJxiFw4XUk+>~BPQXK*H-Aj^`3onixD23@=rej7nPD6 zXJ8=BW!-~Ks5_Nw9#nzTY-d~g8nG@c$$4}RiWHCR4MUx}l8;R*=_mGsTQ{H2fsVzR zHPf(LOF6gP49^>0jXB5)?_I2ry9>SYZf$&r0{tFGLiXZyj@=UIBgJ{!`kW~P(?icF zI*=jX_>i~ciR-&Fe*5B8e4fj5+|6My@2%v+L0CH&ct`p&^8N$=`Kd#jWN)Ha$kNU# z*c*V~Uze|FZiMr~wV`OamU}^A4%3+vMex>3TJfhPk&%T2F1%Vb+%ge~O+1kzX5Ie1R zggk-9BMcKh6X^d^nlC?xZRYpagJI25wpA4*o>w)ttwr6#XG!cAT(sP{xedt}U+}NM z5MHw{e#}^JA7y7^fi{O*Q^cXV;Ov!hD7owvmxlB2SR@%of%BcM;pZ8S_^oD6u^23g zzy8hn80M**1MAP>fBNMeMv|yYrMy?pgXJBjvGPbRmM0>A(878->v z&Rjy0ukbqmQ_TAU1sRF;GGF6*cFj;=g!bkq@yI@WevH}wm60Gn>l{)h+&B88+x^li z;)lmi=Y6clbLLcZ4m86;6DQ%yC&*Ld{@i+o*nr1Ya)k!@{aolHLLK?_nTpqj@KeCE zf9Gh?-@G^DTGGOEAk@fbPNKimQ+`I-1MmA;*~mhjjvM_~?eIGL>l6LXAs^KuXXrsJ zT%(!a46hu&CFfFsdA`TlyCm?yGpFKYNM8I^MxqkW70{Yk$uDywcG~I<1g!?^+>Ec|*-Ox|DI|uP1PG$ewF@gAvxXGv68CZvXDsjaEHkm#c zok+*~?XNM+Mm%tNDJDq`b&)yB+%8BVZcWRjj`hyxQ!3_&_tS=c7!g9hkabkX2u8`( z#A-t~Zc^evVT{wy)r2k@;C(&cBk~B+?g@$rBbe!ARRYgXw`>Vq!Zw7SR z`75OJ-j^DSJ%eza zcDEgN#JKo|i?a6-Y+5zBKB<9qqAybu`kLsM%~ey6oJ6|{UT|5!@sHbj&YvR*&;1K| z@hS@W+vj;6&#RaZQ8PO_Ax^!P9ZcAl`TXx3IRnnOP@q_xK4RqyWBuRZH+x}g^<4B9 zW-pk;pbb}gWjk!q|Lu~A^+i+eyl--Lc%J2qcumPUj8kjECNH5vc8<{)Fn3O3~NRoRb44fKJg~)sud4J5`hUX&MU$`Sr@xwh)rahE(hYUc`mf;8 z>JX>$E(a6t^OI(BUoz{(dAoB`I}fqI0{?@zf3ctB5x=WBjPaqFehw#kUhM7g`a=6SXsF z!)gaAW|>m7-?HNmpOj#HSrF7?f!xYDQG0QG#ems@@SGGYDTAamN95BKj50?Mvk!?2 zi^CC0`@GQ_^t)|orM}RI*~9h)43<(zFNZw36$=&ja32!43PW|ptUCAN8EH{C7yW5c z3$nJK)h~RG{T-!WRsEr8JMVx_JI(`rFbxqj%IaRfk%juCuyF$wbT$?3<%bSa3hus; zwW!SKBgVP^nx=@4BOf+Cl--pMH!ppql85)>&bwL2BA*aFphYi-`W8Fq=WaNhZ2ORK zKkC9G2R;rDe4p~H8;uHlFi5*O=RT{>psc)}1b4`9bm*cEc*NkJ>jij^PT|y3)C-&A zedo&%)A-mtBYcnXuhYFZ%+T)%h2~tXf@ixNL;pa&OQ-sJ<4_-6SI;JaQt9K}cJbK1 z>QWqj9`=?hJ3qoW(wY#@`Qizlk6K$8wSxFtJ-^jC#OEi<>1MpKj^)dFEY1g?OMhT= zFr*w{va!PPy?e+G|4zVl+ErpU1X)%d(=#RF=TfUB#PA|Z>N!cwW25;xxAWF9?yq=f<;8mW_B<%c%T$D)Ln+U9}913)lE` z6U^YP)co6rpy`|NVkTX*Xyk5prirx^{G8{l+|mn;z0$41ZJt zcTGAbIQ_;-p~LPZ4U!@BV#@N{2_j#7Gz5 z`facOOVb0NJ*Hkge*p7^*JG-Lx@L67hukUrUHgN5Rdk3SG1EVFbH=!Q^tmtvB(id| z>VTg1^2#;vLy9^7Cl2IEWg;bt&^BH@)fw~JYZIM~BZ!461*?Ayg2~Z4kBy@Y`vl_&Tu>#`QUbI}SWRq!vxWOVkE0!MOb~1TggYxT zsh#j#un4_Ea~16g$5U8Y?Uu#JTo{D`3`p4DP1Pq zkNM0uh5bF^TMATMQ74e^klL}HS3`<}cde{Q9NXC}`569g_=>+wFcXz_`UPy0J$$5_#N(i*rJ7Urx#4 zbnHv(4H%Ref*+d=PF)s6zjTX)-W~d$sMN4Ngzxt#3SLNn9WO45yktWEx?v@t%Z&5O zMVfpJvRk!1BY|4QBEME#P_KG|^N4)lRjeYp8r(@8{%--t`+u^#t_@;6gQoVl_y?>% zMmKb(L2O}!PV+7Lqf0UZE>a6< zuk(@>E>J@K@LVXAHR!&=jdj9Gx3thYs8R1iCjc$>w7;Lndg9QxJ$FA|$9-LUs)mQ4 z9j7fjnm3VJA4&&-u)`@m#+sF3YnjH0tEyj>rWY{lp zLSbtHvPIm`>BI5vYewH%^swJ+DL(WCOiYs&XNJr_zwBf}nKs8)3HWzhX`iS%p~6bk zttzNd5)*3#2Soj8C8BYk&eLyR25^d!$MMTm{5-3xEE=)%2G`kew3ig0-e)ghDMQxb zFYuJu89pr-8^u?+fp(T3mm4<=DcnTg?^nV2P181cQyKGZN@mI9JJ@$gl&U2G$Icr1 zoQ0p(9(>J$7s^i+on1vcTj1v<-2WfYx)mM?!wih~JR=-uPp}*GM89b+v2e@__n$O0 zUt5MNrvopMdSf2qWaLZ8&s1sbxqreauJ(Kr`1!Jowlezr#y6gy#&NzlwvLnL!~Xa{ z;x?!@mwTrGem3}4uYuRe{5r8W28P#3f3t$->3e5r@ji4jn`}1C(C^UhO=^N6D$`-I z=E#dVt?q3=nZw77cP}6&YPsI-j=Xu!xQ7Sv8qMA*ZNy7uQ4C71=*LHNEs4)#->|1s ztc4piRttCwrD8H8mC=rv6yv*zAQxkLuNa(O{?9fZ(kT2gNEyQWd((MN4eom=cJ&lA z&LaLE3GMdgTdkU79J0T!-(Z39dX^l!c-~uM{QT-os5Vg(XAe)5`G=^$=j?K~hhtD@sUFG5fXqL0__N^T z%CFy7V$n`T0tA1(!Md5_Bksc(k3ZJ&P5puuHlOMV8Hegw?y^j z{eFmVaJSy+Lu|ZD{l)z)))ytBw;#YAF#|Lz(I8XsT} zpLj?;jJ(=Zc>^A9mTurWhCEzxZ$|8Ke1oVf!z+CQy*f&J8`{EwiFHkpdj4EC4zzbU7MDj(}x z6XDUMsuTRESLi*d3#&$cK&kNei~;&xsr<&UTEwPa?3|DPi8bmytA#(B6)6B}5)U zJ1nU@?sNj07B!ig{=)S=D75$JGV)Ll1;#`e>#69#0pB^KA121{(K!8eNd>06FwOhI z;*`TqL=xzi63I6L&SL&+`?6#go+queS%ld;^BE2Ls3+)t%c0}N=V;R;-vaR^C4(QJ zqOH$tDIeIo?uMq%t}k(v z;&YU0SE+)^)OYr@a-yF4;Ngu3Sbo1nFdnteH=K8eyCeh`boQ-L9{pN{L!_8^+J4^#jC!lqf)H4NKr|0IVI+fv; zbTsErT)%${UFhr)6YIoSrYEBR(CjKuO+ubi_D9VY@fsh+qiHCtL2X*}68lb^78S@} zVZHE+hcPuAqUTO|0LPyFw!9~daeaTz>>$iPTlr@PvNchvU6lha z(7|WA&YPBNb*hyS}W4=90vngn3GDZfokg z7xIOv@z*?vkBew?UW18ul7$j;k^kv*8xzC#VJw=Gs2d!cR^8u%xKjJRY!5y!;{L+J zL{Nh$(WL~Ax%@DS#^?98jqLRHQLLW^+>f}7{!X}w!i`fB^P$jQUrC5(LmV#0=g^@N zq2LY|*`_!gp=B*oF9|ncosmO=kY}miS<>l)T|Jegt?=>0`1}vZJ<>rsEP(Z_cPlw2 zf|yr$)$+z6uDlc=%Ym5tR-%(&Bl=hBn!6hC3y}=<6?j06rr!LZlE7F2Xkr*oJU~KVJd+IKve`9>%^oevTM##C2?L{NI-G`TE6;2dtH=AI608;+}222ArZoTf9dbHIR3)Lcs7A!cQBtQb3RuB zGsph3wY!V?hEO`+Bw`81^;v<*8Fdl9-y-RdE&jns4D@92`QQhMUW*iH6=Poi?tI1` z)cb^O9&i>S_Rw)^I*OQHQo?pOdRm?9xU*MN?6kU6U(eJ?%(S{8JLP&Z;^Xm}0S7Wr zA2puf(}MyB9!{~r(>wn8TWP3EJm>jKkJo8?iAGZz@59|Gw~_(Q`>=-jLb<`UfrADZ zm(D317KAh1Ubkw{uMH(zKdOe|H;qEp)o~x&*7YPG4YY3orDtsL+{=^!A*d_YoK_!- zeI6-stly!|KhAZzFyv9Bav>VfUXj&y&&q)cBGE}}oWR{nhtjFW0K4uxi_mPH0u z=r@v%@vFh{+bz-ZFg@|F?;;#=Yr7D19r?VqypC52_KiK#c^Lxx&rsexfa6yi*p4kk z;`cv_B?*P@RkrB~a4)?<+zPy3L~*EM3jJSwb)^yv+y8OyCNy=^8qbHuszg_eAE8dj z{B%3D8g+H)#A#i`9~nhyZ$k&A+ao?E=;xbhIao}wuA9PctBP1S%i%#Z;;KVJ+evP- z>YTyfE>fPyeYw5=xiP`RDS4(palD*t_m}b>)C<%U0;Ax$(_Fkaph;%G!9(ay_gSIn z8lG>L)W<80_a#Wjl6nNHY)Qr&LZY;x-*xB*nSDneSf0Xl<1V}I0>jwMz2afKXItjv zRg8Onk$%+CIA14qwR>Qp-YM}+Xc#EWm_&^F3A=@AF#eusyRVNXV*TBVQ!0@0tJscK z3+k`<%;XZ`%f)Q)PN3&CjhM;CqLFI)5`2E9gUoFCGw+fFl!perf7PlagX~CQc zUVl&kQ8M9q`G=$C<0?1^c<%BLi>3`kM6+ZTNfJFNF^Iuc9t@ zY{&)FosW>jKXS+O6aQEyTEk02r0hyK{`E*p9WC;}jL51QV_2$~P`djO`w?XC3>1Gt z9);T#XM-_bzBPY43C$wTT)q&3=SoHD4?jZ8bNVoG)>*W(6Rm4IaO&Sc%QB3zQ2*Es zbJQ*OC>mk>Ykl`R8mfI319F$2|j_`NVYX%H6u z6MU!Pg7q#k>IOPjwATXh6k2#9h&lfRjyElf9n?pEc4$=M?@7!D2P4SX&0+P?chj0U zo=c@)N#QX`7Jj}0uQ@r-)4l2>-m3n?jj#zqBK{A+o@L+S>P9`OKUp! zkoV|*__H2_^)2#aA%6pLoIO790^-4PW9CEfx-|uZ`BAJZaS=K8!pDgcAEhu3Dcz?Q zI0~7A?zRk*AfKe`3^Uw2t1gmP!~YoZyNCz_3dFx2@~LUtq5ecddD9uTcwHu%fj$Bj zvM(Ur$H0-XdF&V7xAmE20r@y(LUIe{ZN8;MZwcS)Qmvg#oU4XBG9mFbHB6Y2-Txfw z*(aUi!Fd_wc~ZiC8^3SgT+0JEscYnX6E+oT%l$_F8{H5#v-ue9|Me+d$r{XGm0Y#8 zU~uqj?+&=Jd3Uq34|U+ZOb?Di1vzf&e0VSQr@ZhxT%S%q|D9sOdSzgAh#WjNTq|^% z5%-V!o)3A3SnNYnFyXm!iss9wRbiPZv7;ia^A{zjfmBrV8_w34=V$7>&01kUhxHc$ zM?$R9@i_yo-TB~LJhavu>$zt^*{$ZKAiul*}Yx7*oSv{|EEPLMyhxE4!oWm>s7IZ^L4%3{1>F_ zAbH3gj`K?C!?@FQ#o|)&Q&}&PpYLf9v

E1Co2n2tH_e#3gM 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 z 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

eE~eru)t9SZGeYTVmE_i;PU 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

dL=5i#8XTjiCHb%~RH zp)u8KN@qwe<=Ve=`>%ut|CwiV>8WC%w)!ff>oS6TL-ksT*GIsx6XIgjN5H64i0{Pr z5&TyWBD(rE8{bu4XriGBg9A3cQ?|r^^q%9-sI_z`EWc^8tLaFEMf21{LRFa4hXWO!8m-9e=ODW{(+q!#UjO2oC44`j0;>a+t*AASTNAC@ft8#lnzWGs* zN;N&O!IOdy<(0LM^^(7{rf#P9_$bJ>8o#HJ8UwTd^S9yO*ubH>+)gY_??pK<14aE~=kaO-LczJI=>{Ip#vD(#)Nu-{w< zQ!}Zz-oLIxCtVJukm(x0o*aqsdv*ByWob8EZzss)ne@7PccPq2toO!$T_AC4^$z>L zPPDK%fBthx8JQR8ruSr)A^Vs4HW{;0Fb(CtHF&)gcDphh*KezUK0cO^gGz*Jm%5+h z`msusyWt;rns5cCPDv&C(-c9_j|WzTyoBSUUUJTFuo6Xba%yS#3c>mu{qHxQV&U5( zlc1+Z!a(7M)L~A=FjTW*9$;^e#MfcRUD&Ookh7bi>k;9+?rRD75n2-t25CzBRzkxd z#^v{!6SYIIFV*YFuJ9o+t9IqkRvf~7!G}F^vP1aldW)=pOBdcUy!r3z)hg7N!1gf7;wK`TXcRs2LGB3-Jw&CL*aWu#lGTkpjW+p-`i!vS@!li zrtzR2#q%^YWfiJmJoh)tOnViaJNhW;pjHjWFxVxFdsTyXUS_rU<7&9jKUYwjU4w^| z>o?rBLV?D=Q0P5>7))s&NT>4h#jv8MCl)`1V6)Z_N#B=6g#UHBe6K_ioHmy}{Fd~o zU4G0|Z2P$gCI#6H9genxy;q}zHdQ+$&kppgH1y&714-IJclvN(mV1DSy#JZHRWyRJ z&A9q;>F2XE&8Wi8Dyu?#0Rts(3|U=rpeDOC?k`m#%0D=9+HxirxMDY|Hj^B>)KfLp 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°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 literal 0 HcmV?d00001 From de2a3afff8da0c3dfb3cc33a044311f6af2a88f7 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 1 Apr 2025 15:08:12 +0200 Subject: [PATCH 32/51] Changed the limit for minimum energy in the Beam class to gamma=10. --- abel/classes/beam.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/abel/classes/beam.py b/abel/classes/beam.py index a8ad786e..fa5fefeb 100644 --- a/abel/classes/beam.py +++ b/abel/classes/beam.py @@ -75,7 +75,7 @@ def set_phase_space(self, Q, xs, ys, zs, uxs=None, uys=None, uzs=None, pxs=None, self.set_zs(zs) # minimum thresholds for energy, uz and pz - energy_thres = 100*particle_mass*SI.c**2/SI.e # [eV], 100 * particle rest energy. + energy_thres = 10*particle_mass*SI.c**2/SI.e # [eV], 10 * particle rest energy. Gives beta=0.995. uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=particle_mass) pz_thres = gamma2momentum(energy2gamma(energy_thres, unit='eV', m=particle_mass)) @@ -200,7 +200,7 @@ def set_uxs(self, uxs): def set_uys(self, uys): self.__phasespace[4,:] = uys def set_uzs(self, uzs): - energy_thres = 100*self.particle_mass*SI.c**2/SI.e # [eV], 100 * particle rest energy. + energy_thres = 10*self.particle_mass*SI.c**2/SI.e # [eV], 10 * particle rest energy. Gives beta=0.995. uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=self.particle_mass) if np.any(uzs < uz_thres): raise ValueError('uzs contains values that are too small.') @@ -211,7 +211,7 @@ def set_xps(self, xps): def set_yps(self, yps): self.set_uys(yps*self.uzs()) def set_Es(self, Es): - energy_thres = 100*self.particle_mass*SI.c**2/SI.e # [eV], 100 * particle rest energy. + energy_thres = 10*self.particle_mass*SI.c**2/SI.e # [eV], 10 * particle rest energy. Gives beta=0.995. if np.any(Es < energy_thres): raise ValueError('Es contains values that are too small.') self.set_uzs(energy2proper_velocity(Es)) From 8f487edbb91df3d04c8cd1bf84b49462aec40e90 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 1 Apr 2025 16:59:07 +0200 Subject: [PATCH 33/51] Added controls to weighted_mean(), weighted_std() and weighted_cov() under statistics.py for when the sum of weights is zero. --- abel/utilities/statistics.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/abel/utilities/statistics.py b/abel/utilities/statistics.py index 9dbef183..61543348 100644 --- a/abel/utilities/statistics.py +++ b/abel/utilities/statistics.py @@ -20,14 +20,20 @@ def prct_clean2d(xs, ys, enable=True, cut_percentile=5): return x[mask], y[mask] def weighted_mean(values, weights, clean=False, cut_percentile=5): - mask = clean_mask(values, enable=clean, cut_percentile=5) + if np.sum(weights) == 0.0: + raise ZeroDivisionError("Weights sum to zero, can't be normalized.") + mask = clean_mask(values, enable=clean, cut_percentile=cut_percentile) return np.average(values[mask], weights=weights[mask]) def weighted_std(values, weights, clean=False, cut_percentile=5): - mask = clean_mask(values, enable=clean, cut_percentile=5) + if np.sum(weights) == 0.0: + raise ZeroDivisionError("Weights sum to zero, can't be normalized.") + mask = clean_mask(values, enable=clean, cut_percentile=cut_percentile) return np.sqrt(np.cov(values[mask], aweights=weights[mask])) def weighted_cov(xs, ys, weights, clean=False, cut_percentile=5): + if np.sum(weights) == 0.0: + raise ZeroDivisionError("Weights sum to zero, can't be normalized.") mask_x = clean_mask(xs, enable=clean, cut_percentile=cut_percentile/2) mask_y = clean_mask(ys, enable=clean, cut_percentile=cut_percentile/2) mask = np.logical_and(mask_x, mask_y) From e21c2393a0f98b8f58c9eb3378ba51079c9553df Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 1 Apr 2025 17:01:06 +0200 Subject: [PATCH 34/51] Edited the str operator and added controls for __init__() and reset_phase_space() for when num_particles is an integer smaller than 1. --- abel/classes/beam.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/abel/classes/beam.py b/abel/classes/beam.py index fa5fefeb..a7ce4b1e 100644 --- a/abel/classes/beam.py +++ b/abel/classes/beam.py @@ -22,9 +22,9 @@ class Beam(): def __init__(self, phasespace=None, num_particles=1000, num_bunches_in_train=1, bunch_separation=0.0): # check the inputs - if num_particles < 1: - raise ValueError('num_particles cannot be lower than 1.') - if num_bunches_in_train < 1: + if num_particles < 1 or not isinstance(num_particles, int): + raise ValueError('num_particles must be an integer larger than 1.') + if num_bunches_in_train < 1 or not isinstance(num_bunches_in_train, int): raise ValueError('num_bunches_in_train cannot be lower than 1.') if bunch_separation < 0.0: raise ValueError('bunch_separation cannot be negative.') @@ -46,8 +46,8 @@ def __init__(self, phasespace=None, num_particles=1000, num_bunches_in_train=1, # reset phase space def reset_phase_space(self, num_particles): - if num_particles < 1: - raise ValueError('num_particles cannot be lower than 1.') + if num_particles < 1 or not isinstance(num_particles, int): + raise ValueError('num_particles must be an integer larger than 1.') self.__phasespace = np.zeros((8, num_particles)) @@ -143,7 +143,10 @@ def __len__(self): # string operator (called when printing) def __str__(self): - return f"Beam: {len(self)} macroparticles, {self.charge()*1e9:.2f} nC, {self.energy()/1e9:.2f} GeV" + if np.sum(self.weightings()) == 0.0: + return f"Beam: {len(self)} macroparticles, {self.charge()*1e9:.2f} nC" + else: + return f"Beam: {len(self)} macroparticles, {self.charge()*1e9:.2f} nC, {self.energy()/1e9:.2f} GeV" ## BUNCH PATTERN From 7d2b100f1abe5878bdcab312cda8123c40a4a635 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 1 Apr 2025 17:04:25 +0200 Subject: [PATCH 35/51] Edited some tests to purposedly trigger exceptions in test_beam.py. --- tests/test_beam.py | 75 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 64 insertions(+), 11 deletions(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index 56881e1a..7d58b6f7 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -102,6 +102,18 @@ def test_initialization(): assert beam.stage_number == 0 assert beam.location == 0 + # Purposedly trigger exceptions + with pytest.raises(ValueError): + beam = Beam(num_particles=-1) # Should raise an error if attempted to initiate with negative number of particles. + with pytest.raises(ValueError): + beam = Beam(num_particles=1000.2) + with pytest.raises(ValueError): + beam = Beam(num_bunches_in_train=-1) + with pytest.raises(ValueError): + beam = Beam(num_bunches_in_train=1300.2) + with pytest.raises(ValueError): + beam = Beam(bunch_separation=-1) + @pytest.mark.beam def test_set_phase_space(): @@ -115,7 +127,7 @@ def test_set_phase_space(): uxs = np.random.rand(num_particles) uys = np.random.rand(num_particles) - energy_thres = 1001*SI.m_e*SI.c**2/SI.e # [eV], 1000 * particle rest energy. + energy_thres = 13*SI.m_e*SI.c**2/SI.e # [eV], 13 * particle rest energy. uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) uzs = random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e)) @@ -274,6 +286,12 @@ def test_reset_phase_space(): assert beam._Beam__phasespace.shape == (8, 10) assert (beam._Beam__phasespace == 0).all() + # Purposedly trigger exceptions + with pytest.raises(ValueError): + beam.reset_phase_space(-11) # Should raise an error if attempted to initiate with negative number of particles. + with pytest.raises(ValueError): + beam.reset_phase_space(10.001) + @pytest.mark.beam def test_delitem(): @@ -351,21 +369,38 @@ def test_len(): assert len(beam) == num_particles -# @pytest.mark.beam TODO -# def test_str(): -# "Test the __str__ method for correct formatting of beam properties." -# beam = Beam() -# beam.reset_phase_space(5) -# string_repr = str(beam) -# assert "Beam:" in string_repr -# assert "5 macroparticles" in string_repr +@pytest.mark.beam +def test_str(): + "Test the __str__ method for correct formatting of beam properties." + + beam = Beam() + num_particles = 5 + beam.reset_phase_space(num_particles) + beam_str = str(beam) + assert "Beam:" in beam_str + assert "0.00 nC" in beam_str + assert str(num_particles) + " macroparticles" in beam_str + + num_particles = 5005 + Es = np.random.normal(151.567e9, 0.02*151.567e9, num_particles) + qs = np.full(num_particles, -1.5e10*SI.e/num_particles) + beam = Beam() + beam.reset_phase_space(num_particles) + beam.particle_mass = SI.m_e + beam.set_qs(qs) + beam.set_Es(Es) + beam_str = str(beam) + assert "Beam:" in beam_str + assert "{:.2f}".format(-1.5e10*SI.e*1e9) in beam_str + assert str(num_particles) + " macroparticles" in beam_str + assert "{:.2f}".format(beam.energy()/1e9) + " GeV" in beam_str @pytest.mark.beam def test_copy_particle_charge(): num_particles = 8051 - energy_thres = 1001*SI.m_e*SI.c**2/SI.e # [eV], 1000 * particle rest energy. + energy_thres = 11*SI.m_e*SI.c**2/SI.e # [eV], 11 * particle rest energy. uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) beam1 = Beam() @@ -393,6 +428,22 @@ def test_copy_particle_charge(): beam1.copy_particle_charge(beam2) assert (beam1._Beam__phasespace[6, :] == median_charge).all() # Verify charge is copied correctly + # Purposedly trigger exceptions + with pytest.raises(ValueError): + beam1 = Beam() + beam2 = Beam() + beam1.copy_particle_charge(beam2) + with pytest.raises(ValueError): + beam1 = Beam() + beam2 = Beam() + beam2.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs, weightings=ws) + beam1.copy_particle_charge(beam2) + with pytest.raises(ValueError): + beam1 = Beam() + beam2 = Beam() + beam1.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs, weightings=ws) + beam1.copy_particle_charge(beam2) + @pytest.mark.beam def test_scale_charge(): @@ -458,6 +509,9 @@ def test_scale_energy(): + + + ############# Tests on bunch pattern ############# # TODO @@ -1720,7 +1774,6 @@ def test_plot_transverse_profile(): def test_save_load(): import os - #from abel.classes.beam import comp_beams source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, rel_energy_spread=0.01, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) beam = source.track() From b3556f61d7d80c8950991ad0be09f5fe37d5fd87 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 1 Apr 2025 17:30:05 +0200 Subject: [PATCH 36/51] Added to test_rs(), test_deltas(), test_transverse_vector(), test_norm_transverse_vector(), and test_gamma_xy() to test_beam.py. --- tests/test_beam.py | 111 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 110 insertions(+), 1 deletion(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index 7d58b6f7..9b1b1d51 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -508,6 +508,83 @@ def test_scale_energy(): assert str(err) == 'Es contains values that are too small.' +@pytest.mark.beam +def test_rs(): + beam = Beam() + num_particles = 4352 + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + Q = -SI.e * 1.0e10 + beam.set_phase_space(Q, xs, ys, zs) + + assert np.allclose(beam.rs(), np.sqrt(xs**2 + ys**2), rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_deltas(): + beam = Beam() + num_particles = 4352 + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + Es = np.random.normal(1e9, 0.02*1e9, num_particles) + Q = -SI.e * 1.0e10 + beam.set_phase_space(Q, xs, ys, zs, Es=Es) + + assert np.allclose(beam.deltas(), beam.pzs()/np.mean(beam.pzs())-1, rtol=1e-15, atol=0.0) + pz0 = np.mean(beam.pzs())*1.1 + assert np.allclose(beam.deltas(pz0=pz0), beam.pzs()/pz0-1, rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_transverse_vector(): + num_particles = 8989 + energy_thres = 11*SI.m_e*SI.c**2/SI.e # [eV], 11 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e)) + Q = -SI.e * 1.0e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + vector = np.zeros((4,len(beam))) + vector[0,:] = beam.xs() + vector[1,:] = beam.xps() + vector[2,:] = beam.ys() + vector[3,:] = beam.yps() + + assert np.allclose(beam.transverse_vector(), vector, rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_norm_transverse_vector(): + num_particles = 8989 + energy_thres = 11*SI.m_e*SI.c**2/SI.e # [eV], 11 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e)) + Q = -SI.e * 1.0e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + vector = np.zeros((4,len(beam))) + vector[0,:] = beam.xs() + vector[1,:] = beam.uxs()/SI.c + vector[2,:] = beam.ys() + vector[3,:] = beam.uys()/SI.c + + assert np.allclose(beam.norm_transverse_vector(), vector, rtol=1e-15, atol=0.0) @@ -687,6 +764,37 @@ def test_param_calcs_generate_symm_trace_space_xyz(): assert np.isclose(beam.norm_emittance_y(), geo_emitt_y*beam.gamma(), rtol=1e-2, atol=0.0) +@pytest.mark.beam +def test_gamma_xy(): + num_particles = 8989 + energy_thres = 11*SI.m_e*SI.c**2/SI.e # [eV], 11 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e)) + Q = -SI.e * 1.0e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + covx = weighted_cov(beam.xs(), beam.xps(), beam.weightings(), clean=False) + gamma_x = covx[1,1]/np.sqrt(np.linalg.det(covx)) + covy = weighted_cov(beam.ys(), beam.yps(), beam.weightings(), clean=False) + gamma_y = covy[1,1]/np.sqrt(np.linalg.det(covy)) + assert np.isclose(beam.gamma_x(), gamma_x, rtol=1e-10, atol=0.0) + assert np.isclose(beam.gamma_y(), gamma_y, rtol=1e-10, atol=0.0) + + covx = weighted_cov(beam.xs(), beam.xps(), beam.weightings(), clean=True) + gamma_x = covx[1,1]/np.sqrt(np.linalg.det(covx)) + covy = weighted_cov(beam.ys(), beam.yps(), beam.weightings(), clean=True) + gamma_y = covy[1,1]/np.sqrt(np.linalg.det(covy)) + assert np.isclose(beam.gamma_x(clean=True), gamma_x, rtol=1e-10, atol=0.0) + assert np.isclose(beam.gamma_y(clean=True), gamma_y, rtol=1e-10, atol=0.0) + + ############# Tests for beam projections ############# @pytest.mark.beam @@ -1786,5 +1894,6 @@ def test_save_load(): beam.save(filename=filename) loaded_beam = Beam.load(filename=filename) - Beam.comp_beams(beam, loaded_beam, rtol=1e-15, atol=0.0) + Beam.comp_beams(beam, loaded_beam, comp_location=True, rtol=1e-15, atol=0.0) + Beam.comp_beams(beam, loaded_beam, comp_location=True) shutil.rmtree(save_dir) \ No newline at end of file From bb597f72e97095b57282813f58caefc036b8d712 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 1 Apr 2025 18:50:48 +0200 Subject: [PATCH 37/51] Added several more tests for beam statistics. --- tests/test_beam.py | 438 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 428 insertions(+), 10 deletions(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index 9b1b1d51..fad34041 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -129,7 +129,7 @@ def test_set_phase_space(): energy_thres = 13*SI.m_e*SI.c**2/SI.e # [eV], 13 * particle rest energy. uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) - uzs = random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e)) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e), size=num_particles) beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) @@ -409,7 +409,7 @@ def test_copy_particle_charge(): zs = np.random.rand(num_particles) uxs = np.random.rand(num_particles) uys = np.random.rand(num_particles) - uzs = random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e)) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e), size=num_particles) Q = -SI.e * 1.0e10 beam1.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) @@ -419,7 +419,7 @@ def test_copy_particle_charge(): zs = np.random.rand(num_particles) uxs = np.random.rand(num_particles) uys = np.random.rand(num_particles) - uzs = random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e)) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e), size=num_particles) Q = -SI.e * 3.4e10 ws = np.random.rand(num_particles)*Q/(-SI.e) beam2.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs, weightings=ws) @@ -549,7 +549,7 @@ def test_transverse_vector(): zs = np.random.rand(num_particles) uxs = np.random.rand(num_particles) uys = np.random.rand(num_particles) - uzs = random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e)) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e), size=num_particles) Q = -SI.e * 1.0e10 beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) @@ -574,7 +574,7 @@ def test_norm_transverse_vector(): zs = np.random.rand(num_particles) uxs = np.random.rand(num_particles) uys = np.random.rand(num_particles) - uzs = random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e)) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e), size=num_particles) Q = -SI.e * 1.0e10 beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) @@ -764,6 +764,345 @@ def test_param_calcs_generate_symm_trace_space_xyz(): assert np.isclose(beam.norm_emittance_y(), geo_emitt_y*beam.gamma(), rtol=1e-2, atol=0.0) +@pytest.mark.beam +def test_total_particles(): + + num_particles = 4344 + energy_thres = 1200*SI.m_e*SI.c**2/SI.e # [eV], 1200 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e), size=num_particles) + Q = -SI.e * 1.8e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + total_particles = int(np.nansum(np.full(num_particles, Q/num_particles/-SI.e))) + assert beam.total_particles() == total_particles + + # TODO: set some nans in beam + + +@pytest.mark.beam +def test_charge(): + + num_particles = 4344 + energy_thres = 1200*SI.m_e*SI.c**2/SI.e # [eV], 1200 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e), size=num_particles) + Q = -SI.e * 1.8e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + charge = np.nansum(np.full(num_particles, Q/num_particles)) + assert np.isclose(beam.charge(), charge, rtol=1e-15, atol=0.0) + + # TODO: set some nans in beam + + +@pytest.mark.beam +def test_energy(): + + num_particles = 4344 + energy_thres = 1200*SI.m_e*SI.c**2/SI.e # [eV], 1200 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e), size=num_particles) + Q = -SI.e * 1.8e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + Es = proper_velocity2energy(uzs, unit='eV', m=SI.m_e) + energy = weighted_mean(Es, beam.weightings(), clean=False) + assert np.isclose(beam.energy(clean=False), energy, rtol=1e-15, atol=0.0) + energy = weighted_mean(Es, beam.weightings(), clean=True) + assert np.isclose(beam.energy(clean=True), energy, rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_gamma(): + + num_particles = 4344 + energy_thres = 1200*SI.m_e*SI.c**2/SI.e # [eV], 1200 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e), size=num_particles) + Q = -SI.e * 1.8e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + gammas = proper_velocity2gamma(uzs) + gamma = weighted_mean(gammas, beam.weightings(), clean=False) + assert np.isclose(beam.gamma(clean=False), gamma, rtol=1e-15, atol=0.0) + gamma = weighted_mean(gammas, beam.weightings(), clean=True) + assert np.isclose(beam.gamma(clean=True), gamma, rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_total_energy(): + + num_particles = 4344 + energy_thres = 1200*SI.m_e*SI.c**2/SI.e # [eV], 1200 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e), size=num_particles) + Q = -SI.e * 1.8e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + total_energy = SI.e * np.nansum(beam.weightings()*beam.Es()) + assert np.isclose(beam.total_energy(), total_energy, rtol=1e-15, atol=0.0) + + # TODO: set some nans in beam + + +@pytest.mark.beam +def test_energy_spread(): + + num_particles = 4344 + energy_thres = 1200*SI.m_e*SI.c**2/SI.e # [eV], 1200 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e), size=num_particles) + Q = -SI.e * 1.8e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + Es = proper_velocity2energy(uzs, unit='eV', m=SI.m_e) + energy_spread = weighted_std(Es, beam.weightings(), clean=False) + assert np.isclose(beam.energy_spread(clean=False), energy_spread, rtol=1e-15, atol=0.0) + energy_spread = weighted_std(Es, beam.weightings(), clean=True) + assert np.isclose(beam.energy_spread(clean=True), energy_spread, rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_rel_energy_spread(): + + num_particles = 4344 + energy_thres = 1200*SI.m_e*SI.c**2/SI.e # [eV], 1200 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e), size=num_particles) + Q = -SI.e * 1.8e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + Es = proper_velocity2energy(uzs, unit='eV', m=SI.m_e) + rel_energy_spread = weighted_std(Es, beam.weightings(), clean=False)/weighted_mean(Es, beam.weightings(), clean=False) + assert np.isclose(beam.rel_energy_spread(clean=False), rel_energy_spread, rtol=1e-15, atol=0.0) + rel_energy_spread = weighted_std(Es, beam.weightings(), clean=True)/weighted_mean(Es, beam.weightings(), clean=True) + assert np.isclose(beam.rel_energy_spread(clean=True), rel_energy_spread, rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_xyz_offset(): + + num_particles = 4344 + energy_thres = 1200*SI.m_e*SI.c**2/SI.e # [eV], 1200 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e), size=num_particles) + Q = -SI.e * 1.8e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + x_offset = weighted_mean(xs, beam.weightings(), clean=False) + y_offset = weighted_mean(ys, beam.weightings(), clean=False) + z_offset = weighted_mean(zs, beam.weightings(), clean=False) + assert np.isclose(beam.x_offset(clean=False), x_offset, rtol=1e-15, atol=0.0) + assert np.isclose(beam.y_offset(clean=False), y_offset, rtol=1e-15, atol=0.0) + assert np.isclose(beam.z_offset(clean=False), z_offset, rtol=1e-15, atol=0.0) + x_offset = weighted_mean(xs, beam.weightings(), clean=True) + y_offset = weighted_mean(ys, beam.weightings(), clean=True) + z_offset = weighted_mean(zs, beam.weightings(), clean=True) + assert np.isclose(beam.x_offset(clean=True), x_offset, rtol=1e-15, atol=0.0) + assert np.isclose(beam.y_offset(clean=True), y_offset, rtol=1e-15, atol=0.0) + assert np.isclose(beam.z_offset(clean=True), z_offset, rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_xpyp_offset(): + + num_particles = 4344 + energy_thres = 1200*SI.m_e*SI.c**2/SI.e # [eV], 1200 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + xps = np.random.rand(num_particles) + yps = np.random.rand(num_particles) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e), size=num_particles) + Q = -SI.e * 1.8e10 + beam.set_phase_space(Q, xs, ys, zs, uzs=uzs, xps=xps, yps=yps) + + x_angle = weighted_mean(xps, beam.weightings(), clean=False) + y_angle = weighted_mean(yps, beam.weightings(), clean=False) + assert np.isclose(beam.x_angle(clean=False), x_angle, rtol=1e-15, atol=0.0) + assert np.isclose(beam.y_angle(clean=False), y_angle, rtol=1e-15, atol=0.0) + x_angle = weighted_mean(xps, beam.weightings(), clean=True) + y_angle = weighted_mean(yps, beam.weightings(), clean=True) + assert np.isclose(beam.x_angle(clean=True), x_angle, rtol=1e-15, atol=0.0) + assert np.isclose(beam.y_angle(clean=True), y_angle, rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_uxuyuz_offset(): + + num_particles = 4344 + energy_thres = 1200*SI.m_e*SI.c**2/SI.e # [eV], 1200 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e), size=num_particles) + Q = -SI.e * 1.8e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + ux_offset = weighted_mean(uxs, beam.weightings(), clean=False) + uy_offset = weighted_mean(uys, beam.weightings(), clean=False) + uz_offset = weighted_mean(uzs, beam.weightings(), clean=False) + assert np.isclose(beam.ux_offset(clean=False), ux_offset, rtol=1e-15, atol=0.0) + assert np.isclose(beam.uy_offset(clean=False), uy_offset, rtol=1e-15, atol=0.0) + assert np.isclose(beam.uz_offset(clean=False), uz_offset, rtol=1e-15, atol=0.0) + ux_offset = weighted_mean(uxs, beam.weightings(), clean=True) + uy_offset = weighted_mean(uys, beam.weightings(), clean=True) + uz_offset = weighted_mean(uzs, beam.weightings(), clean=True) + assert np.isclose(beam.ux_offset(clean=True), ux_offset, rtol=1e-15, atol=0.0) + assert np.isclose(beam.uy_offset(clean=True), uy_offset, rtol=1e-15, atol=0.0) + assert np.isclose(beam.uz_offset(clean=True), uz_offset, rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_geom_emittance_xy(): + num_particles = 4444 + energy_thres = 1400*SI.m_e*SI.c**2/SI.e # [eV], 1400 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + xps = np.random.rand(num_particles) + yps = np.random.rand(num_particles) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e), size=num_particles) + Q = -SI.e * 1.4e10 + beam.set_phase_space(Q, xs, ys, zs, uzs=uzs, xps=xps, yps=yps) + + geom_emittance_x = np.sqrt(np.linalg.det(weighted_cov(xs, xps, beam.weightings(), clean=False))) + geom_emittance_y = np.sqrt(np.linalg.det(weighted_cov(ys, yps, beam.weightings(), clean=False))) + assert np.isclose(beam.geom_emittance_x(clean=False), geom_emittance_x, rtol=1e-15, atol=0.0) + assert np.isclose(beam.geom_emittance_y(clean=False), geom_emittance_y, rtol=1e-15, atol=0.0) + + geom_emittance_x = np.sqrt(np.linalg.det(weighted_cov(xs, xps, beam.weightings(), clean=True))) + geom_emittance_y = np.sqrt(np.linalg.det(weighted_cov(ys, yps, beam.weightings(), clean=True))) + assert np.isclose(beam.geom_emittance_x(clean=True), geom_emittance_x, rtol=1e-15, atol=0.0) + assert np.isclose(beam.geom_emittance_y(clean=True), geom_emittance_y, rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_norm_emittance_xy(): + num_particles = 4444 + energy_thres = 1400*SI.m_e*SI.c**2/SI.e # [eV], 1400 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e), size=num_particles) + Q = -SI.e * 1.4e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + norm_emittance_x = np.sqrt(np.linalg.det(weighted_cov(xs, uxs/SI.c, beam.weightings(), clean=False))) + norm_emittance_y = np.sqrt(np.linalg.det(weighted_cov(ys, uys/SI.c, beam.weightings(), clean=False))) + assert np.isclose(beam.norm_emittance_x(clean=False), norm_emittance_x, rtol=1e-15, atol=0.0) + assert np.isclose(beam.norm_emittance_y(clean=False), norm_emittance_y, rtol=1e-15, atol=0.0) + + norm_emittance_x = np.sqrt(np.linalg.det(weighted_cov(xs, uxs/SI.c, beam.weightings(), clean=True))) + norm_emittance_y = np.sqrt(np.linalg.det(weighted_cov(ys, uys/SI.c, beam.weightings(), clean=True))) + assert np.isclose(beam.norm_emittance_x(clean=True), norm_emittance_x, rtol=1e-15, atol=0.0) + assert np.isclose(beam.norm_emittance_y(clean=True), norm_emittance_y, rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_beta_xy(): + num_particles = 4444 + energy_thres = 1400*SI.m_e*SI.c**2/SI.e # [eV], 1400 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e), size=num_particles) + Q = -SI.e * 1.4e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + covx = weighted_cov(xs, beam.xps(), beam.weightings(), clean=False) + beta_x = covx[0,0]/np.sqrt(np.linalg.det(covx)) + covy = weighted_cov(ys, beam.yps(), beam.weightings(), clean=False) + beta_y = covy[0,0]/np.sqrt(np.linalg.det(covy)) + assert np.isclose(beam.beta_x(clean=False), beta_x, rtol=1e-15, atol=0.0) + assert np.isclose(beam.beta_y(clean=False), beta_y, rtol=1e-15, atol=0.0) + + covx = weighted_cov(xs, beam.xps(), beam.weightings(), clean=True) + beta_x = covx[0,0]/np.sqrt(np.linalg.det(covx)) + covy = weighted_cov(ys, beam.yps(), beam.weightings(), clean=True) + beta_y = covy[0,0]/np.sqrt(np.linalg.det(covy)) + assert np.isclose(beam.beta_x(clean=True), beta_x, rtol=1e-15, atol=0.0) + assert np.isclose(beam.beta_y(clean=True), beta_y, rtol=1e-15, atol=0.0) + + @pytest.mark.beam def test_gamma_xy(): num_particles = 8989 @@ -776,25 +1115,104 @@ def test_gamma_xy(): zs = np.random.rand(num_particles) uxs = np.random.rand(num_particles) uys = np.random.rand(num_particles) - uzs = random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e)) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e), size=num_particles) Q = -SI.e * 1.0e10 beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) - covx = weighted_cov(beam.xs(), beam.xps(), beam.weightings(), clean=False) + covx = weighted_cov(xs, beam.xps(), beam.weightings(), clean=False) gamma_x = covx[1,1]/np.sqrt(np.linalg.det(covx)) - covy = weighted_cov(beam.ys(), beam.yps(), beam.weightings(), clean=False) + covy = weighted_cov(ys, beam.yps(), beam.weightings(), clean=False) gamma_y = covy[1,1]/np.sqrt(np.linalg.det(covy)) assert np.isclose(beam.gamma_x(), gamma_x, rtol=1e-10, atol=0.0) assert np.isclose(beam.gamma_y(), gamma_y, rtol=1e-10, atol=0.0) - covx = weighted_cov(beam.xs(), beam.xps(), beam.weightings(), clean=True) + covx = weighted_cov(xs, beam.xps(), beam.weightings(), clean=True) gamma_x = covx[1,1]/np.sqrt(np.linalg.det(covx)) - covy = weighted_cov(beam.ys(), beam.yps(), beam.weightings(), clean=True) + covy = weighted_cov(ys, beam.yps(), beam.weightings(), clean=True) gamma_y = covy[1,1]/np.sqrt(np.linalg.det(covy)) assert np.isclose(beam.gamma_x(clean=True), gamma_x, rtol=1e-10, atol=0.0) assert np.isclose(beam.gamma_y(clean=True), gamma_y, rtol=1e-10, atol=0.0) +@pytest.mark.beam +def test_beam_size_xy(): + + num_particles = 4444 + energy_thres = 1400*SI.m_e*SI.c**2/SI.e # [eV], 1400 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e), size=num_particles) + Q = -SI.e * 1.4e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + beam_size_x = weighted_std(xs, beam.weightings(), clean=False) + beam_size_y = weighted_std(ys, beam.weightings(), clean=False) + assert np.isclose(beam.beam_size_x(clean=False), beam_size_x, rtol=1e-15, atol=0.0) + assert np.isclose(beam.beam_size_y(clean=False), beam_size_y, rtol=1e-15, atol=0.0) + + beam_size_x = weighted_std(xs, beam.weightings(), clean=True) + beam_size_y = weighted_std(ys, beam.weightings(), clean=True) + assert np.isclose(beam.beam_size_x(clean=True), beam_size_x, rtol=1e-15, atol=0.0) + assert np.isclose(beam.beam_size_y(clean=True), beam_size_y, rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_bunch_length(): + num_particles = 4444 + energy_thres = 1400*SI.m_e*SI.c**2/SI.e # [eV], 1400 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e)) + Q = -SI.e * 1.4e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + bunch_length = weighted_std(zs, beam.weightings(), clean=False) + assert np.isclose(beam.bunch_length(clean=False), bunch_length, rtol=1e-15, atol=0.0) + + bunch_length = weighted_std(zs, beam.weightings(), clean=True) + assert np.isclose(beam.bunch_length(clean=True), bunch_length, rtol=1e-15, atol=0.0) + + +@pytest.mark.beam +def test_divergence_xy(): + + num_particles = 4444 + energy_thres = 1400*SI.m_e*SI.c**2/SI.e # [eV], 1400 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + + beam = Beam() + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e), size=num_particles) + Q = -SI.e * 1.4e10 + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) + + divergence_x = weighted_std(beam.xps(), beam.weightings(), clean=False) + divergence_y = weighted_std(beam.yps(), beam.weightings(), clean=False) + assert np.isclose(beam.divergence_x(clean=False), divergence_x, rtol=1e-15, atol=0.0) + assert np.isclose(beam.divergence_y(clean=False), divergence_y, rtol=1e-15, atol=0.0) + + divergence_x = weighted_std(beam.xps(), beam.weightings(), clean=True) + divergence_y = weighted_std(beam.yps(), beam.weightings(), clean=True) + assert np.isclose(beam.divergence_x(clean=True), divergence_x, rtol=1e-15, atol=0.0) + assert np.isclose(beam.divergence_y(clean=True), divergence_y, rtol=1e-15, atol=0.0) + + ############# Tests for beam projections ############# @pytest.mark.beam From 59347277a6ec9c4062ef419ff6e478e18a3c96a3 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 1 Apr 2025 19:04:33 +0200 Subject: [PATCH 38/51] Added exception triggering to test_rotate_coord_sys_3D() under test_beam.py. --- tests/test_beam.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index fad34041..91b9e598 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -1616,7 +1616,6 @@ def test_rotate_coord_sys_3D(): start_y_angle = 7.040999e-09 # [rad], define an angle in the zy-plane. source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=start_x_angle, y_angle=start_y_angle) - source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0) old_beam = source.track() old_beam.add_pointing_tilts() # Add an initial tilt in the zy-plane. @@ -1662,6 +1661,32 @@ def test_rotate_coord_sys_3D(): assert np.isclose(beam.x_angle(), old_beam.x_angle(), rtol=1e-7, atol=1e-13) assert np.isclose(beam.y_angle(), old_beam.y_angle(), rtol=1e-7, atol=1e-13) + # Purpposedly trigger exceptions + with pytest.raises(ValueError): + beam = source.track() + axis1 = np.array([1, 1.1, 0]) # Axis as an non-unit vector. + axis2 = np.array([0, 1, 0]) + axis3 = np.array([1, 0, 0]) + beam.rotate_coord_sys_3D(axis1, angle1=nom_x_angle, axis2=axis2, angle2=nom_y_angle, axis3=axis3, angle3=0.0, invert=False) + with pytest.raises(ValueError): + beam = source.track() + axis1 = np.array([1, 0, 0]) # Axis as an non-unit vector. + axis2 = np.array([0, 0.45, 0]) + axis3 = np.array([1, 0, 0]) + beam.rotate_coord_sys_3D(axis1, angle1=nom_x_angle, axis2=axis2, angle2=nom_y_angle, axis3=axis3, angle3=0.0, invert=False) + with pytest.raises(ValueError): + beam = source.track() + axis1 = np.array([1, 0, 0]) # Axis as an non-unit vector. + axis2 = np.array([0, 1, 0]) + axis3 = np.array([-0.1, 0, 0]) + beam.rotate_coord_sys_3D(axis1, angle1=nom_x_angle, axis2=axis2, angle2=nom_y_angle, axis3=axis3, angle3=0.0, invert=False) + with pytest.raises(ValueError): + beam = source.track() + axis1 = np.array([1, 0, -3.14]) # Axis as an non-unit vector. + axis2 = np.array([0.3, 1, 0]) + axis3 = np.array([-0.1, 0, 0]) + beam.rotate_coord_sys_3D(axis1, angle1=nom_x_angle, axis2=axis2, angle2=nom_y_angle, axis3=axis3, angle3=0.0, invert=False) + ############# Tests of in-house beam field calculation methods ############# From d5b33368f14bd71847e314feeacabac90c47609d Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 1 Apr 2025 19:17:46 +0200 Subject: [PATCH 39/51] Added test_density_map_diags() and test_print_summary() to test_beam.py. --- tests/test_beam.py | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index 91b9e598..d0c15ce0 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -1827,6 +1827,8 @@ def test_scale_to_length(): @pytest.mark.beam def test_scale_norm_emittance_x(): + + np.random.seed(42) source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) beam = source.track() @@ -1837,7 +1839,7 @@ def test_scale_norm_emittance_x(): beam.scale_norm_emittance_x(scale_factor*beam.norm_emittance_x()) assert np.allclose(beam.xs(), expected_xs, rtol=1e-15, atol=0.0) assert np.allclose(beam.uxs(), expected_uxs, rtol=1e-15, atol=0.0) - assert np.isclose(beam.norm_emittance_x(), expct_emit_nx, rtol=1e-15, atol=0.0) + assert np.isclose(beam.norm_emittance_x(), expct_emit_nx, rtol=1e-10, atol=0.0) beam = source.track() scale_factor = 0.5354 @@ -1847,7 +1849,7 @@ def test_scale_norm_emittance_x(): beam.scale_norm_emittance_x(scale_factor*beam.norm_emittance_x()) assert np.allclose(beam.xs(), expected_xs, rtol=1e-15, atol=0.0) assert np.allclose(beam.uxs(), expected_uxs, rtol=1e-15, atol=0.0) - assert np.isclose(beam.norm_emittance_x(), expct_emit_nx, rtol=1e-15, atol=0.0) + assert np.isclose(beam.norm_emittance_x(), expct_emit_nx, rtol=1e-10, atol=0.0) beam = source.track() scale_factor = 0.0 @@ -1867,6 +1869,8 @@ def test_scale_norm_emittance_x(): @pytest.mark.beam def test_scale_norm_emittance_y(): + + np.random.seed(42) source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) beam = source.track() @@ -1887,7 +1891,7 @@ def test_scale_norm_emittance_y(): beam.scale_norm_emittance_y(scale_factor*beam.norm_emittance_y()) assert np.allclose(beam.ys(), expected_ys, rtol=1e-15, atol=0.0) assert np.allclose(beam.uys(), expected_uys, rtol=1e-15, atol=0.0) - assert np.isclose(beam.norm_emittance_y(), expct_emit_ny, rtol=1e-15, atol=0.0) + assert np.isclose(beam.norm_emittance_y(), expct_emit_ny, rtol=1e-13, atol=0.0) beam = source.track() scale_factor = 0.0 @@ -2319,6 +2323,23 @@ def test_plot_transverse_profile(): # beam.plot_bunch_pattern() +@pytest.mark.beam +def test_density_map_diags(): + + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + beam.density_map_diags() + plt.close() + + +@pytest.mark.beam +def test_print_summary(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.0, y_offset=0.0, x_angle=0.0, y_angle=0.0) + beam = source.track() + beam.beam_name = 'beam' + beam.print_summary() + + ############# Tests of saving and loading ############# @pytest.mark.beam From 97528904932bde4deec5016df48befadd7e4ba08 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 1 Apr 2025 22:46:53 +0200 Subject: [PATCH 40/51] Small correction in test_beam.py --- tests/test_beam.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_beam.py b/tests/test_beam.py index d0c15ce0..4bf1e603 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -2359,5 +2359,5 @@ def test_save_load(): loaded_beam = Beam.load(filename=filename) Beam.comp_beams(beam, loaded_beam, comp_location=True, rtol=1e-15, atol=0.0) - Beam.comp_beams(beam, loaded_beam, comp_location=True) + Beam.comp_beam_params(beam, loaded_beam, comp_location=True) shutil.rmtree(save_dir) \ No newline at end of file From 027c5980645c5b04922e3cc7b7f93a1eea560cf6 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Tue, 1 Apr 2025 22:47:40 +0200 Subject: [PATCH 41/51] Rearranged code in beam.py. --- abel/classes/beam.py | 323 +++++++++++++++++++++---------------------- 1 file changed, 161 insertions(+), 162 deletions(-) diff --git a/abel/classes/beam.py b/abel/classes/beam.py index a7ce4b1e..15578240 100644 --- a/abel/classes/beam.py +++ b/abel/classes/beam.py @@ -1441,167 +1441,6 @@ def plot_transverse_profile(self): # ax.set_ylabel('Beam current (kA)') - - ## SAVE AND LOAD BEAM - - def filename(self, runnable, beam_name): - return runnable.shot_path() + "/" + beam_name + "_" + str(self.trackable_number).zfill(3) + "_{:012.6F}".format(self.location) + ".h5" - - - # save beam (to OpenPMD format) - def save(self, runnable=None, filename=None, beam_name="beam", series=None): - - if len(self) == 0: - return - - # make new file if not provided - if series is None: - - # open a new file - if runnable is not None: - filename = self.filename(runnable, beam_name) - - # open a new file - series = io.Series(filename, io.Access.create) - - - # add metadata - series.author = "ABEL (the Adaptable Beginning-to-End Linac simulation framework)" - series.date = datetime.now(timezone('CET')).strftime('%Y-%m-%d %H:%M:%S %z') - - # make step (only one) - index = 0 - iteration = series.iterations[index] - - # add attributes - iteration.set_attribute("time", self.location/SI.c) - for key, value in self.__dict__.items(): - if not "__phasespace" in key: - iteration.set_attribute(key, value) - - # make beam record - particles = iteration.particles[beam_name] - - # generate datasets - dset_z = io.Dataset(self.zs().dtype, extent=self.zs().shape) - dset_x = io.Dataset(self.xs().dtype, extent=self.xs().shape) - dset_y = io.Dataset(self.ys().dtype, extent=self.ys().shape) - dset_zoff = io.Dataset(np.dtype('float64'), extent=[1]) - dset_xoff = io.Dataset(np.dtype('float64'), extent=[1]) - dset_yoff = io.Dataset(np.dtype('float64'), extent=[1]) - dset_uz = io.Dataset(self.uzs().dtype, extent=self.uzs().shape) - dset_ux = io.Dataset(self.uxs().dtype, extent=self.uxs().shape) - dset_uy = io.Dataset(self.uys().dtype, extent=self.uys().shape) - dset_w = io.Dataset(self.weightings().dtype, extent=self.weightings().shape) - dset_id = io.Dataset(self.ids().dtype, extent=self.ids().shape) - dset_q = io.Dataset(np.dtype('float64'), extent=[1]) - dset_m = io.Dataset(np.dtype('float64'), extent=[1]) - - dset_n = io.Dataset(self.ids().dtype, extent=[1]) - dset_f = io.Dataset(np.dtype('float64'), extent=[1]) - - # prepare for writing - particles['position']['z'].reset_dataset(dset_z) - particles['position']['x'].reset_dataset(dset_x) - particles['position']['y'].reset_dataset(dset_y) - particles['positionOffset']['z'].reset_dataset(dset_zoff) - particles['positionOffset']['x'].reset_dataset(dset_xoff) - particles['positionOffset']['y'].reset_dataset(dset_yoff) - particles['momentum']['z'].reset_dataset(dset_uz) - particles['momentum']['x'].reset_dataset(dset_ux) - particles['momentum']['y'].reset_dataset(dset_uy) - particles['weighting'][io.Record_Component.SCALAR].reset_dataset(dset_w) - particles['id'][io.Record_Component.SCALAR].reset_dataset(dset_id) - particles['charge'][io.Record_Component.SCALAR].reset_dataset(dset_q) - particles['mass'][io.Record_Component.SCALAR].reset_dataset(dset_m) - - # store data - particles['position']['z'].store_chunk(self.zs()) - particles['position']['x'].store_chunk(self.xs()) - particles['position']['y'].store_chunk(self.ys()) - particles['positionOffset']['x'].make_constant(0.) - particles['positionOffset']['y'].make_constant(0.) - particles['positionOffset']['z'].make_constant(0.) - particles['momentum']['z'].store_chunk(self.uzs()) - particles['momentum']['x'].store_chunk(self.uxs()) - particles['momentum']['y'].store_chunk(self.uys()) - particles['weighting'][io.Record_Component.SCALAR].store_chunk(self.weightings()) - particles['id'][io.Record_Component.SCALAR].store_chunk(self.ids()) - particles['charge'][io.Record_Component.SCALAR].make_constant(self.charge_sign()*SI.e) - particles['mass'][io.Record_Component.SCALAR].make_constant(SI.m_e) - - # set SI units (scaling factor) - particles['momentum']['z'].unit_SI = SI.m_e - particles['momentum']['x'].unit_SI = SI.m_e - particles['momentum']['y'].unit_SI = SI.m_e - - # set dimensional units - particles['position'].unit_dimension = {io.Unit_Dimension.L: 1} - particles['positionOffset'].unit_dimension = {io.Unit_Dimension.L: 1} - particles['momentum'].unit_dimension = {io.Unit_Dimension.L: 1, io.Unit_Dimension.M: 1, io.Unit_Dimension.T: -1} - particles['charge'].unit_dimension = {io.Unit_Dimension.T: 1, io.Unit_Dimension.I: 1} - particles['mass'].unit_dimension = {io.Unit_Dimension.M: 1} - - # save data to file - series.flush() - - return series - - - # load beam (from OpenPMD format) - @classmethod - def load(_, filename, beam_name='beam'): - - # load file - series = io.Series(filename, io.Access.read_only) - - # find index (use last one) - *_, index = series.iterations - - # get particle data - particles = series.iterations[index].particles[beam_name] - - # get attributes - charge = particles["charge"][io.Record_Component.SCALAR].get_attribute("value") - mass = particles["mass"][io.Record_Component.SCALAR].get_attribute("value") - - # extract phase space - ids = particles["id"][io.Record_Component.SCALAR].load_chunk() - weightings = particles["weighting"][io.Record_Component.SCALAR].load_chunk() - xs = particles['position']['x'].load_chunk() - ys = particles['position']['y'].load_chunk() - zs = particles['position']['z'].load_chunk() - pxs_unscaled = particles['momentum']['x'].load_chunk() - pys_unscaled = particles['momentum']['y'].load_chunk() - pzs_unscaled = particles['momentum']['z'].load_chunk() - series.flush() - - # apply SI scaling - pxs = pxs_unscaled * particles['momentum']['x'].unit_SI - pys = pys_unscaled * particles['momentum']['y'].unit_SI - pzs = pzs_unscaled * particles['momentum']['z'].unit_SI - - # make beam - beam = Beam() - beam.set_phase_space(Q=np.sum(weightings*charge), xs=xs, ys=ys, zs=zs, pxs=pxs, pys=pys, pzs=pzs, weightings=weightings) - - # add metadata to beam - try: - beam.trackable_number = series.iterations[index].get_attribute("trackable_number") - beam.stage_number = series.iterations[index].get_attribute("stage_number") - beam.location = series.iterations[index].get_attribute("location") - beam.num_bunches_in_train = series.iterations[index].get_attribute("num_bunches_in_train") - beam.bunch_separation = series.iterations[index].get_attribute("bunch_separation") - except: - beam.trackable_number = None - beam.stage_number = None - beam.location = None - beam.num_bunches_in_train = None - beam.bunch_separation = None - - return beam - - # ================================================== def imshow_plot(self, data, axes=None, extent=None, vmin=None, vmax=None, colmap='seismic', xlab=None, ylab=None, clab='', gridOn=False, origin='lower', interpolation=None, aspect='auto', log_cax=False, reduce_cax_pad=False): @@ -1821,7 +1660,7 @@ def density_map_diags(self): self.distribution_plot_2D(arr1=zs, arr2=Es, weights=weights, hist_bins=hist_bins, hist_range=hist_range_energ, axes=axs[2][2], extent=extent_energ, vmin=None, vmax=None, colmap=cmap, xlab=xilab, ylab=energ_lab, clab=r'$\partial^2 N/\partial \xi \partial\mathcal{E}$ [$\mathrm{m}^{-1}$ $\mathrm{eV}^{-1}$]', origin='lower', interpolation='nearest') - # ================================================== + # ================================================== def print_summary(self): print('---------------------------------------------------') @@ -1853,3 +1692,163 @@ def print_summary(self): print(f"rms beam length [um]:\t\t\t {self.bunch_length()*1e6 :.3f} \t\t") print(f"Peak current [kA]:\t\t\t {self.peak_current()/1e3 :.3f} \t\t") print('---------------------------------------------------') + + + ## SAVE AND LOAD BEAM + + def filename(self, runnable, beam_name): + return runnable.shot_path() + "/" + beam_name + "_" + str(self.trackable_number).zfill(3) + "_{:012.6F}".format(self.location) + ".h5" + + + # save beam (to OpenPMD format) + def save(self, runnable=None, filename=None, beam_name="beam", series=None): + + if len(self) == 0: + return + + # make new file if not provided + if series is None: + + # open a new file + if runnable is not None: + filename = self.filename(runnable, beam_name) + + # open a new file + series = io.Series(filename, io.Access.create) + + + # add metadata + series.author = "ABEL (the Adaptable Beginning-to-End Linac simulation framework)" + series.date = datetime.now(timezone('CET')).strftime('%Y-%m-%d %H:%M:%S %z') + + # make step (only one) + index = 0 + iteration = series.iterations[index] + + # add attributes + iteration.set_attribute("time", self.location/SI.c) + for key, value in self.__dict__.items(): + if not "__phasespace" in key: + iteration.set_attribute(key, value) + + # make beam record + particles = iteration.particles[beam_name] + + # generate datasets + dset_z = io.Dataset(self.zs().dtype, extent=self.zs().shape) + dset_x = io.Dataset(self.xs().dtype, extent=self.xs().shape) + dset_y = io.Dataset(self.ys().dtype, extent=self.ys().shape) + dset_zoff = io.Dataset(np.dtype('float64'), extent=[1]) + dset_xoff = io.Dataset(np.dtype('float64'), extent=[1]) + dset_yoff = io.Dataset(np.dtype('float64'), extent=[1]) + dset_uz = io.Dataset(self.uzs().dtype, extent=self.uzs().shape) + dset_ux = io.Dataset(self.uxs().dtype, extent=self.uxs().shape) + dset_uy = io.Dataset(self.uys().dtype, extent=self.uys().shape) + dset_w = io.Dataset(self.weightings().dtype, extent=self.weightings().shape) + dset_id = io.Dataset(self.ids().dtype, extent=self.ids().shape) + dset_q = io.Dataset(np.dtype('float64'), extent=[1]) + dset_m = io.Dataset(np.dtype('float64'), extent=[1]) + + dset_n = io.Dataset(self.ids().dtype, extent=[1]) + dset_f = io.Dataset(np.dtype('float64'), extent=[1]) + + # prepare for writing + particles['position']['z'].reset_dataset(dset_z) + particles['position']['x'].reset_dataset(dset_x) + particles['position']['y'].reset_dataset(dset_y) + particles['positionOffset']['z'].reset_dataset(dset_zoff) + particles['positionOffset']['x'].reset_dataset(dset_xoff) + particles['positionOffset']['y'].reset_dataset(dset_yoff) + particles['momentum']['z'].reset_dataset(dset_uz) + particles['momentum']['x'].reset_dataset(dset_ux) + particles['momentum']['y'].reset_dataset(dset_uy) + particles['weighting'][io.Record_Component.SCALAR].reset_dataset(dset_w) + particles['id'][io.Record_Component.SCALAR].reset_dataset(dset_id) + particles['charge'][io.Record_Component.SCALAR].reset_dataset(dset_q) + particles['mass'][io.Record_Component.SCALAR].reset_dataset(dset_m) + + # store data + particles['position']['z'].store_chunk(self.zs()) + particles['position']['x'].store_chunk(self.xs()) + particles['position']['y'].store_chunk(self.ys()) + particles['positionOffset']['x'].make_constant(0.) + particles['positionOffset']['y'].make_constant(0.) + particles['positionOffset']['z'].make_constant(0.) + particles['momentum']['z'].store_chunk(self.uzs()) + particles['momentum']['x'].store_chunk(self.uxs()) + particles['momentum']['y'].store_chunk(self.uys()) + particles['weighting'][io.Record_Component.SCALAR].store_chunk(self.weightings()) + particles['id'][io.Record_Component.SCALAR].store_chunk(self.ids()) + particles['charge'][io.Record_Component.SCALAR].make_constant(self.charge_sign()*SI.e) + particles['mass'][io.Record_Component.SCALAR].make_constant(SI.m_e) + + # set SI units (scaling factor) + particles['momentum']['z'].unit_SI = SI.m_e + particles['momentum']['x'].unit_SI = SI.m_e + particles['momentum']['y'].unit_SI = SI.m_e + + # set dimensional units + particles['position'].unit_dimension = {io.Unit_Dimension.L: 1} + particles['positionOffset'].unit_dimension = {io.Unit_Dimension.L: 1} + particles['momentum'].unit_dimension = {io.Unit_Dimension.L: 1, io.Unit_Dimension.M: 1, io.Unit_Dimension.T: -1} + particles['charge'].unit_dimension = {io.Unit_Dimension.T: 1, io.Unit_Dimension.I: 1} + particles['mass'].unit_dimension = {io.Unit_Dimension.M: 1} + + # save data to file + series.flush() + + return series + + + # load beam (from OpenPMD format) + @classmethod + def load(_, filename, beam_name='beam'): + + # load file + series = io.Series(filename, io.Access.read_only) + + # find index (use last one) + *_, index = series.iterations + + # get particle data + particles = series.iterations[index].particles[beam_name] + + # get attributes + charge = particles["charge"][io.Record_Component.SCALAR].get_attribute("value") + mass = particles["mass"][io.Record_Component.SCALAR].get_attribute("value") + + # extract phase space + ids = particles["id"][io.Record_Component.SCALAR].load_chunk() + weightings = particles["weighting"][io.Record_Component.SCALAR].load_chunk() + xs = particles['position']['x'].load_chunk() + ys = particles['position']['y'].load_chunk() + zs = particles['position']['z'].load_chunk() + pxs_unscaled = particles['momentum']['x'].load_chunk() + pys_unscaled = particles['momentum']['y'].load_chunk() + pzs_unscaled = particles['momentum']['z'].load_chunk() + series.flush() + + # apply SI scaling + pxs = pxs_unscaled * particles['momentum']['x'].unit_SI + pys = pys_unscaled * particles['momentum']['y'].unit_SI + pzs = pzs_unscaled * particles['momentum']['z'].unit_SI + + # make beam + beam = Beam() + beam.set_phase_space(Q=np.sum(weightings*charge), xs=xs, ys=ys, zs=zs, pxs=pxs, pys=pys, pzs=pzs, weightings=weightings) + + # add metadata to beam + try: + beam.trackable_number = series.iterations[index].get_attribute("trackable_number") + beam.stage_number = series.iterations[index].get_attribute("stage_number") + beam.location = series.iterations[index].get_attribute("location") + beam.num_bunches_in_train = series.iterations[index].get_attribute("num_bunches_in_train") + beam.bunch_separation = series.iterations[index].get_attribute("bunch_separation") + except: + beam.trackable_number = None + beam.stage_number = None + beam.location = None + beam.num_bunches_in_train = None + beam.bunch_separation = None + + return beam \ No newline at end of file From 6d69d5aff00ae2d68a6473ac244c96174c51550d Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Wed, 2 Apr 2025 13:14:57 +0200 Subject: [PATCH 42/51] Added checks for input types in Beam.set_phase_space() and implemented tests for triggering the exceptions. --- abel/classes/beam.py | 120 ++++++++++++++++++++++++++++++++++++- tests/test_beam.py | 137 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 255 insertions(+), 2 deletions(-) diff --git a/abel/classes/beam.py b/abel/classes/beam.py index 15578240..e6818ccd 100644 --- a/abel/classes/beam.py +++ b/abel/classes/beam.py @@ -64,9 +64,127 @@ def remove_nans(self): # set phase space def set_phase_space(self, Q, xs, ys, zs, uxs=None, uys=None, uzs=None, pxs=None, pys=None, pzs=None, xps=None, yps=None, Es=None, weightings=None, particle_mass=SI.m_e): + """ + Set the phase space of the beam. All input arrays must have the same lengths. + + Parameters + ---------- + Q : [C], float + Total beam charge. + + xs, ys, zs: [m], 1D ndarray + Coordinates for the macroparticles. + + uxs, uys, uzs: [m/s], 1D ndarray, optional + Proper velocities for the macroparticles. All uzs values must be above 10*particle rest energy/c/particle mass. Default set to ``None``. + + pxs, pys, pzs: [kg m/s], 1D ndarray, optional + Momenta for the macroparticles. All pzs values must be above 10*particle rest energy/c. Default set to ``None``. + + xps, yps: [rad], 1D ndarray, optional + Angles dx/ds and dy/ds for the macroparticles. Default set to ``None``. + + Es : [eV], 1D ndarray, optional + Energies for the macroparticles. All values must be above 10*particle rest energy. Default set to ``None``. + + weightings : 1D ndarray, optional + Weights for the macroparticles. Default set to ``None``. + + particle_mass : [kg], float, optional + Particle mass for a single real particle. Default set to ``SI.m_e``. + + + Returns + ---------- + ``None`` + """ + + # Check coordinate type and length + if not isinstance(xs, np.ndarray) or not isinstance(ys, np.ndarray) or not isinstance(zs, np.ndarray): + raise TypeError('Incompatible input type.') - # make empty phase space num_particles = len(xs) + if len(ys) != num_particles or len(zs) != num_particles: + raise ValueError('The input arrays must have the same lengths.') + + # Check proper velocity type and length + if uxs is not None: + if not isinstance(uxs, np.ndarray): + raise TypeError('Incompatible input type.') + if len(uxs) != num_particles: + raise ValueError('The input arrays must have the same lengths.') + if uys is not None: + if not isinstance(uys, np.ndarray): + raise TypeError('Incompatible input type.') + if len(uys) != num_particles: + raise ValueError('The input arrays must have the same lengths.') + if uzs is not None: + if not isinstance(uzs, np.ndarray): + raise TypeError('Incompatible input type.') + if len(uzs) != num_particles: + raise ValueError('The input arrays must have the same lengths.') + + # Check momentum type and length + if pxs is not None: + if not isinstance(pxs, np.ndarray): + raise TypeError('Incompatible input type.') + if len(pxs) != num_particles: + raise ValueError('The input arrays must have the same lengths.') + if pys is not None: + if not isinstance(pys, np.ndarray): + raise TypeError('Incompatible input type.') + if len(pys) != num_particles: + raise ValueError('The input arrays must have the same lengths.') + if pzs is not None: + if not isinstance(pzs, np.ndarray): + raise TypeError('Incompatible input type.') + if len(pzs) != num_particles: + raise ValueError('The input arrays must have the same lengths.') + + # Check angle type and length + if xps is not None: + if not isinstance(xps, np.ndarray): + raise TypeError('Incompatible input type.') + if len(xps) != num_particles: + raise ValueError('The input arrays must have the same lengths.') + if yps is not None: + if not isinstance(yps, np.ndarray): + raise TypeError('Incompatible input type.') + if len(yps) != num_particles: + raise ValueError('The input arrays must have the same lengths.') + + # Check energy type and length + if Es is not None: + if not isinstance(Es, np.ndarray): + raise TypeError('Incompatible input type.') + if len(Es) != num_particles: + raise ValueError('The input arrays must have the same lengths.') + + # Prevent defining proper velocity, momentum or angle in the same direction + if uxs is not None and pxs is not None: + raise ValueError('Cannot define proper velocity and momentum in the same direction.') + if uxs is not None and xps is not None: + raise ValueError('Cannot define proper velocity and angle in the same direction.') + if pxs is not None and xps is not None: + raise ValueError('Cannot define momentum and angle in the same direction.') + if uys is not None and pys is not None: + raise ValueError('Cannot define proper velocity and momentum in the same direction.') + if uys is not None and yps is not None: + raise ValueError('Cannot define proper velocity and angle in the same direction.') + if pys is not None and yps is not None: + raise ValueError('Cannot define momentum and angle in the same direction.') + if uzs is not None and pzs is not None: + raise ValueError('Cannot define proper velocity and momentum in the same direction.') + if uzs is not None and Es is not None: + raise ValueError('Cannot set both uzs and Es.') + if pzs is not None and Es is not None: + raise ValueError('Cannot set both pzs and Es.') + + if particle_mass is not None and particle_mass < 0: + raise ValueError('Particle mass cannot be negative.') + + + # make empty phase space self.reset_phase_space(num_particles) # add positions diff --git a/tests/test_beam.py b/tests/test_beam.py index 4bf1e603..b650a2e3 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -278,6 +278,141 @@ def test_set_phase_space4(): assert np.allclose(beam.Es(), np.sqrt((pzs*SI.c)**2 + (SI.m_e*SI.c**2)**2)/SI.e, rtol=1e-15, atol=0.0) +@pytest.mark.beam +def test_set_phase_space5(): + "Verify that the phase space is set correctly." + + num_particles = 10042 + Q = -SI.e * 1.0e10 + xs = np.random.rand(num_particles) + ys = np.random.rand(num_particles) + zs = np.random.rand(num_particles) + uxs = np.random.rand(num_particles) + uys = np.random.rand(num_particles) + + energy_thres = 13*SI.m_e*SI.c**2/SI.e # [eV], 13 * particle rest energy. + uz_thres = energy2proper_velocity(energy_thres, unit='eV', m=SI.m_e) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(10e12, unit='eV', m=SI.m_e), size=num_particles) + pz_thres = gamma2momentum(energy2gamma(energy_thres, unit='eV', m=SI.m_e)) + pzs = np.random.normal(pz_thres, 0.02*pz_thres, num_particles) + Es = np.random.normal(energy_thres, 0.02*energy_thres, num_particles) + + + ## Purposedly trigger exceptions + # Coordinates type and length + with pytest.raises(TypeError): + beam = Beam() + beam.set_phase_space(Q, 3.14, ys, 1.0) + with pytest.raises(TypeError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, 1.0) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, np.random.rand(num_particles+1), ys, zs) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, np.random.rand(num_particles-1), zs) + + # Momenta type and length + with pytest.raises(TypeError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, uxs=2.9) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, np.random.rand(num_particles+1), uys, uzs) + with pytest.raises(TypeError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, uxs, 15.16, uzs) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, uxs, np.random.rand(num_particles-1), uzs) + with pytest.raises(TypeError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uz_thres) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, np.append(uzs, uz_thres)) + + with pytest.raises(TypeError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, pxs=2.9) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, pxs=np.random.rand(num_particles+1), pys=uys, pzs=pzs) + with pytest.raises(TypeError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, pxs=uxs, pys=15.16, pzs=pzs) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, pxs=uxs, pys=np.random.rand(num_particles-1), pzs=pzs) + with pytest.raises(TypeError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, pxs=uxs, pys=uys, pzs=1.6e-18) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, pxs=uxs, pys=uys, pzs=np.append(pzs, 1.6e-18)) + + with pytest.raises(TypeError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, xps=2.9) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, xps=np.random.rand(num_particles+1)) + with pytest.raises(TypeError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, xps=uxs, yps=15.16) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, xps=uxs, yps=np.random.rand(num_particles-1), Es=Es) + with pytest.raises(TypeError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, xps=uxs, yps=uys, Es=100e9) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, xps=uxs, yps=uys, Es=np.append(Es, 10e9)) + + # Define proper velocity, momentum or angle in the same direction + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, uxs=uxs, pxs=uxs) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, uxs=uxs, xps=uxs) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, pxs=uxs, xps=uxs) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, uys=uys, pys=uys) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, uys=uys, yps=uys) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, pys=uys, yps=uys) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, uzs=uys, pzs=pzs) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, uzs=uzs, Es=Es) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, pzs=pzs, Es=Es) + + # Set energies below the accepted threshold + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs=np.random.rand(num_particles)) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, pzs=pzs*0.01) + with pytest.raises(ValueError): + beam = Beam() + beam.set_phase_space(Q, xs, ys, zs, Es=np.random.rand(num_particles)) + + + @pytest.mark.beam def test_reset_phase_space(): "Test reset_phase_space to ensure it initializes an 8xN zero matrix for the specified number of particles." @@ -1174,7 +1309,7 @@ def test_bunch_length(): zs = np.random.rand(num_particles) uxs = np.random.rand(num_particles) uys = np.random.rand(num_particles) - uzs = random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e)) + uzs = np.random.uniform(uz_thres, energy2proper_velocity(energy_thres*1.01, unit='eV', m=SI.m_e), num_particles) Q = -SI.e * 1.4e10 beam.set_phase_space(Q, xs, ys, zs, uxs, uys, uzs) From 4ac59544499a5b48037fd4665a8754aef5e30fb6 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Wed, 2 Apr 2025 15:46:54 +0200 Subject: [PATCH 43/51] Added test_remove_halo_particles() to test_beam.py. --- tests/test_beam.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/test_beam.py b/tests/test_beam.py index b650a2e3..d29e0a6c 100644 --- a/tests/test_beam.py +++ b/tests/test_beam.py @@ -643,6 +643,30 @@ def test_scale_energy(): assert str(err) == 'Es contains values that are too small.' +@pytest.mark.beam +def test_remove_halo_particles(): + source = setup_basic_source(plasma_density=6.0e20, ramp_beta_mag=5.0, energy=3e9, z_offset=0.0, x_offset=0.1516e-6, y_offset=-5.354e-6, x_angle=-1.3e-6, y_angle=0.7e-6) + beam = source.track() + initial_beam = copy.deepcopy(beam) + + nsigma = 3 + xfilter = np.abs(beam.xs()-beam.x_offset(clean=True)) > nsigma*beam.beam_size_x(clean=True) + xpfilter = np.abs(beam.xps()-beam.x_angle(clean=True)) > nsigma*beam.divergence_x(clean=True) + yfilter = np.abs(beam.ys()-beam.y_offset(clean=True)) > nsigma*beam.beam_size_y(clean=True) + ypfilter = np.abs(beam.yps()-beam.y_angle(clean=True)) > nsigma*beam.divergence_y(clean=True) + filter = np.logical_or(np.logical_or(xfilter, xpfilter), np.logical_or(yfilter, ypfilter)) + count = np.count_nonzero(filter) # Number of particles to be filtered away. + num_particles_left = len(beam) - count + + beam.remove_halo_particles(nsigma=3) + + assert len(beam) == num_particles_left + assert np.all( np.abs(beam.xs()-beam.x_offset(clean=True)) < nsigma*initial_beam.beam_size_x(clean=True) ) + assert np.all( np.abs(beam.xps()-beam.x_angle(clean=True)) < nsigma*initial_beam.divergence_x(clean=True) ) + assert np.all( np.abs(beam.ys()-beam.y_offset(clean=True)) < nsigma*initial_beam.beam_size_y(clean=True) ) + assert np.all( np.abs(beam.yps()-beam.y_angle(clean=True)) < nsigma*initial_beam.divergence_y(clean=True) ) + + @pytest.mark.beam def test_rs(): beam = Beam() From 3a246fa8405387ef5eda73d83b06ebafe4b28a57 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Thu, 3 Apr 2025 12:23:53 +0200 Subject: [PATCH 44/51] Added doc string to Beam.apply_betatron_motion(). --- abel/classes/beam.py | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/abel/classes/beam.py b/abel/classes/beam.py index e6818ccd..7e996311 100644 --- a/abel/classes/beam.py +++ b/abel/classes/beam.py @@ -1399,7 +1399,39 @@ def flip_transverse_phase_spaces(self, flip_momenta=True, flip_positions=False): self.set_ys(-self.ys()) - def apply_betatron_motion(self, L, n0, deltaEs, x0_driver=0, y0_driver=0, radiation_reaction=False, calc_evolution=False, evolution_samples=None): + def apply_betatron_motion(self, L, n0, deltaEs, x0_driver=0, y0_driver=0, radiation_reaction=False, calc_evolution=False): + """ + Evolve the beam by solving Hill's equation. + + Parameters + ---------- + L : [m] float + The beam propagation distance. + + n0 : [m^-3] float + Plasme number density. + + deltaEs : [m^-3] 1D float ndarray + Energy change for the macroparticles. + + x0_driver, y0_driver : [m] float, optional + Initial transverse offsets of the drive beam. Defaults set to 0. + + radiation_reaction : bool + Flag for enabling ating radiation reaction. + + calc_evolution : bool + Flag for recording the beam parameter evolution. + + + Returns + ---------- + Es_final : [eV] 1D float ndarray + The final energies for all macroparticles. + + evol : SimpleNamespace object + only returns when ``calc_evolution=True``. Contains beam parameter evolution data. + """ # remove particles with subzero and Nan energy neg_indices = self.Es() < 0 @@ -1418,7 +1450,7 @@ def apply_betatron_motion(self, L, n0, deltaEs, x0_driver=0, y0_driver=0, radiat gammas = energy2gamma(Es_final) dgamma_ds = (gammas-gamma0s)/L - if calc_evolution: + if calc_evolution: # TODO: This seems to be very clumsy. Consider re-writing. # calculate evolution num_evol_steps = max(20, min(400, round(2*L/(beta_matched(n0, self.energy()+min(0,np.mean(deltaEs))))))) From 40c5fe1703a5e750566f5ff0d714b6d33120cecc Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Thu, 3 Apr 2025 12:24:35 +0200 Subject: [PATCH 45/51] Added minor comment to stage_basic.py. --- abel/classes/stage/impl/stage_basic.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/abel/classes/stage/impl/stage_basic.py b/abel/classes/stage/impl/stage_basic.py index f44b3dec..c5e29b8f 100644 --- a/abel/classes/stage/impl/stage_basic.py +++ b/abel/classes/stage/impl/stage_basic.py @@ -86,7 +86,7 @@ def track(self, beam_incoming, savedepth=0, runnable=None, verbose=False): # ========== Betatron oscillations ========== - deltaEs = np.full(len(beam.Es()), self.nom_energy_gain_flattop) + deltaEs = np.full(len(beam.Es()), self.nom_energy_gain_flattop) # Homogeneous energy gain for all macroparticles. if self.calc_evolution: _, evol = beam.apply_betatron_motion(self.length_flattop, self.plasma_density, deltaEs, x0_driver=driver0.x_offset(), y0_driver=driver0.y_offset(), calc_evolution=self.calc_evolution) self.evolution.beam = evol From 9bb7a736886bdef648118ad3eef36761a34d4a8b Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Thu, 3 Apr 2025 13:06:00 +0200 Subject: [PATCH 46/51] Added controls in source_from_file.py to ensure valid file path in both the constructor and file setter. --- abel/classes/source/impl/source_from_file.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/abel/classes/source/impl/source_from_file.py b/abel/classes/source/impl/source_from_file.py index a491825e..1b49d3bc 100644 --- a/abel/classes/source/impl/source_from_file.py +++ b/abel/classes/source/impl/source_from_file.py @@ -1,12 +1,27 @@ from abel import Source, Beam +import os class SourceFromFile(Source): def __init__(self, length=0, charge=None, energy=None, accel_gradient=None, wallplug_efficiency=1, file=None, x_offset=0, y_offset=0, x_angle=0, y_angle=0, waist_shift_x=0, waist_shift_y=0): + + if file is not None and not os.path.exists(file): + raise FileNotFoundError(f"Error: The file '{file}' was not found.") - self.file = file + self._file = file super().__init__(length, charge, energy, accel_gradient, wallplug_efficiency, x_offset, y_offset, x_angle, y_angle, waist_shift_x, waist_shift_y) + + + @property + def file(self) -> str | None: + return self._file + @file.setter + def file(self, file_path : str): + if file_path is not None and not os.path.exists(file_path): + raise FileNotFoundError(f"Error: The file '{file_path}' was not found.") + else: + self._file = file_path def track(self, _=None, savedepth=0, runnable=None, verbose=False): From b903b8213a7256faf242489ab8c351ac4d3d4ab5 Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Thu, 3 Apr 2025 13:07:13 +0200 Subject: [PATCH 47/51] Edited test_SourceFromFile2Beam() in test_sources.py to trigger exceptions for invalid file path. --- tests/test_sources.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_sources.py b/tests/test_sources.py index 6100e71d..77de8df7 100644 --- a/tests/test_sources.py +++ b/tests/test_sources.py @@ -191,4 +191,13 @@ def test_SourceFromFile2Beam(): ref_beam = Beam.load(beam_file) Beam.comp_beams(beam, ref_beam) + # Trigger exception for when a file does not exist + with pytest.raises(FileNotFoundError): + file = 'tests/data/test_StagePrtclTransWakeInstability_beamline/test_baseline_linac/blabla.h5' + source = SourceFromFile(file=file) + with pytest.raises(FileNotFoundError): + file = 'tests/data/test_StagePrtclTransWakeInstability_beamline/test_baseline_linac/shot_000/blabla.h5' + source = SourceFromFile() + source.file = file + From 04c546222e16a72fcb25919a1da8ea1b3c9006a5 Mon Sep 17 00:00:00 2001 From: Kyrre Ness Sjobak Date: Thu, 3 Apr 2025 15:41:42 +0200 Subject: [PATCH 48/51] Revert "Rearranged code in beam.py." This reverts commit 027c5980645c5b04922e3cc7b7f93a1eea560cf6. That commit moved functions around in Beam : filename, save, load --- abel/classes/beam.py | 323 ++++++++++++++++++++++--------------------- 1 file changed, 162 insertions(+), 161 deletions(-) diff --git a/abel/classes/beam.py b/abel/classes/beam.py index 7e996311..2996ad47 100644 --- a/abel/classes/beam.py +++ b/abel/classes/beam.py @@ -1591,6 +1591,167 @@ def plot_transverse_profile(self): # ax.set_ylabel('Beam current (kA)') + + ## SAVE AND LOAD BEAM + + def filename(self, runnable, beam_name): + return runnable.shot_path() + "/" + beam_name + "_" + str(self.trackable_number).zfill(3) + "_{:012.6F}".format(self.location) + ".h5" + + + # save beam (to OpenPMD format) + def save(self, runnable=None, filename=None, beam_name="beam", series=None): + + if len(self) == 0: + return + + # make new file if not provided + if series is None: + + # open a new file + if runnable is not None: + filename = self.filename(runnable, beam_name) + + # open a new file + series = io.Series(filename, io.Access.create) + + + # add metadata + series.author = "ABEL (the Adaptable Beginning-to-End Linac simulation framework)" + series.date = datetime.now(timezone('CET')).strftime('%Y-%m-%d %H:%M:%S %z') + + # make step (only one) + index = 0 + iteration = series.iterations[index] + + # add attributes + iteration.set_attribute("time", self.location/SI.c) + for key, value in self.__dict__.items(): + if not "__phasespace" in key: + iteration.set_attribute(key, value) + + # make beam record + particles = iteration.particles[beam_name] + + # generate datasets + dset_z = io.Dataset(self.zs().dtype, extent=self.zs().shape) + dset_x = io.Dataset(self.xs().dtype, extent=self.xs().shape) + dset_y = io.Dataset(self.ys().dtype, extent=self.ys().shape) + dset_zoff = io.Dataset(np.dtype('float64'), extent=[1]) + dset_xoff = io.Dataset(np.dtype('float64'), extent=[1]) + dset_yoff = io.Dataset(np.dtype('float64'), extent=[1]) + dset_uz = io.Dataset(self.uzs().dtype, extent=self.uzs().shape) + dset_ux = io.Dataset(self.uxs().dtype, extent=self.uxs().shape) + dset_uy = io.Dataset(self.uys().dtype, extent=self.uys().shape) + dset_w = io.Dataset(self.weightings().dtype, extent=self.weightings().shape) + dset_id = io.Dataset(self.ids().dtype, extent=self.ids().shape) + dset_q = io.Dataset(np.dtype('float64'), extent=[1]) + dset_m = io.Dataset(np.dtype('float64'), extent=[1]) + + dset_n = io.Dataset(self.ids().dtype, extent=[1]) + dset_f = io.Dataset(np.dtype('float64'), extent=[1]) + + # prepare for writing + particles['position']['z'].reset_dataset(dset_z) + particles['position']['x'].reset_dataset(dset_x) + particles['position']['y'].reset_dataset(dset_y) + particles['positionOffset']['z'].reset_dataset(dset_zoff) + particles['positionOffset']['x'].reset_dataset(dset_xoff) + particles['positionOffset']['y'].reset_dataset(dset_yoff) + particles['momentum']['z'].reset_dataset(dset_uz) + particles['momentum']['x'].reset_dataset(dset_ux) + particles['momentum']['y'].reset_dataset(dset_uy) + particles['weighting'][io.Record_Component.SCALAR].reset_dataset(dset_w) + particles['id'][io.Record_Component.SCALAR].reset_dataset(dset_id) + particles['charge'][io.Record_Component.SCALAR].reset_dataset(dset_q) + particles['mass'][io.Record_Component.SCALAR].reset_dataset(dset_m) + + # store data + particles['position']['z'].store_chunk(self.zs()) + particles['position']['x'].store_chunk(self.xs()) + particles['position']['y'].store_chunk(self.ys()) + particles['positionOffset']['x'].make_constant(0.) + particles['positionOffset']['y'].make_constant(0.) + particles['positionOffset']['z'].make_constant(0.) + particles['momentum']['z'].store_chunk(self.uzs()) + particles['momentum']['x'].store_chunk(self.uxs()) + particles['momentum']['y'].store_chunk(self.uys()) + particles['weighting'][io.Record_Component.SCALAR].store_chunk(self.weightings()) + particles['id'][io.Record_Component.SCALAR].store_chunk(self.ids()) + particles['charge'][io.Record_Component.SCALAR].make_constant(self.charge_sign()*SI.e) + particles['mass'][io.Record_Component.SCALAR].make_constant(SI.m_e) + + # set SI units (scaling factor) + particles['momentum']['z'].unit_SI = SI.m_e + particles['momentum']['x'].unit_SI = SI.m_e + particles['momentum']['y'].unit_SI = SI.m_e + + # set dimensional units + particles['position'].unit_dimension = {io.Unit_Dimension.L: 1} + particles['positionOffset'].unit_dimension = {io.Unit_Dimension.L: 1} + particles['momentum'].unit_dimension = {io.Unit_Dimension.L: 1, io.Unit_Dimension.M: 1, io.Unit_Dimension.T: -1} + particles['charge'].unit_dimension = {io.Unit_Dimension.T: 1, io.Unit_Dimension.I: 1} + particles['mass'].unit_dimension = {io.Unit_Dimension.M: 1} + + # save data to file + series.flush() + + return series + + + # load beam (from OpenPMD format) + @classmethod + def load(_, filename, beam_name='beam'): + + # load file + series = io.Series(filename, io.Access.read_only) + + # find index (use last one) + *_, index = series.iterations + + # get particle data + particles = series.iterations[index].particles[beam_name] + + # get attributes + charge = particles["charge"][io.Record_Component.SCALAR].get_attribute("value") + mass = particles["mass"][io.Record_Component.SCALAR].get_attribute("value") + + # extract phase space + ids = particles["id"][io.Record_Component.SCALAR].load_chunk() + weightings = particles["weighting"][io.Record_Component.SCALAR].load_chunk() + xs = particles['position']['x'].load_chunk() + ys = particles['position']['y'].load_chunk() + zs = particles['position']['z'].load_chunk() + pxs_unscaled = particles['momentum']['x'].load_chunk() + pys_unscaled = particles['momentum']['y'].load_chunk() + pzs_unscaled = particles['momentum']['z'].load_chunk() + series.flush() + + # apply SI scaling + pxs = pxs_unscaled * particles['momentum']['x'].unit_SI + pys = pys_unscaled * particles['momentum']['y'].unit_SI + pzs = pzs_unscaled * particles['momentum']['z'].unit_SI + + # make beam + beam = Beam() + beam.set_phase_space(Q=np.sum(weightings*charge), xs=xs, ys=ys, zs=zs, pxs=pxs, pys=pys, pzs=pzs, weightings=weightings) + + # add metadata to beam + try: + beam.trackable_number = series.iterations[index].get_attribute("trackable_number") + beam.stage_number = series.iterations[index].get_attribute("stage_number") + beam.location = series.iterations[index].get_attribute("location") + beam.num_bunches_in_train = series.iterations[index].get_attribute("num_bunches_in_train") + beam.bunch_separation = series.iterations[index].get_attribute("bunch_separation") + except: + beam.trackable_number = None + beam.stage_number = None + beam.location = None + beam.num_bunches_in_train = None + beam.bunch_separation = None + + return beam + + # ================================================== def imshow_plot(self, data, axes=None, extent=None, vmin=None, vmax=None, colmap='seismic', xlab=None, ylab=None, clab='', gridOn=False, origin='lower', interpolation=None, aspect='auto', log_cax=False, reduce_cax_pad=False): @@ -1810,7 +1971,7 @@ def density_map_diags(self): self.distribution_plot_2D(arr1=zs, arr2=Es, weights=weights, hist_bins=hist_bins, hist_range=hist_range_energ, axes=axs[2][2], extent=extent_energ, vmin=None, vmax=None, colmap=cmap, xlab=xilab, ylab=energ_lab, clab=r'$\partial^2 N/\partial \xi \partial\mathcal{E}$ [$\mathrm{m}^{-1}$ $\mathrm{eV}^{-1}$]', origin='lower', interpolation='nearest') - # ================================================== + # ================================================== def print_summary(self): print('---------------------------------------------------') @@ -1842,163 +2003,3 @@ def print_summary(self): print(f"rms beam length [um]:\t\t\t {self.bunch_length()*1e6 :.3f} \t\t") print(f"Peak current [kA]:\t\t\t {self.peak_current()/1e3 :.3f} \t\t") print('---------------------------------------------------') - - - ## SAVE AND LOAD BEAM - - def filename(self, runnable, beam_name): - return runnable.shot_path() + "/" + beam_name + "_" + str(self.trackable_number).zfill(3) + "_{:012.6F}".format(self.location) + ".h5" - - - # save beam (to OpenPMD format) - def save(self, runnable=None, filename=None, beam_name="beam", series=None): - - if len(self) == 0: - return - - # make new file if not provided - if series is None: - - # open a new file - if runnable is not None: - filename = self.filename(runnable, beam_name) - - # open a new file - series = io.Series(filename, io.Access.create) - - - # add metadata - series.author = "ABEL (the Adaptable Beginning-to-End Linac simulation framework)" - series.date = datetime.now(timezone('CET')).strftime('%Y-%m-%d %H:%M:%S %z') - - # make step (only one) - index = 0 - iteration = series.iterations[index] - - # add attributes - iteration.set_attribute("time", self.location/SI.c) - for key, value in self.__dict__.items(): - if not "__phasespace" in key: - iteration.set_attribute(key, value) - - # make beam record - particles = iteration.particles[beam_name] - - # generate datasets - dset_z = io.Dataset(self.zs().dtype, extent=self.zs().shape) - dset_x = io.Dataset(self.xs().dtype, extent=self.xs().shape) - dset_y = io.Dataset(self.ys().dtype, extent=self.ys().shape) - dset_zoff = io.Dataset(np.dtype('float64'), extent=[1]) - dset_xoff = io.Dataset(np.dtype('float64'), extent=[1]) - dset_yoff = io.Dataset(np.dtype('float64'), extent=[1]) - dset_uz = io.Dataset(self.uzs().dtype, extent=self.uzs().shape) - dset_ux = io.Dataset(self.uxs().dtype, extent=self.uxs().shape) - dset_uy = io.Dataset(self.uys().dtype, extent=self.uys().shape) - dset_w = io.Dataset(self.weightings().dtype, extent=self.weightings().shape) - dset_id = io.Dataset(self.ids().dtype, extent=self.ids().shape) - dset_q = io.Dataset(np.dtype('float64'), extent=[1]) - dset_m = io.Dataset(np.dtype('float64'), extent=[1]) - - dset_n = io.Dataset(self.ids().dtype, extent=[1]) - dset_f = io.Dataset(np.dtype('float64'), extent=[1]) - - # prepare for writing - particles['position']['z'].reset_dataset(dset_z) - particles['position']['x'].reset_dataset(dset_x) - particles['position']['y'].reset_dataset(dset_y) - particles['positionOffset']['z'].reset_dataset(dset_zoff) - particles['positionOffset']['x'].reset_dataset(dset_xoff) - particles['positionOffset']['y'].reset_dataset(dset_yoff) - particles['momentum']['z'].reset_dataset(dset_uz) - particles['momentum']['x'].reset_dataset(dset_ux) - particles['momentum']['y'].reset_dataset(dset_uy) - particles['weighting'][io.Record_Component.SCALAR].reset_dataset(dset_w) - particles['id'][io.Record_Component.SCALAR].reset_dataset(dset_id) - particles['charge'][io.Record_Component.SCALAR].reset_dataset(dset_q) - particles['mass'][io.Record_Component.SCALAR].reset_dataset(dset_m) - - # store data - particles['position']['z'].store_chunk(self.zs()) - particles['position']['x'].store_chunk(self.xs()) - particles['position']['y'].store_chunk(self.ys()) - particles['positionOffset']['x'].make_constant(0.) - particles['positionOffset']['y'].make_constant(0.) - particles['positionOffset']['z'].make_constant(0.) - particles['momentum']['z'].store_chunk(self.uzs()) - particles['momentum']['x'].store_chunk(self.uxs()) - particles['momentum']['y'].store_chunk(self.uys()) - particles['weighting'][io.Record_Component.SCALAR].store_chunk(self.weightings()) - particles['id'][io.Record_Component.SCALAR].store_chunk(self.ids()) - particles['charge'][io.Record_Component.SCALAR].make_constant(self.charge_sign()*SI.e) - particles['mass'][io.Record_Component.SCALAR].make_constant(SI.m_e) - - # set SI units (scaling factor) - particles['momentum']['z'].unit_SI = SI.m_e - particles['momentum']['x'].unit_SI = SI.m_e - particles['momentum']['y'].unit_SI = SI.m_e - - # set dimensional units - particles['position'].unit_dimension = {io.Unit_Dimension.L: 1} - particles['positionOffset'].unit_dimension = {io.Unit_Dimension.L: 1} - particles['momentum'].unit_dimension = {io.Unit_Dimension.L: 1, io.Unit_Dimension.M: 1, io.Unit_Dimension.T: -1} - particles['charge'].unit_dimension = {io.Unit_Dimension.T: 1, io.Unit_Dimension.I: 1} - particles['mass'].unit_dimension = {io.Unit_Dimension.M: 1} - - # save data to file - series.flush() - - return series - - - # load beam (from OpenPMD format) - @classmethod - def load(_, filename, beam_name='beam'): - - # load file - series = io.Series(filename, io.Access.read_only) - - # find index (use last one) - *_, index = series.iterations - - # get particle data - particles = series.iterations[index].particles[beam_name] - - # get attributes - charge = particles["charge"][io.Record_Component.SCALAR].get_attribute("value") - mass = particles["mass"][io.Record_Component.SCALAR].get_attribute("value") - - # extract phase space - ids = particles["id"][io.Record_Component.SCALAR].load_chunk() - weightings = particles["weighting"][io.Record_Component.SCALAR].load_chunk() - xs = particles['position']['x'].load_chunk() - ys = particles['position']['y'].load_chunk() - zs = particles['position']['z'].load_chunk() - pxs_unscaled = particles['momentum']['x'].load_chunk() - pys_unscaled = particles['momentum']['y'].load_chunk() - pzs_unscaled = particles['momentum']['z'].load_chunk() - series.flush() - - # apply SI scaling - pxs = pxs_unscaled * particles['momentum']['x'].unit_SI - pys = pys_unscaled * particles['momentum']['y'].unit_SI - pzs = pzs_unscaled * particles['momentum']['z'].unit_SI - - # make beam - beam = Beam() - beam.set_phase_space(Q=np.sum(weightings*charge), xs=xs, ys=ys, zs=zs, pxs=pxs, pys=pys, pzs=pzs, weightings=weightings) - - # add metadata to beam - try: - beam.trackable_number = series.iterations[index].get_attribute("trackable_number") - beam.stage_number = series.iterations[index].get_attribute("stage_number") - beam.location = series.iterations[index].get_attribute("location") - beam.num_bunches_in_train = series.iterations[index].get_attribute("num_bunches_in_train") - beam.bunch_separation = series.iterations[index].get_attribute("bunch_separation") - except: - beam.trackable_number = None - beam.stage_number = None - beam.location = None - beam.num_bunches_in_train = None - beam.bunch_separation = None - - return beam \ No newline at end of file From 5665394fd6c4facc0a5ba0f5e279aaed2dd44dd9 Mon Sep 17 00:00:00 2001 From: Kyrre Ness Sjobak Date: Thu, 3 Apr 2025 15:54:41 +0200 Subject: [PATCH 49/51] Manually undo the moving of 'beam statistics' function from commit fcc2ce9ed879a5dcce4291138d9b8e5129080756 --- abel/classes/beam.py | 464 +++++++++++++++++++++---------------------- 1 file changed, 229 insertions(+), 235 deletions(-) diff --git a/abel/classes/beam.py b/abel/classes/beam.py index 2996ad47..0540596b 100644 --- a/abel/classes/beam.py +++ b/abel/classes/beam.py @@ -505,237 +505,6 @@ def norm_transverse_vector(self): vector[3,:] = self.uys()/SI.c return vector - - - ## BEAM STATISTICS - - def total_particles(self): - return int(np.nansum(self.weightings())) - - def charge(self): - return np.nansum(self.qs()) - - def abs_charge(self): - return abs(self.charge()) - - def charge_sign(self): - if self.charge() == 0: - return 1.0 - else: - return self.charge()/abs(self.charge()) - - def energy(self, clean=False): - return weighted_mean(self.Es(), self.weightings(), clean) - - def gamma(self, clean=False): - return weighted_mean(self.gammas(), self.weightings(), clean) - - def total_energy(self): - return SI.e * np.nansum(self.weightings()*self.Es()) - - def energy_spread(self, clean=False): - return weighted_std(self.Es(), self.weightings(), clean) - - def rel_energy_spread(self, clean=False): - return self.energy_spread(clean)/self.energy(clean) - - def z_offset(self, clean=False): - return weighted_mean(self.zs(), self.weightings(), clean) - - def bunch_length(self, clean=False): - return weighted_std(self.zs(), self.weightings(), clean) - - def x_offset(self, clean=False): - return weighted_mean(self.xs(), self.weightings(), clean) - - def beam_size_x(self, clean=False): - return weighted_std(self.xs(), self.weightings(), clean) - - def y_offset(self, clean=False): - return weighted_mean(self.ys(), self.weightings(), clean) - - def beam_size_y(self, clean=False): - return weighted_std(self.ys(), self.weightings(), clean) - - def x_angle(self, clean=False): - return weighted_mean(self.xps(), self.weightings(), clean) - - def divergence_x(self, clean=False): - return weighted_std(self.xps(), self.weightings(), clean) - - def y_angle(self, clean=False): - return weighted_mean(self.yps(), self.weightings(), clean) - - def divergence_y(self, clean=False): - return weighted_std(self.yps(), self.weightings(), clean) - - def ux_offset(self, clean=False): - return weighted_mean(self.uxs(), self.weightings(), clean) - - def uy_offset(self, clean=False): - return weighted_mean(self.uys(), self.weightings(), clean) - - def uz_offset(self, clean=False): - return weighted_mean(self.uzs(), self.weightings(), clean) - - - def geom_emittance_x(self, clean=False): - return np.sqrt(np.linalg.det(weighted_cov(self.xs(), self.xps(), self.weightings(), clean))) - - def geom_emittance_y(self, clean=False): - return np.sqrt(np.linalg.det(weighted_cov(self.ys(), self.yps(), self.weightings(), clean))) - - def norm_emittance_x(self, clean=False): - return np.sqrt(np.linalg.det(weighted_cov(self.xs(), self.uxs()/SI.c, self.weightings(), clean))) - - def norm_emittance_y(self, clean=False): - return np.sqrt(np.linalg.det(weighted_cov(self.ys(), self.uys()/SI.c, self.weightings(), clean))) - - def beta_x(self, clean=False): - covx = weighted_cov(self.xs(), self.xps(), self.weightings(), clean) - return covx[0,0]/np.sqrt(np.linalg.det(covx)) - - def beta_y(self, clean=False): - covy = weighted_cov(self.ys(), self.yps(), self.weightings(), clean) - return covy[0,0]/np.sqrt(np.linalg.det(covy)) - - def alpha_x(self, clean=False): - covx = weighted_cov(self.xs(), self.xps(), self.weightings(), clean) - return -covx[1,0]/np.sqrt(np.linalg.det(covx)) - - def alpha_y(self, clean=False): - covy = weighted_cov(self.ys(), self.yps(), self.weightings(), clean) - return -covy[1,0]/np.sqrt(np.linalg.det(covy)) - - def gamma_x(self, clean=False): - covx = weighted_cov(self.xs(), self.xps(), self.weightings(), clean) - return covx[1,1]/np.sqrt(np.linalg.det(covx)) - - def gamma_y(self, clean=False): - covy = weighted_cov(self.ys(), self.yps(), self.weightings(), clean) - return covy[1,1]/np.sqrt(np.linalg.det(covy)) - - def intrinsic_emittance(self): - covxy = np.cov(self.norm_transverse_vector(), aweights=self.weightings()) - return np.sqrt(np.sqrt(np.linalg.det(covxy))) - - def angular_momentum(self): - covxy = np.cov(self.norm_transverse_vector(), aweights=self.weightings()) - det_covxy_cross = np.linalg.det(covxy[2:4,0:2]) - return np.sign(covxy[3,0]-covxy[2,1])*np.sqrt(np.abs(det_covxy_cross)) - - def eigen_emittance_max(self): - return np.sqrt(self.norm_emittance_x()*self.norm_emittance_y()) + self.angular_momentum() - - def eigen_emittance_min(self): - return np.sqrt(self.norm_emittance_x()*self.norm_emittance_y()) - self.angular_momentum() - - def norm_amplitude_x(self, plasma_density=None, clean=False): - if plasma_density is not None: - beta_x = beta_matched(plasma_density, self.energy()) - alpha_x = 0 - else: - covx = weighted_cov(self.xs(), self.xps(), self.weightings(), clean) - emgx = np.sqrt(np.linalg.det(covx)) - beta_x = covx[0,0]/emgx - alpha_x = -covx[1,0]/emgx - return np.sqrt(self.gamma()/beta_x)*np.sqrt(self.x_offset()**2 + (self.x_offset()*alpha_x + self.x_angle()*beta_x)**2) - - def norm_amplitude_y(self, plasma_density=None, clean=False): - if plasma_density is not None: - beta_y = beta_matched(plasma_density, self.energy()) - alpha_y = 0 - else: - covy = weighted_cov(self.ys(), self.yps(), self.weightings(), clean) - emgy = np.sqrt(np.linalg.det(covy)) - beta_y = covy[0,0]/emgy - alpha_y = -covy[1,0]/emgy - return np.sqrt(self.gamma()/beta_y)*np.sqrt(self.y_offset()**2 + (self.y_offset()*alpha_y + self.y_angle()*beta_y)**2) - - def peak_density(self): # TODO: this is only valid for Gaussian beams. - return (self.charge()/SI.e)/(np.sqrt(2*SI.pi)**3*self.beam_size_x()*self.beam_size_y()*self.bunch_length()) - - def peak_current(self): - Is, _ = self.current_profile() - return max(abs(Is)) - - - ## BEAM HALO CLEANING (EXTREME OUTLIERS) - def remove_halo_particles(self, nsigma=20): - xfilter = np.abs(self.xs()-self.x_offset(clean=True)) > nsigma*self.beam_size_x(clean=True) - xpfilter = np.abs(self.xps()-self.x_angle(clean=True)) > nsigma*self.divergence_x(clean=True) - yfilter = np.abs(self.ys()-self.y_offset(clean=True)) > nsigma*self.beam_size_y(clean=True) - ypfilter = np.abs(self.yps()-self.y_angle(clean=True)) > nsigma*self.divergence_y(clean=True) - filter = np.logical_or(np.logical_or(xfilter, xpfilter), np.logical_or(yfilter, ypfilter)) - del self[filter] - - - ## BEAM PROJECTIONS - - def projected_density(self, fcn, bins=None): - if bins is None: - Nbins = int(np.sqrt(len(self)/2)) - bins = np.linspace(min(fcn()), max(fcn()), Nbins) - counts, edges = np.histogram(fcn(), weights=self.qs(), bins=bins) - ctrs = (edges[0:-1] + edges[1:])/2 - proj = counts/np.diff(edges) - return proj, ctrs - - def current_profile(self, bins=None): - return self.projected_density(self.ts, bins=bins) - - def longitudinal_num_density(self, bins=None): - dQdz, zs = self.projected_density(self.zs, bins=bins) - dNdz = dQdz / SI.e / self.charge_sign() - return dNdz, zs - - def energy_spectrum(self, bins=None): - return self.projected_density(self.Es, bins=bins) - - def rel_energy_spectrum(self, nom_energy=None, bins=None): - if nom_energy is None: - nom_energy = self.energy() - return self.projected_density(lambda: self.Es()/nom_energy-1, bins=bins) - - def transverse_profile_x(self, bins=None): - return self.projected_density(self.xs, bins=bins) - - def transverse_profile_y(self, bins=None): - return self.projected_density(self.ys, bins=bins) - - def transverse_profile_xp(self, bins=None): - return self.projected_density(self.xps, bins=bins) - - def transverse_profile_yp(self, bins=None): - return self.projected_density(self.yps, bins=bins) - - ## phase spaces - - def phase_space_density(self, hfcn, vfcn, hbins=None, vbins=None): - self.remove_nans() - if hbins is None: - hbins = round(np.sqrt(len(self))/2) - if vbins is None: - vbins = round(np.sqrt(len(self))/2) - counts, hedges, vedges = np.histogram2d(hfcn(), vfcn(), weights=self.qs(), bins=(hbins, vbins)) - hctrs = (hedges[0:-1] + hedges[1:])/2 - vctrs = (vedges[0:-1] + vedges[1:])/2 - density = (counts/np.diff(vedges)).T/np.diff(hedges) - - #dx = np.diff(hedges) - #dy = np.diff(vedges) - #bin_areas = dx[:, None] * dy[None, :] - #density = counts/bin_areas - #print(np.sum(density*np.diff(vedges)*np.diff(hedges))/self.charge()) - return density, hctrs, vctrs - - def density_lps(self, hbins=None, vbins=None): - return self.phase_space_density(self.zs, self.Es, hbins=hbins, vbins=vbins) - - def density_transverse(self, hbins=None, vbins=None): - return self.phase_space_density(self.xs, self.ys, hbins=hbins, vbins=vbins) - - ## Rotate the coordinate system of the beam # ================================================== def rotate_coord_sys_3D(self, axis1, angle1, axis2=np.array([0, 1, 0]), angle2=0.0, axis3=np.array([1, 0, 0]), angle3=0.0, invert=False): @@ -1022,10 +791,7 @@ def x_tilt_angle(self, z_cutoff=None): return np.arctan(slope) - # # ================================================== - # def y_tilt_angle(self, clean=False): - # return np.arcsin(self.uy_offset(clean=clean)/self.uz_offset(clean=clean)) - + # ================================================== def y_tilt_angle(self, z_cutoff=None): "Retrieve the tilt angle of the beam in the zy-plane. WARNING: becomes unreliable around > 1e-4 rad." if z_cutoff is None: @@ -1036,7 +802,235 @@ def y_tilt_angle(self, z_cutoff=None): slope, _ = np.polyfit(z_centroids, y_centroids, 1) return np.arctan(slope) + + ## BEAM STATISTICS + + def total_particles(self): + return int(np.nansum(self.weightings())) + + def charge(self): + return np.nansum(self.qs()) + + def abs_charge(self): + return abs(self.charge()) + + def charge_sign(self): + if self.charge() == 0: + return 1.0 + else: + return self.charge()/abs(self.charge()) + + def energy(self, clean=False): + return weighted_mean(self.Es(), self.weightings(), clean) + + def gamma(self, clean=False): + return weighted_mean(self.gammas(), self.weightings(), clean) + + def total_energy(self): + return SI.e * np.nansum(self.weightings()*self.Es()) + + def energy_spread(self, clean=False): + return weighted_std(self.Es(), self.weightings(), clean) + + def rel_energy_spread(self, clean=False): + return self.energy_spread(clean)/self.energy(clean) + + def z_offset(self, clean=False): + return weighted_mean(self.zs(), self.weightings(), clean) + + def bunch_length(self, clean=False): + return weighted_std(self.zs(), self.weightings(), clean) + + def x_offset(self, clean=False): + return weighted_mean(self.xs(), self.weightings(), clean) + + def beam_size_x(self, clean=False): + return weighted_std(self.xs(), self.weightings(), clean) + + def y_offset(self, clean=False): + return weighted_mean(self.ys(), self.weightings(), clean) + + def beam_size_y(self, clean=False): + return weighted_std(self.ys(), self.weightings(), clean) + + def x_angle(self, clean=False): + return weighted_mean(self.xps(), self.weightings(), clean) + + def divergence_x(self, clean=False): + return weighted_std(self.xps(), self.weightings(), clean) + + def y_angle(self, clean=False): + return weighted_mean(self.yps(), self.weightings(), clean) + + def divergence_y(self, clean=False): + return weighted_std(self.yps(), self.weightings(), clean) + + def ux_offset(self, clean=False): + return weighted_mean(self.uxs(), self.weightings(), clean) + + def uy_offset(self, clean=False): + return weighted_mean(self.uys(), self.weightings(), clean) + + def uz_offset(self, clean=False): + return weighted_mean(self.uzs(), self.weightings(), clean) + + + def geom_emittance_x(self, clean=False): + return np.sqrt(np.linalg.det(weighted_cov(self.xs(), self.xps(), self.weightings(), clean))) + + def geom_emittance_y(self, clean=False): + return np.sqrt(np.linalg.det(weighted_cov(self.ys(), self.yps(), self.weightings(), clean))) + + def norm_emittance_x(self, clean=False): + return np.sqrt(np.linalg.det(weighted_cov(self.xs(), self.uxs()/SI.c, self.weightings(), clean))) + + def norm_emittance_y(self, clean=False): + return np.sqrt(np.linalg.det(weighted_cov(self.ys(), self.uys()/SI.c, self.weightings(), clean))) + + def beta_x(self, clean=False): + covx = weighted_cov(self.xs(), self.xps(), self.weightings(), clean) + return covx[0,0]/np.sqrt(np.linalg.det(covx)) + + def beta_y(self, clean=False): + covy = weighted_cov(self.ys(), self.yps(), self.weightings(), clean) + return covy[0,0]/np.sqrt(np.linalg.det(covy)) + + def alpha_x(self, clean=False): + covx = weighted_cov(self.xs(), self.xps(), self.weightings(), clean) + return -covx[1,0]/np.sqrt(np.linalg.det(covx)) + + def alpha_y(self, clean=False): + covy = weighted_cov(self.ys(), self.yps(), self.weightings(), clean) + return -covy[1,0]/np.sqrt(np.linalg.det(covy)) + + def gamma_x(self, clean=False): + covx = weighted_cov(self.xs(), self.xps(), self.weightings(), clean) + return covx[1,1]/np.sqrt(np.linalg.det(covx)) + + def gamma_y(self, clean=False): + covy = weighted_cov(self.ys(), self.yps(), self.weightings(), clean) + return covy[1,1]/np.sqrt(np.linalg.det(covy)) + + def intrinsic_emittance(self): + covxy = np.cov(self.norm_transverse_vector(), aweights=self.weightings()) + return np.sqrt(np.sqrt(np.linalg.det(covxy))) + + def angular_momentum(self): + covxy = np.cov(self.norm_transverse_vector(), aweights=self.weightings()) + det_covxy_cross = np.linalg.det(covxy[2:4,0:2]) + return np.sign(covxy[3,0]-covxy[2,1])*np.sqrt(np.abs(det_covxy_cross)) + + def eigen_emittance_max(self): + return np.sqrt(self.norm_emittance_x()*self.norm_emittance_y()) + self.angular_momentum() + + def eigen_emittance_min(self): + return np.sqrt(self.norm_emittance_x()*self.norm_emittance_y()) - self.angular_momentum() + + def norm_amplitude_x(self, plasma_density=None, clean=False): + if plasma_density is not None: + beta_x = beta_matched(plasma_density, self.energy()) + alpha_x = 0 + else: + covx = weighted_cov(self.xs(), self.xps(), self.weightings(), clean) + emgx = np.sqrt(np.linalg.det(covx)) + beta_x = covx[0,0]/emgx + alpha_x = -covx[1,0]/emgx + return np.sqrt(self.gamma()/beta_x)*np.sqrt(self.x_offset()**2 + (self.x_offset()*alpha_x + self.x_angle()*beta_x)**2) + + def norm_amplitude_y(self, plasma_density=None, clean=False): + if plasma_density is not None: + beta_y = beta_matched(plasma_density, self.energy()) + alpha_y = 0 + else: + covy = weighted_cov(self.ys(), self.yps(), self.weightings(), clean) + emgy = np.sqrt(np.linalg.det(covy)) + beta_y = covy[0,0]/emgy + alpha_y = -covy[1,0]/emgy + return np.sqrt(self.gamma()/beta_y)*np.sqrt(self.y_offset()**2 + (self.y_offset()*alpha_y + self.y_angle()*beta_y)**2) + + def peak_density(self): # TODO: this is only valid for Gaussian beams. + return (self.charge()/SI.e)/(np.sqrt(2*SI.pi)**3*self.beam_size_x()*self.beam_size_y()*self.bunch_length()) + def peak_current(self): + Is, _ = self.current_profile() + return max(abs(Is)) + + + ## BEAM HALO CLEANING (EXTREME OUTLIERS) + def remove_halo_particles(self, nsigma=20): + xfilter = np.abs(self.xs()-self.x_offset(clean=True)) > nsigma*self.beam_size_x(clean=True) + xpfilter = np.abs(self.xps()-self.x_angle(clean=True)) > nsigma*self.divergence_x(clean=True) + yfilter = np.abs(self.ys()-self.y_offset(clean=True)) > nsigma*self.beam_size_y(clean=True) + ypfilter = np.abs(self.yps()-self.y_angle(clean=True)) > nsigma*self.divergence_y(clean=True) + filter = np.logical_or(np.logical_or(xfilter, xpfilter), np.logical_or(yfilter, ypfilter)) + del self[filter] + + + ## BEAM PROJECTIONS + + def projected_density(self, fcn, bins=None): + if bins is None: + Nbins = int(np.sqrt(len(self)/2)) + bins = np.linspace(min(fcn()), max(fcn()), Nbins) + counts, edges = np.histogram(fcn(), weights=self.qs(), bins=bins) + ctrs = (edges[0:-1] + edges[1:])/2 + proj = counts/np.diff(edges) + return proj, ctrs + + def current_profile(self, bins=None): + return self.projected_density(self.ts, bins=bins) + + def longitudinal_num_density(self, bins=None): + dQdz, zs = self.projected_density(self.zs, bins=bins) + dNdz = dQdz / SI.e / self.charge_sign() + return dNdz, zs + + def energy_spectrum(self, bins=None): + return self.projected_density(self.Es, bins=bins) + + def rel_energy_spectrum(self, nom_energy=None, bins=None): + if nom_energy is None: + nom_energy = self.energy() + return self.projected_density(lambda: self.Es()/nom_energy-1, bins=bins) + + def transverse_profile_x(self, bins=None): + return self.projected_density(self.xs, bins=bins) + + def transverse_profile_y(self, bins=None): + return self.projected_density(self.ys, bins=bins) + + def transverse_profile_xp(self, bins=None): + return self.projected_density(self.xps, bins=bins) + + def transverse_profile_yp(self, bins=None): + return self.projected_density(self.yps, bins=bins) + + ## phase spaces + + def phase_space_density(self, hfcn, vfcn, hbins=None, vbins=None): + self.remove_nans() + if hbins is None: + hbins = round(np.sqrt(len(self))/2) + if vbins is None: + vbins = round(np.sqrt(len(self))/2) + counts, hedges, vedges = np.histogram2d(hfcn(), vfcn(), weights=self.qs(), bins=(hbins, vbins)) + hctrs = (hedges[0:-1] + hedges[1:])/2 + vctrs = (vedges[0:-1] + vedges[1:])/2 + density = (counts/np.diff(vedges)).T/np.diff(hedges) + + #dx = np.diff(hedges) + #dy = np.diff(vedges) + #bin_areas = dx[:, None] * dy[None, :] + #density = counts/bin_areas + #print(np.sum(density*np.diff(vedges)*np.diff(hedges))/self.charge()) + return density, hctrs, vctrs + + def density_lps(self, hbins=None, vbins=None): + return self.phase_space_density(self.zs, self.Es, hbins=hbins, vbins=vbins) + + def density_transverse(self, hbins=None, vbins=None): + return self.phase_space_density(self.xs, self.ys, hbins=hbins, vbins=vbins) + # ================================================== # TODO: Currently does not reproduce the correct peak density for Gaussian beams unless the bin numbers are adjusted manually. From 35425313222583c12ba8205ce1815924d1a54a22 Mon Sep 17 00:00:00 2001 From: Kyrre Ness Sjobak Date: Thu, 3 Apr 2025 16:01:11 +0200 Subject: [PATCH 50/51] Manually undo the moving of plotting functions from commit 74c833294e7492389d81b9888fbeaa044aa628d6 --- abel/classes/beam.py | 159 +++++++++++++++++++++---------------------- 1 file changed, 79 insertions(+), 80 deletions(-) diff --git a/abel/classes/beam.py b/abel/classes/beam.py index 0540596b..a51a273e 100644 --- a/abel/classes/beam.py +++ b/abel/classes/beam.py @@ -1313,6 +1313,85 @@ def Ex_Ey(self, x_box_min, x_box_max, y_box_min, y_box_max, dx, dy, num_z_cells= + ## PLOTTING + def plot_current_profile(self): + dQdt, ts = self.current_profile() + + fig, ax = plt.subplots() + fig.set_figwidth(6) + fig.set_figheight(4) + ax.plot(ts*SI.c*1e6, np.abs(dQdt)/1e3) + ax.set_xlabel('z (um)') + ax.set_ylabel('Beam current (kA)') + + def plot_lps(self): + dQdzdE, zs, Es = self.density_lps() + + fig, ax = plt.subplots() + fig.set_figwidth(8) + fig.set_figheight(5) + + p = ax.pcolor(zs*1e6, Es/1e9, -dQdzdE*1e15, cmap=CONFIG.default_cmap, shading='auto') + ax.set_xlabel('z (um)') + ax.set_ylabel('E (GeV)') + ax.set_title('Longitudinal phase space') + cb = fig.colorbar(p) + cb.ax.set_ylabel('Charge density (pC/um/GeV)') + + def plot_trace_space_x(self): + dQdxdxp, xs, xps = self.phase_space_density(self.xs, self.xps) + + fig, ax = plt.subplots() + fig.set_figwidth(8) + fig.set_figheight(5) + p = ax.pcolor(xs*1e6, xps*1e3, -dQdxdxp*1e3, cmap=CONFIG.default_cmap, shading='auto') + ax.set_xlabel('x (um)') + ax.set_ylabel('x'' (mrad)') + ax.set_title('Horizontal trace space') + cb = fig.colorbar(p) + cb.ax.set_ylabel('Charge density (pC/um/mrad)') + + def plot_trace_space_y(self): + dQdydyp, ys, yps = self.phase_space_density(self.ys, self.yps) + + fig, ax = plt.subplots() + fig.set_figwidth(8) + fig.set_figheight(5) + p = ax.pcolor(ys*1e6, yps*1e3, -dQdydyp*1e3, cmap=CONFIG.default_cmap, shading='auto') + ax.set_xlabel('y (um)') + ax.set_ylabel('y'' (mrad)') + ax.set_title('Vertical trace space') + cb = fig.colorbar(p) + cb.ax.set_ylabel('Charge density (pC/um/mrad)') + + def plot_transverse_profile(self): + dQdxdy, xs, ys = self.phase_space_density(self.xs, self.ys) + + fig, ax = plt.subplots() + fig.set_figwidth(8) + fig.set_figheight(5) + p = ax.pcolor(xs*1e6, ys*1e6, -dQdxdy, cmap=CONFIG.default_cmap, shading='auto') + #p = ax.imshow(-dQdxdy, extent=[xs.min()*1e6, xs.max()*1e6, ys.min()*1e6, ys.max()*1e6], + # origin='lower', cmap=CONFIG.default_cmap, aspect='auto') + ax.set_xlabel('x (um)') + ax.set_ylabel('y (um)') + ax.set_title('Transverse profile') + cb = fig.colorbar(p) + cb.ax.set_ylabel('Charge density (pC/um^2)') + + + # TODO: unfinished! + # def plot_bunch_pattern(self): + + # fig, ax = plt.subplots() + # fig.set_figwidth(6) + # fig.set_figheight(4) + # ax.plot(ts*SI.c*1e6, np.abs(dQdt)/1e3) + # ax.set_xlabel('z (um)') + # ax.set_ylabel('Beam current (kA)') + + + ## CHANGE BEAM def accelerate(self, energy_gain=0, chirp=0, z_offset=0): @@ -1505,86 +1584,6 @@ def apply_betatron_motion(self, L, n0, deltaEs, x0_driver=0, y0_driver=0, radiat else: return Es_final - - - ## PLOTTING - def plot_current_profile(self): - dQdt, ts = self.current_profile() - - fig, ax = plt.subplots() - fig.set_figwidth(6) - fig.set_figheight(4) - ax.plot(ts*SI.c*1e6, np.abs(dQdt)/1e3) - ax.set_xlabel('z (um)') - ax.set_ylabel('Beam current (kA)') - - def plot_lps(self): - dQdzdE, zs, Es = self.density_lps() - - fig, ax = plt.subplots() - fig.set_figwidth(8) - fig.set_figheight(5) - - p = ax.pcolor(zs*1e6, Es/1e9, -dQdzdE*1e15, cmap=CONFIG.default_cmap, shading='auto') - ax.set_xlabel('z (um)') - ax.set_ylabel('E (GeV)') - ax.set_title('Longitudinal phase space') - cb = fig.colorbar(p) - cb.ax.set_ylabel('Charge density (pC/um/GeV)') - - def plot_trace_space_x(self): - dQdxdxp, xs, xps = self.phase_space_density(self.xs, self.xps) - - fig, ax = plt.subplots() - fig.set_figwidth(8) - fig.set_figheight(5) - p = ax.pcolor(xs*1e6, xps*1e3, -dQdxdxp*1e3, cmap=CONFIG.default_cmap, shading='auto') - ax.set_xlabel('x (um)') - ax.set_ylabel('x'' (mrad)') - ax.set_title('Horizontal trace space') - cb = fig.colorbar(p) - cb.ax.set_ylabel('Charge density (pC/um/mrad)') - - def plot_trace_space_y(self): - dQdydyp, ys, yps = self.phase_space_density(self.ys, self.yps) - - fig, ax = plt.subplots() - fig.set_figwidth(8) - fig.set_figheight(5) - p = ax.pcolor(ys*1e6, yps*1e3, -dQdydyp*1e3, cmap=CONFIG.default_cmap, shading='auto') - ax.set_xlabel('y (um)') - ax.set_ylabel('y'' (mrad)') - ax.set_title('Vertical trace space') - cb = fig.colorbar(p) - cb.ax.set_ylabel('Charge density (pC/um/mrad)') - - def plot_transverse_profile(self): - dQdxdy, xs, ys = self.phase_space_density(self.xs, self.ys) - - fig, ax = plt.subplots() - fig.set_figwidth(8) - fig.set_figheight(5) - p = ax.pcolor(xs*1e6, ys*1e6, -dQdxdy, cmap=CONFIG.default_cmap, shading='auto') - #p = ax.imshow(-dQdxdy, extent=[xs.min()*1e6, xs.max()*1e6, ys.min()*1e6, ys.max()*1e6], - # origin='lower', cmap=CONFIG.default_cmap, aspect='auto') - ax.set_xlabel('x (um)') - ax.set_ylabel('y (um)') - ax.set_title('Transverse profile') - cb = fig.colorbar(p) - cb.ax.set_ylabel('Charge density (pC/um^2)') - - - # TODO: unfinished! - # def plot_bunch_pattern(self): - - # fig, ax = plt.subplots() - # fig.set_figwidth(6) - # fig.set_figheight(4) - # ax.plot(ts*SI.c*1e6, np.abs(dQdt)/1e3) - # ax.set_xlabel('z (um)') - # ax.set_ylabel('Beam current (kA)') - - ## SAVE AND LOAD BEAM From 95de216b259bb5e62c79d1b3e1feab7c8b921dfb Mon Sep 17 00:00:00 2001 From: Ben Chen Date: Thu, 3 Apr 2025 16:46:09 +0200 Subject: [PATCH 51/51] Changed beam reference file path in test_SourceFromFile2Beam() using os.sep. --- tests/test_sources.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/test_sources.py b/tests/test_sources.py index 77de8df7..c7fe64ae 100644 --- a/tests/test_sources.py +++ b/tests/test_sources.py @@ -22,6 +22,7 @@ import pytest from abel import * +import os def check_beam_source_parameters(beam, source): assert np.allclose(beam.particle_mass, SI.m_e, rtol=1e-05, atol=1e-08) @@ -183,7 +184,7 @@ def test_SourceCapsule2Beam(): def test_SourceFromFile2Beam(): "Check that ``SourceFromFile`` retuns returns the same ``Beam`` as the input ``Beam``." - beam_file = 'tests/data/test_StagePrtclTransWakeInstability_beamline/test_baseline_linac/shot_000/beam_003_00048.558626.h5' + beam_file = 'tests' + os.sep + 'data' + os.sep + 'test_StagePrtclTransWakeInstability_beamline' + os.sep + 'test_baseline_linac' + os.sep + 'shot_000' + os.sep + 'beam_003_00048.558626.h5' source = SourceFromFile() source.file = beam_file @@ -193,10 +194,10 @@ def test_SourceFromFile2Beam(): # Trigger exception for when a file does not exist with pytest.raises(FileNotFoundError): - file = 'tests/data/test_StagePrtclTransWakeInstability_beamline/test_baseline_linac/blabla.h5' + file = 'tests' + os.sep + 'data' + os.sep + 'test_StagePrtclTransWakeInstability_beamline' + os.sep + 'test_baseline_linac' + os.sep + 'blabla.h5' source = SourceFromFile(file=file) with pytest.raises(FileNotFoundError): - file = 'tests/data/test_StagePrtclTransWakeInstability_beamline/test_baseline_linac/shot_000/blabla.h5' + file = 'tests' + os.sep + 'data' + os.sep + 'test_StagePrtclTransWakeInstability_beamline' + os.sep + 'test_baseline_linac' + os.sep + 'shot_000' + os.sep + 'blabla.h5' source = SourceFromFile() source.file = file

n@fUfn8jcTYb%>h=$z?PBV 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 z zr(^eonsLPAGPYNb8xh;M^F7X$F|;G<0M=(4$9xpt->iO)VTChVw_0#1u z+Ay`QcpDFY5jL|ERkZ$Di1RwHm)4DBBJq=71bB3_QQi5~KV%1EaGlN)yZz!vto6Gx zSmSCilAGtNNGu9O?jtgzEfPscAieLJiCG+?{AKdGN(kd`g(PXk1BLjt|AzBMZyGLN zZMM8{Gz|$EN*t=>Ohu-5?V`BF((t<9KGneo?Kr;fO0&}8HpHbkV8Q3zj>n`!qXh1> zAs+jlgWgHiNUPqLW8-KI_Pd^%VsNJ#)dfVR7(#uHQ+EqLpaRj%Z4Q zfO5oC(%|L@emlscm`{_k0v(B*91xu;M>l!y2*ycQ;N|)G+j4c~c%bxgulIBPYlqUHESoB3ry)^b#9XI*kay&Q+!0($72e5<&TRxpXGuvVSNV8@AYg{9_5`n09Tt z^P&VBcxCLbW6DQ;Q+2wTJO#+HxBgP?>kd>BT_be5t_wTTlO0i=>cWb1DNGf5P*1