It is possible to run ResSim simulations on the command line without actually opening the ResSim graphical user interface (GUI). This is called running ResSim "headless." Often, headless computing is used to save time, particularly when there are many simulations that must be run consecutively, or when a simulation needs to be automated in some way. To perform a headless compute, a user needs to run a jython script on their computer's command line. This can be done by typing directly on the command line via the command prompt or executing a batch (.bat) file. This web page describes how to enter commands and arguments onto the command line, how to create and run a .bat file, and how to use example jython scripts to perform headless ResSim computes.

Using the Command Line

A command-line interface is a means of executing programs, running scripts, and managing files through text commands instead of using the mouse and graphical interface of your computer. In Windows, the built-in Command Prompt app is used to type commands on the command line.

When the command prompt opens, text will appear indicating the current directory that arguments on the command line are directed to.

In order to change the current directory, type 'cd' followed by a space, followed by the pathname of the new directory. When running ResSim from the command line, it is easiest to set the current directory to the ResSim program directory (i.e., the directory where the HEC-ResSim.exe file is found). After setting the current directory to the ResSim program directory, the user simply needs to place the jython script they would like to run in the ResSim program directory, then type 'HEC-ResSim' followed by a space, followed by the name of the script (e.g., 'script_1a.py') on the command line. The space character separates arguments on the command line, so if there are additional arguments needed to run the script, they should be separated with a space. Once you've finished typing your command, press Enter to run it. The example below shows a user setting the current directory to the ResSim program directory and then running a script called script_1a.py (explained in detail later) with several arguments. Note it is not necessary to enclose arguments in brackets, that was just done for this example to make them easier to see.

It can make things easier to put your script in the ResSim program directory, but it isn't absolutely necessary. If the script is located in a different directory, simply use its full pathname instead of the shortened 'script_1a.py' when entering it on the command line.

Using a Batch File

A batch (.bat) file is a shortcut method of running commands on the command line. Instead of opening the Command Prompt and typing a command each time you'd like to run a script, you can create a .bat file that has your command saved inside it. Then to run the command, all you need to do is double-click on the .bat file.  Batch files can be created by creating a .txt file with a text editor like Notepad or Notepad++ and then saving the .txt file as a .bat file.  The example below shows the contents of a .bat file used to perform the command in the figure above.

 

For the .bat file shown above to work, it must be located in the same directory as the ResSim program and the script_1a.py script. If you don't want the .bat file to be in the same location as the ResSim program files and/or jython script, simply specify the full path for the HEC-ResSim.exe file and the script_1a.py file.

Below is another example of a .bat file. This .bat file specifies the full path for the ResSim executable and the script, which means it can be run from any directory. Set is used to create variables, and the % symbol is used to signify a command line parameter (i.e., an argument). A space separates each argument.


Just like a python script, a .bat file can be run from the command line. If the .bat file is run by double-clicking it in the file explorer, the console window will open while the script is running and then close automatically when the script is finished. If you want the console window to stay open so you can view print statements and debug any errors in the script, you will need to open the Command Prompt app (or similar command line interface if not using Windows) and run the .bat file from there.

Example script_1a.py

script_1a.py

# Imports
from hec.script import ResSim
from hec.script import Constants
import os

# User inputs: watershed directory, watershed name, watershed .wksp file, simulation name, alternative name
watershedDir = os.path.realpath(sys.argv[0])
watershedName = sys.argv[1]
watershedWkspFile = os.path.realpath(sys.argv[2])
simName = sys.argv[3]
altName = sys.argv[4]

print '#===================================================='
print '#=== User inputs: =================================='
print "Argument 1 -> Watershed Directory =", watershedDir
print "Argument 2 -> Watershed Name =", watershedName
print "Argument 3 -> Watershed .wksp File =", watershedWkspFile
print "Argument 4 -> Simulation Name =", simName
print "Argument 5 -> Alternative Name =", altName
print '#===================================================='

# ResSim only likes unix-style path
watershedWkspFile = watershedWkspFile.replace(os.sep, "/")

# Open the watershed
ResSim.openWatershed(watershedWkspFile)
print '#===================================================='
print 'ResSim Watershed Name:', ResSim.getWatershedName()
print '#===================================================='

# If watersehd name doesn't match what is expected, raise exception
if ResSim.getWatershedName() != watershedName :
    raise Exception("Unable to open watershed %s" % watershedWkspFile)

# Open the simulation module
ResSim.selectModule('Simulation')

# Get the current module
print '#===================================================='
print '#=== Opening simulation module ======================'
print '#===================================================='
simMode = ResSim.getCurrentModule()
simMode.resetWorkspace()
# Print the type and name of the simMode object (not necessary, but useful syntax for debugging)
print '#=== simMode type ==='
print type(simMode)
print '#=== simMode name ==='
print simMode.getName()

# Open the target simulation
print '#===================================================='
print '#=== Opening simulation ============================='
print '#===================================================='
simMode.openSimulation(simName)
simulation = simMode.getSimulation()
simulation.setComputeAll(1)
simRun = simulation.getSimulationRun(altName)
print '#===================================================='
print 'Simulation Name:', simName
print '#===================================================='

# Compute and save the target simulation, then close the watershed
print '#===================================================='
print '#=== Computing simulation ==========================='
print '#===================================================='
simMode.computeRun(simRun, -1, Constants.TRUE, Constants.TRUE)
print '#===================================================='
print '#=== Saving simulation =============================='
print '#===================================================='
ResSim.getCurrentModule().saveSimulation()
print '#===================================================='
print '#=== Closing watershed =============================='
print '#===================================================='
ResSim.closeWatershed()
print '#===================================================='
PY

The first example script simply opens a ResSim watershed, computes a simulation, and saves the simulation. The script takes 5 arguments:

  1. Watershed directory
  2. Watershed name
  3. Watershed .wksp file
  4. Simulation name
  5. Alternative name

The figure below shows the text in the Command Prompt that will run the script using a sample watershed, assuming the script is named 'script_1a.py' and it is located in the ResSim program directory. In the case of this example, the arguments are as follows:

  1. Watershed directory = C:\Cybertron\HEC\ResSim_Testing\3.5_TEST_model\SourisRiverPoS
  2. Watershed name = SourisRiverPoS
  3. Watershed .wksp file = C:\Cybertron\HEC\ResSim_Testing\3.5_TEST_model\SourisRiverPoS\SourisRiverPoS.wksp
  4. Simulation name = TEST_headless
  5. Alternative name = Base_LD2

In Windows, you can copy the pathname for a specific file by holding the Shift key, right-clicking on the file, and selecting Copy as path.

Example script_1b.py

script_1b.py

# Imports
from hec.script import ResSim
from hec.script import Constants
import os

# User inputs: simulation name, alternative name, watershed directory, watershed wksp file
simName = "TEST_general"
altName = "Base_LD2"
watershedDir = r"C:\Cybertron\HEC\ResSim_Testing\3.5_TEST_model\SourisRiverPoS"
watershedName = "SourisRiverPoS"
watershedWkspFile = r"C:\Cybertron\HEC\ResSim_Testing\3.5_TEST_model\SourisRiverPoS\SourisRiverPoS.wksp"

# ResSim only likes unix-style path
watershedWkspFile = watershedWkspFile.replace(os.sep, "/")

# Open the watershed
ResSim.openWatershed(watershedWkspFile)
print '#===================================================='
print 'ResSim Watershed Name:', ResSim.getWatershedName()
print '#===================================================='

# If watersehd name doesn't match what is expected, raise exception
if ResSim.getWatershedName() != watershedName :
    raise Exception("Unable to open watershed %s" % watershedWkspFile)

# Open the simulation module
ResSim.selectModule('Simulation')

# Get the current module
print '#===================================================='
print '#=== Opening simulation module ======================'
print '#===================================================='
simMode = ResSim.getCurrentModule()
simMode.resetWorkspace()
# Print the type and name of the simMode object (not necessary, but useful syntax for debugging)
print '#=== simMode type ==='
print type(simMode)
print '#=== simMode name ==='
print simMode.getName()

# Open the target simulation
print '#===================================================='
print '#=== Opening simulation ============================='
print '#===================================================='
simMode.openSimulation(simName)
simulation = simMode.getSimulation()
simulation.setComputeAll(1)
simRun = simulation.getSimulationRun(altName)
print '#===================================================='
print 'Simulation Name:', simName
print '#===================================================='

# Compute and save the target simulation, then close the watershed
print '#===================================================='
print '#=== Computing simulation ==========================='
print '#===================================================='
simMode.computeRun(simRun, -1, Constants.TRUE, Constants.TRUE)
print '#===================================================='
print '#=== Saving simulation =============================='
print '#===================================================='
ResSim.getCurrentModule().saveSimulation()
print '#===================================================='
print '#=== Closing watershed =============================='
print '#===================================================='
ResSim.closeWatershed()
print '#===================================================='
PY


The second example script has the same functionality as the first example, but all of the arguments are hard-coded into the script, so they don't need to be entered onto the command line. Using a .bat file is an excellent way to run a script like this, since the arguments will be the same every time. In this case, the full pathname has been specified for both the HEC-ResSim program and the script, so the .bat file can be run from any directory.

RUNscript_2.bat

"C:\Programs for portable applications\HEC-ResSim_Development\HEC-ResSim-3.5.0.532\HEC-ResSim.exe" "C:\Programs for portable applications\HEC-ResSim_Development\HEC-ResSim-3.5.0.532\script_1b.py"
PY


Example script_2.py

script_2.py

# Imports
from hec.script import ResSim
from hec.script import Constants
from hec.heclib.util import HecTime
from java.lang import String
import jarray
import os

# User inputs: watershed directory, watershed .wksp file, simulation name, alternative name, lookback time, start time, end time
watershedDir = os.path.realpath(sys.argv[0])
watershedWkspFile = os.path.realpath(sys.argv[1])
simName = sys.argv[2]
altName = sys.argv[3]
lookBackTime = sys.argv[4]  # <-- should be in the format "ddMMMyyyy,hh:mm", example: 01JAN2015,00:00
startTime = sys.argv[5]  # <-- should be in the format "ddMMMyyyy,hh:mm", example: 15JAN2015,00:00
endTime = sys.argv[6]       # <-- should be in the format "ddMMMyyyy,hh:mm", example: 31DEC2015,00:00

print '#===================================================='
print '#=== User inputs: =================================='
print "Argument 1 -> Watershed Directory =", watershedDir
print "Argument 2 -> Watershed .wksp File =", watershedWkspFile
print "Argument 3 -> Simulation Name =", simName
print "Argument 4 -> Alternative Name =", altName
print "Argument 5 -> Lookback Time =", lookBackTime
print "Argument 6 -> Start Time =", startTime
print "Argument 7 -> End Time =", endTime
print '#===================================================='

# ResSim only likes unix-style path
watershedWkspFile = watershedWkspFile.replace(os.sep, "/")

# Pad the alternative name with dashes to 10 characters
# This is what ResSim actually stores the altenative name as and is needed for createSimulation() later
altNamePadded = altName
altNamePadded = altNamePadded.replace(' ', '$')
altNamePadded = altNamePadded.ljust(10)
altNamePadded = altNamePadded.replace(' ', '-')
altNamePadded = altNamePadded.replace('$', ' ')

# Get the padded alternative name as a string for createSimulation() later
alt = jarray.array([altNamePadded], String)

# Open the watershed
ResSim.openWatershed(watershedWkspFile)
print '#===================================================='
print 'ResSim Watershed Name:', ResSim.getWatershedName()
print '#===================================================='

# Open the simulation module
ResSim.selectModule('Simulation')

# Get the current module
print '#===================================================='
print '#=== Opening simulation module ======================'
print '#===================================================='
simMode = ResSim.getCurrentModule()
simMode.resetWorkspace()

# If the simulation exists, delete it. Does not remove its directory
if simMode.simulationExists(simName):
    print '#==================================================================='
    print '#=== Simulation already exists. Deleting existing simulation... ===='
    print '#==================================================================='
    simMode.deleteSimulation(simName)
    print '#=== Simulation deleted ======================'

# Create a simulation with a daily time step
print '#===================================================='
print '#=== Creating simulation:', simName
print '#===================================================='
simulation = simMode.createSimulation(simName, "Description for test simulation", lookBackTime, startTime, endTime, 1, HecTime.DAY_INCREMENT, alt)

# Example of creating a simulation with a 6-hour timestep:
# simulation = simMode.createSimulation(simName, "Description for test simulation", lookBackTime, startTime, endTime, 6, HecTime.HOUR_INCREMENT, alt)

# Open the simulation
print '#===================================================='
print '#=== Opening simulation:', simName
print '#===================================================='
simMode.openSimulation(simName)
simulation = simMode.getSimulation()
simulation.setComputeAll(1)
simRun = simulation.getSimulationRun(altName)

# Compute and save the target simulation, then close the watershed
print '#===================================================='
print '#=== Computing simulation:', simName
print '#===================================================='
simMode.computeRun(simRun, -1, Constants.TRUE, Constants.TRUE)
print '#===================================================='
print '#=== Saving simulation:', simName
print '#===================================================='
ResSim.getCurrentModule().saveSimulation()
print '#===================================================='
print '#=== Closing watershed =============================='
print '#===================================================='
ResSim.closeWatershed()
print '#===================================================='
PY


The third example script opens a watershed, creates a new simulation using an existing alternative, and computes and saves the new simulation. The script takes 7 arguments:

  1. Watershed directory
  2. Watershed .wksp file
  3. Simulation name
  4. Alternative name
  5. Lookback time
  6. Start time
  7. End time

Note the lookback time, start time, and end time should be in the format "ddMMMyyyy,hh:mm" (e.g., 01JAN2015,00:00)

Server-Side Scripts

All of the example scripts above are called "client-side" scripts because they utilize various methods and options in the ResSim user interface (UI) even though the UI is not visible. Client-side scripts are usually the simplest kinds of scripts to read and understand because the methods they use correspond to options in the ResSim UI that users are familiar with. For example, the ResSim.openWatershed() method is literally the File>Open Watershed... option from the ResSim UI. Another way to write a script for headless computes is to use "server-side" methods. A script that uses these methods is called a server-side script. These scripts take advantage of the client-server nature of ResSim and expect ResSim to be launched without its UI. While they are a bit more complicated than client-side scripts, server-side scripts are ultimately more computationally efficient because the methods they use bypass the ResSim UI completely.

In order to run a server-side script, a user must first add two additional files to their ResSim program directory, HEC-ResSim-server.config and HEC-ResSim-server.exe. These files are contained in the 7zip file below:

ResSimServerLauncher.7z

Example Server-Side Script

Example Server-Side Script

# RunHeadless.py
# This is a ResSim (server-side) command script to:
# open a watershed, then compute an alternative in a simulation

from hec.server import RmiAppImpl
from hec.io import Identifier
from java.lang import System
from hec.rss.model import SimulationExtractModel
from hec.script import Constants
from rma.util import RMAIO
from hec.heclib.dss import HecDSSFileAccess
import os

def openWatershed(workspaceFile, user):
	rmiApp = RmiAppImpl.getApp()

	workspaceFile = workspaceFile.replace(os.sep, "/")	#ResSim doesn't like backslashes in paths
	assert os.path.isfile(workspaceFile), "####SCRIPT### - Watershed file does exist"

	id = Identifier(workspaceFile)
	rmiWksp = rmiApp.openWorkspace(user, id)
	if rmiWksp == None:
		print("ERROR: Failed to open Watershed "+workspaceFile)
		return rmiWksp
	rssRmiWksp = rmiWksp.getChildWorkspace("rss")
	return rssRmiWksp

def openSimulation(simulationName, rssWksp):
	wtrshdPath= rssWksp.getWorkspacePath()
	simulationPath = wtrshdPath+"/rss/"+simulationName+".simperiod"
	assert os.path.isfile(simulationPath), "####SCRIPT### - Simulation's simperiod file does exist"

	simId = Identifier(simulationPath)
	simMgr = rssWksp.getManager("hec.model.SimulationPeriod", simId)
	if simMgr == None:
		print("ERROR: Failed to getManager for simulation "+simulationName)
		return simMgr
	simMgr.loadWorkspace(None,wtrshdPath)
	return simMgr

def runExtract(simMgr):
	success = simMgr.runExtract(SimulationExtractModel())
	if success:
		print("####SCRIPT### finished extracting")
	else:
		print("####SCRIPT### extract failed")
	return 0

def computeAll(simMgr):
	runs = simMgr.getSimulationRuns()
	for run in runs:
		altname = run.getUserName()
		print("\n####SCRIPT### ----------------------------------------------------------------------------------------------")
		print("####SCRIPT### Computing alternative: \t" +altname)
		print("####SCRIPT### ----------------------------------------------------------------------------------------------\n")
		simRun = simMgr.getSimulationRun(altname)
		if simRun != None:
			simRun.getRssAlt().setLogLevel(LogLevel)		#log level controls how much messaging is sent to the console and log
			simMgr.setComputeAll(Constants.TRUE)
			if simMgr.computeRun(simRun,-1):
				print("####SCRIPT### Computed "+altname+" successfully")
			else:
				print("ERROR: "+altname+" failed to compute\n")
	return 0
	
def computeRun(altName, simMgr):
	simRun = simMgr.getSimulationRun(altName)
	if simRun == None:
		print("ERROR: Failed to find SimulationRun "+altName)
		return 1
	print("\n####SCRIPT### ----------------------------------------------------------------------------------------------")
	print("####SCRIPT### Computing alternative: \t" +altName)
	print("####SCRIPT### ----------------------------------------------------------------------------------------------\n")
	simRun.getRssAlt().setLogLevel(LogLevel)		#log level controls how much messaging is sent to the console and log
	simMgr.setComputeAll(Constants.TRUE)	#ComputeAll=True forces the compute even if already computed
	if simMgr.computeRun(simRun, -1):
		# do something
		print("####SCRIPT### Computed "+altName+" successfully")
	else:
		print("ERROR:"+altName+" failed to compute\n")
	return 0

#
#	Main()
#
print "\n####SCRIPT### - commandline args", sys.argv[0:]
programName  = "BatchRunControl"
wkspfile = ""
simulationName = ""
alternativeName = ""
argcnt = len(sys.argv)
if argcnt < 2 :
	# This script assumes that you are using a Windows batch file to run ResSim headless 
	# and that you are specifying the workspace file, the simulation name, and the alternative name 
	# that you want to run in that file (and on the command line).  If you prefer to enter them here
	# in the script, follow the instructions below:
	#	Uncomment and Revise the following three strings to match your watershed, simulation, and alternative names.
	#		The wkspFile must be a fully qualified path to the .wksp file in your watershed.
	#		The simulationName is only the name of the simulation, not the path to it.
	#		The alternativeName is only the name of the alternative, not the run name (i.e., no dashes).
	#		NOTE: you can enter -All- for the alternativeName to compute all alternatives in the simulation.
	#	Then, comment out the following print and System.exit(2) statements
	
	#wkspFile = r"E:\Testing\ResSim3.5\BaldEagle_V3.3\BaldEagle_V3.3\BaldEagle_V3.3.wksp"
	#simulationName = "1993.11.27-1400"
	#alternativeName = "WithDSOps"
	#alternativeName = "-All-"
	
	print("The following arguments must follow this script's name on the HEC-ResSim command line.")
	print("Watershed(wksp)_file simulation_name [alternative_name]")
	System.exit(2)
else :
	# HEC-ResSim driver only passes the command line entries that follow the script name as arguments to the script
	wkspFile = os.path.realpath(sys.argv[0])
	simulationName = sys.argv[1]
	if argcnt > 2:
		alternativeName = sys.argv[2]
	else:
		alternativeName = "-All-"

LogLevel = 3
user = System.getProperty("user.name")

print("\n####SCRIPT### ----------------------------------------------------------------------------------------------")
print("####SCRIPT### - Workspace file:\t"+wkspFile)
print("####SCRIPT### - Simulation:\t"+simulationName)
print("####SCRIPT### - Alternative:\t"+alternativeName)
print("####SCRIPT### - User:\t\t"+user)
print("####SCRIPT### ----------------------------------------------------------------------------------------------\n")

wksp = openWatershed(wkspFile, user)
if wksp == None: sys.exit("####SCRIPT### - openWatershed failed")
watershedDir = wksp.getWorkspacePath()

# This next command turns down the HEC-DSS logging level to the lowest level. (default level is 4)
from hec.heclib.dss import HecDSSFileAccess
HecDSSFileAccess.setMessageLevel(1)

sim = openSimulation(simulationName, wksp)
if sim == None: sys.exit("####SCRIPT### - openSimulation failed")

# runExtract(sim)

if alternativeName == "-All-":
	status = computeAll(sim)
else:
	status = computeRun(alternativeName, sim)

wksp.closeWorkspace(user)

if status == 0 :
	print("####SCRIPT### Script Complete - Compute Completed Successfully")
else:
	print("####SCRIPT### Script Complete - Compute Failed")


PY


This is an example of a server-side script that opens a watershed and computes an alternative in a simulation. Note the script can compute multiple alternatives in a simulation if the alternativeName is set to "-All-" but it will not compute a trial.