Skip to content

Commit 5a5ca40

Browse files
authored
Merge pull request #93 from scipp/monitor-norm
DREAM monitor normalization
2 parents 9dc224d + 419a9d9 commit 5a5ca40

File tree

12 files changed

+611
-113
lines changed

12 files changed

+611
-113
lines changed

docs/user-guide/dream/dream-data-reduction.ipynb

+149-55
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
"outputs": [],
2121
"source": [
2222
"import scipp as sc\n",
23-
"from scippneutron.io import cif\n",
23+
"import scippneutron as scn\n",
24+
"import scippneutron.io\n",
2425
"\n",
2526
"from ess import dream, powder\n",
2627
"import ess.dream.data # noqa: F401\n",
@@ -44,7 +45,7 @@
4445
"metadata": {},
4546
"outputs": [],
4647
"source": [
47-
"workflow = dream.DreamGeant4Workflow()"
48+
"workflow = dream.DreamGeant4Workflow(run_norm=powder.RunNormalization.proton_charge)"
4849
]
4950
},
5051
{
@@ -74,7 +75,7 @@
7475
"workflow[DspacingBins] = sc.linspace(\"dspacing\", 0.0, 2.3434, 201, unit=\"angstrom\")\n",
7576
"# Mask in time-of-flight to crop to valid range\n",
7677
"workflow[TofMask] = lambda x: (x < sc.scalar(0.0, unit=\"ns\")) | (\n",
77-
" x > sc.scalar(86e6, unit=\"ns\")\n",
78+
" x > sc.scalar(86e6, unit=\"ns\")\n",
7879
")\n",
7980
"workflow[TwoThetaMask] = None\n",
8081
"workflow[WavelengthMask] = None\n",
@@ -86,31 +87,6 @@
8687
"cell_type": "markdown",
8788
"id": "6",
8889
"metadata": {},
89-
"source": [
90-
"We also need some parameters to configure the output file:"
91-
]
92-
},
93-
{
94-
"cell_type": "code",
95-
"execution_count": null,
96-
"id": "7",
97-
"metadata": {},
98-
"outputs": [],
99-
"source": [
100-
"workflow[CIFAuthors] = CIFAuthors([\n",
101-
" cif.Author(\n",
102-
" name=\"Jane Doe\",\n",
103-
" email=\"[email protected]\",\n",
104-
" orcid=\"0000-0000-0000-0001\",\n",
105-
" role=\"measurement\",\n",
106-
" ),\n",
107-
"])"
108-
]
109-
},
110-
{
111-
"cell_type": "markdown",
112-
"id": "8",
113-
"metadata": {},
11490
"source": [
11591
"## Use the workflow\n",
11692
"\n",
@@ -120,7 +96,7 @@
12096
{
12197
"cell_type": "code",
12298
"execution_count": null,
123-
"id": "9",
99+
"id": "7",
124100
"metadata": {},
125101
"outputs": [],
126102
"source": [
@@ -129,29 +105,27 @@
129105
},
130106
{
131107
"cell_type": "markdown",
132-
"id": "10",
108+
"id": "8",
133109
"metadata": {},
134110
"source": [
135-
"We then call `compute()` to compute the result:\n",
136-
"(The `cif` object will later be used to write the result to disk.)"
111+
"We then call `compute()` to compute the result:"
137112
]
138113
},
139114
{
140115
"cell_type": "code",
141116
"execution_count": null,
142-
"id": "11",
117+
"id": "9",
143118
"metadata": {},
144119
"outputs": [],
145120
"source": [
146-
"results = workflow.compute([IofDspacing, ReducedDspacingCIF])\n",
147-
"result = results[IofDspacing]\n",
148-
"cif_data = results[ReducedDspacingCIF]"
121+
"result = workflow.compute(IofDspacing)\n",
122+
"result"
149123
]
150124
},
151125
{
152126
"cell_type": "code",
153127
"execution_count": null,
154-
"id": "12",
128+
"id": "10",
155129
"metadata": {},
156130
"outputs": [],
157131
"source": [
@@ -161,30 +135,29 @@
161135
},
162136
{
163137
"cell_type": "markdown",
164-
"id": "13",
138+
"id": "11",
165139
"metadata": {},
166140
"source": [
167-
"We can now save the result to disk:\n",
168-
"(The comment is optional but helps to identify the file later.)"
141+
"We can now save the result to disk:"
169142
]
170143
},
171144
{
172145
"cell_type": "code",
173146
"execution_count": null,
174-
"id": "14",
147+
"id": "12",
175148
"metadata": {},
176149
"outputs": [],
177150
"source": [
178-
"cif_data.comment = \"\"\"This file was generated with the DREAM data reduction user guide\n",
179-
"in the documentation of ESSdiffraction.\n",
180-
"See https://scipp.github.io/essdiffraction/\n",
181-
"\"\"\"\n",
182-
"cif_data.save('dspacing.cif')"
151+
"to_save = dspacing_histogram.assign_coords(\n",
152+
" dspacing=sc.midpoints(\n",
153+
" dspacing_histogram.coords[\"dspacing\"]\n",
154+
" ))\n",
155+
"scn.io.save_xye(\"dspacing.xye\", to_save)"
183156
]
184157
},
185158
{
186159
"cell_type": "markdown",
187-
"id": "15",
160+
"id": "13",
188161
"metadata": {},
189162
"source": [
190163
"## Compute intermediate results\n",
@@ -197,7 +170,7 @@
197170
{
198171
"cell_type": "code",
199172
"execution_count": null,
200-
"id": "16",
173+
"id": "14",
201174
"metadata": {},
202175
"outputs": [],
203176
"source": [
@@ -214,7 +187,7 @@
214187
{
215188
"cell_type": "code",
216189
"execution_count": null,
217-
"id": "17",
190+
"id": "15",
218191
"metadata": {},
219192
"outputs": [],
220193
"source": [
@@ -226,7 +199,7 @@
226199
},
227200
{
228201
"cell_type": "markdown",
229-
"id": "18",
202+
"id": "16",
230203
"metadata": {},
231204
"source": [
232205
"## Grouping by scattering angle\n",
@@ -238,7 +211,7 @@
238211
{
239212
"cell_type": "code",
240213
"execution_count": null,
241-
"id": "19",
214+
"id": "17",
242215
"metadata": {},
243216
"outputs": [],
244217
"source": [
@@ -250,7 +223,7 @@
250223
{
251224
"cell_type": "code",
252225
"execution_count": null,
253-
"id": "20",
226+
"id": "18",
254227
"metadata": {},
255228
"outputs": [],
256229
"source": [
@@ -261,7 +234,7 @@
261234
{
262235
"cell_type": "code",
263236
"execution_count": null,
264-
"id": "21",
237+
"id": "19",
265238
"metadata": {},
266239
"outputs": [],
267240
"source": [
@@ -279,12 +252,133 @@
279252
{
280253
"cell_type": "code",
281254
"execution_count": null,
282-
"id": "22",
255+
"id": "20",
283256
"metadata": {},
284257
"outputs": [],
285258
"source": [
286259
"grouped_dspacing.hist().plot(norm=\"log\")"
287260
]
261+
},
262+
{
263+
"cell_type": "markdown",
264+
"id": "21",
265+
"metadata": {},
266+
"source": [
267+
"## Normalizing by monitor\n",
268+
"\n",
269+
"The workflow used above normalizes the detected counts by proton charge.\n",
270+
"Alternatively, ESSdiffraction can normalize by a monitor.\n",
271+
"In this example, this is DREAM's cave monitor.\n",
272+
"\n",
273+
"There are two options for normalizing by monitor:\n",
274+
"1. Normalize by a wavelength-histogram of the monitor counts ([normalize_by_monitor_histogram](../../generated/modules/ess.powder.correction.normalize_by_monitor_histogram.rst)).\n",
275+
"2. Normalized by the integral over all wavelength bins ([normalize_by_monitor_integrated](../../generated/modules/ess.powder.correction.normalize_by_monitor_integrated.rst)).\n",
276+
"\n",
277+
"Here, we use option 1.\n",
278+
"Option 2 can be chosen by constructing a workflow using `run_norm=powder.RunNormalization.monitor_integrated`.\n",
279+
"\n",
280+
"Construct a workflow as before but select normalization by monitor histogram:"
281+
]
282+
},
283+
{
284+
"cell_type": "code",
285+
"execution_count": null,
286+
"id": "22",
287+
"metadata": {},
288+
"outputs": [],
289+
"source": [
290+
"workflow = dream.DreamGeant4Workflow(run_norm=powder.RunNormalization.monitor_histogram)"
291+
]
292+
},
293+
{
294+
"cell_type": "markdown",
295+
"id": "23",
296+
"metadata": {},
297+
"source": [
298+
"In addition to the parameters used before, we also need to provide filenames for monitor data and a position of the monitor as that is not saved in the simulation files:"
299+
]
300+
},
301+
{
302+
"cell_type": "code",
303+
"execution_count": null,
304+
"id": "24",
305+
"metadata": {},
306+
"outputs": [],
307+
"source": [
308+
"workflow[MonitorFilename[SampleRun]] = dream.data.simulated_monitor_diamond_sample()\n",
309+
"workflow[MonitorFilename[VanadiumRun]] = dream.data.simulated_monitor_vanadium_sample()\n",
310+
"workflow[MonitorFilename[BackgroundRun]] = dream.data.simulated_monitor_empty_can()\n",
311+
"workflow[CaveMonitorPosition] = sc.vector([0.0, 0.0, -4220.0], unit='mm')\n",
312+
"\n",
313+
"# These are the same as at the top of the notebook:\n",
314+
"workflow[Filename[SampleRun]] = dream.data.simulated_diamond_sample()\n",
315+
"workflow[Filename[VanadiumRun]] = dream.data.simulated_vanadium_sample()\n",
316+
"workflow[Filename[BackgroundRun]] = dream.data.simulated_empty_can()\n",
317+
"workflow[CalibrationFilename] = None\n",
318+
"workflow[NeXusDetectorName] = \"mantle\"\n",
319+
"workflow[UncertaintyBroadcastMode] = UncertaintyBroadcastMode.drop\n",
320+
"workflow[DspacingBins] = sc.linspace(\"dspacing\", 0.0, 2.3434, 201, unit=\"angstrom\")\n",
321+
"workflow[TofMask] = lambda x: (x < sc.scalar(0.0, unit=\"ns\")) | (\n",
322+
" x > sc.scalar(86e6, unit=\"ns\")\n",
323+
")\n",
324+
"workflow[TwoThetaMask] = None\n",
325+
"workflow[WavelengthMask] = None\n",
326+
"workflow = powder.with_pixel_mask_filenames(workflow, [])"
327+
]
328+
},
329+
{
330+
"cell_type": "code",
331+
"execution_count": null,
332+
"id": "25",
333+
"metadata": {},
334+
"outputs": [],
335+
"source": [
336+
"workflow.visualize(IofDspacing, graph_attr={\"rankdir\": \"LR\"})"
337+
]
338+
},
339+
{
340+
"cell_type": "code",
341+
"execution_count": null,
342+
"id": "26",
343+
"metadata": {},
344+
"outputs": [],
345+
"source": [
346+
"results = workflow.compute((IofDspacing, WavelengthMonitor[SampleRun, CaveMonitor]))\n",
347+
"normalized_by_monitor = results[IofDspacing]\n",
348+
"monitor = results[WavelengthMonitor[SampleRun, CaveMonitor]]\n",
349+
"monitor"
350+
]
351+
},
352+
{
353+
"cell_type": "code",
354+
"execution_count": null,
355+
"id": "27",
356+
"metadata": {},
357+
"outputs": [],
358+
"source": [
359+
"monitor.plot()"
360+
]
361+
},
362+
{
363+
"cell_type": "markdown",
364+
"id": "28",
365+
"metadata": {},
366+
"source": [
367+
"Comparing the final, normalized result shows that it agrees with the data that was normalized by proton-charge:"
368+
]
369+
},
370+
{
371+
"cell_type": "code",
372+
"execution_count": null,
373+
"id": "29",
374+
"metadata": {},
375+
"outputs": [],
376+
"source": [
377+
"sc.plot({\n",
378+
" 'By proton charge': dspacing_histogram,\n",
379+
" 'By monitor': normalized_by_monitor.hist()\n",
380+
"})"
381+
]
288382
}
289383
],
290384
"metadata": {
@@ -303,7 +397,7 @@
303397
"name": "python",
304398
"nbconvert_exporter": "python",
305399
"pygments_lexer": "ipython3",
306-
"version": "3.10.13"
400+
"version": "3.10.14"
307401
}
308402
},
309403
"nbformat": 4,

src/ess/dream/data.py

+27
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ def _make_pooch():
2424
"DREAM_simple_pwd_workflow/data_dream_vana_container_sample_union.csv.zip": "md5:1e22917b2bb68b5cacfb506b72700a4d", # noqa: E501
2525
"DREAM_simple_pwd_workflow/data_dream_vanadium.csv.zip": "md5:e5addfc06768140c76533946433fa2ec", # noqa: E501
2626
"DREAM_simple_pwd_workflow/data_dream_vanadium_inc_coh.csv.zip": "md5:39d1a44e248b12966b26f7c2f6c602a2", # noqa: E501
27+
"DREAM_simple_pwd_workflow/Cave_TOF_Monitor_diam_in_can.dat": "md5:ef24f4a4186c628574046e6629e31611", # noqa: E501
28+
"DREAM_simple_pwd_workflow/Cave_TOF_Monitor_van_can.dat": "md5:e63456c347fb36a362a0b5ae2556b3cf", # noqa: E501
29+
"DREAM_simple_pwd_workflow/Cave_TOF_Monitor_vana_inc_coh.dat": "md5:701d66792f20eb283a4ce76bae0c8f8f", # noqa: E501
2730
},
2831
)
2932

@@ -119,3 +122,27 @@ def simulated_empty_can() -> str:
119122
return get_path(
120123
"DREAM_simple_pwd_workflow/data_dream_vana_container_sample_union.csv.zip"
121124
)
125+
126+
127+
def simulated_monitor_diamond_sample() -> str:
128+
"""Path to a Mcstas file for a monitor for the diamond measurement.
129+
130+
This is the DREAM cave monitor for ``simulated_diamond_sample``.
131+
"""
132+
return get_path("DREAM_simple_pwd_workflow/Cave_TOF_Monitor_diam_in_can.dat")
133+
134+
135+
def simulated_monitor_vanadium_sample() -> str:
136+
"""Path to a Mcstas file for a monitor for the vanadium measurement.
137+
138+
This is the DREAM cave monitor for ``simulated_vanadium_sample``.
139+
"""
140+
return get_path("DREAM_simple_pwd_workflow/Cave_TOF_Monitor_vana_inc_coh.dat")
141+
142+
143+
def simulated_monitor_empty_can() -> str:
144+
"""Path to a Mcstas file for a monitor for the empty can measurement.
145+
146+
This is the DREAM cave monitor for ``simulated_empty_can``.
147+
"""
148+
return get_path("DREAM_simple_pwd_workflow/Cave_TOF_Monitor_van_can.dat")

0 commit comments

Comments
 (0)