34 struct emelem_comp_key_ :
virtual public dal::static_stored_object_key {
36 pintegration_method ppi;
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)
54 emelem_comp_key_(pmat_elem_type pm, pintegration_method pi,
56 { pmt = pm; ppi = pi; pgt = pg; prefer_comp_on_real_element = on_relt; }
57 emelem_comp_key_(
void) { }
60 struct emelem_comp_structure_ :
public mat_elem_computation {
61 bgeot::pgeotrans_precomp pgp;
62 ppoly_integration ppi;
63 papprox_integration pai;
65 mutable std::vector<base_tensor> mref;
66 mutable std::vector<pfem_precomp> pfp;
67 mutable std::vector<base_tensor> elmt_stored;
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;
76 bool computed_on_real_element;
78 size_type sz =
sizeof(emelem_comp_structure_) +
79 mref.capacity()*
sizeof(base_tensor) +
84 trans_reduction_pfi.size()*
sizeof(
pfem);
86 for (
size_type i=0; i < mref.size(); ++i) sz += mref[i].memsize();
90 emelem_comp_structure_(pmat_elem_type pm, pintegration_method pi,
92 bool prefer_comp_on_real_element) {
95 pgp = bgeot::geotrans_precomp(pg, pi->pintegration_points(), pi);
99 ppi = pi->exact_method(); pai = 0; is_ppi =
true;
break;
101 ppi = 0; pai = pi->approx_method(); is_ppi =
false;
break;
103 GMM_ASSERT1(
false,
"Attempt to use IM_NONE integration method " 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);
111 nbf = pgt->structure()->nb_faces();
112 dim = pgt->structure()->dim();
113 mat_elem_type::const_iterator it = pme->begin(), ite = pme->end();
116 for (
short_type k = 0; it != ite; ++it, ++k) {
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");
123 if ((*it).t != GETFEM_NONLINEAR_ && !((*it).pfi->is_equivalent())) {
125 trans_reduction.push_back(k);
126 trans_reduction_pfi.push_back((*it).pfi);
131 if ((*it).pfi->target_dim() > 1) {
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;
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_ : {
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;
156 if ((*it).pfi->target_dim() > 1) ++k;
157 if (!((*it).pfi->is_on_real_element()))
158 grad_reduction.push_back(k);
160 case GETFEM_HESSIAN_ : {
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;
170 if ((*it).pfi->target_dim() > 1) ++k;
171 if (!((*it).pfi->is_on_real_element()))
172 hess_reduction.push_back(k);
174 case GETFEM_NONLINEAR_ : {
175 if ((*it).nl_part == 0) {
177 GMM_ASSERT1(!is_ppi,
"For nonlinear terms you have " 178 "to use approximated integration");
179 computed_on_real_element =
true;
186 pfp.resize(pme->size());
187 it = pme->begin(), ite = pme->end();
188 for (
size_type k = 0; it != ite; ++it, ++k)
190 pfp[k] =
fem_precomp((*it).pfi, pai->pintegration_points(), pi);
192 elmt_stored.resize(pme->size());
194 if (!computed_on_real_element) mref.resize(nbf + 1);
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;
204 for (
size_type k = 0; it != ite; ++it, ++k) {
205 if ((*it).t == GETFEM_NONLINEAR_)
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]);
217 if ((*it).pfi && (*it).pfi->target_dim() > 1) ++mit;
219 (*it).pfi->real_base_value(ctx, elmt_stored[k], icb != 0);
221 elmt_stored[k] = pfp[k]->val(ctx.ii());
225 if ((*it).pfi && (*it).pfi->target_dim() > 1) ++mit;
227 (*it).pfi->real_grad_base_value(ctx, elmt_stored[k], icb != 0);
231 elmt_stored[k] = pfp[k]->grad(ctx.ii());
233 case GETFEM_HESSIAN_ :
235 if ((*it).pfi && (*it).pfi->target_dim() > 1) ++mit;
237 (*it).pfi->real_hess_base_value(ctx, elmt_stored[k], icb != 0);
241 base_tensor tt = pfp[k]->hess(ctx.ii());
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);
249 case GETFEM_UNIT_NORMAL_ :
252 aux_ind.resize(1); aux_ind[0] =
short_type(ctx.N());
253 elmt_stored[k].adjust_sizes(aux_ind);
255 std::copy(up.begin(), up.end(), elmt_stored[k].begin());
257 case GETFEM_GRAD_GEOTRANS_ :
258 case GETFEM_GRAD_GEOTRANS_INV_ : {
259 size_type P = gmm::mat_ncols(ctx.K()), N=ctx.N();
261 if (it->t == GETFEM_GRAD_GEOTRANS_INV_) {
262 Bt.resize(P,N); gmm::copy(gmm::transposed(ctx.B()),Bt);
264 const base_matrix &A = (it->t==GETFEM_GRAD_GEOTRANS_) ? ctx.K():Bt;
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());
271 case GETFEM_NONLINEAR_ :
272 if ((*it).nl_part != 0) {
274 if ((*it).nlt->term_num() ==
size_type(-1)) {
275 (*it).nlt->prepare(ctx, (*it).nl_part);
279 aux_ind.resize(1); aux_ind[0] = 1;
280 elmt_stored[k].adjust_sizes(aux_ind); elmt_stored[k][0] = 1.;
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];
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];
303 GMM_ASSERT1(mit == sizes.end(),
"internal error");
306 scalar_type c = J*pai->coeff(ctx.ii());
308 if (first) { t.adjust_sizes(sizes); }
309 expand_product_daxpy(t, c, first);
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]);
317 icb->exec(t, first, c);
322 void expand_product_old(base_tensor &t, scalar_type J,
bool first)
const {
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();
333 unsigned n0 = unsigned(elmt_stored[0].size());
338 base_tensor::const_iterator pts0 = pts[k0];
341 k = pme->size()-1; Vtab[k] = J;
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");
359 void expand_product_daxpy(base_tensor &t, scalar_type J,
bool first)
const {
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);
367 pts.resize(0); pts.resize(pme->size());
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());
372 if (first) memset(&(*t.begin()), 0, t.size()*
sizeof(*t.begin()));
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();
379 }
else J *= elmt_stored[k][0];
384 long n0 = int(es_end[0] - es_beg[0]);
385 base_tensor::const_iterator pts0 = pts[0];
388 k = nm-1; Vtab[k] = J;
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);
398 for (k=1; k != nm && ++pts[k] == es_end[k]; ++k)
401 GMM_ASSERT1(pt == t.end(),
"Internal error");
406 void pre_tensors_for_linear_trans(
bool volumic)
const {
408 if ((volumic && volume_computed) || (!volumic && faces_computed))
return;
411 bgeot::multi_index sizes = pme->sizes(0), mi(sizes.size());
412 bgeot::multi_index::iterator mit = sizes.begin(), mite = sizes.end();
414 for ( ; mit != mite; ++mit, ++f) f *= *mit;
416 GMM_WARNING2(
"Warning, very large elementary computations.\n" 417 <<
"Be sure you need to compute this elementary matrix.\n" 418 <<
"(sizes = " << sizes <<
" )\n");
420 base_tensor aux(sizes);
421 std::fill(aux.begin(), aux.end(), 0.0);
423 volume_computed =
true;
427 faces_computed =
true;
428 std::fill(mref.begin()+1, mref.end(), aux);
433 base_poly P(dim, 0), Q(dim, 0), R(dim, 0);
435 for ( ; !mi.finished(sizes); mi.incrementation(sizes)) {
437 mat_elem_type::const_iterator it = pme->begin(), ite = pme->end();
443 if ((*it).pfi->target_dim() > 1)
444 { ind += (*it).pfi->nb_base(0) * (*mit); ++mit; }
446 Q = ((
ppolyfem)((*it).pfi).get())->base()[ind];
450 case GETFEM_GRAD_ : Q.derivative(
short_type(*mit)); ++mit;
break;
451 case GETFEM_HESSIAN_ :
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_ :
461 "Normals, gradients of geotrans and non linear " 462 "terms are not compatible with exact integration, " 463 "use an approximate method instead");
467 if (it != ite && *mit != old_ind) {
470 for (; it != ite; ++it) {
473 if ((*it).pfi->target_dim() > 1)
474 { ind += (*it).pfi->nb_base(0) * (*mit); ++mit; }
475 R = ((
ppolyfem)((*it).pfi).get())->base()[ind];
481 case GETFEM_HESSIAN_ :
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");
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)));
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++; }
510 add_elem(mref[ind_l], ctx, 1.0, first,
false, NULL, sizes);
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());
523 fem_interpolation_context ctx(pgp, 0, 0, G, elt,
526 GMM_ASSERT1(G.ncols() == NP,
"dimensions mismatch");
528 up.resize(N); un.resize(P);
530 gmm::copy(pgt->normals()[ir-1],un);
535 if (!computed_on_real_element) {
536 pre_tensors_for_linear_trans(ir == 0);
537 const base_matrix& B = ctx.B();
538 scalar_type J=ctx.J();
540 gmm::mult(B, un, up);
543 gmm::scale(up,1.0/nup);
546 t = mref[ir]; gmm::scale(t.as_vector(), J);
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);
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);
567 if (hess_reduction.size() > 0) {
568 std::deque<short_type>::const_iterator it = hess_reduction.begin(),
569 ite = hess_reduction.end();
571 (flag ? t:taux).mat_transp_reduction(flag ? taux:t, ctx.B3(), *it);
577 bgeot::multi_index sizes = pme->sizes(elt);
580 for (
size_type ip=(ir == 0) ? 0 : pai->repart()[ir-1];
581 ip < pai->repart()[ir]; ++ip, first =
false) {
583 const base_matrix& B = ctx.B();
584 scalar_type J = ctx.J();
586 gmm::mult(B, un, up);
588 J *= nup; gmm::scale(up,1.0/nup);
590 add_elem(t, ctx, J, first,
true, icb, sizes);
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());
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) {
609 (flag ? t:taux).mat_transp_reduction(flag ? taux:t, ctx.M(), *it);
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); }
620 void compute_on_face(base_tensor &t,
const base_matrix &G,
622 mat_elem_integration_callback *icb)
const 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);
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);
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.
size_t size_type
used as the common size type in the library
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.
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
void clear(L &l)
clear (fill with zeros) a vector or matrix.
gmm::uint16_type short_type
used as the common short type integer in the library
pfem_precomp fem_precomp(pfem pf, bgeot::pstored_point_tab pspt, dal::pstatic_stored_object dep)
Handles precomputations for FEM.
Definition of the finite element methods.
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation