5

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?

weemattisnot
  • 889
  • 5
  • 16
  • 1
    I think that I have found an example that does what I need at https://github.com/boostorg/odeint/blob/master/examples/thrust/phase_oscillator_ensemble.cu. I will look further and post back here. – weemattisnot Aug 29 '14 at 19:14
  • 2
    You can pass an initializing parameter to your functor. That parameter could be the pointer returned by `.data()` for a `thrust::device_vector`. That pointer could then be used within the functor, using ordinary c pointer methods, to access any element of the device vector within the functor. – Robert Crovella Aug 29 '14 at 19:36
  • 2
    a general approach of passing an initializing value to a functor (via it's constructor) is outlined [here](http://stackoverflow.com/questions/17468745/thrust-filter-by-key-value/17471046#17471046) In your case you would have a data element of your structure like `T *a;` and pass the initializing element as `m_unchangingVector.data()`, roughly speaking. – Robert Crovella Aug 29 '14 at 19:52
  • @RobertCrovella I can withdraw my answer such that you could give the correct (and hopefully) accepted answer... – headmyshoulder Aug 30 '14 at 21:31
  • I don't see anything wrong with your answer. I upvoted it. I haven't actually tried it, but I think it communicates the idea correctly. – Robert Crovella Aug 31 '14 at 02:47

1 Answers1

4

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.

headmyshoulder
  • 6,240
  • 2
  • 20
  • 27