Skip to content

Commit ad1b15d

Browse files
Add resistive wall impedance
1 parent e89dd9c commit ad1b15d

File tree

4 files changed

+791
-1
lines changed

4 files changed

+791
-1
lines changed
Lines changed: 337 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,337 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"id": "04477050",
7+
"metadata": {},
8+
"outputs": [],
9+
"source": [
10+
"import numpy as np\n",
11+
"import matplotlib.pyplot as plt\n",
12+
"\n",
13+
"from pmd_beamphysics.wakefields import FlatResistiveWallImpedance"
14+
]
15+
},
16+
{
17+
"cell_type": "markdown",
18+
"id": "0b806816",
19+
"metadata": {},
20+
"source": [
21+
"## Basic Usage\n",
22+
"\n",
23+
"Create an impedance object by specifying the geometry and material properties:"
24+
]
25+
},
26+
{
27+
"cell_type": "code",
28+
"execution_count": null,
29+
"id": "b22ca02e",
30+
"metadata": {},
31+
"outputs": [],
32+
"source": [
33+
"imp = FlatResistiveWallImpedance(\n",
34+
" half_gap=4.5e-3, # m (half-gap between plates)\n",
35+
" conductivity=2.4e7, # S/m (DC conductivity)\n",
36+
" relaxation_time=8e-15, # s (Drude relaxation time)\n",
37+
")\n",
38+
"\n",
39+
"imp"
40+
]
41+
},
42+
{
43+
"cell_type": "markdown",
44+
"id": "e545b33a",
45+
"metadata": {},
46+
"source": [
47+
"The characteristic length scale $s_0$ is computed automatically:\n",
48+
"\n",
49+
"$$s_0 = \\left( \\frac{2a^2}{Z_0 \\sigma_0} \\right)^{1/3}$$"
50+
]
51+
},
52+
{
53+
"cell_type": "code",
54+
"execution_count": null,
55+
"id": "d75ad878",
56+
"metadata": {},
57+
"outputs": [],
58+
"source": [
59+
"print(f\"Characteristic length s₀ = {imp.s0*1e6:.2f} µm\")"
60+
]
61+
},
62+
{
63+
"cell_type": "markdown",
64+
"id": "418a1551",
65+
"metadata": {},
66+
"source": [
67+
"## Computing Impedance $Z(k)$\n",
68+
"\n",
69+
"The longitudinal impedance is computed by integrating the surface impedance kernel over all transverse modes."
70+
]
71+
},
72+
{
73+
"cell_type": "code",
74+
"execution_count": null,
75+
"id": "4f8884e5",
76+
"metadata": {},
77+
"outputs": [],
78+
"source": [
79+
"ks = np.linspace(0, 3e5, 100)\n",
80+
"Zk = imp.impedance(ks)"
81+
]
82+
},
83+
{
84+
"cell_type": "code",
85+
"execution_count": null,
86+
"id": "fd741ae8",
87+
"metadata": {},
88+
"outputs": [],
89+
"source": [
90+
"fig, ax = plt.subplots(figsize=(8, 5))\n",
91+
"ax.plot(ks * 1e-3, np.real(Zk), label=r\"Re[$Z(k)$]\")\n",
92+
"ax.plot(ks * 1e-3, np.imag(Zk), label=r\"Im[$Z(k)$]\")\n",
93+
"ax.set_xlabel(r\"$k$ (1/mm)\")\n",
94+
"ax.set_ylabel(r\"$Z(k)$ (Ω/m)\")\n",
95+
"ax.legend()\n",
96+
"ax.set_title(\"Longitudinal Impedance\")\n",
97+
"plt.tight_layout()"
98+
]
99+
},
100+
{
101+
"cell_type": "markdown",
102+
"id": "40091658",
103+
"metadata": {},
104+
"source": [
105+
"The built-in plot method provides a quick visualization:"
106+
]
107+
},
108+
{
109+
"cell_type": "code",
110+
"execution_count": null,
111+
"id": "15d074d0",
112+
"metadata": {},
113+
"outputs": [],
114+
"source": [
115+
"imp.plot_impedance(k_max=5e5, n_points=200)"
116+
]
117+
},
118+
{
119+
"cell_type": "markdown",
120+
"id": "74a4b289",
121+
"metadata": {},
122+
"source": [
123+
"## Computing Wakefield $W(z)$\n",
124+
"\n",
125+
"The wakefield is computed from the real part of the impedance using a cosine transform:\n",
126+
"\n",
127+
"$$W(z) = \\frac{2}{\\pi} \\int_0^{k_{\\max}} \\text{Re}[Z(k)] \\cos(kz) \\, dk$$"
128+
]
129+
},
130+
{
131+
"cell_type": "code",
132+
"execution_count": null,
133+
"id": "6adce166",
134+
"metadata": {},
135+
"outputs": [],
136+
"source": [
137+
"zs = np.linspace(0, 200e-6, 30)\n",
138+
"Wz = imp.wakefield(zs, k_max=1e6)"
139+
]
140+
},
141+
{
142+
"cell_type": "code",
143+
"execution_count": null,
144+
"id": "50a34a22",
145+
"metadata": {},
146+
"outputs": [],
147+
"source": [
148+
"fig, ax = plt.subplots(figsize=(8, 5))\n",
149+
"ax.plot(zs * 1e6, Wz * 1e-12)\n",
150+
"ax.set_xlabel(r\"$z$ (µm)\")\n",
151+
"ax.set_ylabel(r\"$W(z)$ (V/pC/m)\")\n",
152+
"ax.set_title(\"Longitudinal Wakefield\")\n",
153+
"plt.tight_layout()"
154+
]
155+
},
156+
{
157+
"cell_type": "markdown",
158+
"id": "cc872afe",
159+
"metadata": {},
160+
"source": [
161+
"The built-in plot method:"
162+
]
163+
},
164+
{
165+
"cell_type": "code",
166+
"execution_count": null,
167+
"id": "23b4135d",
168+
"metadata": {},
169+
"outputs": [],
170+
"source": [
171+
"imp.plot_wakefield(z_max=200e-6, n_points=40, k_max=1e6)"
172+
]
173+
},
174+
{
175+
"cell_type": "markdown",
176+
"id": "fe70c4f2",
177+
"metadata": {},
178+
"source": [
179+
"## Low-Level Functions\n",
180+
"\n",
181+
"The module also provides low-level functions for more control:"
182+
]
183+
},
184+
{
185+
"cell_type": "code",
186+
"execution_count": null,
187+
"id": "61e275b9",
188+
"metadata": {},
189+
"outputs": [],
190+
"source": [
191+
"from pmd_beamphysics.wakefields.resistive_wall_impedance import (\n",
192+
" ac_conductivity,\n",
193+
" longitudinal_impedance,\n",
194+
" wakefield_from_impedance,\n",
195+
")"
196+
]
197+
},
198+
{
199+
"cell_type": "markdown",
200+
"id": "6e8572a6",
201+
"metadata": {},
202+
"source": [
203+
"### AC Conductivity\n",
204+
"\n",
205+
"The Drude model for frequency-dependent conductivity:\n",
206+
"\n",
207+
"$$\\sigma(k) = \\frac{\\sigma_0}{1 - i k c \\tau}$$"
208+
]
209+
},
210+
{
211+
"cell_type": "code",
212+
"execution_count": null,
213+
"id": "05c898c3",
214+
"metadata": {},
215+
"outputs": [],
216+
"source": [
217+
"sigma0 = 2.4e7 # S/m\n",
218+
"ctau = 2.4e-6 # m\n",
219+
"\n",
220+
"ks = np.linspace(0, 1e6, 200)\n",
221+
"sigma_ac = ac_conductivity(ks, sigma0, ctau)\n",
222+
"\n",
223+
"fig, ax = plt.subplots(figsize=(8, 5))\n",
224+
"ax.plot(ks * 1e-3, np.real(sigma_ac) / sigma0, label=r\"Re[$\\sigma$]/$\\sigma_0$\")\n",
225+
"ax.plot(ks * 1e-3, np.imag(sigma_ac) / sigma0, label=r\"Im[$\\sigma$]/$\\sigma_0$\")\n",
226+
"ax.set_xlabel(r\"$k$ (1/mm)\")\n",
227+
"ax.set_ylabel(r\"Normalized conductivity\")\n",
228+
"ax.legend()\n",
229+
"ax.set_title(\"AC Conductivity (Drude Model)\")\n",
230+
"plt.tight_layout()"
231+
]
232+
},
233+
{
234+
"cell_type": "markdown",
235+
"id": "1573edcb",
236+
"metadata": {},
237+
"source": [
238+
"### Direct Impedance Calculation\n",
239+
"\n",
240+
"Use `longitudinal_impedance` directly with explicit parameters:"
241+
]
242+
},
243+
{
244+
"cell_type": "code",
245+
"execution_count": null,
246+
"id": "c6d40f1c",
247+
"metadata": {},
248+
"outputs": [],
249+
"source": [
250+
"a = 4.5e-3 # half-gap [m]\n",
251+
"sigma0 = 2.4e7 # conductivity [S/m]\n",
252+
"ctau = 2.4e-6 # relaxation distance [m]\n",
253+
"\n",
254+
"k_test = 1e5 # 1/m\n",
255+
"Zk_test = longitudinal_impedance(k_test, a, sigma0, ctau)\n",
256+
"print(f\"Z({k_test:.0e} 1/m) = {Zk_test:.4f} Ω/m\")"
257+
]
258+
},
259+
{
260+
"cell_type": "markdown",
261+
"id": "1715a4f6",
262+
"metadata": {},
263+
"source": [
264+
"### Wakefield from Custom Impedance Function\n",
265+
"\n",
266+
"The `wakefield_from_impedance` function accepts any callable that returns $Z(k)$:"
267+
]
268+
},
269+
{
270+
"cell_type": "code",
271+
"execution_count": null,
272+
"id": "3a99efcb",
273+
"metadata": {},
274+
"outputs": [],
275+
"source": [
276+
"from functools import partial\n",
277+
"\n",
278+
"# Create a custom impedance function\n",
279+
"my_Zk = partial(longitudinal_impedance, a=4.5e-3, sigma0=2.4e7, ctau=2.4e-6)\n",
280+
"\n",
281+
"# Compute wakefield at a single point\n",
282+
"z_test = 50e-6 # m\n",
283+
"Wz_test = wakefield_from_impedance(z_test, my_Zk, k_max=1e6)\n",
284+
"print(f\"W({z_test*1e6:.0f} µm) = {Wz_test:.2e} V/C/m = {Wz_test*1e-12:.2f} V/pC/m\")"
285+
]
286+
},
287+
{
288+
"cell_type": "markdown",
289+
"id": "fe65f33a",
290+
"metadata": {},
291+
"source": [
292+
"## Performance Notes\n",
293+
"\n",
294+
"The impedance calculation involves nested numerical integration (over k and a transverse integration variable), which can be slow for large arrays. For production use with many particles, consider:\n",
295+
"\n",
296+
"1. Pre-computing Z(k) on a grid and interpolating\n",
297+
"2. Using the `ResistiveWallWakefield` class with pseudomode fits for faster evaluation\n",
298+
"\n",
299+
"See the [resistive_wall_wakefield](resistive_wall_wakefield.ipynb) notebook for the pseudomode approach."
300+
]
301+
},
302+
{
303+
"cell_type": "code",
304+
"execution_count": null,
305+
"id": "f76779c2",
306+
"metadata": {},
307+
"outputs": [],
308+
"source": [
309+
"%%timeit -n 1 -r 3\n",
310+
"# Time a typical impedance calculation\n",
311+
"ks = np.linspace(0, 3e5, 50)\n",
312+
"Zk = imp.impedance(ks)"
313+
]
314+
}
315+
],
316+
"metadata": {
317+
"kernelspec": {
318+
"display_name": "pmd_beamphysics-dev",
319+
"language": "python",
320+
"name": "python3"
321+
},
322+
"language_info": {
323+
"codemirror_mode": {
324+
"name": "ipython",
325+
"version": 3
326+
},
327+
"file_extension": ".py",
328+
"mimetype": "text/x-python",
329+
"name": "python",
330+
"nbconvert_exporter": "python",
331+
"pygments_lexer": "ipython3",
332+
"version": "3.13.9"
333+
}
334+
},
335+
"nbformat": 4,
336+
"nbformat_minor": 5
337+
}

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ nav:
2222
- examples/fields/solenoid_modeling.ipynb
2323
- Wakefields:
2424
- examples/wakefields/resistive_wall_wakefield.ipynb
25+
- examples/wakefields/resistive_wall_impedance.ipynb
2526
- Utilities:
2627
- examples/units.ipynb
2728
- examples/labels.ipynb
Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,21 @@
11
from .resistive_wall import ResistiveWallWakefield
2+
from .resistive_wall_impedance import (
3+
FlatResistiveWallImpedance,
4+
ac_conductivity,
5+
characteristic_length,
6+
longitudinal_impedance,
7+
sinhc,
8+
surface_impedance,
9+
wakefield_from_impedance,
10+
)
211

3-
__all__ = ["ResistiveWallWakefield"]
12+
__all__ = [
13+
"ResistiveWallWakefield",
14+
"FlatResistiveWallImpedance",
15+
"ac_conductivity",
16+
"characteristic_length",
17+
"longitudinal_impedance",
18+
"sinhc",
19+
"surface_impedance",
20+
"wakefield_from_impedance",
21+
]

0 commit comments

Comments
 (0)