Skip to content
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

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open

Woolam parser dev #98

wants to merge 17 commits into from

Conversation

andyfaff
Copy link
Contributor

@andyfaff andyfaff commented Oct 3, 2024

igresh and others added 17 commits October 4, 2024 09:20
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
Linted with black.
This time with -180 flag

def open_M2000file(fname, dropdatapoints=1):
"""
Open and load in an Accurion EP4 formmated data file.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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):
Copy link
Contributor Author

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(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

needs docstring

@andyfaff
Copy link
Contributor Author

andyfaff commented Oct 3, 2024

@igresh, working locally you can add a remote as git remote add andyfaff https://github.com/andyfaff/refellips.git. You can then fetch my changes via git fetch andyfaff, which will allow you to git checkout andyfaff/Woolam-parser-dev.

You can then create a feature branch off of 0ef6cdc, push that feature branch to igresh/refellips, then make a PR against the Woolam-parser-dev branch on my fork. When that gets merged this PR will be updated.

Things this PR needs:

  1. Add tests/test files for the file loaders that are added in this PR.
  2. We need to talk about the delta_offset changes. I was never totally familiar with delta_offset, and this PR definitely doesn't make anything clearer to me.
  3. If you want to make changes to ObjectiveSE.residuals then we need to amend how the lnsigma scaling is done in ObjectiveSE.logl.
  4. The flake8 problems need to be addressed.
  5. docstrings need to be added for the new file loaders.

psi, delta = self.model(wavelength_aoi)
return np.r_[psi - psi_d, delta - delta_d]
delta_err = 2 * np.rad2deg(
Copy link
Contributor Author

@andyfaff andyfaff Oct 4, 2024

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.

Copy link
Contributor Author

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?

Copy link
Contributor

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.

Copy link
Contributor Author

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

Copy link
Contributor

@igresh igresh Oct 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Screenshot 2024-10-04 at 8 02 44 pm

Seems like:
delta_error = (delta - delta_d + 180) % 360 - 180

produces the desired effect.

Copy link
Contributor

@igresh igresh Oct 4, 2024

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:

Screenshot 2024-10-04 at 9 11 23 pm
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])

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants