Depth reconstruction#
Depth reconstruction assigns the intensity that disappears between consecutive wire-scan frames to depths along the incident beam. This page describes the transformations and binning implemented by the native kernel. It uses the coordinate conventions of the 34-ID-E geometry file without assigning physical axis names.
Pixel positions#
The kernel converts a binned image coordinate to a laboratory position in four steps.
Map the image column and row to full-detector pixel coordinates using the image geometry’s
startandgroup. The result is the center of the pixel group:\[i = c\,g_x + s_x + \frac{g_x - 1}{2}, \qquad j = r\,g_y + s_y + \frac{g_y - 1}{2}\]Here
candrare the zero-based image column and row,(s_x, s_y)isstart, and(g_x, g_y)isgroup, all in unbinned pixels.Convert to detector-local physical coordinates using the detector’s pixel size and full dimensions:
\[x_d = \left(i - \tfrac{N_x - 1}{2}\right) p_x + P_x, \qquad y_d = \left(j - \tfrac{N_y - 1}{2}\right) p_y + P_y, \qquad z_d = P_z\]N_xandN_yare the full-detector dimensions in unbinned pixels,p_xandp_yare the pixel sizes in µm, andPis the detector translation from the geometry file.Apply the detector rotation matrix from the geometry file.
Apply the wire-alignment rotation
\rhodescribed below.
The kernel evaluates two positions for every pixel: the column edges c - 0.5 and c + 0.5. They bound the pixel along the column direction and give each pixel a finite depth interval for one wire position.
Wire positions#
Raw wire positions are (x, y, z) values in the acquisition coordinate system. The kernel transforms each one in this order:
Apply the selected positioner correction.
"pm500"adds a periodic table correction toyandz."alio"and"none"apply no correction.Subtract the wire origin from the geometry file.
Apply the wire rotation matrix from the geometry file.
Apply
\rho.
\rho is the rotation that brings the wire axis onto the x axis. It is derived from the wire axis vector in the geometry file. When the wire axis is already parallel to x, \rho is the identity. After this rotation the wire is a cylinder along x, and the depth construction uses only y and z components.
The incident-beam direction used by the depth calculation is:
Depth of one pixel and wire position#
Let (y_p, z_p) be the rotated pixel position and (y_w, z_w) the rotated wire-center position. With wire radius a, the kernel calculates:
\varphi_0 is the direction from the pixel to the wire center, and \Delta\varphi is the half-angle subtended by the wire. The tangent ray from the pixel past the wire edge has direction \varphi_0 - \Delta\varphi for the leading edge and \varphi_0 + \Delta\varphi for the trailing edge:
The kernel intersects this ray, written as z = z_p + (y - y_p)\tan\varphi, with the incident-beam line through the origin along \hat{k}_i. The depth is the signed projection of the intersection point \mathbf{s} onto the beam direction:
D is in µm and increases along \hat{k}_i. Depth is measured from the laboratory-frame origin. Subtracting the wire origin expresses the raw positioner readings in that frame, so D = 0 corresponds to the Si origin recorded in the geometry file.
Depth grid#
The output depths form a regular grid. The requested depth_range endpoints are rounded to the nearest multiple of resolution:
where \delta is resolution in µm and D_1 is the rounded end. Output depth k is D_0 + k\delta, and its bin covers [D_0 + (k - \tfrac12)\delta,\; D_0 + (k + \tfrac12)\delta). ReconstructionResult.depth_um lists D_0 + k\delta for k = 0, \dots, n - 1. Equal endpoints give one depth.
Frame differencing#
For one pixel, the kernel reads its value from each scan frame into a trace I_0, \dots, I_{N-1}, applies the per-frame scale and the per-pixel normalization plane, and optionally runs the cosmic-ray filter. It then forms the differences:
The final difference I_{N-2} - I_{N-1} is never formed. This reproduces the executable’s loop bound. A zero difference deposits nothing.
Scan frame k is paired with wire positions w_k and w_{k+1}. The leading edge deposits d_k with positive sign. The trailing edge deposits -d_k. With wire_edge="both", the kernel performs both deposits for the same difference, each with its own edge depths.
Trapezoid deposit#
For frame pair k, the pixel’s two edge positions and two wire positions give four depths:
Symbol |
Pixel edge |
Wire position |
|---|---|---|
|
front ( |
|
|
back ( |
|
|
front |
|
|
back |
|
D_\text{fs} and D_\text{fe} are swapped when reversed. The weight is a trapezoid: zero outside [D_\text{ps}, D_\text{pe}], rising linearly to one at D_\text{fs}, one between D_\text{fs} and D_\text{fe}, and falling linearly to zero at D_\text{pe}. Its total area is (D_\text{pe} - D_\text{ps}) / 2.
Each output bin that overlaps the trapezoid receives:
The deposit is skipped when the trapezoid lies entirely outside the depth grid or its area is negative or not a number. Bins are clamped to the grid, so intensity from a trapezoid that partly extends outside the range is lost rather than folded into the edge bins.
Intensity mask#
The intensity map is the first scan frame unless array input supplies intensity_map. The mask retains a pixel when its intensity-map value is at least a cutoff:
Here v is the ascending sorted intensity map with n pixels, and p is percent_brightest. Because the cutoff is at least 1, a pixel whose intensity-map value is below 1 is never reconstructed, even with percent_brightest=100.
Normalization#
Two normalizations can scale the trace before differencing.
Per-frame scale. File input reads the HDF5 vector named by normalization and divides it by a fixed beamline divisor: 102 for mA and 88100 for cnt3. Other tags have no divisor. Array input takes the equivalent dimensionless scale array directly.
Exponent normalization. With norm_exponent set to e, every frame is multiplied element-wise by a plane derived from the intensity map M:
When norm_threshold is None, T is the mean plus five standard deviations of the lowest half of the sorted intensity-map values, using the sample variance. The exponent and threshold are rounded to single precision to match the executable. When files use an integer output type, written images are multiplied by a type-dependent rescale factor. Retained result images are not rescaled.
Cosmic-ray filter. With cosmic_filter=True, the kernel replaces isolated spikes in each pixel’s trace with a running median before differencing. A value counts as a spike when it exceeds the local median by a fixed count or a fixed factor. Traces shorter than seven frames are not filtered.
Conventions requiring review#
The kernel reproduces the executable’s arithmetic and is verified against it by regression references. The following interpretations are not established by the implementation alone:
The physical sign convention for depth relative to the sample surface.
Physical names for the laboratory axes and the wire scan direction.
Scientific guidance for
percent_brightest,norm_exponent, and the choice of wire edge.
Until a 34-ID-E source confirms them, treat depth_um as the projection onto \hat{k}_i defined above and validate edge and normalization choices against the executable on representative data.