Skip to content

feat(optimizers): Add scipy-based FF optimizer#56

Merged
ericchansen merged 2 commits intomasterfrom
feat/scipy-optimizers
Mar 18, 2026
Merged

feat(optimizers): Add scipy-based FF optimizer#56
ericchansen merged 2 commits intomasterfrom
feat/scipy-optimizers

Conversation

@ericchansen
Copy link
Copy Markdown
Owner

Summary

Add q2mm.optimizers -- a scipy-based force field optimization framework built on the clean model layer and OpenMM backend.

What changed

New: q2mm/optimizers/ package

objective.py -- ObjectiveFunction class

  • Takes a ForceField, MM engine, molecules, and ReferenceData
  • Computes weighted sum-of-squares residuals between MM-calculated and reference data
  • Supports energy, frequency, bond length, and bond angle observables
  • Multi-molecule training sets with per-observation weights
  • Tracks evaluation count and score history for convergence analysis

scipy_opt.py -- ScipyOptimizer class

  • Wraps scipy.optimize.minimize and scipy.optimize.least_squares
  • Methods: L-BFGS-B (default), Nelder-Mead, Powell, trust-constr, least_squares (LM/TRF)
  • Auto-bounds from ForceField.get_bounds() for bounded methods
  • Tuned finite-difference step size (eps=1e-3) -- scipy's default ~1e-8 produces sub-precision energy changes for FF parameter magnitudes
  • Returns OptimizationResult with success flag, scores, history, and human-readable summary

Modified: q2mm/models/forcefield.py

  • Added get_bounds() method returning (min, max) tuples matching the param vector layout
  • Chemical constraints: force constants >= 0, distances > 0, angles in [60, 180]

Testing

  • 18 new integration tests covering all optimizer methods and data types
  • L-BFGS-B, Nelder-Mead, least_squares all successfully recover known parameters
  • Multi-parameter water test (bond k, r0, angle k, theta0) with frequency fitting
  • Full suite: 113 passed, 22 skipped, 1 xfailed
  • Validation harness: 4 passed, 0 failed, 2 blocked (unchanged)
  • Ruff lint + format: clean

Design notes

The key insight for scipy integration with MM force fields: scipy's default finite-difference step for gradient estimation (~1e-8) is far too small for FF parameters with magnitudes of ~0.5-10. A step of 1e-3 reliably produces meaningful energy differences through the OpenMM evaluation pipeline. This is set via the eps parameter and passed as options['eps'] for minimize or diff_step for least_squares.

ericchansen and others added 2 commits March 18, 2026 14:29
Introduce q2mm.optimizers package with ObjectiveFunction, ReferenceData,
and ScipyOptimizer wrapping scipy.optimize.minimize and least_squares.

- ObjectiveFunction: weighted sum-of-squares over energy, frequency,
  and geometry reference data with multi-molecule support
- ScipyOptimizer: L-BFGS-B, Nelder-Mead, Powell, trust-constr, and
  Levenberg-Marquardt with auto-bounds from ForceField.get_bounds()
- Tuned finite-difference step size (eps=1e-3) for FF parameter
  magnitudes where scipy defaults produce sub-precision changes
- 18 integration tests covering all methods and data types

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix critical: DetectedAngle.angle → .value (AttributeError crash)
- Fix geometry refs: use engine.minimize() so bond/angle observables
  respond to FF parameter changes instead of being constant
- Fix silent failure: raise IndexError for out-of-range data_idx
- Fix API trap: make data_idx required for frequency/bond/angle refs
- Fix method options: per-method tolerance mapping (Powell ftol/xtol,
  Nelder-Mead fatol/xatol, trust-constr gtol)
- Fix history: residuals() now tracks n_eval and history for
  least_squares convergence analysis
- Improve bounds: configurable via overrides dict, wider defaults
  for angles (30-180°) and vdW epsilon (0.001-2.0)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@ericchansen ericchansen merged commit ac2c403 into master Mar 18, 2026
6 checks passed
@ericchansen ericchansen deleted the feat/scipy-optimizers branch March 18, 2026 19:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant