User guide¶
Defining a grey-box problem¶
A problem is a Pyomo ConcreteModel plus an efmap.
Black boxes. Each black-box output is a Python function wrapped in
pyomo.environ.ExternalFunction. It is called with floats and returns one
float. A black box with several outputs has one function per output. Call
each function in a constraint that links it to an output variable:
m.bb_conv = ExternalFunction(conversion) # conversion(T, tau) -> float
m.bb_sel = ExternalFunction(selectivity)
m.link_conv = Constraint(expr=m.conv == m.bb_conv(m.T, m.tau))
m.link_sel = Constraint(expr=m.sel == m.bb_sel(m.T, m.tau))
Inputs. The arguments of a black-box call must be distinct, unfixed variables with finite bounds. For a constant, a parameter or an expression, introduce a bounded variable and constrain it to that value.
efmap. efmap groups the functions by black box: {name: [functions]}.
For example:
efmap = {"reactor": [m.bb_conv, m.bb_sel], "flash": [m.bb_split]}
Every function that the model calls must appear exactly once in efmap. The
error of a black box is the sum of the errors of its outputs. With the default
multiple_black_boxes=1, the solver tracks the error of each black box
separately. So give each independent black box its own entry, and group only
the outputs that really come from one model. On the quick start, the two
functions as separate black boxes reach the optimum. Grouped as one black
box, the run stops early at f = 2.20 instead of 1.53.
Bounds. By default (scaling=0), the trust region is measured in units of
each variable’s bound range, so every unfixed variable needs finite bounds.
With scaling=1, only the black-box inputs need bounds, and trust_radius is
in the variables’ own units.
Objective. The model needs exactly one active objective. It may minimise or maximise. Results are reported in the objective’s own sense.
Expensive outputs that share one simulation. The solver calls each output
function separately. If several outputs come from one expensive simulation,
cache the simulation in your own code (for example with
functools.lru_cache on the inputs), so it runs once per point.
Choosing a configuration¶
The default is A-TRFu: a funnel, the hypervolume sampling region and restoration R1. Four switches select the components, and presets name the common combinations:
preset |
|
|
|
|
|---|---|---|---|---|
|
1 funnel |
1 per-black-box errors, hypervolume |
1 |
1 (R1) |
|
1 |
1 |
1 |
2 (R2) |
|
1 |
0 one aggregate error |
1 |
1 |
|
1 |
1 |
0 |
1 |
|
0 filter |
1 |
1 |
1 |
TrustRegionSolver(preset="filter", max_it=300) # explicit options override the preset
Start with the default. The other presets are mainly for comparison. On the quick start, they stall or stop before the optimum.
Reading the result¶
solve returns a dict and leaves the final point in the model’s variables.
key |
meaning |
|---|---|
|
exit status (next section) |
|
|
|
objective at the final point, in the model’s sense |
|
infeasibility: 1-norm of true black-box outputs minus output variables |
|
criticality measure at the final point (small near a stationary point) |
|
index of the final iterate |
|
true black-box evaluations, total and per black box |
|
calls answered from the evaluation cache ( |
|
accepted objective steps, accepted feasibility steps, rejected steps |
|
restoration phases entered, restoration subproblems solved, rejected restoration iterations |
|
run time |
|
problem size (x = black-box inputs, y = outputs, z = others) |
|
constraint multipliers, with |
|
per iterate, from the starting point (iteration 0): |
Exit statuses¶
status |
meaning |
|---|---|
|
feasible, |
|
feasible and the last step was shorter than |
|
feasible, but the trust region shrank to |
|
|
|
R2 restoration reached |
|
subproblems kept failing at the smallest radius and the radius resets were used up |
With verbose=2 (the default), the log shows each iteration and each
restoration step. verbose=1 prints only the banner and the summary, and
verbose=0 prints nothing.