/**
 * @file MetalSHEelectrons.cpp
 * Definition file for the %MetalSHEElectrons class, which represents the
 * electrons in a metal that are consistent with the
 * SHE electrode (see \ref thermoprops and
 * class \link Cantera::MetalSHEelectrons MetalSHEelectrons\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/MetalSHEelectrons.h"
#include "cantera/thermo/SingleSpeciesTP.h"
#include "cantera/thermo/ThermoFactory.h"

#include <string>

namespace Cantera
{

/*
 * ----  Constructors -------
 */

MetalSHEelectrons::MetalSHEelectrons():
    SingleSpeciesTP(),
    xdef_(0)
{
}

MetalSHEelectrons::MetalSHEelectrons(const std::string& infile, std::string id_) :
    SingleSpeciesTP(),
    xdef_(0)
{
    XML_Node* root;
    if (infile == "MetalSHEelectrons_default.xml") {
        xdef_ = MetalSHEelectrons::makeDefaultXMLTree();
        root = xdef_;
    } else {
        root = get_XML_File(infile);
    }
    if (id_ == "-") {
        id_ = "";
    }
    XML_Node* xphase = get_XML_NameID("phase", std::string("#")+id_, root);
    if (!xphase) {
        throw CanteraError("MetalSHEelectrons::MetalSHEelectrons",
                           "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 != "MetalSHEelectrons") {
        throw CanteraError("MetalSHEelectrons::MetalSHEelectrons",
                           "thermo model attribute must be MetalSHEelectrons");
    }
    importPhase(*xphase, this);
}

MetalSHEelectrons::MetalSHEelectrons(XML_Node& xmlphase, const std::string& id_) :
    SingleSpeciesTP(),
    xdef_(0)
{
    if (id_ != "") {
        std::string idxml = xmlphase["id"];
        if (id_ != idxml) {
            throw CanteraError("MetalSHEelectrons::MetalSHEelectrons",
                               "id's don't match");
        }
    }
    const XML_Node& th = xmlphase.child("thermo");
    std::string model = th["model"];
    if (model != "MetalSHEelectrons") {
        throw CanteraError("MetalSHEelectrons::MetalSHEelectrons",
                           "thermo model attribute must be MetalSHEelectrons");
    }
    importPhase(xmlphase, this);
}

MetalSHEelectrons::MetalSHEelectrons(const MetalSHEelectrons&  right) :
    SingleSpeciesTP()
{
    operator=(right);
}

MetalSHEelectrons::~MetalSHEelectrons()
{
    delete xdef_;
}

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

    delete xdef_;
    xdef_ = new XML_Node(*right.xdef_);

    return *this;
}

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

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

int MetalSHEelectrons::eosType() const
{
    return cMetalSHEelectrons;
}

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

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

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

doublereal MetalSHEelectrons::isothermalCompressibility() const
{
    return 1.0/pressure();
}

doublereal MetalSHEelectrons::thermalExpansionCoeff() const
{
    return 1.0/temperature();

}

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

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

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

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

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

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

void MetalSHEelectrons::
getStandardChemPotentials(doublereal* mu0) const
{
    getGibbs_RT(mu0);
    mu0[0] *= GasConstant * temperature();
}

void MetalSHEelectrons::getEnthalpy_RT(doublereal* hrt) const
{
    getEnthalpy_RT_ref(hrt);
}

void MetalSHEelectrons::getEntropy_R(doublereal* sr) const
{
    getEntropy_R_ref(sr);
    doublereal tmp = log(pressure() / m_p0);
    sr[0] -= tmp;
}

void MetalSHEelectrons::getGibbs_RT(doublereal* grt) const
{
    getGibbs_RT_ref(grt);
    doublereal tmp = log(pressure() / m_p0);
    grt[0] += tmp;
}

void MetalSHEelectrons::getCp_R(doublereal* cpr) const
{
    _updateThermo();
    cpr[0] = m_cp0_R[0];
}
void MetalSHEelectrons::getIntEnergy_RT(doublereal* urt) const
{
    getEnthalpy_RT(urt);
    urt[0] -= 1.0;
}

void MetalSHEelectrons::getIntEnergy_RT_ref(doublereal* urt) const
{
    _updateThermo();
    doublereal RT = GasConstant * temperature();
    urt[0] = m_h0_RT[0] - m_p0 / molarDensity() / RT;
}

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

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

void MetalSHEelectrons::initThermoXML(XML_Node& phaseNode, const std::string& id_)
{
    /*
     * Find the Thermo XML node
     */
    if (!phaseNode.hasChild("thermo")) {
        throw CanteraError("MetalSHEelectrons::initThermoXML",
                           "no thermo XML node");
    }
    XML_Node& tnode = phaseNode.child("thermo");
    doublereal dens = 2.65E3;
    if (tnode.hasChild("density")) {
        dens = ctml::getFloatDefaultUnits(tnode, "density", "kg/m3");
    }
    setDensity(dens);
    SingleSpeciesTP::initThermoXML(phaseNode, id_);
}

XML_Node* MetalSHEelectrons::makeDefaultXMLTree()
{
    XML_Node* xtop = new XML_Node("ctml", 0);
    XML_Node& xv = xtop->addChild("validate");
    xv.addAttribute("reactions", "yes");
    xv.addAttribute("species", "yes");

    XML_Node& xp = xtop->addChild("phase");
    xp.addAttribute("dim", "3");
    xp.addAttribute("id", "MetalSHEelectrons");
    XML_Node& xe = xp.addChild("elementArray", "E");
    xe.addAttribute("datasrc", "elements.xml");
    XML_Node& xs = xp.addChild("speciesArray", "she_electron");
    xs.addAttribute("datasrc", "#species_Metal_SHEelectrons");
    XML_Node& xt = xp.addChild("thermo");
    xt.addAttribute("model", "metalSHEelectrons");
    XML_Node& xtr = xp.addChild("transport");
    xtr.addAttribute("model", "none");
    XML_Node& xk = xp.addChild("kinetics");
    xk.addAttribute("model", "none");

    XML_Node& xsd = xtop->addChild("speciesData");
    xsd.addAttribute("id", "species_Metal_SHEelectrons");

    XML_Node& xsp = xsd.addChild("species");
    xsp.addAttribute("name", "she_electron");
    xsp.addChild("atomArray", "E:1");
    xsp.addChild("charge", "-1");
    XML_Node& xspt = xsp.addChild("thermo");

    XML_Node& xN1 = xspt.addChild("NASA");
    xN1.addAttribute("Tmax", "1000.");
    xN1.addAttribute("Tmin", "200.");
    xN1.addAttribute("P0", "100000.0");
    XML_Node& xF1 = xsd.addChild("floatArray",
                                 "1.172165560E+00,   3.990260375E-03,  -9.739075500E-06, "
                                 "1.007860470E-08, -3.688058805E-12, -4.589675865E+02,  3.415051190E-01");
    xF1.addAttribute("name", "coeffs");
    xF1.addAttribute("size", "7");

    XML_Node& xN2 = xspt.addChild("NASA");
    xN2.addAttribute("Tmax", "6000.");
    xN2.addAttribute("Tmin", "1000.");
    xN2.addAttribute("P0", "100000.0");
    XML_Node& xF2 = xsd.addChild("floatArray",
                                 "1.466432895E+00,  4.133039835E-04, -7.320116750E-08, 7.705017950E-12,"
                                 "-3.444022160E-16, -4.065327985E+02, -5.121644350E-01");
    xF2.addAttribute("name", "coeffs");
    xF2.addAttribute("size", "7");

    return xtop;
}

void MetalSHEelectrons::setParameters(int n, doublereal* const c)
{
    doublereal rho = c[0];
    setDensity(rho);
}

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

void MetalSHEelectrons::setParametersFromXML(const XML_Node& eosdata)
{
    std::string model = eosdata["model"];
    if (model != "MetalSHEelectrons") {
        throw CanteraError("MetalSHEelectrons::setParametersFromXML",
                           "thermo model attribute must be MetalSHEelectrons");
    }
    doublereal rho = 2.65E3;
    if (eosdata.hasChild("density")) {
        rho = ctml::getFloat(eosdata, "density", "toSI");
    }
    setDensity(rho);
}

}
