odeint(c ++) - 下采样观察

时间:2013-12-03 20:26:26

标签: c++ numeric odeint

很抱歉,如果这是一个简单的问题 - 但是有一个"最佳实践"用于下采样odeint中状态变量的演变?

下面,我复制了一个很好的例子来构建一个"观察者"记录本文中提供的状态变量(http://www.codeproject.com/Articles/268589/odeint-v2-Solving-ordinary-differential-equations

struct streaming_observer
{
     std::ostream &m_out;

     streaming_observer( std::ostream &out ) : m_out( out ) {}

     void operator()( const state_type &x , double t ) const
     {
          m_out << t;
          for( size_t i=0 ; i < x.size() ; ++i )
              m_out << "\t" << x[i];
          m_out << "\n";
     }
};

// ...

integrate_const( runge_kutta4< state_type >() , lorenz , x , 0.0 , 10.0 , dt , streaming_observer( std::cout ) );

你如何改变观察者只能每10步记录一次状态(例如)。我想知道是否有更优雅的解决方案而不是使用if语句:

struct streaming_observer
{
  std::ostream &m_out;
  int count;

  streaming_observer( std::ostream &out ) : m_out( out ) {count = 10;}

  void operator()( const state_type &x , double t ) const
  {
    if( count == 10 )  {
      count = 1;
      m_out << t;
      for( size_t i=0 ; i < x.size() ; ++i )
        m_out << "\t" << x[i];
        m_out << "\n";
      }
      else {
        count++;
      }
   }
};

2 个答案:

答案 0 :(得分:3)

我遇到了同样的问题并且像你一样解决了它。但是,您也可以考虑使用具有步长控制的步进器,然后将integrate_const与dt一起使用,以便以所需的间隔调用观察器。当您使用具有步长控制的步进器(甚至更好:像dopri5这样的密集输出)时,integrate_const会根据您的容错来调整步长,但随后会确保在t0 + n * dt时调用观察者。

答案 1 :(得分:2)

实际上我会像你一样。您还可以编写一个小型适配器来进行跨步:

template< typename Obs >
struct striding_observer {
    size_t stride , count;
    Observer obs;
    striding_observer( size_t s , Obs o ) : stride(s) , count(1) , obs(o) { }
    template< typename S , typename T >
    void operator()( State const& s , Time const& t ) {
        if( count == stride ) {
            obs( s , t );
            count = 1;
        } else {
            ++count;
        }
    }
};

template< typename Obs >
striding_observer< Obs > make_striding_observer( size_t stride , Obs o ) {
    return striding_observer< Obs >( stride , o );
}

然后跨步是可选的和可组合的。然后,您可以将第一个示例写为

integrate_const( runge_kutta4< state_type >() ,
    lorenz , x , 0.0 , 10.0 , dt ,
    make_striding_observer( 10 , streaming_observer( std::cout ) ) );