Proof-of-concept for a Python interface written using Cython

This module is compatible with both Python 2 and Python 3. Unlike the existing
Python module, this module directly utilizes the Cantera C++ interface,
bypassing the "clib" compatibility layer, as well as all of the direct use of
the Python C API.

Currently, this contains just enough to instantiate a ThermoPhase object from an
XML input file.
This commit is contained in:
Ray Speth 2012-09-06 19:55:25 +00:00
parent ea16489a82
commit 8afc669b67
9 changed files with 202 additions and 0 deletions

View file

@ -790,6 +790,11 @@ std::string getChildValue(const Cantera::XML_Node& parent,
void get_CTML_Tree(Cantera::XML_Node* node, const std::string file,
const int debug = 0);
//! Read an ctml file from a file and fill up an XML tree.
//! @param file Name of the file
//! @return Root of the tree
Cantera::XML_Node getCtmlTree(const std::string file);
//! Convert a cti file into a ctml file
/*!
*

3
interfaces/cython/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
cantera/*.cpp
cantera/*.c
setup.py

View file

@ -0,0 +1 @@
from .solution import *

View file

@ -0,0 +1,43 @@
from libcpp.vector cimport vector
from utils cimport *
cdef extern from "cantera/thermo/ThermoPhase.h" namespace "Cantera":
cdef cppclass CxxThermoPhase "Cantera::ThermoPhase":
CxxThermoPhase()
double pressure() except +
void setMoleFractions(double*) except +
void getMassFractions(double*) except +
int nSpecies()
XML_Node& xml()
cdef extern from "cantera/kinetics/Kinetics.h" namespace "Cantera":
cdef cppclass CxxKinetics "Cantera::Kinetics":
CxxKinetics()
int nReactions()
cdef extern from "cantera/transport/TransportBase.h" namespace "Cantera":
cdef cppclass CxxTransport "Cantera::Transport":
CxxTransport(CxxThermoPhase*)
double viscosity() except +
cdef extern from "cantera/thermo/ThermoFactory.h" namespace "Cantera":
cdef CxxThermoPhase* newPhase(string, string) except +
cdef CxxThermoPhase* newPhase(XML_Node&) except +
cdef extern from "cantera/kinetics/KineticsFactory.h" namespace "Cantera":
cdef CxxKinetics* newKineticsMgr(XML_Node&, vector[CxxThermoPhase*]) except +
cdef extern from "cantera/transport/TransportFactory.h" namespace "Cantera":
cdef CxxTransport* newDefaultTransportMgr(CxxThermoPhase*) except +
cdef CxxTransport* newTransportMgr(string, CxxThermoPhase*) except +
cdef class _SolutionBase:
cdef CxxThermoPhase* thermo
cdef CxxKinetics* kinetics
cdef CxxTransport* transport

View file

@ -0,0 +1,84 @@
import numpy as np
cimport numpy as np
from cython.operator cimport dereference as deref
from utils cimport *
cdef class _SolutionBase:
def __cinit__(self, infile, phaseid=''):
rootNode = getCtmlTree(stringify(infile))
# Get XML data
cdef XML_Node* phaseNode
if phaseid:
phaseNode = rootNode.findID(stringify(phaseid))
else:
phaseNode = rootNode.findByName(stringify('phase'))
if phaseNode is NULL:
raise ValueError("Couldn't read phase node from XML file")
# Thermo
if isinstance(self, ThermoPhase):
self.thermo = newPhase(deref(phaseNode))
else:
self.thermo = NULL
# Kinetics
cdef vector[CxxThermoPhase*] v
if isinstance(self, Kinetics):
v.push_back(self.thermo)
self.kinetics = newKineticsMgr(deref(phaseNode), v)
else:
self.kinetics = NULL
# Transport
if isinstance(self, Transport):
self.transport = newDefaultTransportMgr(self.thermo)
else:
self.transport = NULL
def __dealloc__(self):
del self.thermo
del self.kinetics
del self.transport
cdef class ThermoPhase(_SolutionBase):
property nSpecies:
def __get__(self):
return self.thermo.nSpecies()
property pressure:
def __get__(self):
return self.thermo.pressure()
def setMoleFractions(self, X):
if len(X) != self.nSpecies:
raise ValueError("Mole fraction array has incorrect length")
cdef np.ndarray[np.double_t, ndim=1] X_c = np.ascontiguousarray(X, dtype=np.double)
self.thermo.setMoleFractions(&X_c[0])
property massFractions:
def __get__(self):
cdef np.ndarray[np.double_t, ndim=1] X_c = np.empty(self.nSpecies)
self.thermo.getMassFractions(&X_c[0])
return X_c
cdef class Kinetics(_SolutionBase):
property nReactions:
def __get__(self):
return self.kinetics.nReactions()
cdef class Transport(_SolutionBase):
property viscosity:
def __get__(self):
return self.transport.viscosity()
class Solution(ThermoPhase, Kinetics, Transport):
def __init__(self, *args, **kwars):
pass

View file

@ -0,0 +1,14 @@
from libcpp.string cimport string
cdef extern from "cantera/base/xml.h" namespace "Cantera":
cdef cppclass XML_Node:
XML_Node* findByName(string)
XML_Node* findID(string)
int nChildren()
cdef extern from "cantera/base/ctml.h" namespace "ctml":
XML_Node getCtmlTree(string) except +
cdef string stringify(x)

View file

@ -0,0 +1,7 @@
from utils cimport *
cdef string stringify(x):
""" Converts Python strings to std::string. """
# This method works with both Python 2.x and 3.x.
tmp = bytes(x.encode())
return string(tmp)

View file

@ -0,0 +1,37 @@
import os
from distutils.core import setup, Extension
from distutils.sysconfig import get_config_var
from Cython.Distutils import build_ext
dataFiles = ['_cantera%s' % get_config_var('SO')]
if os.name == 'nt':
dataFiles.append('cantera_shared.dll')
else:
dataFiles.append('libcantera_shared.so')
canteraExtensions = []
def addExtension(name):
canteraExtensions.append(Extension("cantera.%s" % name,
["cantera/%s.pyx" % name],
include_dirs=[".", "../../include"],
language="c++",
libraries=['cantera_shared','sundials_cvodes','sundials_idas','sundials_nvecserial','lapack','blas'],
library_dirs=['../../build/lib'],
extra_link_args=['-Wl,-rpath=$ORIGIN']))
addExtension('solution')
addExtension('utils')
setup(name="Cantera",
version="2.1a1",
description="The Cantera Python Interface",
long_description="""
""",
author="Raymond Speth",
author_email="speth@mit.edu",
url="http://code.google.com/p/cantera",
packages = ["cantera"],
cmdclass = {'build_ext': build_ext},
ext_modules = canteraExtensions,
package_data = {'cantera': dataFiles})

View file

@ -279,4 +279,12 @@ void get_CTML_Tree(Cantera::XML_Node* rootPtr, const std::string file, const int
rootPtr->build(fin);
fin.close();
}
Cantera::XML_Node getCtmlTree(const std::string file)
{
Cantera::XML_Node root;
get_CTML_Tree(&root, file);
return root;
}
}