Skip to content

Correction addons and frame selection

This page describes two different places in calng pipelines where user code can be executed to improve online analysis applications: correction addons, which run within each correction device (and therefore per module), and frame selection kernels, which run in an arbiter, telling group matchers which frames they should forward.

The purpose of correction addons may be to perform additional computation on the corrected detector data to provide useful information either to downstream online analysis or for use with a frame selection arbiter. The purpose of the arbiter is to select on a train-by-train basis which frames should be sent out of the pipeline, thus allowing flexible data reduction for online analysis. The arbiter will have access only to small data / metadata (and not the full image data), but it will get this for every module for each train. Used in combination, a correction addon may, for instance, be used to compute a few interesting values per frame, which an arbiter can then use to decide, over the full detector, which frames are relevant for further analysis. The sketch below illustrates the data flow with a frame selection arbiter in place (for simplicity, only one group of correction devices is drawn):

For the operator

The rest of the content of this page will be more technical than other pages in the user documentation. From an operator point of view, these extensions mostly introduce additional configuration and thus complexity to running pipelines.

The correction addons each register their configuration subnodes in the correction device schema under addons. Configuring these will typically be done via the manager. Only addons which are marked as enabled are actually executed.

The frame selection feature involves an arbiter - essentially yet another train matcher - which runs user code and interation with each of the group matchers. The group matchers will only try to filter out frames if frameSelector.enable is set and if they actually receive data from the arbiter (specified by the frameSelector.arbiterSource). That means that if the arbiter for some reason did not provide a mask for a given train (arbiter could be down, not matching, or otherwise having issues), all data is still forwarded as usual.

Configuration of the arbiter consists of setting up the matching part (it behaves like a full matcher except it does not get full image data) and the arbiter kernel part. Only the latter differs from other matchers and involves user kernels. The frameSelection node contains all the relevant configuration: frameSelection.kernelChoice selects which of the installed kernels to use and under frameSelection.kernels, each of these installed kernels may provide additional configuration parameters needs.

Correction addon API

A correction addon should inherit from calng.correction_addons.BaseCorrectionAddon. This base class, for now, contains method stubs. When writing a subclass, you will want to override a subset of these stubs:

  • __init__(self, config): initializer similar to that of a karabo device.
    • The config passed to the addon will be the contents of the addon's node within the the correction device's configuration.
    • This means you will here get the keys you added under the prefix with extend_device_schema.
  • extend_device_schema(schema, prefix): a static method which will be called during the correction device's expectedParameters (where the class tells Karabo about the schema of this device type).
    • This is used to add configurable parameters for the addon in the regular Karabo bound API style.
    • schema is the device schema (passed from the expectedParameters call.
    • prefix will be a substring under which you should put any elements you add to the schema.
    • You will probably want to add .tags("managed") to most parameters to control them via the manager.
    • Note that the boolean to control whether the addon is active is added and managed automatically. Please use it - this means add elements by something like FLOAT_ELEMENT(schema).key(f"{prefix}.someParameter").
    • Ordinary Karabo schema features apply. Remember to .commit(), give default values, and consider .reconfigurable().
  • extend_output_schema(schema): a static method used to extend the output schema of the correction device, typically to add additional fields to the output.
    • You can technically add keys to the output hashes without advertising them in the schema, but please use this method to indicate what you will want to add.
  • post_correction(self, processed_data, cell_table, pulse_table, output_hash): the main hook where the addon will want to compute something exciting.
    • processed_data is the image data right after it has been corrected. If running a GPU kernel, this data is still on GPU which you may want to exploit.
    • cell_table and pulse_table are the mappings from frame to cells and pulses provided by the detector (if available). These are discussed in preview configuration and may be relevant for some kernel types.
    • output_hash is the hash which will eventually be written to the main output channel. The addon can do whatever it wants with this hash. Typically, you will want to add some new computed keys to it (which you have hopefully mentioned in extend_output_schema).
  • post_reshape is mostly the same as post_correction, except it is called slightly later in the input handler and data is guaranteed to be in system memory rather than on GPU.
  • reconfigure: when any of the addon's parameters are changed, this is called with the parameters which have been changed (similar to preReconfigure in Karabo bound).

Frame selection API

A frame selection arbiter kernel should inherit from calng.arbiter_kernels.BaseArbiterKernel. This class for now containts stubs for the methods a kernel will need to provide:

  • __init__(self, config): as with correction addons, this initializer behaves very much like one from a Karabo bound device.
    • It is given the part of the device configuration hash under the node belonging to this kernel.
    • This depends on what is added via extend_device_schema.
  • extend_device_schema(schema, prefix): see the method of the same name for correction addons.
  • consider(self, train_id, sources, num_frames) is the main function called upon matching to compute a frame mask.
    • The default one provides a mask of all ones (truthy), meaning all frames are included. Note that the dtype of the returned array is numpy.uint8.
    • The sources argument comes from on_matched_data (the arbiter is a TrainMatcher). It is a dictionary mapping source names to tuples of data (the data hash received from the source) and timestamp.

The configuration keys added by extend_device_schema will go in the arbiter schema under frameSelection.kernels.[node name] where the node name is automatically based on the class name. Note that this node name is automatically part of the prefix passed to extend_device_schema.

Most parameters to most arbiter kernels should be reconfigurable - if not, changing them means restarting the kernel arbiter entirely. For now, changing a parameter for the kernel will cause the kernel to be reinstantiated; in the future, a reconfigure option similar to that of correction addons may be added for kernels which are changed often / expensive to reinstantiate.

From the base class, an arbiter kernel gets the following properties / methods:

  • _config: points to the hash with the configuration passed to init
  • _device: will point to the host device - but only after __init__; should generally not be used directly
  • geometry: property containing the current detector geometry (gotten from device, requires correctly configured FrameSelectionArbiter)
  • warning_context: helper function returning a context manager to allow emitting custom warnings via the host device, setting the warning state of frameSelection.kernelState
    • Note that uncaught exceptions in consider will also trigger this with KernelWarning.PROCESSING
    • Some common warning types are defined in the base_kernel.KernelWarning enum type; feel free to define additional warnings and pass them to the context manager
    • See example kernels for examples of how to use this

Existing arbiter kernels

The following arbiter kernels are distributed with calng as examples:

  • BooleanCombination: will combine a set of existing frame masks with ordinary Boolean operation per frame. This is useful if some correction addon has already computed a frame mask (a vector of booleans under data.dataFramePattern) for each detector module in a multi-module detector. In this case, this arbiter kernel allows you to compute a frame mask consisting either of frames where all individual module frame masks include it or where any masks include it.
  • RandomFrames: simple example arbiter demonstrating how to add trivial configuration parameters and provide a valid frame mask. Will use numpy.random to filter frames uniformly at random with a given probability per frame.
  • ReduceAndThreshold: a generic kernel applicable in some cases where correction addons provide some relevant stats on a per-frame basis for each module. The reduction will be applied to this stat (name is configured) along the module axis and frames are included based on thresholding the result against a set parameter.

Installing new extensions

Both arbiter kernels as well as correction addons are installed using Python entry points. Correction addons go in the calng.correction_addon namespace while arbiter kernels go in calng.arbiter_kernel. So to expose custom extensions in a custom package, you may add something like this to your setup.py:

setup(
    ...
    entry_points={
        "calng.correction_addon": [
            "CoolAddon = my_package.addon_module:CoolAddon",
        ],
        "calng.arbiter_kernel": [
            "CoolKernel = my_package.arbiter_module:CoolKernel",
        ],
    },
    ...
    ),
)

Correction addons may be specific to individual detectors and thus correction device classes. The "extras" field can be used to list detectors (in lowercase) for whcih an addon should be available. For example, append [agipd] to the string specifying the path to CoolAddon in the example above to indicate that it should only be used in the AgipdCorrection class. If no extra string is provided, the addon is made available to all correction device classes by default.