18 IonFlow::IonFlow(IdealGasPhase* ph,
size_t nsp,
size_t points) :
19 StFlow(ph, nsp, points),
20 m_import_electron_transport(false),
25 for (
size_t k = 0; k < m_nsp; k++) {
26 m_speciesCharge.push_back(m_thermo->charge(k));
30 for (
size_t k = 0; k < m_nsp; k++){
31 if (m_speciesCharge[k] != 0){
32 m_kCharge.push_back(k);
34 m_kNeutral.push_back(k);
39 if (m_thermo->speciesIndex(
"E") !=
npos ) {
40 m_kElectron = m_thermo->speciesIndex(
"E");
44 setBounds(c_offset_E, -1.0e20, 1.0e20);
49 for (
size_t k : m_kCharge) {
50 setBounds(c_offset_Y + k, -1e-14, 1.0);
52 setBounds(c_offset_Y + m_kElectron, -1e-18, 1.0);
54 m_refiner->setActive(c_offset_E,
false);
55 m_mobility.resize(m_nsp*m_points);
56 m_do_electric_field.resize(m_points,
false);
59 void IonFlow::resize(
size_t components,
size_t points){
60 StFlow::resize(components, points);
61 m_mobility.resize(m_nsp*m_points);
62 m_do_species.resize(m_nsp,
true);
63 m_do_electric_field.resize(m_points,
false);
66 void IonFlow::updateTransport(
double* x,
size_t j0,
size_t j1)
68 StFlow::updateTransport(x,j0,j1);
69 for (
size_t j = j0; j < j1; j++) {
70 setGasAtMidpoint(x,j);
71 m_trans->getMobilities(&m_mobility[j*m_nsp]);
72 if (m_import_electron_transport) {
73 size_t k = m_kElectron;
74 double tlog = log(m_thermo->temperature());
75 m_mobility[k+m_nsp*j] =
poly5(tlog, m_mobi_e_fix.data());
76 m_diff[k+m_nsp*j] =
poly5(tlog, m_diff_e_fix.data());
81 void IonFlow::updateDiffFluxes(
const double* x,
size_t j0,
size_t j1)
84 frozenIonMethod(x,j0,j1);
87 electricFieldMethod(x,j0,j1);
91 void IonFlow::frozenIonMethod(
const double* x,
size_t j0,
size_t j1)
93 for (
size_t j = j0; j < j1; j++) {
94 double wtm = m_wtm[j];
95 double rho = density(j);
96 double dz = z(j+1) - z(j);
98 for (
size_t k : m_kNeutral) {
99 m_flux(k,j) = m_wt[k]*(rho*m_diff[k+m_nsp*j]/wtm);
100 m_flux(k,j) *= (X(x,k,j) - X(x,k,j+1))/dz;
105 for (
size_t k : m_kNeutral) {
106 m_flux(k,j) += sum*Y(x,k,j);
112 for (
size_t k : m_kCharge) {
118 void IonFlow::electricFieldMethod(
const double* x,
size_t j0,
size_t j1)
120 for (
size_t j = j0; j < j1; j++) {
121 double wtm = m_wtm[j];
122 double rho = density(j);
123 double dz = z(j+1) - z(j);
127 for (
size_t k = 0; k < m_nsp; k++) {
128 m_flux(k,j) = m_wt[k]*(rho*m_diff[k+m_nsp*j]/wtm);
129 m_flux(k,j) *= (X(x,k,j) - X(x,k,j+1))/dz;
134 double E_ambi = E(x,j);
135 for (
size_t k : m_kCharge) {
136 double Yav = 0.5 * (Y(x,k,j) + Y(x,k,j+1));
137 double drift = rho * Yav * E_ambi
138 * m_speciesCharge[k] * m_mobility[k+m_nsp*j];
139 m_flux(k,j) += drift;
143 double sum_flux = 0.0;
144 for (
size_t k = 0; k < m_nsp; k++) {
145 sum_flux -= m_flux(k,j);
147 double sum_ion = 0.0;
148 for (
size_t k : m_kCharge) {
152 for (
size_t k : m_kNeutral) {
153 m_flux(k,j) += Y(x,k,j) / (1-sum_ion) * sum_flux;
158 void IonFlow::setSolvingStage(
const size_t stage)
160 if (stage == 1 || stage == 2) {
164 "solution stage must be set to: "
165 "1) frozenIonMethod, "
166 "2) electricFieldEqnMethod");
170 void IonFlow::evalResidual(
double* x,
double* rsd,
int* diag,
171 double rdt,
size_t jmin,
size_t jmax)
173 StFlow::evalResidual(x, rsd, diag, rdt, jmin, jmax);
178 for (
size_t j = jmin; j <= jmax; j++) {
183 for (
size_t k : m_kCharge) {
184 rsd[index(c_offset_Y + k, 0)] = Y(x,k,0) - Y(x,k,1);
186 rsd[index(c_offset_E, j)] = E(x,0);
187 diag[index(c_offset_E, j)] = 0;
188 }
else if (j == m_points - 1) {
189 rsd[index(c_offset_E, j)] = dEdz(x,j) - rho_e(x,j) /
epsilon_0;
190 diag[index(c_offset_E, j)] = 0;
199 rsd[index(c_offset_E, j)] = dEdz(x,j) - rho_e(x,j) /
epsilon_0;
200 diag[index(c_offset_E, j)] = 0;
205 void IonFlow::solveElectricField(
size_t j)
207 bool changed =
false;
209 for (
size_t i = 0; i < m_points; i++) {
210 if (!m_do_electric_field[i]) {
213 m_do_electric_field[i] =
true;
216 if (!m_do_electric_field[j]) {
219 m_do_electric_field[j] =
true;
221 m_refiner->setActive(c_offset_U,
true);
222 m_refiner->setActive(c_offset_V,
true);
223 m_refiner->setActive(c_offset_T,
true);
224 m_refiner->setActive(c_offset_E,
true);
230 void IonFlow::fixElectricField(
size_t j)
232 bool changed =
false;
234 for (
size_t i = 0; i < m_points; i++) {
235 if (m_do_electric_field[i]) {
238 m_do_electric_field[i] =
false;
241 if (m_do_electric_field[j]) {
244 m_do_electric_field[j] =
false;
246 m_refiner->setActive(c_offset_U,
false);
247 m_refiner->setActive(c_offset_V,
false);
248 m_refiner->setActive(c_offset_T,
false);
249 m_refiner->setActive(c_offset_E,
false);
258 m_import_electron_transport =
true;
260 size_t n = tfix.size();
262 for (
size_t i = 0; i < n; i++) {
263 tlog.push_back(log(tfix[i]));
266 m_diff_e_fix.resize(degree + 1);
267 m_mobi_e_fix.resize(degree + 1);
268 polyfit(n, degree, tlog.data(), diff_e.data(), w.data(), m_diff_e_fix.data());
269 polyfit(n, degree, tlog.data(), mobi_e.data(), w.data(), m_mobi_e_fix.data());
272 void IonFlow::_finalize(
const double* x)
274 StFlow::_finalize(x);
276 bool p = m_do_electric_field[0];
278 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.
const size_t npos
index returned by functions to indicate "no position"
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].
Namespace for the Cantera kernel.
R poly5(D x, R *c)
Templated evaluation of a polynomial of order 5.
double polyfit(size_t n, size_t deg, const double *xp, const double *yp, const double *wp, double *pp)
Fits a polynomial function to a set of data points.