Skip to content
Snippets Groups Projects
SteadyStateBoost.cpp 32.01 KiB
/***
 *       Filename:  SteadyStateBoost.cpp
 *
 *    Description:  Steady state solver. Copy of ../ksolve/SteadyStateGsl.cpp
 *    but it uses boost solver.
 *
 *        Created:  2016-05-10
 *
 *         Author:  Dilawar Singh <dilawars@ncbs.res.in>
 *   Organization:  NCBS Bangalore
 *
 * This program works out a steady-state value for a reaction system.
 * It uses boost-ublas and lapack heavily.
 *
 * It finds the ss value closest to the initial conditions.
 *
 * If you want to find multiple stable states, it is best to do this
 * in Python as it gives a lot of flexibility in working out how to
 * find steady states.
 *
 * Likewise, if you want to carry out a dose-response calculation.
 */


#include "header.h"
#include "global.h"
#include "SparseMatrix.h"
#include "KinSparseMatrix.h"
#include "RateTerm.h"
#include "FuncTerm.h"
#include "VoxelPoolsBase.h"
#include "../mesh/VoxelJunction.h"
#include "XferInfo.h"
#include "ZombiePoolInterface.h"
#include "Stoich.h"
#include "../randnum/RNG.h"

/* Root finding algorithm is implemented here */
#include "NonlinearSystem.h"

/*
 * Bindings to lapack. These headers are not part of standard boost
 * distribution. They are available with moose distribution. See 'external'
 * folder.
 */
#include "boost/numeric/bindings/lapack/lapack.hpp"
#include "boost/numeric/bindings/lapack/geev.hpp"

#include "VoxelPoolsBase.h"
#include "OdeSystem.h"
#include "VoxelPools.h"
#include "SteadyStateBoost.h"

using namespace boost::numeric::bindings;
using namespace boost::numeric;

void ss_func( const vector_type& x, void* params, vector_type& f );
unsigned int rankUsingBoost( ublas::matrix<double>& U );

// Limit below which small numbers are treated as zero.
const double SteadyState::EPSILON = 1e-9;

// This fraction of molecules is used as an increment in computing the
// Jacobian
const double SteadyState::DELTA = 1e-6;
/**
 * This is used by the multidimensional root finder
 */
struct reac_info
{

    int rank;
    int num_reacs;
    size_t num_mols;
    int nIter;
    double convergenceCriterion;

    double* T;
    VoxelPools* pool;
    vector< double > nVec;

    ublas::matrix< double >* Nr;
    ublas::matrix< double >* gamma;
};

const Cinfo* SteadyState::initCinfo()
{
    /**
     * This picks up the entire Stoich data structure
    static Finfo* gslShared[] =
    {
    	new SrcFinfo( "reinitSrc", Ftype0() ),
    	new DestFinfo( "assignStoich",
    		Ftype1< void* >(),
    		RFCAST( &SteadyState::assignStoichFunc )
    		),
    	new DestFinfo( "setMolN",
    		Ftype2< double, unsigned int >(),
    		RFCAST( &SteadyState::setMolN )
    		),
    	new SrcFinfo( "requestYsrc", Ftype0() ),
    	new DestFinfo( "assignY",
    		Ftype1< double* >(),
    		RFCAST( &SteadyState::assignY )
    		),
    };
     */

    /**
     * These are the fields of the SteadyState class
     */
    ///////////////////////////////////////////////////////
    // Field definitions
    ///////////////////////////////////////////////////////
    static ValueFinfo< SteadyState, Id > stoich(
        "stoich",
        "Specify the Id of the stoichiometry system to use",
        &SteadyState::setStoich,
        &SteadyState::getStoich
    );
    static ReadOnlyValueFinfo< SteadyState, bool > badStoichiometry(
        "badStoichiometry",
        "Bool: True if there is a problem with the stoichiometry",
        &SteadyState::badStoichiometry
    );
    static ReadOnlyValueFinfo< SteadyState, bool > isInitialized(
        "isInitialized",
        "True if the model has been initialized successfully",
        &SteadyState::isInitialized
    );
    static ReadOnlyValueFinfo< SteadyState, unsigned int > nIter(
        "nIter",
        "Number of iterations done by steady state solver",
        &SteadyState::getNiter
    );
    static ReadOnlyValueFinfo< SteadyState, string > status(
        "status",
        "Status of solver",
        &SteadyState::getStatus
    );
    static ValueFinfo< SteadyState, unsigned int > maxIter(
        "maxIter",
        "Max permissible number of iterations to try before giving up",
        &SteadyState::setMaxIter,
        &SteadyState::getMaxIter
    );
    static ValueFinfo< SteadyState, double> convergenceCriterion(
        "convergenceCriterion",
        "Fractional accuracy required to accept convergence",
        &SteadyState::setConvergenceCriterion,
        &SteadyState::getConvergenceCriterion
    );
    static ReadOnlyValueFinfo< SteadyState, unsigned int > numVarPools(
        "numVarPools",
        "Number of variable molecules in reaction system.",
        &SteadyState::getNumVarPools
    );
    static ReadOnlyValueFinfo< SteadyState, unsigned int > rank(
        "rank",
        "Number of independent molecules in reaction system",
        &SteadyState::getRank
    );
    static ReadOnlyValueFinfo< SteadyState, unsigned int > stateType(
        "stateType",
        "0: stable; 1: unstable; 2: saddle; 3: osc?; 4: one near-zero eigenvalue; 5: other",
        &SteadyState::getStateType
    );
    static ReadOnlyValueFinfo< SteadyState, unsigned int >
    nNegEigenvalues (
        "nNegEigenvalues",
        "Number of negative eigenvalues: indicates type of solution",
        &SteadyState::getNnegEigenvalues
    );
    static ReadOnlyValueFinfo< SteadyState, unsigned int >
    nPosEigenvalues(
        "nPosEigenvalues",
        "Number of positive eigenvalues: indicates type of solution",
        &SteadyState::getNposEigenvalues
    );
    static ReadOnlyValueFinfo< SteadyState, unsigned int > solutionStatus(
        "solutionStatus",
        "0: Good; 1: Failed to find steady states; "
        "2: Failed to find eigenvalues",
        &SteadyState::getSolutionStatus
    );
    static LookupValueFinfo< SteadyState, unsigned int, double > total(
        "total",
        "Totals table for conservation laws. The exact mapping of"
        "this to various sums of molecules is given by the "
        "conservation matrix, and is currently a bit opaque."
        "The value of 'total' is set to initial conditions when"
        "the 'SteadyState::settle' function is called."
        "Assigning values to the total is a special operation:"
        "it rescales the concentrations of all the affected"
        "molecules so that they are at the specified total."
        "This happens the next time 'settle' is called.",
        &SteadyState::setTotal,
        &SteadyState::getTotal
    );
    static ReadOnlyLookupValueFinfo<
    SteadyState, unsigned int, double > eigenvalues(
        "eigenvalues",
        "Eigenvalues computed for steady state",
        &SteadyState::getEigenvalue
    );
    ///////////////////////////////////////////////////////
    // MsgDest definitions
    ///////////////////////////////////////////////////////
    static DestFinfo setupMatrix( "setupMatrix",
                                  "This function initializes and rebuilds the matrices used "
                                  "in the calculation.",
                                  new OpFunc0< SteadyState >(&SteadyState::setupMatrix)
                                );

    static DestFinfo settle( "settle",
                             "Finds the nearest steady state to the current initial "
                             "conditions. This function rebuilds the entire calculation "
                             "only if the object has not yet been initialized.",
                             new OpFunc0< SteadyState >( &SteadyState::settleFunc )
                           );
    static DestFinfo resettle( "resettle",
                               "Finds the nearest steady state to the current initial "
                               "conditions. This function rebuilds the entire calculation ",
                               new OpFunc0< SteadyState >( &SteadyState::resettleFunc )
                             );
    static DestFinfo showMatrices( "showMatrices",
                                   "Utility function to show the matrices derived for the calculations on the reaction system. Shows the Nr, gamma, and total matrices",
                                   new OpFunc0< SteadyState >( &SteadyState::showMatrices )
                                 );
    static DestFinfo randomInit( "randomInit",
                                 "Generate random initial conditions consistent with the mass"
                                 "conservation rules. Typically invoked in order to scan"
                                 "states",
                                 new EpFunc0< SteadyState >(
                                     &SteadyState::randomizeInitialCondition )
                               );
    ///////////////////////////////////////////////////////
    // Shared definitions
    ///////////////////////////////////////////////////////

    static Finfo * steadyStateFinfos[] =
    {
        &stoich,				// Value
        &badStoichiometry,		// ReadOnlyValue
        &isInitialized,			// ReadOnlyValue
        &nIter,					// ReadOnlyValue
        &status,				// ReadOnlyValue
        &maxIter,				// Value
        &convergenceCriterion,	// ReadOnlyValue
        &numVarPools,			// ReadOnlyValue
        &rank,					// ReadOnlyValue
        &stateType,				// ReadOnlyValue
        &nNegEigenvalues,		// ReadOnlyValue
        &nPosEigenvalues,		// ReadOnlyValue
        &solutionStatus,		// ReadOnlyValue
        &total,					// LookupValue
        &eigenvalues,			// ReadOnlyLookupValue
        &setupMatrix,			// DestFinfo
        &settle,				// DestFinfo
        &resettle,				// DestFinfo
        &showMatrices,			// DestFinfo
        &randomInit,			// DestFinfo


    };

    static string doc[] =
    {
        "Name", "SteadyState",
        "Author", "Upinder S. Bhalla, 2009, updated 2014, NCBS",
        "Description", "SteadyState: works out a steady-state value for "
        "a reaction system. "
        "This class uses the multidimensional root finder algorithms "
        "to find the fixed points closest to the "
        "current molecular concentrations. "
        "When it finds the fixed points, it figures out eigenvalues of "
        "the solution, as a way to help classify the fixed points. "
        "Note that the method finds unstable as well as stable fixed "
        "points.\n "
        "The SteadyState class also provides a utility function "
        "*randomInit()*	to "
        "randomly initialize the concentrations, within the constraints "
        "of stoichiometry. This is useful if you are trying to find "
        "the major fixed points of the system. Note that this is "
        "probabilistic. If a fixed point is in a very narrow range of "
        "state space the probability of finding it is small and you "
        "will have to run many iterations with different initial "
        "conditions to find it.\n "
        "The numerical calculations used by the SteadyState solver are "
        "prone to failing on individual calculations. All is not lost, "
        "because the system reports the solutionStatus. "
        "It is recommended that you test this field after every "
        "calculation, so you can simply ignore "
        "cases where it failed and try again with different starting "
        "conditions.\n "
        "Another rule of thumb is that the SteadyState object is more "
        "likely to succeed in finding solutions from a new starting point "
        "if you numerically integrate the chemical system for a short "
        "time (typically under 1 second) before asking it to find the "
        "fixed point. "
    };

    static Dinfo< SteadyState > dinfo;
    static Cinfo steadyStateCinfo(
        "SteadyState",
        Neutral::initCinfo(),
        steadyStateFinfos,
        sizeof( steadyStateFinfos )/sizeof(Finfo *),
        &dinfo,
        doc, sizeof( doc ) / sizeof( string )
    );

    return &steadyStateCinfo;
}

static const Cinfo* steadyStateCinfo = SteadyState::initCinfo();

///////////////////////////////////////////////////
// Class function definitions
///////////////////////////////////////////////////

SteadyState::SteadyState()
    :
    nIter_( 0 ),
    maxIter_( 100 ),
    badStoichiometry_( 0 ),
    status_( "OK" ),
    isInitialized_( 0 ),
    isSetup_( 0 ),
    convergenceCriterion_( 1e-7 ),
    stoich_(),
    numVarPools_( 0 ),
    nReacs_( 0 ),
    rank_( 0 ),
    reassignTotal_( 0 ),
    nNegEigenvalues_( 0 ),
    nPosEigenvalues_( 0 ),
    stateType_( 0 ),
    solutionStatus_( 0 ),
    numFailed_( 0 )
{
    rng.setSeed( moose::__rng_seed__ );
}

SteadyState::~SteadyState()
{

}

///////////////////////////////////////////////////
// Field function definitions
///////////////////////////////////////////////////

Id SteadyState::getStoich() const
{
    return stoich_;
}

void SteadyState::setStoich( Id value )
{
    if ( !value.element()->cinfo()->isA( "Stoich" ) )
    {
        cout << "Error: SteadyState::setStoich: Must be of Stoich class\n";
        return;
    }

    stoich_ = value;
    Stoich* stoichPtr = reinterpret_cast< Stoich* >( value.eref().data());
    numVarPools_ = Field< unsigned int >::get( stoich_, "numVarPools" );
    nReacs_ = Field< unsigned int >::get( stoich_, "numRates" );
    setupSSmatrix();
    double vol = LookupField< unsigned int, double >::get(
                     stoichPtr->getCompartment(), "oneVoxelVolume", 0 );
    pool_.setVolume( vol );
    pool_.setStoich( stoichPtr, 0 );
    pool_.updateAllRateTerms( stoichPtr->getRateTerms(),
                              stoichPtr->getNumCoreRates() );
    isInitialized_ = 1;
}

bool SteadyState::badStoichiometry() const
{
    return badStoichiometry_;
}

bool SteadyState::isInitialized() const
{
    return isInitialized_;
}

unsigned int SteadyState::getNiter() const
{
    return nIter_;
}

string SteadyState::getStatus() const
{
    return status_;
}

unsigned int SteadyState::getMaxIter() const
{
    return maxIter_;
}

void SteadyState::setMaxIter( unsigned int value )
{
    maxIter_ = value;
}

unsigned int SteadyState::getRank() const
{
    return rank_;
}

unsigned int SteadyState::getNumVarPools() const
{
    return numVarPools_;
}
unsigned int SteadyState::getStateType() const
{
    return stateType_;
}

unsigned int SteadyState::getNnegEigenvalues() const
{
    return nNegEigenvalues_;
}

unsigned int SteadyState::getNposEigenvalues() const
{
    return nPosEigenvalues_;
}

unsigned int SteadyState::getSolutionStatus() const
{
    return solutionStatus_;
}

void SteadyState::setConvergenceCriterion( double value )
{
    if ( value > 1e-10 )
        convergenceCriterion_ = value;
    else
        cout << "Warning: Convergence criterion " << value <<
             " too small. Old value " <<
             convergenceCriterion_ << " retained\n";
}

double SteadyState::getConvergenceCriterion() const
{
    return convergenceCriterion_;
}

double SteadyState::getTotal( const unsigned int i ) const
{
    if ( i < total_.size() )
        return total_[i];
    cout << "Warning: SteadyState::getTotal: index " << i <<
         " out of range " << total_.size() << endl;
    return 0.0;
}

void SteadyState::setTotal( const unsigned int i, double val )
{
    if ( i < total_.size() )
    {
        total_[i] = val;
        reassignTotal_ = 1;
        return;
    }
    cout << "Warning: SteadyState::setTotal: index " << i <<
         " out of range " << total_.size() << endl;
}

double SteadyState::getEigenvalue( const unsigned int i ) const
{
    if ( i < eigenvalues_.size() )
        return eigenvalues_[i];
    cout << "Warning: SteadyState::getEigenvalue: index " << i <<
         " out of range " << eigenvalues_.size() << endl;
    return 0.0;
}

///////////////////////////////////////////////////
// Dest function definitions
///////////////////////////////////////////////////

// Static func
void SteadyState::setupMatrix()
{
    setupSSmatrix();
}
void SteadyState::settleFunc()
{
    settle( 0 );
}

void SteadyState::resettleFunc()
{
    settle( 1 );
}

// Dummy function
void SteadyState::assignY( double* S )
{
}

void SteadyState::showMatrices()
{
    if ( !isInitialized_ ) {
        cout << "SteadyState::showMatrices: Sorry, the system is not yet initialized.\n";
        return;
    }
    int numConsv = numVarPools_ - rank_;
    cout << "Totals:	";
    for ( int i = 0; i < numConsv; ++i )
        cout << total_[i] << "	";
    cout << endl;
    cout << "gamma " << gamma_ << endl;
    cout << "Nr " << Nr_ << endl;
    cout << "LU " << LU_ << endl;
}

void SteadyState::setupSSmatrix()
{

    if ( numVarPools_ == 0 || nReacs_ == 0 )
        return;

    int nTot = numVarPools_ + nReacs_;

    ublas::matrix<double> N(numVarPools_, nReacs_, 0.0);

    LU_ = ublas::matrix< double >( numVarPools_, nTot, 0.0);

    vector< int > entry = Field< vector< int > >::get(
                              stoich_, "matrixEntry" );
    vector< unsigned int > colIndex = Field< vector< unsigned int > >::get(
                                          stoich_, "columnIndex" );
    vector< unsigned int > rowStart = Field< vector< unsigned int > >::get(
                                          stoich_, "rowStart" );

    for ( unsigned int i = 0; i < numVarPools_; ++i )
    {
        LU_(i, i + nReacs_) = 1;
        unsigned int k = rowStart[i];
        for ( unsigned int j = 0; j < nReacs_; ++j )
        {
            double x = 0;
            if ( j == colIndex[k] && k < rowStart[i+1] )
            {
                x = entry[k++];
            }
            N(i,j) = x;
            LU_(i,j) = x;
        }
    }
    // This function reorgranize LU_.
    rank_ = rankUsingBoost( LU_ );
    Nr_ = ublas::matrix< double >( rank_, nReacs_ );
    Nr_.assign( ublas::zero_matrix< double >( rank_, nReacs_ ) );

    unsigned int nConsv = numVarPools_ - rank_;
    if ( nConsv == 0 )
    {
        cout << "SteadyState::setupSSmatrix(): Number of conserved species == 0. Aborting\n";
        return;
    }

    // Fill up Nr.
    for ( unsigned int i = 0; i < rank_; i++)
        for ( unsigned int j = i; j < nReacs_; j++)
            Nr_(i,j) = LU_(i, j);

    gamma_ = ublas::matrix< double >( nConsv, numVarPools_, 0.0 );

    // Fill up gamma
    for ( unsigned int i = rank_; i < numVarPools_; ++i )
        for ( unsigned int j = 0; j < numVarPools_; ++j )
            gamma_(i-rank_, j) = LU_(i, j+nReacs_);

    // Fill up boundary condition values
    total_.resize( nConsv );
    total_.assign( nConsv, 0.0 );

    Id ksolve = Field< Id >::get( stoich_, "ksolve" );
    vector< double > nVec =
        LookupField< unsigned int, vector< double > >::get(
            ksolve,"nVec", 0 );

    if ( nVec.size() >= numVarPools_ )
    {
        for ( unsigned int i = 0; i < nConsv; ++i )
            for ( unsigned int j = 0; j < numVarPools_; ++j )
                total_[i] += gamma_(i,j) * nVec[ j ];
        isSetup_ = 1;
    }
    else
    {
        cout << "Error: SteadyState::setupSSmatrix(): unable to get"
             "pool numbers from ksolve.\n";
        isSetup_ = 0;
    }

}

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
    }
}

static bool isSolutionValid( const vector< double >& x )
{
    for( size_t i = 0; i < x.size(); i++ )
    {
        double v = x[i];
        if ( std::isnan( v ) or std::isinf( v ) )
        {
            cout << "Warning: SteadyState iteration gave nan/inf concs\n";
            return false;
        }
        else if( v < 0.0 )
        {
            cout << "Warning: SteadyState iteration gave negative concs\n";
            return false;
        }
    }
    return true;
}

/**
 * The settle function computes the steady state nearest the initial
 * conditions.
 */
void SteadyState::settle( bool forceSetup )
{

    if ( !isInitialized_ )
    {
        cout << "Error: SteadyState object has not been initialized. No calculations done\n";
        return;
    }

    if ( forceSetup || isSetup_ == 0 )
        setupSSmatrix();

    // Setting up matrices and vectors for the calculation.
    unsigned int nConsv = numVarPools_ - rank_;
    double * T = (double *) calloc( nConsv, sizeof( double ) );

    // Setting up matrices and vectors for the calculation.
    Id ksolve = Field< Id >::get( stoich_, "ksolve" );

    ss = new NonlinearSystem( numVarPools_ );

    ss->ri.rank = rank_;
    ss->ri.num_reacs = nReacs_;
    ss->ri.num_mols = numVarPools_;
    ss->ri.T = T;
    ss->ri.Nr = Nr_;
    ss->ri.gamma = gamma_;
    ss->ri.pool = &pool_;
    ss->ri.nVec = LookupField< unsigned int, vector< double > >::get(
            ksolve,"nVec", 0
            );
    ss->ri.convergenceCriterion = convergenceCriterion_;

    // This gives the starting point for finding the solution.
    vector<double> init( numVarPools_ );

    // Instead of starting at sqrt( x ),
    for( size_t i = 0; i < numVarPools_; ++i )
        init[i] = max( 0.0, sqrt(ss->ri.nVec[i]) );

    ss->initialize<vector<double>>( init );

    // Fill up boundary condition values
    if ( reassignTotal_ )   // The user has defined new conservation values.
    {
        for (size_t i = 0; i < nConsv; ++i )
            T[i] = total_[i];
        reassignTotal_ = 0;
    }
    else
    {
        for ( size_t i = 0; i < nConsv; ++i )
            for ( size_t j = 0; j < numVarPools_; ++j )
                T[i] += gamma_( i, j ) * ss->ri.nVec[ j ];
        total_.assign( T, T + nConsv );
    }

    vector< double > repair( numVarPools_, 0.0 );

    for ( unsigned int j = 0; j < numVarPools_; ++j )
        repair[j] = ss->ri.nVec[j];


    int status = 1;

    // Find roots . If successful, set status to 0.
    if( ss->find_roots_gnewton( ) )
        status = 0;

    if ( status == 0 && isSolutionValid( ss->ri.nVec ) )
    {
        solutionStatus_ = 0; // Good solution

        LookupField< unsigned int, vector< double > >::set(
            ksolve, "nVec", 0, ss->ri.nVec
            );
        // Check what we set
        vector<double> t = LookupField< unsigned int, vector< double > >::get(
             ksolve,"nVec", 0
             );

        //classifyState( T );
    }
    else
    {
        cout << "Warning: SteadyState iteration failed, status = " <<
             status_ << ", nIter = " << ss->ri.nIter << endl;

        for ( unsigned int j = 0; j < numVarPools_; j++ )
            ss->ri.nVec[j] = repair[j];

        solutionStatus_ = 1; // Steady state failed.
        LookupField< unsigned int, vector< double > >::set(
            ksolve, "nVec", 0, ss->ri.nVec
            );

    }

    // Clean up.
    free( T );
}


/*-----------------------------------------------------------------------------
 *  These functions computes rank of a matrix.
 *-----------------------------------------------------------------------------*/

/**
 * @brief Swap row r1 and r2.
 *
 * @param mat Matrix input
 * @param r1 index of row 1
 * @param r2 index of row 2
 */
void swapRows( ublas::matrix< double >& mat, unsigned int r1, unsigned int r2)
{
    ublas::vector<value_type> temp( mat.size2() );
    for (size_t i = 0; i < mat.size2(); i++)
    {
        temp[i] = mat(r1, i );
        mat(r1, i ) = mat(r2, i );
    }

    for (size_t i = 0; i < mat.size2(); i++)
        mat(r2, i) = temp[i];
}


int reorderRows( ublas::matrix< double >& U, int start, int leftCol )
{
    int leftMostRow = start;
    int numReacs = U.size2() - U.size1();
    int newLeftCol = numReacs;
    for ( size_t i = start; i < U.size1(); ++i )
    {
        for ( int j = leftCol; j < numReacs; ++j )
        {
            if ( fabs( U(i,j )) > SteadyState::EPSILON )
            {
                if ( j < newLeftCol )
                {
                    newLeftCol = j;
                    leftMostRow = i;
                }
                break;
            }
        }
    }

    if ( leftMostRow != start )   // swap them.
        swapRows( U, start, leftMostRow );

    return newLeftCol;
}

void eliminateRowsBelow( ublas::matrix< double >& U, int start, int leftCol )
{
    int numMols = U.size1();
    double pivot = U( start, leftCol );
    assert( fabs( pivot ) > SteadyState::EPSILON );
    for ( int i = start + 1; i < numMols; ++i )
    {
        double factor = U(i, leftCol);
        if( fabs ( factor ) > SteadyState::EPSILON )
        {
            factor = factor / pivot;
            for ( size_t j = leftCol + 1; j < U.size2(); ++j )
            {
                double x = U(i,j);
                double y = U( start, j );
                x -= y * factor;
                if ( fabs( x ) < SteadyState::EPSILON )
                    x = 0.0;
                U( i, j ) = x;
            }
        }
        U(i, leftCol) = 0.0;
    }
}

unsigned int rankUsingBoost( ublas::matrix<double>& U )
{
    int numMols = U.size1();
    int numReacs = U.size2() - numMols;
    int i;
    // Start out with a nonzero entry at 0,0
    int leftCol = reorderRows( U, 0, 0 );

    for ( i = 0; i < numMols - 1; ++i )
    {
        eliminateRowsBelow( U, i, leftCol );
        leftCol = reorderRows( U, i + 1, leftCol );
        if ( leftCol == numReacs )
            break;
    }
    return i + 1;
}


static bool checkAboveZero( const vector< double >& y )
{
    for ( vector< double >::const_iterator
            i = y.begin(); i != y.end(); ++i )
    {
        if ( *i < 0.0 )
            return false;
    }
    return true;
}

/**
 * @brief Utility funtion to doing scans for steady states.
 *
 * @param tot
 * @param g
 * @param S
 */
void recalcTotal( vector< double >& tot, ublas::matrix<double>& g, const double* S )
{
    assert( g.size1() == tot.size() );
    for ( size_t i = 0; i < g.size1(); ++i )
    {
        double t = 0.0;
        for ( unsigned int j = 0; j < g.size2(); ++j )
            t += g( i, j ) * S[j];
        tot[ i ] = t;
    }
}

/**
 * Generates a new set of values for the S vector that is a) random
 * and b) obeys the conservation rules.
 */
void SteadyState::randomizeInitialCondition( const Eref& me )
{
    Id ksolve = Field< Id >::get( stoich_, "ksolve" );
    vector< double > nVec =
        LookupField< unsigned int, vector< double > >::get(
                ksolve,"nVec", 0 );
    int numConsv = total_.size();
    recalcTotal( total_, gamma_, &nVec[0] );
    // The reorderRows function likes to have an I matrix at the end of
    // numVarPools_, so we provide space for it, although only its first
    // column is used for the total vector.
    ublas::matrix<double> U(numConsv, numVarPools_ + numConsv, 0);

    for ( int i = 0; i < numConsv; ++i )
    {
        for ( unsigned int j = 0; j < numVarPools_; ++j )
            U(i, j) = gamma_(i, j);

        U(i, numVarPools_) = total_[i];
    }
    // Do the forward elimination
    int rank = rankUsingBoost( U );
    assert( rank = numConsv );

    vector< double > eliminatedTotal( numConsv, 0.0 );
    for ( int i = 0; i < numConsv; ++i )
        eliminatedTotal[i] = U( i, numVarPools_ );

    // Put Find a vector Y that fits the consv rules.
    vector< double > y( numVarPools_, 0.0 );
    do
    {
        fitConservationRules( U, eliminatedTotal, y );
    }
    while ( !checkAboveZero( y ) );

    // Sanity check. Try the new vector with the old gamma and tots
    for ( int i = 0; i < numConsv; ++i )
    {
        double tot = 0.0;
        for ( unsigned int j = 0; j < numVarPools_; ++j )
        {
            tot += y[j] * gamma_( i, j );
        }
        assert( fabs( tot - total_[i] ) / tot < EPSILON );
    }

    // Put the new values into S.
    // cout << endl;
    for ( unsigned int j = 0; j < numVarPools_; ++j )
    {
        nVec[j] = y[j];
        // cout << y[j] << " ";
    }
    LookupField< unsigned int, vector< double > >::set(
        ksolve,"nVec", 0, nVec );
}

/**
 * This does the actual work of generating random numbers and
 * making sure they fit.
 */
void SteadyState::fitConservationRules(
    ublas::matrix<double>& U, const vector< double >& eliminatedTotal,
    vector< double >&y
)
{
    int numConsv = total_.size();
    int lastJ = numVarPools_;
    for ( int i = numConsv - 1; i >= 0; --i )
    {
        for ( unsigned int j = 0; j < numVarPools_; ++j )
        {
            double g = U( i, j );
            if ( fabs( g ) > EPSILON )
            {
                // double ytot = calcTot( g, i, j, lastJ );
                double ytot = 0.0;
                for ( int k = j; k < lastJ; ++k )
                {
                    y[k] = rng.uniform( );
                    ytot += y[k] * U( i, k );
                }
                assert( fabs( ytot ) > EPSILON );
                double lastYtot = 0.0;
                for ( unsigned int k = lastJ; k < numVarPools_; ++k )
                {
                    lastYtot += y[k] * U( i, k );
                }
                double scale = ( eliminatedTotal[i] - lastYtot ) / ytot;
                for ( int k = j; k < lastJ; ++k )
                {
                    y[k] *= scale;
                }
                lastJ = j;
                break;
            }
        }
    }
}