\n", "

\n", "\n", "## Once parameters have been adjusted you can proceed through the calculation one step at a time by pressing shift+enter or you can execute the rest of the notebook by pressing \n", "## \"Cell\" ->\"Run All Below\"\n", "\n", "

\n", "

" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Determine Required Solar Capacity (Procedure Step 2)\n", "

\n", "\n", "Required nameplate capacity (Capacity DC) is calculated using the equation below. Capacity Factor, Energy generation, time period, and Derate factors are known. \n", "

\n", "\n", "\n", " \\begin{equation*} \\text{Capacity Factor (%) } = \\frac{ \\text{Energy generation AC (GWH)}}{\\text{Time period(hours)}*\\frac{\\text{Capacity DC(GW)}}{\\text{Derate Factor(%)}}} \\end{equation*} \n", " \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "derate_factor= 0.85 # converts from DC capacity to AC capacity[5](https://www.nrel.gov/docs/fy13osti/56290.pdf)\n", "Current_Capacity = 60 # GW \n", "\n", "Required_Capacity_AC= Electricity_Generation_GWH/(365*24*Capacity_factor)\n", "Required_Capacity= Required_Capacity_AC/derate_factor\n", "\n", "print(' When capacity factor is {:.2f}% required capacity is {:.1f} GW'.format(Capacity_factor*100,Required_Capacity))\n", "\n", "plt.bar(['Current US Capacity', ' Required Capacity '],[Current_Capacity, Required_Capacity])\n", "plt.ylabel(' Nameplate Capacity (GW)')\n", "plt.show()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Total Solar Array Costs (Procedure Step 3)\n", "\n", "In order to calculate total solar array cost a panel life of 25 years is assumed. In reality solar arrays often last 25-40 years. Salvage cost is not considered. \n", "\n", "Rapid installation of 20% additional generation capacity would have substantial economic and energetic impacts, spiking the demand for materials and labor associated with PV, and driving electricity prices down as a result of the energy supply surge. Fully untangling these potential impacts is beyond the scope of this reduced-order analysis.\n", "\n", "For this calculation we assume that the total installation will commence over a ten year install period, mitigating some of the potential impacts. Panels are assumed to have a 25 year life span with a 0.5% rate of degradation per year [15]. Thus, given the 10 year install period, the assessed total project life is 35 years.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Total_Operating_cost=(ONM/1000)*(Required_Capacity*10**9)*Panel_life \n", "\n", "\n", "Cost=Capex*(Required_Capacity*10**9)+Total_Operating_cost # Cost over life of the system\n", "\n", "\n", "print('When Capacity factor is {:.2f}%, Total cost to meet 20% of US electricity generation is ${:.2f} trillion'.format(Capacity_factor*100, Cost/(10**12)))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Comparison with traditional systems\n", "\n", "In order to compare estimated AVS costs with traditional systems we assume the same operating costs per year (\\\\$19/kWh) and a cost of $1.25/Watt capacity for traditional systems " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Capex_traditional_systems=1.25# $/Watt\n", "Cost_traditional=Capex_traditional_systems*(Required_Capacity*10**9)+Total_Operating_cost # Cost over life of the system\n", "Cost_difference=Cost-Cost_traditional\n", "\n", "print('Anticipated cost difference between AV and traditional systems over {} year project life is ${:.2f} billion'.format(tPeriod,Cost_difference/(10**9)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Energy Storage (Procedure Step 4)\n", "\n", "The variable nature of solar power makes energy storage an important component of successful grid integration at high penetrations. The optimal storage medium is often dependent on situation and climate. \n", " \n", "In the interest of an upper-bound estimate, this reduced order estimate looks exclusively at the cost of lithium-ion standalone storage systems. NREL ([4](https://www.nrel.gov/docs/fy19osti/71714.pdf)) estimates the cost for 30 min, 1 hour, 2 hour, and 4 hours of storage when using a 60 MW battery array. \n", "The values used here are from the \"2018 U.S. Utility-Scale Photovoltaics Plus-Energy Storage System Costs Benchmark\" . Stand-alone storage requires higher overall costs and greater land area. The study also details co-located PV + battery systems but in the interest of an upper-bound cost estimate these systems were not considered.\n", "\n", "A battery and inverter lifespan of 10 years was assumed." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# all cost estimates from NREL 2018 [4](https://www.nrel.gov/docs/fy19osti/71714.pdf)\n", "\n", "Battery_lifespan=10 #Assume Battery lifespan = 10 years\n", "Req_batt_replace=int(np.ceil((Panel_life/Battery_lifespan)-1)) #determine number of times battery must be replaced\n", "\n", "# assume using 60 MW batteries \n", "B_capc=60/1000 # capacity of Battery Array 60 MW (0.06GW)\n", "\n", "#Total Cost for 60MW storage system\n", "Cost_storage=pd.DataFrame([[26845079],[36050172],[54460359],[91280733]],columns=['Total Energy System Cost per 60MW Battery Array ($)'],index=['30 min','1 Hour', '2 Hour', '4 Hour'])\n", "Cost_storage=Cost_storage*inflationFactor_2018 #Values from NREL 2018 report converted to 2020 dollars using CPI index\n", "\n", "# Cost for batteries & inverter ( must be replaced every ~ 10 years)\n", "Cost_Battery=pd.DataFrame([[6270000+4200000],[12540000+4200000],[25080000+4200000],[50160000+4200000]],columns=['Cost for Li-ion battery and Central inverter ($)'],index=['30 min','1 Hour', '2 Hour', '4 Hour'])\n", "Cost_Battery=Cost_Battery*inflationFactor_2018 #Values from NREL 2018 report converted to 2020 dollars using CPI index\n", "\n", "#Conversion to millions to improve readibility - not used in any calculations\n", "Cost_storage_mill=Cost_storage/(10**6); Cost_storage_mill.columns=['Total Energy System Cost per 60MW Battery Array (million $)'];\n", "display(Cost_storage_mill) # cost of storage in millions \n", "\n", "# Storage per Battery Array (GWh)\n", "store=pd.DataFrame([[B_capc*0.5],[B_capc],[B_capc*2],[B_capc*4]],columns=['Storage per Array - GWh'], index=['30 min','1 Hour', '2 Hour', '4 Hour'])\n", "\n", "#total energy required for storage of various lengths (GWh)\n", "req_store=pd.DataFrame([Electricity_Generation_GWH/365/24/2,Electricity_Generation_GWH/365/24,Electricity_Generation_GWH/365/24*2,Electricity_Generation_GWH/365/24*4],columns=['Required Storage GWh'], index=['30 min','1 Hour', '2 Hour', '4 Hour'])\n", "\n", "\n", "# number of battery arrays required to meet storage requirement\n", "\n", "num_battery_array=pd.DataFrame([req_store.loc['30 min'][0]/(store.loc['30 min'][0]),req_store.loc['1 Hour'][0]/store.loc['1 Hour'][0],req_store.loc['2 Hour'][0]/store.loc['2 Hour'][0],req_store.loc['4 Hour'][0]/store.loc['4 Hour'][0]],columns=['Number of 60 MW Battery Arrays Required'], index=['30 min','1 Hour', '2 Hour', '4 Hour'])\n", "\n", "\n", "# Storage cost = The number of battery arrays required * Cost per array\n", "Storage_cost=pd.DataFrame([[num_battery_array.loc['30 min'][0]*Cost_storage.loc['30 min'][0]],[num_battery_array.loc['1 Hour'][0]*Cost_storage.loc['1 Hour'][0]],[num_battery_array.loc['2 Hour'][0]*Cost_storage.loc['2 Hour'][0]],[num_battery_array.loc['4 Hour'][0]*Cost_storage.loc['4 Hour'][0]]],columns=['Cost for US Storage ($)'], index=['30 min','1 Hour', '2 Hour', '4 Hour'])\n", "Storage_cost_mill=Storage_cost/(10**6)\n", "Storage_cost_mill.columns=['Cost for US Storage (Million $)']\n", "\n", "display(Storage_cost_mill)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Total Cost: Array + Storage\n", "\n", "Total costs to meet 20% of 2019 electricity generation using Agrivoltaic systems is calculated as:\n", "\n", "Total Capital Expenditures + (Operating expenses * Panel life) + Total cost for storage system * ( panel life/ life span of battery) \n", "\n", "Given the assumed array life span of 25 years and battery life span of 10 years this calcualtion assumes all batteries must be replaced twice. \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Total_Cost=Cost+np.add(Storage_cost,(Cost_Battery*num_battery_array.loc[t_stor][0]*Req_batt_replace)) \n", "#add cost of array + cost of batteries&inverters * number of battery arrays * the number of times items will be replaced\n", "\n", "Total_Cost.columns=[' US Cost for Agrivoltaic System + Storage System ($)']\n", "Total_Cost_Trill=Total_Cost/(10**12)\n", "Total_Cost_Trill.columns=[' US Cost for Agrivoltaic System + Storage System (Trillion $)']\n", "display(Total_Cost_Trill)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Potential Returns (Procedure Step 5)\n", "\n", "Revenue is calculated based on the total energy produced and the price per kWh, the default calculation uses the 2018 national average of $0.1053/kWh\n", "\n", "We assume a 10 year install period, during this time electricity generation. commences uniformly.\n", "\n", "Panels are expected to degrade by 0.5\\% each year [15].\n", "\n", "\n", "Batteries and inverters are replaced every 10 years.\n", "\n", "Default discount rate is 6%.\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Agrivoltaic Arrays no storage\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def solar_panel_degredation(degredation_rate,Panel_life,install_period):\n", " '''\n", " Account for degredation of panels\n", " \n", " Parameters\n", " ----------\n", " \n", " degradation_rate: float\n", " value that solar panel generation decreases by annually \n", " default value is 0.005 (0.5%)\n", " \n", " Panel_life: int\n", " life span panel, after this period of time panel generation is \n", " assumed to drop to 0\n", " default value is 25\n", " \n", " install_period: int\n", " # of years to reach full generation\n", " default value is 10\n", " \n", " Returns\n", " -------\n", " \n", " Percent_generation_array: array_like\n", " array with fraction of available generation in each year of the project life\n", " shape: [len(panel_life)+len(install_period),1]\n", " \n", " \n", " '''\n", " tPeriod=Panel_life+install_period+1 # total time period of this analysis, default 35 years\n", "\n", " #array containg degredation over project life of an array\n", " degrade_series=np.zeros(Panel_life)\n", " for i in range(Panel_life):\n", " degrade_series[i]=1-(i*degredation_rate)\n", " \n", " # array to hold the percent of total capacity for each segment of total arrays\n", " # row corresponds to year column corresponds to segment of total arrays (ie 1/10 of total arrays given a 10 year install period)\n", " percent_capacity=np.zeros((tPeriod,install_period)) \n", "\n", " for i in range(install_period):\n", " percent_capacity[i+1:Panel_life+i+1,i]=1/install_period*degrade_series\n", "\n", " # Fraction of total capacity available in each year \n", " Percent_generation_array=np.sum(percent_capacity,axis=1)\n", " Percent_generation_array = np.reshape(Percent_generation_array,(Percent_generation_array.size,1))\n", "\n", " \n", " return Percent_generation_array" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "hide_toggle(for_next=True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "install_period=10 # 10 years until full production\n", "tPeriod=Panel_life+install_period+1 # total time period of this analysis, default 35 years\n", "degredation_rate=0.005 # an assumed degredation rate of 0.5% per year \n", "\n", "#Account for solar panel degredation, default degredation rate= 0.5% per year\n", "Percent_generation_array=solar_panel_degredation(degredation_rate,Panel_life,install_period)\n", "no_degredation=solar_panel_degredation(0,Panel_life,install_period) # calculate without degredation (used for cost estimates)\n", "\n", "EG_ann=Electricity_Generation_GWH*Percent_generation_array #annual electricity generation\n", "rev_ann=EG_ann*Energy_price_GWh #annual revenue\n", "Capacity_available=Required_Capacity*no_degredation #annual capacity available (used to calcualte O&M, assume no degredation)\n", "\n", "Capex_ann=np.zeros((install_period,1)) #annual capital expenditures\n", "Capex_ann[:]=((1/install_period)*Required_Capacity)*Capex*10**9 # Cost per watt capacity($/Gw) * capacity(Gw)* 10^9 W/GW\n", "\n", "ONM_ann=(ONM/1000)*(Capacity_available*10**9) #annual O&M costs\n", "\n", "\n", "\n", "# The following lines construct the cash flows array\n", "Cash_Flows_array=pd.DataFrame(np.zeros((tPeriod,8)),columns=[ 'Year','CAPEX', 'O & M', 'Revenue', 'Net',\n", " 'Cumulative', 'NPV','NPV Cumulative'])\n", "Cash_Flows_array.loc[:,'Year']=np.arange(0,tPeriod)\n", "\n", "\n", "Cash_Flows_array.loc[0:install_period-1,'CAPEX']=Capex_ann \n", "Cash_Flows_array.loc[0:tPeriod,'O & M']=ONM_ann\n", " \n", "#Account for annual revenue = total GWh * electricity price\n", "Cash_Flows_array.loc[0:tPeriod,'Revenue']=rev_ann\n", "\n", "#Net = Revenue - Capex - O&M - Storage costs\n", "Cash_Flows_array.loc[0:tPeriod,'Net']=(Cash_Flows_array.loc[0:tPeriod,'Revenue']-(Cash_Flows_array.loc[0:tPeriod,'CAPEX']+Cash_Flows_array.loc[0:tPeriod,'O & M']))\n", "\n", "# Calculate Net present value \n", "Cash_Flows_array.loc[0:tPeriod,'NPV']=Cash_Flows_array.loc[0:tPeriod,'Net']/(1+Discount_rate)**Cash_Flows_array.loc[0:tPeriod,'Year']\n", "\n", "#Initial Cumulative net value\n", "Cash_Flows_array.loc[0,'Cumulative']=Cash_Flows_array.loc[0,'Net']\n", "\n", "#Initial Cumulative net present value \n", "Cash_Flows_array.loc[0,'NPV Cumulative']=Cash_Flows_array.loc[0,'NPV']\n", "\n", "chk=Cash_Flows_array.loc[0:tPeriod,'CAPEX']+Cash_Flows_array.loc[0:tPeriod,'O & M']\n", "\n", "# Calculate cumulative and NPV values for each year\n", "for i in range (1,tPeriod):\n", " Cash_Flows_array.loc[i,'Cumulative']=Cash_Flows_array.loc[i-1,'Cumulative']+Cash_Flows_array.loc[i,'Net']\n", " Cash_Flows_array.loc[i,'NPV Cumulative']= Cash_Flows_array.loc[i-1,'NPV Cumulative']+Cash_Flows_array.loc[i,'NPV']\n", "\n", "\n", "AVS_net_rev=Cash_Flows_array.loc[tPeriod-1,'Cumulative']\n", "NPV_AVS_net_rev=Cash_Flows_array.loc[tPeriod-1,'NPV Cumulative']\n", "Total_Revenue=sum( Cash_Flows_array.loc[:,'Revenue'])\n", "\n", "Payback_time=np.argmax(Cash_Flows_array.loc[:,'Cumulative']>0) # determine first year where cumulative revenue is above 0\n", "\n", "\n", "display(Cash_Flows_array)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Agrivoltaics With Storage" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "hide_toggle(for_next=True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# The following lines construct the cash flows array for AV arrays with storage\n", "\n", "Cash_Flows_array_S=pd.DataFrame(np.zeros((tPeriod,9)),columns=[ 'Year','CAPEX', 'O & M','Storage', 'Revenue', 'Net',\n", " 'Cumulative', 'NPV','NPV Cumulative'])\n", "\n", "Cash_Flows_array_S.loc[:,'Year']=np.arange(0,tPeriod)\n", "\n", "Cash_Flows_array_S.loc[0,'Storage']=Storage_cost.loc[t_stor][0]\n", "\n", "#Account for Battery replacment costs\n", "batt_replace_series=np.zeros(Panel_life)\n", "\n", "#batteries must be replaced once every 10 years\n", "for i in range(1,Req_batt_replace+1):\n", " batt_replace_series[Battery_lifespan*i]=Cost_Battery.loc[t_stor][0]*num_battery_array.loc[t_stor][0]/install_period \n", "batt_replacment=np.zeros((tPeriod,install_period)) \n", "for i in range(install_period):\n", " batt_replacment[i+1:Panel_life+i+1,i]=batt_replace_series \n", "batt_replacment_cost=np.sum(batt_replacment,axis=1)\n", "batt_replacment_cost = np.reshape(batt_replacment_cost,(batt_replacment_cost.size,1))\n", "\n", "\n", "Cash_Flows_array_S.loc[1:,'Storage']=batt_replacment_cost[1:]\n", "\n", "Cash_Flows_array_S.loc[0:install_period-1,'CAPEX']=Capex_ann \n", "Cash_Flows_array_S.loc[0:tPeriod,'O & M']=ONM_ann\n", " \n", "#Account for annual revenue = total GWh * electricity price\n", "Cash_Flows_array_S.loc[0:tPeriod,'Revenue']=rev_ann\n", "\n", "#Net = Revenue - Capex - O&M - Storage costs\n", "Cash_Flows_array_S.loc[0:tPeriod,'Net']=(Cash_Flows_array_S.loc[0:tPeriod,'Revenue']-(Cash_Flows_array_S.loc[0:tPeriod,'CAPEX']+Cash_Flows_array_S.loc[0:tPeriod,'O & M']+Cash_Flows_array_S.loc[0:tPeriod,'Storage']))\n", "# Calculate Net present value \n", "Cash_Flows_array_S.loc[0:tPeriod,'NPV']=Cash_Flows_array_S.loc[0:tPeriod,'Net']/(1+Discount_rate)**Cash_Flows_array_S.loc[0:tPeriod,'Year']\n", "\n", "#Initial Cumulative net value\n", "Cash_Flows_array_S.loc[0,'Cumulative']=Cash_Flows_array_S.loc[0,'Net']\n", "\n", "#Initial Cumulative net present value \n", "Cash_Flows_array_S.loc[0,'NPV Cumulative']=Cash_Flows_array_S.loc[0,'NPV']\n", "\n", "chk=Cash_Flows_array_S.loc[0:tPeriod,'CAPEX']+Cash_Flows_array_S.loc[0:tPeriod,'O & M']\n", "\n", "# Calculate cumulative and NPV values for each year\n", "for i in range (1,tPeriod):\n", " Cash_Flows_array_S.loc[i,'Cumulative']=Cash_Flows_array_S.loc[i-1,'Cumulative']+Cash_Flows_array_S.loc[i,'Net']\n", " Cash_Flows_array_S.loc[i,'NPV Cumulative']= Cash_Flows_array_S.loc[i-1,'NPV Cumulative']+Cash_Flows_array_S.loc[i,'NPV']\n", "\n", "\n", "AVS_stor_net_rev=Cash_Flows_array_S.loc[tPeriod-1,'Cumulative']\n", "NPV_AVS_stor_net_rev=Cash_Flows_array_S.loc[tPeriod-1,'NPV Cumulative']\n", "Total_Revenue=sum( Cash_Flows_array_S.loc[:,'Revenue'])\n", "\n", "Payback_time_S=np.argmax(Cash_Flows_array_S.loc[:,'Cumulative']>0) # determine first year where cumulative revenue is above 0\n", "\n", "\n", "display(Cash_Flows_array_S)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Estimated Total Costs and Revenue" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print('When energy price is {:.2f} cents/KwH and discount rate is {} % : '.format(Energy_price*100,Discount_rate*100))\n", "print('') \n", "print('') \n", "print(' Estimated Total Revenue is ${:.2f} Trillion USD'.format(Total_Revenue/(10**12)) )\n", "print('')\n", "print(' Net Revenue for AV systems is ${:.2f} Trillion USD'.format(AVS_net_rev/(10**12)) )\n", "print('')\n", "print(' Payback time for AV systems is {:.1f} years'.format(Payback_time) )\n", "print('')\n", "print('')\n", "print(' Net Revenue for AV systems with {} storage is ${:.2f} Trillion USD'.format(t_stor,AVS_stor_net_rev/(10**12)) )\n", "print('')\n", "print(' Payback time for AV systems with {} storage is {:.1f} years'.format(t_stor,Payback_time_S) )\n", "\n", "print('')\n", "print('')\n", "print('Time Value of Money ')\n", "print('')\n", "\n", "print('')\n", "print(' Net Present Value of Revenue for AV systems after {} years is ${:.2f} billion USD'.format(tPeriod-1,Cash_Flows_array.loc[tPeriod-1,'NPV Cumulative']/(10**9)) )\n", "print('')\n", "print(' Net Present Value of Revenue for AV systems with {} storage is ${:.2f} billion USD'.format(t_stor,Cash_Flows_array_S.loc[tPeriod-1,'NPV Cumulative']/(10**9)))\n", "print('')\n", "\n", "hide_toggle()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Comparisons with US FY 2019 Budget" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#FY 2019 budget\n", "# [12]https://www.usgovernmentspending.com/federal_budget_detail_fy19bc62020n#usgs302\n", "\n", "AVS_Amortized=Cost/tPeriod # AVS cost over life of system\n", "cost_dif_Amortized=Cost_difference/tPeriod # AVS cost over life of system\n", "AVS_Amortized_stor=Total_Cost.loc[t_stor][0]/tPeriod #AVS + storage over life of system\n", "\n", "Budget_2019=pd.DataFrame([[cost_dif_Amortized],[AVS_Amortized],[AVS_Amortized_stor],[1047*10**9],[651.2*10**9],[418.7*10**9],[384.5*10**9],[58.3*10**9],[939.4*10**9],[1041.2*10**9]],columns=['US Budget 2020($) '],index=['Δ Cost AV and PV','Agrivoltaic Arrays','Agrivoltaic + 4 hr storage','Social Security','Medicare (Net)', 'Medicade', 'Other Welfare', 'Employee Pensions (Net)', 'Defense', 'All Other Spending'])\n", "Budget_total=np.sum(Budget_2019)-(AVS_Amortized_stor+AVS_Amortized+cost_dif_Amortized)\n", "\n", "#format Table into billions for improved readibility\n", "Budget_2019_Billion=Budget_2019/(10**9); Budget_2019_Billion.columns=['US Budget FY 2019( Billion $) ']\n", "Budget_2019_Billion=Budget_2019_Billion.sort_values('US Budget FY 2019( Billion $) ', ascending=True)\n", "\n", "#Calculate budget fractions\n", "Budget_fraction=AVS_Amortized/Budget_total*100\n", "Budget_fraction_stor=AVS_Amortized_stor/Budget_total*100\n", "Budget_fraction_diff=cost_dif_Amortized/Budget_total*100\n", "\n", "\n", "print(\"Fraction of US FY 2019 Budget required to meet 20% of US electricity Generation with AVS = {:.3} %\".format(Budget_fraction[0]))\n", "print(\"\")\n", "print(\"Fraction of US FY 2019 Budget required to meet 20% of US electricity Generation with AVS and {} storage = {:.3} %\".format(t_stor,Budget_fraction_stor[0]))\n", "print(\"\")\n", "\n", "print(\"Fraction of US FY 2019 Budget required to meet cost differences between AVS and traditional PV = {:.3} %\".format(Budget_fraction_diff[0]))\n", "print(\"\")\n", "\n", "display(Budget_2019_Billion)\n", "\n", "# Plot Results\n", "\n", "plt.figure(figsize=(10,5))\n", "x=np.arange(0,len(Budget_2019_Billion))\n", "\n", "edge_colors=['red','red','black','red','black','black','black','black','black','black']\n", "\n", "data=[13.55062573,47.86076517,58.3,60.74550049,384.5,418.7,651.2,939.4,1041.2,1047]\n", "data=(Budget_2019_Billion.values).tolist()\n", "data=[val for sublist in data for val in sublist]\n", "plt.bar(x,height=data,color='tab:blue', edgecolor=edge_colors)\n", "\n", "plt.xticks(x,Budget_2019_Billion.index )\n", "plt.xticks(rotation=35, ha=\"right\")\n", "plt.ylabel('Annual Cost (Billion $)')\n", "\n", "\n", "\n", "AV_patch= mpatches.Patch( edgecolor='red', label='Agrivoltaics')\n", "base_patch= mpatches.Patch(color='tab:blue', label='FY 2019 Budget')\n", "plt.legend(handles=[AV_patch,base_patch])\n", "plt.tight_layout()\n", "plt.gcf().subplots_adjust(bottom=0.3)\n", "plt.show()\n", "\n", "hide_toggle()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Land Requirement Data (Procedure Step 6)\n", "\n", "Land use data was obtained from \"Land-Use Requirements for Solar Power Plants in the United States\" ([5](https://www.nrel.gov/docs/fy13osti/56290.pdf)). The study provides estimated required land area, both direct and indirect, for a variety of solar array types and for small (<20 Mw capacity) and large (> 20 Mw capacity) solar arrays. These values can be found in the table below. For the purposes of this study only large solar arrays were considered. The calculation used the average total area for large arrays. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#land use data from NREL 2013 study [5] (https://www.nrel.gov/docs/fy13osti/56290.pdf)\n", "\n", "#generation Weighted average (acres/MWac)\n", "L_PV=pd.DataFrame([[7.2,7.9],[5.8,7.5],[9.0,8.3],[6.1,8.1]],index=['Average','Fixed','1-axis','2-axis CPV'],columns=['Direct Area','Total Area'])\n", "L_PV=L_PV*0.404686*10**3 # Convert acres/MWac to ha/GWac\n", "\n", "print ('Large Photovoltaic array (>20 MW) Area(ha)/ GWac')\n", "display(L_PV)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Calculated Land Requirements (Procedure Step 7)\n", "\n", "AV systems are designed to minimally inhibit agricultural operations. They have greater spacings between panels than traditional arrays and an increased area per unit of capacity. Thus, NREL’s average total required area per capacity for large photovoltaic arrays ([5](https://www.nrel.gov/docs/fy13osti/56290.pdf)) was doubled for our land area calculation. It is important to note that capacity-based land requirements have wide and skewed distributions which are not adequately captured when using an average value. The actual land required per unit capacity is highly dependent on the solar radiation at the site and thus varies widely throughout the US. \n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Area_per_GWac=L_PV['Total Area']['Average']\n", "Solar_land=Required_Capacity/derate_factor*Area_per_GWac #ha required to meet demand using traditional solar arrays\n", "AV_land=Solar_land*2 # Double required land, assuming half density of Agrivoltaic arrays for agricultural production\n", "print('Anticipated land required to meet 20% of Electricity Generation using APV systems: {:,.1} ha ({:,.1f} km^2) ({:,.1f} mile^2)'.format(AV_land, AV_land/100, AV_land/259 )) \n", "Area_MD=3213300 # ha\n", "Total_farmland = 363164895.346 #ha (from USDA Farms and Land in Farm 2019 Summary) [13] \n", " #(https://www.nass.usda.gov/Publications/Todays_Reports/reports/fnlo0220.pdf)\n", "\n", "print('')\n", "print ('Aproximately {:.2f} times the area of the State of Maryland '.format(AV_land/Area_MD))\n", "print('')\n", "print ('Aproximately {:.2f} % of total US Farmland'.format(AV_land/Total_farmland*100))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Land for storage\n", "\n", "The land for storage value here is considered to be the area of the individual battery continers. Additional indirect space is not accounted for. Land required for storage is orders of magnitude less than for solar arrays. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "Bat_container=40 * 8.5 # Sq feet - Dimensions from NREL study [6](https://www.nrel.gov/docs/fy19osti/71714.pdf)\n", "Bat_container_ha=Bat_container/(9.2903*10**6) # conver to ha\n", "num_container=(store*1000/5) # Number of containers per array , 1 container needed per 5 MWh storage\n", "num_container.columns=['Number of Containers Required per 60MW Storage system']\n", "\n", "Area_stor=pd.DataFrame([[num_battery_array.loc['30 min'][0]*num_container.loc['30 min'][0]*Bat_container_ha],[num_battery_array.loc['1 Hour'][0]*num_container.loc['1 Hour'][0]*Bat_container_ha],[num_battery_array.loc['2 Hour'][0]*num_container.loc['2 Hour'][0]*Bat_container_ha],[num_battery_array.loc['4 Hour'][0]*num_container.loc['4 Hour'][0]*Bat_container_ha]],columns=['Area Required for Storage (ha)'],index=['30 min','1 Hour', '2 Hour', '4 Hour'])\n", "display(Area_stor)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Green House Gas Emissions (Procedure Step 8)\n", "\n", "Emission reductions were calculated by comparing current emission estimates for US electricity generation ([8](https://www.eia.gov/tools/faqs/faq.php?id=74&t=11#:~:text=In%202018%2C%20total%20U.S.%20electricity,of%20CO2%20emissions%20per%20kWh))\n", "with Intergovernmental Panel on Climate Change (IPCC) emission estimates for large scale PV ([9](https://www.ipcc.ch/report/ar5/wg2/)). The calculation does not consider related emissions from the manufacturing or end-of-life processing of the panels" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Grid_CO2=449.0564 # gram CO2 per kWh (EIA [8] https://www.eia.gov/tools/faqs/faq.php?id=74&t=11#:~:text=In%202018%2C%20total%20U.S.%20electricity,of%20CO2%20emissions%20per%20kWh.)\n", "PV_CO2= 48 # gCO2eq per kWh (IPCC [9] (https://www.ipcc.ch/report/ar5/wg2/))\n", "Car_Co2= 4.6 #Metric tons of Co2 per year (US EPA [14] https://nepis.epa.gov/Exe/ZyPDF.cgi?Dockey=P100U8YT.pdf (2018) )\n", "\n", "Carbon_reduction=Electricity_Generation_GWH*1000*(Grid_CO2-PV_CO2)/(10**6)\n", "\n", "print(\"\")\n", "print('Anticipated reduction of CO2 emmisions by {:,.1f} Metric tons'.format(Carbon_reduction))\n", "print(\"\")\n", "print('This is approximately equivalent to removing {:,.0f} cars from the road annually'.format(Carbon_reduction/Car_Co2))\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Jobs Created (Procedure Step 9)\n", "\n", "In an attempt to quantify the potential jobs created by large scale implementation of Agrivoltaic systems, employment factors from Hondo and Moriizumi ([10](https://www.sciencedirect.com/science/article/pii/S1364032117306676)) were considered. Hondo and Moriizumi applied a Renewable Energy-Focused Input-Output model to determine the total employment creation potential over the lifecycle of nine different renewable energy technologies. The employment factors have the units of person-years/ GWh. \n", "\n", "For clarification: A person year refers to the amount of work done by an individual during a working year on a specific job. So for example 30 person-years could refer to a job that 30 people work on full time for year or that 15 people work on for 2 years, etc. \n", "\n", "These employment factors are broken down into both Construction and Operation, and direct and indirect employment. The specific Employment factors are shown below. For further specifics visit the original publication ([10](https://www.sciencedirect.com/science/article/pii/S1364032117306676)).\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "#Employment factors, units = person-years/ GWh\n", "# Hondo and Moriizumi[10] (https://www.sciencedirect.com/science/article/pii/S1364032117306676)\n", "\n", "Jobs=pd.DataFrame([[0.67,1.43,0.33,0.30,2.73],[0.59,1.12,0.89,0.23,2.84]],index=['Small PV','Large PV'],columns=['Construction direct','Construction indirect','Operation direct','Operation indirect','Total'])\n", "display(Jobs)\n", "print(\" Units = person-years/ GWh\")\n", "hide_toggle(for_next=True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Jobs_LPV=Electricity_Generation_GWH*Jobs['Total']['Large PV']\n", "print('Anticipated life cycle jobs created by meeting 20% of US electricity generation with AV systems : {:.2f} million person-years'.format(Jobs_LPV/(10**6)))\n", "print('')\n", "Operational_jobs_LPV=Electricity_Generation_GWH*(Jobs['Operation direct']['Large PV']+Jobs['Operation indirect']['Large PV'])\n", "print('Anticipated Operation and Maintenance jobs created by meeting 20% of US electricity generation with AV systems : {:.2f} million person-years'.format(Operational_jobs_LPV/(10**6)))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Overall Results\n", "\n", "Estimated total Costs, land used, and jobs created\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "hide_toggle(for_next=True)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print('Cost to meet 2019 Electricity generation with AV systems: $ {:,.2f} Trillion '.format(Cost/(10**12)))\n", "print('')\n", "print('Cost to meet 2019 Electricity generation with AV with {} storage: $ {:.2f} Trillion '.format(t_stor,Total_Cost.loc[t_stor][0]/(10**12)))\n", "print('')\n", "print('Total land required to meet 2018 Domestic Electricity Consumption with AV with {} storage: {:.2} square km'.format(t_stor,(AV_land+ Area_stor.loc[t_stor][0]/100)))\n", "print('')\n", "print('Total jobs created by meeting US domestic electricity demand with AV systems : {:.2f} million person-years or {:,.0f} people employed for 20 years'.format(Jobs_LPV/(10**6),Jobs_LPV/20))\n", "print('')\n", "print('Operation and Maintenance jobs created by meeting US domestic electricity with AV systems : {:.2f} million person-years or {:,.0f} people employed for 20 years'.format(Operational_jobs_LPV/(10**6),Operational_jobs_LPV/20))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Inputs for this Run\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "Electricity_Generation_GWH = Estimated_Electricity_Generation.result # current value of returned object (in this case a+b)\n", "print('Electricity Generation Value used for calculations (GWh) = {:,.2f}'.format(Electricity_Generation_GWH))\n", "print('')\n", "print('Percent increase from 2019 value = {} %'.format(Estimated_Electricity_Generation.children[0].value))\n", "\n", "Capacity_factor=C_factor.result\n", "print('')\n", "print('Capacity factor = {:.2f} %'.format(Capacity_factor*100))\n", "\n", "Capex= float(f.Capex.value)\n", "ONM=float(f.ONM.value)\n", "print('')\n", "print('Capital Expenditures = ${:.2f}/Watt'.format(Capex))\n", "print('')\n", "print('Operation and Maintenance = ${:.2f}/kW/Year'.format(ONM))\n", "\n", "Discount_rate=d_r.result/100\n", "print(\"\")\n", "print(\"Discount rate = {} %\".format(d_r.result))\n", "\n", "Panel_life=Array_lifespan.result\n", "print('')\n", "print('Panel life = {} years'.format(Panel_life))\n", "\n", "print(\"\")\n", "t_stor=storage_time.value\n", "print(\"Lithium Ion Storage Capacity = {}\".format(t_stor))\n", "\n", "\n", "Energy_price=E_price.result/100 #$/kWh\n", "Energy_price_GWh=Energy_price*(10**6) #$/GWh\n", "print('')\n", "print('Electricity Price = {:.2f} cents/kWh'.format(E_price.result))\n", "\n", "hide_toggle()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.6.9" } }, "nbformat": 4, "nbformat_minor": 2 }