Skip to content

Commit bdaa4e3

Browse files
authored
Merge pull request #99 from igresh/delta_residual_fix
Delta residual fix
2 parents 1be91bf + 30fa1ec commit bdaa4e3

3 files changed

Lines changed: 69 additions & 7 deletions

File tree

refellips/dataSE.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22

3-
""""
3+
"""
44
A basic representation of a 1D dataset
55
"""
66

refellips/objectiveSE.py

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,28 @@
1818
from refnx._lib import flatten
1919

2020

21+
def circular_distance(angle1, angle2, period=360):
22+
"""
23+
Calculates the circular distance between two angles.
24+
Units (rad or deg) do not matter as long as they are
25+
consistent.
26+
27+
Parameters
28+
----------
29+
angle1 : float, np.ndarray
30+
First angle
31+
angle2 : float, np.ndarray
32+
Second angle
33+
period : float
34+
The period of the circular domain (e.g.,360 for full circle).
35+
36+
Returns:
37+
float or np.ndarray: The shortest circular distance between the angles.
38+
"""
39+
diff = np.abs(angle1 - angle2)
40+
return np.minimum(diff, period - diff)
41+
42+
2143
class ObjectiveSE(BaseObjective):
2244
"""
2345
Objective function for using with curvefitters such as
@@ -178,9 +200,9 @@ def residuals(self, pvals=None):
178200

179201
wavelength, aoi, psi_d, delta_d = self.data.data
180202
wavelength_aoi = np.c_[wavelength, aoi]
181-
182203
psi, delta = self.model(wavelength_aoi)
183-
return np.r_[psi - psi_d, delta - delta_d]
204+
delta_err = circular_distance(delta, delta_d, period=360)
205+
return np.r_[psi - psi_d, delta_err]
184206

185207
def chisqr(self, pvals=None):
186208
"""
@@ -369,16 +391,16 @@ def logl(self, pvals=None):
369391

370392
psi, delta = self.model(wavelength_aoi)
371393

372-
model = np.r_[psi, delta]
373-
374394
logl = 0.0
375395

376396
# TODO investigate ellipsometry uncertainties
377397
# here just set it to unity
378398
y_err = 1
379399
if self.lnsigma is not None:
400+
_model = np.r_[psi, delta]
380401
var_y = (
381-
y_err * y_err + np.exp(2 * float(self.lnsigma)) * model * model
402+
y_err * y_err
403+
+ np.exp(2 * float(self.lnsigma)) * _model * _model
382404
)
383405
else:
384406
var_y = y_err**2
@@ -387,7 +409,8 @@ def logl(self, pvals=None):
387409
if self.weighted:
388410
logl += np.log(2 * np.pi * var_y)
389411

390-
logl += (np.r_[psi_d, delta_d] - model) ** 2 / var_y
412+
res = self.residuals(None)
413+
logl += (res) ** 2 / var_y
391414

392415
# nans play havoc
393416
if np.isnan(logl).any():

refellips/tests/test_refellips.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,3 +477,42 @@ def test_TaucLorentz():
477477

478478
assert_allclose(psi, data.psi, rtol=0.0176)
479479
assert_allclose(delta, data.delta, rtol=0.0066)
480+
481+
482+
def test_residuals():
483+
"""
484+
Specifically testing for correct delta error handling (delta is an angle between 0 and 360)
485+
"""
486+
wavelength = np.linspace(400, 900, 100)
487+
aoi = 70
488+
489+
si = load_material("silicon")
490+
sio2 = load_material("silica")
491+
polymer = Cauchy(A=1.43, B=0.0005)
492+
solvent = Cauchy(A=1.45, B=0.0005)
493+
494+
polymer_layer_1 = polymer(55)
495+
polymer_layer_2 = polymer(45)
496+
497+
struc_1 = solvent() | polymer_layer_1 | sio2(20) | si()
498+
struc_2 = solvent() | polymer_layer_2 | sio2(20) | si()
499+
500+
model_1 = ReflectModelSE(struc_1)
501+
model_2 = ReflectModelSE(struc_2)
502+
503+
psi_1, delta_1 = model_1(np.c_[wavelength, np.ones_like(wavelength) * aoi])
504+
psi_2, delta_2 = model_2(np.c_[wavelength, np.ones_like(wavelength) * aoi])
505+
faux_data = DataSE(
506+
[wavelength, np.ones_like(wavelength) * aoi, psi_1, delta_1]
507+
)
508+
509+
obj = ObjectiveSE(model=model_2, data=faux_data)
510+
res = obj.residuals()
511+
obj_psi_res = res[: int(len(res) / 2)]
512+
obj_delta_res = res[int(len(res) / 2) :]
513+
514+
test_psi_res = psi_2 - psi_1
515+
test_delta_res = np.abs((delta_2 - delta_1 + 180) % 360 - 180)
516+
517+
assert_allclose(test_psi_res, obj_psi_res, rtol=0.002)
518+
assert_allclose(test_delta_res, obj_delta_res, rtol=0.003)

0 commit comments

Comments
 (0)