Cantera  2.0
ReactorNet.cpp
4 #include "cantera/zeroD/Wall.h"
5 
6 #include <cstdio>
7 
8 using namespace std;
9 using namespace Cantera;
10 
11 namespace Cantera
12 {
13 
14 ReactorNet::ReactorNet() : Cantera::FuncEval(), m_nr(0), m_nreactors(0),
15  m_integ(0), m_time(0.0), m_init(false),
16  m_nv(0), m_rtol(1.0e-9), m_rtolsens(1.0e-4),
17  m_atols(1.0e-15), m_atolsens(1.0e-4),
18  m_maxstep(-1.0),
19  m_verbose(false), m_ntotpar(0)
20 {
21 #ifdef DEBUG_MODE
22  m_verbose = true;
23 #endif
24  m_integ = newIntegrator("CVODE");// CVodeInt;
25 
26  // use backward differencing, with a full Jacobian computed
27  // numerically, and use a Newton linear iterator
28 
29  m_integ->setMethod(BDF_Method);
30  m_integ->setProblemType(DENSE + NOJAC);
31  m_integ->setIterator(Newton_Iter);
32 }
33 
34 ReactorNet::~ReactorNet()
35 {
36  for (size_t n = 0; n < m_nr; n++) {
37  if (m_iown[n]) {
38  delete m_r[n];
39  }
40  m_r[n] = 0;
41  }
42  m_r.clear();
43  m_reactors.clear();
44  deleteIntegrator(m_integ);
45 }
46 
47 void ReactorNet::initialize(doublereal t0)
48 {
49  size_t n, nv;
50  char buf[100];
51  m_nv = 0;
52  m_reactors.clear();
53  m_nreactors = 0;
54  if (m_verbose) {
55  writelog("Initializing reactor network.\n");
56  }
57  if (m_nr == 0)
58  throw CanteraError("ReactorNet::initialize",
59  "no reactors in network!");
60  for (n = 0; n < m_nr; n++) {
61  if (m_r[n]->type() >= ReactorType) {
62  m_r[n]->initialize(t0);
63  Reactor* r = (Reactor*)m_r[n];
64  m_reactors.push_back(r);
65  nv = r->neq();
66  m_size.push_back(nv);
67  m_nparams.push_back(r->nSensParams());
68  m_ntotpar += r->nSensParams();
69  m_nv += nv;
70  m_nreactors++;
71 
72  if (m_verbose) {
73  sprintf(buf,"Reactor %s: %s variables.\n",
74  int2str(n).c_str(), int2str(nv).c_str());
75  writelog(buf);
76  sprintf(buf," %s sensitivity params.\n",
77  int2str(r->nSensParams()).c_str());
78  writelog(buf);
79  }
80  if (m_r[n]->type() == FlowReactorType && m_nr > 1) {
81  throw CanteraError("ReactorNet::initialize",
82  "FlowReactors must be used alone.");
83  }
84  }
85  }
86 
87  m_connect.resize(m_nr*m_nr,0);
88  m_ydot.resize(m_nv,0.0);
89  size_t i, j, nin, nout, nw;
90  ReactorBase* r, *rj;
91  for (i = 0; i < m_nr; i++) {
92  r = m_reactors[i];
93  for (j = 0; j < m_nr; j++) {
94  if (i == j) {
95  connect(i,j);
96  } else {
97  rj = m_reactors[j];
98  nin = rj->nInlets();
99  for (n = 0; n < nin; n++) {
100  if (&rj->inlet(n).out() == r) {
101  connect(i,j);
102  }
103  }
104  nout = rj->nOutlets();
105  for (n = 0; n < nout; n++) {
106  if (&rj->outlet(n).in() == r) {
107  connect(i,j);
108  }
109  }
110  nw = rj->nWalls();
111  for (n = 0; n < nw; n++) {
112  if (&rj->wall(n).left() == rj
113  && &rj->wall(n).right() == r) {
114  connect(i,j);
115  } else if (&rj->wall(n).left() == r
116  && &rj->wall(n).right() == rj) {
117  connect(i,j);
118  }
119  }
120  }
121  }
122  }
123 
124  m_atol.resize(neq());
125  fill(m_atol.begin(), m_atol.end(), m_atols);
126  m_integ->setTolerances(m_rtol, neq(), DATA_PTR(m_atol));
127  m_integ->setSensitivityTolerances(m_rtolsens, m_atolsens);
128  m_integ->setMaxStepSize(m_maxstep);
129  if (m_verbose) {
130  sprintf(buf, "Number of equations: %s\n", int2str(neq()).c_str());
131  writelog(buf);
132  sprintf(buf, "Maximum time step: %14.6g\n", m_maxstep);
133  writelog(buf);
134  }
135  m_integ->initialize(t0, *this);
136  m_init = true;
137 }
138 
139 void ReactorNet::advance(doublereal time)
140 {
141  if (!m_init) {
142  if (m_maxstep < 0.0) {
143  m_maxstep = time - m_time;
144  }
145  initialize();
146  }
147  m_integ->integrate(time);
148  m_time = time;
149  updateState(m_integ->solution());
150 }
151 
152 double ReactorNet::step(doublereal time)
153 {
154  if (!m_init) {
155  if (m_maxstep < 0.0) {
156  m_maxstep = time - m_time;
157  }
158  initialize();
159  }
160  m_time = m_integ->step(time);
161  updateState(m_integ->solution());
162  return m_time;
163 }
164 
165 
166 void ReactorNet::addReactor(ReactorBase* r, bool iown)
167 {
168  if (r->type() >= ReactorType) {
169  m_r.push_back(r);
170  m_iown.push_back(iown);
171  m_nr++;
172  if (m_verbose) {
173  writelog("Adding reactor "+r->name()+"\n");
174  }
175  } else {
176  if (m_verbose) {
177  writelog("Not adding reactor "+r->name()+
178  ", since type = "+int2str(r->type())+"\n");
179  }
180  }
181 }
182 
183 // void ReactorNet::addSensitivityParam(int n, int stype, int i) {
184 // m_reactors[n]->addSensitivityParam(int stype, int i);
185 // m_sensreactor.push_back(n);
186 // m_nSenseParams++;
187 // }
188 
189 // void ReactorNet::setParameters(int np, double* p) {
190 // int n, nr;
191 // for (n = 0; n < np; n++) {
192 // if (n < m_nSenseParams) {
193 // nr = m_sensreactor[n];
194 // m_reactors[nr]->setParameter(n, p[n]);
195 // }
196 // }
197 // }
198 
199 
200 void ReactorNet::eval(doublereal t, doublereal* y,
201  doublereal* ydot, doublereal* p)
202 {
203  size_t n;
204  size_t start = 0;
205  size_t pstart = 0;
206  // use a try... catch block, since exceptions are not passed
207  // through CVODE, since it is C code
208  try {
209  updateState(y);
210  for (n = 0; n < m_nreactors; n++) {
211  m_reactors[n]->evalEqs(t, y + start,
212  ydot + start, p + pstart);
213  start += m_size[n];
214  pstart += m_nparams[n];
215  }
216  } catch (CanteraError& err) {
217  std::cerr << err.what() << std::endl;
218  error("Terminating execution.");
219  }
220 }
221 
222 
223 
224 void ReactorNet::evalJacobian(doublereal t, doublereal* y,
225  doublereal* ydot, doublereal* p, Array2D* j)
226 {
227  doublereal ysave, dy;
228  Array2D& jac = *j;
229 
230  // use a try... catch block, since exceptions are not passed
231  // through CVODE, since it is C code
232  try {
233  //evaluate the unperturbed ydot
234  eval(t, y, ydot, p);
235  for (size_t n = 0; n < m_nv; n++) {
236 
237  // perturb x(n)
238  ysave = y[n];
239  dy = m_atol[n] + fabs(ysave)*m_rtol;
240  y[n] = ysave + dy;
241  dy = y[n] - ysave;
242 
243  // calculate perturbed residual
244  eval(t, y, DATA_PTR(m_ydot), p);
245 
246  // compute nth column of Jacobian
247  for (size_t m = 0; m < m_nv; m++) {
248  jac(m,n) = (m_ydot[m] - ydot[m])/dy;
249  }
250  y[n] = ysave;
251  }
252  } catch (CanteraError& err) {
253  std::cerr << err.what() << std::endl;
254  error("Terminating execution.");
255  }
256 }
257 
258 void ReactorNet::updateState(doublereal* y)
259 {
260  size_t start = 0;
261  for (size_t n = 0; n < m_nreactors; n++) {
262  m_reactors[n]->updateState(y + start);
263  start += m_size[n];
264  }
265 }
266 
267 void ReactorNet::getInitialConditions(doublereal t0,
268  size_t leny, doublereal* y)
269 {
270  size_t start = 0;
271  for (size_t n = 0; n < m_nreactors; n++) {
272  m_reactors[n]->getInitialConditions(t0, m_size[n], y + start);
273  start += m_size[n];
274  }
275 }
276 
277 size_t ReactorNet::globalComponentIndex(string species, size_t reactor)
278 {
279  size_t start = 0;
280  size_t n;
281  for (n = 0; n < reactor; n++) {
282  start += m_size[n];
283  }
284  return start + m_reactors[n]->componentIndex(species);
285 }
286 
287 }