Source code for mbtrack2.impedance.tapers

# -*- coding: utf-8 -*-
"""
Module where taper elements are defined.
"""

import numpy as np
from scipy.constants import c, mu_0, pi
from scipy.integrate import trapz

from mbtrack2.impedance.wakefield import Impedance, WakeField


[docs]class StupakovRectangularTaper(WakeField): """ Rectangular vertical taper WakeField element, using the low frequency approxmiation. Assume constant taper angle. Formulas from [1]. ! Valid for low w Parameters ---------- frequency: frequency points where the impedance will be evaluated in [Hz] gap_entrance : full vertical gap at taper entrance in [m] gap_exit: full vertical gap at taper exit in [m] length: taper length in [m] width : full horizontal width of the taper in [m] """ def __init__(self, frequency, gap_entrance, gap_exit, length, width, m_max=100, n_points=int(1e4)): super().__init__() self.frequency = frequency self.gap_entrance = gap_entrance self.gap_exit = gap_exit self.length = length self.width = width self.m_max = m_max self.n_points = n_points Zlong = Impedance(variable=frequency, function=self.long(), component_type='long') Zxdip = Impedance(variable=frequency, function=self.xdip(), component_type='xdip') Zydip = Impedance(variable=frequency, function=self.ydip(), component_type='ydip') Zxquad = Impedance(variable=frequency, function=-1 * self.quad(), component_type='xquad') Zyquad = Impedance(variable=frequency, function=self.quad(), component_type='yquad') super().append_to_model(Zlong) super().append_to_model(Zxdip) super().append_to_model(Zydip) super().append_to_model(Zxquad) super().append_to_model(Zyquad) @property def gap_prime(self): return (self.gap_entrance - self.gap_exit) / self.length @property def angle(self): return np.arctan( (self.gap_entrance / 2 - self.gap_exit / 2) / self.length) @property def Z0(self): return mu_0 * c
[docs] def long(self, frequency=None): if frequency is None: frequency = self.frequency def F(x, m_max): m = np.arange(0, m_max) phi = np.outer(pi * x / 2, 2*m + 1) val = 1 / (2*m + 1) / (np.cosh(phi)**2) * np.tanh(phi) return val.sum(1) z = np.linspace(0, self.length, self.n_points) g = np.linspace(self.gap_entrance, self.gap_exit, self.n_points) to_integrate = self.gap_prime**2 * F(g / self.width, self.m_max) integral = trapz(to_integrate, x=z) return -1j * frequency * self.Z0 / (2*c) * integral
[docs] def Z_over_n(self, f0): return np.imag(self.long(1)) * f0
[docs] def ydip(self): def G1(x, m_max): m = np.arange(0, m_max) phi = np.outer(pi * x / 2, 2*m + 1) val = (2*m + 1) / (np.sinh(phi)**2) / np.tanh(phi) val = x[:, None]**3 * val return val.sum(1) z = np.linspace(0, self.length, self.n_points) g = np.linspace(self.gap_entrance, self.gap_exit, self.n_points) to_integrate = self.gap_prime**2 / (g**3) * G1(g / self.width, self.m_max) integral = trapz(to_integrate, x=z) return -1j * pi * self.width * self.Z0 / 4 * integral
[docs] def xdip(self): def G3(x, m_max): m = np.arange(0, m_max) phi = np.outer(pi * x, m) val = 2 * m / (np.cosh(phi)**2) * np.tanh(phi) val = x[:, None]**2 * val return val.sum(1) z = np.linspace(0, self.length, self.n_points) g = np.linspace(self.gap_entrance, self.gap_exit, self.n_points) to_integrate = self.gap_prime**2 / (g**2) * G3(g / self.width, self.m_max) integral = trapz(to_integrate, x=z) return -1j * pi * self.Z0 / 4 * integral
[docs] def quad(self): def G2(x, m_max): m = np.arange(0, m_max) phi = np.outer(pi * x / 2, 2*m + 1) val = (2*m + 1) / (np.cosh(phi)**2) * np.tanh(phi) val = x[:, None]**2 * val return val.sum(1) z = np.linspace(0, self.length, self.n_points) g = np.linspace(self.gap_entrance, self.gap_exit, self.n_points) to_integrate = self.gap_prime**2 / (g**2) * G2(g / self.width, self.m_max) integral = trapz(to_integrate, x=z) return -1j * pi * self.Z0 / 4 * integral
[docs]class StupakovCircularTaper(WakeField): """ Circular taper WakeField element, using the low frequency approxmiation. Assume constant taper angle. Formulas from [1]. ! Valid for low w Parameters ---------- frequency: frequency points where the impedance will be evaluated in [Hz] radius_entrance : radius at taper entrance in [m] radius_exit : radius at taper exit in [m] length : taper length in [m] """ def __init__(self, frequency, radius_entrance, radius_exit, length, m_max=100, n_points=int(1e4)): super().__init__() self.frequency = frequency self.radius_entrance = radius_entrance self.radius_exit = radius_exit self.length = length self.m_max = m_max self.n_points = n_points Zlong = Impedance(variable=frequency, function=self.long(), component_type='long') Zxdip = Impedance(variable=frequency, function=self.dip(), component_type='xdip') Zydip = Impedance(variable=frequency, function=self.dip(), component_type='ydip') super().append_to_model(Zlong) super().append_to_model(Zxdip) super().append_to_model(Zydip) @property def angle(self): return np.arctan( (self.radius_entrance - self.radius_exit) / self.length) @property def radius_prime(self): return (self.radius_entrance - self.radius_exit) / self.length @property def Z0(self): return mu_0 * c
[docs] def long(self, frequency=None): if frequency is None: frequency = self.frequency return (self.Z0 / (2*pi) * np.log(self.radius_entrance / self.radius_exit) - 1j * self.Z0 * frequency / (2*c) * self.radius_prime**2 * self.length)
[docs] def Z_over_n(self, f0): return np.imag(self.long(1)) * f0
[docs] def dip(self, frequency=None): if frequency is None: frequency = self.frequency z = np.linspace(0, self.length, self.n_points) r = np.linspace(self.radius_entrance, self.radius_exit, self.n_points) to_integrate = self.radius_prime**2 / (r**2) integral = trapz(to_integrate, x=z) return (self.Z0 * c / (4 * pi**2 * frequency) * (1 / (self.radius_exit**2) - 1 / (self.radius_entrance**2)) - 1j * self.Z0 / (2*pi) * integral)