-
Notifications
You must be signed in to change notification settings - Fork 4
Optimisation
This section provides information about the optimisation process in CLOVER and the various inputs required.
The optimisation process in CLOVER is mostly automatic but in order for it to work we need to state the conditions under which it should operate. CLOVER performs a large number of system simulations, each with different combinations of generation and storage capacity sizes, and appraises them based on their technical, financial and environmental performances; depending on our interests, any of them might be considered the best”. For this reason we need to provide CLOVER with some details about what we consider to be the “optimum” system using two variables that we define:
- The threshold criterion, which determines whether a simulated system meets the standards required to be considered as a potential optimum system,
- and The optimisation criterion, which determines which of the potential systems is selected to be the best.
Simply put, the threshold criterion decides whether a system meets our stated needs and, as many systems are likely to be able to meet our needs, the optimisation criterion selects the one that performs the best according to its financial or environmental impact. As an example, consider that we want to design a system which provides electricity 95% of the time or more: clearly many systems will be able to do that, some much larger than would be affordable, so we decide that the one which provides the lowest cost of electricity would be best. Here we would define the threshold criterion to be Blackouts (from Section 5.2.3 and set to a value of 0.05, i.e. a maximum of 5% of the time can experience a loss of supply), whilst the optimisation criterion would be the levelised cost of used electricity in $/kWh (LCUE, explained further later) with the lowest being the best. CLOVER would then identify a system which meets those two criteria, and give us a range of other impact metrics as well.
We also need to provide information about scenario we are investigating: optimising over different time periods will potentially provide different results as resource generation, load demands, technological performance and degradation all change over time. CLOVER uses a step-by-step optimisation process which divides the total investigation lifetime into shorter time periods; this allows us to replicate the process of designing a system to meet some future needs, then revisiting the system after a few years to upgrade it as necessary to meet a growing demand or maintain its performance. This also allows us to consider that additional capacity in the context of what has already been installed, adding only what is necessary rather than overhauling the existing equipment.
The inputs for the optimisation parameters are included in the optimisation_inputs.yaml file, which is located in the optimisation directory of your location's inputs folder. Let’s take a look at the inputs for the Bahraich case study:
---
################################################################################
# optimisation_inputs.yaml - Specifications for running optimisations. #
# #
# Author: Phil Sandwell, Ben Winchester #
# Copyright: Phil Sandwell & Ben Winchester, 2021 #
# Date created: 14/07/2021 #
# License: Open source #
################################################################################
# Valid optimisation criteria, usually set to "minimise":
# CRITERION UNIT
# blackouts
# clean_water_blackouts
# lcue $/kWh
# emissions_intensity gCO2/kWh
# unmet_energy_fraction
# cumulative_cost $
# cumulative_ghgs kgCO2eq
# cumulative_system_cost $
# cumulative_system_ghgs kgCO2eq
# emissions_intensity gCO2/kWh
# lcue $/kWh
# total_cost $
# total_system_cost $
# total_ghgs kgCO2eq
# total_system_ghgs kgCO2eq
# unmet_energy_fraction
# Valid optimisation criteria, usually set to "maximise":
# kerosene_cost_mitigated $
# kerosene_displacement
# kerosene_ghgs_mitigated kgCO2eq
# renewables_fraction
#
# NOTE: Not all optimisation criteria may be available for the system depending
# on the resource types being considered.
#
iteration_length: 4 # [years]
number_of_iterations: 3 # number of iterations to carry out
pv_size:
min: 5 # [PV units], [kWp] by default
max: 20 # [PV units], [kWp] by default
step: 5 # [PV units], [kWp] by default
storage_size:
min: 5 # [storage units], [kWh] by default
max: 30 # [storage units], [kWh] by default
step: 5 # [storage units], [kWh] by default
optimisations:
- optimisation_criteria:
- lcue: minimise # Name of the column and whether to maximise/minimise.
threshold_criteria:
- blackouts: 0.1 # Max/min value permitted (see guidance)
- optimisation_criteria:
- lcue: minimise
threshold_criteria:
- blackouts: 0.05
scenario: defaultThis file may look like a lot! But, in reality, there is only a small amount of information at the bottom of the file which CLOVER uses. The rest of the file is simply handy information to help you know what valid variables you can use as optimisation and threshold criteria. We'll take a look at the process of the optimisation as a means to understanding these variables.
Two variables control the length of the investigation period and that of each of the sub-periods, with the total length of the optimisation comprised of several smaller iterations length. For example, setting the iteration_length to 4 and the number_of_iterations to 3 would result in there being three distinct periods: the first considering the first four years, the second considering the next four years (including the performance of the system that was already installed for the period before), and the third considering the last set of four years (again including the periods before).
Both the iteration_length and the number_of_iterations must be integer numbers for the process to work. Further, the multiple of these two numbers can be any value up to the total investigation lifetime we defined in our location_inputs.yaml file to be 20 years. See the Establish your location section for more information on this.
The optimisation process in CLOVER first considers a system with the smallest generation and storage capacity and gradually increases it until it finds one that meets the threshold criterion. The first system it considers at the start of the investigation period, with the smallest installed capacity, is defined by pv_size: max and storage_size: max. These variables identify the starting point of the optimisation. When CLOVER moves on to the second (or later) iterations during the optimisation process it automatically considers the capacity that was installed during the previous time period.
The optimisation function requires the user to define the resolution of the investigation, defined through the variables pv_size: step and storage_size: step respectively: once CLOVER has investigated a system, if it finds it to be insufficient, it then analyses one with a larger capacity, with the increase in capacity of the next system defined by these two variables. For example, with pv_size: step set to 1 (here, 1 $\textsf{kW}\textsf{p}$ by default) and a pv_size: max of 5, CLOVER would consider systems with a pv size of 5, 6, 7, 8, etc. $\textsf{kW}\textsf{p}$ until it found a sufficient system, whereas with pv_size: step set to 5, CLOVER would consider systems with a pv size of 5, 10, 15, 20, etc. with the same logic being true for the storage system size.
In this way, it investigates systems thusly:
| ⬇️ Storage / |
5 | 10 | 15 | 20 | 25 |
|---|---|---|---|---|---|
| 25 | ✅ | ||||
| 20 | ✅ | ||||
| 15 | |||||
| 10 | |||||
| 5 |
Both of these variables can be set to different values, and can be non-integers. For an investigation of a theoretical system, choosing a round number for the step size might be more convenient, but, for a real investigation, it could be better to use the real available capacity of the equipment being installed. For example, if you know that the system will be build using solar panels with a capacity of 350 pv_size: step variable to 0.35 to reflect this.
You may notice that CLOVER has gone one step further than a sufficient system. This is to prevent CLOVER from accidentally choosing a system which meets the criteria but which isn't the most optimal. There are a few other checks for this as well which we'll get to, don't worry!
Once CLOVER has found a system which is sufficient, having effectively worked up in increasing size, it explores the surrounding systems in search of systems which are "sufficient." (We'll get to what this means later.) It hence explores the surrounding systems:
| ⬇️ Storage / |
25 | 20 | 15 | 10 | 5 |
|---|---|---|---|---|---|
| 25 | ✅ | ✅ | ✅ | ✅ | ❌ |
| 20 | ✅ | ✅ | ✅ | ❌ | |
| 15 | ✅ | ❌ | |||
| 10 | ❌ | ||||
| 5 | ❌ |
Here, CLOVER has looked at systems of decreasing PV size for each storage size, stopping once a system is not sufficient. It has hence identified 8 systems which are sufficient, from which it selects the most optimal system.
Threshold criteria are what we call the variables being used to decide whether a system provides sufficient performance to be considered as a potential optimum system. The choices for Threshold criterion are listed for convenience in the opimisation_inputs.yaml file at the top in the large comment and CLOVER knows automatically whether the Threshold value should be considered as a maximum or minimum value: for example, in the Bahraich optimisation inputs file above, we have the threshold criteria for our optimisation listed:
threshold_criteria:
- blackouts: 0.05CLOVER interprets the threshold value of 0.05 as meaning that only systems which have blackout periods for 5% of the time or lower are permitted. You can keep listing threshold criteria here, and CLOVER will reject all systems that do not meet all of the criteria.
Optimisation criteria, meanwhile, are the variables being used to select the optimum system. For each of these, you can specify whether you want CLOVER to minimise or maximise the criterion. Looking again at the above Bahraich example optimisation inputs file,
optimisation_criteria:
- lcue: minimisewe see that this optimisation is being instructed to minimise the lcue. Take care that the inputs for the threshold_criteria and optimisation_criteria are spelt correctly, otherwise the optimisation process will not work. CLOVER should provide a helpful error, but it is best to check this first by hand.
CLOVER can take a number of variables as either the threshold or optimisation criteria and these should be chosen to best reflect the context of the investigation and its goals. Typically the threshold criterion relates to the technological performance of the system on the basis that, in order for a system to be viable, it needs to be able to provide a minimum level of service to the community which is (almost always) based on its core technical functionality, rather than economic or environmental factors. The level of service availability, either in terms of the time energy is (un)available (blackouts) or the proportion of demanded that should be met (unmet_energy_fraction), are the most commonly used threshold criteria. Selecting an appropriate threshold value will vary depending on the situation, for example a
system for basic domestic applications could permit blackouts 5-10% of the time whilst one for a hospital may need 0% system downtime.
The optimisation criterion, meanwhile, is typically a measure of the system impact either in financial, technical or environmental terms. Most commonly this is the levelised cost of used electricity (LCUE, measured in $/kWh), which considers the cost of power over the lifetime of the system and is normally most relevant to system designers, but could also be other financial metrics such as the total system cost which may be more relevant to donor-led projects. Environmental analogues of these metrics, such as the emissions intensity of electricity or the cumulative GHG emissions, may be more relevant for projects driven by climate change objectives.
Whilst a single criterion must be selected for use in the optimisation process, the optimisation process gives us all of the available outputs and so we can investigate all of them for an optimum system configuration. Using different optimisation criteria may yield different results but often the optimum systems will be relatively similar: for a given level of service availability, it is likely that the capacity of a system optimised for lowest cost of electricity will be similar to one optimised for lowest cumulative cost, but may not be identical.
Choosing the resolution of an optimisation is a trade-off between precision and computation time. Taking the above example of 1 $\textsf{kW}\textsf{p}$ or 5 $\textsf{kW}\textsf{p}$ resolutions, the former method would be more likely to suggest a system closer to the true optimum: for example, if the true optimum system (if it were possible to know it exactly) has 7 $\textsf{kW}\textsf{p}$ of installed PV then the former method would be able to find it, but the latter method would suggest either 5 or 10 $\textsf{kW}\textsf{p}$ of PV panels, depending on how the other aspects of system influence this. Even if the true optimum system is actually 7.2
The importance of a precise answer will depend on the requirements of your investigation, the size of the system, your available processing power and your patience, so there is no exact answer for the "best" step sizes to use. In general, it is good practice to run an initial optimisation with a low resolution (e.g. PV size = 10) to get an idea of the order of magnitude of the system: if the optimum output for this trial run is 20 $\textsf{kW}\textsf{p}$ of PV, it would be appropriate to re-run the optimisation with a higher resolution (e.g. step sizes of 1 $\textsf{kW}\textsf{p}$ or 5 $\textsf{kW}\textsf{p}$) to gain greater precision. If the output is 300 $\textsf{kW}\textsf{p}$ of PV, it might be better to increase the step size (e.g. to 20 kWp) to reduce computational time.
The optimisation process CLOVER uses provides the optimum system for the iteration period under consideration, which is not necessarily the same as one for the entire lifetime of the system. This is to replicate real-life system design and the timeframes of community energy projects, where plans are built around time horizons of a few years owing to practical constraints such as funding, the limits of demand prediction, or the likelihood of altering the business model. This also matches a reasonable timeframe of making major upgrades to the system, for example returning to the site every few years to perform capacity upgrades to meet a growing demand. As such CLOVER identifies the optimum system for the next short-term time window, providing the system that best meets the requirements for the next stage of design, before moving on to the next stage in time.
This allows users to know the optimum system for the immediate future and what subsequent system upgrades might look like to maintain that optimum performance. As will all predictions the further into the future you consider the greater uncertainty there is, but remember that you can always return in a few years’ time to re-run your optimisation when it’s time to upgrade your system. As a result the of the precision of your system, the CLOVER optimisation process might suggest different pathways of capacity sizing over the lifetime of the system. In the example above, if a system requires 7.2 $\textsf{kW}\textsf{p}$ of PV in its first period and 12.1 $\textsf{kW}\textsf{p}$ of PV in its second, then using a PV size (step) of 1 $\textsf{kW}\textsf{p}$ would probably give 7 $\textsf{kW}\textsf{p}$ and 12 $\textsf{kW}\textsf{p}$ of PV as its outputs, whereas using a step size of 10 $\textsf{kW}\textsf{p}$ might give 10 $\textsf{kW}\textsf{p}$ for both periods. The latter case might have evaluated the relative costs and benefits of increasing the capacity to 20 $\textsf{kW}\textsf{p}$ and found that, for example, increasing the storage capacity instead was more worthwhile. The precision we chose has therefore locked the two optimisations into different pathways, one with a larger PV capacity and one with a larger storage capacity; both will provide the same level of service (as the threshold criteria are the same in both cases) but the optimisation impacts such as the costs will be different.
In some cases this effect can be exacerbated over several time periods, but in general the most effective way to mitigate this is through using higher precision in your optimisations to stay as close as possible to the true optimum system.
Complete the optimisation_inputs.yaml file with the optimisation information for your investigation.
To run an optimisation, we can use the -opt or --optimisation option on the command-line. When doing so, we don't need to tell CLOVER the sizes of the components as we did when running a simulation:
- If you have run a git clone to download CLOVER, you will run the code as before:
python -m src.clover -l <location_name> -opt
- or, on a linux machine,
./bin/clover.sh -l <location_name> -opt
- or, if you have installed the
clover-energypackage:clover -l <location_name> -opt
Provided all of your input files have been setup correctly, you will see a similar output to this displayed:
$ python -u -m src.clover -opt -l debug
(((((* /(((
((((((( ((((((((
(((((((((((( ((((((((((((
((((((((((((*((((((((((((( _____ _ ______ ________ _____
*((((((((( (((((((((((( / ____| | / __ \ \ / / ____| __ \
(((((((. /((((((((((/ | | | | | | | \ \ / /| |__ | |__) |
((((((((((((((((((((((((((, | | | | | | | |\ \/ / | __| | _ /
(((((((((((* ((((((((((((( | |____| |___| |__| | \ / | |____| | \ \
,(((((((. ( (((((((((((/ \_____|______\____/ \/ |______|_| \_\
.(((((( ( ((((((((
/ (((((
,
,
(
(
(
Continuous Lifetime Optimisation of Variable Electricity Resources
Copyright Phil Sandwell, 2018
Version 5.1.0
For more information, contact
Phil Sandwell (philip.sandwell@gmail.com),
Hamish Beath (hamishbeath@outlook.com),
or Ben Winchester (benedict.winchester@gmail.com)
A CLOVER optimisation will be run for debug
Verifying location information ................................ [ DONE ]
Parsing input files ........................................... [ DONE ]
Generating necessary profiles
solar profiles: 100%|██████████████████████| 10/10 [00:00<00:00, 5802.05year/s]
electric load profiles: 100%|██████████████| 12/12 [00:00<00:00, 22.23device/s]
total load profile: 100%|████████████████| 12/12 [00:00<00:00, 1047.86device/s]
grid profiles: 100%|███████████████████████████| 5/5 [00:00<00:00, 46.99grid/s]
Generating necessary profiles ................................. [ DONE ]
Beginning CLOVER optimisation runs ............................
optimisations: 0%| | 0/1 [00:00<?, ?optimisation/s]
Running an optimisation with:
- PV resolution of 5 units (1 kWp per unit)
- Storage resolution of 5 units (1 kWh per unit)
Determining largest suitable system ...........................
Determining largest suitable system ........................... [ DONE ]
Determining largest suitable system ...........................
Determining largest suitable system ........................... [ DONE ]
Determining largest suitable system ...........................
Determining largest suitable system ........................... [ DONE ]
optimisations: 100%|███████████████████| 1/1 [00:48<00:00, 48.02s/optimisation]
Beginning CLOVER optimisation runs ............................ [ DONE ]
Time taken for optimisations: 11.995 s/year
Finished. See locations/debug/outputs for output files. Here, we can see the familiar process that CLOVER has gone through of parsing input files, checking that solar profiles are downloaded, then running the optimisation. If you watched it as it ran, you should have seen that it ran a series of simulations for each of the potential PV and storage size combinations that it needed to consider, picking the best system from each iteration before moving onto the next iteration. The step sizes have been outputted for us to check that they are correct, and we can see CLOVER working through its process of running a single optimisation.
Our optimisation function gives us a large number of results in its output. Let's look at the results of our optimisation that we just ran. NOTE: your results will likely differ from these results as your input files will be different by this point from the default values:
{
"optimisation_inputs": {
"clean_water_pvt_size_max": 0,
"clean_water_pvt_size_min": 0,
"clean_water_pvt_size_step": 1,
"clean_water_tanks_max": 0,
"clean_water_tanks_min": 0,
"clean_water_tanks_step": 1,
"hot_water_pvt_size_max": 0,
"hot_water_pvt_size_min": 0,
"hot_water_pvt_size_step": 1,
"hot_water_tanks_max": 0,
"hot_water_tanks_min": 0,
"hot_water_tanks_step": 1,
"iteration_length": 4,
"number_of_iterations": 3,
"pv_size_max": 25,
"pv_size_min": 5,
"pv_size_step": 5,
"storage_size_max": 25,
"storage_size_min": 5,
"storage_size_step": 5
},
"scenario": {
"battery": true,
"demands": {
"commercial": true,
"domestic": true,
"public": true
},
"diesel_scenario": {
"backup_threshold": 0.1,
"mode": "backup"
},
"distribution_network": "dc",
"grid": true,
"grid_type": "default",
"name": "default",
"resource_types": [
"electricity"
],
"prioritise_self_generation": true,
"pv": true
},
"system_appraisals": {
"iteration_0": {
"cumulative_results": {
"cumulative_cost": 29473.526,
"cumulative_discounted_energy": 44406.848,
"cumulative_energy": 54151.304,
"cumulative_ghgs": 54540.445,
"cumulative_system_cost": 28865.655,
"cumulative_system_ghgs": 48982.915,
"clean_water": 0
},
"environmental_appraisal": {
"diesel_ghgs": 0.0,
"grid_ghgs": 9792.915,
"kerosene_ghgs": 5557.53,
"kerosene_ghgs_mitigated": 145605.295,
"new_connection_ghgs": 40.0,
"new_equipment_ghgs": 37350.0,
"om_ghgs": 1800.0,
"total_ghgs": 54540.445,
"total_system_ghgs": 48982.915
},
"financial_appraisal": {
"diesel_cost": 0.0,
"grid_cost": 105.693,
"kerosene_cost": 607.872,
"kerosene_cost_mitigated": 17659.471,
"new_connection_cost": 400.0,
"new_equipment_cost": 25200.0,
"om_cost": 3159.962,
"total_cost": 29473.526,
"total_system_cost": 28865.655
},
"system_details": {
"diesel_capacity": 0.0,
"end_year": 4,
"final_pv_size": 9.6,
"final_storage_size": 37.456,
"initial_pv_size": 10.0,
"initial_storage_size": 40.0,
"input_files": {
"batteries": "locations/debug/inputs/simulation/battery_inputs.yaml",
"converters": "locations/debug/inputs/generation/conversion_inputs.yaml",
"devices": "locations/debug/inputs/load/devices.yaml",
"diesel_inputs": "locations/debug/inputs/generation/diesel_inputs.yaml",
"energy_system": "locations/debug/inputs/simulation/energy_system.yaml",
"finance_inputs": "locations/debug/inputs/impact/finance_inputs.yaml",
"generation_inputs": "locations/debug/inputs/generation/generation_inputs.yaml",
"ghg_inputs": "locations/debug/inputs/impact/ghg_inputs.yaml",
"grid_times": "locations/debug/inputs/generation/grid_times.csv",
"location_inputs": "locations/debug/inputs/location_data/location_inputs.yaml",
"optimisation_inputs": "locations/debug/inputs/optimisation/optimisation_inputs.yaml",
"scenarios": "locations/debug/inputs/scenario/scenario_inputs.yaml",
"simularion": "locations/debug/inputs/simulation/simulations.yaml",
"solar_inputs": "locations/debug/inputs/generation/solar_generation_inputs.yaml",
"transmission_inputs": "locations/debug/inputs/simulation/transmission_inputs.yaml"
},
"start_year": 0
},
"technical_appraisal": {
"blackouts": 0.035,
"diesel_energy": 0.0,
"diesel_fuel_usage": 0.0,
"discounted_energy": 44406.848,
"grid_energy": 12953.598,
"kerosene_displacement": 0.963,
"renewable_energy": 22120.307,
"renewable_energy_fraction": 0.761,
"storage_energy": 19077.399,
"total_clean_water": 0.0,
"total_energy": 54151.304,
"unmet_energy": 1299.263,
"unmet_energy_fraction": 0.024
},
"criteria": {
"blackouts": 0.035,
"cumulative_cost": 29473.526,
"cumulative_ghgs": 54540.445,
"cumulative_system_cost": 28865.655,
"cumulative_system_ghgs": 48982.915,
"emissions_intensity": 904.557,
"kerosene_cost_mitigated": 17659.471,
"kerosene_displacement": 0.963,
"kerosene_ghgs_mitigated": 145605.295,
"lcue": 0.65,
"renewables_fraction": 0.761,
"total_cost": 29473.526,
"total_ghgs": 54540.445,
"total_system_cost": 28865.655,
"total_system_ghgs": 48982.915,
"unmet_energy_fraction": 0.024
}
},
"iteration_1": {
"cumulative_results": {
"cumulative_cost": 44890.253000000004,
"cumulative_discounted_energy": 99986.38699999999,
"cumulative_energy": 153509.168,
"cumulative_ghgs": 113718.891,
"cumulative_system_cost": 43803.344,
"cumulative_system_ghgs": 101833.94099999999,
"clean_water": 0
},
"environmental_appraisal": {
"diesel_ghgs": 0.0,
"grid_ghgs": 15868.624,
"kerosene_ghgs": 6327.42,
"kerosene_ghgs_mitigated": 144149.995,
"new_connection_ghgs": 40.0,
"new_equipment_ghgs": 34422.402,
"om_ghgs": 2520.0,
"total_ghgs": 59178.446,
"total_system_ghgs": 52851.026
},
"financial_appraisal": {
"diesel_cost": 0.0,
"grid_cost": 130.67,
"kerosene_cost": 479.038,
"kerosene_cost_mitigated": 11946.203,
"new_connection_cost": 262.44,
"new_equipment_cost": 11670.636,
"om_cost": 2873.942,
"total_cost": 15416.727,
"total_system_cost": 14937.689
},
"system_details": {
"diesel_capacity": 0.0,
"end_year": 8,
"final_pv_size": 18.24,
"final_storage_size": 62.444,
"initial_pv_size": 19.0,
"initial_storage_size": 67.0,
"input_files": {
"batteries": "locations/debug/inputs/simulation/battery_inputs.yaml",
"converters": "locations/debug/inputs/generation/conversion_inputs.yaml",
"devices": "locations/debug/inputs/load/devices.yaml",
"diesel_inputs": "locations/debug/inputs/generation/diesel_inputs.yaml",
"energy_system": "locations/debug/inputs/simulation/energy_system.yaml",
"finance_inputs": "locations/debug/inputs/impact/finance_inputs.yaml",
"generation_inputs": "locations/debug/inputs/generation/generation_inputs.yaml",
"ghg_inputs": "locations/debug/inputs/impact/ghg_inputs.yaml",
"grid_times": "locations/debug/inputs/generation/grid_times.csv",
"location_inputs": "locations/debug/inputs/location_data/location_inputs.yaml",
"optimisation_inputs": "locations/debug/inputs/optimisation/optimisation_inputs.yaml",
"scenarios": "locations/debug/inputs/scenario/scenario_inputs.yaml",
"simularion": "locations/debug/inputs/simulation/simulations.yaml",
"solar_inputs": "locations/debug/inputs/generation/solar_generation_inputs.yaml",
"transmission_inputs": "locations/debug/inputs/simulation/transmission_inputs.yaml"
},
"start_year": 4
},
"technical_appraisal": {
"blackouts": 0.045,
"diesel_energy": 0.0,
"diesel_fuel_usage": 0.0,
"discounted_energy": 55579.539,
"grid_energy": 23484.816,
"kerosene_displacement": 0.958,
"renewable_energy": 41706.236,
"renewable_energy_fraction": 0.764,
"storage_energy": 34166.812,
"total_clean_water": 0.0,
"total_energy": 99357.864,
"unmet_energy": 3001.763,
"unmet_energy_fraction": 0.03
},
"criteria": {
"blackouts": 0.045,
"cumulative_cost": 44890.253,
"cumulative_ghgs": 113718.891,
"cumulative_system_cost": 43803.344,
"cumulative_system_ghgs": 101833.941,
"emissions_intensity": 663.374,
"kerosene_cost_mitigated": 11946.203,
"kerosene_displacement": 0.958,
"kerosene_ghgs_mitigated": 144149.995,
"lcue": 0.438,
"renewables_fraction": 0.764,
"total_cost": 15416.727,
"total_ghgs": 59178.446,
"total_system_cost": 14937.689,
"total_system_ghgs": 52851.026,
"unmet_energy_fraction": 0.03
}
},
"iteration_2": {
"cumulative_results": {
"cumulative_cost": 56690.856,
"cumulative_discounted_energy": 160980.35799999998,
"cumulative_energy": 312195.074,
"cumulative_ghgs": 197465.241,
"cumulative_system_cost": 55303.87699999999,
"cumulative_system_ghgs": 179793.906,
"clean_water": 0
},
"environmental_appraisal": {
"diesel_ghgs": 0.0,
"grid_ghgs": 21983.162,
"kerosene_ghgs": 5786.385,
"kerosene_ghgs_mitigated": 141843.405,
"new_connection_ghgs": 40.0,
"new_equipment_ghgs": 52536.803,
"om_ghgs": 3400.0,
"total_ghgs": 83746.35,
"total_system_ghgs": 77959.965
},
"financial_appraisal": {
"diesel_cost": 0.0,
"grid_cost": 140.908,
"kerosene_cost": 300.071,
"kerosene_cost_mitigated": 8028.698,
"new_connection_cost": 172.187,
"new_equipment_cost": 8650.356,
"om_cost": 2537.082,
"total_cost": 11800.603,
"total_system_cost": 11500.533
},
"system_details": {
"diesel_capacity": 0.0,
"end_year": 12,
"final_pv_size": 31.68,
"final_storage_size": 89.993,
"initial_pv_size": 33.0,
"initial_storage_size": 97.0,
"input_files": {
"batteries": "locations/debug/inputs/simulation/battery_inputs.yaml",
"converters": "locations/debug/inputs/generation/conversion_inputs.yaml",
"devices": "locations/debug/inputs/load/devices.yaml",
"diesel_inputs": "locations/debug/inputs/generation/diesel_inputs.yaml",
"energy_system": "locations/debug/inputs/simulation/energy_system.yaml",
"finance_inputs": "locations/debug/inputs/impact/finance_inputs.yaml",
"generation_inputs": "locations/debug/inputs/generation/generation_inputs.yaml",
"ghg_inputs": "locations/debug/inputs/impact/ghg_inputs.yaml",
"grid_times": "locations/debug/inputs/generation/grid_times.csv",
"location_inputs": "locations/debug/inputs/location_data/location_inputs.yaml",
"optimisation_inputs": "locations/debug/inputs/optimisation/optimisation_inputs.yaml",
"scenarios": "locations/debug/inputs/scenario/scenario_inputs.yaml",
"simularion": "locations/debug/inputs/simulation/simulations.yaml",
"solar_inputs": "locations/debug/inputs/generation/solar_generation_inputs.yaml",
"transmission_inputs": "locations/debug/inputs/simulation/transmission_inputs.yaml"
},
"start_year": 8
},
"technical_appraisal": {
"blackouts": 0.048,
"diesel_energy": 0.0,
"diesel_fuel_usage": 0.0,
"discounted_energy": 60993.971,
"grid_energy": 36809.531,
"kerosene_displacement": 0.961,
"renewable_energy": 69326.003,
"renewable_energy_fraction": 0.768,
"storage_energy": 52550.372,
"total_clean_water": 0.0,
"total_energy": 158685.906,
"unmet_energy": 4503.422,
"unmet_energy_fraction": 0.028
},
"criteria": {
"blackouts": 0.048,
"cumulative_cost": 56690.856,
"cumulative_ghgs": 197465.241,
"cumulative_system_cost": 55303.877,
"cumulative_system_ghgs": 179793.906,
"emissions_intensity": 575.902,
"kerosene_cost_mitigated": 8028.698,
"kerosene_displacement": 0.961,
"kerosene_ghgs_mitigated": 141843.405,
"lcue": 0.344,
"renewables_fraction": 0.768,
"total_cost": 11800.603,
"total_ghgs": 83746.35,
"total_system_cost": 11500.533,
"total_system_ghgs": 77959.965,
"unmet_energy_fraction": 0.028
}
}
}
}At first glance, this looks like a lot! We'll look at each part of the results in turn, starting from our top-level headings.
We'll look at what each of the top-level headings mean.
| Variable | Explanation |
|---|---|
optimsiation_inputs |
The input information that we gave our optimisation via the optimisation_inputs.yaml file. NOTE: if you are running CLOVER on Imperial College London's High-Performance Computers (HPCs), then only the information for this specific optimisation will be contained here. |
scenario |
The scenario information used for the run. We can specify a specific scenario to use for our optimisation, so this is contained here. |
system_appraisals |
This contains the appraisals for each of the iteration steps. |
The optimisation_inputs and scenario information is included in the output files so that you can keep track of results when dealing with large numbers of locations, systems, scenarios and optimisations. In this way, by including the results in the file, it is clear from where the input information was gathered.
The main results of our optimisation process are the system appraisals contained under the system_appraisals heading. These appraisals are carried out as the optimisation runs in order to determine both which systems are sufficient and, from the list of sufficient systems, which either minimises or maximises the desired optimisation criterion. As we ran three iterations, there are three headings here:
>>> import json
>>> with open(os.path.join("location", <location_name>, "outputs", "optimisation_outputs", <optimisation_name>, "optimisation_output_1.json"), "r") as f:
... data = json.load(f)
...
>>> data["system_appraisals"].keys()
dict_keys(['iteration_0', 'iteration_1', 'iteration_2'])These are numbered from 0 and correspond to each iteration period: 0 for the first four years, 1 for the second four years (years 5 through to 8 inclusive) and 2 for the final four years (years numbered 9 through 12 inclusive). We'll take a look at the final iteration period as these are the results that we're most interested in.
>>> data["system_appraisals"]["iteration_2"].keys()
dict_keys(['cumulative_results', 'environmental_appraisal', 'financial_appraisal', 'system_details', 'technical_appraisal', 'criteria'])Here, we have an insight into how CLOVER appraises systems:
| Variable | Explanation |
|---|---|
cumulative_results |
These are results which have accumulated across all the previous iteration periods. "Total cost" would be an example of a variable for which we're most interested in the cumulative result. |
environmental_appraisal |
These are environmental results, i.e., GHG-emission calculations for our system. |
financial_appraisal |
These are financial results, i.e., cost calculations for our system. |
system_details |
This heading lists general information about our system, such as the sizes selected for the various components. |
technical_appraisal |
These are technical results, such as the blackouts or unmet_energy_fraction, for our system: i.e., results which are neither financial or environmental. |
criteria |
These are the evaluated criteria that we could be choosing as either threshold or optimisation criteria. |
As CLOVER runs, it calculates the various optimisation and threshold criteria for each system as part of the appraisal process. As this information has already been calculated, it makes sense to output it for each system that CLOVER has chosen. This is listed under criteria. The financial, technical and environmental appraisals that CLOVER carries out are also listed here, along with general information.
We'll take a look at the cumulative results that CLOVER outputs:
>>> print(json.dumps(data["system_appraisals"]["iteration_2"]["cumulative_results"], indent=4))
{
"cumulative_cost": 56690.856,
"cumulative_discounted_energy": 160980.35799999998,
"cumulative_energy": 312195.074,
"cumulative_ghgs": 197465.241,
"cumulative_system_cost": 55303.87699999999,
"cumulative_system_ghgs": 179793.906,
"clean_water": 0
}Here, we can see some of the values that CLOVER has calculated:
| Variable | Explanation |
|---|---|
cumulative_cost |
Running total of cumulative costs over the system lifetime in $ |
cumulative_discounted_energy |
Running total of cumulative discounted energy over the system lifetime in kWh |
cumulative_energy |
Running total of cumulative (undiscounted) energy over the system lifetime in kWh |
cumulative_ghgs |
Running total of cumulative GHG emissions over the system lifetime in |
cumulative_system_cost |
Running total of cumulative costs for just the system, i.e., excluding the kerosene emissions, over the system lifetime in $ |
cumulative_system_ghgs |
Running total of cumulative GHG emissions for just the system, i.e., excluding the kerosene emissions, over the system lifetime in |