Source code for orgui.backend.scans

# /*##########################################################################
#
# Copyright (c) 2020-2025 Timo Fuchs
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
# ###########################################################################*/
__author__ = "Timo Fuchs"
__copyright__ = "Copyright 2020-2025 Timo Fuchs"
__license__ = "MIT License"
__version__ = "1.3.0"
__maintainer__ = "Timo Fuchs"
__email__ = "tfuchs@cornell.edu"


import numpy as np
from abc import ABC, abstractmethod

[docs] class Scan(ABC): """Base class for every backend. All methods in this class must be populated for a working backend. """ @abstractmethod def __init__(self,hdffilepath_orNode=None, scanno=None): """Constructor of the class. hdffilepath_orNode is an either an object selected from the file browser, where data scan be accessed, or a file path. Example on how to open .. code-block:: python if isinstance(hdffilepath_orNode, str): # check if this is a file path or already an opened h5node with silx.io.open(hdffilepath_orNode) as f: # file path, so we have to open the file manually self.th = f[scanno ,'th'] # read data from the file, see below for the required entries ... else: # file already open, so just read the data from the file hdffilepath = hdffilepath_orNode.local_filename # to get the filename f = hdffilepath_orNode.file self.th = f[scanno ,'th'] ... A backend must populate the following entries * axisname : 'th' or 'mu', defines the scan axis * axis : data value of the axis (should be a numpy array) * title : a meaningful title of the scan (e.g. "ascan th 0 90 90 1") * th : motor value (as array) * om : = -th (just populate the value) * mu : motor value with actual data """ self.axisname = None # either "th" or "mu", this defines the scan axis self.axis = None # value of either "th" or "mu" self.th = 0. # or self.mu, depending on scanaxis self.omega = -self.th # = -1*th self.title = "generic_scan" # for mu-scan you must provide a value for omega/theta # optional: provide a unique identifier, which is used as key in h5 database to identify # the dataset # self.name = "identifier" @property def auxillary_counters(self): """Optional: provide a list of counters or motor names, that should be copied into the orGUI data base for further processing. e.g. return ['exposure_time', 'elapsed_time','time', 'srcur', 'mondio', 'epoch'] after each integration, orGUI will search for these counter names in the Scan object and copy the entries into the database. """ return [] @classmethod @abstractmethod def parse_h5_node(cls, node): pass @abstractmethod def __len__(self): """returns the number of entries in the scan. """ raise NotImplementedError()
[docs] @abstractmethod def get_raw_img(self, i): """This should return a populated image class such as h5_Image (see below) Only the image data is required as numpy array, accessible as h5_image.img """ raise NotImplementedError()
class h5_Image: def __init__(self, data): """Only the image data is required as numpy array. motors and counters do not need to be populated. """ self.img = data self.motors = dict() self.counters = dict()
[docs] class SimulationScan(Scan): def __init__(self, detshape, axismin, axismax, points, axis='th', fixed=0.): self.shape = detshape self.axisname = axis self.axis = np.linspace(axismin,axismax,points) if axis == 'th': self.th = self.axis self.omega = -1*self.th self.mu = fixed elif axis == 'mu': self.mu = self.axis self.th = fixed self.omega = -1*self.th else: raise ValueError("%s is not an implemented scan axis." % axis) self.nopoints = points self.images = np.zeros((points,*detshape)) + 10 self.title = "sim ascan %s %s %s %s" % (self.axisname,axismin,axismax,points) def __len__(self): return self.nopoints
[docs] def get_raw_img(self, i): return h5_Image(self.images[i])
def set_raw_img(self, i, data): #for intensity simulation in the future. self.images[i] = data def parse_h5_node(cls, node): # unused pass