停止与推力使用的odeint集成
Stop integration with odeint used with thrust
我正在尝试将ODE系统与odeint库集成,并在一组点上并行推进(这意味着具有许多不同初始条件的相同ODE)。特别地,我使用了自适应步长算法runge_kutta_dopri5。算法在某些点上失败,减少了步长,极大地减慢了整个积分过程。
是否存在一种方法,如果集合中的某些点未能通过某个测试,则仅对这些点停止积分过程?
在我的特殊情况下,因为我在积分一个重力问题,我想在点靠近吸引子时停止积分,所以距离小于某个极限。
在串行计算中,我认为这可以通过使用stepper.try_step
函数的自定义while循环来执行,如本问题背后的思想所示。
如何在带推力的并行计算中实现这一点?
谢谢。
如上所述,这个问题没有直接的解决方案。
一个可能的解决方案是提供一个
- 报告ODE已经停止的整型向量。因此,如果此向量的第i个元素为零,则表示第i个ODE仍在运行。
- runge_kutta_dopri5中的一个自定义错误检查器,如果当前系统已经停止,它将错误设置为0。这样就避免了该误差对步长控制机制的影响,至少不会对步长控制产生负面影响。下面是如何实现的草图
- 检查集成是否停止的功能。这原则上可以放置在观察者中。
自定义错误检查器的草图可以是(它是从default_error_checker复制的):
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;
};
您可以通过
在受控runge kutta中使用这样的检查器。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 , ... )));
最后需要一个函数检查哪个ODE已经停止。我们称这个函数为check_finish_status
:
void check_finish_status(
const state_type &x ,
thrust::device_vector< int > &is_stopped );
你可以在观察者内部调用这个函数,你需要将is_stopped传递给观察者。
我们还有一个实验性的脏分支,其中步长控制直接在GPU上运行,并分别控制每个ODE。这是非常强大和高性能的。不幸的是,这个功能不能很容易地集成到主分支中,因为许多__device__ __host__
说明符需要添加到odeint的方法中。如果您愿意,您可以检查odeint存储库中的cuda_controlled_step分支和/或给我留言以获取进一步的说明。
我认为这是一个很难在GPU上实现的问题。
我曾经做过一个类似的模拟,我必须对同一个系统的许多初始条件进行积分,但每次积分在不同的步数后停止。不仅仅是微小的变化,而是数量级的变化,比如在1000到10^6步之间。我用OpenMP编写了一个并行化程序,运行在48核上。我所做的对于OpenMP并行化非常简单:每当一个初始条件完成时,下一个初始条件就会启动。只要轨迹的总数比并行线程大得多,这是相当有效的。原则上,你也可以在GPU上实现这种方式。一旦一个轨迹结束,你用一个新的初始条件替换它。当然,你必须做一些记录,特别是如果你的系统是时间依赖的。但总的来说,我认为这是可行的
- 将公共但非静态的成员函数与ALGLIB集成
- 将IBM Rhapsody模型集成到VS 2019中
- 从R调用C++函数并对其进行集成时出错
- boost odeint什么时候真正调用观测者
- 将 boost::odeint 与向量类一起使用,而无需调整向量的大小
- 如何集成 HID USB 控制器?
- 在VS2019项目中集成ImageMagick:x64-windows-static library
- 将Qt集成到现有的VS项目中以取代WinAPI
- 将 Crashpad 与 Windows Qt 应用程序集成
- Python3.6 模板中的 CGAL C++ 集成错误
- Eigen::VectorXd 和 Boost::Odeint,不起作用
- 基本 Cuda C++项目集成问题
- 如何使用CMake将QtMultimedia组件集成到项目中?
- 在 Mac OS 中将 QT 与 CMAKE 集成
- 使用 GSL 库制作样条曲线并使用它们进行集成
- 与 boost odeint 集成期间的析构函数调用
- 犰狳与 Boost Odeint 冲突:Odeint 在集成期间将状态向量调整为零
- 我需要做些什么才能使odeint集成函数在另一个类中编译
- 用僵硬的代码停止odeint中的集成
- 停止与推力使用的odeint集成