Cantera  3.1.0
Loading...
Searching...
No Matches
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_domain(&domain)
16{
17 m_nv = m_domain->nComponents();
18 m_active.resize(m_nv, true);
19}
20
21void Refiner::setCriteria(double ratio, double slope, double curve, double prune)
22{
23 if (ratio < 2.0) {
24 throw CanteraError("Refiner::setCriteria",
25 "'ratio' must be greater than 2.0 ({} was specified).", ratio);
26 } else if (slope < 0.0 || slope > 1.0) {
27 throw CanteraError("Refiner::setCriteria",
28 "'slope' must be between 0.0 and 1.0 ({} was specified).", slope);
29 } else if (curve < 0.0 || curve > 1.0) {
30 throw CanteraError("Refiner::setCriteria",
31 "'curve' must be between 0.0 and 1.0 ({} was specified).", curve);
32 } else if (prune > curve || prune > slope) {
33 throw CanteraError("Refiner::setCriteria",
34 "'prune' must be less than 'curve' and 'slope' ({} was specified).",
35 prune);
36 }
37 m_ratio = ratio;
38 m_slope = slope;
39 m_curve = curve;
40 m_prune = prune;
41}
42
43int Refiner::analyze(size_t n, const double* z, const double* x)
44{
45 if (n >= m_npmax) {
46 throw CanteraError("Refiner::analyze", "max number of grid points reached ({}).", m_npmax);
47 }
48
49 if (m_domain->nPoints() <= 1) {
50 return 0;
51 }
52
53 // check consistency
54 if (n != m_domain->nPoints()) {
55 throw CanteraError("Refiner::analyze", "number of grid points provided does not match domain size.");
56 }
57
58 // Reset the state of the refiner
59 m_insertPts.clear();
60 m_componentNames.clear();
61 m_keep.clear();
62
63 // Keep the first and last grid points
64 m_keep[0] = KEEP;
65 m_keep[n-1] = KEEP;
66
67 m_nv = m_domain->nComponents();
68
69 // find locations where cell size ratio is too large.
70 vector<double> val(n);
71 vector<double> slope(n-1);
72
73 vector<double> dz(n-1); // Store the right-looking grid spacings
74 for (size_t j = 0; j < n-1; j++) {
75 dz[j] = z[j+1] - z[j];
76 }
77
78 for (size_t i = 0; i < m_nv; i++) {
79 if (m_active[i]) {
80 string name = m_domain->componentName(i);
81 // get component i at all points
82 for (size_t j = 0; j < n; j++) {
83 val[j] = value(x, i, j);
84 }
85
86 // slope of component i (using forward difference)
87 for (size_t j = 0; j < n-1; j++) {
88 slope[j] = (val[j+1] - val[j]) / dz[j];
89 }
90
91 // find the range of values and slopes of component i over the domain
92 double valMin = *min_element(val.begin(), val.end());
93 double valMax = *max_element(val.begin(), val.end());
94 double slopeMin = *min_element(slope.begin(), slope.end());
95 double slopeMax = *max_element(slope.begin(), slope.end());
96
97 // max absolute values of val and slope
98 double valMagnitude = std::max(fabs(valMax), fabs(valMin));
99 double slopeMagnitude = std::max(fabs(slopeMax), fabs(slopeMin));
100
101 // refine based on component i only if the range of val is greater than a
102 // fraction 'min_range' of max |val|. This eliminates components that
103 // consist of small fluctuations around a constant value.
104 if (valMax - valMin > m_min_range*valMagnitude) {
105 // maximum allowable difference in value between adjacent points. Based
106 // on the global min and max values of the component over the domain.
107 double max_change = m_slope*(valMax - valMin);
108 for (size_t j = 0; j < n-1; j++) {
109 double ratio = fabs(val[j+1] - val[j]) / (max_change + m_thresh);
110 if (ratio > 1.0 && dz[j] >= 2 * m_gridmin) {
111 m_insertPts.insert(j);
112 m_componentNames.insert(name);
113 }
114 if (ratio >= m_prune) {
115 m_keep[j] = KEEP;
116 m_keep[j+1] = KEEP;
117 } else if (m_keep[j] == UNSET) {
118 m_keep[j] = REMOVE;
119 }
120 }
121 }
122
123 // refine based on the slope of component i only if the range of s is
124 // greater than a fraction 'min_range' of max|s|. This eliminates
125 // components that consist of small fluctuations on a constant slope
126 // background.
127 if (slopeMax - slopeMin > m_min_range*slopeMagnitude) {
128 // maximum allowable difference in slope between adjacent points.
129 double max_change = m_curve*(slopeMax - slopeMin);
130 for (size_t j = 0; j < n-2; j++) {
131 // Using the solution component absolute tolerance (m_thresh),
132 // an absolute tolerance for the change in slope can be estimated
133 // for an interval dz as m_thresh/dz.
134 double ratio = fabs(slope[j+1] - slope[j]) / (max_change + m_thresh/dz[j]);
135 if (ratio > 1.0 && dz[j] >= 2*m_gridmin && dz[j+1] >= 2*m_gridmin) {
136 m_componentNames.insert(name);
137 m_insertPts.insert(j);
138 m_insertPts.insert(j+1);
139 }
140 if (ratio >= m_prune) {
141 m_keep[j+1] = KEEP;
142 } else if (m_keep[j+1] == UNSET) {
143 m_keep[j+1] = REMOVE;
144 }
145 }
146 }
147 }
148 }
149
150 // Refine based on properties of the grid itself
151 for (size_t j = 1; j < n-1; j++) {
152 // Add a new point if the ratio with left interval is too large.
153 // Extra points around the interval set under consideration are kept.
154 if (dz[j] > m_ratio*dz[j-1]) {
155 m_insertPts.insert(j);
156 m_componentNames.insert(fmt::format("point {}", j));
157 m_keep[j-1] = KEEP;
158 m_keep[j] = KEEP;
159 m_keep[j+1] = KEEP;
160 m_keep[j+2] = KEEP;
161 }
162
163 // Add a point if the ratio with right interval is too large
164 if (dz[j-1] > m_ratio*dz[j]) {
165 m_insertPts.insert(j-1);
166 m_componentNames.insert(fmt::format("point {}", j-1));
167 m_keep[j-2] = KEEP;
168 m_keep[j-1] = KEEP;
169 m_keep[j] = KEEP;
170 m_keep[j+1] = KEEP;
171 }
172
173 // Keep the point if removing would make the ratio with the left interval too
174 // large.
175 if (j > 1 && z[j+1]-z[j-1] > m_ratio * dz[j-2]) {
176 m_keep[j] = KEEP;
177 }
178
179 // Keep the point if removing would make the ratio with the right interval too
180 // large.
181 if (j < n-2 && z[j+1]-z[j-1] > m_ratio * dz[j+1]) {
182 m_keep[j] = KEEP;
183 }
184
185 Flow1D* fflame = dynamic_cast<Flow1D*>(m_domain);
186 // Keep the point where the temperature is fixed
187 if (fflame && fflame->isFree() && z[j] == fflame->m_zfixed) {
188 m_keep[j] = KEEP;
189 }
190
191 // Keep the point if it is a control point used for two-point flame control
192 if (fflame && fflame->twoPointControlEnabled() &&
193 (z[j] == fflame->leftControlPointCoordinate() ||
194 z[j] == fflame->rightControlPointCoordinate()))
195 {
196 m_keep[j] = KEEP;
197 }
198 }
199
200 // Don't allow pruning to remove multiple adjacent grid points
201 // in a single pass.
202 for (size_t j = 2; j < n-1; j++) {
203 if (m_keep[j] == REMOVE && m_keep[j-1] == REMOVE) {
204 m_keep[j] = KEEP;
205 }
206 }
207
208 return int(m_insertPts.size());
209}
210
211double Refiner::value(const double* x, size_t n, size_t j)
212{
213 return x[m_domain->index(n,j)];
214}
215
216void Refiner::show()
217{
218 if (!m_insertPts.empty()) {
219 writeline('#', 78);
220 writelog(string("Refining grid in ") +
221 m_domain->id()+".\n"
222 +" New points inserted after grid points ");
223 for (const auto& loc : m_insertPts) {
224 writelog("{} ", loc);
225 }
226 writelog("\n");
227 writelog(" to resolve ");
228 for (const auto& c : m_componentNames) {
229 writelog(c + " ");
230 }
231 writelog("\n");
232 writeline('#', 78);
233 } else if (m_domain->nPoints() > 1) {
234 writelog("no new points needed in "+m_domain->id()+"\n");
235 }
236}
237
238int Refiner::getNewGrid(int n, const double* z, int nn, double* zn)
239{
241 "Refiner::getNewGrid",
242 "Deprecated in Cantera 3.1; unused function that will be removed.");
243
244 int nnew = static_cast<int>(m_insertPts.size());
245 if (nnew + n > nn) {
246 throw CanteraError("Refine::getNewGrid", "array size too small.");
247 }
248
249 if (m_insertPts.empty()) {
250 copy(z, z + n, zn);
251 return 0;
252 }
253
254 int jn = 0;
255 for (int j = 0; j < n - 1; j++) {
256 zn[jn] = z[j];
257 jn++;
258 if (m_insertPts.count(j)) {
259 zn[jn] = 0.5*(z[j] + z[j+1]);
260 jn++;
261 }
262 }
263 zn[jn] = z[n-1];
264 return 0;
265}
266}
Base class for exceptions thrown by Cantera classes.
This class represents 1D flow domains that satisfy the one-dimensional similarity solution for chemic...
Definition Flow1D.h:46
bool twoPointControlEnabled() const
Returns the status of the two-point control.
Definition Flow1D.h:328
double m_zfixed
Location of the point where temperature is fixed.
Definition Flow1D.h:1002
double leftControlPointCoordinate() const
Returns the z-coordinate of the left control point.
Definition Flow1D.cpp:1162
bool isFree() const
Retrieve flag indicating whether flow is freely propagating.
Definition Flow1D.h:360
double rightControlPointCoordinate() const
Returns the z-coordinate of the right control point.
Definition Flow1D.cpp:1217
This file contains definitions for utility functions and text for modules, inputfiles and logging,...
void writelog(const string &fmt, const Args &... args)
Write a formatted message to the screen.
Definition global.h:171
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
void warn_deprecated(const string &source, const AnyBase &node, const string &message)
A deprecation warning for syntax in an input file.
Definition AnyMap.cpp:1997