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)
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));
570 std::stringstream name;
571 name <<
"IM_EXACT_SIMPLEX(" << int(nc) <<
")";
574 c.fill(scalar_type(0.0));
576 c.fill(1.0 / scalar_type(nc+1));
578 gmm::dense_matrix<long_scalar_type> M(R, R);
579 std::vector<long_scalar_type> F(R), U(R);
580 std::vector<bgeot::power_index> base(R);
581 std::vector<base_node> nodes(R);
586 if (k != 0 && nc > 0)
587 for (
size_type r = 0; r < R; ++r, ++pi) {
591 c[l] += 1.0 / scalar_type(k);
594 sum -= int(floor(0.5+(c[l] * k)));
598 c[l] += 1.0 / scalar_type(k);
603 for (
size_type r = 0; r < R; ++r, ++pi) {
621 F[r] = ppi->int_monomial(base[r]);
635 M(r, q) = bgeot::eval_monomial(base[r], nodes[q].begin());
641 add_point(nodes[r], bgeot::to_scalar(U[r]));
643 std::stringstream name2;
644 name2 <<
"IM_NC(" << int(nc-1) <<
"," << int(k) <<
")";
651 static pintegration_method
652 Newton_Cotes(im_param_list ¶ms,
653 std::vector<dal::pstatic_stored_object> &dependencies) {
654 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
655 << params.size() <<
" should be 2.");
656 GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
657 "Bad type of parameters");
658 int n = int(::floor(params[0].num() + 0.01));
659 int k = int(::floor(params[1].num() + 0.01));
660 GMM_ASSERT1(n >= 0 && n < 100 && k >= 0 && k <= 150 &&
661 double(n) == params[0].num() &&
double(k) == params[1].num(),
664 pai = std::make_shared<Newton_Cotes_approx_integration_>(dim_type(n),
666 pintegration_method p = std::make_shared<integration_method>(pai);
667 dependencies.push_back(p->approx_method()->ref_convex());
668 dependencies.push_back(p->approx_method()->pintegration_points());
676 struct a_int_pro_integration :
public approx_integration
678 a_int_pro_integration(papprox_integration a, papprox_integration b);
682 a_int_pro_integration::a_int_pro_integration(papprox_integration a,
683 papprox_integration b) {
687 std::vector<base_node> int_points;
688 int_points.resize(n1 * n2);
689 int_coeffs.resize(n1 * n2);
690 repartition.resize(cvr->structure()->nb_faces()+1);
691 repartition[0] = n1 * n2;
694 int_coeffs[i1 + i2 * n1] = a->coeff(i1) * b->coeff(i2);
695 int_points[i1 + i2 * n1].resize(dim());
696 std::copy(a->point(i1).begin(), a->point(i1).end(),
697 int_points[i1 + i2 * n1].begin());
698 std::copy(b->point(i2).begin(), b->point(i2).end(),
699 int_points[i1 + i2 * n1].begin() + a->dim());
702 for (
short_type f1 = 0; f1 < a->structure()->nb_faces(); ++f1, ++f) {
703 n1 = a->nb_points_on_face(f1);
704 n2 = b->nb_points_on_convex();
706 repartition[f+1] = w + n1 * n2;
707 int_points.resize(repartition[f+1]);
708 int_coeffs.resize(repartition[f+1]);
711 int_coeffs[w + i1 + i2 * n1] = a->coeff_on_face(f1, i1)
713 int_points[w + i1 + i2 * n1].resize(dim());
714 std::copy(a->point_on_face(f1, i1).begin(),
715 a->point_on_face(f1, i1).end(),
716 int_points[w + i1 + i2 * n1].begin());
717 std::copy(b->point(i2).begin(), b->point(i2).end(),
718 int_points[w + i1 + i2 * n1].begin() + a->dim());
721 for (
short_type f2 = 0; f2 < b->structure()->nb_faces(); ++f2, ++f) {
722 n1 = a->nb_points_on_convex();
723 n2 = b->nb_points_on_face(f2);
725 repartition[f+1] = w + n1 * n2;
726 int_points.resize(repartition[f+1]);
727 int_coeffs.resize(repartition[f+1]);
730 int_coeffs[w + i1 + i2 * n1] = a->coeff(i1)
731 * b->coeff_on_face(f2, i2);
732 int_points[w + i1 + i2 * n1].resize(dim());
733 std::copy(a->point(i1).begin(), a->point(i1).end(),
734 int_points[w + i1 + i2 * n1].begin());
735 std::copy(b->point_on_face(f2, i2).begin(),
736 b->point_on_face(f2, i2).end(),
737 int_points[w + i1 + i2 * n1].begin() + a->dim());
740 pint_points = bgeot::store_point_tab(int_points);
744 static pintegration_method
745 product_approx(im_param_list ¶ms,
746 std::vector<dal::pstatic_stored_object> &dependencies) {
747 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
748 << params.size() <<
" should be 2.");
749 GMM_ASSERT1(params[0].type() == 1 && params[1].type() == 1,
750 "Bad type of parameters");
751 pintegration_method a = params[0].method();
752 pintegration_method b = params[1].method();
753 GMM_ASSERT1(a->type() == IM_APPROX && b->type() == IM_APPROX,
756 pai = std::make_shared<a_int_pro_integration>(a->approx_method(),
758 pintegration_method p = std::make_shared<integration_method>(pai);
759 dependencies.push_back(p->approx_method()->ref_convex());
760 dependencies.push_back(p->approx_method()->pintegration_points());
764 static pintegration_method
765 product_which(im_param_list ¶ms,
766 std::vector<dal::pstatic_stored_object> &dependencies) {
767 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
768 << params.size() <<
" should be 2.");
769 GMM_ASSERT1(params[0].type() == 1 && params[1].type() == 1,
770 "Bad type of parameters");
771 pintegration_method a = params[0].method();
772 pintegration_method b = params[1].method();
773 if (a->type() == IM_EXACT || b->type() == IM_EXACT)
774 return product_exact(params, dependencies);
775 else return product_approx(params, dependencies);
783 static pintegration_method
784 Newton_Cotes_para(im_param_list ¶ms,
785 std::vector<dal::pstatic_stored_object> &) {
786 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
787 << params.size() <<
" should be 2.");
788 GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
789 "Bad type of parameters");
790 int n = int(::floor(params[0].num() + 0.01));
791 int k = int(::floor(params[1].num() + 0.01));
792 GMM_ASSERT1(n > 0 && n < 100 && k >= 0 && k <= 150 &&
793 double(n) == params[0].num() &&
double(k) == params[1].num(),
796 std::stringstream name;
798 name <<
"IM_NC(1," << k <<
")";
800 name <<
"IM_PRODUCT(IM_NC_PARALLELEPIPED(" << n-1 <<
"," << k
801 <<
"),IM_NC(1," << k <<
"))";
805 static pintegration_method
806 Newton_Cotes_prism(im_param_list ¶ms,
807 std::vector<dal::pstatic_stored_object> &) {
808 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
809 << params.size() <<
" should be 2.");
810 GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
811 "Bad type of parameters");
812 int n = int(::floor(params[0].num() + 0.01));
813 int k = int(::floor(params[1].num() + 0.01));
814 GMM_ASSERT1(n > 1 && n < 100 && k >= 0 && k <= 150 &&
815 double(n) == params[0].num() &&
double(k) == params[1].num(),
818 std::stringstream name;
819 name <<
"IM_PRODUCT(IM_NC(" << n-1 <<
"," << k <<
"),IM_NC(1,"
828 static pintegration_method
829 Gauss_paramul(im_param_list ¶ms,
830 std::vector<dal::pstatic_stored_object> &) {
831 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
832 << params.size() <<
" should be 2.");
833 GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
834 "Bad type of parameters");
835 int n = int(::floor(params[0].num() + 0.01));
836 int k = int(::floor(params[1].num() + 0.01));
837 GMM_ASSERT1(n > 0 && n < 100 && k >= 0 && k <= 150 &&
838 double(n) == params[0].num() &&
double(k) == params[1].num(),
841 std::stringstream name;
843 name <<
"IM_GAUSS1D(" << k <<
")";
845 name <<
"IM_PRODUCT(IM_GAUSS_PARALLELEPIPED(" << n-1 <<
"," << k
846 <<
"),IM_GAUSS1D(" << k <<
"))";
854 struct quasi_polar_integration :
public approx_integration {
855 quasi_polar_integration(papprox_integration base_im,
863 enum { SQUARE, PRISM, TETRA_CYL, PRISM2, PYRAMID } what;
864 if (N == 2) what = SQUARE;
866 what = (ip2 ==
size_type(-1) || ip1 == ip2) ? PRISM2 : PRISM;
871 else GMM_ASSERT1(
false,
"Incoherent integration method");
878 std::vector<base_node> nodes1 = pgt1->convex_ref()->points();
880 std::vector<base_node> nodes2(N+1);
881 if (what == PYRAMID) {
882 pgt2 = bgeot::pyramid_QK_geotrans(1);
885 std::vector<size_type> other_nodes;
887 std::vector<base_node> nodes3(N+1);
891 nodes1[3] = nodes1[1];
892 nodes2[ip1] = nodes1[1]; ip2 = ip1;
893 other_nodes.push_back(0);
894 other_nodes.push_back(2);
897 nodes1[4] = nodes1[0]; nodes1[5] = nodes1[1];
898 nodes2[ip1] = nodes1[0];
899 nodes2[ip2] = nodes1[1];
900 other_nodes.push_back(2);
901 other_nodes.push_back(6);
904 nodes3[0] = nodes1[0]; nodes3[1] = nodes1[1];
905 nodes3[2] = nodes1[2]; nodes3[3] = nodes1[4];
907 nodes2[ip1] = nodes1[1]; ip2 = ip1;
908 other_nodes.push_back(0);
909 other_nodes.push_back(2);
910 other_nodes.push_back(4);
913 nodes2[ip1] = nodes1[4];
914 other_nodes.push_back(0);
915 other_nodes.push_back(1);
916 other_nodes.push_back(2);
920 nodes1[0] = base_node(-1.,-1., 0.);
921 nodes1[1] = base_node( 1.,-1., 0.);
922 nodes1[2] = base_node(-1., 1., 0.);
923 nodes1[3] = base_node( 1., 1., 0.);
924 nodes1[4] = base_node( 0., 0., 1.);
925 nodes1[5] = nodes1[6] = nodes1[7] = nodes1[4];
926 nodes2[ip1] = nodes1[0];
927 other_nodes.push_back(4);
928 other_nodes.push_back(3);
929 other_nodes.push_back(2);
930 other_nodes.push_back(1);
933 for (
size_type i = 0; i <= nodes2.size()-1; ++i)
934 if (i != ip1 && i != ip2) {
935 GMM_ASSERT3(!other_nodes.empty(),
"");
936 nodes2[i] = nodes1[other_nodes.back()];
937 other_nodes.pop_back();
940 base_matrix G1, G2, G3;
941 base_matrix K(N, N), grad(N, N), K3(N, N), K4(N, N);
942 base_node normal1(N), normal2(N);
944 scalar_type J1, J2, J3(1), J4(1);
946 bgeot::vectors_to_base_matrix(G1, nodes1);
947 bgeot::vectors_to_base_matrix(G2, nodes2);
951 if (what == TETRA_CYL) {
952 if (nc == 1) nodes3[0] = nodes1[3];
953 bgeot::vectors_to_base_matrix(G3, nodes3);
954 pgt3->poly_vector_grad(nodes1[0], grad);
955 gmm::mult(gmm::transposed(grad), gmm::transposed(G3), K3);
956 J3 = gmm::abs(gmm::lu_inverse(K3));
959 for (
size_type i=0; i < base_im->nb_points(); ++i) {
961 gmm::copy(gmm::identity_matrix(), K4); J4 = J1 = scalar_type(1);
964 if (i >= base_im->nb_points_on_convex()) {
965 size_type ii = i - base_im->nb_points_on_convex();
966 for (
short_type ff=0; ff < base_im->structure()->nb_faces(); ++ff) {
967 if (ii < base_im->nb_points_on_face(ff)) { fp = ff;
break; }
968 else ii -= base_im->nb_points_on_face(ff);
970 normal1 = base_im->ref_convex()->normals()[fp];
973 base_node P = base_im->point(i);
974 if (what == TETRA_CYL) {
975 P = pgt3->transform(P, nodes3);
976 scalar_type x = P[0], y = P[1], one_minus_z = 1.0 - P[2];
977 K4(0, 1) = - y / one_minus_z;
978 K4(1, 1) = 1.0 - x / one_minus_z;
979 K4(2, 1) = - x * y / gmm::sqr(one_minus_z);
980 J4 = gmm::abs(gmm::lu_det(K4));
981 P[1] *= (1.0 - x / one_minus_z);
983 if (what == PRISM2) {
984 scalar_type x = P[0], y = P[1], one_minus_z = 1.0 - P[2];
985 K4(0,0) = one_minus_z; K4(2,0) = -x;
986 K4(1,1) = one_minus_z; K4(2,1) = -y;
987 J4 = gmm::abs(gmm::lu_det(K4));
992 base_node P1 = pgt1->transform(P, nodes1), P2(N);
993 pgt1->poly_vector_grad(P, grad);
994 gmm::mult(gmm::transposed(grad), gmm::transposed(G1), K);
995 J1 = gmm::abs(gmm::lu_det(K)) * J3 * J4;
997 if (fp !=
size_type(-1) && J1 > 1E-10 && J4 > 1E-10) {
998 if (what == TETRA_CYL) {
1011 GMM_ASSERT1(pgt2->convex_ref()->is_in(P2) < 1E-8,
1012 "Point not in the convex ref : " << P2);
1014 pgt2->poly_vector_grad(P2, grad);
1015 gmm::mult(gmm::transposed(grad), gmm::transposed(G2), K);
1016 J2 = gmm::abs(gmm::lu_det(K));
1018 if (i < base_im->nb_points_on_convex())
1019 add_point(P2, base_im->coeff(i)*J1/J2,
short_type(-1));
1020 else if (J1 > 1E-10) {
1023 if (gmm::abs(pgt2->convex_ref()->is_in_face(ff, P2)) < 1E-8) {
1025 "An integration point is common to two faces");
1030 add_point(P2,base_im->coeff(i)*J1*gmm::vect_norm2(normal1)/J2,f);
1035 if (what != TETRA_CYL)
break;
1042 static pintegration_method
1043 quasi_polar(im_param_list ¶ms,
1044 std::vector<dal::pstatic_stored_object> &dependencies) {
1045 GMM_ASSERT1(params.size() >= 1 && params[0].type() == 1,
1046 "Bad parameters for quasi polar integration: the first "
1047 "parameter should be an integration method");
1048 pintegration_method a = params[0].method();
1049 GMM_ASSERT1(a->type()==IM_APPROX,
"need an approximate integration method");
1050 int ip1 = 0, ip2 = 0;
1052 GMM_ASSERT1(params.size() == 1,
"Bad number of parameters");
1054 GMM_ASSERT1(params.size() == 2 || params.size() == 3,
1055 "Bad number of parameters : " << params.size()
1056 <<
" should be 2 or 3.");
1057 GMM_ASSERT1(params[1].type() == 0
1058 && params.back().type() == 0,
"Bad type of parameters");
1059 ip1 = int(::floor(params[1].num() + 0.01));
1060 ip2 = int(::floor(params.back().num() + 0.01));
1062 int N = a->approx_method()->dim();
1063 GMM_ASSERT1(N >= 2 && N <= 3 && ip1 >= 0 && ip2 >= 0 && ip1 <= N
1064 && ip2 <= N,
"Bad parameters");
1067 pai = std::make_shared<quasi_polar_integration>(a->approx_method(),
1069 pintegration_method p = std::make_shared<integration_method>(pai);
1070 dependencies.push_back(p->approx_method()->ref_convex());
1071 dependencies.push_back(p->approx_method()->pintegration_points());
1075 static pintegration_method
1076 pyramid(im_param_list ¶ms,
1077 std::vector<dal::pstatic_stored_object> &dependencies) {
1078 GMM_ASSERT1(params.size() == 1 && params[0].type() == 1,
1079 "Bad parameters for pyramid integration: the first "
1080 "parameter should be an integration method");
1081 pintegration_method a = params[0].method();
1082 GMM_ASSERT1(a->type()==IM_APPROX,
"need an approximate integration method");
1083 int N = a->approx_method()->dim();
1084 GMM_ASSERT1(N == 3,
"Bad parameters");
1087 pai = std::make_shared<quasi_polar_integration>(a->approx_method(), 0, 0);
1088 pintegration_method p = std::make_shared<integration_method>(pai);
1089 dependencies.push_back(p->approx_method()->ref_convex());
1090 dependencies.push_back(p->approx_method()->pintegration_points());
1101 structured_composite_int_method(im_param_list &,
1102 std::vector<dal::pstatic_stored_object> &);
1103 pintegration_method HCT_composite_int_method(im_param_list ¶ms,
1104 std::vector<dal::pstatic_stored_object> &dependencies);
1106 pintegration_method QUADC1_composite_int_method(im_param_list ¶ms,
1107 std::vector<dal::pstatic_stored_object> &dependencies);
1109 pintegration_method pyramid_composite_int_method(im_param_list ¶ms,
1110 std::vector<dal::pstatic_stored_object> &dependencies);
1113 im_naming_system() :
dal::naming_system<integration_method>(
"IM") {
1115 add_suffix(
"EXACT_SIMPLEX", exact_simplex);
1116 add_suffix(
"PRODUCT", product_which);
1117 add_suffix(
"EXACT_PARALLELEPIPED",exact_parallelepiped);
1118 add_suffix(
"EXACT_PRISM", exact_prism);
1119 add_suffix(
"GAUSS1D", gauss1d);
1120 add_suffix(
"NC", Newton_Cotes);
1121 add_suffix(
"NC_PARALLELEPIPED", Newton_Cotes_para);
1122 add_suffix(
"NC_PRISM", Newton_Cotes_prism);
1123 add_suffix(
"GAUSS_PARALLELEPIPED", Gauss_paramul);
1124 add_suffix(
"QUASI_POLAR", quasi_polar);
1125 add_suffix(
"PYRAMID", pyramid);
1126 add_suffix(
"STRUCTURED_COMPOSITE",
1127 structured_composite_int_method);
1128 add_suffix(
"HCT_COMPOSITE",
1129 HCT_composite_int_method);
1130 add_suffix(
"QUADC1_COMPOSITE",
1131 QUADC1_composite_int_method);
1132 add_suffix(
"PYRAMID_COMPOSITE",
1133 pyramid_composite_int_method);
1134 add_generic_function(im_list_integration);
1139 bool throw_if_not_found) {
1142 (name, i, throw_if_not_found);
1146 if (!(p.get()))
return "IM_NONE";
1151 void add_integration_name(std::string name,
1160 THREAD_SAFE_STATIC pintegration_method pim =
nullptr;
1163 std::stringstream name;
1164 name <<
"IM_EXACT_SIMPLEX(" << n <<
")";
1172 THREAD_SAFE_STATIC pintegration_method pim =
nullptr;
1175 std::stringstream name;
1176 name <<
"IM_EXACT_PARALLELEPIPED(" << n <<
")";
1184 THREAD_SAFE_STATIC pintegration_method pim =
nullptr;
1187 std::stringstream name;
1188 name <<
"IM_EXACT_PRISM(" << n <<
")";
1202 THREAD_SAFE_STATIC pintegration_method im_last =
nullptr;
1205 if (cvs_last == cvs)
1210 std::stringstream name;
1216 { name <<
"IM_EXACT_SIMPLEX("; found =
true; }
1220 if (!found && nbp == (
size_type(1) << n))
1222 { name <<
"IM_EXACT_PARALLELEPIPED("; found =
true; }
1226 if (!found && nbp == 2 * n)
1228 { name <<
"IM_EXACT_PRISM("; found =
true; }
1233 name << int(n) <<
')';
1239 GMM_ASSERT1(
false,
"This element is not taken into account. Contact us");
1247 static pintegration_method
1250 std::stringstream name;
1252 if(bgeot::is_torus_structure(cvs) && n == 3) n = 2;
1254 degree = std::max<dim_type>(degree, 1);
1260 case 1: name <<
"IM_GAUSS1D";
break;
1261 case 2: name <<
"IM_TRIANGLE";
break;
1262 case 3: name <<
"IM_TETRAHEDRON";
break;
1263 case 4: name <<
"IM_SIMPLEX4D";
break;
1264 default: GMM_ASSERT1(
false,
"no approximate integration method "
1265 "for simplexes of dimension " << n);
1268 std::stringstream name2;
1269 name2 << name.str() <<
"(" << k <<
")";
1273 GMM_ASSERT1(
false,
"could not find an " << name.str()
1274 <<
" of degree >= " <<
int(degree));
1276 GMM_ASSERT1(n == 3,
"Wrong dimension");
1277 name <<
"IM_PYRAMID(IM_GAUSS_PARALLELEPIPED(3," << degree <<
"))";
1278 }
else if (cvs->is_product(&a,&b) ||
1281 name <<
"IM_PRODUCT("
1284 }
else GMM_ASSERT1(
false,
"unknown convex structure!");
1291 THREAD_SAFE_STATIC dim_type degree_last;
1292 THREAD_SAFE_STATIC pintegration_method im_last =
nullptr;
1293 if (pgt_last == pgt && degree == degree_last)
1295 im_last = classical_approx_im_(pgt->structure(),degree);
1296 degree_last = degree;
1302 THREAD_SAFE_STATIC pintegration_method im_last =
nullptr;
1309 scalar_type test_integration_error(papprox_integration pim, dim_type order) {
1312 opt_long_scalar_type error(0);
1314 opt_long_scalar_type sum(0), realsum;
1315 for (
size_type i=0; i < pim->nb_points_on_convex(); ++i) {
1316 opt_long_scalar_type prod = pim->coeff(i);
1318 prod *= pow(opt_long_scalar_type(pim->point(i)[d]), idx[d]);
1321 realsum = exact->exact_method()->int_monomial(idx);
1322 error = std::max(error, gmm::abs(realsum-sum));
1324 return bgeot::to_scalar(error);
1327 papprox_integration get_approx_im_or_fail(pintegration_method pim) {
1328 GMM_ASSERT1(pim->type() == IM_APPROX,
"error estimate work only with "
1329 "approximate integration methods");
1330 return pim->approx_method();
Inversion of geometric transformations.
does the inversion of the geometric transformation for a given convex
generation of permutations, and ranking/unranking of these.
Vector of integer (16 bits type) which represent the powers of a monomial.
short_type degree() const
Gives the degree.
Associate a name to a method descriptor and store method descriptors.
static T & instance()
Instance from the current thread.
Description of an exact integration of polynomials.
long_scalar_type int_poly(const base_poly &P) const
Evaluate the integral of the polynomial P on the reference element.
bgeot::pconvex_structure structure(void) const
{Structure of convex of reference.
long_scalar_type int_poly_on_face(const base_poly &P, short_type f) const
Evaluate the integral of the polynomial P on the face f of the reference element.
A simple singleton implementation.
This file is generated by cubature/make_getfem_list.
Integration methods (exact and approximated) on convexes.
Tools for multithreaded, OpenMP and Boost based parallelization.
Provides mesh and mesh fem of torus.
void copy(const L1 &l1, L2 &l2)
*/
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2(const V &v)
Euclidean norm of a vector.
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*/
LU factorizations and determinant computation for dense matrices.
void lu_inverse(const DenseMatrixLU &LU, const Pvector &pvector, const DenseMatrix &AInv_)
Given an LU factored matrix, build the inverse of the matrix.
void lu_solve(const DenseMatrix &LU, const Pvector &pvector, VectorX &x, const VectorB &b)
LU Solve : Solve equation Ax=b, given an LU factored matrix.
pconvex_ref convex_ref_product(pconvex_ref a, pconvex_ref b)
tensorial product of two convex ref.
gmm::uint16_type short_type
used as the common short type integer in the library
pconvex_structure pyramid_QK_structure(dim_type k)
Give a pointer on the 3D pyramid structure for a degree k = 1 or 2.
pconvex_ref pyramid_QK_of_reference(dim_type k)
pyramidal element of reference of degree k (k = 1 or 2 only)
pconvex_ref simplex_of_reference(dim_type nc, short_type K)
returns a simplex of reference of dimension nc and degree k
std::shared_ptr< const convex_structure > pconvex_structure
Pointer on a convex structure description.
pconvex_structure parallelepiped_structure(dim_type nc, dim_type k)
Give a pointer on the structures of a parallelepiped of dimension d.
pconvex_structure prism_P1_structure(dim_type nc)
Give a pointer on the structures of a prism of dimension d.
pconvex_structure simplex_structure(dim_type nc)
Give a pointer on the structures of a simplex of dimension d.
pgeometric_trans geometric_trans_descriptor(std::string name)
Get the geometric transformation from its string name.
size_t size_type
used as the common size type in the library
pconvex_structure convex_product_structure(pconvex_structure a, pconvex_structure b)
Give a pointer on the structures of a convex which is the direct product of the convexes represented ...
pconvex_structure basic_structure(pconvex_structure cv)
Original structure (if concerned)
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation
size_type alpha(short_type n, short_type d)
Return the value of which is the number of monomials of a polynomial of variables and degree .
GEneric Tool for Finite Element Methods.
pintegration_method exact_parallelepiped_im(size_type n)
return IM_EXACT_PARALLELEPIPED(n)
std::string name_of_int_method(pintegration_method p)
Get the string name of an integration method .
pintegration_method exact_simplex_im(size_type n)
return IM_EXACT_SIMPLEX(n)
pintegration_method exact_prism_im(size_type n)
return IM_EXACT_PRISM(n)
pintegration_method classical_approx_im(bgeot::pgeometric_trans pgt, dim_type degree)
try to find an approximate integration method for the geometric transformation pgt which is able to i...
pintegration_method classical_exact_im(bgeot::pgeometric_trans pgt)
return an exact integration method for convex type handled by pgt.
pintegration_method exact_classical_im(bgeot::pgeometric_trans pgt) IS_DEPRECATED
use classical_exact_im instead.
pintegration_method int_method_descriptor(std::string name, bool throw_if_not_found=true)
Get an integration method from its name .
pintegration_method im_none(void)
return IM_NONE