Cantera  2.0
Sim1D.cpp
Go to the documentation of this file.
1 /**
2  * @file Sim1D.cpp
3  */
4 
5 #include "cantera/oneD/Sim1D.h"
7 
8 #include <fstream>
9 #include <cstdlib>
10 #include <cstdio>
11 
12 using namespace std;
13 
14 namespace Cantera
15 {
16 
17 static void sim1D_drawline()
18 {
19  string s(78,'.');
20  s += '\n';
21  writelog(s.c_str());
22 }
23 //====================================================================================================================
24 Sim1D::Sim1D() :
25  OneDim()
26 {
27  //writelog("Sim1D default constructor\n");
28 }
29 //====================================================================================================================
30 Sim1D::Sim1D(vector<Domain1D*>& domains) :
31  OneDim(domains)
32 {
33 
34  // resize the internal solution vector and the wprk array,
35  // and perform domain-specific initialization of the
36  // solution vector.
37 
38  m_x.resize(size(), 0.0);
39  m_xnew.resize(size(), 0.0);
40  for (size_t n = 0; n < m_nd; n++) {
41  domain(n)._getInitialSoln(DATA_PTR(m_x) + start(n));
42  domain(n).m_adiabatic=false;
43  }
44 
45  // set some defaults
46  m_tstep = 1.0e-5;
47  //m_maxtimestep = 10.0;
48  m_steps.push_back(1);
49  m_steps.push_back(2);
50  m_steps.push_back(5);
51  m_steps.push_back(10);
52 
53 }
54 //====================================================================================================================
55 
56 void Sim1D::setInitialGuess(string component, vector_fp& locs, vector_fp& vals)
57 {
58 
59  for (size_t dom=0; dom<m_nd; dom++) {
60  Domain1D& d = domain(dom);
61  size_t ncomp = d.nComponents();
62  for (size_t comp=0; comp<ncomp; comp++) {
63  if (d.componentName(comp)==component) {
64  setProfile(dom,comp,locs,vals);
65  }
66  }
67  }
68 }
69 
70 
71 /**
72  * Set a single value in the solution vector.
73  * @param dom domain number, beginning with 0 for the leftmost domain.
74  * @param comp component number
75  * @param localPoint grid point within the domain, beginning with 0 for
76  * the leftmost grid point in the domain.
77  * @param value the value.
78  */
79 void Sim1D::setValue(size_t dom, size_t comp, size_t localPoint, doublereal value)
80 {
81  size_t iloc = domain(dom).loc() + domain(dom).index(comp, localPoint);
82  m_x[iloc] = value;
83 }
84 
85 
86 /**
87  * @param dom domain number, beginning with 0 for the leftmost domain.
88  * @param comp component number
89  * @param localPoint grid point within the domain, beginning with 0 for
90  * the leftmost grid point in the domain.
91  */
92 doublereal Sim1D::value(size_t dom, size_t comp, size_t localPoint) const
93 {
94  size_t iloc = domain(dom).loc() + domain(dom).index(comp, localPoint);
95 #ifdef DEBUG_MODE
96  int j = static_cast<int>(iloc);
97  if (j < 0) {
98  throw CanteraError("Sim1D::value", "out of bounds: " + int2str(j));
99  }
100  if (j >= (int) m_x.size()) {
101  throw CanteraError("Sim1D::value", "exceeded top of bounds: " + int2str(j) +
102  " >= " + int2str(m_x.size()));
103  }
104 #endif
105  return m_x[iloc];
106 }
107 
108 doublereal Sim1D::workValue(size_t dom, size_t comp, size_t localPoint) const
109 {
110  size_t iloc = domain(dom).loc() + domain(dom).index(comp, localPoint);
111  return m_xnew[iloc];
112 }
113 
114 
115 /**
116  * @param dom domain number, beginning with 0 for the leftmost domain.
117  * @param comp component number
118  * @param pos A vector of relative positions, beginning with 0.0 at the
119  * left of the domain, and ending with 1.0 at the right of the domain.
120  * @param values A vector of values corresponding to the relative position
121  * locations.
122  *
123  * Note that the vector pos and values can have lengths
124  * different than the number of grid points, but their lengths
125  * must be equal. The values at the grid points will be
126  * linearly interpolated based on the (pos, values)
127  * specification.
128  */
129 void Sim1D::setProfile(size_t dom, size_t comp,
130  const vector_fp& pos, const vector_fp& values)
131 {
132 
133  Domain1D& d = domain(dom);
134  doublereal z0 = d.zmin();
135  doublereal z1 = d.zmax();
136  doublereal zpt, frac, v;
137  for (size_t n = 0; n < d.nPoints(); n++) {
138  zpt = d.z(n);
139  frac = (zpt - z0)/(z1 - z0);
140  v = linearInterp(frac, pos, values);
141  setValue(dom, comp, n, v);
142  }
143 }
144 
145 
146 void Sim1D::save(string fname, string id, string desc)
147 {
148  OneDim::save(fname, id, desc, DATA_PTR(m_x));
149 }
150 
151 /**
152  * Initialize the solution with a previously-saved solution.
153  */
154 void Sim1D::restore(string fname, string id)
155 {
156  ifstream s(fname.c_str());
157  //char buf[100];
158  if (!s)
159  throw CanteraError("Sim1D::restore",
160  "could not open input file "+fname);
161 
162  XML_Node root;
163  root.build(s);
164  s.close();
165 
166  XML_Node* f = root.findID(id);
167  if (!f) {
168  throw CanteraError("Sim1D::restore","No solution with id = "+id);
169  }
170 
171  vector<XML_Node*> xd;
172  size_t sz = 0, np, m;
173  for (m = 0; m < m_nd; m++) {
174  XML_Node* d = f->findID(domain(m).id());
175  if (!d) {
176  writelog("No data for domain "+domain(m).id());
177  xd.push_back(0);
178  sz += domain(m).nComponents();
179  } else {
180  const XML_Node& node = *d;
181  xd.push_back(d);
182  np = intValue(node["points"]);
183  sz += np*domain(m).nComponents();
184  }
185  }
186  m_x.resize(sz);
187  m_xnew.resize(sz);
188  for (m = 0; m < m_nd; m++) {
189  if (xd[m]) {
190  domain(m).restore(*xd[m], DATA_PTR(m_x) + domain(m).loc());
191  }
192  }
193  resize();
194  finalize();
195 }
196 
197 
198 void Sim1D::setFlatProfile(size_t dom, size_t comp, doublereal v)
199 {
200  size_t np = domain(dom).nPoints();
201  size_t n;
202  for (n = 0; n < np; n++) {
203  setValue(dom, comp, n, v);
204  }
205 }
206 
207 
208 void Sim1D::showSolution(ostream& s)
209 {
210  for (size_t n = 0; n < m_nd; n++) {
211  if (domain(n).domainType() != cEmptyType) {
212  domain(n).showSolution_s(s, DATA_PTR(m_x) + start(n));
213  }
214  }
215 }
216 
217 void Sim1D::showSolution()
218 {
219  for (size_t n = 0; n < m_nd; n++) {
220  if (domain(n).domainType() != cEmptyType) {
221  writelog("\n\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> "+domain(n).id()
222  +" <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n");
223  domain(n).showSolution(DATA_PTR(m_x) + start(n));
224  }
225  }
226 }
227 
228 void Sim1D::getInitialSoln()
229 {
230  for (size_t n = 0; n < m_nd; n++) {
231  domain(n)._getInitialSoln(DATA_PTR(m_x) + start(n));
232  }
233 }
234 
236 {
237  for (size_t n = 0; n < m_nd; n++) {
238  domain(n)._finalize(DATA_PTR(m_x) + start(n));
239  }
240 }
241 
242 
243 void Sim1D::setTimeStep(doublereal stepsize, size_t n, integer* tsteps)
244 {
245  m_tstep = stepsize;
246  m_steps.resize(n);
247  for (size_t i = 0; i < n; i++) {
248  m_steps[i] = tsteps[i];
249  }
250 }
251 
252 
253 int Sim1D::newtonSolve(int loglevel)
254 {
255  int m = OneDim::solve(DATA_PTR(m_x), DATA_PTR(m_xnew), loglevel);
256  if (m >= 0) {
257  copy(m_xnew.begin(), m_xnew.end(), m_x.begin());
258  return 0;
259  } else if (m > -10) {
260  return -1;
261  } else {
262  throw CanteraError("Sim1D::newtonSolve",
263  "ERROR: OneDim::solve returned m = " + int2str(m) + "\n");
264  }
265 }
266 
267 
268 void Sim1D::solve(int loglevel, bool refine_grid)
269 {
270  int new_points = 1;
271  int nsteps;
272  doublereal dt = m_tstep;
273  int soln_number = -1;
274  finalize();
275 
276  while (new_points > 0) {
277  size_t istep = 0;
278  nsteps = m_steps[istep];
279 
280  bool ok = false;
281  while (!ok) {
282  if (loglevel > 0) {
283  sim1D_drawline();
284  writelog("\nAttempt Newton solution of steady-state problem...");
285  }
286  int status = newtonSolve(loglevel-1);
287 
288  if (status == 0) {
289  if (loglevel > 0) {
290  writelog(" success.\n\n");
291  writelog("Problem solved on [");
292  for (size_t mm = 1; mm < nDomains(); mm+=2) {
293  writelog(int2str(domain(mm).nPoints()));
294  if (mm + 2 < nDomains()) {
295  writelog(", ");
296  }
297  }
298  writelog("]");
299  writelog(" point grid(s).\n\n");
300  }
301  ok = true;
302  soln_number++;
303  } else {
304  char buf[100];
305  if (loglevel > 0) {
306  writelog(" failure. \n\n");
307  sim1D_drawline();
308  writelog("Take "+int2str(nsteps)+" timesteps ");
309  }
310  dt = timeStep(nsteps, dt, DATA_PTR(m_x), DATA_PTR(m_xnew),
311  loglevel-1);
312  if (loglevel == 1) {
313  sprintf(buf, " %10.4g %10.4g \n", dt,
314  log10(ssnorm(DATA_PTR(m_x), DATA_PTR(m_xnew))));
315  writelog(buf);
316  }
317  istep++;
318  if (istep >= m_steps.size()) {
319  nsteps = m_steps.back();
320  } else {
321  nsteps = m_steps[istep];
322  }
323  if (dt > m_tmax) {
324  dt = m_tmax;
325  }
326  }
327  }
328  if (loglevel > 2) {
329  showSolution();
330  }
331 
332  if (refine_grid) {
333  new_points = refine(loglevel);
334  if (new_points < 0) {
335  writelog("Maximum number of grid points reached.");
336  new_points = 0;
337  }
338  } else {
339  if (loglevel > 0) {
340  writelog("grid refinement disabled.\n");
341  }
342  new_points = 0;
343  }
344  }
345 }
346 
347 
348 /**
349  * Refine the grid in all domains.
350  */
351 int Sim1D::refine(int loglevel)
352 {
353  int ianalyze, np = 0;
354  vector_fp znew, xnew;
355  doublereal xmid, zmid;
356  std::vector<size_t> dsize;
357 
358  for (size_t n = 0; n < m_nd; n++) {
359  Domain1D& d = domain(n);
360  Refiner& r = d.refiner();
361 
362  // determine where new points are needed
363  ianalyze = r.analyze(d.grid().size(),
364  DATA_PTR(d.grid()), DATA_PTR(m_x) + start(n));
365  if (ianalyze < 0) {
366  return ianalyze;
367  }
368 
369  if (loglevel > 0) {
370  r.show();
371  }
372 
373  np += r.nNewPoints();
374  size_t comp = d.nComponents();
375 
376  // loop over points in the current grid
377  size_t npnow = d.nPoints();
378  size_t nstart = znew.size();
379  for (size_t m = 0; m < npnow; m++) {
380 
381  if (r.keepPoint(m)) {
382  // add the current grid point to the new grid
383  znew.push_back(d.grid(m));
384 
385  // do the same for the solution at this point
386  for (size_t i = 0; i < comp; i++) {
387  xnew.push_back(value(n, i, m));
388  }
389 
390  // now check whether a new point is needed in the
391  // interval to the right of point m, and if so, add
392  // entries to znew and xnew for this new point
393 
394  if (r.newPointNeeded(m) && m + 1 < npnow) {
395 
396  // add new point at midpoint
397  zmid = 0.5*(d.grid(m) + d.grid(m+1));
398  znew.push_back(zmid);
399  np++;
400  //writelog(string("refine: adding point at ")+fp2str(zmid)+"\n");
401 
402  // for each component, linearly interpolate
403  // the solution to this point
404  for (size_t i = 0; i < comp; i++) {
405  xmid = 0.5*(value(n, i, m) + value(n, i, m+1));
406  xnew.push_back(xmid);
407  }
408  }
409  } else {
410  writelog(string("refine: discarding point at ")+fp2str(d.grid(m))+"\n");
411  ; // throw CanteraError("refine","keepPoint is false at m = "+int2str(m));
412  }
413  }
414  dsize.push_back(znew.size() - nstart);
415  }
416 
417  // At this point, the new grid znew and the new solution
418  // vector xnew have been constructed, but the domains
419  // themselves have not yet been modified. Now update each
420  // domain with the new grid.
421 
422  size_t gridstart = 0, gridsize;
423  for (size_t n = 0; n < m_nd; n++) {
424  Domain1D& d = domain(n);
425  // Refiner& r = d.refiner();
426  gridsize = dsize[n]; // d.nPoints() + r.nNewPoints();
427  d.setupGrid(gridsize, DATA_PTR(znew) + gridstart);
428  gridstart += gridsize;
429  }
430 
431  // Replace the current solution vector with the new one
432  m_x.resize(xnew.size());
433  copy(xnew.begin(), xnew.end(), m_x.begin());
434 
435  // resize the work array
436  m_xnew.resize(xnew.size());
437 
438  // copy(xnew.begin(), xnew.end(), m_xnew.begin());
439 
440  resize();
441  finalize();
442  return np;
443 }
444 
445 
446 /**
447  * Add node for fixed temperature point of freely propagating flame
448  */
449 int Sim1D::setFixedTemperature(doublereal t)
450 {
451  int np = 0;
452  vector_fp znew, xnew;
453  doublereal xmid;
454  doublereal zfixed,interp_factor;
455  doublereal z1 = 0.0, z2 = 0.0, t1,t2;
456  size_t n, m, i;
457  size_t m1 = 0;
458  std::vector<size_t> dsize;
459 
460 
461  for (n = 0; n < m_nd; n++) {
462  bool addnewpt=false;
463  Domain1D& d = domain(n);
464 
465  size_t comp = d.nComponents();
466 
467  // loop over points in the current grid to determine where new point is needed.
468  size_t npnow = d.nPoints();
469  size_t nstart = znew.size();
470  for (m = 0; m < npnow-1; m++) {
471  //cout << "T["<<m<<"]="<<value(n,2,m)<<endl;
472  if (value(n,2,m) == t) {
473  zfixed = d.grid(m);
474  //set d.zfixed, d.ztemp
475  d.m_zfixed = zfixed;
476  d.m_tfixed = t;
477  cout << "T already fixed at " << d.grid(m) << endl;
478  addnewpt = false;
479  break;
480  } else if ((value(n,2,m)<t) && (value(n,2,m+1)>t)) {
481  cout << "T in between "<<value(n,2,m)<<" and "<<value(n,2,m+1)<<endl;
482  z1 = d.grid(m);
483  m1 = m;
484  z2 = d.grid(m+1);
485  t1 = value(n,2,m);
486  t2 = value(n,2,m+1);
487 
488  zfixed = (z1-z2)/(t1-t2)*(t-t2)+z2;
489  //cout << zfixed<<endl;
490  //set d.zfixed, d.ztemp;
491  d.m_zfixed = zfixed;
492  d.m_tfixed = t;
493  addnewpt = true;
494  break;
495  //copy solution domain and push back values
496  }
497  }
498 
499 
500  for (m = 0; m < npnow; m++) {
501  // add the current grid point to the new grid
502  znew.push_back(d.grid(m));
503 
504  // do the same for the solution at this point
505  for (i = 0; i < comp; i++) {
506  xnew.push_back(value(n, i, m));
507  }
508  if (m==m1 && addnewpt) {
509  //add new point at zfixed
510  znew.push_back(zfixed);
511  np++;
512  interp_factor = (zfixed-z2) / (z1-z2);
513  // for each component, linearly interpolate
514  // the solution to this point
515  for (i = 0; i < comp; i++) {
516  xmid = interp_factor*(value(n, i, m) - value(n, i, m+1)) + value(n,i,m+1);
517  xnew.push_back(xmid);
518  }
519  }
520 
521 
522  }
523  dsize.push_back(znew.size() - nstart);
524  }
525 
526  // At this point, the new grid znew and the new solution
527  // vector xnew have been constructed, but the domains
528  // themselves have not yet been modified. Now update each
529  // domain with the new grid.
530 
531  size_t gridstart = 0, gridsize;
532  for (n = 0; n < m_nd; n++) {
533  Domain1D& d = domain(n);
534  // Refiner& r = d.refiner();
535  gridsize = dsize[n]; // d.nPoints() + r.nNewPoints();
536  d.setupGrid(gridsize, DATA_PTR(znew) + gridstart);
537  gridstart += gridsize;
538  }
539 
540  // Replace the current solution vector with the new one
541  m_x.resize(xnew.size());
542  copy(xnew.begin(), xnew.end(), m_x.begin());
543 
544  // resize the work array
545  m_xnew.resize(xnew.size());
546 
547  copy(xnew.begin(), xnew.end(), m_xnew.begin());
548 
549  resize();
550  finalize();
551  return np;
552 }
553 
554 void Sim1D::setAdiabaticFlame(void)
555 {
556  for (size_t n = 0; n < m_nd; n++) {
557  Domain1D& d = domain(n);
558  d.m_adiabatic=true;
559  }
560 }
561 
562 /**
563  * Set grid refinement criteria. If dom >= 0, then the settings
564  * apply only to the specified domain. If dom < 0, the settings
565  * are applied to each domain. @see Refiner::setCriteria.
566  */
567 void Sim1D::setRefineCriteria(int dom, doublereal ratio,
568  doublereal slope, doublereal curve, doublereal prune)
569 {
570  if (dom >= 0) {
571  Refiner& r = domain(dom).refiner();
572  r.setCriteria(ratio, slope, curve, prune);
573  } else {
574  for (size_t n = 0; n < m_nd; n++) {
575  Refiner& r = domain(n).refiner();
576  r.setCriteria(ratio, slope, curve, prune);
577  }
578  }
579 }
580 
581 void Sim1D::setGridMin(int dom, double gridmin)
582 {
583  if (dom >= 0) {
584  Refiner& r = domain(dom).refiner();
585  r.setGridMin(gridmin);
586  } else {
587  for (size_t n = 0; n < m_nd; n++) {
588  Refiner& r = domain(n).refiner();
589  r.setGridMin(gridmin);
590  }
591  }
592 }
593 
594 
595 void Sim1D::setMaxGridPoints(int dom, int npoints)
596 {
597  if (dom >= 0) {
598  Refiner& r = domain(dom).refiner();
599  r.setMaxPoints(npoints);
600  } else {
601  for (size_t n = 0; n < m_nd; n++) {
602  Refiner& r = domain(n).refiner();
603  r.setMaxPoints(npoints);
604  }
605  }
606 }
607 
608 doublereal Sim1D::jacobian(int i, int j)
609 {
610  return OneDim::jacobian().value(i,j);
611 }
612 
613 void Sim1D::evalSSJacobian()
614 {
615  OneDim::evalSSJacobian(DATA_PTR(m_x), DATA_PTR(m_xnew));
616 }
617 }