Optimizing the RTE and CAPEX of a Carnot Battery (CB)

Using the pymoo framework with the Non-dominated Sorting Genetic Algorithm (NSGA-II) [1]

First, we import the required packages. By default, the optimization is parallelized.

[ ]:
import os
import carbatpy as cb

The optimization is imported via:

[ ]:
from carbatpy.optimizations.opti_NSGA2 import optimize

The following helper functions can be imported to create a config out of the optimizations result, ready as an input for the CB simulation

[ ]:
from carbatpy.optimizations.helpers_optimization import (
    extract_boundary_with_path,
    create_config,
)

Next, the bounds for the optimization variables are defined. They must follow the same structure as the input configurations. Note: The configurations can be specified either as paths to the YAML configuration files (including their directories) or directly as a Python dictionary.

[ ]:
bounds_hp = {
        "working_fluid": {"p_high": [10e5, 40e5],
            "fractions": [[0, 0.45], [0, 1], [0, 1]],
    }
}

bounds_orc = {
    "working_fluid": {
        "p_high": [8e5, 25e5],
        "p_low": [3e5, 15e5],
    },
}

boundaries = {"hp": bounds_hp, "orc": bounds_orc}

dir_data = cb.CB_DEFAULTS["General"]["CB_DATA"]
hp_file = os.path.join(dir_data, "reference_data/io-hp-data-ref.yaml")
orc_file = os.path.join(dir_data, "reference_data/io-orc-data-ref.yaml")

config = {"hp": hp_file, "orc": orc_file}

Finally, you can run the optimization. Depending on the selected mode (cb, hp, or orc), additional parameters may be required:

  • cb: no additional parameters required

  • hp: no additional parameters required

  • orc: COP: float and q_dot: float

optimize returns the corresponding pymoo result object. Next, you may want to plot the one optimized CB directly or save the desired outputs to os.environ[“CARBATPY_RES_DIR”].

[ ]:
if __name__ == "__main__":
    result = optimize(
        mode="cb",
        config=config,
        boundaries=boundaries,
        same_fluid=True,
        heat_losses=0.00,
        n_gen=10,
    )

[ ]:
# Now one can plot some Carnot Batteries, plot the Pareto-Front or safe the results if found
if result.X is None:
        raise ValueError("No result found")
# Plot Pareto-Front
from pymoo.visualization.scatter import Scatter
plot = Scatter()
plot.add(result.F, alpha=0.8)
plot.show(block=True)

# Plot the highest RTE Carnot Battery
paths, _, _ = extract_boundary_with_path(boundaries)
best_solution_vars = result.X[-1]
config_cb = create_config(best_solution_vars, paths)

rte, res_cb = cb.cb_comp.cb_calc(
    config,
    config=config_cb,
    verbose=False,
    plotting=True,
    same_fluid=True,
    heat_losses=0.00,
)
for i in ("hp", "orc"):
    if any(ns.value != 0 for ns in res_cb[i]["warnings"].values()):
        raise Exception(
            f"Check warnings, at least one deviates from 0!\n{res_cb[i]['warnings']}"
        )
print("RTE: ", rte)

Note: The results will differ between runs due to the stochastic nature of the optimization algorithm.

For advanced users familiar with pymoo, the following default settings can be overridden when calling optimize:

[ ]:
DEFAULTS = {
    "verbose": True,
    "n_processes": None,
    "maxtasksperchild": 20,
    "n_ieq_constr": 3,
    "n_gen": 100,
    "period": 20,
    "ftol": 1e-4,
    "pop_size": 50,
    "n_offspring": None,
    "sampling_iterations": 50,
    "crowding_func": "pcd",
    "eliminate_duplicates": True,
    "save_history": False,
    "return_least_infeasible": False,
}

Reference

[1] J. Blank and K. Deb, Pymoo: Multi-Objective Optimization in Python, in IEEE Access, vol. 8, pp. 89497-89509, 2020, doi: 10.1109/ACCESS.2020.2990567.