Cantera  2.0
refine.cpp
1 #include <map>
2 #include <algorithm>
4 
5 #include "cantera/oneD/refine.h"
6 
7 using namespace std;
8 
9 namespace Cantera
10 {
11 
12 template<class M>
13 bool has_key(const M& m, size_t j)
14 {
15  if (m.find(j) != m.end()) {
16  return true;
17  }
18  return false;
19 }
20 
21 static void r_drawline()
22 {
23  string s(78,'#');
24  s += '\n';
25  writelog(s.c_str());
26 }
27 
28 /**
29  * Return the square root of machine precision.
30  */
31 static doublereal eps()
32 {
33  doublereal e = 1.0;
34  while (1.0 + e != 1.0) {
35  e *= 0.5;
36  }
37  return sqrt(e);
38 }
39 
40 
41 Refiner::Refiner(Domain1D& domain) :
42  m_ratio(10.0), m_slope(0.8), m_curve(0.8), m_prune(-0.001),
43  m_min_range(0.01), m_domain(&domain), m_npmax(3000),
44  m_gridmin(5e-6)
45 {
46  m_nv = m_domain->nComponents();
47  m_active.resize(m_nv, true);
48  m_thresh = eps();
49 }
50 
51 
52 int Refiner::analyze(size_t n, const doublereal* z,
53  const doublereal* x)
54 {
55 
56  if (n >= m_npmax) {
57  writelog("max number of grid points reached ("+int2str(m_npmax)+".\n");
58  return -2;
59  }
60 
61  if (m_domain->nPoints() <= 1) {
62  //writelog("can't refine a domain with 1 point: "+m_domain->id()+"\n");
63  return 0;
64  }
65 
66  m_loc.clear();
67  m_c.clear();
68  m_keep.clear();
69 
70  m_keep[0] = 1;
71  m_keep[n-1] = 1;
72 
73  m_nv = m_domain->nComponents();
74 
75  // check consistency
76  if (n != m_domain->nPoints()) {
77  throw CanteraError("analyze","inconsistent");
78  }
79 
80 
81  /**
82  * find locations where cell size ratio is too large.
83  */
84  size_t j;
85  string name;
86  doublereal vmin, vmax, smin, smax, aa, ss;
87  doublereal dmax, r;
88  vector_fp v(n), s(n-1);
89 
90  vector_fp dz(n-1);
91  for (j = 0; j < n-1; j++) {
92  dz[j] = z[j+1] - z[j];
93  }
94 
95  for (size_t i = 0; i < m_nv; i++) {
96  if (m_active[i]) {
97  name = m_domain->componentName(i);
98  //writelog("refine: examining "+name+"\n");
99  // get component i at all points
100  for (j = 0; j < n; j++) {
101  v[j] = value(x, i, j);
102  }
103 
104  // slope of component i
105  for (j = 0; j < n-1; j++)
106  s[j] = (value(x, i, j+1) - value(x, i, j))/
107  (z[j+1] - z[j]);
108 
109  // find the range of values and slopes
110 
111  vmin = *min_element(v.begin(), v.end());
112  vmax = *max_element(v.begin(), v.end());
113  smin = *min_element(s.begin(), s.end());
114  smax = *max_element(s.begin(), s.end());
115 
116  // max absolute values of v and s
117  aa = std::max(fabs(vmax), fabs(vmin));
118  ss = std::max(fabs(smax), fabs(smin));
119 
120  // refine based on component i only if the range of v is
121  // greater than a fraction 'min_range' of max |v|. This
122  // eliminates components that consist of small fluctuations
123  // on a constant background.
124 
125  if ((vmax - vmin) > m_min_range*aa) {
126 
127  // maximum allowable difference in value between
128  // adjacent points.
129 
130  dmax = m_slope*(vmax - vmin) + m_thresh;
131  for (j = 0; j < n-1; j++) {
132  r = fabs(v[j+1] - v[j])/dmax;
133  if (r > 1.0 && dz[j] >= 2 * m_gridmin) {
134  m_loc[j] = 1;
135  m_c[name] = 1;
136  //if (int(m_loc.size()) + n > m_npmax) goto done;
137  }
138  if (r >= m_prune) {
139  m_keep[j] = 1;
140  m_keep[j+1] = 1;
141  } else {
142  //writelog(string("r = ")+fp2str(r)+"\n");
143  if (m_keep[j] == 0) {
144  //if (m_keep[j-1] > -1 && m_keep[j+1] > -1)
145  m_keep[j] = -1;
146  }
147  //if (m_keep[j+1] == 0) m_keep[j+1] = -1;
148  }
149  }
150  }
151 
152 
153  // refine based on the slope of component i only if the
154  // range of s is greater than a fraction 'min_range' of max
155  // |s|. This eliminates components that consist of small
156  // fluctuations on a constant slope background.
157 
158  if ((smax - smin) > m_min_range*ss) {
159 
160  // maximum allowable difference in slope between
161  // adjacent points.
162  dmax = m_curve*(smax - smin); // + 0.5*m_curve*(smax + smin);
163  for (j = 0; j < n-2; j++) {
164  r = fabs(s[j+1] - s[j]) / (dmax + m_thresh/dz[j]);
165  if (r > 1.0 && dz[j] >= 2 * m_gridmin &&
166  dz[j+1] >= 2 * m_gridmin) {
167  m_c[name] = 1;
168  m_loc[j] = 1;
169  m_loc[j+1] = 1;
170  //if (int(m_loc.size()) + n > m_npmax) goto done;
171  }
172  if (r >= m_prune) {
173  m_keep[j+1] = 1;
174  } else {
175  //writelog(string("r slope = ")+fp2str(r)+"\n");
176  if (m_keep[j+1] == 0) {
177  //if (m_keep[j] > -1 && m_keep[j+2] > -1)
178  m_keep[j+1] = -1;
179  }
180  }
181  }
182  }
183 
184  }
185  }
186 
187  for (j = 1; j < n-1; j++) {
188  if (dz[j] > m_ratio*dz[j-1]) {
189  m_loc[j] = 1;
190  m_c["point "+int2str(j)] = 1;
191  }
192  if (dz[j] < dz[j-1]/m_ratio) {
193  m_loc[j-1] = 1;
194  m_c["point "+int2str(j-1)] = 1;
195  }
196  //if (m_loc.size() + n > m_npmax) goto done;
197  }
198 
199  //done:
200  //m_did_analysis = true;
201  return int(m_loc.size());
202 }
203 
204 double Refiner::value(const double* x, size_t i, size_t j)
205 {
206  return x[m_domain->index(i,j)];
207 }
208 
209 void Refiner::show()
210 {
211  int nnew = static_cast<int>(m_loc.size());
212  if (nnew > 0) {
213  r_drawline();
214  writelog(string("Refining grid in ") +
215  m_domain->id()+".\n"
216  +" New points inserted after grid points ");
217  map<size_t, int>::const_iterator b = m_loc.begin();
218  for (; b != m_loc.end(); ++b) {
219  writelog(int2str(b->first)+" ");
220  }
221  writelog("\n");
222  writelog(" to resolve ");
223  map<string, int>::const_iterator bb = m_c.begin();
224  for (; bb != m_c.end(); ++bb) {
225  writelog(string(bb->first)+" ");
226  }
227  writelog("\n");
228  } else if (m_domain->nPoints() > 1) {
229  writelog("no new points needed in "+m_domain->id()+"\n");
230  //writelog("curve = "+fp2str(m_curve)+"\n");
231  //writelog("slope = "+fp2str(m_slope)+"\n");
232  //writelog("prune = "+fp2str(m_prune)+"\n");
233  }
234 }
235 
236 
237 int Refiner::getNewGrid(int n, const doublereal* z,
238  int nn, doublereal* zn)
239 {
240  int j;
241  int nnew = static_cast<int>(m_loc.size());
242  if (nnew + n > nn) {
243  throw CanteraError("Refine::getNewGrid",
244  "array size too small.");
245  return -1;
246  }
247 
248  int jn = 0;
249  if (m_loc.empty()) {
250  copy(z, z + n, zn);
251  return 0;
252  }
253 
254  for (j = 0; j < n - 1; j++) {
255  zn[jn] = z[j];
256  jn++;
257  if (has_key(m_loc, j)) {
258  zn[jn] = 0.5*(z[j] + z[j+1]);
259  jn++;
260  }
261  }
262  zn[jn] = z[n-1];
263  return 0;
264 }
265 }