Optimizing the RTE of a Carnot Battery (CB)
Using the pymoo framework with differential evolution (DE) [1]
First, the necessary packages need to be imported. By default, the optimization is parallelized.
[1]:
# %%
import os
import carbatpy as cb
The optimization is imported via:
[2]:
from carbatpy.optimizations.opti_de 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
[3]:
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.
[9]:
# Define boundaries
boundaries_cb = {
"hp": {
"working_fluid": {
"p_high": [15e5, 40e5],
"fractions": [[0, 0.45], [0, 1], [0, 1]],
}
},
"orc": {
"working_fluid": {
"p_high": [15e5, 20e5],
"p_low": [2e5, 8e5],
},
},
}
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; A boolean for using the same working fluid or a simple loss factor for the storages may be provided
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 optimized CB directly or save the desired outputs to os.environ[“CARBATPY_RES_DIR”].
[10]:
if __name__ == "__main__":
# Start optimization
result = optimize(
mode="cb",
config=config,
boundaries=boundaries_cb,
same_fluid=True,
heat_losses=0.00,
n_gen=10,
)
=================================================================================
n_gen | n_eval | cv_min | cv_avg | f_avg | f_min
=================================================================================
1 | 50 | 2.9041343070 | 7.400235E+05 | - | -
2 | 100 | 2.9041343070 | 6.600317E+05 | - | -
3 | 150 | 2.9041343070 | 5.600418E+05 | - | -
4 | 200 | 2.8424585841 | 4.800479E+05 | - | -
5 | 250 | 2.8424585841 | 4.400519E+05 | - | -
6 | 300 | 2.8424585841 | 3.400601E+05 | - | -
7 | 350 | 2.8424585841 | 3.000641E+05 | - | -
8 | 400 | 0.000000E+00 | 2.800641E+05 | -1.799498E-01 | -1.799498E-01
9 | 450 | 0.000000E+00 | 2.800638E+05 | -1.799498E-01 | -1.799498E-01
Max number of generations reached!
10 | 500 | 0.000000E+00 | 2.600657E+05 | -1.799498E-01 | -1.799498E-01
[ ]:
# Plot optimal CB
paths, _, _ = extract_boundary_with_path(boundaries_cb)
config_cb = create_config(result.X, 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)
RTE: 0.17994979010444911
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,
"sampling_iterations": 50,
"de_variant": "DE/rand/1/bin",
"CR": 0.3,
"dither": "vector",
"jitter": 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.