예제 #1
0
    def stageData(self, m):

        # Get the observational data
        obs = Variable(filename=self.source,
                       variable_name=self.variable,
                       alternate_vars=self.alternate_vars)

        # Reduce the sites
        if self.map:
            obs.lat = obs.lat[self.map]
            obs.lon = obs.lon[self.map]
            obs.depth = obs.depth[self.map]
            obs.data = obs.data[:, self.map]
            obs.ndata = len(self.map)

        # Get the model result
        force_emulation = self.keywords.get("force_emulation",
                                            "False").lower() == "true"
        never_emulation = self.keywords.get("never_emulation",
                                            "False").lower() == "true"
        no_co2 = False
        mod = None
        if not force_emulation:
            try:
                #print "Trying to get co2 from %s" % m.name
                mod = m.extractTimeSeries(
                    self.variable,
                    alt_vars=self.alternate_vars,
                    initial_time=obs.time_bnds[0, 0],
                    final_time=obs.time_bnds[-1, 1],
                    lats=None if obs.spatial else obs.lat,
                    lons=None if obs.spatial else obs.lon)
            except il.VarNotInModel:
                #print "co2 not in %s" % m.name
                no_co2 = True

        if (((mod is None) or no_co2) and (not never_emulation)):
            #print "Emulating co2 in %s" % m.name
            mod = self.emulatedModelResult(m, obs)

        if mod is None: raise il.VarNotInModel()

        # get the right layering, closest to the layer elevation where all aren't masked.
        if mod.layered:
            ind = (np.abs(obs.depth[:, np.newaxis] - mod.depth)).argmin(axis=1)
            for i in range(ind.size):
                while (mod.data[:, ind[i], i].mask.sum() >
                       0.5 * mod.data.shape[0]):
                    ind[i] += 1
            data = []
            for i in range(ind.size):
                data.append(mod.data[:, ind[i], i])
            mod.data = np.ma.masked_array(data).T
            mod.depth = None
            mod.depth_bnds = None
            mod.layered = False
            obs, mod = il.MakeComparable(obs,
                                         mod,
                                         mask_ref=True,
                                         clip_ref=True)
            mod.data.mask += obs.data.mask

        # Remove the trend via quadradic polynomial
        obs = _detrend(obs)
        mod = _detrend(mod)

        return obs, mod
예제 #2
0
def getDiurnalDataForGivenYear(var, year):
    """
    """

    # Get this year's data, make sure there is enough
    spd = int(round(1 / np.diff(var.time_bnds, axis=1).mean()))
    datum = cftime.date2num(cftime.datetime(year, 1, 1), "days since 1850-1-1")
    ind = np.where(year == var.year)[0]
    t = var.time[ind] - datum
    tb = var.time_bnds[ind] - datum
    data = var.data[ind, 0]

    # Reshape the data
    begin = np.argmin(tb[:(spd - 1), 0] % 1)
    end = begin + int(t[begin:].size / float(spd) - 1) * spd
    shift = int(round((var.tmax - 12) / (var.dt * 24)))
    begin += shift
    end += shift
    shp = (-1, spd) + data.shape[1:]
    data = data[begin:end].reshape(shp)
    t = t[begin:end].reshape(shp).mean(axis=1)

    # Diurnal magnitude
    mag = Variable(name="mag%d" % year,
                   unit=var.unit,
                   time=t,
                   data=data.max(axis=1) - data.min(axis=1))

    # Some of the tower data is 'intelligently' masked which leads to
    # too much of the data being removed to use my change-detection
    # algorithm to determine season begin/end.
    mag.skip = False
    if mag.data.mask.all(): raise NotEnoughDataInYear  # if year is all masked
    dmag = (mag.data.max() - mag.data.min())
    if dmag < 1e-14:
        raise NotEnoughDataInYear  # if diurnal mag has no amplitude

    # Some mask out off seasons, season is taken to be all the data
    begin_day, end_day = mag.time[mag.data.mask == False][[
        0, -1
    ]]  # begin/end of the mask data
    if ((begin_day < 2 and end_day < 363)
            or (begin_day > 2 and end_day > 363)):
        # this is likely a dataset which is a partial year
        raise NotEnoughDataInYear
    elif (begin_day > 2 and end_day < 363):
        # this is likely a dataset that masks out off-seasons
        season = np.asarray([begin_day, end_day])
    else:
        season = findSeasonalTiming(mag.time, mag.data)
    centroid = findSeasonalCentroid(mag.time, mag.data)
    mag.season = season
    mag.centroid = centroid

    # Mask out off season
    mask = (t < season[0]) + (t > season[1])
    data = np.ma.masked_array(data,
                              mask=mask[:, np.newaxis] *
                              np.ones(data.shape[1], dtype=bool))

    # Mean seasonal diurnal cycle
    uncert = np.zeros((data.shape[1], 2))
    for i in range(data.shape[1]):
        d = data[:, i].compressed()
        if d.size == 0: continue
        uncert[i, :] = np.percentile(d, [10, 90])
    day = np.linspace(0, 1, spd + 1)
    day = 0.5 * (day[:-1] + day[1:])
    with np.errstate(under='ignore', over='ignore'):
        cycle = Variable(name="cycle%d" % year,
                         unit=var.unit,
                         time=day,
                         data=data.mean(axis=0),
                         data_bnds=uncert)

    # Mean seasonal uptake
    uptake = Variable(unit=var.unit,
                      time=var.time[ind] - datum,
                      time_bnds=var.time_bnds[ind] - datum,
                      data=var.data[ind, 0])
    uptake.data = np.ma.masked_array(uptake.data,
                                     mask=((uptake.time < season[0]) +
                                           (uptake.time > season[1])))
    uptake = uptake.integrateInTime(mean=True)
    cycle.uptake = uptake.data

    # Timing of peak seasonal cycle, could be a maximum or minimum,
    # check second derivative of a best-fit parabola to the daytime
    # data.
    begin = int(spd / 4)
    end = int(spd * 3 / 4)
    p = np.polyfit(cycle.time[begin:end], cycle.data[begin:end], 2)
    if p[0] < 0:
        cycle.peak = day[cycle.data.argmax()] * 24
    else:
        cycle.peak = day[cycle.data.argmin()] * 24

    return mag, cycle