import xarray as xr
import pandas as pd
import numpy as np
import calliope
calliope.set_log_verbosity('INFO', include_solver_output=False)
# Initialise the model with the Urban Scale example model
m = calliope.examples.urban_scale()
[2023-01-18 13:20:45] INFO Model: initialising [2023-01-18 13:20:46] INFO Model: preprocessing stage 1 (model_run) [2023-01-18 13:20:47] INFO Model: preprocessing stage 2 (model_data) [2023-01-18 13:20:47] INFO Model: preprocessing complete
# Get information on the model
m.info()
'Model name: Urban-scale example model\nModel size: 4 locations, 9 technologies, 48 timesteps'
m._model_run is a python dictionary. The underscore before the method indicates that it defaults to being hidden (i.e. you wouldn't see it by trying a tab auto-complete and it isn't documented)
# Model run holds all the data from the YAML and CSV files, restructured into one dictionary
m._model_run.keys()
dict_keys(['scenario', 'applied_overrides', 'techs', 'tech_groups', 'locations', 'timeseries_data', 'run', 'model', 'group_constraints', 'sets', 'constraint_sets'])
# All locations now hold all information about a technology at that location
m._model_run['locations']['X2']['techs']['pv']
{'costs': {'monetary': {'export': -0.0491, 'om_prod': -0.0203, 'depreciation_rate': 0.11016807219002081, 'energy_cap': 1350}}, 'constraints': {'energy_cap_max': 250, 'energy_prod': True, 'export_carrier': 'electricity', 'force_resource': True, 'lifetime': 25, 'parasitic_eff': 0.85, 'resource': 'file=pv_resource.csv:per_area', 'resource_area_max': 1500, 'resource_area_per_energy_cap': 7, 'resource_eff': 1.0, 'resource_unit': 'energy_per_area'}}
# This includes location-specific overrides, such as energy_cap_max of 50 for the pv technology at location X3
m._model_run['locations']['X3']['techs']['pv']
{'constraints': {'energy_cap_max': 50, 'energy_prod': True, 'export_carrier': 'electricity', 'force_resource': True, 'lifetime': 25, 'parasitic_eff': 0.85, 'resource': 'file=pv_resource.csv:per_area', 'resource_area_max': 1500, 'resource_area_per_energy_cap': 7, 'resource_eff': 1.0, 'resource_unit': 'energy_per_area'}, 'costs': {'monetary': {'om_annual': -80.5, 'depreciation_rate': 0.11016807219002081, 'energy_cap': 1350}}}
# All sets have also been collated.
# locations and technologies are concatenated into loc::tech sets,
# to create a dense matrix and smaller overall model size
m._model_run['sets']['loc_techs']
['X3::power_lines:X1', 'X1::supply_gas', 'X3::boiler', 'X3::pv', 'X2::pv', 'X1::supply_grid_power', 'X1::chp', 'X2::power_lines:X1', 'X1::power_lines:X2', 'X3::demand_heat', 'X2::heat_pipes:N1', 'X3::heat_pipes:N1', 'X1::pv', 'X1::power_lines:X3', 'X1::demand_heat', 'N1::heat_pipes:X3', 'X2::supply_gas', 'X2::demand_electricity', 'N1::heat_pipes:X2', 'X2::demand_heat', 'X1::demand_electricity', 'N1::heat_pipes:X1', 'X2::boiler', 'X1::heat_pipes:N1', 'X3::supply_gas', 'X3::demand_electricity']
# For every constraint, a set of loc_techs (or loc_tech_carriers) is prepared,
# so we only build the constraint over that set
m._model_run['constraint_sets']['loc_techs_energy_capacity_constraint']
['X3::power_lines:X1', 'X1::supply_gas', 'X3::boiler', 'X3::pv', 'X2::pv', 'X1::supply_grid_power', 'X1::chp', 'X2::power_lines:X1', 'X1::power_lines:X2', 'X3::demand_heat', 'X2::heat_pipes:N1', 'X3::heat_pipes:N1', 'X1::pv', 'X1::power_lines:X3', 'X1::demand_heat', 'N1::heat_pipes:X3', 'X2::supply_gas', 'X2::demand_electricity', 'N1::heat_pipes:X2', 'X2::demand_heat', 'X1::demand_electricity', 'N1::heat_pipes:X1', 'X2::boiler', 'X1::heat_pipes:N1', 'X3::supply_gas', 'X3::demand_electricity']
m._model_run['constraint_sets']['loc_techs_resource_area_constraint']
['X2::pv', 'X3::pv', 'X1::pv']
# timeseries data is stored as dataframes, having been loaded from CSV
m._model_run['timeseries_data']['pv_resource.csv'].head()
per_area | per_cap | |
---|---|---|
2005-07-01 00:00:00 | 0.0 | 0.0 |
2005-07-01 01:00:00 | 0.0 | 0.0 |
2005-07-01 02:00:00 | 0.0 | 0.0 |
2005-07-01 03:00:00 | 0.0 | 0.0 |
2005-07-01 04:00:00 | 0.0 | 0.0 |
m._model_data is an xarray Dataset
# Users would usually access information for the initialised model using m.inputs
m.inputs
<xarray.Dataset> Dimensions: (loc_techs: 26, loc_techs_export: 4, loc_techs_finite_resource: 9, timesteps: 48, loc_techs_supply_plus: 3, loc_techs_area: 3, costs: 1, loc_techs_investment_cost: 20, ... loc_tech_carriers_conversion_plus: 3, loc_carriers: 10, loc_techs_non_conversion: 23, loc_techs_conversion: 2, loc_techs_conversion_plus: 1, carriers: 3) Coordinates: (12/20) * carrier_tiers (carrier_tiers) <U5 'out_2' 'in' 'out' * carriers (carriers) <U11 'gas' ... 'heat' * coordinates (coordinates) object 'y' 'x' * costs (costs) object 'monetary' * loc_carriers (loc_carriers) object 'X1::gas' ...... * loc_tech_carriers_conversion_plus (loc_tech_carriers_conversion_plus) object ... ... ... * loc_techs_om_cost (loc_techs_om_cost) object 'X1::sup... * loc_techs_supply_plus (loc_techs_supply_plus) object 'X2:... * loc_techs_transmission (loc_techs_transmission) object 'N1... * locs (locs) object 'N1' 'X3' 'X2' 'X1' * techs (techs) object 'pv' ... 'chp' * timesteps (timesteps) datetime64[ns] 2005-07-... Data variables: (12/38) lifetime (loc_techs) float64 25.0 25.0 ... nan energy_con (loc_techs) float64 1.0 nan ... 1.0 export_carrier (loc_techs_export) object 'electric... resource (loc_techs_finite_resource, timesteps) float64 ... resource_unit (loc_techs_finite_resource) object ... parasitic_eff (loc_techs_supply_plus) float64 0.8... ... ... lookup_loc_techs_conversion_plus (carrier_tiers, loc_techs_conversion_plus) object ... lookup_loc_techs_export (loc_techs_export) object 'X1::chp:... lookup_loc_techs_area (locs) object '' 'X3::pv' ... 'X1::pv' timestep_resolution (timesteps) float64 1.0 1.0 ... 1.0 timestep_weights (timesteps) float64 1.0 1.0 ... 1.0 max_demand_timesteps (carriers) datetime64[ns] 2005-07-0... Attributes: calliope_version: 0.6.10 applied_overrides: scenario: None defaults: carrier_ratios:\ncharge_rate:\nenergy_cap_per_storag... allow_operate_mode: 1
# This is just a filtered view on the model_data Dataset, which includes all the information
# which will be sent to the solver
m._model_data
<xarray.Dataset> Dimensions: ( carrier_tiers: 3, carriers: 3, coordinates: 2, costs: 1, loc_carriers: 10, ... techs_non_transmission: 7, techs_supply: 2, techs_supply_plus: 1, techs_transmission: 7, techs_transmission_names: 2, timesteps: 48) Coordinates: (12/76) * carrier_tiers (carrier_tiers) <U5 ... * carriers (carriers) <U11 ... * coordinates (coordinates) object ... * costs (costs) object ... * loc_carriers (loc_carriers) object ... * loc_carriers_system_balance_constraint (loc_carriers_system_balance_constraint) <U15 ... ... ... * techs_non_transmission (techs_non_transmission) <U18 ... * techs_supply (techs_supply) <U17 ... * techs_supply_plus (techs_supply_plus) <U2 ... * techs_transmission (techs_transmission) <U14 ... * techs_transmission_names (techs_transmission_names) <U11 ... * timesteps (timesteps) datetime64[ns] ... Data variables: (12/38) lifetime (loc_techs) float64 ... energy_con (loc_techs) float64 ... export_carrier (loc_techs_export) object ... resource (loc_techs_finite_resource, timesteps) float64 ... resource_unit (loc_techs_finite_resource) object ... parasitic_eff (loc_techs_supply_plus) float64 ... ... ... lookup_loc_techs_conversion_plus (carrier_tiers, loc_techs_conversion_plus) object ... lookup_loc_techs_export (loc_techs_export) object ... lookup_loc_techs_area (locs) object ... timestep_resolution (timesteps) float64 ... timestep_weights (timesteps) float64 ... max_demand_timesteps (carriers) datetime64[ns] ... Attributes: calliope_version: 0.6.10 applied_overrides: scenario: None defaults: carrier_ratios:\ncharge_rate:\nenergy_cap_per_storag... allow_operate_mode: 1 model_config: calliope_version: 0.6.10\nname: Urban-scale example ... run_config: backend: pyomo\nbigM: 1000000.0\ncyclic_storage: tru...
# If timeseries aggregation of any kind has taken place, then m._model_data_original can be accessed to see the
# model data prior to aggregation
m._model_data_original # In this case, it is the same as m._model_data
<xarray.Dataset> Dimensions: (carriers: 3, timesteps: 48, locs: 4, loc_techs_export: 4, loc_techs_conversion_plus: 1, loc_carriers: 10, ... loc_techs_cost_var_conversion_constraint: 2, loc_techs_balance_conversion_plus_primary_constraint: 1, loc_techs_carrier_production_max_conversion_plus_constraint: 1, loc_techs_cost_var_conversion_plus_constraint: 1, loc_techs_balance_conversion_plus_out_2_constraint: 1, loc_techs_symmetric_transmission_constraint: 10) Coordinates: (12/76) * carriers (carriers) <U11 ... * timesteps (timesteps) datetime64[ns] ... * locs (locs) object ... * loc_techs_export (loc_techs_export) object ... * loc_techs_conversion_plus (loc_techs_conversion_plus) <U7 ... * loc_carriers (loc_carriers) object ... ... ... * loc_techs_cost_var_conversion_constraint (loc_techs_cost_var_conversion_constraint) <U10 ... * loc_techs_balance_conversion_plus_primary_constraint (loc_techs_balance_conversion_plus_primary_constraint) <U7 ... * loc_techs_carrier_production_max_conversion_plus_constraint (loc_techs_carrier_production_max_conversion_plus_constraint) <U7 ... * loc_techs_cost_var_conversion_plus_constraint (loc_techs_cost_var_conversion_plus_constraint) <U7 ... * loc_techs_balance_conversion_plus_out_2_constraint (loc_techs_balance_conversion_plus_out_2_constraint) <U7 ... * loc_techs_symmetric_transmission_constraint (loc_techs_symmetric_transmission_constraint) <U18 ... Data variables: (12/38) lifetime (loc_techs) float64 ... energy_con (loc_techs) float64 ... export_carrier (loc_techs_export) object ... resource (loc_techs_finite_resource, timesteps) float64 ... resource_unit (loc_techs_finite_resource) object ... parasitic_eff (loc_techs_supply_plus) float64 ... ... ... lookup_loc_techs_conversion_plus (loc_techs_conversion_plus, carrier_tiers) object ... lookup_loc_techs_export (loc_techs_export) object ... lookup_loc_techs_area (locs) object ... timestep_resolution (timesteps) float64 ... timestep_weights (timesteps) float64 ... max_demand_timesteps (carriers) datetime64[ns] ... Attributes: calliope_version: 0.6.10 applied_overrides: scenario: None defaults: carrier_ratios:\ncharge_rate:\nenergy_cap_per_storag... allow_operate_mode: 1
# We can find the same PV energy_cap_max data as seen in m._model_run
m._model_data.energy_cap_max.loc[{'loc_techs': 'X2::pv'}]
<xarray.DataArray 'energy_cap_max' ()> array(250.) Coordinates: loc_techs <U6 'X2::pv' Attributes: is_result: 0
m._model_data.energy_cap_max.loc[{'loc_techs': 'X3::pv'}]
<xarray.DataArray 'energy_cap_max' ()> array(50.) Coordinates: loc_techs <U6 'X3::pv' Attributes: is_result: 0
# We can also see the constraint-specific set of loc::techs for setting the energy capacity constraint
m._model_data.loc_techs_energy_capacity_constraint
<xarray.DataArray 'loc_techs_energy_capacity_constraint' ( loc_techs_energy_capacity_constraint: 26)> array(['X3::power_lines:X1', 'X1::supply_gas', 'X3::boiler', 'X3::pv', 'X2::pv', 'X1::supply_grid_power', 'X1::chp', 'X2::power_lines:X1', 'X1::power_lines:X2', 'X3::demand_heat', 'X2::heat_pipes:N1', 'X3::heat_pipes:N1', 'X1::pv', 'X1::power_lines:X3', 'X1::demand_heat', 'N1::heat_pipes:X3', 'X2::supply_gas', 'X2::demand_electricity', 'N1::heat_pipes:X2', 'X2::demand_heat', 'X1::demand_electricity', 'N1::heat_pipes:X1', 'X2::boiler', 'X1::heat_pipes:N1', 'X3::supply_gas', 'X3::demand_electricity'], dtype='<U22') Coordinates: * loc_techs_energy_capacity_constraint (loc_techs_energy_capacity_constraint) <U22 ...
# It is these constraint sets that we cannot see in m.inputs
m.inputs.loc_techs_energy_capacity_constraint
--------------------------------------------------------------------------- AttributeError Traceback (most recent call last) Cell In[18], line 2 1 # It is these constraint sets that we cannot see in m.inputs ----> 2 m.inputs.loc_techs_energy_capacity_constraint File ~/miniconda3/envs/calliope_dev/lib/python3.9/site-packages/xarray/core/common.py:239, in AttrAccessMixin.__getattr__(self, name) 237 with suppress(KeyError): 238 return source[name] --> 239 raise AttributeError( 240 f"{type(self).__name__!r} object has no attribute {name!r}" 241 ) AttributeError: 'Dataset' object has no attribute 'loc_techs_energy_capacity_constraint'
m.run()
[2023-01-18 13:21:19] INFO Backend: starting model run [2023-01-18 13:21:19] INFO Loading sets [2023-01-18 13:21:19] INFO Loading parameters [2023-01-18 13:21:19] INFO constraints are loaded in the following order: ['capacity', 'dispatch', 'policy', 'energy_balance', 'costs', 'network', 'conversion', 'group', 'conversion_plus', 'export', 'milp'] [2023-01-18 13:21:19] INFO creating capacity constraints [2023-01-18 13:21:19] INFO creating dispatch constraints [2023-01-18 13:21:19] INFO creating policy constraints [2023-01-18 13:21:19] INFO creating energy_balance constraints [2023-01-18 13:21:19] INFO creating costs constraints [2023-01-18 13:21:19] INFO creating network constraints [2023-01-18 13:21:19] INFO creating conversion constraints [2023-01-18 13:21:19] INFO creating group constraints [2023-01-18 13:21:19] INFO creating conversion_plus constraints [2023-01-18 13:21:19] INFO creating export constraints [2023-01-18 13:21:19] INFO creating milp constraints [2023-01-18 13:21:19] INFO Backend: model generated. Time since start of model run: 0:00:00.692113 [2023-01-18 13:21:19] INFO Backend: sending model to solver [2023-01-18 13:21:21] INFO Backend: solver finished running. Time since start of model run: 0:00:02.575869 [2023-01-18 13:21:21] INFO Backend: loaded results [2023-01-18 13:21:21] INFO Backend: generated solution array. Time since start of model run: 0:00:02.712495 [2023-01-18 13:21:21] INFO Postprocessing: started [2023-01-18 13:21:22] INFO Postprocessing: All values < 1e-10 set to 0 in system_balance [2023-01-18 13:21:22] INFO Postprocessing: ended. Time since start of model run: 0:00:02.827880
# Results are processed and merged into m.model data, and can be viewed in m.results
m.results
<xarray.Dataset> Dimensions: (loc_techs: 26, loc_tech_carriers_prod: 21, timesteps: 48, loc_tech_carriers_con: 19, costs: 1, loc_techs_cost: 20, loc_techs_area: 3, ... loc_techs_investment_cost: 20, loc_carriers: 10, loc_carriers_system_balance_constraint: 10, loc_techs_balance_demand_constraint: 6, loc_techs_cost_investment_constraint: 20, carriers: 3, techs: 16) Coordinates: (12/17) * techs (techs) object 'boiler' ... 'supp... * carriers (carriers) <U11 'electricity' ...... * costs (costs) <U8 'monetary' * loc_carriers (loc_carriers) <U15 'X1::gas' ...... * loc_carriers_system_balance_constraint (loc_carriers_system_balance_constraint) <U15 ... * loc_tech_carriers_con (loc_tech_carriers_con) <U35 'X3:... ... ... * loc_techs_cost (loc_techs_cost) <U21 'X3::power_... * loc_techs_cost_investment_constraint (loc_techs_cost_investment_constraint) <U21 ... * loc_techs_investment_cost (loc_techs_investment_cost) <U21 ... * loc_techs_om_cost (loc_techs_om_cost) <U21 'X1::sup... * loc_techs_supply_plus (loc_techs_supply_plus) <U6 'X2::... * timesteps (timesteps) datetime64[ns] 2005-0... Data variables: (12/19) energy_cap (loc_techs) float64 45.78 ... 64.93 carrier_prod (loc_tech_carriers_prod, timesteps) float64 ... carrier_con (loc_tech_carriers_con, timesteps) float64 ... cost (costs, loc_techs_cost) float64 0... resource_area (loc_techs_area) float64 443.2 ..... resource_con (loc_techs_supply_plus, timesteps) float64 ... ... ... cost_investment_rhs (costs, loc_techs_cost_investment_constraint) float64 ... cost_var_rhs (costs, loc_techs_om_cost, timesteps) float64 ... capacity_factor (timesteps, loc_tech_carriers_prod) float64 ... systemwide_capacity_factor (carriers, techs) float64 0.0 ...... systemwide_levelised_cost (carriers, costs, techs) float64 ... total_levelised_cost (carriers, costs) float64 0.08069... Attributes: termination_condition: optimal objective_function_value: 842.3529094335404 solution_time: 2.712495 time_finished: 2023-01-18 13:21:21 calliope_version: 0.6.10 applied_overrides: scenario: None defaults: carrier_ratios:\ncharge_rate:\nenergy_cap_per_... allow_operate_mode: 1 model_config: calliope_version: 0.6.10\nname: Urban-scale ex... run_config: backend: pyomo\nbigM: 1000000.0\ncyclic_storag...
# As with inputs, the results dataset is a filtered view of m._model_data.
# All variables in `m.results` have the attribute `is_result` = 1
m._model_data.energy_cap
<xarray.DataArray 'energy_cap' (loc_techs: 26)> array([4.5778336e+01, 6.4431283e+02, 1.5600000e-02, 5.0000000e+01, 6.3309509e+01, 3.3620147e+01, 2.6094670e+02, 2.7451170e+02, 2.7451170e+02, 9.3982291e+00, 1.9024262e+02, 1.0382599e+01, 0.0000000e+00, 4.5778336e+01, 1.7197109e+00, 1.0382599e+01, 2.2685938e+02, 2.6934435e+02, 1.9024262e+02, 3.6513767e+02, 1.3079378e+00, 5.9805562e+02, 1.9283047e+02, 5.9805562e+02, 1.8352941e-02, 6.4927357e+01]) Coordinates: * loc_techs (loc_techs) <U22 'X3::power_lines:X1' ... 'X3::demand_electric... Attributes: is_result: 1
# Data can also be reformatted to be easier to read (removes dimension concatenation).
# Conversion to a pandas DataFrame is a good idea for greater readibility.
m.get_formatted_array('energy_cap').to_pandas()
techs | boiler | chp | demand_electricity | demand_heat | heat_pipes:N1 | heat_pipes:X1 | heat_pipes:X2 | heat_pipes:X3 | power_lines:X1 | power_lines:X2 | power_lines:X3 | pv | supply_gas | supply_grid_power |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
locs | ||||||||||||||
N1 | NaN | NaN | NaN | NaN | NaN | 598.05562 | 190.24262 | 10.382599 | NaN | NaN | NaN | NaN | NaN | NaN |
X1 | NaN | 260.9467 | 1.307938 | 1.719711 | 598.055620 | NaN | NaN | NaN | NaN | 274.5117 | 45.778336 | 0.000000 | 644.312830 | 33.620147 |
X2 | 192.83047 | NaN | 269.344350 | 365.137670 | 190.242620 | NaN | NaN | NaN | 274.511700 | NaN | NaN | 63.309509 | 226.859380 | NaN |
X3 | 0.01560 | NaN | 64.927357 | 9.398229 | 10.382599 | NaN | NaN | NaN | 45.778336 | NaN | NaN | 50.000000 | 0.018353 | NaN |
# >2 dimensions cannot be easily viewed in a pandas dataframe, unless a MultiIndex is used.
# To view a 4-dimensional result, we can use `to_series()`
m.get_formatted_array('carrier_prod').to_series().dropna() # drop_na() removes all NaN values
carriers locs techs timesteps electricity X1 chp 2005-07-01 00:00:00 116.076700 2005-07-01 01:00:00 98.082871 2005-07-01 02:00:00 98.596008 2005-07-01 03:00:00 98.596709 2005-07-01 04:00:00 104.005810 ... heat X3 heat_pipes:N1 2005-07-02 19:00:00 0.860291 2005-07-02 20:00:00 0.015600 2005-07-02 21:00:00 0.844700 2005-07-02 22:00:00 0.000000 2005-07-02 23:00:00 0.844690 Name: carrier_prod, Length: 1008, dtype: float64
m._backend_model is a Pyomo data structure, attached to which are Pyomo objects including Sets, Parameters, Constraints, and Variables
# A set
m._backend_model.loc_techs_energy_capacity_constraint.pprint()
loc_techs_energy_capacity_constraint : Size=1, Index=None, Ordered=Insertion Key : Dimen : Domain : Size : Members None : 1 : Any : 26 : {'X3::power_lines:X1', 'X1::supply_gas', 'X3::boiler', 'X3::pv', 'X2::pv', 'X1::supply_grid_power', 'X1::chp', 'X2::power_lines:X1', 'X1::power_lines:X2', 'X3::demand_heat', 'X2::heat_pipes:N1', 'X3::heat_pipes:N1', 'X1::pv', 'X1::power_lines:X3', 'X1::demand_heat', 'N1::heat_pipes:X3', 'X2::supply_gas', 'X2::demand_electricity', 'N1::heat_pipes:X2', 'X2::demand_heat', 'X1::demand_electricity', 'N1::heat_pipes:X1', 'X2::boiler', 'X1::heat_pipes:N1', 'X3::supply_gas', 'X3::demand_electricity'}
# A Parameter
m._backend_model.energy_cap_max.pprint()
energy_cap_max : Size=26, Index=loc_techs, Domain=NonNegativeReals, Default=inf, Mutable=True Key : Value N1::heat_pipes:X1 : 2000.0 N1::heat_pipes:X2 : 2000.0 N1::heat_pipes:X3 : 2000.0 X1::chp : 1500.0 X1::demand_electricity : inf X1::demand_heat : inf X1::heat_pipes:N1 : 2000.0 X1::power_lines:X2 : 2000.0 X1::power_lines:X3 : 2000.0 X1::pv : 250.0 X1::supply_gas : 2000.0 X1::supply_grid_power : 2000.0 X2::boiler : 600.0 X2::demand_electricity : inf X2::demand_heat : inf X2::heat_pipes:N1 : 2000.0 X2::power_lines:X1 : 2000.0 X2::pv : 250.0 X2::supply_gas : 2000.0 X3::boiler : 600.0 X3::demand_electricity : inf X3::demand_heat : inf X3::heat_pipes:N1 : 2000.0 X3::power_lines:X1 : 2000.0 X3::pv : 50.0 X3::supply_gas : 2000.0
# A constraint
m._backend_model.energy_capacity_constraint.pprint()
energy_capacity_constraint : Size=20, Index=loc_techs_energy_capacity_constraint, Active=True Key : Lower : Body : Upper : Active N1::heat_pipes:X1 : 0.0 : energy_cap['N1::heat_pipes:X1'] : energy_cap_max['N1::heat_pipes:X1'] : True N1::heat_pipes:X2 : 0.0 : energy_cap['N1::heat_pipes:X2'] : energy_cap_max['N1::heat_pipes:X2'] : True N1::heat_pipes:X3 : 0.0 : energy_cap['N1::heat_pipes:X3'] : energy_cap_max['N1::heat_pipes:X3'] : True X1::chp : 0.0 : energy_cap['X1::chp'] : energy_cap_max['X1::chp'] : True X1::heat_pipes:N1 : 0.0 : energy_cap['X1::heat_pipes:N1'] : energy_cap_max['X1::heat_pipes:N1'] : True X1::power_lines:X2 : 0.0 : energy_cap['X1::power_lines:X2'] : energy_cap_max['X1::power_lines:X2'] : True X1::power_lines:X3 : 0.0 : energy_cap['X1::power_lines:X3'] : energy_cap_max['X1::power_lines:X3'] : True X1::pv : 0.0 : energy_cap['X1::pv'] : energy_cap_max['X1::pv'] : True X1::supply_gas : 0.0 : energy_cap['X1::supply_gas'] : energy_cap_max['X1::supply_gas'] : True X1::supply_grid_power : 0.0 : energy_cap['X1::supply_grid_power'] : energy_cap_max['X1::supply_grid_power'] : True X2::boiler : 0.0 : energy_cap['X2::boiler'] : energy_cap_max['X2::boiler'] : True X2::heat_pipes:N1 : 0.0 : energy_cap['X2::heat_pipes:N1'] : energy_cap_max['X2::heat_pipes:N1'] : True X2::power_lines:X1 : 0.0 : energy_cap['X2::power_lines:X1'] : energy_cap_max['X2::power_lines:X1'] : True X2::pv : 0.0 : energy_cap['X2::pv'] : energy_cap_max['X2::pv'] : True X2::supply_gas : 0.0 : energy_cap['X2::supply_gas'] : energy_cap_max['X2::supply_gas'] : True X3::boiler : 0.0 : energy_cap['X3::boiler'] : energy_cap_max['X3::boiler'] : True X3::heat_pipes:N1 : 0.0 : energy_cap['X3::heat_pipes:N1'] : energy_cap_max['X3::heat_pipes:N1'] : True X3::power_lines:X1 : 0.0 : energy_cap['X3::power_lines:X1'] : energy_cap_max['X3::power_lines:X1'] : True X3::pv : 0.0 : energy_cap['X3::pv'] : energy_cap_max['X3::pv'] : True X3::supply_gas : 0.0 : energy_cap['X3::supply_gas'] : energy_cap_max['X3::supply_gas'] : True
# A variable
m._backend_model.energy_cap.pprint()
energy_cap : Size=26, Index=loc_techs Key : Lower : Value : Upper : Fixed : Stale : Domain N1::heat_pipes:X1 : 0 : 598.05562 : None : False : False : NonNegativeReals N1::heat_pipes:X2 : 0 : 190.24262 : None : False : False : NonNegativeReals N1::heat_pipes:X3 : 0 : 10.382599 : None : False : False : NonNegativeReals X1::chp : 0 : 260.9467 : None : False : False : NonNegativeReals X1::demand_electricity : 0 : 1.3079378 : None : False : False : NonNegativeReals X1::demand_heat : 0 : 1.7197109 : None : False : False : NonNegativeReals X1::heat_pipes:N1 : 0 : 598.05562 : None : False : False : NonNegativeReals X1::power_lines:X2 : 0 : 274.5117 : None : False : False : NonNegativeReals X1::power_lines:X3 : 0 : 45.778336 : None : False : False : NonNegativeReals X1::pv : 0 : 0.0 : None : False : False : NonNegativeReals X1::supply_gas : 0 : 644.31283 : None : False : False : NonNegativeReals X1::supply_grid_power : 0 : 33.620147 : None : False : False : NonNegativeReals X2::boiler : 0 : 192.83047 : None : False : False : NonNegativeReals X2::demand_electricity : 0 : 269.34435 : None : False : False : NonNegativeReals X2::demand_heat : 0 : 365.13767 : None : False : False : NonNegativeReals X2::heat_pipes:N1 : 0 : 190.24262 : None : False : False : NonNegativeReals X2::power_lines:X1 : 0 : 274.5117 : None : False : False : NonNegativeReals X2::pv : 0 : 63.309509 : None : False : False : NonNegativeReals X2::supply_gas : 0 : 226.85938 : None : False : False : NonNegativeReals X3::boiler : 0 : 0.0156 : None : False : False : NonNegativeReals X3::demand_electricity : 0 : 64.927357 : None : False : False : NonNegativeReals X3::demand_heat : 0 : 9.3982291 : None : False : False : NonNegativeReals X3::heat_pipes:N1 : 0 : 10.382599 : None : False : False : NonNegativeReals X3::power_lines:X1 : 0 : 45.778336 : None : False : False : NonNegativeReals X3::pv : 0 : 50.0 : None : False : False : NonNegativeReals X3::supply_gas : 0 : 0.018352941 : None : False : False : NonNegativeReals
There are a few interface methods available to the standard user, i.e. avoiding m._backend_model
# The inputs as used by Pyomo can be printed. This includes filled default data where necessary
pd.concat(
(m.backend.access_model_inputs()['energy_cap_max'].to_pandas().rename('backend'), # get the data from Pyomo
m.inputs['energy_cap_max'].to_pandas().rename('pre-run')), # get the data from model_data (via inputs)
axis=1, sort=True
)
backend | pre-run | |
---|---|---|
loc_techs | ||
N1::heat_pipes:X1 | 2000.0 | 2000.0 |
N1::heat_pipes:X2 | 2000.0 | 2000.0 |
N1::heat_pipes:X3 | 2000.0 | 2000.0 |
X1::chp | 1500.0 | 1500.0 |
X1::demand_electricity | inf | NaN |
X1::demand_heat | inf | NaN |
X1::heat_pipes:N1 | 2000.0 | 2000.0 |
X1::power_lines:X2 | 2000.0 | 2000.0 |
X1::power_lines:X3 | 2000.0 | 2000.0 |
X1::pv | 250.0 | 250.0 |
X1::supply_gas | 2000.0 | 2000.0 |
X1::supply_grid_power | 2000.0 | 2000.0 |
X2::boiler | 600.0 | 600.0 |
X2::demand_electricity | inf | NaN |
X2::demand_heat | inf | NaN |
X2::heat_pipes:N1 | 2000.0 | 2000.0 |
X2::power_lines:X1 | 2000.0 | 2000.0 |
X2::pv | 250.0 | 250.0 |
X2::supply_gas | 2000.0 | 2000.0 |
X3::boiler | 600.0 | 600.0 |
X3::demand_electricity | inf | NaN |
X3::demand_heat | inf | NaN |
X3::heat_pipes:N1 | 2000.0 | 2000.0 |
X3::power_lines:X1 | 2000.0 | 2000.0 |
X3::pv | 50.0 | 50.0 |
X3::supply_gas | 2000.0 | 2000.0 |
# We can activate and deactivate constraints, such as switching off the energy capacity constraint
m.backend.activate_constraint('energy_capacity_constraint', False) # set to True to activate
m._backend_model.energy_capacity_constraint.pprint()
energy_capacity_constraint : Size=20, Index=loc_techs_energy_capacity_constraint, Active=False Key : Lower : Body : Upper : Active N1::heat_pipes:X1 : 0.0 : energy_cap['N1::heat_pipes:X1'] : energy_cap_max['N1::heat_pipes:X1'] : False N1::heat_pipes:X2 : 0.0 : energy_cap['N1::heat_pipes:X2'] : energy_cap_max['N1::heat_pipes:X2'] : False N1::heat_pipes:X3 : 0.0 : energy_cap['N1::heat_pipes:X3'] : energy_cap_max['N1::heat_pipes:X3'] : False X1::chp : 0.0 : energy_cap['X1::chp'] : energy_cap_max['X1::chp'] : False X1::heat_pipes:N1 : 0.0 : energy_cap['X1::heat_pipes:N1'] : energy_cap_max['X1::heat_pipes:N1'] : False X1::power_lines:X2 : 0.0 : energy_cap['X1::power_lines:X2'] : energy_cap_max['X1::power_lines:X2'] : False X1::power_lines:X3 : 0.0 : energy_cap['X1::power_lines:X3'] : energy_cap_max['X1::power_lines:X3'] : False X1::pv : 0.0 : energy_cap['X1::pv'] : energy_cap_max['X1::pv'] : False X1::supply_gas : 0.0 : energy_cap['X1::supply_gas'] : energy_cap_max['X1::supply_gas'] : False X1::supply_grid_power : 0.0 : energy_cap['X1::supply_grid_power'] : energy_cap_max['X1::supply_grid_power'] : False X2::boiler : 0.0 : energy_cap['X2::boiler'] : energy_cap_max['X2::boiler'] : False X2::heat_pipes:N1 : 0.0 : energy_cap['X2::heat_pipes:N1'] : energy_cap_max['X2::heat_pipes:N1'] : False X2::power_lines:X1 : 0.0 : energy_cap['X2::power_lines:X1'] : energy_cap_max['X2::power_lines:X1'] : False X2::pv : 0.0 : energy_cap['X2::pv'] : energy_cap_max['X2::pv'] : False X2::supply_gas : 0.0 : energy_cap['X2::supply_gas'] : energy_cap_max['X2::supply_gas'] : False X3::boiler : 0.0 : energy_cap['X3::boiler'] : energy_cap_max['X3::boiler'] : False X3::heat_pipes:N1 : 0.0 : energy_cap['X3::heat_pipes:N1'] : energy_cap_max['X3::heat_pipes:N1'] : False X3::power_lines:X1 : 0.0 : energy_cap['X3::power_lines:X1'] : energy_cap_max['X3::power_lines:X1'] : False X3::pv : 0.0 : energy_cap['X3::pv'] : energy_cap_max['X3::pv'] : False X3::supply_gas : 0.0 : energy_cap['X3::supply_gas'] : energy_cap_max['X3::supply_gas'] : False
# Rerun the model with this constraint switched off.
# This will dump results to a new dataset, *NOT* to m._model_data (or m.results)
new_model = m.backend.rerun()
[2023-01-18 13:21:24] INFO model_creation [2023-01-18 13:21:24] INFO Backend: starting model run [2023-01-18 13:21:24] INFO Backend: sending model to solver [2023-01-18 13:21:24] INFO Backend: solver finished running. Time since start of model run: 0:00:00.405365 [2023-01-18 13:21:24] INFO Backend: loaded results [2023-01-18 13:21:24] INFO Backend: generated solution array. Time since start of model run: 0:00:00.502773 [2023-01-18 13:21:24] INFO Postprocessing: started [2023-01-18 13:21:25] INFO Postprocessing: All values < 1e-10 set to 0 in system_balance [2023-01-18 13:21:25] INFO Postprocessing: ended. Time since start of model run: 0:00:00.622720 [2023-01-18 13:21:25] WARNING /Users/brynmorp/Repos/calliope-project/calliope/calliope/exceptions.py:60: ModelWarning: The results of rerunning the backend model are only available within the Calliope model returned by this function call. [2023-01-18 13:21:25] INFO Model: initialising [2023-01-18 13:21:25] INFO Model: loaded model_data
# The results are now updated, which we can compare to our old results
pd.concat((new_model.results.energy_cap.to_pandas().rename('new'), m.results.energy_cap.to_pandas().rename('old')),
axis=1, sort=True)
new | old | |
---|---|---|
loc_techs | ||
N1::heat_pipes:X1 | 577.990760 | 598.055620 |
N1::heat_pipes:X2 | 184.854000 | 190.242620 |
N1::heat_pipes:X3 | 10.382599 | 10.382599 |
X1::chp | 253.679380 | 260.946700 |
X1::demand_electricity | 1.307938 | 1.307938 |
X1::demand_heat | 1.719711 | 1.719711 |
X1::heat_pipes:N1 | 577.990760 | 598.055620 |
X1::power_lines:X2 | 274.841170 | 274.511700 |
X1::power_lines:X3 | 66.370659 | 45.778336 |
X1::pv | 0.000000 | 0.000000 |
X1::supply_gas | 626.368830 | 644.312830 |
X1::supply_grid_power | 40.808044 | 33.620147 |
X2::boiler | 197.824970 | 192.830470 |
X2::demand_electricity | 269.344350 | 269.344350 |
X2::demand_heat | 365.137670 | 365.137670 |
X2::heat_pipes:N1 | 184.854000 | 190.242620 |
X2::power_lines:X1 | 274.841170 | 274.511700 |
X2::pv | 0.000000 | 63.309509 |
X2::supply_gas | 232.735260 | 226.859380 |
X3::boiler | 0.015600 | 0.015600 |
X3::demand_electricity | 64.927357 | 64.927357 |
X3::demand_heat | 9.398229 | 9.398229 |
X3::heat_pipes:N1 | 10.382599 | 10.382599 |
X3::power_lines:X1 | 66.370659 | 45.778336 |
X3::pv | 128.571430 | 50.000000 |
X3::supply_gas | 0.018353 | 0.018353 |
# We can also see that the Pyomo backend_model has updated to the new values
m._backend_model.energy_cap.pprint()
energy_cap : Size=26, Index=loc_techs Key : Lower : Value : Upper : Fixed : Stale : Domain N1::heat_pipes:X1 : 0 : 577.99076 : None : False : False : NonNegativeReals N1::heat_pipes:X2 : 0 : 184.854 : None : False : False : NonNegativeReals N1::heat_pipes:X3 : 0 : 10.382599 : None : False : False : NonNegativeReals X1::chp : 0 : 253.67938 : None : False : False : NonNegativeReals X1::demand_electricity : 0 : 1.3079378 : None : False : False : NonNegativeReals X1::demand_heat : 0 : 1.7197109 : None : False : False : NonNegativeReals X1::heat_pipes:N1 : 0 : 577.99076 : None : False : False : NonNegativeReals X1::power_lines:X2 : 0 : 274.84117 : None : False : False : NonNegativeReals X1::power_lines:X3 : 0 : 66.370659 : None : False : False : NonNegativeReals X1::pv : 0 : 0.0 : None : False : False : NonNegativeReals X1::supply_gas : 0 : 626.36883 : None : False : False : NonNegativeReals X1::supply_grid_power : 0 : 40.808044 : None : False : False : NonNegativeReals X2::boiler : 0 : 197.82497 : None : False : False : NonNegativeReals X2::demand_electricity : 0 : 269.34435 : None : False : False : NonNegativeReals X2::demand_heat : 0 : 365.13767 : None : False : False : NonNegativeReals X2::heat_pipes:N1 : 0 : 184.854 : None : False : False : NonNegativeReals X2::power_lines:X1 : 0 : 274.84117 : None : False : False : NonNegativeReals X2::pv : 0 : 0.0 : None : False : False : NonNegativeReals X2::supply_gas : 0 : 232.73526 : None : False : False : NonNegativeReals X3::boiler : 0 : 0.0156 : None : False : False : NonNegativeReals X3::demand_electricity : 0 : 64.927357 : None : False : False : NonNegativeReals X3::demand_heat : 0 : 9.3982291 : None : False : False : NonNegativeReals X3::heat_pipes:N1 : 0 : 10.382599 : None : False : False : NonNegativeReals X3::power_lines:X1 : 0 : 66.370659 : None : False : False : NonNegativeReals X3::pv : 0 : 128.57143 : None : False : False : NonNegativeReals X3::supply_gas : 0 : 0.018352941 : None : False : False : NonNegativeReals
# With the original data (i.e. capacity constraint is active), we can plot the capacities
m.plot.capacity()
[2023-01-18 13:21:25] WARNING /Users/brynmorp/Repos/calliope-project/calliope/calliope/postprocess/plotting/plotting.py:105: FutureWarning: Plotting will no longer be available as a method of the Calliope model object infuture versions of Calliope. In the meantime, as of v0.6.6, plotting is untested; this functionality should now be used with caution. We expect to reintroduce it as a seperate module in v0.7.0.
# We can save at any point, which will dump the entire m._model_data to file.
# NetCDF is recommended, as it retains most of the data and can be reloaded into a Calliope model at a later date.
m.to_netcdf('path/to/file.nc') # Saves a single file
m.to_csv('path/to/folder') # Saves a file for each xarray DataArray