28 THREAD_SAFE_STATIC fem_precomp_pool HHO_pfp_pool;
38 class _HHO_reconstructed_gradient
39 :
public virtual_elementary_transformation {
43 virtual void give_transformation(
const mesh_fem &mf1,
const mesh_fem &mf2,
55 pfem pf1 = mf1.fem_of_element(cv);
56 pfem pf2 = mf2.fem_of_element(cv);
59 size_type degree = std::max(pf1->estimated_degree(),
60 pf2->estimated_degree());
62 papprox_integration pim
66 bgeot::vectors_to_base_matrix(G, mf1.linked_mesh().points_of_convex(cv));
68 bgeot::pgeotrans_precomp pgp
69 = HHO_pgp_pool(pgt, pim->pintegration_points());
70 pfem_precomp pfp1 = HHO_pfp_pool(pf1, pim->pintegration_points());
71 pfem_precomp pfp2 = HHO_pfp_pool(pf2, pim->pintegration_points());
72 pfem_precomp pfpi = HHO_pfp_pool(pfi, pim->pintegration_points());
74 fem_interpolation_context ctx1(pgp, pfp1, 0, G, cv);
75 fem_interpolation_context ctx2(pgp, pfp2, 0, G, cv);
76 fem_interpolation_context ctxi(pgp, pfpi, 0, G, cv);
78 size_type Q = mf1.get_qdim(), N = mf1.linked_mesh().dim();
81 size_type ndof1 = pf1->nb_dof(cv) * qmult1;
82 size_type qmult2 = Q*N / pf2->target_dim();
83 size_type ndof2 = pf2->nb_dof(cv) * qmult2;
85 size_type ndofi = pfi->nb_dof(cv) * qmulti;
87 base_tensor t1, t2, ti, tv1;
88 base_matrix tv2, tv1p, tvi;
89 base_matrix M1(ndof2, ndof1), M2(ndof2, ndof2), M2inv(ndof2, ndof2);
90 base_matrix aux2(ndof2, ndof2);
93 for (
size_type ipt = 0; ipt < pim->nb_points_on_convex(); ++ipt) {
94 ctx1.set_ii(ipt); ctx2.set_ii(ipt);
95 scalar_type coeff = pim->coeff(ipt) * ctx1.J();
97 ctx1.grad_base_value(t1);
98 vectorize_grad_base_tensor(t1, tv1, ndof1, pf1->target_dim(), Q);
101 vectorize_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q*N);
103 gmm::mult(tv2, gmm::transposed(tv2), aux2);
104 gmm::add(gmm::scaled(aux2, coeff), M2);
109 M1(j, i) += coeff * tv1.as_vector()[i+k*ndof1] * tv2(j, k);
113 for (
short_type ifc = 0; ifc < pgt->structure()->nb_faces(); ++ifc) {
114 ctx1.set_face_num(ifc); ctx2.set_face_num(ifc); ctxi.set_face_num(ifc);
115 size_type first_ind = pim->ind_first_point_on_face(ifc);
116 for (
size_type ipt = 0; ipt < pim->nb_points_on_face(ifc); ++ipt) {
117 ctx1.set_ii(first_ind+ipt);
118 ctx2.set_ii(first_ind+ipt);
119 ctxi.set_ii(first_ind+ipt);
120 scalar_type coeff = pim->coeff(first_ind+ipt) * ctx1.J();
121 gmm::mult(ctx1.B(), pgt->normals()[ifc], un);
124 vectorize_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q*N);
127 vectorize_base_tensor(t1, tv1p, ndof1, pf1->target_dim(), Q);
130 vectorize_base_tensor(ti, tvi, ndofi, pfi->target_dim(), Q);
135 scalar_type b(0), a = coeff *
136 (tv1p(i, k1) - (i < ndofi ? tvi(i, k1) : 0.));
138 b += a * tv2(j, k1 + k2*Q) * un[k2];
144 if (pf2->target_dim() == 1) {
145 gmm::sub_slice I(0, ndof2/(N*Q), N*Q);
148 gmm::sub_slice I2(i, ndof2/(N*Q), N*Q);
149 gmm::copy(gmm::sub_matrix(M2, I, I), gmm::sub_matrix(M2inv, I2, I2));
154 gmm::clean(M, gmm::vect_norminf(M.as_vector()) * 1E-13);
159 pelementary_transformation
160 p = std::make_shared<_HHO_reconstructed_gradient>();
165 class _HHO_reconstructed_sym_gradient
166 :
public virtual_elementary_transformation {
170 virtual void give_transformation(
const mesh_fem &mf1,
const mesh_fem &mf2,
183 pfem pf1 = mf1.fem_of_element(cv);
184 pfem pf2 = mf2.fem_of_element(cv);
187 size_type degree = std::max(pf1->estimated_degree(),
188 pf2->estimated_degree());
190 papprox_integration pim
194 bgeot::vectors_to_base_matrix(G, mf1.linked_mesh().points_of_convex(cv));
196 bgeot::pgeotrans_precomp pgp
197 = HHO_pgp_pool(pgt, pim->pintegration_points());
198 pfem_precomp pfp1 = HHO_pfp_pool(pf1, pim->pintegration_points());
199 pfem_precomp pfp2 = HHO_pfp_pool(pf2, pim->pintegration_points());
200 pfem_precomp pfpi = HHO_pfp_pool(pfi, pim->pintegration_points());
202 fem_interpolation_context ctx1(pgp, pfp1, 0, G, cv);
203 fem_interpolation_context ctx2(pgp, pfp2, 0, G, cv);
204 fem_interpolation_context ctxi(pgp, pfpi, 0, G, cv);
206 size_type Q = mf1.get_qdim(), N = mf1.linked_mesh().dim();
207 GMM_ASSERT1(Q == N,
"This transformation works only for vector fields "
208 "having the same dimension as the domain");
210 size_type qmult1 = N / pf1->target_dim();
211 size_type ndof1 = pf1->nb_dof(cv) * qmult1;
212 size_type qmult2 = N*N / pf2->target_dim();
213 size_type ndof2 = pf2->nb_dof(cv) * qmult2;
214 size_type qmulti = N / pfi->target_dim();
215 size_type ndofi = pfi->nb_dof(cv) * qmulti;
218 base_tensor t1, t2, ti, tv1;
219 base_matrix tv2, tv1p, tvi;
220 base_matrix M1(ndof2, ndof1), M2(ndof2, ndof2), M2inv(ndof2, ndof2);
221 base_matrix aux2(ndof2, ndof2);
225 for (
size_type ipt = 0; ipt < pim->nb_points_on_convex(); ++ipt) {
226 ctx1.set_ii(ipt); ctx2.set_ii(ipt);
227 scalar_type coeff = pim->coeff(ipt) * ctx1.J();
229 ctx1.grad_base_value(t1);
230 vectorize_grad_base_tensor(t1, tv1, ndof1, pf1->target_dim(), N);
233 vectorize_base_tensor(t2, tv2, ndof2, pf2->target_dim(), N*N);
235 gmm::mult(tv2, gmm::transposed(tv2), aux2);
236 gmm::add(gmm::scaled(aux2, coeff), M2);
242 M1(j, i) += coeff * tv1.as_vector()[i+(k1+k2*N)*ndof1]
243 * 0.5 * (tv2(j, k1+k2*N) + tv2(j, k2+k1*N));
247 for (
short_type ifc = 0; ifc < pgt->structure()->nb_faces(); ++ifc) {
248 ctx1.set_face_num(ifc); ctx2.set_face_num(ifc); ctxi.set_face_num(ifc);
249 size_type first_ind = pim->ind_first_point_on_face(ifc);
250 for (
size_type ipt = 0; ipt < pim->nb_points_on_face(ifc); ++ipt) {
251 ctx1.set_ii(first_ind+ipt);
252 ctx2.set_ii(first_ind+ipt);
253 ctxi.set_ii(first_ind+ipt);
254 scalar_type coeff = pim->coeff(first_ind+ipt) * ctx1.J();
255 gmm::mult(ctx1.B(), pgt->normals()[ifc], un);
258 vectorize_base_tensor(t2, tv2, ndof2, pf2->target_dim(), N*N);
261 vectorize_base_tensor(t1, tv1p, ndof1, pf1->target_dim(), N);
264 vectorize_base_tensor(ti, tvi, ndofi, pfi->target_dim(), N);
269 scalar_type b(0), a = coeff *
270 (tv1p(i, k1) - (i < ndofi ? tvi(i, k1) : 0.));
272 b += a*0.5*(tv2(j, k1 + k2*N) + tv2(j, k2 + k1*N)) * un[k2];
279 if (pf2->target_dim() == 1) {
280 gmm::sub_slice I(0, ndof2/(N*Q), N*Q);
283 gmm::sub_slice I2(i, ndof2/(N*Q), N*Q);
284 gmm::copy(gmm::sub_matrix(M2, I, I), gmm::sub_matrix(M2inv, I2, I2));
290 gmm::clean(M, gmm::vect_norminf(M.as_vector()) * 1E-13);
295 pelementary_transformation
296 p = std::make_shared<_HHO_reconstructed_sym_gradient>();
302 class _HHO_reconstructed_value
303 :
public virtual_elementary_transformation {
307 virtual void give_transformation(
const mesh_fem &mf1,
const mesh_fem &mf2,
321 pfem pf1 = mf1.fem_of_element(cv);
322 pfem pf2 = mf2.fem_of_element(cv);
325 size_type degree = std::max(pf1->estimated_degree(),
326 pf2->estimated_degree());
328 papprox_integration pim
332 bgeot::vectors_to_base_matrix(G, mf1.linked_mesh().points_of_convex(cv));
334 bgeot::pgeotrans_precomp pgp
335 = HHO_pgp_pool(pgt, pim->pintegration_points());
336 pfem_precomp pfp1 = HHO_pfp_pool(pf1, pim->pintegration_points());
337 pfem_precomp pfp2 = HHO_pfp_pool(pf2, pim->pintegration_points());
338 pfem_precomp pfpi = HHO_pfp_pool(pfi, pim->pintegration_points());
340 fem_interpolation_context ctx1(pgp, pfp1, 0, G, cv);
341 fem_interpolation_context ctx2(pgp, pfp2, 0, G, cv);
342 fem_interpolation_context ctxi(pgp, pfpi, 0, G, cv);
344 size_type Q = mf1.get_qdim(), N = mf1.linked_mesh().dim();
346 size_type qmult1 = Q / pf1->target_dim();
347 size_type ndof1 = pf1->nb_dof(cv) * qmult1;
348 size_type qmult2 = Q / pf2->target_dim();
349 size_type ndof2 = pf2->nb_dof(cv) * qmult2;
350 size_type qmulti = Q / pfi->target_dim();
351 size_type ndofi = pfi->nb_dof(cv) * qmulti;
354 base_tensor t1, t2, ti, tv1, tv2, t1p, t2p;
355 base_matrix tv1p, tv2p, tvi;
356 base_matrix M1(ndof2, ndof1), M2(ndof2, ndof2), M2inv(ndof2, ndof2);
357 base_matrix M3(Q, ndof1), M4(Q, ndof2);
358 base_matrix aux1(ndof2, ndof1), aux2(ndof2, ndof2);
364 for (
size_type ipt = 0; ipt < pim->nb_points_on_convex(); ++ipt) {
365 ctx1.set_ii(ipt); ctx2.set_ii(ipt);
366 scalar_type coeff = pim->coeff(ipt) * ctx1.J();
369 ctx1.grad_base_value(t1);
370 vectorize_grad_base_tensor(t1, tv1, ndof1, pf1->target_dim(), Q);
372 ctx1.base_value(t1p);
373 vectorize_base_tensor(t1p, tv1p, ndof1, pf1->target_dim(), Q);
375 ctx2.grad_base_value(t2);
376 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q);
378 ctx2.base_value(t2p);
379 vectorize_base_tensor(t2p, tv2p, ndof2, pf2->target_dim(), Q);
384 M2(j, i) += coeff * tv2.as_vector()[i+k*ndof2]
385 * tv2.as_vector()[j+k*ndof2];
389 M4(k, i) += coeff * tv2p(i, k);
394 M1(j, i) += coeff * tv1.as_vector()[i+k*ndof1]
395 * tv2.as_vector()[j+k*ndof2];
399 M3(k, i) += coeff * tv1p(i, k);
404 for (
short_type ifc = 0; ifc < pgt->structure()->nb_faces(); ++ifc) {
405 ctx1.set_face_num(ifc); ctx2.set_face_num(ifc); ctxi.set_face_num(ifc);
406 size_type first_ind = pim->ind_first_point_on_face(ifc);
407 for (
size_type ipt = 0; ipt < pim->nb_points_on_face(ifc); ++ipt) {
408 ctx1.set_ii(first_ind+ipt);
409 ctx2.set_ii(first_ind+ipt);
410 ctxi.set_ii(first_ind+ipt);
411 scalar_type coeff = pim->coeff(first_ind+ipt) * ctx1.J();
412 gmm::mult(ctx1.B(), pgt->normals()[ifc], un);
414 ctx2.grad_base_value(t2);
415 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q);
418 vectorize_base_tensor(t1, tv1p, ndof1, pf1->target_dim(), Q);
421 vectorize_base_tensor(ti, tvi, ndofi, pfi->target_dim(), Q);
426 scalar_type b(0), a = coeff *
427 (tv1p(i, k1) - (i < ndofi ? tvi(i, k1) : 0.));
429 b += a * tv2.as_vector()[j+(k1+k2*Q)*ndof2] * un[k2];
437 scalar_type coeff_p = pow(area, -1. - 2./scalar_type(N));
438 gmm::mult(gmm::transposed(M4), M4, aux2);
439 gmm::add (gmm::scaled(aux2, coeff_p), M2);
440 gmm::mult(gmm::transposed(M4), M3, aux1);
441 gmm::add (gmm::scaled(aux1, coeff_p), M1);
443 if (pf2->target_dim() == 1 && Q > 1) {
444 gmm::sub_slice I(0, ndof2/Q, Q);
447 gmm::sub_slice I2(i, ndof2/Q, Q);
448 gmm::copy(gmm::sub_matrix(M2, I, I), gmm::sub_matrix(M2inv, I2, I2));
454 gmm::clean(M, gmm::vect_norminf(M.as_vector()) * 1E-13);
459 pelementary_transformation
460 p = std::make_shared<_HHO_reconstructed_value>();
465 class _HHO_reconstructed_sym_value
466 :
public virtual_elementary_transformation {
470 virtual void give_transformation(
const mesh_fem &mf1,
const mesh_fem &mf2,
485 pfem pf1 = mf1.fem_of_element(cv);
486 pfem pf2 = mf2.fem_of_element(cv);
489 size_type degree = std::max(pf1->estimated_degree(),
490 pf2->estimated_degree());
492 papprox_integration pim
496 bgeot::vectors_to_base_matrix(G, mf1.linked_mesh().points_of_convex(cv));
498 bgeot::pgeotrans_precomp pgp
499 = HHO_pgp_pool(pgt, pim->pintegration_points());
500 pfem_precomp pfp1 = HHO_pfp_pool(pf1, pim->pintegration_points());
501 pfem_precomp pfp2 = HHO_pfp_pool(pf2, pim->pintegration_points());
502 pfem_precomp pfpi = HHO_pfp_pool(pfi, pim->pintegration_points());
504 fem_interpolation_context ctx1(pgp, pfp1, 0, G, cv);
505 fem_interpolation_context ctx2(pgp, pfp2, 0, G, cv);
506 fem_interpolation_context ctxi(pgp, pfpi, 0, G, cv);
508 size_type Q = mf1.get_qdim(), N = mf1.linked_mesh().dim();
509 GMM_ASSERT1(Q == N,
"This transformation works only for vector fields "
510 "having the same dimension as the domain");
512 size_type qmult1 = N / pf1->target_dim();
513 size_type ndof1 = pf1->nb_dof(cv) * qmult1;
514 size_type qmult2 = N / pf2->target_dim();
515 size_type ndof2 = pf2->nb_dof(cv) * qmult2;
516 size_type qmulti = N / pfi->target_dim();
517 size_type ndofi = pfi->nb_dof(cv) * qmulti;
520 base_tensor t1, t2, ti, tv1, tv2, t1p, t2p;
521 base_matrix tv1p, tv2p, tvi;
522 base_matrix M1(ndof2, ndof1), M2(ndof2, ndof2), M2inv(ndof2, ndof2);;
523 base_matrix M3(N, ndof1), M4(N, ndof2);
524 base_matrix M5(N*N, ndof1), M6(N*N, ndof2);
525 base_matrix aux1(ndof2, ndof1), aux2(ndof2, ndof2);
532 for (
size_type ipt = 0; ipt < pim->nb_points_on_convex(); ++ipt) {
533 ctx1.set_ii(ipt); ctx2.set_ii(ipt);
534 scalar_type coeff = pim->coeff(ipt) * ctx1.J();
537 ctx1.grad_base_value(t1);
538 vectorize_grad_base_tensor(t1, tv1, ndof1, pf1->target_dim(), N);
540 ctx1.base_value(t1p);
541 vectorize_base_tensor(t1p, tv1p, ndof1, pf1->target_dim(), N);
543 ctx2.grad_base_value(t2);
544 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), N);
546 ctx2.base_value(t2p);
547 vectorize_base_tensor(t2p, tv2p, ndof2, pf2->target_dim(), N);
553 M2(j, i) += coeff * tv2.as_vector()[i+(k1+k2*N)*ndof2]
554 * 0.5 * (tv2.as_vector()[j+(k1+k2*N)*ndof2] +
555 tv2.as_vector()[j+(k2+k1*N)*ndof2]);
559 M4(k, i) += coeff * tv2p(i, k);
564 M6(k1+k2*N, i) += 0.5*coeff*(tv2.as_vector()[i+(k1+k2*N)*ndof2] -
565 tv2.as_vector()[i+(k2+k1*N)*ndof2]);
571 M1(j, i) += coeff * tv1.as_vector()[i+(k1+k2*N)*ndof1]
572 * 0.5 * (tv2.as_vector()[j+(k1+k2*N)*ndof2] +
573 tv2.as_vector()[j+(k2+k1*N)*ndof2]);
577 M3(k, i) += coeff * tv1p(i, k);
583 for (
short_type ifc = 0; ifc < pgt->structure()->nb_faces(); ++ifc) {
584 ctx1.set_face_num(ifc); ctx2.set_face_num(ifc); ctxi.set_face_num(ifc);
585 size_type first_ind = pim->ind_first_point_on_face(ifc);
586 for (
size_type ipt = 0; ipt < pim->nb_points_on_face(ifc); ++ipt) {
587 ctx1.set_ii(first_ind+ipt);
588 ctx2.set_ii(first_ind+ipt);
589 ctxi.set_ii(first_ind+ipt);
590 scalar_type coeff = pim->coeff(first_ind+ipt) * ctx1.J();
591 gmm::mult(ctx1.B(), pgt->normals()[ifc], un);
593 ctx2.grad_base_value(t2);
594 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), N);
597 vectorize_base_tensor(t1, tv1p, ndof1, pf1->target_dim(), N);
600 vectorize_base_tensor(ti, tvi, ndofi, pfi->target_dim(), N);
605 scalar_type b(0), a = coeff *
606 (tv1p(i, k1) - (i < ndofi ? tvi(i, k1) : 0.));
608 b += a * 0.5 * (tv2.as_vector()[j+(k1+k2*N)*ndof2] +
609 tv2.as_vector()[j+(k2+k1*N)*ndof2]) * un[k2];
616 M5(k1+k2*N, i) += 0.5 * coeff * (tv1p(i, k1) * un[k2] -
617 tv1p(i, k2) * un[k1]);
622 scalar_type coeff_p1 = pow(area, -1. - 2./scalar_type(N));
623 scalar_type coeff_p2 = pow(area, -1. - 1./scalar_type(N));
624 gmm::mult(gmm::transposed(M4), M4, aux2);
625 gmm::add (gmm::scaled(aux2, coeff_p1), M2);
626 gmm::mult(gmm::transposed(M6), M6, aux2);
627 gmm::add (gmm::scaled(aux2, coeff_p2), M2);
628 gmm::mult(gmm::transposed(M4), M3, aux1);
629 gmm::add (gmm::scaled(aux1, coeff_p1), M1);
630 gmm::mult(gmm::transposed(M6), M5, aux1);
631 gmm::add (gmm::scaled(aux1, coeff_p2), M1);
636 gmm::clean(M, gmm::vect_norminf(M.as_vector()) * 1E-13);
641 pelementary_transformation
642 p = std::make_shared<_HHO_reconstructed_sym_value>();
648 class _HHO_stabilization
649 :
public virtual_elementary_transformation {
653 virtual void give_transformation(
const mesh_fem &mf1,
const mesh_fem &mf2,
675 GMM_ASSERT1(&mf1 == &mf2,
"The HHO stabilization transformation is "
676 "only defined on the HHO space to itself");
679 pfem pf1 = mf1.fem_of_element(cv);
686 papprox_integration pim
690 bgeot::vectors_to_base_matrix(G, mf1.linked_mesh().points_of_convex(cv));
692 bgeot::pgeotrans_precomp pgp
693 = HHO_pgp_pool(pgt, pim->pintegration_points());
694 pfem_precomp pfp1 = HHO_pfp_pool(pf1, pim->pintegration_points());
695 pfem_precomp pfp2 = HHO_pfp_pool(pf2, pim->pintegration_points());
696 pfem_precomp pfpi = HHO_pfp_pool(pfi, pim->pintegration_points());
698 fem_interpolation_context ctx1(pgp, pfp1, 0, G, cv);
699 fem_interpolation_context ctx2(pgp, pfp2, 0, G, cv);
700 fem_interpolation_context ctxi(pgp, pfpi, 0, G, cv);
702 size_type Q = mf1.get_qdim(), N = mf1.linked_mesh().dim();
704 size_type qmult1 = Q / pf1->target_dim();
705 size_type ndof1 = pf1->nb_dof(cv) * qmult1;
706 size_type qmult2 = Q / pf2->target_dim();
707 size_type ndof2 = pf2->nb_dof(cv) * qmult2;
708 size_type qmulti = Q / pfi->target_dim();
709 size_type ndofi = pfi->nb_dof(cv) * qmulti;
712 base_tensor t1, t2, ti, tv1, tv2, t1p, t2p;
713 base_matrix tv1p, tv2p, tvi;
714 base_matrix M1(ndof2, ndof1), M2(ndof2, ndof2), M2inv(ndof2, ndof2);
715 base_matrix M3(Q, ndof1), M4(Q, ndof2);
716 base_matrix aux1(ndof2, ndof1), aux2(ndof2, ndof2);
717 base_matrix M7(ndof1, ndof1), M7inv(ndof1, ndof1), M8(ndof1, ndof2);
718 base_matrix M9(ndof1, ndof1), MD(ndof2, ndof1);
724 for (
size_type ipt = 0; ipt < pim->nb_points_on_convex(); ++ipt) {
725 ctx1.set_ii(ipt); ctx2.set_ii(ipt);
726 scalar_type coeff = pim->coeff(ipt) * ctx1.J();
729 ctx1.grad_base_value(t1);
730 vectorize_grad_base_tensor(t1, tv1, ndof1, pf1->target_dim(), Q);
732 ctx1.base_value(t1p);
733 vectorize_base_tensor(t1p, tv1p, ndof1, pf1->target_dim(), Q);
735 ctx2.grad_base_value(t2);
736 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q);
738 ctx2.base_value(t2p);
739 vectorize_base_tensor(t2p, tv2p, ndof2, pf2->target_dim(), Q);
744 M2(j, i) += coeff * tv2.as_vector()[i+k*ndof2]
745 * tv2.as_vector()[j+k*ndof2];
749 M4(k, i) += coeff * tv2p(i, k);
754 M1(j, i) += coeff * tv1.as_vector()[i+k*ndof1]
755 * tv2.as_vector()[j+k*ndof2];
759 M3(k, i) += coeff * tv1p(i, k);
764 M7(i, j) += coeff * tv1p(i, k) * tv1p(j, k);
769 M8(i, j) += coeff * tv1p(i, k) * tv2p(j, k);
774 for (
short_type ifc = 0; ifc < pgt->structure()->nb_faces(); ++ifc) {
775 ctx1.set_face_num(ifc); ctx2.set_face_num(ifc); ctxi.set_face_num(ifc);
776 size_type first_ind = pim->ind_first_point_on_face(ifc);
777 for (
size_type ipt = 0; ipt < pim->nb_points_on_face(ifc); ++ipt) {
778 ctx1.set_ii(first_ind+ipt);
779 ctx2.set_ii(first_ind+ipt);
780 ctxi.set_ii(first_ind+ipt);
781 scalar_type coeff = pim->coeff(first_ind+ipt) * ctx1.J();
782 gmm::mult(ctx1.B(), pgt->normals()[ifc], un);
785 ctx2.grad_base_value(t2);
786 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q);
788 ctx2.base_value(t2p);
789 vectorize_base_tensor(t2p, tv2p, ndof2, pf2->target_dim(), Q);
792 vectorize_base_tensor(t1, tv1p, ndof1, pf1->target_dim(), Q);
795 vectorize_base_tensor(ti, tvi, ndofi, pfi->target_dim(), Q);
801 scalar_type b(0), a = coeff *
802 (tv1p(i, k1) - (i < ndofi ? tvi(i, k1) : 0.));
804 b += a * tv2.as_vector()[j+(k1 + k2*Q)*ndof2] * un[k2];
811 M7(i, j) += coeff * normun * tv1p(i,k) * tv1p(j, k);
816 M8(i, j) += coeff * normun * tv1p(i,k) * tv2p(j, k);
821 M9(i, j) += coeff * normun * tv1p(i,k) * tvi(j, k);
826 scalar_type coeff_p = pow(area, -1. - 2./scalar_type(N));
827 gmm::mult(gmm::transposed(M4), M4, aux2);
828 gmm::add (gmm::scaled(aux2, coeff_p), M2);
829 gmm::mult(gmm::transposed(M4), M3, aux1);
830 gmm::add (gmm::scaled(aux1, coeff_p), M1);
832 if (pf2->target_dim() == 1 && Q > 1) {
833 gmm::sub_slice I(0, ndof2/Q, Q);
836 gmm::sub_slice I2(i, ndof2/Q, Q);
837 gmm::copy(gmm::sub_matrix(M2, I, I), gmm::sub_matrix(M2inv, I2, I2));
842 if (pf1->target_dim() == 1 && Q > 1) {
843 gmm::sub_slice I(0, ndof1/Q, Q);
846 gmm::sub_slice I2(i, ndof1/Q, Q);
847 gmm::copy(gmm::sub_matrix(M7, I, I), gmm::sub_matrix(M7inv, I2, I2));
853 gmm::clean(MD, gmm::vect_norminf(MD.as_vector()) * 1E-13);
856 base_matrix MPB(ndof1, ndof1);
859 gmm::add(gmm::scaled(MPB, scalar_type(-1)), M9);
861 base_matrix MPC(ndof1, ndof1), MPD(ndof1, ndof1);
865 gmm::add(gmm::scaled(MPD, scalar_type(-1)), M7);
873 pelementary_transformation
874 p = std::make_shared<_HHO_stabilization>();
875 md.add_elementary_transformation(name, p);
882 class _HHO_stabilization
883 :
public virtual_elementary_transformation {
887 virtual void give_transformation(
const mesh_fem &mf1,
const mesh_fem &mf2,
910 pfem pf1 = mf1.fem_of_element(cv);
915 pfem pf3 = mf2.fem_of_element(cv);
919 papprox_integration pim
923 bgeot::vectors_to_base_matrix(G, mf1.linked_mesh().points_of_convex(cv));
925 bgeot::pgeotrans_precomp pgp
926 = HHO_pgp_pool(pgt, pim->pintegration_points());
927 pfem_precomp pfp1 = HHO_pfp_pool(pf1, pim->pintegration_points());
928 pfem_precomp pfp2 = HHO_pfp_pool(pf2, pim->pintegration_points());
929 pfem_precomp pfp3 = HHO_pfp_pool(pf3, pim->pintegration_points());
930 pfem_precomp pfp1i = HHO_pfp_pool(pf1i, pim->pintegration_points());
931 pfem_precomp pfp3i = HHO_pfp_pool(pf3i, pim->pintegration_points());
933 fem_interpolation_context ctx1(pgp, pfp1, 0, G, cv);
934 fem_interpolation_context ctx2(pgp, pfp2, 0, G, cv);
935 fem_interpolation_context ctx3(pgp, pfp3, 0, G, cv);
936 fem_interpolation_context ctx1i(pgp, pfp1i, 0, G, cv);
937 fem_interpolation_context ctx3i(pgp, pfp3i, 0, G, cv);
939 size_type Q = mf1.get_qdim(), N = mf1.linked_mesh().dim();
941 size_type qmult1 = Q / pf1->target_dim();
942 size_type ndof1 = pf1->nb_dof(cv) * qmult1;
943 size_type qmult2 = Q / pf2->target_dim();
944 size_type ndof2 = pf2->nb_dof(cv) * qmult2;
945 size_type qmult3 = Q / pf3->target_dim();
946 size_type ndof3 = pf3->nb_dof(cv) * qmult3;
947 size_type qmult1i = Q / pf1i->target_dim();
948 size_type ndof1i = pf1i->nb_dof(cv) * qmult1i;
949 size_type qmult3i = Q / pf3i->target_dim();
950 size_type ndof3i = pf3i->nb_dof(cv) * qmult3i;
953 base_tensor t1, t2, t3, t1i, t3i, tv1, tv2, t1p, t2p;
954 base_matrix tv1p, tv2p, tv3p, tv1i, tv3i;
955 base_matrix M1(ndof2, ndof1), M2(ndof2, ndof2), M2inv(ndof2, ndof2);
956 base_matrix M3(Q, ndof1), M4(Q, ndof2);
957 base_matrix aux1(ndof2, ndof1), aux2(ndof2, ndof2);
958 base_matrix M7(ndof3, ndof3), M7inv(ndof3, ndof3), M8(ndof3, ndof2);
959 base_matrix M9(ndof3, ndof1), M10(ndof3, ndof3), MD(ndof2, ndof1);
965 for (
size_type ipt = 0; ipt < pim->nb_points_on_convex(); ++ipt) {
966 ctx1.set_ii(ipt); ctx2.set_ii(ipt); ctx3.set_ii(ipt);
967 scalar_type coeff = pim->coeff(ipt) * ctx1.J();
970 ctx1.grad_base_value(t1);
971 vectorize_grad_base_tensor(t1, tv1, ndof1, pf1->target_dim(), Q);
973 ctx1.base_value(t1p);
974 vectorize_base_tensor(t1p, tv1p, ndof1, pf1->target_dim(), Q);
976 ctx2.grad_base_value(t2);
977 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q);
979 ctx2.base_value(t2p);
980 vectorize_base_tensor(t2p, tv2p, ndof2, pf2->target_dim(), Q);
983 vectorize_base_tensor(t3, tv3p, ndof3, pf3->target_dim(), Q);
988 M2(j, i) += coeff * tv2.as_vector()[i+k*ndof2]
989 * tv2.as_vector()[j+k*ndof2];
993 M4(k, i) += coeff * tv2p(i, k);
998 M1(j, i) += coeff * tv1.as_vector()[i+k*ndof1]
999 * tv2.as_vector()[j+k*ndof2];
1003 M3(k, i) += coeff * tv1p(i, k);
1008 M7(i, j) += coeff * tv3p(i, k) * tv3p(j, k);
1013 M8(i, j) += coeff * tv3p(i, k) * tv2p(j, k);
1018 M9(i, j) += coeff * tv3p(i, k) * tv1p(j, k);
1022 for (
short_type ifc = 0; ifc < pgt->structure()->nb_faces(); ++ifc) {
1023 ctx1.set_face_num(ifc); ctx2.set_face_num(ifc); ctx3.set_face_num(ifc);
1024 ctx1i.set_face_num(ifc); ctx3i.set_face_num(ifc);
1025 size_type first_ind = pim->ind_first_point_on_face(ifc);
1026 for (
size_type ipt = 0; ipt < pim->nb_points_on_face(ifc); ++ipt) {
1027 ctx1.set_ii(first_ind+ipt); ctx2.set_ii(first_ind+ipt);
1028 ctx3.set_ii(first_ind+ipt); ctx1i.set_ii(first_ind+ipt);
1029 ctx3i.set_ii(first_ind+ipt);
1030 scalar_type coeff = pim->coeff(first_ind+ipt) * ctx1.J();
1031 gmm::mult(ctx1.B(), pgt->normals()[ifc], un);
1034 ctx2.grad_base_value(t2);
1035 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q);
1037 ctx2.base_value(t2p);
1038 vectorize_base_tensor(t2p, tv2p, ndof2, pf2->target_dim(), Q);
1040 ctx1.base_value(t1);
1041 vectorize_base_tensor(t1, tv1p, ndof1, pf1->target_dim(), Q);
1043 ctx1i.base_value(t1i);
1044 vectorize_base_tensor(t1i, tv1i, ndof1i, pf1i->target_dim(), Q);
1046 ctx3i.base_value(t3i);
1047 vectorize_base_tensor(t3i, tv3i, ndof3i, pf3i->target_dim(), Q);
1049 ctx3.base_value(t3);
1050 vectorize_base_tensor(t3, tv3p, ndof3, pf3->target_dim(), Q);
1056 scalar_type b(0), a = coeff *
1057 (tv1p(i, k1) - (i < ndof1i ? tv1i(i, k1) : 0.));
1059 b += a * tv2.as_vector()[j+(k1 + k2*Q)*ndof2] * un[k2];
1066 M7(i, j) += coeff * normun * tv3p(i,k) * tv3p(j, k);
1071 M8(i, j) += coeff * normun * tv3p(i,k) * tv2p(j, k);
1076 M9(i, j) += coeff * normun * tv3p(i, k) * tv1p(j, k);
1081 M10(i, j) += coeff * normun * tv3p(i,k) * tv3i(j, k);
1086 scalar_type coeff_p = pow(area, -1. - 2./scalar_type(N));
1087 gmm::mult(gmm::transposed(M4), M4, aux2);
1088 gmm::add (gmm::scaled(aux2, coeff_p), M2);
1089 gmm::mult(gmm::transposed(M4), M3, aux1);
1090 gmm::add (gmm::scaled(aux1, coeff_p), M1);
1092 if (pf2->target_dim() == 1 && Q > 1) {
1093 gmm::sub_slice I(0, ndof2/Q, Q);
1096 gmm::sub_slice I2(i, ndof2/Q, Q);
1097 gmm::copy(gmm::sub_matrix(M2, I, I), gmm::sub_matrix(M2inv, I2, I2));
1102 if (pf3->target_dim() == 1 && Q > 1) {
1103 gmm::sub_slice I(0, ndof3/Q, Q);
1106 gmm::sub_slice I2(i, ndof3/Q, Q);
1107 gmm::copy(gmm::sub_matrix(M7, I, I), gmm::sub_matrix(M7inv, I2, I2));
1113 gmm::clean(MD, gmm::vect_norminf(MD.as_vector()) * 1E-13);
1116 base_matrix MPB(ndof3, ndof3);
1119 gmm::add(gmm::scaled(MPB, scalar_type(-1)), M10);
1121 base_matrix MPC(ndof3, ndof1);
1122 gmm::mult(gmm::scaled(M8, scalar_type(-1)), MD, MPC);
1131 pelementary_transformation
1132 p = std::make_shared<_HHO_stabilization>();
1138 class _HHO_symmetrized_stabilization
1139 :
public virtual_elementary_transformation {
1143 virtual void give_transformation(
const mesh_fem &mf1,
const mesh_fem &mf2,
1167 pfem pf1 = mf1.fem_of_element(cv);
1172 pfem pf3 = mf2.fem_of_element(cv);
1176 papprox_integration pim
1180 bgeot::vectors_to_base_matrix(G, mf1.linked_mesh().points_of_convex(cv));
1182 bgeot::pgeotrans_precomp pgp
1183 = HHO_pgp_pool(pgt, pim->pintegration_points());
1184 pfem_precomp pfp1 = HHO_pfp_pool(pf1, pim->pintegration_points());
1185 pfem_precomp pfp2 = HHO_pfp_pool(pf2, pim->pintegration_points());
1186 pfem_precomp pfp3 = HHO_pfp_pool(pf3, pim->pintegration_points());
1187 pfem_precomp pfp1i = HHO_pfp_pool(pf1i, pim->pintegration_points());
1188 pfem_precomp pfp3i = HHO_pfp_pool(pf3i, pim->pintegration_points());
1190 fem_interpolation_context ctx1(pgp, pfp1, 0, G, cv);
1191 fem_interpolation_context ctx2(pgp, pfp2, 0, G, cv);
1192 fem_interpolation_context ctx3(pgp, pfp3, 0, G, cv);
1193 fem_interpolation_context ctx1i(pgp, pfp1i, 0, G, cv);
1194 fem_interpolation_context ctx3i(pgp, pfp3i, 0, G, cv);
1196 size_type Q = mf1.get_qdim(), N = mf1.linked_mesh().dim();
1197 GMM_ASSERT1(Q == N,
"This transformation works only for vector fields "
1198 "having the same dimension as the domain");
1200 size_type qmult1 = N / pf1->target_dim();
1201 size_type ndof1 = pf1->nb_dof(cv) * qmult1;
1202 size_type qmult2 = N / pf2->target_dim();
1203 size_type ndof2 = pf2->nb_dof(cv) * qmult2;
1204 size_type qmult3 = Q / pf3->target_dim();
1205 size_type ndof3 = pf3->nb_dof(cv) * qmult3;
1206 size_type qmult1i = Q / pf1i->target_dim();
1207 size_type ndof1i = pf1i->nb_dof(cv) * qmult1i;
1208 size_type qmult3i = Q / pf3i->target_dim();
1209 size_type ndof3i = pf3i->nb_dof(cv) * qmult3i;
1212 base_tensor t1, t2, t3, t1i, t3i, tv1, tv2, t1p, t2p;
1213 base_matrix tv1p, tv2p, tv3p, tv1i, tv3i;
1214 base_matrix M1(ndof2, ndof1), M2(ndof2, ndof2), M2inv(ndof2, ndof2);
1215 base_matrix M3(N, ndof1), M4(N, ndof2);
1216 base_matrix aux1(ndof2, ndof1), aux2(ndof2, ndof2);
1217 base_matrix M5(N*N, ndof1), M6(N*N, ndof2);
1218 base_matrix M7(ndof3, ndof3), M7inv(ndof3, ndof3), M8(ndof3, ndof2);
1219 base_matrix M9(ndof3, ndof1), M10(ndof3, ndof3), MD(ndof2, ndof1);
1220 scalar_type area(0);
1226 for (
size_type ipt = 0; ipt < pim->nb_points_on_convex(); ++ipt) {
1227 ctx1.set_ii(ipt); ctx2.set_ii(ipt); ctx3.set_ii(ipt);
1228 scalar_type coeff = pim->coeff(ipt) * ctx1.J();
1231 ctx1.grad_base_value(t1);
1232 vectorize_grad_base_tensor(t1, tv1, ndof1, pf1->target_dim(), Q);
1234 ctx1.base_value(t1p);
1235 vectorize_base_tensor(t1p, tv1p, ndof1, pf1->target_dim(), Q);
1237 ctx2.grad_base_value(t2);
1238 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q);
1240 ctx2.base_value(t2p);
1241 vectorize_base_tensor(t2p, tv2p, ndof2, pf2->target_dim(), Q);
1243 ctx3.base_value(t3);
1244 vectorize_base_tensor(t3, tv3p, ndof3, pf3->target_dim(), Q);
1250 M2(j, i) += coeff * tv2.as_vector()[i+(k1+k2*N)*ndof2]
1251 * 0.5 * (tv2.as_vector()[j+(k1+k2*N)*ndof2] +
1252 tv2.as_vector()[j+(k2+k1*N)*ndof2]);
1256 M4(k, i) += coeff * tv2p(i, k);
1261 M6(k1+k2*N, i) += 0.5*coeff*(tv2.as_vector()[i+(k1+k2*N)*ndof2] -
1262 tv2.as_vector()[i+(k2+k1*N)*ndof2]);
1268 M1(j, i) += coeff * tv1.as_vector()[i+(k1+k2*N)*ndof1]
1269 * 0.5 * (tv2.as_vector()[j+(k1+k2*N)*ndof2] +
1270 tv2.as_vector()[j+(k2+k1*N)*ndof2]);
1274 M3(k, i) += coeff * tv1p(i, k);
1279 M7(i, j) += coeff * tv3p(i,k) * tv3p(j, k);
1284 M8(i, j) += coeff * tv3p(i,k) * tv2p(j, k);
1289 M9(i, j) += coeff * tv3p(i, k) * tv1p(j, k);
1294 for (
short_type ifc = 0; ifc < pgt->structure()->nb_faces(); ++ifc) {
1295 ctx1.set_face_num(ifc); ctx2.set_face_num(ifc); ctx3.set_face_num(ifc);
1296 ctx1i.set_face_num(ifc); ctx3i.set_face_num(ifc);
1297 size_type first_ind = pim->ind_first_point_on_face(ifc);
1298 for (
size_type ipt = 0; ipt < pim->nb_points_on_face(ifc); ++ipt) {
1299 ctx1.set_ii(first_ind+ipt); ctx2.set_ii(first_ind+ipt);
1300 ctx3.set_ii(first_ind+ipt); ctx1i.set_ii(first_ind+ipt);
1301 ctx3i.set_ii(first_ind+ipt);
1302 scalar_type coeff = pim->coeff(first_ind+ipt) * ctx1.J();
1303 gmm::mult(ctx1.B(), pgt->normals()[ifc], un);
1306 ctx2.grad_base_value(t2);
1307 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q);
1309 ctx2.base_value(t2p);
1310 vectorize_base_tensor(t2p, tv2p, ndof2, pf2->target_dim(), Q);
1312 ctx1.base_value(t1);
1313 vectorize_base_tensor(t1, tv1p, ndof1, pf1->target_dim(), Q);
1315 ctx1i.base_value(t1i);
1316 vectorize_base_tensor(t1i, tv1i, ndof1i, pf1i->target_dim(), Q);
1318 ctx3i.base_value(t3i);
1319 vectorize_base_tensor(t3i, tv3i, ndof3i, pf3i->target_dim(), Q);
1321 ctx3.base_value(t3);
1322 vectorize_base_tensor(t3, tv3p, ndof3, pf3->target_dim(), Q);
1327 scalar_type b(0), a = coeff *
1328 (tv1p(i, k1) - (i < ndof1i ? tv1i(i, k1) : 0.));
1330 b += a * 0.5 * (tv2.as_vector()[j+(k1 + k2*N)*ndof2] +
1331 tv2.as_vector()[j+(k2 + k1*N)*ndof2])* un[k2];
1338 M5(k1+k2*N, i) += 0.5 * coeff * (tv1p(i, k1) * un[k2] -
1339 tv1p(i, k2) * un[k1]);
1344 M7(i, j) += coeff * normun * tv3p(i,k) * tv3p(j, k);
1349 M8(i, j) += coeff * normun * tv3p(i,k) * tv2p(j, k);
1354 M9(i, j) += coeff * normun * tv3p(i, k) * tv1p(j, k);
1359 M10(i, j) += coeff * normun * tv3p(i,k) * tv3i(j, k);
1364 scalar_type coeff_p1 = pow(area, -1. - 2./scalar_type(N));
1365 scalar_type coeff_p2 = pow(area, -1. - 1./scalar_type(N));
1366 gmm::mult(gmm::transposed(M4), M4, aux2);
1367 gmm::add (gmm::scaled(aux2, coeff_p1), M2);
1368 gmm::mult(gmm::transposed(M6), M6, aux2);
1369 gmm::add (gmm::scaled(aux2, coeff_p2), M2);
1370 gmm::mult(gmm::transposed(M4), M3, aux1);
1371 gmm::add (gmm::scaled(aux1, coeff_p1), M1);
1372 gmm::mult(gmm::transposed(M6), M5, aux1);
1373 gmm::add (gmm::scaled(aux1, coeff_p2), M1);
1377 if (pf3->target_dim() == 1 && Q > 1) {
1378 gmm::sub_slice I(0, ndof3/Q, Q);
1381 gmm::sub_slice I2(i, ndof3/Q, Q);
1382 gmm::copy(gmm::sub_matrix(M7, I, I), gmm::sub_matrix(M7inv, I2, I2));
1388 gmm::clean(MD, gmm::vect_norminf(MD.as_vector()) * 1E-13);
1391 base_matrix MPB(ndof3, ndof3);
1394 gmm::add(gmm::scaled(MPB, scalar_type(-1)), M10);
1396 base_matrix MPC(ndof3, ndof1);
1397 gmm::mult(gmm::scaled(M8, scalar_type(-1)), MD, MPC);
1406 pelementary_transformation
1407 p = std::make_shared<_HHO_symmetrized_stabilization>();
The object geotrans_precomp_pool Allow to allocate a certain number of geotrans_precomp and automatic...
`‘Model’' variables store the variables, the data and the description of a model.
void add_elementary_transformation(const std::string &name, pelementary_transformation ptrans)
Add an elementary transformation to the model to be used with the generic assembly.
Tools for Hybrid-High-Order methods.
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 clean(L &l, double threshold)
Clean a vector or matrix (replace near-zero entries with zeroes).
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*/
void add(const L1 &l1, L2 &l2)
*/
void lu_inverse(const DenseMatrixLU &LU, const Pvector &pvector, const DenseMatrix &AInv_)
Given an LU factored matrix, build the inverse of the matrix.
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
pfem classical_fem(bgeot::pgeometric_trans pgt, short_type k, bool complete=false)
Give a pointer on the structures describing the classical polynomial fem of degree k on a given conve...
pfem interior_fem_of_hho_method(pfem hho_method)
Specific function for a HHO method to obtain the method in the interior.
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
GEneric Tool for Finite Element Methods.
void add_HHO_symmetrized_stabilization(model &md, std::string name)
Add to the model the elementary transformation corresponding to the HHO stabilization operator using ...
pintegration_method classical_approx_im(bgeot::pgeometric_trans pgt, dim_type degree)
try to find an approximate integration method for the geometric transformation pgt which is able to i...
void add_HHO_reconstructed_value(model &md, std::string name)
Add to the model the elementary transformation corresponding to the reconstruction of the variable.
void add_HHO_reconstructed_symmetrized_value(model &md, std::string name)
Add to the model the elementary transformation corresponding to the reconstruction of the variable us...
void add_HHO_reconstructed_symmetrized_gradient(model &md, std::string name)
Add to the model the elementary transformation corresponding to the reconstruction of a symmetrized g...
void add_HHO_stabilization(model &md, std::string name)
Add to the model the elementary transformation corresponding to the HHO stabilization operator.
void add_HHO_reconstructed_gradient(model &md, std::string name)
Add to the model the elementary transformation corresponding to the reconstruction of a gradient for ...