Skip to content

Commit f64f6a0

Browse files
committed
ENH: add analysis of chi sensativity
TLDR; 7mdeg / .5mdeg is enough
1 parent 7b3a369 commit f64f6a0

File tree

1 file changed

+115
-0
lines changed

1 file changed

+115
-0
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
# %% [markdown]
2+
# # Sensitivity to χ missalignment on 2ϴ to 2θ correction
3+
4+
5+
# %%
6+
import dataclasses
7+
8+
import matplotlib as mpl
9+
import matplotlib.pyplot as plt
10+
import numpy as np
11+
from multihead.config import AnalyzerConfig
12+
from multihead.corrections import tth_from_z
13+
from scipy import optimize
14+
15+
from hrd_tools.xrt import CrystalProperties
16+
17+
# %%
18+
mpl.rcParams["savefig.dpi"] = 300
19+
20+
# %% [markdown]
21+
#
22+
# The error gets large with both the displacment across the detector
23+
# and the detector arm angle
24+
25+
# %%
26+
27+
props = CrystalProperties.create(E=40)
28+
29+
# Configure analyzer with realistic parameters
30+
cfg = AnalyzerConfig(
31+
910, # R: sample to crystal distance (mm)
32+
120, # Rd: crystal to detector distance (mm)
33+
props.bragg_angle,
34+
2 * props.bragg_angle,
35+
detector_roll=0,
36+
)
37+
38+
z = 15
39+
40+
41+
fig, (ax1, ax2) = plt.subplots(1, 2, layout="constrained", sharey=True)
42+
43+
44+
def one_z(z, ax):
45+
arm_angle = np.linspace(2, 88)
46+
baseline, _ = tth_from_z(z, arm_angle, cfg)
47+
for chi in [0.0001, 0.001, 0.01]:
48+
corrected_tths, _ = tth_from_z(
49+
z, arm_angle, dataclasses.replace(cfg, crystal_roll=chi)
50+
)
51+
(ln,) = ax.plot(
52+
arm_angle, (baseline - corrected_tths) * 1000, label=rf"$\chi$={chi}"
53+
)
54+
corrected_tths, _ = tth_from_z(
55+
-z, arm_angle, dataclasses.replace(cfg, crystal_roll=chi)
56+
)
57+
ax.plot(arm_angle, (baseline - corrected_tths) * 1000, color=ln.get_color())
58+
59+
ax.axhline(1e-1, color=".5", ls="--")
60+
ax.axhline(-1e-1, color=".5", ls="--")
61+
62+
ax.legend(loc="best")
63+
ax.set_title(rf"$z_d$={z}mm")
64+
ax.set_xlabel(r"arm $2\Theta$ (deg)")
65+
66+
67+
def one_angle(arm_angle, ax):
68+
z = np.linspace(-20, 20, 256)
69+
baseline, _ = tth_from_z(z, arm_angle, cfg)
70+
for chi in [0.0001, 0.001, 0.01]:
71+
corrected_tths, _ = tth_from_z(
72+
z, arm_angle, dataclasses.replace(cfg, crystal_roll=chi)
73+
)
74+
ax.plot(z, (baseline - corrected_tths) * 1000, label=rf"$\chi$={chi}")
75+
76+
ax.axhline(1e-1, color=".5", ls="--")
77+
ax.axhline(-1e-1, color=".5", ls="--")
78+
79+
ax.legend()
80+
ax.set_title(rf"$2\Theta$={arm_angle}deg")
81+
ax.set_xlabel(r"arm $2\Theta$ (deg)")
82+
83+
84+
ax1.set_ylabel(r"scatter $\Delta 2\theta$ (mdeg)")
85+
86+
one_z(z, ax2)
87+
one_angle(45, ax1)
88+
89+
90+
plt.show()
91+
92+
# %%
93+
94+
zd = 15
95+
arm_angle = 88
96+
delta_tth = 1e-5
97+
98+
baseline_tth, _ = tth_from_z(zd, arm_angle, cfg)
99+
100+
101+
def f(chi, delta):
102+
corrected_tth, _ = tth_from_z(
103+
zd, arm_angle, dataclasses.replace(cfg, crystal_roll=chi)
104+
)
105+
106+
return delta - (-corrected_tth + baseline_tth)
107+
108+
109+
chi_limit = optimize.root_scalar(f, args=(delta_tth,), bracket=[0, 0.01])
110+
111+
print(
112+
f"at z_d={zd}mm and 2ϴ={arm_angle}deg the maximum χ "
113+
f"to stay under Δ2θ ≤ {delta_tth * 1000:.2g}mdeg "
114+
f"is {1000 * chi_limit.root:.2g}mdeg"
115+
)

0 commit comments

Comments
 (0)