Source code for solcore.light_source.spectral2

import numpy
from numpy import *
from datetime import datetime
from solcore import spectral_conversion_nm_ev
from solcore.science_tracker import science_reference
import os

this_dir = os.path.split(__file__)[0]


[docs]def equation_of_time(day_angle): value = 229.18 * (0.000075 + 0.001868 * cos(day_angle) - 0.032077 * sin(day_angle) - 0.014615 * cos(2 * day_angle) - 0.040849 * sin(2 * day_angle)) return value
[docs]def loadUtilitySpectra(): global am_zero_wavelength, am_zero_irradiance, waterspectra, ozonespectra, uniformgasspectra spctra = numpy.loadtxt(os.path.join(this_dir, "SPCTRAL_si_units.txt"), unpack=True) (am_zero_wavelength, am_zero_irradiance, waterspectra, ozonespectra, uniformgasspectra) \ = spctra waterspectra = waterspectra / 100 ozonespectra = ozonespectra / 100
loadUtilitySpectra()
[docs]def get_default_spectral2_object(): """ Returns a default state object for use with calculate_spectrum. Parameters returned are for: - Coventry (52.39°N,-1.56°E) - for 12:30 pm on the 30th of June 2011 (that's in the future!) (not any more..) - rural atmospheric conditions - 30% humidity - 1.42mm precipitated water - 1030 hPa atmospheric pressure - 0.34mm of Ozone - turbidity of 15%. """ defaults = {} defaults["latitude"] = 52.39 / 180 * numpy.pi # Coventry defaults["longitude"] = -1.56 / 180 * numpy.pi defaults["dateAndTime"] = datetime(2011, 6, 30, 12, 30) # 12:30pm, 30th of June 2011 defaults["aod_model"] = "rural" defaults["pressure"] = 103000.0 # si("1030 hPa") #si ("1 atm") defaults["humidity"] = 0.3 # si("30 %") defaults["precipwater"] = 0.00142 # si("1.42 mm") # unit? defaults["ozone"] = 0.00034 # si("0.34 mm") # unit? defaults["turbidity"] = 0.15 # unit? defaults["display units"] = { "pressure": ("hPa", 0), "latitude": (u"degrees", 3), "longitude": (u"degrees", 3), "precipwater": ("cm", 3), "ozone": ("cm", 3), "humidity": ("%", 1), } return defaults
[docs]def calculate_spectrum_spectral2(stateObject=None, suppress_nan=True, power_density_in_nm=False): """ Calculates a solar spectrum using the SPECTRAL2 irradiance model developed by the NRL: "http://rredc.nrel.gov/solar/models/spectral/SPCTRAL2/" :param stateObject: :param suppress_nan: :return: """ science_reference("spectral2 irradiance model", "http://rredc.nrel.gov/solar/models/spectral/SPCTRAL2/") if stateObject == None: stateObject = get_default_spectral2_object() latitude = stateObject["latitude"] longitude = stateObject["longitude"] dateAndTime = stateObject["dateAndTime"] aod_model = stateObject["aod_model"] pressure = stateObject["pressure"] humidity = stateObject["humidity"] ozone = stateObject["ozone"] turbidity = stateObject["turbidity"] precipwater = stateObject["precipwater"] assert aod_model in "rural urban maritime tropospheric".split(), "aod_model must be rural, urban, maritime, or tropospheric" time_since_new_years = dateAndTime - datetime(dateAndTime.year, 1, 1, 0, 0) # 1/1/year, 0:00 am. time_since_midnight = dateAndTime - datetime(dateAndTime.year, dateAndTime.month, dateAndTime.day, 0, 0) # hours_since_midnight = time_since_midnight.seconds / convert(time_since_midnight.seconds, "s", "h") hours_since_midnight = time_since_midnight.seconds / 3600 day_number = time_since_new_years.days # converting back go degrees for longitude rounding longitude_degrees = longitude / numpy.pi * 180 # convert(longitude,"radians",u"degrees") day_angle = (2.0 * pi * (day_number - 1.0)) / 365.0 # this is in radians hour_angle_degrees = 15.0 * (hours_since_midnight + equation_of_time(day_angle) / 60.0 + ((int(longitude_degrees / 15.0) * 15.0 - longitude_degrees) * 4.0) / 60.0 + 12.0) - 360.0 # this is in degrees. hour_angle = hour_angle_degrees / 180 * numpy.pi # convert(hour_angle_degrees, "degrees", "radians") declination = ( 0.006918 - 0.399912 * cos(day_angle) + 0.070257 * sin(day_angle) - 0.006758 * cos(2 * day_angle) + 0.000907 * sin(2 * day_angle) - 0.002697 * cos(3 * day_angle) + 0.00148 * sin(3 * day_angle) ) earth_sun_distance_factor = ( 1.00011 + 0.034221 * cos(day_angle) + 0.001280 * sin(day_angle) + 0.000719 * cos(2 * day_angle) + 0.000077 * sin(2 * day_angle) ) solar_zenith_angle = arccos( cos(declination) * cos(latitude) * cos(hour_angle) + sin(declination) * sin(latitude) ) solar_zenith_angle_degrees = solar_zenith_angle / pi * 180 # convert(solar_zenith_angle,"radians",u'degrees') # original code checked to stop sun dropping below horizon # //Stop sun dropping below horizon # if(solar_zenith_angle > 91) # solar_zenith_angle = 91; (was in degrees) # this used to be 1/ could this cause issues in java? relative_am = 1.0 / (cos(solar_zenith_angle) + ( 0.15 * pow((93.885 - solar_zenith_angle_degrees), -1.253))) ##AARG raised to the power of degrees pressure_corrected_am = relative_am * (pressure / 101325.33538686013) # si("1 atm") effective_ozone_am = (1.0 + (22.0 / 6370.0)) / ( pow((pow(cos(solar_zenith_angle), 2.0) + (2.0 * (22.0 / 6370.0))), 0.5)) if aod_model == "rural": c_coefficient = [0.581, 16.823, 17.539] d_coefficient = [0.8547, 78.696, 0, 64.458] elif aod_model == "rural": c_coefficient = [0.2595, 33.843, 39.524] d_coefficient = [1.0, 84.254, -9.1, 65.458] elif aod_model == "maritime": c_coefficient = [0.1134, 0.8941, 1.0796] d_coefficient = [0.04435, 1.6048, 0, 1.5298]; elif aod_model == "tropospheric": c_coefficient = [0.6786, 13.899, 13.313] d_coefficient = [1.8379, 14.912, 0, 5.96] elif type(aod_model) == list: c_coefficient, d_coefficient = aod_model # 0.9 degrees * something_in_percent rather than 90 degrees?? Honestly. x_humidity = cos(humidity * pi / 2.) # si(0.9,"degrees","radians") alpha1 = (c_coefficient[0] + c_coefficient[1] * x_humidity) / (1 + c_coefficient[2] * x_humidity) alpha2 = (d_coefficient[0] + d_coefficient[1] * x_humidity + d_coefficient[2] * x_humidity ** 2) / ( 1 + (d_coefficient[3] * x_humidity)) wavelength_um = am_zero_wavelength * 1e6 # convert(am_zero_wavelength, "m", 'um') rayleigh_coeff = exp(-pressure_corrected_am / (wavelength_um ** 4 * (115.6406 - 1.335 / wavelength_um ** 2))) aerosol_coeff = where(wavelength_um <= 0.5, exp(-pressure_corrected_am * turbidity * 2.0 ** (alpha2 - alpha1) * wavelength_um ** -alpha1), exp(-pressure_corrected_am * turbidity * wavelength_um ** -alpha2) ) vapour_coeff = exp(-(0.2385 * precipwater * waterspectra * relative_am) / (1. + 20.07 * precipwater * waterspectra * relative_am) ** 0.45) ozone_coeff = exp(-ozonespectra * ozone * effective_ozone_am) mixed_coeff = exp((-1.41 * uniformgasspectra * pressure_corrected_am) / (1. + 118.93 * uniformgasspectra * pressure_corrected_am) ** 0.45); # Apply attenuation/scatting coefficients to the per m specturm (SI wavelength spectrum) wavelength_m = am_zero_wavelength irradiance_per_m = am_zero_irradiance * earth_sun_distance_factor * rayleigh_coeff * aerosol_coeff * vapour_coeff * ozone_coeff * mixed_coeff if suppress_nan: irradiance_per_m = numpy.nan_to_num(irradiance_per_m) storage = dict() # Convert to per nm spectrum wavelength_nm = wavelength_m * 1e9 # asUnit(wavelength_m,"nm") irradiance_per_nm = 1e-9 * irradiance_per_m # asUnit(irradiance_per_m,"nm-1") if power_density_in_nm: storage = wavelength_nm, irradiance_per_nm else: # Convert to per eV spectrum energy_ev, irradiance_per_ev = spectral_conversion_nm_ev(wavelength_nm, irradiance_per_nm) # Covert to energy per Joule spectrum energy_j = energy_ev * 1.6e-19 # siUnits(energy_ev, 'J') irradiance_per_j = irradiance_per_ev / 1.6e-19 # siUnits(irradiance_per_ev, 'J-1') # integrate to find power density power_density = trapz(x=wavelength_m, y=irradiance_per_m) storage['incident power density'] = power_density storage['incident spectrum wavelength si'] = array([wavelength_m, irradiance_per_m]) storage['incident spectrum wavelength nm'] = array([wavelength_nm, irradiance_per_nm]) storage['incident spectrum energy si'] = array([energy_j, irradiance_per_j]) storage['incident spectrum energy eV'] = array([energy_ev, irradiance_per_ev]) return storage
if __name__ == "__main__": data = calculate_spectrum_spectral2() import matplotlib.pyplot as plt plt.plot(data['incident spectrum wavelength nm'][0], data['incident spectrum wavelength nm'][1]) plt.show()