double SingleCellViewSimulation::requiredMemory()
{
    // Determine and return the amount of required memory to run our simulation
    // Note #1: we return the amount as a double rather than a qulonglong (as we
    //          do when retrieving the total/free amount of memory available;
    //          see [OpenCOR]/src/plugins/misc/Core/src/coreutils.cpp) in case a
    //          simulation requires an insane amount of memory...
    // Note #2: the 1 is for mPoints in SingleCellViewSimulationResults...

    iface::cellml_services::CellMLCompiledModel*
        compModel(mData->isDAETypeSolver() ?
                  static_cast<iface::cellml_services::CellMLCompiledModel*>
                  (mRuntime->daeCompiledModel()) :
                  static_cast<iface::cellml_services::CellMLCompiledModel*>
                  (mRuntime->odeCompiledModel()));
    ObjRef<iface::cellml_services::CodeInformation> codeInfo
        (compModel->codeInformation());

    // This is not very accurate at all, because the solver caches a lot more
    // information about the problem being solved, some of it bigger than any
    // of the below (e.g. Jacobian matricies. Given the solver dependence of
    // this size, I'm not sure this function is that useful.
    return 
        size() *
        (1 + codeInfo->constantIndexCount() + codeInfo->rateIndexCount() * 3 +
         codeInfo->algebraicIndexCount())
        * sizeof(double);
}
void SingleCellViewSimulationData::startNextRepeat()
{
    mCurrentRepeat++;
    if (mCurrentRepeat >= solverProperties()["nrepeats"].toInt()) {
        emit simulationComplete();
        return;
    }

    if (mCurrentRepeat == 0)
      mStatesWhenRun = mStates;
    else
      mStates = mStatesWhenRun;

    newIntegrationRun();

    if (!mIntegrationRun)
        return;

    mState = SingleCellViewSimulationData::SIMSTATE_WAITING_RESULTS;

    iface::cellml_services::CellMLCompiledModel*
        compModel(isDAETypeSolver() ?
                  static_cast<iface::cellml_services::CellMLCompiledModel*>
                  (mRuntime->daeCompiledModel()) :
                  static_cast<iface::cellml_services::CellMLCompiledModel*>
                  (mRuntime->odeCompiledModel()));
    ObjRef<iface::cellml_services::CodeInformation> codeInfo
        (compModel->codeInformation());

    mResultReceiver = new ResultListener(mIntegrationRun, codeInfo->rateIndexCount(),
                                         codeInfo->algebraicIndexCount());
    mResultReceiver->delay(mDelay);

    mIntegrationRun->setStepSizeControl(mSolverProperties["absTol"].toDouble(),
                                        mSolverProperties["relTol"].toDouble(),
                                        1.0, // Scaling factor: states
                                        1.0, // Scaling factor: rates
                                        mSolverProperties["maxStep"].toDouble());
    mIntegrationRun->setResultRange(mStartingPoint, mEndingPoint,
                                    10000.0 // Maximum density of points in bvar, as an upper bound on the number
                                            // of points returned.
                                   );
    mIntegrationRun->setProgressObserver(mResultReceiver);

    QObject::connect(mResultReceiver, SIGNAL(constantsAvailable(const QList<double>)), this, SIGNAL(constantsAvailable(const QList<double>)));
    QObject::connect(mResultReceiver, SIGNAL(solveDone()), this, SLOT(startNextRepeat()));
    QObject::connect(mResultReceiver, SIGNAL(solveFailure(QString)), this, SIGNAL(simulationFailed(QString)));
    QObject::connect(mResultReceiver, SIGNAL(solvePointAvailable(double,QList<double>,QList<double>,QList<double>)), this, SIGNAL(simulationDataAvailable(double,QList<double>,QList<double>,QList<double>)));

    setupOverrides();
    mIntegrationRun->start();
}
void SingleCellViewSimulationData::setupOverrides()
{
    iface::cellml_services::CellMLCompiledModel*
        compModel(isDAETypeSolver() ?
                  static_cast<iface::cellml_services::CellMLCompiledModel*>
                  (mRuntime->daeCompiledModel()) :
                  static_cast<iface::cellml_services::CellMLCompiledModel*>
                  (mRuntime->odeCompiledModel()));
    ObjRef<iface::cellml_services::CodeInformation> codeInfo
        (compModel->codeInformation());
    
    for (unsigned int i = 0; i < codeInfo->constantIndexCount(); i++)
        if (mInitialConstants[i] != mConstants[i])
            mIntegrationRun->setOverride(iface::cellml_services::CONSTANT,
                                         i, mConstants[i]);
    for (unsigned int i = 0; i < codeInfo->rateIndexCount(); i++)
        if (mInitialStates[i] != mStates[i])
            mIntegrationRun->setOverride(iface::cellml_services::STATE_VARIABLE,
                                         i, mStates[i]);
}
void SingleCellViewSimulationData::initialValuesIn()
{
    iface::cellml_services::CellMLCompiledModel*
        compModel(isDAETypeSolver() ?
                  static_cast<iface::cellml_services::CellMLCompiledModel*>
                  (mRuntime->daeCompiledModel()) :
                  static_cast<iface::cellml_services::CellMLCompiledModel*>
                  (mRuntime->odeCompiledModel()));
    ObjRef<iface::cellml_services::CodeInformation> codeInfo
        (compModel->codeInformation());

    mState = SingleCellViewSimulationData::SIMSTATE_GOT_IV;

    if (mDidReset)
    {
      mInitialConstants.clear();
      mInitialConstants.reserve(codeInfo->constantIndexCount());
      mInitialStates.clear();
      mInitialStates.reserve(codeInfo->rateIndexCount());
    }

    mConstants.clear();
    mConstants.reserve(codeInfo->constantIndexCount());

    std::cout << "Computed " << mIVGrabber->consts().size() << " constants and "
              << mIVGrabber->states().size() << " initial values." << std::endl;
        

    for (std::vector<double>::iterator i = mIVGrabber->consts().begin();
         i != mIVGrabber->consts().end(); i++) {
        if (mDidReset)
            mInitialConstants << *i;
        mConstants << *i;
    }

    std::vector<double>& computedData = mIVGrabber->states();
    mStates.clear();
    mStates.reserve(codeInfo->rateIndexCount());
    for (unsigned int i = 0; i < codeInfo->rateIndexCount(); i++) {
        double v = computedData[1 + i];
        if (mDidReset)
            mInitialStates << v;
        mStates << v;
    }

    mRates.clear();
    mRates.reserve(codeInfo->rateIndexCount());
    const unsigned int rateOffset = codeInfo->rateIndexCount() + 1;
    for (unsigned int i = 0; i < codeInfo->rateIndexCount(); i++) {
      mRates << computedData[rateOffset + i];
    }
    
    mAlgebraic.clear();
    mAlgebraic.reserve(codeInfo->algebraicIndexCount());
    const unsigned int algebraicOffset = codeInfo->rateIndexCount() * 2 + 1;
    for (unsigned int i = 0; i < codeInfo->algebraicIndexCount(); i++) {
      mAlgebraic << computedData[algebraicOffset + i];
    }

    emit updated();
    emit modified(this, !mDidReset);
}