MOOSE - Multiscale Object Oriented Simulation Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
SteadyStateGsl.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 ** This program is part of 'MOOSE', the
3 ** Messaging Object Oriented Simulation Environment.
4 ** Copyright (C) 2003-2007 Upinder S. Bhalla. and NCBS
5 ** It is made available under the terms of the
6 ** GNU Lesser General Public License version 2.1
7 ** See the file COPYING.LIB for the full notice.
8 **********************************************************************/
9 
21 #include "../basecode/header.h"
22 #include "../basecode/global.h"
23 
24 #include "SparseMatrix.h"
25 #include "KinSparseMatrix.h"
26 #include "RateTerm.h"
27 #include "FuncTerm.h"
28 #include "VoxelPoolsBase.h"
29 #include "../mesh/VoxelJunction.h"
30 #include "XferInfo.h"
31 #include "ZombiePoolInterface.h"
32 #include "Stoich.h"
33 
34 #ifdef USE_GSL
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>
45 #endif
46 
47 #include "VoxelPoolsBase.h"
48 #include "OdeSystem.h"
49 #include "VoxelPools.h"
50 #include "SteadyStateGsl.h"
51 
52 int ss_func( const gsl_vector* x, void* params, gsl_vector* f );
53 #ifdef USE_GSL
54 int myGaussianDecomp( gsl_matrix* U );
55 #endif
56 
57 // Limit below which small numbers are treated as zero.
58 const double SteadyState::EPSILON = 1e-9;
59 
60 // This fraction of molecules is used as an increment in computing the
61 // Jacobian
62 const double SteadyState::DELTA = 1e-6;
66 struct reac_info
67 {
68  int rank;
69  int num_reacs;
70  size_t num_mols;
71  int nIter;
72  double convergenceCriterion;
73 
74  double* T;
76  vector< double > nVec;
77 
78 #ifdef USE_GSL
79  gsl_matrix* Nr;
80  gsl_matrix* gamma;
81 #endif
82 };
83 
85 {
110  // Field definitions
113  static ValueFinfo< SteadyState, Id > stoich(
114  "stoich",
115  "Specify the Id of the stoichiometry system to use",
118  );
120  "badStoichiometry",
121  "Bool: True if there is a problem with the stoichiometry",
123  );
125  "isInitialized",
126  "True if the model has been initialized successfully",
128  );
130  "nIter",
131  "Number of iterations done by steady state solver",
133  );
135  "status",
136  "Status of solver",
138  );
140  "maxIter",
141  "Max permissible number of iterations to try before giving up",
144  );
145  static ValueFinfo< SteadyState, double> convergenceCriterion(
146  "convergenceCriterion",
147  "Fractional accuracy required to accept convergence",
150  );
152  "numVarPools",
153  "Number of variable molecules in reaction system.",
155  );
157  "rank",
158  "Number of independent molecules in reaction system",
160  );
162  "stateType",
163  "0: stable; 1: unstable; 2: saddle; 3: osc?; 4: one near-zero eigenvalue; 5: other",
165  );
167  nNegEigenvalues (
168  "nNegEigenvalues",
169  "Number of negative eigenvalues: indicates type of solution",
171  );
173  nPosEigenvalues(
174  "nPosEigenvalues",
175  "Number of positive eigenvalues: indicates type of solution",
177  );
179  "solutionStatus",
180  "0: Good; 1: Failed to find steady states; "
181  "2: Failed to find eigenvalues",
183  );
185  "total",
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.",
197  );
199  SteadyState, unsigned int, double > eigenvalues(
200  "eigenvalues",
201  "Eigenvalues computed for steady state",
203  );
205  // MsgDest definitions
207  static DestFinfo setupMatrix( "setupMatrix",
208  "This function initializes and rebuilds the matrices used "
209  "in the calculation.",
211  );
212 
213  static DestFinfo settle( "settle",
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.",
218  );
219  static DestFinfo resettle( "resettle",
220  "Finds the nearest steady state to the current initial "
221  "conditions. This function rebuilds the entire calculation ",
223  );
224  static DestFinfo showMatrices( "showMatrices",
225  "Utility function to show the matrices derived for the calculations on the reaction system. Shows the Nr, gamma, and total matrices",
227  );
228  static DestFinfo randomInit( "randomInit",
229  "Generate random initial conditions consistent with the mass"
230  "conservation rules. Typically invoked in order to scan"
231  "states",
234  );
236  // Shared definitions
238 
239  static Finfo * steadyStateFinfos[] =
240  {
241  &stoich, // Value
242  &badStoichiometry, // ReadOnlyValue
243  &isInitialized, // ReadOnlyValue
244  &nIter, // ReadOnlyValue
245  &status, // ReadOnlyValue
246  &maxIter, // Value
247  &convergenceCriterion, // ReadOnlyValue
248  &numVarPools, // ReadOnlyValue
249  &rank, // ReadOnlyValue
250  &stateType, // ReadOnlyValue
251  &nNegEigenvalues, // ReadOnlyValue
252  &nPosEigenvalues, // ReadOnlyValue
253  &solutionStatus, // ReadOnlyValue
254  &total, // LookupValue
255  &eigenvalues, // ReadOnlyLookupValue
256  &setupMatrix, // DestFinfo
257  &settle, // DestFinfo
258  &resettle, // DestFinfo
259  &showMatrices, // DestFinfo
260  &randomInit, // DestFinfo
261 
262 
263  };
264 
265  static string doc[] =
266  {
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 "
277  "points.\n "
278  "The SteadyState class also provides a utility function "
279  "*randomInit()* to "
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 "
293  "conditions.\n "
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 "
298  "fixed point. "
299  };
300 
301  static Dinfo< SteadyState > dinfo;
302  static Cinfo steadyStateCinfo(
303  "SteadyState",
305  steadyStateFinfos,
306  sizeof( steadyStateFinfos )/sizeof(Finfo *),
307  &dinfo,
308  doc, sizeof( doc ) / sizeof( string )
309  );
310 
311  return &steadyStateCinfo;
312 }
313 
315 
317 // Class function definitions
319 
321  :
322  nIter_( 0 ),
323  maxIter_( 100 ),
324  badStoichiometry_( 0 ),
325  status_( "OK" ),
326  isInitialized_( 0 ),
327  isSetup_( 0 ),
328  convergenceCriterion_( 1e-7 ),
329 #ifdef USE_GSL
330  LU_( 0 ),
331  Nr_( 0 ),
332  gamma_( 0 ),
333 #endif
334  stoich_(),
335  numVarPools_( 0 ),
336  nReacs_( 0 ),
337  rank_( 0 ),
338  reassignTotal_( 0 ),
339  nNegEigenvalues_( 0 ),
340  nPosEigenvalues_( 0 ),
341  stateType_( 0 ),
342  solutionStatus_( 0 ),
343  numFailed_( 0 )
344 {
345  ;
346 }
347 
349 {
350 #ifdef USE_GSL
351  if ( LU_ != 0 )
352  gsl_matrix_free( LU_ );
353  if ( Nr_ != 0 )
354  gsl_matrix_free( Nr_ );
355  if ( gamma_ != 0 )
356  gsl_matrix_free( gamma_ );
357 #endif
358 }
359 
361 // Field function definitions
363 
365 {
366  return stoich_;
367 }
368 
370 {
371  if ( !value.element()->cinfo()->isA( "Stoich" ) )
372  {
373  cout << "Error: SteadyState::setStoich: Must be of Stoich class\n";
374  return;
375  }
376 
377  stoich_ = value;
378  Stoich* stoichPtr = reinterpret_cast< Stoich* >( value.eref().data());
379  numVarPools_ = Field< unsigned int >::get( stoich_, "numVarPools" );
380  nReacs_ = Field< unsigned int >::get( stoich_, "numRates" );
381  setupSSmatrix();
383  stoichPtr->getCompartment(), "oneVoxelVolume", 0 );
384  pool_.setVolume( vol );
385  pool_.setStoich( stoichPtr, 0 );
386  pool_.updateAllRateTerms( stoichPtr->getRateTerms(),
387  stoichPtr->getNumCoreRates() );
388  isInitialized_ = 1;
389 }
390 
392 {
393  return badStoichiometry_;
394 }
395 
396 bool SteadyState::isInitialized() const
397 {
398  return isInitialized_;
399 }
400 
401 unsigned int SteadyState::getNiter() const
402 {
403  return nIter_;
404 }
405 
406 string SteadyState::getStatus() const
407 {
408  return status_;
409 }
410 
411 unsigned int SteadyState::getMaxIter() const
412 {
413  return maxIter_;
414 }
415 
416 void SteadyState::setMaxIter( unsigned int value )
417 {
418  maxIter_ = value;
419 }
420 
421 unsigned int SteadyState::getRank() const
422 {
423  return rank_;
424 }
425 
426 unsigned int SteadyState::getNumVarPools() const
427 {
428  return numVarPools_;
429 }
430 
431 unsigned int SteadyState::getStateType() const
432 {
433  return stateType_;
434 }
435 
436 unsigned int SteadyState::getNnegEigenvalues() const
437 {
438  return nNegEigenvalues_;
439 }
440 
441 unsigned int SteadyState::getNposEigenvalues() const
442 {
443  return nPosEigenvalues_;
444 }
445 
446 unsigned int SteadyState::getSolutionStatus() const
447 {
448  return solutionStatus_;
449 }
450 
451 void SteadyState::setConvergenceCriterion( double value )
452 {
453  if ( value > 1e-10 )
455  else
456  cout << "Warning: Convergence criterion " << value <<
457  " too small. Old value " <<
458  convergenceCriterion_ << " retained\n";
459 }
460 
462 {
463  return convergenceCriterion_;
464 }
465 
466 double SteadyState::getTotal( const unsigned int i ) const
467 {
468  if ( i < total_.size() )
469  return total_[i];
470  cout << "Warning: SteadyState::getTotal: index " << i <<
471  " out of range " << total_.size() << endl;
472  return 0.0;
473 }
474 
475 void SteadyState::setTotal( const unsigned int i, double val )
476 {
477  if ( i < total_.size() )
478  {
479  total_[i] = val;
480  reassignTotal_ = 1;
481  return;
482  }
483  cout << "Warning: SteadyState::setTotal: index " << i <<
484  " out of range " << total_.size() << endl;
485 }
486 
487 double SteadyState::getEigenvalue( const unsigned int i ) const
488 {
489  if ( i < eigenvalues_.size() )
490  return eigenvalues_[i];
491  cout << "Warning: SteadyState::getEigenvalue: index " << i <<
492  " out of range " << eigenvalues_.size() << endl;
493  return 0.0;
494 }
495 
497 // Dest function definitions
499 
500 // Static func
502 {
503  setupSSmatrix();
504 }
506 {
507  settle( 0 );
508 }
509 
511 {
512  settle( 1 );
513 }
514 
515 // Dummy function
516 void SteadyState::assignY( double* S )
517 {
518 }
519 
521 // GSL interface stuff
523 
524 #ifdef USE_GSL
525 void print_gsl_mat( gsl_matrix* m, const char* name )
526 {
527  size_t i, j;
528  printf( "%s[%lu, %lu] = \n", name, m->size1, m->size2 );
529  for (i = 0; i < m->size1; i++)
530  {
531  for (j = 0; j < m->size2; j++)
532  {
533  double x = gsl_matrix_get (m, i, j );
534  if ( fabs( x ) < 1e-9 ) x = 0;
535  printf( "%6g", x );
536  }
537 
538  printf( "\n");
539  }
540 }
541 #endif
542 
544 {
545  if ( !isInitialized_ )
546  {
547  cout << "SteadyState::showMatrices: Sorry, the system is not yet initialized.\n";
548  return;
549  }
550  int numConsv = numVarPools_ - rank_;
551  cout << "Totals: ";
552  for ( int i = 0; i < numConsv; ++i )
553  cout << total_[i] << " ";
554  cout << endl;
555 #ifdef USE_GSL
556  print_gsl_mat( gamma_, "gamma" );
557  print_gsl_mat( Nr_, "Nr" );
558  print_gsl_mat( LU_, "LU" );
559 #endif
560 }
561 
563 {
564 #ifdef USE_GSL
565  if ( numVarPools_ == 0 || nReacs_ == 0 )
566  return;
567 
568  int nTot = numVarPools_ + nReacs_;
569  gsl_matrix* N = gsl_matrix_calloc (numVarPools_, nReacs_);
570  if ( LU_ ) // Clear out old one.
571  {
572  gsl_matrix_free( LU_ );
573  }
574  LU_ = gsl_matrix_calloc (numVarPools_, nTot);
575  vector< int > entry = Field< vector< int > >::get(
576  stoich_, "matrixEntry" );
577  vector< unsigned int > colIndex = Field< vector< unsigned int > >::get(
578  stoich_, "columnIndex" );
579  vector< unsigned int > rowStart = Field< vector< unsigned int > >::get(
580  stoich_, "rowStart" );
581 
582  // cout << endl << endl;
583  for ( unsigned int i = 0; i < numVarPools_; ++i )
584  {
585  gsl_matrix_set (LU_, i, i + nReacs_, 1 );
586  unsigned int k = rowStart[i];
587  // cout << endl << i << ": ";
588  for ( unsigned int j = 0; j < nReacs_; ++j )
589  {
590  double x = 0;
591  if ( j == colIndex[k] && k < rowStart[i+1] )
592  {
593  x = entry[k++];
594  }
595  // cout << " " << x;
596  gsl_matrix_set (N, i, j, x);
597  gsl_matrix_set (LU_, i, j, x );
598  }
599  }
600  cout << endl << endl;
601 
602  rank_ = myGaussianDecomp( LU_ );
603 
604  unsigned int nConsv = numVarPools_ - rank_;
605  if ( nConsv == 0 )
606  {
607  cout << "SteadyState::setupSSmatrix(): Number of conserved species == 0. Aborting\n";
608  return;
609  }
610 
611  if ( Nr_ ) // Clear out old one.
612  {
613  gsl_matrix_free( Nr_ );
614  }
615  Nr_ = gsl_matrix_calloc ( rank_, nReacs_ );
616  // Fill up Nr.
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 ) );
620 
621  if ( gamma_ ) // Clear out old one.
622  {
623  gsl_matrix_free( gamma_ );
624  }
625  gamma_ = gsl_matrix_calloc (nConsv, numVarPools_ );
626 
627  // Fill up gamma
628  for ( unsigned int i = rank_; i < numVarPools_; ++i )
629  for ( unsigned int j = 0; j < numVarPools_; ++j )
630  gsl_matrix_set( gamma_, i - rank_, j,
631  gsl_matrix_get( LU_, i, j + nReacs_ ) );
632 
633  // Fill up boundary condition values
634  total_.resize( nConsv );
635  total_.assign( nConsv, 0.0 );
636 
637  /*
638  cout << "S = (";
639  for ( unsigned int j = 0; j < numVarPools_; ++j )
640  cout << s_->S()[ j ] << ", ";
641  cout << "), Sinit = ( ";
642  for ( unsigned int j = 0; j < numVarPools_; ++j )
643  cout << s_->Sinit()[ j ] << ", ";
644  cout << ")\n";
645  */
646  Id ksolve = Field< Id >::get( stoich_, "ksolve" );
647  vector< double > nVec =
649  ksolve,"nVec", 0 );
650 
651  if ( nVec.size() >= numVarPools_ )
652  {
653  for ( unsigned int i = 0; i < nConsv; ++i )
654  for ( unsigned int j = 0; j < numVarPools_; ++j )
655  total_[i] += gsl_matrix_get( gamma_, i, j ) * nVec[ j ];
656  isSetup_ = 1;
657  }
658  else
659  {
660  cout << "Error: SteadyState::setupSSmatrix(): unable to get"
661  "pool numbers from ksolve.\n";
662  isSetup_ = 0;
663  }
664 
665  gsl_matrix_free( N );
666 #endif
667 }
668 
669 static double op( double x )
670 {
671  return x * x;
672 }
673 
674 static double invop( double x )
675 {
676  if ( x > 0.0 )
677  return sqrt( x );
678  return 0.0;
679 }
680 
681 
688 #ifdef USE_GSL
689 int iterate( const gsl_multiroot_fsolver_type* st, struct reac_info *ri,
690  int maxIter )
691 {
692  int status = 0;
693  gsl_vector* x = gsl_vector_calloc( ri->num_mols );
694  gsl_multiroot_fsolver *solver =
695  gsl_multiroot_fsolver_alloc( st, ri->num_mols );
696  gsl_multiroot_function func = {&ss_func, ri->num_mols, ri};
697 
698  // This gives the starting point for finding the solution
699  for ( unsigned int i = 0; i < ri->num_mols; ++i )
700  gsl_vector_set( x, i, invop( ri->nVec[i] ) );
701 
702  gsl_multiroot_fsolver_set( solver, &func, x );
703 
704  ri->nIter = 0;
705  do
706  {
707  ri->nIter++;
708  status = gsl_multiroot_fsolver_iterate( solver );
709  if (status ) break;
710  status = gsl_multiroot_test_residual(
711  solver->f, ri->convergenceCriterion);
712  }
713  while (status == GSL_CONTINUE && ri->nIter < maxIter );
714 
715  gsl_multiroot_fsolver_free( solver );
716  gsl_vector_free( x );
717  return status;
718 }
719 #endif
720 
721 void SteadyState::classifyState( const double* T )
722 {
723 #ifdef USE_GSL
724  // unsigned int nConsv = numVarPools_ - rank_;
725  gsl_matrix* J = gsl_matrix_calloc ( numVarPools_, numVarPools_ );
726  // double* yprime = new double[ numVarPools_ ];
727  // vector< double > yprime( numVarPools_, 0.0 );
728  // Generate an approximation to the Jacobean by generating small
729  // increments to each of the molecules in the steady state, one
730  // at a time, and putting the resultant rate vector into a column
731  // of the J matrix.
732  // This needs a bit of heuristic to decide what is a 'small' increment.
733  // Use the CoInits for this. Stoichiometry shouldn't matter too much.
734  // I used the totals from consv rules earlier, but that can have
735  // negative values.
736  double tot = 0.0;
737  Stoich* s = reinterpret_cast< Stoich* >( stoich_.eref().data() );
738  vector< double > nVec = LookupField< unsigned int, vector< double > >::get(
739  s->getKsolve(), "nVec", 0 );
740  for ( unsigned int i = 0; i < numVarPools_; ++i )
741  {
742  tot += nVec[i];
743  }
744  tot *= DELTA;
745 
746  vector< double > yprime( nVec.size(), 0.0 );
747  // Fill up Jacobian
748  for ( unsigned int i = 0; i < numVarPools_; ++i )
749  {
750  double orig = nVec[i];
751  if ( isNaN( orig ) )
752  {
753  cout << "Warning: SteadyState::classifyState: orig=nan\n";
754  solutionStatus_ = 2; // Steady state OK, eig failed
755  gsl_matrix_free ( J );
756  return;
757  }
758  if ( isNaN( tot ) )
759  {
760  cout << "Warning: SteadyState::classifyState: tot=nan\n";
761  solutionStatus_ = 2; // Steady state OK, eig failed
762  gsl_matrix_free ( J );
763  return;
764  }
765  nVec[i] = orig + tot;
766 
767  pool_.updateRates( &nVec[0], &yprime[0] );
768  nVec[i] = orig;
769 
770  // Assign the rates for each mol.
771  for ( unsigned int j = 0; j < numVarPools_; ++j )
772  {
773  gsl_matrix_set( J, i, j, yprime[j] );
774  }
775  }
776 
777  // Jacobian is now ready. Find eigenvalues.
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 );
782  eigenvalues_.clear();
783  eigenvalues_.resize( numVarPools_, 0.0 );
784  if ( status != GSL_SUCCESS )
785  {
786  cout << "Warning: SteadyState::classifyState failed to find eigenvalues. Status = " <<
787  status << endl;
788  solutionStatus_ = 2; // Steady state OK, eig classification failed
789  }
790  else // Eigenvalues are ready. Classify state.
791  {
792  nNegEigenvalues_ = 0;
793  nPosEigenvalues_ = 0;
794  for ( unsigned int i = 0; i < numVarPools_; ++i )
795  {
796  gsl_complex z = gsl_vector_complex_get( vec, i );
797  double r = GSL_REAL( z );
798  nNegEigenvalues_ += ( r < -EPSILON );
799  nPosEigenvalues_ += ( r > EPSILON );
800  eigenvalues_[i] = r;
801  // We have a problem here because numVarPools_ usually > rank
802  // This means we have several zero eigenvalues.
803  }
804 
805  if ( nNegEigenvalues_ == rank_ )
806  stateType_ = 0; // Stable
807  else if ( nPosEigenvalues_ == rank_ ) // Never see it.
808  stateType_ = 1; // Unstable
809  else if (nPosEigenvalues_ == 1)
810  stateType_ = 2; // Saddle
811  else if ( nPosEigenvalues_ >= 2 )
812  stateType_ = 3; // putative oscillatory
813  else if ( nNegEigenvalues_ == ( rank_ - 1) && nPosEigenvalues_ == 0 )
814  stateType_ = 4; // one zero or unclassified eigenvalue. Messy.
815  else
816  stateType_ = 5; // Other
817  }
818 
819  gsl_vector_complex_free( vec );
820  gsl_matrix_free ( J );
821  gsl_eigen_nonsymm_free( workspace );
822 #endif
823 }
824 
825 static bool isSolutionPositive( const vector< double >& x )
826 {
827  for ( vector< double >::const_iterator
828  i = x.begin(); i != x.end(); ++i )
829  {
830  if ( *i < 0.0 )
831  {
832  cout << "Warning: SteadyState iteration gave negative concs\n";
833  return false;
834  }
835  }
836  return true;
837 }
838 
843 void SteadyState::settle( bool forceSetup )
844 {
845 #ifdef USE_GSL
846  gsl_set_error_handler_off();
847 
848  if ( !isInitialized_ )
849  {
850  cout << "Error: SteadyState object has not been initialized. No calculations done\n";
851  return;
852  }
853  if ( forceSetup || isSetup_ == 0 )
854  {
855  setupSSmatrix();
856  }
857 
858  // Setting up matrices and vectors for the calculation.
859  unsigned int nConsv = numVarPools_ - rank_;
860  double * T = (double *) calloc( nConsv, sizeof( double ) );
861 
862  unsigned int i, j;
863 
864 
865  Id ksolve = Field< Id >::get( stoich_, "ksolve" );
866  struct reac_info ri;
867  ri.rank = rank_;
868  ri.num_reacs = nReacs_;
869  ri.num_mols = numVarPools_;
870  ri.T = T;
871  ri.Nr = Nr_;
872  ri.gamma = gamma_;
873  ri.pool = &pool_;
874  ri.nVec =
876  ksolve,"nVec", 0 );
878 
879  // Fill up boundary condition values
880  if ( reassignTotal_ ) // The user has defined new conservation values.
881  {
882  for ( i = 0; i < nConsv; ++i )
883  T[i] = total_[i];
884  reassignTotal_ = 0;
885  }
886  else
887  {
888  for ( i = 0; i < nConsv; ++i )
889  for ( j = 0; j < numVarPools_; ++j )
890  T[i] += gsl_matrix_get( gamma_, i, j ) * ri.nVec[ j ];
891  total_.assign( T, T + nConsv );
892  }
893 
894  vector< double > repair( numVarPools_, 0.0 );
895  for ( unsigned int j = 0; j < numVarPools_; ++j )
896  repair[j] = ri.nVec[j];
897 
898  int status = iterate( gsl_multiroot_fsolver_hybrids, &ri, maxIter_ );
899  if ( status ) // It failed. Fall back with the Newton method
900  status = iterate( gsl_multiroot_fsolver_dnewton, &ri, maxIter_ );
901  status_ = string( gsl_strerror( status ) );
902  nIter_ = ri.nIter;
903  if ( status == GSL_SUCCESS && isSolutionPositive( ri.nVec ) )
904  {
905  solutionStatus_ = 0; // Good solution
907  ksolve,"nVec", 0, ri.nVec );
908  classifyState( T );
909  }
910  else
911  {
912  cout << "Warning: SteadyState iteration failed, status = " <<
913  status_ << ", nIter = " << nIter_ << endl;
914  // Repair the mess
915  for ( unsigned int j = 0; j < numVarPools_; ++j )
916  ri.nVec[j] = repair[j];
917  solutionStatus_ = 1; // Steady state failed.
918  LookupField< unsigned int, vector< double > >::set(
919  ksolve,"nVec", 0, ri.nVec );
920  }
921 
922  // Clean up.
923  free( T );
924 #endif
925 }
926 
927 // Long section here of functions using GSL
928 #ifdef USE_GSL
929 int ss_func( const gsl_vector* x, void* params, gsl_vector* f )
930 {
931  struct reac_info* ri = (struct reac_info *)params;
932  // Stoich* s = reinterpret_cast< Stoich* >( ri->stoich.eref().data() );
933  int num_consv = ri->num_mols - ri->rank;
934 
935  for ( unsigned int i = 0; i < ri->num_mols; ++i )
936  {
937  double temp = op( gsl_vector_get( x, i ) );
938  if ( isNaN( temp ) || isInfinity( temp ) )
939  {
940  return GSL_ERANGE;
941  }
942  else
943  {
944  ri->nVec[i] = temp;
945  }
946  }
947  vector< double > vels;
948  ri->pool->updateReacVelocities( &ri->nVec[0], vels );
949  assert( vels.size() == static_cast< unsigned int >( ri->num_reacs ) );
950 
951  // y = Nr . v
952  // Note that Nr is row-echelon: diagonal and above.
953  for ( int i = 0; i < ri->rank; ++i )
954  {
955  double temp = 0;
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 );
959  }
960 
961  // dT = gamma.S - T
962  for ( int i = 0; i < num_consv; ++i )
963  {
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 ) );
968 
969  gsl_vector_set( f, i + ri->rank, dT );
970  }
971 
972  return GSL_SUCCESS;
973 }
974 
984 void eliminateRowsBelow( gsl_matrix* U, int start, int leftCol )
985 {
986  int numMols = U->size1;
987  double pivot = gsl_matrix_get( U, start, leftCol );
988  assert( fabs( pivot ) > SteadyState::EPSILON );
989  for ( int i = start + 1; i < numMols; ++i )
990  {
991  double factor = gsl_matrix_get( U, i, leftCol );
992  if ( fabs ( factor ) > SteadyState::EPSILON )
993  {
994  factor = factor / pivot;
995  for ( size_t j = leftCol + 1; j < U->size2; ++j )
996  {
997  double x = gsl_matrix_get( U, i, j );
998  double y = gsl_matrix_get( U, start, j );
999  x -= y * factor;
1000  if ( fabs( x ) < SteadyState::EPSILON )
1001  x = 0.0;
1002  gsl_matrix_set( U, i, j, x );
1003  }
1004  }
1005  gsl_matrix_set( U, i, leftCol, 0.0 ); // Cleaning up.
1006  }
1007 }
1008 
1017 int reorderRows( gsl_matrix* U, int start, int leftCol )
1018 {
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 )
1023  {
1024  for ( int j = leftCol; j < numReacs; ++j )
1025  {
1026  if ( fabs( gsl_matrix_get( U, i, j ) ) > SteadyState::EPSILON )
1027  {
1028  if ( j < newLeftCol )
1029  {
1030  newLeftCol = j;
1031  leftMostRow = i;
1032  }
1033  break;
1034  }
1035  }
1036  }
1037  if ( leftMostRow != start ) // swap them.
1038  {
1039  gsl_matrix_swap_rows( U, start, leftMostRow );
1040  }
1041  return newLeftCol;
1042 }
1043 
1051 int myGaussianDecomp( gsl_matrix* U )
1052 {
1053  int numMols = U->size1;
1054  int numReacs = U->size2 - numMols;
1055  int i;
1056  // Start out with a nonzero entry at 0,0
1057  int leftCol = reorderRows( U, 0, 0 );
1058 
1059  for ( i = 0; i < numMols - 1; ++i )
1060  {
1061  eliminateRowsBelow( U, i, leftCol );
1062  leftCol = reorderRows( U, i + 1, leftCol );
1063  if ( leftCol == numReacs )
1064  break;
1065  }
1066  return i + 1;
1067 }
1068 
1070 // Utility functions for doing scans for steady states
1072 
1073 void recalcTotal( vector< double >& tot, gsl_matrix* g, const double* S )
1074 {
1075  assert( g->size1 == tot.size() );
1076  for ( unsigned int i = 0; i < g->size1; ++i )
1077  {
1078  double t = 0.0;
1079  for ( unsigned int j = 0; j < g->size2; ++j )
1080  t += gsl_matrix_get( g, i, j ) * S[j];
1081  tot[ i ] = t;
1082  }
1083 }
1084 #endif // end of long section of functions using GSL
1085 
1086 static bool checkAboveZero( const vector< double >& y )
1087 {
1088  for ( vector< double >::const_iterator
1089  i = y.begin(); i != y.end(); ++i )
1090  {
1091  if ( *i < 0.0 )
1092  return false;
1093  }
1094  return true;
1095 }
1096 
1102 {
1103 #ifdef USE_GSL
1104  Id ksolve = Field< Id >::get( stoich_, "ksolve" );
1105  vector< double > nVec =
1107  ksolve,"nVec", 0 );
1108  int numConsv = total_.size();
1109  recalcTotal( total_, gamma_, &nVec[0] );
1110  // The reorderRows function likes to have an I matrix at the end of
1111  // numVarPools_, so we provide space for it, although only its first
1112  // column is used for the total vector.
1113  gsl_matrix* U = gsl_matrix_calloc ( numConsv, numVarPools_ + numConsv );
1114  for ( int i = 0; i < numConsv; ++i )
1115  {
1116  for ( unsigned int j = 0; j < numVarPools_; ++j )
1117  {
1118  gsl_matrix_set( U, i, j, gsl_matrix_get( gamma_, i, j ) );
1119  }
1120  gsl_matrix_set( U, i, numVarPools_, total_[i] );
1121  }
1122  // Do the forward elimination
1123  int rank = myGaussianDecomp( U );
1124  assert( rank = numConsv );
1125 
1126  vector< double > eliminatedTotal( numConsv, 0.0 );
1127  for ( int i = 0; i < numConsv; ++i )
1128  {
1129  eliminatedTotal[i] = gsl_matrix_get( U, i, numVarPools_ );
1130  }
1131 
1132  // Put Find a vector Y that fits the consv rules.
1133  vector< double > y( numVarPools_, 0.0 );
1134  do
1135  {
1136  fitConservationRules( U, eliminatedTotal, y );
1137  }
1138  while ( !checkAboveZero( y ) );
1139 
1140  // Sanity check. Try the new vector with the old gamma and tots
1141  for ( int i = 0; i < numConsv; ++i )
1142  {
1143  double tot = 0.0;
1144  for ( unsigned int j = 0; j < numVarPools_; ++j )
1145  {
1146  tot += y[j] * gsl_matrix_get( gamma_, i, j );
1147  }
1148  assert( fabs( tot - total_[i] ) / tot < EPSILON );
1149  }
1150 
1151  // Put the new values into S.
1152  // cout << endl;
1153  for ( unsigned int j = 0; j < numVarPools_; ++j )
1154  {
1155  nVec[j] = y[j];
1156  // cout << y[j] << " ";
1157  }
1159  ksolve,"nVec", 0, nVec );
1160 #endif
1161 }
1162 
1167 #ifdef USE_GSL
1169  gsl_matrix* U, const vector< double >& eliminatedTotal,
1170  vector< double >&y
1171 )
1172 {
1173  int numConsv = total_.size();
1174  int lastJ = numVarPools_;
1175  for ( int i = numConsv - 1; i >= 0; --i )
1176  {
1177  for ( unsigned int j = 0; j < numVarPools_; ++j )
1178  {
1179  double g = gsl_matrix_get( U, i, j );
1180  if ( fabs( g ) > EPSILON )
1181  {
1182  // double ytot = calcTot( g, i, j, lastJ );
1183  double ytot = 0.0;
1184  for ( int k = j; k < lastJ; ++k )
1185  {
1186  // Use global RNG.
1187  y[k] = moose::mtrand();
1188  ytot += y[k] * gsl_matrix_get( U, i, k );
1189  }
1190  assert( fabs( ytot ) > EPSILON );
1191  double lastYtot = 0.0;
1192  for ( unsigned int k = lastJ; k < numVarPools_; ++k )
1193  {
1194  lastYtot += y[k] * gsl_matrix_get( U, i, k );
1195  }
1196  double scale = ( eliminatedTotal[i] - lastYtot ) / ytot;
1197  for ( int k = j; k < lastJ; ++k )
1198  {
1199  y[k] *= scale;
1200  }
1201  lastJ = j;
1202  break;
1203  }
1204  }
1205  }
1206 }
1207 
1208 #endif
void randomizeInitialCondition(const Eref &e)
char * data() const
Definition: Eref.cpp:41
uint32_t value
Definition: moosemodule.h:42
unsigned int getMaxIter() const
Id getCompartment() const
Definition: Stoich.cpp:505
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)
Definition: SetGet.h:532
Element * element() const
Synonym for Id::operator()()
Definition: Id.cpp:113
unsigned int getNiter() const
unsigned int getNumVarPools() const
Definition: Dinfo.h:60
Definition: SetGet.h:236
Id getKsolve() const
Definition: Stoich.cpp:446
double getConvergenceCriterion() const
unsigned int getRank() const
vector< double > eigenvalues_
double convergenceCriterion_
bool isNaN(T value)
Definition: numutil.h:46
Eref eref() const
Definition: Id.cpp:125
bool badStoichiometry() const
unsigned int rank_
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)
Definition: VoxelPools.cpp:67
string getStatus() const
Definition: Stoich.h:49
unsigned int nPosEigenvalues_
vector< double > nVec
static const Cinfo * steadyStateCinfo
static const double DELTA
vector< double > total_
VoxelPools * pool
unsigned int stateType_
double getTotal(const unsigned int i) const
bool isInfinity(T value)
Definition: numutil.h:52
VoxelPools pool_
void setMaxIter(unsigned int value)
Definition: EpFunc.h:49
ublas::matrix< double > * Nr
unsigned int nIter_
unsigned int nNegEigenvalues_
static bool checkAboveZero(const vector< double > &y)
unsigned int getSolutionStatus() const
static const double EPSILON
Definition: Eref.h:26
bool isA(const string &ancestor) const
Definition: Cinfo.cpp:280
const Cinfo * cinfo() const
Definition: Element.cpp:66
Id getStoich() 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
Definition: VoxelPools.cpp:318
unsigned int getNnegEigenvalues() const
unsigned int maxIter_
void setConvergenceCriterion(double value)
static char name[]
Definition: mfield.cpp:401
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.
Definition: global.cpp:97
Definition: Id.h:17
static const Cinfo * initCinfo()
unsigned int getNumCoreRates() const
Number of rate terms for reactions purely on this compartment.
Definition: Stoich.cpp:574
Definition: OpFunc.h:13
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)
Definition: SetGet.h:284
const vector< RateTerm * > & getRateTerms() const
Returns a reference to the entire rates_ vector.
Definition: Stoich.cpp:589
void setStoich(Id s)
static const Cinfo * initCinfo()
Definition: Neutral.cpp:16
void classifyState(const double *T)
unsigned int nReacs_
void updateReacVelocities(const double *s, vector< double > &v) const
Definition: VoxelPools.cpp:350
void updateAllRateTerms(const vector< RateTerm * > &rates, unsigned int numCoreRates)
Updates all the rate constants from the reference rates vector.
Definition: VoxelPools.cpp:282
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_
Definition: Cinfo.h:18
void settle(bool forceSetup)
void setTotal(const unsigned int i, double val)
Definition: Finfo.h:12