Skip to content

Beam-center finder from I(Q) stops before converging #749

Description

@SimonHeybrock

beam_center_from_iofq passes its tolerance argument (default 0.1) straight to scipy.optimize.minimize as tol. For the default minimizer, Nelder-Mead, scipy maps tol onto xatol and fatol. xatol = 0.1 means 0.1 m in the search coordinates, which is larger than the region being searched, so the minimizer stops almost immediately and returns a barely-perturbed center-of-mass estimate.

Evidence

SANS2D tutorial data, against the MANTID_BEAM_CENTER reference used by the skipped tests in sans2d_reduction_test.py. Center of mass is [0.09007, -0.08264, 4], Mantid is [0.09288, -0.08195, 4].

tolerance cost evaluations result deviation from Mantid vertical shift from center of mass
0.1 (default) 14 [0.09458, -0.08264, 4] 1.83 mm 0.000 mm
0.01 20 [0.09445, -0.08184, 4] 1.57 mm 0.803 mm
0.001 39 [0.09425, -0.08234, 4] 1.42 mm 0.302 mm
0.0001 59 [0.09423, -0.08230, 4] 1.40 mm 0.336 mm

The last column is the clearest symptom: at the default tolerance the vertical coordinate comes back bit-identical to the center-of-mass estimate. That half of the refinement never runs.

Why it goes unnoticed

The center-of-mass initial guess is good, so the answer is roughly right either way, and the existing 2 mm test tolerance passes without the refinement doing anything.

There is a second, related fragility. Nelder-Mead sizes its initial simplex relative to x0, so the search step is whatever the magnitude of the initial guess happens to be rather than a deliberate choice. A beam center near the nominal axis therefore gets a much smaller search than one far from it, and an initial guess of exactly zero degenerates.

Not simply a different default

scipy maps tol per method, so no single value is correct across the minimizer argument:

  • Nelder-Mead: xatol and fatol, absolute, in metres and in cost units respectively.
  • Powell: xtol and ftol, relative.

The user guide's manual walk-through of the algorithm uses Powell with tol=0.01 and lands on a different value than the workflow does. The notebook attributes this to the different initial guess; the differing meaning of tol is plausibly also involved.

Suggested direction: set the scipy options explicitly for the chosen method, with a search scale derived from the problem (pixel size, or a fraction of the detector extent) instead of inherited from |x0|.

Notes

Present on main; found while reviewing #729 but independent of it. Not a duplicate of #401, which is about the cost of each evaluation rather than how many are performed. Resolving this looks like a prerequisite for un-skipping the beam-center tests in sans2d_reduction_test.py.

The 0.1 predates the current code: it was hard-coded when the module was first imported, and commit 74bbf86 only turned it into an overridable BeamCenterFinderTolerance parameter. That parameter type has since been removed, so the or 0.1 fallback is now the only value, with no way to set it from the workflow.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    esssansIssues for esssans.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions