diff --git a/ext/SConscript b/ext/SConscript index f5bd4f088..2a4832c91 100644 --- a/ext/SConscript +++ b/ext/SConscript @@ -3,6 +3,10 @@ from buildutils import * Import('env', 'build', 'install', 'libraryTargets') localenv = env.Clone() +# +# prep function seem to return the environment +# + def prep_default(env): return env.Clone() @@ -19,7 +23,16 @@ def prep_f2c(env): localenv.Append(CPPDEFINES=['USE_CLOCK']) if not localenv['HAS_UNISTD_H']: localenv.Append(CPPDEFINES=['MSDOS']) + if env['VERBOSE'] : + print "INFO 2: prep_f2c: adding MSDOS to CPPDEFINES" + if env['VERBOSE'] : + localenv.Append(CPPDEFINES=['added']) + print "INFO 2: CPPDEFINES ", localenv['CPPDEFINES'] + #print "localenv", localenv.Dump() + #exit(0) + + # The F2C code generates a lot of warnings designed to catch # programmer errors, but since this is autogenerated code, those # warnings are irrelevant. @@ -52,6 +65,10 @@ def prep_gtest(env): CPPDEFINES={'GTEST_HAS_PTHREAD': 0}) return localenv +# libs is a list of length 3 +# 0 subdir for execution +# 1 file extension +# 2 function pointer # (subdir, (file extensions), prepfunction) libs = [('libexecstream', ['cpp'], prep_default)] @@ -95,6 +112,10 @@ if env['use_sundials'] == 'n': for subdir, extensions, prepFunction in libs: + + if env['VERBOSE']: + print "INFO 2: Prep the environment for ", subdir, ' with extensions ', extensions, ' by calling func ', prepFunction.__name__ + localenv = prepFunction(env) if localenv['single_library']: @@ -120,6 +141,10 @@ for subdir, extensions, prepFunction in libs: else: sharedLibName = libName + if env['VERBOSE'] : + print "INFO 2:" , subdir , ' with ', extensions + print " libName = ", libName, " sharedLibName = ", sharedLibName + objects = localenv.SharedObject(mglob(localenv, subdir, *extensions)) # Build the static library diff --git a/include/cantera/thermo/HMWSoln.h b/include/cantera/thermo/HMWSoln.h index d0783fe9d..fb9d453cc 100644 --- a/include/cantera/thermo/HMWSoln.h +++ b/include/cantera/thermo/HMWSoln.h @@ -1333,6 +1333,46 @@ public: */ ThermoPhase* duplMyselfAsThermoPhase() const; + + //! Import, construct, and initialize a HMWSoln phase + /*! specification from an XML tree into the current object. + * + * This routine is a precursor to constructPhaseXML(XML_Node*) + * routine, which does most of the work. + * + * @param inputfile XML file containing the description of the phase + * + * @param id Optional parameter identifying the name of the + * phase. If none is given, the first XML + * phase element will be used. + */ + void constructPhaseFile(std::string inputFile, std::string id); + + //! Import and initialize a HMWSoln phase specification in an XML tree into the current object. + /*! + * Here we read an XML description of the phase. + * We import descriptions of the elements that make up the + * species in a phase. + * We import information about the species, including their + * reference state thermodynamic polynomials. We then freeze + * the state of the species. + * + * Then, we read the species molar volumes from the xml + * tree to finish the initialization. + * + * @param phaseNode This object must be the phase node of a complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + void constructPhaseXML(XML_Node& phaseNode, std::string id); + /** * @name Utilities * @{ diff --git a/include/cantera/thermo/IonsFromNeutralVPSSTP.h b/include/cantera/thermo/IonsFromNeutralVPSSTP.h index 348652724..76e6bcaed 100644 --- a/include/cantera/thermo/IonsFromNeutralVPSSTP.h +++ b/include/cantera/thermo/IonsFromNeutralVPSSTP.h @@ -159,6 +159,50 @@ public: */ virtual ThermoPhase* duplMyselfAsThermoPhase() const; + /// The following methods are used in the process of constructing + /// the phase and setting its parameters from a specification in an + /// input file. + + //! Initialization of an IonsFromNeutralVPSSTP phase using an xml file + /*! + * This routine is a precursor to initThermo(XML_Node*) + * routine, which does most of the work. + * + * @param inputFile XML file containing the description of the phase + * + * @param id Optional parameter identifying the name of the + * phase. If none is given, the first XML + * phase element will be used. + */ + void constructPhaseFile(std::string inputFile, std::string id); + + //! Import and initialize an IonsFromNeutralVPSSTP phase + //! specification in an XML tree into the current object. + /*! + * Here we read an XML description of the phase. + * We import descriptions of the elements that make up the + * species in a phase. + * We import information about the species, including their + * reference state thermodynamic polynomials. We then freeze + * the state of the species. + * + * Then, we read the species molar volumes from the xml + * tree to finish the initialization. + * + * @param phaseNode This object must be the phase node of a complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + void constructPhaseXML(XML_Node& phaseNode, std::string id); + + /** * * @name Utilities diff --git a/platform/posix/SConscript b/platform/posix/SConscript index 66fdee31d..644aaa9d2 100644 --- a/platform/posix/SConscript +++ b/platform/posix/SConscript @@ -107,6 +107,9 @@ if not localenv['build_with_f2c']: else: localenv['mak_syslibs'] = '' +# print localenv.Dump() +# exit(0) + mak = build(localenv.SubstFile('Cantera.mak', 'Cantera.mak.in')) install('$inst_incdir', mak) diff --git a/src/thermo/HMWSoln_input.cpp b/src/thermo/HMWSoln_input.cpp index 8c971690f..dd71b5440 100644 --- a/src/thermo/HMWSoln_input.cpp +++ b/src/thermo/HMWSoln_input.cpp @@ -1047,6 +1047,206 @@ void HMWSoln::initThermo() initLengths(); } + /* + * Import, construct, and initialize a HMWSoln phase + * specification from an XML tree into the current object. + * + * This routine is a precursor to constructPhaseXML(XML_Node*) + * routine, which does most of the work. + * + * @param infile XML file containing the description of the + * phase + * + * @param id Optional parameter identifying the name of the + * phase. If none is given, the first XML + * phase element will be used. + */ + void HMWSoln::constructPhaseFile(std::string inputFile, std::string id) { + + if (inputFile.size() == 0) { + throw CanteraError("HMWSoln:constructPhaseFile", + "input file is null"); + } + string path = findInputFile(inputFile); + std::ifstream fin(path.c_str()); + if (!fin) { + throw CanteraError("HMWSoln:constructPhaseFile","could not open " + +path+" for reading."); + } + /* + * The phase object automatically constructs an XML object. + * Use this object to store information. + */ + XML_Node &phaseNode_XML = xml(); + XML_Node *fxml = new XML_Node(); + fxml->build(fin); + XML_Node *fxml_phase = findXMLPhase(fxml, id); + if (!fxml_phase) { + throw CanteraError("HMWSoln:constructPhaseFile", + "ERROR: Can not find phase named " + + id + " in file named " + inputFile); + } + fxml_phase->copy(&phaseNode_XML); + constructPhaseXML(*fxml_phase, id); + delete fxml; + } + + /* + * Import, construct, and initialize a HMWSoln phase + * specification from an XML tree into the current object. + * + * Most of the work is carried out by the cantera base + * routine, importPhase(). That routine imports all of the + * species and element data, including the standard states + * of the species. + * + * Then, In this routine, we read the information + * particular to the specification of the activity + * coefficient model for the Pitzer parameterization. + * + * We also read information about the molar volumes of the + * standard states if present in the XML file. + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + void HMWSoln::constructPhaseXML(XML_Node& phaseNode, std::string id) { + string stemp; + if (id.size() > 0) { + string idp = phaseNode.id(); + if (idp != id) { + throw CanteraError("HMWSoln::constructPhaseXML", + "phasenode and Id are incompatible"); + } + } + + /* + * Find the Thermo XML node + */ + if (!phaseNode.hasChild("thermo")) { + throw CanteraError("HMWSoln::constructPhaseXML", + "no thermo XML node"); + } + XML_Node& thermoNode = phaseNode.child("thermo"); + + /* + * Possibly change the form of the standard concentrations + */ + if (thermoNode.hasChild("standardConc")) { + XML_Node& scNode = thermoNode.child("standardConc"); + m_formGC = 2; + stemp = scNode.attrib("model"); + string formString = lowercase(stemp); + if (formString != "") { + if (formString == "unity") { + m_formGC = 0; + printf("exit standardConc = unity not done\n"); + exit(EXIT_FAILURE); + } else if (formString == "molar_volume") { + m_formGC = 1; + printf("exit standardConc = molar_volume not done\n"); + exit(EXIT_FAILURE); + } else if (formString == "solvent_volume") { + m_formGC = 2; + } else { + throw CanteraError("HMWSoln::constructPhaseXML", + "Unknown standardConc model: " + formString); + } + } + } + /* + * Get the Name of the Solvent: + * solventName + */ + string solventName = ""; + if (thermoNode.hasChild("solvent")) { + XML_Node& scNode = thermoNode.child("solvent"); + vector nameSolventa; + getStringArray(scNode, nameSolventa); + int nsp = static_cast(nameSolventa.size()); + if (nsp != 1) { + throw CanteraError("HMWSoln::constructPhaseXML", + "badly formed solvent XML node"); + } + solventName = nameSolventa[0]; + } + + /* + * Determine the form of the Pitzer model, + * We will use this information to size arrays below. + */ + if (thermoNode.hasChild("activityCoefficients")) { + XML_Node& scNode = thermoNode.child("activityCoefficients"); + stemp = scNode.attrib("model"); + string formString = lowercase(stemp); + if (formString != "") { + if (formString == "pitzer" || formString == "default") { + m_formPitzer = PITZERFORM_BASE; + } else if (formString == "base") { + m_formPitzer = PITZERFORM_BASE; + } else { + throw CanteraError("HMWSoln::constructPhaseXML", + "Unknown Pitzer ActivityCoeff model: " + + formString); + } + } + /* + * Determine the form of the temperature dependence + * of the Pitzer activity coefficient model. + */ + stemp = scNode.attrib("TempModel"); + formString = lowercase(stemp); + if (formString != "") { + if (formString == "constant" || formString == "default") { + m_formPitzerTemp = PITZER_TEMP_CONSTANT; + } else if (formString == "linear") { + m_formPitzerTemp = PITZER_TEMP_LINEAR; + } else if (formString == "complex" || formString == "complex1") { + m_formPitzerTemp = PITZER_TEMP_COMPLEX1; + } else { + throw CanteraError("HMWSoln::constructPhaseXML", + "Unknown Pitzer ActivityCoeff Temp model: " + + formString); + } + } + + /* + * Determine the reference temperature + * of the Pitzer activity coefficient model's temperature + * dependence formulation: defaults to 25C + */ + stemp = scNode.attrib("TempReference"); + formString = lowercase(stemp); + if (formString != "") { + m_TempPitzerRef = atofCheck(formString.c_str()); + } else { + m_TempPitzerRef = 273.15 + 25; + } + + } + + /* + * Call the Cantera importPhase() function. This will import + * all of the species into the phase. This will also handle + * all of the solvent and solute standard states + */ + bool m_ok = importPhase(phaseNode, this); + if (!m_ok) { + throw CanteraError("HMWSoln::constructPhaseXML","importPhase failed "); + } + + } + + + /** * Process the XML file after species are set up. * diff --git a/src/thermo/IonsFromNeutralVPSSTP.cpp b/src/thermo/IonsFromNeutralVPSSTP.cpp index abbc33191..b9ac0c4e4 100644 --- a/src/thermo/IonsFromNeutralVPSSTP.cpp +++ b/src/thermo/IonsFromNeutralVPSSTP.cpp @@ -240,6 +240,146 @@ IonsFromNeutralVPSSTP::duplMyselfAsThermoPhase() const return new IonsFromNeutralVPSSTP(*this); } +/* + * Import, construct, and initialize a phase + * specification from an XML tree into the current object. + * + * This routine is a precursor to constructPhaseXML(XML_Node*) + * routine, which does most of the work. + * + * @param infile XML file containing the description of the + * phase + * + * @param id Optional parameter identifying the name of the + * phase. If none is given, the first XML + * phase element will be used. + */ +void IonsFromNeutralVPSSTP::constructPhaseFile(std::string inputFile, std::string id) { + + if (inputFile.size() == 0) { + throw CanteraError("MargulesVPSSTP:constructPhaseFile", + "input file is null"); + } + string path = findInputFile(inputFile); + std::ifstream fin(path.c_str()); + if (!fin) { + throw CanteraError("MargulesVPSSTP:constructPhaseFile","could not open " + +path+" for reading."); + } + /* + * The phase object automatically constructs an XML object. + * Use this object to store information. + */ + XML_Node &phaseNode_XML = xml(); + XML_Node *fxml = new XML_Node(); + fxml->build(fin); + XML_Node *fxml_phase = findXMLPhase(fxml, id); + if (!fxml_phase) { + throw CanteraError("MargulesVPSSTP:constructPhaseFile", + "ERROR: Can not find phase named " + + id + " in file named " + inputFile); + } + fxml_phase->copy(&phaseNode_XML); + constructPhaseXML(*fxml_phase, id); + delete fxml; +} + +/* + * Import, construct, and initialize a HMWSoln phase + * specification from an XML tree into the current object. + * + * Most of the work is carried out by the cantera base + * routine, importPhase(). That routine imports all of the + * species and element data, including the standard states + * of the species. + * + * Then, In this routine, we read the information + * particular to the specification of the activity + * coefficient model for the Pitzer parameterization. + * + * We also read information about the molar volumes of the + * standard states if present in the XML file. + * + * @param phaseNode This object must be the phase node of a + * complete XML tree + * description of the phase, including all of the + * species data. In other words while "phase" must + * point to an XML phase object, it must have + * sibling nodes "speciesData" that describe + * the species in the phase. + * @param id ID of the phase. If nonnull, a check is done + * to see if phaseNode is pointing to the phase + * with the correct id. + */ + +void IonsFromNeutralVPSSTP::constructPhaseXML(XML_Node& phaseNode, std::string id) { + string stemp; + if (id.size() > 0) { + string idp = phaseNode.id(); + if (idp != id) { + throw CanteraError("IonsFromNeutralVPSSTP::constructPhaseXML", + "phasenode and Id are incompatible"); + } + } + + /* + * Find the thermo XML node + */ + if (!phaseNode.hasChild("thermo")) { + throw CanteraError("IonsFromNeutralVPSSTP::constructPhaseXML", + "no thermo XML node"); + } + XML_Node& thermoNode = phaseNode.child("thermo"); + + + + /* + * Make sure that the thermo model is IonsFromNeutralMolecule + */ + stemp = thermoNode.attrib("model"); + string formString = lowercase(stemp); + if (formString != "ionsfromneutralmolecule") { + throw CanteraError("IonsFromNeutralVPSSTP::constructPhaseXML", + "model name isn't IonsFromNeutralMolecule: " + formString); + } + + /* + * Find the Neutral Molecule Phase + */ + if (!thermoNode.hasChild("neutralMoleculePhase")) { + throw CanteraError("IonsFromNeutralVPSSTP::constructPhaseXML", + "no neutralMoleculePhase XML node"); + } + XML_Node& neutralMoleculeNode = thermoNode.child("neutralMoleculePhase"); + + string nsource = neutralMoleculeNode["datasrc"]; + XML_Node *neut_ptr = get_XML_Node(nsource, 0); + if (!neut_ptr) { + throw CanteraError("IonsFromNeutralVPSSTP::constructPhaseXML", + "neut_ptr = 0"); + } + + /* + * Create the neutralMolecule ThermoPhase if we haven't already + */ + if (!neutralMoleculePhase_) { + neutralMoleculePhase_ = newPhase(*neut_ptr); + } + + /* + * Call the Cantera importPhase() function. This will import + * all of the species into the phase. This will also handle + * all of the solvent and solute standard states + */ + bool m_ok = importPhase(phaseNode, this); + if (!m_ok) { + throw CanteraError("IonsFromNeutralVPSSTP::constructPhaseXML", + "importPhase failed "); + } + + } + + /* * -------------- Utilities ------------------------------- */ diff --git a/src/thermo/ThermoFactory.cpp b/src/thermo/ThermoFactory.cpp index 2484d0a1a..700479b6a 100644 --- a/src/thermo/ThermoFactory.cpp +++ b/src/thermo/ThermoFactory.cpp @@ -247,7 +247,22 @@ ThermoPhase* newPhase(XML_Node& xmlphase) const XML_Node& th = xmlphase.child("thermo"); string model = th["model"]; ThermoPhase* t = newThermoPhase(model); - importPhase(xmlphase, t); + if (model == "singing cows") { + throw CanteraError("ThermoPhase::newPhase", "Cows don't sing"); + } + else if (model == "HMW") { + HMWSoln* p = dynamic_cast(t); + p->constructPhaseXML(xmlphase,""); + } + else if (model == "IonsFromNeutralMolecule") { + IonsFromNeutralVPSSTP* p = dynamic_cast(t); + p->constructPhaseXML(xmlphase,""); + } + else { + importPhase(xmlphase, t); + } + //return t; + //importPhase(xmlphase, t); return t; }