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