From 7139e29daf11b58cac70e748f4282e2ae05ba748 Mon Sep 17 00:00:00 2001 From: Tobin Ford Date: Wed, 11 Dec 2024 15:41:42 -0700 Subject: [PATCH 1/2] changed degradation.degradation signature, @njit --- pvdeg/degradation.py | 261 +++++++++++--- tests/test_degradation.py | 22 +- .../3 - Spectral Degradation.ipynb | 332 ++++++++++++++++-- 3 files changed, 532 insertions(+), 83 deletions(-) diff --git a/pvdeg/degradation.py b/pvdeg/degradation.py index 7c9b85c5..5845baee 100644 --- a/pvdeg/degradation.py +++ b/pvdeg/degradation.py @@ -13,7 +13,8 @@ from . import spectral from . import weather -from pvdeg.decorators import geospatial_quick_shape +from typing import Optional +from pvdeg.decorators import geospatial_quick_shape, deprecated # TODO: Clean up all those functions and add gaps functionality @@ -862,33 +863,70 @@ def _gJtoMJ(gJ): return MJ +# new version of degradation def degradation( - spectra: pd.Series, - rh_module: pd.Series, - temp_module: pd.Series, - wavelengths: Union[int, np.ndarray[float]], + spectra_df: pd.DataFrame, + conditions_df: pd.DataFrame = None, + temp_module: pd.Series = None, + rh_module: pd.Series = None, Ea: float = 40.0, n: float = 1.0, p: float = 0.5, C2: float = 0.07, C: float = 1.0, -) -> float: +)-> float: """ Compute degredation as double integral of Arrhenius (Activation Energy, RH, Temperature) and spectral (wavelength, irradiance) functions over wavelength and time. + .. math:: + + D = C \\int_{0}^{t} RH(t)^n \\cdot e^{\\frac{-E_a}{RT(t)}} \\int_{\\lambda} [e^{-C_2 \\lambda} \\cdot G(\\lambda, t)]^p d\\lambda dt + Parameters ---------- - spectra : pd.Series type=Float - front or rear irradiance at each wavelength in "wavelengths" [W/m^2 nm] - rh_module : pd.Series type=Float - module RH, time indexed [%] - temp_module : pd.Series type=Float - module temperature, time indexed [C] - wavelengths : int-array - integer array (or list) of wavelengths tested w/ uniform delta - in nanometers [nm] + spectra_df : pd.DataFrame + front or rear irradiance data in dataframe format + + - `data`: Spectral irradiance values for each wavelength [W/m^2 nm]. + - `index`: pd.DateTimeIndex + - `columns`: Wavelengths as floats (e.g., 280, 300, etc.). + + Example:: + + timestamp 280 300 320 340 360 380 400 + 2021-03-09 10:00:00 0.6892 0.4022 0.6726 0.0268 0.3398 0.9432 0.7411 + 2021-03-09 11:00:00 0.1558 0.5464 0.6896 0.7828 0.5050 0.9336 0.4652 + 2021-03-09 12:00:00 0.2278 0.9057 0.2639 0.0572 0.9906 0.9370 0.1800 + 2021-03-09 13:00:00 0.3742 0.0358 0.4052 0.9578 0.1044 0.8917 0.4876 + + conditions_df : pd.DataFrame, optional + Environmental conditions including temperature and relative humidity. + + - `index`: pd.DateTimeIndex + - `columns`: (required) + - "temperature" [°C or K] + - "relative_humidity" [%] + + Example:: + + timestamp temperature relative_humidity + 2021-03-09 10:00:00 298.0 45.0 + 2021-03-09 11:00:00 303.0 50.0 + 2021-03-09 12:00:00 310.0 55.0 + 2021-03-09 13:00:00 315.0 60.0 + + temp_module : pd.Series, optional + Module temperatures [°C]. Required if `conditions_df` is not provided. Time indexed same as spectra_df + + rh_module : pd.Series, optional + Relative humidity values [%]. Required if `conditions_df` is not provided. Time indexed same as spectra_df + + Example:: + + 30 = 30% + Ea : float Arrhenius activation energy. The default is 40. [kJ/mol] n : float @@ -907,58 +945,183 @@ def degradation( ------- degradation : float Total degredation factor over time and wavelength. - """ - # --- TO DO --- - # unpack input-dataframe - # spectra = df['spectra'] - # temp_module = df['temp_module'] - # rh_module = df['rh_module'] - # Constants - R = 0.0083145 # Gas Constant in [kJ/mol*K] - wav_bin = list(np.diff(wavelengths)) - wav_bin.append(wav_bin[-1]) # Adding a bin for the last wavelength + if conditions_df is not None and (temp_module is not None or rh_module is not None): + raise ValueError("Provide either conditions_df or temp_module and rh_module") - # Integral over Wavelength - try: - irr = pd.DataFrame(spectra.tolist(), index=spectra.index) - irr.columns = wavelengths - except: - # TODO: Fix this except it works on some cases, veto it by cases - print("Removing brackets from spectral irradiance data") - # irr = data['spectra'].str.strip('[]').str.split(',', expand=True).astype(float) - irr = spectra.str.strip("[]").str.split(",", expand=True).astype(float) - irr.columns = wavelengths + if conditions_df is not None: + rh = conditions_df["relative_humidity"].values + temps = conditions_df["temperature"].values + else: + rh = rh_module.values + temps = temp_module.values + + wavelengths = spectra_df.columns.values.astype(float) + irr = spectra_df.values # irradiance as array + + # call numba compiled function + return deg( + wavelengths=wavelengths, + irr=irr, + rh=rh, + temps=temps, + Ea=Ea, + C2=C2, + p=p, + n=n, + C=C + ) - sensitivitywavelengths = np.exp(-C2 * wavelengths) - irr = irr * sensitivitywavelengths - irr *= np.array(wav_bin) - irr = irr**p - data = pd.DataFrame(index=spectra.index) - data["G_integral"] = irr.sum(axis=1) +@njit +def deg( + wavelengths: np.ndarray, + irr: np.ndarray, + rh: np.ndarray, + temps: np.ndarray, + Ea: float, + C2: float, + p: float, + n: float, + C: float +) -> float: - EApR = -Ea / R - C4 = np.exp(EApR / temp_module) + R = 0.0083145 # Gas Constant in [kJ/mol*K] - RHn = rh_module**n - data["Arr_integrand"] = C4 * RHn + wav_bin = np.diff(wavelengths) + wav_bin = np.append(wav_bin, wav_bin[-1]) # Extend last bin + + # inner integral + # wavelength d lambda + irr_weighted = irr * np.exp(-C2 * wavelengths) # weight irradiances + irr_weighted *= wav_bin + irr_pow = irr_weighted ** p + wavelength_integral = np.sum(irr_pow, axis=1) # sum over wavelengths - data["dD"] = data["G_integral"] * data["Arr_integrand"] + # outer integral + # arrhenius integral dt + time_integrand = (rh ** n) * np.exp(-Ea / (R * temps)) - degradation = C * data["dD"].sum(axis=0) + dD = wavelength_integral * time_integrand + degradation = C * np.sum(dD) return degradation +# @deprecated("old double integral degradation function will be replaced 'pvdegradation' in an updated version of pvdeg") +# def degradation( +# spectra: pd.Series, +# rh_module: pd.Series, +# temp_module: pd.Series, +# wavelengths: Union[int, np.ndarray[float]], +# Ea: float = 40.0, +# n: float = 1.0, +# p: float = 0.5, +# C2: float = 0.07, +# C: float = 1.0, +# ) -> float: +# """ +# Compute degredation as double integral of Arrhenius (Activation +# Energy, RH, Temperature) and spectral (wavelength, irradiance) +# functions over wavelength and time. + +# .. math:: + +# D = C \\int_{0}^{t} RH(t)^n \\cdot e^{\\frac{-E_a}{RT(t)}} \\int_{\\lambda} [e^{-C_2 \\lambda} \\cdot G(\\lambda, t)]^p d\\lambda dt + +# Parameters +# ---------- +# spectra : pd.Series type=Float +# front or rear irradiance at each wavelength in "wavelengths" [W/m^2 nm] +# rh_module : pd.Series type=Float +# module RH, time indexed [%] +# temp_module : pd.Series type=Float +# module temperature, time indexed [C] +# wavelengths : int-array +# integer array (or list) of wavelengths tested w/ uniform delta +# in nanometers [nm] +# Ea : float +# Arrhenius activation energy. The default is 40. [kJ/mol] +# n : float +# Fit paramter for RH sensitivity. The default is 1. +# p : float +# Fit parameter for irradiance sensitivity. Typically +# 0.6 +- 0.22 +# C2 : float +# Fit parameter for sensitivity to wavelength exponential. +# Typically 0.07 +# C : float +# Fit parameter for the Degradation equaiton +# Typically 1.0 + +# Returns +# ------- +# degradation : float +# Total degredation factor over time and wavelength. +# """ +# # --- TO DO --- +# # unpack input-dataframe +# # spectra = df['spectra'] +# # temp_module = df['temp_module'] +# # rh_module = df['rh_module'] + +# # Constants +# R = 0.0083145 # Gas Constant in [kJ/mol*K] + +# wav_bin = list(np.diff(wavelengths)) +# wav_bin.append(wav_bin[-1]) # Adding a bin for the last wavelength + +# # Integral over Wavelength +# try: +# irr = pd.DataFrame(spectra.tolist(), index=spectra.index) +# irr.columns = wavelengths +# except: +# # TODO: Fix this except it works on some cases, veto it by cases +# print("Removing brackets from spectral irradiance data") +# # irr = data['spectra'].str.strip('[]').str.split(',', expand=True).astype(float) +# irr = spectra.str.strip("[]").str.split(",", expand=True).astype(float) +# irr.columns = wavelengths + + +# # double integral calculation +# sensitivitywavelengths = np.exp(-C2 * wavelengths) +# irr = irr * sensitivitywavelengths +# irr *= np.array(wav_bin) +# irr = irr**p +# data = pd.DataFrame(index=spectra.index) +# data["G_integral"] = irr.sum(axis=1) + +# EApR = -Ea / R +# C4 = np.exp(EApR / temp_module) + +# RHn = rh_module**n + +# data["Arr_integrand"] = C4 * RHn + +# print("arr integral", data["Arr_integrand"]) +# print("wavelength integral", data["G_integral"] ) + +# data["dD"] = data["G_integral"] * data["Arr_integrand"] + +# print(f"delta degradation ", data["dD"]) + +# degradation = C * data["dD"].sum(axis=0) + +# return degradation + + # change it to take pd.DataFrame? instead of np.ndarray @njit def vecArrhenius( poa_global: np.ndarray, module_temp: np.ndarray, ea: float, x: float, lnr0: float ) -> float: """ - Calculates degradation using :math:`R_D = R_0 * I^X * e^{\\frac{-Ea}{kT}}` + Calculate arrhenius degradation using vectorized operations. To eliminate the irradiance term set the irradiance sensitivity to 0. + + .. math:: + + R_D = R_0 \\cdot I^X \\cdot e^{\\frac{-E_a}{kT}} Parameters ---------- @@ -972,7 +1135,7 @@ def vecArrhenius( Activation energy [kJ/mol] x : float - Irradiance relation [unitless] + Irradiance sensitivity [unitless] lnR0 : float prefactor [ln(%/h)] diff --git a/tests/test_degradation.py b/tests/test_degradation.py index d9428e99..0454a01c 100644 --- a/tests/test_degradation.py +++ b/tests/test_degradation.py @@ -131,12 +131,26 @@ def test_degradation(): data = pd.read_csv(INPUT_SPECTRA) wavelengths = np.array(range(280, 420, 20)) + + # convert to expected format + spectra = data["Spectra"] + spectra_df = pd.DataFrame(spectra.tolist(), index=spectra.index) + spectra_df = spectra.str.strip("[]").str.split(",", expand=True).astype(float) + spectra_df.columns = wavelengths + + conditions_df = pd.DataFrame( + index=spectra_df.index, + data={ + "relative_humidity": data["RH"], + "temperature": data["Temperature"], + } + ) + degradation = pvdeg.degradation.degradation( - spectra=data["Spectra"], - rh_module=data["RH"], - temp_module=data["Temperature"], - wavelengths=wavelengths, + spectra_df=spectra_df, + conditions_df=conditions_df ) + assert degradation == pytest.approx(4.4969e-38, abs=0.02e-38) diff --git a/tutorials_and_tools/tutorials_and_tools/3 - Spectral Degradation.ipynb b/tutorials_and_tools/tutorials_and_tools/3 - Spectral Degradation.ipynb index 91c048f0..dce03564 100644 --- a/tutorials_and_tools/tutorials_and_tools/3 - Spectral Degradation.ipynb +++ b/tutorials_and_tools/tutorials_and_tools/3 - Spectral Degradation.ipynb @@ -32,22 +32,7 @@ "cell_type": "code", "execution_count": 2, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Users\\mspringe\\AppData\\Local\\Temp\\1\\ipykernel_40480\\1750438778.py:2: DeprecationWarning: \n", - "Pyarrow will become a required dependency of pandas in the next major release of pandas (pandas 3.0),\n", - "(to allow more performant data types, such as the Arrow string type, and better interoperability with other libraries)\n", - "but was not found to be installed on your system.\n", - "If this would cause problems for you,\n", - "please provide us feedback at https://github.com/pandas-dev/pandas/issues/54466\n", - " \n", - " import pandas as pd\n" - ] - } - ], + "outputs": [], "source": [ "import os\n", "import pandas as pd\n", @@ -66,9 +51,9 @@ "output_type": "stream", "text": [ "Working on a Windows 10\n", - "Python version 3.11.7 | packaged by Anaconda, Inc. | (main, Dec 15 2023, 18:05:47) [MSC v.1916 64 bit (AMD64)]\n", - "Pandas version 2.2.0\n", - "pvdeg version 0.2.4.dev83+ge2ceab9.d20240422\n" + "Python version 3.9.19 (main, May 6 2024, 20:12:36) [MSC v.1916 64 bit (AMD64)]\n", + "Pandas version 2.2.3\n", + "pvdeg version 0.4.3.dev22+g0ef212c.d20241017\n" ] } ], @@ -101,7 +86,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -201,6 +186,218 @@ "SPECTRA.head()" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "**Convert To Expected Format**\n", + "\n", + "Since the original version of this tutorial, the expected inputs for the spectral degradation function have changed, we must convert the previously loaded inputs to the expected form. \n", + "\n", + "We will created the desired spectra dataframe and conditions dataframe in the following cell." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "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", + " \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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
280300320340360380400
timestamp
2021-03-09 10:00:000.6892150.4021560.6725890.0267550.3397720.9432470.741140
2021-03-09 11:00:000.1557570.5464370.6895800.7827660.5049820.9335720.465200
2021-03-09 12:00:000.2278210.9056500.2638720.0572300.9905800.9369940.180034
2021-03-09 13:00:000.3741940.0358310.4052370.9578220.1043990.8916960.487553
2021-03-09 14:00:000.4032120.6473170.6981120.0633600.8680300.6869390.416581
2021-03-09 15:00:000.7461340.8382590.8390970.1348490.5484540.6060190.101388
2021-03-09 16:00:000.4629110.0323000.5794190.3702470.5205980.5665950.672994
2021-03-09 17:00:000.1735030.8139710.8662740.3441680.6677450.6899450.143764
2021-03-09 18:00:000.3699190.8874100.0823970.0853350.6335600.1955460.374416
2021-03-09 19:00:000.1497640.7994750.6171050.1562690.3227450.7293110.606430
\n", + "
" + ], + "text/plain": [ + " 280 300 320 340 360 \\\n", + "timestamp \n", + "2021-03-09 10:00:00 0.689215 0.402156 0.672589 0.026755 0.339772 \n", + "2021-03-09 11:00:00 0.155757 0.546437 0.689580 0.782766 0.504982 \n", + "2021-03-09 12:00:00 0.227821 0.905650 0.263872 0.057230 0.990580 \n", + "2021-03-09 13:00:00 0.374194 0.035831 0.405237 0.957822 0.104399 \n", + "2021-03-09 14:00:00 0.403212 0.647317 0.698112 0.063360 0.868030 \n", + "2021-03-09 15:00:00 0.746134 0.838259 0.839097 0.134849 0.548454 \n", + "2021-03-09 16:00:00 0.462911 0.032300 0.579419 0.370247 0.520598 \n", + "2021-03-09 17:00:00 0.173503 0.813971 0.866274 0.344168 0.667745 \n", + "2021-03-09 18:00:00 0.369919 0.887410 0.082397 0.085335 0.633560 \n", + "2021-03-09 19:00:00 0.149764 0.799475 0.617105 0.156269 0.322745 \n", + "\n", + " 380 400 \n", + "timestamp \n", + "2021-03-09 10:00:00 0.943247 0.741140 \n", + "2021-03-09 11:00:00 0.933572 0.465200 \n", + "2021-03-09 12:00:00 0.936994 0.180034 \n", + "2021-03-09 13:00:00 0.891696 0.487553 \n", + "2021-03-09 14:00:00 0.686939 0.416581 \n", + "2021-03-09 15:00:00 0.606019 0.101388 \n", + "2021-03-09 16:00:00 0.566595 0.672994 \n", + "2021-03-09 17:00:00 0.689945 0.143764 \n", + "2021-03-09 18:00:00 0.195546 0.374416 \n", + "2021-03-09 19:00:00 0.729311 0.606430 " + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# convert to expected format\n", + "spectra = SPECTRA[\"Spectra\"]\n", + "spectra_df = pd.DataFrame(spectra.tolist(), index=spectra.index)\n", + "spectra_df = spectra.str.strip(\"[]\").str.split(\",\", expand=True).astype(float)\n", + "spectra_df.columns = wavelengths\n", + "\n", + "conditions_df = pd.DataFrame(\n", + " index=spectra_df.index,\n", + " data={\n", + " \"relative_humidity\": SPECTRA[\"RH\"],\n", + " \"temperature\": SPECTRA[\"Temperature\"],\n", + " }\n", + ")\n", + "\n", + "spectra_df" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -212,28 +409,108 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "4.496994351804118e-38" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "degradation = pvdeg.degradation.degradation(\n", + " spectra_df=spectra_df,\n", + " conditions_df=conditions_df\n", + ")\n", + "degradation" + ] + }, + { + "cell_type": "code", + "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Removing brackets from spectral irradiance data\n" + "Removing brackets from spectral irradiance data\n", + "arr integral timestamp\n", + "2021-03-09 10:00:00 2.193695e-45\n", + "2021-03-09 11:00:00 1.833548e-46\n", + "2021-03-09 12:00:00 1.508690e-34\n", + "2021-03-09 13:00:00 4.256451e-47\n", + "2021-03-09 14:00:00 1.041473e-82\n", + "2021-03-09 15:00:00 5.746285e-189\n", + "2021-03-09 16:00:00 2.430948e-62\n", + "2021-03-09 17:00:00 1.440645e-46\n", + "2021-03-09 18:00:00 2.196529e-64\n", + "2021-03-09 19:00:00 1.433768e-103\n", + "Name: Arr_integrand, dtype: float64\n", + "wavelength integral timestamp\n", + "2021-03-09 10:00:00 0.000358\n", + "2021-03-09 11:00:00 0.000287\n", + "2021-03-09 12:00:00 0.000298\n", + "2021-03-09 13:00:00 0.000258\n", + "2021-03-09 14:00:00 0.000338\n", + "2021-03-09 15:00:00 0.000412\n", + "2021-03-09 16:00:00 0.000275\n", + "2021-03-09 17:00:00 0.000309\n", + "2021-03-09 18:00:00 0.000311\n", + "2021-03-09 19:00:00 0.000284\n", + "Name: G_integral, dtype: float64\n", + "delta degradation timestamp\n", + "2021-03-09 10:00:00 7.861213e-49\n", + "2021-03-09 11:00:00 5.263019e-50\n", + "2021-03-09 12:00:00 4.496994e-38\n", + "2021-03-09 13:00:00 1.099005e-50\n", + "2021-03-09 14:00:00 3.519596e-86\n", + "2021-03-09 15:00:00 2.369241e-192\n", + "2021-03-09 16:00:00 6.696099e-66\n", + "2021-03-09 17:00:00 4.452817e-50\n", + "2021-03-09 18:00:00 6.827920e-68\n", + "2021-03-09 19:00:00 4.071628e-107\n", + "Name: dD, dtype: float64\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\tford\\AppData\\Local\\Temp\\2\\ipykernel_26040\\2414568496.py:1: DeprecationWarning: Call to deprecated function degradation (old double integral degradation function will be replaced 'pvdegradation' in an updated version of pvdeg).\n", + " degradation = pvdeg.degradation.degradation(spectra=SPECTRA['Spectra'],\n" ] + }, + { + "data": { + "text/plain": [ + "4.496994351804118e-38" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ "degradation = pvdeg.degradation.degradation(spectra=SPECTRA['Spectra'],\n", " rh_module=SPECTRA['RH'],\n", " temp_module=SPECTRA['Temperature'],\n", - " wavelengths=wavelengths)" + " wavelengths=wavelengths)\n", + "\n", + "degradation " ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "deg", "language": "python", "name": "python3" }, @@ -247,12 +524,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.7" - }, - "vscode": { - "interpreter": { - "hash": "14c04630f1cd445b2532d35c77825134bfcafda47af70d0b9c2b5023b1f357a5" - } + "version": "3.9.19" } }, "nbformat": 4, From 0ee3550931fc3449701340b28a753cb60b13bcbb Mon Sep 17 00:00:00 2001 From: Tobin Ford Date: Wed, 11 Dec 2024 15:53:22 -0700 Subject: [PATCH 2/2] docs --- .../_autosummary/pvdeg.degradation.deg.rst | 6 + .../source/_autosummary/pvdeg.degradation.rst | 8 ++ .../pvdeg.diffusion.esdiffusion.rst | 6 + .../pvdeg.geospatial.can_auto_template.rst | 6 + docs/source/_autosummary/pvdeg.geospatial.rst | 8 ++ ...spectral.calc_full_from_irradiance_340.rst | 6 + ...temperature.fdm_temperature_irradiance.rst | 6 + docs/source/whatsnew/index.rst | 1 + docs/source/whatsnew/releases/v0.4.5.rst | 45 ++++++++ pvdeg/degradation.py | 104 +----------------- 10 files changed, 93 insertions(+), 103 deletions(-) create mode 100644 docs/source/_autosummary/pvdeg.degradation.deg.rst create mode 100644 docs/source/_autosummary/pvdeg.diffusion.esdiffusion.rst create mode 100644 docs/source/_autosummary/pvdeg.geospatial.can_auto_template.rst create mode 100644 docs/source/_autosummary/pvdeg.spectral.calc_full_from_irradiance_340.rst create mode 100644 docs/source/_autosummary/pvdeg.temperature.fdm_temperature_irradiance.rst create mode 100644 docs/source/whatsnew/releases/v0.4.5.rst diff --git a/docs/source/_autosummary/pvdeg.degradation.deg.rst b/docs/source/_autosummary/pvdeg.degradation.deg.rst new file mode 100644 index 00000000..406abe21 --- /dev/null +++ b/docs/source/_autosummary/pvdeg.degradation.deg.rst @@ -0,0 +1,6 @@ +pvdeg.degradation.deg +===================== + +.. currentmodule:: pvdeg.degradation + +.. autofunction:: deg \ No newline at end of file diff --git a/docs/source/_autosummary/pvdeg.degradation.rst b/docs/source/_autosummary/pvdeg.degradation.rst index 9e2e6ca6..26847b1f 100644 --- a/docs/source/_autosummary/pvdeg.degradation.rst +++ b/docs/source/_autosummary/pvdeg.degradation.rst @@ -22,6 +22,7 @@ pvdeg.degradation pvdeg.degradation.IwaArrhenius pvdeg.degradation.IwaVantHoff pvdeg.degradation.arrhenius_deg + pvdeg.degradation.deg pvdeg.degradation.degradation pvdeg.degradation.vantHoff_deg pvdeg.degradation.vecArrhenius @@ -61,6 +62,13 @@ pvdeg.degradation .. minigallery:: pvdeg.degradation.arrhenius_deg :add-heading: + .. autofunction:: deg + + .. _sphx_glr_backref_pvdeg.degradation.deg: + + .. minigallery:: pvdeg.degradation.deg + :add-heading: + .. autofunction:: degradation .. _sphx_glr_backref_pvdeg.degradation.degradation: diff --git a/docs/source/_autosummary/pvdeg.diffusion.esdiffusion.rst b/docs/source/_autosummary/pvdeg.diffusion.esdiffusion.rst new file mode 100644 index 00000000..3a3b7bce --- /dev/null +++ b/docs/source/_autosummary/pvdeg.diffusion.esdiffusion.rst @@ -0,0 +1,6 @@ +pvdeg.diffusion.esdiffusion +=========================== + +.. currentmodule:: pvdeg.diffusion + +.. autofunction:: esdiffusion \ No newline at end of file diff --git a/docs/source/_autosummary/pvdeg.geospatial.can_auto_template.rst b/docs/source/_autosummary/pvdeg.geospatial.can_auto_template.rst new file mode 100644 index 00000000..dfce6002 --- /dev/null +++ b/docs/source/_autosummary/pvdeg.geospatial.can_auto_template.rst @@ -0,0 +1,6 @@ +pvdeg.geospatial.can\_auto\_template +==================================== + +.. currentmodule:: pvdeg.geospatial + +.. autofunction:: can_auto_template \ No newline at end of file diff --git a/docs/source/_autosummary/pvdeg.geospatial.rst b/docs/source/_autosummary/pvdeg.geospatial.rst index 159523fc..7c5970fc 100644 --- a/docs/source/_autosummary/pvdeg.geospatial.rst +++ b/docs/source/_autosummary/pvdeg.geospatial.rst @@ -24,6 +24,7 @@ pvdeg.geospatial pvdeg.geospatial.auto_template pvdeg.geospatial.calc_block pvdeg.geospatial.calc_gid + pvdeg.geospatial.can_auto_template pvdeg.geospatial.elevation_stochastic_downselect pvdeg.geospatial.feature_downselect pvdeg.geospatial.identify_mountains_radii @@ -88,6 +89,13 @@ pvdeg.geospatial .. minigallery:: pvdeg.geospatial.calc_gid :add-heading: + .. autofunction:: can_auto_template + + .. _sphx_glr_backref_pvdeg.geospatial.can_auto_template: + + .. minigallery:: pvdeg.geospatial.can_auto_template + :add-heading: + .. autofunction:: elevation_stochastic_downselect .. _sphx_glr_backref_pvdeg.geospatial.elevation_stochastic_downselect: diff --git a/docs/source/_autosummary/pvdeg.spectral.calc_full_from_irradiance_340.rst b/docs/source/_autosummary/pvdeg.spectral.calc_full_from_irradiance_340.rst new file mode 100644 index 00000000..bd06f360 --- /dev/null +++ b/docs/source/_autosummary/pvdeg.spectral.calc_full_from_irradiance_340.rst @@ -0,0 +1,6 @@ +pvdeg.spectral.calc\_full\_from\_irradiance\_340 +================================================ + +.. currentmodule:: pvdeg.spectral + +.. autofunction:: calc_full_from_irradiance_340 \ No newline at end of file diff --git a/docs/source/_autosummary/pvdeg.temperature.fdm_temperature_irradiance.rst b/docs/source/_autosummary/pvdeg.temperature.fdm_temperature_irradiance.rst new file mode 100644 index 00000000..e4157f4c --- /dev/null +++ b/docs/source/_autosummary/pvdeg.temperature.fdm_temperature_irradiance.rst @@ -0,0 +1,6 @@ +pvdeg.temperature.fdm\_temperature\_irradiance +============================================== + +.. currentmodule:: pvdeg.temperature + +.. autofunction:: fdm_temperature_irradiance \ No newline at end of file diff --git a/docs/source/whatsnew/index.rst b/docs/source/whatsnew/index.rst index d5b2f041..84ec153a 100644 --- a/docs/source/whatsnew/index.rst +++ b/docs/source/whatsnew/index.rst @@ -4,6 +4,7 @@ What's New ========== PVDegradationTools (pvdeg) change log: +.. include:: releases/v0.4.5.rst .. include:: releases/v0.4.4.rst .. include:: releases/v0.4.3.rst .. include:: releases/v0.4.2.rst diff --git a/docs/source/whatsnew/releases/v0.4.5.rst b/docs/source/whatsnew/releases/v0.4.5.rst new file mode 100644 index 00000000..43f32d47 --- /dev/null +++ b/docs/source/whatsnew/releases/v0.4.5.rst @@ -0,0 +1,45 @@ + +v0.4.5 (2024-12-11) +=================== + +Breaking Change +------------ +* Changed function signature of ``pvdeg.degradation.degradation``. + - New function takes ``spectra_df`` instead of ``spectra`` and ``wavelengths`` disparate arguments. + Also takes ``conditions_df`` instead of disparate ``rh_module`` and ``temp_module`` pandas series. + + spectra_df : pd.DataFrame + front or rear irradiance data in dataframe format + + - `data`: Spectral irradiance values for each wavelength [W/m^2/nm]. + - `index`: pd.DateTimeIndex + - `columns`: Wavelengths as floats (e.g., 280, 300, etc.) [nm]. + + Example:: + + timestamp 280 300 320 340 360 380 400 + 2021-03-09 10:00:00 0.6892 0.4022 0.6726 0.0268 0.3398 0.9432 0.7411 + 2021-03-09 11:00:00 0.1558 0.5464 0.6896 0.7828 0.5050 0.9336 0.4652 + 2021-03-09 12:00:00 0.2278 0.9057 0.2639 0.0572 0.9906 0.9370 0.1800 + 2021-03-09 13:00:00 0.3742 0.0358 0.4052 0.9578 0.1044 0.8917 0.4876 + + conditions_df : pd.DataFrame, optional + Environmental conditions including temperature and relative humidity. + + - `index`: pd.DateTimeIndex + - `columns`: (required) + - "temperature" [°C or K] + - "relative_humidity" [%] + + Example:: + + timestamp temperature relative_humidity + 2021-03-09 10:00:00 298.0 45.0 + 2021-03-09 11:00:00 303.0 50.0 + 2021-03-09 12:00:00 310.0 55.0 + 2021-03-09 13:00:00 315.0 60.0 + + +Contributors +----------- +* Tobin Ford (:ghuser:`tobin-ford`) \ No newline at end of file diff --git a/pvdeg/degradation.py b/pvdeg/degradation.py index 5845baee..d89f5c09 100644 --- a/pvdeg/degradation.py +++ b/pvdeg/degradation.py @@ -891,7 +891,7 @@ def degradation( - `data`: Spectral irradiance values for each wavelength [W/m^2 nm]. - `index`: pd.DateTimeIndex - - `columns`: Wavelengths as floats (e.g., 280, 300, etc.). + - `columns`: Wavelengths as floats (e.g., 280, 300, etc.) [nm]. Example:: @@ -1009,108 +1009,6 @@ def deg( return degradation -# @deprecated("old double integral degradation function will be replaced 'pvdegradation' in an updated version of pvdeg") -# def degradation( -# spectra: pd.Series, -# rh_module: pd.Series, -# temp_module: pd.Series, -# wavelengths: Union[int, np.ndarray[float]], -# Ea: float = 40.0, -# n: float = 1.0, -# p: float = 0.5, -# C2: float = 0.07, -# C: float = 1.0, -# ) -> float: -# """ -# Compute degredation as double integral of Arrhenius (Activation -# Energy, RH, Temperature) and spectral (wavelength, irradiance) -# functions over wavelength and time. - -# .. math:: - -# D = C \\int_{0}^{t} RH(t)^n \\cdot e^{\\frac{-E_a}{RT(t)}} \\int_{\\lambda} [e^{-C_2 \\lambda} \\cdot G(\\lambda, t)]^p d\\lambda dt - -# Parameters -# ---------- -# spectra : pd.Series type=Float -# front or rear irradiance at each wavelength in "wavelengths" [W/m^2 nm] -# rh_module : pd.Series type=Float -# module RH, time indexed [%] -# temp_module : pd.Series type=Float -# module temperature, time indexed [C] -# wavelengths : int-array -# integer array (or list) of wavelengths tested w/ uniform delta -# in nanometers [nm] -# Ea : float -# Arrhenius activation energy. The default is 40. [kJ/mol] -# n : float -# Fit paramter for RH sensitivity. The default is 1. -# p : float -# Fit parameter for irradiance sensitivity. Typically -# 0.6 +- 0.22 -# C2 : float -# Fit parameter for sensitivity to wavelength exponential. -# Typically 0.07 -# C : float -# Fit parameter for the Degradation equaiton -# Typically 1.0 - -# Returns -# ------- -# degradation : float -# Total degredation factor over time and wavelength. -# """ -# # --- TO DO --- -# # unpack input-dataframe -# # spectra = df['spectra'] -# # temp_module = df['temp_module'] -# # rh_module = df['rh_module'] - -# # Constants -# R = 0.0083145 # Gas Constant in [kJ/mol*K] - -# wav_bin = list(np.diff(wavelengths)) -# wav_bin.append(wav_bin[-1]) # Adding a bin for the last wavelength - -# # Integral over Wavelength -# try: -# irr = pd.DataFrame(spectra.tolist(), index=spectra.index) -# irr.columns = wavelengths -# except: -# # TODO: Fix this except it works on some cases, veto it by cases -# print("Removing brackets from spectral irradiance data") -# # irr = data['spectra'].str.strip('[]').str.split(',', expand=True).astype(float) -# irr = spectra.str.strip("[]").str.split(",", expand=True).astype(float) -# irr.columns = wavelengths - - -# # double integral calculation -# sensitivitywavelengths = np.exp(-C2 * wavelengths) -# irr = irr * sensitivitywavelengths -# irr *= np.array(wav_bin) -# irr = irr**p -# data = pd.DataFrame(index=spectra.index) -# data["G_integral"] = irr.sum(axis=1) - -# EApR = -Ea / R -# C4 = np.exp(EApR / temp_module) - -# RHn = rh_module**n - -# data["Arr_integrand"] = C4 * RHn - -# print("arr integral", data["Arr_integrand"]) -# print("wavelength integral", data["G_integral"] ) - -# data["dD"] = data["G_integral"] * data["Arr_integrand"] - -# print(f"delta degradation ", data["dD"]) - -# degradation = C * data["dD"].sum(axis=0) - -# return degradation - - # change it to take pd.DataFrame? instead of np.ndarray @njit def vecArrhenius(