KTH-dESA/MJ2383

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)

image

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.

image

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!

Closed by #3