Cantera  2.0
Domain1D.h
Go to the documentation of this file.
1 /**
2  * @file Domain1D.h
3  */
4 /*
5  * Copyright 2002 California Institute of Technology
6  */
7 
8 #ifndef CT_DOMAIN1D_H
9 #define CT_DOMAIN1D_H
10 
11 
12 #include "cantera/base/xml.h"
15 #include "refine.h"
16 
17 
18 namespace Cantera
19 {
20 
21 // domain types
22 const int cFlowType = 50;
23 const int cConnectorType = 100;
24 const int cSurfType = 102;
25 const int cInletType = 104;
26 const int cSymmType = 105;
27 const int cOutletType = 106;
28 const int cEmptyType = 107;
29 const int cOutletResType = 108;
30 const int cPorousType = 109;
31 
32 class MultiJac;
33 class OneDim;
34 
35 
36 /**
37  * Base class for one-dimensional domains.
38  */
39 class Domain1D
40 {
41 public:
42 
43  /**
44  * Constructor.
45  * @param nv Number of variables at each grid point.
46  * @param points Number of grid points.
47  */
48  Domain1D(size_t nv=1, size_t points=1,
49  doublereal time = 0.0) :
50  m_rdt(0.0),
51  m_nv(0),
52  m_time(time),
53  m_container(0),
54  m_index(npos),
55  m_type(0),
56  m_iloc(0),
57  m_jstart(0),
58  m_left(0),
59  m_right(0),
60  m_id(""), m_desc(""),
61  m_refiner(0), m_bw(-1) {
62  resize(nv, points);
63  }
64 
65  /// Destructor. Does nothing
66  virtual ~Domain1D() {
67  delete m_refiner;
68  }
69 
70  /// Domain type flag.
71  int domainType() {
72  return m_type;
73  }
74 
75  /**
76  * The left-to-right location of this domain.
77  */
78  size_t domainIndex() {
79  return m_index;
80  }
81 
82  /**
83  * True if the domain is a connector domain.
84  */
85  bool isConnector() {
86  return (m_type >= cConnectorType);
87  }
88 
89  /**
90  * The container holding this domain.
91  */
92  const OneDim& container() const {
93  return *m_container;
94  }
95 
96  /**
97  * Specify the container object for this domain, and the
98  * position of this domain in the list.
99  */
100  void setContainer(OneDim* c, size_t index) {
101  m_container = c;
102  m_index = index;
103  }
104 
105  /*
106  * Set the Jacobian bandwidth. See the discussion of method bandwidth.
107  */
108  void setBandwidth(int bw = -1) {
109  m_bw = bw;
110  }
111 
112  /**
113  * Set the Jacobian bandwidth for this domain. When class
114  * OneDim computes the bandwidth of the overall multi-domain
115  * problem (in OneDim::resize()), it calls this method for the
116  * bandwidth of each domain. If setBandwidth has not been
117  * called, then a negative bandwidth is returned, in which
118  * case OneDim assumes that this domain is dense -- that is,
119  * at each point, all components depend on the value of all
120  * other components at that point. In this case, the bandwidth
121  * is bw = 2*nComponents() - 1. However, if this domain
122  * contains some components that are uncoupled from other
123  * components at the same point, then this default bandwidth
124  * may greatly overestimate the true bandwidth, with a
125  * substantial penalty in performance. For such domains, use
126  * method setBandwidth to specify the bandwidth before passing
127  * this domain to the Sim1D or OneDim constructor.
128  */
129  size_t bandwidth() {
130  return m_bw;
131  }
132 
133  /**
134  * Initialize. This method is called by OneDim::init() for
135  * each domain once at the beginning of a simulation. Base
136  * class method does nothing, but may be overloaded.
137  */
138  virtual void init() { }
139 
140  virtual void setInitialState(doublereal* xlocal = 0) {}
141  virtual void setState(size_t point, const doublereal* state, doublereal* x) {}
142 
143  /**
144  * Resize the domain to have nv components and np grid points.
145  * This method is virtual so that subclasses can perform other
146  * actions required to resize the domain.
147  */
148  virtual void resize(size_t nv, size_t np) {
149  // if the number of components is being changed, then a
150  // new grid refiner is required.
151  if (nv != m_nv || !m_refiner) {
152  m_nv = nv;
153  delete m_refiner;
154  m_refiner = new Refiner(*this);
155  }
156  m_nv = nv;
157  m_td.resize(m_nv, 1);
158  m_name.resize(m_nv,"");
159  m_max.resize(m_nv, 0.0);
160  m_min.resize(m_nv, 0.0);
161  m_rtol_ss.resize(m_nv, 1.0e-8);
162  m_atol_ss.resize(m_nv, 1.0e-15);
163  m_rtol_ts.resize(m_nv, 1.0e-8);
164  m_atol_ts.resize(m_nv, 1.0e-15);
165  m_points = np;
166  m_z.resize(np, 0.0);
167  m_slast.resize(m_nv * m_points, 0.0);
168  locate();
169  }
170 
171  /// Return a reference to the grid refiner.
172  Refiner& refiner() {
173  return *m_refiner;
174  }
175 
176  /// Number of components at each grid point.
177  size_t nComponents() const {
178  return m_nv;
179  }
180 
181  //! Check that the specified component index is in range
182  //! Throws an exception if n is greater than nComponents()-1
183  void checkComponentIndex(size_t n) const {
184  if (n >= m_nv) {
185  throw IndexError("checkComponentIndex", "points", n, m_nv-1);
186  }
187  }
188 
189  //! Check that an array size is at least nComponents()
190  //! Throws an exception if nn is less than nComponents(). Used before calls
191  //! which take an array pointer.
192  void checkComponentArraySize(size_t nn) const {
193  if (m_nv > nn) {
194  throw ArraySizeError("checkComponentArraySize", nn, m_nv);
195  }
196  }
197 
198  /// Number of grid points in this domain.
199  size_t nPoints() const {
200  return m_points;
201  }
202 
203  //! Check that the specified point index is in range
204  //! Throws an exception if n is greater than nPoints()-1
205  void checkPointIndex(size_t n) const {
206  if (n >= m_points) {
207  throw IndexError("checkPointIndex", "points", n, m_points-1);
208  }
209  }
210 
211  //! Check that an array size is at least nPoints()
212  //! Throws an exception if nn is less than nPoints(). Used before calls
213  //! which take an array pointer.
214  void checkPointArraySize(size_t nn) const {
215  if (m_points > nn) {
216  throw ArraySizeError("checkPointArraySize", nn, m_points);
217  }
218  }
219 
220  /// Name of the nth component. May be overloaded.
221  virtual std::string componentName(size_t n) const {
222  if (m_name[n] != "") {
223  return m_name[n];
224  } else {
225  return "component " + int2str(n);
226  }
227  }
228 
229  void setComponentName(size_t n, std::string name) {
230  m_name[n] = name;
231  }
232 
233  void setComponentType(size_t n, int ctype) {
234  if (ctype == 0) {
235  setAlgebraic(n);
236  }
237  }
238 
239  /// index of component with name \a name.
240  size_t componentIndex(std::string name) const {
241  size_t nc = nComponents();
242  for (size_t n = 0; n < nc; n++) {
243  if (name == componentName(n)) {
244  return n;
245  }
246  }
247  throw CanteraError("Domain1D::componentIndex",
248  "no component named "+name);
249  }
250 
251  /**
252  * Set the lower and upper bounds for each solution component.
253  */
254  void setBounds(size_t nl, const doublereal* lower,
255  size_t nu, const doublereal* upper) {
256  if (nl < m_nv || nu < m_nv)
257  throw CanteraError("Domain1D::setBounds",
258  "wrong array size for solution bounds. "
259  "Size should be at least "+int2str(m_nv));
260  std::copy(upper, upper + m_nv, m_max.begin());
261  std::copy(lower, lower + m_nv, m_min.begin());
262  }
263 
264  void setBounds(size_t n, doublereal lower, doublereal upper) {
265  m_min[n] = lower;
266  m_max[n] = upper;
267  }
268 
269  /// set the error tolerances for all solution components.
270  void setTolerances(size_t nr, const doublereal* rtol,
271  size_t na, const doublereal* atol, int ts = 0);
272 
273  /// set the error tolerances for solution component \a n.
274  void setTolerances(size_t n, doublereal rtol, doublereal atol, int ts = 0);
275 
276  /// set scalar error tolerances. All solution components will
277  /// have the same relative and absolute error tolerances.
278  void setTolerances(doublereal rtol, doublereal atol,int ts=0);
279 
280  void setTolerancesTS(doublereal rtol, doublereal atol);
281 
282  void setTolerancesSS(doublereal rtol, doublereal atol);
283 
284  /// Relative tolerance of the nth component.
285  doublereal rtol(size_t n) {
286  return (m_rdt == 0.0 ? m_rtol_ss[n] : m_rtol_ts[n]);
287  }
288 
289  /// Absolute tolerance of the nth component.
290  doublereal atol(size_t n) {
291  return (m_rdt == 0.0 ? m_atol_ss[n] : m_atol_ts[n]);
292  }
293 
294  /// Upper bound on the nth component.
295  doublereal upperBound(size_t n) const {
296  return m_max[n];
297  }
298 
299  /// Lower bound on the nth component
300  doublereal lowerBound(size_t n) const {
301  return m_min[n];
302  }
303 
304 
305  /**
306  * Prepare to do time stepping with time step dt. Copy the
307  * internally-stored solution at the last time step to array
308  * x0.
309  */
310  void initTimeInteg(doublereal dt, const doublereal* x0) {
311  std::copy(x0 + loc(), x0 + loc() + size(), m_slast.begin());
312  m_rdt = 1.0/dt;
313  }
314 
315  /**
316  * Prepare to solve the steady-state problem.
317  * Set the internally-stored reciprocal of the time step to 0,0
318  */
319  void setSteadyMode() {
320  m_rdt = 0.0;
321  }
322 
323  /// True if in steady-state mode
324  bool steady() {
325  return (m_rdt == 0.0);
326  }
327 
328  /// True if not in steady-state mode
329  bool transient() {
330  return (m_rdt != 0.0);
331  }
332 
333  /**
334  * Set this if something has changed in the governing
335  * equations (e.g. the value of a constant has been changed,
336  * so that the last-computed Jacobian is no longer valid.
337  * Note: see file OneDim.cpp for the implementation of this method.
338  */
339  void needJacUpdate();
340 
341  /**
342  * Evaluate the steady-state residual at all points, even if in
343  * transient mode. Used only to print diagnostic output.
344  */
345  void evalss(doublereal* x, doublereal* r, integer* mask) {
346  eval(npos,x,r,mask,0.0);
347  }
348 
349  //! Evaluate the residual function at point j. If j == npos,
350  //! evaluate the residual function at all points.
351  /*!
352  * @param j Grid point j
353  * @param x Soln vector. This is the input.
354  * @param r residual this is the output.
355  */
356  virtual void eval(size_t j, doublereal* x, doublereal* r,
357  integer* mask, doublereal rdt=0.0);
358 
359  virtual doublereal residual(doublereal* x, size_t n, size_t j) {
360  throw CanteraError("Domain1D::residual","residual function must be overloaded in derived class "+id());
361  }
362 
363  int timeDerivativeFlag(size_t n) {
364  return m_td[n];
365  }
366  void setAlgebraic(size_t n) {
367  m_td[n] = 0;
368  }
369 
370  /**
371  * Does nothing.
372  */
373  virtual void update(doublereal* x) {}
374 
375  doublereal time() const {
376  return m_time;
377  }
378  void incrementTime(doublereal dt) {
379  m_time += dt;
380  }
381  size_t index(size_t n, size_t j) const {
382  return m_nv*j + n;
383  }
384  doublereal value(const doublereal* x, size_t n, size_t j) const {
385  return x[index(n,j)];
386  }
387 
388  virtual void setJac(MultiJac* jac) {}
389 
390  //! Save the current solution for this domain into an XML_Node
391  /*!
392  * Base class version of the general domain1D save function. This
393  * base class version will throw an error condition. Inherited classes
394  * will know how to save the solution vector.
395  *
396  * @param o XML_Node to save the solution to.
397  * @param sol Current value of the solution vector.
398  * The object will pick out which part of the solution
399  * vector pertains to this object.
400  */
401  virtual void save(XML_Node& o, const doublereal* const sol) {
402  throw CanteraError("Domain1D::save","base class method called");
403  }
404 
405  size_t size() const {
406  return m_nv*m_points;
407  }
408 
409  /**
410  * Find the index of the first grid point in this domain, and
411  * the start of its variables in the global solution vector.
412  */
413  void locate() {
414 
415  if (m_left) {
416  // there is a domain on the left, so the first grid point
417  // in this domain is one more than the last one on the left
418  m_jstart = m_left->lastPoint() + 1;
419 
420  // the starting location in the solution vector
421  m_iloc = m_left->loc() + m_left->size();
422  } else {
423  // this is the left-most domain
424  m_jstart = 0;
425  m_iloc = 0;
426  }
427  // if there is a domain to the right of this one, then
428  // repeat this for it
429  if (m_right) {
430  m_right->locate();
431  }
432  }
433 
434  /**
435  * Location of the start of the local solution vector in the global
436  * solution vector,
437  */
438  virtual size_t loc(size_t j = 0) const {
439  return m_iloc;
440  }
441 
442  /**
443  * The index of the first (i.e., left-most) grid point
444  * belonging to this domain.
445  */
446  size_t firstPoint() const {
447  return m_jstart;
448  }
449 
450  /**
451  * The index of the last (i.e., right-most) grid point
452  * belonging to this domain.
453  */
454  size_t lastPoint() const {
455  return m_jstart + m_points - 1;
456  }
457 
458  /**
459  * Set the left neighbor to domain 'left.' Method 'locate' is
460  * called to update the global positions of this domain and
461  * all those to its right.
462  */
464  m_left = left;
465  locate();
466  }
467 
468  /**
469  * Set the right neighbor to domain 'right.'
470  */
472  m_right = right;
473  }
474 
475  /**
476  * Append domain 'right' to this one, and update all links.
477  */
479  linkRight(right);
480  right->linkLeft(this);
481  }
482 
483  /**
484  * Return a pointer to the left neighbor.
485  */
486  Domain1D* left() const {
487  return m_left;
488  }
489 
490  /**
491  * Return a pointer to the right neighbor.
492  */
493  Domain1D* right() const {
494  return m_right;
495  }
496 
497  /**
498  * Value of component n at point j in the previous solution.
499  */
500  double prevSoln(size_t n, size_t j) const {
501  return m_slast[m_nv*j + n];
502  }
503 
504  /**
505  * Specify an identifying tag for this domain.
506  */
507  void setID(const std::string& s) {
508  m_id = s;
509  }
510 
511  std::string id() const {
512  if (m_id != "") {
513  return m_id;
514  } else {
515  return std::string("domain ") + int2str(m_index);
516  }
517  }
518 
519  /**
520  * Specify descriptive text for this domain.
521  */
522  void setDesc(const std::string& s) {
523  m_desc = s;
524  }
525  const std::string& desc() {
526  return m_desc;
527  }
528 
529  virtual void getTransientMask(integer* mask) {}
530 
531  virtual void showSolution_s(std::ostream& s, const doublereal* x) {}
532  virtual void showSolution(const doublereal* x);
533 
534  virtual void restore(const XML_Node& dom, doublereal* soln) {}
535 
536  doublereal z(size_t jlocal) const {
537  return m_z[jlocal];
538  }
539  doublereal zmin() const {
540  return m_z[0];
541  }
542  doublereal zmax() const {
543  return m_z[m_points - 1];
544  }
545 
546 
547  void setProfile(std::string name, doublereal* values, doublereal* soln) {
548  for (size_t n = 0; n < m_nv; n++) {
549  if (name == componentName(n)) {
550  for (size_t j = 0; j < m_points; j++) {
551  soln[index(n, j) + m_iloc] = values[j];
552  }
553  return;
554  }
555  }
556  throw CanteraError("Domain1D::setProfile",
557  "unknown component: "+name);
558  }
559 
560  vector_fp& grid() {
561  return m_z;
562  }
563  const vector_fp& grid() const {
564  return m_z;
565  }
566  doublereal grid(size_t point) {
567  return m_z[point];
568  }
569 
570  virtual void setupGrid(size_t n, const doublereal* z);
571 
572  void setGrid(size_t n, const doublereal* z);
573 
574  /**
575  * Writes some or all initial solution values into the global
576  * solution array, beginning at the location pointed to by
577  * x. This method is called by the Sim1D constructor, and
578  * allows default values or ones that have been set locally
579  * prior to installing this domain into the container to be
580  * written to the global solution vector.
581  */
582  virtual void _getInitialSoln(doublereal* x);
583 
584  /**
585  * Initial value of solution component \a n at grid point \a j.
586  */
587  virtual doublereal initialValue(size_t n, size_t j);
588 
589  /**
590  * In some cases, a domain may need to set parameters that
591  * depend on the initial solution estimate. In such cases, the
592  * parameters may be set in method _finalize. This method is
593  * called just before the Newton solver is called, and the x
594  * array is guaranteed to be the local solution vector for
595  * this domain that will be used as the initial guess. If no
596  * such parameters need to be set, then method _finalize does
597  * not need to be overloaded.
598  */
599  virtual void _finalize(const doublereal* x) {}
600 
601  doublereal m_zfixed;
602  doublereal m_tfixed;
603 
604  bool m_adiabatic;
605 
606 protected:
607 
608  doublereal m_rdt;
609  size_t m_nv;
610  size_t m_points;
611  vector_fp m_slast;
612  doublereal m_time;
613  vector_fp m_max;
614  vector_fp m_min;
615  vector_fp m_rtol_ss, m_rtol_ts;
616  vector_fp m_atol_ss, m_atol_ts;
617  vector_fp m_z;
618  OneDim* m_container;
619  size_t m_index;
620  int m_type;
621 
622  //! Starting location within the solution vector for unknowns
623  //! that correspond to this domain
624  /*!
625  * Remember there may be multiple domains associated with
626  * this problem
627  */
628  size_t m_iloc;
629 
630  size_t m_jstart;
631 
632  Domain1D* m_left, *m_right;
633 
634  //! Identity tag for the domain
635  std::string m_id;
636  std::string m_desc;
637  Refiner* m_refiner;
638  vector_int m_td;
639  std::vector<std::string> m_name;
640  int m_bw;
641 
642 private:
643 
644 };
645 }
646 
647 #endif