SANS2D: I(Q) for sample and background#

In this notebook, we will be reducing a sample and a background measurements to a one-dimensional \(I(Q)\).

It assumes the detector data has been recorded in event mode, while the monitor data has been histogrammed.

The data used in this notebook has been published in Manasi et al. (2021), and we kindly thank the authors for allowing us to use their data.

Outline:

  • We will begin by loading the data files containing the sample, direct, and background measurements.

  • We will then apply some corrections to beamline components specific to the SANS2D beamline.

  • This will be followed by some masking of some saturated or defect detector pixels

  • Finally, the sample and background measurement will be converted to the \(Q\) dimension

[1]:
import matplotlib.pyplot as plt
import scipp as sc
from ess import loki, sans
from ess.logging import configure_workflow
import scippneutron as scn
import scippnexus.v2 as snx
from scippnexus.v2.application_definitions import nxcansas
[2]:
logger = configure_workflow('sans2d_reduction', filename='sans2d.log')

Define reduction workflow parameters#

We define here whether to include the effects of gravity, as well as common wavelength and \(Q\) bins for all the measurements.

[3]:
# Include effects of gravity?
gravity = True

# Wavelength binning
wavelength_bins = sc.linspace(
    dim='wavelength', start=2.0, stop=16.0, num=141, unit='angstrom'
)

# Q binning
q_bins = sc.linspace(dim='Q', start=0.01, stop=0.5, num=141, unit='1/angstrom')

Loading data files#

We load the following files:

  • The direct beam function for the main detector (gives detector efficiency as a function of wavelength)

  • The sample measurement

  • The direct measurement: this is the run with the empty sample holder/cuvette

  • The background measurement: this is the run with only the solvent which the sample is placed in

[4]:
direct_beam = sc.io.load_hdf5(
    loki.data.get_path('DIRECT_SANS2D_REAR_34327_4m_8mm_16Feb16.hdf5')
)
sample = loki.io.load_sans2d(filename=loki.data.get_path('SANS2D00063114.hdf5'))
direct = loki.io.load_sans2d(filename=loki.data.get_path('SANS2D00063091.hdf5'))
background = loki.io.load_sans2d(filename=loki.data.get_path('SANS2D00063159.hdf5'))
dg = {'sample': sample, 'direct': direct, 'background': background}
Downloading file 'DIRECT_SANS2D_REAR_34327_4m_8mm_16Feb16.hdf5' from 'https://public.esss.dk/groups/scipp/ess/loki/1/DIRECT_SANS2D_REAR_34327_4m_8mm_16Feb16.hdf5' to '/home/runner/.cache/ess/loki/1'.
Downloading file 'SANS2D00063114.hdf5' from 'https://public.esss.dk/groups/scipp/ess/loki/1/SANS2D00063114.hdf5' to '/home/runner/.cache/ess/loki/1'.
Downloading file 'SANS2D00063091.hdf5' from 'https://public.esss.dk/groups/scipp/ess/loki/1/SANS2D00063091.hdf5' to '/home/runner/.cache/ess/loki/1'.
Downloading file 'SANS2D00063159.hdf5' from 'https://public.esss.dk/groups/scipp/ess/loki/1/SANS2D00063159.hdf5' to '/home/runner/.cache/ess/loki/1'.

Pre-process monitor data#

We convert the monitor data from time-of-flight to wavelength, remove background noise, and rebin to the requested wavelength binning using the preprocess_monitor_data helper function from the i_of_q submodule:

[5]:
monitors = {}
for key, da in dg.items():
    monitors[f'{key}-incident'] = da.attrs["monitor2"].value
    monitors[f'{key}-transmission'] = da.attrs["monitor4"].value

# Define range outside of which monitor data is considered to be background
non_background_range = sc.array(
    dims=['wavelength'], values=[0.7, 17.1], unit='angstrom'
)

# Run preprocessing
monitors = sans.i_of_q.preprocess_monitor_data(
    monitors, non_background_range=non_background_range, wavelength_bins=wavelength_bins
)

# Unpack monitors to make steps below easier
sample_monitors = {
    'incident': monitors['sample-incident'],
    'transmission': monitors['sample-transmission'],
}
direct_monitors = {
    'incident': monitors['direct-incident'],
    'transmission': monitors['direct-transmission'],
}
background_monitors = {
    'incident': monitors['background-incident'],
    'transmission': monitors['background-transmission'],
}

Masking bad detector pixels#

Note: We use programmatic masks here and not those stored in xml files.

Now that the monitor data is cleaned and binned to the correct wavelength range, we turn to the detector data. The first step is to mask noisy and saturated pixels. We mask the edges of the square-shaped detector panel with a simple distance relation. We also mask the region close to the beam center, where the sample holder is visible as a dark patch with an arm extending to the north-east.

[6]:
mask_edges = (
    sc.abs(sample.coords['position'].fields.x) > sc.scalar(0.48, unit='m')
) | (sc.abs(sample.coords['position'].fields.y) > sc.scalar(0.45, unit='m'))

summed = sample.sum('tof')
holder_mask = (
    (summed.data < sc.scalar(100, unit='counts'))
    & (sample.coords['position'].fields.x > sc.scalar(0, unit='m'))
    & (sample.coords['position'].fields.x < sc.scalar(0.42, unit='m'))
    & (sample.coords['position'].fields.y < sc.scalar(0.05, unit='m'))
    & (sample.coords['position'].fields.y > sc.scalar(-0.15, unit='m'))
)

for da in dg.values():
    da.masks['edges'] = mask_edges
    da.masks['holder_mask'] = holder_mask

A good sanity check is to view the masks on the instrument view:

[7]:
scn.instrument_view(sample.hist(), pixel_size=0.0075)
[7]:

Beam center finder#

The beam is not guaranteed to travel through the center of the detector panel, and we thus have to apply a horizontal and vertical offset to our pixel positions so that the beam centre is at x = y = 0. This is necessary for subsequent azimuthal averaging of the data counts into \(Q\) bins.

The beam_center utility in the sans module is designed for this. It requires us to define a \(Q\) range over which convergence will be checked.

[8]:
q_range = sc.linspace('Q', 0.02, 0.3, 71, unit='1/angstrom')

center = sans.beam_center(
    data=dg['sample'],
    data_monitors=sample_monitors,
    direct_monitors=direct_monitors,
    wavelength_bins=wavelength_bins,
    q_bins=q_range,
    gravity=gravity,
)

print(center)

# Now shift pixels positions to get the correct beam center
for da in dg.values():
    da.coords['position'] -= center
<scipp.Variable> ()    vector3              [m]  (0.0945643, -0.082074, 0)

Mask Bragg peaks in wavelength#

We will now take out the time regions with Bragg peaks from the beam stop and detector window, although in reality the peaks appear only close to the beam stop, and will make little difference to \(I(Q)\).

This could be implemented as masking specific time bins for a specific region in space, but for now we keep it simple.

[9]:
wavelength_mask = sc.DataArray(
    data=sc.array(dims=['wavelength'], values=[True]),
    coords={
        'wavelength': sc.array(
            dims=['wavelength'], values=[2.21, 2.59], unit='angstrom'
        )
    },
)

Use to_I_of_Q workflow#

We now reduce the sample and the background measurements to Q using the sans.to_I_of_Q workflow.

In that process, the intensity as a function of Q is normalized using the direct measurement and direct beam function.

We call the workflow on both the sample and background runs:

[10]:
sample_q = sans.to_I_of_Q(
    data=dg['sample'],
    data_monitors=sample_monitors,
    direct_monitors=direct_monitors,
    direct_beam=direct_beam,
    wavelength_bins=wavelength_bins,
    q_bins=q_bins,
    gravity=gravity,
    wavelength_mask=wavelength_mask,
)
sample_q.hist().plot()
[2024-04-03T11:19:15+0000] WARNING  <scipp.ess.sans> :
    An interpolation was performed on the direct_beam function. The variances in the direct_beam function have been dropped.
[10]:
../../_images/instruments_loki_sans2d_reduction_18_1.svg
[11]:
background_q = sans.to_I_of_Q(
    data=dg['background'],
    data_monitors=background_monitors,
    direct_monitors=direct_monitors,
    direct_beam=direct_beam,
    wavelength_bins=wavelength_bins,
    q_bins=q_bins,
    gravity=gravity,
    wavelength_mask=wavelength_mask,
)
background_q.hist().plot()
[2024-04-03T11:19:16+0000] WARNING  <scipp.ess.sans> :
    An interpolation was performed on the direct_beam function. The variances in the direct_beam function have been dropped.
[11]:
../../_images/instruments_loki_sans2d_reduction_19_1.svg

We are now in a position to subtract the background from the sample measurement:

[12]:
result = sample_q.bins.sum() - background_q.bins.sum()
result
[12]:
Show/Hide data repr Show/Hide attributes
scipp.DataArray (64.13 KB)
    • Q: 140
    • L1
      ()
      float64
      m
      19.334
      Values:
      array(19.334)
    • Q
      (Q [bin-edge])
      float64
      1/Å
      0.01, 0.013, ..., 0.496, 0.5
      Values:
      array([0.01 , 0.0135, 0.017 , 0.0205, 0.024 , 0.0275, 0.031 , 0.0345, 0.038 , 0.0415, 0.045 , 0.0485, 0.052 , 0.0555, 0.059 , 0.0625, 0.066 , 0.0695, 0.073 , 0.0765, 0.08 , 0.0835, 0.087 , 0.0905, 0.094 , 0.0975, 0.101 , 0.1045, 0.108 , 0.1115, 0.115 , 0.1185, 0.122 , 0.1255, 0.129 , 0.1325, 0.136 , 0.1395, 0.143 , 0.1465, 0.15 , 0.1535, 0.157 , 0.1605, 0.164 , 0.1675, 0.171 , 0.1745, 0.178 , 0.1815, 0.185 , 0.1885, 0.192 , 0.1955, 0.199 , 0.2025, 0.206 , 0.2095, 0.213 , 0.2165, 0.22 , 0.2235, 0.227 , 0.2305, 0.234 , 0.2375, 0.241 , 0.2445, 0.248 , 0.2515, 0.255 , 0.2585, 0.262 , 0.2655, 0.269 , 0.2725, 0.276 , 0.2795, 0.283 , 0.2865, 0.29 , 0.2935, 0.297 , 0.3005, 0.304 , 0.3075, 0.311 , 0.3145, 0.318 , 0.3215, 0.325 , 0.3285, 0.332 , 0.3355, 0.339 , 0.3425, 0.346 , 0.3495, 0.353 , 0.3565, 0.36 , 0.3635, 0.367 , 0.3705, 0.374 , 0.3775, 0.381 , 0.3845, 0.388 , 0.3915, 0.395 , 0.3985, 0.402 , 0.4055, 0.409 , 0.4125, 0.416 , 0.4195, 0.423 , 0.4265, 0.43 , 0.4335, 0.437 , 0.4405, 0.444 , 0.4475, 0.451 , 0.4545, 0.458 , 0.4615, 0.465 , 0.4685, 0.472 , 0.4755, 0.479 , 0.4825, 0.486 , 0.4895, 0.493 , 0.4965, 0.5 ])
    • gravity
      ()
      vector3
      m/s^2
      [ 0. -9.80665 0. ]
      Values:
      array([ 0. , -9.80665, 0. ])
    • incident_beam
      ()
      vector3
      m
      [ 0. 0. 19.334]
      Values:
      array([ 0. , 0. , 19.334])
    • pixel_height
      ()
      float64
      m
      0.002033984375
      Values:
      array(0.00203398)
    • pixel_width
      ()
      float64
      m
      0.0035
      Values:
      array(0.0035)
    • sample_position
      ()
      vector3
      m
      [ 0. 0. 19.334]
      Values:
      array([ 0. , 0. , 19.334])
    • source_position
      ()
      vector3
      m
      [0. 0. 0.]
      Values:
      array([0., 0., 0.])
    • wavelength
      (wavelength)
      float64
      Å
      2.0, 16.0
      Values:
      array([ 2., 16.])
    • (Q)
      float32
      𝟙
      161.78444, 165.29965, ..., 13.476799, 15.517735
      σ = 1.3260165, 1.042895, ..., 1.7960951, 1.967876
      Values:
      array([161.78444 , 165.29965 , 171.25478 , 175.2563 , 183.40327 , 193.42014 , 201.35278 , 210.56567 , 224.33945 , 238.68176 , 258.84473 , 280.33835 , 305.01505 , 333.4955 , 364.42712 , 395.85257 , 422.90314 , 444.27954 , 450.4084 , 437.84937 , 408.74414 , 363.2295 , 311.37177 , 259.4588 , 211.42996 , 171.83272 , 139.6375 , 113.08425 , 92.71926 , 76.140686 , 63.164036 , 53.819695 , 45.84127 , 39.518814 , 34.46906 , 30.297415 , 27.540356 , 24.990686 , 22.95015 , 21.41086 , 20.077946 , 19.107616 , 18.784996 , 18.306068 , 17.741531 , 17.434677 , 17.040321 , 17.305439 , 16.861364 , 17.095934 , 16.935135 , 16.988256 , 16.779318 , 16.45695 , 16.720547 , 16.50543 , 16.669086 , 16.250322 , 15.979316 , 15.868567 , 16.228926 , 15.8302765, 15.760885 , 15.847942 , 16.119442 , 15.979694 , 15.376701 , 15.274389 , 15.412689 , 15.579598 , 15.159598 , 15.252158 , 15.422558 , 14.860669 , 14.897312 , 14.890955 , 15.219356 , 14.922459 , 15.021738 , 14.841351 , 14.342807 , 15.210317 , 14.133667 , 14.853384 , 14.653447 , 14.537657 , 15.254662 , 15.20522 , 15.434814 , 14.29929 , 15.423164 , 14.142195 , 14.816057 , 14.703209 , 14.68547 , 15.237367 , 15.839544 , 14.801003 , 14.4092865, 14.763835 , 15.466315 , 14.936306 , 15.2029705, 14.175878 , 15.652899 , 14.543182 , 14.137838 , 14.459902 , 15.416008 , 14.654943 , 14.505656 , 15.005402 , 14.195094 , 14.022969 , 14.150953 , 14.497314 , 13.856966 , 14.14429 , 14.861629 , 14.229111 , 13.331196 , 14.930405 , 14.17462 , 15.687802 , 13.055973 , 15.397145 , 14.307382 , 15.312213 , 14.023117 , 14.753797 , 14.785855 , 12.179808 , 13.155926 , 12.271888 , 10.933204 , 14.237772 , 13.778609 , 11.915322 , 13.476799 , 15.517735 ], dtype=float32)

      Variances (σ²):
      array([1.7583197 , 1.0876298 , 0.8152003 , 0.67626584, 0.60469294, 0.55829257, 0.5168169 , 0.48769057, 0.47252294, 0.46340716, 0.46652868, 0.4735413 , 0.48509178, 0.502195 , 0.52430487, 0.54558456, 0.5605339 , 0.5708923 , 0.5611004 , 0.5319528 , 0.485764 , 0.42330873, 0.35715216, 0.29282087, 0.23640609, 0.1906748 , 0.15405802, 0.12467595, 0.10203931, 0.08396456, 0.07004694, 0.06011045, 0.051602 , 0.04508053, 0.03968527, 0.03563153, 0.03287712, 0.03022594, 0.02822677, 0.02693907, 0.02573748, 0.02510064, 0.02502436, 0.02478819, 0.02459623, 0.02467373, 0.02469771, 0.02540914, 0.02544596, 0.02625924, 0.02677828, 0.02764825, 0.02789999, 0.02838071, 0.02963788, 0.03025249, 0.03121522, 0.03171728, 0.0322886 , 0.03318183, 0.03476194, 0.03566809, 0.03654954, 0.03792671, 0.04019926, 0.04164233, 0.04139678, 0.04311093, 0.04495625, 0.0473176 , 0.04678401, 0.04951651, 0.0517948 , 0.05379223, 0.05454113, 0.05685369, 0.06056976, 0.06246104, 0.06576307, 0.06767666, 0.0691793 , 0.07796361, 0.07639227, 0.08372991, 0.0880893 , 0.09333858, 0.10204349, 0.1066614 , 0.11879715, 0.12010423, 0.13256356, 0.13131465, 0.14859737, 0.15892981, 0.16893926, 0.18539147, 0.2147794 , 0.20608588, 0.22680768, 0.24627978, 0.26227814, 0.28425866, 0.29928806, 0.30683067, 0.36096698, 0.34571573, 0.37534234, 0.37558445, 0.4531969 , 0.45728898, 0.48383632, 0.5232283 , 0.5289032 , 0.54186743, 0.61048144, 0.6574644 , 0.6260512 , 0.68812996, 0.7724814 , 0.813479 , 0.82270044, 0.9434157 , 0.97440815, 1.1310067 , 1.0624584 , 1.3480734 , 1.3999326 , 1.522354 , 1.6545621 , 1.7093427 , 1.9869848 , 1.7573869 , 1.906035 , 2.291194 , 1.7023892 , 2.6989024 , 2.7843099 , 2.5185847 , 3.2259579 , 3.872536 ], dtype=float32)
    • current_period
      ()
      int64
      𝟙
      1
      Values:
      array(1)
    • experiment_identifier
      ()
      string
      𝟙
      1920676
      Values:
      '1920676'
    • instrument_name
      ()
      string
      SANS2D
      Values:
      'SANS2D'
    • measurement_id
      ()
      string
      𝟙
      Values:
      ''
    • measurement_label
      ()
      string
      𝟙
      Values:
      ''
    • measurement_subid
      ()
      string
      𝟙
      Values:
      ''
    • measurement_type
      ()
      string
      𝟙
      Values:
      ''
    • nperiods
      ()
      int64
      𝟙
      1
      Values:
      array(1)
    • placeholder monitor_5
      ()
      DataArray
      {dims=[tof: 481], unit=counts, coords=[tof, position, source_position]}
      Values:
      <scipp.DataArray> Dimensions: Sizes[tof:481, ] Coordinates: * position vector3 [m] () (0, 0, 0) * source_position vector3 [m] () (0, 0, 0) * tof float64 [µs] (tof [bin-edge]) [5.5, 50, ..., 99750, 100005] Data: float64 [counts] (tof) [0, 0, ..., 0, 0] [0, 0, ..., 0, 0] Attributes: instrument_name string <no unit> () "SANS2D" sample_position vector3 [m] () (0, 0, 19.281) spectrum int32 <no unit> () 5
    • placeholder monitor_6
      ()
      DataArray
      {dims=[tof: 481], unit=counts, coords=[tof, position, source_position]}
      Values:
      <scipp.DataArray> Dimensions: Sizes[tof:481, ] Coordinates: * position vector3 [m] () (0, 0, 0) * source_position vector3 [m] () (0, 0, 0) * tof float64 [µs] (tof [bin-edge]) [5.5, 50, ..., 99750, 100005] Data: float64 [counts] (tof) [0, 0, ..., 0, 0] [0, 0, ..., 0, 0] Attributes: instrument_name string <no unit> () "SANS2D" sample_position vector3 [m] () (0, 0, 19.281) spectrum int32 <no unit> () 6
    • placeholder monitor_7
      ()
      DataArray
      {dims=[tof: 481], unit=counts, coords=[tof, position, source_position]}
      Values:
      <scipp.DataArray> Dimensions: Sizes[tof:481, ] Coordinates: * position vector3 [m] () (0, 0, 0) * source_position vector3 [m] () (0, 0, 0) * tof float64 [µs] (tof [bin-edge]) [5.5, 50, ..., 99750, 100005] Data: float64 [counts] (tof) [0, 0, ..., 0, 0] [0, 0, ..., 0, 0] Attributes: instrument_name string <no unit> () "SANS2D" sample_position vector3 [m] () (0, 0, 19.281) spectrum int32 <no unit> () 7
    • placeholder monitor_8
      ()
      DataArray
      {dims=[tof: 481], unit=counts, coords=[tof, position, source_position]}
      Values:
      <scipp.DataArray> Dimensions: Sizes[tof:481, ] Coordinates: * position vector3 [m] () (0, 0, 0) * source_position vector3 [m] () (0, 0, 0) * tof float64 [µs] (tof [bin-edge]) [5.5, 50, ..., 99750, 100005] Data: float64 [counts] (tof) [0, 0, ..., 0, 0] [0, 0, ..., 0, 0] Attributes: instrument_name string <no unit> () "SANS2D" sample_position vector3 [m] () (0, 0, 19.281) spectrum int32 <no unit> () 8
[13]:
fig1, ax1 = plt.subplots(1, 2, figsize=(10, 4))
sc.plot(result, ax=ax1[0])
sc.plot(result, norm='log', ax=ax1[1])
[13]:
../../_images/instruments_loki_sans2d_reduction_22_0.svg

Note

Instead of .bins.sum(), one could use sc.histogram() above to define different Q bins compared to the ones defined at the top of the notebook. This can be done in event mode, see here.

There may be performance advantages to first use a coarse Q binning when the computing I(Q) numerator, and use finer binning for the final results.

Wavelength bands#

It is often useful to process the data in a small number (~10) of separate wavelength bands.

This can be achieved by requesting 10 bands from the to_I_of_Q workflow via the wavelength_bands argument.

[14]:
wavelength_bands = sc.linspace(
    dim='wavelength', start=2.0, stop=16.0, num=11, unit='angstrom'
)

sample_slices = sans.to_I_of_Q(
    data=dg['sample'],
    data_monitors=sample_monitors,
    direct_monitors=direct_monitors,
    direct_beam=direct_beam,
    wavelength_bins=wavelength_bins,
    q_bins=q_bins,
    gravity=gravity,
    wavelength_bands=wavelength_bands,
    wavelength_mask=wavelength_mask,
)

background_slices = sans.to_I_of_Q(
    data=dg['background'],
    data_monitors=background_monitors,
    direct_monitors=direct_monitors,
    direct_beam=direct_beam,
    wavelength_bins=wavelength_bins,
    q_bins=q_bins,
    gravity=gravity,
    wavelength_bands=wavelength_bands,
    wavelength_mask=wavelength_mask,
)

result_slices = sample_slices.bins.sum() - background_slices.bins.sum()
result_slices
[2024-04-03T11:19:18+0000] WARNING  <scipp.ess.sans> :
    An interpolation was performed on the direct_beam function. The variances in the direct_beam function have been dropped.
[2024-04-03T11:19:19+0000] WARNING  <scipp.ess.sans> :
    An interpolation was performed on the direct_beam function. The variances in the direct_beam function have been dropped.
[14]:
Show/Hide data repr Show/Hide attributes
scipp.DataArray (74.05 KB)
    • Q: 140
    • wavelength: 10
    • L1
      ()
      float64
      m
      19.334
      Values:
      array(19.334)
    • Q
      (Q [bin-edge])
      float64
      1/Å
      0.01, 0.013, ..., 0.496, 0.5
      Values:
      array([0.01 , 0.0135, 0.017 , 0.0205, 0.024 , 0.0275, 0.031 , 0.0345, 0.038 , 0.0415, 0.045 , 0.0485, 0.052 , 0.0555, 0.059 , 0.0625, 0.066 , 0.0695, 0.073 , 0.0765, 0.08 , 0.0835, 0.087 , 0.0905, 0.094 , 0.0975, 0.101 , 0.1045, 0.108 , 0.1115, 0.115 , 0.1185, 0.122 , 0.1255, 0.129 , 0.1325, 0.136 , 0.1395, 0.143 , 0.1465, 0.15 , 0.1535, 0.157 , 0.1605, 0.164 , 0.1675, 0.171 , 0.1745, 0.178 , 0.1815, 0.185 , 0.1885, 0.192 , 0.1955, 0.199 , 0.2025, 0.206 , 0.2095, 0.213 , 0.2165, 0.22 , 0.2235, 0.227 , 0.2305, 0.234 , 0.2375, 0.241 , 0.2445, 0.248 , 0.2515, 0.255 , 0.2585, 0.262 , 0.2655, 0.269 , 0.2725, 0.276 , 0.2795, 0.283 , 0.2865, 0.29 , 0.2935, 0.297 , 0.3005, 0.304 , 0.3075, 0.311 , 0.3145, 0.318 , 0.3215, 0.325 , 0.3285, 0.332 , 0.3355, 0.339 , 0.3425, 0.346 , 0.3495, 0.353 , 0.3565, 0.36 , 0.3635, 0.367 , 0.3705, 0.374 , 0.3775, 0.381 , 0.3845, 0.388 , 0.3915, 0.395 , 0.3985, 0.402 , 0.4055, 0.409 , 0.4125, 0.416 , 0.4195, 0.423 , 0.4265, 0.43 , 0.4335, 0.437 , 0.4405, 0.444 , 0.4475, 0.451 , 0.4545, 0.458 , 0.4615, 0.465 , 0.4685, 0.472 , 0.4755, 0.479 , 0.4825, 0.486 , 0.4895, 0.493 , 0.4965, 0.5 ])
    • gravity
      ()
      vector3
      m/s^2
      [ 0. -9.80665 0. ]
      Values:
      array([ 0. , -9.80665, 0. ])
    • incident_beam
      ()
      vector3
      m
      [ 0. 0. 19.334]
      Values:
      array([ 0. , 0. , 19.334])
    • pixel_height
      ()
      float64
      m
      0.002033984375
      Values:
      array(0.00203398)
    • pixel_width
      ()
      float64
      m
      0.0035
      Values:
      array(0.0035)
    • sample_position
      ()
      vector3
      m
      [ 0. 0. 19.334]
      Values:
      array([ 0. , 0. , 19.334])
    • source_position
      ()
      vector3
      m
      [0. 0. 0.]
      Values:
      array([0., 0., 0.])
    • wavelength
      (wavelength [bin-edge])
      float64
      Å
      2.0, 3.4, ..., 14.6, 16.0
      Values:
      array([ 2. , 3.4, 4.8, 6.2, 7.6, 9. , 10.4, 11.8, 13.2, 14.6, 16. ])
    • (Q, wavelength)
      float32
      𝟙
      95.59793, 129.73592, ..., 0.0, 0.0
      σ = 16.669903, 3.2071216, ..., 0.0, 0.0
      Values:
      array([[ 95.59793 , 129.73592 , 152.61768 , ..., 187.0749 , 181.9613 , 196.12837 ], [114.29981 , 153.99359 , 167.6352 , ..., 178.72124 , 186.442 , 191.61877 ], [141.40605 , 168.64348 , 171.59222 , ..., 181.55257 , 202.8205 , 200.87894 ], ..., [ 11.915322, 0. , 0. , ..., 0. , 0. , 0. ], [ 13.476799, 0. , 0. , ..., 0. , 0. , 0. ], [ 15.517735, 0. , 0. , ..., 0. , 0. , 0. ]], dtype=float32)

      Variances (σ²):
      array([[277.88568 , 10.285629 , 5.9534698, ..., 45.006645 , 64.12296 , 97.744064 ], [ 16.891293 , 4.0625243, 4.577567 , ..., 33.06983 , 49.57422 , 73.468575 ], [ 6.2256346, 3.128347 , 3.7712398, ..., 27.112074 , 43.547905 , 62.603054 ], ..., [ 2.5185847, 0. , 0. , ..., 0. , 0. , 0. ], [ 3.2259579, 0. , 0. , ..., 0. , 0. , 0. ], [ 3.872536 , 0. , 0. , ..., 0. , 0. , 0. ]], dtype=float32)
    • current_period
      ()
      int64
      𝟙
      1
      Values:
      array(1)
    • experiment_identifier
      ()
      string
      𝟙
      1920676
      Values:
      '1920676'
    • instrument_name
      ()
      string
      SANS2D
      Values:
      'SANS2D'
    • measurement_id
      ()
      string
      𝟙
      Values:
      ''
    • measurement_label
      ()
      string
      𝟙
      Values:
      ''
    • measurement_subid
      ()
      string
      𝟙
      Values:
      ''
    • measurement_type
      ()
      string
      𝟙
      Values:
      ''
    • nperiods
      ()
      int64
      𝟙
      1
      Values:
      array(1)
    • placeholder monitor_5
      ()
      DataArray
      {dims=[tof: 481], unit=counts, coords=[tof, position, source_position]}
      Values:
      <scipp.DataArray> Dimensions: Sizes[tof:481, ] Coordinates: * position vector3 [m] () (0, 0, 0) * source_position vector3 [m] () (0, 0, 0) * tof float64 [µs] (tof [bin-edge]) [5.5, 50, ..., 99750, 100005] Data: float64 [counts] (tof) [0, 0, ..., 0, 0] [0, 0, ..., 0, 0] Attributes: instrument_name string <no unit> () "SANS2D" sample_position vector3 [m] () (0, 0, 19.281) spectrum int32 <no unit> () 5
    • placeholder monitor_6
      ()
      DataArray
      {dims=[tof: 481], unit=counts, coords=[tof, position, source_position]}
      Values:
      <scipp.DataArray> Dimensions: Sizes[tof:481, ] Coordinates: * position vector3 [m] () (0, 0, 0) * source_position vector3 [m] () (0, 0, 0) * tof float64 [µs] (tof [bin-edge]) [5.5, 50, ..., 99750, 100005] Data: float64 [counts] (tof) [0, 0, ..., 0, 0] [0, 0, ..., 0, 0] Attributes: instrument_name string <no unit> () "SANS2D" sample_position vector3 [m] () (0, 0, 19.281) spectrum int32 <no unit> () 6
    • placeholder monitor_7
      ()
      DataArray
      {dims=[tof: 481], unit=counts, coords=[tof, position, source_position]}
      Values:
      <scipp.DataArray> Dimensions: Sizes[tof:481, ] Coordinates: * position vector3 [m] () (0, 0, 0) * source_position vector3 [m] () (0, 0, 0) * tof float64 [µs] (tof [bin-edge]) [5.5, 50, ..., 99750, 100005] Data: float64 [counts] (tof) [0, 0, ..., 0, 0] [0, 0, ..., 0, 0] Attributes: instrument_name string <no unit> () "SANS2D" sample_position vector3 [m] () (0, 0, 19.281) spectrum int32 <no unit> () 7
    • placeholder monitor_8
      ()
      DataArray
      {dims=[tof: 481], unit=counts, coords=[tof, position, source_position]}
      Values:
      <scipp.DataArray> Dimensions: Sizes[tof:481, ] Coordinates: * position vector3 [m] () (0, 0, 0) * source_position vector3 [m] () (0, 0, 0) * tof float64 [µs] (tof [bin-edge]) [5.5, 50, ..., 99750, 100005] Data: float64 [counts] (tof) [0, 0, ..., 0, 0] [0, 0, ..., 0, 0] Attributes: instrument_name string <no unit> () "SANS2D" sample_position vector3 [m] () (0, 0, 19.281) spectrum int32 <no unit> () 8
[15]:
collapsed = sc.collapse(result_slices, keep='Q')

fig2, ax2 = plt.subplots(1, 2, figsize=(10, 4))
sc.plot(collapsed, ax=ax2[0])
sc.plot(collapsed, norm='log', ax=ax2[1])
/home/runner/micromamba/envs/ess-developer/lib/python3.8/site-packages/matplotlib/axes/_axes.py:3642: RuntimeWarning: invalid value encountered in add
  low, high = dep + np.row_stack([-(1 - lolims), 1 - uplims]) * err
[15]:
../../_images/instruments_loki_sans2d_reduction_26_1.svg

Saving reduced data to file#

Finally, we can save reduced data to the file. Below there is an example of saving data for full range into NXcanSAS format (NeXus compatible)

[16]:
result.coords['Q'] = sc.midpoints(result.coords['Q'])

with snx.File('test.nxs', 'w') as f:
    f['sasentry'] = nxcansas.SASentry(title='hd-DES_10_h-C16EO8', run=63114)
    f['sasentry']['sasdata'] = nxcansas.SASdata(result, Q_variances='resolutions')

References#

Manasi I., Andalibi M. R., Atri R. S., Hooton J., King S. M., Edler K. J., 2021, Self-assembly of ionic and non-ionic surfactants in type IV cerium nitrate and urea based deep eutectic solvent, J. Chem. Phys. 155, 084902