GetFEM++  5.3
getfem_mat_elem.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 
23 #include <deque>
24 #include "getfem/dal_singleton.h"
25 #include "getfem/getfem_fem.h"
26 #include "getfem/getfem_mat_elem.h"
27 #include "getfem/getfem_omp.h"
28 
29 namespace getfem {
30  /* ********************************************************************* */
31  /* Elementary matrices computation. */
32  /* ********************************************************************* */
33 
34  struct emelem_comp_key_ : virtual public dal::static_stored_object_key {
35  pmat_elem_type pmt;
36  pintegration_method ppi;
38  /* prefer_comp_on_real_element: compute elementary matrices on the real
39  element if possible (i.e. if no exact integration is used); this allow
40  using inline reduction during the integration */
41  bool prefer_comp_on_real_element;
42  virtual bool compare(const static_stored_object_key &oo) const {
43  const emelem_comp_key_ &o = dynamic_cast<const emelem_comp_key_ &>(oo);
44  if (pmt < o.pmt) return true;
45  if (o.pmt < pmt) return false;
46  if (ppi < o.ppi) return true;
47  if (o.ppi < ppi) return false;
48  if (pgt < o.pgt) return true;
49  if (o.pgt < pgt) return false;
50  if (prefer_comp_on_real_element < o.prefer_comp_on_real_element)
51  return true;
52  return false;
53  }
54  emelem_comp_key_(pmat_elem_type pm, pintegration_method pi,
55  bgeot::pgeometric_trans pg, bool on_relt)
56  { pmt = pm; ppi = pi; pgt = pg; prefer_comp_on_real_element = on_relt; }
57  emelem_comp_key_(void) { }
58  };
59 
60  struct emelem_comp_structure_ : public mat_elem_computation {
61  bgeot::pgeotrans_precomp pgp;
62  ppoly_integration ppi;
63  papprox_integration pai;
64  bool is_ppi;
65  mutable std::vector<base_tensor> mref;
66  mutable std::vector<pfem_precomp> pfp;
67  mutable std::vector<base_tensor> elmt_stored;
68  short_type nbf, dim;
69  std::deque<short_type> grad_reduction, hess_reduction, trans_reduction;
70  std::deque<short_type> K_reduction;
71  std::deque<pfem> trans_reduction_pfi;
72  mutable base_vector un, up;
73  mutable bool faces_computed;
74  mutable bool volume_computed;
75  bool is_linear;
76  bool computed_on_real_element;
77  size_type memsize() const {
78  size_type sz = sizeof(emelem_comp_structure_) +
79  mref.capacity()*sizeof(base_tensor) +
80  grad_reduction.size()*sizeof(short_type) +
81  K_reduction.size()*sizeof(short_type) +
82  hess_reduction.size()*sizeof(short_type) +
83  trans_reduction.size()*sizeof(short_type) +
84  trans_reduction_pfi.size()*sizeof(pfem);
85 
86  for (size_type i=0; i < mref.size(); ++i) sz += mref[i].memsize();
87  return sz;
88  }
89 
90  emelem_comp_structure_(pmat_elem_type pm, pintegration_method pi,
92  bool prefer_comp_on_real_element) {
93 
94  pgt = pg;
95  pgp = bgeot::geotrans_precomp(pg, pi->pintegration_points(), pi);
96  pme = pm;
97  switch (pi->type()) {
98  case IM_EXACT:
99  ppi = pi->exact_method(); pai = 0; is_ppi = true; break;
100  case IM_APPROX:
101  ppi = 0; pai = pi->approx_method(); is_ppi = false; break;
102  case IM_NONE:
103  GMM_ASSERT1(false, "Attempt to use IM_NONE integration method "
104  "in assembly!\n");
105  }
106 
107  faces_computed = volume_computed = false;
108  is_linear = pgt->is_linear();
109  computed_on_real_element = !is_linear || (prefer_comp_on_real_element && !is_ppi);
110  // computed_on_real_element = true;
111  nbf = pgt->structure()->nb_faces();
112  dim = pgt->structure()->dim();
113  mat_elem_type::const_iterator it = pme->begin(), ite = pme->end();
114  // size_type d = pgt->dim();
115 
116  for (short_type k = 0; it != ite; ++it, ++k) {
117  if ((*it).pfi) {
118  if ((*it).pfi->is_on_real_element()) computed_on_real_element = true;
119  GMM_ASSERT1(!is_ppi || (((*it).pfi->is_polynomial()) && is_linear
120  && !computed_on_real_element),
121  "Exact integration not allowed in this context");
122 
123  if ((*it).t != GETFEM_NONLINEAR_ && !((*it).pfi->is_equivalent())) {
124  // TODO : le numero d'indice à reduire peut changer ...
125  trans_reduction.push_back(k);
126  trans_reduction_pfi.push_back((*it).pfi);
127  }
128  }
129  switch ((*it).t) {
130  case GETFEM_BASE_ :
131  if ((*it).pfi->target_dim() > 1) {
132  ++k;
133  switch((*it).pfi->vectorial_type()) {
134  case virtual_fem::VECTORIAL_PRIMAL_TYPE:
135  K_reduction.push_back(k); break;
136  case virtual_fem::VECTORIAL_DUAL_TYPE:
137  grad_reduction.push_back(k); break;
138  default: break;
139  }
140  }
141  break;
142  case GETFEM_UNIT_NORMAL_ :
143  computed_on_real_element = true; break;
144  case GETFEM_GRAD_GEOTRANS_ :
145  case GETFEM_GRAD_GEOTRANS_INV_ :
146  ++k; computed_on_real_element = true; break;
147  case GETFEM_GRAD_ : {
148  ++k;
149  switch((*it).pfi->vectorial_type()) {
150  case virtual_fem::VECTORIAL_PRIMAL_TYPE:
151  K_reduction.push_back(k); break;
152  case virtual_fem::VECTORIAL_DUAL_TYPE:
153  grad_reduction.push_back(k); break;
154  default: break;
155  }
156  if ((*it).pfi->target_dim() > 1) ++k;
157  if (!((*it).pfi->is_on_real_element()))
158  grad_reduction.push_back(k);
159  } break;
160  case GETFEM_HESSIAN_ : {
161  ++k;
162  switch((*it).pfi->vectorial_type()) {
163  case virtual_fem::VECTORIAL_PRIMAL_TYPE:
164  K_reduction.push_back(k); break;
165  case virtual_fem::VECTORIAL_DUAL_TYPE:
166  grad_reduction.push_back(k); break;
167  default: break;
168  }
169 
170  if ((*it).pfi->target_dim() > 1) ++k;
171  if (!((*it).pfi->is_on_real_element()))
172  hess_reduction.push_back(k);
173  } break;
174  case GETFEM_NONLINEAR_ : {
175  if ((*it).nl_part == 0) {
176  k = short_type(k+(*it).nlt->sizes(size_type(-1)).size()-1);
177  GMM_ASSERT1(!is_ppi, "For nonlinear terms you have "
178  "to use approximated integration");
179  computed_on_real_element = true;
180  }
181  } break;
182  }
183  }
184 
185  if (!is_ppi) {
186  pfp.resize(pme->size());
187  it = pme->begin(), ite = pme->end();
188  for (size_type k = 0; it != ite; ++it, ++k)
189  if ((*it).pfi)
190  pfp[k] = fem_precomp((*it).pfi, pai->pintegration_points(), pi);
191  else pfp[k] = 0;
192  elmt_stored.resize(pme->size());
193  }
194  if (!computed_on_real_element) mref.resize(nbf + 1);
195  }
196 
197  void add_elem(base_tensor &t, fem_interpolation_context& ctx,
198  scalar_type J, bool first, bool trans,
199  mat_elem_integration_callback *icb,
200  bgeot::multi_index sizes) const {
201  mat_elem_type::const_iterator it = pme->begin(), ite = pme->end();
202  bgeot::multi_index aux_ind;
203 
204  for (size_type k = 0; it != ite; ++it, ++k) {
205  if ((*it).t == GETFEM_NONLINEAR_)
206  (*it).nlt->term_num() = size_type(-1);
207  }
208  it = pme->begin();
209 
210  // incrementing "mit" should match increments of "j" in mat_elem_type::sizes
211  bgeot::multi_index::iterator mit = sizes.begin();
212  for (size_type k = 0; it != ite; ++it, ++k, ++mit) {
213  if (pfp[k]) ctx.set_pfp(pfp[k]);
214 
215  switch ((*it).t) {
216  case GETFEM_BASE_ :
217  if ((*it).pfi && (*it).pfi->target_dim() > 1) ++mit;
218  if (trans)
219  (*it).pfi->real_base_value(ctx, elmt_stored[k], icb != 0);
220  else
221  elmt_stored[k] = pfp[k]->val(ctx.ii());
222  break;
223  case GETFEM_GRAD_ :
224  ++mit;
225  if ((*it).pfi && (*it).pfi->target_dim() > 1) ++mit;
226  if (trans) {
227  (*it).pfi->real_grad_base_value(ctx, elmt_stored[k], icb != 0);
228  *mit = short_type(ctx.N());
229  }
230  else
231  elmt_stored[k] = pfp[k]->grad(ctx.ii());
232  break;
233  case GETFEM_HESSIAN_ :
234  ++mit;
235  if ((*it).pfi && (*it).pfi->target_dim() > 1) ++mit;
236  if (trans) {
237  (*it).pfi->real_hess_base_value(ctx, elmt_stored[k], icb != 0);
238  *mit = short_type(gmm::sqr(ctx.N()));
239  }
240  else {
241  base_tensor tt = pfp[k]->hess(ctx.ii());
242  aux_ind.resize(3);
243  aux_ind[2] = gmm::sqr(tt.sizes()[2]); aux_ind[1] = tt.sizes()[1];
244  aux_ind[0] = tt.sizes()[0];
245  tt.adjust_sizes(aux_ind);
246  elmt_stored[k] = tt;
247  }
248  break;
249  case GETFEM_UNIT_NORMAL_ :
250  *mit = short_type(ctx.N());
251  {
252  aux_ind.resize(1); aux_ind[0] = short_type(ctx.N());
253  elmt_stored[k].adjust_sizes(aux_ind);
254  }
255  std::copy(up.begin(), up.end(), elmt_stored[k].begin());
256  break;
257  case GETFEM_GRAD_GEOTRANS_ :
258  case GETFEM_GRAD_GEOTRANS_INV_ : {
259  size_type P = gmm::mat_ncols(ctx.K()), N=ctx.N();
260  base_matrix Bt;
261  if (it->t == GETFEM_GRAD_GEOTRANS_INV_) {
262  Bt.resize(P,N); gmm::copy(gmm::transposed(ctx.B()),Bt);
263  }
264  const base_matrix &A = (it->t==GETFEM_GRAD_GEOTRANS_) ? ctx.K():Bt;
265  aux_ind.resize(2);
266  *mit++ = aux_ind[0] = short_type(gmm::mat_nrows(A));
267  *mit = aux_ind[1] = short_type(gmm::mat_ncols(A));
268  elmt_stored[k].adjust_sizes(aux_ind);
269  std::copy(A.begin(), A.end(), elmt_stored[k].begin());
270  } break;
271  case GETFEM_NONLINEAR_ :
272  if ((*it).nl_part != 0) { /* for auxiliary fem of nonlinear_term,*/
273  /* the "prepare" method is called */
274  if ((*it).nlt->term_num() == size_type(-1)) {
275  (*it).nlt->prepare(ctx, (*it).nl_part);
276  /* the dummy assistant multiplies everybody by 1
277  -> not efficient ! */
278  }
279  aux_ind.resize(1); aux_ind[0] = 1;
280  elmt_stored[k].adjust_sizes(aux_ind); elmt_stored[k][0] = 1.;
281  } else {
282  if ((*it).nlt->term_num() == size_type(-1)) {
283  const bgeot::multi_index &nltsizes
284  = (*it).nlt->sizes(ctx.convex_num());
285  elmt_stored[k].adjust_sizes(nltsizes);
286  (*it).nlt->compute(ctx, elmt_stored[k]);
287  (*it).nlt->term_num() = k;
288  for (dim_type ii = 0; ii < nltsizes.size(); ++ii)
289  *mit++ = nltsizes[ii];
290  --mit;
291  } else {
292  elmt_stored[k] = elmt_stored[(*it).nlt->term_num()];
293  const bgeot::multi_index &nltsizes = elmt_stored[k].sizes();
294  for (dim_type ii = 0; ii < nltsizes.size(); ++ii)
295  *mit++ = nltsizes[ii];
296  --mit;
297  }
298  }
299  break;
300  }
301  }
302 
303  GMM_ASSERT1(mit == sizes.end(), "internal error");
304 
305  //expand_product_old(t,J*pai->coeff(ctx.ii()), first);
306  scalar_type c = J*pai->coeff(ctx.ii());
307  if (!icb) {
308  if (first) { t.adjust_sizes(sizes); }
309  expand_product_daxpy(t, c, first);
310  } else {
311  icb->eltm.resize(0);
312  for (unsigned k=0; k != pme->size(); ++k) {
313  if (icb && !((*pme)[k].t == GETFEM_NONLINEAR_
314  && (*pme)[k].nl_part != 0))
315  icb->eltm.push_back(&elmt_stored[k]);
316  }
317  icb->exec(t, first, c);
318  }
319  }
320 
321 
322  void expand_product_old(base_tensor &t, scalar_type J, bool first) const {
323  scalar_type V;
324  size_type k;
325  if (first) std::fill(t.begin(), t.end(), 0.0);
326  base_tensor::iterator pt = t.begin();
327  std::vector<base_tensor::const_iterator> pts(pme->size());
328  std::vector<scalar_type> Vtab(pme->size());
329  for (k = 0; k < pme->size(); ++k)
330  pts[k] = elmt_stored[k].begin();
331 
332  size_type k0 = 0;
333  unsigned n0 = unsigned(elmt_stored[0].size());
334  /*while (elmt_stored[k0].size() == 1 && k0+1 < pme->size()) {
335  J *= elmt_stored[k0][0];
336  ++k0; n0 = elmt_stored[k0].size();
337  }*/
338  base_tensor::const_iterator pts0 = pts[k0];
339 
340 
341  k = pme->size()-1; Vtab[k] = J;
342  /* very heavy expansion .. takes much time */
343  do {
344  for (V = Vtab[k]; k!=k0; --k)
345  Vtab[k-1] = V = *pts[k] * V;
346  for (k=0; k < n0; ++k)
347  *pt++ += V * pts0[k];
348  for (k=k0+1; k != pme->size() && ++pts[k] == elmt_stored[k].end(); ++k)
349  pts[k] = elmt_stored[k].begin();
350  } while (k != pme->size());
351  GMM_ASSERT1(pt == t.end(), "Internal error");
352  }
353 
354  /* do the tensorial product using the blas function daxpy (much more
355  efficient than a loop).
356 
357  efficiency is maximized when the first tensor has a large dimension
358  */
359  void expand_product_daxpy(base_tensor &t, scalar_type J, bool first)const {
360  size_type k;
361  base_tensor::iterator pt = t.begin();
362  DEFINE_STATIC_THREAD_LOCAL(std::vector<base_tensor::const_iterator>, pts);
363  DEFINE_STATIC_THREAD_LOCAL(std::vector<base_tensor::const_iterator>,es_beg);
364  DEFINE_STATIC_THREAD_LOCAL(std::vector<base_tensor::const_iterator>,es_end);
365  DEFINE_STATIC_THREAD_LOCAL(std::vector<scalar_type>,Vtab);
366 
367  pts.resize(0); pts.resize(pme->size()); // resize(0) necessary, do not remove
368  es_beg.resize(0); es_beg.resize(pme->size());
369  es_end.resize(0); es_end.resize(pme->size());
370  Vtab.resize(pme->size());
371  size_type nm = 0;
372  if (first) memset(&(*t.begin()), 0, t.size()*sizeof(*t.begin())); //std::fill(t.begin(), t.end(), 0.0);
373  for (k = 0, nm = 0; k < pme->size(); ++k) {
374  if (elmt_stored[k].size() != 1) {
375  es_beg[nm] = elmt_stored[k].begin();
376  es_end[nm] = elmt_stored[k].end();
377  pts[nm] = elmt_stored[k].begin();
378  ++nm;
379  } else J *= elmt_stored[k][0];
380  }
381  if (nm == 0) {
382  t[0] += J;
383  } else {
384  long n0 = int(es_end[0] - es_beg[0]);
385  base_tensor::const_iterator pts0 = pts[0];
386 
387  /* very heavy reduction .. takes much time */
388  k = nm-1; Vtab[k] = J;
389  long one = 1;
390  scalar_type V;
391  do {
392  for (V = Vtab[k]; k; --k)
393  Vtab[k-1] = V = *pts[k] * V;
394  GMM_ASSERT1(pt+n0 <= t.end(), "Internal error");
395  gmm::daxpy_(&n0, &V, const_cast<double*>(&(pts0[0])), &one,
396  (double*)&(*pt), &one);
397  pt+=n0;
398  for (k=1; k != nm && ++pts[k] == es_end[k]; ++k)
399  pts[k] = es_beg[k];
400  } while (k != nm);
401  GMM_ASSERT1(pt == t.end(), "Internal error");
402  }
403  }
404 
405 
406  void pre_tensors_for_linear_trans(bool volumic) const {
407 
408  if ((volumic && volume_computed) || (!volumic && faces_computed)) return;
409  // scalar_type exectime = ftool::uclock_sec();
410 
411  bgeot::multi_index sizes = pme->sizes(0), mi(sizes.size());
412  bgeot::multi_index::iterator mit = sizes.begin(), mite = sizes.end();
413  size_type f = 1;
414  for ( ; mit != mite; ++mit, ++f) f *= *mit;
415  if (f > 1000000)
416  GMM_WARNING2("Warning, very large elementary computations.\n"
417  << "Be sure you need to compute this elementary matrix.\n"
418  << "(sizes = " << sizes << " )\n");
419 
420  base_tensor aux(sizes);
421  std::fill(aux.begin(), aux.end(), 0.0);
422  if (volumic) {
423  volume_computed = true;
424  mref[0] = aux;
425  }
426  else {
427  faces_computed = true;
428  std::fill(mref.begin()+1, mref.end(), aux);
429  }
430 
431  if (is_ppi) // pour accelerer, il faudrait précalculer les dérivées
432  {
433  base_poly P(dim, 0), Q(dim, 0), R(dim, 0);
434  size_type old_ind = size_type(-1), ind;
435  for ( ; !mi.finished(sizes); mi.incrementation(sizes)) {
436 
437  mat_elem_type::const_iterator it = pme->begin(), ite = pme->end();
438  mit = mi.begin();
439 
440  ind = *mit; ++mit;
441 
442  if ((*it).pfi) {
443  if ((*it).pfi->target_dim() > 1)
444  { ind += (*it).pfi->nb_base(0) * (*mit); ++mit; }
445 
446  Q = ((ppolyfem)((*it).pfi).get())->base()[ind];
447  }
448 
449  switch ((*it).t) {
450  case GETFEM_GRAD_ : Q.derivative(short_type(*mit)); ++mit; break;
451  case GETFEM_HESSIAN_ :
452  Q.derivative(short_type(*mit % dim));
453  Q.derivative(short_type(*mit / dim));
454  ++mit; break;
455  case GETFEM_BASE_ : break;
456  case GETFEM_GRAD_GEOTRANS_:
457  case GETFEM_GRAD_GEOTRANS_INV_:
458  case GETFEM_UNIT_NORMAL_ :
459  case GETFEM_NONLINEAR_ :
460  GMM_ASSERT1(false,
461  "Normals, gradients of geotrans and non linear "
462  "terms are not compatible with exact integration, "
463  "use an approximate method instead");
464  }
465  ++it;
466 
467  if (it != ite && *mit != old_ind) {
468  old_ind = *mit;
469  P.one();
470  for (; it != ite; ++it) {
471  ind = *mit; ++mit;
472 
473  if ((*it).pfi->target_dim() > 1)
474  { ind += (*it).pfi->nb_base(0) * (*mit); ++mit; }
475  R = ((ppolyfem)((*it).pfi).get())->base()[ind];
476 
477  switch ((*it).t) {
478  case GETFEM_GRAD_ :
479  R.derivative(short_type(*mit)); ++mit;
480  break;
481  case GETFEM_HESSIAN_ :
482  R.derivative(short_type(*mit % dim));
483  R.derivative(short_type(*mit / dim));
484  ++mit; break;
485  case GETFEM_BASE_ : break;
486  case GETFEM_UNIT_NORMAL_ :
487  case GETFEM_GRAD_GEOTRANS_:
488  case GETFEM_GRAD_GEOTRANS_INV_ :
489  case GETFEM_NONLINEAR_ :
490  GMM_ASSERT1(false, "No nonlinear term allowed here");
491  }
492  P *= R;
493  }
494  }
495  R = P * Q;
496  if (volumic) mref[0](mi) = bgeot::to_scalar(ppi->int_poly(R));
497  for (f = 0; f < nbf && !volumic; ++f)
498  mref[f+1](mi) = bgeot::to_scalar(ppi->int_poly_on_face(R, short_type(f)));
499  }
500  }
501  else {
502  bool first = true;
503  fem_interpolation_context ctx;
504  size_type ind_l = 0, nb_ptc = pai->nb_points_on_convex(),
505  nb_pt_l = nb_ptc, nb_pt_tot =(volumic ? nb_ptc : pai->nb_points());
506  for (size_type ip = (volumic ? 0:nb_ptc); ip < nb_pt_tot; ++ip) {
507  while (ip == nb_pt_l && ind_l < nbf)
508  { nb_pt_l += pai->nb_points_on_face(short_type(ind_l)); ind_l++; }
509  ctx.set_ii(ip);
510  add_elem(mref[ind_l], ctx, 1.0, first, false, NULL, sizes);
511  first = false;
512  }
513  }
514  // cout << "precompute Mat elem computation time : "
515  // << ftool::uclock_sec() - exectime << endl;
516  }
517 
518 
519  void compute(base_tensor &t, const base_matrix &G, short_type ir,
520  size_type elt, mat_elem_integration_callback *icb = 0) const {
521  dim_type P = dim_type(dim), N = dim_type(G.nrows());
522  short_type NP = short_type(pgt->nb_points());
523  fem_interpolation_context ctx(pgp, 0, 0, G, elt,
524  short_type(ir-1));
525 
526  GMM_ASSERT1(G.ncols() == NP, "dimensions mismatch");
527  if (ir > 0) {
528  up.resize(N); un.resize(P);
529  //un = pgt->normals()[ir-1];
530  gmm::copy(pgt->normals()[ir-1],un);
531  }
532  base_tensor taux;
533  bool flag = false;
534 
535  if (!computed_on_real_element) {
536  pre_tensors_for_linear_trans(ir == 0);
537  const base_matrix& B = ctx.B(); // compute B and J
538  scalar_type J=ctx.J();
539  if (ir > 0) {
540  gmm::mult(B, un, up);
541  scalar_type nup = gmm::vect_norm2(up);
542  J *= nup; //up /= nup;
543  gmm::scale(up,1.0/nup);
544  }
545 
546  t = mref[ir]; gmm::scale(t.as_vector(), J);
547 
548  if (grad_reduction.size() > 0) {
549  std::deque<short_type>::const_iterator it = grad_reduction.begin(),
550  ite = grad_reduction.end();
551  for ( ; it != ite; ++it) {
552  (flag ? t:taux).mat_transp_reduction(flag ? taux:t, B, *it);
553  flag = !flag;
554  }
555  }
556 
557  if (K_reduction.size() > 0) {
558  std::deque<short_type>::const_iterator it = K_reduction.begin(),
559  ite = K_reduction.end();
560  for ( ; it != ite; ++it) {
561  (flag ? t:taux).mat_transp_reduction(flag ? taux:t, ctx.K(), *it);
562  // (flag ? t:taux).mat_transp_reduction(flag ? taux:t, B, *it);
563  flag = !flag;
564  }
565  }
566 
567  if (hess_reduction.size() > 0) {
568  std::deque<short_type>::const_iterator it = hess_reduction.begin(),
569  ite = hess_reduction.end();
570  for (short_type l = 1; it != ite; ++it, l = short_type(l*2)) {
571  (flag ? t:taux).mat_transp_reduction(flag ? taux:t, ctx.B3(), *it);
572  flag = !flag;
573  }
574  }
575 
576  } else { // non linear transformation and methods defined on real elements
577  bgeot::multi_index sizes = pme->sizes(elt);
578 
579  bool first = true;
580  for (size_type ip=(ir == 0) ? 0 : pai->repart()[ir-1];
581  ip < pai->repart()[ir]; ++ip, first = false) {
582  ctx.set_ii(ip);
583  const base_matrix& B = ctx.B(); // J computed as side-effect
584  scalar_type J = ctx.J();
585  if (ir > 0) {
586  gmm::mult(B, un, up);
587  scalar_type nup = gmm::vect_norm2(up);
588  J *= nup; /*up /= nup;*/gmm::scale(up,1.0/nup);
589  }
590  add_elem(t, ctx, J, first, true, icb, sizes);
591  }
592 
593  // GMM_ASSERT1(!first, "No integration point on this element.");
594  if (first) {
595  GMM_WARNING3("No integration point on this element. "
596  "Caution, returning a null tensor");
597  t.adjust_sizes(sizes); gmm::clear(t.as_vector());
598  }
599  }
600 
601  /* Applying linear transformation for non tau-equivalent elements. */
602 
603  if (trans_reduction.size() > 0 && !icb) {
604  std::deque<short_type>::const_iterator it = trans_reduction.begin(),
605  ite = trans_reduction.end();
606  std::deque<pfem>::const_iterator iti = trans_reduction_pfi.begin();
607  for ( ; it != ite; ++it, ++iti) {
608  ctx.set_pf(*iti); // cout << "M = " << ctx.M() << endl;
609  (flag ? t:taux).mat_transp_reduction(flag ? taux:t, ctx.M(), *it);
610  flag = !flag;
611  }
612  }
613  if (flag) t = taux;
614  }
615 
616  void compute(base_tensor &t, const base_matrix &G, size_type elt,
617  mat_elem_integration_callback *icb) const
618  { compute(t, G, 0, elt, icb); }
619 
620  void compute_on_face(base_tensor &t, const base_matrix &G,
621  short_type f, size_type elt,
622  mat_elem_integration_callback *icb) const
623  { compute(t, G, short_type(f+1), elt, icb); }
624  };
625 
626  pmat_elem_computation mat_elem(pmat_elem_type pm, pintegration_method pi,
628  bool prefer_comp_on_real_element) {
629  dal::pstatic_stored_object_key
630  pk = std::make_shared<emelem_comp_key_>(pm, pi, pg,
631  prefer_comp_on_real_element);
632  dal::pstatic_stored_object o = dal::search_stored_object(pk);
633  if (o) return std::dynamic_pointer_cast<const mat_elem_computation>(o);
634  pmat_elem_computation
635  p = std::make_shared<emelem_comp_structure_>
636  (pm, pi, pg, prefer_comp_on_real_element);
637  dal::add_stored_object(pk, p, pm, pi, pg);
638  return p;
639  }
640 
641 
642 } /* end of namespace getfem. */
643 
pmat_elem_computation mat_elem(pmat_elem_type pm, pintegration_method pi, bgeot::pgeometric_trans pg, bool prefer_comp_on_real_element=false)
allocate a structure for computation (integration over elements or faces of elements) of elementary t...
Tools for multithreaded, OpenMP and Boost based parallelization.
pstatic_stored_object search_stored_object(pstatic_stored_object_key k)
Gives a pointer to an object from a key pointer.
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2(const V &v)
Euclidean norm of a vector.
Definition: gmm_blas.h:557
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:49
void add_stored_object(pstatic_stored_object_key k, pstatic_stored_object o, permanence perm)
Add an object with two optional dependencies.
A simple singleton implementation.
const fem< bgeot::base_poly > * ppolyfem
Classical polynomial FEM.
Definition: getfem_fem.h:594
elementary computations (used by the generic assembly).
GEneric Tool for Finite Element Methods.
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
Definition: getfem_fem.h:239
void clear(L &l)
clear (fill with zeros) a vector or matrix.
Definition: gmm_blas.h:59
gmm::uint16_type short_type
used as the common short type integer in the library
Definition: bgeot_config.h:79
pfem_precomp fem_precomp(pfem pf, bgeot::pstored_point_tab pspt, dal::pstatic_stored_object dep)
Handles precomputations for FEM.
Definition: getfem_fem.cc:4051
Definition of the finite element methods.
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation