20 template<
typename Ret,
typename Arg>
21 void PiecewisePolynomFunction<Ret(Arg)>::calculateSplinePeriodic() {
24 if(nrm2(y.row(0)-y.row(y.rows()-1))>epsroot) this->throwError(
"(PiecewisePolynomFunction::calculateSplinePeriodic): f(0)= "+fmatvec::toString(y.row(0))+
"!="+fmatvec::toString(y.row(y.rows()-1))+
" =f(end)");
25 fmatvec::SqrMat C(N-1,fmatvec::INIT,0.0);
26 fmatvec::Mat rs(N-1,y.cols(),fmatvec::INIT,0.0);
29 for(
int i=0; i<N-3;i++) {
33 C(i,i+1) = 2*(hi+hii);
35 rs.set(i, 3.*((y.row(i+2)-y.row(i+1))/hii - (y.row(i+1)-y.row(i))/hi));
42 C(N-3,N-2)= 2*(hi+hii);
44 rs.set(N-3, 3.*((y.row(N-1)-y.row(N-2))/hii - (y.row(N-2)-y.row(N-3))/hi));
47 double h1 = x(1)-x(0);
48 double hN_1 = x(N-1)-x(N-2);
49 C(N-2,0) = 2*(h1+hN_1);
52 rs.set(N-2, 3.*((y.row(1)-y.row(0))/h1 - (y.row(0)-y.row(N-2))/hN_1));
55 fmatvec::Mat c = slvLU(C,rs);
56 fmatvec::Mat ctmp(N,y.cols());
57 ctmp.set(N-1, c.row(0));
58 ctmp.set(fmatvec::RangeV(0,N-2),fmatvec::RangeV(0,y.cols()-1), c);
61 fmatvec::Mat d(N-1,y.cols(),fmatvec::INIT,0.0);
62 fmatvec::Mat b(N-1,y.cols(),fmatvec::INIT,0.0);
63 fmatvec::Mat a(N-1,y.cols(),fmatvec::INIT,0.0);
65 for(
int i=0; i<N-1; i++) {
68 d.set(i, (ctmp.row(i+1) - ctmp.row(i) ) / 3. / hi);
69 b.set(i, (y.row(i+1)-y.row(i)) / hi - (ctmp.row(i+1) + 2.*ctmp.row(i) ) / 3. * hi);
81 template<
typename Ret,
typename Arg>
82 void PiecewisePolynomFunction<Ret(Arg)>::calculateSplineNatural() {
86 if(N<4) this->throwError(
"(PiecewisePolynomFunction::calculateSplineNatural): number of datapoints does not match, must be greater 3");
87 fmatvec::SqrMat C(N-2,fmatvec::INIT,0.0);
88 fmatvec::Mat rs(N-2,y.cols(),fmatvec::INIT,0.0);
89 double hi = x(i+1)-x(i);
90 double hii = x(i+2)-x(i+1);
93 rs.set(i, 3.*(y.row(i+2)-y.row(i+1))/hii - 3.*(y.row(i+1)-y.row(i))/hi);
100 C(i,i) = 2*hii + 2*hi;
101 rs.set(i, 3.*(y.row(i+2)-y.row(i+1))/hii - 3.*(y.row(i+1)-y.row(i))/hi);
109 rs.set(i, 3.*(y.row(i+2)-y.row(i+1))/hii - 3.*(y.row(i+1)-y.row(i))/hi);
113 fmatvec::Mat C_rs(N-2,N-1+y.cols(),fmatvec::INIT,0.0);
114 C_rs.set(fmatvec::RangeV(0,N-3),fmatvec::RangeV(0,N-3), C);
115 C_rs.set(fmatvec::RangeV(0,N-3),fmatvec::RangeV(N-2,N-2+y.cols()-1), rs);
116 for(i=1; i<N-2; i++) C_rs.set(i, C_rs.row(i) - C_rs.row(i-1)*C_rs(i,i-1)/C_rs(i-1,i-1));
117 fmatvec::Mat rs1 = C_rs(fmatvec::RangeV(0,N-3),fmatvec::RangeV(N-2,N-2+y.cols()-1));
118 fmatvec::Mat C1 = C_rs(fmatvec::RangeV(0,N-3),fmatvec::RangeV(0,N-3));
119 fmatvec::Mat c(N-2,y.cols(),fmatvec::INIT,0.0);
120 for(i=N-3;i>=0 ;i--) {
121 fmatvec::RowVecV sum_ciCi(y.cols(),fmatvec::NONINIT);
123 for(
int ii=i+1; ii<=N-3; ii++) sum_ciCi = sum_ciCi + C1(i,ii)*c.row(ii);
124 c.set(i, (rs1.row(i) - sum_ciCi)/C1(i,i));
126 fmatvec::Mat ctmp(N,y.cols(),fmatvec::INIT,0.0);
127 ctmp.set(fmatvec::RangeV(1,N-2),fmatvec::RangeV(0,y.cols()-1), c);
130 fmatvec::Mat d(N-1,y.cols(),fmatvec::INIT,0.0);
131 fmatvec::Mat b(N-1,y.cols(),fmatvec::INIT,0.0);
132 fmatvec::Mat a(N-1,y.cols(),fmatvec::INIT,0.0);
134 for(i=0; i<N-1; i++) {
137 d.set(i, (ctmp.row(i+1) - ctmp.row(i) ) / 3. / hi);
138 b.set(i, (y.row(i+1)-y.row(i)) / hi - (ctmp.row(i+1) + 2.*ctmp.row(i) ) / 3. * hi);
145 coefs.push_back(ctmp(fmatvec::RangeV(0,N-2),fmatvec::RangeV(0,y.cols()-1)));
150 template<
typename Ret,
typename Arg>
151 void PiecewisePolynomFunction<Ret(Arg)>::calculatePLinear() {
157 fmatvec::Mat m(N-1,y.cols(),fmatvec::INIT,0.0);
158 fmatvec::Mat a(N-1,y.cols(),fmatvec::INIT,0.0);
159 for(
int i=1;i<N;i++) {
160 m.set(i-1, (y.row(i)-y.row(i-1))/(x(i)-x(i-1)));
161 a.set(i-1, y.row(i-1));
168 template<
typename Ret,
typename Arg>
169 Ret PiecewisePolynomFunction<Ret(Arg)>::ZerothDerivative::operator()(
const double& x) {
170 if(parent->extrapolationMethod==error) {
171 if(x-1e-13>(parent->breaks)(parent->nPoly))
172 throw std::runtime_error(
"(PiecewisePolynomFunction::operator()): x out of range! x= "+fmatvec::toString(x)+
", upper bound= "+fmatvec::toString((parent->breaks)(parent->nPoly)));
173 if(x+1e-13<(parent->breaks)(0))
174 throw std::runtime_error(
"(PiecewisePolynomFunction::operator()): x out of range! x= "+fmatvec::toString(x)+
", lower bound= "+fmatvec::toString((parent->breaks)(0)));
176 if(parent->extrapolationMethod==linear && (x<parent->breaks(0) || x>parent->breaks(parent->nPoly))) {
177 int idx = x<parent->breaks(0) ? 0 : parent->nPoly;
178 auto xv = parent->breaks(idx);
179 auto value = parent->f(xv);
180 auto der = parent->fd(xv);
181 return value + der * (x - parent->breaks(idx));
184 if ((fabs(x-xSave)<macheps) && !firstCall)
185 return FromVecV<Ret>::cast(ySave);
188 if(x<(parent->breaks)(parent->index))
189 while((parent->index) > 0 && (parent->breaks)(parent->index) > x)
191 else if(x>(parent->breaks)((parent->index)+1)) {
192 while((parent->index) < (parent->nPoly) && (parent->breaks)(parent->index) <= x)
197 const double dx = x - (parent->breaks)(parent->index);
198 fmatvec::VecV yi = trans(((parent->coefs)[0]).row(parent->index));
199 for(
int i=1;i<=(parent->order);i++)
200 yi = yi*dx+trans(((parent->coefs)[i]).row(parent->index));
203 return FromVecV<Ret>::cast(yi);
207 template<
typename Ret,
typename Arg>
208 Ret PiecewisePolynomFunction<Ret(Arg)>::FirstDerivative::operator()(
const double& x) {
209 if(parent->extrapolationMethod==error) {
210 if(x-1e-13>(parent->breaks)(parent->nPoly))
throw std::runtime_error(
"(PiecewisePolynomFunction::diff1): x out of range! x= "+fmatvec::toString(x)+
", upper bound= "+fmatvec::toString((parent->breaks)(parent->nPoly)));
211 if(x+1e-13<(parent->breaks)(0))
throw std::runtime_error(
"(PiecewisePolynomFunction::diff1): x out of range! x= "+fmatvec::toString(x)+
" lower bound= "+fmatvec::toString((parent->breaks)(0)));
213 if(parent->extrapolationMethod==linear && (x<parent->breaks(0) || x>parent->breaks(parent->nPoly))) {
214 int idx = x<parent->breaks(0) ? 0 : parent->nPoly;
215 auto xv = parent->breaks(idx);
216 auto der = parent->fd(xv);
220 if ((fabs(x-xSave)<macheps) && !firstCall)
221 return FromVecV<Ret>::cast(ySave);
224 if(x<(parent->breaks)(parent->index))
225 while((parent->index) > 0 && (parent->breaks)(parent->index) > x)
227 else if(x>(parent->breaks)((parent->index)+1)) {
228 while((parent->index) < (parent->nPoly) && (parent->breaks)(parent->index) <= x)
233 double dx = x - (parent->breaks)(parent->index);
234 fmatvec::VecV yi = trans(((parent->coefs)[0]).row(parent->index))*double(parent->order);
235 for(
int i=1;i<parent->order;i++)
236 yi = yi*dx+trans(((parent->coefs)[i]).row(parent->index))*double((parent->order)-i);
239 return FromVecV<Ret>::cast(yi);
243 template<
typename Ret,
typename Arg>
244 Ret PiecewisePolynomFunction<Ret(Arg)>::SecondDerivative::operator()(
const double& x) {
245 if(parent->extrapolationMethod==error) {
246 if(x-1e-13>(parent->breaks)(parent->nPoly))
throw std::runtime_error(
"(PiecewisePolynomFunction::diff2): x out of range! x= "+fmatvec::toString(x)+
" upper bound= "+fmatvec::toString((parent->breaks)(parent->nPoly)));
247 if(x+1e-13<(parent->breaks)(0))
throw std::runtime_error(
"(PiecewisePolynomFunction::diff2): x out of range! x= "+fmatvec::toString(x)+
" lower bound= "+fmatvec::toString((parent->breaks)(0)));
249 if(parent->extrapolationMethod==linear && (x<parent->breaks(0) || x>parent->breaks(parent->nPoly)))
250 return FromVecV<Ret>::cast(fmatvec::VecV(parent->getRetSize().first, fmatvec::INIT, 0.0));
252 if ((fabs(x-xSave)<macheps) && !firstCall)
253 return FromVecV<Ret>::cast(ySave);
256 if(x<(parent->breaks)(parent->index))
257 while((parent->index) > 0 && (parent->breaks)(parent->index) > x)
259 else if(x>(parent->breaks)((parent->index)+1)) {
260 while((parent->index) < (parent->nPoly) && (parent->breaks)(parent->index) <= x)
265 double dx = x - (parent->breaks)(parent->index);
266 fmatvec::VecV yi = trans(((parent->coefs)[0]).row(parent->index))*double(parent->order)*double((parent->order)-1);
267 for(
int i=1;i<=((parent->order)-2);i++)
268 yi = yi*dx+trans(((parent->coefs)[i]).row(parent->index))*
double((parent->order)-i)*
double((parent->order)-i-1);
271 return FromVecV<Ret>::cast(yi);
275 template<
typename Ret,
typename Arg>
276 void PiecewisePolynomFunction<Ret(Arg)>::setCoefficientsArray(
const std::vector<fmatvec::MatV> &allCoefs) {
277 interpolationMethod=useBreaksAndCoefs;
280 coefs.resize(allCoefs[0].cols());
282 x.resize(allCoefs[0].rows(),allCoefs.size());
283 for(
size_t c=0; c<allCoefs.size(); ++c) {
284 if(allCoefs[c].cols()!=
static_cast<int>(coefs.size()))
285 this->throwError(
"The number of columns in the coefficients elements differ.");
286 if(allCoefs[c].rows()!=
static_cast<int>(coefs[0].rows()))
287 this->throwError(
"The number of rows in the coefficients elements differ.");
288 for(
int deg=0; deg<allCoefs[c].cols(); deg++)
289 coefs[deg].set(c, allCoefs[c].col(deg));
293 template<
typename Ret,
typename Arg>
294 void PiecewisePolynomFunction<Ret(Arg)>::addCoefficients(
const fmatvec::MatV &coef) {
295 interpolationMethod=useBreaksAndCoefs;
299 coefs.resize(coef.cols());
300 if(
static_cast<int>(coefs.size())!=coef.cols())
301 this->throwError(
"The added coefficients have a different spline order.");
302 for(
auto &x : coefs) {
303 auto xold(std::move(x));
304 x.resize(coef.rows(),xold.cols()+1);
305 x.set(fmatvec::RangeV(0,xold.rows()-1), fmatvec::RangeV(0,xold.cols()-1), std::move(xold));
307 if(coef.cols()!=
static_cast<int>(coefs.size()))
308 this->throwError(
"The number of columns in the coefficients elements differ.");
309 if(coef.rows()!=
static_cast<int>(coefs[0].rows()))
310 this->throwError(
"The number of rows in the coefficients elements differ.");
311 for(
int deg=0; deg<coef.cols(); deg++)
312 coefs[deg].set(coefs[deg].cols()-1, coef.col(deg));
315 template<
typename Ret,
typename Arg>
316 void PiecewisePolynomFunction<Ret(Arg)>::initializeUsingXML(xercesc::DOMElement * element) {
317 xercesc::DOMElement *e;
320 e=MBXMLUtils::E(element)->getFirstElementChildNamed(MBSIM%
"x");
322 setx(MBXMLUtils::E(e)->getText<fmatvec::Vec>());
323 e=MBXMLUtils::E(element)->getFirstElementChildNamed(MBSIM%
"y");
324 sety(MBXMLUtils::E(e)->getText<fmatvec::Mat>(x.size(), 0));
326 e=MBXMLUtils::E(element)->getFirstElementChildNamed(MBSIM%
"xy");
328 e=MBXMLUtils::E(element)->getFirstElementChildNamed(MBSIM%
"xy");
329 setxy(MBXMLUtils::E(e)->getText<fmatvec::Mat>());
331 e=MBXMLUtils::E(element)->getFirstElementChildNamed(MBSIM%
"interpolationMethod");
333 std::string str=
MBXMLUtils::X()%MBXMLUtils::E(e)->getFirstTextChild()->getData();
334 str=str.substr(1,str.length()-2);
335 if(str==
"cSplinePeriodic") interpolationMethod=cSplinePeriodic;
336 else if(str==
"cSplineNatural") interpolationMethod=cSplineNatural;
337 else if(str==
"piecewiseLinear") interpolationMethod=piecewiseLinear;
338 else interpolationMethod=useBreaksAndCoefs;
341 e=MBXMLUtils::E(element)->getFirstElementChildNamed(MBSIM%
"breaks");
343 setBreaks(MBXMLUtils::E(e)->getText<fmatvec::Vec>());
345 std::vector<fmatvec::MatV> allCoefs;
346 e=MBXMLUtils::E(element)->getFirstElementChildNamed(MBSIM%
"coefficientsArray");
348 xercesc::DOMElement* ee=e->getFirstElementChild();
349 if(MBXMLUtils::E(ee)->getTagName()==MBSIM%
"ele") {
351 allCoefs.emplace_back(MBXMLUtils::E(ee)->getText<fmatvec::MatV>());
352 ee=ee->getNextElementSibling();
358 e=MBXMLUtils::E(element)->getFirstElementChildNamed(MBSIM%
"coefficients");
361 "please use <setCoefficientsArray>[<ele>...</ele>]+</setCoefficientsArray>", e);
362 allCoefs.emplace_back(MBXMLUtils::E(e)->getText<fmatvec::Mat>());
363 e=MBXMLUtils::E(e)->getNextElementSiblingNamed(MBSIM%
"coefficients");
366 setCoefficientsArray(allCoefs);
369 e=MBXMLUtils::E(element)->getFirstElementChildNamed(MBSIM%
"extrapolationMethod");
371 std::string str=
MBXMLUtils::X()%MBXMLUtils::E(e)->getFirstTextChild()->getData();
372 str=str.substr(1,str.length()-2);
373 if(str==
"error") extrapolationMethod=error;
374 else if(str==
"continuePolynom") extrapolationMethod=continuePolynom;
375 else if(str==
"linear") extrapolationMethod=linear;
376 else this->throwError(
"Unknown extrapolationMethod.");
static void message(const fmatvec::Atom *ele, const std::string &msg, const xercesc::DOMElement *e=nullptr)