Извините, если это простой вопрос — но есть ли «лучшая практика» для уменьшения выборки переменных состояния в 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++;
}
}
};
У меня была та же проблема, и я решил ее точно так же, как ты. Однако вы также можете рассмотреть возможность использования степпера с управлением размером шага, а затем использовать integrate_const с dt, чтобы наблюдатель вызывался с необходимыми интервалами. Когда вы используете степпер с контролем размера шага (даже лучше: плотный выход, такой как dopri5), integrate_const регулирует размер шага в соответствии с вашей погрешностью, но затем гарантирует, что наблюдатель вызывается в моменты времени t0 + n * dt.
На самом деле я бы сделал это так же, как вы. Вы также можете написать небольшой адаптер для выполнения шага:
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 ) ) );