Lab 1 review - CRG
Closed this issue · 2 comments
I will provide feedback and some ideas I have for the lab to make it more challenging for the students (which I think can be encouraging for them). If we agree on some of these changes then I can create a PR to include them.
In the import statements plotly express
is imported as ex
, the standard alias is px
.
I think we can ask the students to create some of the formulas we are giving to them as the crf
and the lcoe
. That way, they will be able to interact a bit with Python. Thus, I think a stage 0 would be useful for them, where we provide some of the basic operators in python so they can get familiarized with them and be able to use them in stages 1 and 2. The idea of this section would be to work as a reference (not to spend much time on it) so they can check what they could use when implementing the formulas. I could write such section and include it in the PR.
Then the part where we calculate the crf
could be like this:
discount_rate = 0.05
crf = 'Replace this string with some code'
print(crf)
The same for the lcoe
formula:
lcoe = 'Replace this string with some code'
print(lcoe) # €/kWh
Additionally, we can have a couple of checker functions to check if the values are correct. We can store such functions in a Python module outside the notebook and import them. Something like the following for the crf
formula:
def checker_crf(value, discount_rate, year):
crf = (1 + discount_rate) ** - year
if isinstance(value, np.ndarray):
if sum(crf == value) == len(crf):
return 'Your answer is correct!'
else:
return 'That is not right, try again!'
else:
return 'That is not right, try again!'
An for the lcoe
calculation we can have the following, which will also give feedback in the case the result is correct:
def checker_lcoe(value, capital_costs, operational_costs, electricity_generation, discount_rate, technical_lifetime):
try:
year = np.arange(technical_lifetime)
crf = (1 + discount_rate) ** - year
lcoe = (capital_costs + sum(crf * operational_costs)) / sum(crf * electricity_generation)
if value == lcoe:
return 'Your answer is correct!'
else:
return 'That is not right, try again!'
except:
return 'That is not right, try again!'
This will work for both if the result is False
or if it raises an error. This checker would replace the assert test currently in place.
In stage 2, the input for capacity
is currently in MW and should be in kW to be consistent with the units of the extended_lcoe
function:
lifetime = 25
discount_rate = 0.08
capacity = 750.0 # MW
overnight_cost = 750.0 # €/kW
fixed_om_cost = 3 # €/kW
efficiency = 0.5
fuel_price = 0.03 # €/kWh
load_factor = 0.75
I am also a bit confused about the variable name overnight_cost
. I understand this refers to the CAPEX right?
In the extended_lcoe
function, we make the lcoe
calculation again but in a slightly different way. Wouldn't it be better to reuse the lcoe
function that we have already coded, so we avoid confusion? like:
def extended_lcoe(station_size, overnight_cost, fuel_efficiency, fuel_price, fixed_om_cost, load_factor,
discount_rate, technical_lifetime):
"""Calculates levelised cost of electricity as a function of useful parameters
Arguments
---------
station_size : float
The capacity of the technology in kW
overnight_cost : float
The capital cost of the technology in €
fuel_efficiency : float
The ratio describing quantity of fuel required per unit of activity
fuel_price : float
The price paid per unit of input fuel in €/kWh
fixed_om_cost : float
The fixed operation and maintenance cost of the technology in €/kW
load_factor : float
The percentage of the year in which the technology generates electricity in %.
discount_rate : float
A decimal value less than 1
technical_lifetime : int
Technical lifetime of the technology in years
Returns
-------
float
The levelised cost of electricity in €/kWh
"""
HOURS_IN_YEAR = 8760
capital_cost = station_size * overnight_cost
total_fixed_om_cost = station_size * fixed_om_cost
annual_electricity_generation = station_size * HOURS_IN_YEAR * load_factor
total_variable_om_cost = (annual_electricity_generation / fuel_efficiency) * fuel_price
annual_operational_cost = total_fixed_om_cost + total_variable_om_cost
value = lcoe(capital_cost, annual_operational_cost, annual_electricity_generation, discount_rate, technical_lifetime)
return value
When we use the extended_lcoe
function for the first time, the value passed as load_factor
is incorrect: capacity * 8760 * 0.75
, this should be 0.75 only.
ccgt_lcoe = extended_lcoe(capacity, overnight_cost, efficiency, fuel_price, fixed_om_cost, capacity * 8760 * 0.75,
discount_rate, lifetime)
ccgt_lcoe
We should change the input value of technical_lifetime
to something like (10, 1, 50)
to prevent the slider raising a division by zero error and select negative values:
interact(extended_lcoe, station_size=fixed(750000), overnight_cost=(500, 1500), fuel_efficiency=(0.3, 0.7),
fuel_price=(0.01, 0.10, 0.01), fixed_om_cost=3, load_factor=(0.01, 1.0, 0.1),
discount_rate=(0.01, 0.30, 0.01), technical_lifetime=25)
About how to extend stages 2 and 3, I could only think on maybe showing a plot per technology disaggregating the lcoe
value per cost type (capital, fixed and variable) and make them reflect on the importance of each cost for the lcoe
and the technology.
For this, some changes would need to be done to the extended_lcoe
function and some additional code.
I will push my branch so you can check all the changes I discussed here. Please feel free to comment/reject anything, I am completely open to ideas.
Hi @camiloramirezgo - thanks so much for this clear review. Can you make a pull request with your branch so I can respond there? In short, I think also everything you suggest can be accepted as is, but I'd like to make a few tweaks. We can do that on your branch and discuss in the PR. Ace!