Optimisation Run Flexibility

It is possible to change the configuration of the algorithm part way through the optimization process, or even to switch algorithms completely. This allows an optimization process to be configured to be more exploritative early on, to explore the whole design space, then later to be more exploitative, to home in in exact optimal solutions. Doing so requires using Platypus algorithms directly, instead of the algorithm wrappers provided through the BESOS optimizer module.

import platypus
from besos import eppy_funcs as ef, optimizer
from besos.evaluator import EvaluatorEP
from besos.parameters import expand_plist
from besos.problem import EPProblem

First we create an example problem, see here for details.

idf = ef.get_idf()
parameters = expand_plist(
    {
        "NonRes Fixed Assembly Window": {
            "UFactor": (0.1, 5),
            "Solar Heat Gain Coefficient": (0.01, 0.99),
        },
        "Mass NonRes Wall Insulation": {"Thickness": (0.01, 0.09)},
    }
)
objectives = ["Electricity:Facility", "Gas:Facility"]
problem = EPProblem(parameters, objectives)
evaluator = EvaluatorEP(problem, idf)

Next we set up NSGA-II as the first algorithm, a good general purpose multi-objective genetic algorithm. The to_platypus shortcut converts the Evaluator object to a platypus.Problem object.

platypus_problem = evaluator.to_platypus()
algorithm = platypus.NSGAII(problem=platypus_problem)

Now we can run the algorithm for a lot of generations, and pause it at some point. Use the stop button at the top of the notebook to interrupt the following cell. Note: The output from the next cells will vary from run to run, due to the randomness of the underlying algorithm as well as the amount of time this cell is run for.

try:
    algorithm.run(10)
except KeyboardInterrupt:
    print("Algorithm interrupted")
algorithm.population[:5]
[Solution[1.0908340504277432,0.16551557505479184,0.08624645903497696|1790121927.5090928,2112480396.5036483|0],
 Solution[3.669368008669323,0.4536590257731561,0.02927202264111818|1888165256.2375371,2864447993.238228|0],
 Solution[0.4048842481345535,0.21011098820673654,0.0820871977282966|1811316457.5204759,1985648992.8552308|0],
 Solution[4.51833839590032,0.05906519561246457,0.028176520417913818|1774638001.8351984,3011098878.738435|0],
 Solution[0.9949394089562864,0.9225128363028766,0.04547968363721608|2082915722.0566134,2208464014.055323|0]]

Now we want to continue from where the first algorithm left off, running EpsMOEA for 10 evaluations. In order to make the population carry over, we use the InjectedPopulation generator, then run the second algorithm.

If we had let the first algorithm finish, we could use algorithm.result instead of algorithm.population to use the solutions found by the first algorithm as a starting point for the next.

generator = platypus.InjectedPopulation(algorithm.population)
alg2 = platypus.EpsMOEA(
    problem=platypus_problem, generator=generator, epsilons=3, population_size=10
)
alg2.run(10)

Now we convert the solutions to a dataframe using the BESOS helper function and display them.

optimizer.solutions_to_df(alg2.result, problem, parts=["inputs", "outputs"])
UFactor Solar Heat Gain Coefficient Thickness Electricity:Facility Gas:Facility pareto-optimal
0 0.120118 0.021326 0.083123 1.767805e+09 1.932621e+09 True
1 0.258848 0.821173 0.087239 2.023985e+09 1.865141e+09 True
2 4.476737 0.044301 0.068937 1.743882e+09 2.693421e+09 True
3 0.163817 0.966123 0.077487 2.098469e+09 1.852508e+09 True