Scripting ASCEND using Python

From ASCEND
Jump to: navigation, search

It's possible to write scripts that 'drive' ASCEND, using the Python language. These scripts can be used for any task you can think of, with the ASCEND engine providing the core capability of loading a system of equations, getting it ready to solve, and then solving it. For example:

  • you have a model and you want to run a large number of parameter studies on it. You can write a Python script to loop through different cases and solve the model for each one and extract the results and put them into a table.
  • you want to plot curves for thermodynamic property data, but the built-in plotting capability of ASCEND doesn't seem right for the job
  • you want to incorporate an ASCEND model into a program with a custom GUI to make it easier for non-technical users to use it
  • you want to write a test suite to check that a model still does what it did when you first write it, and you want to run that test suite automatically every night.

As well as the current suppport for Python scripting of ASCEND, it's also possible to write ASCEND scripts using Tcl/Tk. See for more information on that.

There are two different ways of accessing the Python API for ASCEND. The first way is the more natural one, which is to simply write a standalone Python script that wraps the ASCEND engine and makes it do things. The second way is via the ExtPy mechanism, which lets you write fragments of Python that can be run embedded within the METHODS interface in the PyGTK GUI. The first is better for quick hacks, the second is better for providing reusable functionality, although it still represents code at a somewhat experimental stage.

Currently, the best place to find examples of what can be done with the ASCEND Python API is in the code of the file test.py from the code repository. There is not yet any good documentation for the Python API, unfortunately.

Example of a standalone Python script with ASCEND

Here is an example of a simple script that loads a model (namely models/johnpye/testlog10.a4c) and solves it, then runs the 'self_test' method on the model, then prints out the value of a variable from the model.

#!/usr/bin/env python
# file 'example.py':

import ascpy
L = ascpy.Library()

L.load("johnpye/testlog10.a4c")

T = L.findType("testlog10")
M = T.getSimulation('sim')

M.solve(ascpy.Solver("QRSlv"),ascpy.SolverReporter())
M.run(T.getMethod('self_test'))

print "After solving, z =",float(M.z)

This script can be run using the command

PYTHONPATH=~/ascend/pygtk python example.py

As well as large amounts of debug output, this also finally outputs:

-----------------solve----------------
pygtk/simulation.cpp:804 (solve): Elapsed time: 0.000 (solver completed)
Converged
pygtk/simulation.cpp:889 (processVarStatus): There are 2 blocks
EMPTY METHOD CREATED
pygtk/simulation.cpp:214 (run): Running method self_test...
base/generic/utilities/error.c:161 (error_reporter_tree_end): TREE END
SUCCESS: /home/john/ascend/models/johnpye/testlog10.a4c:24:ASSERT: Assertion OK
SUCCESS: /home/john/ascend/models/johnpye/testlog10.a4c:25:ASSERT: Assertion OK
SUCCESS: /home/john/ascend/models/johnpye/testlog10.a4c:26:ASSERT: Assertion OK
base/generic/utilities/error.c:308 (va_error_reporter): DONE WRITING TREE
SUCCESS: Method 'self_test' returned 'all_ok' and output no errors.

After solving, z = 2.30258509299

With care, one can set up the model then repeatedly solve it for different variable values, etc.

Example of a script embedded within an ASCEND model

See ExtPy.

A more robust example

This example will work without needing to set any environment variables. We tested it on Ubuntu 9.04, but perhaps it still needs some tweaking for other releases and platforms:

This example solves a model for a few different values of one particular variable, and then plots the results using Matplotlib.

#!/usr/bin/env python
"""
For this script to work properly, you may need set the following environment vars:
LD_LIBRARY_PATH ...so that libascend can be found
ASCENDLIBRARY ...so that your models can be found
ASCENDSOLVERS ... so that the QRSlv solver can be found
PYTHONPATH ...so that 'import ascpy' works correctly.
"""

# some tricky stuff to set up the environment variables so that ASCEND can find 
# all the files it needs
import os, os.path, sys
if not os.environ.get('ASCENDLIBRARY'):
	if os.path.exists('/usr/bin/ascend'):
		ASCROOT="/usr/lib/ascend"
		os.environ['ASCENDLIBRARY'] = os.path.split(sys.path[0])[0] + ":" + os.path.join(ASCROOT,"models")
		os.environ['PYTHONPATH'] = "/usr/lib/python2.6/dist-packages/ascend/"
		print "Using installed version of ASCEND"
	else:
		ASCROOT= os.path.expanduser("~/ascend")
		os.environ['ASCENDLIBRARY'] = os.path.split(sys.path[0])[0] + ":" + os.path.join(ASCROOT,"models")
		os.environ['ASCENDSOLVERS'] = os.path.join(ASCROOT,"solvers","qrslv")
		os.environ['PYTHONPATH'] = os.path.join(ASCROOT,"ascxx") + ":" + os.path.join(ASCROOT,"pygtk")
		os.environ['LD_LIBRARY_PATH'] = ASCROOT
	script=os.path.join(sys.argv[0])
	print "Restarting with corrected environment"
	os.execvp('/usr/bin/python',[script,script]+sys.argv[1:])

import ascpy, pylab

def airrec_tester():
	# prepare ASCEND's library object. you gotta do that.
	L = ascpy.Library()

	# load our model file
	L.load('air_receiver.a4c')

	# hunt for the model name that we need from the file that we loaded
	T = L.findType('air_receiver')

	# create the simulation. this is the same as the 'simulation' tab in the GUI
	M = T.getSimulation('sim')

	# run the 'on_load' method for this model... FIX all the vars, values etc.
	M.run(T.getMethod('on_load')) # you have to explicitly do this in Python

	# now, create a set of diameter values that we will want to solve
	dd = [40,50,60,70]
	# this will contain the results for the pressure drops at different diameters.
	dpp = []
	
	# assign the 'QRSlv' solver to the problem
	M.setSolver(ascpy.Solver("QRSlv"))

	# loop through the different diameters
	for d in dd:
		# set the pipe inside diameter to the value that we want
		M.pipe.d_i.setRealValueWithUnits(d,"mm")
		
		print "\n\n\nd_i = %f \n\n\n" % float(M.pipe.d_i)

		# solve the model
		M.solve(ascpy.Solver("QRSlv"),ascpy.SolverReporter())

		# store the pressure drop in our list
		dpp += [float(M.dp)/1.e5]

	# now, we finished, so plot the results
	pylab.plot(dd,dpp)

	# you have to do 'show' or else the plot won't appear!
	pylab.show()

# run all the stuff above!
airrec_tester()