Created
November 2, 2022 21:37
-
-
Save mrakitin/19d82941c814656137e55b84fe5ace6b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"# Generation of equations for PGM Energy pseudo-axis\n", | |
"This notebook is used to derive the equations required to add a energy ($E_{ph}$) pseudo-axis to the Sirepo-Bluesky PGM ophyd object. It uses equations provided by Joe Dvorak. In addition to the Energy pseudo-axis it will require the Sirepo-Bluesky PGM ophyd object to have pseudo-axes for the fixed foxus constant ($c_{ff}$) and the Grating as well as some internal parameters (defined at instantiation). It also assumes that the Sirepo-Bluesky PGM ophyd object already has axes related to the angle of the M2 mirror ($\\Theta_{M2}$) and the grating ($\\Theta_{Gr}$). In the following I assume all distances are in mm and all angels are in degrees. A full list of these parameters is given here\n", | |
"\n", | |
"- $\\Theta_{M2}$/$\\Theta_{Gr}$ : M2/Grating mirror angles, axis from simulation parameters.\n", | |
"- $a_{0}$/$a_{1}$/$a_{2}$/$a_{3}$ : Grating equation parameters, axes from simulation parameters.\n", | |
"- $E_{ph}$ : Photon Energy, required pseudo-axis.\n", | |
"- Grating : Grating pseudo-axis, updates $a_{0}$, $a_{1}$, $k$ and $c_{ff}$ when changed.\n", | |
"- $r_{2}$: output focal length, required pseudo-axis.\n", | |
"- $c_{ff}$ : Fixed Focus Constant, required read-only pseudo-axis, updates on changes to $E_{ph}$ or $r_{2}$.\n", | |
"- $r_{1}$: input focal length, instantiation parameter.\n", | |
"- $m$ : diffraction order (usually +1), instantiation parameters.\n", | |
"- $X_{inc}$/$X_{diff}$ : incident/diffracted X-ray beam angles, instantiation parameters.\n", | |
"- $b$ : bounce direction (1=up, -1=down), instantiation parameter.\n", | |
"\n", | |
"The relationships between these parameters are given by:\n", | |
"\n", | |
"$$\n", | |
"c_{ff} = \\sqrt((B_{0}+B_{1})/B{2})\\\\\n", | |
"\\begin{align}\n", | |
"\\text{where: } B_{0} &= 2A_{1}+4(A_{1}/A_{0})^2+(4+2A_{1}-A_{0}^{2})(\\frac{r_{2}}{r_{1}})\\\\\n", | |
"B_{1} &= -4(A_{1}/A_{0})\\sqrt((\\frac{r_{2}}{r_{1}})^2+2A_{1}(1+r)-A_{0}^{2}(\\frac{r_{2}}{r_{1}}))\\\\\n", | |
"B_{2} &= -4+A_{0}^{2}-4A_{1}+4(A_{1}/A_{0})^2\\\\\n", | |
"A_{0} &= m\\lambda a_{0}\\\\\n", | |
"A_{1} &= -\\frac{1}{2}m\\lambda r_{2}a_{1}\\\\\n", | |
"\\lambda &= (12398.4197/E_{ph})1e-7\\\\\n", | |
"\\end{align}\n", | |
"\\tag{Eqn 1}\n", | |
"$$\n", | |
" \n", | |
"$$\n", | |
"\\Theta_{M2} = \\frac{1}{2}(X_{diff}+X_{inc}+b(180-\\alpha+\\beta))\\\\\n", | |
"\\begin{align}\n", | |
"\\text{where: } \\alpha &=sin^{-1}(-ma_{0}\\lambda /(c_{eff}^{2}-1)+\\sqrt(1+(c_{ff}ma_{0}\\lambda /(c_{eff}^{2}-1))^2))\\\\\n", | |
"\\beta &= sin^{-1}(ma_{0}\\lambda-sin(\\alpha))\\\\\n", | |
"\\lambda &= (12398.4197/E_{ph})1e-7\\\\\n", | |
"\\end{align}\n", | |
"\\tag{Eqn 2}\n", | |
"$$\n", | |
" \n", | |
"$$\n", | |
"\\theta_{GR} = b(90+\\beta)+X_{diff}\n", | |
"\\tag{Eqn 3}\n", | |
"$$\n", | |
" \n", | |
"$$\n", | |
"E_{ph}=(12398.4197/\\lambda)1e-7\\\\\n", | |
"\\begin{align}\n", | |
"\\text{where: } \\lambda &= (sin(\\alpha)+sin(\\beta))/(ma_{0})\\\\\n", | |
"\\beta &= - 90 +b(\\Theta_{Gr} - X_{diff})\\\\\n", | |
"\\alpha &= 80 + \\beta + b(X_{diff} + X_{inc} - 2\\Theta_{M2})\n", | |
"\\end{align}\n", | |
"\\tag{Eqn 4}\n", | |
"$$\n" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": {}, | |
"outputs": [], | |
"source": [ | |
"import numpy as np\n", | |
"# define the instantiation parameters here.\n", | |
"_m=1\n", | |
"_r1=33350 #in mm: 33350 for ARI and 33000 for SXN\n", | |
"_r2=11500 #in mm: 11500 for ARI and 17500 for SXN\n", | |
"_x_inc=90 #in degrees\n", | |
"_x_diff=90 #in degrees\n", | |
"_b=1 #bounce direction, 1 is up -1 is down\n", | |
"_grating='lowE'\n", | |
"_ari_gratings={'lowE':{'a0':50,'a1':.01868,'a2':1.95E-06,'a3':4E-9},\n", | |
" 'HighE':{'a0':50,'a1':.02986,'a2':2.87E-06,'a3':8E-9},\n", | |
" 'HighR':{'a0':200,'a1':.05743,'a2':6.38E-06,'a3':1.5E-8}\n", | |
" }\n", | |
"_sxn_gratings={'LowE':{'a0':150,'a1':.04341,'a2':2.6E-06,'a3':1.5E-8},\n", | |
" 'MedE':{'a0':350,'a1':.0755,'a2':4.95E-06,'a3':2.5E-8},\n", | |
" 'HighE':{'a0':350,'a1':.05739,'a2':4.18E-06,'a3':1.2E-8}\n", | |
" }\n", | |
"_gratings=_ari_gratings\n", | |
"\n", | |
"\n", | |
"def _cff(e_ph, grating, r2, r1=_r1, m=_m, gratings=_gratings):\n", | |
" '''\n", | |
" Returns the fine focus constant given the energy, grating and output focal length.\n", | |
" \n", | |
" Based on the photon energy, grating, the output focal length and several other \n", | |
" instantiation time parameters, seen as keywords, this function returns the fine \n", | |
" focus constant using the relations:\n", | |
" $$c_{ff} = \\sqrt((B_{0}+B_{1})/B{2})\\\\\n", | |
" \\begin{align}\n", | |
" \\text{where: } B_{0} &= 2A_{1}+4(A_{1}/A_{0})^2+(4+2A_{1}-A_{0}^{2})\n", | |
" (\\frac{r_{2}}{r_{1}})\\\\\n", | |
" B_{1} &= -4(A_{1}/A_{0})\\sqrt((1+\\frac{r_{2}}{r_{1}})^2+\n", | |
" 2A_{1}(1+\\frac{r_{2}}{r_{1}})-\n", | |
" A_{0}^{2}(\\frac{r_{2}}{r_{1}})\\\\\n", | |
" B_{2} &= -4+A_{0}^{2}-4A_{2}+4(A_{2}/A_{0})^2\\\\\n", | |
" A_{0} &= m\\lambda a_{0}\\\\\n", | |
" A_{1} &= -\\frac{1}{2}m\\lambda r_{2}a_{1}\\\\\n", | |
" \\lambda &= (12398.4197/E_{ph})1e-7\\\\\n", | |
" \\end{align}\n", | |
" $$\n", | |
"\n", | |
" Units for each parameter are: eV for energies, mm for lengths and mm^{-1}/ \n", | |
" mm^{-2}/ mm^{-3}/ mm^{-4} for the respective grating equation parameters.\n", | |
"\n", | |
" Parameters\n", | |
" ----------\n", | |
" e_ph : float\n", | |
" The photon energy in eV.\n", | |
" grating : string\n", | |
" The grating name.\n", | |
" r2 : float\n", | |
" The output focal length for the PGM in mm \n", | |
" r1 : float, optional\n", | |
" The input focal length for the PGM in mm\n", | |
" m : integer, optional\n", | |
" The diffraction order.\n", | |
" gratings : dict, optional\n", | |
" A dictionary that matches grating names to a dictionary of grating parameters.\n", | |
" \n", | |
" Returns\n", | |
" -------\n", | |
" cff : float\n", | |
" The fine focus constant.\n", | |
" '''\n", | |
" \n", | |
" lambda_ = (12398.4197/e_ph)*1E-7 # wavelength in mm from e_ph in eV\n", | |
" A1 = -0.5*m*lambda_*r2*gratings[grating]['a1']\n", | |
" A0 = m*lambda_*gratings[grating]['a0']\n", | |
" B2 = (-4+A0**2-4*A1+4*(A1/A0)**2)\n", | |
" B1 = -4*(A1/A0)*np.sqrt((1+r2/r1)**2+2*A1*(1+r2/r1)-A0**2*(r2/r1))\n", | |
" B0 = 2*A1+4*(A1/A0)**2+(4+2*A1-A0**2)*(r2/r1)\n", | |
" cff = np.sqrt((B0+B1)/B2)\n", | |
" \n", | |
" return cff\n", | |
"\n", | |
"\n", | |
"def _pgm_angles(e_ph, grating, r2, r1=_r1, m=_m, gratings=_gratings,\n", | |
" x_inc=_x_inc, x_diff=_x_diff, b=_b):\n", | |
" '''\n", | |
" Returns the M2/Grating angles given the photon energy, grating and output focal \n", | |
" length.\n", | |
" \n", | |
" Based on the photon energy, grating, the output focal length and several other \n", | |
" instantiation time parameters, seen as keywords, this function returns the \n", | |
" required angles for the M2 mirror and the grating using the _cff function and \n", | |
" the relations:\n", | |
" $$\n", | |
" \\Theta_{M2} = \\frac{1}{2}(X_{diff}+X_{inc}+b(180-\\alpha+\\beta))\\\\\n", | |
" \\Theta_{GR} = b(90+\\beta)+X_{diff}\n", | |
" \\begin{align}\n", | |
" \\text{where: } \\alpha &=sin^{-1}(-ma_{0}\\lambda /(c_{eff}^{2}-1)+\n", | |
" \\sqrt(1+(c_{ff}ma_{0}\\lambda /(c_{eff}^{2}-1))^2))\\\\\n", | |
" \\beta &= sin^{-1}(ma_{0}\\lambda-sin(\\alpha))\\\\\n", | |
" \\lambda &= (12398.4197/E_{ph})1e-7\\\\\n", | |
" \\end{align}\n", | |
" $$\n", | |
" \n", | |
" Units for each parameter are: eV for energies, mm for lengths, degrees for angles\n", | |
" and mm^{-1}/ mm^{-2}/ mm^{-3}/ mm^{-4} for the respective grating equation \n", | |
" parameters.\n", | |
" \n", | |
" Parameters\n", | |
" ----------\n", | |
" E_ph : float\n", | |
" The photon energy in eV.\n", | |
" grating : string\n", | |
" The grating name.\n", | |
" r2 : float\n", | |
" The output focal length for the PGM in mm \n", | |
" r1 : float, optional\n", | |
" The input focal length for the PGM in mm\n", | |
" m : integer, optional\n", | |
" The diffraction order.\n", | |
" gratings : dict, optional\n", | |
" A dictionary that matches grating names to a dictionary of grating parameters.\n", | |
" x_inc : float, optional\n", | |
" The incident X-ray angle\n", | |
" x_diff : float, optional\n", | |
" The outgoing X-ray angle\n", | |
" b : int, optional\n", | |
" integer indicating the bounce direction: +1 (for upward bounce) or -1 \n", | |
" (for downward bounce)\n", | |
" \n", | |
" Returns\n", | |
" -------\n", | |
" (theta_m2, theta_gr) : (float, float)\n", | |
" The required angles for M2 and the grating in degrees.\n", | |
" '''\n", | |
" ##NOTE if I choose to read in cff from a read-only ophyd signal then I no longer\n", | |
" ## need r2 and r1 as args/kwargs (but I will need cff as an arg)\n", | |
" lambda_ = (12398.4197/e_ph)*1E-7 # wavelength in mm from e_ph in eV\n", | |
" #NOTE the next line may be better read from the read-only axis instead of calculating\n", | |
" cff = _cff(e_ph, grating, r2, r1=r1, m=m, gratings=gratings) \n", | |
" alpha =np.degrees(np.arcsin(-m*gratings[grating]['a0']*lambda_/(cff**2-1)+\n", | |
" np.sqrt(1+(cff*m*gratings[grating]['a0']*lambda_/(cff**2-1))**2)))\n", | |
" beta = np.degrees(np.arcsin(m*gratings[grating]['a0']*lambda_-\n", | |
" np.sin(np.radians(alpha))))\n", | |
" theta_m2 = abs(0.5*(x_diff+x_inc+b*(180-alpha+beta)))\n", | |
" theta_gr = b*(90+beta)+x_diff\n", | |
" \n", | |
" return (theta_m2, theta_gr)\n", | |
"\n", | |
"\n", | |
"def _pgm_energy(theta_m2, theta_gr, grating, m=_m, gratings=_gratings,\n", | |
" x_inc=_x_inc, x_diff=_x_diff, b=_b):\n", | |
" '''\n", | |
" Returns the energy given the M2/grating angles, grating and output focal \n", | |
" length.\n", | |
" \n", | |
" Based on the M2/grating angles, grating, the output focal length and several other \n", | |
" instantiation time parameters, seen as keywords, this function returns the \n", | |
" photon energy using the _cff function and the relations:\n", | |
" \n", | |
" E_{ph}=(12398.4197/\\lambda)1e-7\\\\\n", | |
" \\begin{align}\n", | |
" \\text{where: } \\lambda &= (sin(\\alpha)+sin(\\beta))/(ma_{0})\\\\\n", | |
" \\beta &= - 90 +b(\\Theta_{Gr} - X_{diff})\\\\\n", | |
" \\alpha &= 80 + \\beta + b(X_{diff} + X_{inc} - 2\\Theta_{M2})\n", | |
" \\end{align}\n", | |
" \n", | |
" Parameters\n", | |
" ----------\n", | |
" theta_m2 : float\n", | |
" The angle of the M2 mirror\n", | |
" theta_gr : float\n", | |
" The angle of the Grating\n", | |
" grating : string\n", | |
" The grating name.\n", | |
" m : integer, optional\n", | |
" The diffraction order.\n", | |
" gratings : dict, optional\n", | |
" A dictionary that matches grating names to a dictionary of grating parameters.\n", | |
" x_inc : float, optional\n", | |
" The incident X-ray angle\n", | |
" x_diff : float, optional\n", | |
" The outgoing X-ray angle\n", | |
" b : int, optional\n", | |
" integer indicating the bounce direction: +1 (for upward bounce) or -1 \n", | |
" (for downward bounce)\n", | |
" \n", | |
" Returns\n", | |
" -------\n", | |
" e_ph : float\n", | |
" The photon energy of the PGM in eV.\n", | |
" '''\n", | |
" \n", | |
" beta = - 90 +b*(theta_gr - x_diff)\n", | |
" alpha = 180 + beta + b*(x_diff + x_inc - 2*theta_m2)\n", | |
" lambda_ = (np.sin(np.radians(alpha))+\n", | |
" np.sin(np.radians(beta)))/(m*gratings[grating]['a0'])\n", | |
" e_ph=(12398.4197/lambda_)*1e-7 #energy in eV\n", | |
" \n", | |
" return e_ph" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 2, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"1.4733076918850723" | |
] | |
}, | |
"execution_count": 2, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"_cff(300,_grating,_r2)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"(93.64909152439252, 94.34669916791917)" | |
] | |
}, | |
"execution_count": 3, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"_pgm_angles(40,_grating,_r2)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"396.8068496324921" | |
] | |
}, | |
"execution_count": 4, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"source": [ | |
"_pgm_energy(91.15, 91.373, _grating)" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"metadata": {}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"angles: (90.72909457701365, 90.86866065984296)\n", | |
"energy: 1000.0000000000539\n" | |
] | |
} | |
], | |
"source": [ | |
"angles=_pgm_angles(1000,_grating,_r2)\n", | |
"energy=_pgm_energy(*angles, _grating)\n", | |
"\n", | |
"print (f'angles: {angles}')\n", | |
"print (f'energy: {energy}')" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 6, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": {}, | |
"outputs": [], | |
"source": [] | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3 (ipykernel)", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 3 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython3", | |
"version": "3.7.3" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 2 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment