cantera/src/transport/SimpleTransport.cpp

1033 lines
34 KiB
C++

/**
* @file SimpleTransport.cpp
* Simple mostly constant transport properties
*/
#include "cantera/thermo/ThermoPhase.h"
#include "cantera/transport/SimpleTransport.h"
#include "cantera/base/utilities.h"
#include "cantera/transport/LiquidTransportParams.h"
#include "cantera/transport/TransportFactory.h"
#include "cantera/numerics/ctlapack.h"
#include "cantera/base/stringUtils.h"
#include <iostream>
using namespace std;
/**
* Mole fractions below MIN_X will be set to MIN_X when computing
* transport properties.
*/
#define MIN_X 1.e-14
#ifndef SAFE_DELETE
//! \cond
#define SAFE_DELETE(x) if (x) { delete (x); x = 0; }
//! \endcond
#endif
namespace Cantera
{
//================================================================================================
SimpleTransport::SimpleTransport(thermo_t* thermo, int ndim) :
Transport(thermo, ndim),
tempDepType_(0),
compositionDepType_(0),
useHydroRadius_(false),
doMigration_(0),
m_tmin(-1.0),
m_tmax(100000.),
m_iStateMF(-1),
concTot_(0.0),
m_temp(-1.0),
m_press(-1.0),
m_lambda(-1.0),
m_viscmix(-1.0),
m_visc_mix_ok(false),
m_visc_temp_ok(false),
m_diff_mix_ok(false),
m_diff_temp_ok(false),
m_cond_temp_ok(false),
m_cond_mix_ok(false),
m_nDim(1)
{
}
//================================================================================================
SimpleTransport::SimpleTransport(const SimpleTransport& right) :
Transport(),
tempDepType_(0),
compositionDepType_(0),
useHydroRadius_(false),
doMigration_(0),
m_tmin(-1.0),
m_tmax(100000.),
m_iStateMF(-1),
m_temp(-1.0),
m_press(-1.0),
m_lambda(-1.0),
m_viscmix(-1.0),
m_visc_mix_ok(false),
m_visc_temp_ok(false),
m_diff_mix_ok(false),
m_diff_temp_ok(false),
m_cond_temp_ok(false),
m_cond_mix_ok(false),
m_nDim(1)
{
/*
* Use the assignment operator to do the brunt
* of the work for the copy constructor.
*/
*this = right;
}
//================================================================================================
SimpleTransport& SimpleTransport::operator=(const SimpleTransport& right)
{
if (&right == this) {
return *this;
}
Transport::operator=(right);
tempDepType_ = right.tempDepType_;
compositionDepType_ = right.compositionDepType_;
useHydroRadius_ = right.useHydroRadius_;
doMigration_ = right.doMigration_;
m_tmin = right.m_tmin;
m_tmax = right.m_tmax;
m_mw = right.m_mw;
m_coeffVisc_Ns = right.m_coeffVisc_Ns;
for (size_t k = 0; k <right.m_coeffVisc_Ns.size() ; k++) {
if (right.m_coeffVisc_Ns[k]) {
m_coeffVisc_Ns[k] = (right.m_coeffVisc_Ns[k])->duplMyselfAsLTPspecies();
}
}
m_coeffLambda_Ns = right.m_coeffLambda_Ns;
for (size_t k = 0; k < right.m_coeffLambda_Ns.size(); k++) {
if (right.m_coeffLambda_Ns[k]) {
m_coeffLambda_Ns[k] = (right.m_coeffLambda_Ns[k])->duplMyselfAsLTPspecies();
}
}
m_coeffDiff_Ns = right.m_coeffDiff_Ns;
for (size_t k = 0; k < right.m_coeffDiff_Ns.size(); k++) {
if (right.m_coeffDiff_Ns[k]) {
m_coeffDiff_Ns[k] = (right.m_coeffDiff_Ns[k])->duplMyselfAsLTPspecies();
}
}
m_coeffHydroRadius_Ns = right.m_coeffHydroRadius_Ns;
for (size_t k = 0; k < right.m_coeffHydroRadius_Ns.size(); k++) {
if (right.m_coeffHydroRadius_Ns[k]) {
m_coeffHydroRadius_Ns[k] = (right.m_coeffHydroRadius_Ns[k])->duplMyselfAsLTPspecies();
}
}
m_Grad_X = right.m_Grad_X;
m_Grad_T = right.m_Grad_T;
m_Grad_P = right.m_Grad_P;
m_Grad_V = right.m_Grad_V;
m_diffSpecies = right.m_diffSpecies;
m_viscSpecies = right.m_viscSpecies;
m_condSpecies = right.m_condSpecies;
m_iStateMF = -1;
m_molefracs = right.m_molefracs;
m_concentrations = right.m_concentrations;
concTot_ = right.concTot_;
meanMolecularWeight_ = right.meanMolecularWeight_;
dens_ = right.dens_;
m_chargeSpecies = right.m_chargeSpecies;
m_temp = right.m_temp;
m_press = right.m_press;
m_lambda = right.m_lambda;
m_viscmix = right.m_viscmix;
m_spwork = right.m_spwork;
m_visc_mix_ok = false;
m_visc_temp_ok = false;
m_diff_mix_ok = false;
m_diff_temp_ok = false;
m_cond_temp_ok = false;
m_cond_mix_ok = false;
m_nDim = right.m_nDim;
return *this;
}
//================================================================================================
Transport* SimpleTransport::duplMyselfAsTransport() const
{
SimpleTransport* tr = new SimpleTransport(*this);
return (dynamic_cast<Transport*>(tr));
}
//================================================================================================
SimpleTransport::~SimpleTransport()
{
for (size_t k = 0; k < m_coeffVisc_Ns.size() ; k++) {
SAFE_DELETE(m_coeffVisc_Ns[k]);
}
for (size_t k = 0; k < m_coeffLambda_Ns.size(); k++) {
SAFE_DELETE(m_coeffLambda_Ns[k]);
}
for (size_t k = 0; k < m_coeffDiff_Ns.size(); k++) {
SAFE_DELETE(m_coeffDiff_Ns[k]);
}
for (size_t k = 0; k < m_coeffHydroRadius_Ns.size(); k++) {
SAFE_DELETE(m_coeffHydroRadius_Ns[k]);
}
}
//================================================================================================
// Initialize the object
/*
* This is where we dimension everything.
*/
bool SimpleTransport::initLiquid(LiquidTransportParams& tr)
{
// constant substance attributes
m_thermo = tr.thermo;
m_nsp = m_thermo->nSpecies();
m_tmin = m_thermo->minTemp();
m_tmax = m_thermo->maxTemp();
/*
* Read the transport block in the phase XML Node
* It's not an error if this block doesn't exist. Just use the defaults
*/
XML_Node& phaseNode = m_thermo->xml();
if (phaseNode.hasChild("transport")) {
XML_Node& transportNode = phaseNode.child("transport");
string transportModel = transportNode.attrib("model");
if (transportModel == "Simple") {
/*
* <compositionDependence model="Solvent_Only"/>
* or
* <compositionDependence model="Mixture_Averaged"/>
*/
std::string modelName = "";
if (ctml::getOptionalModel(transportNode, "compositionDependence",
modelName)) {
modelName = lowercase(modelName);
if (modelName == "solvent_only") {
compositionDepType_ = 0;
} else if (modelName == "mixture_averaged") {
compositionDepType_ = 1;
} else {
throw CanteraError("SimpleTransport::initLiquid", "Unknown compositionDependence Model: " + modelName);
}
}
}
}
// make a local copy of the molecular weights
m_mw.resize(m_nsp);
copy(m_thermo->molecularWeights().begin(),
m_thermo->molecularWeights().end(), m_mw.begin());
/*
* Get the input Viscosities
*/
m_viscSpecies.resize(m_nsp);
m_coeffVisc_Ns.clear();
m_coeffVisc_Ns.resize(m_nsp);
//Cantera::LiquidTransportData &ltd0 = tr.LTData[0];
std::string spName = m_thermo->speciesName(0);
/*
LiquidTR_Model vm0 = ltd0.model_viscosity;
std::string spName0 = m_thermo->speciesName(0);
if (vm0 == LTR_MODEL_CONSTANT) {
tempDepType_ = 0;
} else if (vm0 == LTR_MODEL_ARRHENIUS) {
tempDepType_ = 1;
} else if (vm0 == LTR_MODEL_NOTSET) {
throw CanteraError("SimpleTransport::initLiquid",
"Viscosity Model is not set for species " + spName0 + " in the input file");
} else {
throw CanteraError("SimpleTransport::initLiquid",
"Viscosity Model for species " + spName0 + " is not handled by this object");
}
*/
for (size_t k = 0; k < m_nsp; k++) {
spName = m_thermo->speciesName(k);
Cantera::LiquidTransportData& ltd = tr.LTData[k];
//LiquidTR_Model vm = ltd.model_viscosity;
//vector_fp &kentry = m_coeffVisc_Ns[k];
/*
if (vm != vm0) {
if (compositionDepType_ != 0) {
throw CanteraError(" SimpleTransport::initLiquid",
"different viscosity models for species " + spName + " and " + spName0 );
} else {
kentry = m_coeffVisc_Ns[0];
}
}
*/
m_coeffVisc_Ns[k] = ltd.viscosity;
ltd.viscosity = 0;
}
/*
* Get the input thermal conductivities
*/
m_condSpecies.resize(m_nsp);
m_coeffLambda_Ns.clear();
m_coeffLambda_Ns.resize(m_nsp);
//LiquidTR_Model cm0 = ltd0.model_thermalCond;
//if (cm0 != vm0) {
// throw CanteraError("SimpleTransport::initLiquid",
// "Conductivity model is not the same as the viscosity model for species " + spName0);
// }
for (size_t k = 0; k < m_nsp; k++) {
spName = m_thermo->speciesName(k);
Cantera::LiquidTransportData& ltd = tr.LTData[k];
//LiquidTR_Model cm = ltd.model_thermalCond;
//vector_fp &kentry = m_coeffLambda_Ns[k];
/*
if (cm != cm0) {
if (compositionDepType_ != 0) {
throw CanteraError(" SimpleTransport::initLiquid",
"different thermal conductivity models for species " + spName + " and " + spName0);
} else {
kentry = m_coeffLambda_Ns[0];
}
}
*/
m_coeffLambda_Ns[k] = ltd.thermalCond;
ltd.thermalCond = 0;
}
/*
* Get the input species diffusivities
*/
useHydroRadius_ = false;
m_diffSpecies.resize(m_nsp);
m_coeffDiff_Ns.clear();
m_coeffDiff_Ns.resize(m_nsp);
//LiquidTR_Model dm0 = ltd0.model_speciesDiffusivity;
/*
if (dm0 != vm0) {
if (dm0 == LTR_MODEL_NOTSET) {
LiquidTR_Model rm0 = ltd0.model_hydroradius;
if (rm0 != vm0) {
throw CanteraError("SimpleTransport::initLiquid",
"hydroradius model is not the same as the viscosity model for species " + spName0);
} else {
useHydroRadius_ = true;
}
}
}
*/
for (size_t k = 0; k < m_nsp; k++) {
spName = m_thermo->speciesName(k);
Cantera::LiquidTransportData& ltd = tr.LTData[k];
/*
LiquidTR_Model dm = ltd.model_speciesDiffusivity;
if (dm == LTR_MODEL_NOTSET) {
LiquidTR_Model rm = ltd.model_hydroradius;
if (rm == LTR_MODEL_NOTSET) {
throw CanteraError("SimpleTransport::initLiquid",
"Neither diffusivity nor hydroradius is set for species " + spName);
}
if (rm != vm0) {
throw CanteraError("SimpleTransport::initLiquid",
"hydroradius model is not the same as the viscosity model for species " + spName);
}
if (rm != LTR_MODEL_CONSTANT) {
throw CanteraError("SimpleTransport::initLiquid",
"hydroradius model is not constant for species " + spName0);
}
vector_fp &kentry = m_coeffHydroRadius_Ns[k];
kentry = ltd.hydroradius;
} else {
if (dm != dm0) {
throw CanteraError(" SimpleTransport::initLiquid",
"different diffusivity models for species " + spName + " and " + spName0 );
}
vector_fp &kentry = m_coeffDiff_Ns[k];
kentry = ltd.speciesDiffusivity;
}
*/
m_coeffDiff_Ns[k] = ltd.speciesDiffusivity;
ltd.speciesDiffusivity = 0;
if (!(m_coeffDiff_Ns[k])) {
if (ltd.hydroRadius) {
m_coeffHydroRadius_Ns[k] = (ltd.hydroRadius)->duplMyselfAsLTPspecies();
}
if (!(m_coeffHydroRadius_Ns[k])) {
throw CanteraError("SimpleTransport::initLiquid",
"Neither diffusivity nor hydroradius is set for species " + spName);
}
}
}
m_molefracs.resize(m_nsp);
m_concentrations.resize(m_nsp);
m_chargeSpecies.resize(m_nsp);
for (size_t k = 0; k < m_nsp; k++) {
m_chargeSpecies[k] = m_thermo->charge(k);
}
m_spwork.resize(m_nsp);
// resize the internal gradient variables
m_Grad_X.resize(m_nDim * m_nsp, 0.0);
m_Grad_T.resize(m_nDim, 0.0);
m_Grad_P.resize(m_nDim, 0.0);
m_Grad_V.resize(m_nDim, 0.0);
// set all flags to false
m_visc_mix_ok = false;
m_visc_temp_ok = false;
m_cond_temp_ok = false;
m_cond_mix_ok = false;
m_diff_temp_ok = false;
m_diff_mix_ok = false;
return true;
}
//================================================================================================
// Returns the mixture viscosity of the solution
/*
* The viscosity is computed using the general mixture rules
* specified in the variable compositionDepType_.
*
* Solvent-only:
* \f[
* \mu = \mu_0
* \f]
* Mixture-average:
* \f[
* \mu = \sum_k {\mu_k X_k}
* \f]
*
* Here \f$ \mu_k \f$ is the viscosity of pure species \e k.
*
* @see updateViscosity_T();
*/
doublereal SimpleTransport::viscosity()
{
update_T();
update_C();
if (m_visc_mix_ok) {
return m_viscmix;
}
// update m_viscSpecies[] if necessary
if (!m_visc_temp_ok) {
updateViscosity_T();
}
if (compositionDepType_ == 0) {
m_viscmix = m_viscSpecies[0];
} else if (compositionDepType_ == 1) {
m_viscmix = 0.0;
for (size_t k = 0; k < m_nsp; k++) {
m_viscmix += m_viscSpecies[k] * m_molefracs[k];
}
}
m_visc_mix_ok = true;
return m_viscmix;
}
//================================================================================================
void SimpleTransport::getSpeciesViscosities(doublereal* const visc)
{
update_T();
if (!m_visc_temp_ok) {
updateViscosity_T();
}
copy(m_viscSpecies.begin(), m_viscSpecies.end(), visc);
}
//================================================================================================
void SimpleTransport::getBinaryDiffCoeffs(size_t ld, doublereal* d)
{
double bdiff;
update_T();
// if necessary, evaluate the species diffusion coefficients
// from the polynomial fits
if (!m_diff_temp_ok) {
updateDiff_T();
}
for (size_t i = 0; i < m_nsp; i++) {
for (size_t j = 0; j < m_nsp; j++) {
bdiff = 0.5 * (m_diffSpecies[i] + m_diffSpecies[j]);
d[i*m_nsp+j] = bdiff;
}
}
}
//================================================================================================
// Get the electrical Mobilities (m^2/V/s).
/*
* This function returns the mobilities. In some formulations
* this is equal to the normal mobility multiplied by faraday's constant.
*
* Frequently, but not always, the mobility is calculated from the
* diffusion coefficient using the Einstein relation
*
* \f[
* \mu^e_k = \frac{F D_k}{R T}
* \f]
*
* @param mobil_e Returns the mobilities of
* the species in array \c mobil_e. The array must be
* dimensioned at least as large as the number of species.
*/
void SimpleTransport::getMobilities(doublereal* const mobil)
{
getMixDiffCoeffs(DATA_PTR(m_spwork));
doublereal c1 = ElectronCharge / (Boltzmann * m_temp);
for (size_t k = 0; k < m_nsp; k++) {
mobil[k] = c1 * m_spwork[k];
}
}
//================================================================================================
// Get the fluid mobilities (s kmol/kg).
/*
* This function returns the fluid mobilities. Usually, you have
* to multiply Faraday's constant into the resulting expression
* to general a species flux expression.
*
* Frequently, but not always, the mobility is calculated from the
* diffusion coefficient using the Einstein relation
*
* \f[
* \mu^f_k = \frac{D_k}{R T}
* \f]
*
*
* @param mobil_f Returns the mobilities of
* the species in array \c mobil. The array must be
* dimensioned at least as large as the number of species.
*/
void SimpleTransport::getFluidMobilities(doublereal* const mobil_f)
{
getMixDiffCoeffs(DATA_PTR(m_spwork));
doublereal c1 = 1.0 / (GasConstant * m_temp);
for (size_t k = 0; k < m_nsp; k++) {
mobil_f[k] = c1 * m_spwork[k];
}
}
//================================================================================================
void SimpleTransport::set_Grad_V(const doublereal* const grad_V)
{
doMigration_ = false;
for (size_t a = 0; a < m_nDim; a++) {
m_Grad_V[a] = grad_V[a];
if (fabs(grad_V[a]) > 1.0E-13) {
doMigration_ = true;
}
}
}
//================================================================================================
void SimpleTransport::set_Grad_T(const doublereal* const grad_T)
{
for (size_t a = 0; a < m_nDim; a++) {
m_Grad_T[a] = grad_T[a];
}
}
//================================================================================================
void SimpleTransport::set_Grad_X(const doublereal* const grad_X)
{
size_t itop = m_nDim * m_nsp;
for (size_t i = 0; i < itop; i++) {
m_Grad_X[i] = grad_X[i];
}
}
//================================================================================================
// Returns the mixture thermal conductivity of the solution
/*
* The thermal is computed using the general mixture rules
* specified in the variable compositionDepType_.
*
* Solvent-only:
* \f[
* \lambda = \lambda_0
* \f]
* Mixture-average:
* \f[
* \lambda = \sum_k {\lambda_k X_k}
* \f]
*
* Here \f$ \lambda_k \f$ is the thermal conductivity of pure species \e k.
*
* @see updateCond_T();
*/
doublereal SimpleTransport::thermalConductivity()
{
update_T();
update_C();
if (!m_cond_temp_ok) {
updateCond_T();
}
if (!m_cond_mix_ok) {
if (compositionDepType_ == 0) {
m_lambda = m_condSpecies[0];
} else if (compositionDepType_ == 1) {
m_lambda = 0.0;
for (size_t k = 0; k < m_nsp; k++) {
m_lambda += m_condSpecies[k] * m_molefracs[k];
}
}
m_cond_mix_ok = true;
}
return m_lambda;
}
//================================================================================================
/*
* Thermal diffusion is not considered in this mixture-averaged
* model. To include thermal diffusion, use transport manager
* MultiTransport instead. This methods fills out array dt with
* zeros.
*/
void SimpleTransport::getThermalDiffCoeffs(doublereal* const dt)
{
for (size_t k = 0; k < m_nsp; k++) {
dt[k] = 0.0;
}
}
//====================================================================================================================
//! Get the species diffusive velocities wrt to the averaged velocity,
//! given the gradients in mole fraction and temperature
/*!
* The average velocity can be computed on a mole-weighted
* or mass-weighted basis, or the diffusion velocities may
* be specified as relative to a specific species (i.e. a
* solvent) all according to the velocityBasis input parameter.
*
* Units for the returned velocities are m s-1.
*
* @param ndim Number of dimensions in the flux expressions
* @param grad_T Gradient of the temperature
* (length = ndim)
* @param ldx Leading dimension of the grad_X array
* (usually equal to m_nsp but not always)
* @param grad_X Gradients of the mole fraction
* Flat vector with the m_nsp in the inner loop.
* length = ldx * ndim
* @param ldf Leading dimension of the fluxes array
* (usually equal to m_nsp but not always)
* @param Vdiff Output of the diffusive velocities.
* Flat vector with the m_nsp in the inner loop.
* length = ldx * ndim
*/
void SimpleTransport::getSpeciesVdiff(size_t ndim,
const doublereal* grad_T,
int ldx,
const doublereal* grad_X,
int ldf,
doublereal* Vdiff)
{
set_Grad_T(grad_T);
set_Grad_X(grad_X);
const doublereal* y = m_thermo->massFractions();
const doublereal rho = m_thermo->density();
getSpeciesFluxesExt(m_nsp, DATA_PTR(Vdiff));
for (size_t n = 0; n < m_nDim; n++) {
for (size_t k = 0; k < m_nsp; k++) {
if (y[k] > 1.0E-200) {
Vdiff[n * m_nsp + k] *= 1.0 / (rho * y[k]);
} else {
Vdiff[n * m_nsp + k] = 0.0;
}
}
}
}
//================================================================================================
// Get the species diffusive velocities wrt to the averaged velocity,
// given the gradients in mole fraction, temperature and electrostatic potential.
/*
* The average velocity can be computed on a mole-weighted
* or mass-weighted basis, or the diffusion velocities may
* be specified as relative to a specific species (i.e. a
* solvent) all according to the velocityBasis input parameter.
*
* Units for the returned velocities are m s-1.
*
* @param ndim Number of dimensions in the flux expressions
* @param grad_T Gradient of the temperature
* (length = ndim)
* @param ldx Leading dimension of the grad_X array
* (usually equal to m_nsp but not always)
* @param grad_X Gradients of the mole fraction
* Flat vector with the m_nsp in the inner loop.
* length = ldx * ndim
* @param ldf Leading dimension of the fluxes array
* (usually equal to m_nsp but not always)
* @param grad_Phi Gradients of the electrostatic potential
* (length = ndim)
* @param Vdiff Output of the species diffusion velocities
* Flat vector with the m_nsp in the inner loop.
* length = ldx * ndim
*/
void SimpleTransport::getSpeciesVdiffES(size_t ndim, const doublereal* grad_T,
int ldx, const doublereal* grad_X,
int ldf, const doublereal* grad_Phi,
doublereal* Vdiff)
{
set_Grad_T(grad_T);
set_Grad_X(grad_X);
set_Grad_V(grad_Phi);
const doublereal* y = m_thermo->massFractions();
const doublereal rho = m_thermo->density();
getSpeciesFluxesExt(m_nsp, DATA_PTR(Vdiff));
for (size_t n = 0; n < m_nDim; n++) {
for (size_t k = 0; k < m_nsp; k++) {
if (y[k] > 1.0E-200) {
Vdiff[n * m_nsp + k] *= 1.0 / (rho * y[k]);
} else {
Vdiff[n * m_nsp + k] = 0.0;
}
}
}
}
//================================================================================================
// Get the species diffusive mass fluxes wrt to the specified solution averaged velocity,
// given the gradients in mole fraction and temperature
/*
* units = kg/m2/s
*
* The diffusive mass flux of species \e k is computed from the following
* formula
*
* Usually the specified solution average velocity is the mass averaged velocity.
* This is changed in some subclasses, however.
*
* \f[
* j_k = - \rho M_k D_k \nabla X_k - Y_k V_c
* \f]
*
* where V_c is the correction velocity
*
* \f[
* V_c = - \sum_j {\rho M_j D_j \nabla X_j}
* \f]
*
*
* @param ndim The number of spatial dimensions (1, 2, or 3).
* @param grad_T The temperature gradient (ignored in this model).
* @param ldx Leading dimension of the grad_X array.
* @param grad_X Gradient of the mole fractions(length nsp * num dimensions);
* @param ldf Leading dimension of the fluxes array.
* @param fluxes Output fluxes of species.
*/
void SimpleTransport::getSpeciesFluxes(size_t ndim, const doublereal* const grad_T,
size_t ldx, const doublereal* const grad_X,
size_t ldf, doublereal* const fluxes)
{
set_Grad_T(grad_T);
set_Grad_X(grad_X);
getSpeciesFluxesExt(ldf, fluxes);
}
//================================================================================================
// Return the species diffusive mass fluxes wrt to
// the mass averaged velocity.
/*
*
* units = kg/m2/s
*
* Internally, gradients in the in mole fraction, temperature
* and electrostatic potential contribute to the diffusive flux
*
*
* The diffusive mass flux of species \e k is computed from the following
* formula
*
* \f[
* j_k = - M_k z_k u^f_k F c_k \nabla \Psi - c M_k D_k \nabla X_k - Y_k V_c
* \f]
*
* where V_c is the correction velocity
*
* \f[
* V_c = - \sum_j {M_k z_k u^f_k F c_k \nabla \Psi + c M_j D_j \nabla X_j}
* \f]
*
* @param ldf stride of the fluxes array. Must be equal to
* or greater than the number of species.
* @param fluxes Vector of calculated fluxes
*/
void SimpleTransport::getSpeciesFluxesExt(size_t ldf, doublereal* fluxes)
{
AssertThrow(ldf >= m_nsp ,"SimpleTransport::getSpeciesFluxesExt: Stride must be greater than m_nsp");
update_T();
update_C();
getMixDiffCoeffs(DATA_PTR(m_spwork));
const vector_fp& mw = m_thermo->molecularWeights();
const doublereal* y = m_thermo->massFractions();
doublereal concTotal = m_thermo->molarDensity();
// Unroll wrt ndim
if (doMigration_) {
double FRT = ElectronCharge / (Boltzmann * m_temp);
for (size_t n = 0; n < m_nDim; n++) {
rhoVc[n] = 0.0;
for (size_t k = 0; k < m_nsp; k++) {
fluxes[n*ldf + k] = - concTotal * mw[k] * m_spwork[k] *
(m_Grad_X[n*m_nsp + k] + FRT * m_molefracs[k] * m_chargeSpecies[k] * m_Grad_V[n]);
rhoVc[n] += fluxes[n*ldf + k];
}
}
} else {
for (size_t n = 0; n < m_nDim; n++) {
rhoVc[n] = 0.0;
for (size_t k = 0; k < m_nsp; k++) {
fluxes[n*ldf + k] = - concTotal * mw[k] * m_spwork[k] * m_Grad_X[n*m_nsp + k];
rhoVc[n] += fluxes[n*ldf + k];
}
}
}
if (m_velocityBasis == VB_MASSAVG) {
for (size_t n = 0; n < m_nDim; n++) {
rhoVc[n] = 0.0;
for (size_t k = 0; k < m_nsp; k++) {
rhoVc[n] += fluxes[n*ldf + k];
}
}
for (size_t n = 0; n < m_nDim; n++) {
for (size_t k = 0; k < m_nsp; k++) {
fluxes[n*ldf + k] -= y[k] * rhoVc[n];
}
}
} else if (m_velocityBasis == VB_MOLEAVG) {
for (size_t n = 0; n < m_nDim; n++) {
rhoVc[n] = 0.0;
for (size_t k = 0; k < m_nsp; k++) {
rhoVc[n] += fluxes[n*ldf + k] / mw[k];
}
}
for (size_t n = 0; n < m_nDim; n++) {
for (size_t k = 0; k < m_nsp; k++) {
fluxes[n*ldf + k] -= m_molefracs[k] * rhoVc[n] * mw[k];
}
}
} else if (m_velocityBasis >= 0) {
for (size_t n = 0; n < m_nDim; n++) {
rhoVc[n] = - fluxes[n*ldf + m_velocityBasis] / mw[m_velocityBasis];
for (size_t k = 0; k < m_nsp; k++) {
rhoVc[n] += fluxes[n*ldf + k] / mw[k];
}
}
for (size_t n = 0; n < m_nDim; n++) {
for (size_t k = 0; k < m_nsp; k++) {
fluxes[n*ldf + k] -= m_molefracs[k] * rhoVc[n] * mw[k];
}
fluxes[n*ldf + m_velocityBasis] = 0.0;
}
} else {
throw CanteraError("SimpleTransport::getSpeciesFluxesExt()",
"unknown velocity basis");
}
}
//================================================================================================
// Mixture-averaged diffusion coefficients [m^2/s].
/*
* Returns the simple diffusion coefficients input into the model. Nothing fancy here.
*/
void SimpleTransport::getMixDiffCoeffs(doublereal* const d)
{
update_T();
update_C();
// update the binary diffusion coefficients if necessary
if (!m_diff_temp_ok) {
updateDiff_T();
}
for (size_t k = 0; k < m_nsp; k++) {
d[k] = m_diffSpecies[k];
}
}
//================================================================================================
// Handles the effects of changes in the mixture concentration
/*
* This is called for every interface call to check whether
* the concentrations have changed. Concentrations change
* whenever the pressure or the mole fraction has changed.
* If it has changed, the recalculations should be done.
*
* Note this should be a lightweight function since it's
* part of all of the interfaces.
*
* @internal
*/
bool SimpleTransport::update_C()
{
// If the pressure has changed then the concentrations
// have changed.
doublereal pres = m_thermo->pressure();
bool qReturn = true;
if (pres != m_press) {
qReturn = false;
m_press = pres;
}
int iStateNew = m_thermo->stateMFNumber();
if (iStateNew != m_iStateMF) {
qReturn = false;
m_thermo->getMoleFractions(DATA_PTR(m_molefracs));
m_thermo->getConcentrations(DATA_PTR(m_concentrations));
concTot_ = 0.0;
for (size_t k = 0; k < m_nsp; k++) {
m_molefracs[k] = std::max(0.0, m_molefracs[k]);
concTot_ += m_concentrations[k];
}
dens_ = m_thermo->density();
meanMolecularWeight_ = m_thermo->meanMolecularWeight();
}
if (qReturn) {
return false;
}
// Mixture stuff needs to be evaluated
m_visc_mix_ok = false;
m_diff_mix_ok = false;
m_cond_mix_ok = false;
return true;
}
//================================================================================================
/**
* Update the temperature-dependent parts of the mixture-averaged
* thermal conductivity.
*/
void SimpleTransport::updateCond_T()
{
if (compositionDepType_ == 0) {
m_condSpecies[0] = m_coeffLambda_Ns[0]->getSpeciesTransProp();
} else {
for (size_t k = 0; k < m_nsp; k++) {
m_condSpecies[k] = m_coeffLambda_Ns[k]->getSpeciesTransProp();
}
}
m_cond_temp_ok = true;
m_cond_mix_ok = false;
}
//================================================================================================
/**
* Update the species diffusion coefficients.
*/
void SimpleTransport::updateDiff_T()
{
if (useHydroRadius_) {
double visc = viscosity();
double RT = GasConstant * m_temp;
for (size_t k = 0; k < m_nsp; k++) {
double rad = m_coeffHydroRadius_Ns[k]->getSpeciesTransProp() ;
m_diffSpecies[k] = RT / (6.0 * Pi * visc * rad);
}
} else {
for (size_t k = 0; k < m_nsp; k++) {
m_diffSpecies[k] = m_coeffDiff_Ns[k]->getSpeciesTransProp();
}
}
m_diff_temp_ok = true;
m_diff_mix_ok = false;
}
//================================================================================================
/**
* Update the pure-species viscosities.
*/
void SimpleTransport::updateViscosities_C()
{
}
//================================================================================================
/**
* Update the temperature-dependent viscosity terms.
* Updates the array of pure species viscosities, and the
* weighting functions in the viscosity mixture rule.
* The flag m_visc_ok is set to true.
*/
void SimpleTransport::updateViscosity_T()
{
if (compositionDepType_ == 0) {
m_viscSpecies[0] = m_coeffVisc_Ns[0]->getSpeciesTransProp();
} else {
for (size_t k = 0; k < m_nsp; k++) {
m_viscSpecies[k] = m_coeffVisc_Ns[k]->getSpeciesTransProp();
}
}
m_visc_temp_ok = true;
m_visc_mix_ok = false;
}
//=================================================================================================
bool SimpleTransport::update_T()
{
doublereal t = m_thermo->temperature();
if (t == m_temp) {
return false;
}
if (t < 0.0) {
throw CanteraError("SimpleTransport::update_T",
"negative temperature "+fp2str(t));
}
// Compute various functions of temperature
m_temp = t;
// temperature has changed, so polynomial temperature
// interpolations will need to be reevaluated.
// Set all of these flags to false
m_visc_mix_ok = false;
m_visc_temp_ok = false;
m_cond_temp_ok = false;
m_cond_mix_ok = false;
m_diff_mix_ok = false;
m_diff_temp_ok = false;
return true;
}
//================================================================================================
/*
* Throw an exception if this method is invoked.
* This probably indicates something is not yet implemented.
*/
doublereal SimpleTransport::err(const std::string& msg) const
{
throw CanteraError("SimpleTransport Class",
"\n\n\n**** Method "+ msg +" not implemented in model "
+ int2str(model()) + " ****\n"
"(Did you forget to specify a transport model?)\n\n\n");
return 0.0;
}
//===================================================================================================================
}
//======================================================================================================================