Esempio n. 1
0
    inline void cvodes_set_options(void* cvodes_mem,
                                   double rel_tol, double abs_tol,
                                   // NOLINTNEXTLINE(runtime/int)
                                   long int max_num_steps) {
      // forward CVode errors to noop error handler
      CVodeSetErrHandlerFn(cvodes_mem, cvodes_silent_err_handler, 0);

      // Initialize solver parameters
      cvodes_check_flag(CVodeSStolerances(cvodes_mem, rel_tol, abs_tol),
                        "CVodeSStolerances");

      cvodes_check_flag(CVodeSetMaxNumSteps(cvodes_mem, max_num_steps),
                        "CVodeSetMaxNumSteps");

      double init_step = 0;
      cvodes_check_flag(CVodeSetInitStep(cvodes_mem, init_step),
                        "CVodeSetInitStep");

      long int max_err_test_fails = 20;  // NOLINT(runtime/int)
      cvodes_check_flag(CVodeSetMaxErrTestFails(cvodes_mem, max_err_test_fails),
                        "CVodeSetMaxErrTestFails");

      long int max_conv_fails = 50;  // NOLINT(runtime/int)
      cvodes_check_flag(CVodeSetMaxConvFails(cvodes_mem, max_conv_fails),
                        "CVodeSetMaxConvFails");
    }
Esempio n. 2
0
int CVodeSetErrHandlerFnB(void *cvadj_mem, CVErrHandlerFn ehfunB, void *eh_dataB)
{
  CVadjMem ca_mem;
  void *cvode_mem;
  int flag;

  if (cvadj_mem == NULL) {
    CVProcessError(NULL, CV_ADJMEM_NULL, "CVODEA", "CVodeSetErrHandlerB", MSGAM_NULL_CAMEM);
    return(CV_ADJMEM_NULL);
  }
  ca_mem = (CVadjMem) cvadj_mem;
  cvode_mem = (void *)ca_mem->cvb_mem;

  flag = CVodeSetErrHandlerFn(cvode_mem, ehfunB, eh_dataB);

  return(flag);
}
Esempio n. 3
0
void CvodeSolver::initialize(const double &pVoiStart,
                             const int &pRatesStatesCount, double *pConstants,
                             double *pRates, double *pStates,
                             double *pAlgebraic,
                             ComputeRatesFunction pComputeRates)
{
    if (!mSolver) {
        // Retrieve some of the CVODE properties

        double maximumStep = MaximumStepDefaultValue;
        int maximumNumberOfSteps = MaximumNumberOfStepsDefaultValue;
        QString integrationMethod = IntegrationMethodDefaultValue;
        QString iterationType = IterationTypeDefaultValue;
        QString linearSolver = LinearSolverDefaultValue;
        QString preconditioner = PreconditionerDefaultValue;
        int upperHalfBandwidth = UpperHalfBandwidthDefaultValue;
        int lowerHalfBandwidth = LowerHalfBandwidthDefaultValue;
        double relativeTolerance = RelativeToleranceDefaultValue;
        double absoluteTolerance = AbsoluteToleranceDefaultValue;

        if (mProperties.contains(MaximumStepId)) {
            maximumStep = mProperties.value(MaximumStepId).toDouble();
        } else {
            emit error(QObject::tr("the 'maximum step' property value could not be retrieved"));

            return;
        }

        if (mProperties.contains(MaximumNumberOfStepsId)) {
            maximumNumberOfSteps = mProperties.value(MaximumNumberOfStepsId).toInt();
        } else {
            emit error(QObject::tr("the 'maximum number of steps' property value could not be retrieved"));

            return;
        }

        if (mProperties.contains(IntegrationMethodId)) {
            integrationMethod = mProperties.value(IntegrationMethodId).toString();
        } else {
            emit error(QObject::tr("the 'integration method' property value could not be retrieved"));

            return;
        }

        if (mProperties.contains(IterationTypeId)) {
            iterationType = mProperties.value(IterationTypeId).toString();

            if (!iterationType.compare(NewtonIteration)) {
                // We are dealing with a Newton iteration, so retrieve and check
                // its linear solver

                if (mProperties.contains(LinearSolverId)) {
                    linearSolver = mProperties.value(LinearSolverId).toString();

                    bool needUpperAndLowerHalfBandwidths = false;

                    if (   !linearSolver.compare(DenseLinearSolver)
                        || !linearSolver.compare(DiagonalLinearSolver)) {
                        // We are dealing with a dense/diagonal linear solver,
                        // so nothing more to do
                    } else if (!linearSolver.compare(BandedLinearSolver)) {
                        // We are dealing with a banded linear solver, so we
                        // need both an upper and a lower half bandwidth

                        needUpperAndLowerHalfBandwidths = true;
                    } else {
                        // We are dealing with a GMRES/Bi-CGStab/TFQMR linear
                        // solver, so retrieve and check its preconditioner

                        if (mProperties.contains(PreconditionerId)) {
                            preconditioner = mProperties.value(PreconditionerId).toString();
                        } else {
                            emit error(QObject::tr("the 'preconditioner' property value could not be retrieved"));

                            return;
                        }

                        if (!preconditioner.compare(BandedPreconditioner)) {
                            // We are dealing with a banded preconditioner, so
                            // we need both an upper and a lower half bandwidth

                            needUpperAndLowerHalfBandwidths = true;
                        }
                    }

                    if (needUpperAndLowerHalfBandwidths) {
                        if (mProperties.contains(UpperHalfBandwidthId)) {
                            upperHalfBandwidth = mProperties.value(UpperHalfBandwidthId).toInt();

                            if (   (upperHalfBandwidth < 0)
                                || (upperHalfBandwidth >= pRatesStatesCount)) {
                                emit error(QObject::tr("the 'upper half-bandwidth' property must have a value between 0 and %1").arg(pRatesStatesCount-1));

                                return;
                            }
                        } else {
                            emit error(QObject::tr("the 'upper half-bandwidth' property value could not be retrieved"));

                            return;
                        }

                        if (mProperties.contains(LowerHalfBandwidthId)) {
                            lowerHalfBandwidth = mProperties.value(LowerHalfBandwidthId).toInt();

                            if (   (lowerHalfBandwidth < 0)
                                || (lowerHalfBandwidth >= pRatesStatesCount)) {
                                emit error(QObject::tr("the 'lower half-bandwidth' property must have a value between 0 and %1").arg(pRatesStatesCount-1));

                                return;
                            }
                        } else {
                            emit error(QObject::tr("the 'lower half-bandwidth' property value could not be retrieved"));

                            return;
                        }
                    }
                } else {
                    emit error(QObject::tr("the 'linear solver' property value could not be retrieved"));

                    return;
                }
            }
        } else {
            emit error(QObject::tr("the 'iteration type' property value could not be retrieved"));

            return;
        }

        if (mProperties.contains(RelativeToleranceId)) {
            relativeTolerance = mProperties.value(RelativeToleranceId).toDouble();

            if (relativeTolerance < 0) {
                emit error(QObject::tr("the 'relative tolerance' property must have a value greater than or equal to 0"));

                return;
            }
        } else {
            emit error(QObject::tr("the 'relative tolerance' property value could not be retrieved"));

            return;
        }

        if (mProperties.contains(AbsoluteToleranceId)) {
            absoluteTolerance = mProperties.value(AbsoluteToleranceId).toDouble();

            if (absoluteTolerance < 0) {
                emit error(QObject::tr("the 'absolute tolerance' property must have a value greater than or equal to 0"));

                return;
            }
        } else {
            emit error(QObject::tr("the 'absolute tolerance' property value could not be retrieved"));

            return;
        }

        if (mProperties.contains(InterpolateSolutionId)) {
            mInterpolateSolution = mProperties.value(InterpolateSolutionId).toBool();
        } else {
            emit error(QObject::tr("the 'interpolate solution' property value could not be retrieved"));

            return;
        }

        // Initialise the ODE solver itself

        OpenCOR::Solver::OdeSolver::initialize(pVoiStart, pRatesStatesCount,
                                               pConstants, pRates, pStates,
                                               pAlgebraic, pComputeRates);

        // Create the states vector

        mStatesVector = N_VMake_Serial(pRatesStatesCount, pStates);

        // Create the CVODE solver

        bool newtonIteration = !iterationType.compare(NewtonIteration);

        mSolver = CVodeCreate(!integrationMethod.compare(BdfMethod)?CV_BDF:CV_ADAMS,
                              newtonIteration?CV_NEWTON:CV_FUNCTIONAL);

        // Use our own error handler

        CVodeSetErrHandlerFn(mSolver, errorHandler, this);

        // Initialise the CVODE solver

        CVodeInit(mSolver, rhsFunction, pVoiStart, mStatesVector);

        // Set some user data

        mUserData = new CvodeSolverUserData(pConstants, pAlgebraic,
                                            pComputeRates);

        CVodeSetUserData(mSolver, mUserData);

        // Set the maximum step

        CVodeSetMaxStep(mSolver, maximumStep);

        // Set the maximum number of steps

        CVodeSetMaxNumSteps(mSolver, maximumNumberOfSteps);

        // Set the linear solver, if needed

        if (newtonIteration) {
            if (!linearSolver.compare(DenseLinearSolver)) {
                CVDense(mSolver, pRatesStatesCount);
            } else if (!linearSolver.compare(BandedLinearSolver)) {
                CVBand(mSolver, pRatesStatesCount, upperHalfBandwidth, lowerHalfBandwidth);
            } else if (!linearSolver.compare(DiagonalLinearSolver)) {
                CVDiag(mSolver);
            } else {
                // We are dealing with a GMRES/Bi-CGStab/TFQMR linear solver

                if (!preconditioner.compare(BandedPreconditioner)) {
                    if (!linearSolver.compare(GmresLinearSolver))
                        CVSpgmr(mSolver, PREC_LEFT, 0);
                    else if (!linearSolver.compare(BiCgStabLinearSolver))
                        CVSpbcg(mSolver, PREC_LEFT, 0);
                    else
                        CVSptfqmr(mSolver, PREC_LEFT, 0);

                    CVBandPrecInit(mSolver, pRatesStatesCount, upperHalfBandwidth, lowerHalfBandwidth);
                } else {
                    if (!linearSolver.compare(GmresLinearSolver))
                        CVSpgmr(mSolver, PREC_NONE, 0);
                    else if (!linearSolver.compare(BiCgStabLinearSolver))
                        CVSpbcg(mSolver, PREC_NONE, 0);
                    else
                        CVSptfqmr(mSolver, PREC_NONE, 0);
                }
            }
        }

        // Set the relative and absolute tolerances

        CVodeSStolerances(mSolver, relativeTolerance, absoluteTolerance);
    } else {
        // Reinitialise the CVODE object

        CVodeReInit(mSolver, pVoiStart, mStatesVector);
    }
}
Esempio n. 4
0
int jmi_ode_cvode_new(jmi_ode_cvode_t** integrator_ptr, jmi_ode_solver_t* solver) {
    jmi_ode_cvode_t* integrator;
    jmi_ode_problem_t* problem = solver -> ode_problem;
    int flag = 0;
    void* cvode_mem;
    jmi_real_t* y;
    jmi_real_t* atol_nv;
    int i;
    
    integrator = (jmi_ode_cvode_t*)calloc(1,sizeof(jmi_ode_cvode_t));
    if(!integrator){
        jmi_log_node(problem->log, logError, "Error", "Failed to allocate the internal CVODE struct.");
        return -1;
    }

    /* DEFAULT VALUES NEEDS TO BE IMPROVED*/
    integrator->lmm  = CV_BDF;
    integrator->iter = CV_NEWTON;
    /* integrator->rtol = 1e-4; */
    integrator->rtol = solver->rel_tol;
    
    if (problem->n_real_x > 0) {
        integrator->atol = N_VNew_Serial(problem->n_real_x);
    } else {
        integrator->atol = N_VNew_Serial(1);
    }
    atol_nv = NV_DATA_S(integrator->atol);
    
    if (problem->n_real_x > 0) {
        for (i = 0; i < problem->n_real_x; i++) {
            atol_nv[i] = 0.01*integrator->rtol*problem->nominal[i];
        }
    }else{
        atol_nv[0] = 0.01*integrator->rtol*1.0;
    }

    cvode_mem = CVodeCreate(integrator->lmm,integrator->iter);
    if(!cvode_mem){
        jmi_log_node(problem->log, logError, "Error", "Failed to allocate the CVODE struct.");
        return -1;
    }

    /* Get the default values for the time and states */
    if (problem->n_real_x > 0) {
        integrator->y_work = N_VNew_Serial(problem->n_real_x);
        y = NV_DATA_S(integrator->y_work);
		memcpy (y, problem->states, problem->n_real_x*sizeof(jmi_real_t));
    }else{
        integrator->y_work = N_VNew_Serial(1);
        y = NV_DATA_S(integrator->y_work);
        y[0] = 0.0;
    }
    
    flag = CVodeInit(cvode_mem, cv_rhs, problem->time, integrator->y_work);
    if(flag != 0) {
        jmi_log_node(problem->log, logError, "Error", "Failed to initialize CVODE. Returned with <error_flag: %d>", flag);
        return -1;
    }

    flag = CVodeSVtolerances(cvode_mem, integrator->rtol, integrator->atol);
    if(flag!=0){
        jmi_log_node(problem->log, logError, "Error", "Failed to specify the tolerances. Returned with <error_flag: %d>", flag);
        return -1;
    }

    if (problem->n_real_x > 0) {
        flag = CVDense(cvode_mem, problem->n_real_x);
    }else{
        flag = CVDense(cvode_mem, 1);
    }
    if(flag!=0){
        jmi_log_node(problem->log, logError, "Error", "Failed to specify the linear solver. Returned with <error_flag: %d>", flag);
        return -1;
    }

    flag = CVodeSetUserData(cvode_mem, (void*)solver);
    if(flag!=0){
        jmi_log_node(problem->log, logError, "Error", "Failed to specify the user data. Returned with <error_flag: %d>", flag);
        return -1;
    }
    
    if (problem->n_sw > 0){
        flag = CVodeRootInit(cvode_mem, problem->n_sw, cv_root);
        if(flag!=0){
            jmi_log_node(problem->log, logError, "Error", "Failed to specify the event indicator function. Returned with <error_flag: %d>", flag);
            return -1;
        }
    }
    
    flag = CVodeSetErrHandlerFn(cvode_mem, cv_err, (void*)solver);
    if(flag!=0){
        jmi_log_node(problem->log, logError, "Error", "Failed to specify the error handling function. Returned with <error_flag: %d>", flag);
        return -1;
    }

    integrator->cvode_mem = cvode_mem;    
      
    *integrator_ptr = integrator;
    return 0;
}
Esempio n. 5
0
int cvode_init(solver_props *props){
  assert(props->statesize > 0);

  cvode_mem *mem = (cvode_mem*) malloc(props->num_models*sizeof(cvode_mem));
  unsigned int modelid;

  props->mem = mem;

  for(modelid=0; modelid<props->num_models; modelid++){
    // Set location to store the value of the next states
    mem[modelid].next_states = &(props->next_states[modelid*props->statesize]);
    mem[modelid].props = props;
    // Set the modelid on a per memory structure basis
    mem[modelid].modelid = modelid;
    // Create intial value vector
    // This is done to avoid having the change the internal indexing within the flows and for the output_buffer
    mem[modelid].y0 = N_VMake_Serial(props->statesize, mem[modelid].next_states);
    // Create data structure for solver
    //    mem[modelid].cvmem = CVodeCreate(CV_BDF, CV_NEWTON);
    mem[modelid].cvmem = CVodeCreate(props->cvode.lmm, props->cvode.iter);
    
    // Initialize CVODE
    if(CVodeInit(mem[modelid].cvmem, user_fun_wrapper, props->starttime, mem[modelid].y0) != CV_SUCCESS){
      PRINTF( "Couldn't initialize CVODE");
    }
    // Set CVODE error handler
    if(CVodeSetErrHandlerFn(mem[modelid].cvmem, cvode_err_handler, mem)){
      PRINTF( "Couldn't set CVODE error handler");
    }
    // Set solver tolerances
    if(CVodeSStolerances(mem[modelid].cvmem, props->reltol, props->abstol) != CV_SUCCESS){
      PRINTF( "Could not set CVODE tolerances");
    }
    // Set maximum order
    if(CVodeSetMaxOrd(mem[modelid].cvmem, props->cvode.max_order) != CV_SUCCESS) {
      PRINTF( "Could not set CVODE maximum order");
    }
    // Set linear solver
    switch (props->cvode.solv) {
    case CVODE_DENSE:
      if(CVDense(mem[modelid].cvmem, mem[modelid].props->statesize) != CV_SUCCESS){
	PRINTF( "Could not set CVODE DENSE linear solver");
      }
      break;
    case CVODE_DIAG:
      if(CVDiag(mem[modelid].cvmem) != CV_SUCCESS){
	PRINTF( "Could not set CVODE DIAG linear solver");
      }
      break;
    case CVODE_BAND:
      if(CVBand(mem[modelid].cvmem, mem[modelid].props->statesize, mem[modelid].props->cvode.upperhalfbw, mem[modelid].props->cvode.lowerhalfbw) != CV_SUCCESS){
	PRINTF( "Could not set CVODE BAND linear solver");
      }
      break;
    default:
      PRINTF( "No valid CVODE solver passed");
      }

    // Set user data to contain pointer to memory structure for use in model_flows
    if(CVodeSetUserData(mem[modelid].cvmem, &mem[modelid]) != CV_SUCCESS){
      PRINTF( "CVODE failed to initialize user data");
    }
  }

  return 0;
}
Esempio n. 6
0
void CVodesIntegrator::initialize(double t0, FuncEval& func)
{
    m_neq = func.neq();
    m_t0 = t0;
    m_time = t0;

    if (m_y) {
        N_VDestroy_Serial(m_y); // free solution vector if already allocated
    }
    m_y = N_VNew_Serial(static_cast<sd_size_t>(m_neq)); // allocate solution vector
    for (size_t i = 0; i < m_neq; i++) {
        NV_Ith_S(m_y, i) = 0.0;
    }
    // check abs tolerance array size
    if (m_itol == CV_SV && m_nabs < m_neq) {
        throw CVodesErr("not enough absolute tolerance values specified.");
    }

    func.getInitialConditions(m_t0, m_neq, NV_DATA_S(m_y));

    if (m_cvode_mem) {
        CVodeFree(&m_cvode_mem);
    }

    /*
     *  Specify the method and the iteration type:
     *      Cantera Defaults:
     *         CV_BDF  - Use BDF methods
     *         CV_NEWTON - use Newton's method
     */
    m_cvode_mem = CVodeCreate(m_method, m_iter);
    if (!m_cvode_mem) {
        throw CVodesErr("CVodeCreate failed.");
    }

    int flag = CVodeInit(m_cvode_mem, cvodes_rhs, m_t0, m_y);
    if (flag != CV_SUCCESS) {
        if (flag == CV_MEM_FAIL) {
            throw CVodesErr("Memory allocation failed.");
        } else if (flag == CV_ILL_INPUT) {
            throw CVodesErr("Illegal value for CVodeInit input argument.");
        } else {
            throw CVodesErr("CVodeInit failed.");
        }
    }
    CVodeSetErrHandlerFn(m_cvode_mem, &cvodes_err, this);

    if (m_itol == CV_SV) {
        flag = CVodeSVtolerances(m_cvode_mem, m_reltol, m_abstol);
    } else {
        flag = CVodeSStolerances(m_cvode_mem, m_reltol, m_abstols);
    }
    if (flag != CV_SUCCESS) {
        if (flag == CV_MEM_FAIL) {
            throw CVodesErr("Memory allocation failed.");
        } else if (flag == CV_ILL_INPUT) {
            throw CVodesErr("Illegal value for CVodeInit input argument.");
        } else {
            throw CVodesErr("CVodeInit failed.");
        }
    }

    // pass a pointer to func in m_data
    m_fdata.reset(new FuncData(&func, func.nparams()));

    flag = CVodeSetUserData(m_cvode_mem, m_fdata.get());
    if (flag != CV_SUCCESS) {
        throw CVodesErr("CVodeSetUserData failed.");
    }
    if (func.nparams() > 0) {
        sensInit(t0, func);
        flag = CVodeSetSensParams(m_cvode_mem, m_fdata->m_pars.data(),
                                  NULL, NULL);
    }
    applyOptions();
}
void CVodesIntegrator::initialize(double t0, FuncEval& func)
{
    m_neq = func.neq();
    m_t0 = t0;
    m_time = t0;

    if (m_y) {
        N_VDestroy_Serial(m_y); // free solution vector if already allocated
    }
    m_y = N_VNew_Serial(static_cast<sd_size_t>(m_neq)); // allocate solution vector
    N_VConst(0.0, m_y);
    // check abs tolerance array size
    if (m_itol == CV_SV && m_nabs < m_neq) {
        throw CanteraError("CVodesIntegrator::initialize",
                           "not enough absolute tolerance values specified.");
    }

    func.getState(NV_DATA_S(m_y));

    if (m_cvode_mem) {
        CVodeFree(&m_cvode_mem);
    }

    //! Specify the method and the iteration type. Cantera Defaults:
    //!        CV_BDF  - Use BDF methods
    //!        CV_NEWTON - use Newton's method
    m_cvode_mem = CVodeCreate(m_method, m_iter);
    if (!m_cvode_mem) {
        throw CanteraError("CVodesIntegrator::initialize",
                           "CVodeCreate failed.");
    }

    int flag = CVodeInit(m_cvode_mem, cvodes_rhs, m_t0, m_y);
    if (flag != CV_SUCCESS) {
        if (flag == CV_MEM_FAIL) {
            throw CanteraError("CVodesIntegrator::initialize",
                               "Memory allocation failed.");
        } else if (flag == CV_ILL_INPUT) {
            throw CanteraError("CVodesIntegrator::initialize",
                               "Illegal value for CVodeInit input argument.");
        } else {
            throw CanteraError("CVodesIntegrator::initialize",
                               "CVodeInit failed.");
        }
    }
    CVodeSetErrHandlerFn(m_cvode_mem, &cvodes_err, this);

    if (m_itol == CV_SV) {
        flag = CVodeSVtolerances(m_cvode_mem, m_reltol, m_abstol);
    } else {
        flag = CVodeSStolerances(m_cvode_mem, m_reltol, m_abstols);
    }
    if (flag != CV_SUCCESS) {
        if (flag == CV_MEM_FAIL) {
            throw CanteraError("CVodesIntegrator::initialize",
                               "Memory allocation failed.");
        } else if (flag == CV_ILL_INPUT) {
            throw CanteraError("CVodesIntegrator::initialize",
                               "Illegal value for CVodeInit input argument.");
        } else {
            throw CanteraError("CVodesIntegrator::initialize",
                               "CVodeInit failed.");
        }
    }

    flag = CVodeSetUserData(m_cvode_mem, &func);
    if (flag != CV_SUCCESS) {
        throw CanteraError("CVodesIntegrator::initialize",
                           "CVodeSetUserData failed.");
    }
    if (func.nparams() > 0) {
        sensInit(t0, func);
        flag = CVodeSetSensParams(m_cvode_mem, func.m_sens_params.data(),
                                  func.m_paramScales.data(), NULL);
        if (flag != CV_SUCCESS) {
            throw CanteraError("CVodesIntegrator::initialize",
                               "CVodeSetSensParams failed.");
        }
    }
    applyOptions();
}
Esempio n. 8
0
void CvodeSolver::initialize(const double &pVoiStart, const int &pStatesCount,
                             double *pConstants, double *pStates,
                             double *pRates, double *pAlgebraic,
                             ComputeRatesFunction pComputeRates)
{
    if (!mSolver) {
        // Initialise the ODE solver itself

        OpenCOR::CoreSolver::CoreOdeSolver::initialize(pVoiStart, pStatesCount,
                                                       pConstants, pStates,
                                                       pRates, pAlgebraic,
                                                       pComputeRates);

        // Retrieve some of the CVODE properties

        if (mProperties.contains(MaximumStepProperty)) {
            mMaximumStep = mProperties.value(MaximumStepProperty).toDouble();
        } else {
            emit error(QObject::tr("the 'maximum step' property value could not be retrieved"));

            return;
        }

        if (mProperties.contains(MaximumNumberOfStepsProperty)) {
            mMaximumNumberOfSteps = mProperties.value(MaximumNumberOfStepsProperty).toInt();
        } else {
            emit error(QObject::tr("the 'maximum number of steps' property value could not be retrieved"));

            return;
        }

        if (mProperties.contains(RelativeToleranceProperty)) {
            mRelativeTolerance = mProperties.value(RelativeToleranceProperty).toDouble();
        } else {
            emit error(QObject::tr("the 'relative tolerance' property value could not be retrieved"));

            return;
        }

        if (mProperties.contains(AbsoluteToleranceProperty)) {
            mAbsoluteTolerance = mProperties.value(AbsoluteToleranceProperty).toDouble();
        } else {
            emit error(QObject::tr("the 'absolute tolerance' property value could not be retrieved"));

            return;
        }

        // Create the states vector

        mStatesVector = N_VMake_Serial(pStatesCount, pStates);

        // Create the CVODE solver

        mSolver = CVodeCreate(CV_BDF, CV_NEWTON);

        // Use our own error handler

        CVodeSetErrHandlerFn(mSolver, errorHandler, this);

        // Initialise the CVODE solver

        CVodeInit(mSolver, rhsFunction, pVoiStart, mStatesVector);

        // Set some user data

        delete mUserData;   // Just in case the solver got initialised before

        mUserData = new CvodeSolverUserData(pConstants, pAlgebraic,
                                            pComputeRates);

        CVodeSetUserData(mSolver, mUserData);

        // Set the linear solver

        CVDense(mSolver, pStatesCount);

        // Set the maximum step

        CVodeSetMaxStep(mSolver, mMaximumStep);

        // Set the maximum number of steps

        CVodeSetMaxNumSteps(mSolver, mMaximumNumberOfSteps);

        // Set the relative and absolute tolerances

        CVodeSStolerances(mSolver, mRelativeTolerance, mAbsoluteTolerance);
    } else {
        // Reinitialise the CVODE object

        CVodeReInit(mSolver, pVoiStart, mStatesVector);
    }
}