MOOSE - Multiscale Object Oriented Simulation Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
SteadyStateBoost.cpp
Go to the documentation of this file.
1 /***
2  * Filename: SteadyStateBoost.cpp
3  *
4  * Description: Steady state solver. Copy of ../ksolve/SteadyStateGsl.cpp
5  * but it uses boost solver.
6  *
7  * Created: 2016-05-10
8  *
9  * Author: Dilawar Singh <dilawars@ncbs.res.in>
10  * Organization: NCBS Bangalore
11  *
12  * This program works out a steady-state value for a reaction system.
13  * It uses boost-ublas and lapack heavily.
14  *
15  * It finds the ss value closest to the initial conditions.
16  *
17  * If you want to find multiple stable states, it is best to do this
18  * in Python as it gives a lot of flexibility in working out how to
19  * find steady states.
20  *
21  * Likewise, if you want to carry out a dose-response calculation.
22  */
23 
24 
25 #include "header.h"
26 #include "global.h"
27 #include "SparseMatrix.h"
28 #include "KinSparseMatrix.h"
29 #include "RateTerm.h"
30 #include "FuncTerm.h"
31 #include "VoxelPoolsBase.h"
32 #include "../mesh/VoxelJunction.h"
33 #include "XferInfo.h"
34 #include "ZombiePoolInterface.h"
35 #include "Stoich.h"
36 #include "../randnum/RNG.h"
37 
38 /* Root finding algorithm is implemented here */
39 #include "NonlinearSystem.h"
40 
41 /*
42  * Bindings to lapack. These headers are not part of standard boost
43  * distribution. They are available with moose distribution. See 'external'
44  * folder.
45  */
46 #include "boost/numeric/bindings/lapack/lapack.hpp"
47 #include "boost/numeric/bindings/lapack/geev.hpp"
48 
49 #include "VoxelPoolsBase.h"
50 #include "OdeSystem.h"
51 #include "VoxelPools.h"
52 #include "SteadyStateBoost.h"
53 
54 using namespace boost::numeric::bindings;
55 using namespace boost::numeric;
56 
57 void ss_func( const vector_type& x, void* params, vector_type& f );
58 unsigned int rankUsingBoost( ublas::matrix<double>& U );
59 
60 // Limit below which small numbers are treated as zero.
61 const double SteadyState::EPSILON = 1e-9;
62 
63 // This fraction of molecules is used as an increment in computing the
64 // Jacobian
65 const double SteadyState::DELTA = 1e-6;
69 struct reac_info
70 {
71 
72  int rank;
73  int num_reacs;
74  size_t num_mols;
75  int nIter;
77 
78  double* T;
80  vector< double > nVec;
81 
82  ublas::matrix< double >* Nr;
83  ublas::matrix< double >* gamma;
84 };
85 
87 {
112  // Field definitions
115  static ValueFinfo< SteadyState, Id > stoich(
116  "stoich",
117  "Specify the Id of the stoichiometry system to use",
120  );
121  static ReadOnlyValueFinfo< SteadyState, bool > badStoichiometry(
122  "badStoichiometry",
123  "Bool: True if there is a problem with the stoichiometry",
125  );
126  static ReadOnlyValueFinfo< SteadyState, bool > isInitialized(
127  "isInitialized",
128  "True if the model has been initialized successfully",
130  );
132  "nIter",
133  "Number of iterations done by steady state solver",
135  );
137  "status",
138  "Status of solver",
140  );
142  "maxIter",
143  "Max permissible number of iterations to try before giving up",
146  );
147  static ValueFinfo< SteadyState, double> convergenceCriterion(
148  "convergenceCriterion",
149  "Fractional accuracy required to accept convergence",
152  );
154  "numVarPools",
155  "Number of variable molecules in reaction system.",
157  );
159  "rank",
160  "Number of independent molecules in reaction system",
162  );
164  "stateType",
165  "0: stable; 1: unstable; 2: saddle; 3: osc?; 4: one near-zero eigenvalue; 5: other",
167  );
169  nNegEigenvalues (
170  "nNegEigenvalues",
171  "Number of negative eigenvalues: indicates type of solution",
173  );
175  nPosEigenvalues(
176  "nPosEigenvalues",
177  "Number of positive eigenvalues: indicates type of solution",
179  );
181  "solutionStatus",
182  "0: Good; 1: Failed to find steady states; "
183  "2: Failed to find eigenvalues",
185  );
187  "total",
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.",
199  );
201  SteadyState, unsigned int, double > eigenvalues(
202  "eigenvalues",
203  "Eigenvalues computed for steady state",
205  );
207  // MsgDest definitions
209  static DestFinfo setupMatrix( "setupMatrix",
210  "This function initializes and rebuilds the matrices used "
211  "in the calculation.",
213  );
214 
215  static DestFinfo settle( "settle",
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.",
220  );
221  static DestFinfo resettle( "resettle",
222  "Finds the nearest steady state to the current initial "
223  "conditions. This function rebuilds the entire calculation ",
225  );
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",
229  );
230  static DestFinfo randomInit( "randomInit",
231  "Generate random initial conditions consistent with the mass"
232  "conservation rules. Typically invoked in order to scan"
233  "states",
236  );
238  // Shared definitions
240 
241  static Finfo * steadyStateFinfos[] =
242  {
243  &stoich, // Value
244  &badStoichiometry, // ReadOnlyValue
245  &isInitialized, // ReadOnlyValue
246  &nIter, // ReadOnlyValue
247  &status, // ReadOnlyValue
248  &maxIter, // Value
249  &convergenceCriterion, // ReadOnlyValue
250  &numVarPools, // ReadOnlyValue
251  &rank, // ReadOnlyValue
252  &stateType, // ReadOnlyValue
253  &nNegEigenvalues, // ReadOnlyValue
254  &nPosEigenvalues, // ReadOnlyValue
255  &solutionStatus, // ReadOnlyValue
256  &total, // LookupValue
257  &eigenvalues, // ReadOnlyLookupValue
258  &setupMatrix, // DestFinfo
259  &settle, // DestFinfo
260  &resettle, // DestFinfo
261  &showMatrices, // DestFinfo
262  &randomInit, // DestFinfo
263 
264 
265  };
266 
267  static string doc[] =
268  {
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 "
279  "points.\n "
280  "The SteadyState class also provides a utility function "
281  "*randomInit()* to "
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 "
295  "conditions.\n "
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 "
300  "fixed point. "
301  };
302 
303  static Dinfo< SteadyState > dinfo;
304  static Cinfo steadyStateCinfo(
305  "SteadyState",
307  steadyStateFinfos,
308  sizeof( steadyStateFinfos )/sizeof(Finfo *),
309  &dinfo,
310  doc, sizeof( doc ) / sizeof( string )
311  );
312 
313  return &steadyStateCinfo;
314 }
315 
317 
319 // Class function definitions
321 
323  :
324  nIter_( 0 ),
325  maxIter_( 100 ),
326  badStoichiometry_( 0 ),
327  status_( "OK" ),
328  isInitialized_( 0 ),
329  isSetup_( 0 ),
330  convergenceCriterion_( 1e-7 ),
331  stoich_(),
332  numVarPools_( 0 ),
333  nReacs_( 0 ),
334  rank_( 0 ),
335  reassignTotal_( 0 ),
336  nNegEigenvalues_( 0 ),
337  nPosEigenvalues_( 0 ),
338  stateType_( 0 ),
339  solutionStatus_( 0 ),
340  numFailed_( 0 )
341 {
342 }
343 
345 {
346 
347 }
348 
350 // Field function definitions
352 
354 {
355  return stoich_;
356 }
357 
359 {
360  if ( !value.element()->cinfo()->isA( "Stoich" ) )
361  {
362  cout << "Error: SteadyState::setStoich: Must be of Stoich class\n";
363  return;
364  }
365 
366  stoich_ = value;
367  Stoich* stoichPtr = reinterpret_cast< Stoich* >( value.eref().data());
368  numVarPools_ = Field< unsigned int >::get( stoich_, "numVarPools" );
369  nReacs_ = Field< unsigned int >::get( stoich_, "numRates" );
370  setupSSmatrix();
372  stoichPtr->getCompartment(), "oneVoxelVolume", 0 );
373  pool_.setVolume( vol );
374  pool_.setStoich( stoichPtr, 0 );
375  pool_.updateAllRateTerms( stoichPtr->getRateTerms(),
376  stoichPtr->getNumCoreRates() );
377  isInitialized_ = 1;
378 }
379 
381 {
382  return badStoichiometry_;
383 }
384 
386 {
387  return isInitialized_;
388 }
389 
390 unsigned int SteadyState::getNiter() const
391 {
392  return nIter_;
393 }
394 
396 {
397  return status_;
398 }
399 
400 unsigned int SteadyState::getMaxIter() const
401 {
402  return maxIter_;
403 }
404 
405 void SteadyState::setMaxIter( unsigned int value )
406 {
407  maxIter_ = value;
408 }
409 
410 unsigned int SteadyState::getRank() const
411 {
412  return rank_;
413 }
414 
415 unsigned int SteadyState::getNumVarPools() const
416 {
417  return numVarPools_;
418 }
419 
420 unsigned int SteadyState::getStateType() const
421 {
422  return stateType_;
423 }
424 
426 {
427  return nNegEigenvalues_;
428 }
429 
431 {
432  return nPosEigenvalues_;
433 }
434 
435 unsigned int SteadyState::getSolutionStatus() const
436 {
437  return solutionStatus_;
438 }
439 
441 {
442  if ( value > 1e-10 )
444  else
445  cout << "Warning: Convergence criterion " << value <<
446  " too small. Old value " <<
447  convergenceCriterion_ << " retained\n";
448 }
449 
451 {
452  return convergenceCriterion_;
453 }
454 
455 double SteadyState::getTotal( const unsigned int i ) const
456 {
457  if ( i < total_.size() )
458  return total_[i];
459  cout << "Warning: SteadyState::getTotal: index " << i <<
460  " out of range " << total_.size() << endl;
461  return 0.0;
462 }
463 
464 void SteadyState::setTotal( const unsigned int i, double val )
465 {
466  if ( i < total_.size() )
467  {
468  total_[i] = val;
469  reassignTotal_ = 1;
470  return;
471  }
472  cout << "Warning: SteadyState::setTotal: index " << i <<
473  " out of range " << total_.size() << endl;
474 }
475 
476 double SteadyState::getEigenvalue( const unsigned int i ) const
477 {
478  if ( i < eigenvalues_.size() )
479  return eigenvalues_[i];
480  cout << "Warning: SteadyState::getEigenvalue: index " << i <<
481  " out of range " << eigenvalues_.size() << endl;
482  return 0.0;
483 }
484 
486 // Dest function definitions
488 
489 // Static func
491 {
492  setupSSmatrix();
493 }
495 {
496  settle( 0 );
497 }
498 
500 {
501  settle( 1 );
502 }
503 
504 // Dummy function
505 void SteadyState::assignY( double* S )
506 {
507 }
508 
510 {
511  if ( !isInitialized_ ) {
512  cout << "SteadyState::showMatrices: Sorry, the system is not yet initialized.\n";
513  return;
514  }
515  int numConsv = numVarPools_ - rank_;
516  cout << "Totals: ";
517  for ( int i = 0; i < numConsv; ++i )
518  cout << total_[i] << " ";
519  cout << endl;
520  cout << "gamma " << gamma_ << endl;
521  cout << "Nr " << Nr_ << endl;
522  cout << "LU " << LU_ << endl;
523 }
524 
526 {
527 
528  if ( numVarPools_ == 0 || nReacs_ == 0 )
529  return;
530 
531  int nTot = numVarPools_ + nReacs_;
532 
533  ublas::matrix<double> N(numVarPools_, nReacs_, 0.0);
534 
535  LU_ = ublas::matrix< double >( numVarPools_, nTot, 0.0);
536 
537  vector< int > entry = Field< vector< int > >::get(
538  stoich_, "matrixEntry" );
539  vector< unsigned int > colIndex = Field< vector< unsigned int > >::get(
540  stoich_, "columnIndex" );
541  vector< unsigned int > rowStart = Field< vector< unsigned int > >::get(
542  stoich_, "rowStart" );
543 
544  for ( unsigned int i = 0; i < numVarPools_; ++i )
545  {
546  LU_(i, i + nReacs_) = 1;
547  unsigned int k = rowStart[i];
548  for ( unsigned int j = 0; j < nReacs_; ++j )
549  {
550  double x = 0;
551  if ( j == colIndex[k] && k < rowStart[i+1] )
552  {
553  x = entry[k++];
554  }
555  N(i,j) = x;
556  LU_(i,j) = x;
557  }
558  }
559 
560  // This function reorgranize LU_.
561  rank_ = rankUsingBoost( LU_ );
562  Nr_ = ublas::matrix< double >( rank_, nReacs_ );
563  Nr_.assign( ublas::zero_matrix< double >( rank_, nReacs_ ) );
564 
565  unsigned int nConsv = numVarPools_ - rank_;
566  if ( nConsv == 0 )
567  {
568  cout << "SteadyState::setupSSmatrix(): Number of conserved species == 0. Aborting\n";
569  return;
570  }
571 
572  // Fill up Nr.
573  for ( unsigned int i = 0; i < rank_; i++)
574  for ( unsigned int j = i; j < nReacs_; j++)
575  Nr_(i,j) = LU_(i, j);
576 
577  gamma_ = ublas::matrix< double >( nConsv, numVarPools_, 0.0 );
578 
579  // Fill up gamma
580  for ( unsigned int i = rank_; i < numVarPools_; ++i )
581  for ( unsigned int j = 0; j < numVarPools_; ++j )
582  gamma_(i-rank_, j) = LU_(i, j+nReacs_);
583 
584  // Fill up boundary condition values
585  total_.resize( nConsv );
586  total_.assign( nConsv, 0.0 );
587 
588  Id ksolve = Field< Id >::get( stoich_, "ksolve" );
589  vector< double > nVec =
591  ksolve,"nVec", 0 );
592 
593  if ( nVec.size() >= numVarPools_ )
594  {
595  for ( unsigned int i = 0; i < nConsv; ++i )
596  for ( unsigned int j = 0; j < numVarPools_; ++j )
597  total_[i] += gamma_(i,j) * nVec[ j ];
598  isSetup_ = 1;
599  }
600  else
601  {
602  cout << "Error: SteadyState::setupSSmatrix(): unable to get"
603  "pool numbers from ksolve.\n";
604  isSetup_ = 0;
605  }
606 
607 }
608 
609 void SteadyState::classifyState( const double* T )
610 {
611  /* column_major trait is needed for fortran */
612  ublas::matrix<double, ublas::column_major> J(numVarPools_, numVarPools_);
613 
614  double tot = 0.0;
615  Stoich* s = reinterpret_cast< Stoich* >( stoich_.eref().data() );
616  vector< double > nVec = LookupField< unsigned int, vector< double > >::get(
617  s->getKsolve(), "nVec", 0 );
618  for ( unsigned int i = 0; i < numVarPools_; ++i )
619  tot += nVec[i];
620 
621  tot *= DELTA;
622 
623  vector< double > yprime( nVec.size(), 0.0 );
624  // Fill up Jacobian
625  for ( unsigned int i = 0; i < numVarPools_; ++i )
626  {
627  double orig = nVec[i];
628  if ( std::isnan( orig ) or std::isinf( orig ) )
629  {
630  cout << "Warning: SteadyState::classifyState: orig=nan\n";
631  solutionStatus_ = 2; // Steady state OK, eig failed
632  J.clear();
633  return;
634  }
635  if ( std::isnan( tot ) or std::isinf( tot ))
636  {
637  cout << "Warning: SteadyState::classifyState: tot=nan\n";
638  solutionStatus_ = 2; // Steady state OK, eig failed
639  J.clear();
640  return;
641  }
642  nVec[i] = orig + tot;
643 
644  pool_.updateRates( &nVec[0], &yprime[0] );
645  nVec[i] = orig;
646 
647  // Assign the rates for each mol.
648  for ( unsigned int j = 0; j < numVarPools_; ++j )
649  {
650  if( std::isnan( yprime[j] ) or std::isinf( yprime[j] ) )
651  {
652  cout << "Warning: Overflow/underflow. Can't continue " << endl;
653  solutionStatus_ = 2;
654  return;
655  }
656  J(i, j) = yprime[j];
657  }
658  }
659 
660  // Jacobian is now ready. Find eigenvalues.
661  ublas::vector< std::complex< double > > eigenVec ( J.size1() );
662 
663  ublas::matrix< std::complex<double>, ublas::column_major >* vl, *vr;
664  vl = NULL; vr = NULL;
665 
666  /*-----------------------------------------------------------------------------
667  * INFO: Calling lapack routine geev to compute eigen vector of matrix J.
668  *
669  * Argument 3 and 4 are left- and right-eigenvectors. Since we do not need
670  * them, they are set to NULL. Argument 2 holds eigen-vector and result is
671  * copied to it (output ).
672  *-----------------------------------------------------------------------------*/
673  int status = lapack::geev( J, eigenVec, vl, vr, lapack::optimal_workspace() );
674 
675  eigenvalues_.clear();
676  eigenvalues_.resize( numVarPools_, 0.0 );
677  if ( status != 0 )
678  {
679  cout << "Warning: SteadyState::classifyState failed to find eigenvalues. Status = " <<
680  status << endl;
681  solutionStatus_ = 2; // Steady state OK, eig classification failed
682  }
683  else // Eigenvalues are ready. Classify state.
684  {
685  nNegEigenvalues_ = 0;
686  nPosEigenvalues_ = 0;
687  for ( unsigned int i = 0; i < numVarPools_; ++i )
688  {
689  std::complex<value_type> z = eigenVec[ i ];
690  double r = z.real();
691  nNegEigenvalues_ += ( r < -EPSILON );
692  nPosEigenvalues_ += ( r > EPSILON );
693  eigenvalues_[i] = r;
694  // We have a problem here because numVarPools_ usually > rank
695  // This means we have several zero eigenvalues.
696  }
697  if ( nNegEigenvalues_ == rank_ )
698  stateType_ = 0; // Stable
699  else if ( nPosEigenvalues_ == rank_ ) // Never see it.
700  stateType_ = 1; // Unstable
701  else if (nPosEigenvalues_ == 1)
702  stateType_ = 2; // Saddle
703  else if ( nPosEigenvalues_ >= 2 )
704  stateType_ = 3; // putative oscillatory
705  else if ( nNegEigenvalues_ == ( rank_ - 1) && nPosEigenvalues_ == 0 )
706  stateType_ = 4; // one zero or unclassified eigenvalue. Messy.
707  else
708  stateType_ = 5; // Other
709  }
710 }
711 
712 static bool isSolutionValid( const vector< double >& x )
713 {
714  for( size_t i = 0; i < x.size(); i++ )
715  {
716  double v = x[i];
717  if ( std::isnan( v ) or std::isinf( v ) )
718  {
719  cout << "Warning: SteadyState iteration gave nan/inf concs\n";
720  return false;
721  }
722  else if( v < 0.0 )
723  {
724  cout << "Warning: SteadyState iteration gave negative concs\n";
725  return false;
726  }
727  }
728  return true;
729 }
730 
735 void SteadyState::settle( bool forceSetup )
736 {
737 
738  if ( !isInitialized_ )
739  {
740  cout << "Error: SteadyState object has not been initialized. No calculations done\n";
741  return;
742  }
743 
744  if ( forceSetup || isSetup_ == 0 )
745  setupSSmatrix();
746 
747  // Setting up matrices and vectors for the calculation.
748  unsigned int nConsv = numVarPools_ - rank_;
749  double * T = (double *) calloc( nConsv, sizeof( double ) );
750 
751  // Setting up matrices and vectors for the calculation.
752  Id ksolve = Field< Id >::get( stoich_, "ksolve" );
753 
754  ss = new NonlinearSystem( numVarPools_ );
755 
756  ss->ri.rank = rank_;
757  ss->ri.num_reacs = nReacs_;
758  ss->ri.num_mols = numVarPools_;
759  ss->ri.T = T;
760  ss->ri.Nr = Nr_;
761  ss->ri.gamma = gamma_;
762  ss->ri.pool = &pool_;
763  ss->ri.nVec = LookupField< unsigned int, vector< double > >::get(
764  ksolve,"nVec", 0
765  );
766  ss->ri.convergenceCriterion = convergenceCriterion_;
767 
768  // This gives the starting point for finding the solution.
769  vector<double> init( numVarPools_ );
770 
771  // Instead of starting at sqrt( x ),
772  for( size_t i = 0; i < numVarPools_; ++i )
773  init[i] = max( 0.0, sqrt(ss->ri.nVec[i]) );
774 
775  ss->initialize<vector<double>>( init );
776 
777  // Fill up boundary condition values
778  if ( reassignTotal_ ) // The user has defined new conservation values.
779  {
780  for (size_t i = 0; i < nConsv; ++i )
781  T[i] = total_[i];
782  reassignTotal_ = 0;
783  }
784  else
785  {
786  for ( size_t i = 0; i < nConsv; ++i )
787  for ( size_t j = 0; j < numVarPools_; ++j )
788  T[i] += gamma_( i, j ) * ss->ri.nVec[ j ];
789  total_.assign( T, T + nConsv );
790  }
791 
792  vector< double > repair( numVarPools_, 0.0 );
793 
794  for ( unsigned int j = 0; j < numVarPools_; ++j )
795  repair[j] = ss->ri.nVec[j];
796 
797 
798  int status = 1;
799 
800  // Find roots . If successful, set status to 0.
801  if( ss->find_roots_gnewton( ) )
802  status = 0;
803 
804  if ( status == 0 && isSolutionValid( ss->ri.nVec ) )
805  {
806  solutionStatus_ = 0; // Good solution
807 
809  ksolve, "nVec", 0, ss->ri.nVec
810  );
811  // Check what we set
812  vector<double> t = LookupField< unsigned int, vector< double > >::get(
813  ksolve,"nVec", 0
814  );
815 
816  //classifyState( T );
817  }
818  else
819  {
820  cout << "Warning: SteadyState iteration failed, status = " <<
821  status_ << ", nIter = " << ss->ri.nIter << endl;
822 
823  for ( unsigned int j = 0; j < numVarPools_; j++ )
824  ss->ri.nVec[j] = repair[j];
825 
826  solutionStatus_ = 1; // Steady state failed.
827  LookupField< unsigned int, vector< double > >::set(
828  ksolve, "nVec", 0, ss->ri.nVec
829  );
830 
831  }
832 
833  // Clean up.
834  free( T );
835 }
836 
837 
838 /*-----------------------------------------------------------------------------
839  * These functions computes rank of a matrix.
840  *-----------------------------------------------------------------------------*/
841 
849 void swapRows( ublas::matrix< double >& mat, unsigned int r1, unsigned int r2)
850 {
851  ublas::vector<value_type> temp( mat.size2() );
852  for (size_t i = 0; i < mat.size2(); i++)
853  {
854  temp[i] = mat(r1, i );
855  mat(r1, i ) = mat(r2, i );
856  }
857 
858  for (size_t i = 0; i < mat.size2(); i++)
859  mat(r2, i) = temp[i];
860 }
861 
862 
863 int reorderRows( ublas::matrix< double >& U, int start, int leftCol )
864 {
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 )
869  {
870  for ( int j = leftCol; j < numReacs; ++j )
871  {
872  if ( fabs( U(i,j )) > SteadyState::EPSILON )
873  {
874  if ( j < newLeftCol )
875  {
876  newLeftCol = j;
877  leftMostRow = i;
878  }
879  break;
880  }
881  }
882  }
883 
884  if ( leftMostRow != start ) // swap them.
885  swapRows( U, start, leftMostRow );
886 
887  return newLeftCol;
888 }
889 
890 void eliminateRowsBelow( ublas::matrix< double >& U, int start, int leftCol )
891 {
892  int numMols = U.size1();
893  double pivot = U( start, leftCol );
894  assert( fabs( pivot ) > SteadyState::EPSILON );
895  for ( int i = start + 1; i < numMols; ++i )
896  {
897  double factor = U(i, leftCol);
898  if( fabs ( factor ) > SteadyState::EPSILON )
899  {
900  factor = factor / pivot;
901  for ( size_t j = leftCol + 1; j < U.size2(); ++j )
902  {
903  double x = U(i,j);
904  double y = U( start, j );
905  x -= y * factor;
906  if ( fabs( x ) < SteadyState::EPSILON )
907  x = 0.0;
908  U( i, j ) = x;
909  }
910  }
911  U(i, leftCol) = 0.0;
912  }
913 }
914 
915 unsigned int rankUsingBoost( ublas::matrix<double>& U )
916 {
917  int numMols = U.size1();
918  int numReacs = U.size2() - numMols;
919  int i;
920  // Start out with a nonzero entry at 0,0
921  int leftCol = reorderRows( U, 0, 0 );
922 
923  for ( i = 0; i < numMols - 1; ++i )
924  {
925  eliminateRowsBelow( U, i, leftCol );
926  leftCol = reorderRows( U, i + 1, leftCol );
927  if ( leftCol == numReacs )
928  break;
929  }
930  return i + 1;
931 }
932 
933 
934 static bool checkAboveZero( const vector< double >& y )
935 {
936  for ( vector< double >::const_iterator
937  i = y.begin(); i != y.end(); ++i )
938  {
939  if ( *i < 0.0 )
940  return false;
941  }
942  return true;
943 }
944 
952 void recalcTotal( vector< double >& tot, ublas::matrix<double>& g, const double* S )
953 {
954  assert( g.size1() == tot.size() );
955  for ( size_t i = 0; i < g.size1(); ++i )
956  {
957  double t = 0.0;
958  for ( unsigned int j = 0; j < g.size2(); ++j )
959  t += g( i, j ) * S[j];
960  tot[ i ] = t;
961  }
962 }
963 
969 {
970  Id ksolve = Field< Id >::get( stoich_, "ksolve" );
971  vector< double > nVec =
973  ksolve,"nVec", 0 );
974  int numConsv = total_.size();
975  recalcTotal( total_, gamma_, &nVec[0] );
976  // The reorderRows function likes to have an I matrix at the end of
977  // numVarPools_, so we provide space for it, although only its first
978  // column is used for the total vector.
979  ublas::matrix<double> U(numConsv, numVarPools_ + numConsv, 0);
980 
981  for ( int i = 0; i < numConsv; ++i )
982  {
983  for ( unsigned int j = 0; j < numVarPools_; ++j )
984  U(i, j) = gamma_(i, j);
985 
986  U(i, numVarPools_) = total_[i];
987  }
988  // Do the forward elimination
989  int rank = rankUsingBoost( U );
990  assert( rank = numConsv );
991 
992  vector< double > eliminatedTotal( numConsv, 0.0 );
993  for ( int i = 0; i < numConsv; ++i )
994  eliminatedTotal[i] = U( i, numVarPools_ );
995 
996  // Put Find a vector Y that fits the consv rules.
997  vector< double > y( numVarPools_, 0.0 );
998  do
999  {
1000  fitConservationRules( U, eliminatedTotal, y );
1001  }
1002  while ( !checkAboveZero( y ) );
1003 
1004  // Sanity check. Try the new vector with the old gamma and tots
1005  for ( int i = 0; i < numConsv; ++i )
1006  {
1007  double tot = 0.0;
1008  for ( unsigned int j = 0; j < numVarPools_; ++j )
1009  {
1010  tot += y[j] * gamma_( i, j );
1011  }
1012  assert( fabs( tot - total_[i] ) / tot < EPSILON );
1013  }
1014 
1015  // Put the new values into S.
1016  // cout << endl;
1017  for ( unsigned int j = 0; j < numVarPools_; ++j )
1018  {
1019  nVec[j] = y[j];
1020  // cout << y[j] << " ";
1021  }
1023  ksolve,"nVec", 0, nVec );
1024 }
1025 
1031  ublas::matrix<double>& U, const vector< double >& eliminatedTotal,
1032  vector< double >&y
1033 )
1034 {
1035  int numConsv = total_.size();
1036  int lastJ = numVarPools_;
1037  for ( int i = numConsv - 1; i >= 0; --i )
1038  {
1039  for ( unsigned int j = 0; j < numVarPools_; ++j )
1040  {
1041  double g = U( i, j );
1042  if ( fabs( g ) > EPSILON )
1043  {
1044  // double ytot = calcTot( g, i, j, lastJ );
1045  double ytot = 0.0;
1046  for ( int k = j; k < lastJ; ++k )
1047  {
1048  y[k] = moose::mtrand();
1049  ytot += y[k] * U( i, k );
1050  }
1051  assert( fabs( ytot ) > EPSILON );
1052  double lastYtot = 0.0;
1053  for ( unsigned int k = lastJ; k < numVarPools_; ++k )
1054  {
1055  lastYtot += y[k] * U( i, k );
1056  }
1057  double scale = ( eliminatedTotal[i] - lastYtot ) / ytot;
1058  for ( int k = j; k < lastJ; ++k )
1059  {
1060  y[k] *= scale;
1061  }
1062  lastJ = j;
1063  break;
1064  }
1065  }
1066  }
1067 }
1068 
Id init(int argc, char **argv, bool &doUnitTests, bool &doRegressionTests, unsigned int &benchmark)
Definition: main.cpp:150
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 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
void ss_func(const vector_type &x, void *params, vector_type &f)
unsigned int getNumVarPools() const
Definition: Dinfo.h:60
Definition: SetGet.h:236
Id getKsolve() const
Definition: Stoich.cpp:446
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_
Eref eref() const
Definition: Id.cpp:125
bool badStoichiometry() const
unsigned int rank_
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)
Definition: VoxelPools.cpp:67
string getStatus() const
Definition: Stoich.h:49
unsigned int nPosEigenvalues_
vector< double > nVec
static const double DELTA
vector< double > total_
VoxelPools * pool
unsigned int stateType_
double getTotal(const unsigned int i) const
VoxelPools pool_
void setMaxIter(unsigned int value)
Definition: EpFunc.h:49
ublas::matrix< double > * Nr
unsigned int nIter_
unsigned int nNegEigenvalues_
static const Cinfo * steadyStateCinfo
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
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
static bool isSolutionValid(const vector< double > &x)
unsigned int maxIter_
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.
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 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)
unsigned int solutionStatus_
Definition: Cinfo.h:18
unsigned int rankUsingBoost(ublas::matrix< double > &U)
void settle(bool forceSetup)
void setTotal(const unsigned int i, double val)
Definition: Finfo.h:12