diff --git a/include/cantera/thermo/Species.h b/include/cantera/thermo/Species.h index 11bda2246..f3ad4a118 100644 --- a/include/cantera/thermo/Species.h +++ b/include/cantera/thermo/Species.h @@ -4,11 +4,13 @@ #define CT_SPECIES_H #include "cantera/base/ct_defs.h" +#include "cantera/base/smart_ptr.h" namespace Cantera { class SpeciesThermoInterpType; +class TransportData; //! Contains data about a single chemical species /*! @@ -49,6 +51,8 @@ public: //! The effective size [m] of the species double size; + shared_ptr transport; + protected: //! Thermodynamic data for the species SpeciesThermoInterpType* thermo_; diff --git a/include/cantera/transport/TransportData.h b/include/cantera/transport/TransportData.h new file mode 100644 index 000000000..6f7862f90 --- /dev/null +++ b/include/cantera/transport/TransportData.h @@ -0,0 +1,76 @@ +//! @file TransportData.h + +#ifndef CT_TRANSPORTDATA_H +#define CT_TRANSPORTDATA_H + +#include "cantera/base/ct_defs.h" + +namespace Cantera +{ + +class Species; + +//! Base class for transport data for a single species +class TransportData +{ +public: + TransportData() {} + explicit TransportData(const std::string& name); + virtual ~TransportData() {} + + virtual void validate(const Species& species) {} + + //! The name of the species + std::string name; +}; + +//! Transport data for a single gas-phase species which can be used in +//! mixture-averaged or multicomponent transport models. +class GasTransportData : public TransportData +{ +public: + GasTransportData(); + + GasTransportData(const std::string& name, const std::string& geometry, + double diameter, double well_depth, double dipole=0.0, + double polarizability=0.0, double rot_relax=0.0, + double acentric=0.0); + + //! Set the parameters using "customary" units: diameter in Angstroms, well + //! depth in Kelvin, dipole in Debye, and polarizability in Angstroms^3. + //! These are the units used in in CK-style input files. + void setCustomaryUnits(const std::string& name, const std::string& geometry, + double diameter, double well_depth, double dipole=0.0, + double polarizability=0.0, double rot_relax=0.0, + double acentric=0.0); + + virtual void validate(const Species& species); + + //! A string specifying the molecular geometry. One of `atom`, `linear`, or + //! `nonlinear`. + std::string geometry; + + //! The Lennard-Jones collision diameter [m] + double diameter; + + //! The Lennard-Jones well depth [J] + double well_depth; + + //! The permanent dipole moment of the molecule [Coulomb-m]. Default 0.0. + double dipole; + + //! The polarizability of the molecule [m^3]. Default 0.0. + double polarizability; + + //! The rotational relaxation number (the number of collisions it takes to + //! equilibrate the rotational degrees of freedom with the temperature). + //! Default 0.0. + double rotational_relaxation; + + // Pitzer's acentric factor [dimensionless]. Default 0.0. + double acentric_factor; +}; + +} + +#endif diff --git a/src/thermo/Species.cpp b/src/thermo/Species.cpp index 8bd8c88e8..54e0482c3 100644 --- a/src/thermo/Species.cpp +++ b/src/thermo/Species.cpp @@ -35,6 +35,7 @@ Species::Species(const Species& other) , composition(other.composition) , charge(other.charge) , size(other.size) + , transport(other.transport) { if (other.thermo_) { thermo_ = other.thermo_->duplMyselfAsSpeciesThermoInterpType(); @@ -52,6 +53,7 @@ Species& Species::operator=(const Species& other) composition = other.composition; charge = other.charge; size = other.size; + transport = other.transport; delete thermo_; if (other.thermo_) { thermo_ = other.thermo_->duplMyselfAsSpeciesThermoInterpType(); diff --git a/src/thermo/ThermoFactory.cpp b/src/thermo/ThermoFactory.cpp index 1a7e28468..45734c7de 100644 --- a/src/thermo/ThermoFactory.cpp +++ b/src/thermo/ThermoFactory.cpp @@ -52,6 +52,8 @@ #include "cantera/thermo/MixedSolventElectrolyte.h" #include "cantera/thermo/IdealSolnGasVPSS.h" +#include "cantera/transport/TransportData.h" + #include "cantera/base/stringUtils.h" using namespace std; @@ -621,7 +623,37 @@ bool installSpecies(size_t k, const XML_Node& s, thermo_t& th, vp_ptr->createInstallPDSS(k, s, phaseNode_ptr); } else { SpeciesThermoInterpType* st = newSpeciesThermoInterpType(s); - th.addSpecies(Species(s["name"], comp_map, st, chrg, sz)); + 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; diff --git a/src/transport/TransportData.cpp b/src/transport/TransportData.cpp new file mode 100644 index 000000000..e708403f5 --- /dev/null +++ b/src/transport/TransportData.cpp @@ -0,0 +1,116 @@ +//! @file TransportData.cpp + +#include "cantera/transport/TransportData.h" +#include "cantera/thermo/Species.h" +#include "cantera/base/ctexceptions.h" +#include "cantera/base/stringUtils.h" + +namespace Cantera +{ + +TransportData::TransportData(const std::string& name_) + : name(name_) +{ +} + +GasTransportData::GasTransportData() + : diameter(0.0) + , well_depth(0.0) + , dipole(0.0) + , polarizability(0.0) + , rotational_relaxation(0.0) + , acentric_factor(0.0) +{ +} + +GasTransportData::GasTransportData( + const std::string& name_, const std::string& geometry_, + double diameter_, double well_depth_, double dipole_, + double polarizability_, double rot_relax, double acentric) + : TransportData(name_) + , geometry(geometry_) + , diameter(diameter_) + , well_depth(well_depth_) + , dipole(dipole_) + , polarizability(polarizability_) + , rotational_relaxation(rot_relax) + , acentric_factor(acentric) +{ +} + +void GasTransportData::setCustomaryUnits( + const std::string& name_, const std::string& geometry_, + double diameter_, double well_depth_, double dipole_, + double polarizability_, double rot_relax, double acentric) +{ + name = name_; + geometry = geometry_; + diameter = 1e-10 * diameter_; // convert from Angstroms to m + well_depth = Boltzmann * well_depth_; // convert from K to J + dipole = 1e-21 / lightSpeed * dipole_; // convert from Debye to Coulomb-m + polarizability = 1e-30 * polarizability_; // convert from Angstroms^3 to m^3 + rotational_relaxation = rot_relax; // pure number + acentric_factor = acentric; // dimensionless +} + +void GasTransportData::validate(const Species& sp) +{ + double nAtoms = 0; + for (compositionMap::const_iterator iter = sp.composition.begin(); + iter != sp.composition.end(); + ++iter) { + nAtoms += iter->second; + } + + if (geometry == "atom") { + if (nAtoms != 1) { + throw CanteraError("GasTransportData::validate", + "invalid geometry for species '" + name + "'. 'atom' specified," + " but species contains multiple atoms."); + } + } else if (geometry == "linear") { + if (nAtoms == 1) { + throw CanteraError("GasTransportData::validate", + "invalid geometry for species '" + name + "'. 'linear'" + " specified, but species only contains one atom."); + } + } else if (geometry == "nonlinear") { + if (nAtoms < 3) { + throw CanteraError("GasTransportData::validate", + "invalid geometry for species '" + name + "'. 'nonlinear'" + " specified, but species only contains " + fp2str(nAtoms) + + " atoms."); + } + } else { + throw CanteraError("GasTransportData::validate", + "invalid geometry for species '" + name + "': '" + + geometry + "'."); + } + + if (well_depth < 0.0) { + throw CanteraError("GasTransportData::validate", + "negative well depth for species '" + name + "'."); + } + + if (diameter <= 0.0) { + throw CanteraError("GasTransportData::validate", + "negative or zero diameter for species '" + name + "'."); + } + + if (dipole < 0.0) { + throw CanteraError("GasTransportData::validate", + "negative dipole moment for species '" + name + "'."); + } + + if (polarizability < 0.0) { + throw CanteraError("GasTransportData::validate", + "negative polarizability for species '" + name + "'."); + } + + if (rotational_relaxation < 0.0) { + throw CanteraError("GasTransportData::validate", + "negative rotation relaxation number for species '" + name + "'"); + } +} + +}