Skip to content

Commit 4b2bcc0

Browse files
Amor to sciline review (#10)
* Rewrite the Amor workflow using Sciline * test: disable orso test * fix: remove 'reflectometry' submodule * fix: delete imports in top level * rename: QStd to QResolution * fix: move Beamline and Resolution types to amor module. remove supermirror scope * rename: NormalizeIOfQ to NormalizeIofQ * rename: Raw to RawData * refactor: move general reflectometry types out of amor.types * fix: remove reflectometry module from tests * refactor: add QBins as explicit requirement of supermirror calibration * refactor: make calibration factor provider used in normalize_reference * docs: docstrings for domain types * docs: basic API-reference * docs: basic API-reference * docs * docs * fix * move supermirror calibration and normalization out of amor * move supermirror parameters to separate package * fix api reference * rename providers * fix import * use supermirror namespace * dont import all --------- Co-authored-by: Simon Heybrock <[email protected]>
1 parent dfdac3e commit 4b2bcc0

File tree

26 files changed

+733
-317
lines changed

26 files changed

+733
-317
lines changed

docs/api-reference/index.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
.. autosummary::
1818
:toctree: ../generated/functions
1919
:recursive:
20+
21+
providers
2022
```
2123

2224
## Submodules
@@ -26,4 +28,8 @@
2628
:toctree: ../generated/modules
2729
:template: module-template.rst
2830
:recursive:
29-
```
31+
32+
types
33+
amor
34+
supermirror
35+
```

docs/examples/amor.ipynb

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"# Divergent data reduction for Amor\n",
8+
"\n",
9+
"In this notebook, we will look at how to use the `essreflectometry` package with Sciline, for reflectometry data collected from the PSI instrument [Amor](https://www.psi.ch/en/sinq/amor) in [divergent beam mode](https://www.psi.ch/en/sinq/amor/selene).\n",
10+
"\n",
11+
"We will begin by importing the modules that are necessary for this notebook."
12+
]
13+
},
14+
{
15+
"cell_type": "code",
16+
"execution_count": null,
17+
"metadata": {},
18+
"outputs": [],
19+
"source": [
20+
"import scipp as sc\n",
21+
"import sciline\n",
22+
"from essreflectometry.amor import providers, default_parameters\n",
23+
"from essreflectometry.types import *"
24+
]
25+
},
26+
{
27+
"cell_type": "code",
28+
"execution_count": null,
29+
"metadata": {},
30+
"outputs": [],
31+
"source": [
32+
"params={\n",
33+
" **default_parameters,\n",
34+
" QBins: sc.geomspace(dim='Q', start=0.008, stop=0.075, num=200, unit='1/angstrom'),\n",
35+
" SampleRotation[Sample]: sc.scalar(0.7989, unit='deg'),\n",
36+
" Filename[Sample]: \"sample.nxs\",\n",
37+
" SampleRotation[Reference]: sc.scalar(0.8389, unit='deg'),\n",
38+
" Filename[Reference]: \"reference.nxs\",\n",
39+
"}"
40+
]
41+
},
42+
{
43+
"cell_type": "code",
44+
"execution_count": null,
45+
"metadata": {},
46+
"outputs": [],
47+
"source": [
48+
"pipeline = sciline.Pipeline(\n",
49+
" providers,\n",
50+
" params=params\n",
51+
")"
52+
]
53+
},
54+
{
55+
"cell_type": "code",
56+
"execution_count": null,
57+
"metadata": {},
58+
"outputs": [],
59+
"source": [
60+
"pipeline.visualize((NormalizedIofQ, QResolution), graph_attr={'rankdir': 'LR'})"
61+
]
62+
},
63+
{
64+
"cell_type": "code",
65+
"execution_count": null,
66+
"metadata": {},
67+
"outputs": [],
68+
"source": [
69+
"# Compute I over Q and the standard deviation of Q\n",
70+
"ioq, qstd = pipeline.compute((NormalizedIofQ, QResolution)).values()"
71+
]
72+
},
73+
{
74+
"cell_type": "code",
75+
"execution_count": null,
76+
"metadata": {},
77+
"outputs": [],
78+
"source": [
79+
"import matplotlib.pyplot as plt\n",
80+
"\n",
81+
"fig = plt.figure(figsize=(5, 7))\n",
82+
"ax1 = fig.add_axes([0, 0.55, 1.0, 0.45])\n",
83+
"ax2 = fig.add_axes([0, 0.0, 1.0, 0.45])\n",
84+
"cax = fig.add_axes([1.05, 0.55, 0.03, 0.45])\n",
85+
"fig1 = ioq.plot(norm='log', ax=ax1, cax=cax, grid=True)\n",
86+
"fig2 = ioq.mean('detector_number').plot(norm='log', ax=ax2, grid=True)\n",
87+
"fig1.canvas.xrange = fig2.canvas.xrange"
88+
]
89+
},
90+
{
91+
"cell_type": "markdown",
92+
"metadata": {},
93+
"source": [
94+
"## Make a $(\\lambda, \\theta)$ map\n",
95+
"A good sanity check is to create a two-dimensional map of the counts in $\\lambda$ and $\\theta$ bins. To achieve this, we request the `ThetaData` from the pipeline. In the graph above we can see that `WavelengthData` is required to compute `ThetaData`, therefore it is also present in `ThetaData` so we don't need to require it separately."
96+
]
97+
},
98+
{
99+
"cell_type": "code",
100+
"execution_count": null,
101+
"metadata": {},
102+
"outputs": [],
103+
"source": [
104+
"from essreflectometry.types import ThetaData\n",
105+
"pipeline.compute(ThetaData[Sample])\\\n",
106+
" .bins.concat('detector_number')\\\n",
107+
" .hist(\n",
108+
" theta=sc.linspace(dim='theta', start=0.0, stop=1.2, num=165, unit='deg').to(unit='rad'),\n",
109+
" wavelength=sc.linspace(dim='wavelength', start=0, stop=15.0, num=165, unit='angstrom'),\n",
110+
" )\\\n",
111+
" .plot()\n"
112+
]
113+
},
114+
{
115+
"cell_type": "markdown",
116+
"metadata": {},
117+
"source": [
118+
"This plot can be used to check if the value of the sample rotation angle $\\omega$ is correct. The bright triangles should be pointing back to the origin $\\lambda = \\theta = 0$."
119+
]
120+
}
121+
],
122+
"metadata": {
123+
"kernelspec": {
124+
"display_name": "essreflectometry",
125+
"language": "python",
126+
"name": "python3"
127+
},
128+
"language_info": {
129+
"codemirror_mode": {
130+
"name": "ipython",
131+
"version": 3
132+
},
133+
"file_extension": ".py",
134+
"mimetype": "text/x-python",
135+
"name": "python",
136+
"nbconvert_exporter": "python",
137+
"pygments_lexer": "ipython3",
138+
"version": "3.10.12"
139+
}
140+
},
141+
"nbformat": 4,
142+
"nbformat_minor": 2
143+
}

docs/examples/index.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Examples
2+
3+
```{toctree}
4+
---
5+
maxdepth: 2
6+
---
7+
8+
amor
9+
```
10+

docs/index.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,19 @@
55
</br></br>
66
</span>
77

8+
## Overview
9+
10+
This documentation is under construction.
11+
See the [Amor data reduction](examples/amor) example for a quick start.
12+
13+
## Table of contents
14+
815
```{toctree}
916
---
10-
hidden:
17+
maxdepth: 2
1118
---
1219
20+
examples/index
1321
api-reference/index
1422
developer/index
1523
about/index

src/essreflectometry/__init__.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,33 @@
11
# SPDX-License-Identifier: BSD-3-Clause
22
# Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
33

4-
# flake8: noqa
4+
# flake8: noqa: F401
55
import importlib.metadata
6+
import itertools
7+
8+
from . import calibrations, conversions, corrections, normalize
69

710
try:
811
__version__ = importlib.metadata.version(__package__ or __name__)
912
except importlib.metadata.PackageNotFoundError:
1013
__version__ = "0.0.0"
1114

15+
providers = list(
16+
itertools.chain(
17+
conversions.providers,
18+
corrections.providers,
19+
calibrations.providers,
20+
normalize.providers,
21+
)
22+
)
23+
"""
24+
List of providers for setting up a Sciline pipeline.
25+
26+
This does not constitute a complete workflow but only
27+
a skeleton for a generic reflectometry setting.
28+
For an example of a complete workflow
29+
see :py:data:`essreflectometry.amor.providers`.
30+
"""
31+
1232
del importlib
33+
del itertools
Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,55 @@
11
# SPDX-License-Identifier: BSD-3-Clause
22
# Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
33
# flake8: noqa: F401
4-
from . import calibrations, conversions, data, normalize, resolution, tools
5-
from .beamline import instrument_view_components, make_beamline
4+
import itertools
5+
6+
import scipp as sc
7+
8+
from .. import providers as reflectometry_providers
9+
from .. import supermirror
10+
from ..types import BeamSize, DetectorSpatialResolution, Gravity, Run, SampleSize
11+
from . import beamline, conversions, load, resolution
12+
from .beamline import instrument_view_components
613
from .instrument_view import instrument_view
7-
from .load import load
14+
from .types import (
15+
AngularResolution,
16+
BeamlineParams,
17+
Chopper1Position,
18+
Chopper2Position,
19+
ChopperFrequency,
20+
ChopperPhase,
21+
SampleSizeResolution,
22+
WavelengthResolution,
23+
)
24+
25+
providers = list(
26+
itertools.chain(
27+
reflectometry_providers,
28+
load.providers,
29+
conversions.providers,
30+
resolution.providers,
31+
beamline.providers,
32+
)
33+
)
34+
"""
35+
List of providers for setting up a Sciline pipeline.
36+
37+
This provides a default Amor workflow including providers for loadings files.
38+
"""
39+
40+
default_parameters = {
41+
supermirror.MValue: sc.scalar(5, unit=sc.units.dimensionless),
42+
supermirror.CriticalEdge: 0.022 * sc.Unit('1/angstrom'),
43+
supermirror.Alpha: sc.scalar(0.25 / 0.088, unit=sc.units.angstrom),
44+
BeamSize[Run]: 2.0 * sc.units.mm,
45+
SampleSize[Run]: 10.0 * sc.units.mm,
46+
DetectorSpatialResolution[Run]: 0.0025 * sc.units.m,
47+
Gravity: sc.vector(value=[0, -1, 0]) * sc.constants.g,
48+
ChopperFrequency[Run]: sc.scalar(20 / 3, unit='Hz'),
49+
ChopperPhase[Run]: sc.scalar(-8.0, unit='deg'),
50+
Chopper1Position[Run]: sc.vector(value=[0, 0, -15.5], unit='m'),
51+
Chopper2Position[Run]: sc.vector(value=[0, 0, -14.5], unit='m'),
52+
}
53+
54+
del sc
55+
del itertools

src/essreflectometry/amor/beamline.py

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,40 @@
11
# SPDX-License-Identifier: BSD-3-Clause
22
# Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
33
import scipp as sc
4-
from scipp.constants import g
54

65
from ..choppers import make_chopper
76
from ..logging import log_call
7+
from ..types import (
8+
BeamSize,
9+
DetectorSpatialResolution,
10+
Gravity,
11+
Run,
12+
SampleRotation,
13+
SampleSize,
14+
)
15+
from .types import (
16+
BeamlineParams,
17+
Chopper1Position,
18+
Chopper2Position,
19+
ChopperFrequency,
20+
ChopperPhase,
21+
)
822

923

1024
@log_call(
1125
instrument='amor', message='Constructing AMOR beamline from default parameters'
1226
)
1327
def make_beamline(
14-
sample_rotation: sc.Variable,
15-
beam_size: sc.Variable = None,
16-
sample_size: sc.Variable = None,
17-
detector_spatial_resolution: sc.Variable = None,
18-
gravity: sc.Variable = None,
19-
chopper_frequency: sc.Variable = None,
20-
chopper_phase: sc.Variable = None,
21-
chopper_1_position: sc.Variable = None,
22-
chopper_2_position: sc.Variable = None,
23-
) -> dict:
28+
sample_rotation: SampleRotation[Run],
29+
beam_size: BeamSize[Run],
30+
sample_size: SampleSize[Run],
31+
detector_spatial_resolution: DetectorSpatialResolution[Run],
32+
gravity: Gravity,
33+
chopper_frequency: ChopperFrequency[Run],
34+
chopper_phase: ChopperPhase[Run],
35+
chopper_1_position: Chopper1Position[Run],
36+
chopper_2_position: Chopper2Position[Run],
37+
) -> BeamlineParams[Run]:
2438
"""
2539
Amor beamline components.
2640
@@ -50,22 +64,6 @@ def make_beamline(
5064
:
5165
A dict.
5266
"""
53-
if beam_size is None:
54-
beam_size = 2.0 * sc.units.mm
55-
if sample_size is None:
56-
sample_size = 10.0 * sc.units.mm
57-
if detector_spatial_resolution is None:
58-
detector_spatial_resolution = 0.0025 * sc.units.m
59-
if gravity is None:
60-
gravity = sc.vector(value=[0, -1, 0]) * g
61-
if chopper_frequency is None:
62-
chopper_frequency = sc.scalar(20 / 3, unit='Hz')
63-
if chopper_phase is None:
64-
chopper_phase = sc.scalar(-8.0, unit='deg')
65-
if chopper_1_position is None:
66-
chopper_1_position = sc.vector(value=[0, 0, -15.5], unit='m')
67-
if chopper_2_position is None:
68-
chopper_2_position = sc.vector(value=[0, 0, -14.5], unit='m')
6967
beamline = {
7068
'sample_rotation': sample_rotation,
7169
'beam_size': beam_size,
@@ -91,7 +89,7 @@ def make_beamline(
9189
position=chopper_1_position,
9290
)
9391
)
94-
return beamline
92+
return BeamlineParams(beamline)
9593

9694

9795
@log_call(instrument='amor', level='DEBUG')
@@ -131,3 +129,6 @@ def instrument_view_components(da: sc.DataArray) -> dict:
131129
'type': 'disk',
132130
},
133131
}
132+
133+
134+
providers = [make_beamline]

0 commit comments

Comments
 (0)