如何将向量传递给基于推力的 odeint 观察者的构造函数,以便可以在函子中读取它

Posted

技术标签:

【中文标题】如何将向量传递给基于推力的 odeint 观察者的构造函数,以便可以在函子中读取它【英文标题】:How to pass a vector to the constructor of a thrust-based odeint observer, such that it can be read within the functor 【发布时间】:2014-10-23 19:47:44 【问题描述】:

我正在从 boost 与推力一起使用的 odeint 扩展参数研究示例,我不知道如何将值向量传递给观察者的构造函数,以便可以从内部访问(只读)这些值观察者的函子。

以下是观察者专用的代码。

//// Observes the system, comparing the current state to 
//// values in unchangingVector

struct minimum_perturbation_observer  
  struct minPerturbFunctor
  
    template< class T >
    __host__ __device__
    void operator()( T t ) const
    
    //// I would like to be able to read any member 
    //// of m_unchangingVector here.
    
  ;


  // CONSTRUCTOR
  minimum_perturbation_observer( size_t N, state_type unchangingVector, int len) : 
        m_N( N ),
        m_output( N ),
        m_unchangingVector( len ) // len is the correct length of unchangingVector
  
    // all trials start with output = 0
    thrust::fill( m_output.begin() , m_output.end() , 0.0 );

    // copy unchangingVector to m_unchangingVector, the latter 
    // of which should be accessible from the functor operator() 
    // above.
    thrust::copy( unchangingVector.begin(), unchangingVector.end(),
                  m_unchangingVector.begin());
  

  template< class State >
  void operator()(State x , value_type t )
  
    thrust::for_each(
                 thrust::make_zip_iterator( thrust::make_tuple(
                                   boost::begin( x ) + 0*m_N,
                                   boost::begin( x ) + 1*m_N,
                                   boost::begin( m_output )
                                   )
                            ),
                 thrust::make_zip_iterator( thrust::make_tuple(
                                   boost::begin( x ) + 1*m_N,
                                   boost::begin( x ) + 2*m_N,
                                   boost::begin( m_output ) + m_N
                                       )
                            ) ,
                 minPerturbFunctor() );
  

  // variables
  size_t m_N; // number of trials (i.e. number of initial conditions)
  state_type m_output;   // of length N_ICS
  state_type m_unchangingVector; // 
;

我尝试过制作 m_unchangVector staticconst,但这不正确,因为它需要在观察者实例化时设置。

或者,也许最好的方法是在thrust::make_zip_iterator( thrust::make_tuple(... 中将 unchangingVector 作为另一个参数传递,但我觉得这些项目将按照状态变量的方式进行索引(这不是我想要的)。一个可能有帮助的答案是解释函子声明中 (T t) 的含义,以及如何将 unchangedVector 作为同一个对象传递给正在评估运算符的每个线程。

我认为这可能只是选择正确的关键字变量描述符的问题,但我不知道要使用哪个(或多个),我不知道如何查找/弄清楚。

上面代码的错误是error: a nonstatic member reference must be relative to a specific object。当我尝试在函子中访问 m_unchangVector 时抛出。


经过进一步探索,我觉得我已经确定了完成这项任务的正确方法,但我仍然卡住了。

我已经为函子添加了一个构造函数。

  struct minPerturbFunctor
  

    minPerturbFunctor( state_type unchangingVector, int len ) :
    f_unchangingVector( len ) 
    
      // copy from argument to local vector (probably unnecessary, but
      // getting errors about calling host-functions from device/host 
      // so being paranoid about trying to make sure things are device-side
      thrust::copy( f_unchangingVector.begin(), 
                    f_unchangingVector.end(), 
                    unchangingVector.begin());
      f_len = len;      
    ;

    template< class T >
    __host__ __device__
    void operator()( T t ) const
    
        // I can now access f_len here (progress!)
        // But when I try to access any element via e.g., 
        // f_unchangingVector[0] I get the error below
    
  ;

警告:从 host device 调用 host 函数("thrust::detail::vector_base > ::operator []") > function("minimum_perturbation_observer::minPerturbFunctor::operator () > ") 是不允许的

错误信息 /usr/local/cuda/bin/..//include/thrust/detail/function.h(104): 错误:调用 host 函数("thrust::device_vector > ::device_vector" ) 来自 设备 函数("thrust::detail::device_function ::device_function") 是不允许的

我做错了什么?

【问题讨论】:

我认为我在github.com/boostorg/odeint/blob/master/examples/thrust/… 找到了一个可以满足我需要的示例。我会进一步查看并在这里发布。 您可以将初始化参数传递给您的仿函数。该参数可以是.data()thrust::device_vector 返回的指针。然后可以在函子中使用该指针,使用普通的 c 指针方法来访问函子中设备向量的任何元素。 概述了将初始化值传递给函子(通过它的构造函数)的一般方法here 在您的情况下,您将拥有像T *a; 这样的结构的数据元素并传递初始化元素大致来说就是m_unchangingVector.data() @RobertCrovella 我可以撤回我的答案,这样您就可以给出正确(并且希望)接受的答案... 我看不出你的回答有什么问题。我投了赞成票。我还没有真正尝试过,但我认为它正确地传达了这个想法。 【参考方案1】:

您可以将推力向量传递给函子,但您不能轻松地将其存储在此处。但是你可以存储来自这个向量的底层原始指针:

struct minPerturbFunctor

    state_type::value_type* m_ptr;
    size_t m_len;
    minPerturbFunctor( state_type const& x )
    : m_ptr( thrust::raw_pointer_cast(&x[0]) )
    , m_len( x.size() )
     

    template< class T >
    __host__ __device__
    void operator()( T t ) const
    
        // now you can access m_ptr like m_ptr[i] 
    
;

这几乎是 Robert Crovella 的建议。

【讨论】:

以上是关于如何将向量传递给基于推力的 odeint 观察者的构造函数,以便可以在函子中读取它的主要内容,如果未能解决你的问题,请参考以下文章

将二维推力::device_vector 复矩阵传递给 CUDA 核函数

Armadillo 与 Boost Odeint 冲突:Odeint 在积分期间将状态向量的大小调整为零

使用推力的向量数组

将向量的值传递给特征库格式[重复]

从推力::设备向量到原始指针并返回?

推力::主机向量和标准::向量有啥区别?