8#include "cantera/oneD/refine.h"
20IonFlow::IonFlow(IdealGasPhase* ph,
size_t nsp,
size_t points) :
21 StFlow(ph, nsp, points),
22 m_import_electron_transport(false),
27 for (
size_t k = 0; k < m_nsp; k++) {
28 m_speciesCharge.push_back(m_thermo->charge(k));
32 for (
size_t k = 0; k < m_nsp; k++){
33 if (m_speciesCharge[k] != 0){
34 m_kCharge.push_back(k);
36 m_kNeutral.push_back(k);
41 if (m_thermo->speciesIndex(
"E") !=
npos ) {
42 m_kElectron = m_thermo->speciesIndex(
"E");
46 setBounds(c_offset_E, -1.0e20, 1.0e20);
51 for (
size_t k : m_kCharge) {
52 setBounds(c_offset_Y + k, -1e-14, 1.0);
54 setBounds(c_offset_Y + m_kElectron, -1e-18, 1.0);
56 m_refiner->setActive(c_offset_E,
false);
57 m_mobility.resize(m_nsp*m_points);
58 m_do_electric_field.resize(m_points,
false);
61void IonFlow::resize(
size_t components,
size_t points){
62 StFlow::resize(components, points);
63 m_mobility.resize(m_nsp*m_points);
64 m_do_species.resize(m_nsp,
true);
65 m_do_electric_field.resize(m_points,
false);
68bool IonFlow::componentActive(
size_t n)
const
70 if (n == c_offset_E) {
73 return StFlow::componentActive(n);
77void IonFlow::updateTransport(
double* x,
size_t j0,
size_t j1)
79 StFlow::updateTransport(x,j0,j1);
80 for (
size_t j = j0; j < j1; j++) {
81 setGasAtMidpoint(x,j);
82 m_trans->getMobilities(&m_mobility[j*m_nsp]);
83 if (m_import_electron_transport) {
84 size_t k = m_kElectron;
85 double tlog = log(m_thermo->temperature());
86 m_mobility[k+m_nsp*j] =
poly5(tlog, m_mobi_e_fix.data());
87 m_diff[k+m_nsp*j] =
poly5(tlog, m_diff_e_fix.data());
92void IonFlow::updateDiffFluxes(
const double* x,
size_t j0,
size_t j1)
95 frozenIonMethod(x,j0,j1);
98 electricFieldMethod(x,j0,j1);
102void IonFlow::frozenIonMethod(
const double* x,
size_t j0,
size_t j1)
104 for (
size_t j = j0; j < j1; j++) {
105 double wtm = m_wtm[j];
106 double rho = density(j);
107 double dz = z(j+1) - z(j);
109 for (
size_t k : m_kNeutral) {
110 m_flux(k,j) = m_wt[k]*(rho*m_diff[k+m_nsp*j]/wtm);
111 m_flux(k,j) *= (X(x,k,j) - X(x,k,j+1))/dz;
116 for (
size_t k : m_kNeutral) {
117 m_flux(k,j) += sum*Y(x,k,j);
123 for (
size_t k : m_kCharge) {
129void IonFlow::electricFieldMethod(
const double* x,
size_t j0,
size_t j1)
131 for (
size_t j = j0; j < j1; j++) {
132 double wtm = m_wtm[j];
133 double rho = density(j);
134 double dz = z(j+1) - z(j);
138 for (
size_t k = 0; k < m_nsp; k++) {
139 m_flux(k,j) = m_wt[k]*(rho*m_diff[k+m_nsp*j]/wtm);
140 m_flux(k,j) *= (X(x,k,j) - X(x,k,j+1))/dz;
145 double E_ambi = E(x,j);
146 for (
size_t k : m_kCharge) {
147 double Yav = 0.5 * (Y(x,k,j) + Y(x,k,j+1));
148 double drift = rho * Yav * E_ambi
149 * m_speciesCharge[k] * m_mobility[k+m_nsp*j];
150 m_flux(k,j) += drift;
154 double sum_flux = 0.0;
155 for (
size_t k = 0; k < m_nsp; k++) {
156 sum_flux -= m_flux(k,j);
158 double sum_ion = 0.0;
159 for (
size_t k : m_kCharge) {
163 for (
size_t k : m_kNeutral) {
164 m_flux(k,j) += Y(x,k,j) / (1-sum_ion) * sum_flux;
169void IonFlow::setSolvingStage(
const size_t stage)
171 if (stage == 1 || stage == 2) {
175 "solution stage must be set to: "
176 "1) frozenIonMethod, "
177 "2) electricFieldEqnMethod");
181void IonFlow::evalResidual(
double* x,
double* rsd,
int* diag,
182 double rdt,
size_t jmin,
size_t jmax)
184 StFlow::evalResidual(x, rsd, diag, rdt, jmin, jmax);
189 for (
size_t j = jmin; j <= jmax; j++) {
194 for (
size_t k : m_kCharge) {
195 rsd[index(c_offset_Y + k, 0)] = Y(x,k,0) - Y(x,k,1);
197 rsd[index(c_offset_E, j)] = E(x,0);
198 diag[index(c_offset_E, j)] = 0;
199 }
else if (j == m_points - 1) {
200 rsd[index(c_offset_E, j)] = dEdz(x,j) - rho_e(x,j) /
epsilon_0;
201 diag[index(c_offset_E, j)] = 0;
210 rsd[index(c_offset_E, j)] = dEdz(x,j) - rho_e(x,j) /
epsilon_0;
211 diag[index(c_offset_E, j)] = 0;
216void IonFlow::solveElectricField(
size_t j)
218 bool changed =
false;
220 for (
size_t i = 0; i < m_points; i++) {
221 if (!m_do_electric_field[i]) {
224 m_do_electric_field[i] =
true;
227 if (!m_do_electric_field[j]) {
230 m_do_electric_field[j] =
true;
232 m_refiner->setActive(c_offset_U,
true);
233 m_refiner->setActive(c_offset_V,
true);
234 m_refiner->setActive(c_offset_T,
true);
235 m_refiner->setActive(c_offset_E,
true);
241void IonFlow::fixElectricField(
size_t j)
243 bool changed =
false;
245 for (
size_t i = 0; i < m_points; i++) {
246 if (m_do_electric_field[i]) {
249 m_do_electric_field[i] =
false;
252 if (m_do_electric_field[j]) {
255 m_do_electric_field[j] =
false;
257 m_refiner->setActive(c_offset_U,
false);
258 m_refiner->setActive(c_offset_V,
false);
259 m_refiner->setActive(c_offset_T,
false);
260 m_refiner->setActive(c_offset_E,
false);
269 m_import_electron_transport =
true;
271 size_t n = tfix.size();
273 for (
size_t i = 0; i < n; i++) {
274 tlog.push_back(log(tfix[i]));
277 m_diff_e_fix.resize(degree + 1);
278 m_mobi_e_fix.resize(degree + 1);
279 polyfit(n, degree, tlog.data(), diff_e.data(), w.data(), m_diff_e_fix.data());
280 polyfit(n, degree, tlog.data(), mobi_e.data(), w.data(), m_mobi_e_fix.data());
283void IonFlow::_finalize(
const double* x)
285 StFlow::_finalize(x);
287 bool p = m_do_electric_field[0];
289 solveElectricField();
Headers for the Transport object, which is the virtual base class for all transport property evaluato...
Base class for exceptions thrown by Cantera classes.
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data.
Header for a file containing miscellaneous numerical functions.
Namespace for the Cantera kernel.
const size_t npos
index returned by functions to indicate "no position"
R poly5(D x, R *c)
Templated evaluation of a polynomial of order 5.
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
const double epsilon_0
Permittivity of free space [F/m].
double polyfit(size_t n, size_t deg, const double *x, const double *y, const double *w, double *p)
Fits a polynomial function to a set of data points.
Various templated functions that carry out common vector operations (see Templated Utility Functions)...