[Transport] Add class IonGasTransport

This commit is contained in:
BangShiuh 2018-04-26 10:49:09 -04:00 committed by Ray Speth
parent b7e32e4604
commit 3a0f46eb56
8 changed files with 654 additions and 51 deletions

View file

@ -2,21 +2,163 @@ units(length='cm', time='s', quantity='mol', act_energy='cal/mol')
ideal_gas(name='gas', ideal_gas(name='gas',
elements=' O H C N Ar E', elements=' O H C N Ar E',
species=['''gri30: H2 H O O2 OH H2O HO2 H2O2 C CH species=['H2 O2 H2O CH4 CO CO2 N2',
CH2 CH2(S) CH3 CH4 CO CO2 HCO CH2O CH2OH CH3O '''gri30: H O OH HO2 H2O2 C CH
CH3OH C2H C2H2 C2H3 C2H4 C2H5 C2H6 HCCO CH2CO HCCOH CH2 CH2(S) CH3 HCO CH2O CH2OH CH3O
N NH NH2 NH3 NNH NO NO2 N2O HNO CN CH3OH C2H C2H2 C2H3 C2H4 C2H5 C2H6 HCCO CH2CO HCCOH
HCN H2CN HCNN HCNO HOCN HNCO NCO N2 AR C3H7 N NH NH2 NH3 NNH NO NO2 N2O HNO CN
HCN H2CN HCNN HCNO HOCN HNCO NCO AR C3H7
C3H8 CH2CHO CH3CHO''', C3H8 CH2CHO CH3CHO''',
'HCO+ H3O+ E'], 'HCO+ H3O+ E'],
reactions=['gri30: all', 'all'], reactions=['gri30: all', 'all'],
transport='Mix', transport='Ion',
options=['skip_undeclared_species', 'skip_undeclared_third_bodies'], options=['skip_undeclared_species', 'skip_undeclared_third_bodies'],
initial_state=state(temperature=300.0, pressure=OneAtm)) initial_state=state(temperature=300.0, pressure=OneAtm))
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# Species data # Species data
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# The values of polarizability of H2, O2, H2O, CH4, CO, CO2, and N2 are from
# the supplementary material of Han, Jie, et al. "Numerical modelling of ion
# transport in flames." Combustion Theory and Modelling 19.6 (2015): 744-772.
# DOI: 10.1080/13647830.2015.1090018
species(name = "H2",
atoms = " H:2 ",
thermo = (
NASA( [ 200.00, 1000.00], [ 2.344331120E+00, 7.980520750E-03,
-1.947815100E-05, 2.015720940E-08, -7.376117610E-12,
-9.179351730E+02, 6.830102380E-01] ),
NASA( [ 1000.00, 3500.00], [ 3.337279200E+00, -4.940247310E-05,
4.994567780E-07, -1.795663940E-10, 2.002553760E-14,
-9.501589220E+02, -3.205023310E+00] )
),
transport = gas_transport(
geom = "linear",
diam = 2.92,
well_depth = 38.00,
polar = 0.455,
rot_relax = 280.00),
note = '''The value of polarizability is from the supplementary
material of Han, Jie, et al. "Numerical modelling of ion
transport in flames." Combustion Theory and Modelling
19.6 (2015): 744-772. DOI: 10.1080/13647830.2015.1090018'''
)
species(name = "O2",
atoms = " O:2 ",
thermo = (
NASA( [ 200.00, 1000.00], [ 3.782456360E+00, -2.996734160E-03,
9.847302010E-06, -9.681295090E-09, 3.243728370E-12,
-1.063943560E+03, 3.657675730E+00] ),
NASA( [ 1000.00, 3500.00], [ 3.282537840E+00, 1.483087540E-03,
-7.579666690E-07, 2.094705550E-10, -2.167177940E-14,
-1.088457720E+03, 5.453231290E+00] )
),
transport = gas_transport(
geom = "linear",
diam = 3.46,
well_depth = 107.40,
polar = 1.131,
rot_relax = 3.80),
note = "TPIS89"
)
species(name = "H2O",
atoms = " H:2 O:1 ",
thermo = (
NASA( [ 200.00, 1000.00], [ 4.198640560E+00, -2.036434100E-03,
6.520402110E-06, -5.487970620E-09, 1.771978170E-12,
-3.029372670E+04, -8.490322080E-01] ),
NASA( [ 1000.00, 3500.00], [ 3.033992490E+00, 2.176918040E-03,
-1.640725180E-07, -9.704198700E-11, 1.682009920E-14,
-3.000429710E+04, 4.966770100E+00] )
),
transport = gas_transport(
geom = "nonlinear",
diam = 2.60,
well_depth = 572.40,
dipole = 1.84,
polar = 1.053,
rot_relax = 4.00),
note = "L 8/89"
)
species(name = "CH4",
atoms = " C:1 H:4 ",
thermo = (
NASA( [ 200.00, 1000.00], [ 5.149876130E+00, -1.367097880E-02,
4.918005990E-05, -4.847430260E-08, 1.666939560E-11,
-1.024664760E+04, -4.641303760E+00] ),
NASA( [ 1000.00, 3500.00], [ 7.485149500E-02, 1.339094670E-02,
-5.732858090E-06, 1.222925350E-09, -1.018152300E-13,
-9.468344590E+03, 1.843731800E+01] )
),
transport = gas_transport(
geom = "nonlinear",
diam = 3.75,
well_depth = 141.40,
polar = 2.60,
rot_relax = 13.00),
note = "L 8/88"
)
species(name = "CO",
atoms = " C:1 O:1 ",
thermo = (
NASA( [ 200.00, 1000.00], [ 3.579533470E+00, -6.103536800E-04,
1.016814330E-06, 9.070058840E-10, -9.044244990E-13,
-1.434408600E+04, 3.508409280E+00] ),
NASA( [ 1000.00, 3500.00], [ 2.715185610E+00, 2.062527430E-03,
-9.988257710E-07, 2.300530080E-10, -2.036477160E-14,
-1.415187240E+04, 7.818687720E+00] )
),
transport = gas_transport(
geom = "linear",
diam = 3.65,
well_depth = 98.10,
polar = 1.95,
rot_relax = 1.80),
note = "TPIS79"
)
species(name = "CO2",
atoms = " C:1 O:2 ",
thermo = (
NASA( [ 200.00, 1000.00], [ 2.356773520E+00, 8.984596770E-03,
-7.123562690E-06, 2.459190220E-09, -1.436995480E-13,
-4.837196970E+04, 9.901052220E+00] ),
NASA( [ 1000.00, 3500.00], [ 3.857460290E+00, 4.414370260E-03,
-2.214814040E-06, 5.234901880E-10, -4.720841640E-14,
-4.875916600E+04, 2.271638060E+00] )
),
transport = gas_transport(
geom = "linear",
diam = 3.76,
well_depth = 244.00,
polar = 2.65,
rot_relax = 2.10),
note = "L 7/88"
)
species(name = "N2",
atoms = " N:2 ",
thermo = (
NASA( [ 300.00, 1000.00], [ 3.298677000E+00, 1.408240400E-03,
-3.963222000E-06, 5.641515000E-09, -2.444854000E-12,
-1.020899900E+03, 3.950372000E+00] ),
NASA( [ 1000.00, 5000.00], [ 2.926640000E+00, 1.487976800E-03,
-5.684760000E-07, 1.009703800E-10, -6.753351000E-15,
-9.227977000E+02, 5.980528000E+00] )
),
transport = gas_transport(
geom = "linear",
diam = 3.62,
well_depth = 97.53,
polar = 1.76,
rot_relax = 4.00),
note = "121286"
)
species(name = 'HCO+', species(name = 'HCO+',
atoms = ' H:1 C:1 O:1 E:-1 ', atoms = ' H:1 C:1 O:1 E:-1 ',
@ -31,9 +173,11 @@ species(name = 'HCO+',
transport=gas_transport(geom='linear', transport=gas_transport(geom='linear',
diam=3.59, diam=3.59,
well_depth=498.0, well_depth=498.0,
polar=2.5, polar=1.356),
rot_relax=0.0), note = '''The polarizability is from Han, Jie, et al.
note = 'J12/70') "Numerical modelling of ion transport in flames."
,and the rest of the parameters are from its neutral
counterpart HCO''')
species(name = 'H3O+', species(name = 'H3O+',
atoms = ' H:3 O:1 E:-1 ', atoms = ' H:3 O:1 E:-1 ',
@ -46,12 +190,12 @@ species(name = 'H3O+',
7.097291130E+04, 7.458507790E+00] ) 7.097291130E+04, 7.458507790E+00] )
), ),
transport=gas_transport(geom='nonlinear', transport=gas_transport(geom='nonlinear',
diam=2.605, diam=3.15,
well_depth=572.4, well_depth=106.2,
dipole=1.844, dipole=1.417,
polar=1.5, polar=0.897),
rot_relax=2.1), note = '''The transport parameters are from Han, Jie, et al.
note = 'TPIS89') "Numerical modelling of ion transport in flames."''')
species(name = 'E', species(name = 'E',
atoms = ' E:1 ', atoms = ' E:1 ',
@ -66,9 +210,8 @@ species(name = 'E',
transport=gas_transport(geom='atom', transport=gas_transport(geom='atom',
diam=2.05, diam=2.05,
well_depth=145.0, well_depth=145.0,
polar=0.667, polar=0.667),
rot_relax=0.0), note = 'The transport parameters are not used in IonGasTransport')
note = 'gas L10/92')
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# Reaction data # Reaction data

View file

@ -144,12 +144,13 @@ protected:
//! @name Initialization //! @name Initialization
//! @{ //! @{
//! Prepare to build a new kinetic-theory-based transport manager for //! Setup parameters for a new kinetic-theory-based transport manager for
//! low-density gases //! low-density gases
/*! virtual void setupCollisionParameters();
* Uses polynomial fits to Monchick & Mason collision integrals.
*/ //! Setup range for polynomial fits to collision integrals of
void setupMM(); //! Monchick & Mason
void setupCollisionIntegral();
//! Read the transport database //! Read the transport database
/*! /*!
@ -180,29 +181,35 @@ protected:
*/ */
void fitCollisionIntegrals(MMCollisionInt& integrals); void fitCollisionIntegrals(MMCollisionInt& integrals);
//! Generate polynomial fits to the viscosity, conductivity, and //! Generate polynomial fits to the viscosity and conductivity
//! the binary diffusion coefficients
/*! /*!
* If CK_mode, then the fits are of the form * If CK_mode, then the fits are of the form
* \f[ * \f[
* \log(\eta(i)) = \sum_{n = 0}^3 a_n(i) (\log T)^n * \log(\eta(i)) = \sum_{n = 0}^3 a_n(i) (\log T)^n
* \f] * \f]
* and
* \f[
* \log(D(i,j)) = \sum_{n = 0}^3 a_n(i,j) (\log T)^n
* \f]
* Otherwise the fits are of the form * Otherwise the fits are of the form
* \f[ * \f[
* \eta(i)/sqrt(k_BT) = \sum_{n = 0}^4 a_n(i) (\log T)^n * \eta(i)/sqrt(k_BT) = \sum_{n = 0}^4 a_n(i) (\log T)^n
* \f] * \f]
* and *
* @param integrals interpolator for the collision integrals
*/
virtual void fitProperties(MMCollisionInt& integrals);
//! Generate polynomial fits to the binary diffusion coefficients
/*!
* If CK_mode, then the fits are of the form
* \f[
* \log(D(i,j)) = \sum_{n = 0}^3 a_n(i,j) (\log T)^n
* \f]
* Otherwise the fits are of the form
* \f[ * \f[
* D(i,j)/sqrt(k_BT)) = \sum_{n = 0}^4 a_n(i,j) (\log T)^n * D(i,j)/sqrt(k_BT)) = \sum_{n = 0}^4 a_n(i,j) (\log T)^n
* \f] * \f]
* *
* @param integrals interpolator for the collision integrals * @param integrals interpolator for the collision integrals
*/ */
void fitProperties(MMCollisionInt& integrals); virtual void fitDiffCoeffs(MMCollisionInt& integrals);
//! Second-order correction to the binary diffusion coefficients //! Second-order correction to the binary diffusion coefficients
/*! /*!

View file

@ -0,0 +1,95 @@
/**
* @file IonGasTransport.h
*/
// This file is part of Cantera. See License.txt in the top-level directory or
// at http://www.cantera.org/license.txt for license and copyright information.
#ifndef CT_ION_GAS_TRANSPORT_H
#define CT_ION_GAS_TRANSPORT_H
#include "MixTransport.h"
namespace Cantera
{
//! Class IonGasTransport implements Stockmayer-(n,6,4) model for transport of ions.
/*!
* As implemented here, only binary transport between netrals and ions is considered
* for calculating mixture-average diffusion coefficients and mobilities. When
* polarizability is not provide for an ion, LJ model is used instead of n64 model.
* Only neutral species are considered for thermal conductivity and viscousity.
*
* References for Stockmayer-(n,6,4) model:
*
* 1. Selle, Stefan, and Uwe Riedel. "Transport properties of ionized species."
* Annals of the New York Academy of Sciences 891.1 (1999): 72-80.
* 2. Selle, Stefan, and Uwe Riedel. "Transport coefficients of reacting air at
* high temperatures." 38th Aerospace Sciences Meeting and Exhibit. 1999.
* 3. Han, Jie, et al. "Numerical modelling of ion transport in flames."
* Combustion Theory and Modelling 19.6 (2015): 744-772.
* DOI: 10.1080/13647830.2015.1090018
* 4. Chiflikian, R. V. "The analog of Blancs law for drift velocities
* of electrons in gas mixtures in weakly ionized plasma."
* Physics of Plasmas 2.10 (1995): 3902-3909.
* 5. Viehland, L. A., et al. "Tables of transport collision integrals for
* (n, 6, 4) ion-neutral potentials." Atomic Data and Nuclear Data Tables
* 16.6 (1975): 495-514.
* @ingroup tranprops
*/
class IonGasTransport : public MixTransport
{
public:
IonGasTransport();
virtual std::string transportType() const {
return "Ion";
}
virtual void init(thermo_t* thermo, int mode, int log_level);
//! Viscosity of the mixture (kg/m/s).
//! Only Neutral species contribute to Viscosity.
virtual double viscosity();
//! Returns the mixture thermal conductivity (W/m/K).
//! Only Neutral species contribute to therrmal conductivity.
virtual double thermalConductivity();
protected:
//! setup parameters for n64 model
void setupN64();
//! Generate polynomial fits to the binary diffusion coefficients.
//! Use Stockmayer-(n,6,4) model for collision between charged and neutral species.
virtual void fitDiffCoeffs(MMCollisionInt& integrals);
/*!
* Collision integral of omega11 of n64 collision model.
* The collision integral was fitted by Han et al. using the table
* by Viehlan et al.
* Note: Han release the range to 1000, but Selle suggested that
* a high temperature model is needed for T* > 10.
*/
double omega11_n64(const double tstar, const double gamma);
virtual void getMixDiffCoeffs(doublereal* const d);
//! electrical properties
vector_int m_speciesCharge;
//! index of ions (exclude electron.)
std::vector<size_t> m_kIon;
//! index of neutral species
std::vector<size_t> m_kNeutral;
//! index of electron
size_t m_kElectron;
//! parameter of omega11 of n64
DenseMatrix m_gamma;
};
}
#endif

View file

@ -151,7 +151,7 @@ public:
virtual void init(thermo_t* thermo, int mode=0, int log_level=0); virtual void init(thermo_t* thermo, int mode=0, int log_level=0);
private: protected:
//! Calculate the pressure from the ideal gas law //! Calculate the pressure from the ideal gas law
doublereal pressure_ig() const { doublereal pressure_ig() const {
return (m_thermo->molarDensity() * GasConstant * return (m_thermo->molarDensity() * GasConstant *

View file

@ -277,8 +277,10 @@ void GasTransport::init(thermo_t* thermo, int mode, int log_level)
m_nsp = m_thermo->nSpecies(); m_nsp = m_thermo->nSpecies();
m_mode = mode; m_mode = mode;
m_log_level = log_level; m_log_level = log_level;
// set up Monchick and Mason collision integrals // set up Monchick and Mason collision integrals
setupMM(); setupCollisionParameters();
setupCollisionIntegral();
m_molefracs.resize(m_nsp); m_molefracs.resize(m_nsp);
m_spwork.resize(m_nsp); m_spwork.resize(m_nsp);
@ -299,15 +301,9 @@ void GasTransport::init(thermo_t* thermo, int mode, int log_level)
m_wratkj1(j,k) = sqrt(1.0 + m_mw[k]/m_mw[j]); m_wratkj1(j,k) = sqrt(1.0 + m_mw[k]/m_mw[j]);
} }
} }
// set flags all false
m_visc_ok = false;
m_viscwt_ok = false;
m_spvisc_ok = false;
m_bindiff_ok = false;
} }
void GasTransport::setupMM() void GasTransport::setupCollisionParameters()
{ {
m_epsilon.resize(m_nsp, m_nsp, 0.0); m_epsilon.resize(m_nsp, m_nsp, 0.0);
m_delta.resize(m_nsp, m_nsp, 0.0); m_delta.resize(m_nsp, m_nsp, 0.0);
@ -332,7 +328,6 @@ void GasTransport::setupMM()
m_poly[i].resize(m_nsp); m_poly[i].resize(m_nsp);
} }
double tstar_min = 1.e8, tstar_max = 0.0;
double f_eps, f_sigma; double f_eps, f_sigma;
for (size_t i = 0; i < m_nsp; i++) { for (size_t i = 0; i < m_nsp; i++) {
@ -346,11 +341,6 @@ void GasTransport::setupMM()
// the effective well depth for (i,j) collisions // the effective well depth for (i,j) collisions
m_epsilon(i,j) = sqrt(m_eps[i]*m_eps[j]); m_epsilon(i,j) = sqrt(m_eps[i]*m_eps[j]);
// The polynomial fits of collision integrals vs. T*
// will be done for the T* from tstar_min to tstar_max
tstar_min = std::min(tstar_min, Boltzmann * m_thermo->minTemp()/m_epsilon(i,j));
tstar_max = std::max(tstar_max, Boltzmann * m_thermo->maxTemp()/m_epsilon(i,j));
// the effective dipole moment for (i,j) collisions // the effective dipole moment for (i,j) collisions
m_dipole(i,j) = sqrt(m_dipole(i,i)*m_dipole(j,j)); m_dipole(i,j) = sqrt(m_dipole(i,i)*m_dipole(j,j));
@ -370,7 +360,19 @@ void GasTransport::setupMM()
m_delta(j,i) = m_delta(i,j); m_delta(j,i) = m_delta(i,j);
} }
} }
}
void GasTransport::setupCollisionIntegral()
{
double tstar_min = 1.e8, tstar_max = 0.0;
for (size_t i = 0; i < m_nsp; i++) {
for (size_t j = i; j < m_nsp; j++) {
// The polynomial fits of collision integrals vs. T*
// will be done for the T* from tstar_min to tstar_max
tstar_min = std::min(tstar_min, Boltzmann * m_thermo->minTemp()/m_epsilon(i,j));
tstar_max = std::max(tstar_max, Boltzmann * m_thermo->maxTemp()/m_epsilon(i,j));
}
}
// Chemkin fits the entire T* range in the Monchick and Mason tables, // Chemkin fits the entire T* range in the Monchick and Mason tables,
// so modify tstar_min and tstar_max if in Chemkin compatibility mode // so modify tstar_min and tstar_max if in Chemkin compatibility mode
if (m_mode == CK_Mode) { if (m_mode == CK_Mode) {
@ -662,7 +664,29 @@ void GasTransport::fitProperties(MMCollisionInt& integrals)
} }
} }
mxerr = 0.0, mxrelerr = 0.0; fitDiffCoeffs(integrals);
}
void GasTransport::fitDiffCoeffs(MMCollisionInt& integrals)
{
// number of points to use in generating fit data
const size_t np = 50;
int degree = (m_mode == CK_Mode ? 3 : 4);
double dt = (m_thermo->maxTemp() - m_thermo->minTemp())/(np-1);
vector_fp tlog(np);
vector_fp w(np), w2(np);
// generate array of log(t) values
for (size_t n = 0; n < np; n++) {
double t = m_thermo->minTemp() + dt*n;
tlog[n] = log(t);
}
// vector of polynomial coefficients
vector_fp c(degree + 1), c2(degree + 1);
double err, relerr,
mxerr = 0.0, mxrelerr = 0.0;
vector_fp diff(np + 1); vector_fp diff(np + 1);
m_diffcoeffs.clear(); m_diffcoeffs.clear();
for (size_t k = 0; k < m_nsp; k++) { for (size_t k = 0; k < m_nsp; k++) {

View file

@ -0,0 +1,336 @@
//! @file IonGasTransport.cpp
// This file is part of Cantera. See License.txt in the top-level directory or
// at http://www.cantera.org/license.txt for license and copyright information.
#include "cantera/transport/IonGasTransport.h"
#include "cantera/numerics/polyfit.h"
#include "cantera/base/stringUtils.h"
#include "MMCollisionInt.h"
namespace Cantera
{
IonGasTransport::IonGasTransport() :
m_kElectron(npos)
{
}
void IonGasTransport::init(thermo_t* thermo, int mode, int log_level)
{
m_thermo = thermo;
m_nsp = m_thermo->nSpecies();
m_mode = mode;
if (m_mode == CK_Mode) {
throw CanteraError("IonGasTransport::init(thermo, mode, log_level)",
"mode = CK_Mode, which is an outdated lower-order fit.");
}
m_log_level = log_level;
// make a local copy of species charge
for (size_t k = 0; k < m_nsp; k++) {
m_speciesCharge.push_back(m_thermo->charge(k));
}
// Find the index of electron
if (m_thermo->speciesIndex("E") != npos ) {
m_kElectron = m_thermo->speciesIndex("E");
}
// Find indices for charge of species
for (size_t k = 0; k < m_nsp; k++) {
if (m_speciesCharge[k] != 0){
if (k != m_kElectron) {
m_kIon.push_back(k);
}
} else {
m_kNeutral.push_back(k);
}
}
// set up Monchick and Mason parameters
setupCollisionParameters();
// set up n64 parameters
setupN64();
// setup collision integrals
setupCollisionIntegral();
m_molefracs.resize(m_nsp);
m_spwork.resize(m_nsp);
m_visc.resize(m_nsp);
m_sqvisc.resize(m_nsp);
m_phi.resize(m_nsp, m_nsp, 0.0);
m_bdiff.resize(m_nsp, m_nsp);
m_cond.resize(m_nsp);
// make a local copy of the molecular weights
m_mw = m_thermo->molecularWeights();
m_wratjk.resize(m_nsp, m_nsp, 0.0);
m_wratkj1.resize(m_nsp, m_nsp, 0.0);
for (size_t j = 0; j < m_nsp; j++) {
for (size_t k = j; k < m_nsp; k++) {
m_wratjk(j,k) = sqrt(m_mw[j]/m_mw[k]);
m_wratjk(k,j) = sqrt(m_wratjk(j,k));
m_wratkj1(j,k) = sqrt(1.0 + m_mw[k]/m_mw[j]);
}
}
}
double IonGasTransport::viscosity()
{
update_T();
update_C();
if (m_visc_ok) {
return m_viscmix;
}
double vismix = 0.0;
// update m_visc and m_phi if necessary
if (!m_viscwt_ok) {
updateViscosity_T();
}
multiply(m_phi, m_molefracs.data(), m_spwork.data());
for (size_t k : m_kNeutral) {
vismix += m_molefracs[k] * m_visc[k]/m_spwork[k]; //denom;
}
m_viscmix = vismix;
return vismix;
}
double IonGasTransport::thermalConductivity()
{
update_T();
update_C();
if (!m_spcond_ok) {
updateCond_T();
}
if (!m_condmix_ok) {
doublereal sum1 = 0.0, sum2 = 0.0;
for (size_t k : m_kNeutral) {
sum1 += m_molefracs[k] * m_cond[k];
sum2 += m_molefracs[k] / m_cond[k];
}
m_lambda = 0.5*(sum1 + 1.0/sum2);
m_condmix_ok = true;
}
return m_lambda;
}
void IonGasTransport::fitDiffCoeffs(MMCollisionInt& integrals)
{
GasTransport::fitDiffCoeffs(integrals);
// number of points to use in generating fit data
const size_t np = 50;
int degree = 4;
double dt = (m_thermo->maxTemp() - m_thermo->minTemp())/(np-1);
vector_fp tlog(np);
vector_fp w(np);
// generate array of log(t) values
for (size_t n = 0; n < np; n++) {
double t = m_thermo->minTemp() + dt*n;
tlog[n] = log(t);
}
// vector of polynomial coefficients
vector_fp c(degree + 1);
double err = 0.0, relerr = 0.0,
mxerr = 0.0, mxrelerr = 0.0;
vector_fp diff(np + 1);
// The array order still not ideal
for (size_t k = 0; k < m_nsp; k++) {
for (size_t j = k; j < m_nsp; j++) {
if (m_alpha[k] == 0.0 || m_alpha[j] == 0.0 ||
k == m_kElectron || j == m_kElectron) {
continue;
}
if (m_speciesCharge[k] == 0) {
if (m_speciesCharge[j] == 0) {
continue;
}
} else {
if (m_speciesCharge[j] != 0) {
continue;
}
}
for (size_t n = 0; n < np; n++) {
double t = m_thermo->minTemp() + dt*n;
double eps = m_epsilon(j,k);
double tstar = Boltzmann * t/eps;
double sigma = m_diam(j,k);
double om11 = omega11_n64(tstar, m_gamma(j,k));
double diffcoeff = 3.0/16.0 * sqrt(2.0 * Pi/m_reducedMass(k,j))
* pow(Boltzmann * t, 1.5) / (Pi * sigma * sigma * om11);
diff[n] = diffcoeff/pow(t, 1.5);
w[n] = 1.0/(diff[n]*diff[n]);
}
polyfit(np, degree, tlog.data(), diff.data(), w.data(), c.data());
for (size_t n = 0; n < np; n++) {
double val, fit;
double t = exp(tlog[n]);
double pre = pow(t, 1.5);
val = pre * diff[n];
fit = pre * poly4(tlog[n], c.data());
err = fit - val;
relerr = err/val;
mxerr = std::max(mxerr, fabs(err));
mxrelerr = std::max(mxrelerr, fabs(relerr));
}
size_t sum = k * (k + 1) / 2;
m_diffcoeffs[k*m_nsp+j-sum] = c;
if (m_log_level >= 2) {
writelog(m_thermo->speciesName(k) + "__" +
m_thermo->speciesName(j) + ": [" + vec2str(c) + "]\n");
}
}
}
if (m_log_level) {
writelogf("Maximum binary diffusion coefficient absolute error:"
" %12.6g\n", mxerr);
writelogf("Maximum binary diffusion coefficient relative error:"
"%12.6g", mxrelerr);
}
}
void IonGasTransport::setupN64()
{
m_gamma.resize(m_nsp, m_nsp, 0.0);
for (size_t i : m_kIon) {
for (size_t j : m_kNeutral) {
if (m_alpha[j] != 0.0 && m_alpha[i] != 0.0) {
double r_alpha = m_alpha[i] / m_alpha[j];
// save a copy of polarizability in Angstrom
double alphaA_i = m_alpha[i] * 1e30;
double alphaA_j = m_alpha[j] * 1e30;
// The ratio of dispersion to induction forces
double xi = alphaA_i / (m_speciesCharge[i] * m_speciesCharge[i] *
(1.0 + pow(2 * r_alpha, 2./3.)) * sqrt(alphaA_j));
// the collision diameter
double K1 = 1.767;
double kappa = 0.095;
m_diam(i,j) = K1 * (pow(m_alpha[i], 1./3.) + pow(m_alpha[j], 1./3.)) /
pow(alphaA_i * alphaA_j * (1.0 + 1.0 / xi), kappa);
// The original K2 is 0.72, but Han et al. suggested that K2 = 1.44
// for better fit.
double K2 = 1.44;
double epsilon = K2 * ElectronCharge * ElectronCharge *
m_speciesCharge[i] * m_speciesCharge[i] *
m_alpha[j] * (1.0 + xi) /
(8 * Pi * epsilon_0 * pow(m_diam(i,j),4));
if (epsilon != 0.0) {
m_epsilon(i,j) = epsilon;
}
// Calculate dipersion coefficient and quadrupole polarizability
// from curve fitting if not available.
// Neutrals
if (m_disp[j] == 0.0) {
m_disp[j] = exp(1.8846*log(alphaA_j)-0.4737)* 1e-50;
}
if (m_quad_polar[j] == 0.0) {
m_quad_polar[j] = 2.0 * m_disp[j];
}
// Ions
if (m_disp[i] == 0.0) {
if (m_speciesCharge[i] > 0) {
m_disp[i] = exp(1.8853*log(alphaA_i)+0.2682)* 1e-50;
} else {
m_disp[i] = exp(3.2246*log(alphaA_i)-3.2397)* 1e-50;
}
}
// The binary dispersion coefficient is determined by the combination rule
// Reference:
// Tang, K. T. "Dynamic polarizabilities and van der Waals coefficients."
// Physical Review 177.1 (1969): 108.
double C6 = 2.0 * m_disp[i] * m_disp[j] /
(1.0/r_alpha * m_disp[i] + r_alpha * m_disp[j]);
m_gamma(i,j) = (2.0 / pow(m_speciesCharge[i],2) * C6 + m_quad_polar[j]) /
(m_alpha[j] * m_diam(i,j) * m_diam(i,j));//Dimensionless
// properties are symmetric
m_diam(j,i) = m_diam(i,j);
m_epsilon(j,i) = m_epsilon(i,j);
m_gamma(j,i) = m_gamma(i,j);
}
}
}
}
double IonGasTransport::omega11_n64(const double tstar, const double gamma)
{
double logtstar = log(tstar);
double om11 = 0.0;
if (tstar < 0.01) {
throw CanteraError("IonGasTransport::omega11_n64(tstar, gamma)",
"tstar = {} is smaller than 0.01", tstar);
} else if (tstar <= 0.04) {
// for interval 0.01 to 0.04, SSE = 0.006; R^2 = 1; RMSE = 0.020
om11 = 2.97 - 12.0 * gamma
- 0.887 * logtstar
+ 3.86 * gamma * gamma
- 6.45 * gamma * logtstar
- 0.275 * logtstar * logtstar
+ 1.20 * gamma * gamma * logtstar
- 1.24 * gamma * logtstar * logtstar
- 0.164 * pow(logtstar,3);
} else if (tstar <= 1000) {
// for interval 0.04 to 1000, SSE = 0.282; R^2 = 1; RMSE = 0.033
om11 = 1.22 - 0.0343 * gamma
+ (-0.769 + 0.232 * gamma) * logtstar
+ (0.306 - 0.165 * gamma) * logtstar * logtstar
+ (-0.0465 + 0.0388 * gamma) * pow(logtstar,3)
+ (0.000614 - 0.00285 * gamma) * pow(logtstar,4)
+ 0.000238 * pow(logtstar,5);
} else {
throw CanteraError("IonGasTransport::omega11_n64(tstar, gamma)",
"tstar = {} is larger than 1000", tstar);
}
return om11;
}
void IonGasTransport::getMixDiffCoeffs(double* const d)
{
update_T();
update_C();
// update the binary diffusion coefficients if necessary
if (!m_bindiff_ok) {
updateDiff_T();
}
double mmw = m_thermo->meanMolecularWeight();
double p = m_thermo->pressure();
if (m_nsp == 1) {
d[0] = m_bdiff(0,0) / p;
} else {
for (size_t k = 0; k < m_nsp; k++) {
if (k == m_kElectron) {
d[k] = 0.4 * m_kbt / ElectronCharge;
} else {
double sum2 = 0.0;
for (size_t j : m_kNeutral) {
if (j != k) {
sum2 += m_molefracs[j] / m_bdiff(j,k);
}
}
if (sum2 <= 0.0) {
d[k] = m_bdiff(k,k) / p;
} else {
d[k] = (mmw - m_molefracs[k] * m_mw[k])/(p * mmw * sum2);
}
}
}
}
}
}

View file

@ -24,10 +24,6 @@ void MixTransport::init(ThermoPhase* thermo, int mode, int log_level)
{ {
GasTransport::init(thermo, mode, log_level); GasTransport::init(thermo, mode, log_level);
m_cond.resize(m_nsp); m_cond.resize(m_nsp);
// set flags all false
m_spcond_ok = false;
m_condmix_ok = false;
} }
void MixTransport::getMobilities(doublereal* const mobil) void MixTransport::getMobilities(doublereal* const mobil)

View file

@ -7,6 +7,7 @@
#include "cantera/transport/MultiTransport.h" #include "cantera/transport/MultiTransport.h"
#include "cantera/transport/MixTransport.h" #include "cantera/transport/MixTransport.h"
#include "cantera/transport/UnityLewisTransport.h" #include "cantera/transport/UnityLewisTransport.h"
#include "cantera/transport/IonGasTransport.h"
#include "cantera/transport/SolidTransport.h" #include "cantera/transport/SolidTransport.h"
#include "cantera/transport/DustyGasTransport.h" #include "cantera/transport/DustyGasTransport.h"
#include "cantera/transport/SimpleTransport.h" #include "cantera/transport/SimpleTransport.h"
@ -50,6 +51,7 @@ TransportFactory::TransportFactory()
reg("UnityLewis", []() { return new UnityLewisTransport(); }); reg("UnityLewis", []() { return new UnityLewisTransport(); });
reg("Mix", []() { return new MixTransport(); }); reg("Mix", []() { return new MixTransport(); });
reg("Multi", []() { return new MultiTransport(); }); reg("Multi", []() { return new MultiTransport(); });
reg("Ion", []() { return new IonGasTransport(); });
m_synonyms["CK_Mix"] = "Mix"; m_synonyms["CK_Mix"] = "Mix";
m_synonyms["CK_Multi"] = "Multi"; m_synonyms["CK_Multi"] = "Multi";
reg("HighP", []() { return new HighPressureGasTransport(); }); reg("HighP", []() { return new HighPressureGasTransport(); });