Skip to main content

midas-saxs

Differentiable small-angle X-ray scattering for MIDAS. Two source terms, one detector:

  • Density contrast — voids, gas bubbles, precipitates. Sphere / ellipsoid / cylinder form factors, lognormal polydispersity, Percus-Yevick S(Q), Guinier and Porod analysis. These came from midas_pdf.saxs, which now re-exports them from here, so MIDAS has one definition of "SAXS form factor".
  • Strain contrast — dislocation loops, driven by a midas_ddd network read from ExaDiS. Optional extra: pip install 'midas-saxs[dislocations]'.
from midas_saxs import SAXSGeometry, SpherePopulation, simulate_frame

geom = SAXSGeometry(lsd_um=2.0e6, bcy_px=512, bcz_px=512, px_um=75.0,
                    wavelength_A=0.7293, n_pix_y=1024, n_pix_z=1024,
                    beamstop_radius_px=30)
voids = SpherePopulation(radius_A=50.0, number_density_per_A3=1e-8,
                         delta_rho_e_per_A3=-2.45, label="voids")
frame = simulate_frame(geom, particles=[voids], sample_volume_A3=1e15)

Read this before promising anyone a loop measurement

Three numbers, measured with a development demo script that is not part of the package.

1. Loops are faint. A dislocation loop of radius R has relaxation volume pi R^2 b; a void of the same radius displaces 4 pi R^3 / 3. For R = 5 nm in Cu that is 26x in volume, so 680x in intensity from volume alone. The loop's relaxation volume is that of a sphere of radius 1.69 nm, but it does not scatter like that sphere: in its own plane its intensity carries a further (1 - kappa)^2 (0.36 for lambda = 100, mu = 75, making 1890x), and along its normal it is zero (point 2).

2. Aligned loops differ from voids in shape. A loop's small-angle amplitude is the distortion term plus the Laue term, the scattering from the loop's own extra or missing atoms (Ehrhart, Trinkaus & Larson, Phys. Rev. B 25 (1982) 834, Eq. 8a/8b). As q -> 0 it is dV (1 - kappa) sin^2(theta), with theta measured from the loop normal and kappa = lambda/(lambda + 2 mu): zero along the normal, largest in the loop plane. On the demo (24 loops, normals along detector z) the azimuthal profile follows cos^4(azimuth), and its minimum is set by the bin width (I_min/I_max = 3.8e-5 with 48 bins, 2.1e-14 with 144). A void is isotropic. Radially averaging a frame destroys the null, which is why this package renders 2-D frames and offers azimuthal_profile alongside radial_average. Two limits: the minimum reaches zero only when the loop normal lies in the detector plane and flattens as the normal tilts toward the beam, and loops with isotropically distributed normals scatter isotropically, like voids (see Identifiability below).

An earlier version of this README quoted kappa dV in the loop plane and dV along the normal, a 1/kappa^2 = 6.25 contrast, and 6.30x from the demo. That is the distortion term alone, and at small angle it is backwards.

3. Real voids bury the signature. Add voids of the same radius at the same number density — the physically realistic irradiated case — and the azimuthal contrast collapses to 1.001x, with the voids outshining the loops by 5212x integrated over the frame.

So: loops are detectable at small angle in a clean matrix, and essentially undetectable alongside a void or bubble population of comparable size. If the question is defect-type discrimination in an irradiated single crystal, near-Bragg diffuse (Huang) scattering is usually the better measurement. For a single prismatic loop (isotropic matrix, Cu 111) the median gain over q directions is 1.3e6, 1.3e4 and 1.3e2 at |q| = 1e-3, 1e-2 and 1e-1 1/A, about 7x below the naive (G/q)^2. The spread covers more than three decades, and small-angle is the stronger signal in 9.8 % of directions at 1e-1 1/A. Method and the full table are in the midas_defect.huang module docstring.

Identifiability — what a frame determines, and what it only appears to

Loop number density is not recoverable from a single SAXS frame. A study in this package claimed 2.6 % on loop number density and 0.6 % on loop radius, at 1e6 photons/q-point with voids at volume fraction 5.2e-5, from a loop-block condition number of 639. It was REFUTED on 2026-09-04 by adversarial review. Every number in it reproduces, several bit-identically — the arithmetic was never the problem. The numbers describe a different parameter vector, a different void loading and a different sample mounting than the claim stated.

Six ways it fails, each measured by a refuter rather than read from the study's own output:

effect
Signed dV restored to the parameter vector (it had been dropped because it made the Fisher matrix rank-deficient — that rank deficiency was the finding) cond 2.77e16; the data fix only the combination n*dV^2; SE[log n_loop] unbounded
Void loading raised to this package's own "realistic irradiation case" (equal radius, equal number density) — the study ran voids 100x rarer than loops SE[n_loop] 252 %
A true Watson habit distribution instead of watson_normals, which is a delta cone at a single polar angle and cannot reach the isotropic control 4.7 % at the planted S = 0.75, 699 % at uniform
Sample rotated: the q-grid had put the habit axis in the detector plane, the single most favourable choice in-plane 2.57 %, 10 deg off the beam 52 %, along the beam 1.4e4-2.7e4 %; about 7 % of habit-axis orientations fail outright
Absolute intensity scale freed (it was hard-fixed, i.e. flux x volume x transmission x efficiency known exactly) an exact null vector appears; only the ratio n_loop/n_void is identifiable. With a 1 % calibration prior 2.77 %, with 10 % 10.3 %
Mild model error: log-normal loop sizes at sigma_ln = 0.2, or a true Watson habit at the same S bias -28 % and -24 % on n_loop, at 9-11 sigma, with chi2/dof of 0.61 and 0.02 — i.e. entirely inside "the fit looks fine"

At the claim's own operating point voids already supply 97.9 % of the photons and the whole result rides on a 3.54 % azimuthal modulation. Over 99 % of the claimed information is azimuthal anisotropy, not scattering-curve shape.

A condition number cannot be a confirm criterion here. A Fisher matrix scales linearly with photon budget, so its condition number is exactly scale-invariant: measured at 639.5832 to seven digits across 1e0, 1e3, 1e6, 1e9 and 1e12 photons/q-point while SE[log n_loop] ran 2580 % to 0.0026 %. Across four decades of void loading it moved 639.6 to 640.2 while SE went 2.58 % to 101 %, straight through the refute threshold with the criterion passing untouched.

What survived. Loop radius at 0.6 % is robust — it held under every lens, including the ones that destroyed the number density, and is unaffected by freeing the absolute scale. State it with its condition: q_max * R >~ 3.

What this means for the code. Nothing here is wrong. Three independent lenses confirmed the Fourier kernel, the Laue correction, the Fisher assembly and the Schur profiling. The forward model is sound; the claim was wrong about what it measured. If you build a Fisher or CRB analysis on this package, include the degenerate directions (signed dV, a loop-vs-plate shape parameter), use a habit distribution that can actually reach isotropy, put the void population at its realistic loading, and report the sample mounting -- because the answer depends on all four.

Scope

Three dislocation populations, treated differently. Closed loops, the irradiation population: exact at every q, distortion plus Laue term. Finite lines (open lines, junction clusters that do not wind): the line-integral amplitude at every q; an edge or mixed line scatters into a sheet perpendicular to itself, an isotropic screw not at all, and a line ending inside the medium carries its ends' unphysical sources off that sheet (the frame warns). Lines that close only through a periodic DDD cell's boundary: an amplitude only on the cell's reciprocal lattice, shown between lattice points at a stated resolution (default two lattice spacings, periodic_resolution_fwhm_inv_A) as the periodic_lines component, with a low-q floor of about three lattice spacings below which pixels are not representative; a bigger simulation cell lowers it. Pure screws in cubic or isotropic elasticity have no dilatation, and the frame says so when a component is only float64 roundoff. The line terms are preregistered and under adversarial verification (2026-09-11), not yet established. An earlier version of this README said lines contribute nothing at small angle; that holds only as q -> 0. include_lines=False reproduces the loops-only frames of 0.1.x and reports the line length it left out.

Units

Quantity Unit
distances, geometry micrometers
wavelength, particle radii, electron density angstroms
q from midas_saxs.geometry inverse angstroms
q into the midas_ddd kernel inverse micrometers

The 1e4 between the last two is easy to lose, so inv_A_to_inv_um / inv_um_to_inv_A exist and strain_source uses them rather than a literal.

Detector geometry

pixel_to_q goes through midas_transforms.apply_tilt_distortion — the same tilt (R_z R_y R_x) and 15-coefficient distortion model the HEDM side uses. That is deliberate: a SAXS geometry and an FF geometry calibrated from the same detector must agree about where q sits. Transmission SAXS has no omega, so lab q is sample q.

Migration note

form_factors, model, wide_band and core_shell moved here from midas_pdf.saxs. Both the package-level path (from midas_pdf.saxs import SAXSModel) and the deep path (from midas_pdf.saxs.form_factors import ...) still resolve, to the same objects — asserted by test_midas_pdf_reexports_the_same_objects. midas_pdf.saxs keeps the genuinely PDF-coupled part: joint SAXS + PDF refinement and its Bayesian variants.

One convention worth knowing: sphere_form_factor_squared returns V^2 |F|^2, not the normalised |F|^2. SpherePopulation.intensity multiplies it by n * delta_rho^2 and nothing else, which is only correct because the volume is already in there.

Metadata

Release files for midas-saxs 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for midas-saxs 0.1.2
File Size Uploaded
midas_saxs-0.1.2.tar.gz 46.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for midas-saxs 0.1.2
File Interpreter ABI Platform
midas_saxs-0.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 85.0 kB

Release files / midas_saxs-0.1.2.tar.gz

Download URL midas_saxs-0.1.2.tar.gz
Size 46.6 kB
Tags Source
SHA-256 checksum
How to use checksums
684727e24c7c4adb92922e50fea7599959222a1f08b9f5c6a4733bfa0b026406
BLAKE2b-256 checksum
How to use checksums
ceb421fb01838821c12eeb9f118575f0c2f1520747fbf005758db0c9810fced3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.

Transparency log

Release files / midas_saxs-0.1.2-py3-none-any.whl

Download URL midas_saxs-0.1.2-py3-none-any.whl
Size 38.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4bf8c8897443f1dfd57d168f51ea2fe4d28a38e5946291a9cdb667c26d59a323
BLAKE2b-256 checksum
How to use checksums
908a1ddfc7a97e91c4bb3ab486ef32720056981a44ab9237b47efab97e4c142c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.

Transparency log

Release history Release notifications | RSS feed

0.2.0

2 release files

This release

0.1.2 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page