ScriSpts listed in the Scripting Utility are functions that provide useful features accessible through scripts. Each function is denoted with and "external" or "compute" to designate where each function should be used. External functions should be used in external scripts and used with caution within a compute script. Compute scripts should be used within a simulation/compute. 

ResSimUtils.py

A ResSimUtils.py file can be used to store functions that would normally reside within an external (e.g., plot scripts, OSI tools, etc.) or compute script (e.g., scripted rules, state variables, etc.). One benefit of utilizing a utilities script is reducing the number of locations a function is defined. If multiple rules contain the same function and an update is needed for that function, a user would need to make the update in multiple rules or scripts. Another benefit is to reduce the size of the scripts. ResSim will throw a memory error if scripted rules are too large, which can happen when capturing complex reservoir operations. To minimize the size, logic can be moved to functions with a ResSimUtils.py file and loaded during the initialization.

External Functions

External scripts or functions should not be used within a compute script as the variable definitions can conflict with variables available during the compute. Examples shown below are best utlized in ResSim external scripts that are found in the user's .../AppData/Roaming/HEC/HEC-ResSim/... directory.

External Functions

#==============================================================================
def closeWatershed() :
    '''
    Returns True or False
    '''
    return ResSim.closeWatershed()

#==============================================================================
def computeSimulationRun(simulationRun) :
    '''
    Computes one alternative of a simulation
    '''
    selectModule("Simulation").computeRun(simulationRun, -1, True, True)

#==============================================================================
def computeSimulationRun(simulationRun) :
    '''
    Computes one alternative of a simulation
    '''
    selectModule("Simulation").computeRun(simulationRun, -1, True, True)
    
#==============================================================================
def extractSimulationData() :
    '''
    Performs new extract for the current simulation
    '''
    getSimulation().runExtract(getSimulation().getSimulationExtract())

#==============================================================================
def createNewTimeSeries(    debug,          # Set to either True or False to print debug statements
                            Pathname,       # Generic pathname
                            Times,          # List of times in minutes
                            Values,         # List of values
                            Units,          # Units of values
                            ValueType,      # Type of values. PER-CUM, PER-AVER, INST-VAL, INST-CUM
                            TimeZone = None # Optional time zone specification for CWMSVue time series    
                            ) : 
    '''
    Create a new time series for either CWMSVue or DSSVue
    '''
    Tsc = TimeSeriesContainer()                    
    Interval = Times[1] - Times[0]
    PathnameParts = Pathname.split('.')
    if len(PathnameParts) > 3 : 
        # CWMSVue
        DssVue = False
        FullName                    = Pathname
        LocationParts               = PathnameParts[0].split('-')
        BaseLocation, SubLocation   = LocationParts[0], '-'.join(LocationParts[1 : ])
        ParameterParts              = PathnameParts[1].split('-')
        BaseParameter, SubParameter = ParameterParts[0], '-'.join(ParameterParts[1 : ])
        if PathnameParts[3][0] == '~' : Interval = 0 # Local regular time series specify Interval as 0
        VersionParts                = PathnameParts[-1].split('-')
        BaseVersion, SubVersion     = VersionParts[0], '-'.join(VersionParts[1 : ])
    else :
        # DSSVue
        DssVue = True # If this remains True, Tsc.watershed will be set
        PathnameParts = Pathname.split('/')
        Watershed                   = PathnameParts[0]
        LocationParts               = PathnameParts[1].split('-')
        BaseLocation, SubLocation   = LocationParts[0], '-'.join(LocationParts[1 : ])
        ParameterParts              = PathnameParts[2].split('-')
        BaseParameter, SubParameter = ParameterParts[0], '-'.join(ParameterParts[1 : ])
        if PathnameParts[-2][ : 2] == 'IR' : Interval = 0 # Irregular time series specify Interval as 0
        VersionParts                = PathnameParts[-1].split('-')
        BaseVersion, SubVersion     = VersionParts[0], '-'.join(VersionParts[1 : ])

    Tsc.fullName                = Pathname
    if DssVue : 
        Tsc.watershed           = Watershed 
    Tsc.location                = BaseLocation
    Tsc.subLocation             = SubLocation
    Tsc.parameter               = BaseParameter
    Tsc.subParameter            = SubParameter
    Tsc.interval                = Interval
    Tsc.version                 = BaseVersion
    Tsc.subVersion              = SubVersion
    Tsc.type                    = ValueType
    Tsc.units                   = Units
    Tsc.times                   = Times
    Tsc.values                  = Values
    Tsc.quality                 = [0] * len(Values)
    Tsc.startTime               = Times[0]
    Tsc.endTime                 = Times[-1]
    Tsc.numberValues            = len(Values)
    if TimeZone is not None :
        Tsc.timeZoneID          = TimeZone
        Tsc.timeZoneRawOffset   = 0
        
    return Tsc

#==============================================================================
def getAlternativeNames() :
    '''
    Returns an array of strings
    '''
    names = []
    for run in getSimulationRuns() : names.append(run.getUserName())
    return names
    
#==============================================================================
def getCurrentModule() :
    '''
    Returns hec.client.ClientMode object
    '''
    return ResSim.getCurrentModule()
    
#==============================================================================
def getFPart(alternativeName) :
    '''
    Returns the F Part for the specified alternative name
    '''
    for run in getSimulationRuns() :
        if str(run) == alternativeName : 
            fpart = run.getKey()
            break
    else :
        raise ValueError, "Alternative Not Found: %s" % alternativeName
    return fpart
    
#==============================================================================
def getFParts() :
    '''
    Returns the F Parts for each alternative name
    '''
    fparts = {}
    for run in getSimulationRuns() :
        fparts[str(run)] = run.getKey()
    return fparts
    
#==============================================================================
def getOSIWindow(SwitchToTab):
	'''
    Retrieve the OSI window if open
    '''
    if(SwitchToTab):
        rssrun = ClientAppWrapper.getCurrentModule().getRssRun()
        return OpSupportPlugin.openOSI(rssrun)
    else:
        osiWindow = OpSupportPlugin.getOSI()
        if(osiWindow == None):
            print ('No OSI Window open. Using reservoir operations rules.')
            #raise EnvironmentError("No OSI Window open. Please open an OSI window or enable SwitchToTab")
        return osiWindow

#==============================================================================
def getResSimModelInfo() :
    '''
    Retrieve the module, simulation, network, Fpart, and OutputDssPath for the simulation
    '''
    module = ResSim.getCurrentModule()
    if `module` != "Simulation" :
        msg = "ResSim is not in Simulation Module, exiting."
        logOutput(msg)
        MessageBox.showError(msg, scriptName)
        return -1
    simulation = module.getSimulation()
    rssRun = module.getActiveRun()
    network = rssRun.getRssSystem()
    Fpart = rssRun.getKey()
    OutputDssPath = simulation.getOutputDSSFilePath()
    return module, simulation, Fpart, OutputDssPath

#==============================================================================
def getResSimTimewindow(simulation):
    '''
    getResSimTimewindow Function  : Get the ResSim time window
    Author/Editor                 : Mike Perryman
    Last updated                  : Unknown
    '''
    runTimeWindow = simulation.getRunTimeWindow()
    lookbackTime = runTimeWindow.getLookbackTimeString()
    startTime = runTimeWindow.getStartTimeString()
    endTime = runTimeWindow.getEndTimeString()

    return lookbackTime, startTime, endTime

#==============================================================================
def getSelectedAlternativeNames() :
    '''
    Returns an array of strings
    '''
    names = []
    for run in getSelectedSimulationRuns() : names.append(run.getUserName())
    return names
    
#==============================================================================
def getSelectedSimulationRuns() :
    '''
    Returns an array of hec.model.SimulationRun objects
    '''
    return selectModule("Simulation").getSelectedSimulationRuns()
    
#==============================================================================
def getSimulation() :
    '''
    Returns the current simulation
    '''
    simulation = selectModule("Simulation").getSimulation()
    if not simulation :
        raise Exception, "No simulation is currently open."
        
    return simulation
    
#==============================================================================
def getSimulationDSSFileName() :
    '''
    Returns the full name of the DSS file for the current simulation
    '''
    return getSimulation().getOutputDSSFilePath()
    
#==============================================================================
def getSimulationName() :
    '''
    Returns the name of the current simulation
    '''
    return getSimulation().getName()
    
#==============================================================================
def getSimulationRun(alternativeName) :
    '''
    Returns an hec.model.SimulationRun object
    '''
    run = selectModule("Simulation").getSimulationRun(alternativeName)
    if not run :
        raise ValueError, "Alternative Not Found: %s" % alternativeName
        
    return run 
    
#==============================================================================
def getSimulationRuns() :
    '''
    Returns an array of hec.model.SimulationRun objects
    '''
    return selectModule("Simulation").getSimulationRuns()
    
#==============================================================================
def getTab(opSupportFrame, tabName, SwitchToTab):
    '''
    getTab Function    : If SwitchToTab is True, attempt to open the specified OSI tab. If it isn't available, throw an error. If SwitchToTab
                         is False, get the current active tab.
    Author/Editor      : RMA
    Last updated       : Unknown
    '''
    if(not isinstance(opSupportFrame, OpSupportFrame)):
        raise TypeError("getTab expects an OpSupportFrame, was passed a " + type(opSupportFrame).__name__)
    if(SwitchToTab):
        success = opSupportFrame.setSelectedTab(tabName) # Should return an OpSupportTabPanel or null, returns a boolean
        if(success is False):
            raise EnvironmentError("No tab named "+tabName)
        tab = opSupportFrame.getSelectedTab()
    else :
        tab = opSupportFrame.getTab(tabName)
    return tab

#==============================================================================
def getTimeWindow() :
    '''
    Returns hec.heclib.util.HecTime objects for start and end time
    '''
    startTime = HecTime()
    endTime = HecTime()
    getCurrentModule().getTimeWindow(startTime, endTime)
    return startTime, endTime
    
#==============================================================================
def getTimeWindowString() :
    '''
    Returns time window as a string
    '''
    return getCurrentModule().getTimeWindowString()
    
#==============================================================================
def getWatershed() :
    '''
    Returns hec.client.ClientWorkspace object or None
    '''
    return ResSim.getWatershed()
    
#==============================================================================
def getWatershedName() :
    '''
    Returns string or None
    '''
    return ResSim.getWatershedName()

#==============================================================================
def isWatershedOpened() :
    '''
    returns whether any watershed is opened
    '''
    return ResSim.isWatershedOpened()
    
#==============================================================================
def openSimulation(simulationName) :
    '''
    causes the simulation module to open the specified simulation
    '''
    if not selectModule("Simulation").openSimulation(simulationName) :
        raise ValueError, "Simulation Not Found: %s" % simulationName
        
#==============================================================================
def openWatershed(watershedName) :
    '''
    returns hec.client.ClientWorkspace object or None
    '''
    return ResSim.openWatershed(watershedName)
#==============================================================================
def runSimulation(simulationName, newExtract=False, *alternativeNames) :
    '''
    returns True if all (possibly specified)  simulations are executed
    
    if no alternativenames are specified, all alternatives are executed
    '''
    
    #---------------------#
    # open the simulation #
    #---------------------#
    openSimulation(simulationName)

    #-----------------------------------#
    # get the runs for the alternatives #
    #-----------------------------------#
    if not alternativeNames :
        #------------------#
        # all alternatives #
        #------------------#
        runs = getSimulationRuns()
    else :
        #------------------------#
        # specified alternatives #
        #------------------------#
        runs = []
        for alternativeName in alternativeNames :
            runs.append(getSimulationRun(str(alternativeName).strip()))

    if newExtract :
        print("===========================================")
        start = time.time()
        print(time.ctime(start))
        print("Extracting data for %s" % str(getSimulation()))
        print("===========================================")
        extractSimulationData()
        print("===========================================")
        end = time.time()
        print(time.ctime(end))
        print("%s extract finished in %s" % (str(getSimulation()), hms(end - start)))
        print("===========================================")
    #----------------------#
    # run the alternatives #
    #----------------------#
    for run in runs : 
        print
        print("===========================================")
        start = time.time()
        print(time.ctime(start))
        print("Computing %s" % run)
        print("===========================================")
        computeSimulationRun(run)
        print("===========================================")
        end = time.time()
        print(time.ctime(end))
        print("%s compute finished in %s" % (run, hms(end - start)))
        print("===========================================")

    return True
      
#==============================================================================
def selectModule(moduleName) :
    '''
    returns hec.client.ClientMode object
    '''
    oldModule = getCurrentModule()
    oldModuleName = oldModule.getName()
    if oldModuleName == moduleName : 
        module = oldModule
    else :
        ResSim.selectModule(moduleName)
        module = ResSim.getCurrentModule()
        if not module or module.getName() != moduleName :
            ResSim.selectModule(oldModuleName)
            raise ValueError, "Invalid Module Name: %s" % moduleName
        
    return module
    
#==============================================================================
PY


Compute Functions

Compute scripts of functions can be used within a compute. Examples shown below are best utilized in scripted rules, state variables, etc.

Compute Functions

#==============================================================================
def getFraction(    val, 
                    loVal, 
                    hiVal
                    ) :
    '''
    Returns fraction of value between high and low values
    '''
    if hiVal == loVal : return 1.
    else : return float(val - loVal) / (hiVal - loVal)

#==============================================================================
def getInterp(  debug, # Set to True to print all debug statements
                seq, 
                val
                ) :
    '''
    Returns interpolation/extrapolation info for a tuple/list.  Returns the location in the list
    '''
    assert len(seq) > 1
    if val > seq[-1] :
        lo = len(seq) - 2
    else :
        lo = max(0, bisect(seq, val) - 1)
    fraction = getFraction(val, seq[lo], seq[lo+1])
    if   fraction > 1. : outputDebug(debug, lineNo(), '** Value %f above high value of %f' % (val, seq[-1]))
    elif fraction < 0. : outputDebug(debug, lineNo(), '** Value %f below low value of %f' % (val, seq[0]))
    return lo, fraction

#==============================================================================
def getYValue(  debug, # Set to True to print all debugging statements
                pdc, 
                lo, 
                fraction, 
                curve
                ) :
    '''
    Get the Y value from a curve
    '''
    hi = lo + 1
    return pdc.yOrdinates[curve][lo] + fraction * (pdc.yOrdinates[curve][hi] - pdc.yOrdinates[curve][lo])

#==============================================================================
def julianDay(  *args
                ) :
    '''
    Returns the julian day, accounting for leap years
    '''
    Year = args[-1] # The year should always be the last argument
    DaysPrev = [0]
    for x in range(1, 13, 1) :
        DaysPrev.append(DaysPrev[x - 1] + maxDay(x, Year))
    argCount = len(args)
    if argCount == 2 :
        if type(args[0]) == type(0) or type(args[0]) == type(0.0) :
            jday = args[0]
            if maxDay(2, Year) == 28 :
                if not 1 <= jday <= 365 :
                    raise ValueError('Julian day out of range 1..365')
            elif maxDay(2, Year) == 29 :
                if not 1 <= jday <= 366 :
                    raise ValueError('Julian day out of range 1..366')
            for i in range(12)[::-1] :
                if jday > DaysPrev[i] :
                    Month = i + 1
                    break
            Day = jday - DaysPrev[Month - 1]
            Date = '%s_%02d' % (calendar.month_abbr[Month], Day)
            return Date
        else :
            Month, Day = args[0].split('_')
            Month = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'].index(Month.upper()) + 1
            Day = int(Day);
            return julianDay(Month, Day, Year)
    elif argCount == 3 :
        Month, Day, Year = args
        if not 1 <= Month <= 12 :
            raise ValueError('Month is out of range 1..12')
        if not 1 <= Day <= 31 :
            raise ValueError('Day is out of range 1..31')
        
        return DaysPrev[Month - 1] + Day
    else :
        raise ValueError('Expected 2 or 3 arguments, got %d' % argCount)

#==============================================================================
def linearInterpolate(  xVal1,    # x value used for slope
                        xVal2,    # x value used for slope
                        yVal1,    # y value used for slope
                        yVal2,    # y value used for slope
                        xVal    # y value used for interpolation
                        ):
    '''
    Linearly interpolates to calculate a value
    '''
    slope = (yVal1 - yVal2) / (xVal1 - xVal2)
    interpVal = slope * (xVal - xVal2) + yVal2
    return interpVal

#==============================================================================
def lineNo() :
    '''
    Returns the current line number
    '''
    return inspect.currentframe().f_back.f_lineno

#==============================================================================
def maxDay( mon,    # Current month
            year    # Current year
            ) :
    '''
    Returns the total number of days in a month, accounting for leap years
    '''
    maxday = None
    if mon in (1,3,5,7,8,10,12) :
        maxday = 31
    elif mon in (4,6,9,11) :
        maxday = 30
    elif year % 4 != 0 or (year % 100 == 0 and year % 400 != 0) :
        maxday = 28
    else :
        maxday = 29
    return maxday

#==============================================================================
def outputDebug(    *args
                    ) :
    '''
    Prints formatted debug statements. Statements are "On" or "Off" depending on the first argument being True or False
    '''
    ArgCount = len(args)
    if ArgCount < 2 :
        raise ValueError('Expected at least 2 arguments, got %d' % argCount)
    if type(args[0]) != type(True) :
        raise ValueError('Expected first argument to be either True or False')
    if type(args[1]) != type(1) :
        raise ValueError('Expected second argument to be line number')

    if args[0] == True: 
        DebugStatement = 'Debug Line %d   |\t' % args[1]
        for x in range(2, ArgCount, 1) :
            DebugStatement += str(args[x])
        print DebugStatement

#==============================================================================
def percentile( debug,          # Set to True to print debug statements. Set to False to turn all debug statements off
                Values,         # List of values
                Quantile,       # Quantile of data requested
                EquationType    # There are multiple equations to estimate the value of a quantile. Type R-6 will match Excel's PERCENTILE.EXC and type R-7 will match
                                #    Excel's PERCENTILE.INC. Enter the type as a string i.e. 'R-6' or 'R-7'
                ) :
    '''
    Estimate quantile value based on a sample and specified quantile. The equations match the R-6 type of quantile estimation that is used by Excel's 
    PERCENTILE.EXC function
    '''
    if not Values : 
        return None
    SortedValues = sorted(Values)
    outputDebug(debug, lineNo(), 'Sorted Values = ', len(SortedValues))
    if EquationType == 'R-6' : 
        h = (len(SortedValues) + 1) * Quantile - 1
        if Quantile == 0. or Quantile == 1. : sys.exit('Quantiles between 0 and 1 are acceptable for R-6 equation type. If 0 or 1 is needed, change equation type to R-7.')
        if 0 < Quantile < 1 : pass
        else : sys.exit('Quantiles between 0 and 1 are acceptable for R-6 equation type.')
    elif EquationType == 'R-7' : 
        h = ((len(SortedValues) - 1) * Quantile + 1) - 1
        if 0 <= Quantile <= 1 : pass
        else : sys.exit('Quantiles between 0 and 1 are acceptable for R-6 equation type.')
    else : sys.exit('Only R-6 and R-7 equation types are supported with this function.')
    if h < 0 : h = 0
    f = math.floor(h)
    c = math.ceil(h)
    outputDebug(debug, lineNo(), 'h = ', h, '\tf = ', f, '\tc = ', c)
    if f == c :
        return SortedValues[int(h)]
    
    ValueOfQuantile = ((h - f) * (SortedValues[int(c)] - SortedValues[int(f)])) / (c - f) + SortedValues[int(f)]
    return ValueOfQuantile

#==============================================================================
def routeFlow(  RoutingCoefficients,    # List of routing coefficients
                FlowDataset             # Flow data that will be routed
                ) :
    '''
    Performs coefficient routing
    '''
    lag = len(RoutingCoefficients) - 1 # Length of time before any portion of flow reaches the downstream location
    routedFlow = []
    for i in range(len(FlowDataset)):
        if i < lag:
            routedFlow.append(0) # Add a place holder of 0 for days less than the lag time
        else:
            routedFlowTempList = []
            for c in range(len(RoutingCoefficients)):
                flow = FlowDataset[i-c] * RoutingCoefficients[c]
                routedFlowTempList.append(flow)
            release = sum(routedFlowTempList)
            routedFlow.append(release)
    return routedFlow

#==============================================================================
PY