Reconstruction scan format#
A reconstructed scan is a directory with one HDF5 file per point and a catalog, scan.h5. The catalog contains the list of requested points, their acquisition metadata, and their outcomes. Each completed file under points/ contains the reconstructed depth stack and all the data needed to inspect, index, or export it without other files: physical depths, reference images, settings, geometry, and acquisition metadata.
This page specifies the two file layouts and the pixel values that they contain. Reconstruction scan protocol describes scan preparation, coordination, point and run statuses, and the readers. Inspect a reconstructed point defines square regions of interest (ROIs). For examples, see Reconstruct a wire scan.
The writers, readers, and validators use the layout definitions in lauelab/reconstruct/_scan_layout.py.
Both files use the HDF5 file conventions, with the exception for point files stated there. The root format attribute of the catalog is lauelab-reconstruction-scan, and its version is 2. The root format attribute of a point file is lauelab-reconstruction-point, and its version is 2.
Scan directory#
<scan directory>/
scan.h5
points/
Twin2_wire_1.h5
Twin2_wire_2.h5
For an input named Twin2_wire_1.h5, reconstruction writes points/Twin2_wire_1.h5. The input stem must be nonempty, must not start with ., and must not contain path separators or control characters; other names accepted by the file system are allowed.
Inputs with the same stem, including names that differ only in letter case, would produce conflicting output paths. Preparation rejects these inputs before writing any files. This also applies to an input listed twice. Reconstruct inputs with conflicting names into separate scan directories.
The scan directory must not exist or must be empty. A nonempty directory is rejected, so the output of two scans cannot mix. Choose another directory, or remove the existing output yourself.
/points/paths contains the path of each point file relative to the directory of scan.h5, with / separators, such as points/Twin2_wire_1.h5. The scan remains readable when the whole directory is moved. A point file can also be copied and used by itself.
scan.h5 also contains one HDF5 external link for each complete point. /point_files/<stem> is a link to the root of points/<stem>.h5 by its relative path. HDF5 resolves the path from the directory of scan.h5, so an HDF5 viewer such as HDFView can open every complete point from the catalog. The lauelab readers use /points/paths and do not follow the links. Neither file contains virtual datasets.
Point file structure#
A point file has the layout of the per-depth files that the reconstruction executable reconstructN_cpu writes, with all depths in one file. The writer copies the input file as the executable does. The root attributes, the groups and their attributes, and the datasets are copied with their paths and values, except /entry1/wire and the raw frames. The writer then adds these objects:
/entry1/data/datacontains the stored frames, shape(n_depths, rows, columns), with the integer attributesignal=1. Image indexing isdata[depth_index, y, x]./entry1/depthcontains the physical depth of each frame in µm along the incident beam from the Si origin of the geometry, shape(n_depths,), withunits="micron". It replaces the/entry1/depthof the input./entry1/microDiffraction/cosmic_filteris written, with the value 1, only when the cosmic-ray filter ran./entry1/microDiffraction/norm_exponent,norm_threshold, andnorm_rescaleare written only when exponent normalization ran. These are the paths and types that the executable writes./entry1/reconstructionis a group of datasets that contain the reconstruction settings that were used, the identity and provenance of the point, the reference images, and the depth totals.
The root also has the lauelab format, version, lauelab_version, and created attributes. The root attributes copied from the input, such as file_name and file_time, are attributes of the acquisition file. The NX_class attributes that the acquisition software wrote are copied with their groups. The writer adds no NeXus attributes.
The datasets added by lauelab have the form of the acquisition values: a single value has shape (1,), text is fixed-length and UTF-8 encoded, and units have the spelling of the acquisition files, such as micron. A value that does not apply is not written. For example, a standalone point has no manifest_index, and a point reconstructed without a normalization vector has no normalization. tests/test_point_files.py compares a point file with the output of the executable for every recorded variant.
Identities#
A frame is selected by its point and its depth index. The initial catalog entries are in input order. For an incremental scan, each successful PreparedScan.add appends one entry in registration order. Existing indices and point files never change. Acquisition order and sample coordinates are independent of registration order; use the point IDs and acquisition metadata to place points in a view.
A running catalog can contain zero points. It lists only registered inputs, whose metadata has been inspected; expected future inputs belong to the caller’s acquisition manifest. A finished catalog must contain at least one point. These rules use the same version-2 datasets and point-file layout as a batch scan.
Identity |
Type |
Meaning |
|---|---|---|
Point ID |
string |
Unique, non-empty identifier of a point within its scan. Defaults to the input stem. It is independent of the point filename. |
Manifest index |
zero-based integer |
Position of the point in registration order, initially the input order. Every dataset under |
Point path |
string |
Location of the point file relative to the scan directory. It is assigned when the point is registered, whatever the point’s outcome. |
Depth index |
zero-based integer |
Position of a frame in the point’s |
Physical depth |
|
Depth along the incident beam from the Si origin of the geometry file. It is |
The point ID and the manifest index are stored in the point file, so they are available when the file is copied elsewhere. Standalone points have no manifest index. Physical depths are stored in /entry1/depth. For example, depth index 0 corresponds to -25 µm when the reconstructed depth grid starts at -25 µm.
A frame reference, ScanFrame, contains the path of a point file and a depth index, which identify one stored frame. A frame reference can be serialized and sent to indexing workers, which open the file locally. Indexing results contain the point ID and the depth index.
Value semantics#
Pixel values have three kinds, one for each stage of processing:
Kind |
Dtype |
Meaning |
|---|---|---|
Raw |
dtype of the input frames |
Detector counts as acquired, before the cosmic-ray filter and before any normalization. |
Computed |
|
Output of the reconstruction kernel. These are |
Stored |
the point’s output pixel type |
The pixels in the file. Inspection, ROI traces, and downstream indexing use these values. |
Before writing, the library multiplies computed intensities by rescale and converts them to the output pixel type. rescale is 1 unless exponent normalization writes an integer type; it is recorded as /entry1/microDiffraction/norm_rescale when exponent normalization ran, and it is applied once. For a floating-point type, the conversion equals a NumPy cast. For an integer type, the conversion truncates toward zero and then saturates at the limits of the type. Positive and negative infinity saturate. NaN stores 0 in an integer type.
The native library converts pixels and computes reductions in one pass. For finite values and infinities, conversion matches the HDF5 conversion used by per-depth output. Integer conversion of NaN depends on the HDF5 destination type and can differ from the scan format’s defined value of zero.
Warning
Reconstructed intensities can be negative with any wire_edge setting. In an unsigned output type, each negative pixel is stored as 0, so the stored totals are larger than the computed totals. For the recorded leading-edge reference, the numpy.uint16 frames sum to 573801 and the computed frames sum to 512684.9.
Reductions#
Stored-pixel totals are calculated after conversion, from the same values that a read of the file returns.
Integer stored pixels accumulate in
numpy.int64and are exact. A sum ofnvalues of at most 4 bytes cannot overflow whilenis below 2³¹, which exceeds the pixel count of a 4096 by 4096 frame.Floating-point stored pixels accumulate in
numpy.float64. The summation order is not specified. Reconstructed pixels are signed, so a total can be much smaller than the pixels that produce it, and a tolerance relative to the total is not meaningful. Compare a reduction with a recomputed one at an absolute tolerance of 10⁻¹² times the sum of the absolute pixel values in the reduction.
/entry1/reconstruction/computed_depth_intensity contains the totals before storage conversion, which are also in the LaueGo-compatible summary. /entry1/reconstruction/depth_intensity contains the stored-pixel totals, which inspection uses. Because of conversion and rescale, the two totals can differ.
Reference images#
Three reference images are saved with each point for inspection after the raw input becomes unavailable. Each has the same shape as a detector frame.
Image |
Values |
Definition |
|---|---|---|
|
raw |
The first selected scan frame. |
|
raw |
The sum of every selected scan frame. |
|
stored |
The sum of the stored frames through depth. |
/entry1/reconstruction/raw_slices contains the half-open range of the selected input slices. For a 34-ID-E multi-image file with n stored slices the range is [frame_skip, n - 1): the first frame_skip slices are bookkeeping, and the last slice is never differenced. See “How a point file is read” in Reconstruct a wire scan. The raw stack itself is not copied.
File layout#
In the tables below, n_points is the number of points in the scan. The depth count (n_depths), frame dimensions (rows, columns), and output pixel type can vary between points. The following dtype rules apply separately to each point:
Rule |
Dtype |
|---|---|
|
The point’s output pixel type. |
|
The dtype of the point’s raw frames. |
|
|
|
|
In the catalog tables, the Fill column gives the value that is stored when a quantity does not apply or is not available. For a numeric dataset, this value is also the HDF5 fill value. enum identifies an HDF5 enumerated type, which HDF5 tools display by name.
Root attributes#
In addition to the attributes common to lauelab files, the root of scan.h5 has these attributes:
Attribute |
Type |
Meaning |
|---|---|---|
|
string |
|
|
string |
Version of the native library that prepared the scan |
|
|
Run status; the codes are listed in Reconstruction scan protocol |
Parameters and geometry#
These datasets contain the requested settings, with the names of the Reconstructor arguments. A point file contains the settings that were used for that point; see the point-file table below. /geometry also has a path attribute, which contains the geometry file path as given.
Path |
Dtype |
Shape |
Units |
Fill |
Meaning |
|---|---|---|---|---|---|
|
|
|
Physical detector slot in the geometry |
||
|
|
|
um |
Requested inclusive depth range |
|
|
|
|
um |
Spacing between depths |
|
|
|
|
|
||
|
|
|
Percentage of intensity-map pixels reconstructed |
||
|
|
|
empty |
Name of the normalization vector |
|
|
|
|
NaN |
Exponent normalization |
|
|
|
|
NaN |
Requested threshold; NaN selects it automatically for each point |
|
|
|
|
1 when the cosmic-ray filter is requested |
||
|
|
|
Leading stored slices skipped |
||
|
|
|
Stored wire-vector entries skipped after entry 0 |
||
|
|
|
-1 |
Requested pixel type code; -1 selects it from the input |
|
|
|
|
-1 |
Requested rows per stripe; -1 selects them automatically |
|
|
|
|
MiB |
Stripe-buffer limit of one worker |
|
|
|
|
Complete text of the geometry file, read once when the scan is prepared |
Points#
Each dataset under /points has one entry per point in manifest order. Listing a scan reads scan.h5 only; no point file is opened.
Path |
Dtype |
Shape |
Units |
Fill |
Meaning |
|---|---|---|---|---|---|
|
|
|
Point ID |
||
|
|
|
Point file relative to the scan directory |
||
|
|
|
Point status |
||
|
|
|
empty |
Error text of a failed point |
|
|
|
|
Absolute input path |
||
|
|
|
-1 |
Acquisition scan number |
|
|
|
|
um |
NaN |
Sample |
|
|
|
keV |
NaN |
Incident energy |
|
|
|
0 |
|
|
|
|
|
um |
NaN |
First and last physical depth |
|
|
|
-1 |
Output pixel type: |
The input path is stored for provenance. It does not identify the contents of the input, and a scan cannot be resumed from it. Each point file also contains the size and modification time of its input. A file-status call reads these values without reading the file, so an unchanged file can have a new modification time, and changed contents can have the same size and modification time.
Point file#
Each completed point file contains the datasets below and the metadata copied from its input. The When column gives the condition for an optional dataset; the other datasets are always present. The file is at its final path only after writing and validation succeed.
Path |
Dtype |
Shape |
Units |
When |
Meaning |
|---|---|---|---|---|---|
|
|
|
Stored frames; attribute |
||
|
|
|
micron |
Physical depth of each frame |
|
|
|
|
cosmic-ray filter ran |
1 |
|
|
|
|
exponent normalization ran |
Normalization exponent |
|
|
|
|
exponent normalization ran |
Threshold used |
|
|
|
|
exponent normalization ran |
Factor applied before conversion |
|
|
|
|
Physical detector slot in the geometry |
||
|
|
|
micron |
Requested inclusive depth range |
|
|
|
|
micron |
Spacing between depths |
|
|
|
|
|
||
|
|
|
Percentage of intensity-map pixels reconstructed |
||
|
|
|
a vector was used |
Name of the normalization vector |
|
|
|
|
Leading stored slices skipped |
||
|
|
|
Stored wire-vector entries skipped after entry 0 |
||
|
|
|
Geometry file path as given |
||
|
|
|
Complete text of the geometry file used |
||
|
|
|
Point ID |
||
|
|
|
the point belongs to a scan |
Manifest index in the scan |
|
|
|
|
Absolute input path |
||
|
|
|
bytes |
the input could be examined |
Input size in bytes |
|
|
|
the input could be examined |
Input modification time in ns since the epoch |
|
|
|
|
Half-open range of selected input slices |
||
|
|
|
Version of the native library that reconstructed the point |
||
|
|
|
OpenMP threads used |
||
|
|
|
Rows per stripe used |
||
|
|
|
MiB |
Stripe-buffer limit |
|
|
|
|
s |
Wall time of the reconstruction |
|
|
|
|
First selected raw frame |
||
|
|
|
Sum of the selected raw frames |
||
|
|
|
Sum of the stored frames |
||
|
|
|
Stored total of each frame |
||
|
|
|
Computed total of each frame |
text is fixed-length UTF-8 text whose length is that of the value. The settings in the point file are the values used. The output pixel type is the dtype of /entry1/data/data. A threshold or stripe height that was selected automatically is recorded as the value selected.
num_threads, rows_per_stripe, memory_limit_mb, and elapsed_seconds are execution values. Runs with identical results can have different execution values.
The writer rejects an input that contains /entry1/reconstruction or one of the four /entry1/microDiffraction datasets above, because such a file is the output of a reconstruction. Per-depth export copies the point file without /entry1/reconstruction and writes one frame and its physical depth to each file.
A point file can be inspected, indexed, and exported to per-depth files without its catalog, raw input, or geometry file. It does not contain the raw frames, so the input is necessary to reconstruct the point again.
/entry1/data/data is stored in HDF5 chunks. The chunk shape and the compression are not part of the format.
Per-depth output#
The in-process and executable paths are cross-checks of each other. The recorded references under tests/data/reconstruction/ are the expected output of both. The stored frames of a point file equal the per-depth frames for every recorded variant.
export_per_depth() reads the stored pixels from a point file and writes them in their stored dtype, with their physical depth, the acquisition metadata, and the normalization values. It does not run reconstruction and does not apply rescale again. Its LaueGo-compatible summary contains /entry1/reconstruction/computed_depth_intensity and the execution time and stripe height of the reconstruction. A failed export does not change the point file.
Evidence#
tests/test_reconstruction_contract.py checks the conversion rule against HDF5, records what each reference variant contains, and verifies the hand-worked fixtures in tests/data/reconstruction_contract/fixtures.py with brute-force oracles. The fixtures contain the cases that are not in any recorded reference: a zero frame, a frame with no positive pixel, saturation at both limits, and integer output with rescale above 1. tests/test_point_files.py compares point files with the output of reconstructN_cpu and checks the point validator. tests/test_scan_preparation.py checks preparation, tasks, destinations, and the catalog validator. tests/test_scan_layout.py compares the tables on this page and the status codes in Reconstruction scan protocol with the layout module.