Catacomb does not need its own scripting language because JPython provides all the usual scripting facilities and a great deal more. JPython is the Java version of Python, a versatile, high-level, widely used and well supported object oriented language (and free).
If you have java installed, installing JPython is straightforward following the instructions on their Web site. A typical UNIX installation will put the jpython startup script in /usr/local/JPython-1.1/ so it is convenient to add this directory to your PATH environment variable.
To give jpython access to
catacomb, the file ccmb.jar must be in the CLASSPATH
variable when you start jpython. Supposing for example the file is in
/home/rcc/, then using bash you would need:
CLASSPATH="/home/rcc/ccmb.jar"; export CLASSPATH
using tcsh it would be
setenv CLASSPATH /home/rcc/ccmb.jar
Then, when you execute jpython it should print a message like:
packageManager: processing modified jar, "/home/rcc/ccmb.jar"
This will only appear the first time after you update the jar file.
To start the JPython interpreter, edit the CcmbPython object. First hold hte right mouse button on the system object and select show children. Then click python. This brings up a small window. From the CcmbPython menu select activate terminal. You can now type commands to the JPython interpreter just as if you were running JPython alone, except that you have access to Catacomb components too. First of all, to gain access to the Catacomb system
Sys = catacomb.Sys
We can now call methods (functions) in the catacomb object:
col = Sys.getObjectByName("extcolor")
Tells catacomb to find the object called "extcolor" and put it in the variable col. Then for example,
brings up the color editor. To instantiate a new framework for one of the models you can call the newObject method with the name of the framework as under the objects menu. For example,
makes a new numerics object for a simple differential equations.
Before manipulating components of the model, you must find them within catacomb, as you would with the tree display in the main window. The easiest way to do this from a script is with getObjectByName as in
calc = Sys.getObjectByName("diffeq")
As before, to get a visual editor for this object:
Now, you have a display of all the variables in the differential equation calculation object. Python can tell you what they are:
just prints the value of parameter B in the object called calc. Python can also change them:
To rerun the calculation change xmax with the slider a little. Now, the value B=0.5 is being used in the calculation (it gives rather bigger wiggles in the solution), but catacomb hasn't noticed that it has changed. Often this isn't a problem if you are running everything from python, but when you want the graphical side to keep up to data, you should call the function sync() on an object that has had its variables changed some way other than by catacomb itself.
Now move the mouse over the B slider: when the mouse arrives the slider checks that it has the latest value, finds that it doesn't and catches up. (it would be easy to make catacomb do the sync() itself and update all the sliders immediately, but this is a deliberate economy to avoid to much unnecessary rattling around of every tiny change).
The last key command for using the user interface with jpython is flagDataChange. This tells catacomb that the data has changed and that it should recompute anything necessary.
The graph should update to show the results of the calculation with the new parameter.
gives access to object in the Catacomb package.
Sys = catacomb.Sys
makes a shortcut to the Sys object which contains the most convenient methods for accessing Catacomb components. However, you still have to start Catacomb itself:
And you must specify an interactor object for it to communicate with the user:
Sys.interactor = catacomb.GuiInteractor()
You can then use all the comands demonstrated in the previous section in just the same way. Normally, python code is packaged in modules. The following example shows a short python module demo1.py. To run it, restart jpython and type:
from demo1 import *
The first command imports the demo1 module and instantiates the ccmb variable. The second runs the method numerics from that module. In addition to the functions above, it uses the sleep method from the class java.lang.Thread to put in some delays, and flagViewChange to tell the display that the data hasn't changed but the preferred view has, so it redraws the same data with the new axes. Something else to note about this module is that while Python statements looks lot like Java or c, there are no curly brackets. The block structure is derived exclusively from the indentation, so the blank spaces at the beginning of lines are not just a matter of taste: they define where blocks begin and end. The script won't run properly if the indentation is wrong.
import catacomb from java.lang import Thread csys = catacomb.Sys csys.init() csys.setInteractor(catacomb.GuiInteractor()) def numerics(): csys.newObject("Numerics") diffeq = csys.getObjectByName("diffeq") csys.editObject(diffeq) diffeq.B for i in range (10): diffeq.B = 1. / (1 + i) diffeq.sync() diffeq.flagDataChange() Thread.sleep(200) res = csys.getObjectByName("diffeq-results") res.x_max for i in range (100): res.x_max = abs (0.2 * (i-50)) res.flagViewChange () Thread.sleep(10)
switches catacomb into batch mode, stopping all its own rerunning and updating. To switch it back on use setInteractiveMode() or, equivalently setBatchMode(1) to switch it on and setBatchMode(0) to switch it off.
If you read the catacomb source to find methods to call from python, you will see that setBatchMode is defined with a boolean argument. When you call methods from python you don't have to worry too much about variable types: python will try to coerce them into what is needed, so, for example, here 0 means false, and 1 means true.
The next example demo2.py uses batch mode without the graphical interface. It also needs the model iafdemo.ccm. To run it, restart jpython and type:
from demo2 import *
The module loads the file, extracts references to various objects, then repeatedly changes a parameter, reruns the calculation, and extracts some values from the results. The nBetween(v, a, b) function counts the number of spikes in the vector v between times a and b. The batchRun() command simply runs the calculation defined in the iafCalc object in the current thread. The script carries on when the calculation returns.
import catacomb from string import ljust csys = catacomb.Sys csys.init() csys.setInteractor(catacomb.GuiInteractor()) def iafdemo(): csys.setBatchMode() csys.loadFile("iafdemo.ccm") calc = csys.getObjectByName("iafcalc") spikes = csys.getObjectByName("spikes") wf = csys.getObjectByName("wavefo_0") f = open('batchresults.txt','w') for i in range(50): yin = -20 + 1.5 * i wf.movePoint(2, 0, yin) calc.batchRun() tspk = spikes.getSpikes() n23 = nBetween(tspk23, 30, 60) n24 = nBetween(tspk24, 30, 60) print 'stim, n23, n24: ' + `yin` + ' ' + `n23` + ' ' + `n24` f.write(ljust(`yin`, 12)) f.write(ljust(`n23`, 12)) f.write(ljust(`n24`, 12)) f.write('\n') f.close() def nBetween (a, t1, t2): n = 0 for x in a: if x > t1 and x < t2: n = n + 1 return n