void GasKinetics::updateROP() { update_rates_C(); update_rates_T(); if (m_ROP_ok) { return; } // copy rate coefficients into ropf copy(m_rfn.begin(), m_rfn.end(), m_ropf.begin()); // multiply ropf by enhanced 3b conc for all 3b rxns if (!concm_3b_values.empty()) { m_3b_concm.multiply(&m_ropf[0], &concm_3b_values[0]); } if (m_nfall) { processFalloffReactions(); } // multiply by perturbation factor multiply_each(m_ropf.begin(), m_ropf.end(), m_perturb.begin()); // copy the forward rates to the reverse rates copy(m_ropf.begin(), m_ropf.end(), m_ropr.begin()); // for reverse rates computed from thermochemistry, multiply the forward // rates copied into m_ropr by the reciprocals of the equilibrium constants multiply_each(m_ropr.begin(), m_ropr.end(), m_rkcn.begin()); // multiply ropf by concentration products m_reactantStoich.multiply(&m_conc[0], &m_ropf[0]); // for reversible reactions, multiply ropr by concentration products m_revProductStoich.multiply(&m_conc[0], &m_ropr[0]); for (size_t j = 0; j != nReactions(); ++j) { m_ropnet[j] = m_ropf[j] - m_ropr[j]; } for (size_t i = 0; i < m_rfn.size(); i++) { AssertFinite(m_rfn[i], "GasKinetics::updateROP", "m_rfn[" + int2str(i) + "] is not finite."); AssertFinite(m_ropf[i], "GasKinetics::updateROP", "m_ropf[" + int2str(i) + "] is not finite."); AssertFinite(m_ropr[i], "GasKinetics::updateROP", "m_ropr[" + int2str(i) + "] is not finite."); } m_ROP_ok = true; }
void IdealGasReactor::updateState(doublereal* y) { for (size_t i = 0; i < m_nv; i++) { AssertFinite(y[i], "IdealGasReactor::updateState", "y[" + int2str(i) + "] is not finite"); } // The components of y are [0] the total mass, [1] the total volume, // [2] the temperature, [3...K+3] are the mass fractions of each species, // and [K+3...] are the coverages of surface species on each wall. m_mass = y[0]; m_vol = y[1]; m_thermo->setMassFractions_NoNorm(y+3); m_thermo->setState_TR(y[2], m_mass / m_vol); size_t loc = m_nsp + 3; SurfPhase* surf; for (size_t m = 0; m < m_nwalls; m++) { surf = m_wall[m]->surface(m_lr[m]); if (surf) { m_wall[m]->setCoverages(m_lr[m], y+loc); loc += surf->nSpecies(); } } // save parameters needed by other connected reactors m_enthalpy = m_thermo->enthalpy_mass(); m_pressure = m_thermo->pressure(); m_intEnergy = m_thermo->intEnergy_mass(); m_thermo->saveState(m_state); }
void GasKinetics::processFalloffReactions() { // use m_ropr for temporary storage of reduced pressure vector_fp& pr = m_ropr; for (size_t i = 0; i < m_nfall; i++) { pr[i] = concm_falloff_values[i] * m_rfn_low[i] / (m_rfn_high[i] + SmallNumber); AssertFinite(pr[i], "GasKinetics::processFalloffReactions", "pr[" + int2str(i) + "] is not finite."); } double* work = (falloff_work.empty()) ? 0 : &falloff_work[0]; m_falloffn.pr_to_falloff(&pr[0], work); for (size_t i = 0; i < m_nfall; i++) { if (m_rxntype[m_fallindx[i]] == FALLOFF_RXN) { pr[i] *= m_rfn_high[i]; } else { // CHEMACT_RXN pr[i] *= m_rfn_low[i]; } } scatter_copy(pr.begin(), pr.begin() + m_nfall, m_ropf.begin(), m_fallindx.begin()); }
void IdealGasReactor::evalEqs(doublereal time, doublereal* y, doublereal* ydot, doublereal* params) { double dmdt = 0.0; // dm/dt (gas phase) double mcvdTdt = 0.0; // m * c_v * dT/dt double* dYdt = ydot + 3; m_thermo->restoreState(m_state); applySensitivity(params); m_thermo->getPartialMolarIntEnergies(&m_uk[0]); const vector_fp& mw = m_thermo->molecularWeights(); const doublereal* Y = m_thermo->massFractions(); if (m_chem) { m_kin->getNetProductionRates(&m_wdot[0]); // "omega dot" } evalWalls(time); double mdot_surf = evalSurfaces(time, ydot + m_nsp + 3); dmdt += mdot_surf; // compression work and external heat transfer mcvdTdt += - m_pressure * m_vdot - m_Q; for (size_t n = 0; n < m_nsp; n++) { // heat release from gas phase and surface reations mcvdTdt -= m_wdot[n] * m_uk[n] * m_vol; mcvdTdt -= m_sdot[n] * m_uk[n]; // production in gas phase and from surfaces dYdt[n] = (m_wdot[n] * m_vol + m_sdot[n]) * mw[n] / m_mass; // dilution by net surface mass flux dYdt[n] -= Y[n] * mdot_surf / m_mass; } // add terms for outlets for (size_t i = 0; i < m_outlet.size(); i++) { double mdot_out = m_outlet[i]->massFlowRate(time); dmdt -= mdot_out; // mass flow out of system mcvdTdt -= mdot_out * m_pressure * m_vol / m_mass; // flow work } // add terms for inlets for (size_t i = 0; i < m_inlet.size(); i++) { double mdot_in = m_inlet[i]->massFlowRate(time); dmdt += mdot_in; // mass flow into system mcvdTdt += m_inlet[i]->enthalpy_mass() * mdot_in; for (size_t n = 0; n < m_nsp; n++) { double mdot_spec = m_inlet[i]->outletSpeciesMassFlowRate(n); // flow of species into system and dilution by other species dYdt[n] += (mdot_spec - mdot_in * Y[n]) / m_mass; // In combintion with h_in*mdot_in, flow work plus thermal // energy carried with the species mcvdTdt -= m_uk[n] / mw[n] * mdot_spec; } } ydot[0] = dmdt; ydot[1] = m_vdot; if (m_energy) { ydot[2] = mcvdTdt / (m_mass * m_thermo->cv_mass()); } else { ydot[2] = 0; } for (size_t i = 0; i < m_nv; i++) { AssertFinite(ydot[i], "IdealGasReactor::evalEqs", "ydot[" + int2str(i) + "] is not finite"); } resetSensitivity(params); }
void IdealGasReactor::evalEqs(doublereal time, doublereal* y, doublereal* ydot, doublereal* params) { m_thermo->restoreState(m_state); // process sensitivity parameters if (params) { size_t npar = m_pnum.size(); for (size_t n = 0; n < npar; n++) { double mult = m_kin->multiplier(m_pnum[n]); m_kin->setMultiplier(m_pnum[n], mult*params[n]); } size_t ploc = npar; for (size_t m = 0; m < m_nwalls; m++) { if (m_nsens_wall[m] > 0) { m_wall[m]->setSensitivityParameters(m_lr[m], params + ploc); ploc += m_nsens_wall[m]; } } } m_vdot = 0.0; m_Q = 0.0; double mcvdTdt = 0.0; // m * c_v * dT/dt double dmdt = 0.0; // dm/dt (gas phase) double* dYdt = ydot + 3; m_thermo->getPartialMolarIntEnergies(&m_uk[0]); // compute wall terms size_t loc = m_nsp+3; fill(m_sdot.begin(), m_sdot.end(), 0.0); for (size_t i = 0; i < m_nwalls; i++) { int lr = 1 - 2*m_lr[i]; double vdot = lr*m_wall[i]->vdot(time); m_vdot += vdot; m_Q += lr*m_wall[i]->Q(time); Kinetics* kin = m_wall[i]->kinetics(m_lr[i]); SurfPhase* surf = m_wall[i]->surface(m_lr[i]); if (surf && kin) { double rs0 = 1.0/surf->siteDensity(); size_t nk = surf->nSpecies(); double sum = 0.0; surf->setTemperature(m_state[0]); m_wall[i]->syncCoverages(m_lr[i]); kin->getNetProductionRates(DATA_PTR(m_work)); size_t ns = kin->surfacePhaseIndex(); size_t surfloc = kin->kineticsSpeciesIndex(0,ns); for (size_t k = 1; k < nk; k++) { ydot[loc + k] = m_work[surfloc+k]*rs0*surf->size(k); sum -= ydot[loc + k]; } ydot[loc] = sum; loc += nk; double wallarea = m_wall[i]->area(); for (size_t k = 0; k < m_nsp; k++) { m_sdot[k] += m_work[k]*wallarea; } } } const vector_fp& mw = m_thermo->molecularWeights(); const doublereal* Y = m_thermo->massFractions(); if (m_chem) { m_kin->getNetProductionRates(&m_wdot[0]); // "omega dot" } double mdot_surf = 0.0; // net mass flux from surfaces for (size_t k = 0; k < m_nsp; k++) { // production in gas phase and from surfaces dYdt[k] = (m_wdot[k] * m_vol + m_sdot[k]) * mw[k] / m_mass; mdot_surf += m_sdot[k] * mw[k]; } dmdt += mdot_surf; // compression work and external heat transfer mcvdTdt += - m_pressure * m_vdot - m_Q; for (size_t n = 0; n < m_nsp; n++) { // heat release from gas phase and surface reations mcvdTdt -= m_wdot[n] * m_uk[n] * m_vol; mcvdTdt -= m_sdot[n] * m_uk[n]; // dilution by net surface mass flux dYdt[n] -= Y[n] * mdot_surf / m_mass; } // add terms for open system if (m_open) { // outlets for (size_t i = 0; i < m_nOutlets; i++) { double mdot_out = m_outlet[i]->massFlowRate(time); dmdt -= mdot_out; // mass flow out of system mcvdTdt -= mdot_out * m_pressure * m_vol / m_mass; // flow work } // inlets for (size_t i = 0; i < m_nInlets; i++) { double mdot_in = m_inlet[i]->massFlowRate(time); dmdt += mdot_in; // mass flow into system mcvdTdt += m_inlet[i]->enthalpy_mass() * mdot_in; for (size_t n = 0; n < m_nsp; n++) { double mdot_spec = m_inlet[i]->outletSpeciesMassFlowRate(n); // flow of species into system and dilution by other species dYdt[n] += (mdot_spec - mdot_in * Y[n]) / m_mass; // In combintion with h_in*mdot_in, flow work plus thermal // energy carried with the species mcvdTdt -= m_uk[n] / mw[n] * mdot_spec; } } } ydot[0] = dmdt; ydot[1] = m_vdot; if (m_energy) { ydot[2] = mcvdTdt / (m_mass * m_thermo->cv_mass()); } else { ydot[2] = 0; } for (size_t i = 0; i < m_nv; i++) { AssertFinite(ydot[i], "IdealGasReactor::evalEqs", "ydot[" + int2str(i) + "] is not finite"); } // reset sensitivity parameters if (params) { size_t npar = m_pnum.size(); for (size_t n = 0; n < npar; n++) { double mult = m_kin->multiplier(m_pnum[n]); m_kin->setMultiplier(m_pnum[n], mult/params[n]); } size_t ploc = npar; for (size_t m = 0; m < m_nwalls; m++) { if (m_nsens_wall[m] > 0) { m_wall[m]->resetSensitivityParameters(m_lr[m]); ploc += m_nsens_wall[m]; } } } }
void Reactor::evalEqs(doublereal time, doublereal* y, doublereal* ydot, doublereal* params) { double dmdt = 0.0; // dm/dt (gas phase) double* dYdt = ydot + 3; m_thermo->restoreState(m_state); applySensitivity(params); evalWalls(time); double mdot_surf = evalSurfaces(time, ydot + m_nsp + 3); dmdt += mdot_surf; // mass added to gas phase from surface reations // volume equation ydot[1] = m_vdot; const vector_fp& mw = m_thermo->molecularWeights(); const doublereal* Y = m_thermo->massFractions(); if (m_chem) { m_kin->getNetProductionRates(&m_wdot[0]); // "omega dot" } for (size_t k = 0; k < m_nsp; k++) { // production in gas phase and from surfaces dYdt[k] = (m_wdot[k] * m_vol + m_sdot[k]) * mw[k] / m_mass; // dilution by net surface mass flux dYdt[k] -= Y[k] * mdot_surf / m_mass; } /* * Energy equation. * \f[ * \dot U = -P\dot V + A \dot q + \dot m_{in} h_{in} * - \dot m_{out} h. * \f] */ if (m_energy) { ydot[2] = - m_thermo->pressure() * m_vdot - m_Q; } else { ydot[2] = 0.0; } // add terms for outlets for (size_t i = 0; i < m_outlet.size(); i++) { double mdot_out = m_outlet[i]->massFlowRate(time); dmdt -= mdot_out; // mass flow out of system if (m_energy) { ydot[2] -= mdot_out * m_enthalpy; } } // add terms for inlets for (size_t i = 0; i < m_inlet.size(); i++) { double mdot_in = m_inlet[i]->massFlowRate(time); dmdt += mdot_in; // mass flow into system for (size_t n = 0; n < m_nsp; n++) { double mdot_spec = m_inlet[i]->outletSpeciesMassFlowRate(n); // flow of species into system and dilution by other species dYdt[n] += (mdot_spec - mdot_in * Y[n]) / m_mass; } if (m_energy) { ydot[2] += mdot_in * m_inlet[i]->enthalpy_mass(); } } ydot[0] = dmdt; for (size_t i = 0; i < m_nv; i++) { AssertFinite(ydot[i], "Reactor::evalEqs", "ydot[" + int2str(i) + "] is not finite"); } resetSensitivity(params); }
void Reactor::updateState(doublereal* y) { for (size_t i = 0; i < m_nv; i++) { AssertFinite(y[i], "Reactor::updateState", "y[" + int2str(i) + "] is not finite"); } // The components of y are [0] the total mass, [1] the total volume, // [2] the total internal energy, [3...K+3] are the mass fractions of each // species, and [K+3...] are the coverages of surface species on each wall. m_mass = y[0]; m_vol = y[1]; m_thermo->setMassFractions_NoNorm(y+3); if (m_energy) { // Use a damped Newton's method to determine the mixture temperature. // Tight tolerances are required both for Jacobian evaluation and for // sensitivity analysis to work correctly. doublereal U = y[2]; doublereal T = temperature(); double dT = 100; double dUprev = 1e10; double dU = 1e10; int i = 0; double damp = 1.0; while (abs(dT / T) > 10 * DBL_EPSILON) { dUprev = dU; m_thermo->setState_TR(T, m_mass / m_vol); double dUdT = m_thermo->cv_mass() * m_mass; dU = m_thermo->intEnergy_mass() * m_mass - U; dT = dU / dUdT; // Reduce the damping coefficient if the magnitude of the error // isn't decreasing if (std::abs(dU) < std::abs(dUprev)) { damp = 1.0; } else { damp *= 0.8; } dT = std::min(dT, 0.5 * T) * damp; T -= dT; i++; if (i > 100) { std::string message = "no convergence"; message += "\nU/m = " + fp2str(U / m_mass); message += "\nT = " + fp2str(T); message += "\nrho = " + fp2str(m_mass / m_vol); message += "\n"; throw CanteraError("Reactor::updateState", message); } } } else { m_thermo->setDensity(m_mass/m_vol); } updateSurfaceState(y + m_nsp + 3); // save parameters needed by other connected reactors m_enthalpy = m_thermo->enthalpy_mass(); m_pressure = m_thermo->pressure(); m_intEnergy = m_thermo->intEnergy_mass(); m_thermo->saveState(m_state); }