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

description | here | XRT | RT4XES | SHADOW3 |

|------------------------+---------+--------+---------+---------| | 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_dspacing(d)[source]

set crystal d-spacing (AA)

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_infos()[source]

show useful information on distances/parameters

set_ene0(ene0, d=None)[source]

set the central energy (eV) and relative Bragg angle

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_dth(eDelta)[source]

Delta heta using differential Bragg law

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_axoff0(chi, Rs=None)[source]

get aXoff at the surface of the analyser

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)

get_ay_off(eDelta, rtheta0=None, d=None, Rm=None)[source]

get analyser Y offset for a given energy delta (eV)

get_ene_off(aZoff, rtheta0=None, d=None, Rm=None)[source]

get analyser delta E for a given Z offset

class sloth.inst.rowland.RcVert(*args, **kws)[source]

Rowland circle vertical frame: sample-detector on XZ plane along Z axis

get_pos(vect)[source]

utility method: return ‘vect’ or its rotated form if self.rotHor

get_det_pos()[source]

detector center position [X,Y,Z]

get_ana_pos(chi=0.0)[source]

analyser XYZ center position for a given chi

Parameters:

chi (float, 0. [deg]) – rotation angle on the sagittal plane (hor plane here)

get_miscut_off(alpha=None, Rm=None)[source]

returns horizontal and vertical offsets for a given miscut angle TODO: NOT CORRECT, CHECK THIS!

class sloth.inst.rowland.RcHoriz(*args, **kws)[source]

Rowland circle horizontal frame: sample-analyser on XY plane along Y axis

get_det_pos()[source]

detector position [X,Y,Z]

get_ana_pos(chi=0.0)[source]

analyser XYZ center position for a given chi

Parameters:

chi (float, 0. [deg]) – rotation angle on the sagittal plane (around sample-detector axis)

get_miscut_off(alpha=None, p=None)[source]

returns horizontal and vertical offsets for a given miscut angle TODO: NOT CORRECT CHECK THIS!

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]
  1. Wittry and S. Sun, J. Appl. Phys. 71 (1992) 564

[Pestehe2]
    1. 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