Skip to content

Commit

Permalink
[numerics] Add previous value option to tabulated Func1 objects
Browse files Browse the repository at this point in the history
  • Loading branch information
ischoegl committed Jan 27, 2020
1 parent 1c0e123 commit 0fb3ece
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 27 deletions.
19 changes: 17 additions & 2 deletions include/cantera/numerics/Func1.h
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,8 @@ class Pow1 : public Func1
class Tabulated1 : public Func1
{
public:
Tabulated1(const std::vector<double>& tvec, const std::vector<double>& fvec) :
Tabulated1(const std::vector<double>& tvec, const std::vector<double>& fvec,
const std::string& method = "linear") :
Func1() {
if (tvec.size() != fvec.size()) {
throw CanteraError("Tabulated1::Tabulated1",
Expand All @@ -291,6 +292,15 @@ class Tabulated1 : public Func1
}
m_tvec = tvec;
m_fvec = fvec;
if (method == "linear") {
m_isLinear = true;
} else if (method == "previous") {
m_isLinear = false;
} else {
throw CanteraError("Tabulated1::Tabulated1",
"interpolation method '{}' is not implemented",
method);
}
}

Tabulated1(const Tabulated1& b) :
Expand All @@ -311,13 +321,18 @@ class Tabulated1 : public Func1
}
virtual double eval(double t) const;
virtual Func1& duplicate() const {
return *(new Tabulated1(m_tvec, m_fvec));
if (m_isLinear) {
return *(new Tabulated1(m_tvec, m_fvec, "linear"));
} else {
return *(new Tabulated1(m_tvec, m_fvec, "previous"));
}
}

virtual Func1& derivative() const;
private:
std::vector<double> m_tvec;
std::vector<double> m_fvec;
bool m_isLinear;
};


Expand Down
4 changes: 2 additions & 2 deletions interfaces/cython/cantera/_cantera.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ cdef extern from "cantera/cython/funcWrapper.h":

cdef extern from "cantera/numerics/Func1.h":
cdef cppclass CxxTabulated1 "Cantera::Tabulated1":
CxxTabulated1(vector[double]&, vector[double]&) except +translate_exception
CxxTabulated1(vector[double]&, vector[double]&, string) except +translate_exception
double eval(double) except +translate_exception

cdef cppclass CxxConst1 "Cantera::Const1":
Expand Down Expand Up @@ -1021,7 +1021,7 @@ cdef class Func1:
cdef object exception
cpdef void _set_callback(self, object) except *
cpdef void _set_const(self, double) except *
cpdef void _set_tables(self, object, object) except *
cpdef void _set_tables(self, object, object, string) except *

cdef class ReactorBase:
cdef CxxReactorBase* rbase
Expand Down
29 changes: 19 additions & 10 deletions interfaces/cython/cantera/func1.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -58,22 +58,29 @@ cdef class Func1:
points and corresponding function values. Inputs are specified either by
two iterable objects containing sample point location and function values,
or a single array that concatenates those inputs in two columns. Between
sample points, values are evaluated using a linear interpolation, whereas
outside the sample interval, the value at the closest end point is returned.
sample points, values are evaluated based on the keyword argument
'interpolation'; options are 'linear' (linear interpolation, default) or
'previous' (nearest previous value). Outside the sample interval, the value
at the closest end point is returned.
Examples for tabulated `Func1` object are::
>>> t1 = Func1([[0, 2], [1, 1], [2, 0]])
>>> [t1(v) for v in [-0.5, 0, 0.5, 1.5, 2, 2.5]]
[2.0, 2.0, 1.5, 0.5, 0.0, 0.0]
>>> t2 = Func1([0, 1, 2], [2, 1, 0])
>>> t2 = Func1([[0, 2], [1, 1], [2, 0]], interpolation='previous')
>>> [t2(v) for v in [-0.5, 0, 0.5, 1.5, 2, 2.5]]
[2.0, 2.0, 1.5, 0.5, 0.0, 0.0]
[2.0, 2.0, 2.0, 1.0, 0.0, 0.0]
>>> t3 = Func1(np.array([0, 1, 2]), (2, 1, 0))
>>> t3 = Func1([0, 1, 2], [2, 1, 0])
>>> [t3(v) for v in [-0.5, 0, 0.5, 1.5, 2, 2.5]]
[2.0, 2.0, 1.5, 0.5, 0.0, 0.0]
>>> t4 = Func1(np.array([0, 1, 2]), (2, 1, 0))
>>> [t4(v) for v in [-0.5, 0, 0.5, 1.5, 2, 2.5]]
[2.0, 2.0, 1.5, 0.5, 0.0, 0.0]
Note that all methods which accept `Func1` objects will also accept the
callable object and create the wrapper on their own, so it is generally
unnecessary to explicitly create a `Func1` object.
Expand All @@ -82,7 +89,7 @@ cdef class Func1:
self.exception = None
self.callable = None

def __init__(self, *args):
def __init__(self, *args, **kwargs):
if len(args) == 1:
c = args[0]
if hasattr(c, '__call__'):
Expand All @@ -104,7 +111,8 @@ cdef class Func1:
if arr.shape[1] == 2:
time = arr[:, 0]
fval = arr[:, 1]
self._set_tables(time, fval)
method = kwargs.get('interpolation', 'linear')
self._set_tables(time, fval, stringify(method))
else:
raise ValueError(
"Invalid dimensions: specification of "
Expand All @@ -121,7 +129,8 @@ cdef class Func1:
elif len(args) == 2:
# tabulated function (two arguments mimic C++ interface)
time, fval = args
self._set_tables(time, fval)
method = kwargs.get('interpolation', 'linear')
self._set_tables(time, fval, stringify(method))

else:
raise ValueError("Invalid number of arguments")
Expand All @@ -134,13 +143,13 @@ cdef class Func1:
cpdef void _set_const(self, double c) except *:
self.func = <CxxFunc1*>(new CxxConst1(c))

cpdef void _set_tables(self, time, fval) except *:
cpdef void _set_tables(self, time, fval, string method) except *:
cdef vector[double] tvec, fvec
for t in time:
tvec.push_back(t)
for f in fval:
fvec.push_back(f)
self.func = <CxxFunc1*>(new CxxTabulated1(tvec, fvec))
self.func = <CxxFunc1*>(new CxxTabulated1(tvec, fvec, method))

def __dealloc__(self):
del self.func
Expand Down
36 changes: 23 additions & 13 deletions src/numerics/Func1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,14 @@ double Tabulated1::eval(double t) const {
while (t > m_tvec[ix+1]) {
ix++;
}
double df = m_fvec[ix+1] - m_fvec[ix];
df /= m_tvec[ix+1] - m_tvec[ix];
df *= t - m_tvec[ix];
return m_fvec[ix] + df;
if (m_isLinear) {
double df = m_fvec[ix+1] - m_fvec[ix];
df /= m_tvec[ix+1] - m_tvec[ix];
df *= t - m_tvec[ix];
return m_fvec[ix] + df;
} else {
return m_fvec[ix];
}
}
} else {
return 0.;
Expand All @@ -241,20 +245,26 @@ Func1& Tabulated1::derivative() const {
std::vector<double> tvec;
std::vector<double> dvec;
size_t siz = m_tvec.size();
if (siz>1) {
for (size_t i=1; i<siz; i++) {
double d = (m_fvec[i] - m_fvec[i-1]) /
(m_tvec[i] - m_tvec[i-1]);
tvec.push_back(m_tvec[i-1]);
dvec.push_back(d);
tvec.push_back(m_tvec[i]);
dvec.push_back(d);
if (m_isLinear) {
// piece-wise continuous derivative
if (siz>1) {
for (size_t i=1; i<siz; i++) {
double d = (m_fvec[i] - m_fvec[i-1]) /
(m_tvec[i] - m_tvec[i-1]);
tvec.push_back(m_tvec[i-1]);
dvec.push_back(d);
}
}
tvec.push_back(m_tvec[siz-1]);
dvec.push_back(0.);
} else {
// derivative is zero (ignoring discontinuities)
tvec.push_back(m_tvec[0]);
tvec.push_back(m_tvec[siz-1]);
dvec.push_back(0.);
dvec.push_back(0.);
}
return *(new Tabulated1(tvec, dvec));
return *(new Tabulated1(tvec, dvec, "previous"));
}

/******************************************************************************/
Expand Down

0 comments on commit 0fb3ece

Please sign in to comment.