26 #include "getfem/bgeot_permutations.h"
38 static pintegration_method
im_none(im_param_list ¶ms,
39 std::vector<dal::pstatic_stored_object> &) {
40 GMM_ASSERT1(params.size() == 0,
"IM_NONE does not accept any parameter");
41 return std::make_shared<integration_method>();
45 long_scalar_type res = 0.0;
46 if (P.size() > int_monomials.size()) {
47 std::vector<long_scalar_type> *hum = &int_monomials;
48 size_type i = P.size(), j = int_monomials.size();
52 (*hum)[k-1] = int_monomial(mi);
54 base_poly::const_iterator it = P.begin(), ite = P.end();
55 std::vector<long_scalar_type>::const_iterator itb = int_monomials.begin();
56 for ( ; it != ite; ++it, ++itb) {
57 res += long_scalar_type(*it) * long_scalar_type(*itb);
64 long_scalar_type res = 0.0;
65 std::vector<long_scalar_type> *hum = &(int_face_monomials[f]);
66 if (P.size() > hum->size()) {
71 (*hum)[k-1] = int_monomial_on_face(mi, f);
73 base_poly::const_iterator it = P.begin(), ite = P.end();
74 std::vector<long_scalar_type>::const_iterator itb = hum->begin();
75 for ( ; it != ite; ++it, ++itb)
76 res += long_scalar_type(*it) * long_scalar_type(*itb);
92 { cvs = c; int_face_monomials.resize(c->nb_faces()); }
98 long_scalar_type res = LONG_SCAL(1);
100 bgeot::power_index::const_iterator itm = power.begin(),
102 for ( ; itm != itme; ++itm)
103 for (
int k = 1; k <= *itm; ++k, ++fa)
104 res *= long_scalar_type(k) / long_scalar_type(fa);
106 for (
int k = 0; k < cvs->dim(); k++) { res /= long_scalar_type(fa); fa++; }
110 long_scalar_type simplex_poly_integration_::int_monomial_on_face
112 long_scalar_type res = LONG_SCAL(0);
114 if (f == 0 || power[f-1] == 0.0) {
115 res = (f == 0) ? sqrt(long_scalar_type(cvs->dim())) : LONG_SCAL(1);
117 bgeot::power_index::const_iterator itm = power.begin(),
119 for ( ; itm != itme; ++itm)
120 for (
int k = 1; k <= *itm; ++k, ++fa)
121 res *= long_scalar_type(k) / long_scalar_type(fa);
123 for (
int k = 1; k < cvs->dim(); k++) { res/=long_scalar_type(fa); fa++; }
128 static pintegration_method
129 exact_simplex(im_param_list ¶ms,
130 std::vector<dal::pstatic_stored_object> &dependencies) {
131 GMM_ASSERT1(params.size() == 1,
"Bad number of parameters : "
132 << params.size() <<
" should be 1.");
133 GMM_ASSERT1(params[0].type() == 0,
"Bad type of parameters");
134 int n = int(::floor(params[0].num() + 0.01));
135 GMM_ASSERT1(n > 0 && n < 100 &&
double(n) == params[0].num(),
138 ppoly_integration ppi = std::make_shared<simplex_poly_integration_>
140 return std::make_shared<integration_method>(ppi);
147 struct plyint_mul_structure_ :
public poly_integration {
148 ppoly_integration cv1, cv2;
155 plyint_mul_structure_(ppoly_integration a, ppoly_integration b);
158 long_scalar_type plyint_mul_structure_::int_monomial
161 std::copy(power.begin(), power.begin() + cv1->dim(), mi1.begin());
162 std::copy(power.begin() + cv1->dim(), power.end(), mi2.begin());
163 return cv1->int_monomial(mi1) * cv2->int_monomial(mi2);
166 long_scalar_type plyint_mul_structure_::int_monomial_on_face
169 std::copy(power.begin(), power.begin() + cv1->dim(), mi1.begin());
170 std::copy(power.begin() + cv1->dim(), power.end(), mi2.begin());
171 short_type nfx = cv1->structure()->nb_faces();
173 return cv1->int_monomial_on_face(mi1,f) * cv2->int_monomial(mi2);
175 return cv1->int_monomial(mi1)
176 * cv2->int_monomial_on_face(mi2,
short_type(f-nfx));
179 plyint_mul_structure_::plyint_mul_structure_(ppoly_integration a,
180 ppoly_integration b) {
184 int_face_monomials.resize(cvs->nb_faces());
187 static pintegration_method
188 product_exact(im_param_list ¶ms,
189 std::vector<dal::pstatic_stored_object> &dependencies) {
190 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
191 << params.size() <<
" should be 2.");
192 GMM_ASSERT1(params[0].type() == 1 && params[1].type() == 1,
193 "Bad type of parameters");
194 pintegration_method a = params[0].method();
195 pintegration_method b = params[1].method();
196 GMM_ASSERT1(a->type() == IM_EXACT && b->type() == IM_EXACT,
198 dependencies.push_back(a); dependencies.push_back(b);
201 ppoly_integration ppi = std::make_shared<plyint_mul_structure_>
202 (a->exact_method(), b->exact_method());
203 return std::make_shared<integration_method>(ppi);
210 static pintegration_method
211 exact_parallelepiped(im_param_list ¶ms,
212 std::vector<dal::pstatic_stored_object> &) {
213 GMM_ASSERT1(params.size() == 1,
"Bad number of parameters : "
214 << params.size() <<
" should be 1.");
215 GMM_ASSERT1(params[0].type() == 0,
"Bad type of parameters");
216 int n = int(::floor(params[0].num() + 0.01));
217 GMM_ASSERT1(n > 0 && n < 100 &&
double(n) == params[0].num(),
220 std::stringstream name;
222 name <<
"IM_EXACT_SIMPLEX(1)";
224 name <<
"IM_PRODUCT(IM_EXACT_PARALLELEPIPED(" << n-1
225 <<
"),IM_EXACT_SIMPLEX(1)))";
229 static pintegration_method
230 exact_prism(im_param_list ¶ms,
231 std::vector<dal::pstatic_stored_object> &) {
232 GMM_ASSERT1(params.size() == 1,
"Bad number of parameters : "
233 << params.size() <<
" should be 1.");
234 GMM_ASSERT1(params[0].type() == 0,
"Bad type of parameters");
235 int n = int(::floor(params[0].num() + 0.01));
236 GMM_ASSERT1(n > 1 && n < 100 &&
double(n) == params[0].num(),
239 std::stringstream name;
240 name <<
"IM_PRODUCT(IM_EXACT_SIMPLEX(" << n-1
241 <<
"),IM_EXACT_SIMPLEX(1))";
249 void approx_integration::add_point(
const base_node &pt,
252 bool include_empty) {
253 GMM_ASSERT1(!valid,
"Impossible to modify a valid integration method.");
254 if (gmm::abs(w) > 1.0E-15 || include_empty) {
256 if (gmm::abs(w) <= 1.0E-15) w = scalar_type(0);
257 GMM_ASSERT1(f <= cvr->structure()->nb_faces(),
"Wrong argument.");
258 size_type i = pt_to_store[f].search_node(pt);
260 i = pt_to_store[f].add_node(pt);
261 int_coeffs.resize(int_coeffs.size() + 1);
262 for (
size_type j = f; j <= cvr->structure()->nb_faces(); ++j)
264 for (
size_type j = int_coeffs.size(); j > repartition[f]; --j)
265 int_coeffs[j-1] = int_coeffs[j-2];
266 int_coeffs[repartition[f]-1] = 0.0;
268 int_coeffs[((f == 0) ? 0 : repartition[f-1]) + i] += w;
272 void approx_integration::add_point_norepeat(
const base_node &pt,
276 if (pt_to_store[f2].search_node(pt) ==
size_type(-1)) add_point(pt,w,f);
279 void approx_integration::add_point_full_symmetric(base_node pt,
281 dim_type n = cvr->structure()->dim();
284 if (n+1 == cvr->structure()->nb_faces()) {
289 std::copy(pt.begin(), pt.end(), pt3.begin());
290 pt3[n] = 1;
for (k = 0; k < n; ++k) pt3[n] -= pt[k];
291 std::vector<int> ind(n); std::fill(ind.begin(), ind.end(), 0);
292 std::vector<bool> ind2(n+1);
295 std::fill(ind2.begin(), ind2.end(),
false);
297 for (k = 0; k < n; ++k)
298 if (ind2[ind[k]]) { good =
false;
break; }
else ind2[ind[k]] =
true;
300 for (k = 0; k < n; ++k) pt2[k] = pt3[ind[k]];
301 add_point_norepeat(pt2, w);
304 while(ind[k] == n+1) { ind[k++] = 0;
if (k == n)
return; ind[k]++; }
308 else if (cvr->structure()->nb_points() == (
size_type(1) << n)) {
311 for (k = 0; k < n; ++k)
312 if (i & (
size_type(1) << k)) pt2[k]=pt[k];
else pt2[k] = 1.0-pt[k];
313 add_point_norepeat(pt2, w);
317 GMM_ASSERT1(
false,
"Fully symmetric option is only valid for"
318 "simplices and parallelepipedic elements");
321 void approx_integration::add_method_on_face(pintegration_method ppi,
323 papprox_integration pai = ppi->approx_method();
324 GMM_ASSERT1(!valid,
"Impossible to modify a valid integration method.");
325 GMM_ASSERT1(*key_of_stored_object(pai->structure())
326 == *key_of_stored_object(structure()->faces_structure()[f]),
327 "structures missmatch");
328 GMM_ASSERT1(ppi->type() == IM_APPROX,
"Impossible with an exact method.");
330 dim_type N = pai->structure()->dim();
331 scalar_type det = 1.0;
333 std::vector<base_node> pts(N);
335 pts[i] = (cvr->dir_points_of_face(f))[i+1]
336 - (cvr->dir_points_of_face(f))[0];
338 base_matrix a(N+1, N), b(N, N), tmp(N, N);
339 for (dim_type i = 0; i < N+1; ++i)
340 for (dim_type j = 0; j < N; ++j)
343 gmm::mult(gmm::transposed(a), a, b);
344 det = ::sqrt(gmm::abs(gmm::lu_det(b)));
346 for (
size_type i = 0; i < pai->nb_points_on_convex(); ++i) {
347 pt = (cvr->dir_points_of_face(f))[0];
348 for (dim_type j = 0; j < N; ++j)
349 pt += pts[j] * ((*(pai->pintegration_points()))[i])[j];
350 add_point(pt, pai->coeff(i) * det, f);
354 void approx_integration::valid_method() {
355 std::vector<base_node> ptab(int_coeffs.size());
358 for (
short_type f = 0; f <= cvr->structure()->nb_faces(); ++f) {
360 for (PT_TAB::const_iterator it = pt_to_store[f].begin();
361 it != pt_to_store[f].end(); ++it ) {
366 GMM_ASSERT1(i == int_coeffs.size(),
"internal error.");
367 pint_points = bgeot::store_point_tab(ptab);
368 pt_to_store = std::vector<PT_TAB>();
378 static pintegration_method
379 im_list_integration(std::string name,
380 std::vector<dal::pstatic_stored_object> &dependencies) {
382 for (
int i = 0; i < NB_IM; ++i)
383 if (!name.compare(im_desc_tab[i].method_name)) {
386 dim_type N = pgt->structure()->dim();
388 auto pai = std::make_shared<approx_integration>(pgt->convex_ref());
390 for (
size_type j = 0; j < im_desc_tab[i].nb_points; ++j) {
391 for (dim_type k = 0; k < N; ++k)
392 pt[k] = atof(im_desc_real[fr+j*(N+1)+k]);
395 switch (im_desc_node_type[im_desc_tab[i].firsttype + j]) {
397 base_node pt2(pt.size());
400 pai->add_point_full_symmetric(pt2,
401 atof(im_desc_real[fr+j*(N+1)+N]));
407 pai->add_point_full_symmetric(pt,atof(im_desc_real[fr+j*(N+1)+N]));
412 pai->add_point(pt, atof(im_desc_real[fr+j*(N+1)+N]));
415 default: GMM_ASSERT1(
false,
"");
419 for (
short_type f = 0; N > 0 && f < pgt->structure()->nb_faces(); ++f)
420 pai->add_method_on_face
422 (im_desc_face_meth[im_desc_tab[i].firstface + f]), f);
427 pintegration_method p(std::make_shared<integration_method>(pai));
428 dependencies.push_back(p->approx_method()->ref_convex());
429 dependencies.push_back(p->approx_method()->pintegration_points());
432 return pintegration_method();
440 struct Legendre_polynomials {
441 std::vector<base_poly> polynomials;
442 std::vector<std::vector<long_scalar_type>> roots;
444 Legendre_polynomials() : nb_lp(-1) {}
446 polynomials.resize(de+2);
449 polynomials[0] = base_poly(1,0);
450 polynomials[0].one();
451 polynomials[1] = base_poly(1,1,0);
459 (base_poly(1,1,0) * polynomials[nb_lp-1]
460 * ((2.0 * long_scalar_type(nb_lp) - 1.0) / long_scalar_type(nb_lp)))
461 + (polynomials[nb_lp-2]
462 * ((1.0 - long_scalar_type(nb_lp)) / long_scalar_type(nb_lp)));
463 roots[nb_lp].resize(nb_lp);
464 roots[nb_lp][nb_lp/2] = 0.0;
465 long_scalar_type a = -1.0, b, c, d, e, cv, ev, ecart, ecart2;
466 for (
int k = 0; k < nb_lp / 2; ++k) {
467 b = roots[nb_lp-1][k];
470 cv = polynomials[nb_lp].eval(&c);
472 ecart = 2.0 * (d - c);
474 --imax;
if (imax == 0)
break;
476 ecart2 = d - c;
if (ecart2 >= ecart)
break;
478 ev = polynomials[nb_lp].eval(&e);
479 if (ev * cv < 0.) { d = e; }
else { c = e; cv = ev; }
483 roots[nb_lp][nb_lp-k-1] = -c;
490 struct gauss_approx_integration_ :
public approx_integration {
494 gauss_approx_integration_::gauss_approx_integration_(
short_type nbpt) {
495 GMM_ASSERT1(nbpt <= 32000,
"too much points");
498 std::vector<base_node> int_points(nbpt+2);
499 int_coeffs.resize(nbpt+2);
500 repartition.resize(3);
501 repartition[0] = nbpt;
502 repartition[1] = nbpt + 1;
503 repartition[2] = nbpt + 2;
505 Legendre_polynomials Lp;
509 int_points[i].resize(1);
510 long_scalar_type lr = Lp.roots[nbpt][i];
511 int_points[i][0] = 0.5 + 0.5 * bgeot::to_scalar(lr);
512 int_coeffs[i] = bgeot::to_scalar((1.0 - gmm::sqr(lr))
513 / gmm::sqr( long_scalar_type(nbpt)
514 * (Lp.polynomials[nbpt-1].eval(&lr))));
517 int_points[nbpt].resize(1);
518 int_points[nbpt][0] = 1.0; int_coeffs[nbpt] = 1.0;
520 int_points[nbpt+1].resize(1);
521 int_points[nbpt+1][0] = 0.0; int_coeffs[nbpt+1] = 1.0;
522 pint_points = bgeot::store_point_tab(int_points);
527 static pintegration_method
528 gauss1d(im_param_list ¶ms,
529 std::vector<dal::pstatic_stored_object> &dependencies) {
530 GMM_ASSERT1(params.size() == 1,
"Bad number of parameters : "
531 << params.size() <<
" should be 1.");
532 GMM_ASSERT1(params[0].type() == 0,
"Bad type of parameters");
533 int n = int(::floor(params[0].num() + 0.01));
534 GMM_ASSERT1(n >= 0 && n < 32000 &&
double(n) == params[0].num(),
537 std::stringstream name;
538 name <<
"IM_GAUSS1D(" << n-1 <<
")";
543 pai = std::make_shared<gauss_approx_integration_>(
short_type(n/2 + 1));
544 pintegration_method p = std::make_shared<integration_method>(pai);
545 dependencies.push_back(p->approx_method()->ref_convex());
546 dependencies.push_back(p->approx_method()->pintegration_points());
555 struct Newton_Cotes_approx_integration_ :
public approx_integration
558 Newton_Cotes_approx_integration_(dim_type nc,
short_type k);
561 Newton_Cotes_approx_integration_::Newton_Cotes_approx_integration_
568 add_point(c, scalar_type(1));
572 std::stringstream name;
573 name <<
"IM_EXACT_SIMPLEX(" << int(nc) <<
")";
577 c.fill(scalar_type(0.0));
578 if (k == 0) c.fill(1.0 / scalar_type(nc+1));
580 gmm::dense_matrix<long_scalar_type> M(R, R);
581 std::vector<long_scalar_type> F(R), U(R);
582 std::vector<bgeot::power_index> base(R);
583 std::vector<base_node> nodes(R);
587 for (
size_type r = 0; r < R; ++r, ++pi) {
588 base[r] = pi; nodes[r] = c;
589 if (k != 0 && nc > 0) {
590 l = 0; c[l] += 1.0 / scalar_type(k); sum++;
592 sum -= int(floor(0.5+(c[l] * k)));
593 c[l] = 0.0; l++;
if (l == nc)
break;
594 c[l] += 1.0 / scalar_type(k); sum++;
613 F[r] = ppi->int_monomial(base[r]);
627 M(r, q) = bgeot::eval_monomial(base[r], nodes[q].begin());
631 gmm::lu_solve(M, U, F);
633 add_point(nodes[r], bgeot::to_scalar(U[r]));
635 std::stringstream name2;
636 name2 <<
"IM_NC(" << int(nc-1) <<
"," << int(k) <<
")";
643 static pintegration_method
644 Newton_Cotes(im_param_list ¶ms,
645 std::vector<dal::pstatic_stored_object> &dependencies) {
646 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
647 << params.size() <<
" should be 2.");
648 GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
649 "Bad type of parameters");
650 int n = int(::floor(params[0].num() + 0.01));
651 int k = int(::floor(params[1].num() + 0.01));
652 GMM_ASSERT1(n >= 0 && n < 100 && k >= 0 && k <= 150 &&
653 double(n) == params[0].num() &&
double(k) == params[1].num(),
656 pai = std::make_shared<Newton_Cotes_approx_integration_>(dim_type(n),
658 pintegration_method p = std::make_shared<integration_method>(pai);
659 dependencies.push_back(p->approx_method()->ref_convex());
660 dependencies.push_back(p->approx_method()->pintegration_points());
668 struct a_int_pro_integration :
public approx_integration
670 a_int_pro_integration(papprox_integration a, papprox_integration b);
674 a_int_pro_integration::a_int_pro_integration(papprox_integration a,
675 papprox_integration b) {
679 std::vector<base_node> int_points;
680 int_points.resize(n1 * n2);
681 int_coeffs.resize(n1 * n2);
682 repartition.resize(cvr->structure()->nb_faces()+1);
683 repartition[0] = n1 * n2;
686 int_coeffs[i1 + i2 * n1] = a->coeff(i1) * b->coeff(i2);
687 int_points[i1 + i2 * n1].resize(dim());
688 std::copy(a->point(i1).begin(), a->point(i1).end(),
689 int_points[i1 + i2 * n1].begin());
690 std::copy(b->point(i2).begin(), b->point(i2).end(),
691 int_points[i1 + i2 * n1].begin() + a->dim());
694 for (
short_type f1 = 0; f1 < a->structure()->nb_faces(); ++f1, ++f) {
695 n1 = a->nb_points_on_face(f1);
696 n2 = b->nb_points_on_convex();
698 repartition[f+1] = w + n1 * n2;
699 int_points.resize(repartition[f+1]);
700 int_coeffs.resize(repartition[f+1]);
703 int_coeffs[w + i1 + i2 * n1] = a->coeff_on_face(f1, i1)
705 int_points[w + i1 + i2 * n1].resize(dim());
706 std::copy(a->point_on_face(f1, i1).begin(),
707 a->point_on_face(f1, i1).end(),
708 int_points[w + i1 + i2 * n1].begin());
709 std::copy(b->point(i2).begin(), b->point(i2).end(),
710 int_points[w + i1 + i2 * n1].begin() + a->dim());
713 for (
short_type f2 = 0; f2 < b->structure()->nb_faces(); ++f2, ++f) {
714 n1 = a->nb_points_on_convex();
715 n2 = b->nb_points_on_face(f2);
717 repartition[f+1] = w + n1 * n2;
718 int_points.resize(repartition[f+1]);
719 int_coeffs.resize(repartition[f+1]);
722 int_coeffs[w + i1 + i2 * n1] = a->coeff(i1)
723 * b->coeff_on_face(f2, i2);
724 int_points[w + i1 + i2 * n1].resize(dim());
725 std::copy(a->point(i1).begin(), a->point(i1).end(),
726 int_points[w + i1 + i2 * n1].begin());
727 std::copy(b->point_on_face(f2, i2).begin(),
728 b->point_on_face(f2, i2).end(),
729 int_points[w + i1 + i2 * n1].begin() + a->dim());
732 pint_points = bgeot::store_point_tab(int_points);
736 static pintegration_method
737 product_approx(im_param_list ¶ms,
738 std::vector<dal::pstatic_stored_object> &dependencies) {
739 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
740 << params.size() <<
" should be 2.");
741 GMM_ASSERT1(params[0].type() == 1 && params[1].type() == 1,
742 "Bad type of parameters");
743 pintegration_method a = params[0].method();
744 pintegration_method b = params[1].method();
745 GMM_ASSERT1(a->type() == IM_APPROX && b->type() == IM_APPROX,
748 pai = std::make_shared<a_int_pro_integration>(a->approx_method(),
750 pintegration_method p = std::make_shared<integration_method>(pai);
751 dependencies.push_back(p->approx_method()->ref_convex());
752 dependencies.push_back(p->approx_method()->pintegration_points());
756 static pintegration_method
757 product_which(im_param_list ¶ms,
758 std::vector<dal::pstatic_stored_object> &dependencies) {
759 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
760 << params.size() <<
" should be 2.");
761 GMM_ASSERT1(params[0].type() == 1 && params[1].type() == 1,
762 "Bad type of parameters");
763 pintegration_method a = params[0].method();
764 pintegration_method b = params[1].method();
765 if (a->type() == IM_EXACT || b->type() == IM_EXACT)
766 return product_exact(params, dependencies);
767 else return product_approx(params, dependencies);
775 static pintegration_method
776 Newton_Cotes_para(im_param_list ¶ms,
777 std::vector<dal::pstatic_stored_object> &) {
778 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
779 << params.size() <<
" should be 2.");
780 GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
781 "Bad type of parameters");
782 int n = int(::floor(params[0].num() + 0.01));
783 int k = int(::floor(params[1].num() + 0.01));
784 GMM_ASSERT1(n > 0 && n < 100 && k >= 0 && k <= 150 &&
785 double(n) == params[0].num() &&
double(k) == params[1].num(),
788 std::stringstream name;
790 name <<
"IM_NC(1," << k <<
")";
792 name <<
"IM_PRODUCT(IM_NC_PARALLELEPIPED(" << n-1 <<
"," << k
793 <<
"),IM_NC(1," << k <<
"))";
797 static pintegration_method
798 Newton_Cotes_prism(im_param_list ¶ms,
799 std::vector<dal::pstatic_stored_object> &) {
800 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
801 << params.size() <<
" should be 2.");
802 GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
803 "Bad type of parameters");
804 int n = int(::floor(params[0].num() + 0.01));
805 int k = int(::floor(params[1].num() + 0.01));
806 GMM_ASSERT1(n > 1 && n < 100 && k >= 0 && k <= 150 &&
807 double(n) == params[0].num() &&
double(k) == params[1].num(),
810 std::stringstream name;
811 name <<
"IM_PRODUCT(IM_NC(" << n-1 <<
"," << k <<
"),IM_NC(1,"
820 static pintegration_method
821 Gauss_paramul(im_param_list ¶ms,
822 std::vector<dal::pstatic_stored_object> &) {
823 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
824 << params.size() <<
" should be 2.");
825 GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
826 "Bad type of parameters");
827 int n = int(::floor(params[0].num() + 0.01));
828 int k = int(::floor(params[1].num() + 0.01));
829 GMM_ASSERT1(n > 0 && n < 100 && k >= 0 && k <= 150 &&
830 double(n) == params[0].num() &&
double(k) == params[1].num(),
833 std::stringstream name;
835 name <<
"IM_GAUSS1D(" << k <<
")";
837 name <<
"IM_PRODUCT(IM_GAUSS_PARALLELEPIPED(" << n-1 <<
"," << k
838 <<
"),IM_GAUSS1D(" << k <<
"))";
846 struct quasi_polar_integration :
public approx_integration {
847 quasi_polar_integration(papprox_integration base_im,
855 enum { SQUARE, PRISM, TETRA_CYL, PRISM2, PYRAMID } what;
856 if (N == 2) what = SQUARE;
858 what = (ip2 ==
size_type(-1) || ip1 == ip2) ? PRISM2 : PRISM;
863 else GMM_ASSERT1(
false,
"Incoherent integration method");
870 std::vector<base_node> nodes1 = pgt1->convex_ref()->points();
872 std::vector<base_node> nodes2(N+1);
873 if (what == PYRAMID) {
874 pgt2 = bgeot::pyramid_QK_geotrans(1);
877 std::vector<size_type> other_nodes;
879 std::vector<base_node> nodes3(N+1);
883 nodes1[3] = nodes1[1];
884 nodes2[ip1] = nodes1[1]; ip2 = ip1;
885 other_nodes.push_back(0);
886 other_nodes.push_back(2);
889 nodes1[4] = nodes1[0]; nodes1[5] = nodes1[1];
890 nodes2[ip1] = nodes1[0];
891 nodes2[ip2] = nodes1[1];
892 other_nodes.push_back(2);
893 other_nodes.push_back(6);
896 nodes3[0] = nodes1[0]; nodes3[1] = nodes1[1];
897 nodes3[2] = nodes1[2]; nodes3[3] = nodes1[4];
899 nodes2[ip1] = nodes1[1]; ip2 = ip1;
900 other_nodes.push_back(0);
901 other_nodes.push_back(2);
902 other_nodes.push_back(4);
905 nodes2[ip1] = nodes1[4];
906 other_nodes.push_back(0);
907 other_nodes.push_back(1);
908 other_nodes.push_back(2);
912 nodes1[0] = base_node(-1.,-1., 0.);
913 nodes1[1] = base_node( 1.,-1., 0.);
914 nodes1[2] = base_node(-1., 1., 0.);
915 nodes1[3] = base_node( 1., 1., 0.);
916 nodes1[4] = base_node( 0., 0., 1.);
917 nodes1[5] = nodes1[6] = nodes1[7] = nodes1[4];
918 nodes2[ip1] = nodes1[0];
919 other_nodes.push_back(4);
920 other_nodes.push_back(3);
921 other_nodes.push_back(2);
922 other_nodes.push_back(1);
925 for (
size_type i = 0; i <= nodes2.size()-1; ++i)
926 if (i != ip1 && i != ip2) {
927 GMM_ASSERT3(!other_nodes.empty(),
"");
928 nodes2[i] = nodes1[other_nodes.back()];
929 other_nodes.pop_back();
932 base_matrix G1, G2, G3;
933 base_matrix K(N, N), grad(N, N), K3(N, N), K4(N, N);
934 base_node normal1(N), normal2(N);
936 scalar_type J1, J2, J3(1), J4(1);
938 bgeot::vectors_to_base_matrix(G1, nodes1);
939 bgeot::vectors_to_base_matrix(G2, nodes2);
943 if (what == TETRA_CYL) {
944 if (nc == 1) nodes3[0] = nodes1[3];
945 bgeot::vectors_to_base_matrix(G3, nodes3);
946 pgt3->poly_vector_grad(nodes1[0], grad);
947 gmm::mult(gmm::transposed(grad), gmm::transposed(G3), K3);
948 J3 = gmm::abs(gmm::lu_inverse(K3));
951 for (
size_type i=0; i < base_im->nb_points(); ++i) {
953 gmm::copy(gmm::identity_matrix(), K4); J4 = J1 = scalar_type(1);
956 if (i >= base_im->nb_points_on_convex()) {
957 size_type ii = i - base_im->nb_points_on_convex();
958 for (
short_type ff=0; ff < base_im->structure()->nb_faces(); ++ff) {
959 if (ii < base_im->nb_points_on_face(ff)) { fp = ff;
break; }
960 else ii -= base_im->nb_points_on_face(ff);
962 normal1 = base_im->ref_convex()->normals()[fp];
965 base_node P = base_im->point(i);
966 if (what == TETRA_CYL) {
967 P = pgt3->transform(P, nodes3);
968 scalar_type x = P[0], y = P[1], one_minus_z = 1.0 - P[2];
969 K4(0, 1) = - y / one_minus_z;
970 K4(1, 1) = 1.0 - x / one_minus_z;
971 K4(2, 1) = - x * y / gmm::sqr(one_minus_z);
972 J4 = gmm::abs(gmm::lu_det(K4));
973 P[1] *= (1.0 - x / one_minus_z);
975 if (what == PRISM2) {
976 scalar_type x = P[0], y = P[1], one_minus_z = 1.0 - P[2];
977 K4(0,0) = one_minus_z; K4(2,0) = -x;
978 K4(1,1) = one_minus_z; K4(2,1) = -y;
979 J4 = gmm::abs(gmm::lu_det(K4));
984 base_node P1 = pgt1->transform(P, nodes1), P2(N);
985 pgt1->poly_vector_grad(P, grad);
986 gmm::mult(gmm::transposed(grad), gmm::transposed(G1), K);
987 J1 = gmm::abs(gmm::lu_det(K)) * J3 * J4;
989 if (fp !=
size_type(-1) && J1 > 1E-10 && J4 > 1E-10) {
990 if (what == TETRA_CYL) {
991 gmm::mult(K3, normal1, normal2);
996 gmm::mult(K4, normal1, normal2);
997 gmm::mult(K, normal2, normal1);
1003 GMM_ASSERT1(pgt2->convex_ref()->is_in(P2) < 1E-8,
1004 "Point not in the convex ref : " << P2);
1006 pgt2->poly_vector_grad(P2, grad);
1007 gmm::mult(gmm::transposed(grad), gmm::transposed(G2), K);
1008 J2 = gmm::abs(gmm::lu_det(K));
1010 if (i < base_im->nb_points_on_convex())
1011 add_point(P2, base_im->coeff(i)*J1/J2,
short_type(-1));
1012 else if (J1 > 1E-10) {
1015 if (gmm::abs(pgt2->convex_ref()->is_in_face(ff, P2)) < 1E-8) {
1017 "An integration point is common to two faces");
1021 gmm::mult(K, normal2, normal1);
1022 add_point(P2,base_im->coeff(i)*J1*gmm::vect_norm2(normal1)/J2,f);
1027 if (what != TETRA_CYL)
break;
1034 static pintegration_method
1035 quasi_polar(im_param_list ¶ms,
1036 std::vector<dal::pstatic_stored_object> &dependencies) {
1037 GMM_ASSERT1(params.size() >= 1 && params[0].type() == 1,
1038 "Bad parameters for quasi polar integration: the first "
1039 "parameter should be an integration method");
1040 pintegration_method a = params[0].method();
1041 GMM_ASSERT1(a->type()==IM_APPROX,
"need an approximate integration method");
1042 int ip1 = 0, ip2 = 0;
1044 GMM_ASSERT1(params.size() == 1,
"Bad number of parameters");
1046 GMM_ASSERT1(params.size() == 2 || params.size() == 3,
1047 "Bad number of parameters : " << params.size()
1048 <<
" should be 2 or 3.");
1049 GMM_ASSERT1(params[1].type() == 0
1050 && params.back().type() == 0,
"Bad type of parameters");
1051 ip1 = int(::floor(params[1].num() + 0.01));
1052 ip2 = int(::floor(params.back().num() + 0.01));
1054 int N = a->approx_method()->dim();
1055 GMM_ASSERT1(N >= 2 && N <= 3 && ip1 >= 0 && ip2 >= 0 && ip1 <= N
1056 && ip2 <= N,
"Bad parameters");
1059 pai = std::make_shared<quasi_polar_integration>(a->approx_method(),
1061 pintegration_method p = std::make_shared<integration_method>(pai);
1062 dependencies.push_back(p->approx_method()->ref_convex());
1063 dependencies.push_back(p->approx_method()->pintegration_points());
1067 static pintegration_method
1068 pyramid(im_param_list ¶ms,
1069 std::vector<dal::pstatic_stored_object> &dependencies) {
1070 GMM_ASSERT1(params.size() == 1 && params[0].type() == 1,
1071 "Bad parameters for pyramid integration: the first "
1072 "parameter should be an integration method");
1073 pintegration_method a = params[0].method();
1074 GMM_ASSERT1(a->type()==IM_APPROX,
"need an approximate integration method");
1075 int N = a->approx_method()->dim();
1076 GMM_ASSERT1(N == 3,
"Bad parameters");
1079 pai = std::make_shared<quasi_polar_integration>(a->approx_method(), 0, 0);
1080 pintegration_method p = std::make_shared<integration_method>(pai);
1081 dependencies.push_back(p->approx_method()->ref_convex());
1082 dependencies.push_back(p->approx_method()->pintegration_points());
1093 structured_composite_int_method(im_param_list &,
1094 std::vector<dal::pstatic_stored_object> &);
1095 pintegration_method HCT_composite_int_method(im_param_list ¶ms,
1096 std::vector<dal::pstatic_stored_object> &dependencies);
1098 pintegration_method QUADC1_composite_int_method(im_param_list ¶ms,
1099 std::vector<dal::pstatic_stored_object> &dependencies);
1101 pintegration_method pyramid_composite_int_method(im_param_list ¶ms,
1102 std::vector<dal::pstatic_stored_object> &dependencies);
1105 im_naming_system() :
dal::naming_system<integration_method>(
"IM") {
1107 add_suffix(
"EXACT_SIMPLEX", exact_simplex);
1108 add_suffix(
"PRODUCT", product_which);
1109 add_suffix(
"EXACT_PARALLELEPIPED",exact_parallelepiped);
1110 add_suffix(
"EXACT_PRISM", exact_prism);
1111 add_suffix(
"GAUSS1D", gauss1d);
1112 add_suffix(
"NC", Newton_Cotes);
1113 add_suffix(
"NC_PARALLELEPIPED", Newton_Cotes_para);
1114 add_suffix(
"NC_PRISM", Newton_Cotes_prism);
1115 add_suffix(
"GAUSS_PARALLELEPIPED", Gauss_paramul);
1116 add_suffix(
"QUASI_POLAR", quasi_polar);
1117 add_suffix(
"PYRAMID", pyramid);
1118 add_suffix(
"STRUCTURED_COMPOSITE",
1119 structured_composite_int_method);
1120 add_suffix(
"HCT_COMPOSITE",
1121 HCT_composite_int_method);
1122 add_suffix(
"QUADC1_COMPOSITE",
1123 QUADC1_composite_int_method);
1124 add_suffix(
"PYRAMID_COMPOSITE",
1125 pyramid_composite_int_method);
1126 add_generic_function(im_list_integration);
1131 bool throw_if_not_found) {
1134 (name, i, throw_if_not_found);
1138 if (!(p.get()))
return "IM_NONE";
1143 void add_integration_name(std::string name,
1152 THREAD_SAFE_STATIC pintegration_method pim =
nullptr;
1155 std::stringstream name;
1156 name <<
"IM_EXACT_SIMPLEX(" << n <<
")";
1164 THREAD_SAFE_STATIC pintegration_method pim =
nullptr;
1167 std::stringstream name;
1168 name <<
"IM_EXACT_PARALLELEPIPED(" << n <<
")";
1176 THREAD_SAFE_STATIC pintegration_method pim =
nullptr;
1179 std::stringstream name;
1180 name <<
"IM_EXACT_PRISM(" << n <<
")";
1194 THREAD_SAFE_STATIC pintegration_method im_last =
nullptr;
1197 if (cvs_last == cvs)
1202 std::stringstream name;
1208 { name <<
"IM_EXACT_SIMPLEX("; found =
true; }
1212 if (!found && nbp == (
size_type(1) << n))
1214 { name <<
"IM_EXACT_PARALLELEPIPED("; found =
true; }
1218 if (!found && nbp == 2 * n)
1220 { name <<
"IM_EXACT_PRISM("; found =
true; }
1225 name << int(n) <<
')';
1231 GMM_ASSERT1(
false,
"This element is not taken into account. Contact us");
1239 static pintegration_method
1242 std::stringstream name;
1244 if(bgeot::is_torus_structure(cvs) && n == 3) n = 2;
1246 degree = std::max<dim_type>(degree, 1);
1252 case 1: name <<
"IM_GAUSS1D";
break;
1253 case 2: name <<
"IM_TRIANGLE";
break;
1254 case 3: name <<
"IM_TETRAHEDRON";
break;
1255 case 4: name <<
"IM_SIMPLEX4D";
break;
1256 default: GMM_ASSERT1(
false,
"no approximate integration method "
1257 "for simplexes of dimension " << n);
1260 std::stringstream name2;
1261 name2 << name.str() <<
"(" << k <<
")";
1265 GMM_ASSERT1(
false,
"could not find an " << name.str()
1266 <<
" of degree >= " <<
int(degree));
1268 GMM_ASSERT1(n == 3,
"Wrong dimension");
1269 name <<
"IM_PYRAMID(IM_GAUSS_PARALLELEPIPED(3," << degree <<
"))";
1270 }
else if (cvs->is_product(&a,&b) ||
1273 name <<
"IM_PRODUCT("
1276 }
else GMM_ASSERT1(
false,
"unknown convex structure!");
1283 THREAD_SAFE_STATIC dim_type degree_last;
1284 THREAD_SAFE_STATIC pintegration_method im_last =
nullptr;
1285 if (pgt_last == pgt && degree == degree_last)
1287 im_last = classical_approx_im_(pgt->structure(),degree);
1288 degree_last = degree;
1294 THREAD_SAFE_STATIC pintegration_method im_last =
nullptr;
1301 scalar_type test_integration_error(papprox_integration pim, dim_type order) {
1304 opt_long_scalar_type error(0);
1306 opt_long_scalar_type sum(0), realsum;
1307 for (
size_type i=0; i < pim->nb_points_on_convex(); ++i) {
1308 opt_long_scalar_type prod = pim->coeff(i);
1310 prod *= pow(opt_long_scalar_type(pim->point(i)[d]), idx[d]);
1313 realsum = exact->exact_method()->int_monomial(idx);
1314 error = std::max(error, gmm::abs(realsum-sum));
1316 return bgeot::to_scalar(error);
1319 papprox_integration get_approx_im_or_fail(pintegration_method pim) {
1320 GMM_ASSERT1(pim->type() == IM_APPROX,
"error estimate work only with "
1321 "approximate integration methods");
1322 return pim->approx_method();