void CILDMModifiedMethod::step(const double & deltaT) { C_INT dim = mData.dim; C_INT fast = 0; C_INT slow = dim - fast; C_INT slow2, fast2; slow2 = dim; fast2 = dim - slow2; C_INT i, j; mY_initial.resize(dim); mJacobian_initial.resize(dim, dim); mQ.resize(dim, dim); mR.resize(dim, dim); mTd.resize(dim, dim); mTdInverse.resize(dim, dim); mQz.resize(dim, dim); mTd_save.resize(dim, dim); mTdInverse_save.resize(dim, dim); mpModel->updateSimulatedValues(mReducedModel); // TO REMOVE : mpModel->applyAssignments(); mpModel->calculateJacobianX(mJacobian, 1e-6, 1e-12); C_INT flag_jacob; flag_jacob = 1; // Set flag_jacob=0 to print Jacobian C_FLOAT64 number2conc = mpModel->getNumber2QuantityFactor() / mpModel->getCompartments()[0]->getInitialValue(); //C_FLOAT64 number2conc = 1.; //this is an ugly hack that only makes sense if all metabs are in the same compartment //at the moment is is the only case the algorithm deals with CVector<C_FLOAT64> Xconc; //current state converted to concentrations Xconc.resize(dim); for (i = 0; i < dim; ++i) Xconc[i] = mY[i] * number2conc; for (i = 0; i < dim; i++) mY_initial[i] = mY[i]; CVector<C_FLOAT64> Xconc_initial; //current state converted to concentrations Xconc_initial.resize(dim); for (i = 0; i < dim; ++i) Xconc_initial[i] = mY_initial[i] * number2conc; // save initial Jacobian before next time step for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) mJacobian_initial(i, j) = mJacobian(i, j); // Next time step integrationStep(deltaT); mpModel->updateSimulatedValues(mReducedModel); // TO REMOVE : mpModel->applyAssignments(); // Calculate Jacobian for time step control mpModel->calculateJacobianX(mJacobian, 1e-6, 1e-12); //CMatrix<C_FLOAT64> mTd_save; for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) { mTd_save(i, j) = 0; mTdInverse_save(i, j) = 0; } for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) { mTd(i, j) = 0; mTdInverse(i, j) = 0; } /** Schur Decomposition of Jacobian (reordered). Output: mQ - transformation matrix mR - block upper triangular matrix (with ordered eigenvalues) */ C_INT failed = 0; C_INT info_schur = 0; C_INT number, k; C_INT failed_while = 0; C_INT flag_deufl; flag_deufl = 1; C_FLOAT64 max = 0.; //C_FLOAT64 max = 0; CVector<C_FLOAT64> re; CVector<C_FLOAT64> dxdt_relax; CVector<C_FLOAT64> x_relax; CVector<C_FLOAT64> x_help; CVector<C_FLOAT64> dxdt; CVector<C_FLOAT64> x_zero; CVector<C_FLOAT64> dxdt_zero; CVector<C_FLOAT64> dxdt_real; CVector<C_FLOAT64> help; CVector<C_INT> index; CVector<C_INT> index_temp; CMatrix<C_FLOAT64> orthog_prove; orthog_prove.resize(dim, dim); C_INT info; CVector<C_INT> index_metab; index_metab.resize(dim); /** Schur transformation of Jacobian */ schur(info_schur); if (info_schur) { CCopasiMessage(CCopasiMessage::WARNING, MCTSSAMethod + 9, mTime - deltaT); goto integration; } for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) mTdInverse(i, j) = mQ(j, i); C_INT flag_schur; flag_schur = 1; // set flag_schur = 0 to print Schur decomposition of jacobian (matrices mR and transformation mQ) mY_cons.resize(dim); // consistent initial vector for DAE /* If complex eigenvalues */ //BUG 873 if (mR(dim - 1, dim - 1) == mR(dim - 2 , dim - 2)) if (dim == 2) { slow = dim; goto integration; } // If positive eigenvalues if (mR(dim - 1, dim - 1) >= 0) { slow = dim; fast = 0; CCopasiMessage(CCopasiMessage::WARNING, MCTSSAMethod + 10, mTime - deltaT); failed = 1; goto integration; } // Iterations to determine the number of slow metabolites while ((slow2 > 1)) { slow2 = slow2 - 1; fast2 = dim - slow2; if (mR(dim - fast2, dim - fast2) >= 0) { failed = 1; goto integration; } deuflhard_metab(slow2, info); if (info) { failed_while = 1; goto integration; } } //end of iterations to determine the number of slow metabolites /** end of the block %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */ /** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */ integration: slow = slow2; fast = fast2; if ((failed == 1) || (failed_while == 1)) { if (slow < dim) { fast = fast - 1; slow = dim - fast; if ((fast >= 1) && (mR(slow - 1, slow - 1) == mR(slow , slow))) fast = fast - 1; slow = dim - fast; } } mSlow = slow; if (slow == dim) CCopasiMessage(CCopasiMessage::WARNING, MCTSSAMethod + 11, mTime); for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) // mTdInverse(i,j) = mQ(i,j); mTd(i, j) = mQ(i, j); // Flag for print Tabs mat_anal_mod(slow); mat_anal_metab(slow); mat_anal_mod_space(slow); mat_anal_fast_space(slow); // This block proves which metabolite could be considered as QSS. In development /** Begin of the block %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */ C_INT flag_dev; flag_dev = 1; if (flag_dev == 0) { C_INT temp; temp = dim - 1; // Mode Analysis to find the dominant metabolites in the modes mat_anal_mod(temp); //index_metab = -1, if there is no dominant metabolites in corresponding mode, //and is equal // to the number of dominant metabolite in opposite case // Dominant metabolite - its contribution to the mode is larger as 70% for (j = 0; j < dim; j++) index_metab[j] = -1; for (i = 0; i < dim ; i ++) for (j = 0; j < dim; j++) if (mVslow(dim - i - 1, j) > 70) index_metab[i] = j; C_FLOAT64 y_cons; info = 0; k = 0; number = index_metab[k]; if (number > - 1) newton_for_timestep(number, y_cons, info); while (k < dim - 1) { if (number > -1) { dxdt.resize(dim); for (j = 0; j < dim; j++) dxdt[j] = 0.; //CVector<C_FLOAT64> x_help; x_help.resize(dim); for (j = 0; j < dim; j++) { x_help[j] = mY_initial[j] * number2conc; } calculateDerivativesX(x_help.array(), dxdt.array()); info = 0; //NEWTON: Looking for consistent initial value for DAE system //Output: y_cons, info newton_for_timestep(number, y_cons, info); if (info) { // TODO info: newton iteration stop } if (info == 0) { // CVector<C_FLOAT64> x_relax; x_relax.resize(dim); for (i = 0; i < dim; i ++) if (i == number) x_relax[i] = y_cons; else x_relax[i] = x_help[i]; //CVector<C_FLOAT64> dxdt_relax; dxdt_relax.resize(dim); calculateDerivativesX(x_relax.array(), dxdt_relax.array()); //CVector<C_FLOAT64> re; re.resize(dim); C_FLOAT64 eps; eps = 1 / fabs(mR(dim - k - 1 , dim - k - 1)); // stop criterion for slow reaction modes for (i = 0; i < dim; i++) { if (i == number) re[i] = 0; else { re[i] = fabs(dxdt_relax[i] - dxdt[i]); re[i] = re[i] * eps; } } //C_FLOAT64 max = 0.; for (i = 0; i < dim; i++) if (max < re[i]) max = re[i]; if (max >= mDtol) info = 1; else info = 0; } } k = k + 1; number = index_metab[k]; max = 0; } } /** end of the of block %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */ /** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */ mpModel->updateSimulatedValues(mReducedModel); // TO REMOVE : mpModel->applyAssignments(); // Calculate Jacobian for time step control mpModel->calculateJacobianX(mJacobian, 1e-6, 1e-12); // new entry for every entry contains the current data of currently step setVectors(slow); // set the stepcounter mCurrentStep += 1; return; }
void CILDMMethod::step(const double & deltaT) { C_INT failed_while = 0; C_INT dim = mData.dim; C_INT fast = 0; C_INT slow = dim - fast; C_INT i, j, k, info_schur = 0; mY_initial.resize(dim); mJacobian_initial.resize(dim, dim); mQ.resize(dim, dim); mR.resize(dim, dim); mQ_desc.resize(dim, dim); mR_desc.resize(dim, dim); mTd.resize(dim, dim); mTdInverse.resize(dim, dim); mQz.resize(dim, dim); mTd_save.resize(dim, dim); mTdInverse_save.resize(dim, dim); mpModel->updateSimulatedValues(mReducedModel); // TO REMOVE : mpModel->applyAssignments(); mpModel->calculateJacobianX(mJacobian, 1e-6, 1e-12); C_INT flag_jacob; flag_jacob = 1; // Set flag_jacob=0 to printing Jacobian // To get the reduced Stoichiometry Matrix; CMatrix<C_FLOAT64> Stoichiom; Stoichiom = mpModel -> getRedStoi(); // const CCopasiVector< CReaction > & reacs = copasiModel->getReactions(); C_INT32 reacs_size = mpModel -> getRedStoi().size(); reacs_size = reacs_size / dim; //TODO what is this? /* the vector mY is the current state of the system*/ C_FLOAT64 number2conc = 1.; //= mpModel->getNumber2QuantityFactor() // / mpModel->getCompartments()[0]->getInitialValue(); //this is an ugly hack that only makes sense if all metabs are in the same compartment //at the moment is is the only case the algorithm deals with CVector<C_FLOAT64> Xconc; //current state converted to concentrations Xconc.resize(dim); for (i = 0; i < dim; ++i) Xconc[i] = mY[i] * number2conc; for (i = 0; i < dim; i++) mY_initial[i] = mY[i]; CVector<C_FLOAT64> Xconc_initial; //current state converted to concentrations Xconc_initial.resize(dim); for (i = 0; i < dim; ++i) Xconc_initial[i] = mY_initial[i] * number2conc; // save initial Jacobian before next time step for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) mJacobian_initial(i, j) = mJacobian(i, j); // Next time step integrationStep(deltaT); mpModel->updateSimulatedValues(mReducedModel); // TO REMOVE : mpModel->applyAssignments(); // Calculate Jacobian for time step control mpModel->calculateJacobianX(mJacobian, 1e-6, 1e-12); #ifdef ILDMDEBUG if (flag_jacob == 0) { std::cout << "Jacobian_next:" << std::endl; std::cout << mJacobian << std::endl; } #endif // to be removed CMatrix<C_FLOAT64> Jacobian_for_test; Jacobian_for_test.resize(dim, dim); for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) Jacobian_for_test(i, j) = mJacobian_initial(i, j); // save initial Jacobian before next time step for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) mJacobian_initial(i, j) = mJacobian(i, j); schur(info_schur); #ifdef ILDMDEBUG std::cout << "Eigenvalues of next Jacobian" << std::endl; for (i = 0; i < dim; i++) std::cout << mR(i, i) << std::endl; #endif for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) mJacobian_initial(i, j) = Jacobian_for_test(i, j); //end to be removed for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) { mTd_save(i, j) = 0; mTdInverse_save(i, j) = 0; } for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) { mTd(i, j) = 0; mTdInverse(i, j) = 0; } /** Schur Decomposition of Jacobian (reordered). Output: mQ - transformation matrix mR - block upper triangular matrix (with ordered eigenvalues) */ C_INT failed = 0; // C_INT info_schur = 0; schur(info_schur); // TO DO : move the test to the TSSAMethod if (info_schur) { CCopasiMessage(CCopasiMessage::WARNING, MCTSSAMethod + 5, mTime - deltaT); goto integration; } C_INT flag_schur; flag_schur = 0; #ifdef ILDMDEBUG std::cout << "Eigenvalues of initial Jacobian" << std::endl; for (i = 0; i < dim; i++) std::cout << mR(i, i) << std::endl; if (flag_schur == 1) { std::cout << "Schur Decomposition" << std::endl; std::cout << "mR - block upper triangular matrix :" << std::endl; std::cout << mR << std::endl; } #endif /* If complex eigenvalues */ //BUG 873 if (mR(dim - 1, dim - 1) == mR(dim - 2 , dim - 2)) if (dim == 2) { slow = dim; goto integration; } // No reduction if the smallest eigenvalue is positive if (mR(dim - 1, dim - 1) >= 0) { slow = dim; fast = 0; CCopasiMessage(CCopasiMessage::WARNING, MCTSSAMethod + 6, mTime - deltaT); failed = 1; goto integration; } // C_INT number, k; /** Classical ILDM iterations. The number of slow variables is decreased until the Deuflhard criterium holds */ /* do START slow iterations */ while (slow > 1) { fast = fast + 1; slow = dim - fast; if (fast < dim - 1) if (mR(slow, slow) == mR(slow - 1 , slow - 1)) fast = fast + 1; slow = dim - fast; for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) { mTd_save(i, j) = mTd(i, j); mTdInverse_save(i, j) = mTdInverse(i, j); } C_INT info = 0; failed_while = 0; if (slow == 0) { for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) { mTdInverse(i, j) = mQ(j, i); mTd(i, j) = mQ(i, j); mQz(i, j) = mR(i, j); } } else { /** Solution of Sylvester equation for given slow, mQ,mR Output: mTd, mTdinverse and mQz (mQz is used later for newton iterations) */ sylvester(slow, info); if (info) { CCopasiMessage(CCopasiMessage::WARNING, MCTSSAMethod + 7, slow, mTime - deltaT); failed_while = 1; goto integration; } } /* Check real parts of eigenvalues of Jacobian */ for (i = slow ; i < dim; i++) if (mR(i , i) >= 0) { failed_while = 1; goto integration; } if (fast > 0) mEPS = 1 / fabs(mR(slow , slow)); mCfast.resize(fast); /** Deuflhard Iteration: Prove Deuflhard criteria, find consistent initial value for DAE output: info - if Deuflhard is satisfied for this slow; transformation matrices mTd and mTdinverse */ info = 0; C_INT help; help = 0; deuflhard(slow, info); help = help + 1; failed_while = 0; if (info) { failed_while = 1; goto integration; } } /** end of iterations to find the number of slow modes */ integration: if ((failed == 1) || (failed_while == 1)) { if (slow < dim) { fast = fast - 1; slow = dim - fast; if ((fast >= 1) && (mR(slow - 1, slow - 1) == mR(slow , slow))) fast = fast - 1; slow = dim - fast; for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) { mTd(i, j) = mTd_save(i, j); mTdInverse(i, j) = mTdInverse_save(i, j); } } } mSlow = slow; if (slow == dim) CCopasiMessage(CCopasiMessage::WARNING, MCTSSAMethod + 8, mTime); // test for orthogonality of the slow space C_INT flag_orthog = 1; if (flag_orthog == 0) { CMatrix<C_FLOAT64> orthog_prove; orthog_prove.resize(dim, dim); for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) orthog_prove(i, j) = orthog(i, j); } C_INT flag_develop; flag_develop = 0; //1; if (flag_develop == 0) { C_INT info_schur_desc = 0; /** Schur Decomposition of Jacobian (with another sorting: from fast to slow). Output: mQ_desc - transformation matrix mR_desc - block upper triangular matrix (with ordered eigenvalues) */ schur_desc(info_schur_desc); for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) { mTd_save(i, j) = mTd(i, j); mTdInverse_save(i, j) = mTdInverse(i, j); } for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) { mTdInverse(i, j) = mQ_desc(j, i); mTd(i, j) = mQ_desc(i, j); } C_INT slow_desc; slow_desc = fast; mat_anal_fast_space(slow_desc); mat_anal_mod_space(slow_desc); CVector<C_FLOAT64> Reac_slow_space_orth; Reac_slow_space_orth.resize(reacs_size); for (i = 0; i < reacs_size; i ++) { Reac_slow_space_orth[i] = 0; for (j = 0; j < dim; j++) { Reac_slow_space_orth[i] = Reac_slow_space_orth[i] + mVfast_space[j] * Stoichiom(j, i); } } for (i = 0; i < dim; i++) for (j = 0; j < dim; j++) { mTd(i, j) = mTd_save(i, j); mTdInverse(i, j) = mTdInverse_save(i, j); } } // end of test // Post Analysis mat_anal_mod(slow); mat_anal_metab(slow); mat_anal_mod_space(slow); mat_anal_fast_space(slow); /** This part corresponds to the investigation of fast and slow reactions. In development at the moment. To activate the calculations take flag_develop = 0; */ if (flag_develop == 0) { CMatrix<C_FLOAT64> Slow_react_contr; Slow_react_contr.resize(dim, reacs_size); CMatrix<C_FLOAT64> Mode_react_contr; Mode_react_contr.resize(dim, reacs_size); CVector<C_FLOAT64> Reac_slow_space; Reac_slow_space.resize(reacs_size); CVector<C_FLOAT64> Reac_fast_space; Reac_fast_space.resize(reacs_size); mReacSlowSpace.resize(reacs_size); //NEW TAB for (i = 0; i < dim; i ++) for (j = 0; j < reacs_size; j++) { Slow_react_contr(i, j) = 0; for (k = 0; k < dim; k++) Slow_react_contr(i, j) = Slow_react_contr(i, j) + mVslow(i, k) * Stoichiom(k, j); } CVector<C_FLOAT64> denom_mode; denom_mode.resize(dim); for (j = 0; j < dim; j++) denom_mode[j] = 0; for (i = 0; i < dim; i++) for (j = 0; j < reacs_size; j++) denom_mode[i] = denom_mode[i] + fabs(Slow_react_contr(i, j)); for (i = 0; i < dim; i++) for (j = 0; j < reacs_size; j++) { if (denom_mode[i] == 0) Mode_react_contr(i, j) = 0; else Mode_react_contr(i, j) = (Slow_react_contr(i, j)) / denom_mode[i] * 100; } CVector<C_FLOAT64> denom_reac; denom_reac.resize(reacs_size); for (j = 0; j < reacs_size; j++) denom_reac[j] = 0; for (i = 0; i < reacs_size; i++) for (j = 0; j < dim; j++) denom_reac[i] = denom_reac[i] + fabs(Slow_react_contr(j, i)); for (i = 0; i < reacs_size; i++) for (j = 0; j < dim; j++) { if (denom_reac[i] == 0) Slow_react_contr(j, i) = 0; else Slow_react_contr(j, i) = (Slow_react_contr(j , i)) / denom_reac[i] * 100; } for (i = 0; i < reacs_size; i ++) { Reac_slow_space[i] = 0; for (j = 0; j < dim; j++) { Reac_slow_space[i] = Reac_slow_space[i] + mVslow_space[j] * Stoichiom(j, i); } } C_FLOAT64 length; length = 0; for (i = 0; i < reacs_size; i++) length = length + fabs(Reac_slow_space[i]); for (i = 0; i < reacs_size; i++) if (length > 0) mReacSlowSpace[i] = Reac_slow_space[i] / length * 100; else mReacSlowSpace[i] = 0; for (i = 0; i < reacs_size; i ++) { Reac_fast_space[i] = 0; for (j = 0; j < dim; j++) Reac_fast_space[i] = Reac_fast_space[i] + mVfast_space[j] * Stoichiom(j, i); } length = 0; for (i = 0; i < reacs_size; i++) length = length + fabs(Reac_fast_space[i]); for (i = 0; i < reacs_size; i++) if (length > 0) Reac_fast_space[i] = Reac_fast_space[i] / length * 100; else Reac_fast_space[i] = 0; #ifdef ILDMDEBUG std::cout << "**********************************************************" << std::endl; std::cout << "**********************************************************" << std::endl; std::cout << std::endl; std::cout << std::endl; #endif mTMP1.resize(reacs_size, dim); mTMP2.resize(reacs_size, dim); mTMP3.resize(reacs_size, 1); for (i = 0; i < dim; i++) for (j = 0; j < reacs_size; j++) { mTMP1(j, i) = Mode_react_contr(i, j); mTMP2(j, i) = Slow_react_contr(i, j); } for (j = 0; j < reacs_size; j++) mTMP3(j, 0) = Reac_fast_space[j]; } // End of reaction analysis mpModel->updateSimulatedValues(mReducedModel); // TO REMOVE : mpModel->applyAssignments(); // Calculate Jacobian for time step control mpModel->calculateJacobianX(mJacobian, 1e-6, 1e-12); // new entry for every entry contains the current data of currently step setVectors(slow); // set the stepcounter mCurrentStep += 1; return; }