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]:
Show/Hide data repr Show/Hide attributes
scipp.DataArray (19.65 KB)
    • wavelength: 49
    • theta: 49
    • sample_position
      ()
      vector_3_float64
      m
      [0. 0. 0.]
      Values:
      array([0., 0., 0.])
    • source_position
      ()
      vector_3_float64
      m
      [ 0. 0. -15.]
      Values:
      array([ 0., 0., -15.])
    • theta
      (theta [bin-edge])
      float64
      deg
      0.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)
      float32
      0.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
      ()
      string
      commissioning
      Values:
      'commissioning'
    • instrument_name
      ()
      string
      AMOR
      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())