32 #include "../mesh/VoxelJunction.h"
36 #include "../randnum/RNG.h"
46 #include "boost/numeric/bindings/lapack/lapack.hpp"
47 #include "boost/numeric/bindings/lapack/geev.hpp"
54 using namespace boost::numeric::bindings;
55 using namespace boost::numeric;
82 ublas::matrix< double >*
Nr;
117 "Specify the Id of the stoichiometry system to use",
123 "Bool: True if there is a problem with the stoichiometry",
128 "True if the model has been initialized successfully",
133 "Number of iterations done by steady state solver",
143 "Max permissible number of iterations to try before giving up",
148 "convergenceCriterion",
149 "Fractional accuracy required to accept convergence",
155 "Number of variable molecules in reaction system.",
160 "Number of independent molecules in reaction system",
165 "0: stable; 1: unstable; 2: saddle; 3: osc?; 4: one near-zero eigenvalue; 5: other",
171 "Number of negative eigenvalues: indicates type of solution",
177 "Number of positive eigenvalues: indicates type of solution",
182 "0: Good; 1: Failed to find steady states; "
183 "2: Failed to find eigenvalues",
188 "Totals table for conservation laws. The exact mapping of"
189 "this to various sums of molecules is given by the "
190 "conservation matrix, and is currently a bit opaque."
191 "The value of 'total' is set to initial conditions when"
192 "the 'SteadyState::settle' function is called."
193 "Assigning values to the total is a special operation:"
194 "it rescales the concentrations of all the affected"
195 "molecules so that they are at the specified total."
196 "This happens the next time 'settle' is called.",
203 "Eigenvalues computed for steady state",
209 static DestFinfo setupMatrix(
"setupMatrix",
210 "This function initializes and rebuilds the matrices used "
211 "in the calculation.",
216 "Finds the nearest steady state to the current initial "
217 "conditions. This function rebuilds the entire calculation "
218 "only if the object has not yet been initialized.",
222 "Finds the nearest steady state to the current initial "
223 "conditions. This function rebuilds the entire calculation ",
226 static DestFinfo showMatrices(
"showMatrices",
227 "Utility function to show the matrices derived for the calculations on the reaction system. Shows the Nr, gamma, and total matrices",
230 static DestFinfo randomInit(
"randomInit",
231 "Generate random initial conditions consistent with the mass"
232 "conservation rules. Typically invoked in order to scan"
241 static Finfo * steadyStateFinfos[] =
249 &convergenceCriterion,
267 static string doc[] =
269 "Name",
"SteadyState",
270 "Author",
"Upinder S. Bhalla, 2009, updated 2014, NCBS",
271 "Description",
"SteadyState: works out a steady-state value for "
272 "a reaction system. "
273 "This class uses the multidimensional root finder algorithms "
274 "to find the fixed points closest to the "
275 "current molecular concentrations. "
276 "When it finds the fixed points, it figures out eigenvalues of "
277 "the solution, as a way to help classify the fixed points. "
278 "Note that the method finds unstable as well as stable fixed "
280 "The SteadyState class also provides a utility function "
282 "randomly initialize the concentrations, within the constraints "
283 "of stoichiometry. This is useful if you are trying to find "
284 "the major fixed points of the system. Note that this is "
285 "probabilistic. If a fixed point is in a very narrow range of "
286 "state space the probability of finding it is small and you "
287 "will have to run many iterations with different initial "
288 "conditions to find it.\n "
289 "The numerical calculations used by the SteadyState solver are "
290 "prone to failing on individual calculations. All is not lost, "
291 "because the system reports the solutionStatus. "
292 "It is recommended that you test this field after every "
293 "calculation, so you can simply ignore "
294 "cases where it failed and try again with different starting "
296 "Another rule of thumb is that the SteadyState object is more "
297 "likely to succeed in finding solutions from a new starting point "
298 "if you numerically integrate the chemical system for a short "
299 "time (typically under 1 second) before asking it to find the "
308 sizeof( steadyStateFinfos )/
sizeof(
Finfo *),
310 doc,
sizeof( doc ) /
sizeof(
string )
326 badStoichiometry_( 0 ),
330 convergenceCriterion_( 1e-7 ),
336 nNegEigenvalues_( 0 ),
337 nPosEigenvalues_( 0 ),
339 solutionStatus_( 0 ),
362 cout <<
"Error: SteadyState::setStoich: Must be of Stoich class\n";
445 cout <<
"Warning: Convergence criterion " << value <<
446 " too small. Old value " <<
459 cout <<
"Warning: SteadyState::getTotal: index " << i <<
460 " out of range " <<
total_.size() << endl;
472 cout <<
"Warning: SteadyState::setTotal: index " << i <<
473 " out of range " <<
total_.size() << endl;
480 cout <<
"Warning: SteadyState::getEigenvalue: index " << i <<
512 cout <<
"SteadyState::showMatrices: Sorry, the system is not yet initialized.\n";
517 for (
int i = 0; i < numConsv; ++i )
520 cout <<
"gamma " <<
gamma_ << endl;
521 cout <<
"Nr " <<
Nr_ << endl;
522 cout <<
"LU " <<
LU_ << endl;
546 LU_(i, i + nReacs_) = 1;
547 unsigned int k = rowStart[i];
548 for (
unsigned int j = 0; j <
nReacs_; ++j )
551 if ( j == colIndex[k] && k < rowStart[i+1] )
563 Nr_.assign( ublas::zero_matrix< double >( rank_, nReacs_ ) );
565 unsigned int nConsv = numVarPools_ -
rank_;
568 cout <<
"SteadyState::setupSSmatrix(): Number of conserved species == 0. Aborting\n";
573 for (
unsigned int i = 0; i <
rank_; i++)
574 for (
unsigned int j = i; j <
nReacs_; j++)
586 total_.assign( nConsv, 0.0 );
589 vector< double > nVec =
595 for (
unsigned int i = 0; i < nConsv; ++i )
602 cout <<
"Error: SteadyState::setupSSmatrix(): unable to get"
603 "pool numbers from ksolve.\n";
623 vector< double > yprime( nVec.size(), 0.0 );
627 double orig = nVec[i];
628 if ( std::isnan( orig ) or std::isinf( orig ) )
630 cout <<
"Warning: SteadyState::classifyState: orig=nan\n";
635 if ( std::isnan( tot ) or std::isinf( tot ))
637 cout <<
"Warning: SteadyState::classifyState: tot=nan\n";
642 nVec[i] = orig + tot;
650 if( std::isnan( yprime[j] ) or std::isinf( yprime[j] ) )
652 cout <<
"Warning: Overflow/underflow. Can't continue " << endl;
661 ublas::vector< std::complex< double > > eigenVec ( J.size1() );
663 ublas::matrix< std::complex<double>, ublas::column_major >* vl, *vr;
664 vl = NULL; vr = NULL;
673 int status = lapack::geev( J, eigenVec, vl, vr, lapack::optimal_workspace() );
679 cout <<
"Warning: SteadyState::classifyState failed to find eigenvalues. Status = " <<
689 std::complex<value_type> z = eigenVec[ i ];
714 for(
size_t i = 0; i < x.size(); i++ )
717 if ( std::isnan( v ) or std::isinf( v ) )
719 cout <<
"Warning: SteadyState iteration gave nan/inf concs\n";
724 cout <<
"Warning: SteadyState iteration gave negative concs\n";
740 cout <<
"Error: SteadyState object has not been initialized. No calculations done\n";
749 double * T = (
double *) calloc( nConsv,
sizeof(
double ) );
762 ss->ri.pool = &
pool_;
773 init[i] = max( 0.0, sqrt(ss->ri.nVec[i]) );
775 ss->initialize<vector<double>>(
init );
780 for (
size_t i = 0; i < nConsv; ++i )
786 for (
size_t i = 0; i < nConsv; ++i )
788 T[i] +=
gamma_( i, j ) * ss->ri.nVec[ j ];
789 total_.assign( T, T + nConsv );
792 vector< double > repair( numVarPools_, 0.0 );
795 repair[j] = ss->ri.nVec[j];
801 if( ss->find_roots_gnewton( ) )
809 ksolve,
"nVec", 0, ss->ri.nVec
820 cout <<
"Warning: SteadyState iteration failed, status = " <<
821 status_ <<
", nIter = " << ss->ri.nIter << endl;
824 ss->ri.nVec[j] = repair[j];
827 LookupField<
unsigned int, vector< double > >::set(
828 ksolve,
"nVec", 0, ss->ri.nVec
849 void swapRows( ublas::matrix< double >& mat,
unsigned int r1,
unsigned int r2)
851 ublas::vector<value_type> temp( mat.size2() );
852 for (
size_t i = 0; i < mat.size2(); i++)
854 temp[i] = mat(r1, i );
855 mat(r1, i ) = mat(r2, i );
858 for (
size_t i = 0; i < mat.size2(); i++)
859 mat(r2, i) = temp[i];
863 int reorderRows( ublas::matrix< double >& U,
int start,
int leftCol )
865 int leftMostRow = start;
866 int numReacs = U.size2() - U.size1();
867 int newLeftCol = numReacs;
868 for (
size_t i = start; i < U.size1(); ++i )
870 for (
int j = leftCol; j < numReacs; ++j )
874 if ( j < newLeftCol )
884 if ( leftMostRow != start )
892 int numMols = U.size1();
893 double pivot = U( start, leftCol );
895 for (
int i = start + 1; i < numMols; ++i )
897 double factor = U(i, leftCol);
900 factor = factor / pivot;
901 for (
size_t j = leftCol + 1; j < U.size2(); ++j )
904 double y = U( start, j );
917 int numMols = U.size1();
918 int numReacs = U.size2() - numMols;
923 for ( i = 0; i < numMols - 1; ++i )
927 if ( leftCol == numReacs )
936 for ( vector< double >::const_iterator
937 i = y.begin(); i != y.end(); ++i )
952 void recalcTotal( vector< double >& tot, ublas::matrix<double>& g,
const double* S )
954 assert( g.size1() == tot.size() );
955 for (
size_t i = 0; i < g.size1(); ++i )
958 for (
unsigned int j = 0; j < g.size2(); ++j )
959 t += g( i, j ) * S[j];
971 vector< double > nVec =
974 int numConsv =
total_.size();
979 ublas::matrix<double> U(numConsv,
numVarPools_ + numConsv, 0);
981 for (
int i = 0; i < numConsv; ++i )
986 U(i, numVarPools_) =
total_[i];
990 assert( rank = numConsv );
992 vector< double > eliminatedTotal( numConsv, 0.0 );
993 for (
int i = 0; i < numConsv; ++i )
1005 for (
int i = 0; i < numConsv; ++i )
1010 tot += y[j] *
gamma_( i, j );
1023 ksolve,
"nVec", 0, nVec );
1031 ublas::matrix<double>& U,
const vector< double >& eliminatedTotal,
1035 int numConsv =
total_.size();
1037 for (
int i = numConsv - 1; i >= 0; --i )
1041 double g = U( i, j );
1046 for (
int k = j; k < lastJ; ++k )
1049 ytot += y[k] * U( i, k );
1051 assert( fabs( ytot ) >
EPSILON );
1052 double lastYtot = 0.0;
1055 lastYtot += y[k] * U( i, k );
1057 double scale = ( eliminatedTotal[i] - lastYtot ) / ytot;
1058 for (
int k = j; k < lastJ; ++k )
Id init(int argc, char **argv, bool &doUnitTests, bool &doRegressionTests, unsigned int &benchmark)
void randomizeInitialCondition(const Eref &e)
unsigned int getMaxIter() const
Id getCompartment() const
unsigned int getNposEigenvalues() const
boost::numeric::ublas::matrix< value_type_ > gamma_
static A get(const ObjId &dest, const string &field, L index)
Element * element() const
Synonym for Id::operator()()
unsigned int getNiter() const
void ss_func(const vector_type &x, void *params, vector_type &f)
unsigned int getNumVarPools() const
static bool checkAboveZero(const vector< double > &y)
double getConvergenceCriterion() const
ublas::vector< value_type > vector_type
unsigned int getRank() const
vector< double > eigenvalues_
double convergenceCriterion_
bool badStoichiometry() const
ublas::matrix< double > * gamma
double convergenceCriterion
bool isInitialized() const
void recalcTotal(vector< double > &tot, ublas::matrix< double > &g, const double *S)
Utility funtion to doing scans for steady states.
double getEigenvalue(const unsigned int i) const
void setStoich(Stoich *stoich, const OdeSystem *ode)
unsigned int nPosEigenvalues_
static const double DELTA
double getTotal(const unsigned int i) const
void setMaxIter(unsigned int value)
ublas::matrix< double > * Nr
unsigned int nNegEigenvalues_
static const Cinfo * steadyStateCinfo
unsigned int getSolutionStatus() const
static const double EPSILON
bool isA(const string &ancestor) const
const Cinfo * cinfo() const
unsigned int getStateType() const
void fitConservationRules(boost::numeric::ublas::matrix< value_type_ > &U, const vector< value_type_ > &eliminatedTotal, vector< value_type_ > &yi)
void updateRates(const double *s, double *yprime) const
unsigned int getNnegEigenvalues() const
static bool isSolutionValid(const vector< double > &x)
void setConvergenceCriterion(double value)
void setVolume(double vol)
Just assigns the volume without any cascading to other values.
void swapRows(ublas::matrix< double > &mat, unsigned int r1, unsigned int r2)
Swap row r1 and r2.
double mtrand(void)
Generate a random double between 0 and 1.
static const Cinfo * initCinfo()
unsigned int getNumCoreRates() const
Number of rate terms for reactions purely on this compartment.
boost::numeric::ublas::matrix< value_type_ > LU_
void eliminateRowsBelow(ublas::matrix< double > &U, int start, int leftCol)
int reorderRows(ublas::matrix< double > &U, int start, int leftCol)
static A get(const ObjId &dest, const string &field)
const vector< RateTerm * > & getRateTerms() const
Returns a reference to the entire rates_ vector.
static const Cinfo * initCinfo()
void classifyState(const double *T)
void updateAllRateTerms(const vector< RateTerm * > &rates, unsigned int numCoreRates)
Updates all the rate constants from the reference rates vector.
boost::numeric::ublas::matrix< value_type_ > Nr_
static void assignY(double *S)
unsigned int solutionStatus_
unsigned int rankUsingBoost(ublas::matrix< double > &U)
void settle(bool forceSetup)
void setTotal(const unsigned int i, double val)