//----------------------------------------------------------------------------- // Examine the values specified by the indices. If any of the values // are identical, then toss out the higher index. bool MgFeatureNumericFunctions::FixIndicesByValue(const std::vector<double>& data, std::vector<int>& indices) { if (indices.size() <= 1) { return false; } // We will create a new vector of indices that is possibly adjusted, // then replace the original vector with the new. Since these vectors // have typically less than 10 entries, we won't deal with making the // adjustments in place. std::vector<int> newIndices; newIndices.push_back(indices[0]); for (unsigned int i = 1; i < indices.size(); ++i) { if ( ! doubles_equal(data[indices[i]], data[indices[i - 1]]) ) newIndices.push_back(indices[i]); } bool changed = (newIndices.size() != indices.size()); indices.clear(); indices = newIndices; return changed; }
void MetamorphismCROCUS::metamorphism() { /* Empirical laws for dry snow metamorphism. From: Vionnet et al, 2012: table 1. TODO: Tgrad > 15 is ommitted here (no depth hoar formation) */ const double dt = (double)_dm.getDt() / (double) sec_in_day; // time in days Grid& grid = _mstate.getGrid(); int Np = grid.size(); if (Np < 2) return; // can't compute gradients on single snow layer double Tgrad; for (int i = 0; i < Np; i++) { if (i == 0) { // SNOW BOTTOM, one-sided up Tgrad = std::abs((grid[1].T-grid[0].T)/(0.5*grid[0].dz+0.5*grid[1].dz)); } else if (i == Np-1) { // SNOW TOP, one-sided down Tgrad = std::abs((grid[Np-1].T-grid[Np-2].T)/(0.5*grid[Np-1].dz+0.5*grid[Np-2].dz)); } else { // central difference Tgrad = std::abs(grid[i+1].T-grid[i-1].T)/(0.5*grid[i+1].dz+grid[i].dz+grid[i-1].dz); } if (doubles_equal(grid[i].dnd, 0.0)) { // Non-dendritic snow if (Tgrad <= 5.) { grid[i].sph = grid[i].sph + dt * 1e9 * exp(-6000./grid[i].T); } else { grid[i].sph = grid[i].sph + dt * -2.e8 * exp(-6000./grid[i].T) * pow(Tgrad,0.4); } } else { // Dendritic snow if (Tgrad <= 5.) { grid[i].dnd = grid[i].dnd + dt * -2.e8 * exp(-6000./grid[i].T); grid[i].sph = grid[i].sph + dt * 1e9 * exp(-6000./grid[i].T); } else { grid[i].dnd = grid[i].dnd + dt * -2.e8 * exp(-6000./grid[i].T) * pow(Tgrad,0.4); grid[i].sph = grid[i].sph + dt * -2.e8 * exp(-6000./grid[i].T) * pow(Tgrad,0.4); } } // consistency checks grid[i].dnd = std::max(std::min(1.0, grid[i].dnd), 0.0); grid[i].sph = std::max(std::min(1.0, grid[i].sph), 0.0); } }
bool MockNamedValue::equals(const MockNamedValue& p) const { if (type_ != p.type_) return false; if (type_ == "int") return value_.intValue_ == p.value_.intValue_; else if (type_ == "char*") return SimpleString(value_.stringValue_) == SimpleString(p.value_.stringValue_); else if (type_ == "void*") return value_.pointerValue_ == p.value_.pointerValue_; else if (type_ == "double") return (doubles_equal(value_.doubleValue_, p.value_.doubleValue_, 0.005)); if (comparator_) return comparator_->isEqual(value_.objectPointerValue_, p.value_.objectPointerValue_); return false; }
TEST(UtestShell, compareDoubles) { double zero = 0.0; double not_a_number = zero / zero; CHECK(doubles_equal(1.0, 1.001, 0.01)); CHECK(!doubles_equal(not_a_number, 1.001, 0.01)); CHECK(!doubles_equal(1.0, not_a_number, 0.01)); CHECK(!doubles_equal(1.0, 1.001, not_a_number)); CHECK(!doubles_equal(1.0, 1.1, 0.05)); double a = 1.2345678; CHECK(doubles_equal(a, a, 0.000000001)); }
double ConfigParser::getDouble(const char* name, bool required, double minval, double maxval, double defval){ const char * rtnnam = "ConfigParser::getDouble()"; double tmp; if (required){ double missval = -9999.; tmp = iniparser_getdouble(_dict, name, missval); if (doubles_equal(tmp, missval)){ logger << "ERROR: " << rtnnam << " required value not found: " << name << std::endl; std::abort(); } } else { tmp = iniparser_getdouble(_dict, name, defval); } if (tmp < minval || tmp > maxval) { logger << "ERROR: " << rtnnam << " value out of bounds " << name << std::endl; logger << "ERROR: " << rtnnam << " val = " << tmp << ", minval = " << minval << ", maxval = " << maxval << std::endl; std::abort(); } logger << "INFO: " << name << " = " << tmp << std::endl; return tmp; }
void UtestShell::assertDoublesEqual(double expected, double actual, double threshold, const char* fileName, int lineNumber, const TestTerminator& testTerminator) { getTestResult()->countCheck(); if (!doubles_equal(expected, actual, threshold)) failWith(DoublesEqualFailure(this, fileName, lineNumber, expected, actual, threshold), testTerminator); }
bool MockNamedValue::equals(const MockNamedValue& p) const { if((type_ == "long int") && (p.type_ == "int")) return value_.longIntValue_ == p.value_.intValue_; else if((type_ == "int") && (p.type_ == "long int")) return value_.intValue_ == p.value_.longIntValue_; else if((type_ == "unsigned int") && (p.type_ == "int")) return (long)value_.unsignedIntValue_ == (long)p.value_.intValue_; else if((type_ == "int") && (p.type_ == "unsigned int")) return (long)value_.intValue_ == (long)p.value_.unsignedIntValue_; else if((type_ == "unsigned long int") && (p.type_ == "int")) return value_.unsignedLongIntValue_ == (unsigned long)p.value_.intValue_; else if((type_ == "int") && (p.type_ == "unsigned long int")) return (unsigned long)value_.intValue_ == p.value_.unsignedLongIntValue_; else if((type_ == "unsigned int") && (p.type_ == "long int")) return (long int)value_.unsignedIntValue_ == p.value_.longIntValue_; else if((type_ == "long int") && (p.type_ == "unsigned int")) return value_.longIntValue_ == (long int)p.value_.unsignedIntValue_; else if((type_ == "unsigned int") && (p.type_ == "unsigned long int")) return value_.unsignedIntValue_ == p.value_.unsignedLongIntValue_; else if((type_ == "unsigned long int") && (p.type_ == "unsigned int")) return value_.unsignedLongIntValue_ == p.value_.unsignedIntValue_; else if((type_ == "long int") && (p.type_ == "unsigned long int")) return (value_.longIntValue_ >= 0) && (value_.longIntValue_ == (long) p.value_.unsignedLongIntValue_); else if((type_ == "unsigned long int") && (p.type_ == "long int")) return (p.value_.longIntValue_ >= 0) && ((long)value_.unsignedLongIntValue_ == p.value_.longIntValue_); if (type_ != p.type_) return false; if (type_ == "bool") return value_.boolValue_ == p.value_.boolValue_; else if (type_ == "int") return value_.intValue_ == p.value_.intValue_; else if (type_ == "unsigned int") return value_.unsignedIntValue_ == p.value_.unsignedIntValue_; else if (type_ == "long int") return value_.longIntValue_ == p.value_.longIntValue_; else if (type_ == "unsigned long int") return value_.unsignedLongIntValue_ == p.value_.unsignedLongIntValue_; else if (type_ == "const char*") return SimpleString(value_.stringValue_) == SimpleString(p.value_.stringValue_); else if (type_ == "void*") return value_.pointerValue_ == p.value_.pointerValue_; else if (type_ == "const void*") return value_.constPointerValue_ == p.value_.constPointerValue_; else if (type_ == "void (*)()") return value_.functionPointerValue_ == p.value_.functionPointerValue_; else if (type_ == "double") return (doubles_equal(value_.doubleValue_, p.value_.doubleValue_, 0.005)); else if (type_ == "const unsigned char*") { if (size_ != p.size_) { return false; } return SimpleString::MemCmp(value_.memoryBufferValue_, p.value_.memoryBufferValue_, size_) == 0; } if (comparator_) return comparator_->isEqual(value_.objectPointerValue_, p.value_.objectPointerValue_); return false; }
//------------------------------------------------------------------------- // Jenks' Optimization Method // //------------------------------------------------------------------------- void MgFeatureNumericFunctions::GetJenksCategories( VECTOR &inputData, int numPartsRequested, double dataMin, double dataMax, VECTOR &distValues ) { // numPartsRequested // 2 - 10; 5 is good int i = 0; // index for numObservations (may be very large) int j = 0; // index for numPartsRequested (about 4-8) int k = 0; // Sort the data values in ascending order std::sort(inputData.begin(), inputData.end()); int numObservations = (int)inputData.size(); // may be very large // Possible improvement: Rework the code to use normal 0 based arrays. // Actually it doesn't matter much since we have to create two // matrices that themselves use more memory than the local copy // of inputData. // // In order to ease the use of original FORTRAN and the later BASIC // code, I will use 1 origin arrays and copy the inputData into // a local array; // I'll dimension the arrays one larger than necessary and use the // index values from the original code. // // The algorithm must calculate with floating point values. // If more optimization is attempted in the future, be aware of // problems with calculations using mixed numeric types. std::vector<double> data; data.push_back(0); // dummy value at index 0 std::copy(inputData.begin(), inputData.end(), std::back_inserter(data)); // copy from parameter inputData so that data index starts from 1 // Note that the Matrix constructors initialize all values to 0. // mat1 contains integer values used for indices into data // mat2 contains floating point values of data and bigNum MgMatrix<int> mat1(numObservations + 1, numPartsRequested + 1); MgMatrix<double> mat2(numObservations + 1, numPartsRequested + 1); // const double bigNum = 1e+14; // from original BASIC code; // const double bigNum = std::numeric_limits<double>::max(); const double bigNum = DBL_MAX; // compiler's float.h for (i = 1; i <= numPartsRequested; ++i) { mat1.Set(1, i, 1); for (j = 2; j <= numObservations; ++j) { mat2.Set(j, i, bigNum); } } std::vector<int> classBounds; classBounds.push_back(-2); // dummy value for (i = 1; i <= numPartsRequested; ++i) { classBounds.push_back(-1); } for (int L = 2; L <= numObservations; ++L) { double s1 = 0; double s2 = 0; double v = 0; int w = 0; for (int m = 1; m <= L; ++m) { int i3 = L - m + 1; double val = data[i3]; s2 += (double(val) * double(val)); // if datatype of val is ever allowed to be same as template // parameter T, make sure multiplication is done in double. s1 += val; ++w; v = s2 - ((s1 * s1) / w); int i4 = i3 - 1; if (i4 > 0) { for (j = 2; j <= numPartsRequested; ++j) { double tempnum = v + mat2.Get(i4, j - 1); if (double(mat2.Get(L, j)) >= tempnum) { mat1.Set(L, j, i3); mat2.Set(L, j, tempnum); } } } } mat1.Set(L, 1, 1); mat2.Set(L, 1, v); } k = numObservations; for (j = numPartsRequested; j >= 1; --j) { if (k >= 0 && k <= numObservations) { classBounds[j] = mat1.Get(k, j); k = mat1.Get(k, j) - 1; } } std::vector<int> indices; indices.push_back(0); for (i = 2; i <= numPartsRequested; ++i) { int index = classBounds[i] - 1; if (index > indices.back()) { indices.push_back(index); } } FixGroups(inputData, indices); double val = 0.0; int index = 0; int totIndex = (int)indices.size(); for (int i = 1; i < totIndex; ++i) { index = indices[i] - 1; val = inputData[index]; distValues.push_back(val); } index = numObservations - 1; val = inputData[index]; distValues.push_back(val); int retCnt = (int)distValues.size(); int inCnt = (int)inputData.size(); if (retCnt > 0 && inCnt > 0) { if (!doubles_equal(distValues[0],inputData[0])) { distValues.insert(distValues.begin(), inputData[0]); } } return; }
void CompactionCROCUS::compactionWindDrift(){ /* Compaction due to wind drift */ Grid& grid = _mstate.getGrid(); const int Np = grid.size(); if (Np < 2) return; // no metamorphism static const double rho_min = 50.; // minimum density [kg/m3] static const double rho_max = 350.; // maximum density [kg/m3] static const double tau_ref = (double)48 * 3600; // reference time [s] const double U = _mstate.getMeteo().surfaceWind(); const double dt = (double)_dm.getDt(); // time step [s] double layer_mass; double Frho; double MO; // mobility index double SI; // driftability index double tau; // time characteristic double zi = 0.; // pseudo-depth in m double gamma_drift; double u0, afac; // TUNING for (int i = grid.size()-1; i >= 0; i--) { Frho = 1.25 - 0.0042*(std::max(rho_min, grid[i].dens)-rho_min); if (doubles_equal(grid[i].dnd, 0.0)) { // Non-dendritic snow MO = 0.34 * (-0.583*grid[i].gs - 0.833*grid[i].sph + 0.833) + 0.66*Frho; } else { // dendritic snow MO = 0.34 * (0.75*grid[i].dnd - 0.5*grid[i].sph + 0.5) + 0.66*Frho; } /* LvK: tuning */ // static const double wind_fac = -0.085; // u0 = log((-1.-MO)/-2.868) / -0.085; // u0 = u0 - 2.; // afac = (-1. - MO) / exp(wind_fac * u0 ); // based on exponent factor, determine pre-factor by setting SI = 0 to the same U-value // SI = afac * exp(wind_fac*U) + 1 + MO; /* LvK: end of Tuning */ SI = -2.868 * exp(-0.085*U)+1.+MO; if (SI <= 0.0) break; // first non-mobile layer has been reached SI = std::min(SI, 3.25); zi += grid[i].dz * 0.5 * (3.25 - SI); gamma_drift = std::max(0., SI*exp(-zi/0.1)); tau = tau_ref / gamma_drift; if (doubles_equal(grid[i].dnd, 0.0)) { // Non-dendritic snow grid[i].sph = grid[i].sph + dt * (1-grid[i].sph)/tau; grid[i].gs = grid[i].gs + dt * 5e-4/tau; } else { // dendritic snow grid[i].dnd = grid[i].dnd + dt * grid[i].dnd/(2*tau); grid[i].sph = grid[i].sph + dt * (1-grid[i].sph)/tau; } // consistency checks grid[i].dnd = std::max(std::min(1.0, grid[i].dnd), 0.0); grid[i].sph = std::max(std::min(1.0, grid[i].sph), 0.0); grid[i].gs = std::max(std::min(fs_gs_max, grid[i].gs), 0.0); layer_mass = grid[i].dz * grid[i].dens; // density evolution //logger << "DEBUG dens = " << grid[i].dens << ", U = " << U << ", zi = " << zi << ", drho / 24h = " << 24*3600 * std::max(0.0, rho_max - grid[i].dens)/tau << std::endl; grid[i].dens = grid[i].dens + dt * std::max(0.0, rho_max - grid[i].dens)/tau; grid[i].dz = layer_mass/grid[i].dens; // # mass conservation if (gamma_drift > 100.0) { logger << "warning: large gamma\n"; logger << "i / Np = " << i << " / " << grid.size() << "\n"; logger << "U = " << U << "\n"; logger << "SI = " << SI << "\n"; logger << "MO = " << MO << "\n"; logger << "zi = " << zi << "\n"; //logger << "dens_old = " << dens_old << "\n"; //logger << "dens_new = " << grid[i].dens << "\n"; //logger << "d= " << s_old << "\n"; //logger << "s= " << d_old << "\n"; //logger << "gs= " << gs_old << "\n"; } logger.flush(); zi += grid[i].dz * 0.5 * (3.25 - SI); } }