Cantera  2.0
SimpleTransport.cpp
Go to the documentation of this file.
1 /**
2  * @file SimpleTransport.cpp
3  * Simple mostly constant transport properties
4  */
7 
13 
14 #include <iostream>
15 using namespace std;
16 
17 /**
18  * Mole fractions below MIN_X will be set to MIN_X when computing
19  * transport properties.
20  */
21 #define MIN_X 1.e-14
22 
23 
24 #ifndef SAFE_DELETE
25 //! \cond
26 #define SAFE_DELETE(x) if (x) { delete (x); x = 0; }
27 //! \endcond
28 #endif
29 
30 namespace Cantera
31 {
32 //================================================================================================
33 SimpleTransport::SimpleTransport(thermo_t* thermo, int ndim) :
34  Transport(thermo, ndim),
35  tempDepType_(0),
36  compositionDepType_(0),
37  useHydroRadius_(false),
38  doMigration_(0),
39  m_tmin(-1.0),
40  m_tmax(100000.),
41  m_iStateMF(-1),
42  concTot_(0.0),
43  m_temp(-1.0),
44  m_press(-1.0),
45  m_lambda(-1.0),
46  m_viscmix(-1.0),
47  m_visc_mix_ok(false),
48  m_visc_temp_ok(false),
49  m_diff_mix_ok(false),
50  m_diff_temp_ok(false),
51  m_cond_temp_ok(false),
52  m_cond_mix_ok(false),
53  m_nDim(1)
54 {
55 }
56 //================================================================================================
58  Transport(),
59  tempDepType_(0),
60  compositionDepType_(0),
61  useHydroRadius_(false),
62  doMigration_(0),
63  m_tmin(-1.0),
64  m_tmax(100000.),
65  m_iStateMF(-1),
66  m_temp(-1.0),
67  m_press(-1.0),
68  m_lambda(-1.0),
69  m_viscmix(-1.0),
70  m_visc_mix_ok(false),
71  m_visc_temp_ok(false),
72  m_diff_mix_ok(false),
73  m_diff_temp_ok(false),
74  m_cond_temp_ok(false),
75  m_cond_mix_ok(false),
76  m_nDim(1)
77 {
78  /*
79  * Use the assignment operator to do the brunt
80  * of the work for the copy constructor.
81  */
82  *this = right;
83 }
84 //================================================================================================
86 {
87  if (&right == this) {
88  return *this;
89  }
90  Transport::operator=(right);
91 
92  tempDepType_ = right.tempDepType_;
95  doMigration_ = right.doMigration_;
96  m_tmin = right.m_tmin;
97  m_tmax = right.m_tmax;
98  m_mw = right.m_mw;
99 
101  for (size_t k = 0; k <right.m_coeffVisc_Ns.size() ; k++) {
102  if (right.m_coeffVisc_Ns[k]) {
103  m_coeffVisc_Ns[k] = (right.m_coeffVisc_Ns[k])->duplMyselfAsLTPspecies();
104  }
105  }
106 
108  for (size_t k = 0; k < right.m_coeffLambda_Ns.size(); k++) {
109  if (right.m_coeffLambda_Ns[k]) {
110  m_coeffLambda_Ns[k] = (right.m_coeffLambda_Ns[k])->duplMyselfAsLTPspecies();
111  }
112  }
113 
115  for (size_t k = 0; k < right.m_coeffDiff_Ns.size(); k++) {
116  if (right.m_coeffDiff_Ns[k]) {
117  m_coeffDiff_Ns[k] = (right.m_coeffDiff_Ns[k])->duplMyselfAsLTPspecies();
118  }
119  }
120 
122  for (size_t k = 0; k < right.m_coeffHydroRadius_Ns.size(); k++) {
123  if (right.m_coeffHydroRadius_Ns[k]) {
124  m_coeffHydroRadius_Ns[k] = (right.m_coeffHydroRadius_Ns[k])->duplMyselfAsLTPspecies();
125  }
126  }
127 
128  m_Grad_X = right.m_Grad_X;
129  m_Grad_T = right.m_Grad_T;
130  m_Grad_P = right.m_Grad_P;
131  m_Grad_V = right.m_Grad_V;
132 
136  m_iStateMF = -1;
137  m_molefracs = right.m_molefracs;
139  concTot_ = right.concTot_;
141  dens_ = right.dens_;
143 
144  m_temp = right.m_temp;
145  m_press = right.m_press;
146  m_lambda = right.m_lambda;
147  m_viscmix = right.m_viscmix;
148  m_spwork = right.m_spwork;
149  m_visc_mix_ok = false;
150  m_visc_temp_ok = false;
151  m_diff_mix_ok = false;
152  m_diff_temp_ok = false;
153  m_cond_temp_ok = false;
154  m_cond_mix_ok = false;
155  m_nDim = right.m_nDim;
156 
157  return *this;
158 }
159 //================================================================================================
161 {
162  SimpleTransport* tr = new SimpleTransport(*this);
163  return (dynamic_cast<Transport*>(tr));
164 }
165 //================================================================================================
167 {
168  for (size_t k = 0; k < m_coeffVisc_Ns.size() ; k++) {
169  SAFE_DELETE(m_coeffVisc_Ns[k]);
170  }
171  for (size_t k = 0; k < m_coeffLambda_Ns.size(); k++) {
172  SAFE_DELETE(m_coeffLambda_Ns[k]);
173  }
174  for (size_t k = 0; k < m_coeffDiff_Ns.size(); k++) {
175  SAFE_DELETE(m_coeffDiff_Ns[k]);
176  }
177  for (size_t k = 0; k < m_coeffHydroRadius_Ns.size(); k++) {
178  SAFE_DELETE(m_coeffHydroRadius_Ns[k]);
179  }
180 }
181 //================================================================================================
182 // Initialize the object
183 /*
184  * This is where we dimension everything.
185  */
187 {
188  // constant substance attributes
189  m_thermo = tr.thermo;
190  m_nsp = m_thermo->nSpecies();
191  m_tmin = m_thermo->minTemp();
192  m_tmax = m_thermo->maxTemp();
193 
194  /*
195  * Read the transport block in the phase XML Node
196  * It's not an error if this block doesn't exist. Just use the defaults
197  */
198  XML_Node& phaseNode = m_thermo->xml();
199  if (phaseNode.hasChild("transport")) {
200  XML_Node& transportNode = phaseNode.child("transport");
201  string transportModel = transportNode.attrib("model");
202  if (transportModel == "Simple") {
203  /*
204  * <compositionDependence model="Solvent_Only"/>
205  * or
206  * <compositionDependence model="Mixture_Averaged"/>
207  */
208  std::string modelName = "";
209  if (ctml::getOptionalModel(transportNode, "compositionDependence",
210  modelName)) {
211  modelName = lowercase(modelName);
212  if (modelName == "solvent_only") {
214  } else if (modelName == "mixture_averaged") {
216  } else {
217  throw CanteraError("SimpleTransport::initLiquid", "Unknown compositionDependence Model: " + modelName);
218  }
219  }
220 
221 
222 
223 
224  }
225  }
226 
227  // make a local copy of the molecular weights
228  m_mw.resize(m_nsp);
229  copy(m_thermo->molecularWeights().begin(),
230  m_thermo->molecularWeights().end(), m_mw.begin());
231 
232  /*
233  * Get the input Viscosities
234  */
235  m_viscSpecies.resize(m_nsp);
236  m_coeffVisc_Ns.clear();
237  m_coeffVisc_Ns.resize(m_nsp);
238 
239  //Cantera::LiquidTransportData &ltd0 = tr.LTData[0];
240  std::string spName = m_thermo->speciesName(0);
241  /*
242  LiquidTR_Model vm0 = ltd0.model_viscosity;
243  std::string spName0 = m_thermo->speciesName(0);
244  if (vm0 == LTR_MODEL_CONSTANT) {
245  tempDepType_ = 0;
246  } else if (vm0 == LTR_MODEL_ARRHENIUS) {
247  tempDepType_ = 1;
248  } else if (vm0 == LTR_MODEL_NOTSET) {
249  throw CanteraError("SimpleTransport::initLiquid",
250  "Viscosity Model is not set for species " + spName0 + " in the input file");
251  } else {
252  throw CanteraError("SimpleTransport::initLiquid",
253  "Viscosity Model for species " + spName0 + " is not handled by this object");
254  }
255  */
256 
257  for (size_t k = 0; k < m_nsp; k++) {
258  spName = m_thermo->speciesName(k);
260  //LiquidTR_Model vm = ltd.model_viscosity;
261  //vector_fp &kentry = m_coeffVisc_Ns[k];
262  /*
263  if (vm != vm0) {
264  if (compositionDepType_ != 0) {
265  throw CanteraError(" SimpleTransport::initLiquid",
266  "different viscosity models for species " + spName + " and " + spName0 );
267  } else {
268  kentry = m_coeffVisc_Ns[0];
269  }
270  }
271  */
272  m_coeffVisc_Ns[k] = ltd.viscosity;
273  ltd.viscosity = 0;
274  }
275 
276  /*
277  * Get the input thermal conductivities
278  */
279  m_condSpecies.resize(m_nsp);
280  m_coeffLambda_Ns.clear();
281  m_coeffLambda_Ns.resize(m_nsp);
282  //LiquidTR_Model cm0 = ltd0.model_thermalCond;
283  //if (cm0 != vm0) {
284  // throw CanteraError("SimpleTransport::initLiquid",
285  // "Conductivity model is not the same as the viscosity model for species " + spName0);
286  // }
287 
288  for (size_t k = 0; k < m_nsp; k++) {
289  spName = m_thermo->speciesName(k);
291  //LiquidTR_Model cm = ltd.model_thermalCond;
292  //vector_fp &kentry = m_coeffLambda_Ns[k];
293  /*
294  if (cm != cm0) {
295  if (compositionDepType_ != 0) {
296  throw CanteraError(" SimpleTransport::initLiquid",
297  "different thermal conductivity models for species " + spName + " and " + spName0);
298  } else {
299  kentry = m_coeffLambda_Ns[0];
300  }
301  }
302  */
303  m_coeffLambda_Ns[k] = ltd.thermalCond;
304  ltd.thermalCond = 0;
305  }
306 
307  /*
308  * Get the input species diffusivities
309  */
310  useHydroRadius_ = false;
311 
312  m_diffSpecies.resize(m_nsp);
313  m_coeffDiff_Ns.clear();
314  m_coeffDiff_Ns.resize(m_nsp);
315  //LiquidTR_Model dm0 = ltd0.model_speciesDiffusivity;
316  /*
317  if (dm0 != vm0) {
318  if (dm0 == LTR_MODEL_NOTSET) {
319  LiquidTR_Model rm0 = ltd0.model_hydroradius;
320  if (rm0 != vm0) {
321  throw CanteraError("SimpleTransport::initLiquid",
322  "hydroradius model is not the same as the viscosity model for species " + spName0);
323  } else {
324  useHydroRadius_ = true;
325  }
326  }
327  }
328  */
329 
330  for (size_t k = 0; k < m_nsp; k++) {
331  spName = m_thermo->speciesName(k);
333  /*
334  LiquidTR_Model dm = ltd.model_speciesDiffusivity;
335  if (dm == LTR_MODEL_NOTSET) {
336  LiquidTR_Model rm = ltd.model_hydroradius;
337  if (rm == LTR_MODEL_NOTSET) {
338  throw CanteraError("SimpleTransport::initLiquid",
339  "Neither diffusivity nor hydroradius is set for species " + spName);
340  }
341  if (rm != vm0) {
342  throw CanteraError("SimpleTransport::initLiquid",
343  "hydroradius model is not the same as the viscosity model for species " + spName);
344  }
345  if (rm != LTR_MODEL_CONSTANT) {
346  throw CanteraError("SimpleTransport::initLiquid",
347  "hydroradius model is not constant for species " + spName0);
348  }
349  vector_fp &kentry = m_coeffHydroRadius_Ns[k];
350  kentry = ltd.hydroradius;
351  } else {
352  if (dm != dm0) {
353  throw CanteraError(" SimpleTransport::initLiquid",
354  "different diffusivity models for species " + spName + " and " + spName0 );
355  }
356  vector_fp &kentry = m_coeffDiff_Ns[k];
357  kentry = ltd.speciesDiffusivity;
358  }
359  */
360 
362  ltd.speciesDiffusivity = 0;
363 
364  if (!(m_coeffDiff_Ns[k])) {
365  if (ltd.hydroRadius) {
366  m_coeffHydroRadius_Ns[k] = (ltd.hydroRadius)->duplMyselfAsLTPspecies();
367  }
368  if (!(m_coeffHydroRadius_Ns[k])) {
369  throw CanteraError("SimpleTransport::initLiquid",
370  "Neither diffusivity nor hydroradius is set for species " + spName);
371  }
372  }
373  }
374 
375 
376 
377 
378  m_molefracs.resize(m_nsp);
379  m_concentrations.resize(m_nsp);
380 
381  m_chargeSpecies.resize(m_nsp);
382  for (size_t k = 0; k < m_nsp; k++) {
384  }
385  m_spwork.resize(m_nsp);
386 
387  // resize the internal gradient variables
388  m_Grad_X.resize(m_nDim * m_nsp, 0.0);
389  m_Grad_T.resize(m_nDim, 0.0);
390  m_Grad_P.resize(m_nDim, 0.0);
391  m_Grad_V.resize(m_nDim, 0.0);
392 
393  // set all flags to false
394  m_visc_mix_ok = false;
395  m_visc_temp_ok = false;
396 
397  m_cond_temp_ok = false;
398  m_cond_mix_ok = false;
399 
400  m_diff_temp_ok = false;
401  m_diff_mix_ok = false;
402 
403  return true;
404 }
405 
406 //================================================================================================
407 // Returns the mixture viscosity of the solution
408 /*
409  * The viscosity is computed using the general mixture rules
410  * specified in the variable compositionDepType_.
411  *
412  * Solvent-only:
413  * \f[
414  * \mu = \mu_0
415  * \f]
416  * Mixture-average:
417  * \f[
418  * \mu = \sum_k {\mu_k X_k}
419  * \f]
420  *
421  * Here \f$ \mu_k \f$ is the viscosity of pure species \e k.
422  *
423  * @see updateViscosity_T();
424  */
426 {
427 
428  update_T();
429  update_C();
430 
431  if (m_visc_mix_ok) {
432  return m_viscmix;
433  }
434 
435  // update m_viscSpecies[] if necessary
436  if (!m_visc_temp_ok) {
438  }
439 
440  if (compositionDepType_ == 0) {
442  } else if (compositionDepType_ == 1) {
443  m_viscmix = 0.0;
444  for (size_t k = 0; k < m_nsp; k++) {
446  }
447  }
448  m_visc_mix_ok = true;
449  return m_viscmix;
450 }
451 //================================================================================================
452 void SimpleTransport::getSpeciesViscosities(doublereal* const visc)
453 {
454  update_T();
455  if (!m_visc_temp_ok) {
457  }
458  copy(m_viscSpecies.begin(), m_viscSpecies.end(), visc);
459 }
460 //================================================================================================
461 void SimpleTransport::getBinaryDiffCoeffs(size_t ld, doublereal* d)
462 {
463  double bdiff;
464  update_T();
465 
466  // if necessary, evaluate the species diffusion coefficients
467  // from the polynomial fits
468  if (!m_diff_temp_ok) {
469  updateDiff_T();
470  }
471 
472  for (size_t i = 0; i < m_nsp; i++) {
473  for (size_t j = 0; j < m_nsp; j++) {
474  bdiff = 0.5 * (m_diffSpecies[i] + m_diffSpecies[j]);
475  d[i*m_nsp+j] = bdiff;
476  }
477  }
478 }
479 //================================================================================================
480 // Get the electrical Mobilities (m^2/V/s).
481 /*
482  * This function returns the mobilities. In some formulations
483  * this is equal to the normal mobility multiplied by faraday's constant.
484  *
485  * Frequently, but not always, the mobility is calculated from the
486  * diffusion coefficient using the Einstein relation
487  *
488  * \f[
489  * \mu^e_k = \frac{F D_k}{R T}
490  * \f]
491  *
492  * @param mobil_e Returns the mobilities of
493  * the species in array \c mobil_e. The array must be
494  * dimensioned at least as large as the number of species.
495  */
496 void SimpleTransport::getMobilities(doublereal* const mobil)
497 {
499  doublereal c1 = ElectronCharge / (Boltzmann * m_temp);
500  for (size_t k = 0; k < m_nsp; k++) {
501  mobil[k] = c1 * m_spwork[k];
502  }
503 }
504 //================================================================================================
505 // Get the fluid mobilities (s kmol/kg).
506 /*
507  * This function returns the fluid mobilities. Usually, you have
508  * to multiply Faraday's constant into the resulting expression
509  * to general a species flux expression.
510  *
511  * Frequently, but not always, the mobility is calculated from the
512  * diffusion coefficient using the Einstein relation
513  *
514  * \f[
515  * \mu^f_k = \frac{D_k}{R T}
516  * \f]
517  *
518  *
519  * @param mobil_f Returns the mobilities of
520  * the species in array \c mobil. The array must be
521  * dimensioned at least as large as the number of species.
522  */
523 void SimpleTransport::getFluidMobilities(doublereal* const mobil_f)
524 {
526  doublereal c1 = 1.0 / (GasConstant * m_temp);
527  for (size_t k = 0; k < m_nsp; k++) {
528  mobil_f[k] = c1 * m_spwork[k];
529  }
530 }
531 //================================================================================================
532 void SimpleTransport::set_Grad_V(const doublereal* const grad_V)
533 {
534  doMigration_ = false;
535  for (size_t a = 0; a < m_nDim; a++) {
536  m_Grad_V[a] = grad_V[a];
537  if (fabs(grad_V[a]) > 1.0E-13) {
538  doMigration_ = true;
539  }
540  }
541 }
542 //================================================================================================
543 void SimpleTransport::set_Grad_T(const doublereal* const grad_T)
544 {
545  for (size_t a = 0; a < m_nDim; a++) {
546  m_Grad_T[a] = grad_T[a];
547  }
548 }
549 //================================================================================================
550 void SimpleTransport::set_Grad_X(const doublereal* const grad_X)
551 {
552  size_t itop = m_nDim * m_nsp;
553  for (size_t i = 0; i < itop; i++) {
554  m_Grad_X[i] = grad_X[i];
555  }
556 }
557 //================================================================================================
558 // Returns the mixture thermal conductivity of the solution
559 /*
560  * The thermal is computed using the general mixture rules
561  * specified in the variable compositionDepType_.
562  *
563  * Solvent-only:
564  * \f[
565  * \lambda = \lambda_0
566  * \f]
567  * Mixture-average:
568  * \f[
569  * \lambda = \sum_k {\lambda_k X_k}
570  * \f]
571  *
572  * Here \f$ \lambda_k \f$ is the thermal conductivity of pure species \e k.
573  *
574  * @see updateCond_T();
575  */
577 {
578  update_T();
579  update_C();
580  if (!m_cond_temp_ok) {
581  updateCond_T();
582  }
583  if (!m_cond_mix_ok) {
584  if (compositionDepType_ == 0) {
585  m_lambda = m_condSpecies[0];
586  } else if (compositionDepType_ == 1) {
587  m_lambda = 0.0;
588  for (size_t k = 0; k < m_nsp; k++) {
590  }
591  }
592  m_cond_mix_ok = true;
593  }
594  return m_lambda;
595 }
596 //================================================================================================
597 
598 /*
599  * Thermal diffusion is not considered in this mixture-averaged
600  * model. To include thermal diffusion, use transport manager
601  * MultiTransport instead. This methods fills out array dt with
602  * zeros.
603  */
604 void SimpleTransport::getThermalDiffCoeffs(doublereal* const dt)
605 {
606  for (size_t k = 0; k < m_nsp; k++) {
607  dt[k] = 0.0;
608  }
609 }
610 
611 //====================================================================================================================
612 //! Get the species diffusive velocities wrt to the averaged velocity,
613 //! given the gradients in mole fraction and temperature
614 /*!
615  * The average velocity can be computed on a mole-weighted
616  * or mass-weighted basis, or the diffusion velocities may
617  * be specified as relative to a specific species (i.e. a
618  * solvent) all according to the velocityBasis input parameter.
619  *
620  * Units for the returned velocities are m s-1.
621  *
622  * @param ndim Number of dimensions in the flux expressions
623  * @param grad_T Gradient of the temperature
624  * (length = ndim)
625  * @param ldx Leading dimension of the grad_X array
626  * (usually equal to m_nsp but not always)
627  * @param grad_X Gradients of the mole fraction
628  * Flat vector with the m_nsp in the inner loop.
629  * length = ldx * ndim
630  * @param ldf Leading dimension of the fluxes array
631  * (usually equal to m_nsp but not always)
632  * @param Vdiff Output of the diffusive velocities.
633  * Flat vector with the m_nsp in the inner loop.
634  * length = ldx * ndim
635  */
637  const doublereal* grad_T,
638  int ldx,
639  const doublereal* grad_X,
640  int ldf,
641  doublereal* Vdiff)
642 {
643  set_Grad_T(grad_T);
644  set_Grad_X(grad_X);
645  const doublereal* y = m_thermo->massFractions();
646  const doublereal rho = m_thermo->density();
647 
649 
650  for (size_t n = 0; n < m_nDim; n++) {
651  for (size_t k = 0; k < m_nsp; k++) {
652  if (y[k] > 1.0E-200) {
653  Vdiff[n * m_nsp + k] *= 1.0 / (rho * y[k]);
654  } else {
655  Vdiff[n * m_nsp + k] = 0.0;
656  }
657  }
658  }
659 }
660 //================================================================================================
661 // Get the species diffusive velocities wrt to the averaged velocity,
662 // given the gradients in mole fraction, temperature and electrostatic potential.
663 /*
664  * The average velocity can be computed on a mole-weighted
665  * or mass-weighted basis, or the diffusion velocities may
666  * be specified as relative to a specific species (i.e. a
667  * solvent) all according to the velocityBasis input parameter.
668  *
669  * Units for the returned velocities are m s-1.
670  *
671  * @param ndim Number of dimensions in the flux expressions
672  * @param grad_T Gradient of the temperature
673  * (length = ndim)
674  * @param ldx Leading dimension of the grad_X array
675  * (usually equal to m_nsp but not always)
676  * @param grad_X Gradients of the mole fraction
677  * Flat vector with the m_nsp in the inner loop.
678  * length = ldx * ndim
679  * @param ldf Leading dimension of the fluxes array
680  * (usually equal to m_nsp but not always)
681  * @param grad_Phi Gradients of the electrostatic potential
682  * (length = ndim)
683  * @param Vdiff Output of the species diffusion velocities
684  * Flat vector with the m_nsp in the inner loop.
685  * length = ldx * ndim
686  */
687 void SimpleTransport::getSpeciesVdiffES(size_t ndim, const doublereal* grad_T,
688  int ldx, const doublereal* grad_X,
689  int ldf, const doublereal* grad_Phi,
690  doublereal* Vdiff)
691 {
692  set_Grad_T(grad_T);
693  set_Grad_X(grad_X);
694  set_Grad_V(grad_Phi);
695  const doublereal* y = m_thermo->massFractions();
696  const doublereal rho = m_thermo->density();
697 
699 
700  for (size_t n = 0; n < m_nDim; n++) {
701  for (size_t k = 0; k < m_nsp; k++) {
702  if (y[k] > 1.0E-200) {
703  Vdiff[n * m_nsp + k] *= 1.0 / (rho * y[k]);
704  } else {
705  Vdiff[n * m_nsp + k] = 0.0;
706  }
707  }
708  }
709 }
710 //================================================================================================
711 // Get the species diffusive mass fluxes wrt to the specified solution averaged velocity,
712 // given the gradients in mole fraction and temperature
713 /*
714  * units = kg/m2/s
715  *
716  * The diffusive mass flux of species \e k is computed from the following
717  * formula
718  *
719  * Usually the specified solution average velocity is the mass averaged velocity.
720  * This is changed in some subclasses, however.
721  *
722  * \f[
723  * j_k = - \rho M_k D_k \nabla X_k - Y_k V_c
724  * \f]
725  *
726  * where V_c is the correction velocity
727  *
728  * \f[
729  * V_c = - \sum_j {\rho M_j D_j \nabla X_j}
730  * \f]
731  *
732  *
733  * @param ndim The number of spatial dimensions (1, 2, or 3).
734  * @param grad_T The temperature gradient (ignored in this model).
735  * @param ldx Leading dimension of the grad_X array.
736  * @param grad_X Gradient of the mole fractions(length nsp * num dimensions);
737  * @param ldf Leading dimension of the fluxes array.
738  * @param fluxes Output fluxes of species.
739  */
740 void SimpleTransport::getSpeciesFluxes(size_t ndim, const doublereal* const grad_T,
741  size_t ldx, const doublereal* const grad_X,
742  size_t ldf, doublereal* const fluxes)
743 {
744  set_Grad_T(grad_T);
745  set_Grad_X(grad_X);
746  getSpeciesFluxesExt(ldf, fluxes);
747 }
748 //================================================================================================
749 // Return the species diffusive mass fluxes wrt to
750 // the mass averaged velocity.
751 /*
752  *
753  * units = kg/m2/s
754  *
755  * Internally, gradients in the in mole fraction, temperature
756  * and electrostatic potential contribute to the diffusive flux
757  *
758  *
759  * The diffusive mass flux of species \e k is computed from the following
760  * formula
761  *
762  * \f[
763  * 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
764  * \f]
765  *
766  * where V_c is the correction velocity
767  *
768  * \f[
769  * V_c = - \sum_j {M_k z_k u^f_k F c_k \nabla \Psi + c M_j D_j \nabla X_j}
770  * \f]
771  *
772  * @param ldf stride of the fluxes array. Must be equal to
773  * or greater than the number of species.
774  * @param fluxes Vector of calculated fluxes
775  */
776 void SimpleTransport::getSpeciesFluxesExt(size_t ldf, doublereal* fluxes)
777 {
778  AssertThrow(ldf >= m_nsp ,"SimpleTransport::getSpeciesFluxesExt: Stride must be greater than m_nsp");
779  update_T();
780  update_C();
781 
783 
784  const vector_fp& mw = m_thermo->molecularWeights();
785  const doublereal* y = m_thermo->massFractions();
786 
787  doublereal concTotal = m_thermo->molarDensity();
788 
789  // Unroll wrt ndim
790 
791 
792  if (doMigration_) {
793  double FRT = ElectronCharge / (Boltzmann * m_temp);
794  for (size_t n = 0; n < m_nDim; n++) {
795  rhoVc[n] = 0.0;
796  for (size_t k = 0; k < m_nsp; k++) {
797  fluxes[n*ldf + k] = - concTotal * mw[k] * m_spwork[k] *
798  (m_Grad_X[n*m_nsp + k] + FRT * m_molefracs[k] * m_chargeSpecies[k] * m_Grad_V[n]);
799  rhoVc[n] += fluxes[n*ldf + k];
800  }
801  }
802  } else {
803  for (size_t n = 0; n < m_nDim; n++) {
804  rhoVc[n] = 0.0;
805  for (size_t k = 0; k < m_nsp; k++) {
806  fluxes[n*ldf + k] = - concTotal * mw[k] * m_spwork[k] * m_Grad_X[n*m_nsp + k];
807  rhoVc[n] += fluxes[n*ldf + k];
808  }
809  }
810  }
811 
812  if (m_velocityBasis == VB_MASSAVG) {
813  for (size_t n = 0; n < m_nDim; n++) {
814  rhoVc[n] = 0.0;
815  for (size_t k = 0; k < m_nsp; k++) {
816  rhoVc[n] += fluxes[n*ldf + k];
817  }
818  }
819  for (size_t n = 0; n < m_nDim; n++) {
820  for (size_t k = 0; k < m_nsp; k++) {
821  fluxes[n*ldf + k] -= y[k] * rhoVc[n];
822  }
823  }
824  } else if (m_velocityBasis == VB_MOLEAVG) {
825  for (size_t n = 0; n < m_nDim; n++) {
826  rhoVc[n] = 0.0;
827  for (size_t k = 0; k < m_nsp; k++) {
828  rhoVc[n] += fluxes[n*ldf + k] / mw[k];
829  }
830  }
831  for (size_t n = 0; n < m_nDim; n++) {
832  for (size_t k = 0; k < m_nsp; k++) {
833  fluxes[n*ldf + k] -= m_molefracs[k] * rhoVc[n] * mw[k];
834  }
835  }
836  } else if (m_velocityBasis >= 0) {
837  for (size_t n = 0; n < m_nDim; n++) {
838  rhoVc[n] = - fluxes[n*ldf + m_velocityBasis] / mw[m_velocityBasis];
839  for (size_t k = 0; k < m_nsp; k++) {
840  rhoVc[n] += fluxes[n*ldf + k] / mw[k];
841  }
842  }
843  for (size_t n = 0; n < m_nDim; n++) {
844  for (size_t k = 0; k < m_nsp; k++) {
845  fluxes[n*ldf + k] -= m_molefracs[k] * rhoVc[n] * mw[k];
846  }
847  fluxes[n*ldf + m_velocityBasis] = 0.0;
848  }
849 
850  } else {
851  throw CanteraError("SimpleTransport::getSpeciesFluxesExt()",
852  "unknown velocity basis");
853  }
854 }
855 //================================================================================================
856 // Mixture-averaged diffusion coefficients [m^2/s].
857 /*
858  * Returns the simple diffusion coefficients input into the model. Nothing fancy here.
859  */
860 void SimpleTransport::getMixDiffCoeffs(doublereal* const d)
861 {
862  update_T();
863  update_C();
864  // update the binary diffusion coefficients if necessary
865  if (!m_diff_temp_ok) {
866  updateDiff_T();
867  }
868  for (size_t k = 0; k < m_nsp; k++) {
869  d[k] = m_diffSpecies[k];
870  }
871 }
872 //================================================================================================
873 
874 // Handles the effects of changes in the mixture concentration
875 /*
876  * This is called for every interface call to check whether
877  * the concentrations have changed. Concentrations change
878  * whenever the pressure or the mole fraction has changed.
879  * If it has changed, the recalculations should be done.
880  *
881  * Note this should be a lightweight function since it's
882  * part of all of the interfaces.
883  *
884  * @internal
885  */
887 {
888  // If the pressure has changed then the concentrations
889  // have changed.
890  doublereal pres = m_thermo->pressure();
891  bool qReturn = true;
892  if (pres != m_press) {
893  qReturn = false;
894  m_press = pres;
895  }
896  int iStateNew = m_thermo->stateMFNumber();
897  if (iStateNew != m_iStateMF) {
898  qReturn = false;
901  concTot_ = 0.0;
902  for (size_t k = 0; k < m_nsp; k++) {
903  m_molefracs[k] = std::max(0.0, m_molefracs[k]);
905  }
906  dens_ = m_thermo->density();
908  }
909  if (qReturn) {
910  return false;
911  }
912 
913 
914  // Mixture stuff needs to be evaluated
915  m_visc_mix_ok = false;
916  m_diff_mix_ok = false;
917  m_cond_mix_ok = false;
918 
919  return true;
920 }
921 
922 //================================================================================================
923 /**
924  * Update the temperature-dependent parts of the mixture-averaged
925  * thermal conductivity.
926  */
928 {
929  if (compositionDepType_ == 0) {
930  m_condSpecies[0] = m_coeffLambda_Ns[0]->getSpeciesTransProp();
931  } else {
932  for (size_t k = 0; k < m_nsp; k++) {
933  m_condSpecies[k] = m_coeffLambda_Ns[k]->getSpeciesTransProp();
934  }
935  }
936  m_cond_temp_ok = true;
937  m_cond_mix_ok = false;
938 }
939 //================================================================================================
940 /**
941  * Update the species diffusion coefficients.
942  */
944 {
945  if (useHydroRadius_) {
946  double visc = viscosity();
947  double RT = GasConstant * m_temp;
948  for (size_t k = 0; k < m_nsp; k++) {
949  double rad = m_coeffHydroRadius_Ns[k]->getSpeciesTransProp() ;
950  m_diffSpecies[k] = RT / (6.0 * Pi * visc * rad);
951  }
952  } else {
953  for (size_t k = 0; k < m_nsp; k++) {
954  m_diffSpecies[k] = m_coeffDiff_Ns[k]->getSpeciesTransProp();
955  }
956  }
957  m_diff_temp_ok = true;
958  m_diff_mix_ok = false;
959 }
960 //================================================================================================
961 /**
962  * Update the pure-species viscosities.
963  */
965 {
966 
967 }
968 //================================================================================================
969 /**
970  * Update the temperature-dependent viscosity terms.
971  * Updates the array of pure species viscosities, and the
972  * weighting functions in the viscosity mixture rule.
973  * The flag m_visc_ok is set to true.
974  */
976 {
977  if (compositionDepType_ == 0) {
978  m_viscSpecies[0] = m_coeffVisc_Ns[0]->getSpeciesTransProp();
979  } else {
980  for (size_t k = 0; k < m_nsp; k++) {
981  m_viscSpecies[k] = m_coeffVisc_Ns[k]->getSpeciesTransProp();
982  }
983  }
984  m_visc_temp_ok = true;
985  m_visc_mix_ok = false;
986 }
987 //=================================================================================================
989 {
990  doublereal t = m_thermo->temperature();
991  if (t == m_temp) {
992  return false;
993  }
994  if (t < 0.0) {
995  throw CanteraError("SimpleTransport::update_T",
996  "negative temperature "+fp2str(t));
997  }
998 
999  // Compute various functions of temperature
1000  m_temp = t;
1001 
1002  // temperature has changed, so polynomial temperature
1003  // interpolations will need to be reevaluated.
1004  // Set all of these flags to false
1005  m_visc_mix_ok = false;
1006  m_visc_temp_ok = false;
1007 
1008  m_cond_temp_ok = false;
1009  m_cond_mix_ok = false;
1010 
1011  m_diff_mix_ok = false;
1012  m_diff_temp_ok = false;
1013 
1014  return true;
1015 }
1016 //================================================================================================
1017 /*
1018  * Throw an exception if this method is invoked.
1019  * This probably indicates something is not yet implemented.
1020  */
1021 doublereal SimpleTransport::err(std::string msg) const
1022 {
1023  throw CanteraError("SimpleTransport Class",
1024  "\n\n\n**** Method "+ msg +" not implemented in model "
1025  + int2str(model()) + " ****\n"
1026  "(Did you forget to specify a transport model?)\n\n\n");
1027 
1028  return 0.0;
1029 }
1030 //===================================================================================================================
1031 
1032 }
1033 //======================================================================================================================