CTrajectoryMethod::Status CLsodaMethod::step(const double & deltaT) { if (mData.dim == 0 && mNumRoots == 0) //just do nothing if there are no variables { mTime = mTime + deltaT; mMethodState.setTime(mTime); *mpCurrentState = mMethodState; return NORMAL; } C_FLOAT64 EndTime = mTime + deltaT; if (mTargetTime != EndTime) { mTargetTime = EndTime; mRootCounter = 0; } else { mRootCounter++; if (mRootCounter > *mpMaxInternalSteps) { return FAILURE; } } C_INT ITOL = 2; // mRtol scalar, mAtol vector C_INT one = 1; C_INT DSize = mDWork.size(); C_INT ISize = mIWork.size(); if (mRoots.size() > 0) { mLSODAR(&EvalF, // 1. evaluate F &mData.dim, // 2. number of variables mY, // 3. the array of current concentrations &mTime, // 4. the current time &EndTime, // 5. the final time &ITOL, // 6. error control &mRtol, // 7. relative tolerance array mAtol.array(), // 8. absolute tolerance array &mState, // 9. output by overshoot & interpolation &mLsodaStatus, // 10. the state control variable &one, // 11. further options (one) mDWork.array(), // 12. the double work array &DSize, // 13. the double work array size mIWork.array(), // 14. the int work array &ISize, // 15. the int work array size NULL, // 16. evaluate J (not given) &mJType, // 17. type of j evaluation 2 internal full matrix &EvalR, // 18. evaluate constraint functions &mNumRoots, // 19. number of constraint functions g(i) mRoots.array()); // 20. integer array of length NG for output of root information switch (mLsodaStatus) { case -33: switch (mRootMasking) { case NONE: case DISCRETE: // Reset the integrator to the state before the failed integration. mMethodState = *mpCurrentState; mTime = mMethodState.getTime(); mLsodaStatus = 1; // Create a mask which hides all roots being constant and zero. createRootMask(); break; case ALL: break; } break; default: switch (mRootMasking) { case NONE: case DISCRETE: break; case ALL: { const bool * pDiscrete = mDiscreteRoots.array(); bool * pMask = mRootMask.array(); bool * pMaskEnd = pMask + mNumRoots; bool Destroy = true; for (; pMask != pMaskEnd; ++pMask, ++pDiscrete) { if (*pMask) { if (*pDiscrete) { Destroy = false; } else { *pMask = false; } } } if (Destroy) { destroyRootMask(); } else { mRootMasking = DISCRETE; } mLsodaStatus = 1; } } break; } } else { mLSODA(&EvalF, // 1. evaluate F &mData.dim, // 2. number of variables mY, // 3. the array of current concentrations &mTime, // 4. the current time &EndTime, // 5. the final time &ITOL, // 6. error control &mRtol, // 7. relative tolerance array mAtol.array(), // 8. absolute tolerance array &mState, // 9. output by overshoot & interpolation &mLsodaStatus, // 10. the state control variable &one, // 11. further options (one) mDWork.array(), // 12. the double work array &DSize, // 13. the double work array size mIWork.array(), // 14. the int work array &ISize, // 15. the int work array size NULL, // 16. evaluate J (not given) &mJType); // 17. the type of jacobian calculate (2) } // Why did we ignore this error? // if (mLsodaStatus == -1) mLsodaStatus = 2; // The status of the integrator. Status Status = NORMAL; if ((mLsodaStatus <= 0)) { Status = FAILURE; CCopasiMessage(CCopasiMessage::EXCEPTION, MCTrajectoryMethod + 6, mErrorMsg.str().c_str()); } // If mLsodaStatus == 3 we have found a root. This needs to be indicated to // the caller as it is not sufficient to rely on the fact that T < TOUT if (mLsodaStatus == 3) { // It is sufficient to switch to 2. Eventual state changes due to events // are indicated via the method stateChanged() mLsodaStatus = 2; Status = ROOT; } mMethodState.setTime(mTime); *mpCurrentState = mMethodState; return Status; }
CTrajectoryMethod::Status CLsodaMethod::step(const double & deltaT) { if (mData.dim == 0 && mNumRoots == 0) //just do nothing if there are no variables { mTime = mTime + deltaT; mMethodState.setTime(mTime); *mpCurrentState = mMethodState; return NORMAL; } C_FLOAT64 EndTime = mTime + deltaT; if (mTargetTime != EndTime) { // We have a new end time and reset the root counter. mTargetTime = EndTime; mRootCounter = 0; } else { // We are called with the same end time which means a root has previously been // found. We increase the root counter and check whether the limit is reached. mRootCounter++; if (mRootCounter > *mpMaxInternalSteps) { return FAILURE; } } C_INT ITOL = 2; // mRtol scalar, mAtol vector C_INT one = 1; C_INT DSize = (C_INT) mDWork.size(); C_INT ISize = (C_INT) mIWork.size(); // The return status of the integrator. Status Status = NORMAL; if (mRoots.size() > 0) { mLSODAR(&EvalF, // 1. evaluate F &mData.dim, // 2. number of variables mY, // 3. the array of current concentrations &mTime, // 4. the current time &EndTime, // 5. the final time &ITOL, // 6. error control &mRtol, // 7. relative tolerance array mAtol.array(), // 8. absolute tolerance array &mState, // 9. output by overshoot & interpolation &mLsodaStatus, // 10. the state control variable &one, // 11. further options (one) mDWork.array(), // 12. the double work array &DSize, // 13. the double work array size mIWork.array(), // 14. the int work array &ISize, // 15. the int work array size &EvalJ, // 16. evaluate J (not given) &mJType, // 17. type of j evaluation 2 internal full matrix &EvalR, // 18. evaluate constraint functions &mNumRoots, // 19. number of constraint functions g(i) mRoots.array()); // 20. integer array of length NG for output of root information // There exist situations where LSODAR reports status = 3, which are actually status = -33 // Obviously the trivial case is where LSODAR did not advance at all, i.e, the start time // equals the current time. It may also happen that a very small steps has been taken in // we reset short before we reach the internal step limit. if (mLsodaStatus == 3 && (mRootCounter > 0.99 * *mpMaxInternalSteps || mTime == mpCurrentState->getTime())) { mLsodaStatus = -33; mRootCounter = 0; } switch (mLsodaStatus) { case -33: switch (mRootMasking) { case NONE: case DISCRETE: // Reset the integrator to the state before the failed integration. mMethodState = *mpCurrentState; mTime = mMethodState.getTime(); mLsodaStatus = 1; // Create a mask which hides all roots being constant and zero. createRootMask(); break; case ALL: break; } break; case 3: // If mLsodaStatus == 3 we have found a root. This needs to be indicated to // the caller as it is not sufficient to rely on the fact that T < TOUT if (mLsodaStatus == 3) { // It is sufficient to switch to 2. Eventual state changes due to events // are indicated via the method stateChanged() mLsodaStatus = 2; Status = ROOT; } // The break statement is intentionally missing since we // have to continue to check the root masking state. default: switch (mRootMasking) { case NONE: case DISCRETE: break; case ALL: { const bool * pDiscrete = mDiscreteRoots.array(); bool * pMask = mRootMask.array(); bool * pMaskEnd = pMask + mNumRoots; bool Destroy = true; for (; pMask != pMaskEnd; ++pMask, ++pDiscrete) { if (*pMask) { if (*pDiscrete) { Destroy = false; } else { *pMask = false; } } } if (Destroy) { destroyRootMask(); } else { mRootMasking = DISCRETE; } // We have to restart the integrator mLsodaStatus = 1; } break; } break; } } else { mLSODA(&EvalF, // 1. evaluate F &mData.dim, // 2. number of variables mY, // 3. the array of current concentrations &mTime, // 4. the current time &EndTime, // 5. the final time &ITOL, // 6. error control &mRtol, // 7. relative tolerance array mAtol.array(), // 8. absolute tolerance array &mState, // 9. output by overshoot & interpolation &mLsodaStatus, // 10. the state control variable &one, // 11. further options (one) mDWork.array(), // 12. the double work array &DSize, // 13. the double work array size mIWork.array(), // 14. the int work array &ISize, // 15. the int work array size EvalJ, // 16. evaluate J (not given) &mJType); // 17. the type of jacobian calculate (2) } // Why did we ignore this error? // if (mLsodaStatus == -1) mLsodaStatus = 2; mMethodState.setTime(mTime); *mpCurrentState = mMethodState; if ((mLsodaStatus <= 0)) { Status = FAILURE; CCopasiMessage(CCopasiMessage::EXCEPTION, MCTrajectoryMethod + 6, mErrorMsg.str().c_str()); } if (!mpCurrentState->isValid()) { Status = FAILURE; CCopasiMessage(CCopasiMessage::EXCEPTION, MCTrajectoryMethod + 25, mTime); } return Status; }