def update(self, data2tape, time_ord): """ Update the tape with new data""" # ------------------------------------------------------------ # # Check that the time_ord is in sync if self._time_ord != time_ord: raise ValueError('rout_var.time_ord does not match the time_ord ' 'passed in by the convolution call') # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Get the next timestamp self._time_ord += self._dt / SECSPERDAY self._timestamp = ord_to_datetime(self._time_ord, TIMEUNITS, calendar=self._calendar) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Advance the Count self._count += 1 # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Update the fields for field in self._fincl: tracer = 'LIQ' log.debug('updating {0}'.format(field)) fdata = data2tape[field][tracer] if self._avgflag == 'A': self._temp_data[field] += fdata elif self._avgflag == 'I': if self._count == self._update_count: self._temp_data[field] = fdata[:] elif self._avgflag == 'X': self._temp_data[field] = np.maximum(self._temp_data[field], fdata) elif self._avgflag == 'M': self._temp_data[field] = np.minimum(self._temp_data[field], fdata) else: raise ValueError('Average flag ({0}) does not match any of' ' (A,I,X,M)'.format(self._avgflag)) # ------------------------------------------------------------ # # If count == _update_count, add to _out_data # Average first, if necessary if (self._avgflag == 'A' and self._count == self._update_count): self.__average() if self._count == self._update_count: # move the data to the out_data structure self.__update_out_data() # Determine next update self.__next_update_out_data() # zero out temp_data for field in self._fincl: self._temp_data[field][:] = 0.0
def convolve(self, aggrunin, time_ord): """ This convoluition funciton works by looping over all points and doing the convolution one timestep at a time. This is accomplished by creating a convolution ring. Contributing flow from each timestep is added to the convolution ring. The convolution ring is saved as the state. The first column of values in the ring are the current runoff. """ # ------------------------------------------------------------ # # Check that the time_ord is in sync # This is the time at the start of the current step (end of last step) if self.time_ord != time_ord: log.error('rout_var.time_ord = %s, time_ord = %s', self.time_ord, time_ord) raise ValueError('rout_var.time_ord does not match the time_ord ' 'passed in by the convolution call') # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Do the convolution log.debug('convolving') for tracer in RVIC_TRACERS: # -------------------------------------------------------- # # First update the ring log.debug('rolling the ring') # Zero out current ring self.ring[tracer][0, :] = 0. # Equivalent to Fortran 90 cshift function self.ring[tracer] = np.roll(self.ring[tracer], -1, axis=0) # -------------------------------------------------------- # # -------------------------------------------------------- # # C convolution call rvic_convolve(self.n_sources, self.n_outlets, self.subset_length, self.xsize, self.source2outlet_ind, self.source_y_ind, self.source_x_ind, self.source_time_offset, self.unit_hydrograph[tracer][:, :], aggrunin[tracer], self.ring[tracer][:, :]) # -------------------------------------------------------- # # ------------------------------------------------------------ # # ------------------------------------------------------------ # # move the time_ord forward self.time_ord += self.unit_hydrograph_dt / SECSPERDAY self.timestamp = ord_to_datetime(self.time_ord, TIMEUNITS, calendar=self._calendar) return self.timestamp
def init_state(self, state_file, run_type, timestamp): if run_type in ['startup', 'restart']: log.info('reading state_file: %s', state_file) f = Dataset(state_file, 'r') for tracer in RVIC_TRACERS: self.ring[tracer] = f.variables['{0}_ring'.format(tracer)][:] file_timestamp = ord_to_datetime( f.variables['time'][:], f.variables['time'].units, calendar=f.variables['time'].calendar) if run_type == 'restart': self.timestamp = file_timestamp elif run_type == 'startup': self.timestamp = timestamp if timestamp != file_timestamp: log.warning('restart timestamps do not match (%s, %s', file_timestamp, self.timestamp) log.warning('Runtype is startup so model will continue') else: raise ValueError('unknown run_type: {0}'.format(run_type)) # Check that timestep and outlet_decomp_ids match ParamFile if f.variables['unit_hydrograph_dt'][:] != self.unit_hydrograph_dt: raise ValueError('Timestep in Statefile does not match ' 'timestep in ParamFile') if not np.array_equal(f.variables['outlet_decomp_ind'][:], self.outlet_decomp_ind): raise ValueError('outlet_decomp_ind in Statefile does not ' 'match ParamFile') if f.RvicDomainFile != self.RvicDomainFile: raise ValueError('RvicDomainFile in StateFile does not match ' 'ParamFile') f.close() elif run_type == 'drystart': log.info('run_type is drystart so no state_file will be read') self.timestamp = timestamp self.time_ord = date2num(self.timestamp, TIMEUNITS, calendar=self._calendar) self._start_date = self.timestamp self._start_ord = self.time_ord
def init_state(self, state_file, run_type, timestamp): if run_type in ['startup', 'restart']: log.info('reading state_file: %s', state_file) f = Dataset(state_file, 'r') for tracer in RVIC_TRACERS: self.ring[tracer] = f.variables['{0}_ring'.format(tracer)][:] file_timestamp = ord_to_datetime(f.variables['time'][:], f.variables['time'].units, calendar=f.variables['time'].calendar) if run_type == 'restart': self.timestamp = file_timestamp elif run_type == 'startup': self.timestamp = timestamp if timestamp != file_timestamp: log.warning('restart timestamps do not match (%s, %s', file_timestamp, self.timestamp) log.warning('Runtype is startup so model will continue') else: raise ValueError('unknown run_type: {0}'.format(run_type)) # Check that timestep and outlet_decomp_ids match ParamFile if f.variables['unit_hydrograph_dt'][:] != self.unit_hydrograph_dt: raise ValueError('Timestep in Statefile does not match ' 'timestep in ParamFile') if not np.array_equal(f.variables['outlet_decomp_ind'][:], self.outlet_decomp_ind): raise ValueError('outlet_decomp_ind in Statefile does not ' 'match ParamFile') if f.RvicDomainFile != self.RvicDomainFile: raise ValueError('RvicDomainFile in StateFile does not match ' 'ParamFile') f.close() elif run_type == 'drystart': log.info('run_type is drystart so no state_file will be read') self.timestamp = timestamp self.time_ord = date2num(self.timestamp, TIMEUNITS, calendar=self._calendar) self._start_date = self.timestamp self._start_ord = self.time_ord
def convolve(self, aggrunin, time_ord): """ This convoluition funciton works by looping over all points and doing the convolution one timestep at a time. This is accomplished by creating an convolution ring. Contributing flow from each timestep is added to the convolution ring. The convolution ring is saved as the state. The first column of values in the ring are the current runoff. """ # ------------------------------------------------------------ # # Check that the time_ord is in sync # This is the time at the start of the current step (end of last step) if self.time_ord != time_ord: log.error('rout_var.time_ord = %s, time_ord = %s' %(self.time_ord, time_ord)) raise ValueError('rout_var.time_ord does not match the time_ord passed in by the convolution call') # ------------------------------------------------------------ # # ------------------------------------------------------------ # # First update the ring log.debug('rolling the ring') self.ring[0, :, 0] = 0 # Zero out current ring self.ring = np.roll(self.ring, 1, axis=0) # Equivalent to Fortran 90 cshift function # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Do the convolution log.debug('convolving') # this matches the fortran implementation, it may be faster to use np.convolve but testing # can be done later # also this is where the parallelization will happen for nt, tracer in enumerate(RVIC_TRACERS): for s, outlet in enumerate(self.source2outlet_ind): # loop over all source points y = self.source_y_ind[s] x = self.source_x_ind[s] for i in xrange(self.subset_length): j = i + self.source_time_offset[s] self.ring[j, outlet, nt] = self.ring[j, outlet, nt] + (self.unit_hydrograph[i, s, nt] * aggrunin[tracer][y, x]) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # move the time_ord forward self.time_ord += self.unit_hydrograph_dt / SECSPERDAY self.timestamp = ord_to_datetime(self.time_ord, TIMEUNITS, calendar=self._calendar) return self.timestamp
def __init__(self, time_ord, caseid, Rvar, tape_num=0, fincl=['streamflow'], mfilt=1, ndens=2, nhtfrq=0, avgflag='A', units='kg m-2 s-1', file_format='NETCDF4_CLASSIC', outtype='grid', grid_lons=False, grid_lats=False, grid_area=None, out_dir='.', calendar=None, glob_ats=None, zlib=True, complevel=4, least_significant_digit=None): self._tape_num = tape_num self._time_ord = time_ord # Days since basetime self._caseid = caseid # Case ID and prefix for outfiles self._fincl = list(fincl) # Fields to include in history file self._mfilt = mfilt # Maximum number of time samples self._ndens = ndens if self._ndens == 1: # Output file precision self._ncprec = NC_FLOAT else: self._ncprec = NC_DOUBLE self._nhtfrq = nhtfrq # Write frequency self._avgflag = avgflag # Average Flag (A,I,X,M) self._outtype = outtype # Outfile type (grid, array) self._count = 0 self.files_count = 0 self._file_format = file_format self._calendar = calendar self._out_dir = out_dir self._glob_ats = glob_ats self.__get_rvar(Rvar) # Get the initial Rvar fields self._grid_shape = grid_area.shape self._out_data = {} # ------------------------------------------------------------ # # calculate the step size for each out_data timestep (units=days) if self._nhtfrq > 0: # If some number of timesteps self._out_data_stepsize = self._nhtfrq * self._dt / SECSPERDAY elif self._nhtfrq < 0: # If some number hours self._out_data_stepsize = -1 * self._nhtfrq / HOURSPERDAY else: # If monthly self._out_data_stepsize = None # varies by month log.debug('_out_data_stepsize: %s', self._out_data_stepsize) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Get Grid Lons/Lats if outtype is grid if outtype == 'grid': self._out_data_shape = self._grid_shape if type(grid_lons) == np.ndarray and type(grid_lats) == np.ndarray: self._grid_lons = grid_lons self._grid_lats = grid_lats else: raise ValueError('Must include grid lons / lats if ' 'outtype == grid') else: self._out_data_shape = (self._num_outlets, ) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Get units multiplier (size of noutlets) self._units = units if units in ['kg/m2/s', 'kg m-2 s-1', 'kg m^-2 s^-1', 'kg*m-2*s-1', 'kg s-1 m-2']: self._units_mult = np.ones_like(self._outlet_y_ind, dtype=np.float64) elif units in ['m3/s', 'm^3/s', 'm3 s-1']: # kg/m2/s --> m3/s self._units_mult = grid_area[self._outlet_y_ind, self._outlet_x_ind] self._units_mult /= WATERDENSITY elif units in ['mm/day', 'mm d-1', 'mm d^-1', 'mm/day']: # kg/m2/s --> mm/day over basin area self._units_mult = grid_area[self._outlet_y_ind, self._outlet_x_ind] self._units_mult *= SECSPERDAY self._units_mult /= WATERDENSITY self._units_mult /= self._outlet_upstream_area elif units in ['gal/day', 'gpd', 'gal d-1']: self._units_mult = grid_area[self._outlet_y_ind, self._outlet_x_ind] self._units_mult /= WATERDENSITY self._units_mult *= 2.28E7 elif units in ['cfs', 'ft^3 s-1', 'f3/s']: self._units_mult = grid_area[self._outlet_y_ind, self._outlet_x_ind] self._units_mult /= WATERDENSITY self._units_mult *= 35.3 elif units in ['acre-ft/d']: self._units_mult = grid_area[self._outlet_y_ind, self._outlet_x_ind] self._units_mult /= WATERDENSITY self._units_mult *= 70.0 else: raise ValueError('{0} is not a valid units string'.format(units)) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # netCDF variable options self.ncvaropts = {'zlib': zlib, 'complevel': complevel, 'least_significant_digit': least_significant_digit} # ------------------------------------------------------------ # # ------------------------------------------------------------ # # get current timestamp self._timestamp = ord_to_datetime(self._time_ord, TIMEUNITS, self._calendar) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Initialize the temporary history fields self._temp_data = {} for field in self._fincl: self._temp_data[field] = np.zeros(self._num_outlets, dtype=np.float64) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Determine the format of the output filename if self._avgflag == 'I': self._fname_format = os.path.join(out_dir, "%s.rvic.h%s%s.%%Y-%%m-%%d-%%H-%%M-%%S.nc" % (self._caseid, self._tape_num, self._avgflag.lower())) else: if self._nhtfrq == 0: self._fname_format = os.path.join(out_dir, "%s.rvic.h%s%s.%%Y-%%m.nc" % (self._caseid, self._tape_num, self._avgflag.lower())) elif (self._nhtfrq == -24) or (nhtfrq*self._dt == SECSPERDAY): self._fname_format = os.path.join(out_dir, "%s.rvic.h%s%s.%%Y-%%m-%%d.nc" % (self._caseid, self._tape_num, self._avgflag.lower())) else: self._fname_format = os.path.join(out_dir, "%s.rvic.h%s%s.%%Y-%%m-%%d-%%H.nc" % (self._caseid, self._tape_num, self._avgflag.lower())) self._rest_fname_format = os.path.join(out_dir, "%s.rvic.rh%s.%%Y-%%m-%%d-%%H-%%M-%%S.nc" % (self._caseid, self._tape_num)) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Determine when the next write should be and initialize out_data self.__next_write_out_data() # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Determine when the update of out_data should be self.__next_update_out_data() # ------------------------------------------------------------ # log.debug(self.__repr__())
def __init__(self, time_ord, caseid, Rvar, tape_num=0, fincl=['streamflow'], mfilt=1, ndens=2, nhtfrq=0, avgflag='A', units='kg m-2 s-1', file_format='NETCDF4_CLASSIC', outtype='grid', grid_lons=False, grid_lats=False, grid_area=None, out_dir='.', calendar=None, glob_ats=None): self._tape_num = tape_num self._time_ord = time_ord # Days since basetime self._caseid = caseid # Case ID and prefix for outfiles self._fincl = fincl # Fields to include in history file self._mfilt = mfilt # Maximum number of time samples self._ndens = ndens if self._ndens == 1: # Output file precision self._ncprec = NC_FLOAT else: self._ncprec = NC_DOUBLE self._nhtfrq = nhtfrq # Write frequency self._avgflag = avgflag # Average Flag (A,I,X,M) self._outtype = outtype # Outfile type (grid, array) self._count = 0 self.files_count = 0 self._file_format = file_format self._calendar = calendar self._out_dir = out_dir self._glob_ats = glob_ats self._out_data_i = 0 # position counter for out_data array self._out_times = np.zeros(self._mfilt, dtype=np.float64) self._out_time_bnds = np.zeros((self._mfilt, 2), dtype=np.float64) self.__get_rvar(Rvar) # Get the initial Rvar fields self._grid_shape = grid_area.shape # ------------------------------------------------------------ # # Get Grid Lons/Lats if outtype is grid, setup out_data self._out_data = {} if outtype == 'grid': if type(grid_lons) == np.ndarray and type(grid_lats) == np.ndarray: self._grid_lons = grid_lons self._grid_lats = grid_lats for field in self._fincl: if grid_lons.ndim == 1: shape = (self._mfilt,) + self._grid_shape else: shape = (self._mfilt,) + self._grid_shape self._out_data[field] = np.zeros(shape, dtype=np.float64) else: raise ValueError('Must include grid lons / lats if ' 'outtype == grid') else: for field in self._fincl: self._out_data[field] = np.zeros((self._mfilt, self._num_outlets)) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Get units multiplier self._units = units if units in ['kg/m2/s', 'kg m-2 s-1', 'kg m^-2 s^-1', 'kg*m-2*s-1', 'kg s-1 m-2']: self._units_mult = 1.0 elif units in ['m3/s', 'm^3/s', 'm3 s-1']: self._units_mult = grid_area / WATERDENSITY else: raise ValueError('{0} is not a valid units string'.format(units)) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # get current timestamp self._timestamp = ord_to_datetime(self._time_ord, TIMEUNITS, self._calendar) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Initialize the temporary history fields self._temp_data = {} for field in self._fincl: self._temp_data[field] = np.zeros(self._num_outlets, dtype=np.float64) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Determine the format of the output filename if self._avgflag == 'I': self._fname_format = os.path.join(out_dir, "%s.rvic.h%s%s.%%Y-%%m-%%d-%%H-%%M-%%S.nc" % (self._caseid, self._tape_num, self._avgflag.lower())) else: if nhtfrq == 0: self._fname_format = os.path.join(out_dir, "%s.rvic.h%s%s.%%Y-%%m.nc" % (self._caseid, self._tape_num, self._avgflag.lower())) elif (nhtfrq == -24) or (nhtfrq*self._dt == SECSPERDAY): self._fname_format = os.path.join(out_dir, "%s.rvic.h%s%s.%%Y-%%m-%%d.nc" % (self._caseid, self._tape_num, self._avgflag.lower())) else: self._fname_format = os.path.join(out_dir, "%s.rvic.h%s%s.%%Y-%%m-%%d-%%H.nc" % (self._caseid, self._tape_num, self._avgflag.lower())) self._rest_fname_format = os.path.join(out_dir, "%s.rvic.rh%s.%%Y-%%m-%%d-%%H-%%M-%%S.nc" % (self._caseid, self._tape_num)) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Determine when the next write should be self.__next_update_out_data()
def __init__(self, time_ord, caseid, Rvar, tape_num=0, fincl=['streamflow'], mfilt=1, ndens=2, nhtfrq=0, avgflag='A', units='kg m-2 s-1', file_format='NETCDF4_CLASSIC', outtype='grid', grid_lons=False, grid_lats=False, grid_area=None, out_dir='.', calendar=None, glob_ats=None, zlib=True, complevel=4, least_significant_digit=None): self._tape_num = tape_num self._time_ord = time_ord # Days since basetime self._caseid = caseid # Case ID and prefix for outfiles self._fincl = list(fincl) # Fields to include in history file self._mfilt = mfilt # Maximum number of time samples self._ndens = ndens if self._ndens == 1: # Output file precision self._ncprec = NC_FLOAT else: self._ncprec = NC_DOUBLE self._nhtfrq = nhtfrq # Write frequency self._avgflag = avgflag # Average Flag (A,I,X,M) self._outtype = outtype # Outfile type (grid, array) self._count = 0 self.files_count = 0 self._file_format = file_format self._calendar = calendar self._out_dir = out_dir self._glob_ats = glob_ats self.__get_rvar(Rvar) # Get the initial Rvar fields self._grid_shape = grid_area.shape self._out_data = {} # ------------------------------------------------------------ # # calculate the step size for each out_data timestep (units=days) if self._nhtfrq > 0: # If some number of timesteps self._out_data_stepsize = self._nhtfrq * self._dt / SECSPERDAY elif self._nhtfrq < 0: # If some number hours self._out_data_stepsize = -1 * self._nhtfrq / HOURSPERDAY else: # If monthly self._out_data_stepsize = None # varies by month log.debug('_out_data_stepsize: %s', self._out_data_stepsize) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Get Grid Lons/Lats if outtype is grid if outtype == 'grid': self._out_data_shape = self._grid_shape if type(grid_lons) == np.ndarray and type(grid_lats) == np.ndarray: self._grid_lons = grid_lons self._grid_lats = grid_lats else: raise ValueError('Must include grid lons / lats if ' 'outtype == grid') else: self._out_data_shape = (self._num_outlets, ) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Get units multiplier (size of noutlets) self._units = units if units in [ 'kg/m2/s', 'kg m-2 s-1', 'kg m^-2 s^-1', 'kg*m-2*s-1', 'kg s-1 m-2' ]: self._units_mult = np.ones_like(self._outlet_y_ind, dtype=np.float64) elif units in ['m3/s', 'm^3/s', 'm3 s-1']: # kg/m2/s --> m3/s self._units_mult = grid_area[self._outlet_y_ind, self._outlet_x_ind] self._units_mult /= WATERDENSITY elif units in ['mm/day', 'mm d-1', 'mm d^-1', 'mm/day']: # kg/m2/s --> mm/day over basin area self._units_mult = grid_area[self._outlet_y_ind, self._outlet_x_ind] self._units_mult *= SECSPERDAY self._units_mult /= WATERDENSITY self._units_mult /= self._outlet_upstream_area elif units in ['gal/day', 'gpd', 'gal d-1']: self._units_mult = grid_area[self._outlet_y_ind, self._outlet_x_ind] self._units_mult /= WATERDENSITY self._units_mult *= 2.28E7 elif units in ['cfs', 'ft^3 s-1', 'f3/s']: self._units_mult = grid_area[self._outlet_y_ind, self._outlet_x_ind] self._units_mult /= WATERDENSITY self._units_mult *= 35.3 elif units in ['acre-ft/d']: self._units_mult = grid_area[self._outlet_y_ind, self._outlet_x_ind] self._units_mult /= WATERDENSITY self._units_mult *= 70.0 else: raise ValueError('{0} is not a valid units string'.format(units)) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # netCDF variable options self.ncvaropts = { 'zlib': zlib, 'complevel': complevel, 'least_significant_digit': least_significant_digit } # ------------------------------------------------------------ # # ------------------------------------------------------------ # # get current timestamp self._timestamp = ord_to_datetime(self._time_ord, TIMEUNITS, self._calendar) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Initialize the temporary history fields self._temp_data = {} for field in self._fincl: self._temp_data[field] = np.zeros(self._num_outlets, dtype=np.float64) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Determine the format of the output filename if self._avgflag == 'I': self._fname_format = os.path.join( out_dir, "%s.rvic.h%s%s.%%Y-%%m-%%d-%%H-%%M-%%S.nc" % (self._caseid, self._tape_num, self._avgflag.lower())) else: if self._nhtfrq == 0: self._fname_format = os.path.join( out_dir, "%s.rvic.h%s%s.%%Y-%%m.nc" % (self._caseid, self._tape_num, self._avgflag.lower())) elif (self._nhtfrq == -24) or (nhtfrq * self._dt == SECSPERDAY): self._fname_format = os.path.join( out_dir, "%s.rvic.h%s%s.%%Y-%%m-%%d.nc" % (self._caseid, self._tape_num, self._avgflag.lower())) else: self._fname_format = os.path.join( out_dir, "%s.rvic.h%s%s.%%Y-%%m-%%d-%%H.nc" % (self._caseid, self._tape_num, self._avgflag.lower())) self._rest_fname_format = os.path.join( out_dir, "%s.rvic.rh%s.%%Y-%%m-%%d-%%H-%%M-%%S.nc" % (self._caseid, self._tape_num)) # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Determine when the next write should be and initialize out_data self.__next_write_out_data() # ------------------------------------------------------------ # # ------------------------------------------------------------ # # Determine when the update of out_data should be self.__next_update_out_data() # ------------------------------------------------------------ # log.debug(self.__repr__())