From 827bd61fe120137876b98076cf3cefe6e549dcfd Mon Sep 17 00:00:00 2001 From: Trond Kristiansen Date: Wed, 10 Feb 2021 12:22:38 -0800 Subject: [PATCH 01/13] Added function for calculating cloud opacity factor and an example for how to use --- docs/examples/plot_spectrl2_overcast.py | 233 ++++++++++++++++++++++++ docs/tutorials/irradiance.ipynb | 2 +- 2 files changed, 234 insertions(+), 1 deletion(-) create mode 100644 docs/examples/plot_spectrl2_overcast.py diff --git a/docs/examples/plot_spectrl2_overcast.py b/docs/examples/plot_spectrl2_overcast.py new file mode 100644 index 0000000000..9577977059 --- /dev/null +++ b/docs/examples/plot_spectrl2_overcast.py @@ -0,0 +1,233 @@ +""" +Modeling Spectral Irradiance in overcast conditions +==================================================== + +Example for implementing and using the "cloud opacity factor" for +calculating spectral irradiance in overcast conditions +""" + +# %% +# This example shows how to model the spectral distribution of irradiance +# based on atmospheric conditions and to correct the distribution according to cloud cover. +# The spectral distribution of irradiance is calculated using the clear sky spectrl2 function +# and modified using the "cloud opacity factor" [1]. +# the power content at each wavelength band in the solar spectrum and is +# affected by various scattering and absorption mechanisms in the atmosphere. +# +# +# References +# ---------- +# [1] Marco Ernst, Hendrik Holst, Matthias Winter, Pietro P. Altermatt, +# SunCalculator: A program to calculate the angular and spectral distribution of +# direct and diffuse solar radiation, +# Solar Energy Materials and Solar Cells, Volume 157, 2016, Pages 913-922. + +# %% +# Trond Kristiansen, https://github.com/trondkr + +import numpy as np +import pandas as pd +import pvlib +import datetime +import matplotlib.pyplot as plt + + +# %% +def setup_pv_system(month, hour_of_day): + """ + This method is just basic setup + """ + offset = 0 + when = [datetime.datetime(2020, month, 15, hour_of_day, 0, 0, + tzinfo=datetime.timezone(datetime.timedelta(hours=offset)))] + time = pd.DatetimeIndex(when) + + sandia_modules = pvlib.pvsystem.retrieve_sam('SandiaMod') + sapm_inverters = pvlib.pvsystem.retrieve_sam('cecinverter') + + module = sandia_modules['Canadian_Solar_CS5P_220M___2009_'] + inverter = sapm_inverters['ABB__MICRO_0_25_I_OUTD_US_208__208V_'] + pv_system = {'module': module, 'inverter': inverter, + 'surface_azimuth': 180} + + return time, pv_system + + +# %% +def plot_spectral_irradiance(spectra, F_dir, F_diff, latitude, day_of_year, year, clouds): + """ + Plot the results showing the spectral distribution of irradiance with and + without the effects of clouds + """ + fig, ax = plt.subplots() + ax.plot(spectra['wavelength'], spectra["poa_sky_diffuse"][:, 0], c="r") + ax.plot(spectra['wavelength'], spectra["poa_direct"][:, 0], c="g") + ax.plot(spectra['wavelength'], spectra["poa_global"][:, 0], c="m") + + ax.plot(spectra['wavelength'], F_dir[:, 0], c="r", linestyle='dashed') + ax.plot(spectra['wavelength'], F_diff[:, 0], c="y", linestyle='dashed') + + plt.xlim(200, 2700) + plt.ylim(0, 1.8) + plt.title(r"Day {} {} latitude {} cloud cover {}".format(day_of_year, year, latitude, clouds)) + plt.ylabel(r"Irradiance ($W m^{-2} nm^{-1}$)") + plt.xlabel(r"Wavelength ($nm$)") + labels = ["poa_sky_diffuse", "poa_direct", "poa_global", "poa_sky_diffuse clouds", "poa_direct clouds"] + + ax.legend(labels) + plt.show() + + +def show_info(latitude, irradiance): + """ + Simple function to show the integrated results of the spectral distributions + """ + print("Latitude {}".format(latitude)) + print("{}: campbell_norman clouds: dni: {:3.2f} dhi: {:3.2f} ghi: {:3.2f}".format(latitude, + float(irradiance['poa_direct']), + float(irradiance['poa_diffuse']), + float(irradiance['poa_global']))) + + +def cloud_opacity_factor(I_diff_clouds, I_dir_clouds, I_ghi_clouds, spectra): + # Calculate the effect of "cloud opacity factor" on the spectral distributions under clear sky. + # + # First we calculate the rho fraction based on campbell_norman irradiance + # with clouds converted to POA irradiance. In the paper these + # values are obtained from observations. The equations used for calculating cloud opacity factor + # to scale the clear sky spectral estimates using spectrl2. Results can be compared with sun calculator: + # https://www2.pvlighthouse.com.au/calculators/solar%20spectrum%20calculator/solar%20spectrum%20calculator.aspx + # + # Ref: Marco Ernst, Hendrik Holst, Matthias Winter, Pietro P. Altermatt, + # SunCalculator: A program to calculate the angular and spectral distribution of direct and diffuse solar radiation, + # Solar Energy Materials and Solar Cells, Volume 157, 2016, Pages 913-922, + + rho = I_diff_clouds / I_ghi_clouds + + I_diff_s = np.trapz(y=spectra['poa_sky_diffuse'][:, 0], x=spectra['wavelength']) + I_dir_s = np.trapz(y=spectra['poa_direct'][:, 0], x=spectra['wavelength']) + I_glob_s = np.trapz(y=spectra['poa_global'][:, 0], x=spectra['wavelength']) + + rho_spectra = I_diff_s / I_glob_s + + N_rho = (rho - rho_spectra) / (1 - rho_spectra) + + # Direct light. Equation 6 Ernst et al. 2016 + F_diff_s = spectra['poa_sky_diffuse'][:, :] + F_dir_s = spectra['poa_direct'][:, :] + + F_dir = (F_dir_s / I_dir_s) * I_dir_clouds + + # Diffuse light scaling factor. Equation 7 Ernst et al. 2016 + s_diff = (1 - N_rho) * (F_diff_s / I_diff_s) + N_rho * ((F_dir_s + F_diff_s) / I_glob_s) + + # Equation 8 Ernst et al. 2016 + F_diff = s_diff * I_diff_clouds + + return F_dir, F_diff + +def calculate_overcast_spectrl2(): + + """ + This example will loop over a range of cloud covers and latitudes (at longitude=0) for a + specific date and calculate the spectral irradiance with and without accounting for clouds. + Clouds are accounted for by applying the cloud opacity factor defined in [1]. Several steps are required: + 1. Calculate the atmospheric and solar conditions for the location and time + 2. Calculate the spectral irradiance using pvlib.spectrum.spectrl2 for clear sky conditions + 3. Calculate the dni, dhi, and ghi for cloudy conditions using pvlib.irradiance.campbell_norman + 4. Determine total in-plane irradiance and its beam, sky diffuse and ground + reflected components for cloudy conditions - pvlib.irradiance.get_total_irradiance + 5. Calculate the dni, dhi, and ghi for clear sky conditions using pvlib.irradiance.campbell_norman + 6. Determine total in-plane irradiance and its beam, sky diffuse and ground + reflected components for clear sky conditions - pvlib.irradiance.get_total_irradiance + 7. Calculate the cloud opacity factor [1] and scale the spectral results from step 4 - func cloud_opacity_factor + 8. Plot the results - func plot_spectral_irradiance + """ + month = 2 + hour_of_day = 12 + altitude = 0.0 + longitude = 0.0 + latitudes = [10, 40] + cloud_covers = [0.2, 0.5] # cloud cover in fraction units + water_vapor_content = 0.5 + tau500 = 0.1 + ground_albedo = 0.06 + ozone = 0.3 + surface_tilt = 0.0 + + ctime, pv_system = setup_pv_system(month, hour_of_day) + + for cloud_cover in cloud_covers: + for latitude in latitudes: + + solpos = pvlib.solarposition.get_solarposition(ctime, latitude, longitude) + airmass_relative = pvlib.atmosphere.get_relative_airmass(solpos['apparent_zenith'].to_numpy(), + model='kastenyoung1989') + pressure = pvlib.atmosphere.alt2pres(altitude) + apparent_zenith = solpos['apparent_zenith'].to_numpy() + azimuth = solpos['azimuth'].to_numpy() + surface_azimuth = pv_system['surface_azimuth'] + + transmittance = (1.0 - cloud_cover) * 0.75 + aoi = pvlib.irradiance.aoi(surface_tilt, surface_azimuth, apparent_zenith, azimuth) + + # day of year is an int64index array so access first item + day_of_year = ctime.dayofyear[0] + + spectra = pvlib.spectrum.spectrl2( + apparent_zenith=apparent_zenith, + aoi=aoi, + surface_tilt=surface_tilt, + ground_albedo=ground_albedo, + surface_pressure=pressure, + relative_airmass=airmass_relative, + precipitable_water=water_vapor_content, + ozone=ozone, + aerosol_turbidity_500nm=tau500, + dayofyear=day_of_year) + + irrads_clouds = pvlib.irradiance.campbell_norman(solpos['zenith'].to_numpy(), transmittance) + + # Convert the irradiance to a plane with tilt zero horizontal to the earth. This is done applying tilt=0 to POA + # calculations using the output from campbell_norman. The POA calculations include calculting sky and ground + # diffuse light where specific models can be selected (we use default) + POA_irradiance_clouds = pvlib.irradiance.get_total_irradiance( + surface_tilt=surface_tilt, + surface_azimuth=pv_system['surface_azimuth'], + dni=irrads_clouds['dni'], + ghi=irrads_clouds['ghi'], + dhi=irrads_clouds['dhi'], + solar_zenith=solpos['apparent_zenith'], + solar_azimuth=solpos['azimuth']) + + show_info(latitude, POA_irradiance_clouds) + + irrads_clearsky = pvlib.irradiance.campbell_norman(solpos['zenith'].to_numpy(), transmittance=0.75) + + POA_irradiance_clearsky = pvlib.irradiance.get_total_irradiance( + surface_tilt=surface_tilt, + surface_azimuth=pv_system['surface_azimuth'], + dni=irrads_clearsky['dni'], + ghi=irrads_clearsky['ghi'], + dhi=irrads_clearsky['dhi'], + solar_zenith=solpos['apparent_zenith'], + solar_azimuth=solpos['azimuth']) + + show_info(latitude, POA_irradiance_clearsky) + + F_dir, F_diff = cloud_opacity_factor(POA_irradiance_clouds['poa_direct'].values, + POA_irradiance_clouds['poa_diffuse'].values, + POA_irradiance_clouds['poa_global'].values, + spectra) + + plot_spectral_irradiance(spectra, + F_dir, + F_diff, + latitude=latitude, + day_of_year=day_of_year, + year=ctime.year[0], + clouds=cloud_cover) + + # %% +if __name__ == '__main__': + calculate_overcast_spectrl2() \ No newline at end of file diff --git a/docs/tutorials/irradiance.ipynb b/docs/tutorials/irradiance.ipynb index 5b1b9a82b6..4695ff4578 100644 --- a/docs/tutorials/irradiance.ipynb +++ b/docs/tutorials/irradiance.ipynb @@ -1978,4 +1978,4 @@ }, "nbformat": 4, "nbformat_minor": 4 -} +} \ No newline at end of file From 4819c06a701d94d601670aa9dbf4c3f460282a02 Mon Sep 17 00:00:00 2001 From: Trond Kristiansen Date: Wed, 24 Mar 2021 14:04:36 -0700 Subject: [PATCH 02/13] Added cloud_opacity_factor to irradiance.py. Added example --- docs/examples/plot_spectrl2_overcast.py | 38 +------------- pvlib/irradiance.py | 66 +++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 37 deletions(-) diff --git a/docs/examples/plot_spectrl2_overcast.py b/docs/examples/plot_spectrl2_overcast.py index 9577977059..449b0b9dd4 100644 --- a/docs/examples/plot_spectrl2_overcast.py +++ b/docs/examples/plot_spectrl2_overcast.py @@ -82,49 +82,13 @@ def show_info(latitude, irradiance): """ Simple function to show the integrated results of the spectral distributions """ - print("Latitude {}".format(latitude)) print("{}: campbell_norman clouds: dni: {:3.2f} dhi: {:3.2f} ghi: {:3.2f}".format(latitude, float(irradiance['poa_direct']), float(irradiance['poa_diffuse']), float(irradiance['poa_global']))) -def cloud_opacity_factor(I_diff_clouds, I_dir_clouds, I_ghi_clouds, spectra): - # Calculate the effect of "cloud opacity factor" on the spectral distributions under clear sky. - # - # First we calculate the rho fraction based on campbell_norman irradiance - # with clouds converted to POA irradiance. In the paper these - # values are obtained from observations. The equations used for calculating cloud opacity factor - # to scale the clear sky spectral estimates using spectrl2. Results can be compared with sun calculator: - # https://www2.pvlighthouse.com.au/calculators/solar%20spectrum%20calculator/solar%20spectrum%20calculator.aspx - # - # Ref: Marco Ernst, Hendrik Holst, Matthias Winter, Pietro P. Altermatt, - # SunCalculator: A program to calculate the angular and spectral distribution of direct and diffuse solar radiation, - # Solar Energy Materials and Solar Cells, Volume 157, 2016, Pages 913-922, - rho = I_diff_clouds / I_ghi_clouds - - I_diff_s = np.trapz(y=spectra['poa_sky_diffuse'][:, 0], x=spectra['wavelength']) - I_dir_s = np.trapz(y=spectra['poa_direct'][:, 0], x=spectra['wavelength']) - I_glob_s = np.trapz(y=spectra['poa_global'][:, 0], x=spectra['wavelength']) - - rho_spectra = I_diff_s / I_glob_s - - N_rho = (rho - rho_spectra) / (1 - rho_spectra) - - # Direct light. Equation 6 Ernst et al. 2016 - F_diff_s = spectra['poa_sky_diffuse'][:, :] - F_dir_s = spectra['poa_direct'][:, :] - - F_dir = (F_dir_s / I_dir_s) * I_dir_clouds - - # Diffuse light scaling factor. Equation 7 Ernst et al. 2016 - s_diff = (1 - N_rho) * (F_diff_s / I_diff_s) + N_rho * ((F_dir_s + F_diff_s) / I_glob_s) - - # Equation 8 Ernst et al. 2016 - F_diff = s_diff * I_diff_clouds - - return F_dir, F_diff def calculate_overcast_spectrl2(): @@ -215,7 +179,7 @@ def calculate_overcast_spectrl2(): show_info(latitude, POA_irradiance_clearsky) - F_dir, F_diff = cloud_opacity_factor(POA_irradiance_clouds['poa_direct'].values, + F_dir, F_diff = pvlib.irradiance.cloud_opacity_factor(POA_irradiance_clouds['poa_direct'].values, POA_irradiance_clouds['poa_diffuse'].values, POA_irradiance_clouds['poa_global'].values, spectra) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index 3ec6b213f9..631a77f559 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -30,6 +30,72 @@ 'dirty steel': 0.08, 'sea': 0.06} +def cloud_opacity_factor(I_diff_clouds:np.ndarray, + I_dir_clouds:np.ndarray, + I_ghi_clouds:np.ndarray, + spectra:np.ndarray) -> np.ndarray: + """ + Calculate the effect of "cloud opacity factor" on spectral irradiance under clear sky. + + First we calculate the rho fraction based on campbell_norman irradiance + with clouds converted to POA irradiance. In the paper [1] these + values are obtained from observations. The equations used for calculating cloud opacity factor + to scale the clear sky spectral estimates using spectrl2. Results can be compared with sun calculator: + https://www2.pvlighthouse.com.au/calculators/solar%20spectrum%20calculator/solar%20spectrum%20calculator.aspx + + Parameters + ---------- + I_diff_clouds:np.ndarray + Total diffuse irradiance (poa_diffuse) estimated using pvlib.irradiance.get_total_irradiance and + pvlib.irradiance.campbell_norman irradiance with clouds (transmittance) + + I_dir_clouds:np.ndarray + Total direct irradiance (poa_direct) estimated using pvlib.irradiance.get_total_irradiance and + pvlib.irradiance.campbell_norman irradiance with clouds (transmittance) + + I_ghi_clouds:np.ndarray + Total direct irradiance (poa_global) estimated using pvlib.irradiance.get_total_irradiance and + pvlib.irradiance.campbell_norman irradiance with clouds (transmittance) + + spectra:np.ndarray + Spectral irradiance output from pvlib.spectrum.spectrl2 under clear-sky conditions + + + Returns + ------- + F_dir, F_diff spectral direct and diffuse irradiance scaled for cloudiness + + References + ---------- + .. [1] Ref: Marco Ernst, Hendrik Holst, Matthias Winter, Pietro P. Altermatt, + SunCalculator: A program to calculate the angular and spectral distribution of direct and + diffuse solar radiation, Solar Energy Materials and Solar Cells, Volume 157, 2016, + Pages 913-922, + """ + + rho = I_diff_clouds / I_ghi_clouds + + I_diff_s = np.trapz(y=spectra['poa_sky_diffuse'][:, 0], x=spectra['wavelength']) + I_dir_s = np.trapz(y=spectra['poa_direct'][:, 0], x=spectra['wavelength']) + I_glob_s = np.trapz(y=spectra['poa_global'][:, 0], x=spectra['wavelength']) + + rho_spectra = I_diff_s / I_glob_s + + N_rho = (rho - rho_spectra) / (1 - rho_spectra) + + # Direct light. Equation 6 Ernst et al. 2016 + F_diff_s = spectra['poa_sky_diffuse'][:, :] + F_dir_s = spectra['poa_direct'][:, :] + + F_dir = (F_dir_s / I_dir_s) * I_dir_clouds + + # Diffuse light scaling factor. Equation 7 Ernst et al. 2016 + s_diff = (1 - N_rho) * (F_diff_s / I_diff_s) + N_rho * ((F_dir_s + F_diff_s) / I_glob_s) + + # Equation 8 Ernst et al. 2016 + F_diff = s_diff * I_diff_clouds + + return F_dir, F_diff def get_extra_radiation(datetime_or_doy, solar_constant=1366.1, method='spencer', epoch_year=2014, **kwargs): From e88d8f43ee1f090eaa5008295efc3f1fbadd5cec Mon Sep 17 00:00:00 2001 From: Trond Kristiansen Date: Wed, 24 Mar 2021 17:30:41 -0700 Subject: [PATCH 03/13] Made some stickler edits --- pvlib/irradiance.py | 278 +++++++++++++++++++++++--------------------- 1 file changed, 143 insertions(+), 135 deletions(-) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index 631a77f559..cccd72edc7 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -13,7 +13,6 @@ from pvlib import atmosphere, solarposition, tools - # see References section of grounddiffuse function SURFACE_ALBEDOS = {'urban': 0.18, 'grass': 0.20, @@ -30,10 +29,11 @@ 'dirty steel': 0.08, 'sea': 0.06} -def cloud_opacity_factor(I_diff_clouds:np.ndarray, - I_dir_clouds:np.ndarray, - I_ghi_clouds:np.ndarray, - spectra:np.ndarray) -> np.ndarray: + +def cloud_opacity_factor(irr_dif_clouds: np.ndarray, + irr_dir_clouds: np.ndarray, + irr_ghi_clouds: np.ndarray, + spectra: np.ndarray) -> (np.ndarray, np.ndarray): """ Calculate the effect of "cloud opacity factor" on spectral irradiance under clear sky. @@ -45,15 +45,15 @@ def cloud_opacity_factor(I_diff_clouds:np.ndarray, Parameters ---------- - I_diff_clouds:np.ndarray + irr_dif_clouds:np.ndarray Total diffuse irradiance (poa_diffuse) estimated using pvlib.irradiance.get_total_irradiance and pvlib.irradiance.campbell_norman irradiance with clouds (transmittance) - I_dir_clouds:np.ndarray + irr_dir_clouds:np.ndarray Total direct irradiance (poa_direct) estimated using pvlib.irradiance.get_total_irradiance and pvlib.irradiance.campbell_norman irradiance with clouds (transmittance) - I_ghi_clouds:np.ndarray + irr_ghi_clouds:np.ndarray Total direct irradiance (poa_global) estimated using pvlib.irradiance.get_total_irradiance and pvlib.irradiance.campbell_norman irradiance with clouds (transmittance) @@ -63,7 +63,7 @@ def cloud_opacity_factor(I_diff_clouds:np.ndarray, Returns ------- - F_dir, F_diff spectral direct and diffuse irradiance scaled for cloudiness + f_dir, f_diff spectral direct and diffuse irradiance scaled for cloudiness References ---------- @@ -73,7 +73,7 @@ def cloud_opacity_factor(I_diff_clouds:np.ndarray, Pages 913-922, """ - rho = I_diff_clouds / I_ghi_clouds + rho = irr_dif_clouds / irr_ghi_clouds I_diff_s = np.trapz(y=spectra['poa_sky_diffuse'][:, 0], x=spectra['wavelength']) I_dir_s = np.trapz(y=spectra['poa_direct'][:, 0], x=spectra['wavelength']) @@ -81,21 +81,22 @@ def cloud_opacity_factor(I_diff_clouds:np.ndarray, rho_spectra = I_diff_s / I_glob_s - N_rho = (rho - rho_spectra) / (1 - rho_spectra) + n_rho = (rho - rho_spectra) / (1 - rho_spectra) # Direct light. Equation 6 Ernst et al. 2016 - F_diff_s = spectra['poa_sky_diffuse'][:, :] - F_dir_s = spectra['poa_direct'][:, :] + f_diff_s = spectra['poa_sky_diffuse'][:, :] + f_dir_s = spectra['poa_direct'][:, :] - F_dir = (F_dir_s / I_dir_s) * I_dir_clouds + f_dir = (f_dir_s / I_dir_s) * irr_dir_clouds # Diffuse light scaling factor. Equation 7 Ernst et al. 2016 - s_diff = (1 - N_rho) * (F_diff_s / I_diff_s) + N_rho * ((F_dir_s + F_diff_s) / I_glob_s) + s_diff = (1 - n_rho) * (f_diff_s / I_diff_s) + n_rho * ((f_dir_s + f_diff_s) / I_glob_s) # Equation 8 Ernst et al. 2016 - F_diff = s_diff * I_diff_clouds + f_diff = s_diff * irr_dif_clouds + + return f_dir, f_diff - return F_dir, F_diff def get_extra_radiation(datetime_or_doy, solar_constant=1366.1, method='spencer', epoch_year=2014, **kwargs): @@ -189,7 +190,10 @@ def _handle_extra_radiation_types(datetime_or_doy, epoch_year): # a better way to do it. if isinstance(datetime_or_doy, pd.DatetimeIndex): to_doy = tools._pandas_to_doy # won't be evaluated unless necessary - def to_datetimeindex(x): return x # noqa: E306 + + def to_datetimeindex(x): + return x # noqa: E306 + to_output = partial(pd.Series, index=datetime_or_doy) elif isinstance(datetime_or_doy, pd.Timestamp): to_doy = tools._pandas_to_doy @@ -203,12 +207,16 @@ def to_datetimeindex(x): return x # noqa: E306 tools._datetimelike_scalar_to_datetimeindex to_output = tools._scalar_out elif np.isscalar(datetime_or_doy): # ints and floats of various types - def to_doy(x): return x # noqa: E306 + def to_doy(x): + return x # noqa: E306 + to_datetimeindex = partial(tools._doy_to_datetimeindex, epoch_year=epoch_year) to_output = tools._scalar_out else: # assume that we have an array-like object of doy - def to_doy(x): return x # noqa: E306 + def to_doy(x): + return x # noqa: E306 + to_datetimeindex = partial(tools._doy_to_datetimeindex, epoch_year=epoch_year) to_output = tools._array_out @@ -244,9 +252,9 @@ def aoi_projection(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth): """ projection = ( - tools.cosd(surface_tilt) * tools.cosd(solar_zenith) + - tools.sind(surface_tilt) * tools.sind(solar_zenith) * - tools.cosd(solar_azimuth - surface_azimuth)) + tools.cosd(surface_tilt) * tools.cosd(solar_zenith) + + tools.sind(surface_tilt) * tools.sind(solar_zenith) * + tools.cosd(solar_azimuth - surface_azimuth)) try: projection.name = 'aoi_projection' @@ -954,7 +962,7 @@ def reindl(surface_tilt, surface_azimuth, dhi, dni, ghi, dni_extra, term2 = 0.5 * (1 + tools.cosd(surface_tilt)) with np.errstate(invalid='ignore', divide='ignore'): hb_to_ghi = np.where(ghi == 0, 0, np.divide(HB, ghi)) - term3 = 1 + np.sqrt(hb_to_ghi) * (tools.sind(0.5 * surface_tilt)**3) + term3 = 1 + np.sqrt(hb_to_ghi) * (tools.sind(0.5 * surface_tilt) ** 3) sky_diffuse = dhi * (AI * Rb + term1 * term2 * term3) sky_diffuse = np.maximum(sky_diffuse, 0) @@ -1474,18 +1482,18 @@ def _disc_kn(clearness_index, airmass, max_airmass=12): bools = (kt <= 0.6) a = np.where(bools, - 0.512 - 1.56*kt + 2.286*kt2 - 2.222*kt3, - -5.743 + 21.77*kt - 27.49*kt2 + 11.56*kt3) + 0.512 - 1.56 * kt + 2.286 * kt2 - 2.222 * kt3, + -5.743 + 21.77 * kt - 27.49 * kt2 + 11.56 * kt3) b = np.where(bools, - 0.37 + 0.962*kt, - 41.4 - 118.5*kt + 66.05*kt2 + 31.9*kt3) + 0.37 + 0.962 * kt, + 41.4 - 118.5 * kt + 66.05 * kt2 + 31.9 * kt3) c = np.where(bools, - -0.28 + 0.932*kt - 2.048*kt2, - -47.01 + 184.2*kt - 222.0*kt2 + 73.81*kt3) + -0.28 + 0.932 * kt - 2.048 * kt2, + -47.01 + 184.2 * kt - 222.0 * kt2 + 73.81 * kt3) - delta_kn = a + b * np.exp(c*am) + delta_kn = a + b * np.exp(c * am) - Knc = 0.866 - 0.122*am + 0.0121*am**2 - 0.000653*am**3 + 1.4e-05*am**4 + Knc = 0.866 - 0.122 * am + 0.0121 * am ** 2 - 0.000653 * am ** 3 + 1.4e-05 * am ** 4 Kn = Knc - delta_kn return Kn, am @@ -1616,8 +1624,8 @@ def _delta_kt_prime_dirint(kt_prime, use_delta_kt_prime, times): kt_next.iloc[-1] = kt_previous.iloc[-1] kt_previous.iloc[0] = kt_next.iloc[0] delta_kt_prime = 0.5 * ((kt_prime - kt_next).abs().add( - (kt_prime - kt_previous).abs(), - fill_value=0)) + (kt_prime - kt_previous).abs(), + fill_value=0)) else: # do not change unless also modifying _dirint_bins delta_kt_prime = pd.Series(-1, index=times) @@ -1664,8 +1672,8 @@ def _dirint_coeffs(times, kt_prime, solar_zenith, w, delta_kt_prime): # subtract 1 to account for difference between MATLAB-style bin # assignment and Python-style array lookup. - dirint_coeffs = coeffs[kt_prime_bin-1, zenith_bin-1, - delta_kt_prime_bin-1, w_bin-1] + dirint_coeffs = coeffs[kt_prime_bin - 1, zenith_bin - 1, + delta_kt_prime_bin - 1, w_bin - 1] # convert unassigned bins to nan dirint_coeffs = np.where((kt_prime_bin == 0) | (zenith_bin == 0) | @@ -2016,8 +2024,8 @@ def _gti_dirint_lt_90(poa_global, aoi, aoi_lt_90, solar_zenith, solar_azimuth, # calculate DHI using Marion eqn 3 (identify 1st term on RHS as GHI) # I0h has a minimum zenith projection, but multiplier of DNI does not - ghi = kt * I0h # Kt * I0 * max(0.065, cos(zen)) - dhi = ghi - dni * cos_zenith # no cos(zen) restriction here + ghi = kt * I0h # Kt * I0 * max(0.065, cos(zen)) + dhi = ghi - dni * cos_zenith # no cos(zen) restriction here # following SSC code dni = np.maximum(dni, 0) @@ -2101,8 +2109,8 @@ def _gti_dirint_gte_90(poa_global, aoi, solar_zenith, solar_azimuth, # isotropic sky plus ground diffuse dhi_gte_90 = ( - (2 * poa_global - dni_gte_90_proj * albedo * (1 - cos_surface_tilt)) / - (1 + cos_surface_tilt + albedo * (1 - cos_surface_tilt))) + (2 * poa_global - dni_gte_90_proj * albedo * (1 - cos_surface_tilt)) / + (1 + cos_surface_tilt + albedo * (1 - cos_surface_tilt))) ghi_gte_90 = dni_gte_90_proj + dhi_gte_90 @@ -2222,12 +2230,12 @@ def erbs(ghi, zenith, datetime_or_doy, min_cos_zenith=0.065, max_zenith=87): max_clearness_index=1) # For Kt <= 0.22, set the diffuse fraction - df = 1 - 0.09*kt + df = 1 - 0.09 * kt # For Kt > 0.22 and Kt <= 0.8, set the diffuse fraction df = np.where((kt > 0.22) & (kt <= 0.8), - 0.9511 - 0.1604*kt + 4.388*kt**2 - - 16.638*kt**3 + 12.336*kt**4, + 0.9511 - 0.1604 * kt + 4.388 * kt ** 2 - + 16.638 * kt ** 3 + 12.336 * kt ** 4, df) # For Kt > 0.8, set the diffuse fraction @@ -2290,9 +2298,9 @@ def campbell_norman(zenith, transmittance, pressure=101325.0, airmass = atmosphere.get_relative_airmass(zenith, model='simple') airmass = atmosphere.get_absolute_airmass(airmass, pressure=pressure) - dni = dni_extra*tau**airmass + dni = dni_extra * tau ** airmass cos_zen = tools.cosd(zenith) - dhi = 0.3 * (1.0 - tau**airmass) * dni_extra * cos_zen + dhi = 0.3 * (1.0 - tau ** airmass) * dni_extra * cos_zen ghi = dhi + dni * cos_zen irrads = OrderedDict() @@ -2349,8 +2357,8 @@ def _liujordan(zenith, transmittance, airmass, dni_extra=1367.0): tau = transmittance - dni = dni_extra*tau**airmass - dhi = 0.3 * (1.0 - tau**airmass) * dni_extra * np.cos(np.radians(zenith)) + dni = dni_extra * tau ** airmass + dhi = 0.3 * (1.0 - tau ** airmass) * dni_extra * np.cos(np.radians(zenith)) ghi = dhi + dni * np.cos(np.radians(zenith)) irrads = OrderedDict() @@ -2417,104 +2425,104 @@ def _get_perez_coefficients(perezmodel): ''' coeffdict = { 'allsitescomposite1990': [ - [-0.0080, 0.5880, -0.0620, -0.0600, 0.0720, -0.0220], - [0.1300, 0.6830, -0.1510, -0.0190, 0.0660, -0.0290], - [0.3300, 0.4870, -0.2210, 0.0550, -0.0640, -0.0260], - [0.5680, 0.1870, -0.2950, 0.1090, -0.1520, -0.0140], - [0.8730, -0.3920, -0.3620, 0.2260, -0.4620, 0.0010], - [1.1320, -1.2370, -0.4120, 0.2880, -0.8230, 0.0560], - [1.0600, -1.6000, -0.3590, 0.2640, -1.1270, 0.1310], - [0.6780, -0.3270, -0.2500, 0.1560, -1.3770, 0.2510]], + [-0.0080, 0.5880, -0.0620, -0.0600, 0.0720, -0.0220], + [0.1300, 0.6830, -0.1510, -0.0190, 0.0660, -0.0290], + [0.3300, 0.4870, -0.2210, 0.0550, -0.0640, -0.0260], + [0.5680, 0.1870, -0.2950, 0.1090, -0.1520, -0.0140], + [0.8730, -0.3920, -0.3620, 0.2260, -0.4620, 0.0010], + [1.1320, -1.2370, -0.4120, 0.2880, -0.8230, 0.0560], + [1.0600, -1.6000, -0.3590, 0.2640, -1.1270, 0.1310], + [0.6780, -0.3270, -0.2500, 0.1560, -1.3770, 0.2510]], 'allsitescomposite1988': [ - [-0.0180, 0.7050, -0.071, -0.0580, 0.1020, -0.0260], - [0.1910, 0.6450, -0.1710, 0.0120, 0.0090, -0.0270], - [0.4400, 0.3780, -0.2560, 0.0870, -0.1040, -0.0250], - [0.7560, -0.1210, -0.3460, 0.1790, -0.3210, -0.0080], - [0.9960, -0.6450, -0.4050, 0.2600, -0.5900, 0.0170], - [1.0980, -1.2900, -0.3930, 0.2690, -0.8320, 0.0750], - [0.9730, -1.1350, -0.3780, 0.1240, -0.2580, 0.1490], - [0.6890, -0.4120, -0.2730, 0.1990, -1.6750, 0.2370]], + [-0.0180, 0.7050, -0.071, -0.0580, 0.1020, -0.0260], + [0.1910, 0.6450, -0.1710, 0.0120, 0.0090, -0.0270], + [0.4400, 0.3780, -0.2560, 0.0870, -0.1040, -0.0250], + [0.7560, -0.1210, -0.3460, 0.1790, -0.3210, -0.0080], + [0.9960, -0.6450, -0.4050, 0.2600, -0.5900, 0.0170], + [1.0980, -1.2900, -0.3930, 0.2690, -0.8320, 0.0750], + [0.9730, -1.1350, -0.3780, 0.1240, -0.2580, 0.1490], + [0.6890, -0.4120, -0.2730, 0.1990, -1.6750, 0.2370]], 'sandiacomposite1988': [ - [-0.1960, 1.0840, -0.0060, -0.1140, 0.1800, -0.0190], - [0.2360, 0.5190, -0.1800, -0.0110, 0.0200, -0.0380], - [0.4540, 0.3210, -0.2550, 0.0720, -0.0980, -0.0460], - [0.8660, -0.3810, -0.3750, 0.2030, -0.4030, -0.0490], - [1.0260, -0.7110, -0.4260, 0.2730, -0.6020, -0.0610], - [0.9780, -0.9860, -0.3500, 0.2800, -0.9150, -0.0240], - [0.7480, -0.9130, -0.2360, 0.1730, -1.0450, 0.0650], - [0.3180, -0.7570, 0.1030, 0.0620, -1.6980, 0.2360]], + [-0.1960, 1.0840, -0.0060, -0.1140, 0.1800, -0.0190], + [0.2360, 0.5190, -0.1800, -0.0110, 0.0200, -0.0380], + [0.4540, 0.3210, -0.2550, 0.0720, -0.0980, -0.0460], + [0.8660, -0.3810, -0.3750, 0.2030, -0.4030, -0.0490], + [1.0260, -0.7110, -0.4260, 0.2730, -0.6020, -0.0610], + [0.9780, -0.9860, -0.3500, 0.2800, -0.9150, -0.0240], + [0.7480, -0.9130, -0.2360, 0.1730, -1.0450, 0.0650], + [0.3180, -0.7570, 0.1030, 0.0620, -1.6980, 0.2360]], 'usacomposite1988': [ - [-0.0340, 0.6710, -0.0590, -0.0590, 0.0860, -0.0280], - [0.2550, 0.4740, -0.1910, 0.0180, -0.0140, -0.0330], - [0.4270, 0.3490, -0.2450, 0.0930, -0.1210, -0.0390], - [0.7560, -0.2130, -0.3280, 0.1750, -0.3040, -0.0270], - [1.0200, -0.8570, -0.3850, 0.2800, -0.6380, -0.0190], - [1.0500, -1.3440, -0.3480, 0.2800, -0.8930, 0.0370], - [0.9740, -1.5070, -0.3700, 0.1540, -0.5680, 0.1090], - [0.7440, -1.8170, -0.2560, 0.2460, -2.6180, 0.2300]], + [-0.0340, 0.6710, -0.0590, -0.0590, 0.0860, -0.0280], + [0.2550, 0.4740, -0.1910, 0.0180, -0.0140, -0.0330], + [0.4270, 0.3490, -0.2450, 0.0930, -0.1210, -0.0390], + [0.7560, -0.2130, -0.3280, 0.1750, -0.3040, -0.0270], + [1.0200, -0.8570, -0.3850, 0.2800, -0.6380, -0.0190], + [1.0500, -1.3440, -0.3480, 0.2800, -0.8930, 0.0370], + [0.9740, -1.5070, -0.3700, 0.1540, -0.5680, 0.1090], + [0.7440, -1.8170, -0.2560, 0.2460, -2.6180, 0.2300]], 'france1988': [ - [0.0130, 0.7640, -0.1000, -0.0580, 0.1270, -0.0230], - [0.0950, 0.9200, -0.1520, 0, 0.0510, -0.0200], - [0.4640, 0.4210, -0.2800, 0.0640, -0.0510, -0.0020], - [0.7590, -0.0090, -0.3730, 0.2010, -0.3820, 0.0100], - [0.9760, -0.4000, -0.4360, 0.2710, -0.6380, 0.0510], - [1.1760, -1.2540, -0.4620, 0.2950, -0.9750, 0.1290], - [1.1060, -1.5630, -0.3980, 0.3010, -1.4420, 0.2120], - [0.9340, -1.5010, -0.2710, 0.4200, -2.9170, 0.2490]], + [0.0130, 0.7640, -0.1000, -0.0580, 0.1270, -0.0230], + [0.0950, 0.9200, -0.1520, 0, 0.0510, -0.0200], + [0.4640, 0.4210, -0.2800, 0.0640, -0.0510, -0.0020], + [0.7590, -0.0090, -0.3730, 0.2010, -0.3820, 0.0100], + [0.9760, -0.4000, -0.4360, 0.2710, -0.6380, 0.0510], + [1.1760, -1.2540, -0.4620, 0.2950, -0.9750, 0.1290], + [1.1060, -1.5630, -0.3980, 0.3010, -1.4420, 0.2120], + [0.9340, -1.5010, -0.2710, 0.4200, -2.9170, 0.2490]], 'phoenix1988': [ - [-0.0030, 0.7280, -0.0970, -0.0750, 0.1420, -0.0430], - [0.2790, 0.3540, -0.1760, 0.0300, -0.0550, -0.0540], - [0.4690, 0.1680, -0.2460, 0.0480, -0.0420, -0.0570], - [0.8560, -0.5190, -0.3400, 0.1760, -0.3800, -0.0310], - [0.9410, -0.6250, -0.3910, 0.1880, -0.3600, -0.0490], - [1.0560, -1.1340, -0.4100, 0.2810, -0.7940, -0.0650], - [0.9010, -2.1390, -0.2690, 0.1180, -0.6650, 0.0460], - [0.1070, 0.4810, 0.1430, -0.1110, -0.1370, 0.2340]], + [-0.0030, 0.7280, -0.0970, -0.0750, 0.1420, -0.0430], + [0.2790, 0.3540, -0.1760, 0.0300, -0.0550, -0.0540], + [0.4690, 0.1680, -0.2460, 0.0480, -0.0420, -0.0570], + [0.8560, -0.5190, -0.3400, 0.1760, -0.3800, -0.0310], + [0.9410, -0.6250, -0.3910, 0.1880, -0.3600, -0.0490], + [1.0560, -1.1340, -0.4100, 0.2810, -0.7940, -0.0650], + [0.9010, -2.1390, -0.2690, 0.1180, -0.6650, 0.0460], + [0.1070, 0.4810, 0.1430, -0.1110, -0.1370, 0.2340]], 'elmonte1988': [ - [0.0270, 0.7010, -0.1190, -0.0580, 0.1070, -0.0600], - [0.1810, 0.6710, -0.1780, -0.0790, 0.1940, -0.0350], - [0.4760, 0.4070, -0.2880, 0.0540, -0.0320, -0.0550], - [0.8750, -0.2180, -0.4030, 0.1870, -0.3090, -0.0610], - [1.1660, -1.0140, -0.4540, 0.2110, -0.4100, -0.0440], - [1.1430, -2.0640, -0.2910, 0.0970, -0.3190, 0.0530], - [1.0940, -2.6320, -0.2590, 0.0290, -0.4220, 0.1470], - [0.1550, 1.7230, 0.1630, -0.1310, -0.0190, 0.2770]], + [0.0270, 0.7010, -0.1190, -0.0580, 0.1070, -0.0600], + [0.1810, 0.6710, -0.1780, -0.0790, 0.1940, -0.0350], + [0.4760, 0.4070, -0.2880, 0.0540, -0.0320, -0.0550], + [0.8750, -0.2180, -0.4030, 0.1870, -0.3090, -0.0610], + [1.1660, -1.0140, -0.4540, 0.2110, -0.4100, -0.0440], + [1.1430, -2.0640, -0.2910, 0.0970, -0.3190, 0.0530], + [1.0940, -2.6320, -0.2590, 0.0290, -0.4220, 0.1470], + [0.1550, 1.7230, 0.1630, -0.1310, -0.0190, 0.2770]], 'osage1988': [ - [-0.3530, 1.4740, 0.0570, -0.1750, 0.3120, 0.0090], - [0.3630, 0.2180, -0.2120, 0.0190, -0.0340, -0.0590], - [-0.0310, 1.2620, -0.0840, -0.0820, 0.2310, -0.0170], - [0.6910, 0.0390, -0.2950, 0.0910, -0.1310, -0.0350], - [1.1820, -1.3500, -0.3210, 0.4080, -0.9850, -0.0880], - [0.7640, 0.0190, -0.2030, 0.2170, -0.2940, -0.1030], - [0.2190, 1.4120, 0.2440, 0.4710, -2.9880, 0.0340], - [3.5780, 22.2310, -10.7450, 2.4260, 4.8920, -5.6870]], + [-0.3530, 1.4740, 0.0570, -0.1750, 0.3120, 0.0090], + [0.3630, 0.2180, -0.2120, 0.0190, -0.0340, -0.0590], + [-0.0310, 1.2620, -0.0840, -0.0820, 0.2310, -0.0170], + [0.6910, 0.0390, -0.2950, 0.0910, -0.1310, -0.0350], + [1.1820, -1.3500, -0.3210, 0.4080, -0.9850, -0.0880], + [0.7640, 0.0190, -0.2030, 0.2170, -0.2940, -0.1030], + [0.2190, 1.4120, 0.2440, 0.4710, -2.9880, 0.0340], + [3.5780, 22.2310, -10.7450, 2.4260, 4.8920, -5.6870]], 'albuquerque1988': [ - [0.0340, 0.5010, -0.0940, -0.0630, 0.1060, -0.0440], - [0.2290, 0.4670, -0.1560, -0.0050, -0.0190, -0.0230], - [0.4860, 0.2410, -0.2530, 0.0530, -0.0640, -0.0220], - [0.8740, -0.3930, -0.3970, 0.1810, -0.3270, -0.0370], - [1.1930, -1.2960, -0.5010, 0.2810, -0.6560, -0.0450], - [1.0560, -1.7580, -0.3740, 0.2260, -0.7590, 0.0340], - [0.9010, -4.7830, -0.1090, 0.0630, -0.9700, 0.1960], - [0.8510, -7.0550, -0.0530, 0.0600, -2.8330, 0.3300]], + [0.0340, 0.5010, -0.0940, -0.0630, 0.1060, -0.0440], + [0.2290, 0.4670, -0.1560, -0.0050, -0.0190, -0.0230], + [0.4860, 0.2410, -0.2530, 0.0530, -0.0640, -0.0220], + [0.8740, -0.3930, -0.3970, 0.1810, -0.3270, -0.0370], + [1.1930, -1.2960, -0.5010, 0.2810, -0.6560, -0.0450], + [1.0560, -1.7580, -0.3740, 0.2260, -0.7590, 0.0340], + [0.9010, -4.7830, -0.1090, 0.0630, -0.9700, 0.1960], + [0.8510, -7.0550, -0.0530, 0.0600, -2.8330, 0.3300]], 'capecanaveral1988': [ - [0.0750, 0.5330, -0.1240, -0.0670, 0.0420, -0.0200], - [0.2950, 0.4970, -0.2180, -0.0080, 0.0030, -0.0290], - [0.5140, 0.0810, -0.2610, 0.0750, -0.1600, -0.0290], - [0.7470, -0.3290, -0.3250, 0.1810, -0.4160, -0.0300], - [0.9010, -0.8830, -0.2970, 0.1780, -0.4890, 0.0080], - [0.5910, -0.0440, -0.1160, 0.2350, -0.9990, 0.0980], - [0.5370, -2.4020, 0.3200, 0.1690, -1.9710, 0.3100], - [-0.8050, 4.5460, 1.0720, -0.2580, -0.9500, 0.7530]], + [0.0750, 0.5330, -0.1240, -0.0670, 0.0420, -0.0200], + [0.2950, 0.4970, -0.2180, -0.0080, 0.0030, -0.0290], + [0.5140, 0.0810, -0.2610, 0.0750, -0.1600, -0.0290], + [0.7470, -0.3290, -0.3250, 0.1810, -0.4160, -0.0300], + [0.9010, -0.8830, -0.2970, 0.1780, -0.4890, 0.0080], + [0.5910, -0.0440, -0.1160, 0.2350, -0.9990, 0.0980], + [0.5370, -2.4020, 0.3200, 0.1690, -1.9710, 0.3100], + [-0.8050, 4.5460, 1.0720, -0.2580, -0.9500, 0.7530]], 'albany1988': [ - [0.0120, 0.5540, -0.0760, -0.0520, 0.0840, -0.0290], - [0.2670, 0.4370, -0.1940, 0.0160, 0.0220, -0.0360], - [0.4200, 0.3360, -0.2370, 0.0740, -0.0520, -0.0320], - [0.6380, -0.0010, -0.2810, 0.1380, -0.1890, -0.0120], - [1.0190, -1.0270, -0.3420, 0.2710, -0.6280, 0.0140], - [1.1490, -1.9400, -0.3310, 0.3220, -1.0970, 0.0800], - [1.4340, -3.9940, -0.4920, 0.4530, -2.3760, 0.1170], - [1.0070, -2.2920, -0.4820, 0.3900, -3.3680, 0.2290]], } + [0.0120, 0.5540, -0.0760, -0.0520, 0.0840, -0.0290], + [0.2670, 0.4370, -0.1940, 0.0160, 0.0220, -0.0360], + [0.4200, 0.3360, -0.2370, 0.0740, -0.0520, -0.0320], + [0.6380, -0.0010, -0.2810, 0.1380, -0.1890, -0.0120], + [1.0190, -1.0270, -0.3420, 0.2710, -0.6280, 0.0140], + [1.1490, -1.9400, -0.3310, 0.3220, -1.0970, 0.0800], + [1.4340, -3.9940, -0.4920, 0.4530, -2.3760, 0.1170], + [1.0070, -2.2920, -0.4820, 0.3900, -3.3680, 0.2290]], } array = np.array(coeffdict[perezmodel]) From 41f5a56cdfaeba88a9d49f48dcc74a3fdc9a9e75 Mon Sep 17 00:00:00 2001 From: Trond Kristiansen Date: Wed, 24 Mar 2021 17:54:59 -0700 Subject: [PATCH 04/13] Improved stickler checking --- docs/examples/plot_spectrl2_overcast.py | 150 +++++++++++++----------- pvlib/irradiance.py | 2 +- 2 files changed, 85 insertions(+), 67 deletions(-) diff --git a/docs/examples/plot_spectrl2_overcast.py b/docs/examples/plot_spectrl2_overcast.py index 449b0b9dd4..5544947cc9 100644 --- a/docs/examples/plot_spectrl2_overcast.py +++ b/docs/examples/plot_spectrl2_overcast.py @@ -8,27 +8,34 @@ # %% # This example shows how to model the spectral distribution of irradiance -# based on atmospheric conditions and to correct the distribution according to cloud cover. -# The spectral distribution of irradiance is calculated using the clear sky spectrl2 function -# and modified using the "cloud opacity factor" [1]. -# the power content at each wavelength band in the solar spectrum and is -# affected by various scattering and absorption mechanisms in the atmosphere. +# based on atmospheric conditions and to correct the distribution according +# to cloud cover. The spectral distribution of irradiance is calculated +# using the clear sky spectrl2 function and modified using the +# "cloud opacity factor" [1]. The power content at each wavelength +# band in the solar spectrum and is affected by various +# scattering and absorption mechanisms in the atmosphere. # # # References # ---------- # [1] Marco Ernst, Hendrik Holst, Matthias Winter, Pietro P. Altermatt, -# SunCalculator: A program to calculate the angular and spectral distribution of -# direct and diffuse solar radiation, -# Solar Energy Materials and Solar Cells, Volume 157, 2016, Pages 913-922. +# SunCalculator: A program to calculate the angular and +# spectral distribution of direct and diffuse solar radiation, +# Solar Energy Materials and Solar Cells, Volume 157, +# 2016, Pages 913-922. # %% # Trond Kristiansen, https://github.com/trondkr -import numpy as np import pandas as pd import pvlib -import datetime +from pvlib.atmosphere import get_relative_airmass +from pvlib.irradiance import campbell_norman +from pvlib.irradiance import get_total_irradiance +from datetime import timedelta as td +from datetime import timezone as timezone +from datetime import datetime + import matplotlib.pyplot as plt @@ -38,8 +45,8 @@ def setup_pv_system(month, hour_of_day): This method is just basic setup """ offset = 0 - when = [datetime.datetime(2020, month, 15, hour_of_day, 0, 0, - tzinfo=datetime.timezone(datetime.timedelta(hours=offset)))] + when = [datetime(2020, month, 15, hour_of_day, 0, 0, + tzinfo=timezone(td(hours=offset)))] time = pd.DatetimeIndex(when) sandia_modules = pvlib.pvsystem.retrieve_sam('SandiaMod') @@ -54,7 +61,7 @@ def setup_pv_system(month, hour_of_day): # %% -def plot_spectral_irradiance(spectra, F_dir, F_diff, latitude, day_of_year, year, clouds): +def plot_spectral_irradiance(spectra, f_dir, f_diff, latitude, day_of_year, year, clouds): """ Plot the results showing the spectral distribution of irradiance with and without the effects of clouds @@ -64,15 +71,16 @@ def plot_spectral_irradiance(spectra, F_dir, F_diff, latitude, day_of_year, year ax.plot(spectra['wavelength'], spectra["poa_direct"][:, 0], c="g") ax.plot(spectra['wavelength'], spectra["poa_global"][:, 0], c="m") - ax.plot(spectra['wavelength'], F_dir[:, 0], c="r", linestyle='dashed') - ax.plot(spectra['wavelength'], F_diff[:, 0], c="y", linestyle='dashed') + ax.plot(spectra['wavelength'], f_dir[:, 0], c="r", linestyle='dashed') + ax.plot(spectra['wavelength'], f_diff[:, 0], c="y", linestyle='dashed') plt.xlim(200, 2700) plt.ylim(0, 1.8) plt.title(r"Day {} {} latitude {} cloud cover {}".format(day_of_year, year, latitude, clouds)) plt.ylabel(r"Irradiance ($W m^{-2} nm^{-1}$)") plt.xlabel(r"Wavelength ($nm$)") - labels = ["poa_sky_diffuse", "poa_direct", "poa_global", "poa_sky_diffuse clouds", "poa_direct clouds"] + labels = ["poa_sky_diffuse", "poa_direct", "poa_global", + "poa_sky_diffuse clouds", "poa_direct clouds"] ax.legend(labels) plt.show() @@ -82,29 +90,37 @@ def show_info(latitude, irradiance): """ Simple function to show the integrated results of the spectral distributions """ - print("{}: campbell_norman clouds: dni: {:3.2f} dhi: {:3.2f} ghi: {:3.2f}".format(latitude, - float(irradiance['poa_direct']), - float(irradiance['poa_diffuse']), - float(irradiance['poa_global']))) - - + print("{}: campbell_norman clouds: dni: {:3.2f} " + "dhi: {:3.2f} ghi: {:3.2f}".format(latitude, + float(irradiance['poa_direct']), + float(irradiance['poa_diffuse']), + float(irradiance['poa_global']))) def calculate_overcast_spectrl2(): - """ - This example will loop over a range of cloud covers and latitudes (at longitude=0) for a - specific date and calculate the spectral irradiance with and without accounting for clouds. - Clouds are accounted for by applying the cloud opacity factor defined in [1]. Several steps are required: - 1. Calculate the atmospheric and solar conditions for the location and time - 2. Calculate the spectral irradiance using pvlib.spectrum.spectrl2 for clear sky conditions - 3. Calculate the dni, dhi, and ghi for cloudy conditions using pvlib.irradiance.campbell_norman - 4. Determine total in-plane irradiance and its beam, sky diffuse and ground - reflected components for cloudy conditions - pvlib.irradiance.get_total_irradiance - 5. Calculate the dni, dhi, and ghi for clear sky conditions using pvlib.irradiance.campbell_norman - 6. Determine total in-plane irradiance and its beam, sky diffuse and ground - reflected components for clear sky conditions - pvlib.irradiance.get_total_irradiance - 7. Calculate the cloud opacity factor [1] and scale the spectral results from step 4 - func cloud_opacity_factor + This example will loop over a range of cloud covers and latitudes + (at longitude=0) for a specific date and calculate the spectral + irradiance with and without accounting for clouds. Clouds are accounted for + by applying the cloud opacity factor defined in [1]. Several steps are required: + 1. Calculate the atmospheric and solar conditions for the + location and time + 2. Calculate the spectral irradiance using `pvlib.spectrum.spectrl2` + for clear sky conditions + 3. Calculate the dni, dhi, and ghi for cloudy conditions using + `pvlib.irradiance.campbell_norman` + 4. Determine total in-plane irradiance and its beam, + sky diffuse and ground + reflected components for cloudy conditions - + `pvlib.irradiance.get_total_irradiance` + 5. Calculate the dni, dhi, and ghi for clear sky conditions + using `pvlib.irradiance.campbell_norman` + 6. Determine total in-plane irradiance and its beam, + sky diffuse and ground + reflected components for clear sky conditions - + `pvlib.irradiance.get_total_irradiance` + 7. Calculate the cloud opacity factor [1] and scale the + spectral results from step 4 - func cloud_opacity_factor 8. Plot the results - func plot_spectral_irradiance """ month = 2 @@ -112,7 +128,9 @@ def calculate_overcast_spectrl2(): altitude = 0.0 longitude = 0.0 latitudes = [10, 40] - cloud_covers = [0.2, 0.5] # cloud cover in fraction units + + # cloud cover in fraction units + cloud_covers = [0.2, 0.5] water_vapor_content = 0.5 tau500 = 0.1 ground_albedo = 0.06 @@ -123,13 +141,12 @@ def calculate_overcast_spectrl2(): for cloud_cover in cloud_covers: for latitude in latitudes: - - solpos = pvlib.solarposition.get_solarposition(ctime, latitude, longitude) - airmass_relative = pvlib.atmosphere.get_relative_airmass(solpos['apparent_zenith'].to_numpy(), - model='kastenyoung1989') + sol = pvlib.solarposition.get_solarposition(ctime, latitude, longitude) + airmass_relative = get_relative_airmass(sol['apparent_zenith'].to_numpy(), + model='kastenyoung1989') pressure = pvlib.atmosphere.alt2pres(altitude) - apparent_zenith = solpos['apparent_zenith'].to_numpy() - azimuth = solpos['azimuth'].to_numpy() + apparent_zenith = sol['apparent_zenith'].to_numpy() + azimuth = sol['azimuth'].to_numpy() surface_azimuth = pv_system['surface_azimuth'] transmittance = (1.0 - cloud_cover) * 0.75 @@ -150,48 +167,49 @@ def calculate_overcast_spectrl2(): aerosol_turbidity_500nm=tau500, dayofyear=day_of_year) - irrads_clouds = pvlib.irradiance.campbell_norman(solpos['zenith'].to_numpy(), transmittance) + irrads_clouds = campbell_norman(sol['zenith'].to_numpy(), + transmittance) - # Convert the irradiance to a plane with tilt zero horizontal to the earth. This is done applying tilt=0 to POA - # calculations using the output from campbell_norman. The POA calculations include calculting sky and ground + # Convert the irradiance to a plane with tilt zero horizontal to the earth. + # This is done applying tilt=0 to POA calculations using the output from + # `campbell_norman`. The POA calculations include calculating sky and ground # diffuse light where specific models can be selected (we use default) - POA_irradiance_clouds = pvlib.irradiance.get_total_irradiance( + poa_irr_clouds = get_total_irradiance( surface_tilt=surface_tilt, surface_azimuth=pv_system['surface_azimuth'], dni=irrads_clouds['dni'], ghi=irrads_clouds['ghi'], dhi=irrads_clouds['dhi'], - solar_zenith=solpos['apparent_zenith'], - solar_azimuth=solpos['azimuth']) + solar_zenith=sol['apparent_zenith'], + solar_azimuth=sol['azimuth']) - show_info(latitude, POA_irradiance_clouds) + show_info(latitude, poa_irr_clouds) - irrads_clearsky = pvlib.irradiance.campbell_norman(solpos['zenith'].to_numpy(), transmittance=0.75) + irr_clearsky = campbell_norman(sol['zenith'].to_numpy(), transmittance=0.75) - POA_irradiance_clearsky = pvlib.irradiance.get_total_irradiance( + poa_irr_clearsky = pvlib.irradiance.get_total_irradiance( surface_tilt=surface_tilt, surface_azimuth=pv_system['surface_azimuth'], - dni=irrads_clearsky['dni'], - ghi=irrads_clearsky['ghi'], - dhi=irrads_clearsky['dhi'], - solar_zenith=solpos['apparent_zenith'], - solar_azimuth=solpos['azimuth']) + dni=irr_clearsky['dni'], + ghi=irr_clearsky['ghi'], + dhi=irr_clearsky['dhi'], + solar_zenith=sol['apparent_zenith'], + solar_azimuth=sol['azimuth']) - show_info(latitude, POA_irradiance_clearsky) + show_info(latitude, poa_irr_clearsky) - F_dir, F_diff = pvlib.irradiance.cloud_opacity_factor(POA_irradiance_clouds['poa_direct'].values, - POA_irradiance_clouds['poa_diffuse'].values, - POA_irradiance_clouds['poa_global'].values, - spectra) + f_dir, f_diff = pvlib.irradiance.cloud_opacity_factor(poa_irr_clouds['poa_direct'].values, + poa_irr_clouds['poa_diffuse'].values, + poa_irr_clouds['poa_global'].values, + spectra) plot_spectral_irradiance(spectra, - F_dir, - F_diff, + f_dir, + f_diff, latitude=latitude, day_of_year=day_of_year, year=ctime.year[0], clouds=cloud_cover) - # %% -if __name__ == '__main__': - calculate_overcast_spectrl2() \ No newline at end of file + +calculate_overcast_spectrl2() diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index cccd72edc7..bd00e8b5df 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -33,7 +33,7 @@ def cloud_opacity_factor(irr_dif_clouds: np.ndarray, irr_dir_clouds: np.ndarray, irr_ghi_clouds: np.ndarray, - spectra: np.ndarray) -> (np.ndarray, np.ndarray): + spectra: dict) -> (np.ndarray, np.ndarray): """ Calculate the effect of "cloud opacity factor" on spectral irradiance under clear sky. From 9387767cce2c09b0894e5be53566dc54066e08b0 Mon Sep 17 00:00:00 2001 From: Trond Kristiansen Date: Wed, 24 Mar 2021 20:36:52 -0700 Subject: [PATCH 05/13] Updated to reccomendations from ci-stickler --- docs/examples/plot_spectrl2_overcast.py | 73 ++++++++++++++----------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/docs/examples/plot_spectrl2_overcast.py b/docs/examples/plot_spectrl2_overcast.py index 5544947cc9..33538bcce6 100644 --- a/docs/examples/plot_spectrl2_overcast.py +++ b/docs/examples/plot_spectrl2_overcast.py @@ -32,6 +32,10 @@ from pvlib.atmosphere import get_relative_airmass from pvlib.irradiance import campbell_norman from pvlib.irradiance import get_total_irradiance +from pvlib.solarposition import get_solarposition +from pvlib.irradiance import cloud_opacity_factor +from pvlib.irradiance import get_total_irradiance +from pvlib.irradiance import aoi from datetime import timedelta as td from datetime import timezone as timezone from datetime import datetime @@ -61,7 +65,7 @@ def setup_pv_system(month, hour_of_day): # %% -def plot_spectral_irradiance(spectra, f_dir, f_diff, latitude, day_of_year, year, clouds): +def plot_spectral_irr(spectra, f_dir, f_diff, lat, doy, year, clouds): """ Plot the results showing the spectral distribution of irradiance with and without the effects of clouds @@ -76,7 +80,7 @@ def plot_spectral_irradiance(spectra, f_dir, f_diff, latitude, day_of_year, year plt.xlim(200, 2700) plt.ylim(0, 1.8) - plt.title(r"Day {} {} latitude {} cloud cover {}".format(day_of_year, year, latitude, clouds)) + plt.title(r"Day {} {} lat {} cloud cover {}".format(doy, year, lat, clouds)) plt.ylabel(r"Irradiance ($W m^{-2} nm^{-1}$)") plt.xlabel(r"Wavelength ($nm$)") labels = ["poa_sky_diffuse", "poa_direct", "poa_global", @@ -86,15 +90,16 @@ def plot_spectral_irradiance(spectra, f_dir, f_diff, latitude, day_of_year, year plt.show() -def show_info(latitude, irradiance): +def show_info(lat: float, irr: dict): """ - Simple function to show the integrated results of the spectral distributions + Simple function to show the integrated results of the + spectral distributions """ print("{}: campbell_norman clouds: dni: {:3.2f} " - "dhi: {:3.2f} ghi: {:3.2f}".format(latitude, - float(irradiance['poa_direct']), - float(irradiance['poa_diffuse']), - float(irradiance['poa_global']))) + "dhi: {:3.2f} ghi: {:3.2f}".format(lat, + float(irr['poa_direct']), + float(irr['poa_diffuse']), + float(irr['poa_global']))) def calculate_overcast_spectrl2(): @@ -102,7 +107,8 @@ def calculate_overcast_spectrl2(): This example will loop over a range of cloud covers and latitudes (at longitude=0) for a specific date and calculate the spectral irradiance with and without accounting for clouds. Clouds are accounted for - by applying the cloud opacity factor defined in [1]. Several steps are required: + by applying the cloud opacity factor defined in [1]. Several steps + are required: 1. Calculate the atmospheric and solar conditions for the location and time 2. Calculate the spectral irradiance using `pvlib.spectrum.spectrl2` @@ -141,8 +147,9 @@ def calculate_overcast_spectrl2(): for cloud_cover in cloud_covers: for latitude in latitudes: - sol = pvlib.solarposition.get_solarposition(ctime, latitude, longitude) - airmass_relative = get_relative_airmass(sol['apparent_zenith'].to_numpy(), + sol = get_solarposition(ctime, latitude, longitude) + az = sol['apparent_zenith'].to_numpy() + airmass_relative = get_relative_airmass(az, model='kastenyoung1989') pressure = pvlib.atmosphere.alt2pres(altitude) apparent_zenith = sol['apparent_zenith'].to_numpy() @@ -150,14 +157,14 @@ def calculate_overcast_spectrl2(): surface_azimuth = pv_system['surface_azimuth'] transmittance = (1.0 - cloud_cover) * 0.75 - aoi = pvlib.irradiance.aoi(surface_tilt, surface_azimuth, apparent_zenith, azimuth) + calc_aoi = aoi(surface_tilt, surface_azimuth, apparent_zenith, azimuth) # day of year is an int64index array so access first item day_of_year = ctime.dayofyear[0] spectra = pvlib.spectrum.spectrl2( apparent_zenith=apparent_zenith, - aoi=aoi, + aoi=calc_aoi, surface_tilt=surface_tilt, ground_albedo=ground_albedo, surface_pressure=pressure, @@ -170,10 +177,12 @@ def calculate_overcast_spectrl2(): irrads_clouds = campbell_norman(sol['zenith'].to_numpy(), transmittance) - # Convert the irradiance to a plane with tilt zero horizontal to the earth. - # This is done applying tilt=0 to POA calculations using the output from - # `campbell_norman`. The POA calculations include calculating sky and ground - # diffuse light where specific models can be selected (we use default) + # Convert the irradiance to a plane with tilt zero + # horizontal to the earth. This is done applying + # tilt=0 to POA calculations using the output from + # `campbell_norman`. The POA calculations include + # calculating sky and ground diffuse light where + # specific models can be selected (we use default). poa_irr_clouds = get_total_irradiance( surface_tilt=surface_tilt, surface_azimuth=pv_system['surface_azimuth'], @@ -184,10 +193,10 @@ def calculate_overcast_spectrl2(): solar_azimuth=sol['azimuth']) show_info(latitude, poa_irr_clouds) + zen = sol['zenith'].to_numpy() + irr_clearsky = campbell_norman(zen, transmittance=0.75) - irr_clearsky = campbell_norman(sol['zenith'].to_numpy(), transmittance=0.75) - - poa_irr_clearsky = pvlib.irradiance.get_total_irradiance( + poa_irr_clearsky = get_total_irradiance( surface_tilt=surface_tilt, surface_azimuth=pv_system['surface_azimuth'], dni=irr_clearsky['dni'], @@ -198,18 +207,18 @@ def calculate_overcast_spectrl2(): show_info(latitude, poa_irr_clearsky) - f_dir, f_diff = pvlib.irradiance.cloud_opacity_factor(poa_irr_clouds['poa_direct'].values, - poa_irr_clouds['poa_diffuse'].values, - poa_irr_clouds['poa_global'].values, - spectra) - - plot_spectral_irradiance(spectra, - f_dir, - f_diff, - latitude=latitude, - day_of_year=day_of_year, - year=ctime.year[0], - clouds=cloud_cover) + f_dir, f_diff = cloud_opacity_factor(poa_irr_clouds['poa_direct'].values, + poa_irr_clouds['poa_diffuse'].values, + poa_irr_clouds['poa_global'].values, + spectra) + + plot_spectral_irr(spectra, + f_dir, + f_diff, + lat=latitude, + doy=day_of_year, + year=ctime.year[0], + clouds=cloud_cover) calculate_overcast_spectrl2() From 68ad5a29f785877ef2767aee2358e1aeeb8038f8 Mon Sep 17 00:00:00 2001 From: Trond Kristiansen Date: Wed, 24 Mar 2021 20:40:30 -0700 Subject: [PATCH 06/13] Updated to reccomendations from ci-stickler --- docs/examples/plot_spectrl2_overcast.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/docs/examples/plot_spectrl2_overcast.py b/docs/examples/plot_spectrl2_overcast.py index 33538bcce6..90e801cda5 100644 --- a/docs/examples/plot_spectrl2_overcast.py +++ b/docs/examples/plot_spectrl2_overcast.py @@ -31,7 +31,6 @@ import pvlib from pvlib.atmosphere import get_relative_airmass from pvlib.irradiance import campbell_norman -from pvlib.irradiance import get_total_irradiance from pvlib.solarposition import get_solarposition from pvlib.irradiance import cloud_opacity_factor from pvlib.irradiance import get_total_irradiance @@ -152,18 +151,18 @@ def calculate_overcast_spectrl2(): airmass_relative = get_relative_airmass(az, model='kastenyoung1989') pressure = pvlib.atmosphere.alt2pres(altitude) - apparent_zenith = sol['apparent_zenith'].to_numpy() + az = sol['apparent_zenith'].to_numpy() azimuth = sol['azimuth'].to_numpy() surface_azimuth = pv_system['surface_azimuth'] transmittance = (1.0 - cloud_cover) * 0.75 - calc_aoi = aoi(surface_tilt, surface_azimuth, apparent_zenith, azimuth) + calc_aoi = aoi(surface_tilt, surface_azimuth, az, azimuth) # day of year is an int64index array so access first item day_of_year = ctime.dayofyear[0] spectra = pvlib.spectrum.spectrl2( - apparent_zenith=apparent_zenith, + apparent_zenith=az, aoi=calc_aoi, surface_tilt=surface_tilt, ground_albedo=ground_albedo, @@ -206,10 +205,12 @@ def calculate_overcast_spectrl2(): solar_azimuth=sol['azimuth']) show_info(latitude, poa_irr_clearsky) - - f_dir, f_diff = cloud_opacity_factor(poa_irr_clouds['poa_direct'].values, - poa_irr_clouds['poa_diffuse'].values, - poa_irr_clouds['poa_global'].values, + poa_dr = poa_irr_clouds['poa_direct'].values + poa_diff = poa_irr_clouds['poa_diffuse'].values + poa_global = poa_irr_clouds['poa_global'].values + f_dir, f_diff = cloud_opacity_factor(poa_dr, + poa_diff, + poa_global, spectra) plot_spectral_irr(spectra, From 604da6dfa6d77521624029b88de951a8b2ac8221 Mon Sep 17 00:00:00 2001 From: Trond Kristiansen Date: Wed, 24 Mar 2021 20:42:40 -0700 Subject: [PATCH 07/13] Updated to reccomendations from ci-stickler - again --- docs/examples/plot_spectrl2_overcast.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/examples/plot_spectrl2_overcast.py b/docs/examples/plot_spectrl2_overcast.py index 90e801cda5..81fb340af3 100644 --- a/docs/examples/plot_spectrl2_overcast.py +++ b/docs/examples/plot_spectrl2_overcast.py @@ -70,16 +70,18 @@ def plot_spectral_irr(spectra, f_dir, f_diff, lat, doy, year, clouds): without the effects of clouds """ fig, ax = plt.subplots() - ax.plot(spectra['wavelength'], spectra["poa_sky_diffuse"][:, 0], c="r") - ax.plot(spectra['wavelength'], spectra["poa_direct"][:, 0], c="g") - ax.plot(spectra['wavelength'], spectra["poa_global"][:, 0], c="m") + wl = spectra['wavelength'] + ax.plot(wl, spectra["poa_sky_diffuse"][:, 0], c="r") + ax.plot(wl, spectra["poa_direct"][:, 0], c="g") + ax.plot(wl, spectra["poa_global"][:, 0], c="m") - ax.plot(spectra['wavelength'], f_dir[:, 0], c="r", linestyle='dashed') - ax.plot(spectra['wavelength'], f_diff[:, 0], c="y", linestyle='dashed') + ax.plot(wl, f_dir[:, 0], c="r", linestyle='dashed') + ax.plot(wl, f_diff[:, 0], c="y", linestyle='dashed') plt.xlim(200, 2700) plt.ylim(0, 1.8) - plt.title(r"Day {} {} lat {} cloud cover {}".format(doy, year, lat, clouds)) + plt.title(r"Day {} {} lat {} clouds {}".format(doy, year, + lat, clouds)) plt.ylabel(r"Irradiance ($W m^{-2} nm^{-1}$)") plt.xlabel(r"Wavelength ($nm$)") labels = ["poa_sky_diffuse", "poa_direct", "poa_global", From f11b407055e42cb47eef5f49374ae84c574b81c2 Mon Sep 17 00:00:00 2001 From: Trond Kristiansen Date: Wed, 24 Mar 2021 20:45:33 -0700 Subject: [PATCH 08/13] Updated to reccomendations from ci-stickler - again --- pvlib/irradiance.py | 52 ++++++++++++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 19 deletions(-) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index bd00e8b5df..ed384b21b1 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -35,42 +35,56 @@ def cloud_opacity_factor(irr_dif_clouds: np.ndarray, irr_ghi_clouds: np.ndarray, spectra: dict) -> (np.ndarray, np.ndarray): """ - Calculate the effect of "cloud opacity factor" on spectral irradiance under clear sky. - - First we calculate the rho fraction based on campbell_norman irradiance - with clouds converted to POA irradiance. In the paper [1] these - values are obtained from observations. The equations used for calculating cloud opacity factor - to scale the clear sky spectral estimates using spectrl2. Results can be compared with sun calculator: - https://www2.pvlighthouse.com.au/calculators/solar%20spectrum%20calculator/solar%20spectrum%20calculator.aspx + Calculate the effect of "cloud opacity factor" on spectral + irradiance under clear sky. + + First we calculate the rho fraction based on campbell_norman + irradiance with clouds converted to POA irradiance. In the + paper [1] these values are obtained from observations. The equations + used for calculating cloud opacity factor to scale the clear sky + spectral estimates using spectrl2. Results can be compared + with sun calculator: + https://www2.pvlighthouse.com.au/calculators/solar%20 + spectrum%20calculator/solar%20spectrum%20calculator.aspx Parameters ---------- irr_dif_clouds:np.ndarray - Total diffuse irradiance (poa_diffuse) estimated using pvlib.irradiance.get_total_irradiance and - pvlib.irradiance.campbell_norman irradiance with clouds (transmittance) + Total diffuse irradiance (poa_diffuse) estimated using + `pvlib.irradiance.get_total_irradiance` and + `pvlib.irradiance.campbell_norman` irradiance with clouds + (transmittance) irr_dir_clouds:np.ndarray - Total direct irradiance (poa_direct) estimated using pvlib.irradiance.get_total_irradiance and - pvlib.irradiance.campbell_norman irradiance with clouds (transmittance) + Total direct irradiance (poa_direct) estimated using + `pvlib.irradiance.get_total_irradiance` and + `pvlib.irradiance.campbell_norman` irradiance with + clouds (transmittance) irr_ghi_clouds:np.ndarray - Total direct irradiance (poa_global) estimated using pvlib.irradiance.get_total_irradiance and - pvlib.irradiance.campbell_norman irradiance with clouds (transmittance) + Total direct irradiance (poa_global) estimated + using `pvlib.irradiance.get_total_irradiance` and + `pvlib.irradiance.campbell_norman irradiance + with clouds (transmittance) spectra:np.ndarray - Spectral irradiance output from pvlib.spectrum.spectrl2 under clear-sky conditions + Spectral irradiance output from `pvlib.spectrum.spectrl2` + under clear-sky conditions Returns ------- - f_dir, f_diff spectral direct and diffuse irradiance scaled for cloudiness + f_dir, f_diff spectral direct and diffuse irradiance + scaled for cloudiness References ---------- - .. [1] Ref: Marco Ernst, Hendrik Holst, Matthias Winter, Pietro P. Altermatt, - SunCalculator: A program to calculate the angular and spectral distribution of direct and - diffuse solar radiation, Solar Energy Materials and Solar Cells, Volume 157, 2016, - Pages 913-922, + .. [1] Ref: Marco Ernst, Hendrik Holst, Matthias Winter, + Pietro P. Altermatt, + SunCalculator: A program to calculate the angular and spectral + distribution of direct and diffuse solar radiation, Solar Energy + Materials and Solar Cells, Volume 157, 2016, + Pages 913-922, """ rho = irr_dif_clouds / irr_ghi_clouds From 8a65bc6892f2c912c8ad1a8bc0eeb6101ed8f654 Mon Sep 17 00:00:00 2001 From: Trond Kristiansen Date: Wed, 24 Mar 2021 20:48:36 -0700 Subject: [PATCH 09/13] Updated to reccomendations from ci-stickler - again --- pvlib/irradiance.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index ed384b21b1..a41367442f 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -89,11 +89,12 @@ def cloud_opacity_factor(irr_dif_clouds: np.ndarray, rho = irr_dif_clouds / irr_ghi_clouds - I_diff_s = np.trapz(y=spectra['poa_sky_diffuse'][:, 0], x=spectra['wavelength']) - I_dir_s = np.trapz(y=spectra['poa_direct'][:, 0], x=spectra['wavelength']) - I_glob_s = np.trapz(y=spectra['poa_global'][:, 0], x=spectra['wavelength']) + wl = spectra['wavelength'] + irr_diff_s = np.trapz(y=spectra['poa_sky_diffuse'][:, 0], x=wl) + irr_dir_s = np.trapz(y=spectra['poa_direct'][:, 0], x=wl) + irr_glob_s = np.trapz(y=spectra['poa_global'][:, 0], x=wl) - rho_spectra = I_diff_s / I_glob_s + rho_spectra = irr_diff_s / irr_glob_s n_rho = (rho - rho_spectra) / (1 - rho_spectra) @@ -101,10 +102,11 @@ def cloud_opacity_factor(irr_dif_clouds: np.ndarray, f_diff_s = spectra['poa_sky_diffuse'][:, :] f_dir_s = spectra['poa_direct'][:, :] - f_dir = (f_dir_s / I_dir_s) * irr_dir_clouds + f_dir = (f_dir_s / irr_dir_s) * irr_dir_clouds # Diffuse light scaling factor. Equation 7 Ernst et al. 2016 - s_diff = (1 - n_rho) * (f_diff_s / I_diff_s) + n_rho * ((f_dir_s + f_diff_s) / I_glob_s) + s_diff = (1 - n_rho) * (f_diff_s / irr_diff_s) + \ + n_rho * ((f_dir_s + f_diff_s) / irr_glob_s) # Equation 8 Ernst et al. 2016 f_diff = s_diff * irr_dif_clouds From 80bfe29a9273477f8f310920c988df2be207ec6a Mon Sep 17 00:00:00 2001 From: Trond Kristiansen Date: Wed, 24 Mar 2021 20:52:33 -0700 Subject: [PATCH 10/13] Updated to reccomendations from ci-stickler - again --- pvlib/irradiance.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index a41367442f..9bc1808e36 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -105,8 +105,8 @@ def cloud_opacity_factor(irr_dif_clouds: np.ndarray, f_dir = (f_dir_s / irr_dir_s) * irr_dir_clouds # Diffuse light scaling factor. Equation 7 Ernst et al. 2016 - s_diff = (1 - n_rho) * (f_diff_s / irr_diff_s) + \ - n_rho * ((f_dir_s + f_diff_s) / irr_glob_s) + s_diff = (1 - n_rho) * (f_diff_s / irr_diff_s) + n_rho \ + * ((f_dir_s + f_diff_s) / irr_glob_s) # Equation 8 Ernst et al. 2016 f_diff = s_diff * irr_dif_clouds From d90a8df95b2275e231c75e08622e56f3e1c019ea Mon Sep 17 00:00:00 2001 From: Trond Kristiansen Date: Thu, 25 Mar 2021 09:39:32 -0700 Subject: [PATCH 11/13] Fixed E127 continuation line over-indented for visual indent --- pvlib/irradiance.py | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index 9bc1808e36..32f1c02a3f 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -105,8 +105,8 @@ def cloud_opacity_factor(irr_dif_clouds: np.ndarray, f_dir = (f_dir_s / irr_dir_s) * irr_dir_clouds # Diffuse light scaling factor. Equation 7 Ernst et al. 2016 - s_diff = (1 - n_rho) * (f_diff_s / irr_diff_s) + n_rho \ - * ((f_dir_s + f_diff_s) / irr_glob_s) + s_diff = ((1 - n_rho) * (f_diff_s / irr_diff_s) + n_rho + * ((f_dir_s + f_diff_s) / irr_glob_s)) # Equation 8 Ernst et al. 2016 f_diff = s_diff * irr_dif_clouds @@ -267,10 +267,12 @@ def aoi_projection(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth): Dot product of panel normal and solar angle. """ - projection = ( - tools.cosd(surface_tilt) * tools.cosd(solar_zenith) + - tools.sind(surface_tilt) * tools.sind(solar_zenith) * - tools.cosd(solar_azimuth - surface_azimuth)) + projection = ((tools.cosd(surface_tilt) * + tools.cosd(solar_zenith) + + tools.sind(surface_tilt) * + tools.sind(solar_zenith) * + tools.cosd(solar_azimuth - + surface_azimuth))) try: projection.name = 'aoi_projection' @@ -1509,7 +1511,8 @@ def _disc_kn(clearness_index, airmass, max_airmass=12): delta_kn = a + b * np.exp(c * am) - Knc = 0.866 - 0.122 * am + 0.0121 * am ** 2 - 0.000653 * am ** 3 + 1.4e-05 * am ** 4 + Knc = ((0.866 - 0.122 * am + 0.0121 * + am ** 2 - 0.000653 * am ** 3 + 1.4e-05 * am ** 4)) Kn = Knc - delta_kn return Kn, am @@ -2124,9 +2127,11 @@ def _gti_dirint_gte_90(poa_global, aoi, solar_zenith, solar_azimuth, cos_surface_tilt = tools.cosd(surface_tilt) # isotropic sky plus ground diffuse - dhi_gte_90 = ( - (2 * poa_global - dni_gte_90_proj * albedo * (1 - cos_surface_tilt)) / - (1 + cos_surface_tilt + albedo * (1 - cos_surface_tilt))) + dhi_gte_90 = (( + (2 * poa_global - dni_gte_90_proj * albedo + * (1 - cos_surface_tilt)) / + (1 + cos_surface_tilt + albedo + * (1 - cos_surface_tilt)))) ghi_gte_90 = dni_gte_90_proj + dhi_gte_90 From 19db0b7bc9d4edb43ad7e1d50cfbbdd6827340f3 Mon Sep 17 00:00:00 2001 From: Trond Kristiansen Date: Thu, 25 Mar 2021 09:40:35 -0700 Subject: [PATCH 12/13] Fixed E127 continuation line over-indented for visual indent --- pvlib/irradiance.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index 32f1c02a3f..bb3cbc15ce 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -2128,7 +2128,8 @@ def _gti_dirint_gte_90(poa_global, aoi, solar_zenith, solar_azimuth, # isotropic sky plus ground diffuse dhi_gte_90 = (( - (2 * poa_global - dni_gte_90_proj * albedo + (2 * poa_global - dni_gte_90_proj + * albedo * (1 - cos_surface_tilt)) / (1 + cos_surface_tilt + albedo * (1 - cos_surface_tilt)))) From 4ce600d0e4325050553ecdd91a5e8ae2dd24e3e0 Mon Sep 17 00:00:00 2001 From: Trond Kristiansen Date: Thu, 25 Mar 2021 09:41:28 -0700 Subject: [PATCH 13/13] Fixed E127 continuation line over-indented for visual indent --- pvlib/irradiance.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/pvlib/irradiance.py b/pvlib/irradiance.py index bb3cbc15ce..7ba96cedee 100644 --- a/pvlib/irradiance.py +++ b/pvlib/irradiance.py @@ -268,11 +268,11 @@ def aoi_projection(surface_tilt, surface_azimuth, solar_zenith, solar_azimuth): """ projection = ((tools.cosd(surface_tilt) * - tools.cosd(solar_zenith) + - tools.sind(surface_tilt) * - tools.sind(solar_zenith) * - tools.cosd(solar_azimuth - - surface_azimuth))) + tools.cosd(solar_zenith) + + tools.sind(surface_tilt) * + tools.sind(solar_zenith) * + tools.cosd(solar_azimuth - + surface_azimuth))) try: projection.name = 'aoi_projection' @@ -2127,12 +2127,11 @@ def _gti_dirint_gte_90(poa_global, aoi, solar_zenith, solar_azimuth, cos_surface_tilt = tools.cosd(surface_tilt) # isotropic sky plus ground diffuse - dhi_gte_90 = (( - (2 * poa_global - dni_gte_90_proj - * albedo - * (1 - cos_surface_tilt)) / - (1 + cos_surface_tilt + albedo - * (1 - cos_surface_tilt)))) + dhi_gte_90 = (((2 * poa_global - dni_gte_90_proj + * albedo + * (1 - cos_surface_tilt)) / + (1 + cos_surface_tilt + albedo + * (1 - cos_surface_tilt)))) ghi_gte_90 = dni_gte_90_proj + dhi_gte_90