Optimisation¶
numgeo-ACT provides four supported, derivative-free strategies. All minimise
the same configured objective function, honour the
model bounds and use the reporting pipeline selected by globals.setup(...).
Choosing an optimiser¶
| Strategy | Best suited to | Budget meaning | Dependencies |
|---|---|---|---|
| DEEM | global search in rugged, multimodal spaces | maxiter generations; each generation evaluates a population |
bundled; NumPy/SciPy stack |
| IPOP-CMA-ES | rugged continuous problems with coupled parameters | max_evaluations is a strict total objective-evaluation budget |
bundled; NumPy only |
| SMAC-style SMBO (Bayesian optimisation) | expensive simulations where the number of real evaluations must be limited | max_evaluations is a strict total objective-evaluation budget |
bundled NumPy surrogate; optional scikit-learn |
| Local pattern search | deterministic refinement of a credible starting point, especially in low dimensions | max_evaluations is a strict total objective-evaluation budget |
bundled; NumPy only |
Budgets are not directly interchangeable
DEEM.optimize(maxiter=80) means 80 population generations, not 80 numgeo
evaluations. CMAES.optimize(max_evaluations=240),
SMAC.optimize(max_evaluations=240) and local.optimize(max_evaluations=240)
each permit at most 240 parameter-set
evaluations in total. Compare
algorithms by reported objective evaluations and wall time, not by the
numeric setting alone.
DEEM¶
Differential Evolution with Elitism and Multi-populations is the default global optimiser. It preserves strong candidates while several sub-populations explore the bounded parameter space. This makes it the safest starting choice when the objective is discontinuous, contains failed-simulation penalties or has several basins of attraction.
from ACT import DEEM
DEEM.optimize(
maxiter=200,
n_cpu=8,
nparticles_max=100,
nparticles_min=100,
npop_max=4,
npop_min=4,
exit_iter=100,
tolerance=1.0e-4,
sampling="LHS",
termination="tolerance",
)
The most important cost controls are the population size, number of generations and selected tests. A large population provides global coverage but may be too expensive when each candidate requires many finite-element calculations.
Algorithm reference
Machaček, J., Siegel, S. & Zachert, H. (2025). DEEM: Differential Evolution with Elitism and Multi-populations. Swarm and Evolutionary Computation, 92, 101818. doi:10.1016/j.swevo.2024.101818
Theory and stand-alone API: DEEM documentation · source repository
IPOP-CMA-ES¶
CMA-ES adapts the scale, direction and correlation of a population as the search progresses. It is useful when several model parameters act together and the objective is too rough for a surrogate model. Because it only uses the ranking of the candidates, failed simulations (penalty 1000) do not distort the search. IPOP restarts the search with a larger population after stagnation; this only pays off for large budgets, see below.
The implementation is part of ACT and uses only NumPy. It evaluates each population through the same process pool as the other lightweight optimisers. Candidates that violate the model's parameter constraints (for example the Hardening Soil stiffness ratios) are redrawn from the current search distribution before anything is evaluated, so the budget is spent on simulations rather than on known penalties.
from ACT import CMAES
result = CMAES.optimize(
max_evaluations=600,
n_cpu=4,
population_size=None,
initial_step=0.3,
restarts=0,
population_multiplier=2,
exit_iter=None,
tolerance=1.0e-5,
random_state=0,
)
| Argument | Default | Meaning |
|---|---|---|
max_evaluations |
600 |
strict total objective-evaluation budget, including the current parameter vector |
n_cpu |
1 |
number of worker processes used to evaluate a population |
population_size |
None |
population \(\lambda\); 4 + floor(3*log(n)) for \(n\) free parameters |
initial_step |
0.3 |
initial standard deviation as a fraction of every parameter range |
restarts |
0 |
maximum number of increasing-population restarts |
population_multiplier |
2 |
population growth factor at each restart |
exit_iter |
None |
evaluations without improvement of the current run's best value before a restart (or the stop after the final restart); None selects \(10\lambda + 30n\) |
tolerance |
1e-5 |
minimum width of the search distribution in normalised coordinates |
random_state |
0 |
seed controlling all sampled populations and restart locations |
Choose population_size as a multiple of n_cpu: a population of 10 on six
workers needs two pool rounds with four idle workers in the second, whereas 12
costs the same wall-clock time per generation and evaluates more candidates.
For the supplied eight-parameter Hardening Soil problem, 1000–1200 evaluations
with population_size=12 and the default patience are a good starting point.
Keep initial_step near 0.3 when the initial values are uncertain. Reduce it
to 0.1 or 0.15 when the starting values already describe the soil reasonably
well.
Leave restarts=0 unless the budget clearly exceeds about 150 evaluations per
free parameter. A restart begins at a random point with the initial step size
and needs several hundred evaluations before it can compete with the first
run; with a smaller budget a single run always uses the evaluations better.
exit_iter should never be much smaller than the default: CMA-ES regularly
goes 10–20 generations without improving its best-ever value while it adapts
the covariance, and stopping earlier discards a run that is still converging.
CMA-ES usually needs more evaluations than a successful SMAC run. Its advantage is that it does not need a smooth objective and learns correlations between parameters. DEEM remains the broader population method when extensive global exploration is affordable.
Algorithm reference
Hansen, N. (2016, revised 2023). The CMA Evolution Strategy: A Tutorial. arXiv:1604.00772
SMAC-style sequential model-based optimisation¶
The ACT.SMAC backend is an independent, compact implementation inspired by
the SMAC family of sequential model-based algorithms. It is not the external
SMAC3 package. It evaluates an initial space-filling design, fits a surrogate to
the observed objective and proposes bounded points using expected improvement.
This is the Bayesian-optimisation option in ACT and targets the user case in
which a numgeo evaluation is much more expensive than fitting the surrogate.
from ACT import SMAC3 is retained as a compatibility alias to ACT.SMAC; it
does not import or claim compatibility with the external SMAC3 package.
from ACT import SMAC
result = SMAC.optimize(
max_evaluations=240,
n_cpu=4,
init_points=None,
exit_iter=80,
tolerance=1.0e-4,
random_state=0,
surrogate="auto",
n_candidates=4096,
exploration=0.01,
)
Failed simulations return the penalty 1000, three orders of magnitude above typical objective values. Such values are kept in the history but replaced by the worst successful value before the surrogate is fitted; otherwise the model's uncertainty peaks along the boundary between feasible and failed parameter sets and expected improvement keeps proposing points there instead of refining the best one. Points that violate the model's parameter constraints are removed from the initial design and from the acquisition candidates before any simulation starts.
| Argument | Default | Meaning |
|---|---|---|
max_evaluations |
240 |
strict total objective-evaluation budget, including the current parameter vector and initial design |
n_cpu |
1 |
spawned worker count; it also caps later acquisition batches, while the initial design is queued through the same pool |
init_points |
None |
initial design size; max(12, 4n+1) for \(n\) free parameters, capped by the budget |
exit_iter |
80 |
stop after this many evaluations without a material improvement; initial-design points after the current vector are included |
tolerance |
1e-4 |
scale-relative improvement threshold used by exit_iter, relative to the larger absolute objective magnitude before and after a decrease |
random_state |
0 |
seed controlling the initial design and acquisition candidates |
surrogate |
'auto' |
use scikit-learn Extra Trees when available, otherwise the bundled NumPy Gaussian process |
n_candidates |
4096 |
bounded acquisition candidates considered per proposal step |
exploration |
0.01 |
dimensionless expected-improvement offset, multiplied internally by the standard deviation of the successful objective values; values above about 0.02 make the search drift away from the incumbent late in the run |
Settings for a difficult soil calibration¶
The former 80-evaluation default was too small for a typical calibration with six to ten free parameters. It also stopped after only 15 unsuccessful trials. The current defaults use a broader initial design and a longer patience interval. They are the middle row below.
For an eight-parameter problem such as the supplied Hardening Soil example, use these values as a starting point:
| Purpose | max_evaluations |
init_points |
exit_iter |
n_candidates |
exploration |
|---|---|---|---|---|---|
| Check the setup and obtain a rough result | 160 | 25 | 50 | 2048 | 0.0 |
| Normal calibration | 240 | 33 | 80 | 4096 | 0.01 |
| Rugged response with several plausible basins | 600 | 41 | 160 | 8192 | 0.02 |
The rugged setting is used in the
SMAC example. Do not
increase every value at once. First increase max_evaluations and
exit_iter. Increase init_points when the search repeatedly settles in very
different regions.
Surrogate-based optimisation pays off while the number of evaluations is small, roughly below 30–50 per free parameter. Beyond that the surrogate adds several seconds per batch without proposing better points than CMA-ES or DEEM would with the same budget; a budget of several thousand evaluations is better spent on CMA-ES.
surrogate="auto" selects Extra Trees when scikit-learn is already installed.
That model is usually the better SMAC choice for a rough or discontinuous
response. The bundled NumPy Gaussian process assumes a smoother response and
is mainly useful when no other surrogate is available. Set the backend
explicitly when two computers must follow the same search path:
SMAC.optimize(surrogate="sklearn", random_state=0) # Extra Trees
SMAC.optimize(surrogate="numpy", random_state=0) # bundled fallback
Run at least two seeds before drawing conclusions from a difficult global search. If most trials return the same penalty, or small parameter changes cause abrupt jumps, the surrogate has too little useful structure to learn. DEEM or CMA-ES is then the safer global method. Pattern search is appropriate only after a credible parameter set has been found.
The complete initial design is always evaluated. If its post-starting-point
evaluations exhaust exit_iter, the optimiser stops before fitting a
surrogate. After that, patience is checked only when a complete acquisition
batch returns. A parallel batch can therefore exceed the requested patience
count by at most n_cpu - 1 evaluations, while max_evaluations remains a
strict upper bound.
An explicit surrogate="sklearn" requires scikit-learn and fails clearly if it
is absent. The optimiser never installs or downloads it.
All three lightweight backends accept maxiter= as a compatibility alias for
max_evaluations=, but new drivers should use max_evaluations to avoid
confusion with DEEM generations. Supplying both names is rejected.
A surrogate can misrepresent a highly discontinuous objective or a search space dominated by penalty plateaus. Always inspect the final curves rather than accepting the lowest objective value on its own.
Local pattern search¶
The local backend searches positive and negative coordinate directions in a normalised bounded space and reduces the step after an unsuccessful poll. It is deterministic and well suited to refining literature parameters, an earlier ACT result or the result of a smaller global search.
from ACT import local
result = local.optimize(
max_evaluations=100,
n_cpu=4,
initial_step=0.2,
step_decay=0.5,
tolerance=1.0e-4,
)
| Argument | Default | Meaning |
|---|---|---|
max_evaluations |
100 |
strict total objective-evaluation budget |
n_cpu |
1 |
number of spawned workers used to evaluate coordinate directions |
initial_step |
0.2 |
initial step as a fraction of every parameter's bound range |
step_decay |
0.5 |
multiplier applied after an unsuccessful poll |
tolerance |
1e-4 |
minimum normalised step before termination |
Pattern search is not a global optimiser. With a poor starting point it can converge to a poor local minimum. Keep the bounds physically meaningful and use DEEM, CMA-ES or SMAC-style search first when the initial parameter set is uncertain.
Additional notes¶
All four backends support process workers with n_cpu > 1. CMA-ES, SMAC-style
and local search use the spawn method on every platform; DEEM uses the
platform multiprocessing default, which is spawn on Windows. Always put model
construction, globals.setup(...) and the optimiser call inside the guarded
run_calibration() shown in the Quickstart.
A worker importing the driver must not repeat model setup or prepare the same
output directories.
Legacy Bayesian entry point
Existing drivers may continue to call ACT.bayesian.optimize(...). It is
now a deprecated compatibility wrapper around ACT.SMAC, so it needs no
bayesian-optimization package and uses the current ACT
objective, bounds and reporting pipeline. New code should import
ACT.SMAC directly. Legacy third-party constraint and bounds-transformer
options are rejected because they cannot be translated safely.
Result object and audit trail¶
CMA-ES, SMAC-style and local runs return a CalibrationResult containing the best
parameter vector, objective, evaluation count, termination message and output
paths. Each run writes its comparison data, plots and history to
<model.out_dir>/<report-stem>/ and the matching raw final numgeo files to
<model.out_dir3>/<report-stem>/. result_directory and final_directory
identify those locations. The result directory contains final comparison data,
figures, fitness_function.png and
<report-stem>-optimization-history.csv; each timestamped PDF embeds that
run's convergence plot. The PDF, text log and terminal transcript themselves
are written directly under globals.setup(path=...); result_directory alone
is not a complete run archive. DEEM records its population history through its
existing reporting pipeline.
Only one lightweight optimiser may use a given globals.setup(path=...)
directory at a time. A second overlapping CMA-ES, SMAC or local run fails
clearly instead of mixing results. Use a separate working path for concurrent
calibrations.
Regardless of backend, always record:
- free and fixed parameters and their bounds;
- selected tests, weights and similarity measure;
- optimiser settings and random seed where applicable;
- objective evaluations, wall time and failed-evaluation penalties;
- the final simulation-versus-experiment plots.
Continue with Weighting to define the calibration priorities.