예제 #1
0
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
    }
}