From 5cdabf68981660db10542acbe2cda94a8a811697 Mon Sep 17 00:00:00 2001 From: Alexis Gamelin <alexis.gamelin@synchrotron-soleil.fr> Date: Fri, 12 Apr 2024 14:52:15 +0200 Subject: [PATCH] Add to_pycolleff --- mbtrack2/impedance/wakefield.py | 20 +++++++++++++++++ mbtrack2/tracking/rf.py | 37 +++++++++++++++++++++++++++++++- mbtrack2/tracking/synchrotron.py | 28 ++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) diff --git a/mbtrack2/impedance/wakefield.py b/mbtrack2/impedance/wakefield.py index 6f221f2..ee83e57 100644 --- a/mbtrack2/impedance/wakefield.py +++ b/mbtrack2/impedance/wakefield.py @@ -780,6 +780,26 @@ class Impedance(ComplexData): label = r"$Z_{" + self.component_type + r"}$" + unit ax.set_ylabel(label) return ax + + def to_pycolleff(self): + from pycolleff.longitudinal_equilibrium import ImpedanceSource + from mbtrack2.utilities.misc import double_sided_impedance + imp = ImpedanceSource() + if self.component_type == "long": + double_sided_impedance(self) + # Negative imag sign convention ! + imp.zl_table = self.data["real"].to_numpy() - 1j*self.data["imag"].to_numpy() + imp.ang_freq_table = self.data.index.to_numpy() * 2 * np.pi + else: + raise NotImplementedError() + + # Methods: Impedance or Wake + imp.calc_method = ImpedanceSource.Methods.ImpedanceDFT + + # Device type: Active of Passive + imp.active_passive = ImpedanceSource.ActivePassive.Passive + + return imp class WakeField: diff --git a/mbtrack2/tracking/rf.py b/mbtrack2/tracking/rf.py index a92c4b3..0b66593 100644 --- a/mbtrack2/tracking/rf.py +++ b/mbtrack2/tracking/rf.py @@ -7,7 +7,7 @@ import matplotlib.patches as mpatches import matplotlib.pyplot as plt import numpy as np from matplotlib.legend_handler import HandlerPatch - +from functools import partial from mbtrack2.instability import lcbi_growth_rate from mbtrack2.tracking.element import Element @@ -1141,6 +1141,41 @@ class CavityResonator(): ref_frame="beam") return pos, voltage_rec + + def to_pycolleff(self): + from pycolleff.longitudinal_equilibrium import ImpedanceSource + + cav = ImpedanceSource() + cav.harm_rf = self.m + cav.Q = self.QL + RoverQ = self.RL/self.QL + cav.shunt_impedance = self.Ncav * RoverQ * cav.Q + cav.ang_freq_rf = self.ring.omega1 + cav.ang_freq = cav.harm_rf * cav.ang_freq_rf + cav.detune_w = 2 * np.pi * self.detune + cav.calc_method = ImpedanceSource.Methods.ImpedanceDFT + if self.Vg != 0: + cav.active_passive = ImpedanceSource.ActivePassive.Active + # Define PID transfer function for control loop + def pid_transfer_func(w, wrf, gain=1, kp=1, ki=1, kd=0, delay=0): + # If you do not want to worry about the details of the voltage gap + # control system, you can use SIRIUS parameters in this function. + phase = wrf * delay + exp_delay = np.exp(-1j * delay * w) + exp_phase = np.exp(1j * phase) + eps = 1e-16 + pid_ctrl = kp + ki / 1j / (w - wrf + eps) + kd * 1j * (w - wrf) + transfer = gain * pid_ctrl * exp_delay * exp_phase + return transfer + + cav.loop_ctrl_ang_freq = self.ring.omega1 + cav.loop_ctrl_transfer = partial(pid_transfer_func, kp=1, ki=1, delay=0) + + else: + cav.active_passive = ImpedanceSource.ActivePassive.Passive + return cav + + class ProportionalLoop(): diff --git a/mbtrack2/tracking/synchrotron.py b/mbtrack2/tracking/synchrotron.py index b6e36fa..70b4f63 100644 --- a/mbtrack2/tracking/synchrotron.py +++ b/mbtrack2/tracking/synchrotron.py @@ -584,3 +584,31 @@ class Synchrotron: U0=self.U0, TimeLag=TimeLag) return at_simple_ring + + def to_pycolleff(self, I0, Vrf, bunch_number): + from pycolleff.colleff import Ring + + ring = Ring() + ring.version = 'from_mbtrack2' + ring.rf_freq = self.f1 + ring.mom_comp = self.ac # momentum compaction factor + ring.energy = self.E0 # energy [eV] + ring.tuney = self.tune[1] # vertical tune + ring.tunex = self.tune[0] # horizontal tune + ring.chromx = self.chro[0] # horizontal chromaticity + ring.chromy = self.chro[1] # vertical chromaticity + ring.harm_num = self.h # harmonic Number + ring.num_bun = bunch_number # number of bunches filled + + ring.total_current = I0 # total current [A] + ring.sync_tune = self.synchrotron_tune(Vrf) # synchrotron tune + ring.espread = self.sigma_delta + ring.bunlen = self.sigma_0*c # [m] + ring.damptx = self.tau[0] # [s] + ring.dampty = self.tau[1] # [s] + ring.dampte = self.tau[2] # [s] + ring.en_lost_rad = self.U0 # [eV] + ring.gap_voltage = Vrf # [V] + + return ring + -- GitLab