void SteadyState::classifyState( const double* T ) { #ifdef USE_GSL // unsigned int nConsv = numVarPools_ - rank_; gsl_matrix* J = gsl_matrix_calloc ( numVarPools_, numVarPools_ ); // double* yprime = new double[ numVarPools_ ]; // vector< double > yprime( numVarPools_, 0.0 ); // Generate an approximation to the Jacobean by generating small // increments to each of the molecules in the steady state, one // at a time, and putting the resultant rate vector into a column // of the J matrix. // This needs a bit of heuristic to decide what is a 'small' increment. // Use the CoInits for this. Stoichiometry shouldn't matter too much. // I used the totals from consv rules earlier, but that can have // negative values. double tot = 0.0; Stoich* s = reinterpret_cast< Stoich* >( stoich_.eref().data() ); vector< double > nVec = LookupField< unsigned int, vector< double > >::get( s->getKsolve(), "nVec", 0 ); for ( unsigned int i = 0; i < numVarPools_; ++i ) { tot += nVec[i]; } tot *= DELTA; vector< double > yprime( nVec.size(), 0.0 ); // Fill up Jacobian for ( unsigned int i = 0; i < numVarPools_; ++i ) { double orig = nVec[i]; if ( isnan( orig ) ) { cout << "Warning: SteadyState::classifyState: orig=nan\n"; solutionStatus_ = 2; // Steady state OK, eig failed gsl_matrix_free ( J ); return; } if ( isnan( tot ) ) { cout << "Warning: SteadyState::classifyState: tot=nan\n"; solutionStatus_ = 2; // Steady state OK, eig failed gsl_matrix_free ( J ); return; } nVec[i] = orig + tot; /// Here we assume we always use voxel zero. s->updateRates( &nVec[0], &yprime[0], 0 ); nVec[i] = orig; // Assign the rates for each mol. for ( unsigned int j = 0; j < numVarPools_; ++j ) { gsl_matrix_set( J, i, j, yprime[j] ); } } // Jacobian is now ready. Find eigenvalues. gsl_vector_complex* vec = gsl_vector_complex_alloc( numVarPools_ ); gsl_eigen_nonsymm_workspace* workspace = gsl_eigen_nonsymm_alloc( numVarPools_ ); int status = gsl_eigen_nonsymm( J, vec, workspace ); eigenvalues_.clear(); eigenvalues_.resize( numVarPools_, 0.0 ); if ( status != GSL_SUCCESS ) { cout << "Warning: SteadyState::classifyState failed to find eigenvalues. Status = " << status << endl; solutionStatus_ = 2; // Steady state OK, eig classification failed } else { // Eigenvalues are ready. Classify state. nNegEigenvalues_ = 0; nPosEigenvalues_ = 0; for ( unsigned int i = 0; i < numVarPools_; ++i ) { gsl_complex z = gsl_vector_complex_get( vec, i ); double r = GSL_REAL( z ); nNegEigenvalues_ += ( r < -EPSILON ); nPosEigenvalues_ += ( r > EPSILON ); eigenvalues_[i] = r; // We have a problem here because numVarPools_ usually > rank // This means we have several zero eigenvalues. } if ( nNegEigenvalues_ == rank_ ) stateType_ = 0; // Stable else if ( nPosEigenvalues_ == rank_ ) // Never see it. stateType_ = 1; // Unstable else if (nPosEigenvalues_ == 1) stateType_ = 2; // Saddle else if ( nPosEigenvalues_ >= 2 ) stateType_ = 3; // putative oscillatory else if ( nNegEigenvalues_ == ( rank_ - 1) && nPosEigenvalues_ == 0 ) stateType_ = 4; // one zero or unclassified eigenvalue. Messy. else stateType_ = 5; // Other } gsl_vector_complex_free( vec ); gsl_matrix_free ( J ); gsl_eigen_nonsymm_free( workspace ); #endif }
void SteadyState::classifyState( const double* T ) { /* column_major trait is needed for fortran */ ublas::matrix<double, ublas::column_major> J(numVarPools_, numVarPools_); double tot = 0.0; Stoich* s = reinterpret_cast< Stoich* >( stoich_.eref().data() ); vector< double > nVec = LookupField< unsigned int, vector< double > >::get( s->getKsolve(), "nVec", 0 ); for ( unsigned int i = 0; i < numVarPools_; ++i ) tot += nVec[i]; tot *= DELTA; vector< double > yprime( nVec.size(), 0.0 ); // Fill up Jacobian for ( unsigned int i = 0; i < numVarPools_; ++i ) { double orig = nVec[i]; if ( std::isnan( orig ) or std::isinf( orig ) ) { cout << "Warning: SteadyState::classifyState: orig=nan\n"; solutionStatus_ = 2; // Steady state OK, eig failed J.clear(); return; } if ( std::isnan( tot ) or std::isinf( tot )) { cout << "Warning: SteadyState::classifyState: tot=nan\n"; solutionStatus_ = 2; // Steady state OK, eig failed J.clear(); return; } nVec[i] = orig + tot; pool_.updateRates( &nVec[0], &yprime[0] ); nVec[i] = orig; // Assign the rates for each mol. for ( unsigned int j = 0; j < numVarPools_; ++j ) { if( std::isnan( yprime[j] ) or std::isinf( yprime[j] ) ) { cout << "Warning: Overflow/underflow. Can't continue " << endl; solutionStatus_ = 2; return; } J(i, j) = yprime[j]; } } // Jacobian is now ready. Find eigenvalues. ublas::vector< std::complex< double > > eigenVec ( J.size1() ); ublas::matrix< std::complex<double>, ublas::column_major >* vl, *vr; vl = NULL; vr = NULL; /*----------------------------------------------------------------------------- * INFO: Calling lapack routine geev to compute eigen vector of matrix J. * * Argument 3 and 4 are left- and right-eigenvectors. Since we do not need * them, they are set to NULL. Argument 2 holds eigen-vector and result is * copied to it (output ). *-----------------------------------------------------------------------------*/ int status = lapack::geev( J, eigenVec, vl, vr, lapack::optimal_workspace() ); eigenvalues_.clear(); eigenvalues_.resize( numVarPools_, 0.0 ); if ( status != 0 ) { cout << "Warning: SteadyState::classifyState failed to find eigenvalues. Status = " << status << endl; solutionStatus_ = 2; // Steady state OK, eig classification failed } else // Eigenvalues are ready. Classify state. { nNegEigenvalues_ = 0; nPosEigenvalues_ = 0; for ( unsigned int i = 0; i < numVarPools_; ++i ) { std::complex<value_type> z = eigenVec[ i ]; double r = z.real(); nNegEigenvalues_ += ( r < -EPSILON ); nPosEigenvalues_ += ( r > EPSILON ); eigenvalues_[i] = r; // We have a problem here because numVarPools_ usually > rank // This means we have several zero eigenvalues. } if ( nNegEigenvalues_ == rank_ ) stateType_ = 0; // Stable else if ( nPosEigenvalues_ == rank_ ) // Never see it. stateType_ = 1; // Unstable else if (nPosEigenvalues_ == 1) stateType_ = 2; // Saddle else if ( nPosEigenvalues_ >= 2 ) stateType_ = 3; // putative oscillatory else if ( nNegEigenvalues_ == ( rank_ - 1) && nPosEigenvalues_ == 0 ) stateType_ = 4; // one zero or unclassified eigenvalue. Messy. else stateType_ = 5; // Other } }