Skip to content

Commit 071ddf1

Browse files
committed
Merge branch 'fix-integration-order' of https://github.com/npaster/diskpp into fix-integration-order
2 parents 81ec0bf + 66f29c9 commit 071ddf1

2 files changed

Lines changed: 159 additions & 24 deletions

File tree

‎apps/tests/raw_quadratures.cpp‎

Lines changed: 157 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
* DOI: 10.1016/j.cam.2017.09.017
2424
*/
2525

26+
#include <limits>
27+
2628
#include <xmmintrin.h>
2729

2830
#include "bases/bases.hpp"
@@ -31,40 +33,173 @@
3133

3234
#include "common.hpp"
3335

34-
template<typename Mesh>
35-
struct test_functor_base
36+
template<class T>
37+
typename std::enable_if<!std::numeric_limits<T>::is_integer, bool>::type
38+
almost_equal(T x, T y, T ulp)
3639
{
37-
virtual typename Mesh::coordinate_type
38-
integrand(const typename Mesh::point_type&) = 0;
39-
40+
// the machine epsilon has to be scaled to the magnitude of the values used
41+
// and multiplied by the desired precision in ULPs (units in the last place)
42+
return std::abs(x-y) <= std::numeric_limits<T>::epsilon() * std::abs(x+y) * ulp
43+
// unless the result is subnormal
44+
|| std::abs(x-y) < std::numeric_limits<T>::min();
45+
}
4046

41-
/* Expect k+1 convergence on the cells and k+0.5 on the faces. */
42-
typename Mesh::coordinate_type
43-
operator()(const Mesh& msh, size_t degree) const
44-
{
45-
typedef Mesh mesh_type;
46-
typedef typename mesh_type::cell cell_type;
47-
typedef typename mesh_type::face face_type;
48-
typedef typename mesh_type::coordinate_type scalar_type;
49-
typedef typename mesh_type::point_type point_type;
47+
enum class quadtype
48+
{
49+
GOLUB_WELSCH,
50+
GAUSS_LEGENDRE,
51+
DRIVER
52+
};
5053

51-
auto f = make_scalar_testing_data(msh);
5254

53-
scalar_type integral_value = 0.0;
55+
/* Test 1D quadratures on [0,1] interval by integrating monomials */
56+
template<typename T>
57+
bool
58+
test_1d_quadrature(quadtype qt)
59+
{
60+
size_t max_test_degree = 20; /* max degree to test */
61+
T ULP_max = 50; /* max error in ULP */
62+
63+
auto transform = [](const std::pair<point<T, 1>, T>& qp) -> auto {
64+
point<T,1> p({0.5 + qp.first.x()/2.0});
65+
T w = 0.5*qp.second;
66+
return std::make_pair(p,w);
67+
};
68+
69+
auto analytic_integral = [](size_t degree) -> T {
70+
return 1.0/(degree+1);
71+
};
72+
73+
auto monomial = [](const point<T,1>& p, size_t degree) -> T {
74+
return iexp_pow(p.x(), degree);
75+
};
76+
77+
auto get_quadrature = [](quadtype qt, size_t degree) -> auto {
78+
/* Those are the functions we are testing: see quad_bones.hpp */
79+
if ( qt == quadtype::GOLUB_WELSCH )
80+
return disk::golub_welsch<T>(degree);
81+
82+
if ( qt == quadtype::GAUSS_LEGENDRE )
83+
return disk::gauss_legendre<T>(degree);
84+
85+
if ( qt == quadtype::DRIVER )
86+
return disk::edge_quadrature<T>(degree);
87+
88+
throw std::invalid_argument("Unknown quadrature to test");
89+
};
5490

55-
for (auto itor = msh.cells_begin(); itor != msh.cells_end(); itor++)
91+
bool success = true;
92+
93+
for (size_t qd = 0; qd <= max_test_degree; qd++)
94+
{
95+
auto qps = get_quadrature(qt, qd);
96+
97+
for (size_t md = 0; md <= qd; md++)
5698
{
57-
auto cl = *itor;
58-
auto qps = disk::integrate(msh, cl, degree);
99+
T int_ana = analytic_integral(md);
100+
T int_num = 0.0;
59101
for (auto& qp : qps)
60-
integral_value += qp.weight() * integrand(qp.point());
102+
{
103+
auto real_qp = transform(qp);
104+
int_num += real_qp.second * monomial(real_qp.first, md);
105+
}
106+
107+
if ( not almost_equal(int_ana, int_num, ULP_max) )
108+
{
109+
std::cout << "FAIL: md = " << md << ", qd = " << qd;
110+
std::cout << " analytical value = " << std::setprecision(16) << int_ana;
111+
std::cout << " numerical value = " << std::setprecision (16) << int_num;
112+
std::cout << std::endl;
113+
success = false;
114+
}
61115
}
116+
}
117+
118+
return success;
119+
}
62120

63-
return integral_value;
121+
void
122+
test_1d_driver(const char *name, quadtype qt, int& status)
123+
{
124+
std::string str_success = "[ \x1b[32mOK\x1b[0m ]";
125+
std::string str_failure = "[\x1b[31mFAIL\x1b[0m]";
126+
127+
std::cout << "Testing 1D " << name << ": ";
128+
if ( not test_1d_quadrature<double>(qt) )
129+
{
130+
std::cout << str_failure << std::endl;
131+
status = EXIT_FAILURE;
64132
}
65-
};
133+
else
134+
{
135+
std::cout << str_success << std::endl;
136+
}
137+
}
138+
139+
/* Test 2D quadrature for triangles */
140+
template<typename T>
141+
bool
142+
test_2d_triangle_quadrature(void)
143+
{
144+
/* max degree to test: pay attention that setting degree k
145+
* means testing up to degree 2*k, because we consider the
146+
* monomial x^m y^n where m and n go from 0 to k. */
147+
size_t max_test_degree = 10;
148+
149+
/* max error in ULP */
150+
T ULP_max = 100;
151+
152+
/* triangle on which we integrate */
153+
std::array<point<T,2>,3> tp;
154+
tp[0] = point<T,2>({0,0});
155+
tp[1] = point<T,2>({1,0});
156+
tp[2] = point<T,2>({1,1});
157+
158+
auto analytic_integral = [](size_t degree_x, size_t degree_y) -> T {
159+
return 1.0/((degree_y+1)*(degree_x+degree_y+2));
160+
};
161+
162+
auto monomial = [](const point<T,2>& pt, size_t m, size_t n) -> T {
163+
return iexp_pow(pt.x(), m)*iexp_pow(pt.y(), n);
164+
};
165+
166+
bool success = true;
167+
for (size_t m = 0; m <= max_test_degree; m++)
168+
{
169+
for (size_t n = 0; n <= max_test_degree; n++)
170+
{
171+
/* This is the function we are testing: see quad_bones.hpp */
172+
auto qps = disk::priv::integrate_triangle<T>(m+n, tp);
173+
T int_num = 0.0;
174+
for (auto& qp : qps)
175+
int_num += qp.weight()*monomial(qp.point(),m,n);
176+
177+
T int_ana = analytic_integral(m,n);
178+
179+
if ( not almost_equal(int_ana, int_num, ULP_max) )
180+
{
181+
std::cout << "FAIL: m = " << m << ", n = " << n;
182+
std::cout << " analytical value = " << std::setprecision(16) << int_ana;
183+
std::cout << " numerical value = " << std::setprecision (16) << int_num;
184+
std::cout << std::endl;
185+
success = false;
186+
}
187+
}
188+
}
189+
190+
return success;
191+
}
66192

67193
int main(void)
68194
{
195+
int ret = EXIT_SUCCESS;
196+
197+
test_1d_driver("Golub-Welsch", quadtype::GOLUB_WELSCH, ret);
198+
test_1d_driver("Gauss-Legendre", quadtype::GAUSS_LEGENDRE, ret);
199+
test_1d_driver("general driver", quadtype::DRIVER, ret);
69200

201+
if (!test_2d_triangle_quadrature<double>())
202+
ret = EXIT_FAILURE;
203+
204+
return ret;
70205
}

‎core/quadratures/quad_bones.hpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ golub_welsch(const size_t degree)
8989

9090
template<typename T>
9191
std::vector<std::pair<point<T, 1>, T>>
92-
gauss_legendre(const size_t degree)
92+
gauss_legendre(size_t degree)
9393
{
9494
auto comp_degree = degree;
9595

@@ -296,7 +296,7 @@ quadrangle_quadrature(const size_t degree)
296296
{
297297
const auto qps = disk::edge_quadrature<T>(degree);
298298

299-
std::vector<std::pair<point<T, 2>, T>> ret; //;
299+
std::vector<std::pair<point<T, 2>, T>> ret;
300300
ret.reserve(qps.size() * qps.size());
301301

302302
for (auto jtor = qps.begin(); jtor != qps.end(); jtor++)

0 commit comments

Comments
 (0)