import calliope
# We increase logging verbosity
calliope.set_log_verbosity('INFO', include_solver_output=False)
model = calliope.examples.urban_scale()
[2023-01-18 13:24:40] INFO Model: initialising [2023-01-18 13:24:40] INFO Model: preprocessing stage 1 (model_run) [2023-01-18 13:24:43] INFO Model: preprocessing stage 2 (model_data) [2023-01-18 13:24:43] INFO Model: preprocessing complete
# Model inputs can be viewed at `model.inputs`.
# Variables are indexed over any combination of `techs`, `locs`, `carriers`, `costs` and `timesteps`,
# although `techs`, `locs`, and `carriers` are often concatenated.
# e.g. `chp`, `X1`, `heat` -> `X1::chp::heat`
model.inputs
<xarray.Dataset> Dimensions: (loc_techs_finite_resource: 9, loc_techs_area: 3, loc_techs: 26, loc_techs_supply_plus: 3, loc_techs_export: 4, timesteps: 48, 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 'heat' ... 'gas' * coordinates (coordinates) object 'x' 'y' * costs (costs) object 'monetary' * loc_carriers (loc_carriers) object 'X1::heat' ..... * loc_tech_carriers_conversion_plus (loc_tech_carriers_conversion_plus) object ... ... ... * loc_techs_om_cost (loc_techs_om_cost) object 'X2::boi... * loc_techs_supply_plus (loc_techs_supply_plus) object 'X1:... * loc_techs_transmission (loc_techs_transmission) object 'N1... * locs (locs) object 'N1' 'X3' 'X2' 'X1' * techs (techs) object 'heat_pipes' ... 'po... * timesteps (timesteps) datetime64[ns] 2005-07-... Data variables: (12/38) force_resource (loc_techs_finite_resource) bool Tr... resource_area_max (loc_techs_area) int64 1500 1500 1500 energy_prod (loc_techs) float64 nan 1.0 ... 1.0 energy_cap_max (loc_techs) float64 nan ... 2e+03 resource_area_per_energy_cap (loc_techs_area) int64 7 7 7 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
# Individual data variables can be accessed easily, `to_pandas()` reformats the data to look nicer
model.inputs.resource.to_pandas()
timesteps | 2005-07-01 00:00:00 | 2005-07-01 01:00:00 | 2005-07-01 02:00:00 | 2005-07-01 03:00:00 | 2005-07-01 04:00:00 | 2005-07-01 05:00:00 | 2005-07-01 06:00:00 | 2005-07-01 07:00:00 | 2005-07-01 08:00:00 | 2005-07-01 09:00:00 | ... | 2005-07-02 14:00:00 | 2005-07-02 15:00:00 | 2005-07-02 16:00:00 | 2005-07-02 17:00:00 | 2005-07-02 18:00:00 | 2005-07-02 19:00:00 | 2005-07-02 20:00:00 | 2005-07-02 21:00:00 | 2005-07-02 22:00:00 | 2005-07-02 23:00:00 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
loc_techs_finite_resource | |||||||||||||||||||||
X3::demand_electricity | -18.762912 | -18.762912 | -18.762912 | -18.762912 | -18.762912 | -30.212425 | -35.233307 | -61.395269 | -63.642962 | -62.679665 | ... | -18.762912 | -18.954418 | -19.145924 | -18.762912 | -18.762912 | -18.762912 | -18.762912 | -18.762912 | -18.762912 | -18.762912 |
X1::pv | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.007857 | 0.029143 | 0.055571 | 0.078429 | 0.096000 | ... | 0.057857 | 0.041143 | 0.027000 | 0.014714 | 0.006143 | 0.000857 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
X2::demand_heat | -64.731991 | -70.453439 | -77.192976 | -104.556436 | -123.228444 | -167.668819 | -264.887092 | -365.137675 | -258.172589 | -190.585578 | ... | -105.261025 | -84.614417 | -104.549875 | -122.646451 | -166.442507 | -161.099889 | -166.931078 | -240.034833 | -143.576460 | -86.082014 |
X3::demand_heat | -0.015600 | -0.860322 | -0.015600 | -0.015600 | -0.860407 | -7.263327 | -9.398229 | -5.792842 | -3.322585 | -1.927264 | ... | -0.015600 | -0.015600 | -0.860335 | -0.015600 | -0.015600 | -0.860291 | -0.015600 | -0.860300 | -0.015600 | -0.860290 |
X2::pv | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.007857 | 0.029143 | 0.055571 | 0.078429 | 0.096000 | ... | 0.057857 | 0.041143 | 0.027000 | 0.014714 | 0.006143 | 0.000857 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
X2::demand_electricity | -94.545801 | -76.960619 | -77.475750 | -77.475750 | -82.731496 | -148.533479 | -189.570817 | -238.734711 | -244.284493 | -231.440181 | ... | -199.895515 | -221.324570 | -188.344877 | -249.962248 | -248.894106 | -269.344347 | -245.412357 | -196.280957 | -135.289242 | -103.741556 |
X3::pv | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.007857 | 0.029143 | 0.055571 | 0.078429 | 0.096000 | ... | 0.057857 | 0.041143 | 0.027000 | 0.014714 | 0.006143 | 0.000857 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
X1::demand_electricity | -0.455564 | -0.405798 | -0.393291 | -0.393992 | -0.440085 | -0.567821 | -0.732535 | -0.713803 | -0.689992 | -0.707650 | ... | -0.683060 | -0.780370 | -0.940634 | -0.978388 | -1.022063 | -1.169519 | -1.307938 | -1.099334 | -0.826212 | -0.559499 |
X1::demand_heat | -0.215376 | -0.200838 | -0.207306 | -0.318949 | -0.650734 | -1.039384 | -1.181567 | -1.285403 | -1.209117 | -1.219912 | ... | -0.491097 | -0.540068 | -0.641510 | -0.741098 | -0.761822 | -0.707075 | -0.634092 | -0.523707 | -0.400787 | -0.272040 |
9 rows × 48 columns
# To reformat the array, deconcatenating loc_techs / loc_tech_carriers, you can use model.get_formatted_array()
# You can then apply loc/tech/carrier only operations, like summing information over locations:
model.get_formatted_array('resource').sum('locs').to_pandas()
timesteps | 2005-07-01 00:00:00 | 2005-07-01 01:00:00 | 2005-07-01 02:00:00 | 2005-07-01 03:00:00 | 2005-07-01 04:00:00 | 2005-07-01 05:00:00 | 2005-07-01 06:00:00 | 2005-07-01 07:00:00 | 2005-07-01 08:00:00 | 2005-07-01 09:00:00 | ... | 2005-07-02 14:00:00 | 2005-07-02 15:00:00 | 2005-07-02 16:00:00 | 2005-07-02 17:00:00 | 2005-07-02 18:00:00 | 2005-07-02 19:00:00 | 2005-07-02 20:00:00 | 2005-07-02 21:00:00 | 2005-07-02 22:00:00 | 2005-07-02 23:00:00 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
techs | |||||||||||||||||||||
demand_electricity | -113.764277 | -96.129329 | -96.631954 | -96.632654 | -101.934493 | -179.313724 | -225.536658 | -300.843784 | -308.617446 | -294.827496 | ... | -219.341487 | -241.059359 | -208.431436 | -269.703548 | -268.679081 | -289.276777 | -265.483207 | -216.143204 | -154.878366 | -123.063967 |
demand_heat | -64.962967 | -71.514599 | -77.415882 | -104.890985 | -124.739585 | -175.971530 | -275.466888 | -372.215920 | -262.704292 | -193.732754 | ... | -105.767723 | -85.170084 | -106.051720 | -123.403148 | -167.219928 | -162.667255 | -167.580770 | -241.418840 | -143.992847 | -87.214344 |
pv | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.000000 | 0.023571 | 0.087429 | 0.166714 | 0.235286 | 0.288000 | ... | 0.173571 | 0.123429 | 0.081000 | 0.044143 | 0.018429 | 0.002571 | 0.000000 | 0.000000 | 0.000000 | 0.000000 |
3 rows × 48 columns
# Solve the model. Results are loaded into `model.results`.
# By including logging (see package importing), we can see the timing of parts of the run, as well as the solver's log
model.run()
[2023-01-18 13:24:46] INFO Backend: starting model run [2023-01-18 13:24:46] INFO Loading sets [2023-01-18 13:24:46] INFO Loading parameters [2023-01-18 13:24:46] 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:24:46] INFO creating capacity constraints [2023-01-18 13:24:46] INFO creating dispatch constraints [2023-01-18 13:24:46] INFO creating policy constraints [2023-01-18 13:24:46] INFO creating energy_balance constraints [2023-01-18 13:24:46] INFO creating costs constraints [2023-01-18 13:24:46] INFO creating network constraints [2023-01-18 13:24:46] INFO creating conversion constraints [2023-01-18 13:24:46] INFO creating group constraints [2023-01-18 13:24:46] INFO creating conversion_plus constraints [2023-01-18 13:24:46] INFO creating export constraints [2023-01-18 13:24:46] INFO creating milp constraints [2023-01-18 13:24:47] INFO Backend: model generated. Time since start of model run: 0:00:00.944208 [2023-01-18 13:24:47] INFO Backend: sending model to solver [2023-01-18 13:24:47] INFO Backend: solver finished running. Time since start of model run: 0:00:01.567531 [2023-01-18 13:24:47] INFO Backend: loaded results [2023-01-18 13:24:47] INFO Backend: generated solution array. Time since start of model run: 0:00:01.694511 [2023-01-18 13:24:47] INFO Postprocessing: started [2023-01-18 13:24:47] INFO Postprocessing: All values < 1e-10 set to 0 in system_balance [2023-01-18 13:24:47] INFO Postprocessing: ended. Time since start of model run: 0:00:01.874165
# Model results are held in the same structure as model inputs.
# The results consist of the optimal values for all decision variables, including capacities and carrier flow
# There are also results, like system capacity factor and levelised costs, which are calculated in postprocessing
# before being added to the results Dataset
model.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::heat' ..... * 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 'X1::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 'X2::boi... * loc_techs_supply_plus (loc_techs_supply_plus) <U6 'X1::... * timesteps (timesteps) datetime64[ns] 2005-0... Data variables: (12/19) energy_cap (loc_techs) float64 64.93 ... 10.38 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 0.0 ... ... 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.3529094335402 solution_time: 1.694511 time_finished: 2023-01-18 13:24:47 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...
# We can sum heat output over all locations and turn the result into a pandas DataFrame
df_heat = model.get_formatted_array('carrier_prod').loc[{'carriers':'heat'}].sum('locs').to_pandas().T
#The information about the dataframe tells us about the amount of data it holds in the index and in each column
df_heat.info()
<class 'pandas.core.frame.DataFrame'> DatetimeIndex: 48 entries, 2005-07-01 00:00:00 to 2005-07-02 23:00:00 Data columns (total 12 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 boiler 48 non-null float64 1 chp 48 non-null float64 2 heat_pipes:N1 48 non-null float64 3 heat_pipes:X1 48 non-null float64 4 heat_pipes:X2 48 non-null float64 5 heat_pipes:X3 48 non-null float64 6 power_lines:X1 48 non-null float64 7 power_lines:X2 48 non-null float64 8 power_lines:X3 48 non-null float64 9 pv 48 non-null float64 10 supply_gas 48 non-null float64 11 supply_grid_power 48 non-null float64 dtypes: float64(12) memory usage: 5.9 KB
# Using .head() to see the first few rows of heat generation and demand
# Note: carrier production in heat_pipes:N1 is heat received by the heat network at any location connected to `N1`
df_heat.head()
techs | boiler | chp | 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 |
---|---|---|---|---|---|---|---|---|---|---|---|---|
timesteps | ||||||||||||
2005-07-01 00:00:00 | 0.000000 | 92.861360 | 170.055601 | 183.475520 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
2005-07-01 01:00:00 | 4.100046 | 78.466297 | 67.213715 | 72.541074 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
2005-07-01 02:00:00 | 9.626102 | 78.876806 | 67.582474 | 72.915564 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
2005-07-01 03:00:00 | 37.084989 | 78.877367 | 67.487047 | 72.812606 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
2005-07-01 04:00:00 | 53.191064 | 83.204646 | 70.897788 | 76.515868 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
# We can plot this by using the timeseries plotting functionality.
# The top-left dropdown gives us the chance to scroll through other timeseries data too.
model.plot.timeseries()
[2023-01-18 13:24:49] 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.