33 struct emelem_comp_key_ :
virtual public dal::static_stored_object_key {
35 pintegration_method ppi;
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;
51 bool equal(
const static_stored_object_key &oo)
const override{
52 auto &o =
dynamic_cast<const emelem_comp_key_ &
>(oo);
54 if (pmt == o.pmt && ppi == o.ppi && pgt == o.pgt)
return true;
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;
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;
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;
70 emelem_comp_key_(pmat_elem_type pm, pintegration_method pi,
72 { pmt = pm; ppi = pi; pgt = pg; prefer_comp_on_real_element = on_relt; }
73 emelem_comp_key_(
void) { }
76 struct emelem_comp_structure_ :
public mat_elem_computation {
77 bgeot::pgeotrans_precomp pgp;
78 ppoly_integration ppi;
79 papprox_integration pai;
81 mutable std::vector<base_tensor> mref;
82 mutable std::vector<pfem_precomp> pfp;
83 mutable std::vector<base_tensor> elmt_stored;
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;
92 bool computed_on_real_element;
94 size_type sz =
sizeof(emelem_comp_structure_) +
95 mref.capacity()*
sizeof(base_tensor) +
100 trans_reduction_pfi.size()*
sizeof(
pfem);
102 for (
size_type i=0; i < mref.size(); ++i) sz += mref[i].memsize();
106 emelem_comp_structure_(pmat_elem_type pm, pintegration_method pi,
108 bool prefer_comp_on_real_element) {
111 pgp = bgeot::geotrans_precomp(pg, pi->pintegration_points(), pi);
113 switch (pi->type()) {
115 ppi = pi->exact_method(); pai = 0; is_ppi =
true;
break;
117 ppi = 0; pai = pi->approx_method(); is_ppi =
false;
break;
119 GMM_ASSERT1(
false,
"Attempt to use IM_NONE integration method "
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);
127 nbf = pgt->structure()->nb_faces();
128 dim = pgt->structure()->dim();
129 mat_elem_type::const_iterator it = pme->begin(), ite = pme->end();
132 for (
short_type k = 0; it != ite; ++it, ++k) {
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");
139 if ((*it).t != GETFEM_NONLINEAR_ && !((*it).pfi->is_equivalent())) {
141 trans_reduction.push_back(k);
142 trans_reduction_pfi.push_back((*it).pfi);
147 if ((*it).pfi->target_dim() > 1) {
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;
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_ : {
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;
172 if ((*it).pfi->target_dim() > 1) ++k;
173 if (!((*it).pfi->is_on_real_element()))
174 grad_reduction.push_back(k);
176 case GETFEM_HESSIAN_ : {
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;
186 if ((*it).pfi->target_dim() > 1) ++k;
187 if (!((*it).pfi->is_on_real_element()))
188 hess_reduction.push_back(k);
190 case GETFEM_NONLINEAR_ : {
191 if ((*it).nl_part == 0) {
193 GMM_ASSERT1(!is_ppi,
"For nonlinear terms you have "
194 "to use approximated integration");
195 computed_on_real_element =
true;
202 pfp.resize(pme->size());
203 it = pme->begin(), ite = pme->end();
204 for (
size_type k = 0; it != ite; ++it, ++k)
206 pfp[k] =
fem_precomp((*it).pfi, pai->pintegration_points(), pi);
208 elmt_stored.resize(pme->size());
210 if (!computed_on_real_element) mref.resize(nbf + 1);
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;
220 for (
size_type k = 0; it != ite; ++it, ++k) {
221 if ((*it).t == GETFEM_NONLINEAR_)
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]);
233 if ((*it).pfi && (*it).pfi->target_dim() > 1) ++mit;
235 (*it).pfi->real_base_value(ctx, elmt_stored[k], icb != 0);
237 elmt_stored[k] = pfp[k]->val(ctx.ii());
241 if ((*it).pfi && (*it).pfi->target_dim() > 1) ++mit;
243 (*it).pfi->real_grad_base_value(ctx, elmt_stored[k], icb != 0);
247 elmt_stored[k] = pfp[k]->grad(ctx.ii());
249 case GETFEM_HESSIAN_ :
251 if ((*it).pfi && (*it).pfi->target_dim() > 1) ++mit;
253 (*it).pfi->real_hess_base_value(ctx, elmt_stored[k], icb != 0);
257 base_tensor tt = pfp[k]->hess(ctx.ii());
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);
265 case GETFEM_UNIT_NORMAL_ :
268 aux_ind.resize(1); aux_ind[0] =
short_type(ctx.N());
269 elmt_stored[k].adjust_sizes(aux_ind);
271 std::copy(up.begin(), up.end(), elmt_stored[k].begin());
273 case GETFEM_GRAD_GEOTRANS_ :
274 case GETFEM_GRAD_GEOTRANS_INV_ : {
275 size_type P = gmm::mat_ncols(ctx.K()), N=ctx.N();
277 if (it->t == GETFEM_GRAD_GEOTRANS_INV_) {
278 Bt.resize(P,N);
gmm::copy(gmm::transposed(ctx.B()),Bt);
280 const base_matrix &A = (it->t==GETFEM_GRAD_GEOTRANS_) ? ctx.K():Bt;
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());
287 case GETFEM_NONLINEAR_ :
288 if ((*it).nl_part != 0) {
290 if ((*it).nlt->term_num() ==
size_type(-1)) {
291 (*it).nlt->prepare(ctx, (*it).nl_part);
295 aux_ind.resize(1); aux_ind[0] = 1;
296 elmt_stored[k].adjust_sizes(aux_ind); elmt_stored[k][0] = 1.;
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];
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];
319 GMM_ASSERT1(mit == sizes.end(),
"internal error");
322 scalar_type c = J*pai->coeff(ctx.ii());
324 if (first) { t.adjust_sizes(sizes); }
325 expand_product_daxpy(t, c, first);
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]);
333 icb->exec(t, first, c);
338 void expand_product_old(base_tensor &t, scalar_type J,
bool first)
const {
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();
349 unsigned n0 = unsigned(elmt_stored[0].size());
354 base_tensor::const_iterator pts0 = pts[k0];
357 k = pme->size()-1; Vtab[k] = J;
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");
375 void expand_product_daxpy(base_tensor &t, scalar_type J,
bool first)
const {
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;
383 pts.resize(0); pts.resize(pme->size());
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());
389 memset(&(*t.begin()), 0, t.size()*
sizeof(*t.begin()));
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();
397 J *= elmt_stored[k][0];
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);
408 base_tensor::const_iterator pts0 = pts[0];
411 k = nm-1; Vtab[k] = J;
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);
422 for (k=0; k < n0; ++k)
425 for (k=1; k != nm && ++pts[k] == es_end[k]; ++k)
428 GMM_ASSERT1(pt == t.end(),
"Internal error");
433 void pre_tensors_for_linear_trans(
bool volumic)
const {
435 if ((volumic && volume_computed) || (!volumic && faces_computed))
439 bgeot::multi_index sizes = pme->sizes(0), mi(sizes.size());
440 bgeot::multi_index::iterator mit = sizes.begin(), mite = sizes.end();
442 for ( ; mit != mite; ++mit, ++f) f *= *mit;
444 GMM_WARNING2(
"Warning, very large elementary computations.\n"
445 <<
"Be sure you need to compute this elementary matrix.\n"
446 <<
"(sizes = " << sizes <<
" )\n");
448 base_tensor aux(sizes);
449 std::fill(aux.begin(), aux.end(), 0.0);
451 volume_computed =
true;
455 faces_computed =
true;
456 std::fill(mref.begin()+1, mref.end(), aux);
461 base_poly P(dim, 0), Q(dim, 0), R(dim, 0);
463 for ( ; !mi.finished(sizes); mi.incrementation(sizes)) {
465 mat_elem_type::const_iterator it = pme->begin(), ite = pme->end();
471 if ((*it).pfi->target_dim() > 1)
472 { ind += (*it).pfi->nb_base(0) * (*mit); ++mit; }
474 Q = ((
ppolyfem)((*it).pfi).get())->base()[ind];
478 case GETFEM_GRAD_ : Q.derivative(
short_type(*mit)); ++mit;
break;
479 case GETFEM_HESSIAN_ :
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_ :
489 "Normals, gradients of geotrans and non linear "
490 "terms are not compatible with exact integration, "
491 "use an approximate method instead");
495 if (it != ite && *mit != old_ind) {
498 for (; it != ite; ++it) {
501 if ((*it).pfi->target_dim() > 1)
502 { ind += (*it).pfi->nb_base(0) * (*mit); ++mit; }
503 R = ((
ppolyfem)((*it).pfi).get())->base()[ind];
509 case GETFEM_HESSIAN_ :
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");
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)));
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++; }
538 add_elem(mref[ind_l], ctx, 1.0, first,
false, NULL, sizes);
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());
551 fem_interpolation_context ctx(pgp, 0, 0, G, elt,
554 GMM_ASSERT1(G.ncols() == NP,
"dimensions mismatch");
556 up.resize(N); un.resize(P);
563 if (!computed_on_real_element) {
564 pre_tensors_for_linear_trans(ir == 0);
565 const base_matrix& B = ctx.B();
566 scalar_type J=ctx.J();
571 gmm::scale(up,1.0/nup);
574 t = mref[ir]; gmm::scale(t.as_vector(), J);
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);
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);
595 if (hess_reduction.size() > 0) {
596 std::deque<short_type>::const_iterator it = hess_reduction.begin(),
597 ite = hess_reduction.end();
599 (flag ? t:taux).mat_transp_reduction(flag ? taux:t, ctx.B3(), *it);
605 bgeot::multi_index sizes = pme->sizes(elt);
608 for (
size_type ip=(ir == 0) ? 0 : pai->repart()[ir-1];
609 ip < pai->repart()[ir]; ++ip, first =
false) {
611 const base_matrix& B = ctx.B();
612 scalar_type J = ctx.J();
616 J *= nup; gmm::scale(up,1.0/nup);
618 add_elem(t, ctx, J, first,
true, icb, sizes);
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());
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) {
637 (flag ? t:taux).mat_transp_reduction(flag ? taux:t, ctx.M(), *it);
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); }
648 void compute_on_face(base_tensor &t,
const base_matrix &G,
650 mat_elem_integration_callback *icb)
const
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);
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);
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)
*/
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2(const V &v)
Euclidean norm of a vector.
void clear(L &l)
clear (fill with zeros) a vector or matrix.
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*/
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
pfem_precomp fem_precomp(pfem pf, bgeot::pstored_point_tab pspt, dal::pstatic_stored_object dep)
Handles precomputations for FEM.
const fem< bgeot::base_poly > * ppolyfem
Classical polynomial FEM.
gmm::uint16_type short_type
used as the common short type integer in the library
size_t size_type
used as the common size type in the library
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...