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