Cantera/Debugging Cantera from Python
From charlesreid1
This page explains how to run Cantera in debug mode via Python.
Note: thanks to Apple's continually-changing compiler toolchain, and their irritating obsession with abandoning standard tools, these instructions no longer work on OS X. I have not figured out how to debug C++ code called from Python using lldb, which has replaced gdb in the latest version of Mac OS X. To do this, you'll need to be running on Linux.
Contents
Creating a Cantera Debug Build
Before following this guide, you'll probably have to rebuild Cantera to include debugging symbols. See the Debugging Cantera page for instructions.
The Relation between Cantera and Python
Cantera is, at the core, a C++ library. When you download a copy of Cantera and build it, you are compiling C++ code into libraries of executable code. So, what does this have to do with Python?
Cantera has a Python interface - essentially, Python classes that are wrappers for the C++ interface. You have much of the same functionality with the Python and C++ libraries, but instead of a Cantera developer rewriting everything from C++ to Python (and probably making it run a lot slower in the process), the wrapper classes provide Python bindings for the underlying C++ code.
To run Cantera in debug mode through Python, what we'll do is run a Python driver, attach GDB to that process, and when Python calls the C++ library, GDB will follow the execution thread into the C++ library. At that point, GDB can halt, hit breakpoints, print stack traces, etc.
Running Cantera Through GDB and Python
Create Your Driver
Now that you have a debug build of Cantera, you'll need to create a driver, in Python, that uses the Cantera libraries. I'm going to issue a few simple commands. First I'll create a GRI Mech gas, then I'll equilibrate it. But I'll put a breakpoint in the equilibrate routine, to stop the code.
For this example, I'll use the following simple sequence of Python commands:
>>> from Cantera import *
>>> from Cantera.Reactor import *
>>> gas = GRI30()
>>> r = Reactor(gas)
>>> n = ReactorNet([r])
We will jump into the C++ core of Cantera, at the equilibrate() function, using gdb.
I'll need to attach GDB to the Python process in the midst of these commands. Order is very important here.
Debugging Cantera 2.0
Step 1: Import Python Module
The first step is to run
>>> from Cantera import *
>>> from Cantera.Reactor import *
This will load all of the Cantera libraries and hook them into Python.
Step 2: Determine Python PID, Attach GDB
The second step is to fire up GDB and attach it to the Python process. Do this by running ps
, and determine the process id (pid) of the Python instance.
For example, if you see this:
$ ps PID TTY TIME CMD 11832 ttys000 0:00.39 -bash 12071 ttys001 0:01.11 -bash 86612 ttys001 0:02.05 python
then your PID is 88612.
Fire up gdb, and run the attach
command:
$ gdb GNU gdb 6.3.50-20050815 (Apple version gdb-1515) (Sat Jan 15 08:33:48 UTC 2011) Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "x86_64-apple-darwin". (gdb) attach 86612
Now you will see the reason for importing the module from Python before attaching gdb to the Python process: the import command loads the C++ libraries.
Running this attach command will spew a bunch of stuff about libraries and such, debug information not being available, unfound object files, etc. Don't worry. What's happening here is, gdb is loading every library that Python is using (including, now that you've executed from Cantera import *
, every library that Cantera loads in).
A Note on Passing Control Between Python and GDB
When you attach gdb to the Python process, it will freeze the Python process and hand control over to gdb. When you issue the gdb command continue
, it will hand control back over to Python. Note that control must be passed to Python to execute Python commands, and must be passed to gdb to execute gdb commands.
If Python has control of the program, and you want to give control to gdb, you can switch to your gdb window and use Control+C to stop execution. You can do this with an interactive Python shell because it is interactive, and always listening.
If you want to switch control from gdb back to Python, you can use gdb's continue
command, which hands control of execution back to Python. Because Python is running as an interactive shell, Python returns to "listening" mode.
Step 3: Set Breakpoint
As mentioned, we'll be looking at a simple breakpoint example, specifically the ReactorNet constructor. First, we'll set the breakpoint in gdb:
Set a breakpoint in the ReactorNet constructor:
(gdb) b ReactorNet.cpp:24 Breakpoint 7 at 0x10efae0f9: file ReactorNet.cpp, line 24.
Now run the continue
command to pass control back to Python:
(gdb) continue Continuing.
If you see something like this:
(gdb) break ReactorNet.cpp:24 No source file named ReactorNet.cpp. Make breakpoint pending on future shared library load? (y or [n]) y Breakpoint 1 (ReactorNet.cpp:24) pending.
it means you didn't follow the instructions I gave at the top of the page! You have to create a debug build of Cantera.
Next, hand control back to Python:
(gdb) continue
Control has now been passed back to Python.
Step 4: Run Python Driver
Next step is to run the Python driver (the short set of commands listed above, which create a reactor network).
>>> gas = GRI30()
>>> r = Reactor(gas)
>>> n = ReactorNet([r])
The Python process should hang, and when you switch over to gdb, you should see a message about the breakpoint you have reached:
(gdb) continue Continuing. Breakpoint 7, Cantera::ReactorNet::ReactorNet (this=0x7f966ac37de0) at ReactorNet.cpp:24 24 m_integ = newIntegrator("CVODE");// CVodeInt; (gdb) Continuing.
Voila!
Now you can, e.g., get a backtrace:
(gdb) bt #0 Cantera::ReactorNet::ReactorNet (this=0x7f966ac37de0) at ReactorNet.cpp:24 #1 0x000000010efc3d1c in reactornet_new () at ctreactor.cpp:291 #2 0x000000010ed5f953 in py_reactornet_new (self=0x7fff51242b28, args=0x7f966ac00000) at ctreactor_methods.cpp:631 #3 0x000000010e9da5a9 in PyEval_EvalFrameEx () #4 0x000000010e9d8147 in PyEval_EvalCodeEx () #5 0x000000010ea11d7a in PyFunction_SetClosure () #6 0x000000010e9d06c6 in PyObject_Call () #7 0x000000010e9ed9bf in PyMethod_New () #8 0x000000010e9d06c6 in PyObject_Call () #9 0x000000010e9de018 in PyEval_CallObjectWithKeywords () #10 0x000000010e9eba7c in PyInstance_New () #11 0x000000010e9d06c6 in PyObject_Call () #12 0x000000010e9da78d in PyEval_EvalFrameEx () #13 0x000000010e9d8147 in PyEval_EvalCodeEx () #14 0x000000010e9d79b3 in PyEval_EvalCode () #15 0x000000010ea13c70 in PyParser_ASTFromFile () #16 0x000000010ea13ae9 in PyRun_InteractiveOneFlags () #17 0x000000010ea13578 in PyRun_InteractiveLoopFlags () #18 0x000000010ea13414 in PyRun_AnyFileExFlags () #19 0x000000010ea37e27 in Py_Main () #20 0x00007fff957e77e1 in start () Current language: auto; currently c++
You can see how Cantera's Python wrapper works: Python calls a binding function py_reactornet_new in ctreactor_methods.cpp, which in turn calls a C binding for creating a new reactor, which calls the actual C++ core of Cantera.
Debugging Cantera 1.8
The following is an example that works for Cantera 1.8 (but not for Cantera 2.0...):
>>> from Cantera import *
>>> gas = GRI30()
>>> gas.set(T=320.0, P=OneAtm, X='CH4:1,O2:2,N2:7.52')
>>> gas.equilibrate('HP')
(Cantera 1.8) Step 1: Import Python Module
From Python, import the Cantera module:
>>> from Cantera import *
>>> from Cantera.Reactor import *
(Cantera 1.8) Step 2: Determine Python PID, Attach GDB
Run the ps
command to see what Python's process ID is, then run the gdb command attach [pid]
.
$ gdb GNU gdb 6.3.50-20050815 (Apple version gdb-1705) (Fri Jul 1 10:50:06 UTC 2011) Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "x86_64-apple-darwin". (gdb) attach 446 Attaching to process 446. [...]
(gdb) break equilibrate.cpp:44 Breakpoint 1 at 0x101099bd9: file equilibrate.cpp, line 44.
Note: the equilibrate class is located in /path/to/cantera/src/equil/equilibrate.cpp
.
(Cantera 2.0) Step 3: Set Breakpoint
Set the breakpoint in the equilibrate class:
(gdb) break equilibrate.cpp:44 Breakpoint 1 at 0x101099bd9: file equilibrate.cpp, line 44.
Note: the equilibrate class is located in /path/to/cantera/src/equil/equilibrate.cpp
.
(Cantera 2.0) Step 4: Run Python Driver
Now run the remainder of the Python driver:
>>> gas = GRI30()
>>> gas.set(T=320.0, P=OneAtm, X='CH4:1,O2:2,N2:7.52')
>>> gas.equilibrate('HP')
Python should hang on the last command, and when you switch to the gdb window, you should see this:
(gdb) continue Continuing. Breakpoint 2, Cantera::equilibrate (s=@0x101f29130, XY=0x101b8a4b4 "HP", tol=1.0000000000000001e-09, maxsteps=1000, maxiter=100, loglevel=-1) at equilibrate.cpp:44 44 if (ixy == TP || ixy == HP || ixy == SP || ixy == TV) { (gdb) Continuing.
Voila! From here you can get a backtrace, step through code, etc etc etc.
Flags
Cantera all pages on the wiki related to the Cantera combustion microkinetics and thermodynamics (a.k.a. "thermochemistry") software.
Cantera · Cantera Outline · Category:Cantera
Outline of Cantera topics: Cantera Outline · Cantera Outline/Brief Understanding Cantera's Structure: Cantera Structure Cantera from Matlab: Using_Cantera#Matlab Cantera from Python: Using_Cantera#Python Cantera from C++: Using_Cantera#C++ Cantera + Fipy (PDE Solver): Fipy and Cantera/Diffusion 1D Cantera Gas Objects: Cantera/Gases Cantera 1D Domains, Stacks: Cantera_One-D_Domains · Cantera_Stacks Cantera Gas Mixing: Cantera_Gas_Mixing
Topics in Combustion: Diffusion: Cantera/Diffusion · Cantera/Diffusion Coefficients Sensitivity Analysis: Cantera/Sensitivity Analysis Analysis of the Jacobian Matrix in Cantera: Jacobian_in_Cantera Chemical Equilibrium: Chemical_Equilibrium Kinetic Mechanisms: Cantera/Kinetic_Mechanisms Reactor Equations: Cantera/Reactor_Equations Differential vs. Integral Reactors: Cantera/Integral_and_Differential_Reactors Effect of Dilution on Adiabatic Flame Temperature: Cantera/Adiabatic_Flame_Temperature_Dilution
Topics in Catalysis: Cantera for Catalysis: Cantera_for_Catalysis Steps for Modeling 0D Multiphase Reactor: Cantera_Multiphase_Zero-D Reaction Rate Source Terms: Cantera/Reaction_Rate_Source_Terms Surface coverage: Cantera/Surface_Coverage Surface reactions: Cantera/Surface_Reactions
Cantera Input Files: Chemkin file format: Chemkin CTI files: Cantera/CTI_Files · Cantera/CTI_Files/Phases · Cantera/CTI_Files/Species · Cantera/CTI_Files/Reactions
Hacking Cantera: Pantera (monkey patches and convenience functions for Cantera): Pantera Extending Cantera's C API: Cantera/Extending_C_API Extending Cantera with Python Classes: Cantera/Adding Python Class Debugging Cantera: Cantera/Debugging_Cantera Debugging Cantera from Python: Cantera/Debugging_Cantera_from_Python Gas Mixing Functions: Cantera_Gas_Mixing Residence Time Reactor (new Cantera class): Cantera/ResidenceTimeReactor
Resources: Cantera Resources: Cantera Resources Cantera Lecture Notes: Cantera_Lecture
Category:Cantera · Category:Combustion Category:C++ · Category:Python Flags · Template:CanteraFlag · e |
Installing Cantera notes on the wiki related to installing the Cantera thermochemistry software library.
Cantera Installation: Mac OS X 10.5 (Leopard): Installing_Cantera#Leopard Mac OS X 10.6 (Snow Leopard): Installing_Cantera#Snow_Leopard · Cantera2 Config Mac OS X 10.7 (Lion): Installing_Cantera#Lion Mac OS X 10.8 (Mountain Lion): Installing_Cantera#Mountain_Lion Ubuntu 12.04 (Precise Pangolin): Installing_Cantera#Ubuntu Windows XP: Installing_Cantera#Windows_XP Windows 7: Installing_Cantera#Windows_7
Cantera Preconfig: In old versions of Cantera, a preconfig file was used to specify library locations and options. Mac OS X 10.5 (Leopard) preconfig: Cantera_Preconfig/Leopard_Preconfig Mac OS X 10.6 (Snow Leopard) preconfig: Cantera_Preconfig/Snow_Leopard_Preconfig Mac OS X 10.8 (Mountain Lion) preconfig: Cantera_Config/MountainLion_SconsConfig Ubuntu 12.04 (Precise Pangolin) preconfig: Cantera_Config/Ubuntu1204_SconsConfig Flags · Template:InstallingCanteraFlag · e |