double GillespieIntegrator::integrate(double t, double hstep) { double tf = 0; bool singleStep; assert(hstep > 0 && "hstep must be > 0"); if (options.integratorFlags & VARIABLE_STEP) { if (options.minimumTimeStep > 0.0) { tf = t + options.minimumTimeStep; singleStep = false; } else { tf = t + hstep; singleStep = true; } } else { tf = t + hstep; singleStep = false; } Log(Logger::LOG_DEBUG) << "ssa(" << t << ", " << tf << ")"; // get the initial state vector model->setTime(t); model->getStateVector(stateVector); while (t < tf) { // random uniform numbers double r1 = urand(); double r2 = urand(); assert(r1 > 0 && r1 <= 1 && r2 >= 0 && r2 <= 1); // sum of propensities double s = 0; // next time double tau = 0; // get the 'propensity' -- reaction rates model->getReactionRates(nReactions, 0, reactionRates); // sum the propensity for (int k = 0; k < nReactions; k++) { Log(Logger::LOG_DEBUG) << "reac rate: " << k << ": " << reactionRates[k]; // if reaction rate is negative, that means reaction goes in reverse, // this is fine, we just have to reverse the stoichiometry, // but still need to sum the absolute value of the propensities // to get tau. s += std::abs(reactionRates[k]); } // sample tau if (s > 0) { tau = -log(r1) / s; } else { // no reaction occurs return std::numeric_limits<double>::infinity(); } t = t + tau; // select reaction int reaction = -1; double sp = 0.0; r2 = r2 * s; for (int i = 0; i < nReactions; ++i) { sp += std::abs(reactionRates[i]); if (r2 < sp) { reaction = i; break; } } assert(reaction >= 0 && reaction < nReactions); // update chemical species // if rate is negative, means reaction goes in reverse, so // multiply by sign double sign = (reactionRates[reaction] > 0) - (reactionRates[reaction] < 0); for (int i = floatingSpeciesStart; i < stateVectorSize; ++i) { stateVector[i] = stateVector[i] + getStoich(i - floatingSpeciesStart, reaction) * stoichScale * sign; if(stateVector[i] < 0.0) { Log(Logger::LOG_WARNING) << "Error, negative value of " << stateVector[i] << " encountred for floating species " << model->getFloatingSpeciesId(i - floatingSpeciesStart); t = std::numeric_limits<double>::infinity(); } } // rates could be time dependent model->setTime(t); model->setStateVector(stateVector); if (singleStep) { return t; } } return t; }
double GillespieIntegrator::integrate(double t, double hstep) { double tf = 0; bool singleStep; assert(hstep > 0 && "hstep must be > 0"); if (getValue("variable_step_size").convert<bool>()) { if (getValue("minimum_time_step").convert<double>() > 0.0) { tf = t + getValue("minimum_time_step").convert<double>(); singleStep = false; } else { tf = t + hstep; singleStep = true; } } else { tf = t + hstep; singleStep = false; } Log(Logger::LOG_DEBUG) << "ssa(" << t << ", " << tf << ")"; // get the initial state vector model->setTime(t); model->getStateVector(stateVector); while (t < tf) { // random uniform numbers double r1 = urand(); double r2 = urand(); assert(r1 > 0 && r1 <= 1 && r2 >= 0 && r2 <= 1); // sum of propensities double s = 0; // next time double tau = 0; // get the 'propensity' -- reaction rates model->getReactionRates(nReactions, 0, reactionRates); // sum the propensity for (int k = 0; k < nReactions; k++) { Log(Logger::LOG_DEBUG) << "reac rate: " << k << ": " << reactionRates[k]; // if reaction rate is negative, that means reaction goes in reverse, // this is fine, we just have to reverse the stoichiometry, // but still need to sum the absolute value of the propensities // to get tau. s += std::abs(reactionRates[k]); } // sample tau if (s > 0) { tau = -log(r1) / s; } else { // no reaction occurs return std::numeric_limits<double>::infinity(); } t = t + tau; // select reaction int reaction = -1; double sp = 0.0; r2 = r2 * s; for (int i = 0; i < nReactions; ++i) { sp += std::abs(reactionRates[i]); if (r2 < sp) { reaction = i; break; } } assert(reaction >= 0 && reaction < nReactions); // update chemical species // if rate is negative, means reaction goes in reverse, so // multiply by sign double sign = (reactionRates[reaction] > 0) - (reactionRates[reaction] < 0); bool skip = false; if (getValueAsBool("nonnegative")) { // skip reactions which cause species amts to become negative for (int i = floatingSpeciesStart; i < stateVectorSize; ++i) { if (stateVector[i] + getStoich(i - floatingSpeciesStart, reaction) * stoichScale * sign < 0.0) { skip = true; break; } } } if (!skip) { for (int i = floatingSpeciesStart; i < stateVectorSize; ++i) { stateVector[i] = stateVector[i] + getStoich(i - floatingSpeciesStart, reaction) * stoichScale * sign; if (stateVector[i] < 0.0) { Log(Logger::LOG_WARNING) << "Error, negative value of " << stateVector[i] << " encountred for floating species " << model->getFloatingSpeciesId(i - floatingSpeciesStart); t = std::numeric_limits<double>::infinity(); } } } // rates could be time dependent model->setTime(t); model->setStateVector(stateVector); // events bool triggered = false; model->getEventTriggers(eventStatus.size(), NULL, eventStatus.size() ? &eventStatus[0] : NULL); for(int k_=0; k_<eventStatus.size(); ++k_) { if (eventStatus.at(k_)) triggered = true; } if (triggered) { applyEvents(t, previousEventStatus); } if (eventStatus.size()) memcpy(&previousEventStatus[0], &eventStatus[0], eventStatus.size()*sizeof(unsigned char)); if (singleStep) { return t; } } return t; }