Parameter estimators¶
Optimizer and sampler schemas used inside DataFit (also available as
the ionworks.pipeline.optimizers alias).
Schemas for parameter_estimators.
- class ionworks.pipeline.parameter_estimators.AskTellOptimizer(method='CMAES', log_to_screen=False, sigma0=None, max_iterations=None, max_unchanged_iterations=None, max_unchanged_iterations_threshold=None, min_iterations=1, max_evaluations=1000000, population_size=None, threshold=None, absolute_tolerance=1e-05, relative_tolerance=0.01, xtol=1e-06, population_convergence_tol=0.005, flat_fitness_tol=None, convergence_patience=3, surrogate_convergence_tol=0.001, algorithm_options=None, type='AskTellOptimizer')[source]¶
Bases:
_AskTellBaseAsk/tell optimizer for population-based and simplex optimization.
Supports CMAES, PSO, DifferentialEvolution, XNES, Nelder-Mead, BayesianOptimization, SOBER, and TuRBO.
- Parameters:
method (str, optional) – Optimization method. Default is “CMAES”. Must be one of: “CMAES”, “Nelder-Mead”, “PSO”, “DifferentialEvolution”, “XNES”, “BayesianOptimization”, “SOBER”, or “TuRBO”.
log_to_screen (bool, optional) – Whether to print optimization progress. Default is False.
sigma0 (float | np.ndarray, optional) – Initial step size for population-based methods. Default is None.
max_iterations (int, optional) – Maximum number of iterations. Default is 300.
max_unchanged_iterations (int, optional) – Stop after this many iterations without improvement. Default is 75.
max_unchanged_iterations_threshold (float, optional) – Legacy alias for
absolute_tolerance. Preferabsolute_toleranceon new code.min_iterations (int, optional) – Minimum iterations before checking stopping criteria. Default is 1.
max_evaluations (int, optional) – Maximum number of function evaluations. Default is 1e6.
population_size (int, optional) – Population size for population-based methods. Default is method-specific.
threshold (float, optional) – Target objective value to stop optimization. Default is None.
absolute_tolerance (float, optional) – Absolute tolerance for unchanged iterations. Default is 1e-5.
relative_tolerance (float, optional) – Relative tolerance for unchanged iterations. Default is 1e-2.
xtol (float, optional) – Parameter change tolerance (L-inf norm). Default is 1e-6.
population_convergence_tol (float, optional) – Population convergence tolerance. The exact convergence semantics are algorithm-dependent (e.g. DE also checks position-space diversity). Default is 5e-3.
flat_fitness_tol (float, optional) – Flat fitness tolerance. Default is None (disabled).
convergence_patience (int, optional) – Number of consecutive generations the population convergence check must pass before actually stopping. Default is 3.
surrogate_convergence_tol (float, optional) – Relative tolerance on the model-native convergence signal for surrogate algorithms (BO, SOBER). Fires when the expected improvement at the algorithm’s best candidate is below
toltimes the range of observed costs forconvergence_patienceconsecutive iterations. Default 1e-3. Set toNoneto disable.algorithm_options (dict, optional) –
Algorithm-specific configuration options. For PSO, supported keys are:
inertia_weight: tuple[float, float] - (w_start, w_end) for linear decay. Enables inertia mode and disables constriction.constriction: bool - Use constriction coefficient (default: True)c1: float - Cognitive coefficient (default: 2.05)c2: float - Social coefficient (default: 2.05)boundary_handling: str | BoundaryHandling - “absorb”, “reflect”, “random”, “ignore”velocity_clamping: str | VelocityClamping - “none”, “fraction”, “adaptive”v_max_fraction: float - Fraction of search space for max velocity (default: 0.2)max_iterations: int - For adaptive parameter scheduling (default: 1000)
**kwargs – Additional arguments for the AskTellOptimizer constructor.
Notes
"CMAES"(default) is robust."DifferentialEvolution"(small population, many generations) makes the most progress per evaluation on cheap objectives with many parameters;"BayesianOptimization"is the most sample-efficient for a small budget of expensive ones with ten or fewer;"TuRBO"suits wide parallel batches or high-dimensional constrained problems (TuRBOOptionsn_initial= batch width)."SOBER"estimates by quadrature. The engine owns parallelism.Examples
>>> opt = iw.pipeline.parameter_estimators.AskTellOptimizer( ... method="CMAES", max_iterations=200, ... ) >>> fit = iw.pipeline.DataFit( ... objectives={"ocp": iw.pipeline.objectives.OCPHalfCell( ... electrode="positive", data_input="path/to/ocp.csv", ... )}, ... parameters={ ... "x": iw.pipeline.Parameter("x", initial_value=1.0, bounds=(0.0, 2.0)) ... }, ... optimizer=opt, ... )
- algorithm_options: dict | CMAESOptions | PSOOptions | DEOptions | XNESOptions | BayesianOptimizationOptions | SOBEROptions | TuRBOOptions | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.BayesianOptimization(*, log_to_screen: bool | None = False, sigma0: float | int | list | tuple | None = None, max_iterations: int | None = None, max_unchanged_iterations: int | None = None, max_unchanged_iterations_threshold: float | int | None = None, min_iterations: int | None = 1, max_evaluations: int | None = 1000000, population_size: int | None = None, threshold: float | int | None = None, absolute_tolerance: float | int | None = 1e-05, relative_tolerance: float | int | None = 0.01, xtol: float | int | None = 1e-06, population_convergence_tol: float | int | None = 0.005, flat_fitness_tol: float | int | None = None, convergence_patience: int | None = 3, surrogate_convergence_tol: float | int | None = 0.001, type: Literal['BayesianOptimization'] = 'BayesianOptimization', algorithm_options: BayesianOptimizationOptions | None = None)[source]¶
Bases:
_AskTellBaseBayesian Optimization with a Gaussian-process surrogate.
Sample-efficient for expensive black-box objectives with fewer than ~30 parameters. Convenience wrapper around
AskTellOptimizer(method="BayesianOptimization"); seeAskTellOptimizerfor the full list of accepted kwargs and passalgorithm_options=iw.pipeline.parameter_estimators.BayesianOptimizationOptions(...)to configure the surrogate.Examples
>>> opt = iw.pipeline.parameter_estimators.BayesianOptimization() >>> fit = iw.pipeline.DataFit( ... objectives={"ocp": iw.pipeline.objectives.OCPHalfCell( ... electrode="positive", data_input="path/to/ocp.csv", ... )}, ... parameters={ ... "x": iw.pipeline.Parameter("x", initial_value=1.0, bounds=(0.0, 2.0)) ... }, ... optimizer=opt, ... )
- algorithm_options: BayesianOptimizationOptions | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.BayesianOptimizationOptions(*, n_initial: int | None = None, noise_floor: str | tuple[float, float] | list[float] | None = None)[source]¶
Bases:
_AlgorithmOptionsOptions for
AskTellOptimizer(method="BayesianOptimization").Any field left as
Nonefalls back to the Bayesian-optimization defaults set by the Ionworks pipeline. Strict (extra="forbid"): an unknown option key is rejected.- Parameters:
n_initial (int, optional) – Number of quasi-random warm-up evaluations before the surrogate model is first fitted.
None(default) usesmax(5, 2 * n_parameters + 1). Set it to the parallel evaluation capacity (e.g. the batch size on a cluster) so the warm-up round uses the full available width.noise_floor (str or tuple of (float, float), optional) – Constrain the objective-GP likelihood noise.
None(default) omits the key, so the pipeline default applies ("deterministic", i.e. noise constrained to(1e-8, 1e-3)— suited to deterministic simulator objectives). Pass"standard"to restore the uncapped default for genuinely noisy objectives;"low"/"deterministic"set the low interval explicitly; a(lo, hi)tuple sets a custom interval.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.CMAES(*, log_to_screen: bool | None = False, sigma0: float | int | list | tuple | None = None, max_iterations: int | None = None, max_unchanged_iterations: int | None = None, max_unchanged_iterations_threshold: float | int | None = None, min_iterations: int | None = 1, max_evaluations: int | None = 1000000, population_size: int | None = None, threshold: float | int | None = None, absolute_tolerance: float | int | None = 1e-05, relative_tolerance: float | int | None = 0.01, xtol: float | int | None = 1e-06, population_convergence_tol: float | int | None = 0.005, flat_fitness_tol: float | int | None = None, convergence_patience: int | None = 3, surrogate_convergence_tol: float | int | None = 0.001, type: Literal['CMAES'] = 'CMAES', algorithm_options: CMAESOptions | None = None)[source]¶
Bases:
_AskTellBaseCovariance Matrix Adaptation Evolution Strategy (CMA-ES).
A strong default for ill-conditioned, noisy, non-linear fits. Convenience wrapper around
AskTellOptimizer(method="CMAES"); seeAskTellOptimizerfor the full list of accepted kwargs.Examples
>>> opt = iw.pipeline.parameter_estimators.CMAES() >>> fit = iw.pipeline.DataFit( ... objectives={"ocp": iw.pipeline.objectives.OCPHalfCell( ... electrode="positive", data_input="path/to/ocp.csv", ... )}, ... parameters={ ... "x": iw.pipeline.Parameter("x", initial_value=1.0, bounds=(0.0, 2.0)) ... }, ... optimizer=opt, ... )
- algorithm_options: CMAESOptions | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.CMAESOptions(**extra_data: Any)[source]¶
Bases:
_AlgorithmOptionsOptions for
AskTellOptimizer(method="CMAES")passed through to pycma.Accepts any key valid for
cma.CMAOptions()— see pycma documentation for the full list. Common keys:CMA_diagonal,ftarget,CMA_stds,scaling_of_variables.This is a genuine passthrough leaf:
cma.CMAOptions()is the source of truth for the (large) option surface and rejects unknown keys at runtime, so this class keepsextra="allow"rather than enumerating dozens of pycma keys. It is on the strictness-guard allowlist for this reason.- model_config = {'arbitrary_types_allowed': True, 'extra': 'allow', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.DEOptions(*, mutation_strategy: str | None = None, crossover_method: str | None = None, F: float | None = None, CR: float | None = None, dither: bool | tuple[float, float] | list[float] | None = None, p_best_rate: float | None = None, archive_size_ratio: float | None = None, memory_size: int | None = None, boundary_handling: str | None = None)[source]¶
Bases:
_AlgorithmOptionsOptions for
AskTellOptimizer(method="DifferentialEvolution").Any field left as
Nonefalls back to the Differential-Evolution defaults set by the Ionworks pipeline.- Parameters:
mutation_strategy (str, optional) – One of
"rand_1","best_1","current_to_best_1","rand_2","best_2","current_to_pbest_1". Default"current_to_pbest_1"(SHADE adaptive).crossover_method (str, optional) – One of
"binomial","exponential". Default"binomial".F (float, optional) – Mutation scale factor; initial mean for SHADE adaptive sampling. Default 0.5.
CR (float, optional) – Crossover probability; initial mean for SHADE adaptive sampling. Default 0.7.
dither (bool or tuple of (float, float), optional) – Randomise
Fper generation when using classic strategies.Trueuses the default range[0.5, 1.0]. DefaultTrue.p_best_rate (float, optional) – Fraction of top individuals for pbest selection. Default 0.1.
archive_size_ratio (float, optional) – Archive size as a multiple of population. Default 1.0.
memory_size (int, optional) – Number of history entries for F/CR adaptation. Default equal to population size.
boundary_handling (str, optional) – Boundary handling strategy. Default
"reflect".
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.DifferentialEvolution(*, log_to_screen: bool | None = False, sigma0: float | int | list | tuple | None = None, max_iterations: int | None = None, max_unchanged_iterations: int | None = None, max_unchanged_iterations_threshold: float | int | None = None, min_iterations: int | None = 1, max_evaluations: int | None = 1000000, population_size: int | None = None, threshold: float | int | None = None, absolute_tolerance: float | int | None = 1e-05, relative_tolerance: float | int | None = 0.01, xtol: float | int | None = 1e-06, population_convergence_tol: float | int | None = 0.005, flat_fitness_tol: float | int | None = None, convergence_patience: int | None = 3, surrogate_convergence_tol: float | int | None = 0.001, type: Literal['DifferentialEvolution'] = 'DifferentialEvolution', algorithm_options: DEOptions | None = None)[source]¶
Bases:
_AskTellBaseDifferential Evolution (DE) with SHADE adaptive control.
Uses success-history based adaptive F/CR with current-to-pbest/1 mutation by default. Convenience wrapper around
AskTellOptimizer(method="DifferentialEvolution"). See AskTellOptimizer class for full parameter documentation.Examples
>>> opt = iw.pipeline.parameter_estimators.DifferentialEvolution() >>> fit = iw.pipeline.DataFit( ... objectives={"ocp": iw.pipeline.objectives.OCPHalfCell( ... electrode="positive", data_input="path/to/ocp.csv", ... )}, ... parameters={ ... "x": iw.pipeline.Parameter("x", initial_value=1.0, bounds=(0.0, 2.0)) ... }, ... optimizer=opt, ... )
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.DummyOptimizer(*, type: Literal['DummyOptimizer', 'Dummy'] = 'DummyOptimizer')[source]¶
Bases:
BaseSchemaAlias for
PointEstimateOptimizer.Returns the supplied initial guess without running any optimisation — useful as a no-op in tests and pipeline scaffolding.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.DummySampler(*, type: Literal['DummySampler'] = 'DummySampler')[source]¶
Bases:
BaseSchemaAlias for
PointEstimateSampler.Returns a single sample equal to the initial guess — useful as a no-op in sampling pipelines.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.GridSearch(npts=10, type='GridSearch')[source]¶
Bases:
BaseSchemaGrid search sampler.
Evaluates the objective at all combinations of grid points across dimensions — a deterministic, exhaustive sweep. Cost grows as
npts ** n_parameters; keep the parameter count small.- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.Nested(*, type: Literal['Nested'] = 'Nested', parameters: list[str], optimizer: DifferentialEvolution | CMAES | PSO | XNES | BayesianOptimization | SOBER | TuRBO | AskTellOptimizer | Nested | ScipyDifferentialEvolution | ScipyMinimize | ScipyLeastSquares | ScipyLsqLinear | ScipyBasinhopping | ScipyDualAnnealing | ScipyShgo | GridSearch | PointEstimateOptimizer | PointEstimateSampler | DummyOptimizer | DummySampler | PintsSampler, inner: DifferentialEvolution | CMAES | PSO | XNES | BayesianOptimization | SOBER | TuRBO | AskTellOptimizer | Nested | ScipyDifferentialEvolution | ScipyMinimize | ScipyLeastSquares | ScipyLsqLinear | ScipyBasinhopping | ScipyDualAnnealing | ScipyShgo | GridSearch | PointEstimateOptimizer | PointEstimateSampler | DummyOptimizer | DummySampler | PintsSampler)[source]¶
Bases:
BaseSchemaBi-level optimizer: an outer
optimizeroverparameterswrapping aninnerover the remaining parameters, which is run to optimality at each outer point (variable projection wheninneris least-squares).innermay itself be aNestedfor deeper nesting.Examples
>>> opt = iw.pipeline.parameter_estimators.Nested( ... parameters=["a", "b"], ... optimizer=iw.pipeline.parameter_estimators.CMAES(), ... inner=iw.pipeline.parameter_estimators.ScipyLeastSquares(), ... )
- optimizer: OptimizerUnion¶
- inner: OptimizerUnion¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.Optimizer[source]¶
Bases:
BaseSchemaBase class for all optimizers.
Optimisers seek a single optimal point in parameter space that minimises the objective. Not used directly — pick a concrete subclass such as
AskTellOptimizeror one of theScipy*wrappers.- Parameters:
**kwargs – Arguments passed to the underlying optimiser algorithm.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.PSO(*, log_to_screen: bool | None = False, sigma0: float | int | list | tuple | None = None, max_iterations: int | None = None, max_unchanged_iterations: int | None = None, max_unchanged_iterations_threshold: float | int | None = None, min_iterations: int | None = 1, max_evaluations: int | None = 1000000, population_size: int | None = None, threshold: float | int | None = None, absolute_tolerance: float | int | None = 1e-05, relative_tolerance: float | int | None = 0.01, xtol: float | int | None = 1e-06, population_convergence_tol: float | int | None = 0.005, flat_fitness_tol: float | int | None = None, convergence_patience: int | None = 3, surrogate_convergence_tol: float | int | None = 0.001, type: Literal['PSO'] = 'PSO', algorithm_options: PSOOptions | None = None)[source]¶
Bases:
_AskTellBaseParticle Swarm Optimization (PSO). Population-based optimiser inspired by bird-flocking behaviour.
Convenience wrapper around
AskTellOptimizer(method="PSO"); seeAskTellOptimizerfor the full list of accepted kwargs.Examples
>>> opt = iw.pipeline.parameter_estimators.PSO() >>> fit = iw.pipeline.DataFit( ... objectives={"ocp": iw.pipeline.objectives.OCPHalfCell( ... electrode="positive", data_input="path/to/ocp.csv", ... )}, ... parameters={ ... "x": iw.pipeline.Parameter("x", initial_value=1.0, bounds=(0.0, 2.0)) ... }, ... optimizer=opt, ... )
- algorithm_options: PSOOptions | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.PSOOptions(*, inertia_weight: tuple[float, float] | list[float] | None = None, constriction: bool | None = None, c1: float | None = None, c2: float | None = None, boundary_handling: str | None = None, velocity_clamping: str | None = None, v_max_fraction: float | None = None, max_iterations: int | None = None)[source]¶
Bases:
_AlgorithmOptionsOptions for
AskTellOptimizer(method="PSO").Any field left as
Nonefalls back to the PSO defaults set by the Ionworks pipeline.- Parameters:
inertia_weight (tuple of (float, float), optional) –
(w_start, w_end)for linear decay. When set, enables inertia mode and disables constriction.constriction (bool, optional) – Use constriction coefficient. Default
True(wheninertia_weightis not set).c1 (float, optional) – Cognitive coefficient (attraction to personal best). Default 2.05.
c2 (float, optional) – Social coefficient (attraction to global best). Default 2.05.
boundary_handling (str, optional) – One of
"absorb","reflect","random","ignore". Default"reflect".velocity_clamping (str, optional) – One of
"none","fraction","adaptive". Default"fraction".v_max_fraction (float, optional) – Fraction of search space for max velocity. Default 0.2.
max_iterations (int, optional) – Horizon used for adaptive parameter scheduling. Default 1000.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.ParameterEstimator[source]¶
Bases:
BaseSchemaBase class for all parameter estimators.
Parameter estimators find an optimal (or posterior) parameter set by minimising an objective. Not used directly — pick a concrete
OptimizerorSamplersubclass.- Parameters:
**kwargs – Arguments passed to the underlying estimation algorithm.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- ionworks.pipeline.parameter_estimators.PintsOptimizer¶
alias of
AskTellOptimizer
- class ionworks.pipeline.parameter_estimators.PintsSampler(method='DramACMC', log_to_screen=False, max_iterations=1000, burnin_iterations=None, initial_phase_iterations=None, type='PintsSampler')[source]¶
Bases:
BaseSchemaSampler using the Pints library: Probabilistic Inference for Bayesian Models.
Wraps Pints’ MCMCController class for MCMC sampling.
- Parameters:
method (str, optional) – Sampling method. Default is “DramACMC”. Must be one of: “DramACMC”, “HamiltonianMCMC”, “HaarioBardenetACMC”, “MALAMCMC”, “MetropolisRandomWalkMCMC”, “MonomialGammaHamiltonianMCMC”, “NoUTurnMCMC”, “PopulationMCMC”, “RelativisticMCMC”, “SliceDoublingMCMC”, “SliceRankShrinkingMCMC”, or “SliceStepoutMCMC”.
log_to_screen (bool, optional) – Whether to print information at runtime. Default is False.
max_iterations (int, optional) – Maximum number of iterations. Default is 1000.
burnin_iterations (int, optional) – Number of initial iterations to discard. Default is 10% of max_iterations.
initial_phase_iterations (int, optional) – Number of iterations in initial phase. Only used for methods that need an initial phase. Default is equal to burnin_iterations.
**kwargs – Additional parameters passed to the pints MCMC sampler. See pints documentation for details.
Notes
The log PDF values are cached internally to work around a pints limitation.
For methods that need an initial phase, initial_phase_iterations must not exceed burnin_iterations, which in turn must not exceed max_iterations.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.PointEstimateOptimizer(*, type: Literal['PointEstimateOptimizer', 'PointEstimate'] = 'PointEstimateOptimizer')[source]¶
Bases:
BaseSchemaNo-op optimiser — returns the initial guess unchanged.
Useful for evaluating a single parameter set or initialising pipelines without paying the cost of a real optimiser run.
Examples
>>> opt = iw.pipeline.parameter_estimators.PointEstimateOptimizer() >>> fit = iw.pipeline.DataFit( ... objectives={"ocp": iw.pipeline.objectives.OCPHalfCell( ... electrode="positive", data_input="path/to/ocp.csv", ... )}, ... parameters={ ... "x": iw.pipeline.Parameter("x", initial_value=1.0, bounds=(0.0, 2.0)) ... }, ... optimizer=opt, ... )
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.PointEstimateSampler(*, type: Literal['PointEstimateSampler'] = 'PointEstimateSampler')[source]¶
Bases:
BaseSchemaNo-op sampler — returns the initial guess as a single sample.
Useful for evaluating a single parameter set within a sampling-style pipeline without paying the cost of real MCMC.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.SOBER(*, log_to_screen: bool | None = False, sigma0: float | int | list | tuple | None = None, max_iterations: int | None = None, max_unchanged_iterations: int | None = None, max_unchanged_iterations_threshold: float | int | None = None, min_iterations: int | None = 1, max_evaluations: int | None = 1000000, population_size: int | None = None, threshold: float | int | None = None, absolute_tolerance: float | int | None = 1e-05, relative_tolerance: float | int | None = 0.01, xtol: float | int | None = 1e-06, population_convergence_tol: float | int | None = 0.005, flat_fitness_tol: float | int | None = None, convergence_patience: int | None = 3, surrogate_convergence_tol: float | int | None = 0.001, type: Literal['SOBER'] = 'SOBER', algorithm_options: SOBEROptions | None = None)[source]¶
Bases:
_AskTellBaseSOBER: batch Bayesian optimization via quadrature-style recombination.
Selects whole batches by Bayesian quadrature; strongest when the goal is quadrature-style estimation rather than pure optimization. Convenience wrapper around
AskTellOptimizer(method="SOBER"); seeAskTellOptimizerfor the full list of accepted kwargs and passalgorithm_options=iw.pipeline.parameter_estimators.SOBEROptions(...)to configure the surrogate.Examples
>>> opt = iw.pipeline.parameter_estimators.SOBER() >>> fit = iw.pipeline.DataFit( ... objectives={"ocp": iw.pipeline.objectives.OCPHalfCell( ... electrode="positive", data_input="path/to/ocp.csv", ... )}, ... parameters={ ... "x": iw.pipeline.Parameter("x", initial_value=1.0, bounds=(0.0, 2.0)) ... }, ... optimizer=opt, ... )
- algorithm_options: SOBEROptions | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.Sampler[source]¶
Bases:
BaseSchemaBase class for all Monte Carlo-style samplers.
Samplers explore parameter space to characterise the posterior, in contrast to optimisers which return a single best point. Not used directly — pick a concrete subclass such as
PintsSamplerorGridSearch.- Parameters:
**kwargs – Arguments passed to the underlying sampling algorithm.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.ScipyBasinhopping(*, type: Literal['ScipyBasinhopping'] = 'ScipyBasinhopping', **extra_data: Any)[source]¶
Bases:
_PassthroughOptimizerGlobal optimizer using basin-hopping with local minimization.
Basin-hopping alternates random perturbations of the current minimum, accepted or rejected by the Metropolis criterion, with local minimization from the new point.
Notes
Accepts initial guess x0 as the starting point for optimization
Local minimizer can be customized via minimizer_kwargs parameter
Stochastic algorithm (use seed parameter for reproducibility)
Constraintobjects are applied as a penalty on the costTemperature parameter controls acceptance of uphill moves (higher = more exploration)
- Parameters:
niter (int, default=100) – Number of basin-hopping iterations.
T (float, default=1.0) – Temperature parameter for the Metropolis acceptance criterion. Higher values increase the probability of accepting uphill moves.
stepsize (float, default=0.5) – Initial step size for random displacement of coordinates.
minimizer_kwargs (dict, optional) – Extra keyword arguments passed to the local minimizer (scipy.optimize.minimize). Can specify the local method, bounds, constraints, and convergence criteria. Default uses L-BFGS-B with provided bounds.
take_step (callable, optional) – Custom step-taking function. If None, uses random displacement.
accept_test (callable, optional) – Custom acceptance test function. If None, uses Metropolis criterion.
interval (int, default=50) – Interval for updating stepsize (adaptive step size adjustment).
seed (int, optional) – Random seed for reproducible results.
**kwargs – Additional arguments passed to scipy.optimize.basinhopping. See scipy documentation for complete options.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'allow', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.ScipyDifferentialEvolution(*, type: Literal['ScipyDifferentialEvolution'] = 'ScipyDifferentialEvolution', **extra_data: Any)[source]¶
Bases:
_PassthroughOptimizerGlobal stochastic optimizer using differential evolution with parallel evaluation.
Evolves a population of candidate solutions across generations; suited to multi-modal, non-convex landscapes and needs no gradient information.
Notes
Constraintobjects are applied as a penalty on the costInitial guess x0 is ignored; initial population is generated from bounds
Polish option disabled by default as it conventionally significantly decreases performance
Callback logs only best solution per generation (not individual evaluations)
workersparallelises evaluations within scipy’s DE loop; fit-level parallelism (multistarts, objectives) is managed by the execution engine
- Parameters:
workers (int, default=1) – Number of parallel workers for function evaluations. Use -1 for all CPU cores.
max_iterations (int, default=1000) – Maximum number of generations. Passed to scipy as
maxiter.population_size (int, default=15) – Population size multiplier (total population = population_size * dimensionality). Passed to scipy as
popsize.strategy (str, default='best1bin') – Differential evolution strategy. Options include ‘best1bin’, ‘rand1bin’, ‘best2bin’, ‘rand2bin’, ‘currenttobest1bin’.
mutation (float or tuple, default=(0.5, 1)) – Mutation constant. Can be float or (min, max) tuple for adaptive mutation.
recombination (float, default=0.7) – Crossover probability for parameter mixing.
seed (int, optional) – Random seed for reproducible results.
atol (float, optional) – Absolute and relative tolerance for convergence.
tol (float, optional) – Absolute and relative tolerance for convergence.
**kwargs – Additional arguments passed to scipy.optimize.differential_evolution. See scipy documentation for complete options.
Examples
>>> opt = iw.pipeline.parameter_estimators.ScipyDifferentialEvolution() >>> fit = iw.pipeline.DataFit( ... objectives={"ocp": iw.pipeline.objectives.OCPHalfCell( ... electrode="positive", data_input="path/to/ocp.csv", ... )}, ... parameters={ ... "x": iw.pipeline.Parameter("x", initial_value=1.0, bounds=(0.0, 2.0)) ... }, ... optimizer=opt, ... )
- model_config = {'arbitrary_types_allowed': True, 'extra': 'allow', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.ScipyDualAnnealing(*, type: Literal['ScipyDualAnnealing'] = 'ScipyDualAnnealing', **extra_data: Any)[source]¶
Bases:
_PassthroughOptimizerGlobal stochastic optimizer using dual annealing.
Dual annealing combines generalized simulated annealing with fast local search. It’s designed for global optimization with a good balance between exploration and exploitation, particularly effective for rugged objective landscapes.
Notes
Constraintobjects are applied as a penalty on the costAccepts optional initial guess x0 to seed the search
Stochastic algorithm (use seed parameter for reproducibility)
Good choice when gradient information is unavailable
- Parameters:
max_iterations (int, default=1000) – Maximum number of global search iterations. Passed to scipy as
maxiter.initial_temp (float, default=5230) – Initial temperature for the annealing schedule.
restart_temp_ratio (float, default=2e-5) – Temperature ratio for restart condition during local search.
visit (float, default=2.62) – Parameter for the visiting distribution (higher = more exploration).
accept (float, default=-5.0) – Parameter for the acceptance distribution (lower = more exploitation).
seed (int, optional) – Random seed for reproducible results.
no_local_search (bool, default=False) – If True, skip local minimization (pure generalized simulated annealing).
**kwargs – Additional arguments passed to scipy.optimize.dual_annealing. See scipy documentation for complete options.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'allow', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.ScipyLeastSquares(*, type: Literal['ScipyLeastSquares'] = 'ScipyLeastSquares', **extra_data: Any)[source]¶
Bases:
_PassthroughOptimizerNonlinear least squares optimizer using scipy’s Trust Region Reflective algorithm.
This optimizer is designed for problems where the objective returns a residual vector rather than a scalar cost. It minimizes the sum of squares of the residuals. Best suited for well-behaved, smooth problems with a clear residual structure.
Notes
Requires objective functions that return an array (residual vector)
Automatically handles linear algebra errors by returning NaN values
More efficient than general minimization for least-squares structure
Constraintobjects are applied as penalty residuals
- Parameters:
method (str, optional) – Algorithm to use. Options: ‘trf’ (default), ‘dogbox’, ‘lm’.
ftol (float, optional) – Tolerance parameters for convergence criteria.
xtol (float, optional) – Tolerance parameters for convergence criteria.
gtol (float, optional) – Tolerance parameters for convergence criteria.
max_nfev (int, optional) – Maximum number of function evaluations.
**kwargs – Additional arguments passed to scipy.optimize.least_squares. See scipy documentation for complete options.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'allow', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.ScipyLsqLinear(*, type: Literal['ScipyLsqLinear'] = 'ScipyLsqLinear', **extra_data: Any)[source]¶
Bases:
_PassthroughOptimizerBounded linear least-squares via scipy.optimize.lsq_linear.
Solves a bounded least-squares problem whose residual is linear in the fitted parameters, reaching the bounded optimum in a single solve (no Gauss-Newton iteration). Intended as the inner solver of a variable- projection / nested fit whose inner parameters enter the model linearly; for nonlinear residuals use
ScipyLeastSquares.- Parameters:
method (str, optional) –
scipy.optimize.lsq_linearmethod:'bvls'(default) or'trf'.jac_rel_step (float, optional) – Relative step for the finite-difference design matrix (default
1e-3); larger than a derivative step since the residual is assumed linear.warm_start (bool, optional) – Reuse the previous solve’s active set (default True) so the inner solve stays consistent across outer perturbations and the concentrated objective stays smooth; falls back to a cold solve when it is no longer optimal.
**kwargs – Additional arguments passed to
scipy.optimize.lsq_linear(e.g.tol,max_iter). See scipy documentation for complete options.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'allow', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.ScipyMinimize(*, type: Literal['ScipyMinimize'] = 'ScipyMinimize', **extra_data: Any)[source]¶
Bases:
_PassthroughOptimizerGeneral-purpose scalar minimization.
Wraps scipy’s minimize local optimization algorithms (e.g., L-BFGS-B, Powell, SLSQP, trust-constr, COBYQA).
Notes
Requires objective functions that return a scalar value
Constraintobjects are applied as a penalty on the cost for everymethod, never as scipyconstraints=
- Parameters:
method (str, optional) – Optimization algorithm. Common choices: - ‘L-BFGS-B’: Bound-constrained, gradient-based (default for bounded problems) - ‘Powell’: Derivative-free, bound-constrained - ‘SLSQP’: Sequential Least Squares Programming - ‘trust-constr’: Trust-region method - ‘COBYQA’: Derivative-free quadratic-model method
max_iterations (int, optional) – Maximum number of iterations. Passed to scipy as
maxiter.tol (float, optional) – Tolerance for termination.
**kwargs – Additional arguments passed to scipy.optimize.minimize. See scipy documentation for complete options.
Examples
>>> opt = iw.pipeline.parameter_estimators.ScipyMinimize(method="L-BFGS-B") >>> fit = iw.pipeline.DataFit( ... objectives={"ocp": iw.pipeline.objectives.OCPHalfCell( ... electrode="positive", data_input="path/to/ocp.csv", ... )}, ... parameters={ ... "x": iw.pipeline.Parameter("x", initial_value=1.0, bounds=(0.0, 2.0)) ... }, ... optimizer=opt, ... )
- model_config = {'arbitrary_types_allowed': True, 'extra': 'allow', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.ScipyShgo(*, type: Literal['ScipyShgo'] = 'ScipyShgo', **extra_data: Any)[source]¶
Bases:
_PassthroughOptimizerGlobal optimizer using simplicial homology techniques.
SHGO (Simplicial Homology Global Optimization) uses topological techniques to identify and sample from all local minima basins. It’s particularly effective for problems with many local minima.
Notes
Deterministic algorithm (reproducible results without random seed)
Constraintobjects are applied as a penalty on the costMay be slower than stochastic methods for high-dimensional problems
Initial guess x0 is ignored; sampling points determined by algorithm
- Parameters:
n (int, default=100) – Number of sampling points used in the algorithm.
iters (int, default=1) – Number of iterations for algorithm convergence.
sampling_method (str, default='simplicial') – Sampling strategy: ‘simplicial’ (default) or ‘sobol’.
minimizer_kwargs (dict, optional) – Additional arguments passed to the local minimizer.
**kwargs – Additional arguments passed to scipy.optimize.shgo. See scipy documentation for complete options.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'allow', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.SOBEROptions(*, n_initial: int | None = None, noise_floor: str | tuple[float, float] | list[float] | None = None, n_candidates: int | None = None, n_nystrom: int | None = None, gp_kernel: str | None = None)[source]¶
Bases:
_AlgorithmOptionsOptions for
AskTellOptimizer(method="SOBER").Any field left as
Nonefalls back to the SOBER defaults set by the Ionworks pipeline. Strict (extra="forbid"): an unknown option key is rejected.SOBER selects batches by Bayesian quadrature. Its strength is quadrature-style estimation rather than pure optimization; when the goal is simply the best parameter set, prefer
method="TuRBO",method="BayesianOptimization", ormethod="DifferentialEvolution"— see theAskTellOptimizerNotes for method-selection guidance.- Parameters:
n_initial (int, optional) – Number of quasi-random warm-up evaluations before the surrogate model is first fitted — see
BayesianOptimizationOptions.noise_floor (str or tuple of (float, float), optional) – Constrain the objective-GP likelihood noise — see
BayesianOptimizationOptions.n_candidates (int, optional) – Number of candidate samples per batch for kernel recombination. Default 1024. The recombination’s selection pressure is
n_candidates : batch size— keep it near ~100:1 (e.g. 20000 at batch 200) when running wide batches; the default is only adequate for small batches.n_nystrom (int, optional) – Number of samples for the Nystrom approximation of the kernel. Default
min(512, n_candidates // 2). Must exceed the batch size.gp_kernel (str, optional) – Objective-GP kernel style.
"botorch"(default) uses an ARD RBF kernel with per-dimension lengthscales — the best general choice, especially on anisotropic or constrained problems."reference"uses the isotropic kernel of the original SOBER implementation, whose sharper sampling measure converges deeper on smooth low-dimensional problems with an interior optimum.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.TuRBO(*, log_to_screen: bool | None = False, sigma0: float | int | list | tuple | None = None, max_iterations: int | None = None, max_unchanged_iterations: int | None = None, max_unchanged_iterations_threshold: float | int | None = None, min_iterations: int | None = 1, max_evaluations: int | None = 1000000, population_size: int | None = None, threshold: float | int | None = None, absolute_tolerance: float | int | None = 1e-05, relative_tolerance: float | int | None = 0.01, xtol: float | int | None = 1e-06, population_convergence_tol: float | int | None = 0.005, flat_fitness_tol: float | int | None = None, convergence_patience: int | None = 3, surrogate_convergence_tol: float | int | None = 0.001, type: Literal['TuRBO'] = 'TuRBO', algorithm_options: TuRBOOptions | None = None)[source]¶
Bases:
_AskTellBaseTuRBO: trust-region Bayesian optimization.
Suited to expensive parallel or constrained problems, scaling to higher dimensions than global BO via a local trust region. Convenience wrapper around
AskTellOptimizer(method="TuRBO"); seeAskTellOptimizerfor the full list of accepted kwargs and passalgorithm_options=iw.pipeline.parameter_estimators.TuRBOOptions(...)to configure the surrogate.Examples
>>> opt = iw.pipeline.parameter_estimators.TuRBO() >>> fit = iw.pipeline.DataFit( ... objectives={"ocp": iw.pipeline.objectives.OCPHalfCell( ... electrode="positive", data_input="path/to/ocp.csv", ... )}, ... parameters={ ... "x": iw.pipeline.Parameter("x", initial_value=1.0, bounds=(0.0, 2.0)) ... }, ... optimizer=opt, ... )
- algorithm_options: TuRBOOptions | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.TuRBOOptions(*, n_initial: int | None = None, noise_floor: str | tuple[float, float] | list[float] | None = None, n_candidates: int | None = None, tr_length_init: float | None = None, tr_length_min: float | None = None, tr_length_max: float | None = None, tr_success_tolerance: int | None = None, tr_failure_tolerance: int | None = None, gp_max_points: int | None = None)[source]¶
Bases:
_AlgorithmOptionsOptions for
AskTellOptimizer(method="TuRBO").Any field left as
Nonefalls back to the TuRBO defaults set by the Ionworks pipeline. Strict (extra="forbid"): an unknown option key is rejected.- Parameters:
n_initial (int, optional) – Number of quasi-random warm-up evaluations before the surrogate model is first fitted — see
BayesianOptimizationOptions. On a parallel cluster, set it to the batch width when that is much larger than the dimension-based default so the warm-up round uses the full available width.noise_floor (str or tuple of (float, float), optional) – Constrain the objective-GP likelihood noise — see
BayesianOptimizationOptions.n_candidates (int, optional) – Candidate-pool size for Thompson sampling inside the trust region. Default
min(5000, 200 * n_parameters).tr_length_init (float, optional) – Initial trust-region edge length in normalized
[0, 1]coordinates. Default 0.8.tr_length_min (float, optional) – Trust-region edge length below which the region restarts. Default
2**-7.tr_length_max (float, optional) – Maximum trust-region edge length. Default 1.6.
tr_success_tolerance (int, optional) – Consecutive improving batches before the region doubles. Default 3.
tr_failure_tolerance (int, optional) – Consecutive non-improving batches before the region halves. Default
ceil(max(4, n_parameters) / batch_size).gp_max_points (int, optional) – Maximum number of observations used per surrogate refit (trust-region-local windowing). Bounds the cubic cost of exact GP fitting on long or wide campaigns. Default 1000.
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.XNES(*, log_to_screen: bool | None = False, sigma0: float | int | list | tuple | None = None, max_iterations: int | None = None, max_unchanged_iterations: int | None = None, max_unchanged_iterations_threshold: float | int | None = None, min_iterations: int | None = 1, max_evaluations: int | None = 1000000, population_size: int | None = None, threshold: float | int | None = None, absolute_tolerance: float | int | None = 1e-05, relative_tolerance: float | int | None = 0.01, xtol: float | int | None = 1e-06, population_convergence_tol: float | int | None = 0.005, flat_fitness_tol: float | int | None = None, convergence_patience: int | None = 3, surrogate_convergence_tol: float | int | None = 0.001, type: Literal['XNES'] = 'XNES', algorithm_options: XNESOptions | None = None)[source]¶
Bases:
_AskTellBaseExponential Natural Evolution Strategy (xNES). Adapts its covariance matrix to the local fitness landscape.
Convenience wrapper around
AskTellOptimizer(method="XNES"); seeAskTellOptimizerfor the full list of accepted kwargs.Examples
>>> opt = iw.pipeline.parameter_estimators.XNES() >>> fit = iw.pipeline.DataFit( ... objectives={"ocp": iw.pipeline.objectives.OCPHalfCell( ... electrode="positive", data_input="path/to/ocp.csv", ... )}, ... parameters={ ... "x": iw.pipeline.Parameter("x", initial_value=1.0, bounds=(0.0, 2.0)) ... }, ... optimizer=opt, ... )
- algorithm_options: XNESOptions | None¶
- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
- class ionworks.pipeline.parameter_estimators.XNESOptions[source]¶
Bases:
_AlgorithmOptionsOptions for
AskTellOptimizer(method="XNES").XNES has no algorithm-specific options today — its search is fully parameterised by the top-level
AskTellOptimizerfields (sigma0,population_size, …). This class exists as a typed marker so the samealgorithm_options=iw.pipeline.parameter_estimators.XNESOptions(...)pattern works across methods. It is strict (extra="forbid"): it declares no option keys, so any key passed to it is rejected.- model_config = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'populate_by_name': True, 'validate_assignment': True}¶
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].