From 4c3266d02bdb339eff6241064a79ce7f53b342a8 Mon Sep 17 00:00:00 2001 From: MDKempe <58960264+MDKempe@users.noreply.github.com> Date: Tue, 29 Aug 2023 14:49:12 -0600 Subject: [PATCH 1/8] Update degradation.py Changed temp_cell to just temp because it can get confusing when you actually want to use the surface temperature. --- pvdeg/degradation.py | 90 ++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/pvdeg/degradation.py b/pvdeg/degradation.py index 4b0f744a..ce948ec3 100644 --- a/pvdeg/degradation.py +++ b/pvdeg/degradation.py @@ -15,7 +15,7 @@ #TODO: Clean up all those functions and add gaps functionality -def _deg_rate_env(poa_global, temp_cell, temp_chamber, p, Tf): +def _deg_rate_env(poa_global, temp, temp_chamber, p, Tf): """ Helper function. Find the rate of degradation kenetics using the Fischer model. Degradation kentics model interpolated 50 coatings with respect to @@ -28,8 +28,8 @@ def _deg_rate_env(poa_global, temp_cell, temp_chamber, p, Tf): ------------ poa_global : float (Global) Plan of Array irradiance [W/m²] - temp_cell : float - Solar module cell temperature [°C] + temp : float + Solar module temperature [°C] temp_chamber : float Reference temperature [°C] "Chamber Temperature" p : float @@ -44,7 +44,7 @@ def _deg_rate_env(poa_global, temp_cell, temp_chamber, p, Tf): rate of Degradation (NEED TO ADD METRIC) """ - return poa_global**(p) * Tf ** ((temp_cell - temp_chamber)/10) + return poa_global**(p) * Tf ** ((temp - temp_chamber)/10) def _deg_rate_chamber(I_chamber, p): """ @@ -96,7 +96,7 @@ def vantHoff_deg(weather_df, meta, I_chamber, temp_chamber, poa=None, - temp_cell=None, + temp=None, p=0.5, Tf=1.41): """ @@ -114,7 +114,7 @@ def vantHoff_deg(weather_df, meta, Reference temperature [°C] "Chamber Temperature" poa : series or data frame, optional dataframe containing 'poa_global', Global Plane of Array Irradiance [W/m²] - temp_cell : pandas series, optional + temp : pandas series, optional Solar module temperature or Cell temperature [°C]. If no cell temperature is given, it will be generated using the default paramters of pvdeg.temperature.cell p : float @@ -135,13 +135,13 @@ def vantHoff_deg(weather_df, meta, if isinstance(poa, pd.DataFrame): poa_global = poa['poa_global'] - if temp_cell is None: - temp_cell = temperature.cell(weather_df=weather_df, + if temp is None: + temp = temperature.cell(weather_df=weather_df, meta=meta, poa=poa) rateOfDegEnv = _deg_rate_env(poa_global=poa_global, - temp_cell=temp_cell, + temp=temp, temp_chamber=temp_chamber, p=p, Tf=Tf) @@ -155,16 +155,16 @@ def vantHoff_deg(weather_df, meta, return accelerationFactor -def _to_eq_vantHoff(temp_cell, Tf=1.41): +def _to_eq_vantHoff(temp, Tf=1.41): """ Function to obtain the Vant Hoff temperature equivalent [°C] Parameters ---------- Tf : float - Multiplier for the increase in degradation for every 10[°C] temperature increase - temp_cell : pandas series - Solar module temperature or Cell temperature [°C] + Multiplier for the increase in degradation for every 10[°C] temperature increase. Default value of 1.41. + temp : pandas series + Solar module surface or Cell temperature [°C] Returns ------- @@ -172,17 +172,18 @@ def _to_eq_vantHoff(temp_cell, Tf=1.41): Vant Hoff temperature equivalent [°C] """ - toSum = Tf ** (temp_cell / 10) + + toSum = Tf ** (temp / 10) summation = toSum.sum(axis=0, skipna=True) - Toeq = (10 / np.log(Tf)) * np.log(summation / len(temp_cell)) + Toeq = (10 / np.log(Tf)) * np.log(summation / len(temp)) return Toeq def IwaVantHoff(weather_df, meta, poa=None, - temp_cell=None, + temp=None, Teq=None, p=0.5, Tf=1.41): @@ -199,7 +200,7 @@ def IwaVantHoff(weather_df, meta, Location meta-data containing at least latitude, longitude, altitude poa : float series or dataframe Series or dataframe containing 'poa_global', Global Plane of Array Irradiance W/m² - temp_cell : float series + temp : float series Solar module temperature or Cell temperature [°C] Teq : series VantHoff equivalent temperature [°C] @@ -214,29 +215,28 @@ def IwaVantHoff(weather_df, meta, Environment Characterization [W/m²[] """ - if poa is None: poa = spectral.poa_irradiance(weather_df,meta) - if temp_cell is None: - temp_cell = temperature.cell(weather_df,meta,poa) + if temp is None: + temp = temperature.cell(weather_df,meta,poa) if Teq is None: - Teq = _to_eq_vantHoff(temp_cell, Tf) + Teq = _to_eq_vantHoff(temp, Tf) if isinstance(poa, pd.DataFrame): poa_global = poa['poa_global'] else: poa_global = poa - toSum = (poa_global ** p) * (Tf ** ((temp_cell - Teq)/10)) + toSum = (poa_global ** p) * (Tf ** ((temp - Teq)/10)) summation = toSum.sum(axis=0, skipna=True) Iwa = (summation / len(poa_global)) ** (1 / p) return Iwa -def _arrhenius_denominator(poa_global, rh_outdoor, temp_cell, Ea, p, n): +def _arrhenius_denominator(poa_global, rh_outdoor, temp, Ea, p, n): """ Helper function. Calculates the rate of degredation of the Environmnet @@ -252,7 +252,7 @@ def _arrhenius_denominator(poa_global, rh_outdoor, temp_cell, Ea, p, n): rh_back_encap(); rh_front_encap(); rh_surface_outside() n : float Fit parameter for relative humidity - temp_cell : pandas series + temp : pandas series Solar module temperature or Cell temperature [°C] Ea : float Degredation Activation Energy [kJ/mol] @@ -264,7 +264,7 @@ def _arrhenius_denominator(poa_global, rh_outdoor, temp_cell, Ea, p, n): """ environmentDegradationRate = poa_global**(p) * rh_outdoor**( - n) * np.exp(- (Ea / (0.00831446261815324 * (temp_cell + 273.15)))) + n) * np.exp(- (Ea / (0.00831446261815324 * (temp + 273.15)))) return environmentDegradationRate @@ -306,7 +306,7 @@ def arrhenius_deg(weather_df, meta, Ea, temp_chamber, poa=None, - temp_cell=None, + temp=None, p=0.5, n=1): """ @@ -337,7 +337,7 @@ def arrhenius_deg(weather_df, meta, if Ea=0 is used there will be not dependence on temperature and degradation will proceed according to the amount of light and humidity. poa : pd.dataframe, optional Global Plane of Array Irradiance [W/m²] - temp_cell : pd.series, optional + temp : pd.series, optional Solar module temperature or Cell temperature [°C]. If no cell temperature is given, it will be generated using the default parameters from pvdeg.temperature.cell p : float @@ -357,8 +357,8 @@ def arrhenius_deg(weather_df, meta, if poa is None: poa = spectral.poa_irradiance(weather_df,meta) - if temp_cell is None: - temp_cell = temperature.cell(weather_df,meta,poa) + if temp is None: + temp = temperature.cell(weather_df,meta,poa) if isinstance(poa, pd.DataFrame): poa_global = poa['poa_global'] @@ -368,7 +368,7 @@ def arrhenius_deg(weather_df, meta, arrheniusDenominator = _arrhenius_denominator(poa_global=poa_global, rh_outdoor=rh_outdoor, - temp_cell=temp_cell, + temp=temp, Ea=Ea, p=p, n=n) @@ -384,14 +384,14 @@ def arrhenius_deg(weather_df, meta, return accelerationFactor -def _T_eq_arrhenius(temp_cell, Ea): +def _T_eq_arrhenius(temp, Ea): """ Get the Temperature equivalent required for the settings of the controlled environment Calculation is used in determining Arrhenius Environmental Characterization Parameters ----------- - temp_cell : pandas series + temp : pandas series Solar module temperature or Cell temperature [°C] Ea : float Degredation Activation Energy [kJ/mol] @@ -405,15 +405,15 @@ def _T_eq_arrhenius(temp_cell, Ea): """ summationFrame = np.exp(- (Ea / - (0.00831446261815324 * (temp_cell + 273.15)))) + (0.00831446261815324 * (temp + 273.15)))) sumForTeq = summationFrame.sum(axis=0, skipna=True) - Teq = -((Ea) / (0.00831446261815324 * np.log(sumForTeq / len(temp_cell)))) + Teq = -((Ea) / (0.00831446261815324 * np.log(sumForTeq / len(temp)))) # Convert to celsius Teq = Teq - 273.15 return Teq -def _RH_wa_arrhenius(rh_outdoor, temp_cell, Ea, Teq=None, n=1): +def _RH_wa_arrhenius(rh_outdoor, temp, Ea, Teq=None, n=1): """ NOTE @@ -426,7 +426,7 @@ def _RH_wa_arrhenius(rh_outdoor, temp_cell, Ea, Teq=None, n=1): Relative Humidity of material of interest. Acceptable relative humiditys can be calculated from the below functions: rh_backsheet(), rh_back_encap(), rh_front_encap(), rh_surface_outside() - temp_cell : pandas series + temp : pandas series solar module temperature or Cell temperature [°C] Ea : float Degredation Activation Energy [kJ/mol] @@ -443,10 +443,10 @@ def _RH_wa_arrhenius(rh_outdoor, temp_cell, Ea, Teq=None, n=1): """ if Teq is None: - Teq = _T_eq_arrhenius(temp_cell, Ea) + Teq = _T_eq_arrhenius(temp, Ea) summationFrame = (rh_outdoor ** n) * np.exp(- (Ea / - (0.00831446261815324 * (temp_cell + 273.15)))) + (0.00831446261815324 * (temp + 273.15)))) sumForRHwa = summationFrame.sum(axis=0, skipna=True) RHwa = (sumForRHwa / (len(summationFrame) * np.exp(- (Ea / (0.00831446261815324 * (Teq + 273.15)))))) ** (1/n) @@ -460,7 +460,7 @@ def IwaArrhenius(weather_df, meta, rh_outdoor, Ea, poa=None, - temp_cell=None, + temp=None, RHwa=None, Teq=None, p=0.5, @@ -484,7 +484,7 @@ def IwaArrhenius(weather_df, meta, Degradation Activation Energy [kJ/mol] poa : pd.dataframe, optional must contain 'poa_global', Global Plan of Array irradiance [W/m²] - temp_cell : pd.series, optional + temp : pd.series, optional Solar module temperature or Cell temperature [°C] RHwa : float, optional Relative Humidity Weighted Average [%] @@ -504,14 +504,14 @@ def IwaArrhenius(weather_df, meta, if poa is None: poa = spectral.poa_irradiance(weather_df,meta) - if temp_cell is None: - temp_cell = temperature.cell(weather_df,meta,poa) + if temp is None: + temp = temperature.cell(weather_df,meta,poa) if Teq is None: - Teq = _T_eq_arrhenius(temp_cell, Ea) + Teq = _T_eq_arrhenius(temp, Ea) if RHwa is None: - RHwa = _RH_wa_arrhenius(rh_outdoor, temp_cell, Ea) + RHwa = _RH_wa_arrhenius(rh_outdoor, temp, Ea) if isinstance(poa, pd.DataFrame): poa_global = poa['poa_global'] @@ -519,7 +519,7 @@ def IwaArrhenius(weather_df, meta, poa_global = poa numerator = poa_global**(p) * rh_outdoor**(n) * \ - np.exp(- (Ea / (0.00831446261815324 * (temp_cell + 273.15)))) + np.exp(- (Ea / (0.00831446261815324 * (temp + 273.15)))) sumOfNumerator = numerator.sum(axis=0, skipna=True) denominator = (len(numerator)) * ((RHwa)**n) * \ From ee331d78c8e87a659f48dafd58a4f09a149d9c5a Mon Sep 17 00:00:00 2001 From: MDKempe <58960264+MDKempe@users.noreply.github.com> Date: Thu, 31 Aug 2023 16:59:39 -0600 Subject: [PATCH 2/8] Documentation change Changed the Documentation. --- ...radation.ipynb => PVDegradationTools.ipynb | 114 ++++-- pvdeg/degradation.py | 2 +- pvdeg/temperature.py | 18 +- .../Van't Hoff Degradation Model.ipynb | 348 ++++++++++++++++++ 4 files changed, 435 insertions(+), 47 deletions(-) rename pvdeg_tutorials/tutorials/2 - Degradation.ipynb => PVDegradationTools.ipynb (75%) create mode 100644 pvdeg_tutorials/tutorials/Van't Hoff Degradation Model.ipynb diff --git a/pvdeg_tutorials/tutorials/2 - Degradation.ipynb b/PVDegradationTools.ipynb similarity index 75% rename from pvdeg_tutorials/tutorials/2 - Degradation.ipynb rename to PVDegradationTools.ipynb index 29db9e1b..ee6d9c98 100644 --- a/pvdeg_tutorials/tutorials/2 - Degradation.ipynb +++ b/PVDegradationTools.ipynb @@ -31,12 +31,12 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 111, "metadata": {}, "outputs": [], "source": [ "# if running on google colab, uncomment the next line and execute this cell to install the dependencies and prevent \"ModuleNotFoundError\" in later cells:\n", - "# !pip install pvdeg==0.1.1" + "# pip install pvdeg==0.1.1" ] }, { @@ -65,10 +65,19 @@ "cell_type": "code", "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Latitude = 39.73 Longitude = -105.18 - -\n" + ] + } + ], "source": [ "PSM_FILE = os.path.join(DATA_DIR,'psm3_demo.csv')\n", - "WEATHER, META = pvdeg.weather.read(PSM_FILE,'psm')" + "WEATHER, META = pvdeg.weather.read(PSM_FILE,'psm')\n", + "print ( 'Latitude =', META['latitude'], 'Longitude =', META ['longitude'] , META['Country'], META['City'])" ] }, { @@ -82,7 +91,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 37, "metadata": {}, "outputs": [], "source": [ @@ -101,35 +110,58 @@ "source": [ "## 3. VantHoff Degradation\n", "\n", - "Van 't Hoff Irradiance Degradation\n", + "Van't Hoff Irradiance Degradation Equation:\n", + "$$ R_o = R_D · G^p · T_f^{\\frac{T}{10} }$$\n", "\n", - "For one year of degredation the controlled environmnet lamp settings will need to be set to IWa.\n", + "For the yearly average degredation outdoors to be the same as the controlled environmnet, the lamp settings will need to be set to *G$_{WA}$* and the temperature set to *T$_{oeq}$*.\n", "\n", "As with most `pvdeg` functions, the following functions will always require two arguments (weather_df and meta)" ] }, { "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], + "execution_count": 39, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "AF = 27.8 , T_oeq = 19.6 (°C) , and G_WA = 297 (W/m²)\n" + ] + } + ], "source": [ - "# chamber irradiance (W/m^2)\n", - "I_chamber = 1000 \n", - "# chamber temperature (C)\n", - "temp_chamber = 60\n", - "\n", - "# calculate the VantHoff Acceleration factor\n", + "# chamber irradiance (W/m²)\n", + "I_chamber = 1600 \n", + "# chamber temperature (°C)\n", + "temp_chamber = 85\n", + "# Schwartzchild Coefficient\n", + "p=0.64\n", + "# Acceleration factor for every 10°C\n", + "Tf=1.41\n", + "\n", + "# calculate the Van't Hoff Acceleration factor\n", "vantHoff_deg = pvdeg.degradation.vantHoff_deg(weather_df=WEATHER, meta=META,\n", " I_chamber=I_chamber,\n", " temp_chamber=temp_chamber,\n", " poa=poa_df,\n", - " temp_cell=temp_cell)\n", + " temp=temp_cell, \n", + " p=p, \n", + " Tf=Tf)\n", "\n", - "# calculate the VantHoff weighted irradiance\n", + "# calculate the Van't Hoff weighted irradiance\n", "irr_weighted_avg_v = pvdeg.degradation.IwaVantHoff(weather_df=WEATHER, meta=META,\n", " poa=poa_df,\n", - " temp_cell=temp_cell)" + " temp=temp_cell, \n", + " p=p, \n", + " Tf=Tf)\n", + "# calculate the Van't Hoff weighted average temperature\n", + "To_eq = pvdeg.degradation._to_eq_vantHoff(temp_cell, Tf)\n", + "\n", + "print ('AF =', round(vantHoff_deg,1), ', T_oeq =', round(To_eq,1) , '(°C) , and G_WA =',round(irr_weighted_avg_v), '(W/m²)')" ] }, { @@ -139,21 +171,23 @@ "## 4. Arrhenius\n", "Calculate the Acceleration Factor between the rate of degredation of a modeled environmnet versus a modeled controlled environmnet\n", "\n", - "Example: \"If the AF=25 then 1 year of Controlled Environment exposure is equal to 25 years in the field\"\n", + "Example: \"If the *AF*=25 then 1 year of Controlled Environment exposure is equal to 25 years in the field\"\n", "\n", "Equation:\n", - "$$ AF = N * \\frac{ I_{chamber}^x * RH_{chamber}^n * e^{\\frac{- E_a}{k T_{chamber}}} }{ \\Sigma (I_{POA}^x * RH_{outdoor}^n * e^{\\frac{-E_a}{k T_outdoor}}) }$$\n", + "$$ AF = N · \\frac{ G_{chamber}^x · RH_{chamber}^n · e^{\\frac{- E_a}{k T_{chamber}}} }{ \\Sigma (G_{POA}^x · RH_{outdoor}^n · e^{\\frac{-E_a}{k T_outdoor}}) }$$\n", "\n", - "Function to calculate IWa, the Environment Characterization (W/m²). For one year of degredation the controlled environmnet lamp settings will need to be set at IWa.\n", + "Function to calculate *G$_{WA}$*, the Environment Characterization (W/m²). If the controlled environmnet lamp settings are set at *G$_{WA}$*, and the temperature set to *T$_{eq}$*, then the degradation will be the same as the yearly average outdoors.\n", "\n", "Equation:\n", - "$$ I_{WA} = [ \\frac{ \\Sigma (I_{outdoor}^x * RH_{outdoor}^n e^{\\frac{-E_a}{k T_{outdood}}}) }{ N * RH_{WA}^n * e^{- \\frac{E_a}{k T_eq}} } ]^{\\frac{1}{x}} $$" + "$$ G_{WA} = [ \\frac{ \\Sigma (G_{outdoor}^x · RH_{outdoor}^n e^{\\frac{-E_a}{k T_{outdood}}}) }{ N · RH_{WA}^n · e^{- \\frac{E_a}{k T_eq}} } ]^{\\frac{1}{x}} $$" ] }, { "cell_type": "code", - "execution_count": 6, - "metadata": {}, + "execution_count": 8, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "# relative humidity within chamber (%)\n", @@ -171,13 +205,13 @@ " rh_chamber=rh_chamber,\n", " temp_chamber=temp_chamber,\n", " poa=poa_df,\n", - " temp_cell=temp_cell,\n", + " temp=temp,\n", " Ea=Ea)\n", "\n", "irr_weighted_avg_a = pvdeg.degradation.IwaArrhenius(weather_df=WEATHER, meta=META,\n", " poa=poa_df, \n", " rh_outdoor=WEATHER['relative_humidity'],\n", - " temp_cell=temp_cell,\n", + " temp=temp,\n", " Ea=Ea)" ] }, @@ -192,8 +226,10 @@ }, { "cell_type": "code", - "execution_count": 7, - "metadata": {}, + "execution_count": 9, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "# chamber settings\n", @@ -213,8 +249,10 @@ }, { "cell_type": "code", - "execution_count": 8, - "metadata": {}, + "execution_count": 10, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "rh_surface = pvdeg.humidity.surface_outside(rh_ambient=WEATHER['relative_humidity'],\n", @@ -244,8 +282,10 @@ }, { "cell_type": "code", - "execution_count": 9, - "metadata": {}, + "execution_count": 11, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "fatigue = pvdeg.fatigue.solder_fatigue(weather_df=WEATHER, meta=META)" @@ -265,8 +305,10 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, + "execution_count": 12, + "metadata": { + "collapsed": true + }, "outputs": [], "source": [ "# select the month of June\n", @@ -301,7 +343,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.13" + "version": "3.9.16" } }, "nbformat": 4, diff --git a/pvdeg/degradation.py b/pvdeg/degradation.py index ce948ec3..b5a55a63 100644 --- a/pvdeg/degradation.py +++ b/pvdeg/degradation.py @@ -100,7 +100,7 @@ def vantHoff_deg(weather_df, meta, p=0.5, Tf=1.41): """ - Van 't Hoff Irradiance Degradation + Van't Hoff Irradiance Degradation Parameters ----------- diff --git a/pvdeg/temperature.py b/pvdeg/temperature.py index a7d1fd87..341e9600 100644 --- a/pvdeg/temperature.py +++ b/pvdeg/temperature.py @@ -14,24 +14,22 @@ def module( wind_speed_factor=1): """ - Calculate module temperature based on weather data from the National Solar Radiation - Database (NSRDB) for a given location (gid). + Calculate module surface temperature using pvlib. Parameters ---------- - nsrdb_file : str - The file path to the NSRDB file. - gid : int - The geographical location ID in the NSRDB file. + weather_df : (pd.dataframe) + Data Frame with minimum requirements of 'temp_air' and 'wind_speed' poa : pandas.DataFrame Contains keys/columns 'poa_global', 'poa_direct', 'poa_diffuse', 'poa_sky_diffuse', 'poa_ground_diffuse'. temp_model : str, optional - The temperature model to use, 'sapm' from pvlib by default. + The temperature model to use, Sandia Array Performance Model 'sapm' from pvlib by default. conf : str, optional The configuration of the PV module architecture and mounting configuration. - Options: 'open_rack_glass_polymer' (default), 'open_rack_glass_glass', - 'close_mount_glass_glass', 'insulated_back_glass_polymer' + Options: + 'sapm': 'open_rack_glass_polymer' (default), 'open_rack_glass_glass', + 'close_mount_glass_glass', 'insulated_back_glass_polymer' Returns ------- @@ -74,7 +72,7 @@ def cell(weather_df, conf : (str) The configuration of the PV module architecture and mounting configuration. Options: 'open_rack_glass_polymer' (default), 'open_rack_glass_glass', - 'close_mount_glass_glass', 'insulated_back_glass_polymer' + 'close_mount_glass_glass', 'insulated_back_glass_polymer' ''' parameters = pvlib.temperature.TEMPERATURE_MODEL_PARAMETERS[temp_model][conf] diff --git a/pvdeg_tutorials/tutorials/Van't Hoff Degradation Model.ipynb b/pvdeg_tutorials/tutorials/Van't Hoff Degradation Model.ipynb new file mode 100644 index 00000000..176bab1f --- /dev/null +++ b/pvdeg_tutorials/tutorials/Van't Hoff Degradation Model.ipynb @@ -0,0 +1,348 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# A - Van't Hoff Degradation\n", + "### Calculate site specific degradation according to the Van't Hoff equation\n", + "***\n", + "Michael Kempe\n", + "\n", + "2023.08.31\n", + "***\n", + "\n", + "**Requirements**:\n", + "- compatible weather file (PSM3, TMY3, EPW) or lattitude and longitude of desired site\n", + "- Accelerated testing chamber parameters\n", + " - chamber irradiance [W/m^2]\n", + " - chamber temperature [°C]\n", + "- 10°C acceleration factor\n", + "\n", + "**Steps**:\n", + "1. Read/find the weather data\n", + "2. Generate basic modeling data\n", + "3. Calculate VantHoff degradation acceleration factor\n", + "4. Expand calculations to a region" + ] + }, + { + "cell_type": "code", + "execution_count": 111, + "metadata": {}, + "outputs": [], + "source": [ + "# if running on google colab, uncomment the next line and execute this cell to install the dependencies and prevent \"ModuleNotFoundError\" in later cells:\n", + "# pip install pvdeg==0.1.1" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import pandas as pd\n", + "\n", + "import pvdeg \n", + "from pvdeg import DATA_DIR" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Read In the Weather File\n", + "\n", + "This is usually the first step. Use a PSM3, TMY3, or EPW file. For this demo, use the provided PSM3 weather file." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Latitude = 39.73 Longitude = -105.18 - -\n" + ] + } + ], + "source": [ + "PSM_FILE = os.path.join(DATA_DIR,'psm3_demo.csv')\n", + "WEATHER, META = pvdeg.weather.read(PSM_FILE,'psm')\n", + "print ( 'Latitude =', META['latitude'], 'Longitude =', META ['longitude'] , META['Country'], META['City'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Generate Basic Modeling Data\n", + "\n", + "For this tutorial we will need solar position, POA, PV cell and module temperature. Let's gernate those individually with their respective functions." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "sol_pos = pvdeg.spectral.solar_position(weather_df=WEATHER, meta=META)\n", + "\n", + "poa_df = pvdeg.spectral.poa_irradiance(weather_df=WEATHER, meta=META, sol_position=sol_pos)\n", + "\n", + "temp_cell = pvdeg.temperature.cell(weather_df=WEATHER, meta=META, poa=poa_df)\n", + "\n", + "temp_module = pvdeg.temperature.module(weather_df=WEATHER, meta=META, poa=poa_df)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. VantHoff Degradation\n", + "\n", + "Van't Hoff Irradiance Degradation Equation:\n", + "$$ R_o = R_D · G^p · T_f^{\\frac{T}{10} }$$\n", + "\n", + "For the yearly average degredation outdoors to be the same as the controlled environmnet, the lamp settings will need to be set to *G$_{WA}$* and the temperature set to *T$_{oeq}$*.\n", + "\n", + "As with most `pvdeg` functions, the following functions will always require two arguments (weather_df and meta)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "AF = 27.8 , T_oeq = 19.6 (°C) , and G_WA = 297 (W/m²)\n" + ] + } + ], + "source": [ + "# chamber irradiance (W/m²)\n", + "I_chamber = 1600 \n", + "# chamber temperature (°C)\n", + "temp_chamber = 85\n", + "# Schwartzchild Coefficient\n", + "p=0.64\n", + "# Acceleration factor for every 10°C\n", + "Tf=1.41\n", + "\n", + "# calculate the Van't Hoff Acceleration factor\n", + "vantHoff_deg = pvdeg.degradation.vantHoff_deg(weather_df=WEATHER, meta=META,\n", + " I_chamber=I_chamber,\n", + " temp_chamber=temp_chamber,\n", + " poa=poa_df,\n", + " temp=temp_cell, \n", + " p=p, \n", + " Tf=Tf)\n", + "\n", + "# calculate the Van't Hoff weighted irradiance\n", + "irr_weighted_avg_v = pvdeg.degradation.IwaVantHoff(weather_df=WEATHER, meta=META,\n", + " poa=poa_df,\n", + " temp=temp_cell, \n", + " p=p, \n", + " Tf=Tf)\n", + "# calculate the Van't Hoff weighted average temperature\n", + "To_eq = pvdeg.degradation._to_eq_vantHoff(temp_cell, Tf)\n", + "\n", + "print ('AF =', round(vantHoff_deg,1), ', T_oeq =', round(To_eq,1) , '(°C) , and G_WA =',round(irr_weighted_avg_v), '(W/m²)')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. Arrhenius\n", + "Calculate the Acceleration Factor between the rate of degredation of a modeled environmnet versus a modeled controlled environmnet\n", + "\n", + "Example: \"If the *AF*=25 then 1 year of Controlled Environment exposure is equal to 25 years in the field\"\n", + "\n", + "Equation:\n", + "$$ AF = N · \\frac{ G_{chamber}^x · RH_{chamber}^n · e^{\\frac{- E_a}{k T_{chamber}}} }{ \\Sigma (G_{POA}^x · RH_{outdoor}^n · e^{\\frac{-E_a}{k T_outdoor}}) }$$\n", + "\n", + "Function to calculate *G$_{WA}$*, the Environment Characterization (W/m²). If the controlled environmnet lamp settings are set at *G$_{WA}$*, and the temperature set to *T$_{eq}$*, then the degradation will be the same as the yearly average outdoors.\n", + "\n", + "Equation:\n", + "$$ G_{WA} = [ \\frac{ \\Sigma (G_{outdoor}^x · RH_{outdoor}^n e^{\\frac{-E_a}{k T_{outdood}}}) }{ N · RH_{WA}^n · e^{- \\frac{E_a}{k T_eq}} } ]^{\\frac{1}{x}} $$" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# relative humidity within chamber (%)\n", + "rh_chamber = 15\n", + "# arrhenius activation energy (kj/mol)\n", + "Ea = 40\n", + "\n", + "rh_surface = pvdeg.humidity.surface_outside(rh_ambient=WEATHER['relative_humidity'],\n", + " temp_ambient=WEATHER['temp_air'],\n", + " temp_module=temp_module)\n", + "\n", + "arrhenius_deg = pvdeg.degradation.arrhenius_deg(weather_df=WEATHER, meta=META,\n", + " rh_outdoor=rh_surface,\n", + " I_chamber=I_chamber,\n", + " rh_chamber=rh_chamber,\n", + " temp_chamber=temp_chamber,\n", + " poa=poa_df,\n", + " temp=temp,\n", + " Ea=Ea)\n", + "\n", + "irr_weighted_avg_a = pvdeg.degradation.IwaArrhenius(weather_df=WEATHER, meta=META,\n", + " poa=poa_df, \n", + " rh_outdoor=WEATHER['relative_humidity'],\n", + " temp=temp,\n", + " Ea=Ea)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Quick Method (Degradation)\n", + "\n", + "For quick calculations, you can omit POA and both module and cell temperature. The function will calculate these figures as needed using the available weather data with the default options for PV module configuration." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# chamber settings\n", + "I_chamber= 1000\n", + "temp_chamber=60\n", + "rh_chamber=15\n", + "\n", + "# activation energy\n", + "Ea = 40\n", + "\n", + "vantHoff_deg = pvdeg.degradation.vantHoff_deg(weather_df=WEATHER, meta=META,\n", + " I_chamber=I_chamber,\n", + " temp_chamber=temp_chamber)\n", + "\n", + "irr_weighted_avg_v = pvdeg.degradation.IwaVantHoff(weather_df=WEATHER, meta=META)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "rh_surface = pvdeg.humidity.surface_outside(rh_ambient=WEATHER['relative_humidity'],\n", + " temp_ambient=WEATHER['temp_air'],\n", + " temp_module=temp_module)\n", + "\n", + "arrhenius_deg = pvdeg.degradation.arrhenius_deg(weather_df=WEATHER, meta=META,\n", + " rh_outdoor=rh_surface,\n", + " I_chamber=I_chamber,\n", + " rh_chamber=rh_chamber,\n", + " temp_chamber=temp_chamber,\n", + " Ea=Ea)\n", + "\n", + "irr_weighted_avg_a = pvdeg.degradation.IwaArrhenius(weather_df=WEATHER, meta=META, \n", + " rh_outdoor=WEATHER['relative_humidity'],\n", + " Ea=Ea)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. Solder Fatigue\n", + "\n", + "Estimate the thermomechanical fatigue of flat plate photovoltaic module solder joints over the time range given using estimated cell temperature. Like other `pvdeg` funcitons, the minimal parameters are (weather_df, meta). Running the function with only these two inputs will use default PV module configurations ( open_rack_glass_polymer ) and the 'sapm' temperature model over the entire length of the weather data. " + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "fatigue = pvdeg.fatigue.solder_fatigue(weather_df=WEATHER, meta=META)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "If you wish to reduce the span of time or use a non-default temperature model, you may specify the parameters manually. Let's try an explicit example.\n", + "We want the solder fatigue estimated over the month of June for a roof mounted glass-front polymer-back module.\n", + "\n", + "1. Lets create a datetime-index for the month of June.\n", + "2. Next, generate the cell temperature. Make sure to explicity restrict the weather data to our dt-index for June. Next, declare the PV module configuration.\n", + "3. Calculate the fatigue. Explicity specify the time_range (our dt-index for June from step 1) and the cell temperature as we caculated in step 2" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# select the month of June\n", + "time_range = WEATHER.index[WEATHER.index.month == 6]\n", + "\n", + "# calculate cell temperature over our selected date-time range.\n", + "# specify the module configuration\n", + "temp_cell = pvdeg.temperature.cell(weather_df=WEATHER.loc[time_range], meta=META,\n", + " temp_model='sapm',\n", + " conf='insulated_back_glass_polymer')\n", + "\n", + "\n", + "fatigue = pvdeg.fatigue.solder_fatigue(weather_df=WEATHER, meta=META,\n", + " time_range = time_range,\n", + " temp_cell = temp_cell)" + ] + } + ], + "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.9.16" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} From da40e80b2070f2db390c6636c4dd1b3b34993683 Mon Sep 17 00:00:00 2001 From: MDKempe <58960264+MDKempe@users.noreply.github.com> Date: Thu, 31 Aug 2023 17:22:00 -0600 Subject: [PATCH 3/8] remove glass/glass option definition For a glass/glass module the options for doing the computation are not correct. It was changed to have the glass/polymer option there as the default with full capability to use whatever you would like in the function call. --- pvdeg/standards.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/pvdeg/standards.py b/pvdeg/standards.py index 07a1344a..36002e79 100644 --- a/pvdeg/standards.py +++ b/pvdeg/standards.py @@ -19,14 +19,18 @@ def eff_gap(T_0, T_inf, level=1, T98=None, x_0=6.1): ''' - Calculate a minimum installation distance for rooftop mounded PV systems. + Calculate a minimum installation standoff distance for rooftop mounded PV systems for + a given levl according to IEC TS 63126 or the standoff to achieve a given 98ᵗʰ percentile + temperature. If the given T₉₈ is that for a specific system, then it is a calculation of + the effective gap of that system. The 98th percentile calculations for T_0 and T_inf are + also calculated. Parameters ---------- level : int, optional - Options 1, or 2. Specifies T98 temperature boundary for level 1 or level 2 according to IEC TS 63216. + Options 1, or 2. Specifies T₉₈ temperature boundary for level 1 or level 2 according to IEC TS 63216. T98 : float, optional - Instead of the level the T98 temperature can be specified directly (overwrites level). + Instead of the level the T₉₈ temperature can be specified directly (overwrites level). x0 : float, optional Thermal decay constant (cm), [Kempe, PVSC Proceedings 2023] @@ -64,6 +68,8 @@ def calc_standoff( sky_model='isotropic', temp_model='sapm', module_type='glass_polymer', # self.module + conf_0= 'insulated_back_glass_polymer', + conf_inf= 'open_rack_glass_polymer', level=1, x_0=6.1, wind_speed_factor=1): @@ -83,9 +89,13 @@ def calc_standoff( sky_model : str, optional Options: 'isotropic', 'klucher', 'haydavies', 'reindl', 'king', 'perez'. temp_model : str, optional - Options: 'sapm', 'pvsyst', 'faiman', 'sandia'. + Options: 'sapm'. 'pvsyst' and 'faiman' will be added later. module_type : str, optional Options: 'glass_polymer', 'glass_glass'. + conf_0 : str, optional + Default: 'insulated_back_glass_polymer' + conf_inf : str, optional + Default: 'open_rack_glass_polymer' level : int, optional Options 1, or 2. Temperature level 1 or level 2 according to IEC TS 63216. x0 : float, optional @@ -93,10 +103,11 @@ def calc_standoff( wind_speed_factor : float, optional Wind speed correction factor to account for different wind speed measurement heights between weather database (e.g. NSRDB) and the tempeature model (e.g. SAPM) + The NSRD uses calculations at 2m (i.e module height) Returns ------- x : float - Minimum installation distance in centimeter per IEC TS 63126. + Minimum installation distance in centimeter per IEC TS 63126 when the default settings are used. Effective gap "x" for the lower limit for Level 1 or Level 0 modules (IEC TS 63216) References @@ -104,12 +115,6 @@ def calc_standoff( M. Kempe, et al. Close Roof Mounted System Temperature Estimation for Compliance to IEC TS 63126, PVSC Proceedings 2023 ''' - if module_type == 'glass_polymer': - conf_0 = 'insulated_back_glass_polymer' - conf_inf = 'open_rack_glass_polymer' - elif module_type == 'glass_glass': - conf_0 = 'close_mount_glass_glass' - conf_inf = 'open_rack_glass_glass' solar_position = spectral.solar_position(weather_df, meta) poa = spectral.poa_irradiance(weather_df, meta, sol_position=solar_position, tilt=tilt, From 680a79d7d534c82aedd5394303cded3617071b18 Mon Sep 17 00:00:00 2001 From: MDKempe <58960264+MDKempe@users.noreply.github.com> Date: Wed, 13 Sep 2023 11:18:09 -0600 Subject: [PATCH 4/8] Update 5 - Weather Database Access.ipynb --- .../5 - Weather Database Access.ipynb | 45 ++++++++++++++----- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/pvdeg_tutorials/tutorials/5 - Weather Database Access.ipynb b/pvdeg_tutorials/tutorials/5 - Weather Database Access.ipynb index eb321a5b..a67f74e3 100644 --- a/pvdeg_tutorials/tutorials/5 - Weather Database Access.ipynb +++ b/pvdeg_tutorials/tutorials/5 - Weather Database Access.ipynb @@ -50,18 +50,20 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "# if running on google colab, uncomment the next line and execute this cell to install the dependencies and prevent \"ModuleNotFoundError\" in later cells:\n", - "# !pip install pvdeg==0.1.1" + " # !pip install pvdeg==0.1.1" ] }, { "cell_type": "code", "execution_count": 1, - "metadata": {}, + "metadata": { + "scrolled": true + }, "outputs": [], "source": [ "import pvdeg\n" @@ -84,20 +86,30 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 5, "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'x': 3.4904744924590694, 'T98_0': 82.57377792878141, 'T98_inf': 53.716463725092396}\n" + "ename": "FileNotFoundError", + "evalue": "Couldn't find NSRDB input files! \nSearched for: '/datasets/NSRDB/full_disc\\*_2021.h5'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mFileNotFoundError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[5], line 13\u001b[0m\n\u001b[0;32m 7\u001b[0m \u001b[38;5;66;03m#weather_id = 1933572\u001b[39;00m\n\u001b[0;32m 8\u001b[0m weather_arg \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msatellite\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mGOES\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[0;32m 9\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mnames\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;241m2021\u001b[39m,\n\u001b[0;32m 10\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mNREL_HPC\u001b[39m\u001b[38;5;124m'\u001b[39m: \u001b[38;5;28;01mTrue\u001b[39;00m,\n\u001b[0;32m 11\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mattributes\u001b[39m\u001b[38;5;124m'\u001b[39m: [\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mair_temperature\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mwind_speed\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdhi\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mghi\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mdni\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mrelative_humidity\u001b[39m\u001b[38;5;124m'\u001b[39m]}\n\u001b[1;32m---> 13\u001b[0m weather_df, meta \u001b[38;5;241m=\u001b[39m pvdeg\u001b[38;5;241m.\u001b[39mweather\u001b[38;5;241m.\u001b[39mget(weather_db, weather_id, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mweather_arg)\n", + "File \u001b[1;32mc:\\users\\mkempe\\documents\\github\\pvdegradationtools\\pvdeg\\weather.py:54\u001b[0m, in \u001b[0;36mget\u001b[1;34m(database, id, **kwargs)\u001b[0m\n\u001b[0;32m 50\u001b[0m \u001b[38;5;66;03m#TODO: decide wether to follow NSRDB or pvlib conventions...\u001b[39;00m\n\u001b[0;32m 51\u001b[0m \u001b[38;5;66;03m# e.g. temp_air vs. air_temperature\u001b[39;00m\n\u001b[0;32m 52\u001b[0m \u001b[38;5;66;03m# \"map variables\" will guarantee PVLIB conventions (automatic in coming update) which is \"temp_air\"\u001b[39;00m\n\u001b[0;32m 53\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m database \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mNSRDB\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[1;32m---> 54\u001b[0m weather_df, meta \u001b[38;5;241m=\u001b[39m get_NSRDB(gid\u001b[38;5;241m=\u001b[39mgid, location\u001b[38;5;241m=\u001b[39mlocation, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m 55\u001b[0m \u001b[38;5;28;01melif\u001b[39;00m database \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mPVGIS\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[0;32m 56\u001b[0m weather_df, _, meta, _ \u001b[38;5;241m=\u001b[39m iotools\u001b[38;5;241m.\u001b[39mget_pvgis_tmy(latitude\u001b[38;5;241m=\u001b[39mlat, longitude\u001b[38;5;241m=\u001b[39mlon,\n\u001b[0;32m 57\u001b[0m map_variables\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", + "File \u001b[1;32mc:\\users\\mkempe\\documents\\github\\pvdegradationtools\\pvdeg\\weather.py:244\u001b[0m, in \u001b[0;36mget_NSRDB\u001b[1;34m(satellite, names, NREL_HPC, gid, location, attributes, **_)\u001b[0m\n\u001b[0;32m 239\u001b[0m DSET_MAP \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mair_temperature\u001b[39m\u001b[38;5;124m'\u001b[39m : \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtemp_air\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[0;32m 240\u001b[0m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mRelative Humidity\u001b[39m\u001b[38;5;124m'\u001b[39m : \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mrelative_humidity\u001b[39m\u001b[38;5;124m'\u001b[39m}\n\u001b[0;32m 242\u001b[0m META_MAP \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m'\u001b[39m\u001b[38;5;124melevation\u001b[39m\u001b[38;5;124m'\u001b[39m : \u001b[38;5;124m'\u001b[39m\u001b[38;5;124maltitude\u001b[39m\u001b[38;5;124m'\u001b[39m}\n\u001b[1;32m--> 244\u001b[0m nsrdb_fnames, hsds \u001b[38;5;241m=\u001b[39m \u001b[43mget_NSRDB_fnames\u001b[49m\u001b[43m(\u001b[49m\u001b[43msatellite\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mnames\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mNREL_HPC\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 246\u001b[0m dattr \u001b[38;5;241m=\u001b[39m {}\n\u001b[0;32m 247\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m i, file \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28menumerate\u001b[39m(nsrdb_fnames):\n", + "File \u001b[1;32mc:\\users\\mkempe\\documents\\github\\pvdegradationtools\\pvdeg\\weather.py:203\u001b[0m, in \u001b[0;36mget_NSRDB_fnames\u001b[1;34m(satellite, names, NREL_HPC, **_)\u001b[0m\n\u001b[0;32m 200\u001b[0m nsrdb_fnames \u001b[38;5;241m=\u001b[39m glob\u001b[38;5;241m.\u001b[39mglob(nsrdb_fp)\n\u001b[0;32m 202\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(nsrdb_fnames) \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[1;32m--> 203\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mFileNotFoundError\u001b[39;00m(\n\u001b[0;32m 204\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCouldn\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mt find NSRDB input files! \u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[38;5;124mSearched for: \u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;241m.\u001b[39mformat(nsrdb_fp))\n\u001b[0;32m 206\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m nsrdb_fnames, hsds\n", + "\u001b[1;31mFileNotFoundError\u001b[0m: Couldn't find NSRDB input files! \nSearched for: '/datasets/NSRDB/full_disc\\*_2021.h5'" ] } ], "source": [ "# Get weather data\n", "weather_db = 'NSRDB'\n", + "\n", + "#Latitude and Longitude\n", + "weather_id = (33.448376, -112.074036)\n", "weather_id = (39.741931, -105.169891)\n", "#weather_id = 1933572\n", "weather_arg = {'satellite': 'GOES',\n", @@ -145,7 +157,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 9, "metadata": {}, "outputs": [ { @@ -153,7 +165,16 @@ "output_type": "stream", "text": [ "Column \"relative_humidity\" not found in DataFrame. Calculating...\n", - "{'x': 2.0063800910065974, 'T98_0': 77.85091991839371, 'T98_inf': 49.84149463751572}\n" + "{'Source': 'NSRDB', 'Location ID': '145809', 'City': '-', 'State': '-', 'Country': '-', 'Time Zone': -7, 'Local Time Zone': -7, 'Dew Point Units': 'c', 'DHI Units': 'w/m2', 'DNI Units': 'w/m2', 'GHI Units': 'w/m2', 'Temperature Units': 'c', 'Pressure Units': 'mbar', 'Wind Direction Units': 'Degrees', 'Wind Speed Units': 'm/s', 'Surface Albedo Units': 'N/A', 'Version': '3.2.0', 'latitude': 39.73, 'longitude': -105.18, 'altitude': 1820}\n", + "{'x': nan, 'T98_0': 77.85091991839371, 'T98_inf': 49.84149463751572}\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "c:\\users\\mkempe\\documents\\github\\pvdegradationtools\\pvdeg\\standards.py:54: RuntimeWarning: invalid value encountered in log\n", + " x = -x_0 * np.log(1-(T98_0-T98)/(T98_0-T98_inf))\n" ] } ], @@ -171,7 +192,7 @@ " 'map_variables': True}\n", "\n", "weather_df, meta = pvdeg.weather.get(weather_db, weather_id, **weather_arg)\n", - "\n", + "print (meta)\n", "# Perform calculation\n", "res = pvdeg.standards.calc_standoff(weather_df, meta, tilt=None, azimuth=180, sky_model='isotropic', temp_model='sapm',\n", " module_type='glass_polymer', level=1, x_0=6.1)\n", @@ -232,7 +253,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.13" + "version": "3.9.16" } }, "nbformat": 4, From 33ce6dcb1584dec10e45613d033a6413ce2eb3c5 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 13 Sep 2023 18:10:37 +0000 Subject: [PATCH 5/8] Update image tag --- binder/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binder/Dockerfile b/binder/Dockerfile index 250ce83f..e56c2764 100644 --- a/binder/Dockerfile +++ b/binder/Dockerfile @@ -1,2 +1,2 @@ ### DO NOT EDIT THIS FILE! This Is Automatically Generated And Will Be Overwritten ### -FROM silvanaayala136/pvdegradationtools:e5d0ad05e725 \ No newline at end of file +FROM silvanaayala136/pvdegradationtools:c256d109169e \ No newline at end of file From f0fa73f1a1f0aabbf57234518b3ee16c95a6eea7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 13 Sep 2023 19:02:51 +0000 Subject: [PATCH 6/8] Update image tag --- binder/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binder/Dockerfile b/binder/Dockerfile index e56c2764..030159e8 100644 --- a/binder/Dockerfile +++ b/binder/Dockerfile @@ -1,2 +1,2 @@ ### DO NOT EDIT THIS FILE! This Is Automatically Generated And Will Be Overwritten ### -FROM silvanaayala136/pvdegradationtools:c256d109169e \ No newline at end of file +FROM silvanaayala136/pvdegradationtools:ad0dae17a2d4 \ No newline at end of file From 110c1d4b5439e2c82ef85338094dded0256094f0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 13 Sep 2023 21:45:53 +0000 Subject: [PATCH 7/8] Update image tag --- binder/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binder/Dockerfile b/binder/Dockerfile index e56c2764..74ea8dc1 100644 --- a/binder/Dockerfile +++ b/binder/Dockerfile @@ -1,2 +1,2 @@ ### DO NOT EDIT THIS FILE! This Is Automatically Generated And Will Be Overwritten ### -FROM silvanaayala136/pvdegradationtools:c256d109169e \ No newline at end of file +FROM silvanaayala136/pvdegradationtools:33ce6dcb1584 \ No newline at end of file From 401dceb39369c4b5f582289c6560b19d5e664943 Mon Sep 17 00:00:00 2001 From: martin-springer Date: Thu, 14 Sep 2023 12:01:59 -0600 Subject: [PATCH 8/8] fix standards py --- .github/workflows/binder.yml | 46 +++++++++++++------------- pvdeg/standards.py | 62 +++++++++++++++++++++++------------- 2 files changed, 62 insertions(+), 46 deletions(-) diff --git a/.github/workflows/binder.yml b/.github/workflows/binder.yml index c66c28dd..5b30f47d 100644 --- a/.github/workflows/binder.yml +++ b/.github/workflows/binder.yml @@ -1,25 +1,25 @@ -name: Binder -on: - workflow_dispatch: - push: - branches: - - main +# name: Binder +# on: +# workflow_dispatch: +# push: +# branches: +# - main -# Push to dockerhub and cache on binder -jobs: - binder: - runs-on: ubuntu-latest - steps: - - name: Checkout Code - uses: actions/checkout@v3 - with: - ref: ${{ github.event.pull_request.head.sha }} +# # Push to dockerhub and cache on binder +# jobs: +# binder: +# runs-on: ubuntu-latest +# steps: +# - name: Checkout Code +# uses: actions/checkout@v3 +# with: +# ref: ${{ github.event.pull_request.head.sha }} - - name: update jupyter dependencies with repo2docker - uses: jupyterhub/repo2docker-action@master - with: - DOCKER_USERNAME: ${{ secrets.DOCKERHUB_NREL_USER }} - DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_NREL_TOKEN }} - BINDER_CACHE: true - PUBLIC_REGISTRY_CHECK: true - MYBINDERORG_TAG: ${{ github.event.ref }} # This builds the container on mybinder.org with the branch that was pushed on. \ No newline at end of file +# - name: update jupyter dependencies with repo2docker +# uses: jupyterhub/repo2docker-action@master +# with: +# DOCKER_USERNAME: ${{ secrets.DOCKERHUB_NREL_USER }} +# DOCKER_PASSWORD: ${{ secrets.DOCKERHUB_NREL_TOKEN }} +# BINDER_CACHE: true +# PUBLIC_REGISTRY_CHECK: true +# MYBINDERORG_TAG: ${{ github.event.ref }} # This builds the container on mybinder.org with the branch that was pushed on. \ No newline at end of file diff --git a/pvdeg/standards.py b/pvdeg/standards.py index 36002e79..0bb14084 100644 --- a/pvdeg/standards.py +++ b/pvdeg/standards.py @@ -19,10 +19,10 @@ def eff_gap(T_0, T_inf, level=1, T98=None, x_0=6.1): ''' - Calculate a minimum installation standoff distance for rooftop mounded PV systems for - a given levl according to IEC TS 63126 or the standoff to achieve a given 98ᵗʰ percentile - temperature. If the given T₉₈ is that for a specific system, then it is a calculation of - the effective gap of that system. The 98th percentile calculations for T_0 and T_inf are + Calculate a minimum installation standoff distance for rooftop mounded PV systems for + a given levl according to IEC TS 63126 or the standoff to achieve a given 98ᵗʰ percentile + temperature. If the given T₉₈ is that for a specific system, then it is a calculation of + the effective gap of that system. The 98th percentile calculations for T_0 and T_inf are also calculated. Parameters @@ -55,14 +55,18 @@ def eff_gap(T_0, T_inf, level=1, T98=None, x_0=6.1): T98_0 = T_0.quantile(q=0.98, interpolation='linear') T98_inf = T_inf.quantile(q=0.98, interpolation='linear') - x = -x_0 * np.log(1-(T98_0-T98)/(T98_0-T98_inf)) + try: + x = -x_0 * np.log(1-(T98_0-T98)/(T98_0-T98_inf)) + except RuntimeWarning as e: + x = np.nan return x, T98_0, T98_inf def calc_standoff( - weather_df, - meta, + weather_df=None, + meta=None, + weather_kwarg=None, tilt=None, azimuth=180, sky_model='isotropic', @@ -71,6 +75,7 @@ def calc_standoff( conf_0= 'insulated_back_glass_polymer', conf_inf= 'open_rack_glass_polymer', level=1, + T98=None, x_0=6.1, wind_speed_factor=1): ''' @@ -116,12 +121,23 @@ def calc_standoff( to IEC TS 63126, PVSC Proceedings 2023 ''' + if weather_df is None: + weather_df, meta = weather.get( + **weather_kwarg) + + if module_type == 'glass_polymer': + conf_0 = 'insulated_back_glass_polymer' + conf_inf = 'open_rack_glass_polymer' + elif module_type == 'glass_glass': + conf_0 = 'close_mount_glass_glass' + conf_inf = 'open_rack_glass_glass' + solar_position = spectral.solar_position(weather_df, meta) poa = spectral.poa_irradiance(weather_df, meta, sol_position=solar_position, tilt=tilt, azimuth=azimuth, sky_model=sky_model) T_0 = temperature.module(weather_df, meta, poa, temp_model, conf_0, wind_speed_factor) T_inf = temperature.module(weather_df, meta, poa, temp_model, conf_inf, wind_speed_factor) - x, T98_0, T98_inf = eff_gap(T_0, T_inf, level, x_0) + x, T98_0, T98_inf = eff_gap(T_0, T_inf, level=level, T98=T98, x_0=x_0) return {'x':x, 'T98_0':T98_0, 'T98_inf':T98_inf} @@ -140,6 +156,7 @@ def run_calc_standoff( temp_model='sapm', module_type='glass_polymer', level=1, + T98=None, x_0=6.1, wind_speed_factor=1 ): @@ -201,24 +218,23 @@ def run_calc_standoff( df_weather_kwargs.index = df_weather_kwargs.index.map( lambda arg: arg.lstrip('weather_')) weather_kwarg = weather_arg | df_weather_kwargs.to_dict() + weather_kwarg['database'] = database + weather_kwarg['id'] = gid - weather_df, meta = weather.load( - database = database, - id = gid, - #satellite = point.satellite, #TODO: check input - **weather_kwarg) future = executor.submit( calc_standoff, - weather_df, - meta, - tilt, - azimuth, - sky_model, - temp_model, - module_type, - level, - x_0, - wind_speed_factor + weather_df=None, + meta=None, + weather_kwarg=weather_kwarg, + tilt=tilt, + azimuth=azimuth, + sky_model=sky_model, + temp_model=temp_model, + module_type=module_type, + level=level, + T98=T98, + x_0=x_0, + wind_speed_factor=wind_speed_factor ) future_to_point[future] = gid