-
Notifications
You must be signed in to change notification settings - Fork 3
feat: frame unwrapping for estia #185
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
Conversation
src/ess/estia/conversions.py
Outdated
| def mcstas_wavelength_coordinate_transformation_graph() -> CoordTransformationGraph: | ||
| return { | ||
| "wavelength": lambda wavelength_from_mcstas: wavelength_from_mcstas, | ||
| "theta": theta, | ||
| "divergence_angle": divergence_angle, | ||
| "Q": reflectometry_q, | ||
| "L1": lambda source_position, sample_position: sc.norm( | ||
| sample_position - source_position | ||
| ), # + extra correction for guides? | ||
| "L2": lambda position, sample_position: sc.norm(position - sample_position), | ||
| } |
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.
This is added so that we can still use the true wavelengths from McStas in cases when we don't want the wavelength uncertainty to contribute to the resolution.
src/ess/estia/load.py
Outdated
|
|
||
| da.coords['chopper_distance'] = sc.scalar(10.895, unit='m') | ||
| velocity_max = sc.scalar(3.956034e3 / 3.75, unit='m/s') | ||
| da.coords['chopper_open_time'] = da.coords['chopper_distance'] / velocity_max |
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.
chopper_open_time and chopper_distance should be read from the file, but in the Estia McStas files the data is not stored in the DiskChopper component.
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.
Is this info still required here or is it now encoded in the lookup table?
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.
It's not required and will be removed 👍
src/ess/estia/conversions.py
Outdated
| # Use frame unwrapping from scippneutron | ||
| raise NotImplementedError() | ||
| """ | ||
| Converts event_time_offset to time_of_flight. |
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.
I think we should create a lookup table and use the GenericTofWorkflow instead?
We need the chopper parameters to make a tof model for estia, or alternatively if there is a good mcstas model, then use that?
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.
You can still get a better estimate from making a lookup table. You get a much more uniform agreement to wavelengths. With a single time/distance origin, the results are good at the center of the frames, and get worse on the edges of the frames.
I don't think it's overkill and it would mean it's using a workflow which is common to other instruments, which is also good? Especially if there is only one chopper, making a table will be very easy (not so many configurations) 🙂
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.
Okay that makes sense, I'll take a stab at it tomorrow 👍
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.
See here for an example of how to make a table (Dream instrument):
https://scipp.github.io/essdiffraction/user-guide/dream/dream-make-tof-lookup-table.html
nvaytet
left a comment
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.
Looking good 👍
Can you also update the PR description to reflect the update?
| "metadata": {}, | ||
| "outputs": [], | ||
| "source": [ | ||
| "table.plot()" |
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.
The time distance diagram I posted didn't use exactly correct chopper parameters, it was just meant illustrate the chopper system qualitatively.
Yeah, there's a big overlap in the lookup table ,and it is a bit problematic because we loose quite a lot of intensity there.
There is an overlap in the McStas data too, but is smaller than the overlap in the lookup table:
So something seems to be wrong.
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.
Aha, found the issue. The LookupTableRelativeErrorThreshold was set too low.
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 I don't misremember a resonable wavelength uncertainty for Estia is ~6%, is that right @paracini?
With the relative error threshold set to 6% the lookup table looks like below:
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.
The time distance diagram I posted didn't use exactly correct chopper parameters, it was just meant illustrate the chopper system qualitatively.
I guess it was an ok representation because in the table above, around 35m (where the detector was placed in the other diagram), there is almost no overlap. You can guess from the time-distance diagram that going to higher distances would lead to more overlap.
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.
yes resolution is between 8% for short wavelengths and 3.5% for the long wavelengths
| "#from ess.estia.conversions import mcstas_wavelength_coordinate_transformation_graph\n", | ||
| "#wf.insert( mcstas_wavelength_coordinate_transformation_graph )\n", | ||
| "\n", | ||
| "wf[TimeOfFlightLookupTable] = estia_tof_lookup_table()\n", |
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.
You should set the TimeOfFlightLookupTableFilename on the workflow instead of the table itself, and let the workflow do the loading (there is some handling between old and new file formats that you would be missing here).
| " sc.scalar(float('nan'), unit=R.unit),\n", | ||
| " R.data\n", | ||
| " R.data,\n", | ||
| " )\n", |
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.
It's kind of weird. I was looking at how the results changed. To me, the new results look more like other reflectometry curves I've seen before (the old ones look very 'spiky').
But when I then look at the plot further down with the 'ground truth' in black, it seems the old results are much better? How was the ground truth result computed?

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.
This is expected, the old results used the exact wavelengths from McStas, so the resolution has no contribution from wavelength uncertainty. When we do frame unwrapping then wavelength uncertainty contributes to the resolution (or lack thereof). As I understand it wavelength uncertainty is the dominant factor of the resolution of Estia.
The black curve shows the ground truth reflectivity of the sample. When the resolution is good the computed reflectivity overlaps it. But with frame unwrapping the sharp peaks are smeared out.
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.
That's correct, resolution on Estia is dominated by wavelength, except at very small angles (around the critical edge) where the detector resolution dominates
| "#from ess.estia.conversions import mcstas_wavelength_coordinate_transformation_graph\n", | ||
| "#wf.insert( mcstas_wavelength_coordinate_transformation_graph )\n", | ||
| "\n", | ||
| "wf[TimeOfFlightLookupTable] = estia_tof_lookup_table()\n", |
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.
Also set the filename
| "wf[TimeOfFlightLookupTable] = estia_tof_lookup_table()\n", | ||
| "\n", | ||
| "# There is no proton current data in the McStas files, here we just add some fake proton current\n", | ||
| "# data to make the workflow run.\n", |
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.
Fixed now
| "\n", | ||
| "\n", | ||
| "wf.insert( mcstas_wavelength_coordinate_transformation_graph )\n", | ||
| "wf[TimeOfFlightLookupTable] = estia_tof_lookup_table()\n", |
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.
Use TimeOfFlightLookupTableFilename
src/ess/estia/data.py
Outdated
|
|
||
|
|
||
| def estia_tof_lookup_table(pulse_stride=1): | ||
| if pulse_stride == 1: |
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.
We should use the loader in essreduce instead.
About the pulse_stride=1 logic, this will hopefully just be handled by the future mechanism in the generic workflow that would check that the chopper params in the file that is being loaded are compatible with the lookup table being used. So it should not be needed here.
|
|
||
|
|
||
| def LoadNeXusWorkflow() -> sciline.Pipeline: | ||
| def LoadNeXusWorkflow(**kwargs) -> sciline.Pipeline: |
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.
Maybe we should pick a different name for the workflow (something like EstiaWorkflow?) as it is no longer just loading from nexus?
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.
Hm, but we do already define EstiaWorkflow in src/ess/estia/workflow.py.
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.
ok
tests/estia/mcstas_data_test.py
Outdated
| wf[WavelengthBins] = sc.geomspace('wavelength', 3.5, 12, 2001, unit='angstrom') | ||
| wf[QBins] = sc.geomspace('Q', 0.005, 0.1, 200, unit='1/angstrom') | ||
|
|
||
| wf[TimeOfFlightLookupTable] = estia_tof_lookup_table() |
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.
Use TimeOfFlightLookupTableFilename
src/ess/estia/load.py
Outdated
|
|
||
| da.coords['chopper_distance'] = sc.scalar(10.895, unit='m') | ||
| velocity_max = sc.scalar(3.956034e3 / 3.75, unit='m/s') | ||
| da.coords['chopper_open_time'] = da.coords['chopper_distance'] / velocity_max |
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.
Is this info still required here or is it now encoded in the lookup table?
It is encoded in the lookup table, so that code can be removed. |
nvaytet
left a comment
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.
I'm happy with the changes.
We need to make sure @paracini is also happy, as the results have changed significantly.
Note that you can still get back the old results by changing the coordinate transformations used to compute wavelength. from ess.estia.conversions import mcstas_wavelength_coordinate_transformation_graph
wf.insert( mcstas_wavelength_coordinate_transformation_graph )then |



Fixes #141
The approach requires five pieces of information:1. The chopper position.2. The chopper opening time.
3. The chopper frequency (only relevant for pulse skipping).
4. The average time at the source. (This might be fine to hard code).
5. The maximum time at the source. (This might be fine to hard code).
We're going to use the Tof lookup table approach from essreduce.
For that we need the chopper information required to run a simulation in tof.