Download this Jupyter notebook
Amor Reduction¶
How to start:¶
Before starting you must:
Have conda installed
conda env create -f ess-notebooks.yml python=3.7
The yaml environment file is part of this repository.
What will this notebook show?¶
The notebook will show how to use the ess.amor.AmorData
, ess.amor.AmorReference
and ess.amor.Normalisation
classes for the reduction of data collected at the Amor instrument at PSI (API level documentation for these classes is available). To achieve this, we will reduce the following data files, sample.nxs and
reference.nxs, and then normalise the sample data (with respect to the reference data).
Reduction¶
Before, we begin, we should import then necessary modules.
[1]:
import os
import dataconfig
import numpy as np
import scipp as sc
import scippneutron as scn
from ess.amor import AmorData, AmorReference, Normalisation, tools
We can then define some information about the reduction, for inclusion in the final .ort
file.
[2]:
name = 'Andrew McCluskey/andrew.mccluskey@ess.eu'
affiliation = 'European Spallation Source'
data_owner = 'Jochen Stahn, PSI'
experiment_id = 'test_0001'
experiment_date = '2020-06-21'
sample_description = 'Ni-Ti Multilayer'
notebook_file = 'amor_reduction.ipynb'
The below cell enables the data to be pulled from the ess-notebook-data repository for the online documentation. For local data data_file
should be changed to the path to the experimental file and reference_file
to that for the reference supermirror dataset.
[3]:
local_data_path = os.path.join('ess-notebooks', 'amor')
data_dir = os.path.join(dataconfig.data_root, local_data_path)
data_file = os.path.join(data_dir, 'sample.nxs')
reference_file = os.path.join(data_dir, 'reference.nxs')
The AmorData
class will take the loaded NeXus file or the NeXus file itself and perform the reduction steps to obtain the reflected intensity as a function of \(q_z\), including accounting for aspects such as gravity. The sample_angle_offset
allows the angular offset of the sample with respect to the horizon to be accounted for.
[4]:
sample = AmorData(data_file,
reduction_creator=name,
data_owner=data_owner,
experiment_id=experiment_id,
experiment_date=experiment_date,
sample_description=sample_description,
reduction_file=notebook_file,
reduction_creator_affiliation=affiliation,
sample_angle_offset=0.04 * sc.units.deg,
sample_size=0.1*sc.units.m)
/usr/share/miniconda/envs/tempenv/lib/python3.7/scippneutron/file_loading/_log_data.py:23: UserWarning: Skipped loading /entry/stages/com due to:
NXlog 'com' has time and value datasets of different shapes
warn(f"Skipped loading {group.path} due to:\n{e}")
/usr/share/miniconda/envs/tempenv/lib/python3.7/scippneutron/file_loading/_log_data.py:23: UserWarning: Skipped loading /entry/stages/coz due to:
NXlog 'coz' has time and value datasets of different shapes
warn(f"Skipped loading {group.path} due to:\n{e}")
/usr/share/miniconda/envs/tempenv/lib/python3.7/scippneutron/file_loading/_log_data.py:23: UserWarning: Skipped loading /entry/stages/diaphragms/middle focus/slot due to:
NXlog 'slot' has an empty value dataset
warn(f"Skipped loading {group.path} due to:\n{e}")
/usr/share/miniconda/envs/tempenv/lib/python3.7/scippneutron/file_loading/_log_data.py:23: UserWarning: Skipped loading /entry/stages/diaphragms/virtual source/horizontal due to:
NXlog 'horizontal' has an empty value dataset
warn(f"Skipped loading {group.path} due to:\n{e}")
/usr/share/miniconda/envs/tempenv/lib/python3.7/scippneutron/file_loading/_log_data.py:23: UserWarning: Skipped loading /entry/stages/diaphragms/virtual source/vertical due to:
NXlog 'vertical' has an empty value dataset
warn(f"Skipped loading {group.path} due to:\n{e}")
/usr/share/miniconda/envs/tempenv/lib/python3.7/scippneutron/file_loading/_log_data.py:23: UserWarning: Skipped loading /entry/stages/som due to:
NXlog 'som' has time and value datasets of different shapes
warn(f"Skipped loading {group.path} due to:\n{e}")
/usr/share/miniconda/envs/tempenv/lib/python3.7/scippneutron/file_loading/_log_data.py:23: UserWarning: Skipped loading /entry/stages/soz due to:
NXlog 'soz' has time and value datasets of different shapes
warn(f"Skipped loading {group.path} due to:\n{e}")
Some detector and wavelength masking can then be performed.
[5]:
sample.detector_masking(y_min=0 * sc.units.m, y_max=100e-3 * sc.units.m)
sample.wavelength_masking()
[6]:
scn.instrument_view(sample.data)
The AmorReference
class reads the reference supermirror measurement, and will perform the necessary corrections. For this measurement, no angular offset is required. Again, detector and wavelength masking is performed.
[7]:
reference = AmorReference(reference_file)
reference.detector_masking(y_min=0 * sc.units.m, y_max=100e-3 * sc.units.m)
reference.wavelength_masking()
For the normalisation of the sample, we use the Normalisation
class.
[8]:
norm = Normalisation(sample, reference)
With this object, there is the choice to bin in the \(\lambda\)/\(\theta\)-space or the \(q_z\)-space.
[9]:
bins = (
sc.linspace(
dim='wavelength',
start=2.5,
stop=15,
num=50,
unit=sc.units.angstrom),
sc.linspace(
dim='theta',
start=0.6,
stop=1.25,
num=50,
unit=sc.units.deg)
)
lambda_theta = norm.wavelength_theta_bin(bins)
The data binned in \(\lambda\)/\(\theta\)-space can be investigated and plotted.
[10]:
lambda_theta
[10]:
- wavelength: 49
- theta: 49
- sample_position()vector_3_float64m[0. 0. 0.]
Values:
array([0., 0., 0.]) - source_position()vector_3_float64m[ 0. 0. -15.]
Values:
array([ 0., 0., -15.]) - theta(theta [bin-edge])float64deg0.6, 0.61, ..., 1.24, 1.25
Values:
array([0.6 , 0.61326531, 0.62653061, 0.63979592, 0.65306122, 0.66632653, 0.67959184, 0.69285714, 0.70612245, 0.71938776, 0.73265306, 0.74591837, 0.75918367, 0.77244898, 0.78571429, 0.79897959, 0.8122449 , 0.8255102 , 0.83877551, 0.85204082, 0.86530612, 0.87857143, 0.89183673, 0.90510204, 0.91836735, 0.93163265, 0.94489796, 0.95816327, 0.97142857, 0.98469388, 0.99795918, 1.01122449, 1.0244898 , 1.0377551 , 1.05102041, 1.06428571, 1.07755102, 1.09081633, 1.10408163, 1.11734694, 1.13061224, 1.14387755, 1.15714286, 1.17040816, 1.18367347, 1.19693878, 1.21020408, 1.22346939, 1.23673469, 1.25 ]) - wavelength(wavelength [bin-edge])float64Å2.5, 2.76, ..., 14.74, 15.0
Values:
array([ 2.5 , 2.75510204, 3.01020408, 3.26530612, 3.52040816, 3.7755102 , 4.03061224, 4.28571429, 4.54081633, 4.79591837, 5.05102041, 5.30612245, 5.56122449, 5.81632653, 6.07142857, 6.32653061, 6.58163265, 6.83673469, 7.09183673, 7.34693878, 7.60204082, 7.85714286, 8.1122449 , 8.36734694, 8.62244898, 8.87755102, 9.13265306, 9.3877551 , 9.64285714, 9.89795918, 10.15306122, 10.40816327, 10.66326531, 10.91836735, 11.17346939, 11.42857143, 11.68367347, 11.93877551, 12.19387755, 12.44897959, 12.70408163, 12.95918367, 13.21428571, 13.46938776, 13.7244898 , 13.97959184, 14.23469388, 14.48979592, 14.74489796, 15. ])
- (wavelength, theta)float320.03, 0.04, ..., 0.82, 0.51σ = 0.01, 0.01, ..., 0.43, 0.3
Values:
array([[0.02941431, 0.03962075, 0.02479 , ..., 0. , 0. , 0.08771684], [0.19342533, 0.13359898, 0.05759268, ..., 0.00450809, 0.00318239, 0. ], [0.6901948 , 0.6206242 , 0.40336338, ..., 0.00289595, 0.00981855, 0.00802646], ..., [0.8790608 , 0.7447142 , 0.52488256, ..., 1.3921973 , 2.0572677 , 0.9610032 ], [1.0074228 , 0.5448837 , 0.8602724 , ..., 1.5262661 , 0.89973843, 0.7908709 ], [1.2005191 , 0.836256 , 1.229325 , ..., 2.378372 , 0.8167902 , 0.5099747 ]], dtype=float32)
Variances (σ²):
array([[1.7396870e-04, 1.5808902e-04, 1.2343863e-04, ..., 0.0000000e+00, 0.0000000e+00, 7.7484306e-03], [7.0455519e-04, 3.2069537e-04, 1.3960512e-04, ..., 2.0330624e-05, 1.0130273e-05, 0.0000000e+00], [1.9628527e-03, 1.2763876e-03, 8.0734747e-04, ..., 8.3886407e-06, 1.9296940e-05, 2.1489215e-05], ..., [8.2516164e-02, 6.3497841e-02, 7.5763062e-02, ..., 1.8515454e-01, 2.8551605e-01, 8.4593095e-02], [1.7398338e-01, 4.6912659e-02, 9.5686071e-02, ..., 2.0795056e-01, 9.8380350e-02, 8.4567048e-02], [3.5688102e-01, 1.1616746e-01, 1.6954046e-01, ..., 5.4390949e-01, 1.8098128e-01, 9.1254145e-02]], dtype=float32)
- experiment_title()stringcommissioning
Values:
'commissioning' - instrument_name()stringAMOR
Values:
'AMOR'
[11]:
sc.plot(lambda_theta)
[12]:
q = norm.q_bin(tools.q_grid())
As can be done for the \(q_z\)-binned data.
[13]:
sc.plot(sc.log10(q))
This data can be written to an ORSO-compatible data file.
[14]:
norm.write_reflectometry('output.ort', tools.q_grid())