Release notes#

Release notes for the published versions of nextnano optimizers.

Unreleased#

  • breaking: EvolutionPlotter is gone. OptimizationPlotter draws every optimizer’s run, and the new OptimizationPlotter.from_optimizer replaces EvolutionPlotter.from_evolution for all three of them: OptimizationPlotter.from_optimizer(evolution).plot_all(). A log records the run and not which optimizer wrote it, so the subclass only ever knew the evolution wording because the caller had picked the class.

  • figures drawn through an optimizer are unchanged: Evolution.plot_all() still titles its progress figure Evolution progress and calls an iteration a generation. Plotting a log directly words itself neutrally, as it already did for LocalOptimizer and BayesianOptimization; pass iteration_label and progress_title to say otherwise.

  • EvolutionPlotter.from_evolution no longer fills the Pareto highlights from the Evolution object when the run’s log summary does not carry them. Every plotted value comes from the log. A completed run’s figures are unchanged — its summary carries the front — while a run that raised before writing its summary draws its figures with the final population scattered and no front emphasized on top.

  • Evolution.plot_all now reports a run it cannot plot the way the other two optimizers already did: on a log holding no evaluated candidate — a run whose first generation failed — it raises RuntimeError saying so rather than IndexError from inside the plotting layer, and before run has produced a log it raises RuntimeError rather than AttributeError.

  • Evolution.setup_plotting and Evolution.plot_all are the same methods the other two optimizers use, so the three document and behave alike. The figures are unchanged, and Evolution’s API page now lists them.

  • an Evolution plotted without setup_plotting now labels its parameter axes with the input-variable names from its IO, as LocalOptimizer and BayesianOptimization already did, instead of param1, param2, … This applies to the figures and to the live window alike, and setup_plotting(param_names=[...]) still overrides it. The objectives keep fitness1, fitness2, … — a multi-objective run has no names for them anywhere, so name them yourself with setup_plotting(fitness_names=[...]).

Version 0.13.0 (October 12th 2026)#

  • every run now writes into a folder of its own, named after the input file and the optimizer — {input_file_name}_evolution/, {input_file_name}_optimization/, {input_file_name}_bayesian/ — created in the output directory configured in nextnanopy.

  • the three optimizers accept output_dir to create that folder somewhere other than the configured output directory: Evolution(io, metric, bounds, output_dir="runs").

  • IO.run_simulation accepts start_index, which numbers the generated input files — and so the simulation output folders nextnanopy names after them — from the given index, zero-padded to five digits: input_file_stem="sim", start_index=1 yields sim_00001, sim_00002

  • plot_all() now saves the figures. With no save_dir they are written into a figures subfolder of the run’s folder; previously the default drew them without saving anything.

  • the saved figures are named after what they show — progress, pareto and inputs — instead of after the run’s log (Simulation_2026_10_08_153958_progress.png). The folder is what identifies the run, so plotting two runs into one save_dir of your own now leaves only the figures of the last.

  • breaking: save_dir="next_to_log" is no longer saves the figures next to a logs. It is an ordinary relative directory name like any other string, so code still passing it writes the figures into ./next_to_log/ rather than next to the log.

Version 0.12.0 (September 24th, 2026)#

  • a LocalOptimizer run now writes the same .log / .json / .dat trio as Evolution and BayesianOptimization, in the same JSON schema: one gen{n} key per function evaluation, one candidate per key, plus a summary section carrying the champion, the initial guess, the method and what scipy returned. A single scipy iteration covers several evaluations — a finite-difference gradient costs one simulation per input variable on top of the iterate — so the evaluation, not the iteration, is what the log records.

  • LocalOptimizer gains champion_x and champion_f: the best evaluated candidate, which is not always the point OptimizeResult.x reports, since a method may take a final step that does not improve the metric.

  • LocalOptimizer.run accepts live_progress=True: the progress viewer opens during the run and closes with it, as it already did for Evolution and BayesianOptimization.

  • LocalOptimizer.setup_plotting and LocalOptimizer.plot_all draw a local run for its own shape: the function evaluations (labelled evaluations, drawn as a connected line) and the best-so-far, without the mean/median/min-max curves that would each summarize a single evaluation. The axis counts function evaluations rather than scipy iterations, which is what the log records.

  • plot_all on a log holding no evaluated candidate — a run whose first simulation failed — raises RuntimeError saying so, rather than IndexError from inside the plotting layer. Applies to LocalOptimizer and BayesianOptimization.

Version 0.11.0 (September 23rd, 2026)#

  • breaking: Optimizer is now LocalOptimizer and wraps only scipy.optimize.minimize. Root finding (optimization_method="root" / "root_scalar") is gone, and with it both constructor arguments that selected the method: LocalOptimizer(nextnanoio, metric) now takes exactly two arguments.

  • breaking: LocalOptimizer.set_target is gone. Fold the target into the metric — an extraction function returning abs(value - target) — so the objective is the distance to the target and the minimizer drives it to zero.

  • breaking: set_optimization_parameters is gone; run takes the arguments instead — optimizer.run(x0=[10.0], bounds=[(5, 20)], method="Nelder-Mead"), forwarded to scipy.optimize.minimize.

  • breaking: run_optimization is gone. run is the single entry point and returns the scipy.optimize.OptimizeResult.

  • breaking: validate_optimization is gone. A non-scalar metric, or an x0 whose length does not match the input variables, raises ValueError from run.

  • breaking: the nextnano_optimizers.bayesian module is gone. BayesianOptimization is imported from nextnano_optimizers.optimizer, the one module that now provides all three optimizers.

  • breaking: the IO.output_datafiles property is now the method IO.load_output_datafiles(): it reads and parses the output files from disk on every call, which an attribute access should not do.

  • breaking: IO.get_target is gone; it only returned the output datafiles. Use IO.load_output_datafiles().

  • breaking: a number of methods that were public but are only ever called by an optimizer during its own run have become internal, so that what the documentation lists is what you are meant to call. Nothing used to set up or drive a run is affected.

  • the example input files are updated for nextnano++ 3.0.0.

Version 0.10.0 (August 28th, 2026)#

  • BayesianOptimization.run accepts live_progress=True: the progress viewer opens during the run and closes with it, as it already did for Evolution.

  • Bayesian runs are plotted for their own shape: the trial values (labelled samples, drawn as a connected line) and the best-so-far, without the mean/median/min-max curves that would each summarize a single evaluation.

  • new OptimizationPlotter, the optimizer-agnostic base of EvolutionPlotter: use it to plot any run’s log, Bayesian included.

  • progress curves can be relabelled and restyled per run (series_labels, series_specs), and the surrounding wording set with iteration_label, progress_title and population_label.

  • breaking: the plotter’s summary, n_params, n_obj, param_names, fitness_names, n_failed and n_limited moved onto its run attribute — plotter.n_obj is now plotter.run.n_obj.

Version 0.9.0 (August 7th, 2026)#

  • BayesianOptimization.run accepts a target: the run stops early once the objective drops to or below it, instead of always exhausting the trials budget.

Version 0.8.1 (August 5th, 2026)#

  • support python 3.14.

Version 0.8.0 (July 29th, 2026)#

  • Bayesian optimization gains setup_plotting, matching Evolution: configure the result figures once (param_names, fitness_names, progress_series, fitness_limits) and plot_all draws with it.

  • plot_all accepts fig_format to save the figures as pdf/svg/jpg/… (any format matplotlib supports); defaults to png.

Version 0.7.0 (July 24th, 2026)#

  • progress plot “best” curve is now the best-so-far (running best over generations), not the per-generation best.

  • live progress viewer closes when the run finishes, and shows a placeholder until the first generation completes.

  • integer ticks on the excluded-evaluations progress panel.

  • experimental Bayesian optimization (Ax-based), opt-in via pip install nextnano_optimizers[bayesian].

Version 0.6.0 (July 21st, 2026)#

  • improve failed simulation error handling.

  • the package is renamed to nextnano_optimizers.

Version 0.5.3 (July 10th, 2026)#

  • bugfixes.

Version 0.5.2 (July 9th, 2026)#

  • progress plot in separate process.

Version 0.5.1 (July 9th, 2026)#

  • fitness limits for plotting.

  • choice of series for progress plotting.

  • other small adjustments in plotting.

Version 0.5.0 (July 8th, 2026)#

  • live progress and evolution results plotting.

  • improved keep_pareto handling.

Version 0.4.3 (July 7th, 2026)#

  • bugfixes.

Version 0.4.2 (July 7th, 2026)#

  • bugfixes.

Version 0.4.0 (May 4th, 2026)#

  • support multiple simulations per fitness via sweeps.

  • adapt Metric API to support multiple simulations.

Version 0.3.3 (April 10th, 2026)#

  • bug fixes.

Version 0.3.2 (April 7th, 2026)#

  • bug fixes.

Version 0.3.1#

  • bug fixes.

Version 0.3.0#

  • switch from pygmo to pymoo.

Version 0.2.0#

  • bug fixes.

  • improved output.

Version 0.1.12#

  • bug fixes.

  • added champion to evolution.

  • extra: data generation for ML.

  • added clean-up of input files after simulation.

Version 0.1.11#

  • extraction function in evolution is now strictly enforced to return numpy.array.

Version 0.1.10#

  • added non_execution_penalty to Evolution.run(..., non_execution_penalty=number), where number is the fitness assigned to the candidates without successful execution of the input file. If non_execution_penalty is not specified, an execution error of the input file leads to an error of the Evolution.

  • added the Simulation*.json history file. The file duplicates the Simulation*.log info, but saves it in a more computer readable format.

  • added the Simulation*.dat history file in column format: (idx, generation, param1, param2, … paramn, fitness1, …, fitnessk).

Version 0.1.9#

  • added algorithm_kwargs, Evolution.run(..., algorithm_kwargs={'cr': 0.95, ...}).

  • added the initial guess feature to evolution, Evolution.run(..., initial_guess=[solution_guess1, solution_guess2, ...]). The length of the initial guess should be equal to or less than the size of the Evolution.