Skip to content

Instantly share code, notes, and snippets.

@mrakitin
Created November 2, 2022 21:37
Show Gist options
  • Save mrakitin/19d82941c814656137e55b84fe5ace6b to your computer and use it in GitHub Desktop.
Save mrakitin/19d82941c814656137e55b84fe5ace6b to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"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