Cavities reference phase

Definitions

There are three ways to define the reference phase of a cavity:

  • by its relative entry phase \(\phi_{0,\,\mathrm{rel}}\),

  • its absolute entry phase \(\phi_{0,\,\mathrm{abs}}\),

  • its synchronous phase \(\phi_s\).

A cavity reference phase controls its behavior when the beam phase differs from the baseline, which happens downstream of a failure if the beam absolute phase was not recovered.

  • "phi_0_abs": the cavity is not rephased.

  • "phi_0_rel": \(\phi_{0,\,\mathrm{rel}}\) is preserved, so that the beam always “sees” the same RF phase.

  • "phi_s": \(\phi_s\) is preserved, so that the cavity acceptance stays the same.

The relation between relative and entry phases is: \begin{equation} E_0\cos{\phi_{0,\,\mathrm{abs}}} = E_0\cos{(\phi_{0,\,\mathrm{rel}} + \phi_\mathrm{in})} \end{equation} where \(\phi_\mathrm{in}\) is the phase at which the synchronous particle enters the cavity, \(E_0\) is the amplitude of the electric field.

There is no analytic relation between \(phi_s\) and the RF phases \(\phi_{0,\,\mathrm{rel}}\), \(\phi_{0,\,\mathrm{abs}}\). Hereby, when the reference phase of a cavity is \(phi_s\), calculations are performed to find the actual RF phase allowing to retrieve \(phi_s\). Those calculations can take some time.

The cavities reference phases are set by the reference_phase_policy entry in the beam_calculator section of the TOML file:

  • "phi_0_rel", "phi_0_abs" or "phi_s": use this phase as reference

  • "as_in_original_dat": keep the reference stated in the DAT file, following the SET_SYNC_PHASE and the FLAG_PHI_ABS value of the FIELD_MAP commands.

    • Different cavities can have different reference phase!

In the rest of this notebook, we illustrate these differences and their impact on the beam dynamics.

Preparation

Load libraries

[1]:
import logging
from pathlib import Path

import matplotlib.pyplot as plt

from lightwin.beam_calculation.beam_calculator import BeamCalculator
from lightwin.beam_calculation.factory import BeamCalculatorsFactory
from lightwin.beam_calculation.simulation_output.simulation_output import SimulationOutput
from lightwin.config.config_manager import process_config
from lightwin.constants import example_config, example_results
from lightwin.core.accelerator.accelerator import Accelerator
from lightwin.failures.fault_scenario import FaultScenario, fault_scenario_factory
from lightwin.util.log_manager import set_up_logging
from lightwin.ui.workflow_setup import set_up_accelerators
from lightwin.visualization import plot

plt.rcParams["figure.figsize"] = (15, 5)

Set the different solvers

[2]:
CONFIG_KEYS = {
    'files': 'files',
    'beam_calculator': 'generic_envelope1d',
    'beam': 'beam',
    'plots': 'plots_minimal',
    'wtf': 'generic_wtf',
    'design_space': 'generic_design_space',
}

Linac with absolute reference phase

[3]:
override = {
    'beam_calculator': {'reference_phase_policy': "phi_0_abs"},
    'plots': {'energy': False, "add_objectives": False, "twiss": False},
    'wtf': {'objective_preset': 'EnergyPhaseMismatch'},
}
config_abs = process_config(example_config, CONFIG_KEYS, warn_mismatch=True, override=override)

# We will use this for plots representing cavity settings, phase
plots_phase = config_abs['plots']

factory = BeamCalculatorsFactory(**config_abs)
solver_abs = factory.run_all()[0]
[INFO    ] [log_manager.py      ] Starting log for LightWin - Version: 0.15.2, Commit: b5f41533c71d9e32770ab3d0a31bd9d0d3fcbc3a
[INFO    ] [files_specs.py      ] Setting project_path = PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/lightwin/envs/0.15.x/lib/python3.12/site-packages/lightwin/data/ads/lw_results')
Setting log_file = 'lightwin.log'

Linac with relative reference phase

[4]:
override = {
    'beam_calculator': {'reference_phase_policy': "phi_0_rel"},
    'plots': {'cav': True, "add_objectives": False, "twiss": False},
    'wtf': {'objective_preset': 'EnergyMismatch'},
}
config_rel = process_config(example_config, CONFIG_KEYS, warn_mismatch=True, override=override)

# We will use this for plots representing cavity settings, phase, energy
plots_complete = config_rel['plots']

factory = BeamCalculatorsFactory(**config_rel)
solver_rel = factory.run_all()[0]
[INFO    ] [table_spec.py       ] .toml table [files] loaded!
[INFO    ] [table_spec.py       ] .toml table [beam] loaded!
[INFO    ] [table_spec.py       ] .toml table [generic_envelope1d] loaded!
[INFO    ] [table_spec.py       ] .toml table [plots_minimal] loaded!
[INFO    ] [table_spec.py       ] .toml table [generic_design_space] loaded!
[INFO    ] [table_spec.py       ] .toml table [generic_wtf] loaded!
[INFO    ] [log_manager.py      ] Starting log for LightWin - Version: 0.15.2, Commit: b5f41533c71d9e32770ab3d0a31bd9d0d3fcbc3a
[INFO    ] [files_specs.py      ] Setting project_path = PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/lightwin/envs/0.15.x/lib/python3.12/site-packages/lightwin/data/ads/lw_results')
Setting log_file = 'lightwin.log'

Linac with synchronous reference phase

[5]:
override = {
    'beam_calculator': {'reference_phase_policy': "phi_s"},
    'wtf': {'objective_preset': 'EnergyMismatch'},
}
config_sync = process_config(example_config, CONFIG_KEYS, warn_mismatch=True, override=override)

factory = BeamCalculatorsFactory(**config_sync)
solver_sync = factory.run_all()[0]
[INFO    ] [table_spec.py       ] .toml table [files] loaded!
[INFO    ] [table_spec.py       ] .toml table [beam] loaded!
[INFO    ] [table_spec.py       ] .toml table [generic_envelope1d] loaded!
[INFO    ] [table_spec.py       ] .toml table [plots_minimal] loaded!
[INFO    ] [table_spec.py       ] .toml table [generic_design_space] loaded!
[INFO    ] [table_spec.py       ] .toml table [generic_wtf] loaded!
[INFO    ] [log_manager.py      ] Starting log for LightWin - Version: 0.15.2, Commit: b5f41533c71d9e32770ab3d0a31bd9d0d3fcbc3a
[INFO    ] [files_specs.py      ] Setting project_path = PosixPath('/home/docs/checkouts/readthedocs.org/user_builds/lightwin/envs/0.15.x/lib/python3.12/site-packages/lightwin/data/ads/lw_results')
Setting log_file = 'lightwin.log'

Set Accelerator objects

[6]:
logging.getLogger().setLevel(logging.WARNING)

accelerators_abs = set_up_accelerators(config_abs, (solver_abs,))
for acc in accelerators_abs:
    acc.name += r' (absolute $\phi_0$)'
working_abs = accelerators_abs[0]
broken_abs = accelerators_abs[1]

accelerators_rel = set_up_accelerators(config_rel, (solver_rel,))
for acc in accelerators_rel:
    acc.name += r' (relative $\phi_0$)'
working_rel = accelerators_rel[0]
broken_rel = accelerators_rel[1]

accelerators_sync = set_up_accelerators(config_sync, (solver_sync,))
for acc in accelerators_sync:
    acc.name += r' ($\phi_s$)'
working_sync = accelerators_sync[0]
broken_sync = accelerators_sync[1]

working_linacs = (working_abs, working_rel, working_sync)
broken_linacs = (broken_abs, broken_rel, broken_sync)
solvers = (solver_abs, solver_rel, solver_sync)

Propagate the beam

Nominal linac

[7]:
for solver, linac in zip(solvers, working_linacs):
    _ = solver.compute(linac)
figs = plot.factory(working_linacs, plots_phase, save_fig=False, clean_fig=False)
../../_images/manual_notebooks_cavities_reference_phase_24_0.png
../../_images/manual_notebooks_cavities_reference_phase_24_1.png

In the nominal linac, there is no difference between the different reference phases.

The reference \(\phi_0\) that is used is the one defined in the DAT. As a matter of a fact, we need to propagate the beam a first time to know the entry phase of the synchronous particle in every cavity. This quantity is necessary to link \(\phi_{0,\,\mathrm{abs}}\) with \(\phi_{0,\,\mathrm{rel}}\).

Linac with one broken cavity

Absolute reference phase

[8]:
fault_scenarios_abs = fault_scenario_factory(accelerators_abs, solver_abs, config_abs['wtf'], config_abs['design_space'])
[9]:
_ = solver_abs.compute(broken_abs)
figs = plot.factory(accelerators_abs, plots_complete, save_fig=False, clean_fig=False)
../../_images/manual_notebooks_cavities_reference_phase_30_0.png
../../_images/manual_notebooks_cavities_reference_phase_30_1.png
../../_images/manual_notebooks_cavities_reference_phase_30_2.png

Cavities in their nominal tuning are green, and the failed cavity is represented in red. Here the beam energy and phase remain very close to the baseline. However, the positive synchronous phases show that high losses would be to expect.

Relative reference phase

[10]:
fault_scenarios_rel = fault_scenario_factory(accelerators_rel, solver_rel, config_rel['wtf'], config_rel['design_space'])
[11]:
_ = solver_rel.compute(broken_rel)
figs = plot.factory(accelerators_rel, plots_complete, save_fig=False, clean_fig=False)
../../_images/manual_notebooks_cavities_reference_phase_34_0.png
../../_images/manual_notebooks_cavities_reference_phase_34_1.png
../../_images/manual_notebooks_cavities_reference_phase_34_2.png

In this example, the error on the beam energy is progressively damped. In LightWin, rephased cavities are represented with olive color.

Synchronous reference phase

[12]:
fault_scenarios_sync = fault_scenario_factory(accelerators_sync, solver_sync, config_sync['wtf'], config_sync['design_space'])
[13]:
_ = solver_sync.compute(broken_sync)
figs = plot.factory(accelerators_sync, plots_complete, save_fig=False, clean_fig=False)
../../_images/manual_notebooks_cavities_reference_phase_38_0.png
../../_images/manual_notebooks_cavities_reference_phase_38_1.png
../../_images/manual_notebooks_cavities_reference_phase_38_2.png

Notice that the synchronous phases are unaffected by failed cavity.

Fixing the fault

Absolute phase linac

For the absolute phase linac, we try to retrieve the energy and the phase at the end of the compensation zone, as well as to minimize the mismatch factor.

[14]:
for scenario in fault_scenarios_abs:
    scenario.fix_all()
figs = plot.factory(accelerators_abs, plots_complete, save_fig=False, clean_fig=False)
[WARNING ] [objective.py        ] key = 'to_deg' is recommended to avoid undetermined behavior but was not found.
../../_images/manual_notebooks_cavities_reference_phase_43_1.png
../../_images/manual_notebooks_cavities_reference_phase_43_2.png
../../_images/manual_notebooks_cavities_reference_phase_43_3.png

Relative phase linac

When downstream cavities are rephased, it is no longer mandatory to retrieve nominal beam phase at the exit of the compensation zone. Here, we try to retrieve the kinetic energy and to minimize the mismatch factor.

[15]:
for scenario in fault_scenarios_rel:
    scenario.fix_all()
figs = plot.factory(accelerators_rel, plots_complete, save_fig=False, clean_fig=False)
[WARNING ] [objective.py        ] key = 'to_deg' is recommended to avoid undetermined behavior but was not found.
[WARNING ] [objective.py        ] key = 'to_deg' is recommended to avoid undetermined behavior but was not found.
../../_images/manual_notebooks_cavities_reference_phase_46_1.png
../../_images/manual_notebooks_cavities_reference_phase_46_2.png
../../_images/manual_notebooks_cavities_reference_phase_46_3.png

Synchronous phase linac

Results will be very similar to the relative phase linac.

[16]:
for scenario in fault_scenarios_sync:
    scenario.fix_all()
figs = plot.factory(accelerators_sync, plots_complete, save_fig=False, clean_fig=False)
[WARNING ] [objective.py        ] key = 'to_deg' is recommended to avoid undetermined behavior but was not found.
[WARNING ] [objective.py        ] key = 'to_deg' is recommended to avoid undetermined behavior but was not found.
../../_images/manual_notebooks_cavities_reference_phase_49_1.png
../../_images/manual_notebooks_cavities_reference_phase_49_2.png
../../_images/manual_notebooks_cavities_reference_phase_49_3.png