Measure Forward/Inverse Performance#

The benchmark module measures the throughput (operations per second) and round-trip accuracy of forward() and inverse() across all preset geometries and their declared diffraction modes.

Run the benchmark#

From the command line:

python -m ad_hoc_diffractometer.benchmark

From Python:

from ad_hoc_diffractometer.benchmark import benchmark_all, benchmark_geometry

# All geometries, all modes
results = benchmark_all()

# Single geometry
results = benchmark_geometry("fourcv")

The output is a formatted table:

geometry   mode                     status       fwd ops/s  inv ops/s  fwd/inv  round-trip err  solns
fourcv     bisecting                ok               3,241     18,502   0.1752        4.70e-13     11
fourcv     fixed_chi                ok               2,890     18,102   0.1596        3.40e-14     21
fourcv     fixed_psi                no_solutions      8,780          -       -               -      0

Output columns#

Column

Description

geometry

Preset geometry name

mode

Diffraction mode name

status

ok, no_solutions, not_implemented, or error

fwd ops/s

forward() operations per second

inv ops/s

inverse() operations per second

fwd/inv

forward_ops / inverse_ops — workstation-independent efficiency ratio. Higher is better. Since inverse() is a single direct computation, its speed characterizes the machine; the ratio measures algorithmic efficiency of the forward solver.

round-trip err

Maximum ‖hkl − inverse(forward(hkl))‖∞

solns

Total solutions returned across all test reflections

Status values#

  • okforward() returned at least one solution; inverse() round-tripped successfully.

  • no_solutionsforward() returned no solutions for any of the test reflections. This is expected for some geometry+mode+reflection combinations (e.g. psi-constant modes where the target ψ does not match the natural value).

  • not_implemented — the mode’s solver is not yet implemented for this geometry. forward() raises NotImplementedError.

  • error — an unexpected exception occurred during setup or computation. The error message is included in the result dict.

Controlling the benchmark#

from ad_hoc_diffractometer.benchmark import benchmark_all

# Fewer iterations (faster, noisier timing)
results = benchmark_all(n_iter=10)

# Custom reflections
results = benchmark_all(reflections=[(1, 0, 0), (1, 1, 1)])

# Suppress table output
results = benchmark_all(verbose=False)

Factors that affect performance#

Number of solutions. Some geometry+mode combinations produce many valid solutions (e.g. double_diffraction on a six-circle geometry can return dozens). Each solution requires inverse verification, so modes with more solutions are slower per forward() call.

Geometry complexity. Six-circle geometries have three free degrees of freedom after the Bragg condition, requiring a three-dimensional search. Four-circle geometries have one free DOF and are correspondingly faster.

Kappa geometries. The virtual-angle solver for kappa geometries uses a Newton–Raphson iteration that adds overhead compared to direct Eulerian solutions.

inverse() is fast. inverse() performs a single matrix solve (UB⁻¹ @ Q_phi) regardless of geometry complexity — it does not enumerate solutions. Typical throughput is 5,000–20,000 ops/sec.

Result dict structure#

Each result is a Python dict with the following keys:

{
    "geometry": "fourcv",
    "mode": "bisecting",
    "status": "ok",
    "forward_ops_per_sec": 3241.0,
    "inverse_ops_per_sec": 18502.0,
    "forward_inverse_ratio": 0.1752,
    "round_trip_max_error": 4.7e-13,
    "n_reflections": 5,
    "n_solutions": 11,
    "error_message": None,
}

See also#