21 #include "../basecode/header.h"
22 #include "../basecode/global.h"
29 #include "../mesh/VoxelJunction.h"
35 #include <gsl/gsl_errno.h>
36 #include <gsl/gsl_vector.h>
37 #include <gsl/gsl_matrix.h>
38 #include <gsl/gsl_blas.h>
39 #include <gsl/gsl_linalg.h>
40 #include <gsl/gsl_multiroots.h>
41 #include <gsl/gsl_sort.h>
42 #include <gsl/gsl_sort_vector.h>
43 #include <gsl/gsl_eigen.h>
44 #include <gsl/gsl_odeiv2.h>
52 int ss_func(
const gsl_vector* x,
void* params, gsl_vector* f );
54 int myGaussianDecomp( gsl_matrix* U );
76 vector< double >
nVec;
115 "Specify the Id of the stoichiometry system to use",
121 "Bool: True if there is a problem with the stoichiometry",
126 "True if the model has been initialized successfully",
131 "Number of iterations done by steady state solver",
141 "Max permissible number of iterations to try before giving up",
146 "convergenceCriterion",
147 "Fractional accuracy required to accept convergence",
153 "Number of variable molecules in reaction system.",
158 "Number of independent molecules in reaction system",
163 "0: stable; 1: unstable; 2: saddle; 3: osc?; 4: one near-zero eigenvalue; 5: other",
169 "Number of negative eigenvalues: indicates type of solution",
175 "Number of positive eigenvalues: indicates type of solution",
180 "0: Good; 1: Failed to find steady states; "
181 "2: Failed to find eigenvalues",
186 "Totals table for conservation laws. The exact mapping of"
187 "this to various sums of molecules is given by the "
188 "conservation matrix, and is currently a bit opaque."
189 "The value of 'total' is set to initial conditions when"
190 "the 'SteadyState::settle' function is called."
191 "Assigning values to the total is a special operation:"
192 "it rescales the concentrations of all the affected"
193 "molecules so that they are at the specified total."
194 "This happens the next time 'settle' is called.",
201 "Eigenvalues computed for steady state",
208 "This function initializes and rebuilds the matrices used "
209 "in the calculation.",
214 "Finds the nearest steady state to the current initial "
215 "conditions. This function rebuilds the entire calculation "
216 "only if the object has not yet been initialized.",
220 "Finds the nearest steady state to the current initial "
221 "conditions. This function rebuilds the entire calculation ",
225 "Utility function to show the matrices derived for the calculations on the reaction system. Shows the Nr, gamma, and total matrices",
228 static DestFinfo randomInit(
"randomInit",
229 "Generate random initial conditions consistent with the mass"
230 "conservation rules. Typically invoked in order to scan"
239 static Finfo * steadyStateFinfos[] =
247 &convergenceCriterion,
265 static string doc[] =
267 "Name",
"SteadyState",
268 "Author",
"Upinder S. Bhalla, 2009, updated 2014, NCBS",
269 "Description",
"SteadyState: works out a steady-state value for "
270 "a reaction system. "
271 "This class uses the GSL multidimensional root finder algorithms "
272 "to find the fixed points closest to the "
273 "current molecular concentrations. "
274 "When it finds the fixed points, it figures out eigenvalues of "
275 "the solution, as a way to help classify the fixed points. "
276 "Note that the method finds unstable as well as stable fixed "
278 "The SteadyState class also provides a utility function "
280 "randomly initialize the concentrations, within the constraints "
281 "of stoichiometry. This is useful if you are trying to find "
282 "the major fixed points of the system. Note that this is "
283 "probabilistic. If a fixed point is in a very narrow range of "
284 "state space the probability of finding it is small and you "
285 "will have to run many iterations with different initial "
286 "conditions to find it.\n "
287 "The numerical calculations used by the SteadyState solver are "
288 "prone to failing on individual calculations. All is not lost, "
289 "because the system reports the solutionStatus. "
290 "It is recommended that you test this field after every "
291 "calculation, so you can simply ignore "
292 "cases where it failed and try again with different starting "
294 "Another rule of thumb is that the SteadyState object is more "
295 "likely to succeed in finding solutions from a new starting point "
296 "if you numerically integrate the chemical system for a short "
297 "time (typically under 1 second) before asking it to find the "
306 sizeof( steadyStateFinfos )/
sizeof(
Finfo *),
308 doc,
sizeof( doc ) /
sizeof(
string )
324 badStoichiometry_( 0 ),
328 convergenceCriterion_( 1e-7 ),
339 nNegEigenvalues_( 0 ),
340 nPosEigenvalues_( 0 ),
342 solutionStatus_( 0 ),
352 gsl_matrix_free(
LU_ );
354 gsl_matrix_free(
Nr_ );
356 gsl_matrix_free(
gamma_ );
373 cout <<
"Error: SteadyState::setStoich: Must be of Stoich class\n";
456 cout <<
"Warning: Convergence criterion " << value <<
457 " too small. Old value " <<
470 cout <<
"Warning: SteadyState::getTotal: index " << i <<
471 " out of range " <<
total_.size() << endl;
483 cout <<
"Warning: SteadyState::setTotal: index " << i <<
484 " out of range " <<
total_.size() << endl;
491 cout <<
"Warning: SteadyState::getEigenvalue: index " << i <<
525 void print_gsl_mat( gsl_matrix* m,
const char*
name )
528 printf(
"%s[%lu, %lu] = \n", name, m->size1, m->size2 );
529 for (i = 0; i < m->size1; i++)
531 for (j = 0; j < m->size2; j++)
533 double x = gsl_matrix_get (m, i, j );
534 if ( fabs( x ) < 1e-9 ) x = 0;
547 cout <<
"SteadyState::showMatrices: Sorry, the system is not yet initialized.\n";
552 for (
int i = 0; i < numConsv; ++i )
556 print_gsl_mat(
gamma_,
"gamma" );
557 print_gsl_mat(
Nr_,
"Nr" );
558 print_gsl_mat(
LU_,
"LU" );
569 gsl_matrix* N = gsl_matrix_calloc (
numVarPools_, nReacs_);
572 gsl_matrix_free(
LU_ );
585 gsl_matrix_set (
LU_, i, i + nReacs_, 1 );
586 unsigned int k = rowStart[i];
588 for (
unsigned int j = 0; j <
nReacs_; ++j )
591 if ( j == colIndex[k] && k < rowStart[i+1] )
596 gsl_matrix_set (N, i, j, x);
597 gsl_matrix_set (
LU_, i, j, x );
600 cout << endl << endl;
602 rank_ = myGaussianDecomp(
LU_ );
604 unsigned int nConsv = numVarPools_ -
rank_;
607 cout <<
"SteadyState::setupSSmatrix(): Number of conserved species == 0. Aborting\n";
613 gsl_matrix_free(
Nr_ );
615 Nr_ = gsl_matrix_calloc ( rank_, nReacs_ );
617 for (
unsigned int i = 0; i <
rank_; i++)
618 for (
unsigned int j = i; j <
nReacs_; j++)
619 gsl_matrix_set (
Nr_, i, j, gsl_matrix_get(
LU_, i, j ) );
623 gsl_matrix_free(
gamma_ );
625 gamma_ = gsl_matrix_calloc (nConsv, numVarPools_ );
630 gsl_matrix_set(
gamma_, i - rank_, j,
631 gsl_matrix_get(
LU_, i, j + nReacs_ ) );
635 total_.assign( nConsv, 0.0 );
647 vector< double > nVec =
653 for (
unsigned int i = 0; i < nConsv; ++i )
655 total_[i] += gsl_matrix_get(
gamma_, i, j ) * nVec[ j ];
660 cout <<
"Error: SteadyState::setupSSmatrix(): unable to get"
661 "pool numbers from ksolve.\n";
665 gsl_matrix_free( N );
669 static double op(
double x )
689 int iterate(
const gsl_multiroot_fsolver_type* st,
struct reac_info *ri,
693 gsl_vector* x = gsl_vector_calloc( ri->
num_mols );
694 gsl_multiroot_fsolver *solver =
695 gsl_multiroot_fsolver_alloc( st, ri->
num_mols );
699 for (
unsigned int i = 0; i < ri->
num_mols; ++i )
700 gsl_vector_set( x, i,
invop( ri->
nVec[i] ) );
702 gsl_multiroot_fsolver_set( solver, &func, x );
708 status = gsl_multiroot_fsolver_iterate( solver );
710 status = gsl_multiroot_test_residual(
713 while (status == GSL_CONTINUE && ri->
nIter < maxIter );
715 gsl_multiroot_fsolver_free( solver );
716 gsl_vector_free( x );
725 gsl_matrix* J = gsl_matrix_calloc ( numVarPools_, numVarPools_ );
746 vector< double > yprime( nVec.size(), 0.0 );
750 double orig = nVec[i];
753 cout <<
"Warning: SteadyState::classifyState: orig=nan\n";
755 gsl_matrix_free ( J );
760 cout <<
"Warning: SteadyState::classifyState: tot=nan\n";
762 gsl_matrix_free ( J );
765 nVec[i] = orig + tot;
773 gsl_matrix_set( J, i, j, yprime[j] );
778 gsl_vector_complex* vec = gsl_vector_complex_alloc( numVarPools_ );
779 gsl_eigen_nonsymm_workspace* workspace =
780 gsl_eigen_nonsymm_alloc( numVarPools_ );
781 int status = gsl_eigen_nonsymm( J, vec, workspace );
784 if ( status != GSL_SUCCESS )
786 cout <<
"Warning: SteadyState::classifyState failed to find eigenvalues. Status = " <<
796 gsl_complex z = gsl_vector_complex_get( vec, i );
797 double r = GSL_REAL( z );
819 gsl_vector_complex_free( vec );
820 gsl_matrix_free ( J );
821 gsl_eigen_nonsymm_free( workspace );
827 for ( vector< double >::const_iterator
828 i = x.begin(); i != x.end(); ++i )
832 cout <<
"Warning: SteadyState iteration gave negative concs\n";
846 gsl_set_error_handler_off();
850 cout <<
"Error: SteadyState object has not been initialized. No calculations done\n";
859 unsigned int nConsv = numVarPools_ -
rank_;
860 double * T = (
double *) calloc( nConsv,
sizeof(
double ) );
882 for ( i = 0; i < nConsv; ++i )
888 for ( i = 0; i < nConsv; ++i )
890 T[i] += gsl_matrix_get(
gamma_, i, j ) * ri.
nVec[ j ];
891 total_.assign( T, T + nConsv );
894 vector< double > repair( numVarPools_, 0.0 );
896 repair[j] = ri.
nVec[j];
898 int status = iterate( gsl_multiroot_fsolver_hybrids, &ri,
maxIter_ );
900 status = iterate( gsl_multiroot_fsolver_dnewton, &ri,
maxIter_ );
901 status_ = string( gsl_strerror( status ) );
907 ksolve,
"nVec", 0, ri.
nVec );
912 cout <<
"Warning: SteadyState iteration failed, status = " <<
916 ri.
nVec[j] = repair[j];
918 LookupField<
unsigned int, vector< double > >::set(
919 ksolve,
"nVec", 0, ri.
nVec );
929 int ss_func(
const gsl_vector* x,
void* params, gsl_vector* f )
935 for (
unsigned int i = 0; i < ri->
num_mols; ++i )
937 double temp =
op( gsl_vector_get( x, i ) );
947 vector< double > vels;
949 assert( vels.size() ==
static_cast< unsigned int >( ri->
num_reacs ) );
953 for (
int i = 0; i < ri->
rank; ++i )
956 for (
int j = i; j < ri->
num_reacs; ++j )
957 temp += gsl_matrix_get( ri->
Nr, i, j ) * vels[j];
958 gsl_vector_set( f, i, temp );
962 for (
int i = 0; i < num_consv; ++i )
964 double dT = - ri->
T[i];
965 for (
unsigned int j = 0; j < ri->
num_mols; ++j )
966 dT += gsl_matrix_get( ri->
gamma, i, j) *
967 op( gsl_vector_get( x, j ) );
969 gsl_vector_set( f, i + ri->
rank, dT );
986 int numMols = U->size1;
987 double pivot = gsl_matrix_get( U, start, leftCol );
989 for (
int i = start + 1; i < numMols; ++i )
991 double factor = gsl_matrix_get( U, i, leftCol );
994 factor = factor / pivot;
995 for (
size_t j = leftCol + 1; j < U->size2; ++j )
997 double x = gsl_matrix_get( U, i, j );
998 double y = gsl_matrix_get( U, start, j );
1002 gsl_matrix_set( U, i, j, x );
1005 gsl_matrix_set( U, i, leftCol, 0.0 );
1017 int reorderRows( gsl_matrix* U,
int start,
int leftCol )
1019 int leftMostRow = start;
1020 int numReacs = U->size2 - U->size1;
1021 int newLeftCol = numReacs;
1022 for (
size_t i = start; i < U->size1; ++i )
1024 for (
int j = leftCol; j < numReacs; ++j )
1028 if ( j < newLeftCol )
1037 if ( leftMostRow != start )
1039 gsl_matrix_swap_rows( U, start, leftMostRow );
1051 int myGaussianDecomp( gsl_matrix* U )
1053 int numMols = U->size1;
1054 int numReacs = U->size2 - numMols;
1059 for ( i = 0; i < numMols - 1; ++i )
1063 if ( leftCol == numReacs )
1073 void recalcTotal( vector< double >& tot, gsl_matrix* g,
const double* S )
1075 assert( g->size1 == tot.size() );
1076 for (
unsigned int i = 0; i < g->size1; ++i )
1079 for (
unsigned int j = 0; j < g->size2; ++j )
1080 t += gsl_matrix_get( g, i, j ) * S[j];
1084 #endif // end of long section of functions using GSL
1088 for ( vector< double >::const_iterator
1089 i = y.begin(); i != y.end(); ++i )
1105 vector< double > nVec =
1108 int numConsv =
total_.size();
1113 gsl_matrix* U = gsl_matrix_calloc ( numConsv, numVarPools_ + numConsv );
1114 for (
int i = 0; i < numConsv; ++i )
1118 gsl_matrix_set( U, i, j, gsl_matrix_get(
gamma_, i, j ) );
1120 gsl_matrix_set( U, i, numVarPools_,
total_[i] );
1123 int rank = myGaussianDecomp( U );
1124 assert( rank = numConsv );
1126 vector< double > eliminatedTotal( numConsv, 0.0 );
1127 for (
int i = 0; i < numConsv; ++i )
1129 eliminatedTotal[i] = gsl_matrix_get( U, i, numVarPools_ );
1133 vector< double > y( numVarPools_, 0.0 );
1141 for (
int i = 0; i < numConsv; ++i )
1146 tot += y[j] * gsl_matrix_get(
gamma_, i, j );
1159 ksolve,
"nVec", 0, nVec );
1169 gsl_matrix* U,
const vector< double >& eliminatedTotal,
1173 int numConsv =
total_.size();
1175 for (
int i = numConsv - 1; i >= 0; --i )
1179 double g = gsl_matrix_get( U, i, j );
1184 for (
int k = j; k < lastJ; ++k )
1188 ytot += y[k] * gsl_matrix_get( U, i, k );
1190 assert( fabs( ytot ) >
EPSILON );
1191 double lastYtot = 0.0;
1194 lastYtot += y[k] * gsl_matrix_get( U, i, k );
1196 double scale = ( eliminatedTotal[i] - lastYtot ) / ytot;
1197 for (
int k = j; k < lastJ; ++k )
void randomizeInitialCondition(const Eref &e)
unsigned int getMaxIter() const
Id getCompartment() const
unsigned int getNposEigenvalues() const
boost::numeric::ublas::matrix< value_type_ > gamma_
static double op(double x)
static A get(const ObjId &dest, const string &field, L index)
Element * element() const
Synonym for Id::operator()()
unsigned int getNiter() const
unsigned int getNumVarPools() const
double getConvergenceCriterion() const
unsigned int getRank() const
vector< double > eigenvalues_
double convergenceCriterion_
bool badStoichiometry() const
ublas::matrix< double > * gamma
double convergenceCriterion
bool isInitialized() const
static bool isSolutionPositive(const vector< double > &x)
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 Cinfo * steadyStateCinfo
static const double DELTA
double getTotal(const unsigned int i) const
void setMaxIter(unsigned int value)
ublas::matrix< double > * Nr
unsigned int nNegEigenvalues_
static bool checkAboveZero(const vector< double > &y)
unsigned int getSolutionStatus() const
static const double EPSILON
bool isA(const string &ancestor) const
const Cinfo * cinfo() const
unsigned int getStateType() const
static double invop(double x)
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
void setConvergenceCriterion(double value)
void setVolume(double vol)
Just assigns the volume without any cascading to other values.
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 updateReacVelocities(const double *s, vector< double > &v) const
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)
int ss_func(const gsl_vector *x, void *params, gsl_vector *f)
unsigned int solutionStatus_
void settle(bool forceSetup)
void setTotal(const unsigned int i, double val)