Scripting ASCEND using Python
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
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) + ":" + 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) + ":" + 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) 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()