This tutorial is divided into the following sections: (1) Using soslibPy directly (2) Example Script Using soslibPy (examples/soslibPyTest.py) (3) Example Script Using SLPyObjects (examples/SLPyObjectsTest.py) (4) Two examples using Compucell3D (see the examples/cc3d folder) #### SECTION 1: Using soslibPy directly #### To use soslibPy directly, open a console window and go into the root directory where soslibPy was installed. Once there, start Python by typing 'python' and pressing Enter. If your python executable (python.exe) is not found (i.e. it is not in your system path), include the full path to the executable (e.g. c:/Python25/python, if your Python installation directory is c:/Python25) and press Enter. Import os and change the working directory to soslibPy: import os os.chdir("soslibPy") This folder contains the following files: -- soslibPy.py -- _soslibPy.pyd -- addPaths.py -- SLPyObjects.py We import the contents of the first file, soslibPy.py, with the following command: import soslibPy as slpy This, in turn, loads the soslibPy library, _soslibPy.pyd, making its functionality available within the namespace 'slpy'. Thus, any soslibPy function that we call must be prepended by 'slpy.' or Python will indicate that the function is not defined. We can read in a simple SBML model, defined in testModel.xml, using the following command: model = slpy.ODEModel_createFromFile("../examples/sbmlModels/testModel.xml") If the SBML file properly loaded, typing 'model' and pressing Enter should give output similar to the following: > where the address in memory will likely be different. This output indicates that an odeModel_t data structure has been created and a pointer to this structure has been returned. However, the object actually stored in the variable 'model' is a Python object that serves as a proxy to the actual SOSlib data structure. We may directly access data members of the data structure by typing 'model.' followed by the name of a data member such as 'neq', which provides the number of ODEs (only 1 in this case). However, one must pay attention to the return type. In this case, 'model.neq' returns an integer type, which Python knows how to print to the console. However, typing 'model.m' and pressing Enter will cause Python to crash. The return type, in this case, is Model_t for which a Python wrapper has not been created. Python has no suitable interpretation of what it means to print a Model_t to the console. In such cases, always store the return value as a variable. For example: m = model.m Doing so allows the Model_t to be passed (by pointer) to any SOSlib function that accepts an argument of type 'Model_t *'. The data structure stored in 'model' is of type odeModel_t (or technically, odeModel_t *, i.e. a pointer to an odeModel_t). SOSlib provides several functions to access information about this odeModel_t (see the header file, odeModel.h, at http://www.tbi.univie.ac.at/~raim/odeSolver/doc/api/odeModel_8h-source.html). The following are some examples: -- slpy.ODEModel_getNeq(model) -- slpy.ODEModel_getNumValues(model) -- slpy.ODEModel_dumpNames(model) The first command, like 'model.neq', provides the number of ODEs in the model (only 1 in this case). The second command returns the number of 'variables' (referring to both time-variant variables and constant parameters) in the model, which is 8. The final command listed above prints the string names of those variables to the console. Typing this command reveals that there are, indeed, 8 variables: S1 _J0 J1 compartment Xo X1 k1 k2 Among the most useful functions declared in odeModel.h are those that provide access to the model variables and their associated numerical values. We may access this information by index or string value and/or by pointer to a variableIndex_t data structure. For example: v = slpy.ODEModel_getVariableIndexByNum(model, 6) As mentioned, above, there are 8 variables in the model loaded from testModel.xml. These are indexed 0 through 7, so that index 6 corresponds to the parameter k1. The function ODEModel_getVariableIndexByNum returns a pointer to a variableIndex_t data structure, which we stored as 'v', above. We may be certain that this variable is the parameter k1 by typing the following: slpy.ODEModel_getVariableName(model, v) This returns a 'char *', which Python appropriately interprets and prints to the console as 'k1'. We make use of these and other functions in soslibPyTest.py, the example discussed in Section 2, below. But, before proceeding to Section 2, we briefly discuss two more essential data structures for running a numerical simulation: cvodeSettings_t and integratorInstance_t. These data structures are defined, respectively, in integratorSettings.h and integratorInstance.h (see http://www.tbi.univie.ac.at/~raim/odeSolver/doc/api/integratorSettings_8h-source.html and http://www.tbi.univie.ac.at/~raim/odeSolver/doc/api/integratorInstance_8h-source.html). An integrator instance is the last data structure created before running a numerical simulation. The creation of an integrator instance requires (1) a model (odeModel_t) and (2) integration settings (cvodeSettings_t). We saw, already, how to load an SBML model and store it as an odeModel_t. We may create a cvodeSettings_t data structure as follows: settings = slpy.CvodeSettings_createWithTime(2.0, 5) The first argument, 2.0, indicates the total time over which we would like to numerically integrate the ODEs. The second argument, 5, indicates the number of time steps at which to store and print results. Alternatively, we could have used the function CvodeSettings_create() to create a cvodeSettings_t data structure with default values of 1.0 and 10 for the stop time and the number of print steps, respectively. There is a third function, CvodeSettings_createWith, that allows finer control of numerical solver settings (such as integration method and tolerances), but we will simply use default values for all of these. SOSlib also provides several 'set' and 'get' functions to access and modify all these settings. We may now create an integrator instance with 'model' and 'settings', run a simulation and print the results: integrator = slpy.IntegratorInstance_create(model, settings) slpy.IntegratorInstance_integrate(integrator) slpy.IntegratorInstance_dumpNames(integrator) slpy.IntegratorInstance_dumpData(integrator) Alternatively, we could have used the function IntegratorInstance_integrateOneStep to advance the integrator only one step before printing results: slpy.IntegratorInstance_reset(integrator) slpy.IntegratorInstance_integrateOneStep(integrator) slpy.IntegratorInstance_dumpData(integrator) Notice that we had to reset the integrator before numerically integrating since we had already advanced the integrator to the stop time, 2.0. #### SECTION 2: Example Script Using soslibPy #### --> Python script: examples/soslibPyTest.py In this section, we discuss the content and output of the example Python script, soslibPyTest.py. Change the current working directory to 'examples' and run the script: os.chdir("../examples") from soslibPyTest import * The os.chdir command, as used in this case, assumes that you are in the directory 'soslibPy' (as a result of following the tutorial instructions in Section 1). So it is necessary to go up one directory before changing to the examples directory ("../examples"). If, however, you are in the root installation directory for soslibPy, simply type: os.chdir("examples"). In your console, you should see the output of soslibPyTest.py where distinct sections of the output are indicated by '-->'. The first section simply provides a brief description of the purpose of this Python script. The next section indicates the relative path and file name of the SBML model, 'sbmlModels/testModel.xml', provided to the ODEModel_createFromFile function. Opening the script (soslibPyTest.py) in a text editor, you may look at the actual commands used to pass the string argument "sbmlModels/testModel.xml" to the appropriate function and store the odeModel_t object in a variable, 'model': sbmlFile = "sbmlModels/testModel.xml" ... model = slpy.ODEModel_createFromFile(sbmlFile) This is very similar to what we saw already in Section 1 of this tutorial except that we stored the path and file name as 'sbmlFile' and then provided this string variable as an argument to the ODEModel_createFromFile function. The next section of the output prints 'model' to the console, indicating that the odeModel_t was properly created from testModel.xml. Next, we obtain the number of variables (both time-dependent variables and constant parameters) and loop through them, obtaining variableIndex_t objects that correspond to each. These are stored in a list, 'variables': numVariables = slpy.ODEModel_getNumValues(model) variables = [] for i in range(numVariables): currentVar = slpy.ODEModel_getVariableIndexByNum(model, i) variables.append(currentVar) print "\t%s" % currentVar Two soslibPy functions are used in this code segment, ODEModel_getNumValues and ODEModel_getVariableIndexByNum. We saw both of these functions in Section 1 of the tutorial. After each variableIndex_t object is created, it is printed to the console: > ... ... In the next few sections (1) a cvodeSettings_t object, 'settings', is created with a stop time of 2.0 and a print steps value of 10 and (2) an integratorInstance_t object, 'integrator', is created from 'model' and 'settings'. Again, this is essentially identical to what we did in Section 1 of the tutorial. In the final sections, we demonstrate how to access string names (illustrated also in Section 1 of the tutorial) and numerical values of time-dependent variables and constant parameters using references to variableIndex_t objects. For example: for i in range(numVariables): print "\t%s = %s" % (slpy.ODEModel_getVariableName(model, variables[i]), \ slpy.IntegratorInstance_getVariableValue(integrator, variables[i])) In this code segment, we loop over all the variableIndex_t objects, accessing the associated variable string names and numerical values and printing these to the console. The soslibPy function, here, that we have not seen previously is IntegratorInstance_getVariableValue. This is used to access numerical values of the variables. After integrating over the specified number of print steps (10), printing the integrator data to the console after each integration step, we use the same code segment, shown above, to print the final results: S1 = 1.6483997699 _J0 = 1.0 J1 = 0.32967995398 compartment = 1.0 Xo = 10.0 X1 = 0.0 k1 = 0.1 k2 = 0.2 Again, you may open the Python script 'soslibPyTest.py' in a text editor to see the actual code that generated the results shown in the console. #### SECTION 3: Example Script Using SLPyObjects #### --> Python script: examples/SLPyObjectsTest.py In this section, we discuss the content and output of the example Python script, SLPyObjectsTest.py. We assume your working directory is 'examples'. If not, type 'import os' and change the working directory using 'os.chdir'. Execute the script by typing the following: from SLPyObjectsTest import * In your console, you should see the output of SLPyObjectsTest.py where distinct sections of the output are indicated by '-->'. As was the case with soslibPyTest.py (discussed in Section 2), the first section of the SLPyObjectsTest.py output simply provides a brief description of the purpose of this Python script. The second section indicates the relative path and file name of the SBML model, 'sbmlModels/testModel.xml', that is loaded. However, looking at SLPyObjectsTest.py in a text editor, the function used to load the SBML model and create an odeModel_t data structure is simpler: sbmlFile = "sbmlModels/testModel.xml" ... model = ODEModel(sbmlFile) Here, and throughout the remainder of the Python script, we use a set of classes defined in SLPyObjects.py. Notice that these class definitions are loaded at the beginning of SLPyObjectsTest.py: from SLPyObjects import * Whereas 'model' in soslibPyTest.py is a Python proxy to a pointer to a SOSlib odeModel_t data structure, the 'model' object created in this case is a Python object that holds, as a data member, a Python pointer to an odeModel_t data structure. Compare the output of each Python script (soslibPyTest.py and SLPyObjectsTest.py) when you type 'model' and press Enter: Output from soslibPyTest.py: > Output from SLPyObjectsTest.py: Similarly, SLPyObjects.py provides the classes CVODESettings and IntegrInstance that 'wrap' the SOSlib data structures cvodeSettings_t and integratorInstance_t, respectively. Within the ODEModel class, the data member 'om' stores a pointer to the odeModel_t data structure so that typing 'model.om' and pressing Enter provides the following output: > Likewise, the data member 'cset' in CVODESettings stores a pointer to the cvodeSettings_t data structure and 'iinst' in IntegrInstance stores a pointer to the integratorInstance_t data structure. However, in all three classes, functions are defined to access information about the SOSlib data structures so that 'om', 'cset' and 'iinst' do not typically need to be accessed directly. Returning to the output of SLPyObjectsTest.py, a CVODESettings object named 'settings' is created with a stop time and a print step number of 1: settings = CVODESettings(1, 1) Instead of creating a single integrator instance, however, we create a list called 'cellArray' that stores five IntegrInstance objects: numCells = 5 ... cellArray = [] for index in range(numCells): cellArray.append(IntegrInstance(model, settings)) print "\t%s" % cellArray[index] Notice the command used to create each integrator instance from 'model' and 'settings': IntegrInstance(model, settings). After they are created, each one is printed to the console: Python scripts: EXAMPLE 1: examples/cc3d/SLPyIntegrator.py examples/cc3d/SLPyIntegratorSteppables.py EXAMPLE 2: examples/cc3d/SLPyIntegrElowitz2000.py examples/cc3d/SLPyIntegrElowitz2000Steppable.py To run these two examples, be sure that you have installed Compucell3D 3.3.1 from http://www.compucell3d.org/Download/. Once you have done so, start the application and open the Python file SLPyIntegrator.py ('File' -> 'Open Simulation'). Be sure that 'Use XML File' is not checked and that 'Run Python script' is checked (Note that the entire model/simulation description is encoded in Python and no XML file is required). Click on 'Browse...' and find 'examples/cc3d/SLPyIntegrator.py' from your soslibPy installation directory. Click 'OK' to accept. Before running the simulation, it is important to note that the default working directory is the location of your CompuCell installation. There are files upon which SLPyIntegrator.py and SLPyIntegrElowitz2000.py depend that CompuCell will not be able to find. The simplest solution to this is to add the following lines directly to SLPyIntegrator.py and SLPyIntegrElowitz2000.py *after* 'import sys': sys.path.append("{soslibPy_installation_path}\soslibPy") sys.path.append("{soslibPy_installation_path}\sbml\bin") Where {soslibPy_installation_path} is replaced by the full path to the root installation directory of soslibPy on your machine. In addition, copy the SBML files 'testModel.xml' and 'Elowitz2000_Repressilator.xml' from the 'examples/sbmlModels' directory of your soslibPy installation into your root CompuCell3D installation directory. Note that on some machines, it may not be necessary to include the second line above i.e. 'sys.path.append("{soslibPy_installation_path}\sbml\bin")'. This is the path to libsbml.dll (libSBML binary) and its dependencies.