Concentration Correction#

Concentration correction compensates for variations in the sample amount (e.g. concentration, beam footprint) that occur between measurements. It works by dividing each signal and monitor by the corresponding signal and monitor of the correction scan.

The concentration_correction() method chooses between two internal correctors based on the arguments you supply.

Simple concentration correction#

The SimpleConcentrationCorrector is activated by passing only the indices or scans argument, without an extra data_mappings dictionary:

measurement.concentration_correction(indices=101)

Internally, daxs reads the correction scan(s) from the same source as the measurement scans. The corrector selects the division strategy based on how many correction scans are provided relative to the measurement scans:

Situation

Behaviour

One correction scan with as many data points as there are measurement scans

Each data point of the correction scan scales the corresponding measurement scan.

One correction scan, but the numbers above do not match

Every measurement scan is divided by the entire correction scan.

As many correction scans as measurement scans

Each correction scan is paired one-to-one with a measurement scan.

Any other combination

An error is raised.

This strategy assumes that measurement scans and correction scan points share the same sequential order, which is usually true when samples are measured in a fixed sequence at the beamline.

Data-driven concentration correction#

The DataDrivenConcentrationCorrector is activated by additionally supplying a data_mappings dictionary:

data_mappings = {
    "sy":    ".1/instrument/positioners/sy",
    "owisz": ".1/instrument/positioners/owisz",
}
measurement.concentration_correction(indices=225, data_mappings=data_mappings)

Here data_mappings names one or more positioner counters. For each measurement scan, daxs reads the positioner values that were recorded at the time of that scan. It then searches the correction scan for the point whose positioner values are closest in Euclidean distance and uses that point as the correction factor.

This approach is more robust because it does not rely on scan order. As long as the sample returns to the same position (within numerical precision), the matching succeeds — even if the order in which positions were visited differs between the measurement and the correction scan.

Note

The keys in data_mappings must correspond to fields that were recorded in the measurement scans (as additional entries in the source data_mappings). The values must be paths to the equivalent counter columns in the correction scan. See also the Advanced Concentration Correction example.

Supplying pre-built scan objects#

Both correctors also accept pre-built Scan or Scans objects via the scans argument, which is useful when the correction data lives in a different file:

from daxs.sources import Hdf5Source

corr_source = Hdf5Source(other_file, selection=42, data_mappings={...})
measurement.concentration_correction(scans=corr_source.scans)

API reference#

See concentration_correction(), SimpleConcentrationCorrector, and DataDrivenConcentrationCorrector.