diff --git a/MJ2383_Lab_1.ipynb b/MJ2383_Lab_1.ipynb index 6f33f93..547ba03 100644 --- a/MJ2383_Lab_1.ipynb +++ b/MJ2383_Lab_1.ipynb @@ -13,7 +13,7 @@ "import pandas as pd\n", "import ipywidgets as widgets\n", "from ipywidgets import interact, fixed\n", - "from checkers import checker_crf, checker_lcoe, checker_parameters" + "from checkers import checker_df, checker_lcoe, checker_parameters" ] }, { @@ -231,13 +231,13 @@ "\n", "According to [OEE](http://www.open-electricity-economics.org/book/text/03.html) the formula to calculate LCOE is as follows:\n", "\n", - "\\\\(LCOE = \\frac{C_{fix} + \\sum_{y=1}^Y CRF_y \\cdot C_y}{\\sum_{y=1}^Y CRF_y \\cdot G_y}\\\\)\n", + "\\\\(LCOE = \\frac{C_{fix} + \\sum_{y=1}^Y DF_y \\cdot C_y}{\\sum_{y=1}^Y DF_y \\cdot G_y}\\\\)\n", "\n", "where LCOE is the levelized cost in EUR per kWh, \\\\(C_{fix}\\\\) is the capital investment costs incurred for setting up the project, \\\\(C_y\\\\) are operational costs incurred in year \\\\(y\\\\), \\\\(Y\\\\) is the technical lifetime in years, and \\\\(G_y\\\\) is electricity generation in kWh. The costs are called levelized because they are “leveled” over all units of output. Levelized costs can be calculated for a specific power plant or for generic types of generation technologies.\n", "\n", - "Capital recovery factor (CRF) is calculated for each year \\\\(y\\\\) of the plant's technical lifetime\n", + "Discount factor (DF) is calculated for each year \\\\(y\\\\) of the plant's technical lifetime\n", "\n", - "\\\\(CRF_y = (1 + r)^{-y}\\\\)\n", + "\\\\(DF_y = (1 + r)^{-y}\\\\)\n", "\n", "where r is the discount rate" ] @@ -297,10 +297,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Now we calculate CRF for each year in our plant's technical lifetime according to the formula we saw earlier:\n", - "\\\\(CRF_y = (1 + r)^{-y}\\\\); \\\\(r\\\\) is the discount rate, and \\\\(y\\\\) is the year.\n", + "Now we calculate DF for each year in our plant's technical lifetime according to the formula we saw earlier:\n", + "\\\\(DF_y = (1 + r)^{-y}\\\\); \\\\(r\\\\) is the discount rate, and \\\\(y\\\\) is the year.\n", "\n", - "**Implement the CRF formula in the cell below. Remember that to exponentiate in Python we use** `**`.\n", + "**Implement the DF formula in the cell below. Remember that to exponentiate in Python we use** `**`.\n", "\n", "**Q. What happens if you change the discount rate?**" ] @@ -312,8 +312,8 @@ "outputs": [], "source": [ "discount_rate = 0.05\n", - "crf = \"replace me with the CRF formula\"\n", - "print(crf) # we use the command print, to show the values stored inside the crf variable" + "df = \"replace me with the DF formula\"\n", + "print(df) # we use the command print, to show the values stored inside the df variable" ] }, { @@ -323,14 +323,14 @@ "outputs": [], "source": [ "# Run this cell to check your answer\n", - "checker_crf(crf, discount_rate, year)" + "checker_df(df, discount_rate, year)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Now we've calculated CRF, let's get some data for the other parameters:" + "Now we've calculated DF, let's get some data for the other parameters:" ] }, { @@ -354,7 +354,7 @@ "\n", "Remember the formula? Let's check it again:\n", "\n", - "\\\\(LCOE = \\frac{C_{fix} + \\sum_{y=1}^Y CRF_y \\cdot C_y}{\\sum_{y=1}^Y CRF_y \\cdot G_y}\\\\)\n", + "\\\\(LCOE = \\frac{C_{fix} + \\sum_{y=1}^Y DF_y \\cdot C_y}{\\sum_{y=1}^Y DF_y \\cdot G_y}\\\\)\n", "\n", "Now, implement the LCOE formula in the cell below:" ] @@ -448,7 +448,7 @@ "If you managed to get it to work, well done! You've written a Python function which computes LCOE. If not, don't worry, the answer is below! Make sure to write it in the function so the following steps of the Lab work.\n", "\n", "- In this stage, we introduced the LCOE equation\n", - "\\\\(LCOE = \\frac{C_{fix} + \\sum_{y=1}^Y CRF_y \\cdot C_y}{\\sum_{y=1}^Y CRF_y \\cdot G_y}\\\\)\n", + "\\\\(LCOE = \\frac{C_{fix} + \\sum_{y=1}^Y DF_y \\cdot C_y}{\\sum_{y=1}^Y DF_y \\cdot G_y}\\\\)\n", "and implemented it using a Python function.\n", "- We also explored how the capital recovery factors weighs future years differently as a function of the discount rate.\n", "- We learnt a lot of Python concepts including *variables*, *arrays*, and *arguments*.\n", @@ -458,12 +458,12 @@ "\n", "### Stage 1 - Answer LCOE Function\n", "\n", - "As you can see, we just need to fill in the gaps. First build the array of years, calculate the array of CRF and then add the lcoe calculation.\n", + "As you can see, we just need to fill in the gaps. First build the array of years, calculate the array of DF and then add the lcoe calculation.\n", "```python\n", "def get_lcoe(capital_costs, operational_costs, electricity_generation, discount_rate, technical_lifetime):\n", " year = np.arange(technical_lifetime)\n", - " crf = (1 + discount_rate) ** - year\n", - " lcoe = (capital_costs + sum(crf * operational_costs)) / sum(crf * electricity_generation)\n", + " df = (1 + discount_rate) ** - year\n", + " lcoe = (capital_costs + sum(df * operational_costs)) / sum(df * electricity_generation)\n", " return lcoe\n", "```" ] @@ -591,7 +591,8 @@ "metadata": {}, "outputs": [], "source": [ - "def get_lcoe_input(station_size, overnight_cost, fuel_efficiency, fuel_price, fixed_om_cost, load_factor):\n", + "def get_lcoe_input(station_size, overnight_cost, fuel_efficiency, \n", + " fuel_price, fixed_om_cost, load_factor, variable_om_cost):\n", " \"\"\"Calculates the input parameters for the lcoe function\n", " \n", " Arguments\n", @@ -608,6 +609,8 @@ " The fixed operation and maintenance cost of the technology in €/kW\n", " load_factor : float\n", " The percentage of the year in which the technology generates electricity in %.\n", + " variable_om_cost : float\n", + " The variable operation and maintenance cost of the technology in €/kW\n", " \n", " Returns\n", " -------\n", @@ -630,7 +633,9 @@ " capital_cost = station_size * overnight_cost\n", " total_fixed_om_cost = station_size * fixed_om_cost\n", " annual_electricity_generation = station_size * HOURS_IN_YEAR * load_factor\n", - " total_variable_om_cost = (annual_electricity_generation / fuel_efficiency) * fuel_price\n", + "\n", + " total_variable_om_cost = ((annual_electricity_generation / fuel_efficiency) * fuel_price) + \\\n", + " (annual_electricity_generation * variable_om_cost)\n", " annual_operational_cost = total_fixed_om_cost + total_variable_om_cost\n", " \n", " return {'capital_cost': capital_cost, 'total_fixed_om_cost': total_fixed_om_cost,\n", @@ -645,7 +650,7 @@ "outputs": [], "source": [ "def extended_lcoe(station_size, overnight_cost, fuel_efficiency, fuel_price, fixed_om_cost, load_factor, \n", - " discount_rate, technical_lifetime):\n", + " discount_rate, technical_lifetime, var_om_cost):\n", " \"\"\"Calculates levelised cost of electricity as a function of useful parameters\n", " \n", " Arguments\n", @@ -666,6 +671,8 @@ " A decimal value less than 1\n", " technical_lifetime : int\n", " Technical lifetime of the technology in years\n", + " var_om_cost : float\n", + " Variable operational and maintenance cost\n", " \n", " Returns\n", " -------\n", @@ -673,7 +680,7 @@ " The levelised cost of electricity in €/kWh\n", " \"\"\"\n", " lcoe_params = get_lcoe_input(station_size, overnight_cost, fuel_efficiency, \n", - " fuel_price, fixed_om_cost, load_factor)\n", + " fuel_price, fixed_om_cost, load_factor, var_om_cost)\n", "\n", " value = get_lcoe(lcoe_params['capital_cost'], lcoe_params['annual_operational_cost'], \n", " lcoe_params['annual_electricity_generation'], discount_rate, \n", @@ -695,7 +702,7 @@ "outputs": [], "source": [ "ccgt_lcoe = extended_lcoe(capacity, overnight_cost, efficiency, fuel_price, fixed_om_cost, 0.75, \n", - " discount_rate, lifetime)\n", + " discount_rate, lifetime, 0.003)\n", "ccgt_lcoe" ] }, @@ -720,9 +727,8 @@ "metadata": {}, "outputs": [], "source": [ - "interact(extended_lcoe, station_size=fixed(750000), overnight_cost=(300, 1200), fuel_efficiency=(0.3, 0.7, 0.05), \n", - " fuel_price=(0.01, 0.10, 0.01), fixed_om_cost=(1, 5, 0.5), load_factor=(0.01, 1.0, 0.1), \n", - " discount_rate=(0.01, 0.30, 0.01), technical_lifetime=(10, 40, 1))" + "interact(extended_lcoe, station_size=(100000,750000, 10000), overnight_cost=(300, 2000), fuel_efficiency=(0.3, 0.7, 0.01), fuel_price=(0.00 , 0.20, 0.01), fixed_om_cost=(1, 50, 0.001), load_factor=(0.01, 1.0, 0.01), \n", + " discount_rate=(0.01, 0.30, 0.01), technical_lifetime=(10, 60, 1), var_om_cost=(0.0, 0.011, 0.001))" ] }, { @@ -793,14 +799,14 @@ " observation['LCOE'] = lcoe\n", " \n", " year = np.arange(technical_lifetime)\n", - " total_crf = sum((1 + discount_rate) ** - year)\n", + " total_df = sum((1 + discount_rate) ** - year)\n", " \n", - " observation['Fixed OM Cost'] = (total_crf * lcoe_params['total_fixed_om_cost']) / \\\n", - " (total_crf * lcoe_params['annual_electricity_generation'])\n", - " observation['Variable OM Cost'] = (total_crf * lcoe_params['total_variable_om_cost']) / \\\n", - " (total_crf * lcoe_params['annual_electricity_generation'])\n", + " observation['Fixed OM Cost'] = (total_df * lcoe_params['total_fixed_om_cost']) / \\\n", + " (total_df * lcoe_params['annual_electricity_generation'])\n", + " observation['Variable OM Cost'] = (total_df * lcoe_params['total_variable_om_cost']) / \\\n", + " (total_df * lcoe_params['annual_electricity_generation'])\n", " observation['Capital Cost'] = lcoe_params['capital_cost'] / \\\n", - " (total_crf * lcoe_params['annual_electricity_generation'])\n", + " (total_df * lcoe_params['annual_electricity_generation'])\n", "\n", " results.append(observation)\n", " \n", @@ -947,7 +953,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.3" + "version": "3.8.5-final" } }, "nbformat": 4, diff --git a/checkers.py b/checkers.py index 4975d1b..cade3cc 100644 --- a/checkers.py +++ b/checkers.py @@ -2,19 +2,19 @@ import sys from IPython.display import display, Markdown, Latex -def checker_crf(value, discount_rate, year): - crf = (1 + discount_rate) ** -year +def checker_df(value, discount_rate, year): + df = (1 + discount_rate) ** -year if isinstance(value, np.ndarray): if len(value) != len(year): return print("The length of your array should be the same as the number of years.") - elif sum(crf == value) == len(crf): + elif sum(df == value) == len(df): return print("Your answer is correct!") else: return print("The values provided are not correct. They should be:\n{}".format( - crf + df )) else: - return display(Markdown("The argument `crf` needs to be of type `np.array()`")) + return display(Markdown("The argument `df` needs to be of type `np.array()`")) def checker_lcoe( @@ -28,9 +28,9 @@ def checker_lcoe( try: if isinstance(value, float): year = np.arange(technical_lifetime) - crf = (1 + discount_rate) ** -year - lcoe = (capital_costs + sum(crf * operational_costs)) / sum( - crf * electricity_generation + df = (1 + discount_rate) ** -year + lcoe = (capital_costs + sum(df * operational_costs)) / sum( + df * electricity_generation ) if value == lcoe: return print("Your answer is correct!") @@ -41,13 +41,13 @@ def checker_lcoe( except: return print("Unexpected error: {}".format(sys.exc_info()[0])) raise - - + + def checker_parameters( - el_gen, - op_costs, - capacity, - load_factor, + el_gen, + op_costs, + capacity, + load_factor, fixed_om_cost, fuel_price, efficiency @@ -56,7 +56,7 @@ def checker_parameters( annual_fixed_om_cost = capacity * fixed_om_cost # in € annual_variable_om_cost = fuel_price * electricity_generation / efficiency # in € operational_costs = annual_fixed_om_cost + annual_variable_om_cost # in € - + try: if el_gen == electricity_generation: str_out = 'Your electricity generation is correct!\n' @@ -68,6 +68,6 @@ def checker_parameters( str_out += f'Your operational costs are not right... they should be {operational_costs}' return print(str_out) except: - return print("Unexpected error: {}".format(sys.exc_info()[0]), + return print("Unexpected error: {}".format(sys.exc_info()[0]), 'Make sure your electricity generation and operational values are of type float') raise