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