sloth.inst: working with instrumentation
sloth.inst.rowland: Rowland circle geometry (=XES spectrometers)
Rowland circle geometry
Units here:
angular [deg] spatial [mm] energy [eV]
Table of variables and conventions
|------------------------+---------+--------+---------+---------| | Bragg angle | heta | heta | heta | heta | | Rowland circle radius | Rm | Rm | R/2 | | | crystal bending radius | 2*Rm | 2*Rm | R | | | rays direction | Y | Y | X | Y | | sagittal direction | X | X | Y | X | | meridional direction | Z | Z | Z | | | sample pos (X,Y,Z) | (0,0,0) | | (0,0,0) | | | | | | | |
Note
The sagittal plane local reference system is a 2D coordinate
system. All analysers are sitting/sliding on this plane. The origin
is located at the central analyser axis at “aL” parametric distance
from the central analyser surface (away from the sample). The
coordinates are (aXoff, SagOff). aXoff is positive on the right
of the central analyser when looking at the sample. SagOff is
positive toward the sample.
Note
The following code has been tested with a 3D CAD model built using
SolidWorks: RowlandSketchPrototype-v1512
Note
Lens equations used here are taken from:
Suortti et al., J. Synchrotron Rad. 6, 69 (1999), DOI: 10.1107/S0909049599000291
Podorov et al., J. Phys. D: Appl. Phys 34, 2363 (2001), DOI: 10.1088/0022-3727/34/15/317
Meridional
p0 = 2 * Rm * sin(theta0 - alpha) q0 = 2 * Rm * sin(theta0 + alpha)
p0/p + q0/q = 2
Sagittal
1/p + 1/q = ( sin(theta0 - alpha) + sin(theta0 + alpha) ) / Rs
RT4XES
ID26specVII.m
sample at (0,0,0); crystal at (Xa,0,Za); detector at (0,0,Zd=2*Za)
- sloth.inst.rowland.cs_h(c, R)[source]
Height of the circular segment, given its radius R and chord length c See: [http://en.wikipedia.org/wiki/Circular_segment]
- sloth.inst.rowland.acenx(n, asx=25.0, agx=5.0)[source]
n-th analyser center (starting from 0!) in x, given its size (asx) and gap between two (agx) in mm
- sloth.inst.rowland.det_pos_rotated(dxyz, drot=35.0, doffsets=[0, 0])[source]
return the detector positions in a rotated reference system with the origin at the sample
- Parameters:
dxyz (numpy array of floats) – [X, Y, Z] detector position in the global coordinate system (detector assumed on the YZ plane)
drot (float [35.]) – angle of rotation, counter-clock-wise, around X axis
doffsets (numpy array of floats [0, 0]) – [Y, Z] offsets of the detector reference system origin
- Returns:
[dy, dz] – absolute positions of the detector stages NOTE: the (dy, dz) sign here is given as the convention setted during the commissioning in Aug 2017
- Return type:
numpy array of floats
- class sloth.inst.rowland.RowlandCircle(Rm=500.0, theta0=0.0, alpha=0.0, d=None, aW=0.0, aWext=0.0, rSext=0.0, aL=0.0, bender_version=None, bender=(0.0, 0.0, 0.0), actuator=(0.0, 0.0), inCircle=False, useCm=False, showInfos=True, **kws)[source]
Rowland circle geometry
- set_theta0(theta0, showInfos=None)[source]
set correct attributes for a given theta0 (Bragg angle = center theta)
- Returns:
None (set attributes)
self.theta0 (in degrees)
self.rtheta0 (in radians)
self.sd (sample-detector distance (independent of lpha?))
self.p (sample-analyser distance)
self.q (analyser-detector distance)
self.Rs (sagittal radius (analyser center, self.aL == 0.))
- get_theta(ene=None, d=None, isDeg=True)[source]
get theta angle (deg or rad, controlled by isDeg var) for a given energy (eV) and d-spacing
- get_ene(theta=None, d=None, isDeg=True)[source]
get energy (eV) for a given angle (deg) and d-spacing
- get_chi(aXoff, Rs=None, aL=None, inDeg=True)[source]
get chi angle in sagittal focusing using offset from centre analyser (aXoff)
- get_chi2(aN=1.0, aWext=None, Rs=None, rSext=None, inDeg=True)[source]
get chi angle in sagittal focusing using touching/connected analysers
Description
Using the extended radius Rsp=Rs+rSext, can be calculated as aN times the chi/2 of the first analyser given by:
chi/2 = tan((aWext/2)/Rsp)
- param aN:
n-th analyser (0 is the central one)
- type aN:
float, 1.
- get_ana_dist(chi, aN=1.0, aW=None, Rs=None, inDeg=True)[source]
get analyser-analyser distance at Rs
- get_axoff(chi, Rs=None, aL=None)[source]
get aXoff for the pivot point when chi is known (simple case)
- get_axoff_line(aXoffMin, SagOffMin, degRot=0.0, Rs=None, aL=None)[source]
get aXoff for the pivot point when only a linear trajectory is known
Description
The local sagittal cartesian coordinate system is assumed: the origin is at the pivot point of the central analyser, the abscissa is pointing toward the center of the sagittal circle and the ordinate is pointing on the right side when looking in the abscissa direction. In the following is given the solution of the linear equations system consisting in the interception of the sagittal circle with the linear trajectory of the pivot point, that is:
(x-Rs-aL)^2 + y^2 - (Rs+aL)^2 = 0 x = x0 - d*cos(phi) y = y0 + d*sin(phi)
where:
x is SagOff y is aXoff x0, y0 is SagOffMin, aXoffMin at minimum Rs phi is degRot
d is the distance of x, y from x0, y0 on the local polar coordinate system of the pivot point
- param aXoffMin, SagOffMin:
coordinates of the minimum position of the pivot point on the linear trajectory on the sagittal plane.
- type aXoffMin, SagOffMin:
float
- param degRot:
angle (deg) of the linear trajectory with respect to the abscissa (horizontal)
- type degRot:
float, 0.
- returns:
aXoff1
- rtype:
float
- get_sag_off(aXoff, Rs=None, aL=None, retAll=False)[source]
analyser sagittal offset from the center one (Y-like direction)
- Parameters:
aXoff (float, required position at the pivot point (will give) – a wrong result using the position at the analyser surface)
retAll (boolean, False) – control return
- Returns:
if retAll (list of float) – [chi_angle_deg, aXoff, SagOff, chi0_angle_deg, aXoff0, SagOff0] where the 0 is referred to the case with aL=0
else – float
SagOff
- get_sag_off0(aXoff)[source]
quick wrap to get the sagittal offset at the analyser surface, use get_sag_off() for full control!
- get_sag_off_mots(aXoff, degRot=0.0, pivotSide=10.0, Rs=None, aL=None)[source]
motors positions for sagittal offset TODO: not working yet, sagoff also negative
- get_bender_pos(aN=5, bender=None, Rs=None, aL=None, rSext=None, bender_version=None)[source]
get the position (aXoff, SagOff) of the bender point (B)
- get_bender_mot(bender_pos, actuator=None, bender_version=None)[source]
get the motor position of the bender, given its point position (B) and the actuator specifications, plus the version of the mechanics
- Parameters:
bender_pos (tuple of floats) – (bender_axoff_mm, bender_sagoff_mm)
actuator (tuple of floats, None) – (axoff_actuator_mm, length_actuator_mm)
bender_version (version of the mechanics) – 0 -> prototype 1 -> pantograph 2017
- get_az_off(eDelta, rtheta0=None, d=None, Rm=None)[source]
get analyser Z offset for a given energy delta (eV)
- class sloth.inst.rowland.RcVert(*args, **kws)[source]
Rowland circle vertical frame: sample-detector on XZ plane along Z axis
- class sloth.inst.rowland.RcHoriz(*args, **kws)[source]
Rowland circle horizontal frame: sample-analyser on XY plane along Y axis
sloth.inst.dthetaxz: analytical expressions for \(\Delta\theta\) (=crystal analyzers)
Analytical expression of $Delta heta (x, z)$ from Wittry
- sloth.inst.dthetaxz.dThetaXZ(x, z, thetab, case=None)[source]
- Analytical espression of the angular deviation from Bragg
reflection over a diffractor in conventional point-to-point focusing geometries
- x, zmasked array of floats
2D meshgrid where to evaluate dThetaXZ
- thetabfloat
Bragg angle [deg]
- caseint or str
diffractor geometries 1 or ‘Johann’ or ‘Jn’ [cylindrical] 2 or ‘Johansson’ or ‘Js’ [cylindrical] 3 or ‘Spherical plate’ or ‘Spherical Jn’ or ‘SphJn’ 4 or ‘Spherical Johansson’ or ‘Spherical Js’ or ‘SphJs’ 5 or ‘Wittry’ or ‘Toroidal Js’ or ‘TorJs’ 6 or ‘Js 45 deg focusing’ or ‘Js45focus’ 7 or ‘Js focusing’ or ‘JsFocus’ 8 or ‘Berreman’ 9 or ‘Jn focusing’ or ‘JnFocus’
dThetaXZ : 2D masked array
The following expression is taken from table I in [Wittry:1992_JAP]. This is the same of Eq.12-13 in [Pestehe2] and holds within the following approximations:
the source is an ideal point source located on the Rowland circle
the diffractor size is small compared with the radius of the focal circle
\[\]egin{eqnarray}label{eq:dthetaxz} Delta heta (x,z) = A_1 x^2 + A_2 x^3 + A_3 z^2 + A_4 xz^2
- onumber
where:
- onumber
A_1 = cot heta_B left( 1-
rac{1}{2R_{1}} ight) onumber
A_2 = cot^2 heta_B left( 1-
rac{1}{2R_{1}} ight) onumber
A_3 =
rac{ an heta_B}{2} left[ rac{1}{R_{2}} - rac{1}{R_{2}^{prime}} + rac{1}{sin heta_{B}^{2}} left( rac{2}{R_{2}^{prime}} - rac{1}{R_{2}} -1 ight) - A_{4}^{prime} ight] onumber
A_4 =
rac{1}{2} left[ rac{1}{R_{2}} + rac{1}{sin heta_{B}^{2}} left( rac{2}{R_{2}^{2}} - rac{1}{R_{2}} -2 ight) ight] - rac{A_{4}^{prime}}{2} onumber
A_4^{prime} =
rac{1-R_{2}^{prime}}{R_{2}^{prime}^{2}} onumber
end{eqnarray}
[Wittry:1992_JAP]Wittry and S. Sun, J. Appl. Phys. 71 (1992) 564
[Pestehe2]Pestehe, J. Appl. Cryst. 45 (2012) 890-901
The parametrization is expressed with 4 radii: 1) in the meridional (dispesion) direction (x), R$_{1}$ and R$_{1}^prime$ and 2) in the sagittal (focusing) direction (z), R$_{2}$ and R$_{2}^prime$. In each direction the two radii, R and R$^prime$, are for the crystal surface and planes, respectively. The implemented cases are the following ones:
|------+----------------------+----------+----------------+------------------+------------------| | Case | Name | R$_{1}$ | R$_{1}^prime$ | R$_{2}$ | R$_{2}^prime$ | | | | surface | planes | surface | planes | |------+----------------------+----------+----------------+------------------+------------------| | 1 | Johann (Jn) | 1. | 1. | $infty$ | $infty$ | | 2 | Johansson (Js) | 0.5 | 1. | $infty$ | $infty$ | | 3 | Spherical Jn (SphJn) | 1. | 1. | 1. | 1. | | 4 | Spherical Js (SphJs) | 0.5 | 1. | 0.5 | 1. | | 5 | Wittry (TorJs) | 0.5 | 1. | 1. | 1. | | 6 | Js 45 deg focusing | 0.5 | 1. | 0.5 | 0.5 | | 7 | Js focusing | 0.5 | 1. | $sin^2( heta)$ | $sin^2( heta)$ | | 8 | Berreman | $infty$ | 1. | $sin^2( heta)$ | $sin^2( heta)$ | | 9 | Jn focusing | 1. | 1. | $sin^2( heta)$ | $sin^2( heta)$ | |------+----------------------+----------+----------------+------------------+------------------|
It is important to note that all the coordinates are given in units of R$_{1}^prime$, the bending radius of the crystal planes. This is crucial for converting to real dimensions (mm).
- sloth.inst.dthetaxz.getMeshMasked(mask='circular', r1p=1000.0, cryst_x=50.0, cryst_z=10.0, csteps=1000j)[source]
returns two 2D masked arrays representing a (flat) grid of the crystal surface
- Parameters:
mask (str, 'circular') – shape of the mask: ‘circular’ or ‘rectangular’
r1p (float, [1000.]) – bending radius of the crystal planes in mm (used only to get the mesh in normlized units)
cryst_x (float, [50.]) – radius of circular analyzer in mm (for rectangular mask, this is half side in meridional/dispersive x-direction)
cryst_z (float [10.]) – half side in sagittal/focusing z-direction of the rectangular analyzer in mm
csteps (grid steps (given as imaginary number!) [1000j]) –
- sloth.inst.dthetaxz.getDthetaDats(mxx, mzz, wrc=0.000125, cases=['Johann', 'Johansson', 'Spherical plate', 'Wittry'], angles=[15, 45, 75])[source]
calculates data (see returns for details) in given loops
- Parameters:
mzz (mxx,) –
wrc (width of the analyzer rocking curve in rad [1.25E-4]) –
cases (list of str, see cases in dThetaXZ()) –
angles (list of int/floats, Bragg angles) –
- Returns:
dd (dictionary of dictionaries, for each case in cases)
Lists – dd[case][‘thetaB’] : angles #dd[case][‘dth’] : $Delta heta$(x,z) #dd[case][‘mdth’] : effective $Delta heta$(x,z) dd[case][‘sa’] : solid angle dd[case][‘eres’] : energy resolution
NOTE (dth, mdth not stored (too much space in memory!))
- sloth.inst.dthetaxz.writeScanDats(dd, fname, scanLabel=None, motpos=None)[source]
writes 1D scan data to SPEC file (refer to ‘getMeshMasked’ and ‘getDthetaDats
plots related to dthetaxz
- sloth.inst.dthetaxz_plot.plotEffScatt(xx, zz, wrc=0.000125, cases=['Johann', 'Johansson', 'Spherical plate', 'Wittry'], casesLabels=None, angles=[15, 45, 75], xyFigHalfRange=None, xyTicks=0.1, xlabel='x, mer. (R$_{m}^{\\prime}$)', ylabel='z, sag. (R$_{m}^{\\prime}$)', figName='fig1', xyFigSize=(1500, 900), figDpi=150, fontSize=8, nlevels=15, rowSpan=2, colSpan=2, xylab=(0.025, 0.97), ylabshift=-0.3, plotMask=True, plotVert=False, absWrc=False, cbarShow=True, cbarTicks=2.5e-05, cbarOrientation='vertical', cbarLabel='$\\Delta \\theta$', figCmap=<matplotlib.colors.LinearSegmentedColormap object>, figOut=None)[source]
plots the effective scattering angle given a masked array
- Parameters:
zz (xx,) – dThetaXZ() is calculated over them
wrc (float, 1.25E-4) – maximum accepted angular range
cases (list of str, ['Johann', 'Johansson', 'Spherical plate', 'Wittry']) – accepted cases by dThetaXZ (tip: nicely shows for 4 items)
casesLabels (list of str, None) – labels for the cases (if none, it takes cases strings)
angles (list of floats, [15, 45, 75]) – theta angles (tip: nicely shows for 3 items)
figName (str, 'fig1') – name of the figure
xyFigHalfRange (float, None) – set figure dimensions in units of r1p (crystal bending radius) and shows a reference circle with this radius
xyTicks (float, 0.1) – spacing between major ticks (labels) in x and y - units of r1p
xlabel (str, r'x, mer. (R$_{m}^{prime}$)') – label x axis
ylabel (str, r'z, sag. (R$_{m}^{prime}$)') – label y axis
xyFigSize (list of int or floats, [10*dpi, 6*dpi]) – x, y size of the figure
figDpi (int, 150) – figure resolution
figOut ([None]) – figure to save
fontSize (int, 8) –
- nlevelsint, 15
number of color levels
- colSpanint, 2
number of columns to span for each subplot (useful if cbarOrientation==’vertical’)
- rowSpanint, 2
number of row to span for each subplot (useful if cbarOrientation==’horizontal’)
- xylabtuple of floats, (0.025, 0.97)
position of the angles label (showing theta) in ‘figure fraction’ units
- xylabshiftfloat, -0.3
shift (‘figure fraction’ units) xylab[1] each subplot
- plotMaskboolean, True
to show the mask
- plotVert: boolean, False
plot vertical scattering
- absWrcboolean, False
to show absolute $Delta heta$
- cbarShowboolean, True
to show the color bar
- cbarTicksfloat, 2.5E-5
spacing between color bar ticks
- cbarOrientationstr, ‘vertical’
orientation of the colorbar: ‘vertical’ or ‘horizontal’
- Returns:
- Return type:
None
- sloth.inst.dthetaxz_plot.plotScanThetaFile(fname, scans, signal='eres', xlims=None, ylims=None, ylog=True, yscale=1, caseScale='Js', plotDeeShells=True, showLegend=True, figName='fig1', figSize=(5, 5), figDpi=150, fontSize=10)[source]
plot 1D $ heta_{B}$ scans from SPEC file
- Parameters:
fname (SPEC file name (refer writeScanDats)) –
scans (list of scans) –
signal (string, 'eres') –
xlims (tuple, None) –
ylims (tuple, None) –
ylog (boolean, True) – sets y in log scale
yscale (int or float, 1) – scale factor for y
caseScale (str, 'Js') – case to apply yscale
plotDeeShells (boolean, True) – plots the energy resolution for K, L$_{2,3}$ and M$_{4,5}$ shells
showLegend (boolean, True) – show the legend on the plot
figName (str, 'fig1') –
figSize (tuple, (5,5)) –
figDpi (int or float, 150) –
fontSize (int or float, 10) –
- Returns:
- Return type:
None