{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Problem 13.10" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Fundamentals of Solar Cells and Photovoltaic Systems Engineering**\n", "\n", "**Solutions Manual - Chapter 13**\n", "\n", "**Problem 13.10**\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**In this problem, the economic viability of a household rooftop solar installation in Aarhus, Denmark is evaluated. \n", "To that end, hourly data will be used and can be accessed through the book repository. The file _“Problem13.10_electricity_demand_and_price_data.csv”_ can be obtained at this book’s online repository. The data file includes:**\n", "\n", "**1. hourly values of electricity demand for a household in Aarhus**\n", "\n", "**2. electricity price in the wholesale electricity market for the power system DK1 [1]**\n", "\n", "**3. capacity factors for a solar PV installation with optimal tilt angle and orientation in Aarhus. [2]**\n", "\n", "**(a) As a first step, determine the capacity of the PV modules that must be installed so that the annual electricity generated by installation equals the household annual electricity demand.**\n", "\n", "**Every hour in which the PV solar generation is lower than the demand, the energy deficit is imported from the utility power grid paying a price of 0.2924 EUR/kWh.3 Every hour in which the PV solar generation is higher than the demand, the excess energy is exported to the grid, and it is paid at the price of the wholesale market in the electricity market DK1.\n", "The installation cost for the rooftop PV system is 1243 EUR/kW. The cost of operation and maintenance (O&M) is neglected, and a discount rate of 4% is assumed.**\n", "\n", "**(b) Calculate the net present value (NPV) of the installation in year 25.**\n", "\n", "**(c) Calculate the year in which the initial investment will be recovered.**\n", "\n", "**(d) Calculate the internal rate of return (IRR) of the investment.**\n", "\n", "**(e) Aarhus municipality has decided to subsidize 20% of the cost of the installation. Repeat the sections (b)–(d) in this case.**\n", "\n", "**(f) Aarhus municipality has decided to try a different strategy, and now, it does not subsidize rooftop PV installations, but it offers zero-interest loans to citizens, so it can be assumed that the discount rate is 0%. Repeat the sections (b)–(c) in this case and discuss the results.**\n", "\n", "\n", "[1] Data was obtained from Nordpoolgroup. It can be accessed at the [Nordpoolgroup web](https://www.nordpoolgroup.com/historical-market-data/) by selecting “elspot-prices_2019_hourly_dkk”\n", "\n", "[2] Data was obtained from PV-GIS, assuming a performance ratio of 86%. It can be retrieved from the webpage [PVGIS](https://re.jrc.ec.europa.eu/pvg_tools/en/tools.html#HR) selecting Aarhus on the map.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We start by importing the [pandas package](https://pandas.pydata.org/) (useful to work with data tables) and importing the data " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
HoursElspot Prices DK1 (EUR/MWh)Household Demand (kWh)Capacity factor solar
Day
01/01/201900 - 0128.390.180.0
01/01/201901 - 0210.090.170.0
01/01/201902 - 03-4.090.200.0
01/01/201903 - 04-9.930.170.0
01/01/201904 - 05-7.430.180.0
\n", "
" ], "text/plain": [ " Hours Elspot Prices DK1 (EUR/MWh) Household Demand (kWh) \\\n", "Day \n", "01/01/2019 00 - 01 28.39 0.18 \n", "01/01/2019 01 - 02 10.09 0.17 \n", "01/01/2019 02 - 03 -4.09 0.20 \n", "01/01/2019 03 - 04 -9.93 0.17 \n", "01/01/2019 04 - 05 -7.43 0.18 \n", "\n", " Capacity factor solar \n", "Day \n", "01/01/2019 0.0 \n", "01/01/2019 0.0 \n", "01/01/2019 0.0 \n", "01/01/2019 0.0 \n", "01/01/2019 0.0 " ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandas as pd\n", "\n", "data=pd.read_csv('data/Problem13.10_electricity_demand_and_price_data.csv', sep=',', encoding='latin-1',\n", " index_col=(0)) #, header=0)\n", "\n", "data.head() #show the initial lines to check that import is working fine" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**(a) Determine the capacity of the PV modules that must be installed so that the annual electricity generated by them equals the annual electricity consumption.**\n", "\n", "We calculate the average capacity factor, the annual electricity consumption and the required PV capacity." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "PV modules capacity = 2.85 kW\n" ] } ], "source": [ "average_CF = data['Capacity factor solar'].mean()\n", "annual_electricity_consumption = data['Household Demand (kWh)'].sum()\n", "\n", "PV_capacity = annual_electricity_consumption / (average_CF*8760)\n", "print('PV modules capacity = ' + str(PV_capacity.round(2)) + ' kW')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Every hour in which the PV solar generation is lower than the demand, the energy deficit is imported from the grid paying a price of 0.2924 €/kWh [3]. Every hour in which the PV solar generation is higher than the demand, the excess energy is exported to the grid and it is paid at the price of the wholesale market in the node DK1.**\n", "\n", "**The installation cost for the rooftop PV system is 1,243 €/kW [4]. The cost of Operation and Maintenance (O&M) is neglected, and a discount rate of 4% is assumed.**\n", "\n", "**(b) Calculate the Net Present Value (NPV) of the installation in year 25.**\n", "\n", "[3] This corresponds to the average price of electricity for consumes in Denmark in 2019 according to [Eurostat](https://ec.europa.eu/eurostat/statistics-explained/index.php/Electricity_price_statistics)\n", "\n", "[4] This is the cost estimated for a rooftop PV installation in the report [“Technology Data for Generation of Electricity and District Heating” by the Danish Energy Agency (DEA) and Energinet.dk](https://ens.dk/en/our-services/projections-and-models/technology-data/technology-data-generation-electricity-and)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We start by calculating the mismatch in every hour, i.e., the difference between the PV electricity generation and demand. " ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Day\n", "31/12/2019 -0.20\n", "31/12/2019 -0.17\n", "31/12/2019 -0.18\n", "31/12/2019 -0.18\n", "31/12/2019 -0.18\n", "dtype: float64" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mismatch = PV_capacity*data['Capacity factor solar'] - data['Household Demand (kWh)']\n", "mismatch.tail()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We calculate the net cost of electricity with and without the PV installation." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Annual electricicy price with PV = 464.84 €\n", "Annual electricicy price without PV = 779.44 €\n" ] } ], "source": [ "market_price = data['Elspot Prices DK1 (EUR/MWh)']\n", "electricity_cost_w_PV = -sum([mismatch_h*market_price_h/1000 if mismatch_h>0 else mismatch_h*0.2924\n", " for mismatch_h, market_price_h in zip(mismatch, market_price)])\n", "\n", "electricity_cost_wo_PV = annual_electricity_consumption*0.2924 \n", "\n", "print('Annual electricicy price with PV = ' + str(round(electricity_cost_w_PV, 2))+ ' €')\n", "print('Annual electricicy price without PV = ' + str(round(electricity_cost_wo_PV, 2))+ ' €')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The annual savings can be calculated as" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Annual savings = 314.6 €\n" ] } ], "source": [ "annual_savings = electricity_cost_wo_PV - electricity_cost_w_PV\n", "print('Annual savings = ' + str(round(annual_savings, 2))+ ' €')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We create the a series with the cash flow in every year and calculate the discounted values, assuming 25 years lifetime and discount rate $r$=4.0%" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "cash_flow=pd.Series(index=range(0,25), data=annual_savings)\n", "cash_flow[0] -= PV_capacity*1243 # Investment cost 1243 EUR/kW\n", "r=0.04\n", "discounted_cash_flow = pd.Series(index=range(0,25), data=[cash_flow[y]/(1+r)**y for y in cash_flow.index])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Net Present Value (NPV) is calculated as the sum of the discounted cash flow. " ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "NPV = 1568.47 €\n" ] } ], "source": [ "print('NPV = ' + str(round(sum(discounted_cash_flow),2))+ ' €')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**(c) Calculate the year in which the initial investment will be recovered.**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We calculate the cumulative discounted cash flow and see that at year 14 NPV>0, that is, the investment is recovered." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0 -3228.177113\n", "1 -2925.680379\n", "2 -2634.818134\n", "3 -2355.142898\n", "4 -2086.224402\n", "5 -1827.648926\n", "6 -1579.018660\n", "7 -1339.951096\n", "8 -1110.078439\n", "9 -889.047038\n", "10 -676.516845\n", "11 -472.160889\n", "12 -275.664779\n", "13 -86.726211\n", "14 94.945489\n", "15 269.629816\n", "16 437.595515\n", "17 599.100995\n", "18 754.394726\n", "19 903.715621\n", "20 1047.293404\n", "21 1185.348965\n", "22 1318.094697\n", "23 1445.734823\n", "24 1568.465714\n", "dtype: float64" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "discounted_cash_flow.cumsum()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**(d) Calculate the Internal Rate of Return (IRR) of the investment.**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The IRR can be calculated at the discount rate that makes the NPV=0 at the end of the installation lifetime." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "NPV = pd.Series(dtype=float)\n", "\n", "for n in range(0, 100):\n", " r=0.001*n\n", " discounted_cash_flow = pd.Series(index=range(0,25), data=[cash_flow[y]/(1+r)**y for y in cash_flow.index])\n", " NPV[r]=sum(discounted_cash_flow)\n" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "IRR = 0.083\n" ] } ], "source": [ "argmin=NPV.abs().argmin()\n", "NPV.index[argmin]\n", "print('IRR = ' + str(NPV.index[argmin]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**(e) Aarhus municipality has decided to subsidize 20% of the cost of the installation. Repeat the sections (b)–(d) in this case.**\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Net Present value" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "NPV = 2277.02 €\n" ] } ], "source": [ "cash_flow=pd.Series(index=range(0,25), data=annual_savings)\n", "cash_flow[0] -= PV_capacity*1243*0.8 # Investment cost 1243 EUR/kW, 20% is subsidized\n", "r=0.04\n", "discounted_cash_flow = pd.Series(index=range(0,25), data=[cash_flow[y]/(1+r)**y for y in cash_flow.index])\n", "print('NPV = ' + str(round(sum(discounted_cash_flow),2))+ ' €')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this case, the investment is recoverd in 10 years. " ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0 -2519.622370\n", "1 -2217.125635\n", "2 -1926.263390\n", "3 -1646.588155\n", "4 -1377.669659\n", "5 -1119.094182\n", "6 -870.463916\n", "7 -631.396353\n", "8 -401.523696\n", "9 -180.492294\n", "10 32.037899\n", "11 236.393854\n", "12 432.889965\n", "13 621.828533\n", "14 803.500233\n", "15 978.184560\n", "16 1146.150259\n", "17 1307.655739\n", "18 1462.949469\n", "19 1612.270364\n", "20 1755.848147\n", "21 1893.903708\n", "22 2026.649440\n", "23 2154.289567\n", "24 2277.020458\n", "dtype: float64" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "discounted_cash_flow.cumsum()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Internal Rate of Return (IRR)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "IRR = 0.099\n" ] } ], "source": [ "NPV = pd.Series(dtype=float)\n", "\n", "for n in range(0, 100):\n", " r=0.001*n\n", " discounted_cash_flow = pd.Series(index=range(0,25), data=[cash_flow[y]/(1+r)**y for y in cash_flow.index])\n", " NPV[r]=sum(discounted_cash_flow)\n", " \n", "argmin=NPV.abs().argmin()\n", "NPV.index[argmin]\n", "print('IRR = ' + str(NPV.index[argmin]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**(f) Aarhus municipality has decided to try a different strategy, and now, it does not subsidize rooftop PV installations, but it offers zero-interest loans to citizens, so it can be assumed that the discount rate is 0%. Repeat the sections (b)–(c) in this case.**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Net Present value\n" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "NPV = 4322.14 €\n" ] } ], "source": [ "cash_flow=pd.Series(index=range(0,25), data=annual_savings)\n", "cash_flow[0] -= PV_capacity*1243# Investment cost 1243 EUR/kW, 20% is subsidized\n", "r=0\n", "discounted_cash_flow = pd.Series(index=range(0,25), data=[cash_flow[y]/(1+r)**y for y in cash_flow.index])\n", "print('NPV = ' + str(round(sum(discounted_cash_flow),2))+ ' €')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this case, the investment is recoverd in 11 years. " ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "0 -3228.177113\n", "1 -2913.580509\n", "2 -2598.983905\n", "3 -2284.387301\n", "4 -1969.790697\n", "5 -1655.194093\n", "6 -1340.597488\n", "7 -1026.000884\n", "8 -711.404280\n", "9 -396.807676\n", "10 -82.211072\n", "11 232.385532\n", "12 546.982136\n", "13 861.578741\n", "14 1176.175345\n", "15 1490.771949\n", "16 1805.368553\n", "17 2119.965157\n", "18 2434.561761\n", "19 2749.158365\n", "20 3063.754970\n", "21 3378.351574\n", "22 3692.948178\n", "23 4007.544782\n", "24 4322.141386\n", "dtype: float64" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "discounted_cash_flow.cumsum()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.12" } }, "nbformat": 4, "nbformat_minor": 4 }