Sparse Grids Example 3: compare different quadrature rules.
The example considers a 4D function that is well approximated in a total degree polynomial space. In one and two dimensions, the Gauss-Legendre rule with tensor type gives creates an approximation with the largest total degree space per number of points. In higher dimensions (4 in this case), the sparse (level and qptotal) types have an advantage but the sparse grid construction suffers because the rule is non-nested. The nested Clenshaw-Curtis rule generates about the same total degree space per number of points, but unlike the non-nested rule the extra points are not wasted and hence the approximation is better. The Gauss-Patterson rule, which combines the higher exactness with forced nested structure, outperforms all other methods in precision per number of points.
#endif
cout << "\n---------------------------------------------------------------------------------------------------\n";
cout << std::scientific; cout.precision(2);
cout << "Example 3: integrate exp(-x1^2 - x2^2) * cos(x3) * cos(x4)\n"
<< " for x1, x2 in [-5,5]; x3, x4 in [-2,3];\n"
<< " using different rules and total degree polynomial space\n\n";
int dimensions = 4;
double exact = 1.861816427518323e+00 * 1.861816427518323e+00;
grid.setDomainTransform({-5.0, -5.0, -2.0, -2.0}, {5.0, 5.0, 3.0, 3.0});
return grid;
};
void{
auto points = grid.getPoints();
auto weights = grid.getQuadratureWeights();
double integral = 0.0;
for(size_t i=0; i<weights.size(); i++){
double x1 = points[4*i + 0];
double x2 = points[4*i + 1];
double x3 = points[4*i + 2];
double x4 = points[4*i + 3];
integral += weights[i] * std::exp(-x1*x1 - x2*x2) * std::cos(x3) * std::cos(x4);
}
cout << setw(10) << grid.getNumPoints() << setw(10) << std::abs(integral - exact);
};
cout << setw(10) << " " << setw(20) << "Clenshaw-Curtis"
<< setw(20) << "Gauss-Legendre" << setw(20) << "Gauss-Patterson\n";
cout << setw(10) << "precision" << setw(10) << "points" << setw(10) << "error"
<< setw(10) << "points" << setw(10) << "error"
<< setw(10) << "points" << setw(10) << "error\n";
for(int precision=5; precision<=40; precision += 5){
cout << setw(10) << precision;
cout << "\n";
}
cout << "\nAt 311K points the Gauss-Legendre error is O(1.E-1),\n"
<< " Clenshaw-Curtis error is O(1.E-7) at 320K points.\n";
cout << "At 70K points the Gauss-Patterson error is O(1.E-4),\n"
<< " Clenshaw-Curtis needs 158K points to achieve the same." << endl;
#ifndef __TASMANIAN_DOXYGEN_SKIP
The master-class that represents an instance of a Tasmanian sparse grid.
Definition: TasmanianSparseGrid.hpp:293
TypeOneDRule
Used to specify the one dimensional family of rules that induces the sparse grid.
Definition: tsgEnumerates.hpp:285
@ rule_gausslegendreodd
Same as rule_gausslegendre but using only odd levels, partially mitigates the non-nested issues.
Definition: tsgEnumerates.hpp:331
@ rule_clenshawcurtis
Classic nested rule using Chebyshev nodes with very low Lebesgue constant.
Definition: tsgEnumerates.hpp:289
@ rule_gausspatterson
Nested rule that is optimized for integration, probably the best integration rule in more than 2 dime...
Definition: tsgEnumerates.hpp:333
@ type_qptotal
Total degree polynomial space for quadrature/integration.
Definition: tsgEnumerates.hpp:224
TasmanianSparseGrid makeGlobalGrid(int dimensions, int outputs, int depth, TypeDepth type, TypeOneDRule rule, std::vector< int > const &anisotropic_weights=std::vector< int >(), double alpha=0.0, double beta=0.0, const char *custom_filename=nullptr, std::vector< int > const &level_limits=std::vector< int >())
Factory method, creates a new grid and calls TasmanianSparseGrid::makeGlobalGrid().
Definition: TasmanianSparseGrid.hpp:2272