Cantera  2.2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
OneDim.cpp
Go to the documentation of this file.
1 //! @file OneDim.cpp
3 #include "cantera/oneD/OneDim.h"
4 
6 #include "cantera/base/ctml.h"
7 
8 #include <fstream>
9 #include <ctime>
10 
11 using namespace std;
12 
13 namespace Cantera
14 {
15 
16 OneDim::OneDim()
17  : m_tmin(1.0e-16), m_tmax(10.0), m_tfactor(0.5),
18  m_jac(0), m_newt(0),
19  m_rdt(0.0), m_jac_ok(false),
20  m_nd(0), m_bw(0), m_size(0),
21  m_init(false), m_pts(0), m_solve_time(0.0),
22  m_ss_jac_age(10), m_ts_jac_age(20),
23  m_interrupt(0), m_nevals(0), m_evaltime(0.0)
24 {
25  m_newt = new MultiNewton(1);
26 }
27 
28 OneDim::OneDim(vector<Domain1D*> domains) :
29  m_tmin(1.0e-16), m_tmax(10.0), m_tfactor(0.5),
30  m_jac(0), m_newt(0),
31  m_rdt(0.0), m_jac_ok(false),
32  m_nd(0), m_bw(0), m_size(0),
33  m_init(false), m_solve_time(0.0),
34  m_ss_jac_age(10), m_ts_jac_age(20),
35  m_interrupt(0), m_nevals(0), m_evaltime(0.0)
36 {
37  // create a Newton iterator, and add each domain.
38  m_newt = new MultiNewton(1);
39  for (size_t i = 0; i < domains.size(); i++) {
40  addDomain(domains[i]);
41  }
42  init();
43  resize();
44 }
45 
46 size_t OneDim::domainIndex(const std::string& name)
47 {
48  for (size_t n = 0; n < m_nd; n++) {
49  if (domain(n).id() == name) {
50  return n;
51  }
52  }
53  throw CanteraError("OneDim::domainIndex","no domain named >>"+name+"<<");
54 }
55 
57 {
58  // if 'd' is not the first domain, link it to the last domain
59  // added (the rightmost one)
60  size_t n = m_dom.size();
61  if (n > 0) {
62  m_dom.back()->append(d);
63  }
64 
65  // every other domain is a connector
66  if (n % 2 == 0) {
67  m_connect.push_back(d);
68  } else {
69  m_bulk.push_back(d);
70  }
71 
72  // add it also to the global domain list, and set its
73  // container and position
74  m_dom.push_back(d);
75  d->setContainer(this, m_nd);
76  m_nd++;
77  resize();
78 }
79 
80 OneDim::~OneDim()
81 {
82  delete m_jac;
83  delete m_newt;
84 }
85 
87 {
88  return *m_jac;
89 }
91 {
92  return *m_newt;
93 }
94 
95 void OneDim::writeStats(int printTime)
96 {
97  saveStats();
98  char buf[100];
99  sprintf(buf,"\nStatistics:\n\n Grid Functions Time Jacobians Time \n");
100  writelog(buf);
101  size_t n = m_gridpts.size();
102  for (size_t i = 0; i < n; i++) {
103  if (printTime) {
104  sprintf(buf,"%5s %5i %9.4f %5i %9.4f \n",
105  int2str(m_gridpts[i]).c_str(), m_funcEvals[i], m_funcElapsed[i],
106  m_jacEvals[i], m_jacElapsed[i]);
107  } else {
108  sprintf(buf,"%5s %5i NA %5i NA \n",
109  int2str(m_gridpts[i]).c_str(), m_funcEvals[i], m_jacEvals[i]);
110  }
111  writelog(buf);
112  }
113 }
114 
116 {
117  if (m_jac) {
118  int nev = m_jac->nEvals();
119  if (nev > 0 && m_nevals > 0) {
120  m_gridpts.push_back(m_pts);
121  m_jacEvals.push_back(m_jac->nEvals());
122  m_jacElapsed.push_back(m_jac->elapsedTime());
123  m_funcEvals.push_back(m_nevals);
124  m_nevals = 0;
125  m_funcElapsed.push_back(m_evaltime);
126  m_evaltime = 0.0;
127  }
128  }
129 }
130 
132 {
133  m_gridpts.clear();
134  m_jacEvals.clear();
135  m_jacElapsed.clear();
136  m_funcEvals.clear();
137  m_funcElapsed.clear();
138  m_nevals = 0;
139  m_evaltime = 0.0;
140 }
141 
143 {
144  m_bw = 0;
145  m_nvars.clear();
146  m_loc.clear();
147  size_t lc = 0;
148 
149  // save the statistics for the last grid
150  saveStats();
151  m_pts = 0;
152  for (size_t i = 0; i < m_nd; i++) {
153  Domain1D* d = m_dom[i];
154 
155  size_t np = d->nPoints();
156  size_t nv = d->nComponents();
157  for (size_t n = 0; n < np; n++) {
158  m_nvars.push_back(nv);
159  m_loc.push_back(lc);
160  lc += nv;
161  m_pts++;
162  }
163 
164  // update the Jacobian bandwidth
165 
166  // bandwidth of the local block
167  size_t bw1 = d->bandwidth();
168  if (bw1 == npos) {
169  bw1 = 2*d->nComponents() - 1;
170  }
171  m_bw = std::max(m_bw, bw1);
172 
173  // bandwidth of the block coupling the first point of this
174  // domain to the last point of the previous domain
175  if (i > 0) {
176  size_t bw2 = m_dom[i-1]->bandwidth();
177  if (bw2 == npos) {
178  bw2 = m_dom[i-1]->nComponents();
179  }
180  bw2 += d->nComponents() - 1;
181  m_bw = std::max(m_bw, bw2);
182  }
183  m_size = d->loc() + d->size();
184  }
185 
186  m_newt->resize(size());
187  m_mask.resize(size());
188 
189  // delete the current Jacobian evaluator and create a new one
190  delete m_jac;
191  m_jac = new MultiJac(*this);
192  m_jac_ok = false;
193 
194  for (size_t i = 0; i < m_nd; i++) {
195  m_dom[i]->setJac(m_jac);
196  }
197 }
198 
199 int OneDim::solve(doublereal* x, doublereal* xnew, int loglevel)
200 {
201  if (!m_jac_ok) {
202  eval(npos, x, xnew, 0.0, 0);
203  m_jac->eval(x, xnew, 0.0);
204  m_jac->updateTransient(m_rdt, DATA_PTR(m_mask));
205  m_jac_ok = true;
206  }
207  return m_newt->solve(x, xnew, *this, *m_jac, loglevel);
208 }
209 
210 void OneDim::evalSSJacobian(doublereal* x, doublereal* xnew)
211 {
212  doublereal rdt_save = m_rdt;
213  m_jac_ok = false;
214  setSteadyMode();
215  eval(npos, x, xnew, 0.0, 0);
216  m_jac->eval(x, xnew, 0.0);
217  m_rdt = rdt_save;
218 }
219 
221 {
222  Domain1D* d = right();
223  while (d) {
224  if (d->loc() <= i) {
225  return d;
226  }
227  d = d->left();
228  }
229  return 0;
230 }
231 
232 void OneDim::eval(size_t j, double* x, double* r, doublereal rdt, int count)
233 {
234  clock_t t0 = clock();
235  if (m_interrupt) {
236  m_interrupt->eval(m_nevals);
237  }
238  fill(r, r + m_size, 0.0);
239  fill(m_mask.begin(), m_mask.end(), 0);
240  if (rdt < 0.0) {
241  rdt = m_rdt;
242  }
243  vector<Domain1D*>::iterator d;
244 
245  // iterate over the bulk domains first
246  for (d = m_bulk.begin(); d != m_bulk.end(); ++d) {
247  (*d)->eval(j, x, r, DATA_PTR(m_mask), rdt);
248  }
249 
250  // then over the connector domains
251  for (d = m_connect.begin(); d != m_connect.end(); ++d) {
252  (*d)->eval(j, x, r, DATA_PTR(m_mask), rdt);
253  }
254 
255  // increment counter and time
256  if (count) {
257  clock_t t1 = clock();
258  m_evaltime += double(t1 - t0)/CLOCKS_PER_SEC;
259  m_nevals++;
260  }
261 }
262 
263 doublereal OneDim::ssnorm(doublereal* x, doublereal* r)
264 {
265  eval(npos, x, r, 0.0, 0);
266  doublereal ss = 0.0;
267  for (size_t i = 0; i < m_size; i++) {
268  ss = std::max(fabs(r[i]),ss);
269  }
270  return ss;
271 }
272 
273 void OneDim::initTimeInteg(doublereal dt, doublereal* x)
274 {
275  doublereal rdt_old = m_rdt;
276  m_rdt = 1.0/dt;
277 
278  // if the stepsize has changed, then update the transient
279  // part of the Jacobian
280  if (fabs(rdt_old - m_rdt) > Tiny) {
281  m_jac->updateTransient(m_rdt, DATA_PTR(m_mask));
282  }
283 
284  // iterate over all domains, preparing each one to begin
285  // time stepping
286  Domain1D* d = left();
287  while (d) {
288  d->initTimeInteg(dt, x);
289  d = d->right();
290  }
291 }
292 
294 {
295  m_rdt = 0.0;
296  m_jac->updateTransient(m_rdt, DATA_PTR(m_mask));
297 
298  // iterate over all domains, preparing them for steady-state solution
299  Domain1D* d = left();
300  while (d) {
301  d->setSteadyMode();
302  d = d->right();
303  }
304 }
305 
307 {
308  if (!m_init) {
309  Domain1D* d = left();
310  while (d) {
311  d->init();
312  d = d->right();
313  }
314  }
315  m_init = true;
316 }
317 
318 doublereal OneDim::timeStep(int nsteps, doublereal dt, doublereal* x,
319  doublereal* r, int loglevel)
320 {
321  // set the Jacobian age parameter to the transient value
322  newton().setOptions(m_ts_jac_age);
323 
324  writelog("\n\n step size (s) log10(ss) \n", loglevel);
325  writelog("===============================\n", loglevel);
326 
327  int n = 0;
328  char str[80];
329  while (n < nsteps) {
330  if (loglevel > 0) {
331  doublereal ss = ssnorm(x, r);
332  sprintf(str, " %4d %10.4g %10.4g" , n,dt,log10(ss));
333  writelog(str);
334  }
335 
336  // set up for time stepping with stepsize dt
337  initTimeInteg(dt,x);
338 
339  // solve the transient problem
340  int m = solve(x, r, loglevel-1);
341 
342  // successful time step. Copy the new solution in r to
343  // the current solution in x.
344  if (m >= 0) {
345  n += 1;
346  writelog("\n", loglevel);
347  copy(r, r + m_size, x);
348  if (m == 100) {
349  dt *= 1.5;
350  }
351  dt = std::min(dt, m_tmax);
352  }
353 
354  // No solution could be found with this time step.
355  // Decrease the stepsize and try again.
356  else {
357  writelog("...failure.\n", loglevel);
358  dt *= m_tfactor;
359  if (dt < m_tmin)
360  throw CanteraError("OneDim::timeStep",
361  "Time integration failed.");
362  }
363  }
364 
365  // Prepare to solve the steady problem.
366  setSteadyMode();
367  newton().setOptions(m_ss_jac_age);
368 
369  // return the value of the last stepsize, which may be smaller
370  // than the initial stepsize
371  return dt;
372 }
373 
374 void OneDim::save(const std::string& fname, std::string id,
375  const std::string& desc, doublereal* sol,
376  int loglevel)
377 {
378  time_t aclock;
379  ::time(&aclock); // Get time in seconds
380  struct tm* newtime = localtime(&aclock); // Convert time to struct tm form
381 
382  XML_Node root("ctml");
383  ifstream fin(fname.c_str());
384  if (fin) {
385  root.build(fin);
386  // Remove existing solution with the same id
387  XML_Node* same_ID = root.findID(id);
388  if (same_ID) {
389  same_ID->parent()->removeChild(same_ID);
390  }
391  fin.close();
392  }
393  XML_Node& sim = root.addChild("simulation");
394  sim.addAttribute("id",id);
395  addString(sim,"timestamp",asctime(newtime));
396  if (desc != "") {
397  addString(sim,"description",desc);
398  }
399 
400  Domain1D* d = left();
401  while (d) {
402  d->save(sim, sol);
403  d = d->right();
404  }
405  ofstream s(fname.c_str());
406  if (!s) {
407  throw CanteraError("OneDim::save","could not open file "+fname);
408  }
409  root.write(s);
410  s.close();
411  writelog("Solution saved to file "+fname+" as solution "+id+".\n", loglevel);
412 }
413 
414 }
size_t m_nd
number of domains
Definition: OneDim.h:268
std::string int2str(const int n, const std::string &fmt)
Convert an int to a string using a format converter.
Definition: stringUtils.cpp:39
Domain1D * left()
Pointer to left-most domain (first added).
Definition: OneDim.h:87
void addDomain(Domain1D *d)
Add a domain. Domains are added left-to-right.
Definition: OneDim.cpp:56
size_t nPoints() const
Number of grid points in this domain.
Definition: Domain1D.h:186
Domain1D * left() const
Return a pointer to the left neighbor.
Definition: Domain1D.h:468
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data...
int nEvals() const
Number of Jacobian evaluations.
Definition: MultiJac.h:44
double timeStep(int nsteps, double dt, double *x, double *r, int loglevel)
Definition: OneDim.cpp:318
void resize()
Call after one or more grids has been refined.
Definition: OneDim.cpp:142
void setSteadyMode()
Definition: Domain1D.h:296
doublereal ssnorm(doublereal *x, doublereal *r)
Steady-state max norm (infinity norm) of the residual evaluated using solution x. ...
Definition: OneDim.cpp:263
void eval(size_t j, double *x, double *r, doublereal rdt=-1.0, int count=1)
Evaluate the multi-domain residual function.
Definition: OneDim.cpp:232
MultiJac & jacobian()
Return a reference to the Jacobian evaluator.
Definition: OneDim.cpp:86
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:165
void addString(XML_Node &node, const std::string &titleString, const std::string &valueString, const std::string &typeString)
This function adds a child node with the name string with a string value to the current node...
Definition: ctml.cpp:122
virtual size_t loc(size_t j=0) const
Location of the start of the local solution vector in the global solution vector,.
Definition: Domain1D.h:427
int solve(doublereal *x0, doublereal *x1, int loglevel)
Solve F(x) = 0, where F(x) is the multi-domain residual function.
Definition: OneDim.cpp:199
Class XML_Node is a tree-based representation of the contents of an XML file.
Definition: xml.h:100
void setContainer(OneDim *c, size_t index)
Definition: Domain1D.h:91
MultiNewton & newton()
Return a reference to the Newton iterator.
Definition: OneDim.cpp:90
virtual doublereal eval(doublereal t) const
Evaluate the function.
Definition: Func1.cpp:56
size_t nComponents() const
Number of components at each grid point.
Definition: Domain1D.h:164
Base class for one-dimensional domains.
Definition: Domain1D.h:37
int solve(doublereal *x0, doublereal *x1, OneDim &r, MultiJac &jac, int loglevel)
Find the solution to F(X) = 0 by damped Newton iteration.
size_t bandwidth()
Set the Jacobian bandwidth for this domain.
Definition: Domain1D.h:116
Domain1D & domain(size_t i) const
Return a reference to domain i.
Definition: OneDim.h:53
void setSteadyMode()
Definition: OneDim.cpp:293
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:99
void resize(size_t points)
Change the problem size.
void saveStats()
Save statistics on function and Jacobian evaluation, and reset the counters.
Definition: OneDim.cpp:115
Domain1D * right() const
Return a pointer to the right neighbor.
Definition: Domain1D.h:473
void clearStats()
Clear saved statistics.
Definition: OneDim.cpp:131
void eval(doublereal *x0, doublereal *resid0, double rdt)
Evaluate the Jacobian at x0.
Definition: MultiJac.cpp:50
void writeStats(int printTime=1)
Write statistics about the number of iterations and Jacobians at each grid level. ...
Definition: OneDim.cpp:95
Class MultiJac evaluates the Jacobian of a system of equations defined by a residual function supplie...
Definition: MultiJac.h:25
void removeChild(const XML_Node *const node)
Remove a child from this node's list of children.
Definition: xml.cpp:440
void initTimeInteg(doublereal dt, doublereal *x)
Prepare for time stepping beginning with solution x and timestep dt.
Definition: OneDim.cpp:273
const doublereal Tiny
Small number to compare differences of mole fractions against.
Definition: ct_defs.h:142
XML_Node * findID(const std::string &id, const int depth=100) const
This routine carries out a recursive search for an XML node based on the XML element attribute...
Definition: xml.cpp:685
doublereal elapsedTime() const
Elapsed CPU time spent computing the Jacobian.
Definition: MultiJac.h:39
#define DATA_PTR(vec)
Creates a pointer to the start of the raw data for a vector.
Definition: ct_defs.h:36
Func1 * m_interrupt
Function called at the start of every call to eval.
Definition: OneDim.h:286
Newton iterator for multi-domain, one-dimensional problems.
Definition: MultiNewton.h:22
void writelog(const std::string &msg)
Write a message to the screen.
Definition: global.cpp:33
Domain1D * right()
Pointer to right-most domain (last added).
Definition: OneDim.h:92
size_t size() const
Total solution vector length;.
Definition: OneDim.h:82
Domain1D * pointDomain(size_t i)
Return a pointer to the domain global point i belongs to.
Definition: OneDim.cpp:220
XML_Node * parent() const
Returns a pointer to the parent node of the current node.
Definition: xml.cpp:552
void setOptions(int maxJacAge=5)
Set options.
Definition: MultiNewton.h:70
virtual void init()
Definition: Domain1D.h:125
void initTimeInteg(doublereal dt, const doublereal *x0)
Definition: Domain1D.h:287