From 8ab9a913ebc767e31707377f9fd96cbf48f0aad3 Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Wed, 27 Nov 2024 19:35:33 -0800 Subject: [PATCH 1/5] Update RFCavity.H and add examples. --- examples/rfcavity/input_rfcavity_multiple.in | 120 ++++++++++++++++ examples/rfcavity/run_rfcavity_multiple.py | 144 +++++++++++++++++++ src/particles/elements/RFCavity.H | 2 + 3 files changed, 266 insertions(+) create mode 100644 examples/rfcavity/input_rfcavity_multiple.in create mode 100755 examples/rfcavity/run_rfcavity_multiple.py diff --git a/examples/rfcavity/input_rfcavity_multiple.in b/examples/rfcavity/input_rfcavity_multiple.in new file mode 100644 index 000000000..0ccbc5850 --- /dev/null +++ b/examples/rfcavity/input_rfcavity_multiple.in @@ -0,0 +1,120 @@ +############################################################################### +# Particle Beam(s) +############################################################################### +beam.npart = 10000 # outside tests, use 1e5 or more +beam.units = static +beam.kin_energy = 230 +beam.charge = 1.0e-10 +beam.particle = electron +beam.distribution = waterbag +beam.lambdaX = 0.352498964601e-3 +beam.lambdaY = 0.207443478142e-3 +beam.lambdaT = 0.70399950746e-4 +beam.lambdaPx = 5.161852770e-6 +beam.lambdaPy = 9.163582894e-6 +beam.lambdaPt = 0.260528852031e-3 +beam.muxpx = 0.5712386101751441 +beam.muypy = -0.514495755427526 +beam.mutpt = -5.05773e-10 + + +############################################################################### +# Beamline: lattice elements and segments +############################################################################### +lattice.elements = monitor dr1 dr2 rf dr2 dr2 rf2 monitor + +monitor.type = beam_monitor +monitor.backend = h5 + +dr1.type = drift +dr1.ds = 0.4 +dr1.nslice = 1 + +dr2.type = drift +dr2.ds = 0.032997 +dr1.nslice = 1 + +rf.type = rfcavity +rf.ds = 1.31879807 +rf.escale = 62.0 +rf.freq = 1.3e9 +rf.phase = 85.5 +rf.mapsteps = 4 +rf.nslice = 100 +rf.cos_coefficients = \ + 0.1644024074311037 \ + -0.1324009958969339 \ + 4.3443060026047219e-002 \ + 8.5602654094946495e-002 \ + -0.2433578169042885 \ + 0.5297150596779437 \ + 0.7164884680963959 \ + -5.2579522442877296e-003 \ + -5.5025369142193678e-002 \ + 4.6845673335028933e-002 \ + -2.3279346335638568e-002 \ + 4.0800777539657775e-003 \ + 4.1378326533752169e-003 \ + -2.5040533340490805e-003 \ + -4.0654981400000964e-003 \ + 9.6630592067498289e-003 \ + -8.5275895985990214e-003 \ + -5.8078747006425020e-002 \ + -2.4044337836660403e-002 \ + 1.0968240064697212e-002 \ + -3.4461179858301418e-003 \ + -8.1201564869443749e-004 \ + 2.1438992904959380e-003 \ + -1.4997753525697276e-003 \ + 1.8685171825676386e-004 +rf.sin_coefficients = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ + 0 0 0 0 0 0 0 + +rf2.type = rfcavity +rf2.ds = 1.31879807 +rf2.escale = 62.0 +rf2.freq = 1.3e9 +rf2.phase = 85.5 +rf2.mapsteps = 4 +rf2.nslice = 100 +rf2.cos_coefficients = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ + 0 0 0 0 0 0 0 +rf2.sin_coefficients = \ + 0.1644024074311037 \ + -0.1324009958969339 \ + 4.3443060026047219e-002 \ + 8.5602654094946495e-002 \ + -0.2433578169042885 \ + 0.5297150596779437 \ + 0.7164884680963959 \ + -5.2579522442877296e-003 \ + -5.5025369142193678e-002 \ + 4.6845673335028933e-002 \ + -2.3279346335638568e-002 \ + 4.0800777539657775e-003 \ + 4.1378326533752169e-003 \ + -2.5040533340490805e-003 \ + -4.0654981400000964e-003 \ + 9.6630592067498289e-003 \ + -8.5275895985990214e-003 \ + -5.8078747006425020e-002 \ + -2.4044337836660403e-002 \ + 1.0968240064697212e-002 \ + -3.4461179858301418e-003 \ + -8.1201564869443749e-004 \ + 2.1438992904959380e-003 \ + -1.4997753525697276e-003 \ + 1.8685171825676386e-004 + + +############################################################################### +# Algorithms +############################################################################### +algo.particle_shape = 2 +algo.space_charge = false + + +############################################################################### +# Diagnostics +############################################################################### +diag.slice_step_diagnostics = true diff --git a/examples/rfcavity/run_rfcavity_multiple.py b/examples/rfcavity/run_rfcavity_multiple.py new file mode 100755 index 000000000..69911fd26 --- /dev/null +++ b/examples/rfcavity/run_rfcavity_multiple.py @@ -0,0 +1,144 @@ +#!/usr/bin/env python3 +# +# Copyright 2022-2023 ImpactX contributors +# Authors: Marco Garten, Axel Huebl, Chad Mitchell +# License: BSD-3-Clause-LBNL +# +# -*- coding: utf-8 -*- + +from impactx import ImpactX, distribution, elements + +sim = ImpactX() + +# set numerical parameters and IO control +sim.particle_shape = 2 # B-spline order +sim.space_charge = False +# sim.diagnostics = False # benchmarking +sim.slice_step_diagnostics = False + +# domain decomposition & space charge mesh +sim.init_grids() + +# load a 230 MeV electron beam with an initial +# unnormalized rms emittance of 1 mm-mrad in all +# three phase planes +kin_energy_MeV = 230.0 # reference energy +bunch_charge_C = 1.0e-10 # used with space charge +npart = 10000 # number of macro particles (outside tests, use 1e5 or more) + +# reference particle +ref = sim.particle_container().ref_particle() +ref.set_charge_qe(-1.0).set_mass_MeV(0.510998950).set_kin_energy_MeV(kin_energy_MeV) + +# particle bunch +distr = distribution.Waterbag( + lambdaX=0.352498964601e-3, + lambdaY=0.207443478142e-3, + lambdaT=0.70399950746e-4, + lambdaPx=5.161852770e-6, + lambdaPy=9.163582894e-6, + lambdaPt=0.260528852031e-3, + muxpx=0.5712386101751441, + muypy=-0.514495755427526, + mutpt=-5.05773e-10, +) +sim.add_particles(bunch_charge_C, distr, npart) + +# design the accelerator lattice + +# Drift elements +dr1 = elements.Drift(name="dr1", ds=0.4, nslice=1) +dr2 = elements.Drift(name="dr2", ds=0.032997, nslice=1) +# RF cavity element +rf = elements.RFCavity( + name="rf", + ds=1.31879807, + escale=62.0, + freq=1.3e9, + phase=85.5, + cos_coefficients=[ + 0.1644024074311037, + -0.1324009958969339, + 4.3443060026047219e-002, + 8.5602654094946495e-002, + -0.2433578169042885, + 0.5297150596779437, + 0.7164884680963959, + -5.2579522442877296e-003, + -5.5025369142193678e-002, + 4.6845673335028933e-002, + -2.3279346335638568e-002, + 4.0800777539657775e-003, + 4.1378326533752169e-003, + -2.5040533340490805e-003, + -4.0654981400000964e-003, + 9.6630592067498289e-003, + -8.5275895985990214e-003, + -5.8078747006425020e-002, + -2.4044337836660403e-002, + 1.0968240064697212e-002, + -3.4461179858301418e-003, + -8.1201564869443749e-004, + 2.1438992904959380e-003, + -1.4997753525697276e-003, + 1.8685171825676386e-004, + ], + sin_coefficients=[ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ], + mapsteps=100, + nslice=4, +) + +# add beam diagnostics +monitor = elements.BeamMonitor("monitor", backend="h5") + +sim.lattice.extend( + [ + monitor, + dr1, + dr2, + rf, + dr2, + dr2, + rf, + dr2, + dr2, + rf, + dr2, + dr2, + rf, + dr2, + monitor, + ] +) + +# run simulation +sim.track_particles() + +# clean shutdown +sim.finalize() diff --git a/src/particles/elements/RFCavity.H b/src/particles/elements/RFCavity.H index 10e598381..b56ede054 100644 --- a/src/particles/elements/RFCavity.H +++ b/src/particles/elements/RFCavity.H @@ -148,6 +148,8 @@ namespace RFCavityData { // next created RF cavity has another id for its data RFCavityData::next_id++; + // update m_id, which did not appear to be previously set + m_id = RFCavityData::next_id; // validate sin and cos coefficients are the same length m_ncoef = int(cos_coef.size()); From ea1fc5d0cd6c8594d27feeb1360800f014b27f88 Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Wed, 27 Nov 2024 19:52:09 -0800 Subject: [PATCH 2/5] Update example files. --- examples/rfcavity/README.rst | 51 ++++++++++ .../rfcavity/analysis_rfcavity_distinct.py | 97 +++++++++++++++++++ ...multiple.in => input_rfcavity_distinct.in} | 0 ...y_multiple.py => run_rfcavity_distinct.py} | 95 ++++++------------ 4 files changed, 178 insertions(+), 65 deletions(-) create mode 100755 examples/rfcavity/analysis_rfcavity_distinct.py rename examples/rfcavity/{input_rfcavity_multiple.in => input_rfcavity_distinct.in} (100%) rename examples/rfcavity/{run_rfcavity_multiple.py => run_rfcavity_distinct.py} (58%) diff --git a/examples/rfcavity/README.rst b/examples/rfcavity/README.rst index f5bc10227..6e1792061 100644 --- a/examples/rfcavity/README.rst +++ b/examples/rfcavity/README.rst @@ -52,3 +52,54 @@ We run the following script to analyze correctness: .. literalinclude:: analysis_rfcavity.py :language: python3 :caption: You can copy this file from ``examples/rfcavity/analysis_rfcavity.py``. + + +.. _examples-rfcavity-distinct: + +Acceleration by Multiple Distinct RF Cavities +=============================================== + +Beam accelerated through a pair of 2 distinct RF cavities (without space charge). + +We use a 230 MeV electron beam with initial normalized rms emittance of 1 um. + +The first RF cavity coincides with the RF cavity design used in ``examples-rfcavity``. + +In this test, the initial and final values of :math:`\lambda_x`, :math:`\lambda_y`, :math:`\lambda_t`, :math:`\epsilon_x`, :math:`\epsilon_y`, and :math:`\epsilon_> + + +Run +--- + +This example can be run **either** as: + +* **Python** script: ``python3 run_rfcavity_distinct.py`` or +* ImpactX **executable** using an input file: ``impactx input_rfcavity_distinct.in`` + +For `MPI-parallel `__ runs, prefix these lines with ``mpiexec -n 4 ...`` or ``srun -n 4 ...``, depending on the system. + +.. tab-set:: + + .. tab-item:: Python: Script + + .. literalinclude:: run_rfcavity_distinct.py + :language: python3 + :caption: You can copy this file from ``examples/rfcavity/run_rfcavity_distinct.py``. + + .. tab-item:: Executable: Input File + + .. literalinclude:: input_rfcavity_distinct.in + :language: ini + :caption: You can copy this file from ``examples/rfcavity/input_rfcavity_distinct.in``. + + +Analyze +------- + +We run the following script to analyze correctness: + +.. dropdown:: Script ``analysis_rfcavity_distinct.py`` + + .. literalinclude:: analysis_rfcavity_distinct.py + :language: python3 + :caption: You can copy this file from ``examples/rfcavity/analysis_rfcavity_distinct.py``. diff --git a/examples/rfcavity/analysis_rfcavity_distinct.py b/examples/rfcavity/analysis_rfcavity_distinct.py new file mode 100755 index 000000000..88c62c32c --- /dev/null +++ b/examples/rfcavity/analysis_rfcavity_distinct.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python3 +# +# Copyright 2022-2023 ImpactX contributors +# Authors: Axel Huebl, Chad Mitchell +# License: BSD-3-Clause-LBNL +# + +import numpy as np +import openpmd_api as io +from scipy.stats import moment + + +def get_moments(beam): + """Calculate standard deviations of beam position & momenta + and emittance values + + Returns + ------- + sigx, sigy, sigt, emittance_x, emittance_y, emittance_t + """ + sigx = moment(beam["position_x"], moment=2) ** 0.5 # variance -> std dev. + sigpx = moment(beam["momentum_x"], moment=2) ** 0.5 + sigy = moment(beam["position_y"], moment=2) ** 0.5 + sigpy = moment(beam["momentum_y"], moment=2) ** 0.5 + sigt = moment(beam["position_t"], moment=2) ** 0.5 + sigpt = moment(beam["momentum_t"], moment=2) ** 0.5 + + epstrms = beam.cov(ddof=0) + emittance_x = (sigx**2 * sigpx**2 - epstrms["position_x"]["momentum_x"] ** 2) ** 0.5 + emittance_y = (sigy**2 * sigpy**2 - epstrms["position_y"]["momentum_y"] ** 2) ** 0.5 + emittance_t = (sigt**2 * sigpt**2 - epstrms["position_t"]["momentum_t"] ** 2) ** 0.5 + + return (sigx, sigy, sigt, emittance_x, emittance_y, emittance_t) + + +# initial/final beam +series = io.Series("diags/openPMD/monitor.h5", io.Access.read_only) +last_step = list(series.iterations)[-1] +initial = series.iterations[1].particles["beam"].to_df() +final = series.iterations[last_step].particles["beam"].to_df() + +# compare number of particles +num_particles = 10000 +assert num_particles == len(initial) +assert num_particles == len(final) + +print("Initial Beam:") +sigx, sigy, sigt, emittance_x, emittance_y, emittance_t = get_moments(initial) +print(f" sigx={sigx:e} sigy={sigy:e} sigt={sigt:e}") +print( + f" emittance_x={emittance_x:e} emittance_y={emittance_y:e} emittance_t={emittance_t:e}" +) + +atol = 0.0 # ignored +rtol = 1.5 * num_particles**-0.5 # from random sampling of a smooth distribution +print(f" rtol={rtol} (ignored: atol~={atol})") + +assert np.allclose( + [sigx, sigy, sigt, emittance_x, emittance_y, emittance_t], + [ + 4.29466150443e-4, + 2.41918588389e-4, + 7.0399951912e-5, + 2.21684103818e-9, + 2.21684103818e-9, + 1.83412186547e-8, + ], + rtol=rtol, + atol=atol, +) + + +print("") +print("Final Beam:") +sigx, sigy, sigt, emittance_x, emittance_y, emittance_t = get_moments(final) +print(f" sigx={sigx:e} sigy={sigy:e} sigt={sigt:e}") +print( + f" emittance_x={emittance_x:e} emittance_y={emittance_y:e} emittance_t={emittance_t:e}" +) + +atol = 0.0 # ignored +rtol = 1.5 * num_particles**-0.5 # from random sampling of a smooth distribution +print(f" rtol={rtol} (ignored: atol~={atol})") + +assert np.allclose( + [sigx, sigy, sigt, emittance_x, emittance_y, emittance_t], + [ + 3.52596000000e-4, + 2.41775000000e-4, + 7.0417917357e-5, + 1.70893497973e-9, + 1.70893497973e-9, + 1.413901564889e-8, + ], + rtol=rtol, + atol=atol, +) diff --git a/examples/rfcavity/input_rfcavity_multiple.in b/examples/rfcavity/input_rfcavity_distinct.in similarity index 100% rename from examples/rfcavity/input_rfcavity_multiple.in rename to examples/rfcavity/input_rfcavity_distinct.in diff --git a/examples/rfcavity/run_rfcavity_multiple.py b/examples/rfcavity/run_rfcavity_distinct.py similarity index 58% rename from examples/rfcavity/run_rfcavity_multiple.py rename to examples/rfcavity/run_rfcavity_distinct.py index 69911fd26..cefb183ba 100755 --- a/examples/rfcavity/run_rfcavity_multiple.py +++ b/examples/rfcavity/run_rfcavity_distinct.py @@ -14,7 +14,7 @@ sim.particle_shape = 2 # B-spline order sim.space_charge = False # sim.diagnostics = False # benchmarking -sim.slice_step_diagnostics = False +sim.slice_step_diagnostics = True # domain decomposition & space charge mesh sim.init_grids() @@ -46,6 +46,18 @@ # design the accelerator lattice +RF_cos_coefs = [0.1644024074311037, -0.1324009958969339, 4.3443060026047219e-002, +8.5602654094946495e-002, -0.2433578169042885, 0.5297150596779437, 0.7164884680963959, +-5.2579522442877296e-003, -5.5025369142193678e-002, 4.6845673335028933e-002, +-2.3279346335638568e-002, 4.0800777539657775e-003, 4.1378326533752169e-003, +-2.5040533340490805e-003, -4.0654981400000964e-003, 9.6630592067498289e-003, +-8.5275895985990214e-003, -5.8078747006425020e-002, -2.4044337836660403e-002, +1.0968240064697212e-002, -3.4461179858301418e-003, -8.1201564869443749e-004, +2.1438992904959380e-003, -1.4997753525697276e-003, 1.8685171825676386e-004] + +RF_sin_coefs = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0] + # Drift elements dr1 = elements.Drift(name="dr1", ds=0.4, nslice=1) dr2 = elements.Drift(name="dr2", ds=0.032997, nslice=1) @@ -56,64 +68,24 @@ escale=62.0, freq=1.3e9, phase=85.5, - cos_coefficients=[ - 0.1644024074311037, - -0.1324009958969339, - 4.3443060026047219e-002, - 8.5602654094946495e-002, - -0.2433578169042885, - 0.5297150596779437, - 0.7164884680963959, - -5.2579522442877296e-003, - -5.5025369142193678e-002, - 4.6845673335028933e-002, - -2.3279346335638568e-002, - 4.0800777539657775e-003, - 4.1378326533752169e-003, - -2.5040533340490805e-003, - -4.0654981400000964e-003, - 9.6630592067498289e-003, - -8.5275895985990214e-003, - -5.8078747006425020e-002, - -2.4044337836660403e-002, - 1.0968240064697212e-002, - -3.4461179858301418e-003, - -8.1201564869443749e-004, - 2.1438992904959380e-003, - -1.4997753525697276e-003, - 1.8685171825676386e-004, - ], - sin_coefficients=[ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - ], - mapsteps=100, - nslice=4, + cos_coefficients=RF_cos_coefs, + sin_coefficients=RF_sin_coefs, + mapsteps=4, + nslice=100, +) +rf2 = elements.RFCavity( + name="rf2", + ds=1.31879807, + escale=62.0, + freq=1.3e9, + phase=85.5, + cos_coefficients=RF_sin_coefs, + sin_coefficients=RF_cos_coefs, + mapsteps=4, + nslice=100, ) + # add beam diagnostics monitor = elements.BeamMonitor("monitor", backend="h5") @@ -125,14 +97,7 @@ rf, dr2, dr2, - rf, - dr2, - dr2, - rf, - dr2, - dr2, - rf, - dr2, + rf2, monitor, ] ) From 639f495f454e611af219ef3ca3e0713cafb15396 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 03:52:38 +0000 Subject: [PATCH 3/5] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- examples/rfcavity/run_rfcavity_distinct.py | 68 ++++++++++++++++++---- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/examples/rfcavity/run_rfcavity_distinct.py b/examples/rfcavity/run_rfcavity_distinct.py index cefb183ba..e3c447170 100755 --- a/examples/rfcavity/run_rfcavity_distinct.py +++ b/examples/rfcavity/run_rfcavity_distinct.py @@ -46,17 +46,61 @@ # design the accelerator lattice -RF_cos_coefs = [0.1644024074311037, -0.1324009958969339, 4.3443060026047219e-002, -8.5602654094946495e-002, -0.2433578169042885, 0.5297150596779437, 0.7164884680963959, --5.2579522442877296e-003, -5.5025369142193678e-002, 4.6845673335028933e-002, --2.3279346335638568e-002, 4.0800777539657775e-003, 4.1378326533752169e-003, --2.5040533340490805e-003, -4.0654981400000964e-003, 9.6630592067498289e-003, --8.5275895985990214e-003, -5.8078747006425020e-002, -2.4044337836660403e-002, -1.0968240064697212e-002, -3.4461179858301418e-003, -8.1201564869443749e-004, -2.1438992904959380e-003, -1.4997753525697276e-003, 1.8685171825676386e-004] - -RF_sin_coefs = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -0, 0, 0, 0, 0, 0, 0, 0] +RF_cos_coefs = [ + 0.1644024074311037, + -0.1324009958969339, + 4.3443060026047219e-002, + 8.5602654094946495e-002, + -0.2433578169042885, + 0.5297150596779437, + 0.7164884680963959, + -5.2579522442877296e-003, + -5.5025369142193678e-002, + 4.6845673335028933e-002, + -2.3279346335638568e-002, + 4.0800777539657775e-003, + 4.1378326533752169e-003, + -2.5040533340490805e-003, + -4.0654981400000964e-003, + 9.6630592067498289e-003, + -8.5275895985990214e-003, + -5.8078747006425020e-002, + -2.4044337836660403e-002, + 1.0968240064697212e-002, + -3.4461179858301418e-003, + -8.1201564869443749e-004, + 2.1438992904959380e-003, + -1.4997753525697276e-003, + 1.8685171825676386e-004, +] + +RF_sin_coefs = [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +] # Drift elements dr1 = elements.Drift(name="dr1", ds=0.4, nslice=1) @@ -81,7 +125,7 @@ phase=85.5, cos_coefficients=RF_sin_coefs, sin_coefficients=RF_cos_coefs, - mapsteps=4, + mapsteps=4, nslice=100, ) From eeeab9a0c36a6507698f81bebcea366a81bd4621 Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Thu, 28 Nov 2024 11:43:18 -0800 Subject: [PATCH 4/5] Implement a simpler solution. --- src/particles/elements/RFCavity.H | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/particles/elements/RFCavity.H b/src/particles/elements/RFCavity.H index b56ede054..fd57083a7 100644 --- a/src/particles/elements/RFCavity.H +++ b/src/particles/elements/RFCavity.H @@ -144,12 +144,10 @@ namespace RFCavityData : Named(name), Thick(ds, nslice), Alignment(dx, dy, rotation_degree), - m_escale(escale), m_freq(freq), m_phase(phase), m_mapsteps(mapsteps) + m_escale(escale), m_freq(freq), m_phase(phase), m_mapsteps(mapsteps), m_id(RFCavityData::next_id) { // next created RF cavity has another id for its data RFCavityData::next_id++; - // update m_id, which did not appear to be previously set - m_id = RFCavityData::next_id; // validate sin and cos coefficients are the same length m_ncoef = int(cos_coef.size()); From b6ff25fd69b38af1893cfd2e8bdc1b77d2759d16 Mon Sep 17 00:00:00 2001 From: Chad Mitchell Date: Thu, 28 Nov 2024 11:53:39 -0800 Subject: [PATCH 5/5] Detailed example as a separate PR. --- examples/rfcavity/README.rst | 51 ------ .../rfcavity/analysis_rfcavity_distinct.py | 97 ----------- examples/rfcavity/input_rfcavity_distinct.in | 120 -------------- examples/rfcavity/run_rfcavity_distinct.py | 153 ------------------ 4 files changed, 421 deletions(-) delete mode 100755 examples/rfcavity/analysis_rfcavity_distinct.py delete mode 100644 examples/rfcavity/input_rfcavity_distinct.in delete mode 100755 examples/rfcavity/run_rfcavity_distinct.py diff --git a/examples/rfcavity/README.rst b/examples/rfcavity/README.rst index 6e1792061..f5bc10227 100644 --- a/examples/rfcavity/README.rst +++ b/examples/rfcavity/README.rst @@ -52,54 +52,3 @@ We run the following script to analyze correctness: .. literalinclude:: analysis_rfcavity.py :language: python3 :caption: You can copy this file from ``examples/rfcavity/analysis_rfcavity.py``. - - -.. _examples-rfcavity-distinct: - -Acceleration by Multiple Distinct RF Cavities -=============================================== - -Beam accelerated through a pair of 2 distinct RF cavities (without space charge). - -We use a 230 MeV electron beam with initial normalized rms emittance of 1 um. - -The first RF cavity coincides with the RF cavity design used in ``examples-rfcavity``. - -In this test, the initial and final values of :math:`\lambda_x`, :math:`\lambda_y`, :math:`\lambda_t`, :math:`\epsilon_x`, :math:`\epsilon_y`, and :math:`\epsilon_> - - -Run ---- - -This example can be run **either** as: - -* **Python** script: ``python3 run_rfcavity_distinct.py`` or -* ImpactX **executable** using an input file: ``impactx input_rfcavity_distinct.in`` - -For `MPI-parallel `__ runs, prefix these lines with ``mpiexec -n 4 ...`` or ``srun -n 4 ...``, depending on the system. - -.. tab-set:: - - .. tab-item:: Python: Script - - .. literalinclude:: run_rfcavity_distinct.py - :language: python3 - :caption: You can copy this file from ``examples/rfcavity/run_rfcavity_distinct.py``. - - .. tab-item:: Executable: Input File - - .. literalinclude:: input_rfcavity_distinct.in - :language: ini - :caption: You can copy this file from ``examples/rfcavity/input_rfcavity_distinct.in``. - - -Analyze -------- - -We run the following script to analyze correctness: - -.. dropdown:: Script ``analysis_rfcavity_distinct.py`` - - .. literalinclude:: analysis_rfcavity_distinct.py - :language: python3 - :caption: You can copy this file from ``examples/rfcavity/analysis_rfcavity_distinct.py``. diff --git a/examples/rfcavity/analysis_rfcavity_distinct.py b/examples/rfcavity/analysis_rfcavity_distinct.py deleted file mode 100755 index 88c62c32c..000000000 --- a/examples/rfcavity/analysis_rfcavity_distinct.py +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2022-2023 ImpactX contributors -# Authors: Axel Huebl, Chad Mitchell -# License: BSD-3-Clause-LBNL -# - -import numpy as np -import openpmd_api as io -from scipy.stats import moment - - -def get_moments(beam): - """Calculate standard deviations of beam position & momenta - and emittance values - - Returns - ------- - sigx, sigy, sigt, emittance_x, emittance_y, emittance_t - """ - sigx = moment(beam["position_x"], moment=2) ** 0.5 # variance -> std dev. - sigpx = moment(beam["momentum_x"], moment=2) ** 0.5 - sigy = moment(beam["position_y"], moment=2) ** 0.5 - sigpy = moment(beam["momentum_y"], moment=2) ** 0.5 - sigt = moment(beam["position_t"], moment=2) ** 0.5 - sigpt = moment(beam["momentum_t"], moment=2) ** 0.5 - - epstrms = beam.cov(ddof=0) - emittance_x = (sigx**2 * sigpx**2 - epstrms["position_x"]["momentum_x"] ** 2) ** 0.5 - emittance_y = (sigy**2 * sigpy**2 - epstrms["position_y"]["momentum_y"] ** 2) ** 0.5 - emittance_t = (sigt**2 * sigpt**2 - epstrms["position_t"]["momentum_t"] ** 2) ** 0.5 - - return (sigx, sigy, sigt, emittance_x, emittance_y, emittance_t) - - -# initial/final beam -series = io.Series("diags/openPMD/monitor.h5", io.Access.read_only) -last_step = list(series.iterations)[-1] -initial = series.iterations[1].particles["beam"].to_df() -final = series.iterations[last_step].particles["beam"].to_df() - -# compare number of particles -num_particles = 10000 -assert num_particles == len(initial) -assert num_particles == len(final) - -print("Initial Beam:") -sigx, sigy, sigt, emittance_x, emittance_y, emittance_t = get_moments(initial) -print(f" sigx={sigx:e} sigy={sigy:e} sigt={sigt:e}") -print( - f" emittance_x={emittance_x:e} emittance_y={emittance_y:e} emittance_t={emittance_t:e}" -) - -atol = 0.0 # ignored -rtol = 1.5 * num_particles**-0.5 # from random sampling of a smooth distribution -print(f" rtol={rtol} (ignored: atol~={atol})") - -assert np.allclose( - [sigx, sigy, sigt, emittance_x, emittance_y, emittance_t], - [ - 4.29466150443e-4, - 2.41918588389e-4, - 7.0399951912e-5, - 2.21684103818e-9, - 2.21684103818e-9, - 1.83412186547e-8, - ], - rtol=rtol, - atol=atol, -) - - -print("") -print("Final Beam:") -sigx, sigy, sigt, emittance_x, emittance_y, emittance_t = get_moments(final) -print(f" sigx={sigx:e} sigy={sigy:e} sigt={sigt:e}") -print( - f" emittance_x={emittance_x:e} emittance_y={emittance_y:e} emittance_t={emittance_t:e}" -) - -atol = 0.0 # ignored -rtol = 1.5 * num_particles**-0.5 # from random sampling of a smooth distribution -print(f" rtol={rtol} (ignored: atol~={atol})") - -assert np.allclose( - [sigx, sigy, sigt, emittance_x, emittance_y, emittance_t], - [ - 3.52596000000e-4, - 2.41775000000e-4, - 7.0417917357e-5, - 1.70893497973e-9, - 1.70893497973e-9, - 1.413901564889e-8, - ], - rtol=rtol, - atol=atol, -) diff --git a/examples/rfcavity/input_rfcavity_distinct.in b/examples/rfcavity/input_rfcavity_distinct.in deleted file mode 100644 index 0ccbc5850..000000000 --- a/examples/rfcavity/input_rfcavity_distinct.in +++ /dev/null @@ -1,120 +0,0 @@ -############################################################################### -# Particle Beam(s) -############################################################################### -beam.npart = 10000 # outside tests, use 1e5 or more -beam.units = static -beam.kin_energy = 230 -beam.charge = 1.0e-10 -beam.particle = electron -beam.distribution = waterbag -beam.lambdaX = 0.352498964601e-3 -beam.lambdaY = 0.207443478142e-3 -beam.lambdaT = 0.70399950746e-4 -beam.lambdaPx = 5.161852770e-6 -beam.lambdaPy = 9.163582894e-6 -beam.lambdaPt = 0.260528852031e-3 -beam.muxpx = 0.5712386101751441 -beam.muypy = -0.514495755427526 -beam.mutpt = -5.05773e-10 - - -############################################################################### -# Beamline: lattice elements and segments -############################################################################### -lattice.elements = monitor dr1 dr2 rf dr2 dr2 rf2 monitor - -monitor.type = beam_monitor -monitor.backend = h5 - -dr1.type = drift -dr1.ds = 0.4 -dr1.nslice = 1 - -dr2.type = drift -dr2.ds = 0.032997 -dr1.nslice = 1 - -rf.type = rfcavity -rf.ds = 1.31879807 -rf.escale = 62.0 -rf.freq = 1.3e9 -rf.phase = 85.5 -rf.mapsteps = 4 -rf.nslice = 100 -rf.cos_coefficients = \ - 0.1644024074311037 \ - -0.1324009958969339 \ - 4.3443060026047219e-002 \ - 8.5602654094946495e-002 \ - -0.2433578169042885 \ - 0.5297150596779437 \ - 0.7164884680963959 \ - -5.2579522442877296e-003 \ - -5.5025369142193678e-002 \ - 4.6845673335028933e-002 \ - -2.3279346335638568e-002 \ - 4.0800777539657775e-003 \ - 4.1378326533752169e-003 \ - -2.5040533340490805e-003 \ - -4.0654981400000964e-003 \ - 9.6630592067498289e-003 \ - -8.5275895985990214e-003 \ - -5.8078747006425020e-002 \ - -2.4044337836660403e-002 \ - 1.0968240064697212e-002 \ - -3.4461179858301418e-003 \ - -8.1201564869443749e-004 \ - 2.1438992904959380e-003 \ - -1.4997753525697276e-003 \ - 1.8685171825676386e-004 -rf.sin_coefficients = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ - 0 0 0 0 0 0 0 - -rf2.type = rfcavity -rf2.ds = 1.31879807 -rf2.escale = 62.0 -rf2.freq = 1.3e9 -rf2.phase = 85.5 -rf2.mapsteps = 4 -rf2.nslice = 100 -rf2.cos_coefficients = 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 \ - 0 0 0 0 0 0 0 -rf2.sin_coefficients = \ - 0.1644024074311037 \ - -0.1324009958969339 \ - 4.3443060026047219e-002 \ - 8.5602654094946495e-002 \ - -0.2433578169042885 \ - 0.5297150596779437 \ - 0.7164884680963959 \ - -5.2579522442877296e-003 \ - -5.5025369142193678e-002 \ - 4.6845673335028933e-002 \ - -2.3279346335638568e-002 \ - 4.0800777539657775e-003 \ - 4.1378326533752169e-003 \ - -2.5040533340490805e-003 \ - -4.0654981400000964e-003 \ - 9.6630592067498289e-003 \ - -8.5275895985990214e-003 \ - -5.8078747006425020e-002 \ - -2.4044337836660403e-002 \ - 1.0968240064697212e-002 \ - -3.4461179858301418e-003 \ - -8.1201564869443749e-004 \ - 2.1438992904959380e-003 \ - -1.4997753525697276e-003 \ - 1.8685171825676386e-004 - - -############################################################################### -# Algorithms -############################################################################### -algo.particle_shape = 2 -algo.space_charge = false - - -############################################################################### -# Diagnostics -############################################################################### -diag.slice_step_diagnostics = true diff --git a/examples/rfcavity/run_rfcavity_distinct.py b/examples/rfcavity/run_rfcavity_distinct.py deleted file mode 100755 index e3c447170..000000000 --- a/examples/rfcavity/run_rfcavity_distinct.py +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright 2022-2023 ImpactX contributors -# Authors: Marco Garten, Axel Huebl, Chad Mitchell -# License: BSD-3-Clause-LBNL -# -# -*- coding: utf-8 -*- - -from impactx import ImpactX, distribution, elements - -sim = ImpactX() - -# set numerical parameters and IO control -sim.particle_shape = 2 # B-spline order -sim.space_charge = False -# sim.diagnostics = False # benchmarking -sim.slice_step_diagnostics = True - -# domain decomposition & space charge mesh -sim.init_grids() - -# load a 230 MeV electron beam with an initial -# unnormalized rms emittance of 1 mm-mrad in all -# three phase planes -kin_energy_MeV = 230.0 # reference energy -bunch_charge_C = 1.0e-10 # used with space charge -npart = 10000 # number of macro particles (outside tests, use 1e5 or more) - -# reference particle -ref = sim.particle_container().ref_particle() -ref.set_charge_qe(-1.0).set_mass_MeV(0.510998950).set_kin_energy_MeV(kin_energy_MeV) - -# particle bunch -distr = distribution.Waterbag( - lambdaX=0.352498964601e-3, - lambdaY=0.207443478142e-3, - lambdaT=0.70399950746e-4, - lambdaPx=5.161852770e-6, - lambdaPy=9.163582894e-6, - lambdaPt=0.260528852031e-3, - muxpx=0.5712386101751441, - muypy=-0.514495755427526, - mutpt=-5.05773e-10, -) -sim.add_particles(bunch_charge_C, distr, npart) - -# design the accelerator lattice - -RF_cos_coefs = [ - 0.1644024074311037, - -0.1324009958969339, - 4.3443060026047219e-002, - 8.5602654094946495e-002, - -0.2433578169042885, - 0.5297150596779437, - 0.7164884680963959, - -5.2579522442877296e-003, - -5.5025369142193678e-002, - 4.6845673335028933e-002, - -2.3279346335638568e-002, - 4.0800777539657775e-003, - 4.1378326533752169e-003, - -2.5040533340490805e-003, - -4.0654981400000964e-003, - 9.6630592067498289e-003, - -8.5275895985990214e-003, - -5.8078747006425020e-002, - -2.4044337836660403e-002, - 1.0968240064697212e-002, - -3.4461179858301418e-003, - -8.1201564869443749e-004, - 2.1438992904959380e-003, - -1.4997753525697276e-003, - 1.8685171825676386e-004, -] - -RF_sin_coefs = [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, -] - -# Drift elements -dr1 = elements.Drift(name="dr1", ds=0.4, nslice=1) -dr2 = elements.Drift(name="dr2", ds=0.032997, nslice=1) -# RF cavity element -rf = elements.RFCavity( - name="rf", - ds=1.31879807, - escale=62.0, - freq=1.3e9, - phase=85.5, - cos_coefficients=RF_cos_coefs, - sin_coefficients=RF_sin_coefs, - mapsteps=4, - nslice=100, -) -rf2 = elements.RFCavity( - name="rf2", - ds=1.31879807, - escale=62.0, - freq=1.3e9, - phase=85.5, - cos_coefficients=RF_sin_coefs, - sin_coefficients=RF_cos_coefs, - mapsteps=4, - nslice=100, -) - - -# add beam diagnostics -monitor = elements.BeamMonitor("monitor", backend="h5") - -sim.lattice.extend( - [ - monitor, - dr1, - dr2, - rf, - dr2, - dr2, - rf2, - monitor, - ] -) - -# run simulation -sim.track_particles() - -# clean shutdown -sim.finalize()