GetFEM++  5.3
getfem_integration.cc
1 /*===========================================================================
2 
3  Copyright (C) 2000-2017 Yves Renard
4 
5  This file is a part of GetFEM++
6 
7  GetFEM++ is free software; you can redistribute it and/or modify it
8  under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version along with the GCC Runtime Library
11  Exception either version 3.1 or (at your option) any later version.
12  This program is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15  License and GCC Runtime Library Exception for more details.
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program; if not, write to the Free Software Foundation,
18  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20 ===========================================================================*/
21 
22 #include "getfem/bgeot_torus.h"
23 #include "getfem/dal_singleton.h"
25 #include "gmm/gmm_dense_lu.h"
26 #include "getfem/bgeot_permutations.h"
28 #include "getfem/getfem_im_list.h"
30 #include "getfem/getfem_omp.h"
31 #include "getfem/getfem_torus.h"
32 
33 namespace getfem {
34 
35  /*
36  * dummy integration method
37  */
38  static pintegration_method im_none(im_param_list &params,
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>();
42  }
43 
44  long_scalar_type poly_integration::int_poly(const base_poly &P) const {
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();
49  hum->resize(i);
50  bgeot::power_index mi(P.dim()); mi[P.dim()-1] = P.degree();
51  for (size_type k = i; k > j; --k, --mi)
52  (*hum)[k-1] = int_monomial(mi);
53  }
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);
58  }
59  return res;
60  }
61 
62  long_scalar_type
63  poly_integration::int_poly_on_face(const base_poly &P,short_type f) const {
64  long_scalar_type res = 0.0;
65  std::vector<long_scalar_type> *hum = &(int_face_monomials[f]);
66  if (P.size() > hum->size()) {
67  size_type i = P.size(), j = hum->size();
68  hum->resize(i);
69  bgeot::power_index mi(P.dim()); mi[P.dim()-1] = P.degree();
70  for (size_type k = i; k > j; --k, --mi)
71  (*hum)[k-1] = int_monomial_on_face(mi, f);
72  }
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);
77  return res;
78  }
79 
80  /* ******************************************************************** */
81  /* integration on simplex */
82  /* ******************************************************************** */
83 
84  struct simplex_poly_integration_ : public poly_integration {
85 
86  long_scalar_type int_monomial(const bgeot::power_index &power) const;
87 
88  long_scalar_type int_monomial_on_face(const bgeot::power_index &power,
89  short_type f) const;
90 
91  simplex_poly_integration_(bgeot::pconvex_structure c)
92  { cvs = c; int_face_monomials.resize(c->nb_faces()); }
93  };
94 
95 
96  long_scalar_type
97  simplex_poly_integration_::int_monomial(const bgeot::power_index &power) const{
98  long_scalar_type res = LONG_SCAL(1);
99  short_type fa = 1;
100  bgeot::power_index::const_iterator itm = power.begin(),
101  itme = power.end();
102  for ( ; itm != itme; ++itm)
103  for (int k = 1; k <= *itm; ++k, ++fa)
104  res *= long_scalar_type(k) / long_scalar_type(fa);
105 
106  for (int k = 0; k < cvs->dim(); k++) { res /= long_scalar_type(fa); fa++; }
107  return res;
108  }
109 
110  long_scalar_type simplex_poly_integration_::int_monomial_on_face
111  (const bgeot::power_index &power, short_type f) const {
112  long_scalar_type res = LONG_SCAL(0);
113 
114  if (f == 0 || power[f-1] == 0.0) {
115  res = (f == 0) ? sqrt(long_scalar_type(cvs->dim())) : LONG_SCAL(1);
116  short_type fa = 1;
117  bgeot::power_index::const_iterator itm = power.begin(),
118  itme = power.end();
119  for ( ; itm != itme; ++itm)
120  for (int k = 1; k <= *itm; ++k, ++fa)
121  res *= long_scalar_type(k) / long_scalar_type(fa);
122 
123  for (int k = 1; k < cvs->dim(); k++) { res/=long_scalar_type(fa); fa++; }
124  }
125  return res;
126  }
127 
128  static pintegration_method
129  exact_simplex(im_param_list &params,
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(),
136  "Bad parameters");
137  dependencies.push_back(bgeot::simplex_structure(dim_type(n)));
138  ppoly_integration ppi = std::make_shared<simplex_poly_integration_>
139  (bgeot::simplex_structure(dim_type(n)));
140  return std::make_shared<integration_method>(ppi);
141  }
142 
143  /* ******************************************************************** */
144  /* integration on direct product of convex structures */
145  /* ******************************************************************** */
146 
147  struct plyint_mul_structure_ : public poly_integration {
148  ppoly_integration cv1, cv2;
149 
150  long_scalar_type int_monomial(const bgeot::power_index &power) const;
151 
152  long_scalar_type int_monomial_on_face(const bgeot::power_index &power,
153  short_type f) const;
154 
155  plyint_mul_structure_(ppoly_integration a, ppoly_integration b);
156  };
157 
158  long_scalar_type plyint_mul_structure_::int_monomial
159  (const bgeot::power_index &power) const {
160  bgeot::power_index mi1(cv1->dim()), mi2(cv2->dim());
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);
164  }
165 
166  long_scalar_type plyint_mul_structure_::int_monomial_on_face
167  (const bgeot::power_index &power, short_type f) const {
168  bgeot::power_index mi1(cv1->dim()), mi2(cv2->dim());
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();
172  if (f < nfx)
173  return cv1->int_monomial_on_face(mi1,f) * cv2->int_monomial(mi2);
174  else
175  return cv1->int_monomial(mi1)
176  * cv2->int_monomial_on_face(mi2, short_type(f-nfx));
177  }
178 
179  plyint_mul_structure_::plyint_mul_structure_(ppoly_integration a,
180  ppoly_integration b) {
181  cv1 = a; cv2 = b;
182  cvs = bgeot::convex_product_structure(cv1->structure(),
183  cv2->structure());
184  int_face_monomials.resize(cvs->nb_faces());
185  }
186 
187  static pintegration_method
188  product_exact(im_param_list &params,
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,
197  "Bad parameters");
198  dependencies.push_back(a); dependencies.push_back(b);
199  dependencies.push_back(bgeot::convex_product_structure(a->structure(),
200  b->structure()));
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);
204  }
205 
206  /* ******************************************************************** */
207  /* integration on parallelepiped. */
208  /* ******************************************************************** */
209 
210  static pintegration_method
211  exact_parallelepiped(im_param_list &params,
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(),
218  "Bad parameters");
219 
220  std::stringstream name;
221  if (n == 1)
222  name << "IM_EXACT_SIMPLEX(1)";
223  else
224  name << "IM_PRODUCT(IM_EXACT_PARALLELEPIPED(" << n-1
225  << "),IM_EXACT_SIMPLEX(1)))";
226  return int_method_descriptor(name.str());
227  }
228 
229  static pintegration_method
230  exact_prism(im_param_list &params,
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(),
237  "Bad parameters");
238 
239  std::stringstream name;
240  name << "IM_PRODUCT(IM_EXACT_SIMPLEX(" << n-1
241  << "),IM_EXACT_SIMPLEX(1))";
242  return int_method_descriptor(name.str());
243  }
244 
245  /* ********************************************************************* */
246  /* Approximated integration */
247  /* ********************************************************************* */
248 
249  void approx_integration::add_point(const base_node &pt,
250  scalar_type w,
251  short_type f,
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) {
255  ++f;
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);
259  if (i == size_type(-1)) {
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)
263  repartition[j] += 1;
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;
267  }
268  int_coeffs[((f == 0) ? 0 : repartition[f-1]) + i] += w;
269  }
270  }
271 
272  void approx_integration::add_point_norepeat(const base_node &pt,
273  scalar_type w,
274  short_type f) {
275  short_type f2 = f; ++f2;
276  if (pt_to_store[f2].search_node(pt) == size_type(-1)) add_point(pt,w,f);
277  }
278 
279  void approx_integration::add_point_full_symmetric(base_node pt,
280  scalar_type w) {
281  dim_type n = cvr->structure()->dim();
282  dim_type k;
283  base_node pt2(n);
284  if (n+1 == cvr->structure()->nb_faces()) {
285  // simplices
286  // for a point at (x,y) you have to consider the other points
287  // at (y,x) (x,1-x-y) (1-x-y,x) (y,1-x-y) (1-x-y,y)
288  base_node pt3(n+1);
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);
293  for (;;) {
294 
295  std::fill(ind2.begin(), ind2.end(), false);
296  bool good = true;
297  for (k = 0; k < n; ++k)
298  if (ind2[ind[k]]) { good = false; break; } else ind2[ind[k]] = true;
299  if (good) {
300  for (k = 0; k < n; ++k) pt2[k] = pt3[ind[k]];
301  add_point_norepeat(pt2, w);
302  }
303  ind[0]++; k = 0;
304  while(ind[k] == n+1) { ind[k++] = 0; if (k == n) return; ind[k]++; }
305  }
306  }
307 
308  else if (cvr->structure()->nb_points() == (size_type(1) << n)) {
309  // parallelepidedic
310  for (size_type i = 0; i < (size_type(1) << n); ++i) {
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);
314  }
315  }
316  else
317  GMM_ASSERT1(false, "Fully symmetric option is only valid for"
318  "simplices and parallelepipedic elements");
319  }
320 
321  void approx_integration::add_method_on_face(pintegration_method ppi,
322  short_type f) {
323  papprox_integration pai = ppi->approx_method();
324  GMM_ASSERT1(!valid, "Impossible to modify a valid integration method.");
325  GMM_ASSERT1(pai->structure() == structure()->faces_structure()[f],
326  "structures missmatch");
327  GMM_ASSERT1(ppi->type() == IM_APPROX, "Impossible with an exact method.");
328 
329  dim_type N = pai->structure()->dim();
330  scalar_type det = 1.0;
331  base_node pt(N+1);
332  std::vector<base_node> pts(N);
333  for (size_type i = 0; i < N; ++i)
334  pts[i] = (cvr->dir_points_of_face(f))[i+1]
335  - (cvr->dir_points_of_face(f))[0];
336  if (N) {
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)
340  a(i, j) = pts[j][i];
341 
342  gmm::mult(gmm::transposed(a), a, b);
343  det = ::sqrt(gmm::abs(gmm::lu_det(b)));
344  }
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);
350  }
351  }
352 
353  void approx_integration::valid_method() {
354  std::vector<base_node> ptab(int_coeffs.size());
355  // std::vector<scalar_type> int_coeffs2(int_coeffs);
356  size_type i = 0;
357  for (short_type f = 0; f <= cvr->structure()->nb_faces(); ++f) {
358  // size_type j = i;
359  for (PT_TAB::const_iterator it = pt_to_store[f].begin();
360  it != pt_to_store[f].end(); ++it /* , ++j */) {
361  // int_coeffs[i] = int_coeffs2[j];
362  ptab[i++] = *it;
363  }
364  }
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>();
368  valid = true;
369  }
370 
371 
372  /* ********************************************************************* */
373  /* methods stored in getfem_im_list.h */
374  /* ********************************************************************* */
375 
376  /// search a method in getfem_im_list.h
377  static pintegration_method
378  im_list_integration(std::string name,
379  std::vector<dal::pstatic_stored_object> &dependencies) {
380  // cerr << "searching " << name << endl;
381  for (int i = 0; i < NB_IM; ++i)
382  if (!name.compare(im_desc_tab[i].method_name)) {
384  = bgeot::geometric_trans_descriptor(im_desc_tab[i].geotrans_name);
385  dim_type N = pgt->structure()->dim();
386  base_node pt(N);
387  auto pai = std::make_shared<approx_integration>(pgt->convex_ref());
388  size_type fr = im_desc_tab[i].firstreal;
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]);
392  // pt[k] = LONG_SCALAR_ATOF(im_desc_real[fr+j*(N+1)+k]);
393 
394  switch (im_desc_node_type[im_desc_tab[i].firsttype + j]) {
395  case 2: {
396  base_node pt2(pt.size());
397  for (bgeot::permutation p(pt.size()); !p.finished(); ++p) {
398  p.apply_to(pt,pt2);
399  pai->add_point_full_symmetric(pt2,
400  atof(im_desc_real[fr+j*(N+1)+N]));
401  // pai->add_point_full_symmetric(pt2,
402  // LONG_SCALAR_ATOF(im_desc_real[fr+j*(N+1)+N]));
403  }
404  } break;
405  case 1: {
406  pai->add_point_full_symmetric(pt,atof(im_desc_real[fr+j*(N+1)+N]));
407  // pai->add_point_full_symmetric(pt,
408  // LONG_SCALAR_ATOF(im_desc_real[fr+j*(N+1)+N]));
409  } break;
410  case 0: {
411  pai->add_point(pt, atof(im_desc_real[fr+j*(N+1)+N]));
412  // pai->add_point(pt,LONG_SCALAR_ATOF(im_desc_real[fr+j*(N+1)+N]));
413  } break;
414  default: GMM_ASSERT1(false, "");
415  }
416  }
417 
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);
422 
423  pai->valid_method();
424  // cerr << "finding " << name << endl;
425 
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());
429  return p;
430  }
431  return pintegration_method();
432  }
433 
434 
435  /* ********************************************************************* */
436  /* Gauss method. */
437  /* ********************************************************************* */
438 
439  struct Legendre_polynomials {
440  std::vector<base_poly> polynomials;
441  std::vector<std::vector<long_scalar_type>> roots;
442  int nb_lp;
443  Legendre_polynomials() : nb_lp(-1) {}
444  void init(short_type de) {
445  polynomials.resize(de+2);
446  roots.resize(de+2);
447  if (nb_lp < 0) {
448  polynomials[0] = base_poly(1,0);
449  polynomials[0].one();
450  polynomials[1] = base_poly(1,1,0);
451  roots[1].resize(1);
452  roots[1][0] = 0.0;
453  nb_lp = 1;
454  }
455  while (nb_lp < de) {
456  ++nb_lp;
457  polynomials[nb_lp] =
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) { // + symetry ...
466  b = roots[nb_lp-1][k];
467 
468  c = a, d = b;
469  cv = polynomials[nb_lp].eval(&c);
470  int imax = 10000;
471  ecart = 2.0 * (d - c);
472  while(c != d) {
473  --imax; if (imax == 0) break;
474  e = (c + d) / 2.0;
475  ecart2 = d - c; if (ecart2 >= ecart) break;
476  ecart = ecart2;
477  ev = polynomials[nb_lp].eval(&e);
478  if (ev * cv < 0.) { d = e; } else { c = e; cv = ev; }
479  }
480 
481  roots[nb_lp][k] = c;
482  roots[nb_lp][nb_lp-k-1] = -c;
483  a = b;
484  }
485  }
486  }
487  };
488 
489  struct gauss_approx_integration_ : public approx_integration {
490  gauss_approx_integration_(short_type nbpt);
491  };
492 
493  gauss_approx_integration_::gauss_approx_integration_(short_type nbpt) {
494  GMM_ASSERT1(nbpt <= 32000, "too much points");
495 
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;
503 
504  Legendre_polynomials Lp;
505  Lp.init(nbpt);
506 
507  for (short_type i = 0; i < nbpt; ++i) {
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))));
514  }
515 
516  int_points[nbpt].resize(1);
517  int_points[nbpt][0] = 1.0; int_coeffs[nbpt] = 1.0;
518 
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);
522  valid = true;
523  }
524 
525 
526  static pintegration_method
527  gauss1d(im_param_list &params,
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(),
534  "Bad parameters");
535  if (n & 1) {
536  std::stringstream name;
537  name << "IM_GAUSS1D(" << n-1 << ")";
538  return int_method_descriptor(name.str());
539  }
540  else {
541  papprox_integration
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());
546  return p;
547  }
548  }
549 
550  /* ********************************************************************* */
551  /* integration on simplexes */
552  /* ********************************************************************* */
553 
554  struct Newton_Cotes_approx_integration_ : public approx_integration
555  {
556  // void calc_base_func(base_poly &p, short_type K, base_node &c) const;
557  Newton_Cotes_approx_integration_(dim_type nc, short_type k);
558  };
559 
560  Newton_Cotes_approx_integration_::Newton_Cotes_approx_integration_
561  (dim_type nc, short_type k)
562  : approx_integration(bgeot::simplex_of_reference(nc)) {
563  size_type R = bgeot::alpha(nc,k);
564 
565  base_node c(nc);
566  if (nc == 0) {
567  add_point(c, scalar_type(1));
568  }
569  else {
570 
571  std::stringstream name;
572  name << "IM_EXACT_SIMPLEX(" << int(nc) << ")";
573  ppoly_integration ppi = int_method_descriptor(name.str())->exact_method();
574 
575  size_type sum = 0, l;
576  c.fill(scalar_type(0.0));
577  if (k == 0) c.fill(1.0 / scalar_type(nc+1));
578 
579  gmm::dense_matrix<long_scalar_type> M(R, R);
580  std::vector<long_scalar_type> F(R), U(R);
581  std::vector<bgeot::power_index> base(R);
582  std::vector<base_node> nodes(R);
583 
584  bgeot::power_index pi(nc);
585 
586  for (size_type r = 0; r < R; ++r, ++pi) {
587  base[r] = pi; nodes[r] = c;
588  if (k != 0 && nc > 0) {
589  l = 0; c[l] += 1.0 / scalar_type(k); sum++;
590  while (sum > k) {
591  sum -= int(floor(0.5+(c[l] * k)));
592  c[l] = 0.0; l++; if (l == nc) break;
593  c[l] += 1.0 / scalar_type(k); sum++;
594  }
595  }
596  }
597 
598 // if (nc == 1) {
599 // M = bgeot::vsmatrix<long_scalar_type>((R+1)/2, (R+1)/2);
600 // U = F = bgeot::vsvector<long_scalar_type>((R+1)/2);
601 // gmm::clear(M);
602 // }
603 
604  for (size_type r = 0; r < R; ++r) {
605 // if (nc == 1) {
606 // if (r < (R+1)/2) {
607 // F[r] = ppi->int_monomial(base[R-1-r]);
608 // cout << "F[" << r << "] = " << F[r] << endl;
609 // }
610 // }
611 // else {
612  F[r] = ppi->int_monomial(base[r]);
613  //cout << "F[" << r << "] = " << F[r] << endl;
614 // }
615  for (size_type q = 0; q < R; ++q) {
616 // if (nc == 1) {
617 // if (r < (R+1)/2) {
618 // if (q < (R+1)/2)
619 // M(r, q) += bgeot::eval_monomial(base[R-1-r], nodes[q].begin());
620 // else
621 // M(r, R-1-q) += bgeot::eval_monomial(base[R-1-r],
622 // nodes[q].begin());
623 // }
624 // }
625 // else
626  M(r, q) = bgeot::eval_monomial(base[r], nodes[q].begin());
627  }
628  }
629 
630  gmm::lu_solve(M, U, F);
631  for (size_type r = 0; r < R; ++r)
632  add_point(nodes[r], bgeot::to_scalar(U[r]));
633 
634  std::stringstream name2;
635  name2 << "IM_NC(" << int(nc-1) << "," << int(k) << ")";
636  for (short_type f = 0; f < structure()->nb_faces(); ++f)
637  add_method_on_face(int_method_descriptor(name2.str()), f);
638  }
639  valid_method();
640  }
641 
642  static pintegration_method
643  Newton_Cotes(im_param_list &params,
644  std::vector<dal::pstatic_stored_object> &dependencies) {
645  GMM_ASSERT1(params.size() == 2, "Bad number of parameters : "
646  << params.size() << " should be 2.");
647  GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
648  "Bad type of parameters");
649  int n = int(::floor(params[0].num() + 0.01));
650  int k = int(::floor(params[1].num() + 0.01));
651  GMM_ASSERT1(n >= 0 && n < 100 && k >= 0 && k <= 150 &&
652  double(n) == params[0].num() && double(k) == params[1].num(),
653  "Bad parameters");
654  papprox_integration
655  pai = std::make_shared<Newton_Cotes_approx_integration_>(dim_type(n),
656  short_type(k));
657  pintegration_method p = std::make_shared<integration_method>(pai);
658  dependencies.push_back(p->approx_method()->ref_convex());
659  dependencies.push_back(p->approx_method()->pintegration_points());
660  return p;
661  }
662 
663  /* ********************************************************************* */
664  /* integration on direct product of convex structures */
665  /* ********************************************************************* */
666 
667  struct a_int_pro_integration : public approx_integration
668  {
669  a_int_pro_integration(papprox_integration a, papprox_integration b);
670  };
671 
672 
673  a_int_pro_integration::a_int_pro_integration(papprox_integration a,
674  papprox_integration b) {
675  cvr = bgeot::convex_ref_product(a->ref_convex(), b->ref_convex());
676  size_type n1 = a->nb_points_on_convex();
677  size_type n2 = b->nb_points_on_convex();
678  std::vector<base_node> int_points;
679  int_points.resize(n1 * n2);
680  int_coeffs.resize(n1 * n2);
681  repartition.resize(cvr->structure()->nb_faces()+1);
682  repartition[0] = n1 * n2;
683  for (size_type i1 = 0; i1 < n1; ++i1)
684  for (size_type i2 = 0; i2 < n2; ++i2) {
685  int_coeffs[i1 + i2 * n1] = a->coeff(i1) * b->coeff(i2);
686  int_points[i1 + i2 * n1].resize(dim());
687  std::copy(a->point(i1).begin(), a->point(i1).end(),
688  int_points[i1 + i2 * n1].begin());
689  std::copy(b->point(i2).begin(), b->point(i2).end(),
690  int_points[i1 + i2 * n1].begin() + a->dim());
691  }
692  short_type f = 0;
693  for (short_type f1 = 0; f1 < a->structure()->nb_faces(); ++f1, ++f) {
694  n1 = a->nb_points_on_face(f1);
695  n2 = b->nb_points_on_convex();
696  size_type w = repartition[f];
697  repartition[f+1] = w + n1 * n2;
698  int_points.resize(repartition[f+1]);
699  int_coeffs.resize(repartition[f+1]);
700  for (size_type i1 = 0; i1 < n1; ++i1)
701  for (size_type i2 = 0; i2 < n2; ++i2) {
702  int_coeffs[w + i1 + i2 * n1] = a->coeff_on_face(f1, i1)
703  * b->coeff(i2);
704  int_points[w + i1 + i2 * n1].resize(dim());
705  std::copy(a->point_on_face(f1, i1).begin(),
706  a->point_on_face(f1, i1).end(),
707  int_points[w + i1 + i2 * n1].begin());
708  std::copy(b->point(i2).begin(), b->point(i2).end(),
709  int_points[w + i1 + i2 * n1].begin() + a->dim());
710  }
711  }
712  for (short_type f2 = 0; f2 < b->structure()->nb_faces(); ++f2, ++f) {
713  n1 = a->nb_points_on_convex();
714  n2 = b->nb_points_on_face(f2);
715  size_type w = repartition[f];
716  repartition[f+1] = w + n1 * n2;
717  int_points.resize(repartition[f+1]);
718  int_coeffs.resize(repartition[f+1]);
719  for (size_type i1 = 0; i1 < n1; ++i1)
720  for (size_type i2 = 0; i2 < n2; ++i2) {
721  int_coeffs[w + i1 + i2 * n1] = a->coeff(i1)
722  * b->coeff_on_face(f2, i2);
723  int_points[w + i1 + i2 * n1].resize(dim());
724  std::copy(a->point(i1).begin(), a->point(i1).end(),
725  int_points[w + i1 + i2 * n1].begin());
726  std::copy(b->point_on_face(f2, i2).begin(),
727  b->point_on_face(f2, i2).end(),
728  int_points[w + i1 + i2 * n1].begin() + a->dim());
729  }
730  }
731  pint_points = bgeot::store_point_tab(int_points);
732  valid = true;
733  }
734 
735  static pintegration_method
736  product_approx(im_param_list &params,
737  std::vector<dal::pstatic_stored_object> &dependencies) {
738  GMM_ASSERT1(params.size() == 2, "Bad number of parameters : "
739  << params.size() << " should be 2.");
740  GMM_ASSERT1(params[0].type() == 1 && params[1].type() == 1,
741  "Bad type of parameters");
742  pintegration_method a = params[0].method();
743  pintegration_method b = params[1].method();
744  GMM_ASSERT1(a->type() == IM_APPROX && b->type() == IM_APPROX,
745  "Bad parameters");
746  papprox_integration
747  pai = std::make_shared<a_int_pro_integration>(a->approx_method(),
748  b->approx_method());
749  pintegration_method p = std::make_shared<integration_method>(pai);
750  dependencies.push_back(p->approx_method()->ref_convex());
751  dependencies.push_back(p->approx_method()->pintegration_points());
752  return p;
753  }
754 
755  static pintegration_method
756  product_which(im_param_list &params,
757  std::vector<dal::pstatic_stored_object> &dependencies) {
758  GMM_ASSERT1(params.size() == 2, "Bad number of parameters : "
759  << params.size() << " should be 2.");
760  GMM_ASSERT1(params[0].type() == 1 && params[1].type() == 1,
761  "Bad type of parameters");
762  pintegration_method a = params[0].method();
763  pintegration_method b = params[1].method();
764  if (a->type() == IM_EXACT || b->type() == IM_EXACT)
765  return product_exact(params, dependencies);
766  else return product_approx(params, dependencies);
767  }
768 
769 
770  /* ********************************************************************* */
771  /* integration on parallelepiped with Newton Cotes formulae */
772  /* ********************************************************************* */
773 
774  static pintegration_method
775  Newton_Cotes_para(im_param_list &params,
776  std::vector<dal::pstatic_stored_object> &) {
777  GMM_ASSERT1(params.size() == 2, "Bad number of parameters : "
778  << params.size() << " should be 2.");
779  GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
780  "Bad type of parameters");
781  int n = int(::floor(params[0].num() + 0.01));
782  int k = int(::floor(params[1].num() + 0.01));
783  GMM_ASSERT1(n > 0 && n < 100 && k >= 0 && k <= 150 &&
784  double(n) == params[0].num() && double(k) == params[1].num(),
785  "Bad parameters");
786 
787  std::stringstream name;
788  if (n == 1)
789  name << "IM_NC(1," << k << ")";
790  else
791  name << "IM_PRODUCT(IM_NC_PARALLELEPIPED(" << n-1 << "," << k
792  << "),IM_NC(1," << k << "))";
793  return int_method_descriptor(name.str());
794  }
795 
796  static pintegration_method
797  Newton_Cotes_prism(im_param_list &params,
798  std::vector<dal::pstatic_stored_object> &) {
799  GMM_ASSERT1(params.size() == 2, "Bad number of parameters : "
800  << params.size() << " should be 2.");
801  GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
802  "Bad type of parameters");
803  int n = int(::floor(params[0].num() + 0.01));
804  int k = int(::floor(params[1].num() + 0.01));
805  GMM_ASSERT1(n > 1 && n < 100 && k >= 0 && k <= 150 &&
806  double(n) == params[0].num() && double(k) == params[1].num(),
807  "Bad parameters");
808 
809  std::stringstream name;
810  name << "IM_PRODUCT(IM_NC(" << n-1 << "," << k << "),IM_NC(1,"
811  << k << "))";
812  return int_method_descriptor(name.str());
813  }
814 
815  /* ********************************************************************* */
816  /* integration on parallelepiped with Gauss formulae */
817  /* ********************************************************************* */
818 
819  static pintegration_method
820  Gauss_paramul(im_param_list &params,
821  std::vector<dal::pstatic_stored_object> &) {
822  GMM_ASSERT1(params.size() == 2, "Bad number of parameters : "
823  << params.size() << " should be 2.");
824  GMM_ASSERT1(params[0].type() == 0 && params[1].type() == 0,
825  "Bad type of parameters");
826  int n = int(::floor(params[0].num() + 0.01));
827  int k = int(::floor(params[1].num() + 0.01));
828  GMM_ASSERT1(n > 0 && n < 100 && k >= 0 && k <= 150 &&
829  double(n) == params[0].num() && double(k) == params[1].num(),
830  "Bad parameters");
831 
832  std::stringstream name;
833  if (n == 1)
834  name << "IM_GAUSS1D(" << k << ")";
835  else
836  name << "IM_PRODUCT(IM_GAUSS_PARALLELEPIPED(" << n-1 << "," << k
837  << "),IM_GAUSS1D(" << k << "))";
838  return int_method_descriptor(name.str());
839  }
840 
841  /* ******************************************************************** */
842  /* Quasi-polar integration */
843  /* ******************************************************************** */
844 
845  struct quasi_polar_integration : public approx_integration {
846  quasi_polar_integration(papprox_integration base_im,
847  size_type ip1, size_type ip2=size_type(-1)) :
848  approx_integration
849  ((base_im->structure() == bgeot::parallelepiped_structure(3)) ?
851  : bgeot::simplex_of_reference(base_im->dim())) {
852  size_type N = base_im->dim();
853 
854  enum { SQUARE, PRISM, TETRA_CYL, PRISM2, PYRAMID } what;
855  if (N == 2) what = SQUARE;
856  else if (base_im->structure() == bgeot::prism_P1_structure(3))
857  what = (ip2 == size_type(-1) || ip1 == ip2) ? PRISM2 : PRISM;
858  else if (base_im->structure() == bgeot::simplex_structure(3))
859  what = TETRA_CYL;
860  else if (base_im->structure() == bgeot::parallelepiped_structure(3))
861  what = PYRAMID;
862  else GMM_ASSERT1(false, "Incoherent integration method");
863 
864  // The first geometric transformation collapse a face of
865  // a parallelepiped or collapse a parrallelepiped on a pyramid.
866  // The second geometric transformation chooses the orientation.
867  // The third is used for the TETRA_CYL case only.
868  bgeot::pgeometric_trans pgt1 = bgeot::parallelepiped_geotrans(N,1);
869  std::vector<base_node> nodes1 = pgt1->convex_ref()->points();
870  bgeot::pgeometric_trans pgt2 = bgeot::simplex_geotrans(N, 1);
871  std::vector<base_node> nodes2(N+1);
872  if (what == PYRAMID) {
873  pgt2 = bgeot::pyramid_QK_geotrans(1);
874  nodes2.resize(5);
875  }
876  std::vector<size_type> other_nodes; // for the construction of node2
877  bgeot::pgeometric_trans pgt3 = bgeot::simplex_geotrans(N, 1);
878  std::vector<base_node> nodes3(N+1);
879 
880  switch (what) {
881  case SQUARE :
882  nodes1[3] = nodes1[1];
883  nodes2[ip1] = nodes1[1]; ip2 = ip1;
884  other_nodes.push_back(0);
885  other_nodes.push_back(2);
886  break;
887  case PRISM :
888  nodes1[4] = nodes1[0]; nodes1[5] = nodes1[1];
889  nodes2[ip1] = nodes1[0];
890  nodes2[ip2] = nodes1[1];
891  other_nodes.push_back(2);
892  other_nodes.push_back(6);
893  break;
894  case TETRA_CYL :
895  nodes3[0] = nodes1[0]; nodes3[1] = nodes1[1];
896  nodes3[2] = nodes1[2]; nodes3[3] = nodes1[4];
897  // nodes1[4] = nodes1[0]; nodes1[7] = base_node(1.0, 1.0, 2.0);
898  nodes2[ip1] = nodes1[1]; ip2 = ip1;
899  other_nodes.push_back(0);
900  other_nodes.push_back(2);
901  other_nodes.push_back(4);
902  break;
903  case PRISM2 :
904  nodes2[ip1] = nodes1[4];
905  other_nodes.push_back(0);
906  other_nodes.push_back(1);
907  other_nodes.push_back(2);
908  break;
909  case PYRAMID :
910  ip2 = ip1 = 0;
911  nodes1[0] = base_node(-1.,-1., 0.);
912  nodes1[1] = base_node( 1.,-1., 0.);
913  nodes1[2] = base_node(-1., 1., 0.);
914  nodes1[3] = base_node( 1., 1., 0.);
915  nodes1[4] = base_node( 0., 0., 1.);
916  nodes1[5] = nodes1[6] = nodes1[7] = nodes1[4];
917  nodes2[ip1] = nodes1[0];
918  other_nodes.push_back(4);
919  other_nodes.push_back(3);
920  other_nodes.push_back(2);
921  other_nodes.push_back(1);
922  }
923 
924  for (size_type i = 0; i <= nodes2.size()-1; ++i)
925  if (i != ip1 && i != ip2) {
926  GMM_ASSERT3(!other_nodes.empty(), "");
927  nodes2[i] = nodes1[other_nodes.back()];
928  other_nodes.pop_back();
929  }
930 
931  base_matrix G1, G2, G3;
932  base_matrix K(N, N), grad(N, N), K3(N, N), K4(N, N);
933  base_node normal1(N), normal2(N);
934  bgeot::geotrans_inv_convex gic(nodes2, pgt2);
935  scalar_type J1, J2, J3(1), J4(1);
936 
937  bgeot::vectors_to_base_matrix(G1, nodes1);
938  bgeot::vectors_to_base_matrix(G2, nodes2);
939 
940  for (size_type nc = 0; nc < 2; ++nc) {
941 
942  if (what == TETRA_CYL) {
943  if (nc == 1) nodes3[0] = nodes1[3];
944  bgeot::vectors_to_base_matrix(G3, nodes3);
945  pgt3->poly_vector_grad(nodes1[0], grad);
946  gmm::mult(gmm::transposed(grad), gmm::transposed(G3), K3);
947  J3 = gmm::abs(gmm::lu_inverse(K3)); /* = 1 */
948  }
949 
950  for (size_type i=0; i < base_im->nb_points(); ++i) {
951 
952  gmm::copy(gmm::identity_matrix(), K4); J4 = J1 = scalar_type(1);
953 
954  size_type fp = size_type(-1); // Search the face number in the
955  if (i >= base_im->nb_points_on_convex()) { // original element
956  size_type ii = i - base_im->nb_points_on_convex();
957  for (short_type ff=0; ff < base_im->structure()->nb_faces(); ++ff) {
958  if (ii < base_im->nb_points_on_face(ff)) { fp = ff; break; }
959  else ii -= base_im->nb_points_on_face(ff);
960  }
961  normal1 = base_im->ref_convex()->normals()[fp];
962  }
963 
964  base_node P = base_im->point(i);
965  if (what == TETRA_CYL) {
966  P = pgt3->transform(P, nodes3);
967  scalar_type x = P[0], y = P[1], one_minus_z = 1.0 - P[2];
968  K4(0, 1) = - y / one_minus_z;
969  K4(1, 1) = 1.0 - x / one_minus_z;
970  K4(2, 1) = - x * y / gmm::sqr(one_minus_z);
971  J4 = gmm::abs(gmm::lu_det(K4));
972  P[1] *= (1.0 - x / one_minus_z);
973  }
974  if (what == PRISM2) {
975  scalar_type x = P[0], y = P[1], one_minus_z = 1.0 - P[2];
976  K4(0,0) = one_minus_z; K4(2,0) = -x;
977  K4(1,1) = one_minus_z; K4(2,1) = -y;
978  J4 = gmm::abs(gmm::lu_det(K4));
979  P[0] *= one_minus_z;
980  P[1] *= one_minus_z;
981  }
982 
983  base_node P1 = pgt1->transform(P, nodes1), P2(N);
984  pgt1->poly_vector_grad(P, grad);
985  gmm::mult(gmm::transposed(grad), gmm::transposed(G1), K);
986  J1 = gmm::abs(gmm::lu_det(K)) * J3 * J4;
987 
988  if (fp != size_type(-1) && J1 > 1E-10 && J4 > 1E-10) {
989  if (what == TETRA_CYL) {
990  gmm::mult(K3, normal1, normal2);
991  normal1 = normal2;
992  }
993  gmm::lu_inverse(K4);
994  gmm::lu_inverse(K);
995  gmm::mult(K4, normal1, normal2);
996  gmm::mult(K, normal2, normal1);
997  normal2 = normal1;
998  J1 *= gmm::vect_norm2(normal2);
999  normal2 /= gmm::vect_norm2(normal2);
1000  }
1001  gic.invert(P1, P2);
1002  GMM_ASSERT1(pgt2->convex_ref()->is_in(P2) < 1E-8,
1003  "Point not in the convex ref : " << P2);
1004 
1005  pgt2->poly_vector_grad(P2, grad);
1006  gmm::mult(gmm::transposed(grad), gmm::transposed(G2), K);
1007  J2 = gmm::abs(gmm::lu_det(K)); /* = 1 */
1008 
1009  if (i < base_im->nb_points_on_convex())
1010  add_point(P2, base_im->coeff(i)*J1/J2, short_type(-1));
1011  else if (J1 > 1E-10) {
1012  short_type f = short_type(-1);
1013  for (short_type ff = 0; ff <= N; ++ff)
1014  if (gmm::abs(pgt2->convex_ref()->is_in_face(ff, P2)) < 1E-8) {
1015  GMM_ASSERT1(f == short_type(-1),
1016  "An integration point is common to two faces");
1017  f = ff;
1018  }
1019  if (f != short_type(-1)) {
1020  gmm::mult(K, normal2, normal1);
1021  add_point(P2,base_im->coeff(i)*J1*gmm::vect_norm2(normal1)/J2,f);
1022  }
1023  // else { cout << "Point " << P2 << " eliminated" << endl; }
1024  }
1025  }
1026  if (what != TETRA_CYL) break;
1027  }
1028  valid_method();
1029  }
1030  };
1031 
1032 
1033  static pintegration_method
1034  quasi_polar(im_param_list &params,
1035  std::vector<dal::pstatic_stored_object> &dependencies) {
1036  GMM_ASSERT1(params.size() >= 1 && params[0].type() == 1,
1037  "Bad parameters for quasi polar integration: the first "
1038  "parameter should be an integration method");
1039  pintegration_method a = params[0].method();
1040  GMM_ASSERT1(a->type()==IM_APPROX,"need an approximate integration method");
1041  int ip1 = 0, ip2 = 0;
1042  if (a->approx_method()->structure() == bgeot::parallelepiped_structure(3)) {
1043  GMM_ASSERT1(params.size() == 1, "Bad number of parameters");
1044  } else {
1045  GMM_ASSERT1(params.size() == 2 || params.size() == 3,
1046  "Bad number of parameters : " << params.size()
1047  << " should be 2 or 3.");
1048  GMM_ASSERT1(params[1].type() == 0
1049  && params.back().type() == 0, "Bad type of parameters");
1050  ip1 = int(::floor(params[1].num() + 0.01));
1051  ip2 = int(::floor(params.back().num() + 0.01));
1052  }
1053  int N = a->approx_method()->dim();
1054  GMM_ASSERT1(N >= 2 && N <= 3 && ip1 >= 0 && ip2 >= 0 && ip1 <= N
1055  && ip2 <= N, "Bad parameters");
1056 
1057  papprox_integration
1058  pai = std::make_shared<quasi_polar_integration>(a->approx_method(),
1059  ip1, ip2);
1060  pintegration_method p = std::make_shared<integration_method>(pai);
1061  dependencies.push_back(p->approx_method()->ref_convex());
1062  dependencies.push_back(p->approx_method()->pintegration_points());
1063  return p;
1064  }
1065 
1066  static pintegration_method
1067  pyramid(im_param_list &params,
1068  std::vector<dal::pstatic_stored_object> &dependencies) {
1069  GMM_ASSERT1(params.size() == 1 && params[0].type() == 1,
1070  "Bad parameters for pyramid integration: the first "
1071  "parameter should be an integration method");
1072  pintegration_method a = params[0].method();
1073  GMM_ASSERT1(a->type()==IM_APPROX,"need an approximate integration method");
1074  int N = a->approx_method()->dim();
1075  GMM_ASSERT1(N == 3, "Bad parameters");
1076 
1077  papprox_integration
1078  pai = std::make_shared<quasi_polar_integration>(a->approx_method(), 0, 0);
1079  pintegration_method p = std::make_shared<integration_method>(pai);
1080  dependencies.push_back(p->approx_method()->ref_convex());
1081  dependencies.push_back(p->approx_method()->pintegration_points());
1082  return p;
1083  }
1084 
1085 
1086 
1087  /* ******************************************************************** */
1088  /* Naming system */
1089  /* ******************************************************************** */
1090 
1091  pintegration_method
1092  structured_composite_int_method(im_param_list &,
1093  std::vector<dal::pstatic_stored_object> &);
1094  pintegration_method HCT_composite_int_method(im_param_list &params,
1095  std::vector<dal::pstatic_stored_object> &dependencies);
1096 
1097  pintegration_method QUADC1_composite_int_method(im_param_list &params,
1098  std::vector<dal::pstatic_stored_object> &dependencies);
1099 
1100  pintegration_method pyramid_composite_int_method(im_param_list &params,
1101  std::vector<dal::pstatic_stored_object> &dependencies);
1102 
1103  struct im_naming_system : public dal::naming_system<integration_method> {
1104  im_naming_system() : dal::naming_system<integration_method>("IM") {
1105  add_suffix("NONE",im_none);
1106  add_suffix("EXACT_SIMPLEX", exact_simplex);
1107  add_suffix("PRODUCT", product_which);
1108  add_suffix("EXACT_PARALLELEPIPED",exact_parallelepiped);
1109  add_suffix("EXACT_PRISM", exact_prism);
1110  add_suffix("GAUSS1D", gauss1d);
1111  add_suffix("NC", Newton_Cotes);
1112  add_suffix("NC_PARALLELEPIPED", Newton_Cotes_para);
1113  add_suffix("NC_PRISM", Newton_Cotes_prism);
1114  add_suffix("GAUSS_PARALLELEPIPED", Gauss_paramul);
1115  add_suffix("QUASI_POLAR", quasi_polar);
1116  add_suffix("PYRAMID", pyramid);
1117  add_suffix("STRUCTURED_COMPOSITE",
1118  structured_composite_int_method);
1119  add_suffix("HCT_COMPOSITE",
1120  HCT_composite_int_method);
1121  add_suffix("QUADC1_COMPOSITE",
1122  QUADC1_composite_int_method);
1123  add_suffix("PYRAMID_COMPOSITE",
1124  pyramid_composite_int_method);
1125  add_generic_function(im_list_integration);
1126  }
1127  };
1128 
1129  pintegration_method int_method_descriptor(std::string name,
1130  bool throw_if_not_found) {
1131  size_type i = 0;
1133  (name, i, throw_if_not_found);
1134  }
1135 
1136  std::string name_of_int_method(pintegration_method p) {
1137  if (!(p.get())) return "IM_NONE";
1138  return dal::singleton<im_naming_system>::instance().shorter_name_of_method(p);
1139  }
1140 
1141  // allows the add of an integration method.
1142  void add_integration_name(std::string name,
1144  dal::singleton<im_naming_system>::instance().add_suffix(name, f);
1145  }
1146 
1147 
1148  /* Fonctions pour la ref. directe. */
1149 
1150  pintegration_method exact_simplex_im(size_type n) {
1151  DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(pintegration_method, pim, 0);
1152  DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(size_type, d, -2);
1153  if (d != n) {
1154  std::stringstream name;
1155  name << "IM_EXACT_SIMPLEX(" << n << ")";
1156  pim = int_method_descriptor(name.str());
1157  d = n;
1158  }
1159  return pim;
1160  }
1161 
1162  pintegration_method exact_parallelepiped_im(size_type n) {
1163  DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(pintegration_method, pim, 0);
1164  DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(size_type, d, -2);
1165  if (d != n) {
1166  std::stringstream name;
1167  name << "IM_EXACT_PARALLELEPIPED(" << n << ")";
1168  pim = int_method_descriptor(name.str());
1169  d = n;
1170  }
1171  return pim;
1172  }
1173 
1174  pintegration_method exact_prism_im(size_type n) {
1175  DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(pintegration_method, pim, 0);
1176  DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(size_type, d, -2);
1177  if (d != n) {
1178  std::stringstream name;
1179  name << "IM_EXACT_PRISM(" << n << ")";
1180  pim = int_method_descriptor(name.str());
1181  d = n;
1182  }
1183  return pim;
1184  }
1185 
1186  pintegration_method exact_classical_im(bgeot::pgeometric_trans pgt) {
1187  return classical_exact_im(pgt);
1188  }
1189 
1190  static pintegration_method classical_exact_im(bgeot::pconvex_structure cvs) {
1191  cvs = bgeot::basic_structure(cvs);
1192  DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(bgeot::pconvex_structure,cvs_last, 0);
1193  DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(pintegration_method, im_last, 0);
1194  bool found = false;
1195 
1196  if (cvs_last == cvs)
1197  return im_last;
1198 
1199  size_type n = cvs->dim();
1200  size_type nbp = cvs->nb_points();
1201  std::stringstream name;
1202 
1203  /* Identifying P1-simplexes. */
1204 
1205  if (nbp == n+1)
1206  if (cvs == bgeot::simplex_structure(dim_type(n)))
1207  { name << "IM_EXACT_SIMPLEX("; found = true; }
1208 
1209  /* Identifying Q1-parallelepiped. */
1210 
1211  if (!found && nbp == (size_type(1) << n))
1212  if (cvs == bgeot::parallelepiped_structure(dim_type(n)))
1213  { name << "IM_EXACT_PARALLELEPIPED("; found = true; }
1214 
1215  /* Identifying Q1-prisms. */
1216 
1217  if (!found && nbp == 2 * n)
1218  if (cvs == bgeot::prism_P1_structure(dim_type(n)))
1219  { name << "IM_EXACT_PRISM("; found = true; }
1220 
1221  // To be completed
1222 
1223  if (found) {
1224  name << int(n) << ')';
1225  im_last = int_method_descriptor(name.str());
1226  cvs_last = cvs;
1227  return im_last;
1228  }
1229 
1230  GMM_ASSERT1(false, "This element is not taken into account. Contact us");
1231  }
1232 
1233 
1234  pintegration_method classical_exact_im(bgeot::pgeometric_trans pgt) {
1235  return classical_exact_im(pgt->structure());
1236  }
1237 
1238  static pintegration_method
1239  classical_approx_im_(bgeot::pconvex_structure cvs, dim_type degree) {
1240  size_type n = cvs->dim();
1241  std::stringstream name;
1242 
1243  if(bgeot::is_torus_structure(cvs) && n == 3) n = 2;
1244 
1245  degree = std::max<dim_type>(degree, 1);
1247  if (bgeot::basic_structure(cvs) == bgeot::simplex_structure(dim_type(n))) {
1248  /* Identifying P1-simplexes. */
1249  switch (n) {
1250  case 0: return int_method_descriptor("IM_NC(0,0)");
1251  case 1: name << "IM_GAUSS1D"; break;
1252  case 2: name << "IM_TRIANGLE"; break;
1253  case 3: name << "IM_TETRAHEDRON"; break;
1254  case 4: name << "IM_SIMPLEX4D"; break;
1255  default: GMM_ASSERT1(false, "no approximate integration method "
1256  "for simplexes of dimension " << n);
1257  }
1258  for (size_type k = degree; k < size_type(degree+10); ++k) {
1259  std::stringstream name2;
1260  name2 << name.str() << "(" << k << ")";
1261  pintegration_method im = int_method_descriptor(name2.str(), false);
1262  if (im) return im;
1263  }
1264  GMM_ASSERT1(false, "could not find an " << name.str()
1265  << " of degree >= " << int(degree));
1266  } else if (bgeot::basic_structure(cvs) == bgeot::pyramid_QK_structure(1)) {
1267  GMM_ASSERT1(n == 3, "Wrong dimension");
1268  name << "IM_PYRAMID(IM_GAUSS_PARALLELEPIPED(3," << degree << "))";
1269  } else if (cvs->is_product(&a,&b) ||
1270  (bgeot::basic_structure(cvs).get() &&
1271  bgeot::basic_structure(cvs)->is_product(&a,&b))) {
1272  name << "IM_PRODUCT("
1273  << name_of_int_method(classical_approx_im_(a,degree)) << ","
1274  << name_of_int_method(classical_approx_im_(b,degree)) << ")";
1275  } else GMM_ASSERT1(false, "unknown convex structure!");
1276  return int_method_descriptor(name.str());
1277  }
1278 
1280  dim_type degree) {
1281  DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(bgeot::pgeometric_trans, pgt_last, 0);
1282  DEFINE_STATIC_THREAD_LOCAL(dim_type, degree_last);
1283  DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(pintegration_method, im_last, 0);
1284  if (pgt_last == pgt && degree == degree_last)
1285  return im_last;
1286  im_last = classical_approx_im_(pgt->structure(),degree);
1287  degree_last = degree;
1288  pgt_last = pgt;
1289  return im_last;
1290  }
1291 
1292  pintegration_method im_none() {
1293  DEFINE_STATIC_THREAD_LOCAL_INITIALIZED(pintegration_method,im_last,0);
1294  if (!im_last) im_last = int_method_descriptor("IM_NONE");
1295  return im_last;
1296  }
1297 
1298  /* try to integrate all monomials up to order 'order' and return the
1299  max. error */
1300  scalar_type test_integration_error(papprox_integration pim, dim_type order) {
1301  short_type dim = pim->dim();
1302  pintegration_method exact = classical_exact_im(pim->structure());
1303  opt_long_scalar_type error(0);
1304  for (bgeot::power_index idx(dim); idx.degree() <= order; ++idx) {
1305  opt_long_scalar_type sum(0), realsum;
1306  for (size_type i=0; i < pim->nb_points_on_convex(); ++i) {
1307  opt_long_scalar_type prod = pim->coeff(i);
1308  for (size_type d=0; d < dim; ++d)
1309  prod *= pow(opt_long_scalar_type(pim->point(i)[d]), idx[d]);
1310  sum += prod;
1311  }
1312  realsum = exact->exact_method()->int_monomial(idx);
1313  error = std::max(error, gmm::abs(realsum-sum));
1314  }
1315  return bgeot::to_scalar(error);
1316  }
1317 
1318  papprox_integration get_approx_im_or_fail(pintegration_method pim) {
1319  GMM_ASSERT1(pim->type() == IM_APPROX, "error estimate work only with "
1320  "approximate integration methods");
1321  return pim->approx_method();
1322  }
1323 
1324 } /* end of namespace getfem. */
pconvex_ref pyramid_QK_of_reference(dim_type k)
pyramidal element of reference of degree k (k = 1 or 2 only)
generation of permutations, and ranking/unranking of these.
Description of an exact integration of polynomials.
Provides mesh and mesh fem of torus.
pconvex_structure prism_P1_structure(dim_type nc)
Give a pointer on the structures of a prism of dimension d.
pintegration_method int_method_descriptor(std::string name, bool throw_if_not_found=true)
Get an integration method from its name .
does the inversion of the geometric transformation for a given convex
Integration methods (exact and approximated) on convexes.
pgeometric_trans geometric_trans_descriptor(std::string name)
Get the geometric transformation from its string name.
Tools for multithreaded, OpenMP and Boost based parallelization.
This file is generated by cubature/make_getfem_list.
pintegration_method exact_parallelepiped_im(size_type n)
return IM_EXACT_PARALLELEPIPED(n)
dim_type dim(void) const
Dimension of convex of reference.
pconvex_ref convex_ref_product(pconvex_ref a, pconvex_ref b)
tensorial product of two convex ref.
static T & instance()
Instance from the current thread.
pintegration_method exact_classical_im(bgeot::pgeometric_trans pgt) IS_DEPRECATED
use classical_exact_im instead.
long_scalar_type int_poly(const base_poly &P) const
Evaluate the integral of the polynomial P on the reference element.
Associate a name to a method descriptor and store method descriptors.
std::shared_ptr< const convex_structure > pconvex_structure
Pointer on a convex structure description.
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49
Inversion of geometric transformations.
pconvex_structure pyramid_QK_structure(dim_type k)
Give a pointer on the 3D pyramid structure for a degree k = 1 or 2.
Vector of integer (16 bits type) which represent the powers of a monomial.
Definition: bgeot_poly.h:64
pintegration_method im_none(void)
return IM_NONE
std::string name_of_int_method(pintegration_method p)
Get the string name of an integration method .
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 ...
A simple singleton implementation.
bool invert(const base_node &n, base_node &n_ref, scalar_type IN_EPS=1e-12)
given the node on the real element, returns the node on the reference element (even if it is outside ...
Naming system.
GEneric Tool for Finite Element Methods.
pintegration_method classical_exact_im(bgeot::pgeometric_trans pgt)
return an exact integration method for convex type handled by pgt.
gmm::uint16_type short_type
used as the common short type integer in the library
Definition: bgeot_config.h:79
pconvex_structure parallelepiped_structure(dim_type nc, dim_type k)
Give a pointer on the structures of a parallelepiped of dimension d.
bgeot::pconvex_structure structure(void) const
{Structure of convex of reference.
pconvex_structure simplex_structure(dim_type nc)
Give a pointer on the structures of a simplex of dimension d.
LU factorizations and determinant computation for dense matrices.
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...
pconvex_structure basic_structure(pconvex_structure cv)
Original structure (if concerned)
pintegration_method exact_prism_im(size_type n)
return IM_EXACT_PRISM(n)
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 ...
Definition: bgeot_poly.cc:46
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. ...
pintegration_method exact_simplex_im(size_type n)
return IM_EXACT_SIMPLEX(n)
pconvex_ref simplex_of_reference(dim_type nc, short_type K)
returns a simplex of reference of dimension nc and degree k
Provides mesh of torus.
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation
short_type degree() const
Gives the degree.
Definition: bgeot_poly.cc:89