-
Notifications
You must be signed in to change notification settings - Fork 3
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
Dream instrument view #184
Conversation
src/ess/dream/diagnostics.py
Outdated
da: | ||
DataArray to reshape. | ||
""" | ||
return da.group('module', 'segment', 'counter', 'wire', 'strip') |
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.
Are those specific to the mantle? The endcaps and high-res detectors may be different?
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.
👍 (even though the NeXus file I have does not have the sumo*
groups, but uses other names)
src/ess/dream/diagnostics.py
Outdated
in_dims = set(da.dims) | ||
out_dims = set(dims) | ||
if (not dims) or (in_dims == out_dims): | ||
return da | ||
grouped = da.group(*list(out_dims - in_dims)) | ||
return grouped.bins.concat(list(set(grouped.dims) - out_dims)) |
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.
set
is unordered, I think this may be a problem here?
src/ess/dream/diagnostics.py
Outdated
out_dims = set(dims) | ||
if (not dims) or (in_dims == out_dims): | ||
return da | ||
grouped = da.group(*list(out_dims - in_dims)) |
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 won't work, I think: If you group
with a dim-name then you will only get those groups that exist. So if you have, e.g., a pixel without any neutrons it will not be present in the output.
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 guess this is works for the Geant4 csv files where you are getting the events, which don't list the zeros anyway.
But as we have often said, the zeros are important.
I'll ask Celine for that Nexus file so I can see how it is stored there and get the data into a form that is equivalent to the Nexus 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.
I don't think it should work for the CSV files either: If there is no event you will not get a group. Try loading a shorter section of the file, I think it will fail here (when reshaping).
src/ess/dream/instrument_view.py
Outdated
import plopp as pp | ||
import scipp as sc | ||
|
||
DREAM_DETECTOR_DIMENSIONS = ('module', 'segment', 'counter', 'wire', 'strip') |
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 define this in a common place, also used by loaders, see my as well as @jl-wynen's PRs.
src/ess/dream/instrument_view.py
Outdated
z: Optional[str] = None, | ||
pos: Optional[str] = None, | ||
dim: Optional[str] = None, | ||
pixel_size: Union[sc.Variable, float] = DREAM_PIXEL_SIZE, |
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.
Note that we are violating the mutable-default-arg rule. We have the same problem in other places. Not sure if we should outright avoid it, or allow it by having the readonly flag set on a variable?
src/ess/dream/instrument_view.py
Outdated
if not isinstance(data, sc.DataArray): | ||
data = sc.concat( | ||
[ | ||
_preprocess_data(data=da, to_be_flattened=dims, dim=dim, to=to) | ||
for da in data.values() | ||
], | ||
dim=to, | ||
) |
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.
Didn't pythreejs support multiple point clouds? Could different detector banks be added separately, potentially with a check box to toggle them on and off?
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, you're right. Having toggle boxes may be a nice addition.
To be honest, I am not so happy about how the implementation is shaping here. I think I'd rather first work on scipp/plopp#247 and then it should be easier to do this one.
src/ess/dream/instrument_view.py
Outdated
f'x ({x}), y ({y}), and z ({z}) must be None.' | ||
) | ||
coords = { | ||
(x := f'{pos}.x'): data.coords[pos].fields.x, |
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.
Why walrus? You are not using x
?
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 instrument view works correctly. But instead of displaying the SUMOs, I think that for consistency, the 4 tick boxes for the SUMOs should be replaced by 2 tick boxes for the endcap backward and forward detectors.
Note that for the endcap detectors, SUMOs are numbered starting from 3.
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.
Right now, I am just using the keys in the data group that is supplied as input, to keep it flexible.
If you want to replace the sumos with end-caps, it's probably at the data loading that we should do 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.
Actually, using dream.load_geant4_csv
should make this go away.
}, | ||
"outputs": [], | ||
"source": [ | ||
"full_view = dream.instrument_view(data, dim='tof')\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.
Is the intention here that one could pass dim='wavelength'
after transforming the coords? Might be worth mentioning here, since it may not be obvious to readers.
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.
Added a sentence.
from ..data import Registry | ||
|
||
def _make_pooch(): | ||
import pooch | ||
_registry = Registry( | ||
instrument='amor', | ||
files={ | ||
"reference.nxs": "md5:56d493c8051e1c5c86fb7a95f8ec643b", | ||
"sample.nxs": "md5:4e07ccc87b5c6549e190bc372c298e83", | ||
}, | ||
version='1', | ||
) | ||
|
||
return pooch.create( | ||
path=pooch.os_cache('ess/amor'), | ||
env='ESS_AMOR_DATA_DIR', | ||
base_url='https://public.esss.dk/groups/scipp/ess/amor/{version}/', | ||
version=_version, | ||
registry={ | ||
"reference.nxs": "md5:56d493c8051e1c5c86fb7a95f8ec643b", | ||
"sample.nxs": "md5:4e07ccc87b5c6549e190bc372c298e83", | ||
}, |
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 code has been moved already, the refactor will get lost (but that is ok, I guess).
src/ess/dream/instrument_view.py
Outdated
@pp.node | ||
def slice_range(da, trunc_range): | ||
min_tr, max_tr = trunc_range | ||
return da['tof', min_tr:max_tr].sum('tof') |
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 seems to assume that data is binned (or histogrammed) with a potentially fine resolution? I believe DREAM has some high-resolution settings, where we may need thousands of TOF bins. Combined with the large number of pixels this may use too much memory. We can work around this using something event filtering.
@celinedurniak How many (how small) TOF (or wavelength) bins will you need to visualize?
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, the slice_range
function is no longer used. In a previous iteration, I used to have a range slider which allowed you to change the tof range to sum over, like the Mantid instrument view.
However, I now switched to just slicing single bins, because it is much faster.
That said, I think the issue you raise is still valid?
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, it is still a problem.
src/ess/dream/instrument_view.py
Outdated
if dim is not None: | ||
dims.remove(dim) | ||
out = da.flatten(dims=dims, to='pixel') | ||
sel = sc.isfinite(out.coords['x']) |
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.
What is 'x'
? The literal X-coord? Why do we need to select based on it?
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 because of the way we compute the coordinates for the pixels. We do a mean
on the positions inside the bins, but some of the bins are empty (no events reached that pixel).
So some positions end up being NaN, and the 3D view complains about nans (nothing is rendered).
So I need some way to filter out NaNs. I agree that maybe the instrument view shouldn't silently drop NaNs, and maybe this should be done explicitly in the notebook?
Filtering on NaNs here was easy because I was internally flattening the data. Using advanced indexing only works using a 1D mask. But I think it makes sense to keep the data with logical dimensions in the notebook.
Which is why I wanted to filter here...
I don't know what the best solution is.
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 thought about filling the empty pixels with a single event with zero weight, which would then appear as a dark pixel in the instrument view, but I then do not know what the positions of those pixels should be, because they are absent from the original 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.
Makes sense.
From NeXus files we will (according to the current plan) get a position
coord instead. Will you handle this as well?
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 that if I use the loader Jan-Lukas wrote, I get a position coord, so I will probably just filter on that.
src/ess/dream/instrument_view.py
Outdated
""" | ||
Three-dimensional visualization of the DREAM instrument. | ||
|
||
Parameters | ||
---------- | ||
data: | ||
Data to visualize. |
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.
Misses some info about the expected structure (datagroup, subgroups, dims, coords) of the input.
src/ess/dream/instrument_view.py
Outdated
self.fig.artists[cut_nodes[key].id].points.visible = val | ||
|
||
|
||
def instrument_view(data, dim=None, pixel_size=None, **kwargs): |
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.
Type hints?
- Add some helper functions to manipulate DREAM data in logical dimensions- Add adream.instrument_view
that can have atof
slider.- Add notebook with dream diagnostics plots and instrument viewsThis adds a
dream.instrument_view
that can have atof
slider.It also has some checkboxes to hide/show the separate detector modules.
Also reduce duplicate code in data registries.