25 #include "getfem/bgeot_permutations.h"
37 static pintegration_method
im_none(im_param_list ¶ms,
38 std::vector<dal::pstatic_stored_object> &) {
39 GMM_ASSERT1(params.size() == 0,
"IM_NONE does not accept any parameter");
40 return std::make_shared<integration_method>();
44 long_scalar_type res = 0.0;
45 if (P.size() > int_monomials.size()) {
46 std::vector<long_scalar_type> *hum = &int_monomials;
47 size_type i = P.size(), j = int_monomials.size();
51 (*hum)[k-1] = int_monomial(mi);
53 base_poly::const_iterator it = P.begin(), ite = P.end();
54 std::vector<long_scalar_type>::const_iterator itb = int_monomials.begin();
55 for ( ; it != ite; ++it, ++itb) {
56 res += long_scalar_type(*it) * long_scalar_type(*itb);
63 long_scalar_type res = 0.0;
64 std::vector<long_scalar_type> *hum = &(int_face_monomials[f]);
65 if (P.size() > hum->size()) {
70 (*hum)[k-1] = int_monomial_on_face(mi, f);
72 base_poly::const_iterator it = P.begin(), ite = P.end();
73 std::vector<long_scalar_type>::const_iterator itb = hum->begin();
74 for ( ; it != ite; ++it, ++itb)
75 res += long_scalar_type(*it) * long_scalar_type(*itb);
91 { cvs = c; int_face_monomials.resize(c->nb_faces()); }
97 long_scalar_type res = LONG_SCAL(1);
99 bgeot::power_index::const_iterator itm = power.begin(),
101 for ( ; itm != itme; ++itm)
102 for (
int k = 1; k <= *itm; ++k, ++fa)
103 res *= long_scalar_type(k) / long_scalar_type(fa);
105 for (
int k = 0; k < cvs->dim(); k++) { res /= long_scalar_type(fa); fa++; }
109 long_scalar_type simplex_poly_integration_::int_monomial_on_face
111 long_scalar_type res = LONG_SCAL(0);
113 if (f == 0 || power[f-1] == 0.0) {
114 res = (f == 0) ? sqrt(long_scalar_type(cvs->dim())) : LONG_SCAL(1);
116 bgeot::power_index::const_iterator itm = power.begin(),
118 for ( ; itm != itme; ++itm)
119 for (
int k = 1; k <= *itm; ++k, ++fa)
120 res *= long_scalar_type(k) / long_scalar_type(fa);
122 for (
int k = 1; k < cvs->dim(); k++) { res/=long_scalar_type(fa); fa++; }
127 static pintegration_method
128 exact_simplex(im_param_list ¶ms,
129 std::vector<dal::pstatic_stored_object> &dependencies) {
130 GMM_ASSERT1(params.size() == 1,
"Bad number of parameters : "
131 << params.size() <<
" should be 1.");
132 GMM_ASSERT1(params[0].type() == 0,
"Bad type of parameters");
133 int n = int(::floor(params[0].num() + 0.01));
134 GMM_ASSERT1(n > 0 && n < 100 &&
double(n) == params[0].num(),
137 ppoly_integration ppi = std::make_shared<simplex_poly_integration_>
139 return std::make_shared<integration_method>(ppi);
146 struct plyint_mul_structure_ :
public poly_integration {
147 ppoly_integration cv1, cv2;
154 plyint_mul_structure_(ppoly_integration a, ppoly_integration b);
157 long_scalar_type plyint_mul_structure_::int_monomial
160 std::copy(power.begin(), power.begin() + cv1->dim(), mi1.begin());
161 std::copy(power.begin() + cv1->dim(), power.end(), mi2.begin());
162 return cv1->int_monomial(mi1) * cv2->int_monomial(mi2);
165 long_scalar_type plyint_mul_structure_::int_monomial_on_face
168 std::copy(power.begin(), power.begin() + cv1->dim(), mi1.begin());
169 std::copy(power.begin() + cv1->dim(), power.end(), mi2.begin());
170 short_type nfx = cv1->structure()->nb_faces();
172 return cv1->int_monomial_on_face(mi1,f) * cv2->int_monomial(mi2);
174 return cv1->int_monomial(mi1)
175 * cv2->int_monomial_on_face(mi2,
short_type(f-nfx));
178 plyint_mul_structure_::plyint_mul_structure_(ppoly_integration a,
179 ppoly_integration b) {
183 int_face_monomials.resize(cvs->nb_faces());
186 static pintegration_method
187 product_exact(im_param_list ¶ms,
188 std::vector<dal::pstatic_stored_object> &dependencies) {
189 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
190 << params.size() <<
" should be 2.");
191 GMM_ASSERT1(params[0].type() == 1 && params[1].type() == 1,
192 "Bad type of parameters");
193 pintegration_method a = params[0].method();
194 pintegration_method b = params[1].method();
195 GMM_ASSERT1(a->type() == IM_EXACT && b->type() == IM_EXACT,
197 dependencies.push_back(a); dependencies.push_back(b);
200 ppoly_integration ppi = std::make_shared<plyint_mul_structure_>
201 (a->exact_method(), b->exact_method());
202 return std::make_shared<integration_method>(ppi);
209 static pintegration_method
210 exact_parallelepiped(im_param_list ¶ms,
211 std::vector<dal::pstatic_stored_object> &) {
212 GMM_ASSERT1(params.size() == 1,
"Bad number of parameters : "
213 << params.size() <<
" should be 1.");
214 GMM_ASSERT1(params[0].type() == 0,
"Bad type of parameters");
215 int n = int(::floor(params[0].num() + 0.01));
216 GMM_ASSERT1(n > 0 && n < 100 &&
double(n) == params[0].num(),
219 std::stringstream name;
221 name <<
"IM_EXACT_SIMPLEX(1)";
223 name <<
"IM_PRODUCT(IM_EXACT_PARALLELEPIPED(" << n-1
224 <<
"),IM_EXACT_SIMPLEX(1)))";
228 static pintegration_method
229 exact_prism(im_param_list ¶ms,
230 std::vector<dal::pstatic_stored_object> &) {
231 GMM_ASSERT1(params.size() == 1,
"Bad number of parameters : "
232 << params.size() <<
" should be 1.");
233 GMM_ASSERT1(params[0].type() == 0,
"Bad type of parameters");
234 int n = int(::floor(params[0].num() + 0.01));
235 GMM_ASSERT1(n > 1 && n < 100 &&
double(n) == params[0].num(),
238 std::stringstream name;
239 name <<
"IM_PRODUCT(IM_EXACT_SIMPLEX(" << n-1
240 <<
"),IM_EXACT_SIMPLEX(1))";
248 void approx_integration::add_point(
const base_node &pt,
251 bool include_empty) {
252 GMM_ASSERT1(!valid,
"Impossible to modify a valid integration method.");
253 if (gmm::abs(w) > 1.0E-15 || include_empty) {
255 if (gmm::abs(w) <= 1.0E-15) w = scalar_type(0);
256 GMM_ASSERT1(f <= cvr->structure()->nb_faces(),
"Wrong argument.");
257 size_type i = pt_to_store[f].search_node(pt);
259 i = pt_to_store[f].add_node(pt);
260 int_coeffs.resize(int_coeffs.size() + 1);
261 for (
size_type j = f; j <= cvr->structure()->nb_faces(); ++j)
263 for (
size_type j = int_coeffs.size(); j > repartition[f]; --j)
264 int_coeffs[j-1] = int_coeffs[j-2];
265 int_coeffs[repartition[f]-1] = 0.0;
267 int_coeffs[((f == 0) ? 0 : repartition[f-1]) + i] += w;
271 void approx_integration::add_point_norepeat(
const base_node &pt,
275 if (pt_to_store[f2].search_node(pt) ==
size_type(-1)) add_point(pt,w,f);
278 void approx_integration::add_point_full_symmetric(base_node pt,
280 dim_type n = cvr->structure()->dim();
283 if (n+1 == cvr->structure()->nb_faces()) {
288 std::copy(pt.begin(), pt.end(), pt3.begin());
289 pt3[n] = 1;
for (k = 0; k < n; ++k) pt3[n] -= pt[k];
290 std::vector<int> ind(n); std::fill(ind.begin(), ind.end(), 0);
291 std::vector<bool> ind2(n+1);
294 std::fill(ind2.begin(), ind2.end(),
false);
296 for (k = 0; k < n; ++k)
297 if (ind2[ind[k]]) { good =
false;
break; }
else ind2[ind[k]] =
true;
299 for (k = 0; k < n; ++k) pt2[k] = pt3[ind[k]];
300 add_point_norepeat(pt2, w);
303 while(ind[k] == n+1) { ind[k++] = 0;
if (k == n)
return; ind[k]++; }
307 else if (cvr->structure()->nb_points() == (
size_type(1) << n)) {
310 for (k = 0; k < n; ++k)
311 if (i & (
size_type(1) << k)) pt2[k]=pt[k];
else pt2[k] = 1.0-pt[k];
312 add_point_norepeat(pt2, w);
316 GMM_ASSERT1(
false,
"Fully symmetric option is only valid for"
317 "simplices and parallelepipedic elements");
320 void approx_integration::add_method_on_face(pintegration_method ppi,
322 papprox_integration pai = ppi->approx_method();
323 GMM_ASSERT1(!valid,
"Impossible to modify a valid integration method.");
324 GMM_ASSERT1(*key_of_stored_object(pai->structure())
325 == *key_of_stored_object(structure()->faces_structure()[f]),
326 "structures missmatch");
327 GMM_ASSERT1(ppi->type() == IM_APPROX,
"Impossible with an exact method.");
329 dim_type N = pai->structure()->dim();
330 scalar_type det = 1.0;
332 std::vector<base_node> pts(N);
334 pts[i] = (cvr->dir_points_of_face(f))[i+1]
335 - (cvr->dir_points_of_face(f))[0];
337 base_matrix a(N+1, N), b(N, N), tmp(N, N);
338 for (dim_type i = 0; i < N+1; ++i)
339 for (dim_type j = 0; j < N; ++j)
343 det = ::sqrt(gmm::abs(gmm::lu_det(b)));
345 for (
size_type i = 0; i < pai->nb_points_on_convex(); ++i) {
346 pt = (cvr->dir_points_of_face(f))[0];
347 for (dim_type j = 0; j < N; ++j)
348 pt += pts[j] * ((*(pai->pintegration_points()))[i])[j];
349 add_point(pt, pai->coeff(i) * det, f);
353 void approx_integration::valid_method() {
354 std::vector<base_node> ptab(int_coeffs.size());
357 for (
short_type f = 0; f <= cvr->structure()->nb_faces(); ++f) {
359 for (PT_TAB::const_iterator it = pt_to_store[f].begin();
360 it != pt_to_store[f].end(); ++it ) {
365 GMM_ASSERT1(i == int_coeffs.size(),
"internal error.");
366 pint_points = bgeot::store_point_tab(ptab);
367 pt_to_store = std::vector<PT_TAB>();
377 static pintegration_method
378 im_list_integration(std::string name,
379 std::vector<dal::pstatic_stored_object> &dependencies) {
381 for (
int i = 0; i < NB_IM; ++i)
382 if (!name.compare(im_desc_tab[i].method_name)) {
385 dim_type N = pgt->structure()->dim();
387 auto pai = std::make_shared<approx_integration>(pgt->convex_ref());
389 for (
size_type j = 0; j < im_desc_tab[i].nb_points; ++j) {
390 for (dim_type k = 0; k < N; ++k)
391 pt[k] = atof(im_desc_real[fr+j*(N+1)+k]);
394 switch (im_desc_node_type[im_desc_tab[i].firsttype + j]) {
396 base_node pt2(pt.size());
399 pai->add_point_full_symmetric(pt2,
400 atof(im_desc_real[fr+j*(N+1)+N]));
406 pai->add_point_full_symmetric(pt,atof(im_desc_real[fr+j*(N+1)+N]));
411 pai->add_point(pt, atof(im_desc_real[fr+j*(N+1)+N]));
414 default: GMM_ASSERT1(
false,
"");
418 for (
short_type f = 0; N > 0 && f < pgt->structure()->nb_faces(); ++f)
419 pai->add_method_on_face
421 (im_desc_face_meth[im_desc_tab[i].firstface + f]), f);
426 pintegration_method p(std::make_shared<integration_method>(pai));
427 dependencies.push_back(p->approx_method()->ref_convex());
428 dependencies.push_back(p->approx_method()->pintegration_points());
431 return pintegration_method();
439 struct Legendre_polynomials {
440 std::vector<base_poly> polynomials;
441 std::vector<std::vector<long_scalar_type>> roots;
443 Legendre_polynomials() : nb_lp(-1) {}
445 polynomials.resize(de+2);
448 polynomials[0] = base_poly(1,0);
449 polynomials[0].one();
450 polynomials[1] = base_poly(1,1,0);
458 (base_poly(1,1,0) * polynomials[nb_lp-1]
459 * ((2.0 * long_scalar_type(nb_lp) - 1.0) / long_scalar_type(nb_lp)))
460 + (polynomials[nb_lp-2]
461 * ((1.0 - long_scalar_type(nb_lp)) / long_scalar_type(nb_lp)));
462 roots[nb_lp].resize(nb_lp);
463 roots[nb_lp][nb_lp/2] = 0.0;
464 long_scalar_type a = -1.0, b, c, d, e, cv, ev, ecart, ecart2;
465 for (
int k = 0; k < nb_lp / 2; ++k) {
466 b = roots[nb_lp-1][k];
469 cv = polynomials[nb_lp].eval(&c);
471 ecart = 2.0 * (d - c);
473 --imax;
if (imax == 0)
break;
475 ecart2 = d - c;
if (ecart2 >= ecart)
break;
477 ev = polynomials[nb_lp].eval(&e);
478 if (ev * cv < 0.) { d = e; }
else { c = e; cv = ev; }
482 roots[nb_lp][nb_lp-k-1] = -c;
489 struct gauss_approx_integration_ :
public approx_integration {
493 gauss_approx_integration_::gauss_approx_integration_(
short_type nbpt) {
494 GMM_ASSERT1(nbpt <= 32000,
"too much points");
497 std::vector<base_node> int_points(nbpt+2);
498 int_coeffs.resize(nbpt+2);
499 repartition.resize(3);
500 repartition[0] = nbpt;
501 repartition[1] = nbpt + 1;
502 repartition[2] = nbpt + 2;
504 Legendre_polynomials Lp;
508 int_points[i].resize(1);
509 long_scalar_type lr = Lp.roots[nbpt][i];
510 int_points[i][0] = 0.5 + 0.5 * bgeot::to_scalar(lr);
511 int_coeffs[i] = bgeot::to_scalar((1.0 - gmm::sqr(lr))
512 / gmm::sqr( long_scalar_type(nbpt)
513 * (Lp.polynomials[nbpt-1].eval(&lr))));
516 int_points[nbpt].resize(1);
517 int_points[nbpt][0] = 1.0; int_coeffs[nbpt] = 1.0;
519 int_points[nbpt+1].resize(1);
520 int_points[nbpt+1][0] = 0.0; int_coeffs[nbpt+1] = 1.0;
521 pint_points = bgeot::store_point_tab(int_points);
526 static pintegration_method
527 gauss1d(im_param_list ¶ms,
528 std::vector<dal::pstatic_stored_object> &dependencies) {
529 GMM_ASSERT1(params.size() == 1,
"Bad number of parameters : "
530 << params.size() <<
" should be 1.");
531 GMM_ASSERT1(params[0].type() == 0,
"Bad type of parameters");
532 int n = int(::floor(params[0].num() + 0.01));
533 GMM_ASSERT1(n >= 0 && n < 32000 &&
double(n) == params[0].num(),
536 std::stringstream name;
537 name <<
"IM_GAUSS1D(" << n-1 <<
")";
542 pai = std::make_shared<gauss_approx_integration_>(
short_type(n/2 + 1));
543 pintegration_method p = std::make_shared<integration_method>(pai);
544 dependencies.push_back(p->approx_method()->ref_convex());
545 dependencies.push_back(p->approx_method()->pintegration_points());
554 struct Newton_Cotes_approx_integration_ :
public approx_integration
557 Newton_Cotes_approx_integration_(dim_type nc,
short_type k);
560 Newton_Cotes_approx_integration_::Newton_Cotes_approx_integration_
567 add_point(c, scalar_type(1));
569 std::stringstream name;
570 name <<
"IM_EXACT_SIMPLEX(" << int(nc) <<
")";
573 c.fill(scalar_type(0.0));
575 c.fill(1.0 / scalar_type(nc+1));
577 gmm::dense_matrix<long_scalar_type> M(R, R);
578 std::vector<long_scalar_type> F(R), U(R);
579 std::vector<bgeot::power_index> base(R);
580 std::vector<base_node> nodes(R);
585 if (k != 0 && nc > 0)
586 for (
size_type r = 0; r < R; ++r, ++pi) {
590 c[l] += 1.0 / scalar_type(k);
593 sum -= int(floor(0.5+(c[l] * k)));
597 c[l] += 1.0 / scalar_type(k);
602 for (
size_type r = 0; r < R; ++r, ++pi) {
620 F[r] = ppi->int_monomial(base[r]);
634 M(r, q) = bgeot::eval_monomial(base[r], nodes[q].begin());
640 add_point(nodes[r], bgeot::to_scalar(U[r]));
642 std::stringstream name2;
643 name2 <<
"IM_NC(" << int(nc-1) <<
"," << int(k) <<
")";
650 static pintegration_method
651 Newton_Cotes(im_param_list ¶ms,
652 std::vector<dal::pstatic_stored_object> &dependencies) {
653 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
654 << params.size() <<
" should be 2.");
655 GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
656 "Bad type of parameters");
657 int n = int(::floor(params[0].num() + 0.01));
658 int k = int(::floor(params[1].num() + 0.01));
659 GMM_ASSERT1(n >= 0 && n < 100 && k >= 0 && k <= 150 &&
660 double(n) == params[0].num() &&
double(k) == params[1].num(),
663 pai = std::make_shared<Newton_Cotes_approx_integration_>(dim_type(n),
665 pintegration_method p = std::make_shared<integration_method>(pai);
666 dependencies.push_back(p->approx_method()->ref_convex());
667 dependencies.push_back(p->approx_method()->pintegration_points());
675 struct a_int_pro_integration :
public approx_integration
677 a_int_pro_integration(papprox_integration a, papprox_integration b);
681 a_int_pro_integration::a_int_pro_integration(papprox_integration a,
682 papprox_integration b) {
686 std::vector<base_node> int_points;
687 int_points.resize(n1 * n2);
688 int_coeffs.resize(n1 * n2);
689 repartition.resize(cvr->structure()->nb_faces()+1);
690 repartition[0] = n1 * n2;
693 int_coeffs[i1 + i2 * n1] = a->coeff(i1) * b->coeff(i2);
694 int_points[i1 + i2 * n1].resize(dim());
695 std::copy(a->point(i1).begin(), a->point(i1).end(),
696 int_points[i1 + i2 * n1].begin());
697 std::copy(b->point(i2).begin(), b->point(i2).end(),
698 int_points[i1 + i2 * n1].begin() + a->dim());
701 for (
short_type f1 = 0; f1 < a->structure()->nb_faces(); ++f1, ++f) {
702 n1 = a->nb_points_on_face(f1);
703 n2 = b->nb_points_on_convex();
705 repartition[f+1] = w + n1 * n2;
706 int_points.resize(repartition[f+1]);
707 int_coeffs.resize(repartition[f+1]);
710 int_coeffs[w + i1 + i2 * n1] = a->coeff_on_face(f1, i1)
712 int_points[w + i1 + i2 * n1].resize(dim());
713 std::copy(a->point_on_face(f1, i1).begin(),
714 a->point_on_face(f1, i1).end(),
715 int_points[w + i1 + i2 * n1].begin());
716 std::copy(b->point(i2).begin(), b->point(i2).end(),
717 int_points[w + i1 + i2 * n1].begin() + a->dim());
720 for (
short_type f2 = 0; f2 < b->structure()->nb_faces(); ++f2, ++f) {
721 n1 = a->nb_points_on_convex();
722 n2 = b->nb_points_on_face(f2);
724 repartition[f+1] = w + n1 * n2;
725 int_points.resize(repartition[f+1]);
726 int_coeffs.resize(repartition[f+1]);
729 int_coeffs[w + i1 + i2 * n1] = a->coeff(i1)
730 * b->coeff_on_face(f2, i2);
731 int_points[w + i1 + i2 * n1].resize(dim());
732 std::copy(a->point(i1).begin(), a->point(i1).end(),
733 int_points[w + i1 + i2 * n1].begin());
734 std::copy(b->point_on_face(f2, i2).begin(),
735 b->point_on_face(f2, i2).end(),
736 int_points[w + i1 + i2 * n1].begin() + a->dim());
739 pint_points = bgeot::store_point_tab(int_points);
743 static pintegration_method
744 product_approx(im_param_list ¶ms,
745 std::vector<dal::pstatic_stored_object> &dependencies) {
746 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
747 << params.size() <<
" should be 2.");
748 GMM_ASSERT1(params[0].type() == 1 && params[1].type() == 1,
749 "Bad type of parameters");
750 pintegration_method a = params[0].method();
751 pintegration_method b = params[1].method();
752 GMM_ASSERT1(a->type() == IM_APPROX && b->type() == IM_APPROX,
755 pai = std::make_shared<a_int_pro_integration>(a->approx_method(),
757 pintegration_method p = std::make_shared<integration_method>(pai);
758 dependencies.push_back(p->approx_method()->ref_convex());
759 dependencies.push_back(p->approx_method()->pintegration_points());
763 static pintegration_method
764 product_which(im_param_list ¶ms,
765 std::vector<dal::pstatic_stored_object> &dependencies) {
766 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
767 << params.size() <<
" should be 2.");
768 GMM_ASSERT1(params[0].type() == 1 && params[1].type() == 1,
769 "Bad type of parameters");
770 pintegration_method a = params[0].method();
771 pintegration_method b = params[1].method();
772 if (a->type() == IM_EXACT || b->type() == IM_EXACT)
773 return product_exact(params, dependencies);
774 else return product_approx(params, dependencies);
782 static pintegration_method
783 Newton_Cotes_para(im_param_list ¶ms,
784 std::vector<dal::pstatic_stored_object> &) {
785 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
786 << params.size() <<
" should be 2.");
787 GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
788 "Bad type of parameters");
789 int n = int(::floor(params[0].num() + 0.01));
790 int k = int(::floor(params[1].num() + 0.01));
791 GMM_ASSERT1(n > 0 && n < 100 && k >= 0 && k <= 150 &&
792 double(n) == params[0].num() &&
double(k) == params[1].num(),
795 std::stringstream name;
797 name <<
"IM_NC(1," << k <<
")";
799 name <<
"IM_PRODUCT(IM_NC_PARALLELEPIPED(" << n-1 <<
"," << k
800 <<
"),IM_NC(1," << k <<
"))";
804 static pintegration_method
805 Newton_Cotes_prism(im_param_list ¶ms,
806 std::vector<dal::pstatic_stored_object> &) {
807 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
808 << params.size() <<
" should be 2.");
809 GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
810 "Bad type of parameters");
811 int n = int(::floor(params[0].num() + 0.01));
812 int k = int(::floor(params[1].num() + 0.01));
813 GMM_ASSERT1(n > 1 && n < 100 && k >= 0 && k <= 150 &&
814 double(n) == params[0].num() &&
double(k) == params[1].num(),
817 std::stringstream name;
818 name <<
"IM_PRODUCT(IM_NC(" << n-1 <<
"," << k <<
"),IM_NC(1,"
827 static pintegration_method
828 Gauss_paramul(im_param_list ¶ms,
829 std::vector<dal::pstatic_stored_object> &) {
830 GMM_ASSERT1(params.size() == 2,
"Bad number of parameters : "
831 << params.size() <<
" should be 2.");
832 GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
833 "Bad type of parameters");
834 int n = int(::floor(params[0].num() + 0.01));
835 int k = int(::floor(params[1].num() + 0.01));
836 GMM_ASSERT1(n > 0 && n < 100 && k >= 0 && k <= 150 &&
837 double(n) == params[0].num() &&
double(k) == params[1].num(),
840 std::stringstream name;
842 name <<
"IM_GAUSS1D(" << k <<
")";
844 name <<
"IM_PRODUCT(IM_GAUSS_PARALLELEPIPED(" << n-1 <<
"," << k
845 <<
"),IM_GAUSS1D(" << k <<
"))";
853 struct quasi_polar_integration :
public approx_integration {
854 quasi_polar_integration(papprox_integration base_im,
862 enum { SQUARE, PRISM, TETRA_CYL, PRISM2, PYRAMID } what;
863 if (N == 2) what = SQUARE;
865 what = (ip2 ==
size_type(-1) || ip1 == ip2) ? PRISM2 : PRISM;
870 else GMM_ASSERT1(
false,
"Incoherent integration method");
877 std::vector<base_node> nodes1 = pgt1->convex_ref()->points();
879 std::vector<base_node> nodes2(N+1);
880 if (what == PYRAMID) {
881 pgt2 = bgeot::pyramid_QK_geotrans(1);
884 std::vector<size_type> other_nodes;
886 std::vector<base_node> nodes3(N+1);
890 nodes1[3] = nodes1[1];
891 nodes2[ip1] = nodes1[1]; ip2 = ip1;
892 other_nodes.push_back(0);
893 other_nodes.push_back(2);
896 nodes1[4] = nodes1[0]; nodes1[5] = nodes1[1];
897 nodes2[ip1] = nodes1[0];
898 nodes2[ip2] = nodes1[1];
899 other_nodes.push_back(2);
900 other_nodes.push_back(6);
903 nodes3[0] = nodes1[0]; nodes3[1] = nodes1[1];
904 nodes3[2] = nodes1[2]; nodes3[3] = nodes1[4];
906 nodes2[ip1] = nodes1[1]; ip2 = ip1;
907 other_nodes.push_back(0);
908 other_nodes.push_back(2);
909 other_nodes.push_back(4);
912 nodes2[ip1] = nodes1[4];
913 other_nodes.push_back(0);
914 other_nodes.push_back(1);
915 other_nodes.push_back(2);
919 nodes1[0] = base_node(-1.,-1., 0.);
920 nodes1[1] = base_node( 1.,-1., 0.);
921 nodes1[2] = base_node(-1., 1., 0.);
922 nodes1[3] = base_node( 1., 1., 0.);
923 nodes1[4] = base_node( 0., 0., 1.);
924 nodes1[5] = nodes1[6] = nodes1[7] = nodes1[4];
925 nodes2[ip1] = nodes1[0];
926 other_nodes.push_back(4);
927 other_nodes.push_back(3);
928 other_nodes.push_back(2);
929 other_nodes.push_back(1);
932 for (
size_type i = 0; i <= nodes2.size()-1; ++i)
933 if (i != ip1 && i != ip2) {
934 GMM_ASSERT3(!other_nodes.empty(),
"");
935 nodes2[i] = nodes1[other_nodes.back()];
936 other_nodes.pop_back();
939 base_matrix G1, G2, G3;
940 base_matrix K(N, N), grad(N, N), K3(N, N), K4(N, N);
941 base_node normal1(N), normal2(N);
943 scalar_type J1, J2, J3(1), J4(1);
945 bgeot::vectors_to_base_matrix(G1, nodes1);
946 bgeot::vectors_to_base_matrix(G2, nodes2);
950 if (what == TETRA_CYL) {
951 if (nc == 1) nodes3[0] = nodes1[3];
952 bgeot::vectors_to_base_matrix(G3, nodes3);
953 pgt3->poly_vector_grad(nodes1[0], grad);
954 gmm::mult(gmm::transposed(grad), gmm::transposed(G3), K3);
955 J3 = gmm::abs(gmm::lu_inverse(K3));
958 for (
size_type i=0; i < base_im->nb_points(); ++i) {
960 gmm::copy(gmm::identity_matrix(), K4); J4 = J1 = scalar_type(1);
963 if (i >= base_im->nb_points_on_convex()) {
964 size_type ii = i - base_im->nb_points_on_convex();
965 for (
short_type ff=0; ff < base_im->structure()->nb_faces(); ++ff) {
966 if (ii < base_im->nb_points_on_face(ff)) { fp = ff;
break; }
967 else ii -= base_im->nb_points_on_face(ff);
969 normal1 = base_im->ref_convex()->normals()[fp];
972 base_node P = base_im->point(i);
973 if (what == TETRA_CYL) {
974 P = pgt3->transform(P, nodes3);
975 scalar_type x = P[0], y = P[1], one_minus_z = 1.0 - P[2];
976 K4(0, 1) = - y / one_minus_z;
977 K4(1, 1) = 1.0 - x / one_minus_z;
978 K4(2, 1) = - x * y / gmm::sqr(one_minus_z);
979 J4 = gmm::abs(gmm::lu_det(K4));
980 P[1] *= (1.0 - x / one_minus_z);
982 if (what == PRISM2) {
983 scalar_type x = P[0], y = P[1], one_minus_z = 1.0 - P[2];
984 K4(0,0) = one_minus_z; K4(2,0) = -x;
985 K4(1,1) = one_minus_z; K4(2,1) = -y;
986 J4 = gmm::abs(gmm::lu_det(K4));
991 base_node P1 = pgt1->transform(P, nodes1), P2(N);
992 pgt1->poly_vector_grad(P, grad);
993 gmm::mult(gmm::transposed(grad), gmm::transposed(G1), K);
994 J1 = gmm::abs(gmm::lu_det(K)) * J3 * J4;
996 if (fp !=
size_type(-1) && J1 > 1E-10 && J4 > 1E-10) {
997 if (what == TETRA_CYL) {
1010 GMM_ASSERT1(pgt2->convex_ref()->is_in(P2) < 1E-8,
1011 "Point not in the convex ref : " << P2);
1013 pgt2->poly_vector_grad(P2, grad);
1014 gmm::mult(gmm::transposed(grad), gmm::transposed(G2), K);
1015 J2 = gmm::abs(gmm::lu_det(K));
1017 if (i < base_im->nb_points_on_convex())
1018 add_point(P2, base_im->coeff(i)*J1/J2,
short_type(-1));
1019 else if (J1 > 1E-10) {
1022 if (gmm::abs(pgt2->convex_ref()->is_in_face(ff, P2)) < 1E-8) {
1024 "An integration point is common to two faces");
1029 add_point(P2,base_im->coeff(i)*J1*gmm::vect_norm2(normal1)/J2,f);
1034 if (what != TETRA_CYL)
break;
1041 static pintegration_method
1042 quasi_polar(im_param_list ¶ms,
1043 std::vector<dal::pstatic_stored_object> &dependencies) {
1044 GMM_ASSERT1(params.size() >= 1 && params[0].type() == 1,
1045 "Bad parameters for quasi polar integration: the first "
1046 "parameter should be an integration method");
1047 pintegration_method a = params[0].method();
1048 GMM_ASSERT1(a->type()==IM_APPROX,
"need an approximate integration method");
1049 int ip1 = 0, ip2 = 0;
1051 GMM_ASSERT1(params.size() == 1,
"Bad number of parameters");
1053 GMM_ASSERT1(params.size() == 2 || params.size() == 3,
1054 "Bad number of parameters : " << params.size()
1055 <<
" should be 2 or 3.");
1056 GMM_ASSERT1(params[1].type() == 0
1057 && params.back().type() == 0,
"Bad type of parameters");
1058 ip1 = int(::floor(params[1].num() + 0.01));
1059 ip2 = int(::floor(params.back().num() + 0.01));
1061 int N = a->approx_method()->dim();
1062 GMM_ASSERT1(N >= 2 && N <= 3 && ip1 >= 0 && ip2 >= 0 && ip1 <= N
1063 && ip2 <= N,
"Bad parameters");
1066 pai = std::make_shared<quasi_polar_integration>(a->approx_method(),
1068 pintegration_method p = std::make_shared<integration_method>(pai);
1069 dependencies.push_back(p->approx_method()->ref_convex());
1070 dependencies.push_back(p->approx_method()->pintegration_points());
1074 static pintegration_method
1075 pyramid(im_param_list ¶ms,
1076 std::vector<dal::pstatic_stored_object> &dependencies) {
1077 GMM_ASSERT1(params.size() == 1 && params[0].type() == 1,
1078 "Bad parameters for pyramid integration: the first "
1079 "parameter should be an integration method");
1080 pintegration_method a = params[0].method();
1081 GMM_ASSERT1(a->type()==IM_APPROX,
"need an approximate integration method");
1082 int N = a->approx_method()->dim();
1083 GMM_ASSERT1(N == 3,
"Bad parameters");
1086 pai = std::make_shared<quasi_polar_integration>(a->approx_method(), 0, 0);
1087 pintegration_method p = std::make_shared<integration_method>(pai);
1088 dependencies.push_back(p->approx_method()->ref_convex());
1089 dependencies.push_back(p->approx_method()->pintegration_points());
1100 structured_composite_int_method(im_param_list &,
1101 std::vector<dal::pstatic_stored_object> &);
1102 pintegration_method HCT_composite_int_method(im_param_list ¶ms,
1103 std::vector<dal::pstatic_stored_object> &dependencies);
1105 pintegration_method QUADC1_composite_int_method(im_param_list ¶ms,
1106 std::vector<dal::pstatic_stored_object> &dependencies);
1108 pintegration_method pyramid_composite_int_method(im_param_list ¶ms,
1109 std::vector<dal::pstatic_stored_object> &dependencies);
1112 im_naming_system() :
dal::naming_system<integration_method>(
"IM") {
1114 add_suffix(
"EXACT_SIMPLEX", exact_simplex);
1115 add_suffix(
"PRODUCT", product_which);
1116 add_suffix(
"EXACT_PARALLELEPIPED",exact_parallelepiped);
1117 add_suffix(
"EXACT_PRISM", exact_prism);
1118 add_suffix(
"GAUSS1D", gauss1d);
1119 add_suffix(
"NC", Newton_Cotes);
1120 add_suffix(
"NC_PARALLELEPIPED", Newton_Cotes_para);
1121 add_suffix(
"NC_PRISM", Newton_Cotes_prism);
1122 add_suffix(
"GAUSS_PARALLELEPIPED", Gauss_paramul);
1123 add_suffix(
"QUASI_POLAR", quasi_polar);
1124 add_suffix(
"PYRAMID", pyramid);
1125 add_suffix(
"STRUCTURED_COMPOSITE",
1126 structured_composite_int_method);
1127 add_suffix(
"HCT_COMPOSITE",
1128 HCT_composite_int_method);
1129 add_suffix(
"QUADC1_COMPOSITE",
1130 QUADC1_composite_int_method);
1131 add_suffix(
"PYRAMID_COMPOSITE",
1132 pyramid_composite_int_method);
1133 add_generic_function(im_list_integration);
1138 bool throw_if_not_found) {
1141 (name, i, throw_if_not_found);
1145 if (!(p.get()))
return "IM_NONE";
1150 void add_integration_name(std::string name,
1159 THREAD_SAFE_STATIC pintegration_method pim =
nullptr;
1162 std::stringstream name;
1163 name <<
"IM_EXACT_SIMPLEX(" << n <<
")";
1171 THREAD_SAFE_STATIC pintegration_method pim =
nullptr;
1174 std::stringstream name;
1175 name <<
"IM_EXACT_PARALLELEPIPED(" << n <<
")";
1183 THREAD_SAFE_STATIC pintegration_method pim =
nullptr;
1186 std::stringstream name;
1187 name <<
"IM_EXACT_PRISM(" << n <<
")";
1201 THREAD_SAFE_STATIC pintegration_method im_last =
nullptr;
1204 if (cvs_last == cvs)
1209 std::stringstream name;
1215 { name <<
"IM_EXACT_SIMPLEX("; found =
true; }
1219 if (!found && nbp == (
size_type(1) << n))
1221 { name <<
"IM_EXACT_PARALLELEPIPED("; found =
true; }
1225 if (!found && nbp == 2 * n)
1227 { name <<
"IM_EXACT_PRISM("; found =
true; }
1232 name << int(n) <<
')';
1238 GMM_ASSERT1(
false,
"This element is not taken into account. Contact us");
1246 static pintegration_method
1249 std::stringstream name;
1251 if(bgeot::is_torus_structure(cvs) && n == 3) n = 2;
1253 degree = std::max<dim_type>(degree, 1);
1259 case 1: name <<
"IM_GAUSS1D";
break;
1260 case 2: name <<
"IM_TRIANGLE";
break;
1261 case 3: name <<
"IM_TETRAHEDRON";
break;
1262 case 4: name <<
"IM_SIMPLEX4D";
break;
1263 default: GMM_ASSERT1(
false,
"no approximate integration method "
1264 "for simplexes of dimension " << n);
1267 std::stringstream name2;
1268 name2 << name.str() <<
"(" << k <<
")";
1272 GMM_ASSERT1(
false,
"could not find an " << name.str()
1273 <<
" of degree >= " <<
int(degree));
1275 GMM_ASSERT1(n == 3,
"Wrong dimension");
1276 name <<
"IM_PYRAMID(IM_GAUSS_PARALLELEPIPED(3," << degree <<
"))";
1277 }
else if (cvs->is_product(&a,&b) ||
1280 name <<
"IM_PRODUCT("
1283 }
else GMM_ASSERT1(
false,
"unknown convex structure!");
1290 THREAD_SAFE_STATIC dim_type degree_last;
1291 THREAD_SAFE_STATIC pintegration_method im_last =
nullptr;
1292 if (pgt_last == pgt && degree == degree_last)
1294 im_last = classical_approx_im_(pgt->structure(),degree);
1295 degree_last = degree;
1301 THREAD_SAFE_STATIC pintegration_method im_last =
nullptr;
1308 scalar_type test_integration_error(papprox_integration pim, dim_type order) {
1311 opt_long_scalar_type error(0);
1313 opt_long_scalar_type sum(0), realsum;
1314 for (
size_type i=0; i < pim->nb_points_on_convex(); ++i) {
1315 opt_long_scalar_type prod = pim->coeff(i);
1317 prod *= pow(opt_long_scalar_type(pim->point(i)[d]), idx[d]);
1320 realsum = exact->exact_method()->int_monomial(idx);
1321 error = std::max(error, gmm::abs(realsum-sum));
1323 return bgeot::to_scalar(error);
1326 papprox_integration get_approx_im_or_fail(pintegration_method pim) {
1327 GMM_ASSERT1(pim->type() == IM_APPROX,
"error estimate work only with "
1328 "approximate integration methods");
1329 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