00001 /** 00002 * @file MetalSHEelectrons.cpp 00003 * Definition file for the %MetalSHEElectrons class, which represents the 00004 * electrons in a metal that are consistent with the 00005 * SHE electrode (see \ref thermoprops and 00006 * class \link Cantera::MetalSHEelectrons MetalSHEelectrons\endlink) 00007 */ 00008 00009 /* 00010 * Copywrite (2005) Sandia Corporation. Under the terms of 00011 * Contract DE-AC04-94AL85000 with Sandia Corporation, the 00012 * U.S. Government retains certain rights in this software. 00013 * 00014 */ 00015 00016 /* 00017 * $Id: MetalSHEelectrons.cpp 279 2009-12-05 19:08:43Z hkmoffa $ 00018 */ 00019 00020 #include "ct_defs.h" 00021 00022 #include "MetalSHEelectrons.h" 00023 #include "SingleSpeciesTP.h" 00024 #include "ThermoFactory.h" 00025 00026 #include <string> 00027 using namespace std; 00028 using namespace Cantera; 00029 00030 namespace Cantera { 00031 00032 /* 00033 * ---- Constructors ------- 00034 */ 00035 //==================================================================================================================== 00036 /* 00037 * Default Constructor for the MetalSHEelectrons class 00038 */ 00039 MetalSHEelectrons::MetalSHEelectrons(): 00040 SingleSpeciesTP(), 00041 xdef_(0) 00042 { 00043 } 00044 //==================================================================================================================== 00045 // Create and initialize a MetalSHEelectrons ThermoPhase object 00046 // from an asci input file 00047 /* 00048 * @param infile name of the input file 00049 * @param id name of the phase id in the file. 00050 * If this is blank, the first phase in the file is used. 00051 */ 00052 MetalSHEelectrons::MetalSHEelectrons(std::string infile, std::string id) : 00053 SingleSpeciesTP(), 00054 xdef_(0) 00055 { 00056 XML_Node* root; 00057 if (infile == "MetalSHEelectrons_default.xml") { 00058 xdef_ = MetalSHEelectrons::makeDefaultXMLTree(); 00059 root = xdef_; 00060 } else { 00061 root = get_XML_File(infile); 00062 } 00063 if (id == "-") id = ""; 00064 XML_Node* xphase = get_XML_NameID("phase", std::string("#")+id, root); 00065 if (!xphase) { 00066 throw CanteraError("MetalSHEelectrons::MetalSHEelectrons", 00067 "Couldn't find phase name in file:" + id); 00068 } 00069 // Check the model name to ensure we have compatibility 00070 const XML_Node& th = xphase->child("thermo"); 00071 std::string model = th["model"]; 00072 if (model != "MetalSHEelectrons") { 00073 throw CanteraError("MetalSHEelectrons::MetalSHEelectrons", 00074 "thermo model attribute must be MetalSHEelectrons"); 00075 } 00076 importPhase(*xphase, this); 00077 } 00078 //==================================================================================================================== 00079 // Full Constructor. 00080 /* 00081 * @param phaseRef XML node pointing to a MetalSHEelectrons description 00082 * @param id Id of the phase. 00083 */ 00084 MetalSHEelectrons::MetalSHEelectrons(XML_Node& xmlphase, std::string id) : 00085 SingleSpeciesTP(), 00086 xdef_(0) 00087 { 00088 if (id != "") { 00089 std::string idxml = xmlphase["id"]; 00090 if (id != idxml) { 00091 throw CanteraError("MetalSHEelectrons::MetalSHEelectrons", 00092 "id's don't match"); 00093 } 00094 } 00095 const XML_Node& th = xmlphase.child("thermo"); 00096 std::string model = th["model"]; 00097 if (model != "MetalSHEelectrons") { 00098 throw CanteraError("MetalSHEelectrons::MetalSHEelectrons", 00099 "thermo model attribute must be MetalSHEelectrons"); 00100 } 00101 importPhase(xmlphase, this); 00102 } 00103 //==================================================================================================================== 00104 // Copy constructor 00105 /* 00106 * @param right Object to be copied 00107 */ 00108 MetalSHEelectrons::MetalSHEelectrons(const MetalSHEelectrons &right) : 00109 SingleSpeciesTP() 00110 { 00111 operator=(right); 00112 } 00113 //==================================================================================================================== 00114 /* 00115 * Destructor for the routine (virtual) 00116 * 00117 */ 00118 MetalSHEelectrons::~MetalSHEelectrons() 00119 { 00120 if (xdef_) { 00121 delete xdef_; 00122 } 00123 } 00124 //==================================================================================================================== 00125 // Assignment operator 00126 /* 00127 * @param right Object to be copied 00128 */ 00129 MetalSHEelectrons & 00130 MetalSHEelectrons::operator=(const MetalSHEelectrons & right) 00131 { 00132 if (&right != this) { 00133 SingleSpeciesTP::operator=(right); 00134 } 00135 00136 if (xdef_) { 00137 delete xdef_; 00138 } 00139 xdef_ = new XML_Node(*right.xdef_); 00140 00141 return *this; 00142 } 00143 //==================================================================================================================== 00144 // Duplication function 00145 /* 00146 * This virtual function is used to create a duplicate of the 00147 * current phase. It's used to duplicate the phase when given 00148 * a ThermoPhase pointer to the phase. 00149 * 00150 * @return It returns a ThermoPhase pointer. 00151 */ 00152 ThermoPhase *MetalSHEelectrons::duplMyselfAsThermoPhase() const { 00153 MetalSHEelectrons *stp = new MetalSHEelectrons(*this); 00154 return (ThermoPhase *) stp; 00155 } 00156 //==================================================================================================================== 00157 00158 /* 00159 * ---- Utilities ----- 00160 */ 00161 00162 /* 00163 * Equation of state flag. Returns the value cStoichSubstance, 00164 * defined in mix_defs.h. 00165 */ 00166 int MetalSHEelectrons::eosType() const { 00167 return cMetalSHEelectrons; 00168 } 00169 //==================================================================================================================== 00170 00171 /* 00172 * ---- Molar Thermodynamic properties of the solution ---- 00173 */ 00174 00175 /** 00176 * ----- Mechanical Equation of State ------ 00177 */ 00178 //==================================================================================================================== 00179 /* 00180 * Pressure. Units: Pa. 00181 * For an incompressible substance, the density is independent 00182 * of pressure. This method simply returns the stored 00183 * pressure value. 00184 */ 00185 doublereal MetalSHEelectrons::pressure() const { 00186 return m_press; 00187 } 00188 //==================================================================================================================== 00189 /* 00190 * Set the pressure at constant temperature. Units: Pa. 00191 * For an incompressible substance, the density is 00192 * independent of pressure. Therefore, this method only 00193 * stores the specified pressure value. It does not 00194 * modify the density. 00195 */ 00196 void MetalSHEelectrons::setPressure(doublereal p) { 00197 m_press = p; 00198 } 00199 //==================================================================================================================== 00200 /* 00201 * The isothermal compressibility. Units: 1/Pa. 00202 * The isothermal compressibility is defined as 00203 * \f[ 00204 * \kappa_T = -\frac{1}{v}\left(\frac{\partial v}{\partial P}\right)_T 00205 * \f] 00206 * 00207 * It's equal to zero for this model, since the molar volume 00208 * doesn't change with pressure or temperature. 00209 */ 00210 doublereal MetalSHEelectrons::isothermalCompressibility() const { 00211 return -1.0/pressure(); 00212 } 00213 //==================================================================================================================== 00214 /* 00215 * The thermal expansion coefficient. Units: 1/K. 00216 * The thermal expansion coefficient is defined as 00217 * 00218 * \f[ 00219 * \beta = \frac{1}{v}\left(\frac{\partial v}{\partial T}\right)_P 00220 * \f] 00221 * 00222 * It's equal to zero for this model, since the molar volume 00223 * doesn't change with pressure or temperature. 00224 */ 00225 doublereal MetalSHEelectrons::thermalExpansionCoeff() const { 00226 return 1.0/temperature(); 00227 00228 } 00229 //==================================================================================================================== 00230 /* 00231 * ---- Chemical Potentials and Activities ---- 00232 */ 00233 //==================================================================================================================== 00234 /* 00235 * This method returns the array of generalized 00236 * concentrations. For a stoichiomeetric substance, there is 00237 * only one species, and the generalized concentration is 1.0. 00238 */ 00239 void MetalSHEelectrons:: 00240 getActivityConcentrations(doublereal* c) const { 00241 c[0] = 1.0; 00242 } 00243 //==================================================================================================================== 00244 /* 00245 * The standard concentration. This is defined as the concentration 00246 * by which the generalized concentration is normalized to produce 00247 * the activity. 00248 */ 00249 doublereal MetalSHEelectrons::standardConcentration(int k) const { 00250 return 1.0; 00251 } 00252 //==================================================================================================================== 00253 /* 00254 * Returns the natural logarithm of the standard 00255 * concentration of the kth species 00256 */ 00257 doublereal MetalSHEelectrons::logStandardConc(int k) const { 00258 return 0.0; 00259 } 00260 //==================================================================================================================== 00261 /* 00262 * Returns the units of the standard and generalized 00263 * concentrations Note they have the same units, as their 00264 * ratio is defined to be equal to the activity of the kth 00265 * species in the solution, which is unitless. 00266 * 00267 * This routine is used in print out applications where the 00268 * units are needed. Usually, MKS units are assumed throughout 00269 * the program and in the XML input files. 00270 * 00271 * uA[0] = kmol units - default = 1 00272 * uA[1] = m units - default = -nDim(), the number of spatial 00273 * dimensions in the Phase class. 00274 * uA[2] = kg units - default = 0; 00275 * uA[3] = Pa(pressure) units - default = 0; 00276 * uA[4] = Temperature units - default = 0; 00277 * uA[5] = time units - default = 0 00278 */ 00279 void MetalSHEelectrons:: 00280 getUnitsStandardConc(doublereal *uA, int k, int sizeUA) const { 00281 for (int i = 0; i < 6; i++) { 00282 uA[i] = 0; 00283 } 00284 } 00285 //==================================================================================================================== 00286 /* 00287 * ---- Partial Molar Properties of the Solution ---- 00288 */ 00289 00290 //==================================================================================================================== 00291 00292 /* 00293 * ---- Properties of the Standard State of the Species in the Solution 00294 * ---- 00295 */ 00296 //==================================================================================================================== 00297 /* 00298 * Get the array of chemical potentials at unit activity 00299 * \f$ \mu^0_k \f$. 00300 * 00301 * For a stoichiometric substance, there is no activity term in 00302 * the chemical potential expression, and therefore the 00303 * standard chemical potential and the chemical potential 00304 * are both equal to the molar Gibbs function. 00305 */ 00306 void MetalSHEelectrons:: 00307 getStandardChemPotentials(doublereal* mu0) const { 00308 getGibbs_RT(mu0); 00309 mu0[0] *= GasConstant * temperature(); 00310 } 00311 //==================================================================================================================== 00312 /* 00313 * Get the nondimensional Enthalpy functions for the species 00314 * at their standard states at the current 00315 * <I>T</I> and <I>P</I> of the solution. 00316 * Molar enthalpy. Units: J/kmol. For an incompressible, 00317 * stoichiometric substance, the internal energy is 00318 * independent of pressure, and therefore the molar enthalpy 00319 * is \f[ \hat h(T, P) = \hat u(T) + P \hat v \f], where the 00320 * molar specific volume is constant. 00321 */ 00322 void MetalSHEelectrons::getEnthalpy_RT(doublereal* hrt) const { 00323 getEnthalpy_RT_ref(hrt); 00324 } 00325 //==================================================================================================================== 00326 /* 00327 * Get the array of nondimensional Entropy functions for the 00328 * standard state species 00329 * at the current <I>T</I> and <I>P</I> of the solution. 00330 */ 00331 void MetalSHEelectrons::getEntropy_R(doublereal* sr) const { 00332 getEntropy_R_ref(sr); 00333 doublereal tmp = log (pressure() / m_p0); 00334 sr[0] -= tmp; 00335 } 00336 //==================================================================================================================== 00337 /* 00338 * Get the nondimensional Gibbs functions for the species 00339 * at their standard states of solution at the current T and P 00340 * of the solution 00341 */ 00342 void MetalSHEelectrons::getGibbs_RT(doublereal* grt) const { 00343 getGibbs_RT_ref(grt); 00344 doublereal tmp = log (pressure() / m_p0); 00345 grt[0] += tmp; 00346 } 00347 //==================================================================================================================== 00348 /* 00349 * Get the nondimensional Gibbs functions for the standard 00350 * state of the species at the current T and P. 00351 */ 00352 void MetalSHEelectrons::getCp_R(doublereal* cpr) const { 00353 _updateThermo(); 00354 cpr[0] = m_cp0_R[0]; 00355 } 00356 //==================================================================================================================== 00357 /* 00358 * Molar internal energy (J/kmol). 00359 * For an incompressible, 00360 * stoichiometric substance, the molar internal energy is 00361 * independent of pressure. Since the thermodynamic properties 00362 * are specified by giving the standard-state enthalpy, the 00363 * term \f$ P_0 \hat v\f$ is subtracted from the specified molar 00364 * enthalpy to compute the molar internal energy. 00365 */ 00366 void MetalSHEelectrons::getIntEnergy_RT(doublereal* urt) const { 00367 getEnthalpy_RT(urt); 00368 urt[0] -= 1.0; 00369 } 00370 //==================================================================================================================== 00371 /* 00372 * ---- Thermodynamic Values for the Species Reference States ---- 00373 */ 00374 /* 00375 * Molar internal energy or the reference state at the current 00376 * temperature, T (J/kmol). 00377 * For an incompressible, 00378 * stoichiometric substance, the molar internal energy is 00379 * independent of pressure. Since the thermodynamic properties 00380 * are specified by giving the standard-state enthalpy, the 00381 * term \f$ P_0 \hat v\f$ is subtracted from the specified molar 00382 * enthalpy to compute the molar internal energy. 00383 * 00384 * Note, this is equal to the standard state internal energy 00385 * evaluated at the reference pressure. 00386 */ 00387 void MetalSHEelectrons::getIntEnergy_RT_ref(doublereal* urt) const { 00388 _updateThermo(); 00389 doublereal RT = GasConstant * temperature(); 00390 doublereal PV = m_p0 / molarDensity(); 00391 urt[0] = m_h0_RT[0] - PV / RT; 00392 } 00393 00394 /* 00395 * ---- Saturation Properties 00396 */ 00397 00398 00399 00400 /* 00401 * ---- Initialization and Internal functions 00402 */ 00403 //==================================================================================================================== 00404 /* 00405 * @internal Initialize. This method is provided to allow 00406 * subclasses to perform any initialization required after all 00407 * species have been added. For example, it might be used to 00408 * resize internal work arrays that must have an entry for 00409 * each species. The base class implementation does nothing, 00410 * and subclasses that do not require initialization do not 00411 * need to overload this method. When importing a CTML phase 00412 * description, this method is called just prior to returning 00413 * from function importPhase. 00414 * 00415 * @see importCTML.cpp 00416 */ 00417 void MetalSHEelectrons::initThermo() { 00418 /* 00419 * Call the base class thermo initializer 00420 */ 00421 SingleSpeciesTP::initThermo(); 00422 } 00423 //==================================================================================================================== 00424 00425 void MetalSHEelectrons::initThermoXML(XML_Node& phaseNode, std::string id) { 00426 /* 00427 * Find the Thermo XML node 00428 */ 00429 if (!phaseNode.hasChild("thermo")) { 00430 throw CanteraError("MetalSHEelectrons::initThermoXML", 00431 "no thermo XML node"); 00432 } 00433 XML_Node &tnode = phaseNode.child("thermo"); 00434 doublereal dens = 2.65E3; 00435 if (tnode.hasChild("density")) { 00436 dens = getFloatDefaultUnits(tnode, "density", "kg/m3"); 00437 } 00438 setDensity(dens); 00439 SingleSpeciesTP::initThermoXML(phaseNode, id); 00440 } 00441 //==================================================================================================================== 00442 XML_Node *MetalSHEelectrons::makeDefaultXMLTree() 00443 { 00444 XML_Node *xtop = new XML_Node("ctml", 0); 00445 XML_Node &xv = xtop->addChild("validate"); 00446 xv.addAttribute("reactions", "yes"); 00447 xv.addAttribute("species", "yes"); 00448 00449 XML_Node &xp = xtop->addChild("phase"); 00450 xp.addAttribute("dim", "3"); 00451 xp.addAttribute("id", "MetalSHEelectrons"); 00452 XML_Node &xe = xp.addChild("elementArray", "E"); 00453 xe.addAttribute("datasrc", "elements.xml"); 00454 XML_Node &xs = xp.addChild("speciesArray", "she_electron"); 00455 xs.addAttribute("datasrc", "#species_Metal_SHEelectrons"); 00456 XML_Node &xt = xp.addChild("thermo"); 00457 xt.addAttribute("model", "metalSHEelectrons"); 00458 XML_Node &xtr = xp.addChild("transport"); 00459 xtr.addAttribute("model", "none"); 00460 XML_Node &xk = xp.addChild("kinetics"); 00461 xk.addAttribute("model", "none"); 00462 00463 XML_Node &xsd = xtop->addChild("speciesData"); 00464 xsd.addAttribute("id", "species_Metal_SHEelectrons"); 00465 00466 XML_Node &xsp = xsd.addChild("species"); 00467 xsp.addAttribute("name", "she_electron"); 00468 xsp.addChild("atomArray", "E:1"); 00469 xsp.addChild("charge", "-1"); 00470 XML_Node &xspt = xsp.addChild("thermo"); 00471 00472 XML_Node &xN1 = xspt.addChild("NASA"); 00473 xN1.addAttribute("Tmax", "1000."); 00474 xN1.addAttribute("Tmin", "200."); 00475 xN1.addAttribute("P0", "100000.0"); 00476 XML_Node &xF1 = xsd.addChild("floatArray", 00477 "1.172165560E+00, 3.990260375E-03, -9.739075500E-06, " 00478 "1.007860470E-08, -3.688058805E-12, -4.589675865E+02, 3.415051190E-01" ); 00479 xF1.addAttribute("name", "coeffs"); 00480 xF1.addAttribute("size", "7"); 00481 00482 XML_Node &xN2 = xspt.addChild("NASA"); 00483 xN2.addAttribute("Tmax", "6000."); 00484 xN2.addAttribute("Tmin", "1000."); 00485 xN2.addAttribute("P0", "100000.0"); 00486 XML_Node &xF2 = xsd.addChild("floatArray", 00487 "1.466432895E+00, 4.133039835E-04, -7.320116750E-08, 7.705017950E-12," 00488 "-3.444022160E-16, -4.065327985E+02, -5.121644350E-01"); 00489 xF2.addAttribute("name", "coeffs"); 00490 xF2.addAttribute("size", "7"); 00491 00492 return xtop; 00493 } 00494 //==================================================================================================================== 00495 /* 00496 * setParameters: 00497 * 00498 * Generic routine that is used to set the parameters used 00499 * by this model. 00500 * C[0] = density of phase [ kg/m3 ] 00501 */ 00502 void MetalSHEelectrons::setParameters(int n, doublereal * const c) { 00503 doublereal rho = c[0]; 00504 setDensity(rho); 00505 } 00506 //==================================================================================================================== 00507 /* 00508 * getParameters: 00509 * 00510 * Generic routine that is used to get the parameters used 00511 * by this model. 00512 * n = 1 00513 * C[0] = density of phase [ kg/m3 ] 00514 */ 00515 void MetalSHEelectrons::getParameters(int &n, doublereal * const c) const { 00516 doublereal rho = density(); 00517 n = 1; 00518 c[0] = rho; 00519 } 00520 //==================================================================================================================== 00521 /* 00522 * Reads an xml data block for the parameters needed by this 00523 * routine. eosdata is a reference to the xml thermo block, and looks 00524 * like this: 00525 * 00526 * <phase id="stoichsolid" > 00527 * <thermo model="StoichSubstance"> 00528 * <density units="g/cm3">3.52</density> 00529 * </thermo> 00530 * </phase> 00531 */ 00532 void MetalSHEelectrons::setParametersFromXML(const XML_Node& eosdata) { 00533 std::string model = eosdata["model"]; 00534 if (model != "MetalSHEelectrons") { 00535 throw CanteraError("MetalSHEelectrons::setParametersFromXML", 00536 "thermo model attribute must be MetalSHEelectrons"); 00537 } 00538 doublereal rho = 2.65E3; 00539 if (eosdata.hasChild("density")) { 00540 rho = getFloat(eosdata, "density", "toSI"); 00541 } 00542 setDensity(rho); 00543 } 00544 //==================================================================================================================== 00545 00546 }