๐ฎ Comparing the Quality and Loess between a Full and a Half SRF Cavity
Calculation of resonant cavity quality factors, losses, life-time and more using the EPR method. This code is based on Ansys HFSS and the pyEPR library.
The cavity is half of a SRF cavity, this will be usefule in a later notebook where we compare the full Tesla cavity to our (half Tesla) cavity.
Imports
%load_ext autoreload
%autoreload 2
%config IPCompleter.greedy = True
import sys
import numpy as np
from IPython.display import display, Math, Latex, display_markdown
from pathlib import Path
import pandas as pd
from scipy import constants
import pyEPR as epr
from pyEPR.calcs import Convert
from pyEPR.core import *
from pyEPR.ansys import *
import warnings
warnings.simplefilter("ignore")
path_to_project = '.'
๐ Half Cavity
We start with the interesting one, the half cavity. This is the cavity weโre going to be using and we want to check that it isnโt that much worse than the full Tesla cavity.
๐ท Mode analysis
๐น Connect to HFSS
pinfo = epr.Project_Info(project_path = path_to_project,
project_name = 'Cavity Analysis',
design_name = 'half cav')
INFO 11:21AM [connect]: Connecting to Ansys Desktop API...
INFO 11:21AM [load_ansys_project]: File path to HFSS project found.
INFO 11:21AM [load_ansys_project]: Opened Ansys App
INFO 11:21AM [load_ansys_project]: Opened Ansys Desktop v2020.1.0
INFO 11:21AM [load_ansys_project]: Opened Ansys Project
Folder: D:/Users/Daniel/Cavity-Analysis/
Project: Cavity Analysis
INFO 11:21AM [connect]: Opened active design
Design: half cav [Solution type: Eigenmode]
INFO 11:21AM [get_setup]: Opened setup `setup` (<class 'pyEPR.ansys.HfssEMSetup'>)
INFO 11:21AM [connect]: Connection to Ansys established successfully. ๐
pinfo.setup.analyze()
eprh = epr.DistributedAnalysis(pinfo)
INFO 11:21AM [analyze]: Analyzing setup setup
Design "half cav" info:
# eigenmodes 1
# variations 2
๐น Get HFSS mode and quality results
modes = eprh.get_freqs_bare_pd(eprh.variations[0])
Fs, Qs = np.array(modes['Freq. (GHz)']), np.array(modes['Quality Factor']) # Get freqs and Q-factors
n_modes = int(pinfo.setup.n_modes)
display(modes)
Freq. (GHz) | Quality Factor | |
---|---|---|
mode | ||
0 | 4.069412 | 1248.378885 |
๐น Calculate the EPRs of the modes
eprh.set_mode(0)
p_cavity, (โฐ_cav, โฐ_total) = eprh.calc_p_electric_volume('cavity')
p_dirt, (โฐ_dirt, โฐ_total) = eprh.calc_p_electric_volume('dirt')
print(f' ๐ธ Energy in cavity = {100*p_cavity:.3f}% -> {โฐ_cav:0.2e} of the total energy in the system')
print(f' ๐ธ Energy in dirt = {100*p_dirt:.3f}% -> {โฐ_dirt:0.2e} of the total energy in the system')
print(f' ๐ธ Total energy = {โฐ_total:0.2e}')
๐ธ Energy in cavity = 95.995% -> 8.11e-17 of the total energy in the system
๐ธ Energy in dirt = 4.005% -> 3.38e-18 of the total energy in the system
๐ธ Total energy = 8.45e-17
๐ท Life-times
Life-time from HFSS
Life time of a mode inside the cavity. Since in this exampole the cavity is perfect, the life time would be infinite
Fs_Hz = np.array(Convert.toSI(Fs,'GHz')) # Mode freqs in Hz
omegas = 2*np.pi*Fs_Hz # Freqs to angular freqs
taus = Qs/omegas # Life times
print(f' ๐ธ Life-time of mode = {taus[0]*1e3:.3f} ms') # Should be inf since no resistive boundry and just inside a vacuum
๐ธ Life-time of mode = 0.000 ms
Life-time from EPR
Life time calculation with the EPR method. This is highly dependent on the loss tangent of the dirt and cavity.
tan_dirt = 4e-7 # Loss tangent of dirt
tau_epr = lambda p, tan, omega: 1/(p*tan*omega) # Easily calculate life time with EPR
tau_cavity = tau_epr(p_dirt, 0, omegas)[0]
tau_dirt = tau_epr(p_cavity, tan_dirt, omegas)[0]
print(f' ๐ธ Cavity life-time = {tau_cavity*1e6:.2f} ns') # Should be infinite since the cavity is a pefect vacum
print(f' ๐ธ Dirt life-time = {tau_dirt*1e6:.2f} ns')
๐ธ Cavity life-time = inf ns
๐ธ Dirt life-time = 101.85 ns
๐ท Losses
๐น Surface loss
Calculating the energy precentage near the cavity walls by the surface integral. The total energy of the electromagnetic field at a layer of thickness dirt_widht
would be approximated as:
First weโll setup a dictionary to store all the data
data = {
"half":{
"volume":{
},
"surface":{
}
},
"full":{
"volume":{
},
"surface":{
}
}
}
dirt_width = 0.1e-3
eps = 1
tan_surf = 5e-3
eprh.set_mode(0)
# --- Surface integral ---
surf = 'cavity'
calcobject = CalcObject([], eprh.setup)
vecE = calcobject.getQty("E").smooth()
A = vecE.times_eps()
B = vecE.conj()
A = A.dot(B)
A = A.real()
A = A.integrate_surf(name=surf)
E_subs = A.evaluate(lv=eprh._get_lv())
E_surf = E_subs*dirt_width*eps
# --- Volume integral ---
E_total = eprh.calc_energy_electric(smooth=True)
p_surf = E_surf/E_total # EPR of surface
Q_surf = 1/tan_surf/p_surf # Q-fact of surface
tau_surf = Q_surf/omegas[0] # Life-time of surface
data['half']['surface'] = {
"EPR": p_surf,
"Q": Q_surf,
"tau": tau_surf
}
print(f' ๐ธ EPR surface = {100*p_surf:.2f}%')
print(f' ๐ธ Q-factor surface = {Q_surf:.2e}')
print(f' ๐ธ Life-time surface = {tau_surf:.2e} seconds \n')
๐ธ EPR surface = 1.54%
๐ธ Q-factor surface = 1.30e+04
๐ธ Life-time surface = 5.07e-07 seconds
๐น Dirt (volume) loss
# Dirt is simulated as much thicker than it actually is (for computation reason).
# Beacuase of that we reduce the loss tangent to an 'effective loss tangent' which is loss_tan*thick_factor
p_dirt, (โฐ_dirt, โฐ_total) = eprh.calc_p_electric_volume('dirt')
Q_dirt = 1/(tan_surf*p_dirt)
tau_dirt = Q_dirt/omegas[0]
data['half']['volume'] = {
"EPR": p_dirt,
"Q": Q_dirt,
"tau": tau_dirt
}
print(f' ๐ธ EPR of dirt = {100*p_dirt:0.2f}% ( {โฐ_dirt:.2e} / {โฐ_total:.2e} )')
print(f' ๐ธ Quality factor = {Q_dirt:0.2e}')
print(f' ๐ธ life time = {tau_dirt:0.2e} seconds\n')
๐ธ EPR of dirt = 4.01% ( 3.38e-18 / 8.45e-17 )
๐ธ Quality factor = 4.99e+03
๐ธ life time = 1.95e-07 seconds
๐ Full Cavity
๐ท Mode analysis
๐น Connect to HFSS
pinfo_full = epr.Project_Info(project_path = path_to_project,
project_name = 'Cavity Analysis',
design_name = 'full cav')
INFO 11:21AM [connect]: Connecting to Ansys Desktop API...
INFO 11:21AM [load_ansys_project]: File path to HFSS project found.
INFO 11:21AM [load_ansys_project]: Opened Ansys App
INFO 11:21AM [load_ansys_project]: Opened Ansys Desktop v2020.1.0
INFO 11:21AM [load_ansys_project]: Opened Ansys Project
Folder: D:/Users/Daniel/Cavity-Analysis/
Project: Cavity Analysis
INFO 11:21AM [connect]: Opened active design
Design: full cav [Solution type: Eigenmode]
INFO 11:21AM [get_setup]: Opened setup `setup` (<class 'pyEPR.ansys.HfssEMSetup'>)
INFO 11:21AM [connect]: Connection to Ansys established successfully. ๐
pinfo_full.setup.analyze()
eprh_full = epr.DistributedAnalysis(pinfo_full)
INFO 11:21AM [analyze]: Analyzing setup setup
Design "full cav" info:
# eigenmodes 1
# variations 2
๐น Get HFSS mode and quality results
modes = eprh_full.get_freqs_bare_pd(eprh_full.variations[0])
Fs, Qs = np.array(modes['Freq. (GHz)']), np.array(modes['Quality Factor']) # Get freqs and Q-factors
n_modes = int(pinfo_full.setup.n_modes)
display(modes)
Freq. (GHz) | Quality Factor | |
---|---|---|
mode | ||
0 | 4.236008 | 2552.281993 |
๐น Calculate the EPRs of the modes
eprh_full.set_mode(0)
p_cavity, (โฐ_cav, โฐ_total) = eprh_full.calc_p_electric_volume('cavity')
p_dirt, (โฐ_dirt, โฐ_total) = eprh_full.calc_p_electric_volume('dirt')
print(f' ๐ธ Energy in cavity = {100*p_cavity:.3f}% -> {โฐ_cav:0.2e}')
print(f' ๐ธ Energy in dirt = {100*p_dirt:.3f}% -> {โฐ_dirt:0.2e}')
print(f' ๐ธ Total energy = {โฐ_total:0.2e}')
๐ธ Energy in cavity = 98.041% -> 1.66e-16
๐ธ Energy in dirt = 1.959% -> 3.31e-18
๐ธ Total energy = 1.69e-16
๐ท Life-times
Life-time from HFSS
Fs_Hz = np.array(Convert.toSI(Fs,'GHz')) # Mode freqs in Hz
omegas = 2*np.pi*Fs_Hz # Freqs to angular freqs
taus = Qs/omegas # Life times
print(f' ๐ธ Life-time of mode = {taus[0]*1e3:.3f} ms')
๐ธ Life-time of mode = 0.000 ms
Life-time from EPR
tan_dirt = 4e-7 # Loss tangent of dirt
tau_epr = lambda p, tan, omega: 1/(p*tan*omega) # Easily calculate life time with EPR
tau_cavity = tau_epr(p_dirt, 0, omegas)[0]
tau_dirt = tau_epr(p_cavity, tan_dirt, omegas)[0]
print(f' ๐ธ Cavity life-time = {tau_cavity*1e6:.2f} ns') # Should be infinite since the cavity is a pefect vacum
print(f' ๐ธ Dirt life-time = {tau_dirt*1e6:.2f} ns')
๐ธ Cavity life-time = inf ns
๐ธ Dirt life-time = 95.81 ns
๐ท Losses
๐น Surface loss
eprh_full.set_mode(0)
# --- Surface integral ---
surf = 'cavity'
calcobject = CalcObject([], eprh_full.setup)
vecE = calcobject.getQty("E").smooth()
A = vecE.times_eps()
B = vecE.conj()
A = A.dot(B)
A = A.real()
A = A.integrate_surf(name=surf)
E_subs = A.evaluate(lv=eprh_full._get_lv())
E_surf = E_subs*dirt_width*eps
# --- Volume integral ---
E_total = eprh_full.calc_energy_electric(smooth=True)
p_surf = E_surf/E_total # EPR of surface
Q_surf = 1/tan_surf/p_surf # Q-fact of surface
tau_surf = Q_surf/omegas[0] # Life-time of surface
data['full']['surface'] = {
"EPR": p_surf,
"Q": Q_surf,
"tau": tau_surf
}
print(f' ๐ธ EPR surface = {100*p_surf:.2f}%')
print(f' ๐ธ Q-factor surface = {Q_surf:.2e}')
print(f' ๐ธ Life-time surface = {tau_surf:.2e} seconds \n')
๐ธ EPR surface = 0.70%
๐ธ Q-factor surface = 2.86e+04
๐ธ Life-time surface = 1.07e-06 seconds
๐น Dirt (volume) loss
# Dirt is simulated as much thicker than it actually is (for computation reason).
# Beacuase of that we reduce the loss tangent to an 'effective loss tangent' which is loss_tan*thick_factor
p_dirt, (โฐ_dirt, โฐ_total) = eprh_full.calc_p_electric_volume('dirt')
Q_dirt = 1/(tan_surf*p_dirt)
tau_dirt = Q_dirt/omegas[0]
data['full']['volume'] = {
"EPR": p_dirt,
"Q": Q_dirt,
"tau": tau_dirt
}
print(f' ๐ธ EPR of dirt = {100*p_dirt:0.2f}% ( {โฐ_dirt:.2e} / {โฐ_total:.2e} )')
print(f' ๐ธ Quality factor = {Q_dirt:0.2e}')
print(f' ๐ธ life time = {tau_dirt:0.2e} seconds\n')
๐ธ EPR of dirt = 1.96% ( 3.31e-18 / 1.69e-16 )
๐ธ Quality factor = 1.02e+04
๐ธ life time = 3.84e-07 seconds
Conclusion ๐
Weโll compare the full cavity to the half cavity now. First with the surface integral calculation, then with the volume calculation and finally weโll compare the two approaches (that should yield roughly the same result). Weโll calculate the ratio between the full cavity calculated parameters and half cavity calculated parameters.
# โโโ Surface integral โโโ
EPR_ratio_surf = data['full']['surface']['EPR']/data['half']['surface']['EPR']
Q_ratio_surf = data['full']['surface']['Q']/data['half']['surface']['Q']
tau_ratio_surf = data['full']['surface']['tau']/data['half']['surface']['tau']
# โโโ Volume integral โโโ
EPR_ratio_vol = data['full']['volume']['EPR']/data['half']['volume']['EPR']
Q_ratio_vol = data['full']['volume']['Q']/data['half']['volume']['Q']
tau_ratio_vol = data['full']['volume']['tau']/data['half']['volume']['tau']
# โโโ Volume vs Surface โโโ
EPR_surf_vol = EPR_ratio_surf/EPR_ratio_vol
Q_surf_vol = Q_ratio_surf/Q_ratio_vol
tau_surf_vol = tau_ratio_surf/tau_ratio_vol
print('โ'*10, '๐ Results ๐', 'โ'*10)
print('Ratio full-to-half cavity parameters\n')
print('\tโโโ Surface integral โโโ')
print(f' ๐ธ EPR: {EPR_ratio_surf:.3f}')
print(f' ๐ธ Q-factor: {Q_ratio_surf:.3f}')
print(f' ๐ธ Life-time: {tau_ratio_surf:.3f}\n')
print('\tโโโ Volume integral โโโ')
print(f' ๐ธ EPR: {EPR_ratio_vol:.3f}')
print(f' ๐ธ Q-factor: {Q_ratio_vol:.3f}')
print(f' ๐ธ Life-time: {tau_ratio_vol:.3f}\n')
print('\tโโโ Volume v Surface โโโ')
print(f' ๐ธ EPR: {EPR_surf_vol:.3f}')
print(f' ๐ธ Q-factor: {Q_surf_vol:.3f}')
print(f' ๐ธ Life-time: {tau_surf_vol:.3f}')
โโโโโโโโโโ ๐ Results ๐ โโโโโโโโโโ
Ratio full-to-half cavity parameters
โโโ Surface integral โโโ
๐ธ EPR: 0.454
๐ธ Q-factor: 2.204
๐ธ Life-time: 2.117
โโโ Volume integral โโโ
๐ธ EPR: 0.489
๐ธ Q-factor: 2.044
๐ธ Life-time: 1.964
โโโ Volume v Surface โโโ
๐ธ EPR: 0.928
๐ธ Q-factor: 1.078
๐ธ Life-time: 1.078
pinfo.disconnect()
pinfo_full.disconnect()
Notes on the design ๐
To simplify the problem as much as possible, the cavity is just a โsquashedโ circle.
Create cavity: The steps to create the cavity are as follows: * Create an elipse with itโs major axis being the radius of the cavity, and the minor axis the โsquashedโ radius. * Create a rectengle in the plane of the cavity so that the intersection between the elipse and the rectangle is half of the elipse (symetric along the minor axis) * Select the rectangel and elipse and choose Draw
->Intersect
, creating a new object that is the intersect between them. * Choose the newly created object and click on Draw
->sweep around axis
(the folding sheet icon) to create a 3D โsquashedโ circle.
To create the half cavity, all you need is to move around the intersecting rectange so youโre left with a quarter of the original elipse.
Create dirt: To create the dirt with constant width, the easiest method is by following these steps: * Duplicate the cavity object once * Right click on the duplicate in the side-bar and choose Select
->All Faces
. * Once all the faces are selected you can press Draw
->Surface
->Move Faces Along Normal
, a window will pop up promting you the write a distance, this would be the thickness of the dirt dirt_width
(make sure itโs a negative number). * Take the newly created smaller cavity and duplicate it, this would be the vacuum. Now select the original cavity (the big one) and one of the smaller ones together and press Draw
->Subtract
(make sure to do so in the correct order), this would make a new object which will be our dirt.
You should be left with one object being the cavity and one object being the dirt.
$\dagger$ Make sure that the cavity and the dirt donโt intersect, if they do, you might get wildly wrong solutions