import calliope
# We increase logging verbosity
calliope.set_log_verbosity('INFO', include_solver_output=False)
model = calliope.examples.national_scale()
[2023-01-18 13:22:58] INFO Model: initialising [2023-01-18 13:22:58] INFO Model: preprocessing stage 1 (model_run) [2023-01-18 13:22:59] INFO Model: preprocessing stage 2 (model_data) [2023-01-18 13:22:59] 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. `ccgt`, `region1`, `power` -> `region1::ccgt::power`
model.inputs
<xarray.Dataset> Dimensions: (loc_techs: 15, loc_techs_store: 4, loc_techs_finite_resource: 5, timesteps: 120, loc_techs_supply_plus: 3, loc_techs_area: 3, costs: 1, loc_techs_investment_cost: 7, loc_techs_om_cost: 12, loc_techs_transmission: 8, coordinates: 2, locs: 5, techs: 6, loc_carriers: 5, loc_techs_non_conversion: 15, carriers: 1) Coordinates: (12/16) * carriers (carriers) <U5 'power' * coordinates (coordinates) object 'lat' 'lon' * costs (costs) object 'monetary' * loc_carriers (loc_carriers) object 'region1::power' ..... * loc_techs (loc_techs) object 'region1::free_transmi... * loc_techs_area (loc_techs_area) object 'region1-3::csp' ... ... ... * loc_techs_store (loc_techs_store) object 'region1-3::csp'... * loc_techs_supply_plus (loc_techs_supply_plus) object 'region1-3... * loc_techs_transmission (loc_techs_transmission) object 'region1:... * locs (locs) object 'region2' ... 'region1-3' * techs (techs) object 'ac_transmission' ... 'csp' * timesteps (timesteps) datetime64[ns] 2005-01-01 ...... Data variables: (12/34) lifetime (loc_techs) float64 nan 25.0 ... nan 25.0 energy_cap_per_storage_cap_max (loc_techs_store) int64 1 4 1 1 energy_con (loc_techs) float64 1.0 1.0 nan ... 1.0 1.0 energy_cap_max (loc_techs) float64 inf 1e+04 ... inf 1e+04 resource (loc_techs_finite_resource, timesteps) float64 ... resource_unit (loc_techs_finite_resource) object 'energ... ... ... lookup_loc_carriers (loc_carriers) object 'region1::free_tran... lookup_loc_techs (loc_techs_non_conversion) object 'region... lookup_loc_techs_area (locs) object '' ... 'region1-3::csp' timestep_resolution (timesteps) float64 1.0 1.0 1.0 ... 1.0 1.0 timestep_weights (timesteps) float64 1.0 1.0 1.0 ... 1.0 1.0 max_demand_timesteps (carriers) datetime64[ns] 2005-01-05T16: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-01-01 00:00:00 | 2005-01-01 01:00:00 | 2005-01-01 02:00:00 | 2005-01-01 03:00:00 | 2005-01-01 04:00:00 | 2005-01-01 05:00:00 | 2005-01-01 06:00:00 | 2005-01-01 07:00:00 | 2005-01-01 08:00:00 | 2005-01-01 09:00:00 | ... | 2005-01-05 14:00:00 | 2005-01-05 15:00:00 | 2005-01-05 16:00:00 | 2005-01-05 17:00:00 | 2005-01-05 18:00:00 | 2005-01-05 19:00:00 | 2005-01-05 20:00:00 | 2005-01-05 21:00:00 | 2005-01-05 22:00:00 | 2005-01-05 23:00:00 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
loc_techs_finite_resource | |||||||||||||||||||||
region1-1::csp | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.021060 | 0.263805 | 0.434037 | ... | 0.322062 | 0.07927 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
region1::demand_power | -25284.480 | -24387.440 | -23730.656 | -23123.040 | -23119.600 | -23683.280 | -24364.720 | -25249.968000 | -26090.208000 | -26870.464000 | ... | -37078.160000 | -38203.12000 | -39033.520 | -38631.008 | -36990.800 | -35330.832 | -33623.456 | -31341.168 | -29390.624 | -28132.928 |
region1-3::csp | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000000 | 0.000000 | 0.026837 | ... | 0.118691 | 0.00000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
region2::demand_power | -2254.098 | -2131.148 | -2090.164 | -2131.148 | -2172.132 | -2172.132 | -2213.114 | -2295.082000 | -2459.016000 | -2459.016000 | ... | -2295.082000 | -2459.01600 | -2909.836 | -2868.852 | -2786.886 | -2745.902 | -2622.950 | -2459.016 | -2254.098 | -2295.082 |
region1-2::csp | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.009056 | 0.096755 | 0.245351 | ... | 0.000000 | 0.00000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 |
5 rows × 120 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-01-01 00:00:00 | 2005-01-01 01:00:00 | 2005-01-01 02:00:00 | 2005-01-01 03:00:00 | 2005-01-01 04:00:00 | 2005-01-01 05:00:00 | 2005-01-01 06:00:00 | 2005-01-01 07:00:00 | 2005-01-01 08:00:00 | 2005-01-01 09:00:00 | ... | 2005-01-05 14:00:00 | 2005-01-05 15:00:00 | 2005-01-05 16:00:00 | 2005-01-05 17:00:00 | 2005-01-05 18:00:00 | 2005-01-05 19:00:00 | 2005-01-05 20:00:00 | 2005-01-05 21:00:00 | 2005-01-05 22:00:00 | 2005-01-05 23:00:00 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
techs | |||||||||||||||||||||
csp | 0.000 | 0.000 | 0.00 | 0.000 | 0.000 | 0.000 | 0.000 | 0.030116 | 0.36056 | 0.706225 | ... | 0.440753 | 0.07927 | 0.000 | 0.00 | 0.000 | 0.000 | 0.000 | 0.000 | 0.000 | 0.00 |
demand_power | -27538.578 | -26518.588 | -25820.82 | -25254.188 | -25291.732 | -25855.412 | -26577.834 | -27545.050000 | -28549.22400 | -29329.480000 | ... | -39373.242000 | -40662.13600 | -41943.356 | -41499.86 | -39777.686 | -38076.734 | -36246.406 | -33800.184 | -31644.722 | -30428.01 |
2 rows × 120 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:23:00] INFO Backend: starting model run [2023-01-18 13:23:00] INFO Loading sets [2023-01-18 13:23:00] INFO Loading parameters [2023-01-18 13:23:00] 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:23:00] INFO creating capacity constraints [2023-01-18 13:23:00] INFO creating dispatch constraints [2023-01-18 13:23:01] INFO creating policy constraints [2023-01-18 13:23:01] INFO creating energy_balance constraints [2023-01-18 13:23:01] INFO creating costs constraints [2023-01-18 13:23:01] INFO creating network constraints [2023-01-18 13:23:01] INFO creating conversion constraints [2023-01-18 13:23:01] INFO creating group constraints [2023-01-18 13:23:01] INFO creating conversion_plus constraints [2023-01-18 13:23:01] INFO creating export constraints [2023-01-18 13:23:01] INFO creating milp constraints [2023-01-18 13:23:01] INFO Backend: model generated. Time since start of model run: 0:00:00.739055 [2023-01-18 13:23:01] INFO Backend: sending model to solver [2023-01-18 13:23:02] INFO Backend: solver finished running. Time since start of model run: 0:00:01.449866 [2023-01-18 13:23:02] INFO Backend: loaded results [2023-01-18 13:23:02] INFO Backend: generated solution array. Time since start of model run: 0:00:01.549066 [2023-01-18 13:23:02] INFO Postprocessing: started [2023-01-18 13:23:02] INFO Postprocessing: All values < 1e-10 set to 0 in energy_cap, carrier_prod, carrier_con, cost, storage, cost_var, system_balance, cost_var_rhs [2023-01-18 13:23:02] INFO Postprocessing: ended. Time since start of model run: 0:00:01.650617
# 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: 15, loc_tech_carriers_prod: 13, timesteps: 120, loc_tech_carriers_con: 11, costs: 1, loc_techs_cost: 13, loc_techs_area: 3, ... loc_techs_investment_cost: 7, loc_carriers: 5, loc_carriers_system_balance_constraint: 5, loc_techs_balance_demand_constraint: 2, loc_techs_cost_investment_constraint: 7, carriers: 1, techs: 12) Coordinates: (12/17) * techs (techs) object 'ac_transmission' ... * costs (costs) <U8 'monetary' * loc_carriers (loc_carriers) <U16 'region1::pow... * loc_carriers_system_balance_constraint (loc_carriers_system_balance_constraint) <U16 ... * loc_tech_carriers_con (loc_tech_carriers_con) <U43 'reg... * loc_tech_carriers_prod (loc_tech_carriers_prod) <U43 're... ... ... * loc_techs_investment_cost (loc_techs_investment_cost) <U32 ... * loc_techs_om_cost (loc_techs_om_cost) <U36 'region1... * loc_techs_store (loc_techs_store) <U16 'region1-3... * loc_techs_supply_plus (loc_techs_supply_plus) <U14 'reg... * timesteps (timesteps) datetime64[ns] 2005-0... * carriers (carriers) <U5 'power' Data variables: (12/20) energy_cap (loc_techs) float64 0.0 ... 3.23e+03 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 8.486e+0... storage_cap (loc_techs_store) float64 2.53e+0... ... ... 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 nan ...... systemwide_levelised_cost (carriers, costs, techs) float64 ... total_levelised_cost (carriers, costs) float64 0.06701 Attributes: termination_condition: optimal objective_function_value: 277048.48266 solution_time: 1.549066 time_finished: 2023-01-18 13:23:02 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: National-scale... run_config: backend: pyomo\nbigM: 1000000.0\ncyclic_storag...
# We can sum power output over all locations and turn the result into a pandas DataFrame
df_power = model.get_formatted_array('carrier_prod').loc[{'carriers':'power'}].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_power.info()
<class 'pandas.core.frame.DataFrame'> DatetimeIndex: 120 entries, 2005-01-01 00:00:00 to 2005-01-05 23:00:00 Data columns (total 9 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 ac_transmission:region1 120 non-null float64 1 ac_transmission:region2 120 non-null float64 2 battery 120 non-null float64 3 ccgt 120 non-null float64 4 csp 120 non-null float64 5 free_transmission:region1 120 non-null float64 6 free_transmission:region1-1 120 non-null float64 7 free_transmission:region1-2 120 non-null float64 8 free_transmission:region1-3 120 non-null float64 dtypes: float64(9) memory usage: 13.4 KB
# Using .head() to see the first few rows of power generation and demand
# Note: power output in ac_transmission:region1 is power received by the high voltage line at any location connected to `r1`
df_power.head()
techs | ac_transmission:region1 | ac_transmission:region2 | battery | ccgt | csp | free_transmission:region1 | free_transmission:region1-1 | free_transmission:region1-2 | free_transmission:region1-3 |
---|---|---|---|---|---|---|---|---|---|
timesteps | |||||||||
2005-01-01 00:00:00 | 2254.098 | 0.0 | 0.0 | 27936.360 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
2005-01-01 01:00:00 | 2131.148 | 0.0 | 0.0 | 26894.673 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
2005-01-01 02:00:00 | 2090.164 | 0.0 | 0.0 | 26189.672 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
2005-01-01 03:00:00 | 2131.148 | 0.0 | 0.0 | 25630.273 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
2005-01-01 04:00:00 | 2172.132 | 0.0 | 0.0 | 25675.049 | 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:23:03] 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.