Cantera  2.0
MixTransport.cpp
Go to the documentation of this file.
1 /**
2  * @file MixTransport.cpp
3  * Mixture-averaged transport properties for ideal gas mixtures.
4  */
5 // copyright 2001 California Institute of Technology
6 
9 
10 #include "cantera/base/utilities.h"
14 
15 #include <iostream>
16 using namespace std;
17 
18 /**
19  * Mole fractions below MIN_X will be set to MIN_X when computing
20  * transport properties.
21  */
22 #ifndef MIN_X
23 #define MIN_X 1.e-20
24 #endif
25 
26 namespace Cantera
27 {
28 
29 //====================================================================================================================
30 MixTransport::MixTransport() :
31  m_condcoeffs(0),
32  m_cond(0),
33  m_lambda(0.0),
34  m_spcond_ok(false),
35  m_condmix_ok(false),
36  m_eps(0),
37  m_diam(0, 0),
38  m_dipoleDiag(0),
39  m_alpha(0),
40  m_crot(0),
41  m_zrot(0),
42  m_debug(false)
43 {
44 }
45 //====================================================================================================================
47  GasTransport(right),
48  m_condcoeffs(0),
49  m_cond(0),
50  m_lambda(0.0),
51  m_spcond_ok(false),
52  m_condmix_ok(false),
53  m_eps(0),
54  m_diam(0, 0),
55  m_dipoleDiag(0),
56  m_alpha(0),
57  m_crot(0),
58  m_zrot(0),
59  m_debug(false)
60 {
61  *this = right;
62 }
63 //====================================================================================================================
64 // Assignment operator
65 /*
66  * This is NOT a virtual function.
67  *
68  * @param right Reference to %LiquidTransport object to be copied
69  * into the current one.
70  */
72 {
73  if (&right == this) {
74  return *this;
75  }
76  GasTransport::operator=(right);
77 
78  m_condcoeffs = right.m_condcoeffs;
79  m_cond = right.m_cond;
80  m_lambda = right.m_lambda;
81  m_spcond_ok = right.m_spcond_ok;
82  m_condmix_ok = right.m_condmix_ok;
83  m_eps = right.m_eps;
84  m_diam = right.m_diam;
85  m_dipoleDiag = right.m_dipoleDiag;
86  m_alpha = right.m_alpha;
87  m_crot = right.m_crot;
88  m_zrot = right.m_zrot;
89  m_debug = right.m_debug;
90 
91  return *this;
92 }
93 //====================================================================================================================
94 // Duplication routine for objects which inherit from %Transport
95 /*
96  * This virtual routine can be used to duplicate %Transport objects
97  * inherited from %Transport even if the application only has
98  * a pointer to %Transport to work with.
99  *
100  * These routines are basically wrappers around the derived copy
101  * constructor.
102  */
104 {
105  MixTransport* tr = new MixTransport(*this);
106  return (dynamic_cast<Transport*>(tr));
107 }
108 
109 //====================================================================================================================
111 {
113 
114  // copy polynomials and parameters into local storage
116 
117  m_zrot = tr.zrot;
118  m_crot = tr.crot;
119  m_diam = tr.diam;
120  m_eps = tr.eps;
121  m_alpha = tr.alpha;
122  m_dipoleDiag.resize(m_nsp);
123  for (size_t i = 0; i < m_nsp; i++) {
124  m_dipoleDiag[i] = tr.dipole(i,i);
125  }
126 
127  m_cond.resize(m_nsp);
128 
129  // set flags all false
130  m_spcond_ok = false;
131  m_condmix_ok = false;
132 
133  return true;
134 }
135 
136 //===================================================================================================================
137 void MixTransport::getMobilities(doublereal* const mobil)
138 {
140  doublereal c1 = ElectronCharge / (Boltzmann * m_temp);
141  for (size_t k = 0; k < m_nsp; k++) {
142  mobil[k] = c1 * m_spwork[k];
143  }
144 }
145 //===================================================================================================================
146 // Returns the mixture thermal conductivity (W/m /K)
147 /*
148  * The thermal conductivity is computed from the following mixture rule:
149  * \f[
150  * \lambda = 0.5 \left( \sum_k X_k \lambda_k + \frac{1}{\sum_k X_k/\lambda_k} \right)
151  * \f]
152  *
153  * It's used to compute the flux of energy due to a thermal gradient
154  *
155  * \f[
156  * j_T = - \lambda \nabla T
157  * \f]
158  *
159  * The flux of energy has units of energy (kg m2 /s2) per second per area.
160  *
161  * The units of lambda are W / m K which is equivalent to kg m / s^3 K.
162  *
163  * @return Returns the mixture thermal conductivity, with units of W/m/K
164  */
166 {
167  update_T();
168  update_C();
169 
170  if (!m_spcond_ok) {
171  updateCond_T();
172  }
173  if (!m_condmix_ok) {
174  doublereal sum1 = 0.0, sum2 = 0.0;
175  for (size_t k = 0; k < m_nsp; k++) {
176  sum1 += m_molefracs[k] * m_cond[k];
177  sum2 += m_molefracs[k] / m_cond[k];
178  }
179  m_lambda = 0.5*(sum1 + 1.0/sum2);
180  m_condmix_ok = true;
181  }
182  return m_lambda;
183 }
184 //===================================================================================================================
185 // Return the thermal diffusion coefficients
186 /*
187  * For this approximation, these are all zero.
188  *
189  * Eqns. (12.168) shows how they are used in an expression for the species flux.
190  *
191  * @param dt Vector of thermal diffusion coefficients. Units = kg/m/s
192  */
193 void MixTransport::getThermalDiffCoeffs(doublereal* const dt)
194 {
195  for (size_t k = 0; k < m_nsp; k++) {
196  dt[k] = 0.0;
197  }
198 }
199 //===================================================================================================================
200 // Get the species diffusive mass fluxes wrt to the mass averaged velocity,
201 // given the gradients in mole fraction and temperature
202 /*
203  * Units for the returned fluxes are kg m-2 s-1.
204  *
205  *
206  * The diffusive mass flux of species \e k is computed from
207  * \f[
208  * \vec{j}_k = -n M_k D_k \nabla X_k.
209  * \f]
210  *
211  * @param ndim Number of dimensions in the flux expressions
212  * @param grad_T Gradient of the temperature
213  * (length = ndim)
214  * @param ldx Leading dimension of the grad_X array
215  * (usually equal to m_nsp but not always)
216  * @param grad_X Gradients of the mole fraction
217  * Flat vector with the m_nsp in the inner loop.
218  * length = ldx * ndim
219  * @param ldf Leading dimension of the fluxes array
220  * (usually equal to m_nsp but not always)
221  * @param fluxes Output of the diffusive mass fluxes
222  * Flat vector with the m_nsp in the inner loop.
223  * length = ldx * ndim
224  */
225 void MixTransport::getSpeciesFluxes(size_t ndim, const doublereal* const grad_T,
226  size_t ldx, const doublereal* const grad_X,
227  size_t ldf, doublereal* const fluxes)
228 {
229  update_T();
230  update_C();
231 
233 
234  const vector_fp& mw = m_thermo->molecularWeights();
235  const doublereal* y = m_thermo->massFractions();
236  doublereal rhon = m_thermo->molarDensity();
237 
238  vector_fp sum(ndim,0.0);
239  for (size_t n = 0; n < ndim; n++) {
240  for (size_t k = 0; k < m_nsp; k++) {
241  fluxes[n*ldf + k] = -rhon * mw[k] * m_spwork[k] * grad_X[n*ldx + k];
242  sum[n] += fluxes[n*ldf + k];
243  }
244  }
245  // add correction flux to enforce sum to zero
246  for (size_t n = 0; n < ndim; n++) {
247  for (size_t k = 0; k < m_nsp; k++) {
248  fluxes[n*ldf + k] -= y[k]*sum[n];
249  }
250  }
251 }
252 
253 //===========================================================================================================
254 /*
255  * @internal This is called whenever a transport property is
256  * requested from ThermoSubstance if the temperature has changed
257  * since the last call to update_T.
258  */
260 {
261  doublereal t = m_thermo->temperature();
262  if (t == m_temp) {
263  return;
264  }
265  if (t < 0.0) {
266  throw CanteraError("MixTransport::update_T",
267  "negative temperature "+fp2str(t));
268  }
269  GasTransport::update_T();
270  // temperature has changed, so polynomial fits will need to be redone.
271  m_spcond_ok = false;
272  m_bindiff_ok = false;
273  m_condmix_ok = false;
274 }
275 //====================================================================================================================
276 /*
277  * @internal This is called the first time any transport property
278  * is requested from Mixture after the concentrations
279  * have changed.
280  */
282 {
283  // signal that concentration-dependent quantities will need to
284  // be recomputed before use, and update the local mole
285  // fractions.
286 
287  m_visc_ok = false;
288  m_condmix_ok = false;
289 
291 
292  // add an offset to avoid a pure species condition
293  for (size_t k = 0; k < m_nsp; k++) {
295  }
296 }
297 //====================================================================================================================
298 /*
299  * Update the temperature-dependent parts of the mixture-averaged
300  * thermal conductivity.
301  */
303 {
304  if (m_mode == CK_Mode) {
305  for (size_t k = 0; k < m_nsp; k++) {
306  m_cond[k] = exp(dot4(m_polytempvec, m_condcoeffs[k]));
307  }
308  } else {
309  for (size_t k = 0; k < m_nsp; k++) {
311  }
312  }
313  m_spcond_ok = true;
314  m_condmix_ok = false;
315 }
316 
317 //====================================================================================================================
318 /*
319  * This function returns a Transport data object for a given species.
320  *
321  */
322 struct GasTransportData MixTransport::getGasTransportData(int kSpecies) const {
323 
324  struct GasTransportData td;
325  td.speciesName = m_thermo->speciesName(kSpecies);
326 
327  td.geometry = 2;
328  if (m_crot[kSpecies] == 0.0) {
329  td.geometry = 0;
330  } else if (m_crot[kSpecies] == 1.0) {
331  td.geometry = 1;
332  }
333  td.wellDepth = m_eps[kSpecies] / Boltzmann;
334  td.dipoleMoment = m_dipoleDiag[kSpecies] * 1.0E25 / SqrtTen;
335  td.diameter = m_diam(kSpecies, kSpecies) * 1.0E10;
336  td.polarizability = m_alpha[kSpecies] * 1.0E30;
337  td.rotRelaxNumber = m_zrot[kSpecies];
338 
339  return td;
340 }
341 //====================================================================================================================
342 }