void Transport::setThermo(thermo_t& thermo) { if (!ready()) { m_thermo = &thermo; m_nsp = m_thermo->nSpecies(); } else { size_t newNum = thermo.nSpecies(); size_t oldNum = m_thermo->nSpecies(); if (newNum != oldNum) { throw CanteraError("Transport::setThermo", "base object cannot be changed after " "the transport manager has been constructed because num species isn't the same."); } for (size_t i = 0; i < newNum; i++) { std::string newS0 = thermo.speciesName(i); std::string oldS0 = m_thermo->speciesName(i); if (newNum != oldNum) { throw CanteraError("Transport::setThermo", "base object cannot be changed after " "the transport manager has been constructed because species names are not the same"); } } m_thermo = &thermo; } }
/* * Add a phase to the kinetics manager object. This must * be done before the function init() is called or * before any reactions are input. * The following fields are updated: * m_start -> vector of integers, containing the * starting position of the species for * each phase in the kinetics mechanism. * m_surfphase -> index of the surface phase. * m_thermo -> vector of pointers to ThermoPhase phases * that participate in the kinetics * mechanism. * m_phaseindex -> map containing the string id of each * ThermoPhase phase as a key and the * index of the phase within the kinetics * manager object as the value. */ void Kinetics::addPhase(thermo_t& thermo) { // if not the first thermo object, set the start position // to that of the last object added + the number of its species if (m_thermo.size() > 0) { m_start.push_back(m_start.back() + m_thermo.back()->nSpecies()); } // otherwise start at 0 else { m_start.push_back(0); } // the phase with lowest dimensionality is assumed to be the // phase/interface at which reactions take place if (thermo.nDim() <= m_mindim) { m_mindim = thermo.nDim(); m_rxnphase = nPhases(); } // there should only be one surface phase int ptype = -100; if (type() == cEdgeKinetics) ptype = cEdge; else if (type() == cInterfaceKinetics) ptype = cSurf; if (thermo.eosType() == ptype) { // if (m_surfphase >= 0) { // throw CanteraError("Kinetics::addPhase", // "cannot add more than one surface phase"); // } m_surfphase = nPhases(); m_rxnphase = nPhases(); } m_thermo.push_back(&thermo); m_phaseindex[m_thermo.back()->id()] = nPhases(); }
void Kinetics::addPhase(thermo_t& thermo) { // the phase with lowest dimensionality is assumed to be the // phase/interface at which reactions take place if (thermo.nDim() <= m_mindim) { m_mindim = thermo.nDim(); m_rxnphase = nPhases(); } // there should only be one surface phase int ptype = -100; if (type() == cEdgeKinetics) { ptype = cEdge; } else if (type() == cInterfaceKinetics) { ptype = cSurf; } if (thermo.eosType() == ptype) { m_surfphase = nPhases(); m_rxnphase = nPhases(); } m_thermo.push_back(&thermo); m_phaseindex[m_thermo.back()->id()] = nPhases(); resizeSpecies(); }
/* * Set a single-phase chemical solution to chemical equilibrium. * This is a convenience function that uses one or the other of * the two chemical equilibrium solvers. * * @param s The object to set to an equilibrium state * * @param XY An integer specifying the two properties to be held * constant. * * @param estimateEquil integer indicating whether the solver * should estimate its own initial condition. * If 0, the initial mole fraction vector * in the %ThermoPhase object is used as the * initial condition. * If 1, the initial mole fraction vector * is used if the element abundances are * satisfied. * if -1, the initial mole fraction vector * is thrown out, and an estimate is * formulated. * * @param printLvl Determines the amount of printing that * gets sent to stdout from the vcs package * (Note, you may have to compile with debug * flags to get some printing). * * @param solver The equilibrium solver to use. If solver = 0, * the ChemEquil solver will be used, and if * solver = 1, the vcs_MultiPhaseEquil solver will * be used (slower than ChemEquil, * but more stable). If solver < 0 (default, then * ChemEquil will be tried first, and if it fails * vcs_MultiPhaseEquil will be tried. * * @param maxsteps The maximum number of steps to take to find * the solution. * * @param maxiter For the MultiPhaseEquil solver only, this is * the maximum number of outer temperature or * pressure iterations to take when T and/or P is * not held fixed. * * @param loglevel Controls amount of diagnostic output. loglevel * = 0 suppresses diagnostics, and increasingly-verbose * messages are written as loglevel increases. The * messages are written to a file in HTML format for viewing * in a web browser. @see HTML_logs */ int vcs_equilibrate(thermo_t& s, const char* XY, int estimateEquil, int printLvl, int solver, doublereal rtol, int maxsteps, int maxiter, int loglevel) { MultiPhase* m = 0; int retn = 1; int retnSub = 0; beginLogGroup("equilibrate", loglevel); // retry: addLogEntry("Single-phase equilibrate function"); { beginLogGroup("arguments"); addLogEntry("phase",s.id()); addLogEntry("XY",XY); addLogEntry("solver",solver); addLogEntry("rtol",rtol); addLogEntry("maxsteps",maxsteps); addLogEntry("maxiter",maxiter); addLogEntry("loglevel",loglevel); endLogGroup("arguments"); } if (solver == 2) { m = new MultiPhase; try { /* * Set the kmoles of the phase to 1.0, arbitrarily. * It actually doesn't matter. */ m->addPhase(&s, 1.0); m->init(); retn = vcs_equilibrate(*m, XY, estimateEquil, printLvl, solver, rtol, maxsteps, maxiter, loglevel); if (retn == 1) { addLogEntry("MultiPhaseEquil solver succeeded."); } else { addLogEntry("MultiPhaseEquil solver returned an error code: ", retn); } delete m; } catch (CanteraError& err) { err.save(); addLogEntry("MultiPhaseEquil solver failed."); delete m; throw err; } } else if (solver == 1) { m = new MultiPhase; try { m->addPhase(&s, 1.0); m->init(); (void) equilibrate(*m, XY, rtol, maxsteps, maxiter, loglevel-1); if (loglevel > 0) { addLogEntry("MultiPhaseEquil solver succeeded."); } delete m; retn = 1; } catch (CanteraError& err) { err.save(); if (loglevel > 0) { addLogEntry("MultiPhaseEquil solver failed."); } delete m; throw err; } } else if (solver == 0) { ChemEquil* e = new ChemEquil; try { e->options.maxIterations = maxsteps; e->options.relTolerance = rtol; bool useThermoPhaseElementPotentials = false; if (estimateEquil == 0) { useThermoPhaseElementPotentials = true; } retnSub = e->equilibrate(s, XY, useThermoPhaseElementPotentials, loglevel-1); if (retnSub < 0) { if (loglevel > 0) { addLogEntry("ChemEquil solver failed."); } delete e; throw CanteraError("equilibrate", "ChemEquil equilibrium solver failed"); } retn = 1; s.setElementPotentials(e->elementPotentials()); delete e; if (loglevel > 0) { addLogEntry("ChemEquil solver succeeded."); } } catch (CanteraError& err) { err.save(); if (loglevel > 0) { addLogEntry("ChemEquil solver failed."); } delete e; throw err; } } else { throw CanteraError("vcs_equilibrate", "unknown solver"); } /* * We are here only for a success */ endLogGroup("equilibrate"); return retn; }
int vcs_equilibrate(thermo_t& s, const char* XY, int estimateEquil, int printLvl, int solver, doublereal rtol, int maxsteps, int maxiter, int loglevel) { warn_deprecated("vcs_equilibrate", "Use ThermoPhase::equilibrate instead. " "To be removed after Cantera 2.2."); MultiPhase* m = 0; int retn = 1; if (solver == 2) { m = new MultiPhase; try { /* * Set the kmoles of the phase to 1.0, arbitrarily. * It actually doesn't matter. */ m->addPhase(&s, 1.0); m->init(); retn = vcs_equilibrate(*m, XY, estimateEquil, printLvl, solver, rtol, maxsteps, maxiter, loglevel); delete m; } catch (CanteraError& err) { err.save(); delete m; throw err; } } else if (solver == 1) { m = new MultiPhase; try { m->addPhase(&s, 1.0); m->init(); (void) equilibrate(*m, XY, rtol, maxsteps, maxiter, loglevel-1); delete m; retn = 1; } catch (CanteraError& err) { err.save(); delete m; throw err; } } else if (solver == 0) { ChemEquil* e = new ChemEquil; try { e->options.maxIterations = maxsteps; e->options.relTolerance = rtol; bool useThermoPhaseElementPotentials = false; if (estimateEquil == 0) { useThermoPhaseElementPotentials = true; } int retnSub = e->equilibrate(s, XY, useThermoPhaseElementPotentials, loglevel-1); if (retnSub < 0) { delete e; throw CanteraError("equilibrate", "ChemEquil equilibrium solver failed"); } retn = 1; s.setElementPotentials(e->elementPotentials()); delete e; } catch (CanteraError& err) { err.save(); delete e; throw err; } } else { throw CanteraError("vcs_equilibrate", "unknown solver"); } /* * We are here only for a success */ return retn; }
/* * Set a single-phase chemical solution to chemical equilibrium. * This is a convenience function that uses one or the other of * the two chemical equilibrium solvers. * * @param s The object to set to an equilibrium state * * @param XY An integer specifying the two properties to be held * constant. * * @param solver The equilibrium solver to use. If solver = 0, * the ChemEquil solver will be used, and if solver = 1, the * MultiPhaseEquil solver will be used (slower than ChemEquil, * but more stable). If solver < 0 (default, then ChemEquil will * be tried first, and if it fails MultiPhaseEquil will be tried. * * @param maxsteps The maximum number of steps to take to find * the solution. * * @param maxiter For the MultiPhaseEquil solver only, this is * the maximum number of outer temperature or pressure iterations * to take when T and/or P is not held fixed. * * @param loglevel Controls amount of diagnostic output. loglevel * = 0 suppresses diagnostics, and increasingly-verbose messages * are written as loglevel increases. The messages are written to * a file in HTML format for viewing in a web browser. * @see HTML_logs * * @ingroup equil */ int equilibrate(thermo_t& s, const char* XY, int solver, doublereal rtol, int maxsteps, int maxiter, int loglevel) { MultiPhase* m = 0; ChemEquil* e = 0; bool redo = true; int retn = -1; int nAttempts = 0; int retnSub = 0; if (loglevel > 0) { beginLogGroup("equilibrate", loglevel); addLogEntry("Single-phase equilibrate function"); { beginLogGroup("arguments"); addLogEntry("phase",s.id()); addLogEntry("XY",XY); addLogEntry("solver",solver); addLogEntry("rtol",rtol); addLogEntry("maxsteps",maxsteps); addLogEntry("maxiter",maxiter); addLogEntry("loglevel",loglevel); endLogGroup("arguments"); } } while (redo) { if (solver >= 2) { #ifdef WITH_VCSNONIDEAL int printLvlSub = 0; int estimateEquil = 0; m = new MultiPhase; try { m->addPhase(&s, 1.0); m->init(); nAttempts++; vcs_equilibrate(*m, XY, estimateEquil, printLvlSub, solver, rtol, maxsteps, maxiter, loglevel-1); redo = false; if (loglevel > 0) addLogEntry("VCSnonideal solver succeeded."); delete m; retn = nAttempts; } catch (CanteraError &err) { if (loglevel > 0) addLogEntry("VCSnonideal solver failed."); delete m; if (nAttempts < 2) { if (loglevel > 0) addLogEntry("Trying single phase ChemEquil solver."); solver = -1; } else { if (loglevel > 0) endLogGroup("equilibrate"); throw err; } } #else throw CanteraError("equilibrate", "VCSNonIdeal solver called, but not compiled"); #endif } else if (solver == 1) { m = new MultiPhase; try { m->addPhase(&s, 1.0); m->init(); nAttempts++; (void) equilibrate(*m, XY, rtol, maxsteps, maxiter, loglevel-1); redo = false; if (loglevel > 0) addLogEntry("MultiPhaseEquil solver succeeded."); delete m; retn = nAttempts; } catch (CanteraError &err) { if (loglevel > 0) addLogEntry("MultiPhaseEquil solver failed."); delete m; if (nAttempts < 2) { if (loglevel > 0) addLogEntry("Trying single phase ChemEquil solver."); solver = -1; } else { if (loglevel > 0) endLogGroup("equilibrate"); throw err; } } } else { // solver <= 0 /* * Call the element potential solver */ e = new ChemEquil; try { e->options.maxIterations = maxsteps; e->options.relTolerance = rtol; nAttempts++; bool useThermoPhaseElementPotentials = true; retnSub = e->equilibrate(s,XY, useThermoPhaseElementPotentials, loglevel-1); if (retnSub < 0) { if (loglevel > 0) addLogEntry("ChemEquil solver failed."); if (nAttempts < 2) { if (loglevel > 0) addLogEntry("Trying MultiPhaseEquil solver."); solver = 1; } else { throw CanteraError("equilibrate", "Both equilibrium solvers failed"); } } retn = nAttempts; s.setElementPotentials(e->elementPotentials()); redo = false; delete e; if (loglevel > 0) addLogEntry("ChemEquil solver succeeded."); } catch (CanteraError &err) { delete e; if (loglevel > 0) addLogEntry("ChemEquil solver failed."); // If ChemEquil fails, try the MultiPhase solver if (solver < 0) { if (loglevel > 0) addLogEntry("Trying MultiPhaseEquil solver."); solver = 1; } else { redo = false; if (loglevel > 0) endLogGroup("equilibrate"); throw err; } } } } // while (redo) /* * We are here only for a success */ if (loglevel > 0) endLogGroup("equilibrate"); return retn; }
bool installSpecies(size_t k, const XML_Node& s, thermo_t& th, SpeciesThermo* spthermo_ptr, int rule, XML_Node* phaseNode_ptr, VPSSMgr* vpss_ptr, SpeciesThermoFactory* factory) { std::string xname = s.name(); if (xname != "species") { throw CanteraError("installSpecies", "Unexpected XML name of species XML_Node: " + xname); } // get the composition of the species const XML_Node& a = s.child("atomArray"); map<string,string> comp; getMap(a, comp); // check that all elements in the species exist in 'p'. If rule != 0, // quietly skip this species if some elements are undeclared; otherwise, // throw an exception map<string,string>::const_iterator _b = comp.begin(); for (; _b != comp.end(); ++_b) { if (th.elementIndex(_b->first) == npos) { if (rule == 0) { throw CanteraError("installSpecies", "Species " + s["name"] + " contains undeclared element " + _b->first); } else { return false; } } } // construct a vector of atom numbers for each element in phase th. Elements // not declared in the species (i.e., not in map comp) will have zero // entries in the vector. size_t nel = th.nElements(); vector_fp ecomp(nel, 0.0); for (size_t m = 0; m < nel; m++) { std::string& es = comp[th.elementName(m)]; if (!es.empty()) { ecomp[m] = fpValueCheck(es); } } // get the species charge, if any. Note that the charge need // not be explicitly specified if special element 'E' // (electron) is one of the elements. doublereal chrg = 0.0; if (s.hasChild("charge")) { chrg = getFloat(s, "charge"); } // get the species size, if any. (This is used by surface // phases to represent how many sites a species occupies.) doublereal sz = 1.0; if (s.hasChild("size")) { sz = getFloat(s, "size"); } // add the species to phase th th.addUniqueSpecies(s["name"], &ecomp[0], chrg, sz); if (vpss_ptr) { VPStandardStateTP* vp_ptr = dynamic_cast<VPStandardStateTP*>(&th); factory->installVPThermoForSpecies(k, s, vp_ptr, phaseNode_ptr); } else { // install the thermo parameterization for this species into // the species thermo manager for phase th factory->installThermoForSpecies(k, s, &th, *spthermo_ptr, phaseNode_ptr); } return true; }
int equilibrate(thermo_t& s, const char* XY, int solver, doublereal rtol, int maxsteps, int maxiter, int loglevel) { bool redo = true; int retn = -1; int nAttempts = 0; int retnSub = 0; if (loglevel > 0) { beginLogGroup("equilibrate", loglevel); addLogEntry("Single-phase equilibrate function"); { beginLogGroup("arguments"); addLogEntry("phase",s.id()); addLogEntry("XY",XY); addLogEntry("solver",solver); addLogEntry("rtol",rtol); addLogEntry("maxsteps",maxsteps); addLogEntry("maxiter",maxiter); addLogEntry("loglevel",loglevel); endLogGroup("arguments"); } } while (redo) { if (solver >= 2) { int printLvlSub = 0; int estimateEquil = 0; try { MultiPhase m; m.addPhase(&s, 1.0); m.init(); nAttempts++; vcs_equilibrate(m, XY, estimateEquil, printLvlSub, solver, rtol, maxsteps, maxiter, loglevel-1); redo = false; if (loglevel > 0) { addLogEntry("VCSnonideal solver succeeded."); } retn = nAttempts; } catch (CanteraError& err) { err.save(); if (loglevel > 0) { addLogEntry("VCSnonideal solver failed."); } if (nAttempts < 2) { if (loglevel > 0) { addLogEntry("Trying single phase ChemEquil solver."); } solver = -1; } else { if (loglevel > 0) { endLogGroup("equilibrate"); } throw err; } } } else if (solver == 1) { try { MultiPhase m; m.addPhase(&s, 1.0); m.init(); nAttempts++; equilibrate(m, XY, rtol, maxsteps, maxiter, loglevel-1); redo = false; if (loglevel > 0) { addLogEntry("MultiPhaseEquil solver succeeded."); } retn = nAttempts; } catch (CanteraError& err) { err.save(); if (loglevel > 0) { addLogEntry("MultiPhaseEquil solver failed."); } if (nAttempts < 2) { if (loglevel > 0) { addLogEntry("Trying single phase ChemEquil solver."); } solver = -1; } else { if (loglevel > 0) { endLogGroup("equilibrate"); } throw err; } } } else { // solver <= 0 /* * Call the element potential solver */ try { ChemEquil e; e.options.maxIterations = maxsteps; e.options.relTolerance = rtol; nAttempts++; bool useThermoPhaseElementPotentials = true; retnSub = e.equilibrate(s, XY, useThermoPhaseElementPotentials, loglevel-1); if (retnSub < 0) { if (loglevel > 0) { addLogEntry("ChemEquil solver failed."); } if (nAttempts < 2) { if (loglevel > 0) { addLogEntry("Trying MultiPhaseEquil solver."); } solver = 1; } else { throw CanteraError("equilibrate", "Both equilibrium solvers failed"); } } retn = nAttempts; s.setElementPotentials(e.elementPotentials()); redo = false; if (loglevel > 0) { addLogEntry("ChemEquil solver succeeded."); } } catch (CanteraError& err) { err.save(); if (loglevel > 0) { addLogEntry("ChemEquil solver failed."); } // If ChemEquil fails, try the MultiPhase solver if (solver < 0) { if (loglevel > 0) { addLogEntry("Trying MultiPhaseEquil solver."); } solver = 1; } else { redo = false; if (loglevel > 0) { endLogGroup("equilibrate"); } throw err; } } } } // while (redo) /* * We are here only for a success */ if (loglevel > 0) { endLogGroup("equilibrate"); } return retn; }
bool installSpecies(size_t k, const XML_Node& s, thermo_t& th, SpeciesThermo* spthermo_ptr, int rule, XML_Node* phaseNode_ptr, VPSSMgr* vpss_ptr, SpeciesThermoFactory* factory) { std::string xname = s.name(); if (xname != "species") { throw CanteraError("installSpecies", "Unexpected XML name of species XML_Node: " + xname); } if (rule) { th.ignoreUndefinedElements(); } // get the composition of the species const XML_Node& a = s.child("atomArray"); map<string,string> comp; getMap(a, comp); // construct a vector of atom numbers for each element in phase th. Elements // not declared in the species (i.e., not in map comp) will have zero // entries in the vector. size_t nel = th.nElements(); vector_fp ecomp(nel, 0.0); compositionMap comp_map = parseCompString(a.value()); for (size_t m = 0; m < nel; m++) { std::string& es = comp[th.elementName(m)]; if (!es.empty()) { ecomp[m] = fpValueCheck(es); } } // get the species charge, if any. Note that the charge need // not be explicitly specified if special element 'E' // (electron) is one of the elements. doublereal chrg = 0.0; if (s.hasChild("charge")) { chrg = getFloat(s, "charge"); } // get the species size, if any. (This is used by surface // phases to represent how many sites a species occupies.) doublereal sz = 1.0; if (s.hasChild("size")) { sz = getFloat(s, "size"); } if (vpss_ptr) { th.addUniqueSpecies(s["name"], &ecomp[0], chrg, sz); VPStandardStateTP* vp_ptr = dynamic_cast<VPStandardStateTP*>(&th); vp_ptr->createInstallPDSS(k, s, phaseNode_ptr); } else { SpeciesThermoInterpType* st = newSpeciesThermoInterpType(s); Species sp(s["name"], comp_map, st, chrg, sz); // Read gas-phase transport data, if provided if (s.hasChild("transport") && s.child("transport")["model"] == "gas_transport") { XML_Node& tr = s.child("transport"); string geometry, dummy; getString(tr, "geometry", geometry, dummy); double diam = getFloat(tr, "LJ_diameter"); double welldepth = getFloat(tr, "LJ_welldepth"); double dipole = 0.0; getOptionalFloat(tr, "dipoleMoment", dipole); double polar = 0.0; getOptionalFloat(tr, "polarizability", polar); double rot = 0.0; getOptionalFloat(tr, "rotRelax", rot); double acentric = 0.0; getOptionalFloat(tr, "acentric_factor", acentric); GasTransportData* gastran = new GasTransportData; gastran->setCustomaryUnits(sp.name, geometry, diam, welldepth, dipole, polar, rot, acentric); sp.transport.reset(gastran); gastran->validate(sp); } th.addSpecies(sp); } return true; }