Search code examples
c++thrustodeint

In a ODEINT + THRUST observer, receiving error that expression must be a modifiable lvalue


I have been working on extending / modifying the thrust + odeint example [code,documentation] that varies systematically a parameter, and observes the effects.

I am having a strange error, where when I try to modify certain variables that should be modifiable, (and are modified in the example), I get the following error.

main.cu: error: expression must be a modifiable lvalue

Below is the source code for the observer struct that I am trying to run, with a comment showing the line that causes the error.

I understand this error to mean that the expression to the left of the assignment operator, =, is not a modifiable value. But it looks exactly the same to me as the variable with the same name in the example source above (which runs fine).

//// Observes the system to detect if it ever dies during the trial
struct death_observer {

  // CONSTRUCTOR
  death_observer( size_t N, size_t historyBufferLen = 1) 
    : m_N( N ), m_count( 0 ) { }

  template< class State , class Deriv >
  void operator()(State &x , Deriv &dxdt , value_type t ) const
  {
    ++m_count;                                 // <-- This line causes the error.
  }

  // variables
  size_t m_N;   
  size_t m_count;
};

... and here is the code from main() that runs the integrator and this observer, in case that is helpful.

  parallel_initial_condition_problem init_con_solver( N_ICS );
  death_observer obs( N_ICS );

  //////////////////////////////// // // integrate   
  typedef runge_kutta_dopri5< state_type , value_type , state_type , value_type, thrust_algebra, thrust_operations > stepper_type;
  const value_type abs_err = 1.0e-6;
  const value_type rel_err = 1.0e-6;

  double t = t_0;
  while( t < t_final ) {
    integrate_adaptive( make_controlled( abs_err, rel_err, stepper_type() ) ,
            init_con_solver ,
            std::make_pair( x.begin() , x.begin() + N_VARS*N_ICS  ),
            t , t + 1.0 , init_dt );
    t += 1.0;
    obs( x, *(&x+N_VARS*N_ICS), t); // not sure about middle arg here, but I don't think it is the cause of the error.
  }

I have tried to pare down my code to the most simple case. Commenting out the 3rd to last line above causes the program to run fine.

What on earth am I doing wrong? What is different between my m_count and the m_count in the example code linked to above? Many thanks!


Solution

  • Converting comment into an answer:

    template< class State , class Deriv >
    void operator()(State &x , Deriv &dxdt , value_type t ) const
    {
        ++m_count;                                 // <-- This line causes the error.
    }
    

    You declared operator() as a const member function, and therefore it cannot modify class data members unless the member is declared as mutable.

    Side note: *(&x+N_VARS*N_ICS) is almost certainly not correct, as x looks like a container from the .begin() calls.