From f8df6e432f8099a2eb303913117ad8cbfeb15b0e Mon Sep 17 00:00:00 2001 From: Dave Goodwin Date: Thu, 26 Apr 2007 23:00:14 +0000 Subject: [PATCH] improved functors --- Cantera/clib/src/ctfunc.cpp | 45 ++++++++++++++++---- Cantera/clib/src/ctfunc.h | 2 + Cantera/python/Cantera/Func.py | 23 ++++++++-- Cantera/python/src/ctfunc_methods.cpp | 22 ++++++++++ Cantera/python/src/methods.h | 1 + Cantera/src/Func1.cpp | 60 +++++++++++++++++++++++---- Cantera/src/Func1.h | 27 ++++++++---- 7 files changed, 152 insertions(+), 28 deletions(-) diff --git a/Cantera/clib/src/ctfunc.cpp b/Cantera/clib/src/ctfunc.cpp index 7cf0feb14..3ae11a0f1 100755 --- a/Cantera/clib/src/ctfunc.cpp +++ b/Cantera/clib/src/ctfunc.cpp @@ -1,6 +1,7 @@ #include "Func1.h" #include "ctexceptions.h" + using namespace Cantera; #include "Cabinet.h" @@ -50,6 +51,9 @@ extern "C" { "exponent for pow must be supplied"); r = new Pow1(params[0]); } + else if (type == ConstFuncType) { + r = new Const1(params[0]); + } else if (type == FourierFuncType) { if (lenp < 2*n + 2) throw CanteraError("func_new", @@ -79,28 +83,35 @@ extern "C" { r = new Periodic1(*_func(n), params[0]); } else if (type == SumFuncType) { - r = new Sum1(*_func(n), *_func(m)); + r = &newSumFunction(_func(n)->duplicate(), + _func(m)->duplicate()); } else if (type == DiffFuncType) { - r = new Diff1(*_func(n), *_func(m)); + r = &newDiffFunction(_func(n)->duplicate(), + _func(m)->duplicate()); } else if (type == ProdFuncType) { - r = new Product1(*_func(n), *_func(m)); + r = &newProdFunction(_func(n)->duplicate(), + _func(m)->duplicate()); } else if (type == RatioFuncType) { - r = new Ratio1(*_func(n), *_func(m)); + r = &newRatioFunction(_func(n)->duplicate(), + _func(m)->duplicate()); } else if (type == CompositeFuncType) { - r = new Composite1(*_func(n), *_func(m)); + r = &newCompositeFunction(_func(n)->duplicate(), + _func(m)->duplicate()); } else if (type == TimesConstantFuncType) { - r = new TimesConstant1(*_func(n), params[0]); + r = &newTimesConstFunction(_func(n)->duplicate(), params[0]); } else if (type == PlusConstantFuncType) { - r = new PlusConstant1(*_func(n), params[0]); + r = &newPlusConstFunction(_func(n)->duplicate(), params[0]); } - else + else { + throw CanteraError("func_new","unknown function type"); r = new Func1(); + } return Cabinet::cabinet()->add(r); } catch (CanteraError) {return -1;} @@ -130,5 +141,23 @@ extern "C" { return Cabinet::cabinet()->add(r); } + int DLL_EXPORT func_duplicate(int i) { + func_t* r = 0; + r = &_func(i)->duplicate(); + return Cabinet::cabinet()->add(r); + } + + int DLL_EXPORT func_write(int i, int lennm, const char* arg, char* nm) { + try { + string a = string(arg); + string w = _func(i)->write(a); + int ws = w.size(); + int lout = (lennm > ws ? ws : lennm); + copy(w.c_str(), w.c_str() + lout, nm); + nm[lout] = '\0'; + return 0; + } + catch (CanteraError) { return -1; } + } } diff --git a/Cantera/clib/src/ctfunc.h b/Cantera/clib/src/ctfunc.h index 630d5b40e..e92765dd7 100755 --- a/Cantera/clib/src/ctfunc.h +++ b/Cantera/clib/src/ctfunc.h @@ -10,6 +10,8 @@ extern "C" { int DLL_IMPORT func_assign(int i, int j); double DLL_IMPORT func_value(int i, double t); int DLL_IMPORT func_derivative(int i); + int DLL_IMPORT func_duplicate(int i); + int DLL_EXPORT func_write(int i, int lennm, const char* arg, char* nm); } #endif diff --git a/Cantera/python/Cantera/Func.py b/Cantera/python/Cantera/Func.py index 0f950997c..ddae67cb4 100644 --- a/Cantera/python/Cantera/Func.py +++ b/Cantera/python/Cantera/Func.py @@ -1,3 +1,4 @@ + """ The classes in this module are designed to allow constructing @@ -44,11 +45,14 @@ class Func1: self._typ = typ self.coeffs = asarray(coeffs,'d') self._func_id = _cantera.func_new(typ, n, self.coeffs) - + def __del__(self): if self._func_id and self._own: _cantera.func_del(self._func_id) - + + def __repr__(self): + return self.write() + def __call__(self, t): """Implements function syntax, so that F(t) is equivalent to F.value(t).""" @@ -141,6 +145,10 @@ class Func1: kernel-level object.""" return self._func_id + def write(self, arg = 'x', length = 1000): + return _cantera.func_write(self._func_id, length, arg) + + class Sin(Func1): def __init__(self,omega=1.0): Func1.__init__(self,100,1,omega) @@ -265,7 +273,7 @@ class Arrhenius(Func1): -def Const(value): +class Const(Func1): """Constant function. Objects created by function Const act as functions that have a constant value. @@ -278,7 +286,9 @@ def Const(value): Function Const returns instances of class Polynomial that have degree zero, with the constant term set to the desired value. """ - return Polynomial([value]) + def __init__(self, value): + Func1.__init__(self,110,1,value) + #return Polynomial([value]) class PeriodicFunction(Func1): @@ -301,6 +311,10 @@ class ComboFunc1(Func1): self._own = 1 self._func_id = 0 self._typ = typ + if type(f1) == types.IntType: + f1 = Const(f1) + if type(f2) == types.IntType: + f2 = Const(f2) self.f1 = f1 self.f2 = f2 self.f1._own = 0 @@ -424,5 +438,6 @@ class DerivativeFunction(Func1): def derivative(f): return DerivativeFunction(f) + diff --git a/Cantera/python/src/ctfunc_methods.cpp b/Cantera/python/src/ctfunc_methods.cpp index 26d331f75..fa16bc01f 100644 --- a/Cantera/python/src/ctfunc_methods.cpp +++ b/Cantera/python/src/ctfunc_methods.cpp @@ -58,3 +58,25 @@ py_func_value(PyObject *self, PyObject *args) return Py_BuildValue("d",r); } + + +static PyObject* +py_func_write(PyObject *self, PyObject *args) +{ + int n; + char* arg; + char* nm; + int lennm; + if (!PyArg_ParseTuple(args, "iis:func_write", &n, &lennm, &arg)) + return NULL; + nm = new char[lennm+1]; + int iok = func_write(n, lennm, arg, nm); + if (iok < 0) { + delete[] nm; + return reportError(iok); + } + PyObject* r = Py_BuildValue("s",nm); + delete[] nm; + return r; +} + diff --git a/Cantera/python/src/methods.h b/Cantera/python/src/methods.h index 1bc0b795d..e29d89adc 100644 --- a/Cantera/python/src/methods.h +++ b/Cantera/python/src/methods.h @@ -263,6 +263,7 @@ static PyMethodDef ct_methods[] = { {"func_derivative", py_func_derivative, METH_VARARGS}, {"func_del", py_func_del, METH_VARARGS}, {"func_value", py_func_value, METH_VARARGS}, + {"func_write", py_func_write, METH_VARARGS}, {"mix_new", py_mix_new, METH_VARARGS}, {"mix_del", py_mix_del, METH_VARARGS}, diff --git a/Cantera/src/Func1.cpp b/Cantera/src/Func1.cpp index ded3ce990..a23b24477 100644 --- a/Cantera/src/Func1.cpp +++ b/Cantera/src/Func1.cpp @@ -4,6 +4,13 @@ using namespace std; namespace Cantera { + static Func1* checkDupl(Func1& f) { + if (f.parent() != 0) + return &f.duplicate(); + else + return &f; + } + Func1& Sin1::derivative() const { Func1* c = new Cos1(m_c); return *(new TimesConstant1(*c, m_c)); @@ -37,19 +44,42 @@ namespace Cantera { string Sin1::write(string arg) const { string c = ""; if (m_c != 1.0) c = fp2str(m_c); - return "\\sin{"+c+arg+"}"; + return "\\sin("+c+arg+")"; } string Cos1::write(string arg) const { string c = ""; if (m_c != 1.0) c = fp2str(m_c); - return "\\cos{"+c+arg+"}"; + return "\\cos("+c+arg+")"; + } + + string Pow1::write(string arg) const { + string c = ""; + if (m_c == 0.5) { + return "\\sqrt{" + arg + "}"; + } + if (m_c == -0.5) { + return "\\frac{1}{\\sqrt{" + arg + "}}"; + } + if (m_c != 1.0) { + c = fp2str(m_c); + return "\\left("+arg+"\\right)^{"+c+"}"; + } + else { + return arg; + } } string Exp1::write(string arg) const { string c = ""; if (m_c != 1.0) c = fp2str(m_c); - return "\\exp{"+c+arg+"}"; + return "\\exp("+c+arg+")"; + } + + string Const1::write(string arg) const { + string c = ""; + c = fp2str(m_c); + return c; } string Ratio1::write(string arg) const { @@ -59,9 +89,9 @@ namespace Cantera { string Product1::write(string arg) const { string s = m_f1->write(arg); - if (m_f1->order() < order()) s = "(" + s + ")"; + if (m_f1->order() < order()) s = "\\left(" + s + "\\right)"; string s2 = m_f2->write(arg); - if (m_f2->order() < order()) s2 = "(" + s2 + ")"; + if (m_f2->order() < order()) s2 = "\\left(" + s2 + "\\right)"; return s + " " + s2; } @@ -86,9 +116,12 @@ namespace Cantera { string TimesConstant1::write(string arg) const { string s = m_f1->write(arg); - if (m_f1->order() < order()) s = "(" + s + ")"; + if (m_f1->order() < order()) s = "\\left(" + s + "\\right)"; if (m_c == 1.0) return s; if (m_c == -1.0) return "-"+s; + char n = s[0]; + if (n >= '0' && n <= '9') + s = "\\left(" + s + "\\right)"; return fp2str(m_c) + s; } @@ -128,6 +161,8 @@ namespace Cantera { } Func1& newSumFunction(Func1& f1, Func1& f2) { + if (f1.isIdentical(f2)) + return newTimesConstFunction(f1, 2.0); if (isZero(f1)) { delete &f1; return f2; @@ -138,8 +173,11 @@ namespace Cantera { } doublereal c = f1.isProportional(f2); if (c != 0) { - if (c == -1.0) return *(new Const1(0.0)); - else return newTimesConstFunction(f1, c + 1.0); + if (c == -1.0) + return *(new Const1(0.0)); + else { + return newTimesConstFunction(f1, c + 1.0); + } } return *(new Sum1(f1, f2)); } @@ -189,7 +227,7 @@ namespace Cantera { } else ff2 = &f2; Func1& p = newProdFunction(*ff1, *ff2); - cout << "p = " << p.write("t") << endl; + //cout << "p = " << p.write("t") << endl; if (c1*c2 != 1.0) { return newTimesConstFunction(p, c1*c2); @@ -227,6 +265,10 @@ namespace Cantera { if (c == 1.0) { return f; } + if (f.ID() == TimesConstantFuncType) { + f.setC(f.c() * c); + return f; + } return *(new TimesConstant1(f, c)); } diff --git a/Cantera/src/Func1.h b/Cantera/src/Func1.h index f18528e18..c495c8fa3 100644 --- a/Cantera/src/Func1.h +++ b/Cantera/src/Func1.h @@ -54,7 +54,7 @@ namespace Cantera { */ class Func1 { public: - Func1() : m_c(0.0), m_f1(0), m_f2(0) {} + Func1() : m_c(0.0), m_f1(0), m_f2(0), m_parent(0) {} virtual ~Func1() {} virtual int ID() const { return 0; } @@ -68,7 +68,8 @@ namespace Cantera { virtual doublereal eval(doublereal t) const { return 0.0; } virtual Func1& derivative() const { - cout << "ERR: ID = " << ID() << endl; + cout << "derivative error... ERR: ID = " << ID() << endl; + cout << write("x") << endl; return *(new Func1); } @@ -92,15 +93,20 @@ namespace Cantera { virtual std::string write(std::string arg) const; doublereal c() const { return m_c; } + void setC(doublereal c) { m_c = c; } Func1& func1() { return *m_f1; } Func1& func2() { return *m_f2; } virtual int order() const { return 3; } Func1& func1_dup() const { return m_f1->duplicate(); } Func1& func2_dup() const { return m_f2->duplicate(); } + Func1* parent() { return m_parent; } + void setParent(Func1* p) { m_parent = p; } protected: doublereal m_c; Func1 *m_f1, *m_f2; + Func1* m_parent; + private: }; @@ -173,6 +179,7 @@ namespace Cantera { public: Pow1(doublereal n) {m_c = n;} virtual ~Pow1() {} + virtual std::string write(std::string arg) const; virtual int ID() const { return PowFuncType; } virtual Func1& duplicate() { return *(new Pow1(m_c)); } virtual doublereal eval(doublereal t) const { @@ -193,11 +200,13 @@ namespace Cantera { m_c = A; } virtual ~Const1() {} + virtual std::string write(std::string arg) const; virtual int ID() const { return ConstFuncType; } virtual doublereal eval(doublereal t) const { return m_c; } - virtual Func1& derivative() { + virtual Func1& duplicate() { return *(new Const1(m_c)); } + virtual Func1& derivative() const { Func1* z = new Const1(0.0); return *z; } @@ -215,6 +224,10 @@ namespace Cantera { Sum1(Func1& f1, Func1& f2) { m_f1 = &f1; m_f2 = &f2; + if (m_f1 == m_f2) + cout << "Same functions!" << endl; + m_f1->setParent(this); + m_f2->setParent(this); } virtual ~Sum1() { delete m_f1; @@ -230,7 +243,7 @@ namespace Cantera { Func1& dup = newSumFunction(f1d, f2d); return dup; } - virtual Func1& derivative() { + virtual Func1& derivative() const { Func1& d1 = m_f1->derivative(); Func1& d2 = m_f2->derivative(); Func1& d = newSumFunction(d1, d2); @@ -287,7 +300,7 @@ namespace Cantera { } virtual ~Product1() { - cout << "In Product1 destructor, deleting" << m_f1 << " " << m_f2 << endl; + //cout << "In Product1 destructor, deleting" << m_f1 << " " << m_f2 << endl; delete m_f1; delete m_f2; } @@ -366,7 +379,7 @@ namespace Cantera { } virtual ~PlusConstant1() { - cout << "PlusConstant1: deleting " << m_f1 << endl; + //cout << "PlusConstant1: deleting " << m_f1 << endl; delete m_f1; } virtual int ID() const { return PlusConstantFuncType; } @@ -400,7 +413,7 @@ namespace Cantera { m_f2 = &f2; } virtual ~Ratio1() { - cout << "Ratio1: deleting " << m_f1 << " " << m_f2 << endl; + //cout << "Ratio1: deleting " << m_f1 << " " << m_f2 << endl; delete m_f1; delete m_f2; }