def generateForcingFields(self, conc_idx, inputs, outputs): """ UPDATE THIS DESCRIPTION! Generate a forcing field taking spacial masks, timezones, and time averaging into account. Keyword Arguments: conc_idx:*int* Index of concentration file in self.conc_files. Done this way so that it's easy to access yesterday's and tomorrow's files. inputs and outputs:*DataFile* dicts of DataFiles where the key is the relative day (so, -1 is yesterday) Returns: Warning: This pretty much assumes each file is a day A dictionary, where key names are variable names, and each contain a float32 3D field. """ Forcing.log("Running %s.generateForcingFields()"%type(self)) # Some variable used later scalar = None if self.griddedTimeZoneFld == None: # Assume all timezones are GMT print "Warning! No gridded time zone information loaded. Using a field of zeros." tz = np.zeros((self.ni,self.nj)) else: tz = self.griddedTimeZoneFld if len(self.species) == 0: raise NoSpeciesException("Must specify species") return # We doing time averaging? if self.averaging in ['AVG_MAX', 'AVG_MAX8', 'AVG_MAX24']: do_averaging=True averaging_window = self.averaging_window else: do_averaging=False averaging_window = None #if self.averaging == 'AVG_MASK' or self.averaging == 'AVG_NONE' if self.averaging == 'AVG_NONE': # Ensure this is set right self.timeMask = range(0,25) # If it's the mask, then the timemask should already be set # Create zero fields to allocate our arrays fld_empty=np.zeros((len(self.species), self.nt, self.nk_f, self.nj, self.ni), dtype=np.float32) # Get the relative days, so [-1 0 1] for [yesterday, today, tomorrow] rdays = inputs.keys() # Probably an easiesr way to initalize this since we're only writing later, but for now we'll do it. flds={} for d in rdays: flds[d] = fld_empty.copy() # This is NOT efficient. Could probably easily make it # more efficient by implementing some sort of cache though.. for idx_s, species in enumerate(self.species): #print "Iteratiing through species %d=%s"%(idx_s, species) # Initialize the data flds. Set to zero if there's a day that doesn't exist datas={} for d in rdays: if inputs[d] is None: datas[d] = np.zeros((self.nt, self.nk_f, self.nj, self.ni), dtype=np.float32) else: datas[d] = inputs[d].variables[species][:] # Recall, mask is already considered in these vectors for k in self._layers: # I think there's a better way to do the next two loops, don't know it though. for i in range(0,self.ni): for j in range(0,self.nj): # Spatial mask if not self.space[j,i]: # This is masked out. Set to zero and go to the next cell for d in rdays: flds[d][idx_s][0:self.nt,k,j,i] = np.zeros((self.nt), dtype=np.float32) continue #else: # # TEMP HACK!! # # This temp hack is used to ensure the mask is working # fld_yest[0:self.nt,k,j,i] = np.ones((self.nt), dtype=np.float32) # fld_today[0:self.nt,k,j,i] = np.ones((self.nt), dtype=np.float32) # fld_tom[0:self.nt,k,j,i] = np.ones((self.nt), dtype=np.float32) # continue # Take averaging into consideration # For almost all of these averagings, we'll have to # build a vector of all values for all times at that # cell. Unfortunately, the data is organized in the # opposite way as we want (time is the top index..) if do_averaging: vecs={} for d in rdays: vecs[d] = datas[d][:Forcing.dayLen,k,j,i] # REMOVE! #if i==self.debug_i and j==self.debug_j: # print "vec_today[%d,%d]: "%(self.debug_j, self.debug_i), vec_today # Prepares a vector of values with respect to the # direction we're going to calculate the average # (forward/backward), the window size, and time # zone vec = Forcing.prepareTimeVectorForAvg(vecs, timezone=tz[j][i], winLen=averaging_window, debug=False) #print "i=%d,j=%d, preped vec[%d] = %s"%(i,j,len(vec)," ".join(map(str, vec))) # Calculate the moving window average avgs = Forcing.calcMovingAverage(vec, winLen=averaging_window) #print "i=%d,j=%d, avg vec[%d] = %s"%(i,j,len(avgs)," ".join(map(str, avgs))) # And then, for the 8-hour max to be used for a # forcing term, generate a vector for yesterday, # today and tomorrow with the forcing terms in them if self.timeInvariantScalarMultiplcativeFld is not None: scalar = self.timeInvariantScalarMultiplcativeFld[j][i]/averaging_window vecs = Forcing.applyForceToAvgTime(avgs, days=vecs.keys(), winLen=averaging_window, timezone=tz[j][i], min_threshold=self.threshold, forcingValue=scalar) # This was done blindly for d in rdays: flds[d][idx_s][:24,k,j,i] = vecs[d] elif self.averaging == 'AVG_MASK' or self.averaging == 'AVG_NONE': # NOT YET TESTED raise NotImplementedError( "Mask timing or no averaging is not yet tested. Averaging options=%s"%self.averaging ) # The comments assume timezone = -6 for t_gmt in self.timeMask: # when t_gmt = 0, t_loc = -6, so we're into yesterday t_loc = t_gmt + tz[j][i] # Reference the arrays if t_loc < 0: dfld = data_yest #ffld = fld_yest elif t_loc>0 and t_loc<Forcing.dayLen: dfld = data_today #ffld = fld_today else: dfld = data_tomorrow #ffld = fld_tomorrow # I have to write in GMT # This is wrong, as local times can write into another day.. maybe.. but since there's no averaging, another iteration will take care of that.. ffld = fld_today # fld[-6] is fld[18] val=dfld[t_loc,k,j,i] if threshold is not None: if val > threshold: force = 1 else: if val > 0.0: force = 1 # Set the field in the referenced forcing field ffld[t_loc,k,j,i] = force else: raise NotImplementedError( "Unavailable time averaging method (%s) selected"%self.averaging ) #endif averaging #endfor j #endfor i #endfor k #endfor species return flds