/** * @file IdealGasReactor.cpp A zero-dimensional reactor */ #include "cantera/zeroD/IdealGasReactor.h" #include "cantera/zeroD/FlowDevice.h" #include "cantera/zeroD/Wall.h" using namespace std; namespace Cantera { void IdealGasReactor::setThermoMgr(ThermoPhase& thermo) { //! @TODO: Add a method to ThermoPhase that indicates whether a given //! subclass is compatible with this reactor model if (thermo.eosType() != cIdealGas) { throw CanteraError("IdealGasReactor::setThermoMgr", "Incompatible phase type provided"); } Reactor::setThermoMgr(thermo); } void IdealGasReactor::getInitialConditions(double t0, size_t leny, double* y) { if (m_thermo == 0) { cout << "Error: reactor is empty." << endl; return; } m_thermo->restoreState(m_state); // set the first component to the total mass m_mass = m_thermo->density() * m_vol; y[0] = m_mass; // set the second component to the total volume y[1] = m_vol; // Set the third component to the temperature y[2] = m_thermo->temperature(); // set components y+3 ... y+K+2 to the mass fractions of each species m_thermo->getMassFractions(y+3); // set the remaining components to the surface species // coverages on the walls getSurfaceInitialConditions(y + m_nsp + 3); } void IdealGasReactor::initialize(doublereal t0) { Reactor::initialize(t0); m_uk.resize(m_nsp, 0.0); } 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); 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); } 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); } size_t IdealGasReactor::componentIndex(const string& nm) const { size_t k = speciesIndex(nm); if (k != npos) { return k + 3; } else if (nm == "m" || nm == "mass") { return 0; } else if (nm == "V" || nm == "volume") { return 1; } else if (nm == "T" || nm == "temperature") { return 2; } else { return npos; } } }