Cantera  2.1.2
refine.cpp
Go to the documentation of this file.
1 //! @file refine.cpp
2 #include "cantera/oneD/refine.h"
4 
5 #include <algorithm>
6 #include <limits>
7 
8 using namespace std;
9 
10 namespace Cantera
11 {
12 static void r_drawline()
13 {
14  string s(78,'#');
15  s += '\n';
16  writelog(s.c_str());
17 }
18 
19 Refiner::Refiner(Domain1D& domain) :
20  m_ratio(10.0), m_slope(0.8), m_curve(0.8), m_prune(-0.001),
21  m_min_range(0.01), m_domain(&domain), m_npmax(3000),
22  m_gridmin(5e-6)
23 {
24  m_nv = m_domain->nComponents();
25  m_active.resize(m_nv, true);
26  m_thresh = std::sqrt(std::numeric_limits<double>::epsilon());
27 }
28 
29 int Refiner::analyze(size_t n, const doublereal* z,
30  const doublereal* x)
31 {
32  if (n >= m_npmax) {
33  writelog("max number of grid points reached ("+int2str(m_npmax)+".\n");
34  return -2;
35  }
36 
37  if (m_domain->nPoints() <= 1) {
38  return 0;
39  }
40 
41  m_loc.clear();
42  m_c.clear();
43  m_keep.clear();
44 
45  m_keep[0] = 1;
46  m_keep[n-1] = 1;
47 
48  m_nv = m_domain->nComponents();
49 
50  // check consistency
51  if (n != m_domain->nPoints()) {
52  throw CanteraError("analyze","inconsistent");
53  }
54 
55  // find locations where cell size ratio is too large.
56  vector_fp v(n), s(n-1);
57 
58  vector_fp dz(n-1);
59  for (size_t j = 0; j < n-1; j++) {
60  dz[j] = z[j+1] - z[j];
61  }
62 
63  for (size_t i = 0; i < m_nv; i++) {
64  if (m_active[i]) {
65  string name = m_domain->componentName(i);
66  // get component i at all points
67  for (size_t j = 0; j < n; j++) {
68  v[j] = value(x, i, j);
69  }
70 
71  // slope of component i
72  for (size_t j = 0; j < n-1; j++) {
73  s[j] = (value(x, i, j+1) - value(x, i, j))/(z[j+1] - z[j]);
74  }
75 
76  // find the range of values and slopes
77  doublereal vmin = *min_element(v.begin(), v.end());
78  doublereal vmax = *max_element(v.begin(), v.end());
79  doublereal smin = *min_element(s.begin(), s.end());
80  doublereal smax = *max_element(s.begin(), s.end());
81 
82  // max absolute values of v and s
83  doublereal aa = std::max(fabs(vmax), fabs(vmin));
84  doublereal ss = std::max(fabs(smax), fabs(smin));
85 
86  // refine based on component i only if the range of v is
87  // greater than a fraction 'min_range' of max |v|. This
88  // eliminates components that consist of small fluctuations
89  // on a constant background.
90  if ((vmax - vmin) > m_min_range*aa) {
91  // maximum allowable difference in value between adjacent
92  // points.
93  doublereal dmax = m_slope*(vmax - vmin) + m_thresh;
94  for (size_t j = 0; j < n-1; j++) {
95  doublereal r = fabs(v[j+1] - v[j])/dmax;
96  if (r > 1.0 && dz[j] >= 2 * m_gridmin) {
97  m_loc[j] = 1;
98  m_c[name] = 1;
99  }
100  if (r >= m_prune) {
101  m_keep[j] = 1;
102  m_keep[j+1] = 1;
103  } else if (m_keep[j] == 0) {
104  m_keep[j] = -1;
105  }
106  }
107  }
108 
109  // refine based on the slope of component i only if the
110  // range of s is greater than a fraction 'min_range' of max
111  // |s|. This eliminates components that consist of small
112  // fluctuations on a constant slope background.
113  if ((smax - smin) > m_min_range*ss) {
114  // maximum allowable difference in slope between
115  // adjacent points.
116  doublereal dmax = m_curve*(smax - smin);
117  for (size_t j = 0; j < n-2; j++) {
118  doublereal r = fabs(s[j+1] - s[j]) / (dmax + m_thresh/dz[j]);
119  if (r > 1.0 && dz[j] >= 2 * m_gridmin &&
120  dz[j+1] >= 2 * m_gridmin) {
121  m_c[name] = 1;
122  m_loc[j] = 1;
123  m_loc[j+1] = 1;
124  }
125  if (r >= m_prune) {
126  m_keep[j+1] = 1;
127  } else if (m_keep[j+1] == 0) {
128  m_keep[j+1] = -1;
129  }
130  }
131  }
132  }
133  }
134 
135  // Refine based on properties of the grid itself
136  for (size_t j = 1; j < n-1; j++) {
137  // Add a new point if the ratio with left interval is too large
138  if (dz[j] > m_ratio*dz[j-1]) {
139  m_loc[j] = 1;
140  m_c["point "+int2str(j)] = 1;
141  m_keep[j-1] = 1;
142  m_keep[j] = 1;
143  m_keep[j+1] = 1;
144  m_keep[j+2] = 1;
145  }
146 
147  // Add a point if the ratio with right interval is too large
148  if (dz[j] < dz[j-1]/m_ratio) {
149  m_loc[j-1] = 1;
150  m_c["point "+int2str(j-1)] = 1;
151  m_keep[j-2] = 1;
152  m_keep[j-1] = 1;
153  m_keep[j] = 1;
154  m_keep[j+1] = 1;
155  }
156 
157  // Keep the point if removing would make the ratio with the left
158  // interval too large.
159  if (j > 1 && z[j+1]-z[j-1] > m_ratio * dz[j-2]) {
160  m_keep[j] = 1;
161  }
162 
163  // Keep the point if removing would make the ratio with the right
164  // interval too large.
165  if (j < n-2 && z[j+1]-z[j-1] > m_ratio * dz[j+1]) {
166  m_keep[j] = 1;
167  }
168 
169  // Keep the point where the temperature is fixed
170  if (z[j] == m_domain->m_zfixed) {
171  m_keep[j] = 1;
172  }
173  }
174 
175  // Don't allow pruning to remove multiple adjacent grid points
176  // in a single pass.
177  for (size_t j = 2; j < n-1; j++) {
178  if (m_keep[j] == -1 && m_keep[j-1] == -1) {
179  m_keep[j] = 1;
180  }
181  }
182 
183  return int(m_loc.size());
184 }
185 
186 double Refiner::value(const double* x, size_t i, size_t j)
187 {
188  return x[m_domain->index(i,j)];
189 }
190 
191 void Refiner::show()
192 {
193  if (!m_loc.empty()) {
194  r_drawline();
195  writelog(string("Refining grid in ") +
196  m_domain->id()+".\n"
197  +" New points inserted after grid points ");
198  map<size_t, int>::const_iterator b = m_loc.begin();
199  for (; b != m_loc.end(); ++b) {
200  writelog(int2str(b->first)+" ");
201  }
202  writelog("\n");
203  writelog(" to resolve ");
204  map<string, int>::const_iterator bb = m_c.begin();
205  for (; bb != m_c.end(); ++bb) {
206  writelog(string(bb->first)+" ");
207  }
208  writelog("\n");
209  r_drawline();
210  } else if (m_domain->nPoints() > 1) {
211  writelog("no new points needed in "+m_domain->id()+"\n");
212  }
213 }
214 
215 int Refiner::getNewGrid(int n, const doublereal* z,
216  int nn, doublereal* zn)
217 {
218  int nnew = static_cast<int>(m_loc.size());
219  if (nnew + n > nn) {
220  throw CanteraError("Refine::getNewGrid", "array size too small.");
221  }
222 
223  if (m_loc.empty()) {
224  copy(z, z + n, zn);
225  return 0;
226  }
227 
228  int jn = 0;
229  for (int j = 0; j < n - 1; j++) {
230  zn[jn] = z[j];
231  jn++;
232  if (m_loc.count(j)) {
233  zn[jn] = 0.5*(z[j] + z[j+1]);
234  jn++;
235  }
236  }
237  zn[jn] = z[n-1];
238  return 0;
239 }
240 }
std::string int2str(const int n, const std::string &fmt)
Convert an int to a string using a format converter.
Definition: stringUtils.cpp:40
size_t nPoints() const
Number of grid points in this domain.
Definition: Domain1D.h:186
virtual std::string componentName(size_t n) const
Name of the nth component. May be overloaded.
Definition: Domain1D.h:208
doublereal m_gridmin
minimum grid spacing [m]
Definition: refine.h:97
size_t nComponents() const
Number of components at each grid point.
Definition: Domain1D.h:164
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
Definition: ct_defs.h:165
void writelog(const std::string &msg)
Write a message to the screen.
Definition: global.cpp:43