Cantera  3.2.0a2
Loading...
Searching...
No Matches
EEDFTwoTermApproximation.cpp
Go to the documentation of this file.
1/**
2 * @file EEDFTwoTermApproximation.cpp
3 * EEDF Two-Term approximation solver. Implementation file for class
4 * EEDFTwoTermApproximation.
5 */
6
7// This file is part of Cantera. See License.txt in the top-level directory or
8// at https://cantera.org/license.txt for license and copyright information.
9
12#include "cantera/numerics/eigen_dense.h"
16
17namespace Cantera
18{
19
20typedef Eigen::SparseMatrix<double> SparseMat;
21
22EEDFTwoTermApproximation::EEDFTwoTermApproximation(PlasmaPhase* s)
23{
24 // store a pointer to s.
25 m_phase = s;
26 m_first_call = true;
27 m_has_EEDF = false;
28 m_gamma = pow(2.0 * ElectronCharge / ElectronMass, 0.5);
29}
30
31void EEDFTwoTermApproximation::setLinearGrid(double& kTe_max, size_t& ncell)
32{
33 m_points = ncell;
34 m_gridCenter.resize(m_points);
35 m_gridEdge.resize(m_points + 1);
36 m_f0.resize(m_points);
37 m_f0_edge.resize(m_points + 1);
38 for (size_t j = 0; j < m_points; j++) {
39 m_gridCenter[j] = kTe_max * ( j + 0.5 ) / m_points;
40 m_gridEdge[j] = kTe_max * j / m_points;
41 }
42 m_gridEdge[m_points] = kTe_max;
43 setGridCache();
44}
45
46int EEDFTwoTermApproximation::calculateDistributionFunction()
47{
48 if (m_first_call) {
50 m_first_call = false;
51 }
52
55
56 if (!m_has_EEDF) {
57 writelog("No existing EEDF. Using first guess method: {}\n", m_firstguess);
58 if (m_firstguess == "maxwell") {
59 writelog("First guess EEDF maxwell\n");
60 for (size_t j = 0; j < m_points; j++) {
61 m_f0(j) = 2.0 * pow(1.0 / Pi, 0.5) * pow(m_init_kTe, -3. / 2.) *
62 exp(-m_gridCenter[j] / m_init_kTe);
63 }
64 } else {
65 throw CanteraError("EEDFTwoTermApproximation::calculateDistributionFunction",
66 " unknown EEDF first guess");
67 }
68 }
69
71
72 // write the EEDF at grid edges
73 vector<double> f(m_f0.data(), m_f0.data() + m_f0.rows() * m_f0.cols());
74 vector<double> x(m_gridCenter.data(), m_gridCenter.data() + m_gridCenter.rows() * m_gridCenter.cols());
75 for (size_t i = 0; i < m_points + 1; i++) {
76 m_f0_edge[i] = linearInterp(m_gridEdge[i], x, f);
77 }
78
79 m_has_EEDF = true;
80
81 // update electron mobility
83 return 0;
84}
85
86void EEDFTwoTermApproximation::converge(Eigen::VectorXd& f0)
87{
88 double err0 = 0.0;
89 double err1 = 0.0;
90 double delta = m_delta0;
91
92 if (m_maxn == 0) {
93 throw CanteraError("EEDFTwoTermApproximation::converge",
94 "m_maxn is zero; no iterations will occur.");
95 }
96 if (m_points == 0) {
97 throw CanteraError("EEDFTwoTermApproximation::converge",
98 "m_points is zero; the EEDF grid is empty.");
99 }
100 if (isnan(delta) || delta == 0.0) {
101 throw CanteraError("EEDFTwoTermApproximation::converge",
102 "m_delta0 is NaN or zero; solver cannot update.");
103 }
104
105 for (size_t n = 0; n < m_maxn; n++) {
106 if (0.0 < err1 && err1 < err0) {
107 delta *= log(m_factorM) / (log(err0) - log(err1));
108 }
109
110 Eigen::VectorXd f0_old = f0;
111 f0 = iterate(f0_old, delta);
112 checkFinite("EEDFTwoTermApproximation::converge: f0", f0.data(), f0.size());
113
114 err0 = err1;
115 Eigen::VectorXd Df0 = (f0_old - f0).cwiseAbs();
116 err1 = norm(Df0, m_gridCenter);
117 if (err1 < m_rtol) {
118 break;
119 } else if (n == m_maxn - 1) {
120 throw CanteraError("WeaklyIonizedGas::converge", "Convergence failed");
121 }
122 }
123}
124
125Eigen::VectorXd EEDFTwoTermApproximation::iterate(const Eigen::VectorXd& f0, double delta)
126{
127 // CQM multiple call to vector_* and matrix_*
128 // probably extremely ineficient
129 // must be refactored!!
130
131 SparseMat PQ(m_points, m_points);
132 vector<double> g = vector_g(f0);
133
134 for (size_t k : m_phase->kInelastic()) {
135 SparseMat Q_k = matrix_Q(g, k);
136 SparseMat P_k = matrix_P(g, k);
137 PQ += (matrix_Q(g, k) - matrix_P(g, k)) * m_X_targets[m_klocTargets[k]];
138 }
139
140 SparseMat A = matrix_A(f0);
141 SparseMat I(m_points, m_points);
142 for (size_t i = 0; i < m_points; i++) {
143 I.insert(i,i) = 1.0;
144 }
145 A -= PQ;
146 A *= delta;
147 A += I;
148
149 // SparseLU :
150 Eigen::SparseLU<SparseMat> solver(A);
151 if (solver.info() == Eigen::NumericalIssue) {
152 throw CanteraError("EEDFTwoTermApproximation::iterate",
153 "Error SparseLU solver: NumericalIssue");
154 } else if (solver.info() == Eigen::InvalidInput) {
155 throw CanteraError("EEDFTwoTermApproximation::iterate",
156 "Error SparseLU solver: InvalidInput");
157 }
158 if (solver.info() != Eigen::Success) {
159 throw CanteraError("EEDFTwoTermApproximation::iterate",
160 "Error SparseLU solver", "Decomposition failed");
161 return f0;
162 }
163
164 // solve f0
165 Eigen::VectorXd f1 = solver.solve(f0);
166 if(solver.info() != Eigen::Success) {
167 throw CanteraError("EEDFTwoTermApproximation::iterate", "Solving failed");
168 return f0;
169 }
170
171 checkFinite("EEDFTwoTermApproximation::converge: f0", f1.data(), f1.size());
172 f1 /= norm(f1, m_gridCenter);
173 return f1;
174}
175
176double EEDFTwoTermApproximation::integralPQ(double a, double b, double u0, double u1,
177 double g, double x0)
178{
179 double A1;
180 double A2;
181 if (g != 0.0) {
182 double expm1a = expm1(g * (-a + x0));
183 double expm1b = expm1(g * (-b + x0));
184 double ag = a * g;
185 double ag1 = ag + 1;
186 double bg = b * g;
187 double bg1 = bg + 1;
188 A1 = (expm1a * ag1 + ag - expm1b * bg1 - bg) / (g*g);
189 A2 = (expm1a * (2 * ag1 + ag * ag) + ag * (ag + 2) -
190 expm1b * (2 * bg1 + bg * bg) - bg * (bg + 2)) / (g*g*g);
191 } else {
192 A1 = 0.5 * (b*b - a*a);
193 A2 = 1.0 / 3.0 * (b*b*b - a*a*a);
194 }
195
196 // The interpolation formula of u(x) = c0 + c1 * x
197 double c0 = (a * u1 - b * u0) / (a - b);
198 double c1 = (u0 - u1) / (a - b);
199
200 return c0 * A1 + c1 * A2;
201}
202
203vector<double> EEDFTwoTermApproximation::vector_g(const Eigen::VectorXd& f0)
204{
205 vector<double> g(m_points, 0.0);
206 const double f_min = 1e-300; // Smallest safe floating-point value
207
208 // Handle first point (i = 0)
209 double f1 = std::max(f0(1), f_min);
210 double f0_ = std::max(f0(0), f_min);
211 g[0] = log(f1 / f0_) / (m_gridCenter[1] - m_gridCenter[0]);
212
213 // Handle last point (i = N)
214 size_t N = m_points - 1;
215 double fN = std::max(f0(N), f_min);
216 double fNm1 = std::max(f0(N - 1), f_min);
217 g[N] = log(fN / fNm1) / (m_gridCenter[N] - m_gridCenter[N - 1]);
218
219 // Handle interior points
220 for (size_t i = 1; i < N; ++i) {
221 double f_up = std::max(f0(i + 1), f_min);
222 double f_down = std::max(f0(i - 1), f_min);
223 g[i] = log(f_up / f_down) / (m_gridCenter[i + 1] - m_gridCenter[i - 1]);
224 }
225 return g;
226}
227
228SparseMat EEDFTwoTermApproximation::matrix_P(const vector<double>& g, size_t k)
229{
230 SparseTriplets tripletList;
231 for (size_t n = 0; n < m_eps[k].size(); n++) {
232 double eps_a = m_eps[k][n][0];
233 double eps_b = m_eps[k][n][1];
234 double sigma_a = m_sigma[k][n][0];
235 double sigma_b = m_sigma[k][n][1];
236 size_t j = m_j[k][n];
237 double r = integralPQ(eps_a, eps_b, sigma_a, sigma_b, g[j], m_gridCenter[j]);
238 double p = m_gamma * r;
239
240 tripletList.emplace_back(j, j, p);
241 }
242 SparseMat P(m_points, m_points);
243 P.setFromTriplets(tripletList.begin(), tripletList.end());
244 return P;
245}
246
247SparseMat EEDFTwoTermApproximation::matrix_Q(const vector<double>& g, size_t k)
248{
249 SparseTriplets tripletList;
250 for (size_t n = 0; n < m_eps[k].size(); n++) {
251 double eps_a = m_eps[k][n][0];
252 double eps_b = m_eps[k][n][1];
253 double sigma_a = m_sigma[k][n][0];
254 double sigma_b = m_sigma[k][n][1];
255 size_t i = m_i[k][n];
256 size_t j = m_j[k][n];
257 double r = integralPQ(eps_a, eps_b, sigma_a, sigma_b, g[j], m_gridCenter[j]);
258 double q = m_inFactor[k] * m_gamma * r;
259
260 tripletList.emplace_back(i, j, q);
261 }
262 SparseMat Q(m_points, m_points);
263 Q.setFromTriplets(tripletList.begin(), tripletList.end());
264 return Q;
265}
266
267SparseMat EEDFTwoTermApproximation::matrix_A(const Eigen::VectorXd& f0)
268{
269 vector<double> a0(m_points + 1);
270 vector<double> a1(m_points + 1);
271 size_t N = m_points - 1;
272 // Scharfetter-Gummel scheme
273 double nu = netProductionFrequency(f0);
274 a0[0] = NAN;
275 a1[0] = NAN;
276 a0[N+1] = NAN;
277 a1[N+1] = NAN;
278
279 double nDensity = m_phase->molarDensity() * Avogadro;
280 double alpha;
281 double E = m_phase->electricField();
282 if (m_growth == "spatial") {
283 double mu = electronMobility(f0);
284 double D = electronDiffusivity(f0);
285 alpha = (mu * E - sqrt(pow(mu * E, 2) - 4 * D * nu * nDensity)) / 2.0 / D / nDensity;
286 } else {
287 alpha = 0.0;
288 }
289
290 double sigma_tilde;
291 double omega = 2 * Pi * m_phase->electricFieldFrequency();
292 for (size_t j = 1; j < m_points; j++) {
293 if (m_growth == "temporal") {
294 sigma_tilde = m_totalCrossSectionEdge[j] + nu / pow(m_gridEdge[j], 0.5) / m_gamma;
295 } else {
296 sigma_tilde = m_totalCrossSectionEdge[j];
297 }
298 double q = omega / (nDensity * m_gamma * pow(m_gridEdge[j], 0.5));
299 double W = -m_gamma * m_gridEdge[j] * m_gridEdge[j] * m_sigmaElastic[j];
300 double F = sigma_tilde * sigma_tilde / (sigma_tilde * sigma_tilde + q * q);
301 double DA = m_gamma / 3.0 * pow(E / nDensity, 2.0) * m_gridEdge[j];
302 double DB = m_gamma * m_phase->temperature() * Boltzmann / ElectronCharge * m_gridEdge[j] * m_gridEdge[j] * m_sigmaElastic[j];
303 double D = DA / sigma_tilde * F + DB;
304 if (m_growth == "spatial") {
305 W -= m_gamma / 3.0 * 2 * alpha * E / nDensity * m_gridEdge[j] / sigma_tilde;
306 }
307
308 double z = W * (m_gridCenter[j] - m_gridCenter[j-1]) / D;
309 if (!std::isfinite(z)) {
310 throw CanteraError("matrix_A", "Non-finite Peclet number encountered");
311 }
312 if (std::abs(z) > 500) {
313 writelog("Warning: Large Peclet number z = {:.3e} at j = {}. W = {:.3e}, D = {:.3e}, E/N = {:.3e}\n",
314 z, j, W, D, E / nDensity);
315 }
316 a0[j] = W / (1 - std::exp(-z));
317 a1[j] = W / (1 - std::exp(z));
318 }
319
320 SparseTriplets tripletList;
321 // center diagonal
322 // zero flux b.c. at energy = 0
323 tripletList.emplace_back(0, 0, a0[1]);
324
325 for (size_t j = 1; j < m_points - 1; j++) {
326 tripletList.emplace_back(j, j, a0[j+1] - a1[j]);
327 }
328
329 // upper diagonal
330 for (size_t j = 0; j < m_points - 1; j++) {
331 tripletList.emplace_back(j, j+1, a1[j+1]);
332 }
333
334 // lower diagonal
335 for (size_t j = 1; j < m_points; j++) {
336 tripletList.emplace_back(j, j-1, -a0[j]);
337 }
338
339 // zero flux b.c.
340 tripletList.emplace_back(N, N, -a1[N]);
341
342 SparseMat A(m_points, m_points);
343 A.setFromTriplets(tripletList.begin(), tripletList.end());
344
345 //plus G
346 SparseMat G(m_points, m_points);
347 if (m_growth == "temporal") {
348 for (size_t i = 0; i < m_points; i++) {
349 G.insert(i, i) = 2.0 / 3.0 * (pow(m_gridEdge[i+1], 1.5) - pow(m_gridEdge[i], 1.5)) * nu;
350 }
351 } else if (m_growth == "spatial") {
352 double nDensity = m_phase->molarDensity() * Avogadro;
353 for (size_t i = 0; i < m_points; i++) {
354 double sigma_c = 0.5 * (m_totalCrossSectionEdge[i] + m_totalCrossSectionEdge[i + 1]);
355 G.insert(i, i) = - alpha * m_gamma / 3 * (alpha * (pow(m_gridEdge[i + 1], 2) - pow(m_gridEdge[i], 2)) / sigma_c / 2
356 - E / nDensity * (m_gridEdge[i + 1] / m_totalCrossSectionEdge[i + 1] - m_gridEdge[i] / m_totalCrossSectionEdge[i]));
357 }
358 }
359 return A + G;
360}
361
363{
364 double nu = 0.0;
365 vector<double> g = vector_g(f0);
366
367 for (size_t k = 0; k < m_phase->nCollisions(); k++) {
368 if (m_phase->collisionRate(k)->kind() == "ionization" ||
369 m_phase->collisionRate(k)->kind() == "attachment") {
370 SparseMat PQ = (matrix_Q(g, k) - matrix_P(g, k)) *
372 Eigen::VectorXd s = PQ * f0;
373 checkFinite("EEDFTwoTermApproximation::netProductionFrequency: s",
374 s.data(), s.size());
375 nu += s.sum();
376 }
377 }
378 return nu;
379}
380
381double EEDFTwoTermApproximation::electronDiffusivity(const Eigen::VectorXd& f0)
382{
383 vector<double> y(m_points, 0.0);
384 double nu = netProductionFrequency(f0);
385 for (size_t i = 0; i < m_points; i++) {
386 if (m_gridCenter[i] != 0.0) {
387 y[i] = m_gridCenter[i] * f0(i) /
388 (m_totalCrossSectionCenter[i] + nu / m_gamma / pow(m_gridCenter[i], 0.5));
389 }
390 }
391 double nDensity = m_phase->molarDensity() * Avogadro;
392 auto f = Eigen::Map<const Eigen::ArrayXd>(y.data(), y.size());
393 auto x = Eigen::Map<const Eigen::ArrayXd>(m_gridCenter.data(), m_gridCenter.size());
394 return 1./3. * m_gamma * simpson(f, x) / nDensity;
395}
396
397double EEDFTwoTermApproximation::electronMobility(const Eigen::VectorXd& f0)
398{
399 double nu = netProductionFrequency(f0);
400 vector<double> y(m_points + 1, 0.0);
401 for (size_t i = 1; i < m_points; i++) {
402 // calculate df0 at i-1/2
403 double df0 = (f0(i) - f0(i-1)) / (m_gridCenter[i] - m_gridCenter[i-1]);
404 if (m_gridEdge[i] != 0.0) {
405 y[i] = m_gridEdge[i] * df0 /
406 (m_totalCrossSectionEdge[i] + nu / m_gamma / pow(m_gridEdge[i], 0.5));
407 }
408 }
409 double nDensity = m_phase->molarDensity() * Avogadro;
410 auto f = ConstMappedVector(y.data(), y.size());
411 auto x = ConstMappedVector(m_gridEdge.data(), m_gridEdge.size());
412 return -1./3. * m_gamma * simpson(f, x) / nDensity;
413}
414
416{
417 // set up target index
418 m_kTargets.resize(m_phase->nCollisions());
420 m_inFactor.resize(m_phase->nCollisions());
421 for (size_t k = 0; k < m_phase->nCollisions(); k++) {
423 // Check if it is a new target or not :
424 auto it = find(m_k_lg_Targets.begin(), m_k_lg_Targets.end(), m_kTargets[k]);
425
426 if (it == m_k_lg_Targets.end()){
427 m_k_lg_Targets.push_back(m_kTargets[k]);
428 m_klocTargets[k] = m_k_lg_Targets.size() - 1;
429 } else {
430 m_klocTargets[k] = distance(m_k_lg_Targets.begin(), it);
431 }
432
433 const auto& kind = m_phase->collisionRate(k)->kind();
434
435 if (kind == "ionization") {
436 m_inFactor[k] = 2;
437 } else if (kind == "attachment") {
438 m_inFactor[k] = 0;
439 } else {
440 m_inFactor[k] = 1;
441 }
442 }
443
444 m_X_targets.resize(m_k_lg_Targets.size());
445 m_X_targets_prev.resize(m_k_lg_Targets.size());
446 for (size_t k = 0; k < m_X_targets.size(); k++) {
447 size_t k_glob = m_k_lg_Targets[k];
448 m_X_targets[k] = m_phase->moleFraction(k_glob);
450 }
451
452 // set up indices of species which has no cross-section data
453 for (size_t k = 0; k < m_phase->nSpecies(); k++) {
454 auto it = std::find(m_kTargets.begin(), m_kTargets.end(), k);
455 if (it == m_kTargets.end()) {
456 m_kOthers.push_back(k);
457 }
458 }
459}
460
462{
463 // Compute sigma_m and sigma_\epsilon
466}
467
468// Update the species mole fractions used for EEDF computation
470{
471 double tmp_sum = 0.0;
472 for (size_t k = 0; k < m_X_targets.size(); k++) {
474 tmp_sum = tmp_sum + m_phase->moleFraction(m_k_lg_Targets[k]);
475 }
476
477 // Normalize the mole fractions to unity:
478 for (size_t k = 0; k < m_X_targets.size(); k++) {
479 m_X_targets[k] = m_X_targets[k] / tmp_sum;
480 }
481}
482
484{
486 m_totalCrossSectionEdge.assign(m_points + 1, 0.0);
487 for (size_t k = 0; k < m_phase->nCollisions(); k++) {
488 auto& x = m_phase->collisionRate(k)->energyLevels();
489 auto& y = m_phase->collisionRate(k)->crossSections();
490
491 for (size_t i = 0; i < m_points; i++) {
493 linearInterp(m_gridCenter[i], x, y);
494 }
495 for (size_t i = 0; i < m_points + 1; i++) {
497 linearInterp(m_gridEdge[i], x, y);
498 }
499 }
500}
501
503{
504 m_sigmaElastic.clear();
505 m_sigmaElastic.resize(m_points, 0.0);
506 for (size_t k : m_phase->kElastic()) {
507 auto& x = m_phase->collisionRate(k)->energyLevels();
508 auto& y = m_phase->collisionRate(k)->crossSections();
509 // Note:
510 // moleFraction(m_kTargets[k]) <=> m_X_targets[m_klocTargets[k]]
511 double mass_ratio = ElectronMass / (m_phase->molecularWeight(m_kTargets[k]) / Avogadro);
512 for (size_t i = 0; i < m_points; i++) {
513 m_sigmaElastic[i] += 2.0 * mass_ratio * m_X_targets[m_klocTargets[k]] *
514 linearInterp(m_gridEdge[i], x, y);
515 }
516 }
517}
518
519void EEDFTwoTermApproximation::setGridCache()
520{
521 m_sigma.clear();
522 m_sigma.resize(m_phase->nCollisions());
523 m_eps.clear();
524 m_eps.resize(m_phase->nCollisions());
525 m_j.clear();
526 m_j.resize(m_phase->nCollisions());
527 m_i.clear();
528 m_i.resize(m_phase->nCollisions());
529 for (size_t k = 0; k < m_phase->nCollisions(); k++) {
530 auto& collision = m_phase->collisionRate(k);
531 auto& x = collision->energyLevels();
532 auto& y = collision->crossSections();
533 vector<double> eps1(m_points + 1);
534 int shiftFactor = (collision->kind() == "ionization") ? 2 : 1;
535
536 for (size_t i = 0; i < m_points + 1; i++) {
537 eps1[i] = clip(shiftFactor * m_gridEdge[i] + collision->threshold(),
538 m_gridEdge[0] + 1e-9, m_gridEdge[m_points] - 1e-9);
539 }
540 vector<double> nodes = eps1;
541 for (size_t i = 0; i < m_points + 1; i++) {
542 if (m_gridEdge[i] >= eps1[0] && m_gridEdge[i] <= eps1[m_points]) {
543 nodes.push_back(m_gridEdge[i]);
544 }
545 }
546 for (size_t i = 0; i < x.size(); i++) {
547 if (x[i] >= eps1[0] && x[i] <= eps1[m_points]) {
548 nodes.push_back(x[i]);
549 }
550 }
551
552 std::sort(nodes.begin(), nodes.end());
553 auto last = std::unique(nodes.begin(), nodes.end());
554 nodes.resize(std::distance(nodes.begin(), last));
555 vector<double> sigma0(nodes.size());
556 for (size_t i = 0; i < nodes.size(); i++) {
557 sigma0[i] = linearInterp(nodes[i], x, y);
558 }
559
560 // search position of cell j
561 for (size_t i = 1; i < nodes.size(); i++) {
562 auto low = std::lower_bound(m_gridEdge.begin(), m_gridEdge.end(), nodes[i]);
563 m_j[k].push_back(low - m_gridEdge.begin() - 1);
564 }
565
566 // search position of cell i
567 for (size_t i = 1; i < nodes.size(); i++) {
568 auto low = std::lower_bound(eps1.begin(), eps1.end(), nodes[i]);
569 m_i[k].push_back(low - eps1.begin() - 1);
570 }
571
572 // construct sigma
573 for (size_t i = 0; i < nodes.size() - 1; i++) {
574 m_sigma[k].push_back({sigma0[i], sigma0[i+1]});
575 }
576
577 // construct eps
578 for (size_t i = 0; i < nodes.size() - 1; i++) {
579 m_eps[k].push_back({nodes[i], nodes[i+1]});
580 }
581
582 // construct sigma_offset
583 auto x_offset = collision->energyLevels();
584 for (auto& element : x_offset) {
585 element -= collision->threshold();
586 }
587 }
588}
589
590double EEDFTwoTermApproximation::norm(const Eigen::VectorXd& f, const Eigen::VectorXd& grid)
591{
592 string m_quadratureMethod = "simpson";
593 Eigen::VectorXd p(f.size());
594 for (int i = 0; i < f.size(); i++) {
595 p[i] = f(i) * pow(grid[i], 0.5);
596 }
597 return numericalQuadrature(m_quadratureMethod, p, grid);
598}
599
600}
EEDF Two-Term approximation solver.
Header for plasma reaction rates parameterized by electron collision cross section and electron energ...
Header file for class PlasmaPhase.
Base class for exceptions thrown by Cantera classes.
double m_rtol
Error tolerance for convergence.
Eigen::VectorXd m_f0
normalized electron energy distribution function
vector< double > m_gridEdge
Grid of electron energy (cell boundary i-1/2) [eV].
vector< vector< size_t > > m_i
Location of cell i for grid cache.
void calculateTotalCrossSection()
Compute the total (elastic + inelastic) cross section.
vector< vector< size_t > > m_j
Location of cell j for grid cache.
vector< double > m_X_targets_prev
Previous mole fraction of targets used to compute eedf.
vector< vector< vector< double > > > m_eps
The energy boundaries of the overlap of cell i and j.
vector< vector< vector< double > > > m_sigma
Cross section at the boundaries of the overlap of cell i and j.
vector< size_t > m_k_lg_Targets
Local to global indices.
Eigen::SparseMatrix< double > matrix_Q(const vector< double > &g, size_t k)
The matrix of scattering-in.
bool m_first_call
First call to calculateDistributionFunction.
void converge(Eigen::VectorXd &f0)
Iterate f0 (EEDF) until convergence.
double m_delta0
Formerly options for the EEDF solver.
double electronDiffusivity(const Eigen::VectorXd &f0)
Diffusivity.
PlasmaPhase * m_phase
Pointer to the PlasmaPhase object used to initialize this object.
double norm(const Eigen::VectorXd &f, const Eigen::VectorXd &grid)
Compute the L1 norm of a function f defined over a given energy grid.
void updateMoleFractions()
Update the vector of species mole fractions.
vector< size_t > m_kTargets
list of target species indices in global Cantera numbering (1 index per cs)
double electronMobility(const Eigen::VectorXd &f0)
Mobility.
Eigen::VectorXd m_gridCenter
Grid of electron energy (cell center) [eV].
size_t m_maxn
Maximum number of iterations.
Eigen::SparseMatrix< double > matrix_A(const Eigen::VectorXd &f0)
Matrix A (Ax = b) of the equation of EEDF, which is discretized by the exponential scheme of Scharfet...
Eigen::VectorXd iterate(const Eigen::VectorXd &f0, double delta)
An iteration of solving electron energy distribution function.
double m_electronMobility
Electron mobility [m²/V·s].
size_t m_points
The number of points in the EEDF grid.
vector< size_t > m_kOthers
Indices of species which has no cross-section data.
double m_factorM
The factor for step size change.
void calculateTotalElasticCrossSection()
Compute the total elastic collision cross section.
void updateCrossSections()
Update the total cross sections based on the current state.
void initSpeciesIndexCrossSections()
Initialize species indices associated with cross-section data.
double m_init_kTe
The initial electron temperature [eV].
Eigen::SparseMatrix< double > matrix_P(const vector< double > &g, size_t k)
The matrix of scattering-out.
double netProductionFrequency(const Eigen::VectorXd &f0)
Reduced net production frequency.
std::string m_firstguess
The first guess for the EEDF.
std::string m_growth
The growth model of EEDF.
vector< double > m_totalCrossSectionEdge
Total electron cross section on the cell boundary (i-1/2) of energy grid.
vector< double > m_f0_edge
EEDF at grid edges (cell boundaries)
vector< size_t > m_klocTargets
list of target species indices in local X EEDF numbering (1 index per cs)
vector< double > m_X_targets
Mole fraction of targets.
double integralPQ(double a, double b, double u0, double u1, double g, double x0)
The integral in [a, b] of assuming that u is linear with u(a) = u0 and u(b) = u1.
vector< double > m_totalCrossSectionCenter
Total electron cross section on the cell center of energy grid.
vector< double > vector_g(const Eigen::VectorXd &f0)
Vector g is used by matrix_P() and matrix_Q().
vector< double > m_sigmaElastic
vector of total elastic cross section weighted with mass ratio
virtual double molarDensity() const
Molar density (kmol/m^3).
Definition Phase.cpp:576
size_t nSpecies() const
Returns the number of species in the phase.
Definition Phase.h:232
double temperature() const
Temperature (K).
Definition Phase.h:563
double moleFraction(size_t k) const
Return the mole fraction of a single species.
Definition Phase.cpp:439
double molecularWeight(size_t k) const
Molecular weight of species k.
Definition Phase.cpp:383
Base class for handling plasma properties, specifically focusing on the electron energy distribution.
Definition PlasmaPhase.h:84
double electricFieldFrequency() const
Get the frequency of the applied electric field [Hz].
size_t nCollisions() const
Number of electron collision cross sections.
double electricField() const
Get the applied electric field strength [V/m].
const vector< size_t > & kElastic() const
Get the indices for elastic electron collisions.
const shared_ptr< ElectronCollisionPlasmaRate > collisionRate(size_t i) const
Get the ElectronCollisionPlasmaRate object associated with electron collision i.
size_t targetIndex(size_t i) const
target of a specific process
const vector< size_t > & kInelastic() const
Get the indicies for inelastic electron collisions.
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
Header for a file containing miscellaneous numerical functions.
void writelog(const string &fmt, const Args &... args)
Write a formatted message to the screen.
Definition global.h:171
T clip(const T &value, const T &lower, const T &upper)
Clip value such that lower <= value <= upper.
Definition global.h:332
double linearInterp(double x, const vector< double > &xpts, const vector< double > &fpts)
Linearly interpolate a function defined on a discrete grid.
Definition funcs.cpp:13
double numericalQuadrature(const string &method, const Eigen::ArrayXd &f, const Eigen::ArrayXd &x)
Numerical integration of a function.
Definition funcs.cpp:116
double simpson(const Eigen::ArrayXd &f, const Eigen::ArrayXd &x)
Numerical integration of a function using Simpson's rule with flexibility of taking odd and even numb...
Definition funcs.cpp:91
const double Boltzmann
Boltzmann constant [J/K].
Definition ct_defs.h:84
const double Avogadro
Avogadro's Number [number/kmol].
Definition ct_defs.h:81
const double ElectronCharge
Elementary charge [C].
Definition ct_defs.h:90
const double Pi
Pi.
Definition ct_defs.h:68
const double ElectronMass
Electron Mass [kg].
Definition ct_defs.h:111
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
void checkFinite(const double tmp)
Check to see that a number is finite (not NaN, +Inf or -Inf)