Calliope Urban Scale Example Model

In [1]:
import calliope

# We increase logging verbosity
calliope.set_log_verbosity('INFO', include_solver_output=False)
In [2]:
model = calliope.examples.urban_scale()
[2020-10-08 20:14:41] INFO     Model: initialising
[2020-10-08 20:14:41] INFO     Model: preprocessing stage 1 (model_run)
[2020-10-08 20:14:42] INFO     Model: preprocessing stage 2 (model_data)
[2020-10-08 20:14:42] INFO     Model: preprocessing complete
In [3]:
# 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
Out[3]:
<xarray.Dataset>
Dimensions:                               (carrier_tiers: 3, carriers: 3, coordinates: 2, costs: 1, loc_carriers: 10, loc_tech_carriers_conversion_plus: 3, loc_techs: 26, loc_techs_area: 3, loc_techs_conversion: 2, loc_techs_conversion_plus: 1, loc_techs_export: 4, loc_techs_finite_resource: 9, loc_techs_investment_cost: 20, loc_techs_non_conversion: 23, loc_techs_om_cost: 9, loc_techs_supply_plus: 3, loc_techs_transmission: 10, locs: 4, techs: 9, timesteps: 48)
Coordinates:
  * carrier_tiers                         (carrier_tiers) object 'out_2' ... ...
  * carriers                              (carriers) object 'gas' ... 'electr...
  * coordinates                           (coordinates) object 'x' 'y'
  * costs                                 (costs) object 'monetary'
  * loc_carriers                          (loc_carriers) object 'X2::gas' ......
  * loc_tech_carriers_conversion_plus     (loc_tech_carriers_conversion_plus) object ...
  * loc_techs                             (loc_techs) object 'N1::heat_pipes:...
  * loc_techs_area                        (loc_techs_area) object 'X3::pv' .....
  * loc_techs_conversion                  (loc_techs_conversion) object 'X3::...
  * loc_techs_conversion_plus             (loc_techs_conversion_plus) object ...
  * loc_techs_export                      (loc_techs_export) object 'X3::pv' ...
  * loc_techs_finite_resource             (loc_techs_finite_resource) object ...
  * loc_techs_investment_cost             (loc_techs_investment_cost) object ...
  * loc_techs_non_conversion              (loc_techs_non_conversion) object '...
  * loc_techs_om_cost                     (loc_techs_om_cost) object 'X2::pv'...
  * loc_techs_supply_plus                 (loc_techs_supply_plus) object 'X3:...
  * loc_techs_transmission                (loc_techs_transmission) object 'N1...
  * locs                                  (locs) object 'N1' 'X3' 'X2' 'X1'
  * techs                                 (techs) object 'supply_gas' ... 'bo...
  * timesteps                             (timesteps) datetime64[ns] 2005-07-...
Data variables:
    resource                              (loc_techs_finite_resource, timesteps) float64 ...
    energy_prod                           (loc_techs) float64 1.0 1.0 ... 1.0
    energy_cap_max                        (loc_techs) float64 2e+03 ... 2e+03
    force_resource                        (loc_techs_finite_resource) bool Tr...
    resource_eff                          (loc_techs_finite_resource) float64 ...
    resource_area_max                     (loc_techs_area) int64 1500 1500 1500
    lifetime                              (loc_techs) float64 25.0 25.0 ... 25.0
    parasitic_eff                         (loc_techs_supply_plus) float64 0.8...
    resource_unit                         (loc_techs_finite_resource) <U15 'e...
    resource_area_per_energy_cap          (loc_techs_area) int64 7 7 7
    energy_con                            (loc_techs) float64 1.0 nan ... nan
    export_carrier                        (loc_techs_export) <U11 'electricit...
    energy_eff                            (loc_techs) float64 0.9269 nan ... nan
    cost_export                           (costs, loc_techs_om_cost, timesteps) float64 ...
    cost_om_con                           (costs, loc_techs_om_cost) float64 ...
    cost_om_annual                        (costs, loc_techs_om_cost) float64 ...
    cost_om_prod                          (costs, loc_techs_om_cost) float64 ...
    cost_energy_cap                       (costs, loc_techs_investment_cost) float64 ...
    cost_depreciation_rate                (costs, loc_techs_investment_cost) float64 ...
    distance                              (loc_techs_transmission) float64 3....
    lookup_remotes                        (loc_techs_transmission) <U18 'X1::...
    available_area                        (locs) float64 nan 900.0 1.3e+03 500.0
    loc_coordinates                       (coordinates, locs) int64 5 5 ... 7 7
    colors                                (techs) <U7 '#C98AAD' ... '#8E2999'
    inheritance                           (techs) <U29 'supply' ... 'conversion'
    names                                 (techs) <U29 'Natural gas import' ....
    carrier_ratios                        (carrier_tiers, loc_tech_carriers_conversion_plus) float64 ...
    lookup_loc_carriers                   (loc_carriers) <U175 'X2::boiler::g...
    lookup_loc_techs                      (loc_techs_non_conversion) <U35 'N1...
    lookup_loc_techs_conversion           (carrier_tiers, loc_techs_conversion) object ...
    lookup_primary_loc_tech_carriers_in   (loc_techs_conversion_plus) <U12 'X...
    lookup_primary_loc_tech_carriers_out  (loc_techs_conversion_plus) <U20 'X...
    lookup_loc_techs_conversion_plus      (carrier_tiers, loc_techs_conversion_plus) object ...
    lookup_loc_techs_export               (loc_techs_export) <U20 'X3::pv::el...
    lookup_loc_techs_area                 (locs) <U6 '' '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.6
    applied_overrides:   
    scenario:            None
    defaults:            available_area: null\ncarrier_ratios: false\ncharge_...
    allow_operate_mode:  1
In [4]:
# Individual data variables can be accessed easily, `to_pandas()` reformats the data to look nicer
model.inputs.resource.to_pandas()
Out[4]:
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
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
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
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
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
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_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
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
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

9 rows × 48 columns

In [5]:
# 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()
Out[5]:
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

In [6]:
# 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()
[2020-10-08 20:14:42] INFO     Backend: starting model run
[2020-10-08 20:14:43] INFO     constraints are loaded in the following order: ['capacity', 'dispatch', 'policy', 'energy_balance', 'costs', 'network', 'conversion', 'group', 'conversion_plus', 'export', 'milp']
[2020-10-08 20:14:43] INFO     Backend: model generated. Time since start of model run: 0:00:00.386264
[2020-10-08 20:14:43] INFO     Backend: sending model to solver
[2020-10-08 20:14:43] INFO     Backend: solver finished running. Time since start of model run: 0:00:00.974130
[2020-10-08 20:14:43] INFO     Backend: loaded results
[2020-10-08 20:14:43] INFO     Backend: generated solution array. Time since start of model run: 0:00:01.019879
[2020-10-08 20:14:43] INFO     Postprocessing: started
[2020-10-08 20:14:44] INFO     Postprocessing: zero threshold of 1e-10 not required
[2020-10-08 20:14:44] INFO     Postprocessing: Model was feasible, deleting unmet_demand variable
[2020-10-08 20:14:44] INFO     Postprocessing: ended. Time since start of model run: 0:00:01.200263
In [7]:
# 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
Out[7]:
<xarray.Dataset>
Dimensions:                     (carriers: 3, costs: 1, loc_tech_carriers_con: 19, loc_tech_carriers_export: 4, loc_tech_carriers_prod: 21, loc_techs: 26, loc_techs_area: 3, loc_techs_cost: 20, loc_techs_investment_cost: 20, loc_techs_om_cost: 9, loc_techs_supply_plus: 3, techs: 9, timesteps: 48)
Coordinates:
  * carriers                    (carriers) object 'gas' 'heat' 'electricity'
  * loc_tech_carriers_con       (loc_tech_carriers_con) object 'X2::boiler::g...
  * loc_tech_carriers_export    (loc_tech_carriers_export) object 'X1::chp::e...
  * loc_tech_carriers_prod      (loc_tech_carriers_prod) object 'X2::heat_pip...
  * loc_techs                   (loc_techs) object 'N1::heat_pipes:X1' ... 'X...
  * loc_techs_area              (loc_techs_area) object 'X3::pv' ... 'X1::pv'
  * loc_techs_cost              (loc_techs_cost) object 'N1::heat_pipes:X1' ....
  * loc_techs_investment_cost   (loc_techs_investment_cost) object 'N1::heat_...
  * loc_techs_om_cost           (loc_techs_om_cost) object 'X2::pv' ... 'X2::...
  * loc_techs_supply_plus       (loc_techs_supply_plus) object 'X3::pv' ... '...
  * techs                       (techs) object 'supply_gas' ... 'boiler'
  * costs                       (costs) object 'monetary'
  * timesteps                   (timesteps) datetime64[ns] 2005-07-01 ... 200...
Data variables:
    energy_cap                  (loc_techs) float64 598.1 50.0 ... 365.1 226.9
    carrier_prod                (loc_tech_carriers_prod, timesteps) float64 6...
    carrier_con                 (loc_tech_carriers_con, timesteps) float64 0....
    cost                        (costs, loc_techs_cost) float64 0.1625 ... 41.99
    resource_area               (loc_techs_area) float64 350.0 443.2 0.0
    resource_con                (loc_techs_supply_plus, timesteps) float64 0....
    resource_cap                (loc_techs_supply_plus) float64 38.95 49.32 0.0
    carrier_export              (loc_tech_carriers_export, timesteps) float64 ...
    cost_var                    (costs, loc_techs_om_cost, timesteps) float64 ...
    cost_investment             (costs, loc_techs_investment_cost) float64 0....
    capacity_factor             (timesteps, loc_tech_carriers_prod) float64 0...
    systemwide_capacity_factor  (carriers, techs) float64 0.5841 nan ... 0.0
    systemwide_levelised_cost   (carriers, costs, techs) float64 0.02502 ... inf
    total_levelised_cost        (carriers, costs) float64 0.03449 ... 0.08069
Attributes:
    calliope_version:          0.6.6
    applied_overrides:         
    scenario:                  None
    defaults:                  available_area: null\ncarrier_ratios: false\nc...
    allow_operate_mode:        1
    model_config:              calliope_version: 0.6.6\nname: Urban-scale exa...
    run_config:                backend: pyomo\nbigM: 1000000.0\ncyclic_storag...
    termination_condition:     optimal
    objective_function_value:  842.3529094335403
    solution_time:             1.019879
    time_finished:             2020-10-08 20:14:43
In [8]:
# 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: 4.9 KB
In [9]:
# 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()
Out[9]:
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
In [10]:
# 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()
[2020-10-08 20:14:46] WARNING  /Users/brynmorp/OneDrive/Projects/project-calliope/repos/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.