Source code for iddefix.resonatorFormulas

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Created on Mon Mar 23 13:20:11 2020

@author: sjoly
"""
import numpy as np
from scipy import special as sp

from .utils import pars_to_dict

[docs]class Wakes: # Longitudinal and transverse wake functions
[docs] def Resonator_longitudinal_wake(times, Rs, Q, resonant_frequency): """Calculates the longitudinal wake function of a resonator. This function calculates the longitudinal wake function of a resonator with shunt impedance `Rs`, quality factor `Q`, and resonant frequency `resonant_frequency` at different times `times`. Args: times (np.ndarray): Array of time values in seconds. Rs (float): Shunt impedance of the resonator in Ohm. Q (float): Quality factor of the resonator. resonant_frequency (float): Resonant frequency of the resonator in Hz. Returns: np.ndarray: Array of longitudinal wake function values [V/C] at the corresponding times. Notes: This formula uses the generalized wake function formula and can be used for any real positive value of `Q`. https://cds.cern.ch/record/192684/files/198812060.pdf Units for this formula are: Rs: Ohm Q: dimensionless resonant_frequency: Hz Examples: >>> times = np.linspace(0, 1e-9, 1000) >>> Rs = 1e6 >>> Q = 0.6 >>> resonant_frequency = 1e9 >>> wake_function = Resonator_longitudinal_wake(times, Rs, Q, resonant_frequency) >>> plt.plot(times, wake_function) >>> plt.xlabel("Time [s]") >>> plt.ylabel("Longitudinal Wake Function [V/C]") >>> plt.show() """ omega_r = 2 * np.pi * resonant_frequency if Q == 0.5: Wl = 2 * Rs * omega_r * np.exp(-omega_r * times) * (1 - omega_r * times) elif Q < 0.5: omega_r_bar = omega_r * np.sqrt((1 / (4 * Q**2)) - 1) cos_term = np.cosh(omega_r_bar * times) sin_term = np.sinh(omega_r_bar * times) exp_term = np.exp(-omega_r * times/(2 * Q)) Wl = Rs * omega_r / Q * exp_term * (cos_term - omega_r / (2 * Q * omega_r_bar) * sin_term) else: omega_r_bar = omega_r * np.sqrt(1 - (1 / (4 * Q**2))) cos_term = np.cos(omega_r_bar * times) sin_term = np.sin(omega_r_bar * times) exp_term = np.exp(-omega_r * times/(2 * Q)) Wl = Rs * omega_r / Q * exp_term * (cos_term - omega_r / (2 * Q * omega_r_bar) * sin_term) Wl[times == 0.] = omega_r / (2 * Q) # Fundamental theorem of beam loading Wl[times < 0] = 0. return Wl
[docs] def Resonator_transverse_wake(times, Rs, Q, resonant_frequency): """Calculates the longitudinal wake function of a resonator. This function calculates the transverse wake function of a resonator with shunt impedance `Rs`, quality factor `Q`, and resonant frequency `resonant_frequency` at different times `times`. Args: times (np.ndarray): Array of time values in seconds. Rs (float): Shunt impedance of the resonator in Ohm/m. Q (float): Quality factor of the resonator. resonant_frequency (float): Resonant frequency of the resonator in Hz. Returns: np.ndarray: Array of longitudinal wake function values [V/C/m] at the corresponding times. Notes: This formula uses the generalized wake function formula and can be used for any real positive value of `Q`. https://cds.cern.ch/record/192684/files/198812060.pdf Units for this formula are: Rs: Ohm/m Q: dimensionless resonant_frequency: Hz Examples: >>> times = np.linspace(0, 1e-9, 1000) >>> Rs = 1e6 >>> Q = 0.6 >>> resonant_frequency = 1e9 >>> wake_function = Resonator_transverse_wake(times, Rs, Q, resonant_frequency) >>> plt.plot(times, wake_function) >>> plt.xlabel("Time [s]") >>> plt.ylabel("Transverse Wake Function [V/C]") >>> plt.show() """ omega_r = 2 * np.pi * resonant_frequency exp_term = np.exp(-omega_r * times / 2 / Q) if Q == 0.5: Wt = omega_r**2 * Rs / Q * exp_term * times elif Q < 0.5: omega_r_bar = omega_r * np.sqrt((1 / (4 * Q**2)) - 1) sqrt_term = np.sqrt((1 /(4 * Q * Q)) - 1) sin_term = np.sinh(omega_r * sqrt_term * times) Wt = omega_r**2 * Rs / (Q * omega_r_bar) * exp_term * sin_term else: omega_r_bar = omega_r * np.sqrt(1 - (1 / (4 * Q**2))) sqrt_term = np.sqrt(1 - (1 /(4 * Q * Q))) sin_term = np.sin(omega_r * sqrt_term * times) Wt = omega_r**2 * Rs / (Q * omega_r_bar) * exp_term * sin_term Wt[times < 0] = 0. return Wt
[docs] def n_Resonator_longitudinal_wake(times, pars): """Calculates the combined longitudinal wake function of multiple resonators. This function calculates the total longitudinal wake function induced by a system consisting of multiple resonators at different times `times`. Each resonator is defined by its parameters provided in a dictionary `dict_params`. Args: times (np.ndarray): Array of time values in seconds. dict_params (dict or ndarray): Dictionary containing resonator parameters. If dict, Keys are unique identifiers for each resonator, and values are lists containing the parameters in the following order: - Rs (float): Shunt impedance of the resonator in Ohm. - Q (float): Quality factor of the resonator. - resonant_frequency (float): Resonant frequency of the resonator in Hz. Returns: np.ndarray: Array of combined transverse wake function values [V/C] at the corresponding times. Examples: >>> times = np.linspace(0, 1e-9, 1000) >>> pars = { ... 1: [1e6, 1, 1e9], ... 2: [2e6, 1, 5e8], ... } >>> # Or, use directly the result from the DE solver >>> pars = DE_model.evolutionParameters >>> wake_function = n_Resonator_longitudinal_wake(times, pars) >>> plt.plot(times, wake_function) >>> plt.xlabel("Time [s]") >>> plt.ylabel("Longitudinal Wake Function [V/C]") >>> plt.show() Notes: - This function assumes all resonators have the same type of longitudinal wake function formula implemented in `Resonator_longitudinal_wake`. - The combined wake function is calculated by summing the individual wake function contributions from each resonator at each time step. - Resonator parameters should be positive values (except for the shunt impedance). Behavior for invalid values is not defined and may lead to errors. """ if type(pars) is dict: dict_params = pars else: dict_params = pars_to_dict(pars) #takes list or ndarray Wl = np.sum(Wakes.Resonator_longitudinal_wake(times, *params) for params in dict_params.values()) return Wl
[docs] def n_Resonator_transverse_wake(times, pars): """Calculates the combined transverse wake function of multiple resonators. This function calculates the total transverse wake function induced by a system consisting of multiple resonators at different times `times`. Each resonator is defined by its parameters provided in a dictionary `dict_params`. Args: times (np.ndarray): Array of time values in seconds. dict_params (dict or ndarray): Dictionary containing resonator parameters. Keys are unique identifiers for each resonator, and values are lists containing the parameters in the following order: - Rs (float): Shunt impedance of the resonator in Ohm/m. - Q (float): Quality factor of the resonator. - resonant_frequency (float): Resonant frequency of the resonator in Hz. Returns: np.ndarray: Array of combined transverse wake function values [V/C/m] at the corresponding times. Examples: >>> times = np.linspace(0, 1e-9, 1000) >>> pars = { ... 1: [1e6, 1, 1e9], ... 2: [2e6, 1, 5e8], ... } >>> # Or, use directly the result from the DE solver >>> pars = DE_model.evolutionParameters >>> wake_function = n_Resonator_transverse_wake(times, pars) >>> plt.plot(times, wake_function) >>> plt.xlabel("Time [s]") >>> plt.ylabel("Transverse Wake Function [V/C/m]") >>> plt.show() Notes: - This function assumes all resonators have the same type of transverse wake function formula implemented in `Resonator_transverse_wake`. - The combined wake function is calculated by summing the individual wake function contributions from each resonator at each time step. - Resonator parameters should be positive values (except for the shunt impedance). Behavior for invalid values is not defined and may lead to errors. """ if type(pars) is dict: dict_params = pars else: dict_params = pars_to_dict(pars) #takes list or ndarray Wt = np.sum(Wakes.Resonator_transverse_wake(times, *params) for params in dict_params.values()) return Wt
# Longitudinal and transverse wake potentials
[docs] def Resonator_longitudinal_wake_potential(times, Rs, Q, resonant_frequency, sigma=1e-10, use_mpmath=False): """ Single resonator wake potential (longitudinal) for a Gaussian bunch of line density. Args: Rs (float or list): Shunt impedance (Ohm). resonant_frequency (float or list): Resonant frequency (Hz). Q (float or list): Quality factor. sigma (float): RMS bunch length (s). times (array-like): Times (s) where wake is computed (times > 0 behind the source). use_mpmath (bool, optional): Use mpmath for calculations. Defaults to False. Returns: np.ndarray: Wake potential at times `times`. Notes: The formula is from Chao's Handbook (p. 237, sec 3.2), partly re-derived by N. Mounet. Equivalent formula in https://cds.cern.ch/record/192684/files/198812060.pdf Q must be different from 0.5! Rs, resonant_frequency, and Q must be scalar. """ omegar = 2 * np.pi * resonant_frequency kr = omegar * (1 - 1 / (4 * Q**2))**0.5 alphar = omegar / (2 * Q) cstsin = -Rs * omegar**2 / (4 * Q**2 * kr) cstcos = Rs * omegar / (2 * Q) mpmath_is_installed = True if use_mpmath: try: import mpmath except: raise ImportError("mpmath is not installed. Please install it to use this function.") mpmath_is_installed = False if use_mpmath and mpmath_is_installed: from mpmath import erfc, exp, matrix, re, im cst = exp((alphar**2 - kr**2) * sigma**2 / 2) times_mp = matrix(times) erfc_arg = -(times_mp - alphar * sigma**2 + 1j * kr * sigma**2) / (np.sqrt(2) * sigma) erfc_v = erfc_arg.apply(erfc) arg_expo1= -alphar * times_mp expo1 = arg_expo1.apply(exp) arg_expo2= 1j * (kr * times_mp - alphar * kr * sigma**2) expo2 = arg_expo2.apply(exp) im_expo_erfc = matrix([im(ex * er) for (ex, er) in zip(expo2, erfc_v)]) re_expo_erfc = matrix([re(ex * er) for (ex, er) in zip(expo2, erfc_v)]) W = np.hstack([cst * ex1 * (cstsin * im_exr + cstcos * re_exr) for (ex1, im_exr, re_exr) in zip(expo1, im_expo_erfc, re_expo_erfc)]) else: cst = np.exp((alphar**2 - kr**2) * sigma**2 / 2) erfc_v = sp.erfc(-(times - alphar * sigma**2 + 1j * kr * sigma**2) / (np.sqrt(2) * sigma)) expo1 = np.exp(-alphar * times) expo2 = np.exp(1j * (kr * times - alphar * kr * sigma**2)) W = cst * expo1 * (cstsin * np.imag(expo2 * erfc_v) + cstcos * np.real(expo2 * erfc_v)) return W
[docs] def n_Resonator_longitudinal_wake_potential(times, pars, sigma=1e-10): if type(pars) is dict: dict_params = pars else: dict_params = pars_to_dict(pars) #takes list or ndarray Wpl = np.sum(Wakes.Resonator_longitudinal_wake_potential(times, *params, sigma=sigma) for params in dict_params.values()) return Wpl
[docs] def Resonator_transverse_wake_potential(times, Rs, Q, resonant_frequency, sigma=1e-10, use_mpmath=False): """ Single resonator wake potential (transverse) for a Gaussian bunch of line density. Args: Rs (float or list): Shunt impedance (Ohm). resonant_frequency (float or list): Resonant frequency (Hz). Q (float or list): Quality factor. sigma (float): RMS bunch length (s). times (array-like): Times (s) where wake is computed (times > 0 behind the source). use_mpmath (bool, optional): Use mpmath for calculations. Defaults to False. Returns: np.ndarray: Wake potential at times `times`. Notes: The formula is from Chao's Handbook (p. 237, sec 3.2), partly re-derived by N. Mounet. Equivalent formula in https://cds.cern.ch/record/192684/files/198812060.pdf Q must be different from 0.5! Rs, resonant_frequency, and Q must be scalar. """ omegar = 2 * np.pi * resonant_frequency kr = omegar * (1 - 1 / (4 * Q**2))**0.5 alphar = omegar / (2 * Q) mpmath_is_installed = True if use_mpmath: try: import mpmath except: raise ImportError("mpmath is not installed. Please install it to use this function.") mpmath_is_installed = False if use_mpmath and mpmath_is_installed: from mpmath import erfc, exp, matrix, re, im times_mp = matrix(times) cst = Rs * omegar**2 / (2 * Q * kr) * exp((alphar**2 - kr**2) * sigma**2 / 2) erfc_arg = -(times_mp - alphar * sigma**2 + 1j * kr * sigma**2) / (np.sqrt(2) * sigma) erfc_v = erfc_arg.apply(erfc) arg_expo1 = -alphar * times_mp expo1 = arg_expo1.apply(exp) arg_expo2= 1j * (kr * times_mp - alphar * kr * sigma**2) expo2 = arg_expo2.apply(exp) im_expo_erfc = matrix([im(ex * er) for (ex, er) in zip(expo2, erfc_v)]) W = np.hstack([cst * ex1 * im_exr for (ex1, im_exr) in zip(expo1, im_expo_erfc)]) else: cst = Rs * omegar**2 / (2 * Q * kr) * np.exp((alphar**2 - kr**2) * sigma**2 / 2) erf_v = sp.erf((times - alphar * sigma**2 + 1j * kr * sigma**2) / (np.sqrt(2) * sigma)) expo1 = np.exp(-alphar * times) expo2 = np.exp(1j * (kr * times - alphar * kr * sigma**2)) W = cst * expo1 * np.imag(expo2 * (1 + erf_v)) return W
[docs] def n_Resonator_transverse_wake_potential(times, pars, sigma=1e-10): if type(pars) is dict: dict_params = pars else: dict_params = pars_to_dict(pars) #takes list or ndarray Wpt = np.sum(Wakes.Resonator_transverse_wake_potential(times, *params, sigma=sigma) for params in dict_params.values()) return Wpt
[docs]class Impedances: # Longitudinal and transverse impedance functions
[docs] def Resonator_longitudinal_imp(frequencies, Rs, Q, resonant_frequency, wake_length=None): """Calculates the longitudinal impedance of a resonator. This function calculates the longitudinal impedance of a resonator with shunt impedance `Rs`, quality factor `Q`, and resonant frequency `resonant_frequency` at different frequencies `frequencies`. Args: frequencies (np.ndarray): Array of frequencies values in Hz. Rs (float): Shunt impedance of the resonator in Ohm. Q (float): Quality factor of the resonator. resonant_frequency (float): Resonant frequency of the resonator in Hz. wake_length (float, optional): Additional parameter for the calculation of the impedance of a partially decayed wake. Defaults to None for the original (fully decayed wake) behavior. Returns: np.ndarray: Array of longitudinal impedance values [Ohm] at the corresponding frequencies. Notes: The fully decayed formula uses the generalized impedance formula (https://cds.cern.ch/record/192684/files/198812060.pdf) and can be used for any real positive value of `Q`. The partially decayed formula uses the formula derived in (Joly, S. thesis not published yet!) Moreover, it sets the impedance value to zero for zero frequencies in both cases. Units for this formula are: Rs: Ohm/m Q: dimensionless resonant_frequency: Hz wake_length: m Examples: >>> frequencies = np.linspace(0, 2.5e9, 1000) >>> Rs = 1e6 >>> Q = 0.6 >>> resonant_frequency = 1e9 >>> impedance = Resonator_longitudinal_imp(frequencies, Rs, Q, resonant_frequency) >>> plt.plot(frequencies, impedance) >>> plt.xlabel("Frequency [Hz]") >>> plt.ylabel("Longitudinal Impedance [Ohm]") >>> plt.show() """ if wake_length is None: # Fully decayed wake zero_index = np.where(frequencies > 0)[0] # find index of non-zero element if zero_index.size < frequencies.size: Zl = np.zeros_like(frequencies, dtype=complex) # initialize Zl as 0 Zl[zero_index] = Rs / (1 + 1j*Q * ( frequencies[zero_index]/resonant_frequency - resonant_frequency/frequencies[zero_index])) # calculate all Zl for non-zero frequencies else: Zl = Rs / (1 + 1j*Q * ( frequencies/resonant_frequency - resonant_frequency/frequencies)) else: # Partially decayed wake omega = 2 * np.pi * frequencies omega_r = 2 * np.pi * resonant_frequency c = 299792458.0 # speed of light in vacuum if Q < 0.5: raise ValueError("Quality factor Q must be larger than 0.5." "The wake is unlikely to be partially decayed" "for such a low quality factor otherwise.") B = omega_r / 2 / Q C = omega_r * np.sqrt(1 - 1 / 4 / Q**2) T = wake_length / c zero_index = np.where(frequencies > 0)[0] # find index of non-zero element if zero_index.size < frequencies.size: #A = Rs * omega_r / 2 / Q A = Rs * omega[zero_index] / 2 / Q # correct scaling to fit with usual formula exp_term = np.exp(-(B - 1j*(C - omega[zero_index])) * T) numerator = A * (1 - exp_term) denominator = B - 1j*(C - omega[zero_index]) Zl = np.zeros_like(frequencies, dtype=complex) # initialize Zl as 0 # calculate all Zl for non-zero frequencies Zl[zero_index] = numerator / denominator else: #A = Rs * omega_r / 2 / Q A = Rs * omega / 2 / Q # correct scaling to fit with usual formula exp_term = np.exp(-(B - 1j*(C - omega)) * T) numerator = A * (1 - exp_term) denominator = B - 1j*(C - omega) Zl = numerator / denominator return Zl
[docs] def Resonator_transverse_imp(frequencies, Rs, Q, resonant_frequency, wake_length=None): """Calculates the transverse impedance of a resonator. This function calculates the transverse impedance of a resonator with shunt impedance `Rs`, quality factor `Q`, and resonant frequency `resonant_frequency` at different frequencies `frequencies`. The `wake_length` argument allows computing the impedance of a partially decayed wake over `wake_length`. Args: frequencies (np.ndarray): Array of frequencies values in Hz. Rs (float): Shunt impedance of the resonator in Ohm/m. Q (float): Quality factor of the resonator. resonant_frequency (float): Resonant frequency of the resonator in Hz. wake_length (float, optional): Additional parameter for the calculation of the impedance of a partially decayed wake. Defaults to None for the original (fully decayed wake) behavior. Returns: np.ndarray: Array of transverse impedance values [Ohm/m] at the corresponding frequencies. Notes: The fully decayed formula uses the generalized impedance formula (https://cds.cern.ch/record/192684/files/198812060.pdf) and can be used for any real positive value of `Q`. The partially decayed formula uses the formula derived in (Joly, S. thesis not published yet!) Moreover, it sets the impedance value to zero for zero frequencies in both cases. Units for this formula are: Rs: Ohm/m Q: dimensionless resonant_frequency: Hz wake_length: m """ if wake_length is None: # Fully decayed wake zero_index = np.where(frequencies > 0)[0] # find index of non-zero element if zero_index.size < frequencies.size: Zt = np.zeros_like(frequencies, dtype=complex) # initialize Zt as 0 Zt[zero_index] = resonant_frequency / frequencies[zero_index] * Rs / (1 + 1j*Q * ( frequencies[zero_index]/resonant_frequency - resonant_frequency/frequencies[zero_index])) # calculate all Zt for non-zero frequencies else: Zt = resonant_frequency / frequencies * Rs / (1 + 1j*Q * ( frequencies/resonant_frequency - resonant_frequency/frequencies)) else: # Partially decayed wake omega = 2 * np.pi * frequencies omega_r = 2 * np.pi * resonant_frequency c = 299792458.0 # speed of light in vacuum if Q < 0.5: raise ValueError("Quality factor Q must be larger than 0.5." "The wake is unlikely to be partially decayed" "for such a low quality factor otherwise.") A = Rs * omega_r / (Q * np.sqrt(1 - 1 / 4 / Q**2)) B = omega_r / 2 / Q C = omega_r * np.sqrt(1 - 1 / 4 / Q**2) T = wake_length / c zero_index = np.where(frequencies > 0)[0] # find index of non-zero element if zero_index.size < frequencies.size: exp_term = np.exp(-T * (B + 1j * omega[zero_index])) cos_term = np.cos(C * T) sin_term = (B + 1j * omega[zero_index]) / C * np.sin(C * T) denominator = C**2 + (B + 1j * omega[zero_index])**2 Zt = np.zeros_like(frequencies, dtype=complex) # initialize Zt as 0 # calculate all Zt for non-zero frequencies Zt[zero_index] = 1j * A * C / denominator * (1 - exp_term * (cos_term + sin_term)) else: exp_term = np.exp(-T * (B + 1j * omega)) cos_term = np.cos(C * T) sin_term = (B + 1j * omega) / C * np.sin(C * T) denominator = C**2 + (B + 1j * omega)**2 Zt = 1j * A * C / denominator * (1 - exp_term * (cos_term + sin_term)) return Zt
[docs] def n_Resonator_longitudinal_imp(frequencies, pars, wake_length=None): """Calculates the combined longitudinal impedance of multiple resonators. This function calculates the total longitudinal impedance of a system consisting of multiple resonators at different frequencies `frequencies`. Each resonator is defined by its parameters provided in a dictionary `dict_params`. Args: frequencies (np.ndarray): Array of frequencies values in Hz. dict_params (dict or ndarray): Dictionary containing resonator parameters. Keys are unique identifiers for each resonator, and values are lists containing the parameters in the following order: - Rs (float): Shunt impedance of the resonator in Ohm. - Q (float): Quality factor of the resonator. - resonant_frequency (float): Resonant frequency of the resonator in Hz. wake_length (float, optional): Additional parameter for the calculation of the impedance of a partially decayed wake. Defaults to None for the original (fully decayed wake) behavior. Returns: np.ndarray: Array of combined longitudinal impedance values [Ohm] at the corresponding frequencies. Examples: >>> frequencies = np.linspace(0, 2.5e9, 1000) >>> pars = { ... 1: [1e6, 1, 1e9], ... 2: [2e6, 1, 5e8], ... } >>> # Or, use directly the result from the DE solver >>> pars = DE_model.evolutionParameters >>> impedance = n_Resonator_longitudinal_imp(frequencies, pars) >>> plt.plot(frequencies, impedance) >>> plt.xlabel("Frequency [Hz]") >>> plt.ylabel("Longitudinal Impedance [Ohm]") >>> plt.show() Notes: - This function assumes all resonators have the same type of longitudinal impedance formula implemented in `Resonator_longitudinal_imp`. - The combined impedance is calculated by summing the individual impedance contributions from each resonator at each frequency. - Resonator parameters should be positive values (except for the shunt impedance). Behavior for invalid values is not defined and may lead to errors. """ if type(pars) is dict: dict_params = pars else: dict_params = pars_to_dict(pars) #takes list or ndarray if wake_length is None: # Fully decayed wake Zl = np.sum(Impedances.Resonator_longitudinal_imp(frequencies, *params) for params in dict_params.values()) else: # Partially decayed wake Zl = np.sum(Impedances.Resonator_longitudinal_imp(frequencies, *params, wake_length=wake_length) for params in dict_params.values()) return Zl
[docs] def n_Resonator_transverse_imp(frequencies, pars, wake_length=None): """Calculates the combined transverse impedance of multiple resonators. This function calculates the total transverse impedance of a system consisting of multiple resonators at different frequencies `frequencies`. Each resonator is defined by its parameters provided in a dictionary `dict_params`. Args: frequencies (np.ndarray): Array of frequencies values in Hz. dict_params (dict or ndaray): Dictionary containing resonator parameters. Keys are unique identifiers for each resonator, and values are lists containing the parameters in the following order: - Rs (float): Shunt impedance of the resonator in Ohm/m. - Q (float): Quality factor of the resonator. - resonant_frequency (float): Resonant frequency of the resonator in Hz. wake_length (float, optional): Additional parameter for the calculation of the impedance of a partially decayed wake. Defaults to None for the original (fully decayed wake) behavior. Returns: np.ndarray: Array of combined transverse impedance values [Ohm/m] at the corresponding frequencies. Examples: >>> frequencies = np.linspace(0, 2.5e9, 1000) >>> pars = { ... 1: [1e6, 1, 1e9], ... 2: [2e6, 1, 5e8], ... } >>> # Or, use directly the result from the DE solver >>> pars = DE_model.evolutionParameters >>> impedance = n_Resonator_transverse_imp(frequencies, pars) >>> plt.plot(frequencies, impedance) >>> plt.xlabel("Frequency [Hz]") >>> plt.ylabel("Transverse Impedance [Ohm/m]") >>> plt.show() Notes: - This function assumes all resonators have the same type of transverse impedance formula implemented in `Resonator_transverse_imp`. - The combined impedance is calculated by summing the individual impedance contributions from each resonator at each frequency. - Resonator parameters should be positive values (except for the shunt impedance). Behavior for invalid values is not defined and may lead to errors. """ if type(pars) is dict: dict_params = pars else: dict_params = pars_to_dict(pars) #takes list or ndarray if wake_length is None: # Fully decayed wake Zt = np.sum(Impedances.Resonator_transverse_imp(frequencies, *params) for params in dict_params.values()) else: # Partially decayed wake Zt = np.sum(Impedances.Resonator_transverse_imp(frequencies, *params, wake_length=wake_length) for params in dict_params.values()) return Zt