Cantera  2.2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PecosTransport.cpp
Go to the documentation of this file.
1 /**
2  * @file PecosTransport.cpp
3  * Mixture-averaged transport properties.
4  */
5 
10 
11 #include <sstream>
12 
13 using namespace std;
14 
15 namespace Cantera
16 {
17 
18 PecosTransport::PecosTransport() :
19  m_nsp(0),
20  m_temp(-1.0),
21  m_logt(0.0)
22 {
23  warn_deprecated("class PecosTransport", "To be removed after Cantera 2.2");
24 }
25 
27 {
28  // constant substance attributes
29  m_thermo = tr.thermo;
30  m_nsp = static_cast<int>(m_thermo->nSpecies());
31 
32  // make a local copy of the molecular weights
33  m_mw.resize(m_nsp);
34  copy(m_thermo->molecularWeights().begin(),
35  m_thermo->molecularWeights().end(), m_mw.begin());
36 
37  // copy polynomials and parameters into local storage
38  m_poly = tr.poly;
39  m_visccoeffs = tr.visccoeffs;
40  m_condcoeffs = tr.condcoeffs;
41  m_diffcoeffs = tr.diffcoeffs;
42 
43  m_zrot = tr.zrot;
44  m_crot = tr.crot;
45  m_epsilon = tr.epsilon;
46  m_mode = tr.mode_;
47  m_diam = tr.diam;
48  m_eps = tr.eps;
49  m_alpha = tr.alpha;
50  m_dipoleDiag.resize(m_nsp);
51  for (int i = 0; i < m_nsp; i++) {
52  m_dipoleDiag[i] = tr.dipole(i,i);
53  }
54 
55  m_phi.resize(m_nsp, m_nsp, 0.0);
56  m_wratjk.resize(m_nsp, m_nsp, 0.0);
57  m_wratkj1.resize(m_nsp, m_nsp, 0.0);
58  int j, k;
59  for (j = 0; j < m_nsp; j++)
60  for (k = j; k < m_nsp; k++) {
61  m_wratjk(j,k) = sqrt(m_mw[j]/m_mw[k]);
62  m_wratjk(k,j) = sqrt(m_wratjk(j,k));
63  m_wratkj1(j,k) = sqrt(1.0 + m_mw[k]/m_mw[j]);
64  }
65 
66  m_polytempvec.resize(5);
67  m_visc.resize(m_nsp);
68  m_sqvisc.resize(m_nsp);
69  m_cond.resize(m_nsp);
70  m_bdiff.resize(m_nsp, m_nsp);
71 
72  m_molefracs.resize(m_nsp);
73  m_spwork.resize(m_nsp);
74 
75  // set flags all false
76  m_viscmix_ok = false;
77  m_viscwt_ok = false;
78  m_spvisc_ok = false;
79  m_spcond_ok = false;
80  m_condmix_ok = false;
81  m_spcond_ok = false;
82  m_diffmix_ok = false;
83  m_abc_ok = false;
84 
85  // read blottner fit parameters (A,B,C)
87 
88  // set specific heats
89  cv_rot.resize(m_nsp);
90  cp_R.resize(m_nsp);
91  cv_int.resize(m_nsp);
92 
93  for (k = 0; k < m_nsp; k++) {
94  cv_rot[k] = tr.crot[k];
95  cp_R[k] = ((IdealGasPhase*)tr.thermo)->cp_R_ref()[k];
96  cv_int[k] = cp_R[k] - 2.5 - cv_rot[k];
97  }
98  return true;
99 }
100 
102 {
103  update_T();
104  update_C();
105 
106  if (m_viscmix_ok) {
107  return m_viscmix;
108  }
109 
110  doublereal vismix = 0.0;
111  int k;
112  // update m_visc and m_phi if necessary
113  if (!m_viscwt_ok) {
115  }
116 
117  multiply(m_phi, DATA_PTR(m_molefracs), DATA_PTR(m_spwork));
118 
119  for (k = 0; k < m_nsp; k++) {
120  vismix += m_molefracs[k] * m_visc[k]/m_spwork[k]; //denom;
121  }
122  m_viscmix = vismix;
123  return vismix;
124 }
125 
126 void PecosTransport::getBinaryDiffCoeffs(const size_t ld, doublereal* const d)
127 {
128  int i,j;
129 
130  update_T();
131 
132  // if necessary, evaluate the binary diffusion coefficents
133  if (!m_bindiff_ok) {
134  updateDiff_T();
135  }
136 
137  doublereal rp = 1.0/pressure_ig();
138  for (i = 0; i < m_nsp; i++)
139  for (j = 0; j < m_nsp; j++) {
140  d[ld*j + i] = rp * m_bdiff(i,j);
141  }
142 }
143 
144 void PecosTransport::getMobilities(doublereal* const mobil)
145 {
146  int k;
147  getMixDiffCoeffs(DATA_PTR(m_spwork));
148  doublereal c1 = ElectronCharge / (Boltzmann * m_temp);
149  for (k = 0; k < m_nsp; k++) {
150  mobil[k] = c1 * m_spwork[k] * m_thermo->charge(k);
151  }
152 }
153 
155 {
156  int k;
157  doublereal lambda = 0.0;
158 
159  update_T();
160  update_C();
161 
162  // update m_cond and m_phi if necessary
163  if (!m_spcond_ok) {
164  updateCond_T();
165  }
166  if (!m_condmix_ok) {
167 
168  multiply(m_phi, DATA_PTR(m_molefracs), DATA_PTR(m_spwork));
169 
170  for (k = 0; k < m_nsp; k++) {
171  lambda += m_molefracs[k] * m_cond[k]/m_spwork[k]; //denom;
172  }
173 
174  }
175  m_lambda = lambda;
176  return m_lambda;
177 
178 }
179 
180 void PecosTransport::getThermalDiffCoeffs(doublereal* const dt)
181 {
182  int k;
183  for (k = 0; k < m_nsp; k++) {
184  dt[k] = 0.0;
185  }
186 }
187 
189  const doublereal* const grad_T,
190  size_t ldx, const doublereal* const grad_X,
191  size_t ldf, doublereal* const fluxes)
192 {
193  size_t n = 0;
194  int k;
195 
196  update_T();
197  update_C();
198 
199  getMixDiffCoeffs(DATA_PTR(m_spwork));
200 
201  const vector_fp& mw = m_thermo->molecularWeights();
202  const doublereal* y = m_thermo->massFractions();
203  doublereal rhon = m_thermo->molarDensity();
204 
205  vector_fp sum(ndim,0.0);
206 
207  doublereal correction=0.0;
208  // grab 2nd (summation) term -- still need to multiply by mass fraction (\rho_s / \rho)
209  for (k = 0; k < m_nsp; k++) {
210  correction += rhon * mw[k] * m_spwork[k] * grad_X[n*ldx + k];
211  }
212 
213  for (n = 0; n < ndim; n++) {
214  for (k = 0; k < m_nsp; k++) {
215  fluxes[n*ldf + k] = -rhon * mw[k] * m_spwork[k] * grad_X[n*ldx + k] + y[k]*correction;
216  sum[n] += fluxes[n*ldf + k];
217  }
218  }
219  // add correction flux to enforce sum to zero
220  for (n = 0; n < ndim; n++) {
221  for (k = 0; k < m_nsp; k++) {
222  fluxes[n*ldf + k] -= y[k]*sum[n];
223  }
224  }
225 }
226 
227 void PecosTransport::getMixDiffCoeffs(doublereal* const d)
228 {
229  update_T();
230  update_C();
231 
232  // update the binary diffusion coefficients if necessary
233  if (!m_bindiff_ok) {
234  updateDiff_T();
235  }
236 
237  int k, j;
238  doublereal mmw = m_thermo->meanMolecularWeight();
239  doublereal sumxw = 0.0, sum2;
240  doublereal p = pressure_ig();
241  if (m_nsp == 1) {
242  d[0] = m_bdiff(0,0) / p;
243  } else {
244  for (k = 0; k < m_nsp; k++) {
245  sumxw += m_molefracs[k] * m_mw[k];
246  }
247  for (k = 0; k < m_nsp; k++) {
248  sum2 = 0.0;
249  for (j = 0; j < m_nsp; j++) {
250  if (j != k) {
251  sum2 += m_molefracs[j] / m_bdiff(j,k);
252  }
253  }
254  if (sum2 <= 0.0) {
255  d[k] = m_bdiff(k,k) / p;
256  } else {
257  d[k] = (sumxw - m_molefracs[k] * m_mw[k])/(p * mmw * sum2);
258  }
259  }
260  }
261 }
262 
263 void PecosTransport::getMixDiffCoeffsMole(doublereal* const d)
264 {
265  update_T();
266  update_C();
267 
268  // update the binary diffusion coefficients if necessary
269  if (!m_bindiff_ok) {
270  updateDiff_T();
271  }
272 
273  doublereal p = m_thermo->pressure();
274  if (m_nsp == 1) {
275  d[0] = m_bdiff(0,0) / p;
276  } else {
277  for (int k = 0; k < m_nsp; k++) {
278  double sum2 = 0.0;
279  for (int j = 0; j < m_nsp; j++) {
280  if (j != k) {
281  sum2 += m_molefracs[j] / m_bdiff(j,k);
282  }
283  }
284  if (sum2 <= 0.0) {
285  d[k] = m_bdiff(k,k) / p;
286  } else {
287  d[k] = (1 - m_molefracs[k]) / (p * sum2);
288  }
289  }
290  }
291 }
292 
293 void PecosTransport::getMixDiffCoeffsMass(doublereal* const d)
294 {
295  update_T();
296  update_C();
297 
298  // update the binary diffusion coefficients if necessary
299  if (!m_bindiff_ok) {
300  updateDiff_T();
301  }
302 
303  doublereal mmw = m_thermo->meanMolecularWeight();
304  doublereal p = m_thermo->pressure();
305 
306  if (m_nsp == 1) {
307  d[0] = m_bdiff(0,0) / p;
308  } else {
309  for (int k=0; k<m_nsp; k++) {
310  double sum1 = 0.0;
311  double sum2 = 0.0;
312  for (int i=0; i<m_nsp; i++) {
313  if (i==k) {
314  continue;
315  }
316  sum1 += m_molefracs[i] / m_bdiff(k,i);
317  sum2 += m_molefracs[i] * m_mw[i] / m_bdiff(k,i);
318  }
319  sum1 *= p;
320  sum2 *= p * m_molefracs[k] / (mmw - m_mw[k]*m_molefracs[k]);
321  d[k] = 1.0 / (sum1 + sum2);
322  }
323  }
324 }
325 
326 /**
327  * @internal This is called whenever a transport property is
328  * requested from ThermoSubstance if the temperature has changed
329  * since the last call to update_T.
330  */
332 {
333  doublereal t = m_thermo->temperature();
334  if (t == m_temp) {
335  return;
336  }
337  if (t <= 0.0) {
338  throw CanteraError("PecosTransport::update_T",
339  "negative temperature "+fp2str(t));
340  }
341  m_temp = t;
342  m_logt = log(m_temp);
343  m_kbt = Boltzmann * m_temp;
344  m_sqrt_t = sqrt(m_temp);
345  m_t14 = sqrt(m_sqrt_t);
346  m_t32 = m_temp * m_sqrt_t;
347  m_sqrt_kbt = sqrt(Boltzmann*m_temp);
348 
349  // compute powers of log(T)
350  m_polytempvec[0] = 1.0;
351  m_polytempvec[1] = m_logt;
352  m_polytempvec[2] = m_logt*m_logt;
353  m_polytempvec[3] = m_logt*m_logt*m_logt;
354  m_polytempvec[4] = m_logt*m_logt*m_logt*m_logt;
355 
356  // temperature has changed, so polynomial fits will need to be redone.
357  m_viscmix_ok = false;
358  m_spvisc_ok = false;
359  m_viscwt_ok = false;
360  m_spcond_ok = false;
361  m_diffmix_ok = false;
362  m_bindiff_ok = false;
363  m_abc_ok = false;
364  m_condmix_ok = false;
365 }
366 
368 {
369  // signal that concentration-dependent quantities will need to
370  // be recomputed before use, and update the local mole
371  // fractions.
372 
373  m_viscmix_ok = false;
374  m_diffmix_ok = false;
375  m_condmix_ok = false;
376 
377  m_thermo->getMoleFractions(DATA_PTR(m_molefracs));
378 
379  // add an offset to avoid a pure species condition
380  int k;
381  for (k = 0; k < m_nsp; k++) {
382  m_molefracs[k] = std::max(Tiny, m_molefracs[k]);
383  }
384 }
385 
387 {
388  int k;
389  doublereal fivehalves = 5/2;
390  for (k = 0; k < m_nsp; k++) {
391  // need to add cv_elec in the future
392  m_cond[k] = m_visc[k] * (fivehalves * cv_int[k] + cv_rot[k] + m_thermo->cv_vib(k,m_temp));
393  }
394  m_spcond_ok = true;
395  m_condmix_ok = false;
396 }
397 
399 {
400  // evaluate binary diffusion coefficients at unit pressure
401  int i,j;
402  int ic = 0;
403  if (m_mode == CK_Mode) {
404  for (i = 0; i < m_nsp; i++) {
405  for (j = i; j < m_nsp; j++) {
406  m_bdiff(i,j) = exp(dot4(m_polytempvec, m_diffcoeffs[ic]));
407  m_bdiff(j,i) = m_bdiff(i,j);
408  ic++;
409  }
410  }
411  } else {
412  for (i = 0; i < m_nsp; i++) {
413  for (j = i; j < m_nsp; j++) {
414  m_bdiff(i,j) = m_temp * m_sqrt_t*dot5(m_polytempvec,
415  m_diffcoeffs[ic]);
416  m_bdiff(j,i) = m_bdiff(i,j);
417  ic++;
418  }
419  }
420  }
421 
422  m_bindiff_ok = true;
423  m_diffmix_ok = false;
424 }
425 
427 {
428  int k;
429  // iterate over species, update pure-species viscosity
430  for (k = 0; k < m_nsp; k++) {
431  m_visc[k] = 0.10*std::exp(a[k]*(m_logt*m_logt) + b[k]*m_logt + c[k]);
432  m_sqvisc[k] = sqrt(m_visc[k]);
433  }
434 
435  // time to update mixing
436  m_spvisc_ok = true;
437 }
438 
440 {
441  // from: AIAA-1997-2474 and Sandia Report SC-RR-70-754
442  //
443  // # Air -- Identical to N2 fit
444  // # N -- Sandia Report SC-RR-70-754
445  // # N2 -- Sandia Report SC-RR-70-754
446  // # CPN2 -- Identical to N2 fit
447  // # NO -- Sandia Report SC-RR-70-754
448  // # O -- Sandia Report SC-RR-70-754
449  // # O2 -- Sandia Report SC-RR-70-754
450  // # C -- AIAA-1997-2474
451  // # C2 -- AIAA-1997-2474
452  // # C3 -- AIAA-1997-2474
453  // # C2H -- wild-ass guess: identical to HCN fit
454  // # CN -- AIAA-1997-2474
455  // # CO -- AIAA-1997-2474
456  // # CO2 -- AIAA-1997-2474
457  // # HCN -- AIAA-1997-2474
458  // # H -- AIAA-1997-2474
459  // # H2 -- AIAA-1997-2474
460  // # e -- Sandia Report SC-RR-70-754
461 
462  istringstream blot
463  ("Air 2.68142000000e-02 3.17783800000e-01 -1.13155513000e+01\n"
464  "CPAir 2.68142000000e-02 3.17783800000e-01 -1.13155513000e+01\n"
465  "N 1.15572000000e-02 6.03167900000e-01 -1.24327495000e+01\n"
466  "N2 2.68142000000e-02 3.17783800000e-01 -1.13155513000e+01\n"
467  "CPN2 2.68142000000e-02 3.17783800000e-01 -1.13155513000e+01\n"
468  "NO 4.36378000000e-02 -3.35511000000e-02 -9.57674300000e+00\n"
469  "O 2.03144000000e-02 4.29440400000e-01 -1.16031403000e+01\n"
470  "O2 4.49290000000e-02 -8.26158000000e-02 -9.20194750000e+00\n"
471  "C -8.3285e-3 0.7703240 -12.7378000\n"
472  "C2 -8.4311e-3 0.7876060 -13.0268000\n"
473  "C3 -8.4312e-3 0.7876090 -12.8240000\n"
474  "C2H -2.4241e-2 1.0946550 -14.5835500\n"
475  "CN -8.3811e-3 0.7860330 -12.9406000\n"
476  "CO -0.019527394 1.013295 -13.97873\n"
477  "CO2 -0.019527387 1.047818 -14.32212\n"
478  "HCN -2.4241e-2 1.0946550 -14.5835500\n"
479  "H -8.3912e-3 0.7743270 -13.6653000\n"
480  "H2 -8.3346e-3 0.7815380 -13.5351000\n"
481  "e 0.00000000000e+00 0.00000000000e+00 -1.16031403000e+01\n");
482 
483  string line;
484  string name;
485  string ss1,ss2,ss3,ss4,sss;
486  int k;
487  int i = 0;
488 
489  while (std::getline(blot, line)) {
490 
491  istringstream ss(line);
492  std::getline(ss, ss1, ' ');
493  std::getline(ss, ss2, ' ');
494  std::getline(ss, ss3, ' ');
495  std::getline(ss, ss4, ' ');
496  name = ss1;
497 
498  // now put coefficients in correct species
499  for (k = 0; k < m_nsp; k++) {
500  string sss = m_thermo->speciesName(k);
501 
502  // this is the right species index
503  if (sss.compare(ss1) == 0) {
504  a[k] = fpValue(ss2);
505  b[k] = fpValue(ss3);
506  c[k] = fpValue(ss4);
507 
508  // index
509  i++;
510  } else { // default to air
511 
512  a[k] = 0.026;
513  b[k] = 0.3;
514  c[k] = -11.3;
515  }
516 
517  } // done with for loop
518  }
519 }
520 
522 {
523  doublereal vratiokj, wratiojk, factor1;
524 
525  if (!m_spvisc_ok) {
527  }
528 
529  // see Eq. (9-5.15) of Reid, Prausnitz, and Poling
530  int j, k;
531  for (j = 0; j < m_nsp; j++) {
532  for (k = j; k < m_nsp; k++) {
533  vratiokj = m_visc[k]/m_visc[j];
534  wratiojk = m_mw[j]/m_mw[k];
535 
536  // Note that m_wratjk(k,j) holds the square root of
537  // m_wratjk(j,k)!
538  factor1 = 1.0 + (m_sqvisc[k]/m_sqvisc[j]) * m_wratjk(k,j);
539  m_phi(k,j) = factor1*factor1 /
540  (sqrt(8.0) * m_wratkj1(j,k));
541  m_phi(j,k) = m_phi(k,j)/(vratiokj * wratiojk);
542  }
543  }
544  m_viscwt_ok = true;
545 }
546 
547 }
doublereal fpValue(const std::string &val)
Translate a string into one doublereal value.
DenseMatrix diam
hard-sphere diameter for (i,j) collision
virtual doublereal thermalConductivity()
Returns the mixture thermal conductivity.
This structure holds transport model parameters relevant to transport in ideal gases with a kinetic t...
vector_fp alpha
Polarizability of each species in the phase.
thermo_t * thermo
Pointer to the ThermoPhase object: shallow pointer.
doublereal dot4(const V &x, const V &y)
Templated Inner product of two vectors of length 4.
Definition: utilities.h:69
virtual doublereal cv_vib(int, double) const
Definition: ThermoPhase.h:262
virtual void getThermalDiffCoeffs(doublereal *const dt)
Return the thermal diffusion coefficients.
Class IdealGasPhase represents low-density gases that obey the ideal gas equation of state...
thermo_t * m_thermo
pointer to the object representing the phase
void warn_deprecated(const std::string &method, const std::string &extra)
Print a warning indicating that method is deprecated.
Definition: global.cpp:78
virtual doublereal viscosity()
Viscosity of the mixture.
doublereal molarDensity() const
Molar density (kmol/m^3).
Definition: Phase.cpp:663
Header file defining class PecosTransport.
void getMoleFractions(doublereal *const x) const
Get the species mole fraction vector.
Definition: Phase.cpp:556
void read_blottner_transport_table()
Reads the transport table specified (currently defaults to internal file)
std::vector< vector_fp > diffcoeffs
temperature-fits of the diffusivity
vector_fp zrot
Rotational relaxation number for the species in the current phase.
void resize(size_t n, size_t m, doublereal v=0.0)
Resize the matrix.
Definition: DenseMatrix.cpp:64
vector_fp eps
Lennard-Jones well-depth of the species in the current phase.
ThermoPhase object for the ideal gas equation of state - workhorse for Cantera (see Thermodynamic Pro...
virtual void update_C()
This is called the first time any transport property is requested from Mixture after the concentratio...
virtual void getMixDiffCoeffs(doublereal *const d)
Mixture-averaged diffusion coefficients [m^2/s].
void getMixDiffCoeffsMass(doublereal *const d)
Returns the mixture-averaged diffusion coefficients [m^2/s].
std::string fp2str(const double x, const std::string &fmt)
Convert a double into a c++ string.
Definition: stringUtils.cpp:28
virtual void getSpeciesFluxes(size_t ndim, const doublereal *const grad_T, size_t ldx, const doublereal *const grad_X, size_t ldf, doublereal *const fluxes)
Get the species diffusive mass fluxes wrt to the mass averaged velocity, given the gradients in mole ...
virtual void getMobilities(doublereal *const mobil)
Get the Electrical mobilities (m^2/V/s).
const doublereal * massFractions() const
Return a const pointer to the mass fraction array.
Definition: Phase.h:482
void multiply(const DenseMatrix &A, const double *const b, double *const prod)
Multiply A*b and return the result in prod. Uses BLAS routine DGEMV.
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:99
void updateDiff_T()
Update the binary diffusion coefficients.
virtual void getBinaryDiffCoeffs(const size_t ld, doublereal *const d)
binary diffusion coefficients
vector_fp crot
Dimensionless rotational heat capacity of the species in the current phase.
void updateSpeciesViscosities()
Update the pure-species viscosities.
DenseMatrix epsilon
The effective well depth for (i,j) collisions.
doublereal pressure_ig() const
Calculate the pressure from the ideal gas law.
size_t nSpecies() const
Returns the number of species in the phase.
Definition: Phase.h:265
std::vector< std::vector< int > > poly
This is vector of vectors containing the integer lookup value for the (i,j) interaction.
virtual doublereal pressure() const
Return the thermodynamic pressure (Pa).
Definition: ThermoPhase.h:278
void updateCond_T()
Update the temperature-dependent parts of the mixture-averaged thermal conductivity.
const vector_fp & molecularWeights() const
Return a const reference to the internal vector of molecular weights.
Definition: Phase.cpp:515
doublereal temperature() const
Temperature (K).
Definition: Phase.h:602
int mode_
Mode parameter.
doublereal dot5(const V &x, const V &y)
Templated Inner product of two vectors of length 5.
Definition: utilities.h:87
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
Definition: ct_defs.h:157
DenseMatrix dipole
The effective dipole moment for (i,j) collisions.
std::vector< vector_fp > visccoeffs
temperature-fit of the viscosity
const doublereal Tiny
Small number to compare differences of mole fractions against.
Definition: ct_defs.h:142
std::vector< vector_fp > condcoeffs
temperature-fits of the heat conduction
doublereal meanMolecularWeight() const
The mean molecular weight. Units: (kg/kmol)
Definition: Phase.h:669
void updateViscosity_T()
Update the temperature-dependent viscosity terms.
Contains declarations for string manipulation functions within Cantera.
#define DATA_PTR(vec)
Creates a pointer to the start of the raw data for a vector.
Definition: ct_defs.h:36
void getMixDiffCoeffsMole(doublereal *const d)
Returns the mixture-averaged diffusion coefficients [m^2/s].
virtual bool initGas(GasTransportParams &tr)
Initialize the transport object.
Class that holds the data that is read in from the XML file, and which is used for processing of the ...
std::string speciesName(size_t k) const
Name of the species with index k.
Definition: Phase.cpp:272
const doublereal Boltzmann
Boltzmann's constant [J/K].
Definition: ct_defs.h:76
doublereal charge(size_t k) const
Dimensionless electrical charge of a single molecule of species k The charge is normalized by the the...
Definition: Phase.h:578