def extractTimeSeries(self,variable,lats=None,lons=None,alt_vars=[],initial_time=-1e20,final_time=1e20,output_unit="",expression=None):
        """Extracts a time series of the given variable from the model.

        Parameters
        ----------
        variable : str
            name of the variable to extract
        alt_vars : list of str, optional
            alternate variables to search for if *variable* is not found
        initial_time : float, optional
            include model results occurring after this time
        final_time : float, optional
            include model results occurring before this time
        output_unit : str, optional
            if specified, will try to convert the units of the variable 
            extract to these units given. 
        lats : numpy.ndarray, optional
            a 1D array of latitude locations at which to extract information
        lons : numpy.ndarray, optional
            a 1D array of longitude locations at which to extract information
        expression : str, optional
            an algebraic expression describing how to combine model outputs

        Returns
        -------
        var : ILAMB.Variable.Variable
            the extracted variable

        """
        # prepend the target variable to the list of possible variables
        altvars = list(alt_vars)
        altvars.insert(0,variable)

        # checks on input consistency
        if lats is not None: assert lons is not None
        if lons is not None: assert lats is not None
        if lats is not None: assert lats.shape == lons.shape

        # create a list of datafiles which have a non-null intersection
        # over the desired time range
        V = []
        tmin =  1e20
        tmax = -1e20
        for v in altvars:
            if not self.variables.has_key(v): continue
            for pathName in self.variables[v]:
                var = Variable(filename       = pathName,
                               variable_name  = variable,
                               alternate_vars = altvars[1:],
                               area           = self.land_areas,
                               t0             = initial_time - self.shift,
                               tf             = final_time   - self.shift)
                tmin = min(tmin,var.time_bnds.min())
                tmax = max(tmax,var.time_bnds.max())
                if ((var.time_bnds.max() < initial_time - self.shift) or
                    (var.time_bnds.min() >   final_time - self.shift)): continue
                if lats is not None and var.ndata:
                    r = np.sqrt((lats[:,np.newaxis]-var.lat)**2 +
                                (lons[:,np.newaxis]-var.lon)**2)
                    imin = r.argmin(axis=1)
                    rmin = r.   min(axis=1)
                    imin = imin[np.where(rmin<1.0)]
                    if imin.size == 0:
                        logger.debug("[%s] Could not find [%s] at the input sites in the model results" % (self.name,",".join(altvars)))
                        raise il.VarNotInModel()
                    var.lat   = var.lat [  imin]
                    var.lon   = var.lon [  imin]
                    var.data  = var.data[:,imin]
                    var.ndata = var.data.shape[1]
                if lats is not None and var.spatial: var = var.extractDatasites(lats,lons)                    
                var.time      += self.shift 
                var.time_bnds += self.shift
                V.append(var)
            if len(V) > 0: break

        # If we didn't find any files, try to put together the
        # variable from a given expression
        if len(V) == 0:
            if expression is not None:
                v = self.derivedVariable(variable,
                                         expression,
                                         lats         = lats,
                                         lons         = lons,
                                         initial_time = initial_time,
                                         final_time   = final_time)
            else:
                tstr = ""
                if tmin < tmax: tstr = " in the given time frame, tinput = [%.1f,%.1f], tmodel = [%.1f,%.1f]" % (initial_time,final_time,tmin+self.shift,tmax+self.shift)
                logger.debug("[%s] Could not find [%s] in the model results%s" % (self.name,",".join(altvars),tstr))
                raise il.VarNotInModel()
        else:
            v = il.CombineVariables(V)
        
            
        return v
Example #2
0
    def stageData(self,m):
        r"""Extracts model data which is comparable to the observations.

        The observational data measure the anomaly in terrestrial
        water storage, 'twsa' in terms of [kg m-2]. We convert this
        unit to [cm] using the density of water. The models are
        expected to provide the terrestrial water storage variable,
        'tws', and we need to find the anomaly. First, the model
        result is trimmed to match the temporal extents of the
        observational data. Then, to get the anomaly, we subtract off
        the temporal mean,

        .. math:: \mathit{twsa}(t,\mathbf{x}) = tws(t,\mathbf{x}) - \frac{1}{t_f-t_0}\int_{t_0}^{t_f} tws(t,\mathbf{x})\ dt 

        We do this for the model 'tws' variable, and optionally for
        the observation, treating its 'twsa' variable as 'tws' in the
        above expression. This is because the observational data can
        have a small mean even though it represents only the anomaly.

        Parameters
        ----------
        m : ILAMB.ModelResult.ModelResult
            the model result context

        Returns
        -------
        obs : ILAMB.Variable.Variable
            the variable context associated with the observational dataset
        mod : ILAMB.Variable.Variable
            the variable context associated with the model result

        """
        # get the observational data
        obs = Variable(filename       = self.source,
                       variable_name  = self.variable,
                       alternate_vars = self.alternate_vars).convert("cm")

        # get the model data, in the units of the obseravtions
        mod = m.extractTimeSeries(self.variable,
                                  alt_vars     = self.alternate_vars,
                                  expression   = self.derived,
                                  initial_time = obs.time_bnds[ 0,0],
                                  final_time   = obs.time_bnds[-1,1])

        # if the derived expression is used, then we get a mass flux
        # rate and need to accumulate
        try:
            mod.convert(obs.unit)
        except:
            mod = mod.accumulateInTime()
            mod.name = obs.name
        obs,mod = il.MakeComparable(obs,mod,clip_ref=True)

        # subtract off the mean
        mean      = obs.integrateInTime(mean=True)
        obs.data -= mean.data
        mean      = mod.integrateInTime(mean=True)
        mod.data -= mean.data

        # compute mean values over each basin
        odata = np.ma.zeros((obs.time.size,len(self.basins)))
        mdata = np.ma.zeros((mod.time.size,len(self.basins)))
        for i,basin in enumerate(self.basins):
            odata[:,i] = obs.integrateInSpace(region=basin,mean=True).data
            mdata[:,i] = mod.integrateInSpace(region=basin,mean=True).data
        obs.data = odata; obs.ndata = odata.shape[1]; obs.spatial = False
        mod.data = mdata; mod.ndata = mdata.shape[1]; mod.spatial = False
        mod.data.mask = obs.data.mask
        
        return obs,mod