Basic run¶
First, we import the essential libraries and modules that will be used throughout this tutorial:
pickle
: Used for saving and loading Python objects to and from files.Energyscope
fromenergyscope.energyscope
: The main class for initializing and running the EnergyScope model.infrastructure_ch_2050
,Model
fromenergyscope.models
: The specific model configuration we will use, which focuses on energy infrastructure. And the object Model to create your own model from external files.postprocessing
fromenergyscope.result
: Functions for processing and analyzing the results after optimization.plot_sankey
fromenergyscope.plots
: A function to generate Sankey diagrams for visualizing energy flows.
import pickle
from energyscope.energyscope import Energyscope
from energyscope.models import infrastructure_ch_2050, Model
from energyscope.result import postprocessing
from energyscope.plots import plot_sankey
Initialize and Run the Model¶
In this section, we initialize the EnergyScope model using the infrastructure dataset and perform a single optimization run.
Initialize the Model¶
Create an instance of the Energyscope
class with the infrastructure
model. This sets up the model with predefined parameters and datasets.
es_infra_ch = Energyscope(model=infrastructure_ch_2050)
Export Model to AMPL and GLPK¶
For compatibility and further analysis, we export the model files in both AMPL and GLPK formats.
# Export model to AMPL
es_infra_ch.export_ampl(mod_filename='tutorial_output/AMPL_infrastructure_ch_2050.mod',dat_filename='tutorial_output/AMPL_infrastructure_ch_2050.dat')
# Export model to GLPK
es_infra_ch.export_glpk(mod_filename='tutorial_output/GLPK_infrastructure_ch_2050.mod',dat_filename='tutorial_output/GLPK_infrastructure_ch_2050.dat')
[INFO] Activating AMPL license with UUID
Load External AMPL files¶
To load external files from AMPL you need to create a new Model as follow.
# Create you own Model object from imported AMPL files
Model_es_infra_ch = Model([
('mod', "tutorial_output/AMPL_infrastructure_ch_2050.mod"),
('dat', "tutorial_output/AMPL_infrastructure_ch_2050.dat")
])
# Create an instance of the Energyscope class with your own model.
es_infra_ch = Energyscope(model=Model_es_infra_ch)
Solve the Model¶
Perform the optimization calculation. This step runs the solver and computes the optimal configuration based on the model.
results_ch = es_infra_ch.calc()
[INFO] Activating AMPL license with UUID
Gurobi 12.0.3:
Gurobi 12.0.3: optimal solution; objective 9229.740656 7346 simplex iterations 1 branching node
Post-Process Results¶
After obtaining the raw results, we apply post-processing to compute Key Performance Indicators (KPIs) and prepare the data for visualization.
results_ch = postprocessing(results_ch)
# Example of how to extract post-processed data
results_ch.postprocessing['df_annual'].loc['WIND',:]
C_inv | C_maint | Annual_Prod | F_Mult | tau | C_op | C_inv_an | Annual_Use | Category | Category_2 | Sector | |
---|---|---|---|---|---|---|---|---|---|---|---|
Run | |||||||||||
0 | 29312.4 | 458.0 | 40299.36 | 20.0 | 0.062433 | 0.0 | 1830.059062 | 40299.36 | (ELECTRICITY_MV,) | Wind | NaN |
fig = plot_sankey(results_ch)
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[7], line 1 ----> 1 fig = plot_sankey(results_ch) File /builds/energyscope/energyscope/src/energyscope/plots.py:286, in plot_sankey(result, aggregate_mobility, aggregate_grid, aggregate_technology, run_id, colors) 284 def plot_sankey(result: Result, aggregate_mobility: bool = True, aggregate_grid: bool = True, 285 aggregate_technology: bool = True, run_id: int = 0, colors: Union[Colors, dict] = None) -> go.Figure: --> 286 df_flow = generate_sankey_flows(result, aggregate_mobility=aggregate_mobility, aggregate_grid=aggregate_grid, 287 aggregate_technology=aggregate_technology, run_id=run_id) 288 return _create_sankey_figure(df_flow, Colors.cast(colors or default_colors)) File /builds/energyscope/energyscope/src/energyscope/plots.py:195, in generate_sankey_flows(results, aggregate_mobility, aggregate_grid, aggregate_technology, run_id) 190 df_flow.at[index, 'source'] = EUD_types_reverse[row['source']] 192 if aggregate_mobility: 193 ## Aggregation of mobility flows 194 # Extract rows concerning mobility --> 195 mob_flow = df_flow.loc[df_flow['target'].str.startswith('MOBILITY_'), :] 196 mob_flow_2 = df_flow.loc[df_flow['target'].isin( 197 df_flow.loc[df_flow['target'].str.startswith('MOBILITY_'), :]['source'].unique()), :] 198 # Drop rows concerning mobility as they will be merged File ~/.local/share/hatch/env/virtual/energyscope/4BIeM0-F/docs/lib/python3.10/site-packages/pandas/core/indexing.py:1185, in _LocationIndexer.__getitem__(self, key) 1183 if self._is_scalar_access(key): 1184 return self.obj._get_value(*key, takeable=self._takeable) -> 1185 return self._getitem_tuple(key) 1186 else: 1187 # we by definition only have the 0th axis 1188 axis = self.axis or 0 File ~/.local/share/hatch/env/virtual/energyscope/4BIeM0-F/docs/lib/python3.10/site-packages/pandas/core/indexing.py:1378, in _LocIndexer._getitem_tuple(self, tup) 1375 if self._multi_take_opportunity(tup): 1376 return self._multi_take(tup) -> 1378 return self._getitem_tuple_same_dim(tup) File ~/.local/share/hatch/env/virtual/energyscope/4BIeM0-F/docs/lib/python3.10/site-packages/pandas/core/indexing.py:1021, in _LocationIndexer._getitem_tuple_same_dim(self, tup) 1018 if com.is_null_slice(key): 1019 continue -> 1021 retval = getattr(retval, self.name)._getitem_axis(key, axis=i) 1022 # We should never have retval.ndim < self.ndim, as that should 1023 # be handled by the _getitem_lowerdim call above. 1024 assert retval.ndim == self.ndim File ~/.local/share/hatch/env/virtual/energyscope/4BIeM0-F/docs/lib/python3.10/site-packages/pandas/core/indexing.py:1413, in _LocIndexer._getitem_axis(self, key, axis) 1411 self._validate_key(key, axis) 1412 return self._get_slice_axis(key, axis=axis) -> 1413 elif com.is_bool_indexer(key): 1414 return self._getbool_axis(key, axis=axis) 1415 elif is_list_like_indexer(key): 1416 # an iterable multi-selection File ~/.local/share/hatch/env/virtual/energyscope/4BIeM0-F/docs/lib/python3.10/site-packages/pandas/core/common.py:136, in is_bool_indexer(key) 132 na_msg = "Cannot mask with non-boolean array containing NA / NaN values" 133 if lib.is_bool_array(key_array, skipna=True): 134 # Don't raise on e.g. ["A", "B", np.nan], see 135 # test_loc_getitem_list_of_labels_categoricalindex_with_na --> 136 raise ValueError(na_msg) 137 return False 138 return True ValueError: Cannot mask with non-boolean array containing NA / NaN values
Display the Diagram¶
Render the Sankey diagram within the notebook for immediate visualization.
Optional: You can save the diagram as an HTML file or an image for external use by uncommenting the following lines:
# fig.write_html("tutorial_output/sankey_infrastructure_ch_2050.html")
# fig.write_image('tutorial_output/sankey_infrastructure_ch_2050.png')
fig.show(renderer="notebook")
--------------------------------------------------------------------------- NameError Traceback (most recent call last) Cell In[9], line 1 ----> 1 fig.show(renderer="notebook") NameError: name 'fig' is not defined
def save_result_to_pickle(data, filename):
"""
Save the Result object to a pickle file.
Parameters:
data: The Result object to save.
filename (str): The file path to save the object to.
"""
with open(filename, 'wb') as fp:
pickle.dump(data, fp, protocol=pickle.HIGHEST_PROTOCOL)
Define Load Function¶
Create a function to load the Result
object from a pickle file.
Note: These utility functions could be integrated into the EnergyScope library for convenience.
def load_result_from_pickle(filename):
"""
Load the Result object from a pickle file.
Parameters:
filename (str): The file path to load the object from.
Returns:
The loaded Result object.
"""
with open(filename, 'rb') as handle:
result = pickle.load(handle)
return result
Save the Results¶
Use the save_result_to_pickle
function to save the results to a file.
save_result_to_pickle(results_ch, "tutorial_input/infrastructure_ch_2050.pickle")
Clear the Results Variable¶
Empty the results_ch
variable to simulate a fresh environment.
results_ch = None
Load the Results¶
Load the previously saved results using the load_result_from_pickle
function.
results_ch = load_result_from_pickle("tutorial_input/infrastructure_ch_2050.pickle")
Display Total Cost¶
Access and display the total cost from the loaded results to verify that the data was correctly saved and loaded.
results_ch.variables['TotalCost']
TotalCost | Run | |
---|---|---|
0 | 9229.740656 | 0 |
This should output a table showing the total cost of the optimized energy system configuration.
By following these steps, you can perform a basic run of the EnergyScope model, visualize the results, and save/load the data for future use. This tutorial serves as a foundation for more complex analyses and customizations.