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
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