Workflow#
In this example, we will use McStas 3 simulation file.
Build Pipeline (Collect Parameters and Providers)#
Import the providers from load_mcstas_nexus
to use the McStas
simulation data workflow. MaximumProbability
can be manually provided to derive more realistic number of events. It is because weights
are given as probability, not number of events in a McStas file.
[1]:
from ess.nmx.mcstas import McStasWorkflow
from ess.nmx.data import small_mcstas_3_sample
from ess.nmx.types import *
from ess.nmx.reduction import NMXData, NMXReducedData, merge_panels
from ess.nmx.nexus import export_as_nexus
wf = McStasWorkflow()
# Replace with the path to your own file
wf[FilePath] = small_mcstas_3_sample()
wf[MaximumProbability] = 10000
wf[TimeBinSteps] = 50
Downloading file 'small_mcstas_3_sample.h5' from 'https://public.esss.dk/groups/scipp/ess/nmx/small_mcstas_3_sample.h5' to '/home/runner/.cache/essnmx/0'.
To see what the workflow can produce, display it:
[2]:
wf
[2]:
Name | Value | Source |
---|---|---|
CrystalRotation |
load_crystal_rotationess.nmx.mcstas.load.load_crystal_rotation | |
DetectorBankPrefix |
load_event_data_bank_nameess.nmx.mcstas.load.load_event_data_bank_name | |
DetectorIndex | ||
DetectorName |
detector_name_from_indexess.nmx.mcstas.load.detector_name_from_index | |
EventData |
event_weights_from_probabilityess.nmx.mcstas.load.event_weights_from_probability | |
FilePath |
/home/runner/.cache/essnmx/0/s.../home/runner/.cache/essnmx/0/small_mcstas_3_sample.h5 |
|
MaximumProbability | 10000 | |
McStasInstrument |
read_mcstas_geometry_xmless.nmx.mcstas.xml.read_mcstas_geometry_xml | |
NMXData |
load_mcstasess.nmx.mcstas.load.load_mcstas | |
NMXReducedData |
bin_time_of_arrivaless.nmx.reduction.bin_time_of_arrival | |
ProtonCharge |
proton_charge_from_event_dataess.nmx.mcstas.load.proton_charge_from_event_data | |
RawEventData |
load_raw_event_dataess.nmx.mcstas.load.load_raw_event_data | |
TimeBinSteps | 50 |
We want to reduce all three panels, so we map the relevant part of the workflow over a list of the three panels:
[3]:
# DetectorIndex selects what detector panels to include in the run
# in this case we select all three panels.
wf[NMXReducedData] = (
wf[NMXReducedData]
.map({DetectorIndex: sc.arange('panel', 3, unit=None)})
.reduce(index="panel", func=merge_panels)
)
Build Workflow#
[4]:
wf.visualize(NMXReducedData, graph_attr={"rankdir": "TD"}, compact=True)
[4]:
Compute Desired Types#
[5]:
from cyclebane.graph import NodeName, IndexValues
# Event data grouped by pixel id for each of the selected detectors
targets = [NodeName(NMXData, IndexValues(("panel",), (i,))) for i in range(3)]
dg = merge_panels(*wf.compute(targets).values())
dg
[5]:
- weightsscippDataArray(panel: 3, id: 1638400)DataArrayViewbinned data [len=0, len=0, ..., len=0, len=0]
- proton_chargescippVariable(panel: 3)float640.006, 0.005, 0.005
- crystal_rotationscippVariable()vector3deg[0. 0. 0.]
- fast_axisscippVariable(panel: 3)vector3𝟙[ 0.999986 0. -0.00529148], [-0.00531614 0. -0.99998587], [0.00531614 0. 0.99998587]
- slow_axisscippVariable(panel: 3)vector3𝟙[0. 1. 0.], [0. 1. 0.], [0. 1. 0.]
- origin_positionscippVariable(panel: 3)vector3m[-0.248454 -0.25 0.292 ], [-0.288666 -0.25 0.252 ], [ 0.288667 -0.25 -0.251 ]
- sample_positionscippVariable()vector3m[0. 0. 0.]
- source_positionscippVariable()vector3m[ -0.53123 0. -157.405 ]
- sample_namescippVariable()stringsampleMantid
- positionscippVariable(panel: 3, id: 1638400)vector3m[-0.248454 -0.25 0.292 ], [-0.24805401 -0.25 0.29199788], ..., [0.29138461 0.2616 0.26019278], [0.29138674 0.2616 0.26059277]
[6]:
# Data from all selected detectors binned by panel, pixel and timeslice
binned_dg = wf.compute(NMXReducedData)
binned_dg
[6]:
- countsscippDataArray(panel: 3, id: 1638400, t: 50)float64counts0.0, 0.0, ..., 0.0, 0.0
- proton_chargescippVariable(panel: 3)float640.006, 0.005, 0.005
- crystal_rotationscippVariable()vector3deg[0. 0. 0.]
- fast_axisscippVariable(panel: 3)vector3𝟙[ 0.999986 0. -0.00529148], [-0.00531614 0. -0.99998587], [0.00531614 0. 0.99998587]
- slow_axisscippVariable(panel: 3)vector3𝟙[0. 1. 0.], [0. 1. 0.], [0. 1. 0.]
- origin_positionscippVariable(panel: 3)vector3m[-0.248454 -0.25 0.292 ], [-0.288666 -0.25 0.252 ], [ 0.288667 -0.25 -0.251 ]
- sample_positionscippVariable()vector3m[0. 0. 0.]
- source_positionscippVariable()vector3m[ -0.53123 0. -157.405 ]
- sample_namescippVariable()stringsampleMantid
- positionscippVariable(panel: 3, id: 1638400)vector3m[-0.248454 -0.25 0.292 ], [-0.24805401 -0.25 0.29199788], ..., [0.29138461 0.2616 0.26019278], [0.29138674 0.2616 0.26059277]
Export Results#
NMXReducedData
object has a method to export the data into nexus or h5 file.
You can save the result as test.nxs
, for example:
[7]:
export_as_nexus(binned_dg, "test.nxs")
Instrument View#
Pixel positions are not used for later steps, but it is included in the coordinates for instrument view.
All pixel positions are relative to the sample position, therefore the sample is at (0, 0, 0).
It might be very slow or not work in the ``VS Code`` jupyter notebook editor.
[8]:
import scippneutron as scn
da = dg["weights"]
da.coords["position"] = dg["position"]
# Plot one out of 100 pixels to reduce size of docs output
view = scn.instrument_view(da["id", ::100].hist(), pixel_size=0.0075)
view
[8]: