-
This commit is contained in:
parent
f8111bc15c
commit
32fed991cf
20 changed files with 1443 additions and 632 deletions
|
|
@ -3,8 +3,9 @@
|
|||
* @file DASPK.h
|
||||
*
|
||||
* Header file for class DASPK
|
||||
*
|
||||
* $Author$
|
||||
*/
|
||||
|
||||
/* $Author$
|
||||
* $Date$
|
||||
* $Revision$
|
||||
*
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ namespace Cantera {
|
|||
|
||||
doublereal SurfPhase::
|
||||
enthalpy_mole() const {
|
||||
if (m_n0 <= 0.0) return 0.0;
|
||||
_updateThermo();
|
||||
return mean_X(m_h0.begin());
|
||||
}
|
||||
|
|
@ -58,10 +59,14 @@ namespace Cantera {
|
|||
}
|
||||
|
||||
void SurfPhase::
|
||||
getActivityConcentrations(doublereal* c) const { getConcentrations(c); }
|
||||
getActivityConcentrations(doublereal* c) const {
|
||||
getConcentrations(c);
|
||||
}
|
||||
|
||||
doublereal SurfPhase::
|
||||
standardConcentration(int k) const { return m_n0/size(k); }
|
||||
standardConcentration(int k) const {
|
||||
return m_n0/size(k);
|
||||
}
|
||||
|
||||
doublereal SurfPhase::
|
||||
logStandardConc(int k) const {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,22 @@
|
|||
|
||||
namespace Cantera {
|
||||
|
||||
/// add a path to or from this node
|
||||
void SpeciesNode::addPath(Path* path) {
|
||||
m_paths.push_back(path);
|
||||
if (path->begin() == this) m_out += path->flow();
|
||||
else if (path->end() == this) m_in += path->flow();
|
||||
else throw CanteraError("addPath","path added to wrong node");
|
||||
}
|
||||
|
||||
void SpeciesNode::printPaths() {
|
||||
for (int i = 0; i < m_paths.size(); i++) {
|
||||
cout << m_paths[i]->begin()->name << " --> "
|
||||
<< m_paths[i]->end()->name << ": "
|
||||
<< m_paths[i]->flow() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a path connecting two species nodes.
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ namespace Cantera {
|
|||
|
||||
/// Default constructor
|
||||
SpeciesNode() : number(-1), name(""), value(0.0),
|
||||
visible(false) {}
|
||||
visible(false), m_in(0.0), m_out(0.0) {}
|
||||
|
||||
/// Destructor
|
||||
virtual ~SpeciesNode() {}
|
||||
|
|
@ -75,10 +75,17 @@ namespace Cantera {
|
|||
int nPaths() const { return m_paths.size(); }
|
||||
|
||||
/// add a path to or from this node
|
||||
void addPath(Path* path) { m_paths.push_back(path); }
|
||||
void addPath(Path* path);
|
||||
|
||||
double outflow() {return m_out;}
|
||||
double inflow() {return m_in;}
|
||||
double netOutflow() {return m_out - m_in;}
|
||||
|
||||
void printPaths();
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
double m_in, m_out;
|
||||
path_list m_paths;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,29 @@ extern "C" {
|
|||
|
||||
namespace Cantera {
|
||||
|
||||
/**
|
||||
* Linearly interpolate a function defined on a discrete grid.
|
||||
* vector xpts contains a monotonic sequence of grid points, and
|
||||
* vector fpts contains function values defined at these points.
|
||||
* The value returned is the linear interpolate at point x.
|
||||
* If x is outside the range of xpts, the value of fpts at the
|
||||
* nearest end is returned.
|
||||
*/
|
||||
|
||||
doublereal linearInterp(doublereal x, const vector_fp& xpts,
|
||||
const vector_fp& fpts) {
|
||||
if (x <= xpts[0]) return fpts[0];
|
||||
if (x >= xpts.back()) return fpts.back();
|
||||
const doublereal* loc = lower_bound(xpts.begin(), xpts.end(), x);
|
||||
int iloc = int(loc - xpts.begin()) - 1;
|
||||
doublereal ff = fpts[iloc] +
|
||||
(x - xpts[iloc])*(fpts[iloc + 1]
|
||||
- fpts[iloc])/(xpts[iloc + 1] - xpts[iloc]);
|
||||
return ff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
doublereal polyfit(int n, doublereal* x, doublereal* y, doublereal* w,
|
||||
int maxdeg, int& ndeg, doublereal eps, doublereal* r) {
|
||||
integer nn = n;
|
||||
|
|
|
|||
|
|
@ -771,7 +771,7 @@ namespace Cantera {
|
|||
int nt = th.size();
|
||||
|
||||
// for each referenced phase, attempt to find its id among those
|
||||
// phases that have already been built.
|
||||
// phases specified.
|
||||
bool phase_ok;
|
||||
|
||||
string phase_id;
|
||||
|
|
|
|||
|
|
@ -30,15 +30,16 @@ namespace Cantera {
|
|||
*/
|
||||
class Application {
|
||||
public:
|
||||
Application() : linelen(0) {}
|
||||
Application() : linelen(0), stop_on_error(false), write_log_to_cout(true) {}
|
||||
virtual ~Application(){}
|
||||
vector<string> inputDirs;
|
||||
vector<string> errorMessage;
|
||||
vector<string> warning;
|
||||
vector<string> errorRoutine;
|
||||
string msglog;
|
||||
bool stop_on_error;
|
||||
size_t linelen;
|
||||
bool stop_on_error;
|
||||
bool write_log_to_cout;
|
||||
map<string, string> options;
|
||||
};
|
||||
|
||||
|
|
@ -87,9 +88,9 @@ namespace Cantera {
|
|||
int i = __app->errorMessage.size();
|
||||
if (i == 0) return;
|
||||
f << endl << endl;
|
||||
f << "**********************" << endl;
|
||||
f << " Cantera Error! " << endl;
|
||||
f << "**********************" << endl << endl;
|
||||
f << "************************************************" << endl;
|
||||
f << " Cantera Error! " << endl;
|
||||
f << "************************************************" << endl << endl;
|
||||
int j;
|
||||
for (j = 0; j < i; j++) {
|
||||
f << endl;
|
||||
|
|
@ -259,6 +260,10 @@ namespace Cantera {
|
|||
__app->msglog += "\n";
|
||||
__app->linelen = 0;
|
||||
}
|
||||
if (__app->write_log_to_cout) {
|
||||
cout << __app->msglog;
|
||||
clearlog();
|
||||
}
|
||||
}
|
||||
void writelog(const char* msg) {writelog(string(msg));}
|
||||
void getlog(string& s) {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,28 @@
|
|||
/**
|
||||
* @file Inlet1D.h
|
||||
*
|
||||
* Boundary objects for one-dimensional simulations.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* $Author$
|
||||
* $Revision$
|
||||
* $Date$
|
||||
*
|
||||
* Copyright 2002-3 California Institute of Technology
|
||||
*/
|
||||
|
||||
|
||||
#ifndef CT_BDRY1D_H
|
||||
#define CT_BDRY1D_H
|
||||
|
||||
#include "Resid1D.h"
|
||||
//#include "surfacePhase.h"
|
||||
//#include "surfKinetics.h"
|
||||
#include "../SurfPhase.h"
|
||||
#include "../InterfaceKinetics.h"
|
||||
#include "StFlow.h"
|
||||
#include "OneDim.h"
|
||||
#include "ctml.h"
|
||||
#include "../ctml.h"
|
||||
|
||||
namespace Cantera {
|
||||
|
||||
|
|
@ -27,56 +42,75 @@ namespace Cantera {
|
|||
*/
|
||||
class Bdry1D : public Resid1D {
|
||||
public:
|
||||
Bdry1D() : Resid1D(1, 1, 0.0) {}
|
||||
|
||||
Bdry1D();
|
||||
|
||||
virtual ~Bdry1D() {}
|
||||
|
||||
/// Initialize.
|
||||
virtual void init(){err("init");}
|
||||
virtual void init() { _init(1); }
|
||||
|
||||
/// Set the temperature.
|
||||
virtual void setTemperature(doublereal t){err("setTemperature");}
|
||||
virtual void setTemperature(doublereal t){m_temp = t;}
|
||||
|
||||
/// Temperature [K].
|
||||
virtual doublereal temperature() {err("temperature"); return 0.0;}
|
||||
virtual doublereal temperature() {return m_temp;}
|
||||
|
||||
/// Set the mole fractions by specifying a string.
|
||||
virtual void setMoleFractions(string xin){err("setMoleFractions");}
|
||||
|
||||
/// Set the mole fractions by specifying an array.
|
||||
virtual void setMoleFractions(doublereal* xin){err("setMoleFractions");}
|
||||
|
||||
/// Mass fraction of species k.
|
||||
virtual doublereal massFraction(int k) {err("massFraction"); return 0.0;}
|
||||
|
||||
/// Set the total mass flow rate.
|
||||
virtual void setMdot(doublereal mdot){err("setMdot");}
|
||||
virtual void setMdot(doublereal mdot){m_mdot = mdot;}
|
||||
|
||||
/// The total mass flow rate [kg/m2/s].
|
||||
virtual doublereal mdot() {err("mdot"); return 0.0;}
|
||||
virtual doublereal mdot() {return m_mdot;}
|
||||
|
||||
protected:
|
||||
|
||||
void _init(int n);
|
||||
|
||||
StFlow *m_flow_left, *m_flow_right;
|
||||
int m_ilr, m_left_nv, m_right_nv;
|
||||
int m_left_loc, m_right_loc;
|
||||
int m_left_points;
|
||||
int m_nv, m_left_nsp, m_right_nsp;
|
||||
int m_sp_left, m_sp_right;
|
||||
int m_start_left, m_start_right;
|
||||
ThermoPhase *m_phase_left, *m_phase_right;
|
||||
doublereal m_temp, m_mdot;
|
||||
|
||||
private:
|
||||
void err(string method) {
|
||||
throw CanteraError("Bdry1D::"+method, "attempt to call base class method "+method);
|
||||
throw CanteraError("Bdry1D::"+method,
|
||||
"attempt to call base class method "+method);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An inlet.
|
||||
*/
|
||||
class Inlet1D : public Bdry1D {
|
||||
|
||||
public:
|
||||
|
||||
Inlet1D(int ilr = 1) {
|
||||
m_type = cInletType;
|
||||
m_flow = 0;
|
||||
m_ilr = ilr;
|
||||
/**
|
||||
* Constructor. Create a new Inlet1D instance. If invoked
|
||||
* without parameters, a left inlet (facing right) is
|
||||
* constructed).
|
||||
*/
|
||||
Inlet1D() : m_V0(0.0), m_nsp(0), m_flow(0) {
|
||||
m_type = cInletType;
|
||||
m_xstr = "";
|
||||
}
|
||||
virtual ~Inlet1D(){}
|
||||
|
||||
/// Set the inlet temperature
|
||||
virtual void setTemperature(doublereal t) {
|
||||
m_temp = t;
|
||||
needJacUpdate();
|
||||
}
|
||||
|
||||
/// set spreading rate
|
||||
virtual void setSpreadRate(doublereal V0) {
|
||||
m_V0 = V0;
|
||||
|
|
@ -88,432 +122,170 @@ namespace Cantera {
|
|||
return m_V0;
|
||||
}
|
||||
|
||||
/// Temperature [K].
|
||||
doublereal temperature() {return m_temp;}
|
||||
|
||||
virtual void setMoleFractions(string xin) {
|
||||
m_xstr = xin;
|
||||
virtual void showSolution(ostream& s, const doublereal* x) {
|
||||
s << "------------------- Inlet " << domainIndex() << " ------------------- " << endl;
|
||||
s << " mdot: " << m_mdot << " kg/m^2/s" << " " << x[0] << endl;
|
||||
s << " temperature: " << m_temp << " K" << " " << x[1] << endl;
|
||||
if (m_flow) {
|
||||
m_flow->phase().setMoleFractionsByName(xin);
|
||||
m_flow->phase().getMassFractions(m_yin.begin());
|
||||
needJacUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void setMoleFractions(doublereal* xin) {
|
||||
if (m_flow) {
|
||||
m_flow->phase().setMoleFractions(xin);
|
||||
m_flow->phase().getMassFractions(m_yin.begin());
|
||||
needJacUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
virtual doublereal massFraction(int k) {return m_yin[k];}
|
||||
|
||||
virtual void setMdot(doublereal mdot) { m_mdot = mdot; }
|
||||
|
||||
virtual string componentName(int n) const {
|
||||
switch (n) {
|
||||
case 0: return "mdot"; break;
|
||||
case 1: return "temperature"; break;
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
virtual void init() {
|
||||
if (m_index < 0) {
|
||||
throw CanteraError("Inlet1D",
|
||||
"install in container before calling init.");
|
||||
}
|
||||
resize(2,1);
|
||||
|
||||
// set bounds
|
||||
const doublereal lower[2] = {-1.0e5, 200.0};
|
||||
const doublereal upper[2] = {1.0e5, 1.e5};
|
||||
setBounds(2, lower, 2, upper);
|
||||
|
||||
// set tolerances
|
||||
vector_fp rtol(2, 1e-4);
|
||||
vector_fp atol(2, 1.e-5);
|
||||
setTolerances(2, rtol.begin(), 2, atol.begin());
|
||||
|
||||
// if a flow domain is present on the left, then this must
|
||||
// be a right inlet
|
||||
if (m_index > 0) {
|
||||
Resid1D& r = container().domain(m_index-1);
|
||||
if (r.domainType() == cFlowType) {
|
||||
m_ilr = RightInlet;
|
||||
m_flow = (StFlow*)&r;
|
||||
}
|
||||
else
|
||||
throw CanteraError("Inlet1D::init",
|
||||
"Inlet domains can only be connected to a flow domain.");
|
||||
}
|
||||
else {
|
||||
if (container().nDomains() > 1) {
|
||||
Resid1D& r = container().domain(1);
|
||||
if (r.domainType() == cFlowType) {
|
||||
m_ilr = LeftInlet;
|
||||
m_flow = (StFlow*)&r;
|
||||
s << " mass fractions: " << endl;
|
||||
for (int k = 0; k < m_flow->phase().nSpecies(); k++) {
|
||||
if (m_yin[k] != 0.0) {
|
||||
s << " " << m_flow->phase().speciesName(k)
|
||||
<< " " << m_yin[k] << endl;
|
||||
}
|
||||
else
|
||||
throw CanteraError("Inlet1D::init",
|
||||
"An inlet domain can only be connected to a flow domain.");
|
||||
}
|
||||
else
|
||||
throw CanteraError("Inlet1D::init",
|
||||
"An inlet domain must be connected to a flow domain.");
|
||||
}
|
||||
// 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;
|
||||
s << endl;
|
||||
}
|
||||
|
||||
virtual void _getInitialSoln(doublereal* x) {
|
||||
x[0] = m_mdot;
|
||||
x[1] = m_temp;
|
||||
}
|
||||
|
||||
virtual void _finalize(const doublereal* x) {
|
||||
; //m_mdot = x[0];
|
||||
//m_temp = x[1];
|
||||
}
|
||||
|
||||
virtual void setMoleFractions(string xin);
|
||||
virtual void setMoleFractions(doublereal* xin);
|
||||
virtual doublereal massFraction(int k) {return m_yin[k];}
|
||||
virtual string componentName(int n) const;
|
||||
virtual void init();
|
||||
virtual void eval(int jg, doublereal* xg, doublereal* rg,
|
||||
integer* diagg, doublereal rdt) {
|
||||
int k;
|
||||
if (jg >= 0 && (jg < firstPoint() - 2 || 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];
|
||||
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;
|
||||
|
||||
// If the energy equation is being solved, then
|
||||
// the flow domain set this residual to T(0).
|
||||
// Subtract the inlet temperature.
|
||||
if (m_flow->doEnergy(0)) {
|
||||
rb[2] -= x[1]; // T
|
||||
}
|
||||
|
||||
// spreading rate. Flow domain sets this to V(0),
|
||||
// so for finite spreading rate subtract m_V0.
|
||||
rb[1] -= m_V0;
|
||||
|
||||
rb[3] += x[0]; // lambda
|
||||
for (k = 0; k < m_nsp; k++) {
|
||||
rb[4+k] += x[0]*m_yin[k];
|
||||
}
|
||||
}
|
||||
|
||||
// right inlet.
|
||||
else {
|
||||
int boffset = m_flow->nComponents();
|
||||
xb = x - boffset;
|
||||
rb = r - boffset;
|
||||
rb[1] -= m_V0;
|
||||
rb[2] -= x[1]; // T
|
||||
xb[0] += x[0]; // u
|
||||
for (k = 0; k < m_nsp; k++)
|
||||
rb[4+k] += x[0]*m_yin[k];
|
||||
}
|
||||
}
|
||||
|
||||
virtual void save(XML_Node& o, doublereal* soln) {
|
||||
doublereal* s = soln + loc();
|
||||
XML_Node& inlt = o.addChild("inlet");
|
||||
for (int k = 0; k < 2; k++) {
|
||||
ctml::addFloat(inlt, componentName(k), s[k], "", "",0.0, 1.0);
|
||||
}
|
||||
}
|
||||
integer* diagg, doublereal rdt);
|
||||
virtual void save(XML_Node& o, doublereal* soln);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
int m_ilr;
|
||||
doublereal m_mdot, m_temp, m_V0;
|
||||
StFlow *m_flow;
|
||||
doublereal m_V0;
|
||||
int m_nsp;
|
||||
vector_fp m_yin;
|
||||
string m_xstr;
|
||||
StFlow *m_flow;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* A symmetry plane. The axial velocity u = 0, and all other
|
||||
* components have zero axial gradients.
|
||||
*/
|
||||
class Symm1D : public Bdry1D {
|
||||
|
||||
public:
|
||||
|
||||
Symm1D(int ilr = 1) {
|
||||
Symm1D() {
|
||||
m_type = cSymmType;
|
||||
m_flow = 0;
|
||||
m_ilr = ilr;
|
||||
}
|
||||
virtual ~Symm1D(){}
|
||||
|
||||
virtual string componentName(int n) const {
|
||||
switch (n) {
|
||||
case 0: return "dummy"; break;
|
||||
default: return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
virtual void init() {
|
||||
if (m_index < 0) {
|
||||
throw CanteraError("Symm1D",
|
||||
"install in container before calling init.");
|
||||
}
|
||||
resize(1,1);
|
||||
|
||||
// set bounds
|
||||
const doublereal lower = -1.0e5;
|
||||
const doublereal upper = 1.0e5;
|
||||
setBounds(1, &lower, 1, &upper);
|
||||
|
||||
// set tolerances
|
||||
doublereal rtol = 1e-4;
|
||||
doublereal atol = 1.e-5;
|
||||
setTolerances(1, &rtol, 1, &atol);
|
||||
|
||||
if (m_index > 0) {
|
||||
Resid1D& r = container().domain(m_index-1);
|
||||
if (r.domainType() == cFlowType) {
|
||||
m_ilr = -1;
|
||||
m_flow = (StFlow*)&r;
|
||||
}
|
||||
else
|
||||
throw CanteraError("Symm1D::init",
|
||||
"Symmetry planes can only be connected to flow domains.");
|
||||
}
|
||||
else {
|
||||
if (container().nDomains() > 1) {
|
||||
Resid1D& r = container().domain(1);
|
||||
if (r.domainType() == cFlowType) {
|
||||
m_ilr = 1;
|
||||
m_flow = (StFlow*)&r;
|
||||
}
|
||||
else
|
||||
throw CanteraError("Symm1D::init",
|
||||
"Symmetry planes can only be connected to flow domains.");
|
||||
}
|
||||
else
|
||||
throw CanteraError("Symm1D::init",
|
||||
"A symmetry plane must be connected to a flow domain.");
|
||||
}
|
||||
m_nsp = m_flow->nComponents() - 4;
|
||||
}
|
||||
virtual string componentName(int n) const;
|
||||
|
||||
virtual void init();
|
||||
|
||||
virtual void eval(int jg, doublereal* xg, doublereal* rg,
|
||||
integer* diagg, doublereal rdt) {
|
||||
int k;
|
||||
if (jg >= 0 && (jg < firstPoint() - 2 || jg > lastPoint() + 2)) return;
|
||||
integer* diagg, doublereal rdt);
|
||||
|
||||
// start of local part of global arrays
|
||||
doublereal* x = xg + loc();
|
||||
doublereal* r = rg + loc();
|
||||
integer* diag = diagg + loc();
|
||||
doublereal *xb, *rb;
|
||||
// integer *db = diag + loc();
|
||||
|
||||
r[0] = x[0];
|
||||
diag[0] = 0;
|
||||
int nc = m_flow->nComponents();
|
||||
|
||||
if (m_ilr == 1) {
|
||||
xb = x + 1;
|
||||
rb = r + 1;
|
||||
rb[0] = xb[0];
|
||||
rb[1] = xb[1] - xb[1 + nc];
|
||||
if (m_flow->doEnergy(0)) {
|
||||
rb[2] = xb[2] - xb[2 + nc];
|
||||
}
|
||||
rb[3] = xb[3] - xb[3 + nc];
|
||||
for (k = 0; k < m_nsp; k++) {
|
||||
rb[4+k] = xb[4+k] - xb[4+k+nc];
|
||||
}
|
||||
}
|
||||
else {
|
||||
xb = x - nc;
|
||||
rb = r - nc;
|
||||
rb[0] = xb[0];
|
||||
rb[1] = xb[1] - xb[1 - nc];
|
||||
// if (m_flow->doEnergy(0)) {
|
||||
rb[2] = xb[2] - xb[2 - nc];
|
||||
// }
|
||||
rb[3] = xb[3] - xb[3 - nc];
|
||||
for (k = 0; k < m_nsp; k++) {
|
||||
rb[4+k] = xb[4+k] - xb[4+k-nc];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void save(XML_Node& o, doublereal* soln) {
|
||||
// doublereal* s = soln + loc();
|
||||
// XML_Node& symm = o.addChild("symmetry_plane");
|
||||
(void) o.addChild("symmetry_plane");
|
||||
}
|
||||
virtual void save(XML_Node& o, doublereal* soln);
|
||||
|
||||
protected:
|
||||
|
||||
int m_ilr;
|
||||
StFlow *m_flow;
|
||||
int m_nsp;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// surf1D
|
||||
//
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* A non-reacting surface. The axial velocity is zero
|
||||
* (impermeable), as is the transverse velocity (no slip). The
|
||||
* temperature is specified, and a zero flux condition is imposed
|
||||
* for the species.
|
||||
*/
|
||||
class Surf1D : public Bdry1D {
|
||||
|
||||
public:
|
||||
|
||||
Surf1D(int ilr = 1) {
|
||||
Surf1D() {
|
||||
m_type = cSurfType;
|
||||
m_flow = 0;
|
||||
m_ilr = ilr;
|
||||
}
|
||||
virtual ~Surf1D(){}
|
||||
|
||||
/// Set the surface temperature
|
||||
virtual void setTemperature(doublereal t) {
|
||||
m_temp = t;
|
||||
needJacUpdate();
|
||||
}
|
||||
|
||||
/// Temperature [K].
|
||||
doublereal temperature() {return m_temp;}
|
||||
|
||||
virtual string componentName(int n) const {
|
||||
switch (n) {
|
||||
case 0: return "dummy"; break;
|
||||
case 1: return "temperature"; break;
|
||||
default: return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
virtual void init() {
|
||||
if (m_index < 0) {
|
||||
throw CanteraError("Surf1D",
|
||||
"install in container before calling init.");
|
||||
}
|
||||
resize(2,1);
|
||||
|
||||
// set bounds
|
||||
const doublereal lower[2] = {-1.0e5, 200.0};
|
||||
const doublereal upper[2] = {1.0e5, 1.e5};
|
||||
setBounds(2, lower, 2, upper);
|
||||
|
||||
// set tolerances
|
||||
vector_fp rtol(2, 1e-4);
|
||||
vector_fp atol(2, 1.e-5);
|
||||
setTolerances(2, rtol.begin(), 2, atol.begin());
|
||||
|
||||
if (m_index > 0) {
|
||||
Resid1D& r = container().domain(m_index-1);
|
||||
if (r.domainType() == cFlowType) {
|
||||
m_ilr = -1;
|
||||
m_flow = (StFlow*)&r;
|
||||
}
|
||||
else
|
||||
throw CanteraError("Surf1D::init",
|
||||
"Surface domains can only be connected to a flow domain.");
|
||||
}
|
||||
else {
|
||||
if (container().nDomains() > 1) {
|
||||
Resid1D& r = container().domain(1);
|
||||
if (r.domainType() == cFlowType) {
|
||||
m_ilr = 1;
|
||||
m_flow = (StFlow*)&r;
|
||||
}
|
||||
else
|
||||
throw CanteraError("Surf1D::init",
|
||||
"A surface domain can only be connected to a flow domain.");
|
||||
}
|
||||
else
|
||||
throw CanteraError("Surf1D::init",
|
||||
"A surface domain must be connected to a flow domain.");
|
||||
}
|
||||
m_nsp = m_flow->nComponents() - 4;
|
||||
}
|
||||
virtual string componentName(int n) const;
|
||||
|
||||
virtual void init();
|
||||
|
||||
virtual void eval(int jg, doublereal* xg, doublereal* rg,
|
||||
integer* diagg, doublereal rdt) {
|
||||
int k;
|
||||
if (jg >= 0 && (jg < firstPoint() - 2 || jg > lastPoint() + 2)) return;
|
||||
integer* diagg, doublereal rdt);
|
||||
|
||||
// start of local part of global arrays
|
||||
doublereal* x = xg + loc();
|
||||
doublereal* r = rg + loc();
|
||||
integer* diag = diagg + loc();
|
||||
doublereal *xb, *rb;
|
||||
//integer *db = diag + loc();
|
||||
virtual void save(XML_Node& o, doublereal* soln);
|
||||
|
||||
r[0] = x[0];
|
||||
r[1] = m_temp - x[1];
|
||||
diag[0] = 0;
|
||||
diag[1] = 0;
|
||||
int nc = m_flow->nComponents();
|
||||
|
||||
if (m_ilr == 1) {
|
||||
xb = x + 2;
|
||||
rb = r + 2;
|
||||
rb[0] = xb[0];
|
||||
rb[1] = xb[1]; // T
|
||||
// if (m_flow->doEnergy(0)) {
|
||||
rb[2] = xb[2] - x[1]; // T
|
||||
//}
|
||||
rb[3] = xb[3] - xb[3 + nc]; // lambda
|
||||
for (k = 0; k < m_nsp; k++) {
|
||||
rb[4+k] += xb[4+k] - xb[4+k+nc];
|
||||
}
|
||||
}
|
||||
else {
|
||||
xb = x - nc;
|
||||
rb = r - nc;
|
||||
rb[0] = xb[0];
|
||||
rb[1] = xb[1]; // T
|
||||
// if (m_flow->doEnergy(0)) {
|
||||
rb[2] = xb[2] - x[1]; // T
|
||||
//}
|
||||
rb[3] = xb[3] - xb[3 - nc]; // lambda
|
||||
for (k = 0; k < m_nsp; k++) {
|
||||
rb[4+k] += xb[4+k] - xb[4+k-nc];
|
||||
}
|
||||
}
|
||||
virtual void _getInitialSoln(doublereal* x) {
|
||||
x[0] = m_temp;
|
||||
}
|
||||
|
||||
virtual void save(XML_Node& o, doublereal* soln) {
|
||||
doublereal* s = soln + loc();
|
||||
XML_Node& srf = o.addChild("surface");
|
||||
for (int k = 1; k < 2; k++) {
|
||||
ctml::addFloat(srf, componentName(k), s[k], "", "",0.0, 1.0);
|
||||
}
|
||||
virtual void _finalize(const doublereal* x) {
|
||||
; //m_temp = x[0];
|
||||
}
|
||||
|
||||
virtual void showSolution(ostream& s, const doublereal* x) {
|
||||
s << "------------------- Surface " << domainIndex() << " ------------------- " << endl;
|
||||
s << " temperature: " << m_temp << " K" << " " << x[0] << endl;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
int m_ilr;
|
||||
doublereal m_temp;
|
||||
StFlow *m_flow;
|
||||
int m_nsp;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
// // };
|
||||
|
||||
|
||||
|
||||
// // /////////////////////////////////////////////////////////////
|
||||
// // //
|
||||
// // // surf1D
|
||||
// // //
|
||||
// // ////////////////////////////////////////////////////////////
|
||||
// // #ifdef WITH_CHEMSURF
|
||||
|
||||
// // class ChemSurf1D : public Bdry1D {
|
||||
|
||||
// // public:
|
||||
|
||||
// // ChemSurf1D(InterfaceKinetics* skin = 0) {
|
||||
// // m_type = cSurfType;
|
||||
// // m_kin = 0;
|
||||
// // m_sphase = 0;
|
||||
// // m_nsp = 0;
|
||||
// // if (skin) setKinetics(skin);
|
||||
// // }
|
||||
// // virtual ~ChemSurf1D(){}
|
||||
|
||||
// // void setKinetics(InterfaceKinetics* kin);
|
||||
|
||||
// // virtual string componentName(int n) const;
|
||||
// // virtual void init();
|
||||
|
||||
// // virtual void eval(int jg, doublereal* xg, doublereal* rg,
|
||||
// // integer* diagg, doublereal rdt);
|
||||
|
||||
// // virtual void save(XML_Node& o, doublereal* soln);
|
||||
|
||||
// // protected:
|
||||
|
||||
// // int m_ilr, m_nsp;
|
||||
// InterfaceKinetics* m_kin;
|
||||
// SurfPhase* m_sphase;
|
||||
// vector_fp m_work;
|
||||
// const doublereal *m_molwt_right, *m_molwt_left;
|
||||
// int m_start_surf;
|
||||
// vector<ThermoPhase*> m_bulk;
|
||||
// vector<int> m_nbulk;
|
||||
// int m_nsurf;
|
||||
// vector_fp m_mult;
|
||||
// vector<bool> m_do_surf_species;
|
||||
// vector_fp m_fixed_cov;
|
||||
// };
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ OBJDIR = .
|
|||
CXX_FLAGS = @CXXFLAGS@ $(CXX_OPT)
|
||||
|
||||
# stirred reactors
|
||||
OBJS = MultiJac.o MultiNewton.o newton_utils.o OneDim.o StFlow.o
|
||||
OBJS = MultiJac.o MultiNewton.o newton_utils.o OneDim.o StFlow.o boundaries1D.o refine.o Sim1D.o
|
||||
|
||||
CXX_INCLUDES = -I..
|
||||
ONED_LIB = @buildlib@/liboneD.a
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ namespace Cantera {
|
|||
writelog("\n\nDamped Newton iteration:\n");
|
||||
writelog(dashedline);
|
||||
|
||||
sprintf(m_buf,"\n%s %8s %8s %8s %8s %8s %5s\n",
|
||||
sprintf(m_buf,"\n%s %9s %9s %9s %9s %9s %5s\n",
|
||||
"m","F_damp","F_bound","log10(ss)",
|
||||
"log10(s0)","log10(s1)","N_jac");
|
||||
writelog(m_buf);
|
||||
|
|
@ -226,7 +226,7 @@ namespace Cantera {
|
|||
// write log information
|
||||
if (loglevel > 0) {
|
||||
doublereal ss = r.ssnorm(x1,step1);
|
||||
sprintf(m_buf,"\n%d %8.4f %8.4f %8.4f %8.4f %8.4f %5d ",
|
||||
sprintf(m_buf,"\n%d %9.5f %9.5f %9.5f %9.5f %9.5f %5d ",
|
||||
m,damp,fbound,log10(ss+SmallNumber),
|
||||
log10(s0+SmallNumber),
|
||||
log10(s1+SmallNumber),
|
||||
|
|
|
|||
|
|
@ -17,15 +17,16 @@ namespace Cantera {
|
|||
* Default constructor. Create an empty object.
|
||||
*/
|
||||
OneDim::OneDim()
|
||||
: m_jac(0), m_newt(0),
|
||||
m_rdt(0.0), m_jac_ok(false),
|
||||
m_nd(0), m_bw(0), m_size(0),
|
||||
m_nflow(0), m_nbdry(0), m_init(false),
|
||||
m_ss_jac_age(10), m_ts_jac_age(20),
|
||||
m_nevals(0), m_evaltime(0.0)
|
||||
: m_tmin(1.0e-16), m_tmax(0.1), m_tfactor(0.5),
|
||||
m_jac(0), m_newt(0),
|
||||
m_rdt(0.0), m_jac_ok(false),
|
||||
m_nd(0), m_bw(0), m_size(0),
|
||||
m_init(false),
|
||||
m_ss_jac_age(10), m_ts_jac_age(20),
|
||||
m_nevals(0), m_evaltime(0.0)
|
||||
{
|
||||
m_newt = new MultiNewton(1);
|
||||
m_solve_time = 0.0;
|
||||
//m_solve_time = 0.0;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -33,11 +34,12 @@ namespace Cantera {
|
|||
* Construct a OneDim container for the domains pointed at by the
|
||||
* input vector of pointers.
|
||||
*/
|
||||
OneDim::OneDim(vector<Resid1D*> domains) :
|
||||
OneDim::OneDim(vector<Resid1D*> domains) :
|
||||
m_tmin(1.0e-16), m_tmax(0.1), m_tfactor(0.5),
|
||||
m_jac(0), m_newt(0),
|
||||
m_rdt(0.0), m_jac_ok(false),
|
||||
m_nd(0), m_bw(0), m_size(0),
|
||||
m_nflow(0), m_nbdry(0), m_init(false),
|
||||
m_init(false),
|
||||
m_ss_jac_age(10), m_ts_jac_age(20),
|
||||
m_nevals(0), m_evaltime(0.0)
|
||||
{
|
||||
|
|
@ -46,17 +48,25 @@ namespace Cantera {
|
|||
m_newt = new MultiNewton(1);
|
||||
int nd = domains.size();
|
||||
int i;
|
||||
for (i = 0; i < nd; i++) addDomain(domains[i]);
|
||||
for (i = 0; i < nd; i++) {
|
||||
addDomain(domains[i]);
|
||||
}
|
||||
init();
|
||||
resize();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Domains are added left-to-right.
|
||||
*/
|
||||
void OneDim::addDomain(Resid1D* d) {
|
||||
|
||||
// if not the first domain, link it to the last (rightmost)
|
||||
// current domain
|
||||
// if 'd' is not the first domain, link it to the last domain
|
||||
// added (the rightmost one)
|
||||
int n = m_dom.size();
|
||||
if (m_dom.size() > 0) m_dom.back()->append(d);
|
||||
if (n > 0) m_dom.back()->append(d);
|
||||
|
||||
// every other domain is a connector
|
||||
if (2*(n/2) == n)
|
||||
m_connect.push_back(d);
|
||||
else
|
||||
|
|
@ -93,6 +103,18 @@ namespace Cantera {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save statistics on function and Jacobiab evaulation, and reset
|
||||
* the counters. Statistics are saved only if the number of
|
||||
* Jacobian evaluations is greater than zero. The statistics saved
|
||||
* are
|
||||
*
|
||||
* - number of grid points
|
||||
* - number of Jacobian evaluations
|
||||
* - CPU time spent evaluating Jacobians
|
||||
* - number of non-Jacobian function evaluations
|
||||
* - CPU time spent evaluating functions
|
||||
*/
|
||||
void OneDim::saveStats() {
|
||||
if (m_jac) {
|
||||
int nev = m_jac->nEvals();
|
||||
|
|
@ -108,16 +130,18 @@ namespace Cantera {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Call after one or more grids has been refined.
|
||||
*/
|
||||
void OneDim::resize() {
|
||||
int i;
|
||||
m_bw = 0;
|
||||
m_nvars.clear();
|
||||
m_loc.clear();
|
||||
|
||||
vector_int nvars, loc;
|
||||
int lc = 0;
|
||||
|
||||
// save the statistics for the last grid
|
||||
saveStats();
|
||||
|
||||
m_pts = 0;
|
||||
for (i = 0; i < m_nd; i++) {
|
||||
Resid1D* d = m_dom[i];
|
||||
|
|
@ -125,8 +149,8 @@ namespace Cantera {
|
|||
int np = d->nPoints();
|
||||
int nv = d->nComponents();
|
||||
for (int n = 0; n < np; n++) {
|
||||
m_nvars.push_back(nv);
|
||||
m_loc.push_back(lc);
|
||||
nvars.push_back(nv);
|
||||
loc.push_back(lc);
|
||||
lc += nv;
|
||||
m_pts++;
|
||||
}
|
||||
|
|
@ -147,9 +171,13 @@ namespace Cantera {
|
|||
|
||||
m_size = d->loc() + d->size();
|
||||
}
|
||||
m_nvars = nvars;
|
||||
m_loc = loc;
|
||||
|
||||
m_newt->resize(size());
|
||||
m_mask.resize(size());
|
||||
|
||||
|
||||
// delete the current Jacobian evaluator and create a new one
|
||||
delete m_jac;
|
||||
m_jac = new MultiJac(*this);
|
||||
m_jac_ok = false;
|
||||
|
|
@ -160,20 +188,13 @@ namespace Cantera {
|
|||
|
||||
|
||||
int OneDim::solve(doublereal* x, doublereal* xnew, int loglevel) {
|
||||
clock_t t0 = clock();
|
||||
static int iok = 0, inotok = 0;
|
||||
if (!m_jac_ok) {
|
||||
eval(-1, x, xnew, 0.0, 0); // m_rdt);
|
||||
m_jac->eval(x, xnew, 0.0); // m_rdt);
|
||||
eval(-1, x, xnew, 0.0, 0);
|
||||
m_jac->eval(x, xnew, 0.0);
|
||||
m_jac->updateTransient(m_rdt, m_mask.begin());
|
||||
m_jac_ok = true;
|
||||
inotok++;
|
||||
}
|
||||
else
|
||||
iok++;
|
||||
int m = m_newt->solve(x, xnew, *this, *m_jac, loglevel);
|
||||
clock_t t1 = clock();
|
||||
m_solve_time += (t1 - t0)/(1.0*CLOCKS_PER_SEC);
|
||||
return m;
|
||||
}
|
||||
|
||||
|
|
@ -202,16 +223,21 @@ namespace Cantera {
|
|||
*/
|
||||
void OneDim::eval(int j, double* x, double* r, doublereal rdt, int count) {
|
||||
clock_t t0 = clock();
|
||||
fill(r, r+m_size, 0.0);
|
||||
fill(r, r + m_size, 0.0);
|
||||
fill(m_mask.begin(), m_mask.end(), 0);
|
||||
if (rdt < 0.0) rdt = m_rdt;
|
||||
|
||||
vector<Resid1D*>::iterator d;
|
||||
|
||||
// iterate over the bulk domains first
|
||||
for (d = m_bulk.begin(); d != m_bulk.end(); ++d)
|
||||
(*d)->eval(j, x, r, m_mask.begin(), rdt);
|
||||
|
||||
// then over the connector domains
|
||||
for (d = m_connect.begin(); d != m_connect.end(); ++d)
|
||||
(*d)->eval(j, x, r, m_mask.begin(), rdt);
|
||||
|
||||
// increment counter and time
|
||||
if (count) {
|
||||
clock_t t1 = clock();
|
||||
m_evaltime += double(t1 - t0)/CLOCKS_PER_SEC;
|
||||
|
|
@ -220,7 +246,7 @@ namespace Cantera {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
/**
|
||||
* The 'infinity' (maximum magnitude) norm of the steady-state
|
||||
* residual. Used only for diagnostic output.
|
||||
*/
|
||||
|
|
@ -240,9 +266,15 @@ namespace Cantera {
|
|||
void OneDim::initTimeInteg(doublereal dt, doublereal* x) {
|
||||
doublereal rdt_old = m_rdt;
|
||||
m_rdt = 1.0/dt;
|
||||
|
||||
// if the stepsize has changed, then update the transient
|
||||
// part of the Jacobian
|
||||
if (fabs(rdt_old - m_rdt) > Tiny) {
|
||||
m_jac->updateTransient(m_rdt, m_mask.begin());
|
||||
}
|
||||
|
||||
// iterate over all domains, preparing each one to begin
|
||||
// time stepping
|
||||
Resid1D* d = left();
|
||||
while (d) {
|
||||
d->initTimeInteg(dt, x);
|
||||
|
|
@ -250,7 +282,8 @@ namespace Cantera {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
/**
|
||||
* Prepare to solve the steady-state problem. Set the reciprocal
|
||||
* of the time step to zero, and, if it was previously non-zero,
|
||||
* signal that a new Jacobian will be needed.
|
||||
|
|
@ -276,6 +309,7 @@ namespace Cantera {
|
|||
m_init = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Signal that the current Jacobian is no longer valid.
|
||||
*/
|
||||
|
|
@ -284,6 +318,7 @@ namespace Cantera {
|
|||
m_container->jacobian().setAge(10000);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Take time steps using Backward Euler.
|
||||
*
|
||||
|
|
@ -294,13 +329,15 @@ namespace Cantera {
|
|||
doublereal OneDim::timeStep(int nsteps, doublereal dt, doublereal* x,
|
||||
doublereal* r, int loglevel) {
|
||||
|
||||
// set the Jacobian age parameter to the transient value
|
||||
newton().setOptions(m_ts_jac_age);
|
||||
|
||||
if (loglevel > 0) {
|
||||
writelog("Begin time integration.\n\n");
|
||||
writelog(" step size (s) log10(ss) ");
|
||||
writelog("===============================");
|
||||
//writelog("Begin time stepping.\n\n");
|
||||
writelog("\n\n step size (s) log10(ss) \n");
|
||||
writelog("===============================\n");
|
||||
}
|
||||
|
||||
int n = 0, m;
|
||||
doublereal ss;
|
||||
char str[80];
|
||||
|
|
@ -310,32 +347,54 @@ namespace Cantera {
|
|||
sprintf(str, " %4d %10.4g %10.4g" , n,dt,log10(ss));
|
||||
writelog(str);
|
||||
}
|
||||
|
||||
// set up for time stepping with stepsize dt
|
||||
initTimeInteg(dt,x);
|
||||
|
||||
// solve the transient problem
|
||||
m = solve(x, r, loglevel-1);
|
||||
|
||||
// successful time step. Copy the new solution in r to
|
||||
// the current solution in x.
|
||||
if (m >= 0) {
|
||||
n += 1;
|
||||
if (loglevel > 0) writelog("\n");
|
||||
copy(r, r + m_size, x);
|
||||
if (m == 100) {
|
||||
dt *= 1.5;
|
||||
cout << "m = 100, dt = " << dt << endl;
|
||||
}
|
||||
if (dt > m_tmax) dt = m_tmax;
|
||||
}
|
||||
|
||||
// No solution could be found with this time step.
|
||||
// Decrease the stepsize and try again.
|
||||
else {
|
||||
if (loglevel > 0) writelog("...failure.");
|
||||
dt *= 0.5;
|
||||
if (dt < 1.e-14)
|
||||
if (loglevel > 0) writelog("...failure.\n");
|
||||
dt *= m_tfactor;
|
||||
cout << "halved dt = " << dt << endl;
|
||||
if (dt < m_tmin)
|
||||
throw CanteraError("OneDim::timeStep",
|
||||
"Time integration failed.");
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare to solve the steady problem.
|
||||
setSteadyMode();
|
||||
newton().setOptions(m_ss_jac_age);
|
||||
newton().setOptions(m_ss_jac_age);
|
||||
|
||||
// return the value of the last stepsize, which may be smaller
|
||||
// than the initial stepsize
|
||||
return dt;
|
||||
}
|
||||
|
||||
|
||||
void OneDim::save(string fname, string id, string desc, doublereal* sol) {
|
||||
|
||||
struct tm *newtime;
|
||||
time_t aclock;
|
||||
::time( &aclock ); /* Get time in seconds */
|
||||
newtime = localtime( &aclock ); /* Convert time to struct tm form */
|
||||
::time( &aclock ); /* Get time in seconds */
|
||||
newtime = localtime( &aclock ); /* Convert time to struct tm form */
|
||||
|
||||
XML_Node root("doc");
|
||||
ifstream fin(fname.c_str());
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ namespace Cantera {
|
|||
* represented by an instance of Resid1D.
|
||||
*/
|
||||
class OneDim {
|
||||
|
||||
public:
|
||||
|
||||
// Default constructor.
|
||||
|
|
@ -31,14 +32,19 @@ namespace Cantera {
|
|||
/// Add a domain.
|
||||
void addDomain(Resid1D* d);
|
||||
|
||||
/// Return a reference to the Jacobian.
|
||||
/// Return a reference to the Jacobian evaluator.
|
||||
MultiJac& jacobian();
|
||||
|
||||
/// Return a reference to the Newton iterator.
|
||||
MultiNewton& newton();
|
||||
|
||||
/// Solve F(x) = 0, where F(x) is the multi-domain residual.
|
||||
int solve(doublereal* x, doublereal* xnew, int loglevel);
|
||||
/**
|
||||
* Solve F(x) = 0, where F(x) is the multi-domain residual function.
|
||||
* @param x0 Starting estimate of solution.
|
||||
* @param x1 Final solution satisfying F(x1) = 0.
|
||||
* @param loglevel Controls amount of diagnostic output.
|
||||
*/
|
||||
int solve(doublereal* x0, doublereal* x1, int loglevel);
|
||||
|
||||
/// Number of domains.
|
||||
int nDomains() const { return m_nd; }
|
||||
|
|
@ -61,8 +67,10 @@ namespace Cantera {
|
|||
/// Number of solution components at global point jg.
|
||||
int nVars(int jg) { return m_nvars[jg]; }
|
||||
|
||||
/** Location in the solution vector of the first component of
|
||||
global point jg. */
|
||||
/**
|
||||
* Location in the solution vector of the first component of
|
||||
* global point jg.
|
||||
*/
|
||||
int loc(int jg) { return m_loc[jg]; }
|
||||
|
||||
/// Jacobian bandwidth.
|
||||
|
|
@ -74,13 +82,16 @@ namespace Cantera {
|
|||
/// Total number of points.
|
||||
int points() { return m_pts; }
|
||||
|
||||
/// Staedy-state max norm of the residual.
|
||||
/**
|
||||
* Steady-state max norm of the residual evaluated using solution x.
|
||||
* On return, array r contains the steady-state residual values.
|
||||
*/
|
||||
doublereal ssnorm(doublereal* x, doublereal* r);
|
||||
|
||||
/// Reciprocal of the time step.
|
||||
doublereal rdt() const { return m_rdt; }
|
||||
|
||||
/// Prepare for time stepping.
|
||||
/// Prepare for time stepping beginning with solution x.
|
||||
void initTimeInteg(doublereal dt, doublereal* x);
|
||||
|
||||
/// True if transient mode.
|
||||
|
|
@ -89,10 +100,25 @@ namespace Cantera {
|
|||
/// True if steady mode.
|
||||
bool steady() const { return (m_rdt == 0.0); }
|
||||
|
||||
/// Set steady mode
|
||||
|
||||
/**
|
||||
* Set steady mode. After invoking this method, subsequent
|
||||
* calls to solve() will solve the steady-state problem.
|
||||
*/
|
||||
void setSteadyMode();
|
||||
|
||||
/// Evaluate the multi-domain residual function
|
||||
|
||||
/**
|
||||
* Evaluate the multi-domain residual function
|
||||
*
|
||||
* @param j if j > 0, only evaluate residual for points j-1, j,
|
||||
* and j + 1; otherwise, evaluate at all grid points.
|
||||
* @param x solution vector
|
||||
* @param r on return, contains the residual vector
|
||||
* @param rdt Reciprocal of the time step. if omitted, then
|
||||
* the default value is used.
|
||||
* @param count Set to zero to omit this call from the statistics
|
||||
*/
|
||||
void eval(int j, double* x, double* r, doublereal rdt=-1.0,
|
||||
int count = 1);
|
||||
|
||||
|
|
@ -100,7 +126,8 @@ namespace Cantera {
|
|||
Resid1D* pointDomain(int i);
|
||||
|
||||
void resize();
|
||||
doublereal solveTime() { return m_solve_time; }
|
||||
|
||||
//doublereal solveTime() { return m_solve_time; }
|
||||
|
||||
//void setTransientMask();
|
||||
vector_int& transientMask() { return m_mask; }
|
||||
|
|
@ -113,21 +140,35 @@ namespace Cantera {
|
|||
|
||||
void save(string fname, string id, string desc, doublereal* sol);
|
||||
|
||||
// options
|
||||
void setMinTimeStep(doublereal tmin) { m_tmin = tmin; }
|
||||
void setMaxTimeStep(doublereal tmax) { m_tmax = tmax; }
|
||||
void setTimeStepFactor(doublereal tfactor) { m_tfactor = tfactor; }
|
||||
void setJacAge(int ss_age, int ts_age=-1) {
|
||||
m_ss_jac_age = ss_age;
|
||||
if (ts_age > 0)
|
||||
m_ts_jac_age = ts_age;
|
||||
else
|
||||
m_ts_jac_age = m_ss_jac_age;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
MultiJac* m_jac;
|
||||
MultiNewton* m_newt;
|
||||
doublereal m_rdt;
|
||||
bool m_jac_ok;
|
||||
int m_nd;
|
||||
int m_bw;
|
||||
int m_size;
|
||||
vector_int m_states;
|
||||
vector_int m_start;
|
||||
vector_int m_comp, m_points;
|
||||
doublereal m_tmin; // minimum timestep size
|
||||
doublereal m_tmax; // maximum timestep size
|
||||
doublereal m_tfactor; // factor time step is multiplied by
|
||||
// if time stepping fails ( < 1 )
|
||||
|
||||
MultiJac* m_jac; // Jacobian evaluator
|
||||
MultiNewton* m_newt; // Newton iterator
|
||||
doublereal m_rdt; // reciprocal of time step
|
||||
bool m_jac_ok; // if true, Jacobian is current
|
||||
int m_nd; // number of domains
|
||||
int m_bw; // Jacobian bandwidth
|
||||
int m_size; // solution vector size
|
||||
|
||||
vector<Resid1D*> m_dom, m_connect, m_bulk;
|
||||
vector_int m_flow, m_bdry;
|
||||
int m_nflow, m_nbdry;
|
||||
|
||||
bool m_init;
|
||||
vector_int m_nvars;
|
||||
vector_int m_loc;
|
||||
|
|
@ -135,9 +176,10 @@ namespace Cantera {
|
|||
int m_pts;
|
||||
doublereal m_solve_time;
|
||||
|
||||
// options
|
||||
int m_ss_jac_age, m_ts_jac_age;
|
||||
|
||||
// stats
|
||||
// statistics
|
||||
int m_nevals;
|
||||
doublereal m_evaltime;
|
||||
vector_int m_gridpts;
|
||||
|
|
@ -147,6 +189,7 @@ namespace Cantera {
|
|||
vector_fp m_funcElapsed;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,9 +13,10 @@
|
|||
#define CT_RESID1D_H
|
||||
|
||||
|
||||
//#include "stringUtils.h"
|
||||
#include "../ctexceptions.h"
|
||||
#include "../xml.h"
|
||||
#include "refine.h"
|
||||
|
||||
|
||||
namespace Cantera {
|
||||
|
||||
|
|
@ -32,16 +33,15 @@ namespace Cantera {
|
|||
|
||||
|
||||
/**
|
||||
* Base class for single-domain, one-dimensional residual function
|
||||
* evaluators.
|
||||
* Base class for one-dimensional domains.
|
||||
*/
|
||||
class Resid1D {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param nv Number of variables at each grid point.
|
||||
* @param points Number of grid points.
|
||||
* @param nv Number of variables at each grid point.
|
||||
* @param points Number of grid points.
|
||||
*/
|
||||
Resid1D(int nv=1, int points=1,
|
||||
doublereal time = 0.0) :
|
||||
|
|
@ -52,17 +52,26 @@ namespace Cantera {
|
|||
m_iloc(0),
|
||||
m_jstart(0),
|
||||
m_left(0),
|
||||
m_right(0) {
|
||||
m_right(0),
|
||||
m_refiner(0) {
|
||||
resize(nv, points);
|
||||
}
|
||||
|
||||
/// Destructor.
|
||||
virtual ~Resid1D(){}
|
||||
/// Destructor. Does nothing
|
||||
virtual ~Resid1D(){ delete m_refiner; }
|
||||
|
||||
/// Domain type flag.
|
||||
const int domainType() { return m_type; }
|
||||
|
||||
const OneDim& container() const{ return *m_container; }
|
||||
/**
|
||||
* The left-to-right location of this domain.
|
||||
*/
|
||||
const int domainIndex() { return m_index; }
|
||||
|
||||
/**
|
||||
* The container holding this domain.
|
||||
*/
|
||||
const OneDim& container() const { return *m_container; }
|
||||
|
||||
/**
|
||||
* Specify the container object for this domain, and the
|
||||
|
|
@ -73,25 +82,40 @@ namespace Cantera {
|
|||
m_index = index;
|
||||
}
|
||||
|
||||
/** Initialize. Base class method does nothing, but may be
|
||||
* overloaded.
|
||||
/**
|
||||
* Initialize. Base class method does nothing, but may be
|
||||
* overloaded.
|
||||
*/
|
||||
virtual void init(){}
|
||||
|
||||
virtual void setInitialState(doublereal* xlocal = 0){}
|
||||
virtual void setState(int point, const doublereal* state, doublereal* x) {}
|
||||
|
||||
/**
|
||||
* Resize the domain to have nv components and np grid points.
|
||||
* This method is virtual so that subclasses can perform other
|
||||
* actions required to resize the domain.
|
||||
*/
|
||||
virtual void resize(int nv, int np) {
|
||||
if (nv != m_nv || !m_refiner) {
|
||||
m_nv = nv;
|
||||
delete m_refiner;
|
||||
m_refiner = new Refiner(*this);
|
||||
cout << "created refiner with nv = " << m_nv << endl;
|
||||
}
|
||||
m_nv = nv;
|
||||
m_max.resize(m_nv, 0.0);
|
||||
m_min.resize(m_nv, 0.0);
|
||||
m_rtol.resize(m_nv, 0.0);
|
||||
m_atol.resize(m_nv, 0.0);
|
||||
m_points = np;
|
||||
m_z.resize(np, 0.0);
|
||||
m_slast.resize(m_nv * m_points, 0.0);
|
||||
locate();
|
||||
}
|
||||
|
||||
Refiner& refiner() { return *m_refiner; }
|
||||
|
||||
/// Number of components at each grid point.
|
||||
int nComponents() const { return m_nv; }
|
||||
|
||||
|
|
@ -107,40 +131,69 @@ namespace Cantera {
|
|||
*/
|
||||
void setBounds(int nl, const doublereal* lower,
|
||||
int nu, const doublereal* upper) {
|
||||
if (nl != m_nv || nu != m_nv)
|
||||
if (nl < m_nv || nu < m_nv)
|
||||
throw CanteraError("Resid1D::setBounds",
|
||||
"wrong array size for solution bounds");
|
||||
"wrong array size for solution bounds. "
|
||||
"Size should be at least "+int2str(m_nv));
|
||||
copy(upper, upper + m_nv, m_max.begin());
|
||||
copy(lower, lower + m_nv, m_min.begin());
|
||||
}
|
||||
|
||||
void setTolerances(int nr, const doublereal* rtol,
|
||||
int na, const doublereal* atol) {
|
||||
if (nr != m_nv || na != m_nv)
|
||||
if (nr < m_nv || na < m_nv)
|
||||
throw CanteraError("Resid1D::setTolerances",
|
||||
"wrong array size for solution error tolerances. Size should be "+int2str(m_nv));
|
||||
"wrong array size for solution error tolerances. "
|
||||
"Size should be at least "+int2str(m_nv));
|
||||
copy(rtol, rtol + m_nv, m_rtol.begin());
|
||||
copy(atol, atol + m_nv, m_atol.begin());
|
||||
}
|
||||
|
||||
/// Relative tolerance of the nth component.
|
||||
doublereal rtol(int n) { return m_rtol[n]; }
|
||||
|
||||
/// Absolute tolerance of the nth component.
|
||||
doublereal atol(int n) { return m_atol[n]; }
|
||||
|
||||
/// Upper bound on the nth component.
|
||||
doublereal upperBound(int n) const { return m_max[n]; }
|
||||
|
||||
/// Lower bound on the nth component
|
||||
doublereal lowerBound(int n) const { return m_min[n]; }
|
||||
|
||||
/**
|
||||
* Prepare to do time stepping with time step dt. Copy the
|
||||
* internally-stored solution at the last time step to array
|
||||
* x0.
|
||||
*/
|
||||
void initTimeInteg(doublereal dt, const doublereal* x0) {
|
||||
copy(x0 + loc(), x0 + loc() + size(), m_slast.begin());
|
||||
m_rdt = 1.0/dt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare to solve the steady-state problem.
|
||||
* Set the internally-stored reciprocal of the time step to 0,0
|
||||
*/
|
||||
void setSteadyMode() { m_rdt = 0.0; }
|
||||
|
||||
/// True if in steady-state mode
|
||||
bool steady() { return (m_rdt == 0.0); }
|
||||
|
||||
/// True if not in steady-state mode
|
||||
bool transient() { return (m_rdt != 0.0); }
|
||||
|
||||
/**
|
||||
* Set this if something has changed in the governing
|
||||
* equations (e.g. the value of a constant has been changed,
|
||||
* so that the last-computed Jacobian is no longer valid.
|
||||
*/
|
||||
void needJacUpdate();
|
||||
|
||||
/**
|
||||
* Evaluate the steady-state residual at all points, even if in
|
||||
* transient mode. Used to print diagnostic output.
|
||||
*/
|
||||
void evalss(doublereal* x, doublereal* r, integer* mask) {
|
||||
eval(-1,x,r,mask,0.0);
|
||||
}
|
||||
|
|
@ -155,59 +208,163 @@ namespace Cantera {
|
|||
"residual function not defined.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Does nothing.
|
||||
*/
|
||||
virtual void update(doublereal* x) {}
|
||||
|
||||
doublereal time() { return m_time;}
|
||||
doublereal time() const { return m_time;}
|
||||
void incrementTime(doublereal dt) { m_time += dt; }
|
||||
size_t index(int n, int j) const { return m_nv*j + n; }
|
||||
doublereal value(doublereal* x, int n, int j) const {
|
||||
return x[index(n,j)];
|
||||
}
|
||||
|
||||
virtual void setJac(MultiJac* jac){}
|
||||
virtual void save(XML_Node& o, doublereal* sol) {
|
||||
throw CanteraError("Resid1D::save","base class method called");
|
||||
}
|
||||
|
||||
int size() { return m_nv*m_points; }
|
||||
int size() const { return m_nv*m_points; }
|
||||
|
||||
/**
|
||||
* Find the index of the first grid point in this domain, and
|
||||
* the start of its variables in the global solution vector.
|
||||
*/
|
||||
void locate() {
|
||||
|
||||
if (m_left) {
|
||||
// there is a domain on the left, so the first grid point
|
||||
// in this domain is one more than the last one on the left
|
||||
m_jstart = m_left->lastPoint() + 1;
|
||||
|
||||
// the starting location in the solution vector
|
||||
m_iloc = m_left->loc() + m_left->size();
|
||||
}
|
||||
else {
|
||||
// this is the left-most domain
|
||||
m_jstart = 0;
|
||||
m_iloc = 0;
|
||||
}
|
||||
// if there is a domain to the right of this one, then
|
||||
// repeat this for it
|
||||
if (m_right) m_right->locate();
|
||||
}
|
||||
|
||||
virtual int loc(int j = 0) { return m_iloc; }
|
||||
/**
|
||||
* Location of the start of the local solution vector in the global
|
||||
* solution vector,
|
||||
*/
|
||||
virtual int loc(int j = 0) const { return m_iloc; }
|
||||
|
||||
int firstPoint() { return m_jstart; }
|
||||
int lastPoint() { return m_jstart + m_points - 1; }
|
||||
/**
|
||||
* The index of the first (i.e., left-most) grid point
|
||||
* belonging to this domain.
|
||||
*/
|
||||
int firstPoint() const { return m_jstart; }
|
||||
|
||||
/**
|
||||
* The index of the last (i.e., right-most) grid point
|
||||
* belonging to this domain.
|
||||
*/
|
||||
int lastPoint() const { return m_jstart + m_points - 1; }
|
||||
|
||||
/**
|
||||
* Set the left neighbor to domain 'left.' Method 'locate' is
|
||||
* called to update the global positions of this domain and
|
||||
* all those to its right.
|
||||
*/
|
||||
void linkLeft(Resid1D* left) {
|
||||
m_left = left;
|
||||
locate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the right neighbor to domain 'right.'
|
||||
*/
|
||||
void linkRight(Resid1D* right) { m_right = right; }
|
||||
|
||||
/**
|
||||
* Append domain 'right' to this one, and update all links.
|
||||
*/
|
||||
void append(Resid1D* right) {
|
||||
linkRight(right);
|
||||
right->linkLeft(this);
|
||||
}
|
||||
|
||||
void linkLeft(Resid1D* left) {
|
||||
m_left = left;
|
||||
locate();
|
||||
}
|
||||
void linkRight(Resid1D* right) { m_right = right; }
|
||||
/**
|
||||
* Return a pointer to the left neighbor.
|
||||
*/
|
||||
Resid1D* left() const { return m_left; }
|
||||
|
||||
Resid1D* left() { return m_left; }
|
||||
Resid1D* right() { return m_right; }
|
||||
/**
|
||||
* Return a pointer to the right neighbor.
|
||||
*/
|
||||
Resid1D* right() const { return m_right; }
|
||||
|
||||
double prevSoln(int n, int j) const{
|
||||
/**
|
||||
* Value of component n at point j in the previous solution.
|
||||
*/
|
||||
double prevSoln(int n, int j) const {
|
||||
return m_slast[m_nv*j + n];
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify an identifying tag for this domain.
|
||||
*/
|
||||
void setID(const string& s) {m_id = s;}
|
||||
|
||||
/**
|
||||
* Specify descriptive text for this domain.
|
||||
*/
|
||||
void setDesc(const string& s) {m_desc = s;}
|
||||
|
||||
virtual void getTransientMask(integer* mask){}
|
||||
|
||||
virtual void showSolution(ostream& s, const doublereal* x) {}
|
||||
|
||||
doublereal z(int jlocal) const {
|
||||
return m_z[jlocal];
|
||||
}
|
||||
doublereal zmin() const { return m_z[0]; }
|
||||
doublereal zmax() const { return m_z[m_points - 1]; }
|
||||
|
||||
|
||||
void setProfile(string name, doublereal* values, doublereal* soln) {
|
||||
int n, j;
|
||||
for (n = 0; n < m_nv; n++) {
|
||||
if (name == componentName(n)) {
|
||||
for (j = 0; j < m_points; j++) {
|
||||
soln[index(n, j) + m_iloc] = values[j];
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw CanteraError("Resid1D::setProfile",
|
||||
"unknown component: "+name);
|
||||
}
|
||||
|
||||
vector_fp& grid() { return m_z; }
|
||||
const vector_fp& grid() const { return m_z; }
|
||||
doublereal grid(int point) { return m_z[point]; }
|
||||
|
||||
virtual void setupGrid(int n, const doublereal* z) {}
|
||||
|
||||
/**
|
||||
* Writes some or all initial solution values into array x,
|
||||
* which is the solution vector for this domain. This allows
|
||||
* initial values that have been set prior to installing this
|
||||
* domain into the container to be written to the global
|
||||
* solution vector.
|
||||
*/
|
||||
virtual void _getInitialSoln(doublereal* x) {cout << "base class method _getInitialSoln called!" << endl;}
|
||||
|
||||
/**
|
||||
* Perform any necessary domain-specific initialization using
|
||||
* local solution vector x.
|
||||
*/
|
||||
virtual void _finalize(const doublereal* x) {cout << "base class method _finalize called!" << endl;}
|
||||
|
||||
protected:
|
||||
|
||||
doublereal m_rdt;
|
||||
|
|
@ -219,6 +376,7 @@ namespace Cantera {
|
|||
vector_fp m_min;
|
||||
vector_fp m_rtol;
|
||||
vector_fp m_atol;
|
||||
vector_fp m_z;
|
||||
OneDim* m_container;
|
||||
int m_index;
|
||||
int m_type;
|
||||
|
|
@ -226,6 +384,7 @@ namespace Cantera {
|
|||
int m_jstart;
|
||||
Resid1D *m_left, *m_right;
|
||||
string m_id, m_desc;
|
||||
Refiner* m_refiner;
|
||||
|
||||
private:
|
||||
|
||||
|
|
|
|||
306
Cantera/src/oneD/Sim1D.cpp
Normal file
306
Cantera/src/oneD/Sim1D.cpp
Normal file
|
|
@ -0,0 +1,306 @@
|
|||
/**
|
||||
* @file Sim1D.cpp
|
||||
*/
|
||||
|
||||
#include "Sim1D.h"
|
||||
|
||||
namespace Cantera {
|
||||
|
||||
|
||||
Sim1D::Sim1D(vector<Resid1D*>& domains) : OneDim(domains) {
|
||||
|
||||
// resize the internal solution vector and the wprk array,
|
||||
// and perform domain-specific initialization of the
|
||||
// solution vector.
|
||||
m_x.resize(size(), 0.0);
|
||||
m_xnew.resize(size(), 0.0);
|
||||
for (int n = 0; n < m_nd; n++) {
|
||||
domain(n)._getInitialSoln(m_x.begin() + start(n));
|
||||
}
|
||||
|
||||
// set some defaults
|
||||
m_tstep = 1.0e-5;
|
||||
//m_maxtimestep = 10.0;
|
||||
m_steps.push_back(1);
|
||||
m_steps.push_back(2);
|
||||
m_steps.push_back(5);
|
||||
m_steps.push_back(10);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a single value in the solution vector.
|
||||
* @param dom domain number, beginning with 0 for the leftmost domain.
|
||||
* @param comp component number
|
||||
* @param localPoint grid point within the domain, beginning with 0 for
|
||||
* the leftmost grid point in the domain.
|
||||
* @param value the value.
|
||||
*/
|
||||
void Sim1D::setValue(int dom, int comp, int localPoint, doublereal value) {
|
||||
int iloc = domain(dom).loc() + domain(dom).index(comp, localPoint);
|
||||
m_x[iloc] = value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param dom domain number, beginning with 0 for the leftmost domain.
|
||||
* @param comp component number
|
||||
* @param localPoint grid point within the domain, beginning with 0 for
|
||||
* the leftmost grid point in the domain.
|
||||
*/
|
||||
doublereal Sim1D::value(int dom, int comp, int localPoint) const {
|
||||
int iloc = domain(dom).loc() + domain(dom).index(comp, localPoint);
|
||||
return m_x[iloc];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param dom domain number, beginning with 0 for the leftmost domain.
|
||||
* @param comp component number
|
||||
* @param pos A vector of relative positions, beginning with 0.0 at the
|
||||
* left of the domain, and ending with 1.0 at the right of the domain.
|
||||
* @param values A vector of values corresponding to the relative position
|
||||
* locations.
|
||||
*
|
||||
* Note that the vector pos and values can have lengths
|
||||
* different than the number of grid points, but their lengths
|
||||
* must be equal. The values at the grid points will be
|
||||
* linearly interpolated based on the (pos, values)
|
||||
* specification.
|
||||
*/
|
||||
void Sim1D::setProfile(int dom, int comp,
|
||||
const vector_fp& pos, const vector_fp& values) {
|
||||
|
||||
Resid1D& d = domain(dom);
|
||||
int np = d.nPoints();
|
||||
int n;
|
||||
doublereal z0 = d.zmin();
|
||||
doublereal z1 = d.zmax();
|
||||
doublereal zpt, frac, v;
|
||||
for (n = 0; n < np; n++) {
|
||||
zpt = d.z(n);
|
||||
frac = (zpt - z0)/(z1 - z0);
|
||||
v = linearInterp(frac, pos, values);
|
||||
setValue(dom, comp, n, v);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Sim1D::setFlatProfile(int dom, int comp, doublereal v) {
|
||||
int np = domain(dom).nPoints();
|
||||
int n;
|
||||
for (n = 0; n < np; n++) { setValue(dom, comp, n, v); }
|
||||
}
|
||||
|
||||
|
||||
void Sim1D::showSolution(ostream& s) {
|
||||
for (int n = 0; n < m_nd; n++) {
|
||||
domain(n).showSolution(s, m_x.begin() + start(n));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Sim1D::finalize() {
|
||||
for (int n = 0; n < m_nd; n++) {
|
||||
domain(n)._finalize(m_x.begin() + start(n));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Sim1D::setTimeStep(doublereal stepsize, int n, integer* tsteps) {
|
||||
m_tstep = stepsize;
|
||||
m_steps.resize(n);
|
||||
for (int i = 0; i < n; i++) m_steps[i] = tsteps[i];
|
||||
}
|
||||
|
||||
|
||||
void Sim1D::newtonSolve(int loglevel) {
|
||||
int m = OneDim::solve(m_x.begin(), m_xnew.begin(), loglevel);
|
||||
if (m >= 0)
|
||||
copy(m_xnew.begin(), m_xnew.end(), m_x.begin());
|
||||
else if (m > -10)
|
||||
throw CanteraError("Sim1D::newtonSolve","no solution found");
|
||||
else {
|
||||
cout << "ERROR: solve returned m = " << m << endl;
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Sim1D::solve(int loglevel, bool refine_grid) {
|
||||
|
||||
int new_points = 1;
|
||||
int istep, nsteps;
|
||||
doublereal dt = m_tstep;
|
||||
int soln_number = -1;
|
||||
|
||||
finalize();
|
||||
|
||||
while (new_points > 0) {
|
||||
|
||||
istep = 0;
|
||||
nsteps = m_steps[istep];
|
||||
|
||||
bool ok = false;
|
||||
while (!ok) {
|
||||
|
||||
try {
|
||||
if (loglevel > 0) {
|
||||
writelog("Attempt Newton solution of steady-state problem...");
|
||||
}
|
||||
newtonSolve(loglevel-1);
|
||||
|
||||
if (loglevel > 0) {
|
||||
writelog("success.\n\n");
|
||||
//writelog("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\n");
|
||||
writelog("Problem solved on [");
|
||||
for (int mm = 1; mm < nDomains(); mm+=2) {
|
||||
writelog(int2str(domain(mm).nPoints()));
|
||||
if (mm < nDomains() - 2) writelog(", ");
|
||||
}
|
||||
writelog("]");
|
||||
writelog(" point grid(s).\n\n");
|
||||
//writelog("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
|
||||
}
|
||||
ok = true;
|
||||
soln_number++;
|
||||
|
||||
}
|
||||
|
||||
catch (CanteraError) {
|
||||
|
||||
char buf[100];
|
||||
if (loglevel > 0) writelog("failure. \n\n");
|
||||
if (loglevel == 1) writelog("Take "+int2str(nsteps)+" timesteps ");
|
||||
dt = timeStep(nsteps, dt, m_x.begin(), m_xnew.begin(), loglevel-1);
|
||||
if (loglevel == 1) {
|
||||
sprintf(buf, " %10.4g %10.4g \n", dt,
|
||||
log10(ssnorm(m_x.begin(), m_xnew.begin())));
|
||||
writelog(buf);
|
||||
}
|
||||
istep++;
|
||||
if (istep >= int(m_steps.size())) {
|
||||
nsteps = m_steps.back();
|
||||
dt *= 2.0;
|
||||
cout << " doubled dt = " << dt << endl;
|
||||
}
|
||||
else {
|
||||
nsteps = m_steps[istep];
|
||||
}
|
||||
if (dt > m_tmax) dt = m_tmax;
|
||||
}
|
||||
}
|
||||
if (loglevel > 2) showSolution(cout);
|
||||
|
||||
if (refine_grid) {
|
||||
new_points = refine(loglevel);
|
||||
}
|
||||
else {
|
||||
new_points = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refine the grid in all domains.
|
||||
*/
|
||||
int Sim1D::refine(int loglevel) {
|
||||
int np = 0;
|
||||
vector_fp znew, xnew;
|
||||
doublereal xmid, zmid;
|
||||
int strt, n, m, i;
|
||||
|
||||
for (n = 0; n < m_nd; n++) {
|
||||
strt = znew.size();
|
||||
Resid1D& d = domain(n);
|
||||
Refiner& r = d.refiner();
|
||||
|
||||
// determine where new points are needed
|
||||
r.analyze(d.grid().size(), d.grid().begin(), m_x.begin() + start(n));
|
||||
if (loglevel > 0) { r.show(); }
|
||||
|
||||
np += r.nNewPoints();
|
||||
int comp = d.nComponents();
|
||||
|
||||
// loop over points in the current grid
|
||||
int npnow = d.nPoints();
|
||||
for (m = 0; m < npnow; m++) {
|
||||
|
||||
// add the current grid point to the new grid
|
||||
znew.push_back(d.grid(m));
|
||||
|
||||
// do the same for the solution at this point
|
||||
for (i = 0; i < comp; i++) {
|
||||
xnew.push_back(value(n, i, m));
|
||||
}
|
||||
|
||||
// now check whether a new point is needed in the interval to the
|
||||
// right of point m, and if so, add entries to znew and xnew for
|
||||
// this new point
|
||||
|
||||
if (r.newPointNeeded(m)) {
|
||||
|
||||
// add new point at midpoint
|
||||
zmid = 0.5*(d.grid(m) + d.grid(m+1));
|
||||
znew.push_back(zmid);
|
||||
|
||||
// for each component, linearly interpolate the solution to
|
||||
// this point
|
||||
for (i = 0; i < comp; i++) {
|
||||
xmid = 0.5*(value(n, i, m) + value(n, i, m+1));
|
||||
xnew.push_back(xmid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, the new grid znew and the new solution vector xnew have
|
||||
// been constructed, but the domains themselves have not yet been modified.
|
||||
// Now update each domain with the new grid.
|
||||
|
||||
int gridstart = 0, gridsize;
|
||||
for (n = 0; n < m_nd; n++) {
|
||||
Resid1D& d = domain(n);
|
||||
Refiner& r = d.refiner();
|
||||
gridsize = d.nPoints() + r.nNewPoints();
|
||||
d.setupGrid(gridsize, znew.begin() + gridstart);
|
||||
gridstart += gridsize;
|
||||
}
|
||||
|
||||
// Replace the current solution vector with the new one
|
||||
m_x.resize(xnew.size());
|
||||
copy(xnew.begin(), xnew.end(), m_x.begin());
|
||||
|
||||
// resize the work array
|
||||
m_xnew.resize(xnew.size());
|
||||
|
||||
// copy(xnew.begin(), xnew.end(), m_xnew.begin());
|
||||
|
||||
resize();
|
||||
finalize();
|
||||
return np;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set grid refinement criteria. If dom >= 0, then the settings
|
||||
* apply only to the specified domain. If dom < 0, the settings
|
||||
* are applied to each domain. @see Refiner::setCriteria.
|
||||
*/
|
||||
void Sim1D::setRefineCriteria(int dom, doublereal ratio,
|
||||
doublereal slope, doublereal curve) {
|
||||
if (dom >= 0) {
|
||||
Refiner& r = domain(dom).refiner();
|
||||
r.setCriteria(ratio, slope, curve);
|
||||
}
|
||||
else {
|
||||
for (int n = 0; n < m_nd; n++) {
|
||||
Refiner& r = domain(n).refiner();
|
||||
r.setCriteria(ratio, slope, curve);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
89
Cantera/src/oneD/Sim1D.h
Normal file
89
Cantera/src/oneD/Sim1D.h
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
* @file Sim1D.h
|
||||
*/
|
||||
|
||||
#ifndef CT_SIM1D_H
|
||||
#define CT_SIM1D_H
|
||||
|
||||
#include "OneDim.h"
|
||||
#include "../funcs.h"
|
||||
|
||||
namespace Cantera {
|
||||
|
||||
/**
|
||||
* One-dimensional simulations.
|
||||
*/
|
||||
class Sim1D : public OneDim {
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Default constructor. This constructor can be used to create
|
||||
* a dummy object if necessary, but is not usually called in
|
||||
* user programs. Use the next constructor instead.
|
||||
*/
|
||||
Sim1D();
|
||||
|
||||
|
||||
/**
|
||||
* Standard constructor.
|
||||
* @param domains A vector of pointers to the domains to be linked together.
|
||||
* The domains must appear in left-to-right order.
|
||||
*/
|
||||
Sim1D(vector<Resid1D*>& domains);
|
||||
|
||||
/// Destructor. Does nothing.
|
||||
virtual ~Sim1D(){}
|
||||
|
||||
|
||||
/// Set one entry in the solution vector.
|
||||
void setValue(int dom, int comp, int localPoint, doublereal value);
|
||||
|
||||
/// Get one entry in the solution vector.
|
||||
doublereal value(int dom, int comp, int localPoint) const;
|
||||
|
||||
/// Specify a profile for one component of one domain.
|
||||
void setProfile(int dom, int comp, const vector_fp& pos,
|
||||
const vector_fp& values);
|
||||
|
||||
/// Set component 'comp' of domain 'dom' to value 'v' at all points.
|
||||
void setFlatProfile(int dom, int comp, doublereal v);
|
||||
|
||||
/// Print to stream s the current solution for all domains.
|
||||
void showSolution(ostream& s);
|
||||
|
||||
/// Calls method _finalize in each domain.
|
||||
void finalize();
|
||||
|
||||
void setTimeStep(doublereal stepsize, int n, integer* tsteps);
|
||||
|
||||
//void setMaxTimeStep(doublereal tmax) { m_maxtimestep = tmax; }
|
||||
|
||||
void solve(int loglevel = 0, bool refine_grid = true);
|
||||
|
||||
int refine(int loglevel=0);
|
||||
|
||||
void setRefineCriteria(int dom = -1, doublereal ratio = 10.0,
|
||||
doublereal slope = 0.8, doublereal curve = 0.8);
|
||||
|
||||
protected:
|
||||
|
||||
vector_fp m_x; // the solution vector
|
||||
vector_fp m_xnew; // a work array used to hold the residual
|
||||
// or the new solution
|
||||
doublereal m_tstep; // timestep
|
||||
vector_int m_steps; // array of number of steps to take before
|
||||
// re-attempting the steady-state solution
|
||||
|
||||
private:
|
||||
|
||||
void newtonSolve(int loglevel);
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -101,28 +101,6 @@ namespace Cantera {
|
|||
|
||||
//--------------------- linear interp ------------------------------
|
||||
|
||||
/**
|
||||
* Linearly interpolate a function defined on a discrete grid.
|
||||
* vector xpts contains a monotonic sequence of grid points, and
|
||||
* vector fpts contains function values defined at these points.
|
||||
* The value returned is the linear interpolate at point x.
|
||||
* If x is outside the range of xpts, the value of fpts at the
|
||||
* nearest end is returned.
|
||||
*/
|
||||
|
||||
doublereal linearInterp(doublereal x, vector_fp& xpts, vector_fp& fpts) {
|
||||
if (x <= xpts[0]) return fpts[0];
|
||||
if (x >= xpts.back()) return fpts.back();
|
||||
doublereal* loc = lower_bound(xpts.begin(), xpts.end(), x);
|
||||
int iloc = int(loc - xpts.begin()) - 1;
|
||||
doublereal ff = fpts[iloc] +
|
||||
(x - xpts[iloc])*(fpts[iloc + 1]
|
||||
- fpts[iloc])/(xpts[iloc + 1] - xpts[iloc]);
|
||||
return ff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
StFlow::StFlow(igthermo_t* ph, int nsp, int points) :
|
||||
Resid1D(nsp+4, points),
|
||||
m_inlet_u(0.0),
|
||||
|
|
@ -146,10 +124,16 @@ namespace Cantera {
|
|||
|
||||
m_points = points;
|
||||
m_thermo = ph;
|
||||
m_nv = m_nsp + 4;
|
||||
|
||||
if (ph == 0) return; // used to create a dummy object
|
||||
|
||||
int nsp2 = m_thermo->nSpecies();
|
||||
if (nsp2 != m_nsp) {
|
||||
m_nsp = nsp2;
|
||||
Resid1D::resize(m_nsp+4, points);
|
||||
}
|
||||
|
||||
|
||||
// make a local copy of the species molecular weight vector
|
||||
m_wt = m_thermo->molecularWeights();
|
||||
|
||||
|
|
@ -170,7 +154,9 @@ namespace Cantera {
|
|||
m_surfdot.resize(m_nsp, 0.0);
|
||||
m_ybar.resize(m_nsp);
|
||||
|
||||
// default solution bounds
|
||||
|
||||
//-------------- default solution bounds --------------------
|
||||
|
||||
vector_fp vmin(m_nv), vmax(m_nv);
|
||||
|
||||
// no bounds on u
|
||||
|
|
@ -178,7 +164,7 @@ namespace Cantera {
|
|||
vmax[0] = 1.e20;
|
||||
|
||||
// no negative V
|
||||
vmin[1] = -0.01;
|
||||
vmin[1] = -0.1;
|
||||
vmax[1] = 1.e20;
|
||||
|
||||
// temperature bounds
|
||||
|
|
@ -187,17 +173,30 @@ namespace Cantera {
|
|||
|
||||
// lamda should be negative
|
||||
vmin[3] = -1.e20;
|
||||
vmax[3] = 0.001;
|
||||
vmax[3] = 1.0;
|
||||
|
||||
// mass fraction bounds
|
||||
int k;
|
||||
for (k = 0; k < m_nsp; k++) {
|
||||
vmin[4+k] = -1.e-5;
|
||||
vmin[4+k] = -1.0e-5;
|
||||
vmax[4+k] = 1.1;
|
||||
}
|
||||
setBounds(vmin.size(), vmin.begin(), vmax.size(), vmax.begin());
|
||||
|
||||
|
||||
//-------------------- default error tolerances ----------------
|
||||
vector_fp rtol(m_nv, 1.0e-8);
|
||||
vector_fp atol(m_nv, 1.0e-15);
|
||||
setTolerances(rtol.size(), rtol.begin(), atol.size(), atol.begin());
|
||||
|
||||
//-------------------- grid refinement -------------------------
|
||||
m_refiner->setActive(0, false);
|
||||
m_refiner->setActive(1, false);
|
||||
m_refiner->setActive(2, false);
|
||||
m_refiner->setActive(3, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Change the grid size. Called after grid refinement.
|
||||
*/
|
||||
|
|
@ -258,6 +257,7 @@ namespace Cantera {
|
|||
throw CanteraError("setTransport","unknown transport model.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the gas object state to be consistent with the solution at
|
||||
* point j.
|
||||
|
|
@ -269,6 +269,11 @@ namespace Cantera {
|
|||
m_thermo->setPressure(m_press);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the gas state to be consistent with the solution at the
|
||||
* midpoint between j and j + 1.
|
||||
*/
|
||||
void StFlow::setGasAtMidpoint(const doublereal* x,int j) {
|
||||
m_thermo->setTemperature(0.5*(T(x,j)+T(x,j+1)));
|
||||
const doublereal* yyj = x + m_nv*j + c_offset_Y;
|
||||
|
|
@ -280,44 +285,26 @@ namespace Cantera {
|
|||
}
|
||||
|
||||
|
||||
// /**
|
||||
// * Integrate the species mass fractions at each point separately,
|
||||
// * without the transport terms. This method is provided to
|
||||
// * condition a poor estimate of the solution to produce a better
|
||||
// * starting estimate for Newton iteration. It is not used by any
|
||||
// * other method, but is available for use in user codes, if
|
||||
// * desired.
|
||||
// */
|
||||
// void StFlow::integrateChem(doublereal* x,doublereal dt) {
|
||||
// int j;
|
||||
// if (!ready()) return;
|
||||
// if (m_integrator == 0) {
|
||||
// m_integrator = new ImplicitChem(*m_kin, *m_thermo);
|
||||
// m_integrator->initialize(0.0);
|
||||
// }
|
||||
// for (j = 0; j < m_points; j++) {
|
||||
// setGas(x,j);
|
||||
// m_integrator->integrate(0.0, dt);
|
||||
// m_thermo->getMassFractions(m_nsp, &x[index(c_offset_Y,j)]);
|
||||
// T(x,j) = m_thermo->temperature();
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate the residual function for stagnation flow. If jpt is
|
||||
* less than zero, the residual function is evaluated at all grid
|
||||
* points. If jpt >= 0, then the residual function is only
|
||||
* evaluated at grid points jpt-1), jpt, and jpt+1. This option
|
||||
* is used to efficiently evaluate the Jacobian numerically.
|
||||
* Evaluate the residual function for axisymmetric stagnation
|
||||
* flow. If jpt is less than zero, the residual function is
|
||||
* evaluated at all grid points. If jpt >= 0, then the residual
|
||||
* function is only evaluated at grid points jpt-1, jpt, and
|
||||
* jpt+1. This option is used to efficiently evaluate the
|
||||
* Jacobian numerically.
|
||||
*
|
||||
*/
|
||||
|
||||
void AxiStagnFlow::eval(int jg, doublereal* xg,
|
||||
doublereal* rg, integer* diagg, doublereal rdt) {
|
||||
|
||||
// if evaluating a Jacobian, and the global point is outside
|
||||
// the domain of influence for this domain, then skip
|
||||
// evaluating the residual
|
||||
if (jg >=0 && (jg < firstPoint() - 1 || jg > lastPoint() + 1)) return;
|
||||
|
||||
// if evaluating a Jacobian, compute the steady-state residual
|
||||
if (jg >= 0) rdt = 0.0;
|
||||
|
||||
// start of local part of global arrays
|
||||
|
|
@ -328,11 +315,11 @@ namespace Cantera {
|
|||
int jmin, jmax, jpt;
|
||||
jpt = jg - firstPoint();
|
||||
|
||||
if (jg < 0) {
|
||||
if (jg < 0) { // evaluate all points
|
||||
jmin = 0;
|
||||
jmax = m_points - 1;
|
||||
}
|
||||
else {
|
||||
else { // evaluate points for Jacobian
|
||||
jmin = max(jpt-1, 0);
|
||||
jmax = min(jpt+1,m_points-1);
|
||||
}
|
||||
|
|
@ -349,14 +336,16 @@ namespace Cantera {
|
|||
// update properties
|
||||
//-----------------------------------------------------
|
||||
|
||||
// thermodynamic properties
|
||||
// thermodynamic properties only if a Jacobian is
|
||||
// not being evaluated
|
||||
if (jpt < 0) updateThermo(x, j0, j1);
|
||||
|
||||
// update transport properties only if a Jacobian is
|
||||
// not being evaluated
|
||||
if (jpt < 0) updateTransport(x, j0, j1);
|
||||
|
||||
// update the species diffusive mass fluxes
|
||||
// update the species diffusive mass fluxes whether or not a
|
||||
// Jacobian is being evaluated
|
||||
updateDiffFluxes(x, j0, j1);
|
||||
|
||||
|
||||
|
|
@ -380,17 +369,28 @@ namespace Cantera {
|
|||
|
||||
#define NEW_INLET
|
||||
#ifdef NEW_INLET
|
||||
// continuity
|
||||
|
||||
// Continuity. This propagates information right-to-left,
|
||||
// since rho_u at point 0 is dependent on rho_u at point 1,
|
||||
// but not on mdot from the inlet.
|
||||
rsd[index(c_offset_U,0)] =
|
||||
-(rho_u(x,1) - rho_u(x,0))/m_dz[0]
|
||||
-(density(1)*V(x,1) + density(0)*V(x,0));
|
||||
|
||||
// the inlet (or other) object connected to this one
|
||||
// will modify these equations by subtracting its values
|
||||
// for V, T, and mdot. As a result, these residual equations
|
||||
// will force the solution variables to the values for
|
||||
// the boundary object
|
||||
rsd[index(c_offset_V,0)] = V(x,0);
|
||||
rsd[index(c_offset_T,0)] = T(x,0);
|
||||
rsd[index(c_offset_L,0)] = -rho_u(x,0);
|
||||
//cout << "rsd: " << rsd[0] << " " << rsd[1] << " " << rsd[2] << endl;
|
||||
//cout << "density = " << density(0) << " " << u(x,0)
|
||||
// << " " << rho_u(x,0) << endl;
|
||||
|
||||
// zero flux
|
||||
// The default boundary condition for species is zero
|
||||
// flux. However, the boundary object may modify
|
||||
// this.
|
||||
for (k = 0; k < m_nsp; k++) {
|
||||
rsd[index(c_offset_Y + k, 0)] =
|
||||
-(m_flux(k,0) + rho_u(x,0)* Y(x,k,0));
|
||||
|
|
@ -421,21 +421,18 @@ namespace Cantera {
|
|||
|
||||
|
||||
//----------------------------------------------
|
||||
// right boundary
|
||||
//
|
||||
// The right boundary residuals are for a nonreacting,
|
||||
// impermeable wall. Since domains are evaluated left to
|
||||
// right, the surface object may add terms to these
|
||||
// residual equations.
|
||||
// right boundary
|
||||
//
|
||||
//----------------------------------------------
|
||||
|
||||
else if (j == m_points - 1) {
|
||||
|
||||
//m_boundary[1]->eval(x + index(0, j), m_rho[j],
|
||||
// m_flux.begin() + m_nsp*(j-1),
|
||||
// rsd + index(0, j));
|
||||
|
||||
// the boundary object connected to the right of this
|
||||
// one may modify these equations by subtracting its
|
||||
// values for V, T, and mdot. As a result, these
|
||||
// residual equations will force the solution
|
||||
// variables to the values for the boundary object
|
||||
rsd[index(0,j)] = rho_u(x,j);
|
||||
rsd[index(1,j)] = V(x,j);
|
||||
rsd[index(2,j)] = T(x,j);
|
||||
|
|
@ -445,10 +442,14 @@ namespace Cantera {
|
|||
sum += Y(x,k,j);
|
||||
rsd[index(k+4,j)] = rho_u(x,j)*Y(x,k,j) + m_flux(k,j-1);
|
||||
}
|
||||
|
||||
// TODO: why is this done here, but not for the left
|
||||
// boundary or interior?
|
||||
rsd[index(4,j)] = 1.0 - sum;
|
||||
diag[index(4,j)] = 0;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------
|
||||
// interior points
|
||||
//------------------------------------------
|
||||
|
|
@ -855,7 +856,8 @@ namespace Cantera {
|
|||
|
||||
|
||||
|
||||
void StFlow::outputTEC(ostream &s, const doublereal* x, string title, int zone) {
|
||||
void StFlow::outputTEC(ostream &s, const doublereal* x,
|
||||
string title, int zone) {
|
||||
int j,k;
|
||||
s << "TITLE = \"" + title + "\"" << endl;
|
||||
s << "VARIABLES = \"Z (m)\"" << endl;
|
||||
|
|
@ -884,17 +886,19 @@ namespace Cantera {
|
|||
|
||||
string StFlow::componentName(int n) const {
|
||||
switch(n) {
|
||||
case 0: return "u [m/s]";
|
||||
case 1: return "V [1/s]";
|
||||
case 2: return "T [K]";
|
||||
case 0: return "u";
|
||||
case 1: return "V";
|
||||
case 2: return "T";
|
||||
case 3: return "lambda";
|
||||
default:
|
||||
if (n >= (int) c_offset_Y && n < (int) (c_offset_Y + m_nsp)) {
|
||||
if (m_do_species[n - c_offset_Y])
|
||||
return m_thermo->speciesName(n - c_offset_Y)+" ";
|
||||
else
|
||||
return m_thermo->speciesName(n - c_offset_Y)+" *";
|
||||
return m_thermo->speciesName(n - c_offset_Y);
|
||||
}
|
||||
// if (m_do_species[n - c_offset_Y])
|
||||
// return m_thermo->speciesName(n - c_offset_Y)+" ";
|
||||
// else
|
||||
// return m_thermo->speciesName(n - c_offset_Y)+" *";
|
||||
//}
|
||||
else
|
||||
return "<unknown>";
|
||||
}
|
||||
|
|
@ -1016,7 +1020,6 @@ namespace Cantera {
|
|||
for (n = 0; n < nd; n++) {
|
||||
XML_Node& fa = *d[n];
|
||||
nm = fa["title"];
|
||||
cout << "nm = " << nm << endl;
|
||||
getFloatArray(fa,x,false);
|
||||
if (nm == "u") {
|
||||
writelog("axial velocity ");
|
||||
|
|
@ -1134,7 +1137,7 @@ namespace Cantera {
|
|||
flow.addAttribute("id",id);
|
||||
addString(flow,"timestamp",asctime(newtime));
|
||||
addFloat(flow, "pressure", m_press, "Pa", "pressure");
|
||||
addString(flow,"solve_time",fp2str(m_container->solveTime()));
|
||||
// addString(flow,"solve_time",fp2str(m_container->solveTime()));
|
||||
if (desc != "") addString(flow,"description",desc);
|
||||
XML_Node& gv = flow.addChild("grid_data");
|
||||
addFloatArray(gv,"z",m_z.size(),m_z.begin(),
|
||||
|
|
@ -1220,9 +1223,9 @@ namespace Cantera {
|
|||
m_jac = jac;
|
||||
}
|
||||
|
||||
void StFlow::requestJacUpdate() {
|
||||
if (m_jac) m_jac->setAge(10000);
|
||||
}
|
||||
//void StFlow::requestJacUpdate() {
|
||||
// if (m_jac) m_jac->setAge(10000);
|
||||
//}
|
||||
|
||||
void StFlow::setEnergyFactor(doublereal efctr) {
|
||||
doublereal de = efctr - m_efctr;
|
||||
|
|
|
|||
|
|
@ -15,17 +15,15 @@
|
|||
#define CT_STFLOW_H
|
||||
|
||||
#include "../transport/TransportBase.h"
|
||||
//#include "IdealGasMix.h"
|
||||
#include "Resid1D.h"
|
||||
//#include "../ChemEquil.h"
|
||||
#include "../Array.h"
|
||||
#include "../sort.h"
|
||||
//#include "ImplicitChem.h"
|
||||
#include "../IdealGasPhase.h"
|
||||
#include "../Kinetics.h"
|
||||
|
||||
#include "../funcs.h"
|
||||
#include "../flowBoundaries.h"
|
||||
|
||||
|
||||
namespace Cantera {
|
||||
|
||||
typedef IdealGasPhase igthermo_t;
|
||||
|
|
@ -82,19 +80,18 @@ namespace Cantera {
|
|||
*/
|
||||
//@{
|
||||
|
||||
void setupGrid(int n, const doublereal* z);
|
||||
virtual void setupGrid(int n, const doublereal* z);
|
||||
|
||||
//thermo_t& phase() { return *m_phase; }
|
||||
thermo_t& phase() { return *m_thermo; }
|
||||
kinetics_t& kinetics() { return *m_kin; }
|
||||
|
||||
/**
|
||||
* Set the thermo manager. Note that the flow equations
|
||||
* assume the ideal gas equation.
|
||||
* Set the thermo manager. Note that the flow equations assume
|
||||
* the ideal gas equation.
|
||||
*/
|
||||
void setThermo(igthermo_t& th) {
|
||||
m_thermo = &th;
|
||||
//m_phase = &th.phase();
|
||||
}
|
||||
|
||||
/// set the kinetics manager
|
||||
|
|
@ -104,13 +101,56 @@ namespace Cantera {
|
|||
void setTransport(Transport& trans, bool withSoret = false);
|
||||
|
||||
/// set the pressure
|
||||
void setPressure(doublereal p) {
|
||||
m_press = p;
|
||||
}
|
||||
void setPressure(doublereal p) { m_press = p; }
|
||||
|
||||
/// Check that all required parameters have been set.
|
||||
bool ready();
|
||||
|
||||
virtual void setState(int point, const doublereal* state) {
|
||||
setTemperature(point, state[2]);
|
||||
int k;
|
||||
for (k = 0; k < m_nsp; k++) {
|
||||
setMassFraction(point, k, state[4+k]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual void _getInitialSoln(doublereal* x) {
|
||||
int k, j;
|
||||
for (j = 0; j < m_points; j++) {
|
||||
x[index(2,j)] = T_fixed(j);
|
||||
for (k = 0; k < m_nsp; k++) {
|
||||
x[index(4+k,j)] = Y_fixed(k,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void _finalize(const doublereal* x) {
|
||||
int k, j;
|
||||
doublereal zz, tt;
|
||||
int nz = m_zfix.size();
|
||||
bool e = m_do_energy[0];
|
||||
for (j = 0; j < m_points; j++) {
|
||||
if (e || nz == 0)
|
||||
setTemperature(j, T(x, j));
|
||||
else {
|
||||
zz = (z(j) - z(0))/(z(m_points - 1) - z(0));
|
||||
tt = linearInterp(zz, m_zfix, m_tfix);
|
||||
setTemperature(j, tt);
|
||||
}
|
||||
for (k = 0; k < m_nsp; k++) {
|
||||
setMassFraction(j, k, Y(x, k, j));
|
||||
}
|
||||
}
|
||||
if (e) solveEnergyEqn();
|
||||
}
|
||||
|
||||
|
||||
void setFixedTempProfile(vector_fp& zfixed, vector_fp& tfixed) {
|
||||
m_zfix = zfixed;
|
||||
m_tfix = tfixed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the temperature fixed point at grid point j, and
|
||||
* disable the energy equation so that the solution will be
|
||||
|
|
@ -128,10 +168,17 @@ namespace Cantera {
|
|||
*/
|
||||
void setMassFraction(int j, int k, doublereal y) {
|
||||
m_fixedy(k,j) = y;
|
||||
m_do_species[k] = false;
|
||||
m_do_species[k] = true; // false;
|
||||
}
|
||||
|
||||
/**
|
||||
* The fixed temperature value at point j.
|
||||
*/
|
||||
doublereal T_fixed(int j) const {return m_fixedtemp[j];}
|
||||
|
||||
/**
|
||||
* The fixed mass fraction value of species k at point j.
|
||||
*/
|
||||
doublereal Y_fixed(int k, int j) const {return m_fixedy(k,j);}
|
||||
|
||||
virtual string componentName(int n) const;
|
||||
|
|
@ -143,7 +190,7 @@ namespace Cantera {
|
|||
void outputTEC(ostream &s, const doublereal* x,
|
||||
string title, int zone);
|
||||
|
||||
void showSolution(ostream& s, const doublereal* x);
|
||||
virtual void showSolution(ostream& s, const doublereal* x);
|
||||
|
||||
void save(string fname, string id, string desc, doublereal* soln);
|
||||
virtual void save(XML_Node& o, doublereal* sol);
|
||||
|
|
@ -159,9 +206,12 @@ namespace Cantera {
|
|||
if (j < 0)
|
||||
for (int i = 0; i < m_points; i++)
|
||||
m_do_energy[i] = true;
|
||||
else
|
||||
m_do_energy[j] = true;
|
||||
requestJacUpdate();
|
||||
else
|
||||
m_do_energy[j] = true;
|
||||
m_refiner->setActive(0, true);
|
||||
m_refiner->setActive(1, true);
|
||||
m_refiner->setActive(2, true);
|
||||
needJacUpdate();
|
||||
}
|
||||
|
||||
void fixTemperature(int j=-1) {
|
||||
|
|
@ -170,7 +220,10 @@ namespace Cantera {
|
|||
m_do_energy[i] = false;
|
||||
}
|
||||
else m_do_energy[j] = false;
|
||||
requestJacUpdate();
|
||||
m_refiner->setActive(0, false);
|
||||
m_refiner->setActive(1, false);
|
||||
m_refiner->setActive(2, false);
|
||||
needJacUpdate();
|
||||
}
|
||||
|
||||
bool doSpecies(int k) { return m_do_species[k]; }
|
||||
|
|
@ -182,7 +235,7 @@ namespace Cantera {
|
|||
m_do_species[i] = true;
|
||||
}
|
||||
else m_do_species[k] = true;
|
||||
requestJacUpdate();
|
||||
needJacUpdate();
|
||||
}
|
||||
|
||||
void setEnergyFactor(doublereal efctr);
|
||||
|
|
@ -193,17 +246,14 @@ namespace Cantera {
|
|||
m_do_species[i] = false;
|
||||
}
|
||||
else m_do_species[k] = false;
|
||||
requestJacUpdate();
|
||||
needJacUpdate();
|
||||
//m_jac->setAge(10000);
|
||||
}
|
||||
|
||||
void integrateChem(doublereal* x,doublereal dt);
|
||||
|
||||
doublereal z(int j) const {return m_z[j];}
|
||||
doublereal zmin() const { return m_z[0]; }
|
||||
doublereal zmax() const { return m_z[m_points - 1]; }
|
||||
|
||||
void resize(int points);
|
||||
|
||||
virtual void setFixedPoint(int j0, doublereal t0){}
|
||||
|
||||
|
||||
|
|
@ -226,14 +276,10 @@ namespace Cantera {
|
|||
|
||||
protected:
|
||||
|
||||
// used to write mole fractions to plot files.
|
||||
// used to write mass fractions to plot files.
|
||||
|
||||
doublereal component(const doublereal* x, int i, int j) const {
|
||||
doublereal xx = x[index(i,j)];
|
||||
//if (i >= 4) {
|
||||
// return xx*m_wtm[j]/m_wt[i-4];
|
||||
//}
|
||||
//else return xx;
|
||||
return xx;
|
||||
}
|
||||
|
||||
|
|
@ -247,11 +293,16 @@ namespace Cantera {
|
|||
|
||||
doublereal wdot(int k, int j) const {return m_wdot(k,j);}
|
||||
|
||||
/// write the net production rates at point j into array m_wdot
|
||||
void getWdot(doublereal* x,int j) {
|
||||
setGas(x,j);
|
||||
m_kin->getNetProductionRates(&m_wdot(0,j));
|
||||
}
|
||||
|
||||
/**
|
||||
* update the thermodynamic properties from point
|
||||
* j0 to point j1 (inclusive), based on solution x.
|
||||
*/
|
||||
void updateThermo(const doublereal* x, int j0, int j1) {
|
||||
int j;
|
||||
for (j = j0; j <= j1; j++) {
|
||||
|
|
@ -262,6 +313,7 @@ namespace Cantera {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------
|
||||
// central-differenced derivatives
|
||||
//--------------------------------
|
||||
|
|
@ -329,17 +381,14 @@ namespace Cantera {
|
|||
// differencing, assuming u(z) is negative
|
||||
|
||||
doublereal dVdz(const doublereal* x,int j) const {
|
||||
//return (V(x,j+1) - V(x,j-1))/(m_dz[j] + m_dz[j-1]);
|
||||
return (V(x,j) - V(x,j-1))/m_dz[j-1];
|
||||
}
|
||||
|
||||
doublereal dYdz(const doublereal* x,int k, int j) const {
|
||||
//return (Y(x,k,j+1) - Y(x,k,j))/m_dz[j];
|
||||
return (Y(x,k,j) - Y(x,k,j-1))/m_dz[j-1];
|
||||
}
|
||||
|
||||
doublereal dTdz(const doublereal* x,int j) const {
|
||||
// return (T(x,j+1) - T(x,j))/m_dz[j];
|
||||
return (T(x,j) - T(x,j-1))/m_dz[j-1];
|
||||
}
|
||||
|
||||
|
|
@ -357,6 +406,12 @@ namespace Cantera {
|
|||
|
||||
void updateDiffFluxes(const doublereal* x, int j0, int j1);
|
||||
|
||||
//---------------------------------------------------------
|
||||
//
|
||||
// member data
|
||||
//
|
||||
//---------------------------------------------------------
|
||||
|
||||
// inlet
|
||||
doublereal m_inlet_u;
|
||||
doublereal m_inlet_V;
|
||||
|
|
@ -369,8 +424,9 @@ namespace Cantera {
|
|||
|
||||
doublereal m_press; // pressure
|
||||
|
||||
// grid parameters
|
||||
vector_fp m_dz;
|
||||
vector_fp m_z;
|
||||
//vector_fp m_z;
|
||||
|
||||
// mixture thermo properties
|
||||
vector_fp m_rho;
|
||||
|
|
@ -393,14 +449,11 @@ namespace Cantera {
|
|||
|
||||
int m_nsp;
|
||||
|
||||
//IdealGasMix* m_fluid;
|
||||
//thermo_t* m_phase;
|
||||
igthermo_t* m_thermo;
|
||||
kinetics_t* m_kin;
|
||||
igthermo_t* m_thermo;
|
||||
kinetics_t* m_kin;
|
||||
Transport* m_trans;
|
||||
//ImplicitChem* m_integrator;
|
||||
|
||||
MultiJac* m_jac;
|
||||
MultiJac* m_jac;
|
||||
|
||||
bool m_ok;
|
||||
|
||||
|
|
@ -410,23 +463,30 @@ namespace Cantera {
|
|||
vector<bool> m_do_species;
|
||||
int m_transport_option;
|
||||
|
||||
vector_fp m_zest;
|
||||
Array2D m_yest;
|
||||
// solution estimate
|
||||
//vector_fp m_zest;
|
||||
//Array2D m_yest;
|
||||
|
||||
// fixed T and Y values
|
||||
Array2D m_fixedy;
|
||||
vector_fp m_fixedtemp;
|
||||
vector_fp m_zfix;
|
||||
vector_fp m_tfix;
|
||||
|
||||
vector<FlowBdry::Boundary*> m_boundary;
|
||||
|
||||
doublereal m_efctr;
|
||||
|
||||
private:
|
||||
|
||||
void requestJacUpdate();
|
||||
vector_fp m_ybar;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A class for axisymmetric stagnation flows.
|
||||
*/
|
||||
class AxiStagnFlow : public StFlow {
|
||||
public:
|
||||
AxiStagnFlow(igthermo_t* ph = 0, int nsp = 1, int points = 1) :
|
||||
|
|
|
|||
|
|
@ -38,10 +38,11 @@ namespace Cantera {
|
|||
for (j = 0; j < np; j++) {
|
||||
val = x[index(m,j)];
|
||||
if (loglevel > 0) {
|
||||
if (val > above + Tiny || val < below - Tiny)
|
||||
cout << "ERROR: solution out of bounds. "
|
||||
<< r.componentName(m) << "(" << j << ") = " << val
|
||||
<< " (" << below << ", " << above << ")" << endl;
|
||||
if (val > above + Tiny || val < below - Tiny) {
|
||||
sprintf(buf, "domain %d: %20s(%d) = %10.3e (%10.3e, %10.3e)\n",
|
||||
r.domainIndex(), r.componentName(m).c_str(), j, val, below, above);
|
||||
writelog(string("ERROR: solution out of bounds.\n")+buf);
|
||||
}
|
||||
}
|
||||
|
||||
newval = val + step[index(m,j)];
|
||||
|
|
@ -57,13 +58,13 @@ namespace Cantera {
|
|||
if (loglevel > 1 && (newval > above || newval < below)) {
|
||||
if (!wroteTitle) {
|
||||
writelog("\nNewton step takes solution out of bounds.\n\n");
|
||||
sprintf(buf," %12s %4s %10s %10s %10s %10s\n",
|
||||
"component","pt","value","step","min","max");
|
||||
sprintf(buf," %12s %12s %4s %10s %10s %10s %10s\n",
|
||||
"domain","component","pt","value","step","min","max");
|
||||
wroteTitle = true;
|
||||
writelog(buf);
|
||||
}
|
||||
sprintf(buf, " %12s %4i %10.3e %10.3e %10.3e %10.3e\n",
|
||||
r.componentName(m).c_str(), j, val,
|
||||
sprintf(buf, " %4i %12s %4i %10.3e %10.3e %10.3e %10.3e\n",
|
||||
r.domainIndex(), r.componentName(m).c_str(), j, val,
|
||||
step[index(m,j)], below, above);
|
||||
writelog(buf);
|
||||
}
|
||||
|
|
|
|||
215
Cantera/src/oneD/refine.cpp
Normal file
215
Cantera/src/oneD/refine.cpp
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include "Resid1D.h"
|
||||
|
||||
#include "refine.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Cantera {
|
||||
|
||||
|
||||
template<class M>
|
||||
static bool has_key(const M& m, int j) {
|
||||
if (m.find(j) != m.end()) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the square root of machine precision.
|
||||
*/
|
||||
static doublereal eps() {
|
||||
doublereal e = 1.0;
|
||||
while (1.0 + e != 1.0) e *= 0.5;
|
||||
return sqrt(e);
|
||||
}
|
||||
|
||||
|
||||
Refiner::Refiner(Resid1D& domain) :
|
||||
m_ratio(10.0), m_slope(0.8), m_curve(0.8), m_min_range(0.01),
|
||||
m_domain(&domain)
|
||||
{
|
||||
m_nv = m_domain->nComponents();
|
||||
m_active.resize(m_nv, true);
|
||||
m_thresh = eps();
|
||||
}
|
||||
|
||||
|
||||
int Refiner::analyze(int n, const doublereal* z,
|
||||
const doublereal* x) {
|
||||
|
||||
if (m_domain->nPoints() <= 1) return 0;
|
||||
m_nv = m_domain->nComponents();
|
||||
|
||||
//m_ok = false;
|
||||
|
||||
// check consistency
|
||||
if (n != m_domain->nPoints()) return -1;
|
||||
|
||||
m_loc.clear();
|
||||
m_c.clear();
|
||||
|
||||
/**
|
||||
* find locations where cell size ratio is too large.
|
||||
*/
|
||||
int j;
|
||||
vector_fp dz(n-1, 0.0);
|
||||
dz[0] = z[1] - z[0];
|
||||
for (j = 1; j < n-1; j++) {
|
||||
dz[j] = z[j+1] - z[j];
|
||||
if (dz[j] > m_ratio*dz[j-1]) {
|
||||
m_loc[j] = 1;
|
||||
m_c["point "+int2str(j)] = 1;
|
||||
}
|
||||
if (dz[j] < dz[j-1]/m_ratio) {
|
||||
m_loc[j-1] = 1;
|
||||
m_c["point "+int2str(j-1)] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
string name;
|
||||
doublereal vmin, vmax, smin, smax, aa, ss;
|
||||
doublereal dmax, r;
|
||||
vector_fp v(n), s(n-1);
|
||||
for (int i = 0; i < m_nv; i++) {
|
||||
//cout << i << " " << m_nv << " " << m_active[i] << endl;
|
||||
if (m_active[i]) {
|
||||
name = m_domain->componentName(i);
|
||||
|
||||
// get component i at all points
|
||||
for (j = 0; j < n; j++) v[j] = value(x, i, j);
|
||||
|
||||
// slope of component i
|
||||
for (j = 0; j < n-1; j++)
|
||||
s[j] = (value(x, i, j+1) - value(x, i, j))/
|
||||
(z[j+1] - z[j]);
|
||||
|
||||
// find the range of values and slopes
|
||||
|
||||
vmin = *min_element(v.begin(), v.end());
|
||||
vmax = *max_element(v.begin(), v.end());
|
||||
smin = *min_element(s.begin(), s.end());
|
||||
smax = *max_element(s.begin(), s.end());
|
||||
|
||||
// max absolute values of v and s
|
||||
aa = fmaxx(abs(vmax), abs(vmin));
|
||||
ss = fmaxx(abs(smax), abs(smin));
|
||||
|
||||
|
||||
// refine based on component i only if the range of v is
|
||||
// greater than a fraction 'min_range' of max |v|. This
|
||||
// eliminates components that consist of small fluctuations
|
||||
// on a constant background.
|
||||
|
||||
if ((vmax - vmin) > m_min_range*aa) {
|
||||
|
||||
// maximum allowable difference in value between
|
||||
// adjacent points.
|
||||
|
||||
dmax = m_slope*(vmax - vmin) + m_thresh;
|
||||
for (j = 0; j < n-1; j++) {
|
||||
r = abs(v[j+1] - v[j])/dmax;
|
||||
if (r > 1.0) {
|
||||
m_loc[j] = 1;
|
||||
m_c[name] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// refine based on the slope of component i only if the
|
||||
// range of s is greater than a fraction 'min_range' of max
|
||||
// |s|. This eliminates components that consist of small
|
||||
// fluctuations on a constant slope background.
|
||||
|
||||
if ((smax - smin) > m_min_range*ss) {
|
||||
|
||||
// maximum allowable difference in slope between
|
||||
// adjacent points.
|
||||
dmax = m_curve*(smax - smin);
|
||||
for (j = 0; j < n-2; j++) {
|
||||
r = abs(s[j+1] - s[j]) / (dmax + m_thresh/dz[j]);
|
||||
if (r > 1.0) {
|
||||
m_c[name] = 1;
|
||||
m_loc[j] = 1;
|
||||
m_loc[j+1] = 1;
|
||||
}
|
||||
//cout << "at point " << j << " slope r = "
|
||||
// << r << " for " << name << endl
|
||||
// << " threshold = " << m_thresh << endl;
|
||||
}
|
||||
}
|
||||
//cout << name << " " << m_curve << " " << smax << " " << smin << " " << ss << " " << m_min_range << endl;
|
||||
}
|
||||
}
|
||||
return m_loc.size();
|
||||
}
|
||||
|
||||
double Refiner::value(const double* x, int i, int j) {
|
||||
return x[m_domain->index(i,j)];
|
||||
}
|
||||
|
||||
void Refiner::show() {
|
||||
int nnew = m_loc.size();
|
||||
if (nnew > 0) {
|
||||
writelog("Refining grid. "
|
||||
"New points inserted after grid points ");
|
||||
map<int, int>::const_iterator b = m_loc.begin();
|
||||
for (; b != m_loc.end(); ++b) {
|
||||
writelog(int2str(b->first)+" ");
|
||||
}
|
||||
writelog("\n");
|
||||
writelog("to resolve ");
|
||||
map<string, int>::const_iterator bb = m_c.begin();
|
||||
for (; bb != m_c.end(); ++bb) {
|
||||
writelog(string(bb->first)+" ");
|
||||
}
|
||||
writelog("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int Refiner::getNewGrid(int n, const doublereal* z,
|
||||
int nn, doublereal* zn) {
|
||||
int j;
|
||||
int nnew = m_loc.size();
|
||||
if (nnew + n > nn) {
|
||||
throw CanteraError("Refine::getNewGrid",
|
||||
"array size too small.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int jn = 0;
|
||||
if (m_loc.size() == 0) {
|
||||
copy(z, z + n, zn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (j = 0; j < n - 1; j++) {
|
||||
zn[jn] = z[j];
|
||||
jn++;
|
||||
if (has_key(m_loc, j)) {
|
||||
zn[jn] = 0.5*(z[j] + z[j+1]);
|
||||
jn++;
|
||||
}
|
||||
}
|
||||
zn[jn] = z[n-1];
|
||||
return 0;
|
||||
}
|
||||
|
||||
// int npts = znew.size();
|
||||
// newsoln.resize(npts*ncomp);
|
||||
// newsoln = Numeric.zeros((npts, ncomp),'d')
|
||||
// for i in range(ncomp):
|
||||
// for j in range(npts):
|
||||
// newsoln[j,i] = interp.interp(znew[j],grid,solution[:,i])
|
||||
|
||||
// return (Numeric.array(znew), Numeric.array(znew), newsoln, self.ok)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
47
Cantera/src/oneD/refine.h
Normal file
47
Cantera/src/oneD/refine.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
#ifndef CT_REFINE_H
|
||||
#define CT_REFINE_H
|
||||
|
||||
namespace Cantera {
|
||||
|
||||
class Resid1D;
|
||||
|
||||
class Refiner {
|
||||
|
||||
public:
|
||||
|
||||
Refiner(Resid1D& domain);
|
||||
virtual ~Refiner(){}
|
||||
|
||||
void setCriteria(doublereal ratio = 10.0,
|
||||
doublereal slope = 0.8,
|
||||
doublereal curve = 0.8) {
|
||||
m_ratio = ratio; m_slope = slope; m_curve = curve;
|
||||
}
|
||||
void setActive(int comp, bool state = true) { m_active[comp] = state; }
|
||||
|
||||
int analyze(int n, const doublereal* z, const doublereal* x);
|
||||
int getNewGrid(int n, const doublereal* z, int nn, doublereal* znew);
|
||||
//int getNewSoln(int n, const doublereal* x, doublereal* xnew);
|
||||
int nNewPoints() { return m_loc.size(); }
|
||||
void show();
|
||||
bool newPointNeeded(int j) {
|
||||
return m_loc.find(j) != m_loc.end();
|
||||
}
|
||||
double value(const double* x, int i, int j);
|
||||
|
||||
protected:
|
||||
|
||||
map<int, int> m_loc;
|
||||
map<string, int> m_c;
|
||||
vector<bool> m_active;
|
||||
doublereal m_ratio, m_slope, m_curve;
|
||||
doublereal m_min_range;
|
||||
Resid1D* m_domain;
|
||||
int m_nv;
|
||||
doublereal m_thresh;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Reference in a new issue