/**
 *  @file FixedChemPotSSTP.cpp
 * Definition file for the FixedChemPotSSTP class, which represents a fixed-composition
 * incompressible substance with a constant chemical potential (see \ref thermoprops and
 * class \link Cantera::FixedChemPotSSTP FixedChemPotSSTP\endlink)
 */

/*
 * Copyright (2005) Sandia Corporation. Under the terms of
 * Contract DE-AC04-94AL85000 with Sandia Corporation, the
 * U.S. Government retains certain rights in this software.
 */

#include "cantera/base/ct_defs.h"
#include "cantera/thermo/mix_defs.h"
#include "cantera/thermo/FixedChemPotSSTP.h"
#include "cantera/thermo/SpeciesThermo.h"
#include "cantera/thermo/ThermoFactory.h"


#include <string>
#include "cantera/thermo/SimpleThermo.h"
namespace Cantera
{
/*
 * ----  Constructors -------
 */

FixedChemPotSSTP::FixedChemPotSSTP() :
    SingleSpeciesTP(),
    chemPot_(0.0)
{
}

FixedChemPotSSTP::FixedChemPotSSTP(const std::string& infile, std::string id_) :
    SingleSpeciesTP(),
    chemPot_(0.0)
{
    XML_Node* root = get_XML_File(infile);
    if (id_ == "-") {
        id_ = "";
    }
    XML_Node* xphase = get_XML_NameID("phase", std::string("#")+id_, root);
    if (!xphase) {
        throw CanteraError("FixedChemPotSSTP::FixedChemPotSSTP",
                           "Couldn't find phase name in file:" + id_);
    }
    // Check the model name to ensure we have compatibility
    const XML_Node& th = xphase->child("thermo");
    std::string model = th["model"];
    if (model != "StoichSubstance" && model != "StoichSubstanceSSTP" && model != "FixedChemPot") {
        throw CanteraError("FixedChemPotSSTP::FixedChemPotSSTP",
                           "thermo model attribute must be FixedChemPot or StoichSubstance");
    }
    importPhase(*xphase, this);
}
FixedChemPotSSTP::FixedChemPotSSTP(XML_Node& xmlphase, const std::string& id_) :
    SingleSpeciesTP(),
    chemPot_(0.0)
{
    if (id_ != "") {
        std::string idxml = xmlphase["id"];
        if (id_ != idxml) {
            throw CanteraError("FixedChemPotSSTP::FixedChemPotSSTP",
                               "id's don't match");
        }
    }
    const XML_Node& th = xmlphase.child("thermo");
    std::string model = th["model"];
    if (model != "StoichSubstance" && model != "StoichSubstanceSSTP" && model != "FixedChemPotSSTP") {
        throw CanteraError("FixedChemPotSSTP::FixedChemPotSSTP",
                           "thermo model attribute must be StoichSubstance or FixedChemPot");
    }
    importPhase(xmlphase, this);

    if (model ==  "StoichSubstance" || model == "StoichSubstanceSSTP") {
        _updateThermo();
        chemPot_ = (m_h0_RT[0] - m_s0_R[0]) * GasConstant * temperature();
    }
}

FixedChemPotSSTP::FixedChemPotSSTP(const std::string& Ename, doublereal val) :
    SingleSpeciesTP(),
    chemPot_(0.0)
{

    std::string pname = Ename + "Fixed";
    setID(pname);
    setName(pname);
    setNDim(3);
    addUniqueElement(Ename, -12345.);
    freezeElements();
    vector_fp ecomp(nElements(), 0.0);
    ecomp[0] = 1.0;
    double chrg = 0.0;
    SpeciesThermo* spth = new SimpleThermo();
    setSpeciesThermo(spth);
    addUniqueSpecies(pname, &ecomp[0], chrg, 0.0);
    double c[4];
    c[0] = 298.15;
    c[1] = val;
    c[2] = 0.0;
    c[3] = 0.0;
    m_spthermo->install(pname, 0, SIMPLE, c, 0.0, 1.0E30, OneAtm);
    freezeSpecies();
    initThermo();
    m_p0 = OneAtm;
    m_tlast = 298.15;
    setChemicalPotential(val);

    // Create an XML_Node entry for this species
    XML_Node* s = new XML_Node("species", 0);
    s->addAttribute("name", pname);
    std::string aaS = Ename + ":1";
    s->addChild("atomArray", aaS);
    XML_Node& tt = s->addChild("thermo");
    XML_Node& ss = tt.addChild("Simple");
    ss.addAttribute("Pref", "1 bar");
    ss.addAttribute("Tmax", "5000.");
    ss.addAttribute("Tmin", "100.");
    ss.addChild("t0", "298.15");
    ss.addChild("cp0", "0.0");
    std::string sval = fp2str(val);
    ss.addChild("h", sval);
    ss.addChild("s", "0.0");
    saveSpeciesData(0, s);
    delete s;
    s = 0;
}

FixedChemPotSSTP::FixedChemPotSSTP(const FixedChemPotSSTP&  right) :
    SingleSpeciesTP()
{
    *this = operator=(right);
}

FixedChemPotSSTP&
FixedChemPotSSTP::operator=(const FixedChemPotSSTP& right)
{
    if (&right != this) {
        SingleSpeciesTP::operator=(right);

        chemPot_ = right.chemPot_;
    }
    return *this;
}

FixedChemPotSSTP::~FixedChemPotSSTP()
{
}

ThermoPhase* FixedChemPotSSTP::duplMyselfAsThermoPhase() const
{
    return new FixedChemPotSSTP(*this);
}

/*
 * ---- Utilities -----
 */

int FixedChemPotSSTP::eosType() const
{
    return cFixedChemPot;
}

/*
 * ----- Mechanical Equation of State ------
 */

doublereal FixedChemPotSSTP::pressure() const
{
    return m_press;
}

void FixedChemPotSSTP::setPressure(doublereal p)
{
    m_press = p;
}

doublereal FixedChemPotSSTP::isothermalCompressibility() const
{
    return 0.0;
}

doublereal FixedChemPotSSTP::thermalExpansionCoeff() const
{
    return 0.0;
}

/*
 * ---- Chemical Potentials and Activities ----
 */

void FixedChemPotSSTP::getActivityConcentrations(doublereal* c) const
{
    c[0] = 1.0;
}

doublereal FixedChemPotSSTP::standardConcentration(size_t k) const
{
    return 1.0;
}

doublereal FixedChemPotSSTP::logStandardConc(size_t k) const
{
    return 0.0;
}

void FixedChemPotSSTP::
getUnitsStandardConc(doublereal* uA, int k, int sizeUA) const
{
    for (int i = 0; i < 6; i++) {
        uA[i] = 0;
    }
}

/*
 *  ---- Partial Molar Properties of the Solution ----
 */

void FixedChemPotSSTP::getPartialMolarVolumes(doublereal* vbar) const
{
    vbar[0] = 0.0;
}

/*
 * Properties of the Standard State of the Species in the Solution
 */

void FixedChemPotSSTP::getStandardChemPotentials(doublereal* mu0) const
{
    mu0[0] = chemPot_;
}

void FixedChemPotSSTP::getEnthalpy_RT(doublereal* hrt) const
{
    double rt = _RT();
    hrt[0] = chemPot_ / rt;
}

void FixedChemPotSSTP::getEntropy_R(doublereal* sr) const
{
    sr[0] = 0.0;
}

void FixedChemPotSSTP::getGibbs_RT(doublereal* grt) const
{
    double rt = _RT();
    grt[0] = chemPot_ / rt;
}

void FixedChemPotSSTP::getCp_R(doublereal* cpr) const
{
    cpr[0] = 0.0;
}

void FixedChemPotSSTP::getIntEnergy_RT(doublereal* urt) const
{
    urt[0] = chemPot_;
}

void FixedChemPotSSTP::getStandardVolumes(doublereal* vbar) const
{
    vbar[0] = 0.0;
}

/*
 * ---- Thermodynamic Values for the Species Reference States ----
 */

void FixedChemPotSSTP::getIntEnergy_RT_ref(doublereal* urt) const
{
    urt[0] = chemPot_;
}

void FixedChemPotSSTP::getEnthalpy_RT_ref(doublereal* hrt) const
{
    double rt = _RT();
    hrt[0] = chemPot_ / rt;
}

void FixedChemPotSSTP::getEntropy_R_ref(doublereal* sr) const
{
    sr[0] = 0.0;
}

void FixedChemPotSSTP::getGibbs_RT_ref(doublereal* grt) const
{
    double rt = _RT();
    grt[0] = chemPot_ / rt;
}

void FixedChemPotSSTP::getGibbs_ref(doublereal* g) const
{
    g[0] = chemPot_;
}

void FixedChemPotSSTP::getCp_R_ref(doublereal* cpr) const
{
    cpr[0] = 0.0;
}

/*
 * ---- Initialization and Internal functions
 */

void FixedChemPotSSTP::initThermo()
{
    /*
     * Call the base class thermo initializer
     */
    SingleSpeciesTP::initThermo();
}

void FixedChemPotSSTP::initThermoXML(XML_Node& phaseNode, const std::string& id_)
{
    /*
     * Find the Thermo XML node
     */
    if (!phaseNode.hasChild("thermo")) {
        throw CanteraError("FixedChemPotSSTP::initThermoXML", "no thermo XML node");
    }
    XML_Node& tnode = phaseNode.child("thermo");
    std::string model = tnode["model"];
    if (model != "StoichSubstance" && model != "FixedChemPot" && model != "StoichSubstanceSSTP") {
        throw CanteraError("FixedChemPotSSTP::initThermoXML()",
                           "thermo model attribute must be FixedChemPot or StoichSubstance or StoichSubstanceSSTP");
    }
    if (model == "FixedChemPot") {
        double val = ctml::getFloatDefaultUnits(tnode, "chemicalPotential", "J/kmol");
        chemPot_ = val;
    }
    SingleSpeciesTP::initThermoXML(phaseNode, id_);
}

void FixedChemPotSSTP::setParameters(int n, doublereal* const c)
{
    chemPot_ = c[0];
}

void FixedChemPotSSTP::getParameters(int& n, doublereal* const c) const
{
    n = 1;
    c[0] = chemPot_;
}

void FixedChemPotSSTP::setParametersFromXML(const XML_Node& eosdata)
{
    std::string model = eosdata["model"];
    if (model != "StoichSubstance" && model != "FixedChemPot" && model != "StoichSubstanceSSTP") {
        throw CanteraError("FixedChemPotSSTP::setParametersFromXML",
                           "thermo model attribute must be FixedChemPot or StoichSubstance or StoichSubstanceSSTP");
    }
    if (model == "FixedChemPotSSTP") {
        doublereal val = ctml::getFloatDefaultUnits(eosdata, "chemicalPotential", "J/kmol");
        chemPot_ = val;
    }
}

void FixedChemPotSSTP::setChemicalPotential(doublereal chemPot)
{
    chemPot_ = chemPot;
}

}
