Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a vector to the constructor of a thrust-based odeint observer, such that it can be read within the functor

I am extending the parameter study example from boost's odeint used with thrust, and I do not know how to pass a vector of values to the constructor of the observer, such that those values can be accessed (read-only) from within the observer's functor.

The following is the code just for the observer.

//// 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; // 
};

I have experimented with making m_unchangingVector static or const, but this is not correct, because it needs to be set upon instantiation of the observer.

Alternatively, perhaps the best way to do this is to pass unchangingVector as another argument within thrust::make_zip_iterator( thrust::make_tuple(..., but I feel like these items would then be indexed the way the state variables are (which would not be what I want). One answer that could help would be an explanation of what (T t) means in the functor's declaration, and how I could pass unchangingVector as the same object to every thread that is evaluating the operator.

I think it may just be the matter of selecting the right key-word variable descriptors, but I don't know which one(s) to use, and I am not sure how to look it up / figure it out.

The error I get for the code above is error: a nonstatic member reference must be relative to a specific object. Thrown when I try to access m_unchangingVector in the functor.


After further exploration, I feel like I have identified the correct way to accomplish this task, but I am still stuck.

I have added a constructor to the functor.

  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
    }
  };

warning: calling a host function("thrust::detail::vector_base > ::operator []") from a host device function("minimum_perturbation_observer::minPerturbFunctor::operator () > ") is not allowed

ERROR MESSAGE /usr/local/cuda/bin/..//include/thrust/detail/function.h(104): error: calling a host function("thrust::device_vector > ::device_vector") from a device function("thrust::detail::device_function ::device_function") is not allowed

What am I doing wrong?

like image 885
weemattisnot Avatar asked Sep 30 '22 23:09

weemattisnot


1 Answers

You can pass a thrust vector to the functor, but you can not easily store it here. But you can store the underlying raw pointer form this vector:

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] 
    }
};

This is pretty much the suggestion from Robert Crovella.

like image 88
headmyshoulder Avatar answered Oct 03 '22 02:10

headmyshoulder