optimize_submit
Search bounded design variables or geometry until constraints pass, then report whether the result is proven, not merely converged. Closes the design-to-spec loop.
Instructions
Vary parameters until the spec is met, then say whether it was PROVEN — the step that closes the design-to-spec loop.
Everything else in this family measures; this searches. Two things make it different from a generic minimizer, and both come from the performance-contract layer underneath it:
A constraint verdict has three states. indeterminate — the measurement's
uncertainty band straddles the limit — is NOT a failed step. An optimizer that reads
it as a failure walks away from good designs; one that reads it as a pass converges
on unproven ones. During the search an indeterminate constraint is scored on its
nominal value, so it neither attracts nor repels, and the winner is proved properly
at the end.
Convergence is not proof. A simplex can settle on a point that clears its limit
by 2 % while its own grid-convergence band is 5 % wide — noise with a favourable
sign. proven is therefore reported separately from converged, and is True only
when the final measurement has every constraint at pass and no margin swallowed by
its own band.
variables must be continuous and bounded — {"name": "diameter_mm", "min": 5, "max": 25, "start": 10}. An optimizer without a box walks to values that satisfy the
arithmetic and mean nothing physically.
objective and each constraints entry use the performance-requirement mapping
({tool, metric, conditions, limit, screen, band_pct}), with "$<variable>" in
conditions carrying the candidate's value. tier='auto' searches cheaply on each
block's screen estimator, then polishes on the real tool from where the screen
landed; 'screen' or 'solver' runs just that leg.
The search is a bounded Nelder-Mead — derivative-free because there is no adjoint
through a CFD solve — so every evaluation is a real measurement. budget
({max_evals, max_wall_s}, default 40 evaluations) is the ceiling; revisited points
are served from cache and do NOT count against it.
Shape optimization. Pass a recipe (+ fixed_inputs) and it is rebuilt for
every candidate, so the search varies GEOMETRY rather than only numbers —
"$handle" in a response's conditions is that candidate's part, and the returned
history carries the handle each point built. Pass handle instead to optimize
parameters against one fixed part; pass neither and the search is purely parametric.
Geometry-driven candidates are built on the MAIN thread through the worker's
work queue, because FreeCAD's document API is not thread-safe and this search runs
as a background job. That queue is drained once per incoming request, so a shape
search only advances while you are polling job_status/job_result — the poll
you must do anyway is what gives it its turn. Poll at your normal cadence and it
simply works; stop polling and it stalls rather than finishing in the background.
A candidate whose recipe fails to build is scored out as an infeasible point, not
an error. study_submit remains the right tool for a FIXED grid over recipe
geometry, which needs no queue at all.
Returns {job_id, status}; poll job_result for {ok, proven, stop_reason, best_params, best_value, objective: {name, metric, sense, value, band_pct}, constraints: [{name, state, measured, limit, band_pct, margin, margin_pct, detail, trust_reasons?}], phases: [{tier, n_evals, best_params, best_value, converged, reason}], history: [{i, tier, params, value, score, feasible, cached}], n_evals, n_cached, budget, variables, warnings}.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| tier | No | auto | |
| budget | No | ||
| handle | No | ||
| recipe | No | ||
| objective | Yes | ||
| variables | Yes | ||
| constraints | No | ||
| fixed_inputs | No |