nx5d

Quick Start

  • Home
  • A First Example

User's Guide

  • Overview
  • Installing
  • Core Concepts
  • API Guide
  • Managing Spice
  • Loading Data
    • URLs, Handles, Keys
    • Subclassing Examples
      • Minimal, Purely In-Memory Example
        • A Made-Up Experiment Structure
        • Preparing The "Loading" Code
        • Simulated "Listing And Loading"
      • Filesystem-Based Custom Format
        • Obtaining And Investigating The Test Data
        • The Code: Loading And Delegating
        • Listing Repository
        • Accessing Data
        • Spicing Things Up
      • H5-Like Array-Based Formats
  • Adapting And Extending

Tutorials

  • A Real-Life Example

Reference

  • Supported Beamlines
  • API Reference
  • Glossary
  • License
nx5d
  • User's Guide
  • Loading Data

Loading Data¶

Loading data involves finding it, and reading it. In Nx5d the distinction is necessary because of the inherent link between experimental data and spice.

Contents:

  • URLs, Handles, Keys
  • Subclassing Examples
    • Minimal, Purely In-Memory Example
    • Filesystem-Based Custom Format
    • H5-Like Array-Based Formats

URLs, Handles, Keys¶

The first step of finding data is, in itself, also a two-step process: finding the proposal within a repository, and then scan within.

Nx5d internally works by referencing data in a URL style: supported schemes (file, http, s3) are followed by a target document (server, folder, path to an HDF5) and an document anchor within that document separated by the rest of the URL by the # token (e.g. path within the HDF5 file). The document boundary may be at any level: proposal, or scan.

A typical URL may look like any of these:

  • file:///tmp/drepo/{proposal}/data.h5#{scan}
  • file:///tmp/drepo/{proposal}/{proposal}.h5#{proposal}/{scan}
  • file:///tmp/drepo.hdf#{proposal}/{scan}
  • file:///tmp/drepo/{proposal}/{proposal}-{scan}.h5#data/

URL patterns are required to contain the {proposal} and {scan} Python formatting keywords for identifying the actual scan data payload. Each of the keywords can appear multiple times at any location in the URL, and the various implementations of the corresponding Nx5d classes will try to cope :-)

The key-parsing / key-replacing pattern is used, in different ways, for two distinct tasks:

  • generate listings by parsing keys, e.g. of proposals in a repository, or scan, in a proposal

  • generate references (i.e. URLs) for loading the corresponding resource, proposal or scan, by filling keys in.

The information that matches the formatting keys is also called a key in Nx5d -- a proposal key for {proposal}, respectively scan key for {scan}. Nx5d also internally needs to create a handle out of each key. Handles are expected to be strings that are compatible with Python symbol naming conventions (i.e. no spaces, no punctuation apart from underscore "_", first character must be a letter). Both handles and keys are used internally within the Nx5d API to address resources (scans and proposals). But handles are also used to build more easy-to-use interfaces, where sub-objects like proposals in a repo, or scans in a proposal, can be accessed by autocompletion in a suitable environment (e.g. Jupyter).

Subclassing Examples¶

Finding and loading data involves work on three levels: repositories, proposals, scans. Repositories and proposals need to be identified and have their contents listed, while scans are the "low-level" component that is actually tasked with reading data from disk. Supporting a data storage format (i.e. a "new beamline") therefore involves implementing the required unique combination of 3 such classes. Typically this involves subclassing of either the corresponding components in nx5d.repo.base, or of slightly more specialized classes in nx5d.repo.filesystem or nx5d.repo.astor.

We are demonstrating this in several examples.

Minimal, Purely In-Memory Example¶

The simplest example is useless in terms of real-world application, but makes the essential API elements that need implementing easier to understand.

A Made-Up Experiment Structure¶

Here's our minimal example scenario:

  • the proposal is a purely in-memory Python dictionary which contains 3 hard-coded proposals ("alfa", "bravo", "charlie")

  • each proposal has 4 scans, labeled by the first letter and a number from 1 to 4 (i.e. "a1", "a2", "a3", "a4" for "alpha"'s scans, "b1", "b2", ... for "bravo"'s scans etc)

  • the data is a simple Python tuple of strings (proposal, scan).

  • the processing, or cooking involved, consists only of transforming the strings to upper case.

Preparing The "Loading" Code¶

...actually, we'll be hard-coding the data into the code.

We are subclassing directly from the nx5d.repo.base classes:

In [48]:
Copied!
from nx5d.repo.base import DataScanBase, DataProposalBase, DataRepoBase
from nx5d.repo.base import DataScanBase, DataProposalBase, DataRepoBase

The first class we're implementing is the scan class, and we call it SimpleScan. We need to overwrite the ._get_raw() and ._cook() functions to simulate loading, respectively processing. The ._get_summary() function may seem like a pointless exercise here, but it's intended for more "heavy use" scenarii: sometimes, when there are serious amounts of data involved, loading by ._get_raw() takes time. Then ._get_summary() is expected to deliver as many individual details as feasible with a minimal amount of processing -- just enough to identify main features of the scan in a (possibly large) listing, but without spending precious time on fully loading a scan's data.

Here the full class:

In [49]:
Copied!
class SimpleScan(DataScanBase):
    def __init__(self, parent_proposal, scan_key):
        super().__init__(parent_proposal, scan_key)
        self._parent_prop = parent_proposal 

    def _get_summary(self):
        return {
            'type': 'default_type',
            'description': 'Nonsensical Demo Scan Class'
        }

    def _get_raw(self):
        return (self._parent_prop.key, self.key)

    def _cook(self, data, **spice):
        return tuple([d.upper() for d in data])
class SimpleScan(DataScanBase): def __init__(self, parent_proposal, scan_key): super().__init__(parent_proposal, scan_key) self._parent_prop = parent_proposal def _get_summary(self): return { 'type': 'default_type', 'description': 'Nonsensical Demo Scan Class' } def _get_raw(self): return (self._parent_prop.key, self.key) def _cook(self, data, **spice): return tuple([d.upper() for d in data])

The proposal and repository classes are simpler. All they do is hold a static database (here a dict()) in memory, from which they provide listing via .all(), or return an instance of a lower-level object via ._scan(), respectively ._proposal():

In [50]:
Copied!
class SimpleProposal(DataProposalBase):
    def __init__(self, repo, key):
        self._scans = [ f'{key[0]}{i}' for i in range(4) ]
        super().__init__(repo, key)

    def all(self):
        return { k:k for k in self._scans }

    def _scan(self, scan_key):
        return SimpleScan(self, scan_key)

class SimpleRepository(DataRepoBase):
    def __init__(self):
        self._proposals = [ 'alpha', 'bravo', 'charlie' ]
        super().__init__(url='memory')

    def all(self):
        return { k:k for k in self._proposals }
        
    def _proposal(self, proposal_key):
        return SimpleProposal(self, proposal_key)
class SimpleProposal(DataProposalBase): def __init__(self, repo, key): self._scans = [ f'{key[0]}{i}' for i in range(4) ] super().__init__(repo, key) def all(self): return { k:k for k in self._scans } def _scan(self, scan_key): return SimpleScan(self, scan_key) class SimpleRepository(DataRepoBase): def __init__(self): self._proposals = [ 'alpha', 'bravo', 'charlie' ] super().__init__(url='memory') def all(self): return { k:k for k in self._proposals } def _proposal(self, proposal_key): return SimpleProposal(self, proposal_key)

Simulated "Listing And Loading"¶

Now we can put our example to the test by initializing a repository, and performing basic activities we'd perform with "real" data:

In [51]:
Copied!
simple = SimpleRepository()
simple.all()
simple = SimpleRepository() simple.all()
Out[51]:
{'alpha': 'alpha', 'bravo': 'bravo', 'charlie': 'charlie'}

Generate a scan listing of simple.alpha:

In [52]:
Copied!
simple.alpha
simple.alpha
Out[52]:
scan type integration steps notes
default_type a0 Nonsensical Demo Scan Class
default_type a1 Nonsensical Demo Scan Class
default_type a2 Nonsensical Demo Scan Class
default_type a3 Nonsensical Demo Scan Class

View the raw and cooked data of simple.alpha.a0:

In [53]:
Copied!
print('   raw:', simple.alpha.a0.raw)
print('cooked:', simple.alpha.a0.cooked)
print(' raw:', simple.alpha.a0.raw) print('cooked:', simple.alpha.a0.cooked)
   raw: ('alpha', 'a0')
cooked: ('ALPHA', 'A0')

In essence, we now understand how the API structure works around "loading" the a0 scan and viewing its "raw data" -- which is a tuple of strings, as hard-coded; and its processing form, the upper-case version of the same strings -- again, as hardcoded.

You're encouraged to retrieve the other scans and/or proposals (b0, c3, ...) and convince yourself that our class family works as intended.

Filesystem-Based Custom Format¶

This is one of the most likely starting points when supporting a new experimental endstation: scan data in files, grouped together in a corresponding folder structure of the kind proposla/scan/.... To demonstrate, let's consider a test data example.

Obtaining And Investigating The Test Data¶

We download the test repository repo2 and consider the structure of the repository:

In [7]:
Copied!
%%bash

# Download and unpack the test data
mkdir -p ~/tmp && cd ~/tmp
curl https://gitlab.com/kmc3-xpp/nx5d-examples/-/raw/master/data/repo2.tgz 2> /dev/null | tar xzf -

# View the folder stucture
find ~/tmp/repo2 -type d -ls

# View the first and last few files (there are ~5200 of them in total...) 
ls -l ~/tmp/repo2/20210205/091726/ | head -n 5
echo ...
ls -l ~/tmp/repo2/20210205/091726/ | tail -n 5
%%bash # Download and unpack the test data mkdir -p ~/tmp && cd ~/tmp curl https://gitlab.com/kmc3-xpp/nx5d-examples/-/raw/master/data/repo2.tgz 2> /dev/null | tar xzf - # View the folder stucture find ~/tmp/repo2 -type d -ls # View the first and last few files (there are ~5200 of them in total...) ls -l ~/tmp/repo2/20210205/091726/ | head -n 5 echo ... ls -l ~/tmp/repo2/20210205/091726/ | tail -n 5
  9806215      0 drwxr-sr-x   1 jovyan   users          16 Oct 11 14:54 /home/jovyan/tmp/repo2
  9806216      0 drwxr-sr-x   1 jovyan   users          12 Oct 11 14:21 /home/jovyan/tmp/repo2/20210205
  9806217      0 drwxr-sr-x   1 jovyan   users      155662 Oct 11 14:53 /home/jovyan/tmp/repo2/20210205/091726
total 21232
-rw-r--r--. 1 jovyan users   2693 Oct 11 14:45 image00000.tiff
-rw-r--r--. 1 jovyan users   2502 Oct 11 14:45 image00001.tiff
-rw-r--r--. 1 jovyan users   2511 Oct 11 14:45 image00002.tiff
-rw-r--r--. 1 jovyan users   2346 Oct 11 14:45 image00003.tiff
...
-rw-r--r--. 1 jovyan users   1594 Oct 11 14:45 image05184.tiff
-rw-r--r--. 1 jovyan users   1642 Oct 11 14:45 image05185.tiff
-rw-r--r--. 1 jovyan users   1464 Oct 11 14:45 image05186.tiff
-rw-r--r--. 1 jovyan users 489989 Oct 11 14:38 manifest.dat
-rw-r--r--. 1 jovyan users    560 Feb  5  2021 parameters.txt

The structure is a simplified version of the UDKM PXS X-ray data format, essentially made up of:

  • a text file called manifest.dat, which is a CSV format of sorts with a header line, and lots of numbers (about 5200 lines -- one line for each data frame), among others scanning angles for $\omega--2\theta$ scans
  • about 5200 individual detector images, each in its own TIFF file -- one image for each line of the manifest file.

The contents of the manifest file are a header line that starts with % and contains comlumn names, and many lines (i.e. "frames") with the numbers for each colum. (Note that we've truncated the lines at ~50 characters in the output below -- this is just to convey an idea of the file structure):

In [5]:
Copied!
%%bash

head -n 5 /home/jovyan/tmp/repo2/20210205/091726/manifest.dat | cut -c -50
%%bash head -n 5 /home/jovyan/tmp/repo2/20210205/091726/manifest.dat | cut -c -50
% Loop_Delay	Delay	Loop_Theta	Theta	Crystal [V]	Crystal [ph/s]	Pilatus
1.000000	-10.000000	1.000000	18.100000	0.500112	1907585.545459	4145.00
1.000000	-10.000000	1.000000	18.150000	0.444915	1684834.053402	2468.00
1.000000	-10.000000	1.000000	18.200000	0.474854	1805655.578219	1534.66
1.000000	-10.000000	1.000000	18.250000	0.481576	1832780.687594	817.000

Later when loading, we will, of course, consider the full file and line length.

The Code: Loading And Delegating¶

As we've seen in the first exammple, Nx5d is fairly agnostic about how you treat your data internally. But most of the tools the Nx5d authors also maintain (e.g. Kmc3recipes) prefer to work with xarray.Dataset flat structures. So that's what we'll do: load all the data in manifest.dat, and the images one by one, in one giant xarray Dataset. For that we'll use Pandas, respectively TiffFile for the heavy lifting. Note that we're skipping all kinds of plausibility tests and error handling here for the sake of clarity (you obviously shouldn't afford that luxury in a production environment):

In [1]:
Copied!
def fs_load_data(scan_path, reduce=1):
    '''
    Loads simplified UDKM data from `scan_path` and returns an xarray.Dataset.
    '''
    import pandas, xarray, numpy, tifffile, re
    tab = pandas.read_csv(f'{scan_path}/manifest.dat', sep='\t')
    result = xarray.Dataset({
        re.sub('[][%/ ]', '', k): ('index', tab[k]) for k in tab
    })
    result['images'] = (
        ('index', 'w', 'h'),
        numpy.stack([
            tifffile.imread(f'{scan_path}/image{i:05d}.tiff')[::reduce,::reduce] \
            for i in range(len(tab))
        ])
    )
    return result
def fs_load_data(scan_path, reduce=1): ''' Loads simplified UDKM data from `scan_path` and returns an xarray.Dataset. ''' import pandas, xarray, numpy, tifffile, re tab = pandas.read_csv(f'{scan_path}/manifest.dat', sep='\t') result = xarray.Dataset({ re.sub('[][%/ ]', '', k): ('index', tab[k]) for k in tab }) result['images'] = ( ('index', 'w', 'h'), numpy.stack([ tifffile.imread(f'{scan_path}/image{i:05d}.tiff')[::reduce,::reduce] \ for i in range(len(tab)) ]) ) return result

Let's risk a peek on how Jupyter sees the data loaded into memory (to save RAM, we'll use a parameter reduce which loads only every i-th pixel):

In [3]:
Copied!
example = fs_load_data('/home/jovyan/tmp/repo2/20210205/091726', reduce=10)
example
example = fs_load_data('/home/jovyan/tmp/repo2/20210205/091726', reduce=10) example
Out[3]:
<xarray.Dataset> Size: 21MB
Dimensions:         (index: 5187, w: 20, h: 49)
Dimensions without coordinates: index, w, h
Data variables:
    Loop_Delay      (index) float64 41kB 1.0 1.0 1.0 1.0 1.0 ... 3.0 3.0 3.0 3.0
    Delay           (index) float64 41kB -10.0 -10.0 -10.0 ... -6.0 -6.0 -6.0
    Loop_Theta      (index) float64 41kB 1.0 1.0 1.0 1.0 1.0 ... 1.0 1.0 1.0 1.0
    Theta           (index) float64 41kB 18.1 18.15 18.2 ... 19.0 19.05 19.1
    CrystalV        (index) float64 41kB 0.5001 0.4449 0.4749 ... 0.3406 0.2961
    Crystalphs      (index) float64 41kB 1.908e+06 1.685e+06 ... 1.084e+06
    Pilatusphs      (index) float64 41kB 4.145e+03 2.468e+03 ... 150.0 109.7
    Repeats         (index) float64 41kB 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
    ImageNumber     (index) float64 41kB 0.0 1.0 2.0 ... 5.185e+03 5.186e+03
    Intensitiesphs  (index) float64 41kB nan nan nan nan nan ... nan nan nan nan
    images          (index, w, h) int32 20MB -2 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0
xarray.Dataset
    • index: 5187
    • w: 20
    • h: 49
      • Loop_Delay
        (index)
        float64
        1.0 1.0 1.0 1.0 ... 3.0 3.0 3.0 3.0
        array([1., 1., 1., ..., 3., 3., 3.], shape=(5187,))
      • Delay
        (index)
        float64
        -10.0 -10.0 -10.0 ... -6.0 -6.0
        array([-10., -10., -10., ...,  -6.,  -6.,  -6.], shape=(5187,))
      • Loop_Theta
        (index)
        float64
        1.0 1.0 1.0 1.0 ... 1.0 1.0 1.0 1.0
        array([1., 1., 1., ..., 1., 1., 1.], shape=(5187,))
      • Theta
        (index)
        float64
        18.1 18.15 18.2 ... 19.0 19.05 19.1
        array([18.1 , 18.15, 18.2 , ..., 19.  , 19.05, 19.1 ], shape=(5187,))
      • CrystalV
        (index)
        float64
        0.5001 0.4449 ... 0.3406 0.2961
        array([0.500112, 0.444915, 0.474854, ..., 0.302756, 0.340584, 0.296051],
              shape=(5187,))
      • Crystalphs
        (index)
        float64
        1.908e+06 1.685e+06 ... 1.084e+06
        array([1907585.545459, 1684834.053402, 1805655.578219, ...,
               1111145.318286, 1263804.249638, 1084088.812054], shape=(5187,))
      • Pilatusphs
        (index)
        float64
        4.145e+03 2.468e+03 ... 150.0 109.7
        array([4145.      , 2468.      , 1534.666667, ...,  160.333333,
                150.      ,  109.666667], shape=(5187,))
      • Repeats
        (index)
        float64
        0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
        array([0., 0., 0., ..., 0., 0., 0.], shape=(5187,))
      • ImageNumber
        (index)
        float64
        0.0 1.0 2.0 ... 5.185e+03 5.186e+03
        array([0.000e+00, 1.000e+00, 2.000e+00, ..., 5.184e+03, 5.185e+03,
               5.186e+03], shape=(5187,))
      • Intensitiesphs
        (index)
        float64
        nan nan nan nan ... nan nan nan nan
        array([nan, nan, nan, ..., nan, nan, nan], shape=(5187,))
      • images
        (index, w, h)
        int32
        -2 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 0
        array([[[-2,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0],
                ...,
                [ 0,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0]],
        
               [[-2,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0],
                ...,
                [ 0,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0]],
        
               [[-2,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0],
                ...,
        ...
                ...,
                [ 0,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0]],
        
               [[-2,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0],
                ...,
                [ 0,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0]],
        
               [[-2,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0],
                ...,
                [ 0,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0],
                [ 0,  0,  0, ...,  0,  0,  0]]], shape=(5187, 20, 49), dtype=int32)

      Armed with this helper function we're ready to build our loading classes arsenal: the Repository, the Proposal and the Scan class.

      To find scans which are represented as sub-foders in a hieararchical filesystem structure, Nx5d already includes the FsDataRepository class, respectively FsDataProposal. Being able to fall back on that kind of functionality makes implementation fairly easy. But in contrast to our simplest exmple we still need to supply the necessary hey-to-handle translation functions. This is because, unlinke in our simplest example, the proposal and scan names here (20210205, respectively 091726) are no valid Python variable names anymore, unless they receive an alphabetic letter as their first character (p, respectively r):

      In [2]:
      Copied!
      from nx5d.repo.filesystem import DataRepository, DataProposal
      from nx5d.repo.base import DataScanBase
      
      
      class UdkmRepository(DataRepository):
          def __init__(self, url, **kw):
              super().__init__(url, proposal_k2h=lambda x: f'p{x}', **kw)
              
          def _proposal(self, key):
              return UdkmProposal(self, key, self.repo_url)
              
      
      class UdkmProposal(DataProposal):
          def __init__(self, repo, key, scanurl):
              super().__init__(repo,
                               key,
                               url=scanurl,
                               scan_k2h=lambda x: f'r{x}')
             
          def _scan(self, key):
              return UdkmDataScan(self, key)
      
      from nx5d.repo.filesystem import DataRepository, DataProposal from nx5d.repo.base import DataScanBase class UdkmRepository(DataRepository): def __init__(self, url, **kw): super().__init__(url, proposal_k2h=lambda x: f'p{x}', **kw) def _proposal(self, key): return UdkmProposal(self, key, self.repo_url) class UdkmProposal(DataProposal): def __init__(self, repo, key, scanurl): super().__init__(repo, key, url=scanurl, scan_k2h=lambda x: f'r{x}') def _scan(self, key): return UdkmDataScan(self, key)

      For the final piece, we'll continue to use the scan base class. By far the most involved part here is the ._cook(...) function, which is as close as feastible to "real-life" data processing based on xrayutilities. Mind that

      In [32]:
      Copied!
      from nx5d.repo.base import DataScanBase
      import glob, urllib, xrayutilities, math, xarray, numpy    
      
      class UdkmDataScan(DataScanBase):
          def _get_raw(self):
              p = urllib.parse.urlparse(self.url)
              return fs_load_data(p.path, reduce=2)
              
          def _get_summary(self):
              p = urllib.parse.urlparse(self.url)
              return {
                  'type': 'default',
                  'description': 'UDKM simplified example',
                  'steps': len(glob.glob(f'{p.path}/*tiff'))
              }
      
          def _cook(self, data, **spice):
      
              # preparation "for later"
              cfg = _rsm_settings(**spice)
      
              img_size = (98, 244)
              
              reduce=2  ## To reduce memmory usage (example only)
          
              qconv = xrayutilities.experiment.QConversion(
                  sampleAxis=('y-',), detectorAxis=('y-',), r_i=(1,0,0), en=8048.0
              )
              hxrd = xrayutilities.HXRD(
                  qconv=qconv, idir=(1,0,0), ndir=(0,1,0)
              )
              
              hxrd.Ang2Q.init_area(
                  'y-', 'z+',  *cfg.img_center, *img_size,
                  pwidth1=0.172, pwidth2=0.172, distance=cfg.img_distance
              )
              
              def _per_delay_transform(delay_data):
                  delay = data.Delay.mean()
                  
                  qx, qy, qz = hxrd.Ang2Q.area(
                      delay_data.Theta.values, delay_data.Theta.values*2  ## Fake 2-theta
                  )
                  
                  gridder = xrayutilities.FuzzyGridder2D(*cfg.grid_size)
                  gridder(qy, qz, delay_data.images.values)
                  
                  return xarray.Dataset({
                      'qdata': (('qy', 'qz'), gridder.data),
                      'qy': gridder.xaxis,
                      'qz': gridder.yaxis,
                  })
          
              return data.groupby('Delay').map(_per_delay_transform)
      
      
      from collections import namedtuple
      RsmSettings = namedtuple('RsmSettings', [
              'img_center', 'grid_size', 'img_distance'
      ])
      
      
      def _rsm_settings(**spice):
          # Set some RSM defaults (hard-coded for now, later we'll extract
          # them from spice).
      
          print('loading hard-coded settings')
      
          return RsmSettings(
              (45, 150), # img_center
              (80, 150), # grid_size
              680.0      # img_distance
          )
      
      from nx5d.repo.base import DataScanBase import glob, urllib, xrayutilities, math, xarray, numpy class UdkmDataScan(DataScanBase): def _get_raw(self): p = urllib.parse.urlparse(self.url) return fs_load_data(p.path, reduce=2) def _get_summary(self): p = urllib.parse.urlparse(self.url) return { 'type': 'default', 'description': 'UDKM simplified example', 'steps': len(glob.glob(f'{p.path}/*tiff')) } def _cook(self, data, **spice): # preparation "for later" cfg = _rsm_settings(**spice) img_size = (98, 244) reduce=2 ## To reduce memmory usage (example only) qconv = xrayutilities.experiment.QConversion( sampleAxis=('y-',), detectorAxis=('y-',), r_i=(1,0,0), en=8048.0 ) hxrd = xrayutilities.HXRD( qconv=qconv, idir=(1,0,0), ndir=(0,1,0) ) hxrd.Ang2Q.init_area( 'y-', 'z+', *cfg.img_center, *img_size, pwidth1=0.172, pwidth2=0.172, distance=cfg.img_distance ) def _per_delay_transform(delay_data): delay = data.Delay.mean() qx, qy, qz = hxrd.Ang2Q.area( delay_data.Theta.values, delay_data.Theta.values*2 ## Fake 2-theta ) gridder = xrayutilities.FuzzyGridder2D(*cfg.grid_size) gridder(qy, qz, delay_data.images.values) return xarray.Dataset({ 'qdata': (('qy', 'qz'), gridder.data), 'qy': gridder.xaxis, 'qz': gridder.yaxis, }) return data.groupby('Delay').map(_per_delay_transform) from collections import namedtuple RsmSettings = namedtuple('RsmSettings', [ 'img_center', 'grid_size', 'img_distance' ]) def _rsm_settings(**spice): # Set some RSM defaults (hard-coded for now, later we'll extract # them from spice). print('loading hard-coded settings') return RsmSettings( (45, 150), # img_center (80, 150), # grid_size 680.0 # img_distance )

      Mind that many processing parameters in the UdkmDataScan._cook(...) above are hard-coded, although they most certainly shouldn't be in a "real" production environment: center pixel of the detector, detector distance, missing $2\theta$ angle etc). This is to keep this example simple. Nonetheless, this is a perfect and hands-on example of what the spice mechanism was intended for: to provide means of supplying useful settings to ._cook(...). We'll circle back to spice use at the end of this example.

      Listing Repository¶

      For now, preparatory steps finished, we can access the repository using our newly created UdkmRepository. At this level we'll have to specify url=... manually.

      Working with on-disk spice is not (yet) a goal of this example. Therefore we're activating a in-memory spice collecting for our Udkm... examples by setting the corresponding to an empty string: spice_url=''.

      In [33]:
      Copied!
      udkm = UdkmRepository(
          url='file:///home/jovyan/tmp/repo2/{proposal}/{scan}',
          spice_url=''
      )
      
      udkm = UdkmRepository( url='file:///home/jovyan/tmp/repo2/{proposal}/{scan}', spice_url='' )

      Now we can list the repository's proposals (spoiler: there's only one ;-) and we can access the proposal by its handle, .p20210205, directly:

      In [34]:
      Copied!
      udkm.all()
      
      udkm.all()
      Out[34]:
      {'20210205': 'p20210205'}
      In [35]:
      Copied!
      udkm.p20210205
      
      udkm.p20210205
      Out[35]:
      scan type integration steps notes
      default 091726 5187 UDKM simplified example

      So obviously our code is able to list and find the scan.

      Accessing Data¶

      It's time to have the data loaded and displayed:

      In [36]:
      Copied!
      raw = udkm.p20210205.r091726.raw
      raw
      
      raw = udkm.p20210205.r091726.raw raw
      Out[36]:
      <xarray.Dataset> Size: 497MB
      Dimensions:         (index: 5187, w: 98, h: 244)
      Dimensions without coordinates: index, w, h
      Data variables:
          Loop_Delay      (index) float64 41kB 1.0 1.0 1.0 1.0 1.0 ... 3.0 3.0 3.0 3.0
          Delay           (index) float64 41kB -10.0 -10.0 -10.0 ... -6.0 -6.0 -6.0
          Loop_Theta      (index) float64 41kB 1.0 1.0 1.0 1.0 1.0 ... 1.0 1.0 1.0 1.0
          Theta           (index) float64 41kB 18.1 18.15 18.2 ... 19.0 19.05 19.1
          CrystalV        (index) float64 41kB 0.5001 0.4449 0.4749 ... 0.3406 0.2961
          Crystalphs      (index) float64 41kB 1.908e+06 1.685e+06 ... 1.084e+06
          Pilatusphs      (index) float64 41kB 4.145e+03 2.468e+03 ... 150.0 109.7
          Repeats         (index) float64 41kB 0.0 0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
          ImageNumber     (index) float64 41kB 0.0 1.0 2.0 ... 5.185e+03 5.186e+03
          Intensitiesphs  (index) float64 41kB nan nan nan nan nan ... nan nan nan nan
          images          (index, w, h) int32 496MB -2 0 0 0 0 0 0 ... 0 0 0 0 0 0 -2
      xarray.Dataset
        • index: 5187
        • w: 98
        • h: 244
          • Loop_Delay
            (index)
            float64
            1.0 1.0 1.0 1.0 ... 3.0 3.0 3.0 3.0
            array([1., 1., 1., ..., 3., 3., 3.], shape=(5187,))
          • Delay
            (index)
            float64
            -10.0 -10.0 -10.0 ... -6.0 -6.0
            array([-10., -10., -10., ...,  -6.,  -6.,  -6.], shape=(5187,))
          • Loop_Theta
            (index)
            float64
            1.0 1.0 1.0 1.0 ... 1.0 1.0 1.0 1.0
            array([1., 1., 1., ..., 1., 1., 1.], shape=(5187,))
          • Theta
            (index)
            float64
            18.1 18.15 18.2 ... 19.0 19.05 19.1
            array([18.1 , 18.15, 18.2 , ..., 19.  , 19.05, 19.1 ], shape=(5187,))
          • CrystalV
            (index)
            float64
            0.5001 0.4449 ... 0.3406 0.2961
            array([0.500112, 0.444915, 0.474854, ..., 0.302756, 0.340584, 0.296051],
                  shape=(5187,))
          • Crystalphs
            (index)
            float64
            1.908e+06 1.685e+06 ... 1.084e+06
            array([1907585.545459, 1684834.053402, 1805655.578219, ...,
                   1111145.318286, 1263804.249638, 1084088.812054], shape=(5187,))
          • Pilatusphs
            (index)
            float64
            4.145e+03 2.468e+03 ... 150.0 109.7
            array([4145.      , 2468.      , 1534.666667, ...,  160.333333,
                    150.      ,  109.666667], shape=(5187,))
          • Repeats
            (index)
            float64
            0.0 0.0 0.0 0.0 ... 0.0 0.0 0.0 0.0
            array([0., 0., 0., ..., 0., 0., 0.], shape=(5187,))
          • ImageNumber
            (index)
            float64
            0.0 1.0 2.0 ... 5.185e+03 5.186e+03
            array([0.000e+00, 1.000e+00, 2.000e+00, ..., 5.184e+03, 5.185e+03,
                   5.186e+03], shape=(5187,))
          • Intensitiesphs
            (index)
            float64
            nan nan nan nan ... nan nan nan nan
            array([nan, nan, nan, ..., nan, nan, nan], shape=(5187,))
          • images
            (index, w, h)
            int32
            -2 0 0 0 0 0 0 0 ... 0 0 0 0 0 0 -2
            array([[[-2,  0,  0, ...,  0,  0, -2],
                    [ 0,  0,  0, ...,  0,  0,  0],
                    [ 0,  0,  0, ...,  0,  0,  0],
                    ...,
                    [ 0,  0,  0, ...,  0,  0,  0],
                    [ 0,  0,  0, ...,  0,  0,  0],
                    [-2,  0,  0, ...,  0,  0, -2]],
            
                   [[-2,  0,  0, ...,  0,  0, -2],
                    [ 0,  0,  0, ...,  0,  0,  0],
                    [ 0,  0,  0, ...,  0,  0,  0],
                    ...,
                    [ 0,  0,  0, ...,  0,  0,  0],
                    [ 0,  0,  0, ...,  0,  0,  0],
                    [-2,  0,  0, ...,  0,  0, -2]],
            
                   [[-2,  0,  0, ...,  0,  0, -2],
                    [ 0,  0,  0, ...,  0,  0,  0],
                    [ 0,  0,  0, ...,  0,  0,  0],
                    ...,
            ...
                    [ 0,  0,  0, ...,  0,  0,  0],
                    [ 0,  0,  0, ...,  0,  0,  0],
                    [-2,  0,  0, ...,  0,  0, -2]],
            
                   [[-2,  0,  0, ...,  0,  0, -2],
                    [ 0,  0,  0, ...,  0,  0,  0],
                    [ 0,  0,  0, ...,  0,  0,  0],
                    ...,
                    [ 0,  0,  0, ...,  0,  0,  0],
                    [ 0,  0,  0, ...,  0,  0,  0],
                    [-2,  0,  0, ...,  0,  0, -2]],
            
                   [[-2,  0,  0, ...,  0,  0, -2],
                    [ 0,  0,  0, ...,  0,  0,  0],
                    [ 0,  0,  0, ...,  0,  0,  0],
                    ...,
                    [ 0,  0,  0, ...,  0,  0,  0],
                    [ 0,  0,  0, ...,  0,  0,  0],
                    [-2,  0,  0, ...,  0,  0, -2]]],
                  shape=(5187, 98, 244), dtype=int32)

          The "natural coordinate system" of these data is a reciprocal space map, i.e. intensity in the Q-space -- one map for each delay point. With our preparatory work, triggering such a transformation step now is as easy as accessing the .cooked property of the scan:

          In [37]:
          Copied!
          rsm = udkm.p20210205.r091726.cooked
          rsm
          
          rsm = udkm.p20210205.r091726.cooked rsm
          loading hard-coded settings
          
          Out[37]:
          <xarray.Dataset> Size: 12MB
          Dimensions:  (Delay: 122, qy: 80, qz: 150)
          Coordinates:
            * qy       (qy) float64 640B -0.05364 -0.05237 -0.05111 ... 0.04515 0.04642
            * qz       (qz) float64 1kB 2.386 2.389 2.391 2.394 ... 2.754 2.757 2.759
            * Delay    (Delay) float64 976B -10.0 -8.0 -6.0 -4.0 ... 318.0 319.0 320.0
          Data variables:
              qdata    (Delay, qy, qz) float64 12MB -1.17 0.0 -0.05348 ... 0.0 -1.209
          xarray.Dataset
            • Delay: 122
            • qy: 80
            • qz: 150
            • qy
              (qy)
              float64
              -0.05364 -0.05237 ... 0.04642
              array([-0.053639, -0.052372, -0.051105, -0.049839, -0.048572, -0.047306,
                     -0.046039, -0.044773, -0.043506, -0.04224 , -0.040973, -0.039707,
                     -0.03844 , -0.037173, -0.035907, -0.03464 , -0.033374, -0.032107,
                     -0.030841, -0.029574, -0.028308, -0.027041, -0.025774, -0.024508,
                     -0.023241, -0.021975, -0.020708, -0.019442, -0.018175, -0.016909,
                     -0.015642, -0.014375, -0.013109, -0.011842, -0.010576, -0.009309,
                     -0.008043, -0.006776, -0.00551 , -0.004243, -0.002977, -0.00171 ,
                     -0.000443,  0.000823,  0.00209 ,  0.003356,  0.004623,  0.005889,
                      0.007156,  0.008422,  0.009689,  0.010956,  0.012222,  0.013489,
                      0.014755,  0.016022,  0.017288,  0.018555,  0.019821,  0.021088,
                      0.022355,  0.023621,  0.024888,  0.026154,  0.027421,  0.028687,
                      0.029954,  0.03122 ,  0.032487,  0.033753,  0.03502 ,  0.036287,
                      0.037553,  0.03882 ,  0.040086,  0.041353,  0.042619,  0.043886,
                      0.045152,  0.046419])
            • qz
              (qz)
              float64
              2.386 2.389 2.391 ... 2.757 2.759
              array([2.386153, 2.388658, 2.391162, 2.393667, 2.396171, 2.398676, 2.40118 ,
                     2.403685, 2.406189, 2.408694, 2.411198, 2.413703, 2.416207, 2.418712,
                     2.421217, 2.423721, 2.426226, 2.42873 , 2.431235, 2.433739, 2.436244,
                     2.438748, 2.441253, 2.443757, 2.446262, 2.448766, 2.451271, 2.453775,
                     2.45628 , 2.458784, 2.461289, 2.463793, 2.466298, 2.468802, 2.471307,
                     2.473812, 2.476316, 2.478821, 2.481325, 2.48383 , 2.486334, 2.488839,
                     2.491343, 2.493848, 2.496352, 2.498857, 2.501361, 2.503866, 2.50637 ,
                     2.508875, 2.511379, 2.513884, 2.516388, 2.518893, 2.521397, 2.523902,
                     2.526407, 2.528911, 2.531416, 2.53392 , 2.536425, 2.538929, 2.541434,
                     2.543938, 2.546443, 2.548947, 2.551452, 2.553956, 2.556461, 2.558965,
                     2.56147 , 2.563974, 2.566479, 2.568983, 2.571488, 2.573992, 2.576497,
                     2.579002, 2.581506, 2.584011, 2.586515, 2.58902 , 2.591524, 2.594029,
                     2.596533, 2.599038, 2.601542, 2.604047, 2.606551, 2.609056, 2.61156 ,
                     2.614065, 2.616569, 2.619074, 2.621578, 2.624083, 2.626587, 2.629092,
                     2.631596, 2.634101, 2.636606, 2.63911 , 2.641615, 2.644119, 2.646624,
                     2.649128, 2.651633, 2.654137, 2.656642, 2.659146, 2.661651, 2.664155,
                     2.66666 , 2.669164, 2.671669, 2.674173, 2.676678, 2.679182, 2.681687,
                     2.684191, 2.686696, 2.689201, 2.691705, 2.69421 , 2.696714, 2.699219,
                     2.701723, 2.704228, 2.706732, 2.709237, 2.711741, 2.714246, 2.71675 ,
                     2.719255, 2.721759, 2.724264, 2.726768, 2.729273, 2.731777, 2.734282,
                     2.736786, 2.739291, 2.741796, 2.7443  , 2.746805, 2.749309, 2.751814,
                     2.754318, 2.756823, 2.759327])
            • Delay
              (Delay)
              float64
              -10.0 -8.0 -6.0 ... 319.0 320.0
              array([-10.,  -8.,  -6.,  -4.,  -2.,   0.,  50.,  70.,  71.,  72.,  73.,  74.,
                      75.,  76.,  77.,  78.,  79.,  80.,  81.,  82.,  83.,  84.,  85.,  86.,
                      87.,  88.,  89.,  90.,  91.,  92.,  93.,  94.,  95.,  96.,  97.,  98.,
                      99., 100., 101., 102., 103., 104., 105., 106., 107., 108., 109., 110.,
                     111., 112., 113., 114., 115., 116., 117., 118., 119., 120., 121., 122.,
                     123., 124., 125., 126., 127., 128., 129., 130., 150., 200., 250., 270.,
                     271., 272., 273., 274., 275., 276., 277., 278., 279., 280., 281., 282.,
                     283., 284., 285., 286., 287., 288., 289., 290., 291., 292., 293., 294.,
                     295., 296., 297., 298., 299., 300., 301., 302., 303., 304., 305., 306.,
                     307., 308., 309., 310., 311., 312., 313., 314., 315., 316., 317., 318.,
                     319., 320.])
            • qdata
              (Delay, qy, qz)
              float64
              -1.17 0.0 -0.05348 ... 0.0 -1.209
              array([[[-1.17023117,  0.        , -0.05347853, ..., -0.04170796,
                        0.        , -1.226831  ],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      ...,
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [-1.18366575,  0.        , -0.03813154, ..., -0.0601713 ,
                        0.        , -1.20853642]],
              
                     [[-1.17023117,  0.        , -0.05347853, ..., -0.04170796,
                        0.        , -1.226831  ],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
              ...
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [-1.18366575,  0.        , -0.03813154, ..., -0.0601713 ,
                        0.        , -1.20853642]],
              
                     [[-1.17023117,  0.        , -0.05347853, ..., -0.04170796,
                        0.        , -1.226831  ],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      ...,
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [-1.18366575,  0.        , -0.03813154, ..., -0.0601713 ,
                        0.        , -1.20853642]]], shape=(122, 80, 150))
            • qy
              PandasIndex
              PandasIndex(Index([    -0.0536385792438071,     -0.0523720274891984,
                         -0.0511054757345897,      -0.049838923979981,
                         -0.0485723722253723,    -0.04730582047076359,
                       -0.046039268716154894,   -0.044772716961546194,
                       -0.043506165206937494,   -0.042239613452328795,
                       -0.040973061697720095,   -0.039706509943111395,
                       -0.038439958188502696,   -0.037173406433893996,
                         -0.0359068546792853,     -0.0346403029246766,
                         -0.0333737511700679,     -0.0321071994154592,
                       -0.030840647660850495,    -0.02957409590624179,
                       -0.028307544151633092,   -0.027040992397024392,
                       -0.025774440642415693,   -0.024507888887806993,
                       -0.023241337133198293,   -0.021974785378589594,
                       -0.020708233623980894,   -0.019441681869372188,
                       -0.018175130114763488,    -0.01690857836015479,
                        -0.01564202660554609,    -0.01437547485093739,
                        -0.01310892309632869,    -0.01184237134171999,
                        -0.01057581958711129,    -0.00930926783250259,
                       -0.008042716077893891,  -0.0067761643232851915,
                       -0.005509612568676485,   -0.004243060814067785,
                      -0.0029765090594590857,   -0.001709957304850386,
                     -0.00044340555024168643,   0.0008231462043670132,
                        0.002089697958975713,   0.0033562497135844124,
                        0.004622801468193112,    0.005889353222801812,
                        0.007155904977410511,    0.008422456732019218,
                         0.00968900848662791,     0.01095556024123661,
                         0.01222211199584531,     0.01348866375045401,
                        0.014755215505062723,    0.016021767259671423,
                        0.017288319014280122,    0.018554870768888822,
                         0.01982142252349752,     0.02108797427810622,
                         0.02235452603271492,     0.02362107778732362,
                         0.02488762954193232,     0.02615418129654102,
                         0.02742073305114972,     0.02868728480575842,
                         0.02995383656036712,    0.031220388314975818,
                         0.03248694006958452,     0.03375349182419322,
                         0.03502004357880192,    0.036286595333410616,
                        0.037553147088019316,    0.038819698842628016,
                        0.040086250597236715,     0.04135280235184543,
                         0.04261935410645413,     0.04388590586106283,
                         0.04515245761567153,     0.04641900937028023],
                    dtype='float64', name='qy'))
            • qz
              PandasIndex
              PandasIndex(Index([2.3861531759781074, 2.3886576996919544,  2.391162223405801,
                      2.393666747119648, 2.3961712708334946, 2.3986757945473416,
                      2.401180318261188,  2.403684841975035, 2.4061893656888818,
                     2.4086938894027288,
                     ...
                     2.7367864959166592, 2.7392910196305063,  2.741795543344353,
                        2.7443000670582, 2.7468045907720464, 2.7493091144858934,
                       2.75181363819974,  2.754318161913587, 2.7568226856274336,
                     2.7593272093412806],
                    dtype='float64', name='qz', length=150))
            • Delay
              PandasIndex
              PandasIndex(Index([-10.0,  -8.0,  -6.0,  -4.0,  -2.0,   0.0,  50.0,  70.0,  71.0,  72.0,
                     ...
                     311.0, 312.0, 313.0, 314.0, 315.0, 316.0, 317.0, 318.0, 319.0, 320.0],
                    dtype='float64', name='Delay', length=122))

          The Nx5d framework has just taken away a lot of "boilerplate code" for loading and transforming off our backs. We can now continue processing, plotting, or any other measure of presentation:

          In [56]:
          Copied!
          from matplotlib.colors import LogNorm
          rsm.qdata.mean('qy').plot(norm=LogNorm(1e-2, 1e-1))
          
          from matplotlib.colors import LogNorm rsm.qdata.mean('qy').plot(norm=LogNorm(1e-2, 1e-1))
          Out[56]:
          <matplotlib.collections.QuadMesh at 0x7fdaa9183890>
          No description has been provided for this image

          Spicing Things Up¶

          This is example was the closest to a real-world application, and here we'll take a moment to observe its developing complexity. Reviewing the ._cook(...) method there are some observations to me made:

          • it's rapidly growing in complexity
          • we've already had to make some decisions for simplificatio (i.e. choosing a data reduction factor, choosing 2 of the 3 Q-space axes that we're interested in retaining, hard-coding the detector distance, choosing a suitable Q grid size...)

          We find ourselves in the lucky situation that there's only one scan to process. But actually, UdkmScan was supposed to be more universtal than that -- it was supposed to be able to process dozens of slightly different scans of the same experiment! This means that we need a way for the parameters we've hardcoded to be supplied on a per-scan basis. And spice is our mechanism.

          Spice can be managed on the udkm.p20210205 proposal level, directly in-memory. We'll introduce a settings spice dictionary for that, with some of the parameters we've previously hardcoded:

          In [39]:
          Copied!
          udkm.p20210205.spice.seed(
              'settings',
              img_center=(50, 120),
              img_distance=690.0,
              grid_size=(70, 140)
          )
          
          udkm.p20210205.spice.seed( 'settings', img_center=(50, 120), img_distance=690.0, grid_size=(70, 140) )
          Out[39]:
          {'version': 'kmc3/1a',
           'type': 'settings',
           'handle': 'settings',
           'uuid': 'f33647c0-f399-4bb9-8d73-875d6479f940',
           'revision': 1,
           'anchor': '',
           'data': {'img_center': (50, 120),
            'img_distance': 690.0,
            'grid_size': (80, 150)}}

          We can now verify that the spice view of our scan 091726 contains the new settings:

          In [40]:
          Copied!
          udkm.p20210205.spice.view('r091726')
          
          udkm.p20210205.spice.view('r091726')
          Out[40]:
          handle clean revision uuid anchor data
          viewpoint
          r091726 settings True 1 f33647 {'img_center': (50, 120), 'img_distance': 690....

          And all we'd have to do now is rewrite UdkmScan._cook(...) to make use of the new settings spice type:

          In [41]:
          Copied!
          def _rsm_settings(**spice):
              if 'settings' not in spice:
                  raise RuntimeError('no settings in spice')
          
              print('settings from spice')
          
              return RsmSettings(
                  spice['settings'].img_center,
                  spice['settings'].grid_size,
                  spice['settings'].img_distance
              )
          
          def _rsm_settings(**spice): if 'settings' not in spice: raise RuntimeError('no settings in spice') print('settings from spice') return RsmSettings( spice['settings'].img_center, spice['settings'].grid_size, spice['settings'].img_distance )

          ...and now, cooking outght to take place using our modifyable spice data (note the updated size of the Q-space grid):

          In [43]:
          Copied!
          rsm = udkm.p20210205.r091726.cooked
          rsm
          
          rsm = udkm.p20210205.r091726.cooked rsm
          settings from spice
          
          Out[43]:
          <xarray.Dataset> Size: 12MB
          Dimensions:  (Delay: 122, qy: 80, qz: 150)
          Coordinates:
            * qy       (qy) float64 640B -0.04778 -0.04653 -0.04528 ... 0.04958 0.05083
            * qz       (qz) float64 1kB 2.418 2.42 2.423 2.425 ... 2.779 2.782 2.784 2.787
            * Delay    (Delay) float64 976B -10.0 -8.0 -6.0 -4.0 ... 318.0 319.0 320.0
          Data variables:
              qdata    (Delay, qy, qz) float64 12MB -1.173 0.0 -0.002105 ... 0.0 -1.218
          xarray.Dataset
            • Delay: 122
            • qy: 80
            • qz: 150
            • qy
              (qy)
              float64
              -0.04778 -0.04653 ... 0.05083
              array([-0.047779, -0.046531, -0.045283, -0.044035, -0.042786, -0.041538,
                     -0.04029 , -0.039042, -0.037794, -0.036545, -0.035297, -0.034049,
                     -0.032801, -0.031553, -0.030304, -0.029056, -0.027808, -0.02656 ,
                     -0.025312, -0.024063, -0.022815, -0.021567, -0.020319, -0.019071,
                     -0.017822, -0.016574, -0.015326, -0.014078, -0.01283 , -0.011581,
                     -0.010333, -0.009085, -0.007837, -0.006589, -0.00534 , -0.004092,
                     -0.002844, -0.001596, -0.000348,  0.000901,  0.002149,  0.003397,
                      0.004645,  0.005893,  0.007142,  0.00839 ,  0.009638,  0.010886,
                      0.012134,  0.013383,  0.014631,  0.015879,  0.017127,  0.018375,
                      0.019624,  0.020872,  0.02212 ,  0.023368,  0.024616,  0.025865,
                      0.027113,  0.028361,  0.029609,  0.030857,  0.032106,  0.033354,
                      0.034602,  0.03585 ,  0.037098,  0.038347,  0.039595,  0.040843,
                      0.042091,  0.043339,  0.044588,  0.045836,  0.047084,  0.048332,
                      0.04958 ,  0.050829])
            • qz
              (qz)
              float64
              2.418 2.42 2.423 ... 2.784 2.787
              array([2.417573, 2.420049, 2.422526, 2.425002, 2.427478, 2.429955, 2.432431,
                     2.434907, 2.437384, 2.43986 , 2.442336, 2.444813, 2.447289, 2.449765,
                     2.452242, 2.454718, 2.457194, 2.459671, 2.462147, 2.464623, 2.4671  ,
                     2.469576, 2.472052, 2.474529, 2.477005, 2.479481, 2.481958, 2.484434,
                     2.48691 , 2.489386, 2.491863, 2.494339, 2.496815, 2.499292, 2.501768,
                     2.504244, 2.506721, 2.509197, 2.511673, 2.51415 , 2.516626, 2.519102,
                     2.521579, 2.524055, 2.526531, 2.529008, 2.531484, 2.53396 , 2.536437,
                     2.538913, 2.541389, 2.543866, 2.546342, 2.548818, 2.551295, 2.553771,
                     2.556247, 2.558724, 2.5612  , 2.563676, 2.566153, 2.568629, 2.571105,
                     2.573582, 2.576058, 2.578534, 2.581011, 2.583487, 2.585963, 2.58844 ,
                     2.590916, 2.593392, 2.595869, 2.598345, 2.600821, 2.603297, 2.605774,
                     2.60825 , 2.610726, 2.613203, 2.615679, 2.618155, 2.620632, 2.623108,
                     2.625584, 2.628061, 2.630537, 2.633013, 2.63549 , 2.637966, 2.640442,
                     2.642919, 2.645395, 2.647871, 2.650348, 2.652824, 2.6553  , 2.657777,
                     2.660253, 2.662729, 2.665206, 2.667682, 2.670158, 2.672635, 2.675111,
                     2.677587, 2.680064, 2.68254 , 2.685016, 2.687493, 2.689969, 2.692445,
                     2.694922, 2.697398, 2.699874, 2.702351, 2.704827, 2.707303, 2.709779,
                     2.712256, 2.714732, 2.717208, 2.719685, 2.722161, 2.724637, 2.727114,
                     2.72959 , 2.732066, 2.734543, 2.737019, 2.739495, 2.741972, 2.744448,
                     2.746924, 2.749401, 2.751877, 2.754353, 2.75683 , 2.759306, 2.761782,
                     2.764259, 2.766735, 2.769211, 2.771688, 2.774164, 2.77664 , 2.779117,
                     2.781593, 2.784069, 2.786546])
            • Delay
              (Delay)
              float64
              -10.0 -8.0 -6.0 ... 319.0 320.0
              array([-10.,  -8.,  -6.,  -4.,  -2.,   0.,  50.,  70.,  71.,  72.,  73.,  74.,
                      75.,  76.,  77.,  78.,  79.,  80.,  81.,  82.,  83.,  84.,  85.,  86.,
                      87.,  88.,  89.,  90.,  91.,  92.,  93.,  94.,  95.,  96.,  97.,  98.,
                      99., 100., 101., 102., 103., 104., 105., 106., 107., 108., 109., 110.,
                     111., 112., 113., 114., 115., 116., 117., 118., 119., 120., 121., 122.,
                     123., 124., 125., 126., 127., 128., 129., 130., 150., 200., 250., 270.,
                     271., 272., 273., 274., 275., 276., 277., 278., 279., 280., 281., 282.,
                     283., 284., 285., 286., 287., 288., 289., 290., 291., 292., 293., 294.,
                     295., 296., 297., 298., 299., 300., 301., 302., 303., 304., 305., 306.,
                     307., 308., 309., 310., 311., 312., 313., 314., 315., 316., 317., 318.,
                     319., 320.])
            • qdata
              (Delay, qy, qz)
              float64
              -1.173 0.0 -0.002105 ... 0.0 -1.218
              array([[[-1.17326302,  0.        , -0.00210457, ..., -0.01304115,
                        0.        , -1.20989671],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      ...,
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [-1.16751018,  0.        , -0.00900377, ..., -0.00474286,
                        0.        , -1.21769304]],
              
                     [[-1.17326302,  0.        , -0.00210457, ..., -0.01304115,
                        0.        , -1.20989671],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
              ...
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [-1.16751018,  0.        , -0.00900377, ..., -0.00474286,
                        0.        , -1.21769304]],
              
                     [[-1.17326302,  0.        , -0.00210457, ..., -0.01304115,
                        0.        , -1.20989671],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      ...,
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [ 0.        ,  0.        ,  0.        , ...,  0.        ,
                        0.        ,  0.        ],
                      [-1.16751018,  0.        , -0.00900377, ..., -0.00474286,
                        0.        , -1.21769304]]], shape=(122, 80, 150))
            • qy
              PandasIndex
              PandasIndex(Index([ -0.047779253610747474,   -0.04653105377109554,    -0.0452828539314436,
                       -0.04403465409179166,   -0.04278645425213972,  -0.041538254412487784,
                       -0.04029005457283585,   -0.03904185473318391,   -0.03779365489353197,
                       -0.03654545505388003,   -0.03529725521422809,  -0.034049055374576156,
                       -0.03280085553492422,   -0.03155265569527228,  -0.030304455855620343,
                      -0.029056256015968403,  -0.027808056176316466,   -0.02655985633666453,
                       -0.02531165649701259,  -0.024063456657360652,  -0.022815256817708712,
                      -0.021567056978056776,   -0.02031885713840484,    -0.0190706572987529,
                      -0.017822457459100962,  -0.016574257619449025,  -0.015326057779797085,
                      -0.014077857940145148,  -0.012829658100493212,  -0.011581458260841275,
                      -0.010333258421189331,  -0.009085058581537395,  -0.007836858741885458,
                      -0.006588658902233521, -0.0053404590625815845,  -0.004092259222929641,
                      -0.002844059383277704, -0.0015958595436257675, -0.0003476597039738308,
                      0.0009005401356781059,  0.0021487399753300496,  0.0033969398149819863,
                       0.004645139654633923,    0.00589333949428586,   0.007141539333937796,
                       0.008389739173589733,   0.009637939013241677,   0.010886138852893613,
                        0.01213433869254555,   0.013382538532197487,   0.014630738371849424,
                       0.015878938211501367,   0.017127138051153304,    0.01837533789080524,
                       0.019623537730457177,   0.020871737570109114,    0.02211993740976105,
                       0.023368137249412987,   0.024616337089064924,   0.025864536928716875,
                        0.02711273676836881,   0.028360936608020748,   0.029609136447672685,
                        0.03085733628732462,    0.03210553612697656,   0.033353735966628495,
                        0.03460193580628043,    0.03585013564593237,   0.037098335485584305,
                        0.03834653532523624,    0.03959473516488819,    0.04084293500454013,
                       0.042091134844192066,      0.043339334683844,    0.04458753452349594,
                       0.045835734363147876,    0.04708393420279981,    0.04833213404245175,
                       0.049580333882103686,    0.05082853372175562],
                    dtype='float64', name='qy'))
            • qz
              PandasIndex
              PandasIndex(Index([   2.4175730379422,  2.420049363855598,  2.422525689768996,
                      2.425002015682394, 2.4274783415957923, 2.4299546675091905,
                     2.4324309934225883, 2.4349073193359865, 2.4373836452493847,
                     2.4398599711627824,
                     ...
                     2.7642586658179287,  2.766734991731327,  2.769211317644725,
                     2.7716876435581232,  2.774163969471521,  2.776640295384919,
                     2.7791166212983174,  2.781592947211715, 2.7840692731251133,
                     2.7865455990385115],
                    dtype='float64', name='qz', length=150))
            • Delay
              PandasIndex
              PandasIndex(Index([-10.0,  -8.0,  -6.0,  -4.0,  -2.0,   0.0,  50.0,  70.0,  71.0,  72.0,
                     ...
                     311.0, 312.0, 313.0, 314.0, 315.0, 316.0, 317.0, 318.0, 319.0, 320.0],
                    dtype='float64', name='Delay', length=122))

          From here on, the whole might of spice management is at our disposal to help us fine-tune processing for any scan of the UdkmDataScan family.

          H5-Like Array-Based Formats¶

          Previous Next

          Built with MkDocs using a theme provided by Read the Docs.