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;
    }
}
Пример #2
0
  /*
   * 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();
  }
Пример #3
0
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();
}
Пример #4
0
/*
 *  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;
}
Пример #5
0
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;
}
Пример #6
0
  /*
   *  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;
  }
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
0
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;
}