831 lines
20 KiB
C++
831 lines
20 KiB
C++
//! @file boundaries1D.cpp
|
|
|
|
// Copyright 2002-3 California Institute of Technology
|
|
|
|
#include "cantera/oneD/Inlet1D.h"
|
|
#include "cantera/oneD/OneDim.h"
|
|
#include "cantera/base/ctml.h"
|
|
|
|
using namespace std;
|
|
|
|
namespace Cantera
|
|
{
|
|
|
|
Bdry1D::Bdry1D() : Domain1D(1, 1, 0.0),
|
|
m_flow_left(0), m_flow_right(0),
|
|
m_ilr(0), m_left_nv(0), m_right_nv(0),
|
|
m_left_loc(0), m_right_loc(0),
|
|
m_left_points(0), m_nv(0),
|
|
m_left_nsp(0), m_right_nsp(0),
|
|
m_sp_left(0), m_sp_right(0),
|
|
m_start_left(0), m_start_right(0),
|
|
m_phase_left(0), m_phase_right(0), m_temp(0.0), m_mdot(0.0)
|
|
{
|
|
m_type = cConnectorType;
|
|
}
|
|
|
|
void Bdry1D::_init(size_t n)
|
|
{
|
|
if (m_index == npos) {
|
|
throw CanteraError("Bdry1D::_init",
|
|
"install in container before calling init.");
|
|
}
|
|
|
|
// A boundary object contains only one grid point
|
|
resize(n,1);
|
|
|
|
m_left_nsp = 0;
|
|
m_right_nsp = 0;
|
|
|
|
// check for left and right flow objects
|
|
if (m_index > 0) {
|
|
Domain1D& r = container().domain(m_index-1);
|
|
if (r.domainType() == cFlowType) {
|
|
m_flow_left = (StFlow*)&r;
|
|
m_left_nv = m_flow_left->nComponents();
|
|
m_left_points = m_flow_left->nPoints();
|
|
m_left_loc = container().start(m_index-1);
|
|
m_left_nsp = m_left_nv - 4;
|
|
m_phase_left = &m_flow_left->phase();
|
|
} else {
|
|
throw CanteraError("Bdry1D::_init",
|
|
"Boundary domains can only be connected on the left to flow "
|
|
"domains, not type {} domains.", r.domainType());
|
|
}
|
|
}
|
|
|
|
// if this is not the last domain, see what is connected on the right
|
|
if (m_index + 1 < container().nDomains()) {
|
|
Domain1D& r = container().domain(m_index+1);
|
|
if (r.domainType() == cFlowType) {
|
|
m_flow_right = (StFlow*)&r;
|
|
m_right_nv = m_flow_right->nComponents();
|
|
m_right_loc = container().start(m_index+1);
|
|
m_right_nsp = m_right_nv - 4;
|
|
m_phase_right = &m_flow_right->phase();
|
|
} else {
|
|
throw CanteraError("Bdry1D::_init",
|
|
"Boundary domains can only be connected on the right to flow "
|
|
"domains, not type {} domains.", r.domainType());
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------- Inlet1D methods ----------------
|
|
|
|
void Inlet1D::setMoleFractions(const std::string& xin)
|
|
{
|
|
m_xstr = xin;
|
|
if (m_flow) {
|
|
m_flow->phase().setMoleFractionsByName(xin);
|
|
m_flow->phase().getMassFractions(m_yin.data());
|
|
needJacUpdate();
|
|
}
|
|
}
|
|
|
|
void Inlet1D::setMoleFractions(const doublereal* xin)
|
|
{
|
|
if (m_flow) {
|
|
m_flow->phase().setMoleFractions(xin);
|
|
m_flow->phase().getMassFractions(m_yin.data());
|
|
needJacUpdate();
|
|
}
|
|
}
|
|
|
|
string Inlet1D::componentName(size_t n) const
|
|
{
|
|
switch (n) {
|
|
case 0:
|
|
return "mdot";
|
|
case 1:
|
|
return "temperature";
|
|
default:
|
|
break;
|
|
}
|
|
return "unknown";
|
|
}
|
|
|
|
void Inlet1D::init()
|
|
{
|
|
_init(2);
|
|
|
|
setBounds(0, -1e5, 1e5); // mdot
|
|
setBounds(1, 200.0, 1e5); // T
|
|
|
|
// set tolerances
|
|
setSteadyTolerances(1e-4, 1e-5);
|
|
setTransientTolerances(1e-4, 1e-5);
|
|
|
|
// if a flow domain is present on the left, then this must be a right inlet.
|
|
// Note that an inlet object can only be a terminal object - it cannot have
|
|
// flows on both the left and right
|
|
if (m_flow_left) {
|
|
m_ilr = RightInlet;
|
|
m_flow = m_flow_left;
|
|
} else if (m_flow_right) {
|
|
m_ilr = LeftInlet;
|
|
m_flow = m_flow_right;
|
|
} else {
|
|
throw CanteraError("Inlet1D::init","no flow!");
|
|
}
|
|
|
|
// components = u, V, T, lambda, + mass fractions
|
|
m_nsp = m_flow->nComponents() - 4;
|
|
m_yin.resize(m_nsp, 0.0);
|
|
if (m_xstr != "") {
|
|
setMoleFractions(m_xstr);
|
|
} else {
|
|
m_yin[0] = 1.0;
|
|
}
|
|
}
|
|
|
|
void Inlet1D::eval(size_t jg, doublereal* xg, doublereal* rg,
|
|
integer* diagg, doublereal rdt)
|
|
{
|
|
if (jg != npos && (jg + 2 < firstPoint() || jg > lastPoint() + 2)) {
|
|
return;
|
|
}
|
|
|
|
// start of local part of global arrays
|
|
doublereal* x = xg + loc();
|
|
doublereal* r = rg + loc();
|
|
integer* diag = diagg + loc();
|
|
doublereal* xb, *rb;
|
|
|
|
// residual equations for the two local variables
|
|
r[0] = m_mdot - x[0];
|
|
|
|
// Temperature
|
|
r[1] = m_temp - x[1];
|
|
|
|
// both are algebraic constraints
|
|
diag[0] = 0;
|
|
diag[1] = 0;
|
|
|
|
// if it is a left inlet, then the flow solution vector
|
|
// starts 2 to the right in the global solution vector
|
|
if (m_ilr == LeftInlet) {
|
|
xb = x + 2;
|
|
rb = r + 2;
|
|
|
|
// The first flow residual is for u. This, however, is not modified by
|
|
// the inlet, since this is set within the flow domain from the
|
|
// continuity equation.
|
|
|
|
// spreading rate. The flow domain sets this to V(0),
|
|
// so for finite spreading rate subtract m_V0.
|
|
rb[1] -= m_V0;
|
|
|
|
// The third flow residual is for T, where it is set to T(0). Subtract
|
|
// the local temperature to hold the flow T to the inlet T.
|
|
rb[2] -= x[1];
|
|
|
|
// The flow domain sets this to -rho*u. Add mdot to specify the mass
|
|
// flow rate.
|
|
rb[3] += x[0];
|
|
|
|
// add the convective term to the species residual equations
|
|
for (size_t k = 1; k < m_nsp; k++) {
|
|
rb[4+k] += x[0]*m_yin[k];
|
|
}
|
|
|
|
// if the flow is a freely-propagating flame, mdot is not specified.
|
|
// Set mdot equal to rho*u, and also set lambda to zero.
|
|
if (!m_flow->fixed_mdot()) {
|
|
m_mdot = m_flow->density(0)*xb[0];
|
|
r[0] = m_mdot - x[0];
|
|
rb[3] = xb[3];
|
|
}
|
|
} else {
|
|
// right inlet.
|
|
size_t boffset = m_flow->nComponents();
|
|
xb = x - boffset;
|
|
rb = r - boffset;
|
|
rb[1] -= m_V0;
|
|
rb[2] -= x[1]; // T
|
|
rb[0] += x[0]; // u
|
|
for (size_t k = 1; k < m_nsp; k++) {
|
|
rb[4+k] += x[0]*m_yin[k];
|
|
}
|
|
}
|
|
}
|
|
|
|
XML_Node& Inlet1D::save(XML_Node& o, const doublereal* const soln)
|
|
{
|
|
const doublereal* s = soln + loc();
|
|
XML_Node& inlt = Domain1D::save(o, soln);
|
|
inlt.addAttribute("type","inlet");
|
|
for (size_t k = 0; k < nComponents(); k++) {
|
|
addFloat(inlt, componentName(k), s[k]);
|
|
}
|
|
for (size_t k=0; k < m_nsp; k++) {
|
|
addFloat(inlt, "massFraction", m_yin[k], "",
|
|
m_flow->phase().speciesName(k));
|
|
}
|
|
return inlt;
|
|
}
|
|
|
|
void Inlet1D::restore(const XML_Node& dom, doublereal* soln, int loglevel)
|
|
{
|
|
Domain1D::restore(dom, soln, loglevel);
|
|
soln[0] = m_mdot = getFloat(dom, "mdot", "massflowrate");
|
|
soln[1] = m_temp = getFloat(dom, "temperature", "temperature");
|
|
|
|
m_yin.assign(m_nsp, 0.0);
|
|
|
|
for (size_t i = 0; i < dom.nChildren(); i++) {
|
|
const XML_Node& node = dom.child(i);
|
|
if (node.name() == "massFraction") {
|
|
size_t k = m_flow->phase().speciesIndex(node.attrib("type"));
|
|
if (k != npos) {
|
|
m_yin[k] = node.fp_value();
|
|
}
|
|
}
|
|
}
|
|
resize(2,1);
|
|
}
|
|
|
|
// ------------- Empty1D -------------
|
|
|
|
string Empty1D::componentName(size_t n) const
|
|
{
|
|
switch (n) {
|
|
case 0:
|
|
return "dummy";
|
|
default:
|
|
break;
|
|
}
|
|
return "<unknown>";
|
|
}
|
|
|
|
void Empty1D::init()
|
|
{
|
|
setBounds(0, -1.0, 1.0);
|
|
|
|
// set tolerances
|
|
setSteadyTolerances(1e-4, 1e-4);
|
|
setTransientTolerances(1e-4, 1e-4);
|
|
}
|
|
|
|
void Empty1D::eval(size_t jg, doublereal* xg, doublereal* rg,
|
|
integer* diagg, doublereal rdt)
|
|
{
|
|
if (jg != npos && (jg + 2 < firstPoint() || jg > lastPoint() + 2)) {
|
|
return;
|
|
}
|
|
|
|
// start of local part of global arrays
|
|
doublereal* x = xg + loc();
|
|
doublereal* r = rg + loc();
|
|
integer* diag = diagg + loc();
|
|
|
|
r[0] = x[0];
|
|
diag[0] = 0;
|
|
}
|
|
|
|
XML_Node& Empty1D::save(XML_Node& o, const doublereal* const soln)
|
|
{
|
|
XML_Node& symm = Domain1D::save(o, soln);
|
|
symm.addAttribute("type","empty");
|
|
return symm;
|
|
}
|
|
|
|
void Empty1D::restore(const XML_Node& dom, doublereal* soln, int loglevel)
|
|
{
|
|
Domain1D::restore(dom, soln, loglevel);
|
|
resize(1,1);
|
|
}
|
|
|
|
// -------------- Symm1D --------------
|
|
|
|
string Symm1D::componentName(size_t n) const
|
|
{
|
|
switch (n) {
|
|
case 0:
|
|
return "dummy";
|
|
default:
|
|
break;
|
|
}
|
|
return "<unknown>";
|
|
}
|
|
|
|
void Symm1D::init()
|
|
{
|
|
_init(1);
|
|
setBounds(0, -1.0, 1.0);
|
|
|
|
// set tolerances
|
|
setSteadyTolerances(1e-4, 1e-4);
|
|
setTransientTolerances(1e-4, 1e-4);
|
|
}
|
|
|
|
void Symm1D::eval(size_t jg, doublereal* xg, doublereal* rg, integer* diagg,
|
|
doublereal rdt)
|
|
{
|
|
if (jg != npos && (jg + 2< firstPoint() || jg > lastPoint() + 2)) {
|
|
return;
|
|
}
|
|
|
|
// start of local part of global arrays
|
|
doublereal* x = xg + loc();
|
|
doublereal* r = rg + loc();
|
|
integer* diag = diagg + loc();
|
|
doublereal* xb, *rb;
|
|
integer* db;
|
|
|
|
r[0] = x[0];
|
|
diag[0] = 0;
|
|
size_t nc;
|
|
|
|
if (m_flow_right) {
|
|
nc = m_flow_right->nComponents();
|
|
xb = x + 1;
|
|
rb = r + 1;
|
|
db = diag + 1;
|
|
db[1] = 0;
|
|
db[2] = 0;
|
|
rb[1] = xb[1] - xb[1 + nc]; // zero dV/dz
|
|
rb[2] = xb[2] - xb[2 + nc]; // zero dT/dz
|
|
}
|
|
|
|
if (m_flow_left) {
|
|
nc = m_flow_left->nComponents();
|
|
xb = x - nc;
|
|
rb = r - nc;
|
|
db = diag - nc;
|
|
db[1] = 0;
|
|
db[2] = 0;
|
|
rb[1] = xb[1] - xb[1 - nc]; // zero dV/dz
|
|
rb[2] = xb[2] - xb[2 - nc]; // zero dT/dz
|
|
}
|
|
}
|
|
|
|
XML_Node& Symm1D::save(XML_Node& o, const doublereal* const soln)
|
|
{
|
|
XML_Node& symm = Domain1D::save(o, soln);
|
|
symm.addAttribute("type","symmetry");
|
|
return symm;
|
|
}
|
|
|
|
void Symm1D::restore(const XML_Node& dom, doublereal* soln, int loglevel)
|
|
{
|
|
Domain1D::restore(dom, soln, loglevel);
|
|
resize(1,1);
|
|
}
|
|
|
|
// -------- Outlet1D --------
|
|
|
|
string Outlet1D::componentName(size_t n) const
|
|
{
|
|
switch (n) {
|
|
case 0:
|
|
return "outlet dummy";
|
|
default:
|
|
break;
|
|
}
|
|
return "<unknown>";
|
|
}
|
|
|
|
void Outlet1D::init()
|
|
{
|
|
_init(1);
|
|
setBounds(0, -1.0, 1.0);
|
|
|
|
// set tolerances
|
|
setSteadyTolerances(1e-4, 1e-4);
|
|
setTransientTolerances(1e-4, 1e-4);
|
|
if (m_flow_right) {
|
|
m_flow_right->setViscosityFlag(false);
|
|
}
|
|
if (m_flow_left) {
|
|
m_flow_left->setViscosityFlag(false);
|
|
}
|
|
}
|
|
|
|
void Outlet1D::eval(size_t jg, doublereal* xg, doublereal* rg, integer* diagg,
|
|
doublereal rdt)
|
|
{
|
|
if (jg != npos && (jg + 2 < firstPoint() || jg > lastPoint() + 2)) {
|
|
return;
|
|
}
|
|
|
|
// start of local part of global arrays
|
|
doublereal* x = xg + loc();
|
|
doublereal* r = rg + loc();
|
|
integer* diag = diagg + loc();
|
|
doublereal* xb, *rb;
|
|
integer* db;
|
|
|
|
r[0] = x[0];
|
|
diag[0] = 0;
|
|
size_t nc, k;
|
|
|
|
if (m_flow_right) {
|
|
nc = m_flow_right->nComponents();
|
|
xb = x + 1;
|
|
rb = r + 1;
|
|
db = diag + 1;
|
|
rb[0] = xb[3];
|
|
rb[2] = xb[2] - xb[2 + nc];
|
|
for (k = 4; k < nc; k++) {
|
|
rb[k] = xb[k] - xb[k + nc];
|
|
}
|
|
}
|
|
|
|
if (m_flow_left) {
|
|
nc = m_flow_left->nComponents();
|
|
xb = x - nc;
|
|
rb = r - nc;
|
|
db = diag - nc;
|
|
|
|
// zero Lambda
|
|
if (m_flow_left->fixed_mdot()) {
|
|
rb[0] = xb[3];
|
|
}
|
|
|
|
rb[2] = xb[2] - xb[2 - nc]; // zero T gradient
|
|
for (k = 5; k < nc; k++) {
|
|
rb[k] = xb[k] - xb[k - nc]; // zero mass fraction gradient
|
|
db[k] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
XML_Node& Outlet1D::save(XML_Node& o, const doublereal* const soln)
|
|
{
|
|
XML_Node& outlt = Domain1D::save(o, soln);
|
|
outlt.addAttribute("type","outlet");
|
|
return outlt;
|
|
}
|
|
|
|
void Outlet1D::restore(const XML_Node& dom, doublereal* soln, int loglevel)
|
|
{
|
|
Domain1D::restore(dom, soln, loglevel);
|
|
resize(1,1);
|
|
}
|
|
|
|
// -------- OutletRes1D --------
|
|
|
|
void OutletRes1D::setMoleFractions(const std::string& xres)
|
|
{
|
|
m_xstr = xres;
|
|
if (m_flow) {
|
|
m_flow->phase().setMoleFractionsByName(xres);
|
|
m_flow->phase().getMassFractions(m_yres.data());
|
|
needJacUpdate();
|
|
}
|
|
}
|
|
|
|
void OutletRes1D::setMoleFractions(const doublereal* xres)
|
|
{
|
|
if (m_flow) {
|
|
m_flow->phase().setMoleFractions(xres);
|
|
m_flow->phase().getMassFractions(m_yres.data());
|
|
needJacUpdate();
|
|
}
|
|
}
|
|
|
|
string OutletRes1D::componentName(size_t n) const
|
|
{
|
|
switch (n) {
|
|
case 0:
|
|
return "dummy";
|
|
default:
|
|
break;
|
|
}
|
|
return "<unknown>";
|
|
}
|
|
|
|
void OutletRes1D::init()
|
|
{
|
|
_init(1);
|
|
// set bounds (dummy)
|
|
setBounds(0, -1.0, 1.0);
|
|
|
|
// set tolerances
|
|
setSteadyTolerances(1e-4, 1e-4);
|
|
setTransientTolerances(1e-4, 1e-4);
|
|
|
|
if (m_flow_left) {
|
|
m_flow = m_flow_left;
|
|
} else if (m_flow_right) {
|
|
m_flow = m_flow_right;
|
|
} else {
|
|
throw CanteraError("OutletRes1D::init","no flow!");
|
|
}
|
|
|
|
m_nsp = m_flow->nComponents() - 4;
|
|
m_yres.resize(m_nsp, 0.0);
|
|
if (m_xstr != "") {
|
|
setMoleFractions(m_xstr);
|
|
} else {
|
|
m_yres[0] = 1.0;
|
|
}
|
|
}
|
|
|
|
void OutletRes1D::eval(size_t jg, doublereal* xg, doublereal* rg,
|
|
integer* diagg, doublereal rdt)
|
|
{
|
|
if (jg != npos && (jg + 2 < firstPoint() || jg > lastPoint() + 2)) {
|
|
return;
|
|
}
|
|
|
|
// start of local part of global arrays
|
|
doublereal* x = xg + loc();
|
|
doublereal* r = rg + loc();
|
|
integer* diag = diagg + loc();
|
|
doublereal* xb, *rb;
|
|
integer* db;
|
|
|
|
// drive dummy component to zero
|
|
r[0] = x[0];
|
|
diag[0] = 0;
|
|
size_t nc, k;
|
|
|
|
if (m_flow_right) {
|
|
nc = m_flow_right->nComponents();
|
|
xb = x + 1;
|
|
rb = r + 1;
|
|
db = diag + 1;
|
|
|
|
// this seems wrong...
|
|
// zero Lambda
|
|
rb[0] = xb[3];
|
|
|
|
// zero gradient for T
|
|
rb[2] = xb[2] - xb[2 + nc];
|
|
|
|
// specified mass fractions
|
|
for (k = 4; k < nc; k++) {
|
|
rb[k] = xb[k] - m_yres[k-4];
|
|
}
|
|
}
|
|
|
|
if (m_flow_left) {
|
|
nc = m_flow_left->nComponents();
|
|
xb = x - nc;
|
|
rb = r - nc;
|
|
db = diag - nc;
|
|
|
|
if (!m_flow_left->fixed_mdot()) {
|
|
;
|
|
} else {
|
|
rb[0] = xb[3]; // zero Lambda
|
|
}
|
|
rb[2] = xb[2] - m_temp; // zero dT/dz
|
|
for (k = 5; k < nc; k++) {
|
|
rb[k] = xb[k] - m_yres[k-4]; // fixed Y
|
|
db[k] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
XML_Node& OutletRes1D::save(XML_Node& o, const doublereal* const soln)
|
|
{
|
|
XML_Node& outlt = Domain1D::save(o, soln);
|
|
outlt.addAttribute("type","outletres");
|
|
addFloat(outlt, "temperature", m_temp, "K");
|
|
for (size_t k=0; k < m_nsp; k++) {
|
|
addFloat(outlt, "massFraction", m_yres[k], "",
|
|
m_flow->phase().speciesName(k));
|
|
}
|
|
return outlt;
|
|
}
|
|
|
|
void OutletRes1D::restore(const XML_Node& dom, doublereal* soln, int loglevel)
|
|
{
|
|
Domain1D::restore(dom, soln, loglevel);
|
|
m_temp = getFloat(dom, "temperature");
|
|
|
|
m_yres.assign(m_nsp, 0.0);
|
|
for (size_t i = 0; i < dom.nChildren(); i++) {
|
|
const XML_Node& node = dom.child(i);
|
|
if (node.name() == "massFraction") {
|
|
size_t k = m_flow->phase().speciesIndex(node.attrib("type"));
|
|
if (k != npos) {
|
|
m_yres[k] = node.fp_value();
|
|
}
|
|
}
|
|
}
|
|
|
|
resize(1,1);
|
|
}
|
|
|
|
// -------- Surf1D --------
|
|
|
|
string Surf1D::componentName(size_t n) const
|
|
{
|
|
switch (n) {
|
|
case 0:
|
|
return "temperature";
|
|
default:
|
|
break;
|
|
}
|
|
return "<unknown>";
|
|
}
|
|
|
|
void Surf1D::init()
|
|
{
|
|
_init(1);
|
|
// set bounds (T)
|
|
setBounds(0, 200.0, 1e5);
|
|
|
|
// set tolerances
|
|
setSteadyTolerances(1e-4, 1e-4);
|
|
setTransientTolerances(1e-4, 1e-4);
|
|
}
|
|
|
|
void Surf1D::eval(size_t jg, doublereal* xg, doublereal* rg,
|
|
integer* diagg, doublereal rdt)
|
|
{
|
|
if (jg != npos && (jg + 2 < firstPoint() || jg > lastPoint() + 2)) {
|
|
return;
|
|
}
|
|
|
|
// start of local part of global arrays
|
|
doublereal* x = xg + loc();
|
|
doublereal* r = rg + loc();
|
|
integer* diag = diagg + loc();
|
|
doublereal* xb, *rb;
|
|
|
|
r[0] = x[0] - m_temp;
|
|
diag[0] = 0;
|
|
size_t nc;
|
|
|
|
if (m_flow_right) {
|
|
rb = r + 1;
|
|
xb = x + 1;
|
|
rb[2] = xb[2] - x[0]; // specified T
|
|
}
|
|
|
|
if (m_flow_left) {
|
|
nc = m_flow_left->nComponents();
|
|
rb = r - nc;
|
|
xb = x - nc;
|
|
rb[2] = xb[2] - x[0]; // specified T
|
|
}
|
|
}
|
|
|
|
XML_Node& Surf1D::save(XML_Node& o, const doublereal* const soln)
|
|
{
|
|
const doublereal* s = soln + loc();
|
|
XML_Node& inlt = Domain1D::save(o, soln);
|
|
inlt.addAttribute("type","surface");
|
|
for (size_t k = 0; k < nComponents(); k++) {
|
|
addFloat(inlt, componentName(k), s[k]);
|
|
}
|
|
return inlt;
|
|
}
|
|
|
|
void Surf1D::restore(const XML_Node& dom, doublereal* soln, int loglevel)
|
|
{
|
|
Domain1D::restore(dom, soln, loglevel);
|
|
soln[0] = m_temp = getFloat(dom, "temperature", "temperature");
|
|
resize(1,1);
|
|
}
|
|
|
|
// -------- ReactingSurf1D --------
|
|
|
|
string ReactingSurf1D::componentName(size_t n) const
|
|
{
|
|
if (n == 0) {
|
|
return "temperature";
|
|
} else if (n < m_nsp + 1) {
|
|
return m_sphase->speciesName(n-1);
|
|
} else {
|
|
return "<unknown>";
|
|
}
|
|
}
|
|
|
|
void ReactingSurf1D::init()
|
|
{
|
|
m_nv = m_nsp + 1;
|
|
_init(m_nsp+1);
|
|
m_fixed_cov.resize(m_nsp, 0.0);
|
|
m_fixed_cov[0] = 1.0;
|
|
m_work.resize(m_kin->nTotalSpecies(), 0.0);
|
|
|
|
setBounds(0, 200.0, 1e5);
|
|
for (size_t n = 0; n < m_nsp; n++) {
|
|
setBounds(n+1, -1.0e-5, 2.0);
|
|
}
|
|
setSteadyTolerances(1.0e-5, 1.0e-9);
|
|
setTransientTolerances(1.0e-5, 1.0e-9);
|
|
setSteadyTolerances(1.0e-5, 1.0e-4, 0);
|
|
setTransientTolerances(1.0e-5, 1.0e-4, 0);
|
|
}
|
|
|
|
void ReactingSurf1D::eval(size_t jg, doublereal* xg, doublereal* rg,
|
|
integer* diagg, doublereal rdt)
|
|
{
|
|
if (jg != npos && (jg + 2 < firstPoint() || jg > lastPoint() + 2)) {
|
|
return;
|
|
}
|
|
|
|
// start of local part of global arrays
|
|
doublereal* x = xg + loc();
|
|
doublereal* r = rg + loc();
|
|
integer* diag = diagg + loc();
|
|
doublereal* xb, *rb;
|
|
|
|
// specified surface temp
|
|
r[0] = x[0] - m_temp;
|
|
|
|
// set the coverages
|
|
doublereal sum = 0.0;
|
|
for (size_t k = 0; k < m_nsp; k++) {
|
|
m_work[k] = x[k+1];
|
|
sum += x[k+1];
|
|
}
|
|
m_sphase->setTemperature(x[0]);
|
|
m_sphase->setCoverages(m_work.data());
|
|
|
|
// set the left gas state to the adjacent point
|
|
|
|
size_t leftloc = 0, rightloc = 0;
|
|
size_t pnt = 0;
|
|
|
|
if (m_flow_left) {
|
|
leftloc = m_flow_left->loc();
|
|
pnt = m_flow_left->nPoints() - 1;
|
|
m_flow_left->setGas(xg + leftloc, pnt);
|
|
}
|
|
|
|
if (m_flow_right) {
|
|
rightloc = m_flow_right->loc();
|
|
m_flow_right->setGas(xg + rightloc, 0);
|
|
}
|
|
|
|
m_kin->getNetProductionRates(m_work.data());
|
|
doublereal rs0 = 1.0/m_sphase->siteDensity();
|
|
size_t ioffset = m_kin->kineticsSpeciesIndex(0, m_surfindex);
|
|
|
|
if (m_enabled) {
|
|
doublereal maxx = -1.0;
|
|
for (size_t k = 0; k < m_nsp; k++) {
|
|
r[k+1] = m_work[k + ioffset] * m_sphase->size(k) * rs0;
|
|
r[k+1] -= rdt*(x[k+1] - prevSoln(k+1,0));
|
|
diag[k+1] = 1;
|
|
maxx = std::max(x[k+1], maxx);
|
|
}
|
|
r[1] = 1.0 - sum;
|
|
diag[1] = 0;
|
|
} else {
|
|
for (size_t k = 0; k < m_nsp; k++) {
|
|
r[k+1] = x[k+1] - m_fixed_cov[k];
|
|
diag[k+1] = 0;
|
|
}
|
|
}
|
|
|
|
if (m_flow_right) {
|
|
rb = r + 1;
|
|
xb = x + 1;
|
|
rb[2] = xb[2] - x[0]; // specified T
|
|
}
|
|
size_t nc;
|
|
if (m_flow_left) {
|
|
nc = m_flow_left->nComponents();
|
|
const vector_fp& mwleft = m_phase_left->molecularWeights();
|
|
rb =r - nc;
|
|
xb = x - nc;
|
|
rb[2] = xb[2] - x[0]; // specified T
|
|
for (size_t nl = 1; nl < m_left_nsp; nl++) {
|
|
rb[4+nl] += m_work[nl]*mwleft[nl];
|
|
}
|
|
}
|
|
}
|
|
|
|
XML_Node& ReactingSurf1D::save(XML_Node& o, const doublereal* const soln)
|
|
{
|
|
const doublereal* s = soln + loc();
|
|
XML_Node& dom = Domain1D::save(o, soln);
|
|
dom.addAttribute("type","surface");
|
|
addFloat(dom, "temperature", s[0], "K");
|
|
for (size_t k=0; k < m_nsp; k++) {
|
|
addFloat(dom, "coverage", s[k+1], "",
|
|
m_sphase->speciesName(k));
|
|
}
|
|
return dom;
|
|
}
|
|
|
|
void ReactingSurf1D::restore(const XML_Node& dom, doublereal* soln,
|
|
int loglevel)
|
|
{
|
|
Domain1D::restore(dom, soln, loglevel);
|
|
soln[0] = m_temp = getFloat(dom, "temperature");
|
|
|
|
m_fixed_cov.assign(m_nsp, 0.0);
|
|
for (size_t i = 0; i < dom.nChildren(); i++) {
|
|
const XML_Node& node = dom.child(i);
|
|
if (node.name() == "coverage") {
|
|
size_t k = m_sphase->speciesIndex(node.attrib("type"));
|
|
if (k != npos) {
|
|
m_fixed_cov[k] = soln[k+1] = node.fp_value();
|
|
}
|
|
}
|
|
}
|
|
m_sphase->setCoverages(&m_fixed_cov[0]);
|
|
|
|
resize(m_nsp+1,1);
|
|
}
|
|
}
|