ODEBND
odebnd_val.hpp
00001 // Copyright (C) 2012-2014 Benoit Chachuat, Imperial College London.
00002 // All Rights Reserved.
00003 // This code is published under the Eclipse Public License.
00004 
00005 #ifndef MC__ODEBND_VAL_HPP
00006 #define MC__ODEBND_VAL_HPP
00007 
00008 #undef  MC__ODEBND_VAL_DEBUG
00009 #undef  MC__ODEBND_VAL_DEBUG_INVARIANT
00010 #undef  MC__ODEBND_VAL_STEPSIZE_HSTAB
00011 
00012 #include <stdexcept>
00013 #include <cassert>
00014 #include <cmath>
00015 #include <fstream>
00016 #include <vector>
00017 #include <sys/time.h>
00018 
00019 #include "ellipsoid.hpp"
00020 #include "tmodel.hpp"
00021 #include "cmodel.hpp"
00022 
00023 #include "odeslv_gsl.hpp"
00024 
00025 namespace mc
00026 {
00038 template <typename T, typename PMT=mc::TModel<T>, typename PVT=mc::TVar<T> >
00039 class ODEBND_VAL: public BASE_ODE                
00040 {
00041 private:
00042 
00043   typedef Ellipsoid E;
00044 
00046   unsigned int _nVAR;
00047 
00049   FFVar* _pVAR;
00050 
00052   T *_IVAR;
00053 
00055   PMT *_PMenv;
00056 
00058   PVT *_PMVAR;
00059 
00061   PMT *_MVenv;
00062 
00064   PVT *_MVVAR;
00065 
00066 
00068   T *_Ix;
00069 
00071   PVT *_PMx;
00072 
00074   E _Ex;
00075 
00077   E _Ex_TE;
00078 
00080   T *_Rx;
00081 
00083   T *_Rx_TE;
00084 
00086   CPPL::dgematrix _Ax;
00087 
00089   T *_Rinv;
00090 
00092   T *_Ninv;
00093 
00095   CPPL::dgematrix _Ainv;
00096 
00097 
00099   T* _IDAG;
00100 
00102   PVT* _PMDAG;
00103 
00104 
00106   std::list<const FFOp*> _opTRHS;
00107 
00109   const FFVar* _pTRHS;
00110 
00112   PVT *_PMTRHS;
00113 
00114 
00116   std::list<const FFOp*> _opFTRHS;
00117 
00119   const FFVar* _pFTRHS;
00120 
00122   T *_IFTRHS;
00123 
00125   PVT *_PMFTRHS;
00126 
00127 
00129   std::list<const FFOp*> _opTRHSval;
00130 
00132   T *_ITRHSval;
00133 
00135   PVT *_PMTRHSval;
00136 
00137 
00139   std::list<const FFOp*> _opIC;
00140 
00142   const FFVar* _pIC;
00143 
00144 
00146   std::list<const FFOp*> _opINV;
00147 
00149   const FFVar* _pINV;
00150 
00152   PVT *_PMINV;
00153 
00154 
00156   std::list<const FFOp*> _opFINV;
00157 
00159   const FFVar* _pFINV;
00160 
00162   T *_IFINV;
00163 
00165   PVT *_PMFINV;
00166 
00167 
00169   double _h;
00170 
00172   double _hmax;
00173 
00175   double _tmax;
00176 
00178   double _tval;
00179 
00181   ODESLV_GSL<T>* _ODESLV_GSL;
00182 
00183 public:
00187 
00188   ODEBND_VAL();
00189 
00191   virtual ~ODEBND_VAL();
00192 
00194   struct Results
00195   {
00197     Results
00198       ( const double tk, const unsigned int nxk, const T*Ixk ):
00199       t( tk ), nx( nxk )
00200       { X = new T[nx];
00201         for( unsigned int ix=0; ix<nx; ix++ ) X[ix] = Ixk[ix]; }
00202     Results
00203       ( const double tk, const unsigned int nxk, const PVT*PMxk ):
00204       t( tk ), nx( nxk )
00205       { X = new T[nx];
00206         for( unsigned int ix=0; ix<nx; ix++ ) X[ix] = PMxk[ix].B(); }
00207     Results
00208       ( const Results&res ):
00209       t( res.t ), nx( res.nx )
00210       { X = new T[nx];
00211         for( unsigned int ix=0; ix<nx; ix++ ) X[ix] = res.X[ix]; }
00213     ~Results()
00214       { delete[] X; }
00216     double t;
00218     unsigned int nx;
00220     T* X;
00221   };
00222 
00224   struct Options:
00225   {
00227     Options():
00228       TSORDER(7), WRAPMIT(ELLIPS), ORDMIT(1), DMAX(1e20), HMIN(1e-8), HMAX(1e8),
00229       HREDUC(0.8), HSTAB(true), TOL(1e-7), SCALING(true), ATOL(1e-10),
00230       QTOL(machprec()), TSTOP(true), PMVALID(false), USEINV(true),
00231       ODESLVOPT(typename ODESLV_GSL<T>::Options()), DISPLAY(1), RESRECORD(false)
00232       {}
00234     enum WRAPPING_STRATEGY{
00235       NONE=0,     
00236       ELLIPS      
00237     };
00239     unsigned int TSORDER;
00241     WRAPPING_STRATEGY WRAPMIT;
00243     unsigned int ORDMIT;
00245     double DMAX;
00247     double HMIN;
00249     double HMAX;
00251     double HREDUC;
00253     double HSTAB;
00255     double TOL;
00257     bool SCALING;
00259     double ATOL;
00261     double QTOL;
00263     bool TSTOP;
00265     bool PMVALID;
00267     bool USEINV;
00269     typename ODESLV_GSL<T>::Options ODESLVOPT;
00271     int DISPLAY;
00273     bool RESRECORD;
00274   } options;
00275 
00277   struct Stats
00278   {
00280     Stats():
00281       cputime(0.), numSteps(0), numTRHS_I(0), numFTRHS_I(0), numTRHS_PM(0), numFTRHS_PM(0)
00282       {}
00284     void reset()
00285       { cputime = 0.;
00286         numSteps = numTRHS_I = numFTRHS_I = numTRHS_PM = numFTRHS_PM = 0; }
00287 
00289     double cputime;
00291     unsigned long numSteps;
00293     unsigned long numTRHS_I;
00295     unsigned long numFTRHS_I;
00297     unsigned long numTRHS_PM;
00299     unsigned long numFTRHS_PM;
00300   };
00301 
00303   Stats stats_traj;
00304 
00306   class Exceptions
00307   {
00308   public:
00310     enum TYPE{
00311       REINIT=1,   
00312       HREDUC,  
00313       UNDEF=-33   
00314     };
00316     Exceptions( TYPE ierr ) : _ierr( ierr ){}
00318     int ierr(){ return _ierr; }
00320     std::string what(){
00321       switch( _ierr ){
00322       case REINIT:
00323         return "ODEBND_VAL::Exceptions  State reinitialization at intermediate stage not allowed";
00324       case HREDUC:
00325         return "ODEBND_VAL::Exceptions  Invalid stepsize reduction parameter";
00326       case UNDEF: default:
00327         return "ODEBND_VAL::Exceptions  Calling a feature not yet implemented";
00328       }
00329     }
00330   private:
00331     TYPE _ierr;
00332   };
00333 
00335   STATUS bounds
00336     ( const unsigned int ns, const double*tk, const PVT*PMp, PVT**PMxk,
00337       E*ERxk=0, std::ostream&os=std::cout );
00338 
00340   STATUS hausdorff
00341     ( const unsigned int ns, const double*tk, const PVT*PMp, double**Hxk,
00342       const unsigned int nsamp, std::ostream&os=std::cout );
00343 
00345   void record
00346     ( std::ofstream&bndrec, const unsigned int iprec=5 ) const;
00347 
00349   double final_time() const
00350     { return _t; };
00353 private:
00355   static void _init_stats
00356     ( Stats&stats );
00357 
00359   static void _final_stats
00360     ( Stats&stats );
00361 
00363   static void _print_stats
00364     ( const Stats&stats, std::ostream&os=std::cout );
00365 
00367   std::vector< Results > _results;
00368 
00370   template <typename U> double _scale
00371     ( U&R, const T&X ) const;
00372 
00374   template <typename U> double _smaxnorm
00375     ( U*R, const T*X ) const;
00376 
00378   template <typename U> double _snorm
00379     ( U*R, const T*X ) const;
00380 
00382   template <typename U> double _diam
00383     ( U*X ) const;
00384 
00386   template <typename U> double _stepsize
00387     ( const unsigned q, U*UTRHS, const T*X, const bool hdep ) const;
00388 
00390   double _validation
00391     ( const unsigned q, PVT*PMTRHS, const T*X );
00392 
00394   template <typename U, typename V> static U _predictor
00395     ( const V&h, const unsigned q, const unsigned n, const U*U_TE,
00396       const unsigned i );
00397 
00399   template <typename U, typename V> static U _predictor
00400     ( const V&h, const unsigned q, const unsigned n, const U*U_FTE,
00401       const unsigned i, const unsigned j );
00402 
00404   bool _prepare
00405     ( const PVT*PMp );
00406 
00408   bool _init
00409     ( const unsigned k, const double tk, PVT*PMxk, E*Exk );
00410 
00412   bool _resize
00413     ( const unsigned q, const unsigned int iRHS );
00414 
00416   STATUS _propagate
00417     ( const double tnext, std::ostream&os );
00418 
00420   STATUS _propagate_INT
00421     ( const double tnext, std::ostream&os );
00422 
00424   STATUS _propagate_ELL
00425     ( const double tnext, std::ostream&os );
00426 
00428   STATUS _propagate_ELL0
00429     ( const unsigned q, const double tnext, std::ostream&os );
00430 
00432   STATUS _propagate_ELL1
00433     ( const unsigned q, const double tnext, std::ostream&os );
00434 
00436   STATUS _propagate_ELL2
00437     ( const unsigned q, const double tnext, std::ostream&os );
00438 
00440   STATUS _invariant_ELL
00441     ( std::ostream&os );
00442 
00444   STATUS _invariant_ELL0
00445     ( const PVT*Px, const T*Rx, std::ostream&os );
00446 
00448   STATUS _invariant_ELL1
00449     ( const PVT*Px, const T*Rx, std::ostream&os );
00450 
00452   STATUS _invariant_ELL2
00453     ( const PVT*Px, const T*Rx, std::ostream&os );
00454 
00456   STATUS _update_ELL
00457     ( std::ostream&os );
00458 
00460   STATUS _remainders
00461     ( const unsigned int ns, const double*tk, const T*Ip, const PVT*const*PMxk,
00462       T**Rxk, const unsigned int nsamp, std::ostream&os=std::cout );
00463 
00465   STATUS _remainders
00466     ( const unsigned int ns, const double*tk, const T*Ip, const PVT*const*PMxk,
00467       T**Rxk, const unsigned int nsamp, unsigned int* vsamp,
00468       const unsigned int ip, double*p, double**xk, std::ostream&os );
00469 
00471   template<typename U> void _print_interm
00472     ( const double t, const U*x, const std::string&var, std::ostream&os=std::cout ) const;
00473 
00475   template<typename U, typename V> void _print_interm
00476     ( const double t, const U*x, const V&r, const std::string&var, std::ostream&os=std::cout ) const;
00477 
00479   static double _factorial
00480     ( const unsigned int n )
00481     {
00482       return( n==1? 1: n*_factorial(n-1) );
00483     }
00484 
00486   ODEBND_VAL(const ODEBND_VAL&);
00487   ODEBND_VAL& operator=(const ODEBND_VAL&);
00488 };
00489 
00490 template <typename T, typename PMT, typename PVT>
00491 inline
00492 ODEBND_VAL<T,PMT,PVT>::ODEBND_VAL
00493 () : BASE_ODE()
00494 {
00495   // Initalize DAG computation
00496   _nVAR = 0;
00497   _pVAR = 0;
00498   _PMVAR = _MVVAR = _PMDAG = 0;
00499   _IVAR = _IDAG = 0;
00500 
00501   // Initalize dynamic system computation
00502   _pTRHS = _pFTRHS = _pIC = _pINV = _pFINV = 0;
00503   _PMenv = _MVenv = 0;
00504   _Ix = _Rx = _Rx_TE = _Rinv = _Ninv = 0;
00505   _PMx = 0;
00506   _IFTRHS = _ITRHSval = _IFINV = 0;
00507   _PMTRHS = _PMFTRHS = _PMTRHSval = _PMINV = _PMFINV = 0;
00508 
00509   // Initialize ellipsoidal calculus
00510 #ifdef MC__ODEBND_VAL_DEBUG
00511   E::options.PSDCHK = true;
00512 #else
00513   E::options.PSDCHK = false;
00514 #endif
00515 
00516   // Initalize GSL
00517   _ODESLV_GSL = new ODESLV_GSL<T>();
00518 }
00519 
00520 template <typename T, typename PMT, typename PVT>
00521 inline
00522 ODEBND_VAL<T,PMT,PVT>::~ODEBND_VAL
00523 ()
00524 {
00525   delete[] _pVAR;
00526   delete[] _IVAR;
00527   delete[] _PMVAR;
00528   delete[] _MVVAR;
00529   delete[] _IDAG;
00530   delete[] _PMDAG;
00531 
00532   // Do *NOT* free _PMenv
00533   delete _MVenv;
00534   delete[] _PMx;
00535   delete[] _Ix;
00536   delete[] _Rx;
00537   delete[] _Rx_TE;
00538   delete[] _Rinv;
00539   delete[] _Ninv;
00540 
00541   delete[] _pTRHS;
00542   delete[] _PMTRHS;
00543   delete[] _pFTRHS;
00544   delete[] _PMFTRHS;
00545   delete[] _IFTRHS;
00546   delete[] _PMTRHSval;
00547   delete[] _ITRHSval;
00548   // Do *NOT* free _pIC;
00549   // Do *NOT* free _pINV;
00550   delete[] _PMINV;
00551   delete[] _pFINV;
00552   delete[] _PMFINV;
00553   delete[] _IFINV;
00554 
00555   delete _ODESLV_GSL;
00556 }
00557 
00558 template <typename T, typename PMT, typename PVT>
00559 template <typename U> inline double
00560 ODEBND_VAL<T,PMT,PVT>::_scale
00561 ( U&R, const T&X ) const
00562 {
00563   return( options.SCALING?
00564           Op<U>::abs(R)/(2.*options.TOL*Op<T>::abs(X)+options.ATOL):
00565      Op<U>::abs(R)/options.TOL );
00566 }
00567 
00568 template <typename T, typename PMT, typename PVT>
00569 template <typename U> inline double
00570 ODEBND_VAL<T,PMT,PVT>::_smaxnorm
00571 ( U*R, const T*X ) const
00572 {
00573   double maxnorm = 0.;
00574   for( unsigned int ix=0; ix<_nx; ix++ )
00575     maxnorm = std::max( maxnorm, _scale(R[ix],X[ix]) );
00576   return maxnorm;
00577 }
00578 
00579 template <typename T, typename PMT, typename PVT>
00580 template <typename U> inline double
00581 ODEBND_VAL<T,PMT,PVT>::_snorm
00582 ( U*R, const T*X ) const
00583 {
00584   double snorm = 0.;
00585   for( unsigned int ix=0; ix<_nx; ix++ )
00586     snorm += _scale(R[ix],X[ix]);
00587   return snorm/(double)_nx;
00588 }
00589 
00590 template <typename T, typename PMT, typename PVT>
00591 template <typename U> inline double
00592 ODEBND_VAL<T,PMT,PVT>::_diam
00593 ( U*X ) const
00594 {
00595   double diam = 0.;
00596   for( unsigned int ix=0; ix<_nx; ix++ )
00597     diam = std::max( diam, Op<U>::diam(X[ix]) );
00598   return diam;
00599 }
00600 
00601 template <typename T, typename PMT, typename PVT>
00602 template <typename U, typename V> inline U
00603 ODEBND_VAL<T,PMT,PVT>::_predictor
00604 ( const V&h, const unsigned q, const unsigned n, const U*U_TE,
00605   const unsigned i )
00606 {
00607 #ifdef MC__ODEBND_VAL_DEBUG
00608   for( unsigned k=0; k<q; q++ )
00609     std::cout << "ODEBND_VAL::_predictor *** f[" << q << "](" << i << ") = "
00610               << U_TE[q*n+i] << std::endl;
00611 #endif
00612   // Compute predictor of xi(_t+h)
00613   unsigned pTEi = q*n+i;
00614   U Xi( U_TE[pTEi] );
00615   pTEi -= n;
00616   for( unsigned k=0; k<q; k++, pTEi-=n )
00617     { Xi *= h; Xi += U_TE[pTEi]; }
00618   return Xi;
00619 
00620 }
00621 
00622 template <typename T, typename PMT, typename PVT>
00623 template <typename U, typename V> inline U
00624 ODEBND_VAL<T,PMT,PVT>::_predictor
00625 ( const V&h, const unsigned q, const unsigned n, const U*U_FTE,
00626   const unsigned i, const unsigned j )
00627 {
00628   // Compute predictor of dxi(_t+h)/dx
00629   unsigned pFTEij = q*n*n+i*n+j;
00630   U DjXi( U_FTE[pFTEij] );
00631   pFTEij -= n*n;
00632   for( unsigned k=0; k<q; k++, pFTEij-=n*n )
00633     { DjXi *= h; DjXi += U_FTE[pFTEij]; };
00634   return DjXi;
00635 }
00636 
00637 template <typename T, typename PMT, typename PVT>
00638 template <typename U> inline double
00639 ODEBND_VAL<T,PMT,PVT>::_stepsize
00640 ( const unsigned q, U*UTRHS, const T*X, const bool hdep ) const
00641 {
00642 #ifdef MC__ODEBND_VAL_DEBUG_STEPSIZE
00643   std::cout << "UTRHS[q+1]:";
00644   for( unsigned int ix=0; ix<_nx; ix++ )
00645     std::cout << "  " << UTRHS[ix];
00646   std::cout << std::endl << "factorial: " << _factorial(q+1) << std::endl;
00647 #endif
00648   return hdep? std::pow( _smaxnorm(UTRHS,X)*_factorial(q+1) + machprec(), -1./q )
00649              : std::pow( _smaxnorm(UTRHS,X)*_factorial(q+1) + machprec(), -1./(q+1) );
00650 }
00651 
00652 template <typename T, typename PMT, typename PVT>
00653 inline double
00654 ODEBND_VAL<T,PMT,PVT>::_validation
00655 ( const unsigned q, PVT*PMTRHS, const T*X )
00656 {
00657   if( options.HREDUC >= 1. || options.HREDUC <=0. ) throw Exceptions( Exceptions::HREDUC );
00658 
00659   // Stepsize validatinon
00660 #ifdef MC__ODEBND_VAL_DEBUG_STEPSIZE
00661   for( unsigned k=1; k<=q; k++ ){
00662     double h0 = _stepsize( k, PMTRHS+k*_nx, X, options.HSTAB );
00663     std::cout << k << "  " << h0 << std::endl;
00664   }
00665   { int dum; std::cin >> dum; }
00666 #endif
00667   double h = _stepsize( q, PMTRHS+q*_nx, X, options.HSTAB ) * options.HREDUC, hval;
00668   for( ; true; h *= options.HREDUC ){
00669 
00670     // Check minimum stepsize criterion
00671     if( h < options.HMIN ) return h;
00672 
00673     // Check predictor validity on full step [0,h]
00674     if( options.PMVALID ){ // polynomial model-based validation
00675       for( unsigned ix=0; ix<_nx; ix++ ){
00676         _PMVAR[ix] = _predictor( T(0,1)*h, q, _nx, PMTRHS, ix ).center();
00677         _PMVAR[ix] += options.HSTAB? h*options.TOL*T(-1,1): options.TOL*T(-1,1);
00678       }
00679       _PMVAR[_nx+_np] = _t; // Keep time when stepsize was computed
00680       _pDAG->eval( _opTRHSval, _PMDAG, _nx, _pTRHS+(q+1)*_nx, _PMTRHSval, _nVAR, _pVAR, _PMVAR );
00681       ++stats_traj.numTRHS_PM;
00682       hval = _stepsize(q, _PMTRHSval, X, options.HSTAB );
00683     }
00684     else{ // Interval-based validation
00685       for( unsigned ix=0; ix<_nx; ix++ ){
00686         _IVAR[ix] = _predictor( T(0,1)*h, q, _nx, PMTRHS, ix ).bound();
00687         _IVAR[ix] += options.HSTAB? h*options.TOL*T(-1,1): options.TOL*T(-1,1);
00688       }
00689       _IVAR[_nx+_np] = _t; // Keep time when stepsize was computed
00690       _pDAG->eval( _opTRHSval, _IDAG, _nx, _pTRHS+(q+1)*_nx, _ITRHSval, _nVAR, _pVAR, _IVAR );
00691       ++stats_traj.numTRHS_I;
00692       hval = _stepsize( q, _ITRHSval, X, options.HSTAB );
00693     }
00694 #ifdef MC__ODEBND_VAL_DEBUG_STEPSIZE
00695   std::cout << "current step: h=" << h << " <=? " << hval << std::endl;
00696 #endif
00697     if( h < hval ) return h;
00698   }
00699 }
00700 
00701 template <typename T, typename PMT, typename PVT>
00702 inline typename ODEBND_VAL<T,PMT,PVT>::STATUS
00703 ODEBND_VAL<T,PMT,PVT>::_propagate_INT
00704 ( const double tnext, std::ostream&os )
00705 {
00706   const unsigned q = options.TSORDER;
00707 
00708   // Taylor series expansion in PVT arithmetic up to order TSORDER+1
00709   for( unsigned ix=0; ix<_nx; ix++ ) _PMVAR[ix] = _PMx[ix];
00710   _PMVAR[_nx+_np] = _t;
00711   _pDAG->eval( _opTRHS, _PMDAG, (q+2)*_nx, _pTRHS, _PMTRHS, _nVAR, _pVAR, _PMVAR );
00712   ++stats_traj.numTRHS_PM;
00713 
00714   // Stepsize selection and validation
00715   _h = _validation( q, _PMTRHS, _Ix );
00716   if( _h < options.HMIN ) return FAILURE;
00717   if( _h > options.HMAX ) _h = options.HMAX;
00718   // Modify stepsize if stage time is exceeded
00719   if( _t+_h > tnext ) _h = tnext-_t;
00720   ++stats_traj.numSteps;
00721 
00722   // Enclosure propagation
00723   for( unsigned int ix=0; ix<_nx; ix++ ){
00724     _PMx[ix] = _predictor( _h, q, _nx, _PMTRHS, ix );
00725     // Truncation error
00726 #ifdef MC__ODEBND_VAL_STEPSIZE_HSTAB
00727     _PMx[ix] += _h*options.TOL*T(-1.,1.);
00728 #else
00729     _PMx[ix] += options.TOL*T(-1.,1.);
00730 #endif
00731 #ifdef MC__ODEBND_VAL_DEBUG
00732     std::cout << "PMx(@" << _t+_h << ")[" << ix << "] = " << _PMx[ix] << std::endl;
00733 #endif
00734     _Ix[ix] = _PMx[ix].bound();
00735   }
00736   _Ex.set();
00737 
00738   // Check enclosure diameter before returning
00739   return( _diam(_Ix) < options.DMAX? NORMAL: FAILURE );
00740 }
00741 
00742 template <typename T, typename PMT, typename PVT>
00743 inline typename ODEBND_VAL<T,PMT,PVT>::STATUS
00744 ODEBND_VAL<T,PMT,PVT>::_propagate_ELL0
00745 ( const unsigned q, const double tnext, std::ostream&os )
00746 {
00747   // Stepsize validation
00748   if( options.TSTOP || isequal( _t, _tmax ) ){
00749 
00750     _Ex_TE = _Ex; // Copy of _Ex at expansion point for updates later on
00751     for( unsigned int ix=0; ix<_nx; ix++ ){
00752       _Rx_TE[ix] = _PMx[ix].remainder(); // Copy of polynomial model remainder at expansion time for updates later on
00753       _PMx[ix].center().set( T(0.) ); // Keep centered polynomial part
00754     }
00755 
00756     // Taylor series expansion in PVT arithmetic up to order TSORDER+1
00757     for( unsigned ix=0; ix<_nx; ix++ ) _PMVAR[ix] = _PMx[ix];
00758     _PMVAR[_nx+_np] = _t; // Keep time when stepsize was computed
00759     _pDAG->eval( _opTRHS, _PMDAG, (q+2)*_nx, _pTRHS, _PMTRHS, _nVAR, _pVAR, _PMVAR );
00760     ++stats_traj.numTRHS_PM;
00761 
00762     // Taylor series expansion and differentiation in T arithmetic up to order TSORDER
00763     for( unsigned ix=0; ix<_nx; ix++ ) _IVAR[ix] = _Ix[ix];
00764     _IVAR[_nx+_np] = _t;
00765     _pDAG->eval( _opFTRHS, _IDAG, (q+1)*_nx*_nx, _pFTRHS, _IFTRHS, _nVAR, _pVAR, _IVAR );
00766     ++stats_traj.numFTRHS_I;
00767 
00768     // Stepsize selection and validation
00769     _hmax = _h = _validation( q, _PMTRHS, _Ix );
00770     if( _hmax < options.HMIN ) return FAILURE;
00771     if( _hmax > options.HMAX ) _hmax = _h = options.HMAX;
00772     // Modify stepsize if stage time is exceeded
00773     _tmax = _t+_hmax;
00774     // Keep time when stepsize was computed
00775     _tval = _t; 
00776     ++stats_traj.numSteps;
00777 #ifdef MC__ODEBND_VAL_DEBUG
00778     std::cout << "\nCurrent step: hmax=" << _hmax << "  tmax=" << _tmax << std::endl;
00779     { int dum; std::cin >> dum; }
00780 #endif
00781   }
00782 
00783   // By-pass stepsize validation if previous integration step can be
00784   // carried out further and ODE RHS is continuous
00785   else{
00786     _h = _hmax;
00787   }
00788 
00789   // Limit stepsize so as to stop at stage time tnext
00790   if( _tmax > tnext ) _h = tnext-_tval; // Do not use _t directly as it may be different from the validation time
00791 #ifdef MC__ODEBND_VAL_DEBUG
00792   std::cout << "\nCurrent step: t=" << _t << "  h=" << _h << "  tnext=" << tnext
00793             << "  hmax=" << _hmax << "  tmax=" << _tmax << std::endl;
00794 #endif
00795 
00796   // Enclosure propagation
00797   for( unsigned int ix=0; ix<_nx; ix++ ){
00798     _PMx[ix] = _predictor( _h, q, _nx, _PMTRHS, ix ).center();
00799 #ifdef MC__ODEBND_VAL_DEBUG
00800     std::cout << "_PMx[" << ix << "] =" << _PMx[ix];
00801 #endif
00802     // Remainder of polynomial model propagation of state polynomial approximant
00803     _Rx[ix] = _PMx[ix].remainder();
00804     // Linear part for ellipsoidal remainder update
00805     for( unsigned int jx=0; jx<_nx; jx++ ){
00806       T IAx = _predictor( _h, q, _nx, _IFTRHS, ix, jx );
00807       _Ax(ix,jx) = Op<T>::mid( IAx );
00808       _Rx[ix] += ( IAx - _Ax(ix,jx) ) * _Rx_TE[jx];
00809     }
00810     // Truncation error
00811 #ifdef MC__ODEBND_VAL_STEPSIZE_HSTAB
00812     _Rx[ix] += _h*options.TOL*T(-1.,1.);
00813 #else
00814     _Rx[ix] += options.TOL*T(-1.,1.);
00815 #endif
00816 #ifdef MC__ODEBND_VAL_DEBUG
00817     std::cout << "_Rx[" << ix << "] =" << _Rx[ix]
00818               << "  diam(_Rx[" << ix << "]) =" << Op<T>::diam(_Rx[ix])
00819               << "  midp(_Rx[" << ix << "]) =" << Op<T>::mid(_Rx[ix])
00820               << std::endl;
00821 #endif
00822   }
00823 #ifdef MC__ODEBND_VAL_DEBUG
00824   std::cout << "_Ax(@" << _tval << ") =\n" << _Ax << std::endl;
00825   std::cout << "_Ex(@" << _tval << ") =" << _Ex_TE << std::endl;
00826 #endif
00827 
00828   // Correct stepsize in case stepsize selection/validation was by-passed
00829   _h -= (_t-_tval); 
00830 #ifdef MC__ODEBND_VAL_DEBUG
00831   std::cout << "\nAdjusted step: h=" << _h << "  tval=" << _tval << std::endl;
00832 #endif
00833 
00834   return NORMAL;
00835 }
00836 
00837 template <typename T, typename PMT, typename PVT>
00838 inline typename ODEBND_VAL<T,PMT,PVT>::STATUS
00839 ODEBND_VAL<T,PMT,PVT>::_propagate_ELL1
00840 ( const unsigned q, const double tnext, std::ostream&os )
00841 {
00842   // Stepsize validation
00843   if( options.TSTOP || isequal( _t, _tmax ) ){
00844 
00845     _Ex_TE = _Ex; // Copy of _Ex at expansion point for updates later on
00846     for( unsigned int ix=0; ix<_nx; ix++ ){
00847       _Rx_TE[ix] = _PMx[ix].remainder(); // Copy of polynomial model remainder at expansion time for updates later on
00848       _PMx[ix].center().set( T(0.) ); // get centered polynomial part
00849     }
00850 
00851     // Taylor series expansion in PVT arithmetic up to order TSORDER+1
00852     for( unsigned ix=0; ix<_nx; ix++ ) _PMVAR[ix] = _PMx[ix];
00853     _PMVAR[_nx+_np] = _t; // Keep time when stepsize was computed
00854     _pDAG->eval( _opTRHS, _PMDAG, (q+2)*_nx, _pTRHS, _PMTRHS, _nVAR, _pVAR, _PMVAR );
00855     ++stats_traj.numTRHS_PM;
00856 
00857     // Taylor series expansion and differentiation in PVT arithmetic up to order TSORDER
00858     for( unsigned ix=0; ix<_nx; ix++ ){
00859       PVT MVri( _MVenv, _np+ix, _Rx_TE[ix] );
00860       _MVVAR[ix].set( _MVenv ).set( _PMx[ix], true );
00861       _MVVAR[ix] += MVri;
00862     }
00863     _MVVAR[_nx+_np] = _t;
00864     _pDAG->eval( _opFTRHS, _PMDAG, (q+1)*_nx*_nx, _pFTRHS, _PMFTRHS, _nVAR, _pVAR, _MVVAR );
00865     ++stats_traj.numFTRHS_PM;
00866 
00867     // Stepsize selection and validation
00868     _hmax = _h = _validation( q, _PMTRHS, _Ix );
00869     if( _hmax < options.HMIN ) return FAILURE;
00870     if( _hmax > options.HMAX ) _hmax = _h = options.HMAX;
00871     // Modify stepsize if stage time is exceeded
00872     _tmax = _t+_hmax;
00873     // Keep time when stepsize was computed
00874     _tval = _t; 
00875     ++stats_traj.numSteps;
00876 #ifdef MC__ODEBND_VAL_DEBUG
00877     std::cout << "\nCurrent step: hmax=" << _hmax << "  tmax=" << _tmax << std::endl;
00878     //{ int dum; std::cin >> dum; }
00879 #endif
00880   }
00881 
00882   // By-pass stepsize validation if previous integration step can be
00883   // carried out further and ODE RHS is continuous
00884   else{
00885     _h = _hmax;
00886   }
00887 
00888   // Limit stepsize so as to stop at stage time tnext
00889   // Do not use _t since might be different from Taylor expansion time
00890   if( _tmax > tnext ) _h = tnext-_tval;
00891 #ifdef MC__ODEBND_VAL_DEBUG
00892   std::cout << "\nCurrent step: t=" << _t << "  h=" << _h << "  tnext=" << tnext
00893             << "  hmax=" << _hmax << "  tmax=" << _tmax << std::endl;
00894 #endif
00895 
00896   // Enclosure propagation
00897   for( unsigned int ix=0; ix<_nx; ix++ ){
00898     _PMx[ix] = _predictor( _h, q, _nx, _PMTRHS, ix ).center();
00899 #ifdef MC__ODEBND_VAL_DEBUG
00900     std::cout << "_PMx[" << ix << "] =" << _PMx[ix];
00901 #endif
00902     // Remainder of polynomial model propagation of state polynomial approximant
00903     _Rx[ix] = _PMx[ix].remainder();
00904     // Linear part for ellipsoidal remainder update
00905     for( unsigned int jx=0; jx<_nx; jx++ ){
00906       PVT MVfx = _predictor( _h, q, _nx, _PMFTRHS, ix, jx ).center();
00907       _Ax(ix,jx) = MVfx.constant();
00908       _Rx[ix] += ( MVfx.bound() - _Ax(ix,jx) ) * _Rx_TE[jx];
00909     }
00910     // Truncation error
00911 #ifdef MC__ODEBND_VAL_STEPSIZE_HSTAB
00912     _Rx[ix] += _h*options.TOL*T(-1.,1.);
00913 #else
00914     _Rx[ix] += options.TOL*T(-1.,1.);
00915 #endif
00916 #ifdef MC__ODEBND_VAL_DEBUG
00917     std::cout << "_Rx[" << ix << "] =" << _Rx[ix]
00918               << "  diam(_Rx[" << ix << "]) =" << Op<T>::diam(_Rx[ix])
00919               << "  midp(_Rx[" << ix << "]) =" << Op<T>::mid(_Rx[ix])
00920               << std::endl;
00921 #endif
00922   }
00923 #ifdef MC__ODEBND_VAL_DEBUG
00924   std::cout << "_Ax(@" << _tval << ") =\n" << _Ax << std::endl;
00925   std::cout << "_Ex(@" << _tval << ") =" << _Ex_TE << std::endl;
00926 #endif
00927 
00928   // Correct stepsize in case stepsize selection/validation was by-passed
00929   _h -= (_t-_tval); 
00930 #ifdef MC__ODEBND_VAL_DEBUG
00931   std::cout << "\nAdjusted step: h=" << _h << "  tval=" << _tval << std::endl;
00932 #endif
00933 
00934   return NORMAL;
00935 }
00936 template <typename T, typename PMT, typename PVT>
00937 inline typename ODEBND_VAL<T,PMT,PVT>::STATUS
00938 ODEBND_VAL<T,PMT,PVT>::_propagate_ELL2
00939 ( const unsigned q, const double tnext, std::ostream&os )
00940 {
00941   // Stepsize validation
00942   if( options.TSTOP || isequal( _t, _tmax ) ){
00943 
00944     _Ex_TE = _Ex; // Copy of _Ex at expansion point for updates later on
00945     for( unsigned int ix=0; ix<_nx; ix++ ){
00946       _Rx[ix] = _PMx[ix].center().remainder(); // get centered remainder
00947       _PMx[ix].set( T(0.) ); // cancel remainder term to get polynomial part
00948 #ifdef MC__ODEBND_VAL_DEBUG
00949       std::cout << "_PMx[" << ix << "] =" << _PMx[ix];
00950       std::cout << "_Rx[" << ix << "] =" << _Rx[ix] << std::endl;
00951 #endif
00952     }
00953 
00954     // Taylor series expansion in PVT arithmetic (joint parameter-state) up to order TSORDER+1
00955    for( unsigned ix=0; ix<_nx; ix++ ){
00956       PVT MVri( _MVenv, _np+ix, _Rx[ix] );
00957       _MVVAR[ix].set( _MVenv ).set( _PMx[ix], true );
00958       _MVVAR[ix] += MVri;
00959     }
00960     _MVVAR[_nx+_np] = _t;
00961     _pDAG->eval( _opTRHS, _PMDAG, (q+2)*_nx, _pTRHS, _PMTRHS, _nVAR, _pVAR, _MVVAR );
00962     ++stats_traj.numTRHS_PM;
00963 
00964     // Stepsize selection and validation
00965     _hmax = _h = _validation( q, _PMTRHS, _Ix );
00966     if( _hmax < options.HMIN ) return FAILURE;
00967     if( _hmax > options.HMAX ) _hmax = _h = options.HMAX;
00968     // Modify stepsize if stage time is exceeded
00969     _tmax = _t+_hmax;
00970     // Keep time when stepsize was computed
00971     _tval = _t; 
00972     ++stats_traj.numSteps;
00973   }
00974 
00975   // By-pass stepsize validation if previous integration step can be
00976   // carried out further and ODE RHS is continuous
00977   else{
00978 #ifdef MC__ODEBND_VAL_DEBUG
00979     std::cout << "Expansion by-passed: t=" << _t << "  tmax=" << _tmax << "  hmax=" << _hmax << std::endl;
00980 #endif
00981     _h = _hmax;
00982   }
00983 
00984   // Limit stepsize so as to stop at stage time tnext
00985   // Do not use _t since might be different from Taylor expansion time
00986   if( _tmax > tnext ) _h = tnext-_tval;
00987 #ifdef MC__ODEBND_VAL_DEBUG
00988   std::cout << "\nCurrent step: t=" << _t << "  h=" << _h << "  tnext=" << tnext
00989             << "  hmax=" << _hmax << "  tmax=" << _tmax << std::endl;
00990 #endif
00991 
00992   // Enclosure propagation
00993   for( unsigned int ix=0; ix<_nx; ix++ ){
00994     PVT MVXh = _predictor( _h, q, _nx, _PMTRHS, ix ).center();
00995 #ifdef MC__ODEBND_VAL_DEBUG
00996     std::cout << "MVXh[" << ix << "] =" << MVXh;
00997 #endif
00998     // Extract state polynomial approximant in p and set to 0
00999     MVXh.get( _PMx[ix].set(_PMenv), true );
01000 #ifdef MC__ODEBND_VAL_DEBUG
01001     std::cout << "_PMx[" << ix << "] =" << _PMx[ix];
01002     std::cout << "MVXh[" << ix << "] =" << MVXh;
01003 #endif
01004     // Extract first-order terms and set to 0
01005     for( unsigned int jx=0; jx<_nx; jx++ )
01006       _Ax(ix,jx) = MVXh.linear(_np+jx,true);
01007     // Remainder is higher-order terms *plus* truncation error
01008 #ifdef MC__ODEBND_VAL_STEPSIZE_HSTAB
01009     _Rx[ix] = MVXh.bound() + _h*options.TOL*T(-1.,1.);
01010 #else
01011     _Rx[ix] = MVXh.bound() + options.TOL*T(-1.,1.);
01012 #endif
01013 #ifdef MC__ODEBND_VAL_DEBUG
01014     std::cout << "_Rx[" << ix << "] =" << _Rx[ix]
01015               << "  diam(_Rx[" << ix << "]) =" << Op<T>::diam(_Rx[ix])
01016               << "  midp(_Rx[" << ix << "]) =" << Op<T>::mid(_Rx[ix])
01017               << std::endl;
01018 #endif
01019   }
01020 #ifdef MC__ODEBND_VAL_DEBUG
01021   std::cout << "_Ax(@" << _tval << ") =\n" << _Ax << std::endl;
01022   std::cout << "_Ex(@" << _tval << ") =" << _Ex_TE << std::endl;
01023 #endif
01024 
01025   // Correct stepsize in case stepsize selection/validation was by-passed
01026   _h -= (_t-_tval); 
01027 #ifdef MC__ODEBND_VAL_DEBUG
01028   std::cout << "\nAdjusted step: h=" << _h << "  tval=" << _tval << std::endl;
01029 #endif
01030 
01031   return NORMAL;
01032 }
01033 
01034 template <typename T, typename PMT, typename PVT>
01035 inline typename ODEBND_VAL<T,PMT,PVT>::STATUS
01036 ODEBND_VAL<T,PMT,PVT>::_invariant_ELL0
01037 ( const PVT*Px, const T*Rx, std::ostream&os )
01038 {
01039   // Compute invariants in PVT arithmetic
01040   for( unsigned i=0; i<_nx; i++ ) _PMVAR[i] = Px[i];
01041   _PMVAR[_nx+_np] = _t;
01042   _pDAG->eval( _opINV, _PMDAG, _ni, _pINV, _PMINV, _nVAR, _pVAR, _PMVAR );
01043 
01044   // Compute invariant derivatives in T arithmetic
01045   for( unsigned i=0; i<_nx; i++ ) _IVAR[i] = _PMx[i].bound() + _Rx[i];
01046   _IVAR[_nx+_np] = _t;
01047   _pDAG->eval( _opFINV, _IDAG, _ni*_nx, _pFINV, _IFINV, _nVAR, _pVAR, _IVAR );
01048 
01049   // Compute invariant directions and remainders
01050   for( unsigned i=0, ij=0; i<_ni; i++ ){
01051     _Rinv[i] = _PMINV[i].remainder();
01052     for( unsigned j=0; j<_nx; j++, ij++ ){
01053       _Ainv(i,j) = Op<T>::mid(_IFINV[ij]); // row-wise storage in IFINV
01054       _Rinv[i] += ( _IFINV[ij] - _Ainv(i,j) ) * Rx[j];
01055     }
01056 #ifdef MC__ODEBND_VAL_DEBUG
01057     std::cout << "_Rinv[" << i << "] =" << _Rinv[i]
01058               << "  diam(_Rinv[" << i << "]) =" << Op<T>::diam(_Rinv[i])
01059               << "  midp(_Rinv[" << i << "]) =" << Op<T>::mid(_Rinv[i])
01060               << std::endl;
01061 #endif
01062   }
01063 #ifdef MC__ODEBND_VAL_DEBUG
01064   std::cout << "_Ainv(@" << _t << ") =\n" << _Ainv << std::endl;
01065   { int dum; std::cin >> dum; }
01066 #endif
01067 
01068   return NORMAL;
01069 }
01070 
01071 template <typename T, typename PMT, typename PVT>
01072 inline typename ODEBND_VAL<T,PMT,PVT>::STATUS
01073 ODEBND_VAL<T,PMT,PVT>::_invariant_ELL1
01074 ( const PVT*Px, const T*Rx, std::ostream&os )
01075 {
01076   // Compute invariants in PVT arithmetic
01077   for( unsigned i=0; i<_nx; i++ ) _PMVAR[i] = Px[i];
01078   _PMVAR[_nx+_np] = _t;
01079   _pDAG->eval( _opINV, _PMDAG, _ni, _pINV, _PMINV, _nVAR, _pVAR, _PMVAR );
01080 
01081   // Compute invariant derivatives in PVT arithmetic
01082   for( unsigned i=0; i<_nx; i++ ){
01083     PVT MVri( _MVenv, _np+i, Rx[i] );
01084     _MVVAR[i].set( _MVenv ).set( Px[i], true );
01085     _MVVAR[i] += MVri;
01086 #ifdef MC__ODEBND_VAL_DEBUG
01087     std::cout << "Px[" << i << "] = " << Px[i] << std::endl;
01088     std::cout << "_MVx[" << i << "] = " << _MVVAR[i] << std::endl;
01089 #endif
01090   }
01091   _MVVAR[_nx+_np] = _t;
01092   _pDAG->eval( _opFINV, _PMDAG, _ni*_nx, _pFINV, _PMFINV, _nVAR, _pVAR, _MVVAR );
01093 
01094   for( unsigned i=0, ij=0; i<_ni; i++ ){
01095     _Rinv[i] = _PMINV[i].remainder();
01096     for( unsigned j=0; j<_nx; j++, ij++ ){
01097 #ifdef MC__ODEBND_VAL_DEBUG
01098       std::cout << "_PMFINV[" << i << "," << j << "] =" << _PMFINV[ij]
01099                 << std::endl;
01100 #endif
01101       _Ainv(i,j) = _PMFINV[ij].center().constant();
01102       _Rinv[i] += ( _PMFINV[ij].bound() - _Ainv(i,j) ) * Rx[j];
01103     }
01104 #ifdef MC__ODEBND_VAL_DEBUG
01105     std::cout << "_Rinv[" << i << "] =" << _Rinv[i]
01106               << "  diam(_Rinv[" << i << "]) =" << Op<T>::diam(_Rinv[i])
01107               << "  midp(_Rinv[" << i << "]) =" << Op<T>::mid(_Rinv[i])
01108               << std::endl;
01109 #endif
01110   }
01111 #ifdef MC__ODEBND_VAL_DEBUG
01112   std::cout << "_Ainv(@" << _t << ") =\n" << _Ainv << std::endl;
01113   { int dum; std::cin >> dum; }
01114 #endif
01115 
01116   return NORMAL;
01117 }
01118 
01119 template <typename T, typename PMT, typename PVT>
01120 inline typename ODEBND_VAL<T,PMT,PVT>::STATUS
01121 ODEBND_VAL<T,PMT,PVT>::_invariant_ELL2
01122 ( const PVT*Px, const T*Rx, std::ostream&os )
01123 {
01124   // Compute invariants in PVT arithmetic (joint X,P expansion)
01125   for( unsigned i=0; i<_nx; i++ ){
01126     PVT MVri( _MVenv, _np+i, Rx[i] );
01127     _MVVAR[i].set( _MVenv ).set( Px[i], true );
01128     _MVVAR[i] += MVri;
01129 #ifdef MC__ODEBND_VAL_DEBUG
01130     std::cout << "Px[" << i << "] = " << Px[i] << std::endl;
01131     std::cout << "_MVx[" << i << "] = " << _MVVAR[i] << std::endl;
01132 #endif
01133   }
01134   _MVVAR[_nx+_np] = _t;
01135   _pDAG->eval( _opINV, _PMDAG, _ni, _pINV, _PMINV, _nVAR, _pVAR, _MVVAR );
01136 
01137   for( unsigned int i=0; i<_ni; i++ ){
01138     // Extract state polynomial approximant in p and set to 0
01139     PVT Pinv; _PMINV[i].get( Pinv.set(_PMenv), true ); //THIS SHOULD NORMALLY BE ZERO!!!
01140     // Extract first-order terms and set to 0
01141     for( unsigned int j=0; j<_nx; j++ )
01142       _Ainv(i,j) = _PMINV[i].linear( _np+j, true );
01143     _Rinv[i] = _PMINV[i].bound();
01144 #ifdef MC__ODEBND_VAL_DEBUG
01145     std::cout << "_Rinv[" << i << "] =" << _Rinv[i]
01146               << "  diam(_Rinv[" << i << "]) =" << Op<T>::diam(_Rinv[i])
01147               << "  midp(_Rinv[" << i << "]) =" << Op<T>::mid(_Rinv[i])
01148               << std::endl;
01149 #endif
01150   }
01151 #ifdef MC__ODEBND_VAL_DEBUG
01152   std::cout << "_Ainv(@" << _t << ") =\n" << _Ainv << std::endl;
01153   { int dum; std::cin >> dum; }
01154 #endif
01155 
01156   return NORMAL;
01157 }
01158 
01159 template <typename T, typename PMT, typename PVT>
01160 inline typename ODEBND_VAL<T,PMT,PVT>::STATUS
01161 ODEBND_VAL<T,PMT,PVT>::_invariant_ELL
01162 ( std::ostream&os )
01163 {
01164   if( !options.USEINV || !_ni ) return NORMAL;
01165   
01166   // Update polynomial model and derived bounds
01167   for( unsigned int ix=0; ix<_nx; ix++ ){
01168     _PMx[ix].set( T(0.) ); // polynomial part
01169     _Rx[ix] = T( _Ex.l(ix), _Ex.u(ix) ); // centered remainder
01170   }
01171 
01172   // In this variant a bound on the Jacobian matrix of the invariant is computed
01173   // and the linear part is taken as the mid-point of this matrix
01174   if( !options.ORDMIT ){
01175     if( _invariant_ELL0( _PMx, _Rx, os ) != NORMAL ) return FAILURE;
01176   }
01177 
01178   // In this variant a polynomial model of the Jacobian matrix of the invariant is
01179   // computed and the linear part is taken as the mid-point of this matrix
01180   else if( options.ORDMIT < _PMenv->nord() ){
01181     if( _invariant_ELL1( _PMx, _Rx, os ) != NORMAL ) return FAILURE;
01182   }
01183 
01184   // In this variant a polynomial model of the invariant in the joint state-parameter
01185   // and of the same order as the parameter polynomial model is computed
01186   else{
01187     if( _invariant_ELL2( _PMx, _Rx, os ) != NORMAL ) return FAILURE;
01188   }
01189 
01190   // Contract ellipsoidal remainder
01191   for( unsigned int ii=0; ii<_ni; ii++ ){
01192     // Try exact intersection with hyperplane
01193     E Ex_red;
01194     try{
01195       Ex_red = hpintersection( _Ex, std::make_pair( t(_Ainv.row(ii)), 0. ) );
01196 #ifdef MC__ODEBND_VAL_DEBUG_INVARIANT
01197       std::cout << "_Ex (intersection) =\n" << Ex_red << std::endl;
01198 #endif
01199       // Nonlinear invariant case <-- NOT YET TESTED EXTENSIVELY-->
01200       if( Op<T>::diam(_Rinv[ii]) > machprec() ){
01201         for( unsigned int jx=0; jx<_nx; jx++ )
01202           _Ninv[jx] = _Ainv(ii,jx)/(_Ainv.row(ii)%_Ainv.row(ii))*_Rinv[ii];
01203         Ex_red = minksum_ea( Ex_red, _Ninv, options.QTOL );
01204 #ifdef MC__ODEBND_VAL_DEBUG_INVARIANT
01205         std::cout << "_Ex (minkowski sum) =\n" << Ex_red << std::endl;
01206 #endif
01207       }
01208 #ifdef MC__ODEBND_VAL_DEBUG_INVARIANT
01209       int dum; std::cin >> dum;
01210 #endif
01211     }
01212     catch( E::Exceptions &eObj){
01213       continue;
01214     }
01215     if( Ex_red.trQ() < _Ex.trQ() ){
01216 #ifdef MC__ODEBND_VAL_DEBUG_INVARIANT
01217       std::cout << "_Ex (initial) =\n" << _Ex << std::endl;
01218       std::cout << "_Ex (updated) =\n" << Ex_red << std::endl;
01219       int dum; std::cin >> dum;
01220 #endif
01221       _Ex = Ex_red;
01222     }
01223   }
01224 
01225   return NORMAL;
01226 }
01227 
01228 template <typename T, typename PMT, typename PVT>
01229 inline typename ODEBND_VAL<T,PMT,PVT>::STATUS
01230 ODEBND_VAL<T,PMT,PVT>::_update_ELL
01231 ( std::ostream&os )
01232 {
01233   try{
01234     //_Ex = mtimes(_Ex_TE,_Ax);
01235     _Ex = minksum_ea( mtimes(_Ex_TE,_Ax), _Rx, options.QTOL );
01236     for( unsigned int ix=0; ix<_nx; ix++ ) _PMx[ix] += _Ex_TE.c(ix);
01237     _Ex = _Ex.O();
01238 #ifdef MC__ODEBND_VAL_DEBUG
01239     std::cout << "_Ex(" << _t+_h << ") =" << _Ex << std::endl;
01240     {int dum; std::cin >> dum;}
01241 #endif
01242   }
01243   catch( E::Exceptions &eObj){
01244     return FAILURE;
01245   }
01246 #ifdef MC__ODEBND_VAL_DEBUG
01247   for( unsigned int ix=0; ix<_nx; ix++ )
01248     std::cout << "_Rx[" << ix << " =\n" << T( _Ex.l(ix), _Ex.u(ix) ) << std::endl;
01249 #endif
01250 
01251   // Contract ellipsoidal remainder using ODE invariants
01252   if( _invariant_ELL( os ) != NORMAL ) return FAILURE;
01253 
01254   // Update polynomial model and derived bounds
01255   for( unsigned int ix=0; ix<_nx; ix++ ){
01256     _PMx[ix].set( T( _Ex.l(ix), _Ex.u(ix) ) );
01257     _Ix[ix] =_PMx[ix].bound();
01258 #ifdef MC__ODEBND_VAL_DEBUG
01259     std::cout << "_Rx[" << ix << " =\n" << T( _Ex.l(ix), _Ex.u(ix) ) << std::endl;
01260     std::cout << "_Ix[" << ix << " (bef.) = " << _Ix[ix] << std::endl;
01261 #endif
01262   }
01263 
01264   return NORMAL;
01265 }
01266 
01267 template <typename T, typename PMT, typename PVT>
01268 inline typename ODEBND_VAL<T,PMT,PVT>::STATUS
01269 ODEBND_VAL<T,PMT,PVT>::_propagate_ELL
01270 ( const double tnext, std::ostream&os )
01271 {
01272   // In this variant a bound on the Jacobian matrix is computed and the
01273   // linear part is taken as the mid-point of this matrix
01274   if( !options.ORDMIT ){
01275     if( _propagate_ELL0( options.TSORDER, tnext, os ) != NORMAL ) return FAILURE;
01276   }
01277   // In this variant a polynomial model of the Jacobian matrix is computed and the
01278   // linear part is taken as the mid-point of this matrix
01279   else if( options.ORDMIT < _PMenv->nord() ){
01280     if( _propagate_ELL1( options.TSORDER, tnext, os ) != NORMAL ) return FAILURE;
01281   }
01282   // In this variant a polynomial model in the joint state-parameter and
01283   // of the same order as the parameter polynomial model is computed
01284   else{
01285     if( _propagate_ELL2( options.TSORDER, tnext, os ) != NORMAL ) return FAILURE;
01286   }
01287 
01288   // Compute ellispoidal remainder
01289   if( _update_ELL( os ) != NORMAL ) return FAILURE;
01290 
01291   // Check enclosure diameter before returning
01292   return( _diam(_Ix) < options.DMAX? NORMAL: FAILURE );
01293 }
01294 
01295 template <typename T, typename PMT, typename PVT>
01296 inline typename ODEBND_VAL<T,PMT,PVT>::STATUS
01297 ODEBND_VAL<T,PMT,PVT>::_propagate
01298 ( const double tnext, std::ostream&os )
01299 {
01300   // Propagate validated enclosure until tnext
01301   STATUS flag = NORMAL;
01302   for( _h = 0; flag == NORMAL && tnext > _t; _t += _h ){
01303     switch( options.WRAPMIT){
01304       case Options::NONE:
01305         flag = _propagate_INT( tnext, os ); break;
01306 
01307       case Options::ELLIPS:
01308       default:
01309         flag = _propagate_ELL( tnext, os ); break;
01310     }
01311   }
01312   return flag;
01313 }
01314 
01315 template <typename T, typename PMT, typename PVT> inline bool
01316 ODEBND_VAL<T,PMT,PVT>::_resize
01317 ( const unsigned q, const unsigned iRHS )
01318 {
01319   if( _vRHS.size() <= iRHS ) return false;
01320 
01321   delete[] _pTRHS; _pTRHS = _pDAG->TAD( q+1, _nx, _vRHS[iRHS], _nx, _pVAR, _pT );
01322   _opTRHS = _pDAG->subgraph( (q+2)*_nx, _pTRHS );
01323   delete[] _PMTRHS; _PMTRHS = new PVT[(q+2)*_nx];
01324   unsigned nPMDAG = _opTRHS.size();
01325 
01326   _opTRHSval = _pDAG->subgraph( _nx, _pTRHS+(q+1)*_nx );
01327   delete[] _PMTRHSval; _PMTRHSval = options.PMVALID? new PVT[_nx]: 0;
01328   delete[] _ITRHSval; _ITRHSval = options.PMVALID? 0: new T[_nx];
01329   unsigned nIDAG = options.PMVALID? 0: _opTRHSval.size();
01330 
01331   delete[] _pFTRHS; _pFTRHS = 0;
01332   _opFTRHS.clear();
01333   delete[] _PMFTRHS; _PMFTRHS = 0;
01334   delete[] _IFTRHS;  _IFTRHS  = 0;
01335 
01336   _pINV = 0;
01337   _opINV.clear();
01338   delete[] _PMINV; _PMINV = 0;
01339 
01340   delete[] _pFINV; _pFINV = 0;
01341   _opFINV.clear();
01342   delete[] _PMFINV; _PMFINV = 0;
01343   delete[] _IFINV;  _IFINV  = 0;
01344 
01345   switch( options.WRAPMIT){
01346   case Options::NONE:
01347     break;
01348 
01349   case Options::ELLIPS: default:
01350     if( options.USEINV && _vINV.size() && _ni ){   // INV
01351       _pINV = _vINV[iRHS];
01352       _opINV = _pDAG->subgraph( _ni, _pINV );
01353       _PMINV = new PVT[_ni];
01354       if( nPMDAG < _opINV.size() ) nPMDAG = _opINV.size();
01355     }
01356     if( !options.ORDMIT ){                         // ELL0
01357       _pFTRHS = _pDAG->FAD( (q+1)*_nx, _pTRHS, _nx, _pVAR );
01358       _opFTRHS = _pDAG->subgraph( (q+1)*_nx*_nx, _pFTRHS );
01359       _IFTRHS  = new T[(q+1)*_nx*_nx];
01360       if( nIDAG < _opFTRHS.size() ) nIDAG = _opFTRHS.size();
01361       if( options.USEINV && _vINV.size() && _ni ){
01362         _pFINV = _pDAG->FAD( _ni, _pINV, _nx, _pVAR );
01363         _opFINV = _pDAG->subgraph( _ni*_nx, _pFINV );
01364         _IFINV  = new T[_ni*_nx];
01365         if( nIDAG < _opFINV.size() ) nIDAG = _opFINV.size();
01366       }
01367     }
01368     else if( _PMenv->nord() > _MVenv->nord() ){    // ELL1
01369       _pFTRHS = _pDAG->FAD( (q+1)*_nx, _pTRHS, _nx, _pVAR );
01370       _opFTRHS = _pDAG->subgraph( (q+1)*_nx*_nx, _pFTRHS );
01371       _PMFTRHS = new PVT[(q+1)*_nx*_nx];
01372       if( nPMDAG < _opFTRHS.size() ) nPMDAG = _opFTRHS.size();
01373       if( options.USEINV && _vINV.size() && _ni ){
01374         _pFINV = _pDAG->FAD( _ni, _pINV, _nx, _pVAR );
01375         _opFINV = _pDAG->subgraph( _ni*_nx, _pFINV );
01376         _PMFINV = new PVT[_ni*_nx];
01377         if( nPMDAG < _opFINV.size() ) nPMDAG = _opFINV.size();
01378       }
01379     }
01380                                                    // ELL2
01381     break;
01382   }
01383 
01384   delete[] _PMDAG; _PMDAG = new PVT[nPMDAG];
01385   delete[] _IDAG;  _IDAG  = new T[nIDAG];
01386 
01387   return true;
01388 }
01389 
01390 template <typename T, typename PMT, typename PVT>
01391 inline bool
01392 ODEBND_VAL<T,PMT,PVT>::_prepare
01393 ( const PVT* PMp )
01394 {
01395   // Check polynomial model compatibility and size
01396   unsigned int kp=_np;
01397   for( unsigned int ip=0; ip<_np && kp==_np; ip++ )
01398     if( PMp[ip].env() ) kp = ip;
01399   if( kp==_np || PMp[kp].env()->nvar()!=_np ) return false;
01400   _PMenv = PMp[kp].env();  
01401 
01402   // Internal polynomial model environment reset
01403   unsigned int MVord = ( options.ORDMIT<_PMenv->nord()? options.ORDMIT: _PMenv->nord() ); 
01404   if( !_MVenv || _MVenv->nord() != MVord || _MVenv->nvar() != _nx+_np ){
01405     delete _MVenv; _MVenv = new PMT( _nx+_np, MVord );
01406     _MVenv->options = _PMenv->options;
01407   }
01408 
01409   // Size and set DAG evaluation arrays
01410   if( _nVAR != _nx+_np+1 ){
01411     _nVAR = _nx+_np+1;
01412     delete[] _pVAR; _pVAR = new FFVar[_nVAR];
01413     delete[] _IVAR; _IVAR = new T[_nVAR];
01414     delete[] _PMVAR; _PMVAR = new PVT[_nVAR];
01415     delete[] _MVVAR; _MVVAR = new PVT[_nVAR];
01416   }
01417   for( unsigned ix=0; ix<_nx; ix++ )
01418     _pVAR[ix] = _pX[ix];
01419   for( unsigned ip=0; ip<_np; ip++ ){
01420     _pVAR[_nx+ip] = _pP[ip];
01421     _IVAR[_nx+ip]  = PMp[ip].bound();
01422     _PMVAR[_nx+ip] = PMp[ip];
01423     _MVVAR[_nx+ip].set( _MVenv, ip, _IVAR[_nx+ip] );
01424   }
01425   _pVAR[_nx+_np] = (_pT? *_pT: 0. );
01426 
01427   // State bounds
01428   if( !_Ix )  _Ix  = new T[_nx];
01429   if( !_PMx ) _PMx = new PVT[_nx];
01430 
01431   // Size environments and arrays
01432   switch( options.WRAPMIT){
01433   case Options::NONE:
01434     break;
01435 
01436   case Options::ELLIPS:
01437   default:
01438     if( _Ax.n != _nx ){
01439       _Ax.resize(_nx,_nx);
01440       delete[] _Rx;    _Rx    = new T[_nx];
01441       delete[] _Rx_TE; _Rx_TE = new T[_nx];
01442     }
01443     if( options.USEINV && _ni && ( _Ainv.n != _nx || _Ainv.m != _ni ) ){
01444       _Ainv.resize(_ni,_nx);
01445       delete[] _Rinv;  _Rinv = new T[_ni];
01446       delete[] _Ninv;  _Ninv = new T[_ni];
01447     }
01448     break;
01449   }
01450 
01451   return true;
01452 }
01453 
01454 template <typename T, typename PMT, typename PVT>
01455 inline bool
01456 ODEBND_VAL<T,PMT,PVT>::_init
01457 ( const unsigned k, const double tk, PVT*PMxk, E*Exk )
01458 {
01459   if( !_vIC.size() ) return false;
01460   if( k && _vIC.size()>1 ) throw Exceptions( Exceptions::REINIT );
01461   if( k ) return true;
01462 
01463   _t = _tmax = tk;
01464   _pIC = _vIC.at(0);
01465   _opIC = _pDAG->subgraph( _nx, _pIC );
01466  
01467   switch( options.WRAPMIT){
01468 
01469   case Options::NONE:
01470     _pDAG->eval( _opIC, _nx, _pIC, _PMx, _np, _pVAR+_nx, _PMVAR+_nx );
01471     for( unsigned int ix=0; ix<_nx; ix++ )
01472       _Ix[ix] = _PMx[ix].center().bound();
01473     _Ex.set();
01474     break;
01475 
01476   case Options::ELLIPS:
01477   default:
01478     _pDAG->eval( _opIC, _nx, _pIC, _PMx, _np, _pVAR+_nx, _PMVAR+_nx );
01479     for( unsigned int ix=0; ix<_nx; ix++ ){
01480       _PMx[ix].center();
01481       _Rx[ix] = _PMx[ix].remainder();
01482       _Ix[ix] = _PMx[ix].bound();
01483 #ifdef MC__ODEBND_VAL_DEBUG
01484       std::cout << "PMx0[" << ix << "] =" << _PMx[ix] << std::endl;
01485 #endif
01486     }
01487     _Ex.set( _nx, _Rx );
01488 #ifdef MC__ODEBND_VAL_DEBUG
01489       std::cout << "Ex0 =" << _Ex << std::endl;
01490 #endif
01491     // THERE MIGHT BE A BETTER WAY OF INITIALIZING IF AN ELLIPSOIDAL
01492     // REMAINDER BOUND IS KNOWN FOR THE PARAMETERS
01493     break;
01494   }
01495 
01496   // Copy internal variables back into arguments
01497   for( unsigned ix=0; ix<_nx; ix++ ) PMxk[ix] = _PMx[ix];
01498   if( Exk ) *Exk = _Ex;
01499   return true;
01500 }
01501 
01516 template <typename T, typename PMT, typename PVT>
01517 inline typename ODEBND_VAL<T,PMT,PVT>::STATUS
01518 ODEBND_VAL<T,PMT,PVT>::bounds
01519 ( const unsigned int ntk, const double*tk, const PVT*PMp, PVT**PMxk,
01520   E*Exk, std::ostream&os )
01521 {
01522 
01523   // Initialize validated ODE bounding
01524   if( !_prepare( PMp ) ) return FATAL;
01525   _results.clear();  
01526   _init_stats( stats_traj );
01527 
01528   try{
01529     // Initial state bounds
01530     if( !_init( 0, tk[0], PMxk[0], Exk ) ) return FATAL;
01531     if( options.DISPLAY >= 1 )
01532       switch( options.WRAPMIT ){
01533         case Options::NONE:   _print_interm( tk[0], _PMx, "x", os );      break;
01534         case Options::ELLIPS: _print_interm( tk[0], _PMx, _Ex, "x", os ); break;
01535       }
01536     // Record initial results
01537     if( options.RESRECORD )
01538       _results.push_back( Results( tk[0], _nx, _PMx ) );
01539 
01540     // Integrate ODEs through each stage
01541     for( _istg=0; _istg<ntk; _istg++ ){
01542 
01543       // update list of operations in RHS and INV
01544       const unsigned int iRHS = ( _vRHS.size()<2? 0: _istg );
01545       if( (!_istg || iRHS) && !_resize( options.TSORDER, iRHS ) ) return FATAL;
01546 
01547       if( _istg && !_init( _istg, tk[_istg], PMxk[_istg], Exk+_istg ) ) return FATAL;
01548       if( _propagate( tk[_istg+1], os ) != NORMAL ){
01549         _final_stats( stats_traj );
01550         if( options.DISPLAY >= 1 ) _print_stats( stats_traj, os );
01551    return FAILURE;
01552       }
01553       for( unsigned int ix=0; ix<_nx; ix++ ) PMxk[_istg+1][ix] = _PMx[ix];
01554       if( Exk ) Exk[_istg+1] = _Ex;
01555       if( options.DISPLAY >= 1 )
01556         switch( options.WRAPMIT ){
01557           case Options::NONE:   _print_interm( tk[_istg+1], _PMx, "x", os );      break;
01558           case Options::ELLIPS: _print_interm( tk[_istg+1], _PMx, _Ex, "x", os ); break;
01559         }
01560       // Record intermediate results
01561       if( options.RESRECORD ) _results.push_back( Results( tk[_istg+1], _nx, _PMx ) );
01562     }
01563   }
01564   catch(...){
01565     _final_stats( stats_traj );
01566     if( options.DISPLAY >= 1 ) _print_stats( stats_traj, os );
01567     return FAILURE;
01568   }
01569 
01570   _final_stats( stats_traj );
01571   if( options.DISPLAY >= 1 ) _print_stats( stats_traj, os );
01572   return NORMAL;
01573 }
01574 
01575 template <typename T, typename PMT, typename PVT> inline typename ODEBND_VAL<T,PMT,PVT>::STATUS
01576 ODEBND_VAL<T,PMT,PVT>::_remainders
01577 ( const unsigned int ns, const double*tk, const T*Ip, const PVT*const*PMxk,
01578   T**Rxk, const unsigned int nsamp, std::ostream&os )
01579 {
01580   STATUS flag = NORMAL;
01581   
01582   // Initialization of sampled bounds at parameter lower bound
01583   double *p = new double[_np];
01584   for( unsigned int ip=0; ip<_np; ip++ )
01585     p[ip] = Op<T>::l(Ip[ip]);
01586   double **xk = new double*[ns+1];
01587   for( unsigned int is=0; is<=ns; is++ )
01588     xk[is] = new double[_nx];
01589   flag = _ODESLV_GSL->states( ns, tk, p, xk, 0, os );
01590   if( flag != NORMAL || nsamp <= 1 ){
01591     delete[] p;
01592     for( unsigned int is=0; is<=ns; is++ ) delete[] xk[is]; delete[] xk;
01593     return flag;
01594   }   
01595   for( unsigned int is=0; is<=ns; is++ )
01596     for( unsigned int ix=0; ix<_nx; ix++ )
01597       Rxk[is][ix] = xk[is][ix] - PMxk[is][ix].polynomial( p );
01598   
01599   // Start sampling process
01600   unsigned int* vsamp = new unsigned int[_np];
01601   flag = _remainders( ns, tk, Ip, PMxk, Rxk, nsamp, vsamp, 0, p, xk, os );
01602   
01603   // Clean-up
01604   delete[] p;
01605   for( unsigned int is=0; is<=ns; is++ ) delete[] xk[is]; delete[] xk;
01606   delete[] vsamp;
01607   
01608   return flag;
01609 }
01610 
01611 template <typename T, typename PMT, typename PVT> inline typename ODEBND_VAL<T,PMT,PVT>::STATUS
01612 ODEBND_VAL<T,PMT,PVT>::_remainders
01613 ( const unsigned int ns, const double*tk, const T*Ip, const PVT*const*PMxk,
01614   T**Rxk, const unsigned int nsamp, unsigned int* vsamp, const unsigned int ip,
01615   double*p, double**xk, std::ostream&os )
01616 {
01617   STATUS flag = NORMAL;
01618 
01619   // Update bounds for all sampling points
01620   for( unsigned int isamp=0; isamp<nsamp; isamp++ ){
01621     vsamp[ip] = isamp;
01622 
01623     // Continue recursive call
01624     if( ip+1 < _np ){
01625       flag = _remainders( ns, tk, Ip, PMxk, Rxk, nsamp, vsamp, ip+1, p, xk, os );
01626       if( flag != NORMAL ) return flag;
01627       continue;
01628     }
01629 
01630     // Update bounds for current point
01631 #ifdef MC__ODEBND_GSL_SAMPLE_DEBUG
01632     std::cout << "Sample: ";
01633 #endif
01634     for( unsigned int ip=0; ip<_np; ip++ ){
01635       p[ip] = Op<T>::l( Ip[ip] ) + vsamp[ip]/(nsamp-1.) * Op<T>::diam( Ip[ip] );
01636 #ifdef MC__ODEBND_GSL_SAMPLE_DEBUG
01637       std::cout << p[ip] << "  ";
01638 #endif
01639     }
01640 #ifdef MC__ODEBND_GSL_SAMPLE_DEBUG
01641     std::cout << std::endl;
01642 #endif
01643     flag = _ODESLV_GSL->states( ns, tk, p, xk, 0, os );
01644     if( flag != NORMAL ) return flag;
01645     for( unsigned int is=0; is<=ns; is++ )
01646       for( unsigned int ix=0; ix<_nx; ix++ )
01647         Rxk[is][ix] = Op<T>::hull( xk[is][ix]-PMxk[is][ix].polynomial(p),
01648                                    Rxk[is][ix] );
01649   }
01650 
01651   return flag;
01652 }  
01653 
01670 
01671 template <typename T, typename PMT, typename PVT> inline typename ODEBND_VAL<T,PMT,PVT>::STATUS
01672 ODEBND_VAL<T,PMT,PVT>::hausdorff
01673 ( const unsigned int ns, const double*tk, const PVT*PMp, double**Hxk,
01674   const unsigned int nsamp, std::ostream&os )
01675 {
01676   int DISPLAY_ODEBND = options.DISPLAY;
01677   int DISPLAY_ODESLV = options.ODESLVOPT.DISPLAY;
01678   options.DISPLAY = 0;
01679   options.ODESLVOPT.DISPLAY = 0;
01680   _ODESLV_GSL->set( *this ); // in base class BASE_ODE
01681   _ODESLV_GSL->options = options.ODESLVOPT;
01682   _ODESLV_GSL->options.RESRECORD = false;
01683 
01684   // Compute approximate bounds
01685   PVT** PMxk = new PVT*[ns+1];
01686   for( unsigned int is=0; is<ns+1; is++ ) PMxk[is] = new PVT[_nx];
01687   try{ bounds( ns, tk, PMp, PMxk, 0, os ); }
01688   catch(...){;}
01689   unsigned int nsf = _istg;
01690   for( unsigned int is=nsf; is<ns; is++ )
01691     for( unsigned int ix=0; ix<_nx; ix++ )
01692       PMxk[is+1][ix] = T( -1e20, 1e20 );
01693 
01694   // Compute remainder bounds 
01695   T* Ip = new T[_np];
01696   for( unsigned int ip=0; ip<_np; ip++ ) Ip[ip] = PMp[ip].B();
01697   T** Rxk = new T*[ns+1];
01698   for( unsigned int is=0; is<ns+1; is++ ) Rxk[is] = new T[_nx];
01699   _remainders( nsf, tk, Ip, PMxk, Rxk, nsamp, os );
01700   for( unsigned int is=nsf; is<ns; is++ )
01701     for( unsigned int ix=0; ix<_nx; ix++ )
01702       Rxk[is+1][ix] = T( 0. );
01703 
01704   // Compute Hausdorff metric at each time step
01705   struct loc{ static double hausdorff
01706     ( const T&Ix, const T&Ix0 )
01707     { return std::max( std::fabs(Op<T>::l(Ix)-Op<T>::l(Ix0)),
01708                        std::fabs(Op<T>::u(Ix)-Op<T>::u(Ix0)) ); }
01709   };
01710 
01711   options.DISPLAY = DISPLAY_ODEBND;
01712   options.ODESLVOPT.DISPLAY = DISPLAY_ODESLV;
01713   for( unsigned int is=0; is<ns+1; is++ ){
01714     for( unsigned int ix=0; ix<_nx; ix++ )
01715       Hxk[is][ix] = loc::hausdorff( PMxk[is][ix].R(), Rxk[is][ix] );
01716     if( options.DISPLAY >= 1 ){
01717       _print_interm( tk[is], Hxk[is], "dH", os );
01718     }
01719   }
01720 
01721   for( unsigned int is=0; is<ns+1; is++ ) delete[] Rxk[is];
01722   delete[] Rxk;
01723   for( unsigned int is=0; is<ns+1; is++ ) delete[] PMxk[is];
01724   delete[] PMxk;
01725   delete[] Ip;
01726 
01727   return NORMAL;
01728 }
01729 
01730 template <typename T, typename PMT, typename PVT>
01731 template <typename U> inline void
01732 ODEBND_VAL<T,PMT,PVT>::_print_interm
01733 ( const double t, const U*x, const std::string&var, std::ostream&os ) const
01734 {
01735   os << " @t = " << std::scientific << std::setprecision(4)
01736                  << std::left << t << " :" << std::endl;
01737   for( unsigned int ix=0; ix<_nx; ix++ )
01738     os << " " << var.c_str() << "[" << ix << "] = " << x[ix] << std::endl;
01739   return;
01740 }
01741 
01742 template <typename T, typename PMT, typename PVT>
01743 template <typename U, typename V> inline void
01744 ODEBND_VAL<T,PMT,PVT>::_print_interm
01745 ( const double t, const U*x, const V&r, const std::string&var, std::ostream&os ) const
01746 {
01747   os << " @t = " << std::scientific << std::setprecision(4)
01748                  << std::left << t << " :" << std::endl;
01749   for( unsigned int ix=0; ix<_nx; ix++ )
01750     os << " " << var.c_str() << "[" << ix << "] = " << x[ix] << std::endl;
01751   os << " " << "R" << var.c_str() << " =" << r << std::endl;
01752   return;
01753 }
01754 
01755 template <typename T, typename PMT, typename PVT>
01756 inline void
01757 ODEBND_VAL<T,PMT,PVT>::record
01758 ( std::ofstream&bndrec, const unsigned int iprec ) const
01759 {
01760   if( !bndrec ) return;
01761 
01762   // Specify format
01763   bndrec << std::right << std::scientific << std::setprecision(iprec);
01764 
01765   // Record computed interval bounds at stage times
01766   typename std::vector< Results >::const_iterator it = _results.begin();
01767   for( ; it != _results.end(); ++it ){
01768     bndrec << std::setw(iprec+9) << (*it).t;
01769     for( unsigned int ix=0; ix<_nx; ix++ )
01770       bndrec << std::setw(iprec+9) << mc::Op<T>::l( (*it).X[ix] )
01771              << std::setw(iprec+9) << mc::Op<T>::u( (*it).X[ix] );
01772     bndrec << std::endl;
01773   }
01774 }
01775 
01776 template <typename T, typename PMT, typename PVT>
01777 inline void
01778 ODEBND_VAL<T,PMT,PVT>::_init_stats
01779 ( Stats&stats )
01780 {
01781   // Initialize statistics
01782   stats.reset();
01783   timeval time;
01784   gettimeofday(&time, 0) ;
01785   stats.cputime = - time.tv_sec - time.tv_usec*1e-6;
01786 }
01787 
01788 template <typename T, typename PMT, typename PVT>
01789 inline void
01790 ODEBND_VAL<T,PMT,PVT>::_final_stats
01791 ( Stats&stats )
01792 {
01793   // Get final CPU time
01794   timeval time;
01795   gettimeofday(&time, 0);
01796   stats.cputime += time.tv_sec + time.tv_usec*1e-6;
01797 }
01798 
01799 template <typename T, typename PMT, typename PVT>
01800 inline void
01801 ODEBND_VAL<T,PMT,PVT>::_print_stats
01802 ( const Stats&stats, std::ostream&os )
01803 {
01804   // Statistics
01805   os << " No STEPS  " << stats.numSteps
01806      << std::endl
01807      << " No EVALATIONS"
01808      << "   TRHS:  " << stats.numTRHS_I << " (IA)  " << stats.numTRHS_PM << " (PM)"
01809      << "   FTRHS: " << stats.numFTRHS_I << " (IA)  " << stats.numFTRHS_PM << " (PM)"
01810      << std::endl
01811      << " CPU TIME (SEC)     " << std::fixed << std::left
01812      << std::setprecision(5) << stats.cputime  << std::endl;
01813   return;
01814 }
01815 
01816 } // end namescape mc
01817 #endif