Пример #1
0
def add_solar(netCDFfile):
    ds = Dataset(netCDFfile, 'a')

    lat = ds.variables['LATITUDE'][:]
    lon = ds.variables['LONGITUDE'][:]

    print('lat ', lat, ' lon ', lon)

    time = ds.variables['TIME']
    dt = num2date(time[:], units=time.units, calendar=time.calendar)

    dt_utc = [d.replace(tzinfo=pytz.UTC) for d in dt]

    print('time ', dt_utc[0])

    altitude_deg = [get_altitude(lat, lon, d) for d in dt_utc]
    rad = [extraterrestrial_irrad(lat, lon, d, 1370) for d in dt_utc]

    print("altitude", altitude_deg[0], " rad ", rad[0])

    ncVarOut = ds.createVariable(
        "SOLAR", "f4", ("TIME", ), fill_value=np.nan,
        zlib=True)  # fill_value=nan otherwise defaults to max
    ncVarOut[:] = rad
    ncVarOut.units = "W/m2"
    ncVarOut.setncattr(
        'name', 'extraterrestrial_irrad celestial incoming solar radiation')
    ncVarOut.long_name = 'incoming_solar_radiation'
    ncVarOut.comment = "using http://docs.pysolar.org/en/latest/ v0.8 extraterrestrial_irrad() with incoming = 1370 W/m^2"

    # update the history attribute
    try:
        hist = ds.history + "\n"
    except AttributeError:
        hist = ""

    ds.setncattr(
        'history', hist + datetime.utcnow().strftime("%Y-%m-%d") +
        " : added incoming radiation")

    ds.close()
Пример #2
0
    def test_util_extraterrestrial_irrad_no_error(self):
        try:
            util.extraterrestrial_irrad(self.lat, self.lon, self.aware)
        except NoTimeZoneInfoError:
            self.fail("""'NoTimeZoneInfoError' should not be raised \
as 'datetime' object is tz-aware.""")
Пример #3
0
 def test_util_extraterrestrial_irrad_raise_error(self):
     with self.assertRaises(NoTimeZoneInfoError):
         util.extraterrestrial_irrad(self.lat, self.lon, self.unaware)
Пример #4
0
    def calc_vis_spectral(self, when: datetime.datetime, temperature: float,
                          relative_humidity: float, tau500: float):

        if temperature < 1:
            temperature = 1

        solar_altitude_deg = solar.get_altitude(self.latitude,
                                                self.longitude,
                                                when,
                                                elevation=self.elevation,
                                                pressure=self.pressure,
                                                temperature=temperature)

        zenref = 90 - abs(solar_altitude_deg)

        if zenref > 90:
            print("Zenref greater than 90 wtf!!! : {}".format(zenref))
            return np.zeros(self.n_wvls + 1, dtype=np.float64)
        # tricky! the way that extraterrestrial_irrad is calculated is by getting the erv.
        etr_total = util.extraterrestrial_irrad(self.latitude,
                                                self.longitude,
                                                when=when)
        if when.hour == 12 and when.minute == 0:
            print(when, "\t", temperature, "\t", relative_humidity, "\t",
                  etr_total)
        erv = etr_total / 1367.0
        # these are almost identical. DO NOT OPT FOR PYSOLAR UNTIL THEY HAVE IMPLEMENTED
        # Airmass Kasten, F. and Young, A. 1989. Revised optical air mass tables
        # amass = radiation.get_air_mass_ratio(altitude_deg=solar_altitude_deg)

        amass = 1.0 / np.cos(np.radians(zenref)) + 0.50572 * pow(
            96.07995 - zenref, -1.6364)

        ampress = amass * (self.pressure / 1.013e6)

        O3 = self.calc_ozone(int(when.timetuple().tm_yday))

        watvap = self.prec_h2o_estimate(temperature, relative_humidity)

        cz = np.cos(np.radians(zenref))

        # Ozone mass
        ozone_mass = 1.003454 / np.sqrt((pow(cz, 2)) + 0.006908)

        if not 0 <= abs(solar_altitude_deg) <= 90:
            # print("NIGHTTIME : {}".format(solar_altitude_deg))
            # print("Solar alt out of range!!! : {}".format(solar_altitude_deg))
            # print(when, self.pressure, temperature, solar_altitude_deg, amass)
            return np.zeros(self.n_wvls + 1, dtype=np.float64)

        if not 0 <= amass < 1000:
            print("NIGHTTIME : {}".format(solar_altitude_deg))
            print("Solar alt out of range!!! : {}".format(solar_altitude_deg))
            return np.zeros(self.n_wvls + 1, dtype=np.float64)

        def calc(wvl):
            etr_spec, watvap_coeff, ozone_absorb_coeff, unif_mix_gas_ab_coeff = coeff_spline(
                wvl)
            watvap_coeff = max(watvap_coeff, 0.0)
            ozone_absorb_coeff = max(ozone_absorb_coeff, 0.0)
            unif_mix_gas_ab_coeff = max(unif_mix_gas_ab_coeff, 0.0)
            etr_spec = max(etr_spec, 0.0)
            etr = etr_spec * erv

            # omegl = OMEG * np.exp(-OMEGP * (np.log(wvl / 0.4) * np.log(wvl / 0.4)))
            c1 = tau500 * pow(wvl * 2.0, -self.alpha)
            # Equation 2-4
            Tr = np.exp(-ampress / (pow(wvl, 4) *
                                    (115.6406 - 1.3366 / pow(wvl, 2))))
            # Equation 2-9
            To = np.exp(-ozone_absorb_coeff * O3 * ozone_mass)
            # Equation 2-8

            tw_v = 1.0 + 20.07 * watvap_coeff * watvap * ampress

            Tw = np.exp(-0.2385 * watvap_coeff * watvap * ampress /
                        pow(tw_v, 0.45))

            # Equation 2-11
            # cast to float makes this value real enough for numpy
            Tu = np.exp(
                -1.41 * unif_mix_gas_ab_coeff * ampress /
                pow(1.0 + 118.3 * unif_mix_gas_ab_coeff * ampress, 0.45))
            # Equation 2-6, sort of
            Ta = np.exp(-c1 * ampress)
            # ........... Direct energy .............
            # Temporary variable
            c2 = etr * To * Tw * Tu
            # Equation 2-1
            direct = c2 * Tr * Ta
            return direct

        vectorized_calc = np.vectorize(calc)

        direct_spec = vectorized_calc(self.wavelengths)

        def integrate(wl_delta, direct, prev_direct):
            return wl_delta * (direct + prev_direct)

        vectorized_integrate = np.vectorize(integrate)
        integrated_d = vectorized_integrate(
            np.append([0], np.diff(self.wavelengths)), direct_spec,
            np.append([0], direct_spec[:-1]))
        return np.append([etr_total], integrated_d)
Пример #5
0
    def calc_vis_spectral_from_array(self, when: datetime.datetime,
                                     temperature, relative_humidity, tau500):

        solar_altitude_deg = solar.get_altitude(self.latitude,
                                                self.longitude,
                                                when,
                                                elevation=self.elevation,
                                                pressure=self.pressure,
                                                temperature=temperature)

        if solar_altitude_deg < 0:
            # print("NIGHTTIME : {}".format(solar_altitude_deg))
            return np.zeros(41, dtype=np.float64)

        zenref = 90 - abs(solar_altitude_deg)

        if zenref > 90:
            print("Zenref greater than 90 wtf!!! : {}".format(zenref))
            return np.zeros(41, dtype=np.float64)

        # tricky! the way that extraterrestrial_irrad is calculated is by getting the erv.
        etr_total = util.extraterrestrial_irrad(self.latitude, self.longitude,
                                                when)
        erv = etr_total / 1367.0

        # these are almost identical. opt for pysolar
        amass = radiation.get_air_mass_ratio(altitude_deg=solar_altitude_deg)
        # amass = 1.0 / np.cos(np.radians(zenref)) + 0.50572 * pow(96.07995 - zenref, -1.6364)

        ampress = amass * self.pressure / 1013000
        if amass < 0:
            print(amass, solar_altitude_deg)

        O3 = self.calc_ozone(int(when.timetuple().tm_yday))

        watvap = self.prec_h2o_estimate(temperature, relative_humidity)

        # spectra array
        spec = np.zeros((122, 5))
        # this array should function as the following 5
        # wavelength
        # delta
        # direct
        # integrated direct
        # etr

        # copy wavelengths
        spec[:, 0] = WAVELENGTH_MICRONS[:]

        # delta between wavlengths
        for idx, (wl1, wl2) in enumerate(zip(spec[:-1, 0], spec[1:, 0])):
            spec[idx + 1, 1] = 0.5 * abs(wl2 - wl1)

        cz = np.cos(np.radians(zenref))

        # Ozone mass
        ozone_mass = 1.003454 / np.sqrt((cz * cz) + 0.006908)

        for idx, (wvl, delta, direct, direct_integrated,
                  etr) in enumerate(spec):
            etr = ETR_SPECTRUM[idx] * erv
            spec[idx, -1] = etr
            watvap_coeff = WATER_VAPOR_COEFF[idx]
            ozone_absorb_coeff = OZONE_ABSORBTION_COEFF[idx]
            unif_mix_gas_ab_coeff = UNIFORMLY_MIXED_GAS_ABSORBTION_COEFF[idx]

            # omegl = OMEG * np.exp(-OMEGP * (np.log(wvl / 0.4) * np.log(wvl / 0.4)))
            c1 = tau500 * pow(wvl * 2.0, -self.alpha)
            # Equation 2-4
            Tr = np.exp(-ampress / ((wvl * wvl * wvl * wvl) *
                                    (115.6406 - 1.3366 / (wvl * wvl))))
            # Equation 2-9
            To = np.exp(-ozone_absorb_coeff * O3 * ozone_mass)
            # Equation 2-8
            tw_v = float(1.0 + 20.07 * watvap_coeff * watvap * ampress)

            Tw = np.exp(-0.2385 * watvap_coeff * watvap * ampress /
                        pow(tw_v, 0.45))
            # print(tw_v, Tw)

            # Equation 2-11
            # cast to float makes this value real enough for numpy
            Tu = np.exp(
                -1.41 * unif_mix_gas_ab_coeff * ampress /
                pow(1.0 + 118.3 * unif_mix_gas_ab_coeff * ampress, 0.45))
            # Equation 2-6, sort of
            Ta = np.exp(-c1 * ampress)
            # ........... Direct energy .............
            # Temporary variable
            c2 = etr * To * Tw * Tu
            # Equation 2-1
            direct = c2 * Tr * Ta
            spec[idx, 2] = direct

            # direct integration
            direct_integrated = delta * (direct + spec[max(idx - 1, 0), 2])

            spec[idx, 3] = direct_integrated
            # prevdirect = direct

        # these probably arent needed.
        # totdirect = np.sum(spec[:, 3])
        # totvis = np.sum(np.clip(spec[14:55, 3], 0.0, np.inf))
        # visible_integration = spec[14:55, 3]
        # visble_wavelength_microns = WAVELENGTH_MICRONS[14:55]
        # trad = np.sum(np.clip(spec[:, 2], 0.0, np.inf))
        # # spec[:, 2] /= (solar_irradiance * trad)
        # vrad = spec[14:55, 2]

        # etr = util.extraterrestrial_irrad(self.latitude, self.longitude, when)
        # only return direct and visible
        return np.append([etr_total] + spec[14:55, 3])
Пример #6
0
def add_solar(netCDFfiles):
    # add incoming radiation

    out_files = []

    for fn in netCDFfiles:
        # Change the creation date in the filename to today
        now = datetime.utcnow()

        fn_new = fn
        if os.path.basename(fn).startswith("IMOS_"):
            fn_new_split = os.path.basename(fn).split('_')
            fn_new_split[-1] = "C-" + now.strftime("%Y%m%d") + ".nc"

            fn_new = os.path.join(os.path.dirname(fn), '_'.join(fn_new_split))

        # If a new (different) filename has been successfully generated, make
        # a copy of the old file with the new name
        if fn_new != fn:
            print('copying file to ', fn_new)
            # copy file
            shutil.copy(fn, fn_new)

        out_files.append(fn_new)

        ds = Dataset(fn_new, 'a')

        lat = ds.variables['LATITUDE'][:]
        lon = ds.variables['LONGITUDE'][:]
        ndepth = ds.variables['NOMINAL_DEPTH'][:]

        print('lat ', lat, ' lon ', lon)

        time_var = ds.variables['TIME']

        print('number of points ', len(time_var))
        dt = num2date(time_var[:],
                      units=time_var.units,
                      calendar=time_var.calendar,
                      only_use_cftime_datetimes=False)

        dt_utc = [d.replace(tzinfo=pytz.UTC) for d in dt]

        print('time start ', dt_utc[0])

        altitude_deg = get_altitude_fast(lat, lon, dt)
        rad = extraterrestrial_irrad(lat, lon, dt, 1361)

        if ndepth > 0:
            #depth_var = ds.variables['PRES']
            #depth = depth_var[:]
            depth = np.ones_like(rad) * ndepth
            par = rad * np.exp(-0.04 * depth) * 2.114
        else:
            par = rad * 2.114

        print("altitude", altitude_deg[0], " rad ", rad[0])

        if 'ALT' in ds.variables:
            ncVarOut = ds.variables["ALT"]
        else:
            ncVarOut = ds.createVariable(
                "ALT", "f4", ("TIME", ), fill_value=np.nan,
                zlib=True)  # fill_value=nan otherwise defaults to max

        ncVarOut[:] = altitude_deg
        ncVarOut.units = "degree"
        ncVarOut.long_name = 'sun_altitude'
        ncVarOut.coordinates = 'TIME LATITUDE LONGITUDE NOMINAL_DEPTH'
        ncVarOut.comment = "using http://docs.pysolar.org/en/latest/ v0.8 get_altitude"

        if 'SOLAR' in ds.variables:
            ncVarOut = ds.variables["SOLAR"]
        else:
            ncVarOut = ds.createVariable(
                "SOLAR", "f4", ("TIME", ), fill_value=np.nan,
                zlib=True)  # fill_value=nan otherwise defaults to max

        ncVarOut[:] = rad
        ncVarOut.units = "W/m2"
        ncVarOut.long_name = 'incoming_solar_radiation'
        ncVarOut.coordinates = 'TIME LATITUDE LONGITUDE NOMINAL_DEPTH'
        ncVarOut.comment = "using http://docs.pysolar.org/en/latest/ v0.8 extraterrestrial_irrad() with incoming = 1361 W/m^2"

        if 'ePAR' in ds.variables:
            ncVarOut = ds.variables["ePAR"]
        else:
            ncVarOut = ds.createVariable(
                "ePAR", "f4", ("TIME", ), fill_value=np.nan,
                zlib=True)  # fill_value=nan otherwise defaults to max

        ncVarOut[:] = par
        ncVarOut.units = "umol/m^2/s"
        ncVarOut.long_name = 'incoming_solar_radiation converted to PAR (x2.114) attenuated by depth'
        ncVarOut.coordinates = 'TIME LATITUDE LONGITUDE NOMINAL_DEPTH'
        ncVarOut.comment = "using http://docs.pysolar.org/en/latest/ v0.8 extraterrestrial_irrad() with incoming = 1361 W/m^2, x 2.114, kd = 0.04"

        # update the history attribute
        try:
            hist = ds.history + "\n"
        except AttributeError:
            hist = ""

        ds.setncattr(
            'history', hist + datetime.utcnow().strftime("%Y-%m-%d") +
            " : added incoming radiation")

        ds.close()

    return out_files