Skip to content

Commit 5310d7e

Browse files
committed
feat: implement calibration and reduction
1 parent 0743f9b commit 5310d7e

File tree

2 files changed

+189
-4
lines changed

2 files changed

+189
-4
lines changed

src/ess/estia/calibration.py

+173
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
import numpy as np
2+
import scipp as sc
3+
4+
from ..reflectometry.normalization import (
5+
reduce_from_events_to_lz,
6+
reduce_from_events_to_q,
7+
reduce_from_lz_to_q,
8+
)
9+
10+
11+
def solve_for_calibration_parameters(Io, Is):
12+
Iopp, Iopa, Ioap, Ioaa = Io
13+
Ipp, Ipa, Iap, Iaa = Is
14+
15+
I0 = 2 * (Iopp * Ioaa - Iopa * Ioap) / (Iopp + Ioaa - Iopa - Ioap)
16+
rho = (Ioaa - Ioap) / (Iopp - Iopa)
17+
alp = (Ioaa - Iopa) / (Iopp - Ioap)
18+
19+
Rspp_plus_Rsaa = (
20+
4
21+
* (rho * alp * Ipp + Iaa + rho * Ipa + alp * Iap)
22+
/ ((1 + rho) * (1 + alp) * I0)
23+
)
24+
Pp = sc.sqrt(
25+
(Ipp + Iaa - Ipa - Iap)
26+
* (alp * (Ipp - Iap) - Iaa + Ipa)
27+
/ (
28+
(rho * alp * Ipp + Iaa + rho * Ipa + alp * Iap)
29+
* (rho * (Ipp - Ipa) - Iaa + Iap)
30+
)
31+
)
32+
Ap = sc.sqrt(
33+
(Ipp + Iaa - Ipa - Iap)
34+
* (rho * (Ipp - Ipa) - Iaa + Iap)
35+
/ (
36+
(rho * alp * Ipp + Iaa + rho * Ipa + alp * Iap)
37+
* (alp * (Ipp - Iap) - Iaa + Ipa)
38+
)
39+
)
40+
Rs = sc.sqrt(
41+
(alp * (Ipp - Iap) - Iaa + Ipa)
42+
* (rho * (Ipp - Ipa) - Iaa + Iap)
43+
/ ((rho * alp * Ipp + Iaa + rho * Ipa + alp * Iap) * (Ipp + Iaa - Ipa - Iap))
44+
)
45+
46+
Pa = -rho * Pp
47+
Aa = -alp * Ap
48+
49+
Rspp_minus_Rsaa = Rs * Rspp_plus_Rsaa
50+
Rspp = (Rspp_plus_Rsaa + Rspp_minus_Rsaa) / 2
51+
Rsaa = Rspp_plus_Rsaa - Rspp
52+
53+
return I0 / 4, Pp, Pa, Ap, Aa, Rspp, Rsaa
54+
55+
56+
def generate_valid_calibration_parameters():
57+
I0 = np.random.random()
58+
Pp = np.random.random()
59+
Pa = -np.random.random()
60+
Ap = np.random.random()
61+
Aa = -np.random.random()
62+
Rspp = np.random.random()
63+
Rsaa = Rspp * np.random.random()
64+
return tuple(map(sc.scalar, (I0, Pp, Pa, Ap, Aa, Rspp, Rsaa)))
65+
66+
67+
def intensity_from_parameters(I0, Pp, Pa, Ap, Aa, Rpp, Rpa, Rap, Raa):
68+
return (
69+
I0
70+
* (
71+
Rpp * (1 + Ap) * (1 + Pp)
72+
+ Rpa * (1 - Ap) * (1 + Pp)
73+
+ Rap * (1 + Ap) * (1 - Pp)
74+
+ Raa * (1 - Ap) * (1 - Pp)
75+
),
76+
I0
77+
* (
78+
Rpp * (1 + Aa) * (1 + Pp)
79+
+ Rpa * (1 - Aa) * (1 + Pp)
80+
+ Rap * (1 + Aa) * (1 - Pp)
81+
+ Raa * (1 - Aa) * (1 - Pp)
82+
),
83+
I0
84+
* (
85+
Rpp * (1 + Ap) * (1 + Pa)
86+
+ Rpa * (1 - Ap) * (1 + Pa)
87+
+ Rap * (1 + Ap) * (1 - Pa)
88+
+ Raa * (1 - Ap) * (1 - Pa)
89+
),
90+
I0
91+
* (
92+
Rpp * (1 + Aa) * (1 + Pa)
93+
+ Rpa * (1 - Aa) * (1 + Pa)
94+
+ Rap * (1 + Aa) * (1 - Pa)
95+
+ Raa * (1 - Aa) * (1 - Pa)
96+
),
97+
)
98+
99+
100+
def correction_matrix(Pp, Pa, Ap, Aa):
101+
return [
102+
[
103+
(1 + Pp) * (1 + Ap),
104+
(1 + Pp) * (1 - Ap),
105+
(1 - Pp) * (1 + Ap),
106+
(1 - Pp) * (1 - Ap),
107+
],
108+
[
109+
(1 + Pp) * (1 + Aa),
110+
(1 + Pp) * (1 - Aa),
111+
(1 - Pp) * (1 + Aa),
112+
(1 - Pp) * (1 - Aa),
113+
],
114+
[
115+
(1 + Pa) * (1 + Ap),
116+
(1 + Pa) * (1 - Ap),
117+
(1 - Pa) * (1 + Ap),
118+
(1 - Pa) * (1 - Ap),
119+
],
120+
[
121+
(1 + Pa) * (1 + Aa),
122+
(1 + Pa) * (1 - Aa),
123+
(1 - Pa) * (1 + Aa),
124+
(1 - Pa) * (1 - Aa),
125+
],
126+
]
127+
128+
129+
def compute_calibration_factors(Io, Is):
130+
I0, Pp, Pa, Ap, Aa, _, _ = solve_for_calibration_parameters(Io, Is)
131+
return I0, correction_matrix(Pp, Pa, Ap, Aa)
132+
133+
134+
def linsolve(A, b):
135+
return np.linalg.solve(
136+
np.stack([[a.values for a in row] for row in A]),
137+
np.stack([bi.values for bi in b], axis=-1),
138+
)
139+
140+
141+
def computer_reflectivity_calibrate_on_q(
142+
reference_supermirror,
143+
reference_polarized_supermirror,
144+
sample,
145+
qbins,
146+
):
147+
reference_supermirror = [
148+
reduce_from_lz_to_q(i, qbins) for i in reference_supermirror
149+
]
150+
reference_polarized_supermirror = [
151+
reduce_from_lz_to_q(i, qbins) for i in reference_polarized_supermirror
152+
]
153+
sample = [reduce_from_events_to_q(i, qbins) for i in sample]
154+
I0, C = compute_calibration_factors(
155+
reference_supermirror, reference_polarized_supermirror
156+
)
157+
return [i / I0 for i in linsolve(C, sample)]
158+
159+
160+
def computer_reflectivity_calibrate_on_lz(
161+
reference_supermirror,
162+
reference_polarized_supermirror,
163+
sample,
164+
wbins,
165+
qbins,
166+
):
167+
sample = reduce_from_events_to_lz(sample, wbins)
168+
I0, C = compute_calibration_factors(
169+
reference_supermirror, reference_polarized_supermirror
170+
)
171+
sample = linsolve(C, sample)
172+
I0 = reduce_from_lz_to_q(I0, qbins)
173+
return [i / I0 for i in reduce_from_lz_to_q(sample, qbins)]

src/ess/reflectometry/normalization.py

+16-4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,18 @@
1919
)
2020

2121

22+
def reduce_from_events_to_q(da, qbins):
23+
return da.bins.concat().hist(Q=qbins)
24+
25+
26+
def reduce_from_events_to_lz(da, wbins):
27+
return da.bins.concat(('stripe',)).hist(wavelength=wbins)
28+
29+
30+
def reduce_from_lz_to_q(da, qbins):
31+
return da.flatten(to='Q').hist(Q=qbins)
32+
33+
2234
def reduce_reference(
2335
reference: ReducibleData[ReferenceRun],
2436
wavelength_bins: WavelengthBins,
@@ -39,7 +51,7 @@ def reduce_reference(
3951
)
4052
reference = reference.bins.assign_masks(invalid=sc.isnan(R))
4153
reference = reference / R
42-
out = reference.bins.concat(('stripe',)).hist(wavelength=wavelength_bins)
54+
out = reduce_from_events_to_lz(reference, wavelength_bins)
4355

4456
if 'position' in reference.coords:
4557
out.coords['position'] = reference.coords['position'].mean('stripe')
@@ -58,8 +70,8 @@ def reduce_sample_over_q(
5870
5971
Returns reflectivity as a function of :math:`Q`.
6072
"""
61-
h = reference.flatten(to='Q').hist(Q=qbins)
62-
R = sample.bins.concat().bin(Q=qbins) / h.data
73+
h = reduce_from_lz_to_q(reference, qbins)
74+
R = reduce_from_events_to_q(sample, qbins) / h.data
6375
R.coords['Q_resolution'] = sc.sqrt(
6476
(
6577
(reference * reference.coords['Q_resolution'] ** 2)
@@ -83,7 +95,7 @@ def reduce_sample_over_zw(
8395
8496
Returns reflectivity as a function of ``blade``, ``wire`` and :math:`\\wavelength`.
8597
"""
86-
R = sample.bins.concat(('stripe',)).bin(wavelength=wbins) / reference.data
98+
R = reduce_from_events_to_lz(sample, wbins) / reference.data
8799
R.masks["too_few_events"] = reference.data < sc.scalar(1, unit="counts")
88100
return R
89101

0 commit comments

Comments
 (0)