-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Woolam parser dev #98
base: main
Are you sure you want to change the base?
Conversation
For opening files from Woolam m2000 ellipsometers, exported as text files
Advice from Andy Co-Authored-By: Andrew Nelson <andyfaff@users.noreply.github.com>
Sellmeier was modifying the passed wavelength array in-place, which produced confusing behaviour.
Delta is in polar coordinates (0-360˚), this needs to be taken into account when calculating error. This problem is most obvious when data is 359˚ and model is 1˚ (for example). Old implementation calculates residual as 358, whereas the correct residual is 2. The change calculates error as: 2*arcsin(sin(Delta_data/2)-sin(Delta_model/2)) The factor of 2 ensures a functional relationship between error and Delta. The maximum possible residual (unweighted) is 180, which is of the same magnitude as before the change.
I had extended the silicon RI model so that it had a larger spectral range. This was causing some tests to fail, as the WVASE model we are comparing to used the old Si model.
Residuals are now calculated by self.residuals, so that the tests now pass and circular delta error is taken into account.
Cauchy, load_materials and RI are now imported from refellips.dispersion
This time with -180 flag
|
||
def open_M2000file(fname, dropdatapoints=1): | ||
""" | ||
Open and load in an Accurion EP4 formmated data file. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Open and load in an Accurion EP4 formmated data file. | |
Open and load in an Accurion EP4 formatted data file. |
return time_dict | ||
|
||
|
||
def open_FilmSenseFile(fname): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs a docstring
|
||
|
||
def open_woolam_time_series(fname, take_every=1): | ||
df = pd.read_csv( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needs docstring
@igresh, working locally you can add a remote as You can then create a feature branch off of 0ef6cdc, push that feature branch to igresh/refellips, then make a PR against the Things this PR needs:
|
psi, delta = self.model(wavelength_aoi) | ||
return np.r_[psi - psi_d, delta - delta_d] | ||
delta_err = 2 * np.rad2deg( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you want to do this calculation, we should probably do it in ReflectModelSE
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, scrub that. What we're working out here is the residual for delta, which you're effectively changing to:
2 * asin(sin(delta/2) - sin(delta_d/2))
? Why is the residual for delta
worked out this way? Do you have a reference?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Delta is measured in degrees; as such, the difference between ∆=359 and ∆=1 should be 2˚. In the old implementation, it was 358˚.
In this method, the delta values are transformed such that 180˚=1, and 0/360˚=0. The residual is calculated, then rescaled such that the magnitude is the same as a simple difference.
I haven't managed to find a reference for the 'correct' way to calculate the residual, but I can demonstrate why the new method makes more sense than the old method by way of example (& comparison to WVASE).
I haven't convinced myself that this is the best way of calculating the residual - will do more searching.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some sort of circular modulus
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For reference, the problem with the old approach is:
wavelength = np.linspace(400,900,100)
si = load_material("silicon")
sio2 = load_material("silica")
polymer = Cauchy(A=1.39, B=0.0005)
solvent = Cauchy(A=1.45, B=0.0005)
polymer_layer_1 = polymer(50)
polymer_layer_1.vfsolv.setp(value=0.5)
polymer_layer_2 = polymer(50)
polymer_layer_2.vfsolv.setp(value=0.6)
struc_1 = solvent() | polymer_layer_1 | sio2(20) | si()
struc_1.solvent = solvent
struc_2 = solvent() | polymer_layer_2 | sio2(20) | si()
struc_2.solvent = solvent
model_1 = ReflectModelSE(struc_1)
model_2 = ReflectModelSE(struc_2)
psi1, delta1 = model_1(np.c_[wavelength, np.ones_like(wavelength) * 70])
psi2, delta2 = model_2(np.c_[wavelength, np.ones_like(wavelength) * 70])
@igresh