cantera/src/oneD/refine.cpp
Ray Speth 2528df0f75 Reorganized source tree structure
These changes make it unnecessary to copy header files around during
the build process, which tends to confuse IDEs and debuggers. The
headers which comprise Cantera's external C++ interface are now in
the 'include' directory.

All of the samples and demos are now in the 'samples' subdirectory.
2012-02-12 02:27:14 +00:00

261 lines
7.1 KiB
C++

#include <map>
#include <algorithm>
#include "Domain1D.h"
#include "refine.h"
using namespace std;
namespace Cantera
{
template<class M>
bool has_key(const M& m, size_t j)
{
if (m.find(j) != m.end()) {
return true;
}
return false;
}
static void r_drawline()
{
string s(78,'#');
s += '\n';
writelog(s.c_str());
}
/**
* Return the square root of machine precision.
*/
static doublereal eps()
{
doublereal e = 1.0;
while (1.0 + e != 1.0) {
e *= 0.5;
}
return sqrt(e);
}
Refiner::Refiner(Domain1D& domain) :
m_ratio(10.0), m_slope(0.8), m_curve(0.8), m_prune(-0.001),
m_min_range(0.01), m_domain(&domain), m_npmax(3000)
{
m_nv = m_domain->nComponents();
m_active.resize(m_nv, true);
m_thresh = eps();
}
int Refiner::analyze(size_t n, const doublereal* z,
const doublereal* x)
{
if (n >= m_npmax) {
writelog("max number of grid points reached ("+int2str(int(m_npmax))+".\n");
return -2;
}
if (m_domain->nPoints() <= 1) {
//writelog("can't refine a domain with 1 point: "+m_domain->id()+"\n");
return 0;
}
m_loc.clear();
m_c.clear();
m_keep.clear();
m_keep[0] = 1;
m_keep[n-1] = 1;
m_nv = m_domain->nComponents();
// check consistency
if (n != m_domain->nPoints()) {
throw CanteraError("analyze","inconsistent");
}
/**
* find locations where cell size ratio is too large.
*/
size_t j;
vector_fp dz(n-1, 0.0);
string name;
doublereal vmin, vmax, smin, smax, aa, ss;
doublereal dmax, r;
vector_fp v(n), s(n-1);
for (size_t i = 0; i < m_nv; i++) {
if (m_active[i]) {
name = m_domain->componentName(i);
//writelog("refine: examining "+name+"\n");
// get component i at all points
for (j = 0; j < n; j++) {
v[j] = value(x, i, j);
}
// slope of component i
for (j = 0; j < n-1; j++)
s[j] = (value(x, i, j+1) - value(x, i, j))/
(z[j+1] - z[j]);
// find the range of values and slopes
vmin = *min_element(v.begin(), v.end());
vmax = *max_element(v.begin(), v.end());
smin = *min_element(s.begin(), s.end());
smax = *max_element(s.begin(), s.end());
// max absolute values of v and s
aa = fmaxx(fabs(vmax), fabs(vmin));
ss = fmaxx(fabs(smax), fabs(smin));
// refine based on component i only if the range of v is
// greater than a fraction 'min_range' of max |v|. This
// eliminates components that consist of small fluctuations
// on a constant background.
if ((vmax - vmin) > m_min_range*aa) {
// maximum allowable difference in value between
// adjacent points.
dmax = m_slope*(vmax - vmin) + m_thresh;
for (j = 0; j < n-1; j++) {
r = fabs(v[j+1] - v[j])/dmax;
if (r > 1.0) {
m_loc[j] = 1;
m_c[name] = 1;
//if (int(m_loc.size()) + n > m_npmax) goto done;
}
if (r >= m_prune) {
m_keep[j] = 1;
m_keep[j+1] = 1;
} else {
//writelog(string("r = ")+fp2str(r)+"\n");
if (m_keep[j] == 0) {
//if (m_keep[j-1] > -1 && m_keep[j+1] > -1)
m_keep[j] = -1;
}
//if (m_keep[j+1] == 0) m_keep[j+1] = -1;
}
}
}
// refine based on the slope of component i only if the
// range of s is greater than a fraction 'min_range' of max
// |s|. This eliminates components that consist of small
// fluctuations on a constant slope background.
if ((smax - smin) > m_min_range*ss) {
// maximum allowable difference in slope between
// adjacent points.
dmax = m_curve*(smax - smin); // + 0.5*m_curve*(smax + smin);
for (j = 0; j < n-2; j++) {
r = fabs(s[j+1] - s[j]) / (dmax + m_thresh/dz[j]);
if (r > 1.0) {
m_c[name] = 1;
m_loc[j] = 1;
m_loc[j+1] = 1;
//if (int(m_loc.size()) + n > m_npmax) goto done;
}
if (r >= m_prune) {
m_keep[j+1] = 1;
} else {
//writelog(string("r slope = ")+fp2str(r)+"\n");
if (m_keep[j+1] == 0) {
//if (m_keep[j] > -1 && m_keep[j+2] > -1)
m_keep[j+1] = -1;
}
}
}
}
}
}
dz[0] = z[1] - z[0];
for (j = 1; j < n-1; j++) {
dz[j] = z[j+1] - z[j];
if (dz[j] > m_ratio*dz[j-1]) {
m_loc[j] = 1;
m_c["point "+int2str(int(j))] = 1;
}
if (dz[j] < dz[j-1]/m_ratio) {
m_loc[j-1] = 1;
m_c["point "+int2str(int(j)-1)] = 1;
}
//if (m_loc.size() + n > m_npmax) goto done;
}
//done:
//m_did_analysis = true;
return int(m_loc.size());
}
double Refiner::value(const double* x, size_t i, size_t j)
{
return x[m_domain->index(i,j)];
}
void Refiner::show()
{
int nnew = static_cast<int>(m_loc.size());
if (nnew > 0) {
r_drawline();
writelog(string("Refining grid in ") +
m_domain->id()+".\n"
+" New points inserted after grid points ");
map<size_t, int>::const_iterator b = m_loc.begin();
for (; b != m_loc.end(); ++b) {
writelog(int2str(int(b->first))+" ");
}
writelog("\n");
writelog(" to resolve ");
map<string, int>::const_iterator bb = m_c.begin();
for (; bb != m_c.end(); ++bb) {
writelog(string(bb->first)+" ");
}
writelog("\n");
} else if (m_domain->nPoints() > 1) {
writelog("no new points needed in "+m_domain->id()+"\n");
//writelog("curve = "+fp2str(m_curve)+"\n");
//writelog("slope = "+fp2str(m_slope)+"\n");
//writelog("prune = "+fp2str(m_prune)+"\n");
}
}
int Refiner::getNewGrid(int n, const doublereal* z,
int nn, doublereal* zn)
{
int j;
int nnew = static_cast<int>(m_loc.size());
if (nnew + n > nn) {
throw CanteraError("Refine::getNewGrid",
"array size too small.");
return -1;
}
int jn = 0;
if (m_loc.empty()) {
copy(z, z + n, zn);
return 0;
}
for (j = 0; j < n - 1; j++) {
zn[jn] = z[j];
jn++;
if (has_key(m_loc, j)) {
zn[jn] = 0.5*(z[j] + z[j+1]);
jn++;
}
}
zn[jn] = z[n-1];
return 0;
}
}