LOG_NAME = 'rvic' def ord_to_datetime(time, units, calendar='standard'):
    '''
    netCDF4.num2date yields a fake datetime object, this function converts
    converts that back to a real datetime object
    '''
    # this is the netCDF4.datetime object
    # if the calendar is standard, t is already a real datetime object
    if type(time) == np.ndarray:
        if len(time) == 1:
            time = time[0]
        else:
            raise ValueError('time variable is a numpy array with length > 1')
    t = num2date(time, units, calendar=calendar)
    if calendar in ['proleptic_gregorian', 'standard', 'gregorian']:
        return t
    else:
        return datetime(t.year, t.month, t.day, t.hour, t.minute, t.second) TIMEUNITS = 'days since ' + REFERENCE_STRING  # do not change (MUST BE DAYS)! NC_INT = 'i4' NC_DOUBLE = 'f8' NC_CHAR = 'S1' RVIC_TRACERS = ('LIQ',)  # Before changing, update history module class NcGlobals(object):
    def __init__(self,
                 title=None,
                 casename=None,
                 casestr=None,
                 history='Created: {}'.format(time_mod.ctime(time_mod.time())),
                 institution='University of Washington',
                 source=sys.argv[0],
                 references='Based on the initial model of Lohmann, et al., '
                            '1996, Tellus, 48(A), 708-721',
                 comment='Output from the RVIC Streamflow Routing Model.',
                 Conventions='CF-1.6',
                 RvicPourPointsFile=None,
                 RvicFdrFile=None,
                 RvicUHFile=None,
                 RvicDomainFile=None,
                 version=None,
                 hostname=None,
                 username=None):

        self.atts = OrderedDict()

        if title is not None:
            self.atts['title'] = title

        if comment is not None:
            self.atts['comment'] = comment

        if Conventions is not None:
            self.atts['Conventions'] = Conventions

        if history is not None:
            self.atts['history'] = history

        if source is not None:
            self.atts['source'] = source

        if institution is not None:
            self.atts['institution'] = institution

        if hostname is not None:
            self.atts['hostname'] = hostname
        else:
            self.atts['hostname'] = socket.gethostname()

        if username is not None:
            self.atts['username'] = username
        else:
            self.atts['username'] = getuser()

        if casename is not None:
            self.atts['casename'] = casename

        if casestr is not None:
            self.atts['casestr'] = casestr

        if references is not None:
            self.atts['references'] = references

        if version is not None:
            self.atts['version'] = version
        else:
            try:
                from rvic import version
                self.atts['version'] = version.short_version
            except ImportError:
                self.atts['version'] = 'unknown'

        if RvicPourPointsFile is not None:
            self.atts['RvicPourPointsFile'] = RvicPourPointsFile

        if RvicUHFile is not None:
            self.atts['RvicUHFile'] = RvicUHFile

        if RvicFdrFile is not None:
            self.atts['RvicFdrFile'] = RvicFdrFile

        if RvicDomainFile is not None:
            self.atts['RvicDomainFile'] = RvicDomainFile

    def update(self):
        self.atts['history'] = \
            'Created: {0}'.format(time_mod.ctime(time_mod.time())) SECSPERDAY = HOURSPERDAY * SECSPERHOUR MAX_NC_CHARS = 256 CALENDAR_KEYS = {0: ['None'],
                 1: ['noleap', '365_day'],
                 2: ['gregorian', 'standard'],
                 3: ['proleptic_gregorian'],
                 4: ['all_leap', '366_day'],
                 5: ['360_day'],
                 6: ['julian']} REFERENCE_DATE = 10101  # i.e. REFERENCE_STRING REFERENCE_TIME = 0  # i.e. REFERENCE_STRING SHAREDOBJECT = 'rvic_convolution' + sysconfig.get_config_var('SO')
LIBPATH = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../')) def iteritems(d):
    return iter(d.items())
import os
import numpy as np
from netCDF4 import Dataset, date2num, stringtochar
from logging import getLogger
from .log import LOG_NAME
from .time_utility import ord_to_datetime
from .share import TIMEUNITS, NC_INT, NC_DOUBLE, NC_CHAR
from .share import RVIC_TRACERS, NcGlobals, SECSPERDAY, MAX_NC_CHARS
from .share import CALENDAR_KEYS, REFERENCE_DATE, REFERENCE_TIME
from .convolution_wrapper import rvic_convolve
from .pycompat import iteritems
from . import share
    # ---------------------------------------------------------------- #

    # ---------------------------------------------------------------- #
    # Flip the y index order
    def _flip_y_inds(self):
        '''
        Flip the y index order
        '''
        self.source_y_ind = self.ysize - self.source_y_ind - 1
        self.outlet_y_ind = self.ysize - self.outlet_y_ind - 1
    # ---------------------------------------------------------------- #

    # ---------------------------------------------------------------- #
    # Initilize State
    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
    # ---------------------------------------------------------------- #

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