Esempio n. 1
0
    def _get_custom_spectrum(self, options):
        """ Convert an custom spectrum into a solcore light source object.

        :param options: A dictionary that contains the following information:
            - 'x_data' and 'y_data' of the custom spectrum.
            - 'input_units', the units of the spectrum, such as 'photon_flux_per_nm' or 'power_density_per_eV'
        :return: A function that takes as input the wavelengths and return the custom spectrum at those wavelengths.
        """

        try:
            x_data = options['x_data']
            y_data = options['y_data']
            units = options['input_units']

            # We check the units type by type.
            # Regardless of the input, we want power_density_per_nm
            if units == 'power_density_per_nm':
                wl = x_data
                spectrum = y_data
            elif units == 'photon_flux_per_nm':
                wl = x_data
                spectrum = y_data * (c * h * 1e+9 / wl)
            elif units == 'power_density_per_eV':
                wl, spectrum = spectral_conversion_nm_ev(x_data, y_data)
            elif units == 'photon_flux_per_eV':
                wl, spectrum = spectral_conversion_nm_ev(x_data, y_data)
                spectrum = spectrum * (c * h * 1e+9 / wl)
            elif units == 'power_density_per_J':
                wl, spectrum = spectral_conversion_nm_ev(
                    x_data / q, y_data * q)
            elif units == 'photon_flux_per_J':
                wl, spectrum = spectral_conversion_nm_ev(
                    x_data / q, y_data * q)
                spectrum = spectrum * (c * h * 1e+9 / wl)
            elif units == 'power_density_per_hz':
                wl, spectrum = spectral_conversion_nm_hz(x_data, y_data)
            elif units == 'photon_flux_per_hz':
                wl, spectrum = spectral_conversion_nm_hz(x_data, y_data)
                spectrum = spectrum * (h * x_data)
            else:
                raise ValueError(
                    'Unknown units: {0}.\nValid units are: {1}.'.format(
                        units, self.output_units))

            self.x_internal = wl
            self.power_density = np.trapz(y=spectrum,
                                          x=wl) * self.options['concentration']
            output = interp1d(x=wl,
                              y=spectrum,
                              bounds_error=False,
                              fill_value=0,
                              assume_sorted=True)
            return output

        except KeyError as err:
            print(err)
Esempio n. 2
0
def test_power_density_per_ev(wavelength, gauss_spectrum):
    from solcore.light_source.light_source import power_density_per_ev
    from solcore import spectral_conversion_nm_ev

    sp, sp_fun = gauss_spectrum
    ev, expected = spectral_conversion_nm_ev(wavelength, sp)

    actual = power_density_per_ev(sp_fun, ev)
    assert actual == approx(expected)
Esempio n. 3
0
    def _get_power_density_per_eV(self, energy):
        """ Function that returns the spectrum in power density per eV.

        :param energy: Array with the energies at which to calculate the spectrum (in eV)
        :return: The spectrum in the chosen units.
        """
        wavelength = eVnm(energy)[::-1]
        output = self._spectrum(wavelength)
        energy_eV, output = spectral_conversion_nm_ev(wavelength, output)
        return output
Esempio n. 4
0
def test_photon_flux_per_joule(wavelength, gauss_spectrum):
    from solcore.light_source.light_source import photon_flux_per_joule
    from solcore import spectral_conversion_nm_ev
    from solcore.constants import q

    sp, sp_fun = gauss_spectrum
    ev, expected = spectral_conversion_nm_ev(wavelength, sp)

    actual = photon_flux_per_joule(sp_fun, ev * q)
    assert actual * q**2 * ev == approx(expected)
Esempio n. 5
0
    def _get_photon_flux_per_J(self, energy):
        """ Function that returns the spectrum in photon flux per Joule.

        :param energy: Array with the energies at which to calculate the spectrum (in J)
        :return: The spectrum in the chosen units.
        """
        wavelength = nmJ(energy)[::-1]
        output = self._spectrum(wavelength)
        energy_eV, output = spectral_conversion_nm_ev(wavelength, output)
        output = output / (q * energy)
        return output
Esempio n. 6
0
def photon_flux_per_joule(spectrum: Callable[[np.ndarray], np.ndarray], x: np.ndarray):
    """ Function that returns the spectrum in photon flux per Joule.

    The input spectrum is assumed to be in power density per nanometer.

    :param spectrum: The spectrum to interpolate.
    :param x: Array with the energies (in J)
    :return: The spectrum in the chosen units.
    """
    wavelength = nmJ(x)[::-1]
    output = spectrum(wavelength)
    _, output = spectral_conversion_nm_ev(wavelength, output)
    return output / (q * x)
Esempio n. 7
0
def power_density_per_ev(spectrum: Callable[[np.ndarray], np.ndarray], x: np.ndarray):
    """ Function that returns the spectrum in power density per eV.

    The input spectrum is assumed to be in power density per nanometer.

    :param spectrum: The spectrum to interpolate.
    :param x: Array with the energies (in eV)
    :return: The spectrum in the chosen units.
    """
    wavelength = eVnm(x)[::-1]
    output = spectrum(wavelength)
    _, output = spectral_conversion_nm_ev(wavelength, output)
    return output
Esempio n. 8
0
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