// virtual void CLsodaMethod::stateChanged() { mMethodState = *mpCurrentState; mTime = mMethodState.getTime(); mLsodaStatus = 1; destroyRootMask(); mRootMasking = NONE; }
void CLsodaMethod::start(const CState * initialState) { /* Retrieve the model to calculate */ mpModel = mpProblem->getModel(); /* Reset lsoda */ mLsodaStatus = 1; mState = 1; mJType = 2; mErrorMsg.str(""); /* Release previous state and make the initialState the current */ mMethodState = *initialState; mTime = mMethodState.getTime(); mTargetTime = mTime; mRootCounter = 0; mNumRoots = mpModel->getNumRoots(); mRoots.resize(mNumRoots); destroyRootMask(); mRootMasking = NONE; if (*mpReducedModel) mData.dim = mMethodState.getNumIndependent(); else mData.dim = mMethodState.getNumIndependent() + mpModel->getNumDependentReactionMetabs(); // When we have roots we need to add an artificial ODE dDummy/dt = 1 if (mData.dim == 0 && mNumRoots != 0) { mData.dim = 1; mNoODE = true; mAtol.resize(1); mAtol[0] = *mpAbsoluteTolerance; mDummy = 0; mY = &mDummy; } else { mNoODE = false; mAtol = mpModel->initializeAtolVector(*mpAbsoluteTolerance, *mpReducedModel); mY = mMethodState.beginIndependent(); } mYdot.resize(mData.dim); /* Configure lsoda(r) */ mRtol = *mpRelativeTolerance; mDWork.resize(22 + mData.dim * std::max<C_INT>(16, mData.dim + 9) + 3 * mNumRoots); mDWork[4] = mDWork[5] = mDWork[6] = mDWork[7] = mDWork[8] = mDWork[9] = 0.0; mIWork.resize(20 + mData.dim); mIWork[4] = mIWork[6] = mIWork[9] = 0; mIWork[5] = *mpMaxInternalSteps; mIWork[7] = 12; mIWork[8] = 5; if (mNumRoots > 0) { mLSODAR.setOstream(mErrorMsg); mDiscreteRoots.resize(mNumRoots); CMathTrigger::CRootFinder * const* ppRootFinder = mpModel->getRootFinders().array(); CMathTrigger::CRootFinder * const* ppRootFinderEnd = ppRootFinder + mNumRoots; bool * pDiscrete = mDiscreteRoots.array(); for (; ppRootFinder != ppRootFinderEnd; ++ppRootFinder, ++pDiscrete) { *pDiscrete = (*ppRootFinder)->isDiscrete(); } } else { mLSODA.setOstream(mErrorMsg); } return; }
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; }
// virtual void CLsodaMethod::stateChanged() { if (!mNoODE && mLsodaStatus != 1) { // Compare the independent state variables // This an be done directly by comparing mMethodState and *mpCurrentState C_FLOAT64 *pMethod = mY; C_FLOAT64 *pMethodEnd = pMethod + mData.dim; C_FLOAT64 *pCurrent = mpCurrentState->beginIndependent(); for (; pMethod != pMethodEnd; ++pMethod, ++pCurrent) { // We may need to use the absolute and relative tolerance if (*pMethod != *pCurrent) { mLsodaStatus = 1; mMethodState = *mpCurrentState; mTime = mMethodState.getTime(); break; } } if (mLsodaStatus != 1) { // Compare the rates of the independent state variables // we need to call evalF for mMethodState and *mpCurrentState and compare the returned rates. CVector< C_FLOAT64 > MethodRate(mData.dim); CVector< C_FLOAT64 > CurrentRate(mData.dim); evalF(&mTime, mY, MethodRate.array()); mMethodState = *mpCurrentState; mTime = mMethodState.getTime(); evalF(&mTime, mY, CurrentRate.array()); pMethod = MethodRate.array(); pMethodEnd = pMethod + mData.dim; pCurrent = CurrentRate.array(); for (; pMethod != pMethodEnd; ++pMethod, ++pCurrent) { // We may need to use the absolute and relative tolerance if (*pMethod != *pCurrent) { mLsodaStatus = 1; break; } } } } else { mMethodState = *mpCurrentState; mTime = mMethodState.getTime(); } destroyRootMask(); mRootMasking = NONE; }