4

抱歉,如果这是一个简单的问题-但是是否有“最佳实践”来对 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++;
      }
   }
};
4

2 回答 2

3

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

于 2013-12-04T10:08:49.770 回答
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 ) ) );
于 2013-12-04T07:12:11.500 回答