Exemple #1
0
    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
Exemple #2
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
Exemple #3
0
    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
Exemple #4
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
Exemple #5
0
    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
Exemple #6
0
    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
Exemple #7
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 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
Exemple #8
0
    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__())
Exemple #9
0
    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()
Exemple #10
0
    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__())