34 struct emelem_comp_key_ :
virtual public dal::static_stored_object_key {
36 pintegration_method ppi;
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;
52 bool equal(
const static_stored_object_key &oo)
const override{
53 auto &o =
dynamic_cast<const emelem_comp_key_ &
>(oo);
55 if (pmt == o.pmt && ppi == o.ppi && pgt == o.pgt)
return true;
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;
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;
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;
71 emelem_comp_key_(pmat_elem_type pm, pintegration_method pi,
73 { pmt = pm; ppi = pi; pgt = pg; prefer_comp_on_real_element = on_relt; }
74 emelem_comp_key_(
void) { }
77 struct emelem_comp_structure_ :
public mat_elem_computation {
78 bgeot::pgeotrans_precomp pgp;
79 ppoly_integration ppi;
80 papprox_integration pai;
82 mutable std::vector<base_tensor> mref;
83 mutable std::vector<pfem_precomp> pfp;
84 mutable std::vector<base_tensor> elmt_stored;
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;
93 bool computed_on_real_element;
95 size_type sz =
sizeof(emelem_comp_structure_) +
96 mref.capacity()*
sizeof(base_tensor) +
101 trans_reduction_pfi.size()*
sizeof(
pfem);
103 for (
size_type i=0; i < mref.size(); ++i) sz += mref[i].memsize();
107 emelem_comp_structure_(pmat_elem_type pm, pintegration_method pi,
109 bool prefer_comp_on_real_element) {
112 pgp = bgeot::geotrans_precomp(pg, pi->pintegration_points(), pi);
114 switch (pi->type()) {
116 ppi = pi->exact_method(); pai = 0; is_ppi =
true;
break;
118 ppi = 0; pai = pi->approx_method(); is_ppi =
false;
break;
120 GMM_ASSERT1(
false,
"Attempt to use IM_NONE integration method "
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);
128 nbf = pgt->structure()->nb_faces();
129 dim = pgt->structure()->dim();
130 mat_elem_type::const_iterator it = pme->begin(), ite = pme->end();
133 for (
short_type k = 0; it != ite; ++it, ++k) {
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");
140 if ((*it).t != GETFEM_NONLINEAR_ && !((*it).pfi->is_equivalent())) {
142 trans_reduction.push_back(k);
143 trans_reduction_pfi.push_back((*it).pfi);
148 if ((*it).pfi->target_dim() > 1) {
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;
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_ : {
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;
173 if ((*it).pfi->target_dim() > 1) ++k;
174 if (!((*it).pfi->is_on_real_element()))
175 grad_reduction.push_back(k);
177 case GETFEM_HESSIAN_ : {
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;
187 if ((*it).pfi->target_dim() > 1) ++k;
188 if (!((*it).pfi->is_on_real_element()))
189 hess_reduction.push_back(k);
191 case GETFEM_NONLINEAR_ : {
192 if ((*it).nl_part == 0) {
194 GMM_ASSERT1(!is_ppi,
"For nonlinear terms you have "
195 "to use approximated integration");
196 computed_on_real_element =
true;
203 pfp.resize(pme->size());
204 it = pme->begin(), ite = pme->end();
205 for (
size_type k = 0; it != ite; ++it, ++k)
207 pfp[k] =
fem_precomp((*it).pfi, pai->pintegration_points(), pi);
209 elmt_stored.resize(pme->size());
211 if (!computed_on_real_element) mref.resize(nbf + 1);
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;
221 for (
size_type k = 0; it != ite; ++it, ++k) {
222 if ((*it).t == GETFEM_NONLINEAR_)
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]);
234 if ((*it).pfi && (*it).pfi->target_dim() > 1) ++mit;
236 (*it).pfi->real_base_value(ctx, elmt_stored[k], icb != 0);
238 elmt_stored[k] = pfp[k]->val(ctx.ii());
242 if ((*it).pfi && (*it).pfi->target_dim() > 1) ++mit;
244 (*it).pfi->real_grad_base_value(ctx, elmt_stored[k], icb != 0);
248 elmt_stored[k] = pfp[k]->grad(ctx.ii());
250 case GETFEM_HESSIAN_ :
252 if ((*it).pfi && (*it).pfi->target_dim() > 1) ++mit;
254 (*it).pfi->real_hess_base_value(ctx, elmt_stored[k], icb != 0);
258 base_tensor tt = pfp[k]->hess(ctx.ii());
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);
266 case GETFEM_UNIT_NORMAL_ :
269 aux_ind.resize(1); aux_ind[0] =
short_type(ctx.N());
270 elmt_stored[k].adjust_sizes(aux_ind);
272 std::copy(up.begin(), up.end(), elmt_stored[k].begin());
274 case GETFEM_GRAD_GEOTRANS_ :
275 case GETFEM_GRAD_GEOTRANS_INV_ : {
276 size_type P = gmm::mat_ncols(ctx.K()), N=ctx.N();
278 if (it->t == GETFEM_GRAD_GEOTRANS_INV_) {
279 Bt.resize(P,N);
gmm::copy(gmm::transposed(ctx.B()),Bt);
281 const base_matrix &A = (it->t==GETFEM_GRAD_GEOTRANS_) ? ctx.K():Bt;
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());
288 case GETFEM_NONLINEAR_ :
289 if ((*it).nl_part != 0) {
291 if ((*it).nlt->term_num() ==
size_type(-1)) {
292 (*it).nlt->prepare(ctx, (*it).nl_part);
296 aux_ind.resize(1); aux_ind[0] = 1;
297 elmt_stored[k].adjust_sizes(aux_ind); elmt_stored[k][0] = 1.;
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];
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];
320 GMM_ASSERT1(mit == sizes.end(),
"internal error");
323 scalar_type c = J*pai->coeff(ctx.ii());
325 if (first) { t.adjust_sizes(sizes); }
326 expand_product_daxpy(t, c, first);
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]);
334 icb->exec(t, first, c);
339 void expand_product_old(base_tensor &t, scalar_type J,
bool first)
const {
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();
350 unsigned n0 = unsigned(elmt_stored[0].size());
355 base_tensor::const_iterator pts0 = pts[k0];
358 k = pme->size()-1; Vtab[k] = J;
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");
376 void expand_product_daxpy(base_tensor &t, scalar_type J,
bool first)
const {
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;
384 pts.resize(0); pts.resize(pme->size());
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());
390 memset(&(*t.begin()), 0, t.size()*
sizeof(*t.begin()));
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();
398 J *= elmt_stored[k][0];
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);
409 base_tensor::const_iterator pts0 = pts[0];
412 k = nm-1; Vtab[k] = J;
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);
423 for (k=0; k < n0; ++k)
426 for (k=1; k != nm && ++pts[k] == es_end[k]; ++k)
429 GMM_ASSERT1(pt == t.end(),
"Internal error");
434 void pre_tensors_for_linear_trans(
bool volumic)
const {
436 if ((volumic && volume_computed) || (!volumic && faces_computed))
440 bgeot::multi_index sizes = pme->sizes(0), mi(sizes.size());
441 bgeot::multi_index::iterator mit = sizes.begin(), mite = sizes.end();
443 for ( ; mit != mite; ++mit, ++f) f *= *mit;
445 GMM_WARNING2(
"Warning, very large elementary computations.\n"
446 <<
"Be sure you need to compute this elementary matrix.\n"
447 <<
"(sizes = " << sizes <<
" )\n");
449 base_tensor aux(sizes);
450 std::fill(aux.begin(), aux.end(), 0.0);
452 volume_computed =
true;
456 faces_computed =
true;
457 std::fill(mref.begin()+1, mref.end(), aux);
462 base_poly P(dim, 0), Q(dim, 0), R(dim, 0);
464 for ( ; !mi.finished(sizes); mi.incrementation(sizes)) {
466 mat_elem_type::const_iterator it = pme->begin(), ite = pme->end();
472 if ((*it).pfi->target_dim() > 1)
473 { ind += (*it).pfi->nb_base(0) * (*mit); ++mit; }
475 Q = ((
ppolyfem)((*it).pfi).get())->base()[ind];
479 case GETFEM_GRAD_ : Q.derivative(
short_type(*mit)); ++mit;
break;
480 case GETFEM_HESSIAN_ :
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_ :
490 "Normals, gradients of geotrans and non linear "
491 "terms are not compatible with exact integration, "
492 "use an approximate method instead");
496 if (it != ite && *mit != old_ind) {
499 for (; it != ite; ++it) {
502 if ((*it).pfi->target_dim() > 1)
503 { ind += (*it).pfi->nb_base(0) * (*mit); ++mit; }
504 R = ((
ppolyfem)((*it).pfi).get())->base()[ind];
510 case GETFEM_HESSIAN_ :
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");
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)));
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++; }
539 add_elem(mref[ind_l], ctx, 1.0, first,
false, NULL, sizes);
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());
552 fem_interpolation_context ctx(pgp, 0, 0, G, elt,
555 GMM_ASSERT1(G.ncols() == NP,
"dimensions mismatch");
557 up.resize(N); un.resize(P);
564 if (!computed_on_real_element) {
565 pre_tensors_for_linear_trans(ir == 0);
566 const base_matrix& B = ctx.B();
567 scalar_type J=ctx.J();
572 gmm::scale(up,1.0/nup);
575 t = mref[ir]; gmm::scale(t.as_vector(), J);
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);
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);
596 if (hess_reduction.size() > 0) {
597 std::deque<short_type>::const_iterator it = hess_reduction.begin(),
598 ite = hess_reduction.end();
600 (flag ? t:taux).mat_transp_reduction(flag ? taux:t, ctx.B3(), *it);
606 bgeot::multi_index sizes = pme->sizes(elt);
609 for (
size_type ip=(ir == 0) ? 0 : pai->repart()[ir-1];
610 ip < pai->repart()[ir]; ++ip, first =
false) {
612 const base_matrix& B = ctx.B();
613 scalar_type J = ctx.J();
617 J *= nup; gmm::scale(up,1.0/nup);
619 add_elem(t, ctx, J, first,
true, icb, sizes);
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());
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) {
638 (flag ? t:taux).mat_transp_reduction(flag ? taux:t, ctx.M(), *it);
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); }
649 void compute_on_face(base_tensor &t,
const base_matrix &G,
651 mat_elem_integration_callback *icb)
const
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);
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);
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...