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