Source code for farms.farms

"""
Created on Fri June 1 2015
FAST Model
Adapted from Yu Xie IDL Fast Radiative Transfer Model
@author: Anthony Lopez

This Fast All-sky Radiation Model for Solar applications (FARMS) was developed
by Yu Xie (Yu.Xie@nrel.gov). Please contact him for more information.

Literature
----------
[1] Yu Xie, Manajit Sengupta, Jimy Dudhia, "A Fast All-sky Radiation Model
    for Solar applications (FARMS): Algorithm and performance evaluation",
    Solar Energy, Volume 135, 2016, Pages 435-445, ISSN 0038-092X,
    https://doi.org/10.1016/j.solener.2016.06.003.
    (http://www.sciencedirect.com/science/article/pii/S0038092X16301827)
"""
import collections
import numpy as np

from farms import CLEAR_TYPES, ICE_TYPES, WATER_TYPES, SOLAR_CONSTANT
import farms.utilities as ut
from farms import farms_dni


[docs]def water_phase(tau, De, solar_zenith_angle): """Get cloudy Tducld and Ruucld for the water phase.""" # enforce water phase particle size between 5 and 120 micron # as per advice from yu xie De = np.maximum(De, 5) De = np.minimum(De, 120) # 12a from [1] Ptau = (2.8850 + 0.002 * (De - 60.0)) * solar_zenith_angle - 0.007347 # 12b from [1] PDHI = (0.7846 * (1.0 + 0.0002 * (De - 60.0)) * np.power(solar_zenith_angle, 0.1605)) # 12c from [1] delta = (-0.644531 * solar_zenith_angle + 1.20117 + 0.129807 / solar_zenith_angle - 0.00121096 / (solar_zenith_angle * solar_zenith_angle) + 1.52587e-07 / (solar_zenith_angle * solar_zenith_angle * solar_zenith_angle)) # part of 12d from [1] y = 0.012 * (tau - Ptau) * solar_zenith_angle # 11 from [1] Tducld = ((1.0 + np.sinh(y)) * PDHI * np.exp(-(np.power(np.log10(tau) - np.log10(Ptau), 2.0)) / delta)) # 14a from [1] Ruucld = np.where(tau < 1.0, 0.107359 * tau, 1.03 - np.exp(-(0.5 + np.log10(tau)) * (0.5 + np.log10(tau)) / 3.105)) return Tducld, Ruucld
[docs]def ice_phase(tau, De, solar_zenith_angle): """Get cloudy Tducld and Ruucld for the ice phase.""" # enforce ice phase particle size between 5 and 140 micron # as per advice from yu xie De = np.maximum(De, 5) De = np.minimum(De, 140) # 13a from [1] Ptau = np.where(De <= 26.0, 2.8487 * solar_zenith_angle - 0.0029, ((2.8355 + (100.0 - De) * 0.006) * solar_zenith_angle - 0.00612)) # 13b from [1] PDHI = 0.756 * np.power(solar_zenith_angle, 0.0883) # 13c from [1] delta = (-0.0549531 * solar_zenith_angle + 0.617632 + (0.17876 / solar_zenith_angle) - (0.002174 / solar_zenith_angle ** 2)) # part of 13c from [1] y = 0.01 * (tau - Ptau) * solar_zenith_angle # 11 from [1] Tducld = ((1.0 + np.sinh(y)) * PDHI * np.exp(-(np.power(np.log10(tau) - np.log10(Ptau), 2.0)) / delta)) # 14b from [1] Ruucld = np.where(tau < 1.0, 0.094039 * tau, 1.02 - np.exp(-(0.5 + np.log10(tau)) * (0.5 + np.log10(tau)) / 3.25)) return Tducld, Ruucld
[docs]def farms(tau, cloud_type, cloud_effective_radius, solar_zenith_angle, radius, Tuuclr, Ruuclr, Tddclr, Tduclr, albedo, debug=False): """Fast All-sky Radiation Model for Solar applications (FARMS). Literature ---------- [1] Yu Xie, Manajit Sengupta, Jimy Dudhia, "A Fast All-sky Radiation Model for Solar applications (FARMS): Algorithm and performance evaluation", Solar Energy, Volume 135, 2016, Pages 435-445, ISSN 0038-092X, https://doi.org/10.1016/j.solener.2016.06.003. (http://www.sciencedirect.com/science/article/pii/S0038092X16301827) Variables --------- F0 Radiative flux at top of atmosphere Fd Direct solar flux in the downwelling direction at the surface (eq 2a from [1]) De Effective cloud particle size (diameter). Parameters ---------- tau : np.ndarray Cloud optical thickness (cld_opd_dcomp) (unitless). cloud_type : np.ndarray Integer values representing different cloud types https://github.nrel.gov/PXS/pxs/wiki/Cloud-Classification cloud_effective_radius : np.ndarray Cloud effective particle radius (cld_reff_dcomp) (micron). solar_zenith_angle : np.ndarray Solar zenith angle (degrees). Must represent the average value over the integration period (e.g. hourly) under scrutiny. radius : np.ndarray Sun-earth radius vector, varies between 1.017 in July and 0.983 in January. Tuuclr : np.ndarray Transmittance of the clear-sky atmosphere for diffuse incident and diffuse outgoing fluxes (uu). ***Calculated from multiple REST2 runs at different solar angles. Average of Tddclr w different solar angles (see eq 5 from [1]). Ruuclr : np.ndarray Calculated in REST2. Aerosol reflectance for diffuse fluxes. Tddclr : np.ndarray Calculated in REST2. Transmittance of the clear-sky atmosphere for direct incident and direct outgoing fluxes (dd). Tddclr = dni / etdirn Tduclr : np.ndarray Calculated in REST2. Transmittance of the clear-sky atmosphere for direct incident and diffuse outgoing fluxes (du). Tduclr = dhi / (etdirn * cosz) albedo : np.ndarray Ground albedo. debug : bool Flag to output additional transmission/reflectance variables. Returns ------- If debug == True: fast_data : collections.namedtuple Named tuple with irradiance data with the following attributes: ghi : np.ndarray global horizontal irradiance (W/m2) dni : np.ndarray direct normal irradiance (W/m2) dhi : np.ndarray diffuse horizontal irradiance (W/m2) Ruucld : np.ndarray Aerosol reflectance for diffuse fluxes for cloudy atmosphere. Tddcld : np.ndarray Transmittance of the cloudy atmosphere for direct incident and direct outgoing fluxes (dd). Tducld : np.ndarray Transmittance of the cloudy atmosphere for direct incident and diffuse outgoing fluxes (du). else: ghi: np.ndarray Global horizontal irradiance (W/m2) dni_farmsdni: np.ndarray DNI computed by FARMS-DNI (W/m2). dni0: np.ndarray DNI computed by the Lambert law (W/m2). It only includes the narrow beam in the circumsolar region. """ # disable divide by zero warnings np.seterr(divide='ignore') ut.check_range(Tddclr, 'Tddclr') ut.check_range(Tduclr, 'Tduclr') ut.check_range(Ruuclr, 'Ruuclr') ut.check_range(Tuuclr, 'Tuuclr') ut.check_range(tau, 'tau (cld_opd_dcomp)', rang=(0, 160)) F0 = SOLAR_CONSTANT / (radius * radius) solar_zenith_angle = np.cos(np.radians(solar_zenith_angle)) phase = np.zeros_like(cloud_type) phase[np.in1d(cloud_type, WATER_TYPES).reshape(cloud_type.shape)] = 1 phase[np.in1d(cloud_type, ICE_TYPES).reshape(cloud_type.shape)] = 2 phase1 = np.where(phase == 1) phase2 = np.where(phase == 2) De = 2.0 * cloud_effective_radius Tducld = np.zeros_like(tau) Ruucld = np.zeros_like(tau) Tducld[phase1], Ruucld[phase1] = water_phase(tau[phase1], De[phase1], solar_zenith_angle[phase1]) Tducld[phase2], Ruucld[phase2] = ice_phase(tau[phase2], De[phase2], solar_zenith_angle[phase2]) # eq 8 from [1] Tddcld = np.exp(-tau / solar_zenith_angle) Fd = solar_zenith_angle * F0 * Tddcld * Tddclr # eq 2a from [1] F1 = solar_zenith_angle * F0 * (Tddcld * (Tddclr + Tduclr) + Tducld * Tuuclr) # eq 3 from [1] # ghi eqn 6 from [1] ghi = F1 / (1.0 - albedo * (Ruuclr + Ruucld * Tuuclr * Tuuclr)) dni = Fd / solar_zenith_angle # eq 2b from [1] dhi = ghi - Fd # eq 7 from [1] Fd, dni_farmsdni, dni0 = farms_dni.farms_dni(F0, tau, solar_zenith_angle, De, phase, phase1, phase2, Tddclr, ghi, F1) clear_mask = np.in1d(cloud_type, CLEAR_TYPES).reshape(cloud_type.shape) if debug: # Return NaN if clear-sky, else return cloudy sky data fast_data = collections.namedtuple('fast_data', ['ghi', 'dni', 'dhi', 'Tddcld', 'Tducld', 'Ruucld']) fast_data.Tddcld = np.where(clear_mask, np.nan, Tddcld) fast_data.Tducld = np.where(clear_mask, np.nan, Tducld) fast_data.Ruucld = np.where(clear_mask, np.nan, Ruucld) fast_data.ghi = np.where(clear_mask, np.nan, ghi) fast_data.dni = np.where(clear_mask, np.nan, dni) fast_data.dhi = np.where(clear_mask, np.nan, dhi) return fast_data else: out = (np.where(clear_mask, np.nan, ghi), np.where(clear_mask, np.nan, dni_farmsdni), np.where(clear_mask, np.nan, dni0)) return out