#ifndef _KORALI_BASEPARAMETER_H_
#define _KORALI_BASEPARAMETER_H_

#include <string>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_math.h>
#include <gsl/gsl_sf.h>

namespace Korali::Parameter
{

class Base
{
 public:
 Base(std::string name);
 gsl_rng* _range;

 std::string _name;
 double _lowerBound;
 double _upperBound;

 void setBounds(double lowerBound, double upperBound) { _lowerBound = lowerBound;	_upperBound = upperBound; }
 void setName(std::string name)    { _name = name; }
 void initializeDistribution(int seed);
 void checkBounds();

 virtual double getDensity(double x) = 0;
 virtual double getDensityLog(double x) = 0;
 virtual double getRandomNumber() = 0;
};

} // namespace Korali

#endif // _KORALI_BASEPARAMETER_H_


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*                                                                           */
/*                  This file is part of the program                         */
/*          GCG --- Generic Column Generation                                */
/*                  a Dantzig-Wolfe decomposition based extension            */
/*                  of the branch-cut-and-price framework                    */
/*         SCIP --- Solving Constraint Integer Programs                      */
/*                                                                           */
/* Copyright (C) 2010-2019 Operations Research, RWTH Aachen University       */
/*                         Zuse Institute Berlin (ZIB)                       */
/*                                                                           */
/* This program is free software; you can redistribute it and/or             */
/* modify it under the terms of the GNU Lesser General Public License        */
/* as published by the Free Software Foundation; either version 3            */
/* of the License, or (at your option) any later version.                    */
/*                                                                           */
/* This program is distributed in the hope that it will be useful,           */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
/* GNU Lesser General Public License for more details.                       */
/*                                                                           */
/* You should have received a copy of the GNU Lesser General Public License  */
/* along with this program; if not, write to the Free Software               */
/* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.*/
/*                                                                           */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/**@file   graph_gcg.h
 * @brief  Implementation of the graph which supports both node and edge weights.
 * @author Igor Pesic
 */

/*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/

#ifndef GCG_GRAPH_GCG_H_
#define GCG_GRAPH_GCG_H_

#include <map>
#include "bridge.h"

#ifdef WITH_GSL
   #include <gsl/gsl_spmatrix.h>
   #include <gsl/gsl_spblas.h>
#endif

namespace gcg {

class EdgeGCG
{
public:
    int src, dest;
    double weight;
    EdgeGCG() {}
    EdgeGCG(int s, int d, double w): src(s), dest(d), weight(w) {}
} ;

class GraphGCG: public gcg::Bridge
{
private:
   bool undirected;
   bool locked;           // true if we are not allowed to change the graph anymore
   bool initialized;      // true if at least 1 node
   std::vector<int> nodes;
#ifdef WITH_GSL
   gsl_spmatrix* adj_matrix_sparse;
   gsl_spmatrix* working_adj_matrix;      // this one is used ONLY during MCL algorithm!
#else
   std::vector<std::vector<double>> adj_matrix;      /** For undirected graphs, this matrix is symmetrical */
#endif
   std::vector<EdgeGCG*> edges;

public:

   GraphGCG();
   GraphGCG(int _n_nodes, bool _undirected);

   virtual ~GraphGCG();
   virtual SCIP_RETCODE addNNodes(int _n_nodes);
   virtual SCIP_RETCODE addNNodes(int _n_nodes, std::vector<int> weights);
   virtual int getNNodes();
   virtual int getNEdges();

#ifdef WITH_GSL
   virtual gsl_spmatrix* getAdjMatrix();
   virtual void expand(int factor);
   virtual void inflate(double factor);
   virtual void colL1Norm();
   virtual void prune();
   virtual bool stopMCL(int iter);
   virtual std::vector<int> getClustersMCL();
   virtual void initMCL();
   virtual void clearMCL();
#else
   virtual std::vector<std::vector<double>> getAdjMatrix();
#endif
   virtual SCIP_RETCODE getEdges(std::vector<void*>& edges);
   virtual SCIP_Bool isEdge(int node_i, int node_j);
   virtual int getNNeighbors(int node);
   virtual std::vector<int> getNeighbors(int node);
   virtual std::vector<std::pair<int, double> > getNeighborWeights(int node);
   virtual SCIP_RETCODE addNode(int node, int weight);
   virtual SCIP_RETCODE addNode();                    /** Sets node weight to 0 and the ID to the next available. */
   virtual SCIP_RETCODE deleteNode(int node);
   virtual SCIP_RETCODE addEdge(int i, int j);        /** Sets edge weight to 1. */
   virtual SCIP_RETCODE addEdge(int node_i, int node_j, double weight);
   virtual SCIP_RETCODE setEdge(int node_i, int node_j, double weight);
   virtual SCIP_RETCODE deleteEdge(int node_i, int node_j);
   virtual int graphGetWeights(int node);
   virtual double getEdgeWeight(int node_i, int node_j);

   virtual int edgeComp(const EdgeGCG* a, const EdgeGCG* b);

   virtual SCIP_RETCODE flush();       // lock the graph and compresses the adj matrix if we use GSL
   virtual SCIP_RETCODE normalize();
   virtual double getEdgeWeightPercentile(double q);
};

} /* namespace gcg */
#endif /* GCG_GRAPH_GCG_H_ */


#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <math.h>
#include <gbpLib.h>
#include <gbpMCMC.h>
#include <gsl/gsl_linalg.h>
#include <gsl/gsl_fit.h>
#include <gsl/gsl_interp.h>

void add_MCMC_DS(MCMC_info *MCMC, const char *name, int n_D, int *D, double *DS, double *dDS, void *params, int n_arrays, ...) {
    int           i_array;
    int           i_D;
    int           n_M;
    MCMC_DS_info *new_DS;
    va_list       vargs;
    va_start(vargs, n_arrays);

    SID_log("Adding data set {%s} to MCMC structure...", SID_LOG_OPEN, name);

#if USE_CFITSIO == 0
    if(n_D > 1)
        SID_exit_error("You can only use 2D datasets if you compile with USE_CFITSIO=1 at the moment.", SID_ERROR_LOGIC);
#endif

    // Initialize new dataset
    init_MCMC_DS(&new_DS, name, n_D, D, DS, dDS, params, n_arrays, vargs);

    // Add new dataset to linked list
    if(MCMC->DS == NULL)
        MCMC->DS = new_DS;
    else
        MCMC->last->next = new_DS;
    MCMC->last = new_DS;

    MCMC->n_DS++;

    SID_log("Done.", SID_LOG_CLOSE);

    va_end(vargs);
}


/**
 *
 * @file qwrapper_dsygst.c
 *
 *  PLASMA core_blas quark wrapper
 *  PLASMA is a software package provided by Univ. of Tennessee,
 *  Univ. of California Berkeley and Univ. of Colorado Denver
 *
 * @version 2.6.0
 * @author Hatem Ltaief
 * @date 2010-11-15
 * @generated d Tue Jan  7 11:44:59 2014
 *
 **/
#include <lapacke.h>
#include "common.h"

#undef COMPLEX
#define REAL

/***************************************************************************//**
 *
 **/
void QUARK_CORE_dsygst(Quark *quark, Quark_Task_Flags *task_flags,
                       int itype, PLASMA_enum uplo, int n,
                       double *A, int lda,
                       double *B, int ldb,
                       PLASMA_sequence *sequence, PLASMA_request *request,
                       int iinfo)
{
    QUARK_Insert_Task(quark, CORE_dsygst_quark, task_flags,
        sizeof(int),                        &itype,      VALUE,
        sizeof(PLASMA_enum),                &uplo,      VALUE,
        sizeof(int),                        &n,         VALUE,
        sizeof(double)*lda*n,    A,             INOUT,
        sizeof(int),                        &lda,       VALUE,
#ifdef COMPLEX
        sizeof(double)*ldb*n,    B,             INOUT,
#else
        sizeof(double)*ldb*n,    B,             INPUT,
#endif
        sizeof(int),                        &ldb,       VALUE,
        sizeof(PLASMA_sequence*),           &sequence,  VALUE,
        sizeof(PLASMA_request*),            &request,   VALUE,
        sizeof(int),                        &iinfo,     VALUE,
        0);
}

/***************************************************************************//**
 *
 **/
#if defined(PLASMA_HAVE_WEAK)
#pragma weak CORE_dsygst_quark = PCORE_dsygst_quark
#define CORE_dsygst_quark PCORE_dsygst_quark
#endif
void CORE_dsygst_quark(Quark *quark)
{
    int itype;
    PLASMA_enum uplo;
    int n;
    double *A;
    int lda;
    double *B;
    int ldb;
    PLASMA_sequence *sequence;
    PLASMA_request *request;
    int iinfo;

    int info;

    quark_unpack_args_10(quark, itype, uplo, n, A, lda, B, ldb, sequence, request, iinfo);
    info = LAPACKE_dsygst_work(
        LAPACK_COL_MAJOR,
        itype,
        lapack_const(uplo),
        n, A, lda, B, ldb);
    if (sequence->status == PLASMA_SUCCESS && info != 0)
      plasma_sequence_flush(quark, sequence, request, iinfo+info);
}


/*
* -----------------------------------------------------------------
*  Thermochemistry Library --- thrm_lib.c
*  Version: 1.6180
*  Date: Mar 15, 2010
* -----------------------------------------------------------------
*  Programmer: Americo Barbosa da Cunha Junior
*              americo.cunhajr@gmail.com
* -----------------------------------------------------------------
*  Copyright (c) 2010 by Americo Barbosa da Cunha Junior
*
*  This program is free software: you can redistribute it and/or
*  modify it under the terms of the GNU General Public License as
*  published by the Free Software Foundation, either version 3 of
*  the License, or (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  A copy of the GNU General Public License is available in
*  LICENSE.txt or http://www.gnu.org/licenses/.
* -----------------------------------------------------------------
*  This is the implementation file of a library
*  with thermochemistry routines.
* -----------------------------------------------------------------
*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_math.h>

#include "../include/cklib.h"
#include "../include/ckthrm.h"
#include "../include/thrm_lib.h"

/*
*------------------------------------------------------------
*   thrm_title
*
*   This function prints the program title on the screen
*
*   last update: Oct 20, 2009
* -----------------------------------------------------------------
*/

void thrm_title()
{
    time_t curtime = time (NULL);
    struct tm *loctime = localtime (&curtime);

    printf("\n");
    printf("=============================================");
    printf("\n Themochemistry Direct Simulation\n");
    printf("\n Author:");
    printf("\n Americo Barbosa da Cunha Junior --- PUC-Rio");
    printf("\n americo.cunhajr@gmail.com\n");
    printf("\n Date:");
    printf("\n %s", asctime(loctime) );
    printf("=============================================");
    printf("\n");

    return;
}

/*
*------------------------------------------------------------
*   thrm_mech
*
*   This function prints on the screen informations about the
*   chemical kinetics mechanism
*
*   Input:
*   n_e  - # of elements
*   n_s  - # of species
*   n_r  - # of reactions
*   mech - mechanism name
*
*   last update: Jul 22, 2009
*------------------------------------------------------------
*/

void thrm_mech(int n_e,int n_s,int n_r,char *mech)
{
    printf("\n");
    printf("\n Thermochemistry Mechanism: %s", mech);
    printf("\n # of elements  = %d", n_e);
    printf("\n # of species   = %d", n_s);
    printf("\n # of reactions = %d", n_r);
    printf("\n");
    printf("\n");

    return;
}
/*------------------------------------------------------------*/

/*
* -----------------------------------------------------------------
*   thrm_input
*
*   This function receives the pmsr parameters
*   and returns GSL_SUCCESS if there is no error.
*
*   Input:
*   Np       - # of particles
*   k        - # of discrete time steps
*   delta_t  - time step
*   tau_res  - residence time
*   tau_mix  - mixture time
*   tau_pair - pairwize time
*
*   Output:
*   success or error
*
*   last update: Feb 5, 2009
* -----------------------------------------------------------------
*/

int thrm_input(int *steps,double *t0,double *delta_t,
                            double *Tmax,double *Tmin,double *tol)
{
    printf("\n Input simulation parameters:\n");

    printf("\n # of integration steps:");
    scanf("%d", steps);
    printf("\n %d\n", *steps);
    if( *steps <= 0 )
	return GSL_EINVAL;

    printf("\n initial time:");
    scanf("%lf", t0);
    printf("\n %+.1e\n", *t0);
    if( *t0 < 0.0 )
	return GSL_EINVAL;

    printf("\n time step:");
    scanf("%lf", delta_t);
    printf("\n %+.1e\n", *delta_t);
    if( *delta_t <= 0.0 )
	return GSL_EINVAL;

    printf("\n temperature upper bound:");
    scanf("%lf", Tmax);
    printf("\n %+.1e\n", *Tmax);
    if( *Tmax < 0.0 )
	return GSL_EINVAL;

    printf("\n temperature lower bound:");
    scanf("%lf", Tmin);
    printf("\n %+.1e\n", *Tmin);
    if( *Tmin < 0.0 || *Tmin > *Tmax )
	return GSL_EINVAL;

    printf("\n tolerance:");
    scanf("%lf", tol);
    printf("\n %+.1e\n", *tol);
    if( *tol <= 0.0 )
	return GSL_EINVAL;

    return GSL_SUCCESS;
}
/*----------------------------------------------------------------*/

/*
*------------------------------------------------------------
*   thrm_alloc
*
*   This function allocates a struct thermochemistry.
*
*   Output:
*   thrm - pointer to a struct thermochemistry
*
*   last update: May 10, 2009
*------------------------------------------------------------
*/

thrm_wrk* thrm_alloc()
{
    thrm_wrk *thrm = NULL;

    /* memory allocation for ck_wrk struct */
    thrm = (thrm_wrk *) malloc(sizeof(thrm_wrk));
    if ( thrm == NULL )
        return NULL;

    /* setting ck_wrk elements equal NULL and 0.0 */
    thrm->iwk    = NULL;
    thrm->rwk    = NULL;
    thrm->cwk    = NULL;
    thrm->leniwk = 0;
    thrm->lenrwk = 0;
    thrm->lencwk = 0;
    thrm->n_e    = 0;
    thrm->n_s    = 0;
    thrm->n_r    = 0;

    return thrm;
}
/*------------------------------------------------------------*/

/*
*------------------------------------------------------------
*   thrm_free
*
*   This function frees the memory used by CK work vectors
*
*   Input:
*   thrm - pointer to a struct chemkin
*
*   Output:
*   void
*
*   last update: Jul 21, 2009
*------------------------------------------------------------
*/

void thrm_free(void **thrm_bl)
{
    thrm_wrk* thrm = NULL;

    /* checking if thrm_bl is NULL */
    if ( *thrm_bl == NULL )
        return;

    thrm = (thrm_wrk *) (*thrm_bl);

    /* releasing ck work vectors */
    if( thrm->iwk != NULL )
    {
        free(thrm->iwk);
        thrm->iwk = NULL;
    }

    if( thrm->rwk != NULL )
    {
        free(thrm->rwk);
        thrm->rwk = NULL;
    }

    if( thrm->cwk != NULL )
    {
        free(thrm->cwk);
        thrm->cwk = NULL;
    }

    /* releasing thrm struct */
    free(*thrm_bl);
    *thrm_bl = NULL;

    return;
}
/*------------------------------------------------------------*/

/*
*------------------------------------------------------------
*   thrm_init
*
*   This function initiates chemkin work vectors and the
*   mechanism parameters.
*
*   Input:
*   thrm - pointer to a struct thermochemistry
*
*   Output:
*   success or error
*
*   last update: Feb 19, 2010
*------------------------------------------------------------
*/

int thrm_init(thrm_wrk *thrm)
{
    if ( thrm == NULL )
        return GSL_EINVAL;

    /* calling ck_wrk_len subroutine */
    ck_wrk_len(&(thrm->leniwk),&(thrm->lenrwk),&(thrm->lencwk));

    /* memory allocation for ck work vectors */
    thrm->iwk =    (int *) malloc(   (thrm->leniwk)*sizeof(int));
    thrm->rwk = (double *) malloc(   (thrm->lenrwk)*sizeof(double));
    thrm->cwk =   (char *) malloc(16*(thrm->lencwk)*sizeof(char));
    if ( thrm->iwk == NULL || thrm->rwk == NULL || thrm->cwk == NULL )
    {
        thrm_free((void **)&thrm);
        return GSL_ENOMEM;
    }

    /* calling ck_wrk_init subroutine */
    ck_wrk_init(&(thrm->leniwk),&(thrm->lenrwk),&(thrm->lencwk),
        thrm->iwk,thrm->rwk,thrm->cwk);

    /* calling ck_wrk_indx subroutine */
    ck_wrk_indx(thrm->iwk,thrm->rwk,&(thrm->n_e),&(thrm->n_s),&(thrm->n_r));

    return GSL_SUCCESS;
}
/*------------------------------------------------------------*/

/*
*------------------------------------------------------------
*   thrm_composition
*
*   This function sets composition vector with values.
*
*   Input:
*   thrm - pointer to a struct thermochemistry
*
*   Output:
*   phi - composition vector
*   success or error
*
*   last update: Mar 2, 2010
*------------------------------------------------------------
*/

void thrm_composition(thrm_wrk *thrm,gsl_vector *phi)
{
    /* calling ck_wrk_comp subroutine */
    ck_composition(&(thrm->n_s),thrm->iwk,thrm->rwk,thrm->cwk,phi->data);

    return;
}
/*------------------------------------------------------------*/

/*
*------------------------------------------------------------
*   thrm_page_heading0
*
*   This function prints the properties names on the screen.
*
*   Input:
*   thrm - pointer to a struct thermochemistry
*
*   last update: Nov 6, 2009
*------------------------------------------------------------
*/

void thrm_page_heading0(FILE *file)
{
    fprintf(file," t(s)      ");
    fprintf(file," T(K)      ");
    fprintf(file," h         ");
    fprintf(file," p         ");
    fprintf(file," CO2       ");
    fprintf(file," O2        ");
    fprintf(file," CO        ");
    fprintf(file," O         ");

    return;
}
/*------------------------------------------------------------*/

/*
*------------------------------------------------------------
*   thrm_h2T
*
*   This function computes the mixture temperature for a
*   given enthalpy, pressure and species mass fraction.
*
*   Input:
*   ck  - pointer to a struct chemkin
*   phi - composition vector
*
*   Output:
*   T   - mixture temperature
*
*   last update: Mar 2, 2010
*------------------------------------------------------------
*/

double thrm_h2T(thrm_wrk *thrm,double *phi,double Tmax,double Tmin,double tol)
{
    double T = 0.0;

    ck_h2t_bisec(&(thrm->n_s),phi,&Tmax,&Tmin,&tol,thrm->iwk,thrm->rwk,&T);
    /*ck_h2t_newt(&(thrm->n_s),phi,&tol,thrm->iwk,thrm->rwk,&T,&T);*/

    return T;
}
/*------------------------------------------------------------*/

/*
* -----------------------------------------------------------------
*   thrm_temp_meanvar
*
*   This function computes the temperature mean and variance
*   using the algorithm of Knuth/Welford.
*
*   Ref.:
*   D. E. Knuth (1998)
*   The Art of Computer Programming,
*   volume 2: Seminumerical Algorithms
*   3rd ed., Addison-Wesley.
*
*   B. P. Welford (1962).
*   "Note on a method for calculating corrected sums
*   of squares and products". Technometrics 4(3):419–420
*
*   Input:
*   Np   - # of particles
*   ps   - system of particle
*   thrm - pointer to a struct thermochemistry
*   Tmax - temperature upper bound
*   Tmin - temperature lower bound
*   tol  - tolerance
*   mean - temperature mean
*   var  - temperature variance
*
*   Output:
*   success or error
*
*   last update: Mar 4, 2010
* -----------------------------------------------------------------
*/

void thrm_temp_meanvar(int Np,gsl_vector **ps,thrm_wrk *thrm,
        double Tmax,double Tmin,double tol,double *mean,double *var)
{
    int i;
    double T     = 0.0;
    double S     = 0.0;
    double M     = 0.0;
    double delta = 0.0;

    for ( i = 0; i < Np; i++ )
    {
        T     = thrm_h2T(thrm,ps[i]->data,Tmax,Tmin,tol);
	delta = T - M;
	M    += delta/(double) (i+1);
        S    += delta*(T - M);
    }

    /* mean */
    *mean  = M;

    /* variance */
    *var   = S/(double) (i-1);

    return;
}
/*----------------------------------------------------------------*/

/*
*------------------------------------------------------------
*   thrm_rrsum
*
*   This function computes the reaction rates sum given the
*   reaction rate vector.
*
*   Input:
*   phi - composition vector
*
*   Output:
*   sum - reaction rates sum
*
*   last update: Sep 28, 2009
*------------------------------------------------------------
*/

double thrm_rrsum(gsl_vector *phi)
{
    unsigned int i;
    double sum = 0.0;

    for (i = 2; i < phi->size; i++)
        sum += phi->data[i];

    return sum;
}
/*------------------------------------------------------------*/

/*
*------------------------------------------------------------
*   thrm_mfsum
*
*   This function computes the mass fraction sum given a
*   composition vector.
*
*   Input:
*   phi - composition vector
*
*   Output:
*   sum - mass fraction sum
*
*   last update: Sep 24, 2009
*------------------------------------------------------------
*/

double thrm_mfsum(gsl_vector *phi)
{
    unsigned int i;
    double sum = 0.0;

    for (i = 2; i < phi->size; i++)
        sum += phi->data[i];

    return sum;
}
/*------------------------------------------------------------*/

/*
*------------------------------------------------------------
*   thrm_mfsign
*
*   This function checks if the mass fraction
*   components are all positive in a composition vector.
*
*   Input:
*   phi  - composition vector
*
*   Output:
*   flag - success or fail
*
*   last update: Sep 28, 2009
*------------------------------------------------------------
*/

int thrm_mfsign(gsl_vector *phi)
{
    unsigned int i;
    int flag = GSL_SUCCESS;

    for (i = 2; i < phi->size; i++)
        if ( phi->data[i] < 0.0 )
            flag = GSL_EFAILED;

    return flag;
}
/*------------------------------------------------------------*/

/*
*------------------------------------------------------------
*   thrm_eqs
*
*   This function defines the set of governing diferential
*   equations, one for enthalpy, one for pressure and ns
*   for species mass fractions.
*
*   Input:
*   t         - instant time
*   phi       - composition vector
*   Sphi      - reaction rate vector
*   thrm_data - pointer to external data
*
*   Output:
*   success or error
*
*   last update: Feb 19, 2010
*------------------------------------------------------------
*/

int thrm_eqs(double t,N_Vector phi,N_Vector Sphi,void *thrm_data)
{
    int i, Neq;
    double tol = 1.0e-4;
    double Tmax = 5000.0, Tmin = 100.0;
    double p, T, rho;
    double *phi_data  = NULL;
    double *Sphi_data = NULL;
    double *wdot      = NULL;
    double *wt        = NULL;
    thrm_wrk *thrm    = NULL;

    /* initiating ck workspace */
    thrm = (thrm_wrk *)thrm_data;
    if ( thrm == NULL )
        return GSL_EINVAL;

    /* obtaining phi and Rphi length and components */
    Neq       = NV_LENGTH_S(phi);
    phi_data  = NV_DATA_S(phi);
    Sphi_data = NV_DATA_S(Sphi);

    /* memory allocation for species molar mass and reaction rate vectors */
    wt   = (double *) malloc((Neq-2)*sizeof(double));
    wdot = (double *) malloc((Neq-2)*sizeof(double));
    if( wt == NULL || wdot == NULL )
    {
        free(wt);
        free(wdot);
        return GSL_ENOMEM;
    }

    /* pressure (dynes/cm^2) */
    p = phi_data[1];

    /* mixture temperature (K) */
    T = thrm_h2T(thrm,phi_data,Tmax,Tmin,tol);
    if( T < tol )
        return GSL_EFAILED;

    /* mixture density (g/cm^3)*/
    ckrhoy(&p,&T,&(phi_data[2]),thrm->iwk,thrm->rwk,&rho);

    /* species molar weight (g/mol) */
    ckwt(thrm->iwk,thrm->rwk,wt);

    /* species molar production rates (mol/(cm^3.s)) */
    ckwyp(&p,&T,&(phi_data[2]),thrm->iwk,thrm->rwk,wdot);

    /* dh/dt = 0 (isoenthalpic) */
    Sphi_data[0] = 0.0;

    /* dp/dt = 0 (isobaric) */
    Sphi_data[1] = 0.0;

    /* dY[i]/dt = wdot[i-2].wt[i-2]/rho */
    for ( i = 2; i < Neq; i++ )
        Sphi_data[i] = wdot[i-2]*wt[i-2]/rho;

    /* releasing allocated memory */
    free(wdot);
    free(wt);
    phi_data  = NULL;
    Sphi_data = NULL;
    wdot      = NULL;
    wt        = NULL;
    thrm      = NULL;

    return GSL_SUCCESS;
}
/*------------------------------------------------------------*/

/*
*------------------------------------------------------------
*   thrm_eqs2
*
*   This function defines the set of governing diferential
*   equations, one for temperature and ns
*   for species mass fractions.
*
*   Input:
*   t         - instant time
*   phi       - state vector
*   Sphi      - reaction rate vector
*   thrm_data - pointer to external data
*
*   Output:
*   success or error
*
*   last update: Dec 28, 2010
*------------------------------------------------------------
*/

int thrm_eqs2(double t,N_Vector phi,N_Vector Sphi,void *thrm_data)
{
    int i, Neq;
    double T, p, rho, cpb, sum = 0.0;
    double *phi_data  = NULL;
    double *Sphi_data = NULL;
    double *wdot      = NULL;
    double *wt        = NULL;
    double *h         = NULL;
    thrm_wrk *thrm    = NULL;

    /* initiating ck workspace */
    thrm = (thrm_wrk *)thrm_data;
    if ( thrm == NULL )
        return GSL_EINVAL;

    /* obtaining phi and Rphi length and components */
    Neq       = NV_LENGTH_S(phi);
    phi_data  = NV_DATA_S(phi);
    Sphi_data = NV_DATA_S(Sphi);

    /* memory allocation for species molar mass and reaction rate vectors */
    wt   = (double *) malloc((Neq-2)*sizeof(double));
    wdot = (double *) malloc((Neq-2)*sizeof(double));
    h    = (double *) malloc((Neq-2)*sizeof(double));
    if( wt == NULL || wdot == NULL || h == NULL)
    {
        free(wt);
        free(wdot);
	free(h);
        return GSL_ENOMEM;
    }

    /* mixture temperature (K) */
    T = phi_data[0];

    /* pressure (dynes/cm^2) */
    p = phi_data[1];

    /* mixture density (g/cm^3)*/
    ckrhoy(&p,&T,&(phi_data[2]),thrm->iwk,thrm->rwk,&rho);

    /* mean specific heat at constant pressure (ergs/g.K) */
    ckcpbs(&T,&(phi_data[2]),thrm->iwk,thrm->rwk,&cpb);

    /* species molar weight (g/mol) */
    ckwt(thrm->iwk,thrm->rwk,wt);

    /* species molar production rates (mol/(cm^3.s)) */
    ckwyp(&p,&T,&(phi_data[2]),thrm->iwk,thrm->rwk,wdot);

    /* species specific enthalpy (ergs/g) */
    ckhms(&T,thrm->iwk,thrm->rwk,h);

    /* dY[i+2]/dt = wdot[i].wt[i]/rho */
    for ( i = 0; i < thrm->n_s; i++ )
    {
        Sphi_data[i+2] = wdot[i]*wt[i]/rho;
	sum += h[i]*wdot[i]*wt[i];
    }

    /* dT/dt =  -1/(rho.cpb) . sum_i=1^ns h[i].wdot[i].wt[i] */
    Sphi_data[0] = -sum/(rho*cpb);

    /* dp/dt = 0 (isobaric) */
    Sphi_data[1] = 0.0;

    /* releasing allocated memory */
    free(wdot);
    free(wt);
    free(h);
    phi_data  = NULL;
    Sphi_data = NULL;
    wdot      = NULL;
    wt        = NULL;
    h         = NULL;
    thrm      = NULL;

    return GSL_SUCCESS;
}
/*------------------------------------------------------------*/