C++ 停止与推力使用的odeint集成
我试图将ODE系统与odeint库集成在一起,并在一组点上并行推进(这意味着相同的ODE具有许多不同的初始条件)。我特别使用了自适应步长算法runge_kutta_dopri5。 在某些情况下,该算法会失败,从而减小步长,并极大地减慢整个积分过程 如果某个测试失败,是否有办法仅对集合中的某些点停止集成过程 在我的特殊情况下,因为我在积分一个重力问题,我想在点靠近吸引子时停止积分,所以距离小于某个极限 在串行计算中,我认为这可以通过使用C++ 停止与推力使用的odeint集成,c++,thrust,differential-equations,odeint,C++,Thrust,Differential Equations,Odeint,我试图将ODE系统与odeint库集成在一起,并在一组点上并行推进(这意味着相同的ODE具有许多不同的初始条件)。我特别使用了自适应步长算法runge_kutta_dopri5。 在某些情况下,该算法会失败,从而减小步长,并极大地减慢整个积分过程 如果某个测试失败,是否有办法仅对集合中的某些点停止集成过程 在我的特殊情况下,因为我在积分一个重力问题,我想在点靠近吸引子时停止积分,所以距离小于某个极限 在串行计算中,我认为这可以通过使用步进器的自定义while循环来实现。请尝试使用step功能,如
步进器的自定义while循环来实现。请尝试使用step
功能,如后面的想法所示
如何在具有推力的并行计算中实现这一点
谢谢。如前所述,这个问题没有直接的解决方案 一种可能的解决方案是提供
我们还有一个实验性的分支,其中步长控制直接在GPU上运行,并分别控制每个ODE。这是非常强大和高性能的。不幸的是,此功能无法轻松集成到主分支中,因为需要在odeint的方法中添加大量的
\uuuuu设备\uuuuuuuuuuu主机\uuuuuuuuu
说明符。如果您愿意,您可以查看odeint存储库中的cuda_控制的_步进器分支和/或给我留言以获取进一步的说明。我认为这是一个很难在具有推力的GPU上实现的问题
我曾经做过一个类似的模拟,我必须对同一个系统的许多初始条件进行积分,但每次积分都会在不同的步骤后停止。不仅仅是微小的变化,还有数量级的变化,比如1000到10^6步之间。我使用在48个内核上运行的OpenMP编写了一个并行化程序。对于OpenMP并行化,我所做的非常简单:只要一个初始条件完成,下一个条件就会开始。只要轨迹的总数远大于并行线程,这是相当有效的。原则上,您也可以通过这种方式在GPU上实现它。一旦一条轨迹完成,就用一个新的初始条件替换它。当然,你必须做一些簿记,特别是如果你的系统是依赖于时间的。但总的来说,我认为这可能有效。你说的“一组点”是什么意思?你有一个大的常微分方程,它由许多小的常微分方程组成,具有不同的参数或初始条件吗?在这种情况下,仅在单独的部分上停止积分并不容易。是的,我必须从许多不同的初始条件开始执行相同的积分。好的,这不是很容易解决的。我很快会尝试绘制一个解决方案。也许你可以抛出一个异常来保证整个计算。这听起来比我的解决方案要简单一些。谢谢,我认为这是正确的方法,我也有一个在OpenMP上实现它的想法,但是我如何在GPU上实现它呢?我认为使用odeint我可以尝试的最近的事情是使用cuda_控制的_步进器分支。。。还有其他方法吗?这应该很容易与推力一起工作。你有两个设备向量,一个是当前在GPU上运行的,另一个应该运行的。如果当前运行的某个IC停止,只需将新IC复制到此位置并继续集成。如果没有更多已调度的IC,只需从设备_向量中删除此初始条件。对于这种方法,您应该使用always_resizer,因为在集成过程中,整个ODE的长度可能会发生变化。谢谢,我尝试了您的解决方案,它是有效的(如果我在第9行用
custom
替换default
),并且我的程序速度快了大约2倍!但我希望有一个程序,正如@mariomulansky所说:“只要一个初始条件完成,下一个条件就会开始”。不幸的是,到目前为止,我认为在odeint中并行化并不是这样做的。我看了cuda_控制的_步进机分支,很快我就会试试。
class custom_error_checker
{
public:
typedef double value_type;
typedef thrust_algebra algebra_type;
typedef thrust_operations operations_type;
default_error_checker(
const thrust::device_vector< int > &is_stopped ,
value_type eps_abs = static_cast< value_type >( 1.0e-6 ) ,
value_type eps_rel = static_cast< value_type >( 1.0e-6 ) ,
value_type a_x = static_cast< value_type >( 1 ) ,
value_type a_dxdt = static_cast< value_type >( 1 ) )
: m_is_stopped( is_stopped ) ,
m_eps_abs( eps_abs ) , m_eps_rel( eps_rel ) ,
m_a_x( a_x ) , m_a_dxdt( a_dxdt )
{ }
template< class State , class Deriv , class Err , class Time >
value_type error( const State &x_old ,
const Deriv &dxdt_old ,
Err &x_err , Time dt ) const
{
return error( algebra_type() , x_old , dxdt_old , x_err , dt );
}
template< class State , class Deriv , class Err , class Time >
value_type error( algebra_type &algebra ,
const State &x_old ,
const Deriv &dxdt_old ,
Err &x_err , Time dt ) const
{
// this overwrites x_err !
algebra.for_each3( x_err , x_old , dxdt_old ,
typename operations_type::template rel_error< value_type >(
m_eps_abs , m_eps_rel , m_a_x ,
m_a_dxdt * get_unit_value( dt ) ) );
thrust::replace_if( x_err.begin() ,
x_err.end() ,
m_is_stopped.begin() ,
thrust::identity< double >()
0.0 );
value_type res = algebra.reduce( x_err ,
typename operations_type::template maximum< value_type >() ,
static_cast< value_type >( 0 ) );
return res;
}
private:
thrust::device_vector< int > m_is_stopped;
value_type m_eps_abs;
value_type m_eps_rel;
value_type m_a_x;
value_type m_a_dxdt;
};
typedef runge_kutta_dopri5< double , state_type , double , state_type ,
thrust_algebra , thrust_operation > stepper;
typedef controlled_runge_kutta< stepper ,
custom_error_checker > controlled_stepper ;
typedef dense_output_runge_kutta< controlled_stepper > dense_output_stepper;
thrust::device_vector< int > is_stopped;
// initialize an is_finished
dense_output_stepper s(
controlled_stepper(
custom_controller( is_stopped , ... )));
void check_finish_status(
const state_type &x ,
thrust::device_vector< int > &is_stopped );