Plot intensity versus Q from a monochromatic image#
Use q_distribution() to calculate mean intensity versus scattering-vector magnitude Q from one monochromatic detector image. The result contains intensity sums, pixel counts, nonfinite-pixel counts, and processing settings. Q is in 1/nm, including the factor of two pi.
You need the image’s photon energy and calibrated detector geometry. The calculation runs in Python without crystal indexing or an Igor installation. It processes one image and does not fit peaks, calculate strain, or construct volumes.
Run the synthetic example#
The synthetic fixtures in tests/data/energy/ contain an image with rings centered at 6.5 and 13 1/nm, a matching dark image, and an exclusion mask. Run this example from the repository root with the package installed:
from pathlib import Path
from tempfile import TemporaryDirectory
import numpy as np
from lauelab.energy import (
q_distribution, save_q_distribution, load_q_distribution,
export_q_distribution_csv,
)
from lauelab.indexing import load_mask
from lauelab.visualization import plot_q_distribution
data = Path("tests/data/energy")
profile = q_distribution(
data / "rings.h5",
geometry=data / "geometry.xml",
dark=data / "dark.h5",
mask=load_mask(data / "mask.h5"),
roi=(5, 73, 7, 91),
q_first=0.0, q_last=20.0, q_points=201,
)
assert profile.pixel_count.sum() == 5596
assert profile.nonfinite_pixel_count.sum() == 0
assert profile.provenance["normalization"]["factor"] == 5.0
figure = plot_q_distribution(profile)
with TemporaryDirectory() as output:
output = Path(output)
save_q_distribution(profile, output / "profile.h5")
export_q_distribution_csv(profile, output / "profile.csv")
reopened = load_q_distribution(output / "profile.h5")
np.testing.assert_array_equal(reopened.intensity_mean, profile.intensity_mean)
reopened_figure = plot_q_distribution(reopened)
In a notebook, display figure to inspect the profile. The plot uses blue points and a dashed line, linear axes, Q in nm⁻¹, inward ticks, mirrored axes, and a y minimum of zero. Negative intensities are included in the arrays; change the returned figure’s y range to display them.
Select an input and detector#
Pass a 2D NumPy array, a supported 34-ID-E HDF5 frame, or a ScanFrame for either the primary image or the dark. A ScanFrame identifies one reconstructed point and depth index. Raw 3D stacks are not accepted.
Images have shape (ny, nx), and image[y, x] accesses pixel (x, y). Full-detector start and group use (x, y). Coordinate conversion uses the fractional center of each grouped pixel. depth is in µm in the detector geometry convention. Stored start and group take precedence over call arguments. An explicit depth, including zero, overrides the stored depth. See Frame input for the input layout.
An HDF5 origin or binning pair must contain both axes or neither: startx with starty, and binx with biny. The function raises InputError for an incomplete pair in either a primary or dark image. When both axes of a primary field are absent, call arguments or their defaults apply. If you supply a dark without coordinate metadata, the function assumes it matches the primary image. Missing or nonfinite stored depth is treated as absent; the default is zero unless you pass an explicit finite depth.
The function selects a detector using the ID in the effective metadata or the sole active detector in the geometry. If neither is available, supply detector_id or detector_index. The function raises InputError for conflicting selections.
Warning
detector_index is a physical geometry slot, not its position among active detectors. Slots can be sparse; the synthetic geometry uses slot 2.
Establish photon energy and beam mode#
Photon energy must be finite and positive. The energy_kev argument takes precedence over energy in supplied metadata, which takes precedence over file energy. Supplied FrameMetadata or mapping fields override other file metadata. The provenance contains the original values and explicit overrides.
Confirm monochromatic illumination with reliable mono_mode="monochromatic" metadata or an explicit monochromatic=True declaration. An incident_energy value alone is insufficient. If white-beam mode is recorded in either the file or supplied metadata, pass both monochromatic=True and a nonempty monochromatic_reason. This requirement applies even when you override the photon energy or mode metadata.
Choose corrections#
Choose a normalization mode. The default is normalization="i0"; all quantities required by the selected mode must be positive and finite:
Mode |
Required metadata |
Effect after direct dark subtraction |
|---|---|---|
|
None |
No scalar correction |
|
|
Divide by exposure in seconds |
|
|
Normalize to exposure and I0, including the |
When i0_gain is omitted, the function uses a nominal gain of 1e9 and records the assumption in the provenance. Supplied i0_gain must be positive and finite. Detector gain is a separate quantity and cannot substitute for I0 gain. Monitor metadata must be scalar or length one. For longer vectors, supply an explicit scalar override, including when processing a ScanFrame.
The function raises InputError for missing or invalid required quantities. For an array without metadata, supply the required fields or select normalization="none". The algorithm defines the correction formula.
A dark must match the entire supplied frame in shape, stored coordinates, binning, units and exposure. The function raises InputError for known mismatches and does not rescale or resample the dark. Use dark_metadata to override a dark file’s metadata. If you supply a dark array without metadata, you are responsible for checking these conditions.
Warning
Reconstructed images can contain normalized or scaled intensities. Inspect the recorded reconstruction settings and select corrections appropriate to the stored values. Energy reduction does not undo reconstruction scaling or identify every correction applied to an image.
The function does not apply flat-field, detector distortion, solid-angle, polarization, Lorentz or automatic background corrections. Applied corrections and references to unapplied distortion maps are recorded in the provenance. The output is corrected detector intensity; it is not calibrated as an absolute scattering cross section.
Select pixels and Q centers#
Pass roi=(y0, y1, x0, x1) to select the half-open slice image[y0:y1, x0:x1]. A mask must match the full supplied image before ROI selection: zero includes a pixel, and nonzero excludes it. Excluded pixels are omitted from both intensity sums and occupancy, including when their intensities are NaN or Inf. The function does not resize or broadcast masks.
Igor’s energy-scan routine uses an inclusion mask: 1 includes a pixel and 0 excludes it. To reuse that mask, arrange it in NumPy (ny, nx) order and pass mask=(igor_mask == 0). The load_mask() helper reads nonzero entries as exclusions, following the peaksearch convention. The maskNorm (“Suppress”) pedestal correction is not supported. Use dark for subtraction of a supplied dark image.
Omit all Q controls to calculate spacing from the selected detector pixels. Alternatively, supply q_first, q_last and q_points together: a finite nonnegative first center, a larger finite last center, and an integer count of at least two. These values specify sample centers. Nearest-center assignment rounds half ties away from zero. Pixels whose rounded indices fall outside the grid are omitted and counted in the diagnostics.
If automatic spacing is undefined or the Q span is zero, the function raises InputError and requests an explicit grid. The default allocation limit is max_bins=1_000_000. Computation and loading check this limit before allocating profile arrays; raise it explicitly for a larger profile. Pixel calculations use bounded blocks, and one source frame is loaded into memory.
Interpret missing and negative values#
Bin contents |
Mean |
Sum |
Counts |
|---|---|---|---|
No assigned pixels |
NaN |
Zero |
Zero occupancy |
Assigned finite pixels, including all zeros |
Sum / occupancy |
Corrected sum |
Positive occupancy |
An assigned nonfinite intensity or dark value |
NaN |
NaN |
Positive occupancy and nonfinite count |
Nonfinite intensities affect only their assigned bins. You can inspect a profile in which every occupied bin has unavailable intensity by using its counts and diagnostics. The function raises InputError when all selected pixels are masked or no pixels map to the requested grid. Zero and finite negative intensities are valid. Pixel counts are diagnostics; the result does not include statistical uncertainties or error bars.
The function accepts real integer and floating-point dtypes, including uint32, int64, uint64, byte-swapped arrays and noncontiguous arrays. Arithmetic and floating-point outputs use numpy.float64. Integers beyond 2**53 can round during conversion; calculations are not exact for arbitrary wide integers. Finite arithmetic overflow raises InputError. The function does not modify its inputs. The result contains independent, read-only arrays, and each access to provenance returns a copy of the metadata and settings.
Save or exchange a result#
Use save_q_distribution() to write an HDF5 file containing profile arrays, geometry, dimensioned settings, original and effective metadata, assumptions, diagnostics, and input, dark and mask content hashes. Source pixel arrays are not embedded in the file. You can load and plot the saved profile without source files; recomputation requires the original inputs.
Saving, validation and loading check the selection and calibration settings. They reject nonpositive binning or detector dimensions, nonpositive physical sizes, nonfinite transforms, and a frame or ROI outside its recorded bounds.
Use export_q_distribution_csv() to write five numeric columns with comment lines identifying units and normalization. Skip lines beginning with # when reading the CSV. Both export functions raise FileExistsError for an existing destination unless you pass overwrite=True.
See the API reference for signatures, the format description for the file layout, and the algorithm for equations and validation evidence.