29 THREAD_SAFE_STATIC fem_precomp_pool HHO_pfp_pool;
39 class _HHO_reconstructed_gradient
40 :
public virtual_elementary_transformation {
44 virtual void give_transformation(
const mesh_fem &mf1,
const mesh_fem &mf2,
56 pfem pf1 = mf1.fem_of_element(cv);
57 pfem pf2 = mf2.fem_of_element(cv);
60 size_type degree = std::max(pf1->estimated_degree(),
61 pf2->estimated_degree());
63 papprox_integration pim
67 bgeot::vectors_to_base_matrix(G, mf1.linked_mesh().points_of_convex(cv));
69 bgeot::pgeotrans_precomp pgp
70 = HHO_pgp_pool(pgt, pim->pintegration_points());
71 pfem_precomp pfp1 = HHO_pfp_pool(pf1, pim->pintegration_points());
72 pfem_precomp pfp2 = HHO_pfp_pool(pf2, pim->pintegration_points());
73 pfem_precomp pfpi = HHO_pfp_pool(pfi, pim->pintegration_points());
75 fem_interpolation_context ctx1(pgp, pfp1, 0, G, cv);
76 fem_interpolation_context ctx2(pgp, pfp2, 0, G, cv);
77 fem_interpolation_context ctxi(pgp, pfpi, 0, G, cv);
79 size_type Q = mf1.get_qdim(), N = mf1.linked_mesh().dim();
82 size_type ndof1 = pf1->nb_dof(cv) * qmult1;
83 size_type qmult2 = Q*N / pf2->target_dim();
84 size_type ndof2 = pf2->nb_dof(cv) * qmult2;
86 size_type ndofi = pfi->nb_dof(cv) * qmulti;
88 base_tensor t1, t2, ti, tv1;
89 base_matrix tv2, tv1p, tvi;
90 base_matrix M1(ndof2, ndof1), M2(ndof2, ndof2), M2inv(ndof2, ndof2);
91 base_matrix aux2(ndof2, ndof2);
94 for (
size_type ipt = 0; ipt < pim->nb_points_on_convex(); ++ipt) {
95 ctx1.set_ii(ipt); ctx2.set_ii(ipt);
96 scalar_type coeff = pim->coeff(ipt) * ctx1.J();
98 ctx1.grad_base_value(t1);
99 vectorize_grad_base_tensor(t1, tv1, ndof1, pf1->target_dim(), Q);
102 vectorize_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q*N);
104 gmm::mult(tv2, gmm::transposed(tv2), aux2);
105 gmm::add(gmm::scaled(aux2, coeff), M2);
110 M1(j, i) += coeff * tv1.as_vector()[i+k*ndof1] * tv2(j, k);
114 for (
short_type ifc = 0; ifc < pgt->structure()->nb_faces(); ++ifc) {
115 ctx1.set_face_num(ifc); ctx2.set_face_num(ifc); ctxi.set_face_num(ifc);
116 size_type first_ind = pim->ind_first_point_on_face(ifc);
117 for (
size_type ipt = 0; ipt < pim->nb_points_on_face(ifc); ++ipt) {
118 ctx1.set_ii(first_ind+ipt);
119 ctx2.set_ii(first_ind+ipt);
120 ctxi.set_ii(first_ind+ipt);
121 scalar_type coeff = pim->coeff(first_ind+ipt) * ctx1.J();
122 gmm::mult(ctx1.B(), pgt->normals()[ifc], un);
125 vectorize_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q*N);
128 vectorize_base_tensor(t1, tv1p, ndof1, pf1->target_dim(), Q);
131 vectorize_base_tensor(ti, tvi, ndofi, pfi->target_dim(), Q);
136 scalar_type b(0), a = coeff *
137 (tv1p(i, k1) - (i < ndofi ? tvi(i, k1) : 0.));
139 b += a * tv2(j, k1 + k2*Q) * un[k2];
145 if (pf2->target_dim() == 1) {
146 gmm::sub_slice I(0, ndof2/(N*Q), N*Q);
147 gmm::lu_inverse(gmm::sub_matrix(M2, I, I));
149 gmm::sub_slice I2(i, ndof2/(N*Q), N*Q);
150 gmm::copy(gmm::sub_matrix(M2, I, I), gmm::sub_matrix(M2inv, I2, I2));
152 }
else { gmm::copy(M2, M2inv); gmm::lu_inverse(M2inv); }
154 gmm::mult(M2inv, M1, M);
155 gmm::clean(M, gmm::vect_norminf(M.as_vector()) * 1E-13);
160 pelementary_transformation
161 p = std::make_shared<_HHO_reconstructed_gradient>();
166 class _HHO_reconstructed_sym_gradient
167 :
public virtual_elementary_transformation {
171 virtual void give_transformation(
const mesh_fem &mf1,
const mesh_fem &mf2,
184 pfem pf1 = mf1.fem_of_element(cv);
185 pfem pf2 = mf2.fem_of_element(cv);
188 size_type degree = std::max(pf1->estimated_degree(),
189 pf2->estimated_degree());
191 papprox_integration pim
195 bgeot::vectors_to_base_matrix(G, mf1.linked_mesh().points_of_convex(cv));
197 bgeot::pgeotrans_precomp pgp
198 = HHO_pgp_pool(pgt, pim->pintegration_points());
199 pfem_precomp pfp1 = HHO_pfp_pool(pf1, pim->pintegration_points());
200 pfem_precomp pfp2 = HHO_pfp_pool(pf2, pim->pintegration_points());
201 pfem_precomp pfpi = HHO_pfp_pool(pfi, pim->pintegration_points());
203 fem_interpolation_context ctx1(pgp, pfp1, 0, G, cv);
204 fem_interpolation_context ctx2(pgp, pfp2, 0, G, cv);
205 fem_interpolation_context ctxi(pgp, pfpi, 0, G, cv);
207 size_type Q = mf1.get_qdim(), N = mf1.linked_mesh().dim();
208 GMM_ASSERT1(Q == N,
"This transformation works only for vector fields "
209 "having the same dimension as the domain");
211 size_type qmult1 = N / pf1->target_dim();
212 size_type ndof1 = pf1->nb_dof(cv) * qmult1;
213 size_type qmult2 = N*N / pf2->target_dim();
214 size_type ndof2 = pf2->nb_dof(cv) * qmult2;
215 size_type qmulti = N / pfi->target_dim();
216 size_type ndofi = pfi->nb_dof(cv) * qmulti;
219 base_tensor t1, t2, ti, tv1;
220 base_matrix tv2, tv1p, tvi;
221 base_matrix M1(ndof2, ndof1), M2(ndof2, ndof2), M2inv(ndof2, ndof2);
222 base_matrix aux2(ndof2, ndof2);
226 for (
size_type ipt = 0; ipt < pim->nb_points_on_convex(); ++ipt) {
227 ctx1.set_ii(ipt); ctx2.set_ii(ipt);
228 scalar_type coeff = pim->coeff(ipt) * ctx1.J();
230 ctx1.grad_base_value(t1);
231 vectorize_grad_base_tensor(t1, tv1, ndof1, pf1->target_dim(), N);
234 vectorize_base_tensor(t2, tv2, ndof2, pf2->target_dim(), N*N);
236 gmm::mult(tv2, gmm::transposed(tv2), aux2);
237 gmm::add(gmm::scaled(aux2, coeff), M2);
243 M1(j, i) += coeff * tv1.as_vector()[i+(k1+k2*N)*ndof1]
244 * 0.5 * (tv2(j, k1+k2*N) + tv2(j, k2+k1*N));
248 for (
short_type ifc = 0; ifc < pgt->structure()->nb_faces(); ++ifc) {
249 ctx1.set_face_num(ifc); ctx2.set_face_num(ifc); ctxi.set_face_num(ifc);
250 size_type first_ind = pim->ind_first_point_on_face(ifc);
251 for (
size_type ipt = 0; ipt < pim->nb_points_on_face(ifc); ++ipt) {
252 ctx1.set_ii(first_ind+ipt);
253 ctx2.set_ii(first_ind+ipt);
254 ctxi.set_ii(first_ind+ipt);
255 scalar_type coeff = pim->coeff(first_ind+ipt) * ctx1.J();
256 gmm::mult(ctx1.B(), pgt->normals()[ifc], un);
259 vectorize_base_tensor(t2, tv2, ndof2, pf2->target_dim(), N*N);
262 vectorize_base_tensor(t1, tv1p, ndof1, pf1->target_dim(), N);
265 vectorize_base_tensor(ti, tvi, ndofi, pfi->target_dim(), N);
270 scalar_type b(0), a = coeff *
271 (tv1p(i, k1) - (i < ndofi ? tvi(i, k1) : 0.));
273 b += a*0.5*(tv2(j, k1 + k2*N) + tv2(j, k2 + k1*N)) * un[k2];
280 if (pf2->target_dim() == 1) {
281 gmm::sub_slice I(0, ndof2/(N*Q), N*Q);
282 gmm::lu_inverse(gmm::sub_matrix(M2, I, I));
284 gmm::sub_slice I2(i, ndof2/(N*Q), N*Q);
285 gmm::copy(gmm::sub_matrix(M2, I, I), gmm::sub_matrix(M2inv, I2, I2));
288 { gmm::copy(M2, M2inv); gmm::lu_inverse(M2inv); }
290 gmm::mult(M2inv, M1, M);
291 gmm::clean(M, gmm::vect_norminf(M.as_vector()) * 1E-13);
296 pelementary_transformation
297 p = std::make_shared<_HHO_reconstructed_sym_gradient>();
303 class _HHO_reconstructed_value
304 :
public virtual_elementary_transformation {
308 virtual void give_transformation(
const mesh_fem &mf1,
const mesh_fem &mf2,
322 pfem pf1 = mf1.fem_of_element(cv);
323 pfem pf2 = mf2.fem_of_element(cv);
326 size_type degree = std::max(pf1->estimated_degree(),
327 pf2->estimated_degree());
329 papprox_integration pim
333 bgeot::vectors_to_base_matrix(G, mf1.linked_mesh().points_of_convex(cv));
335 bgeot::pgeotrans_precomp pgp
336 = HHO_pgp_pool(pgt, pim->pintegration_points());
337 pfem_precomp pfp1 = HHO_pfp_pool(pf1, pim->pintegration_points());
338 pfem_precomp pfp2 = HHO_pfp_pool(pf2, pim->pintegration_points());
339 pfem_precomp pfpi = HHO_pfp_pool(pfi, pim->pintegration_points());
341 fem_interpolation_context ctx1(pgp, pfp1, 0, G, cv);
342 fem_interpolation_context ctx2(pgp, pfp2, 0, G, cv);
343 fem_interpolation_context ctxi(pgp, pfpi, 0, G, cv);
345 size_type Q = mf1.get_qdim(), N = mf1.linked_mesh().dim();
347 size_type qmult1 = Q / pf1->target_dim();
348 size_type ndof1 = pf1->nb_dof(cv) * qmult1;
349 size_type qmult2 = Q / pf2->target_dim();
350 size_type ndof2 = pf2->nb_dof(cv) * qmult2;
351 size_type qmulti = Q / pfi->target_dim();
352 size_type ndofi = pfi->nb_dof(cv) * qmulti;
355 base_tensor t1, t2, ti, tv1, tv2, t1p, t2p;
356 base_matrix tv1p, tv2p, tvi;
357 base_matrix M1(ndof2, ndof1), M2(ndof2, ndof2), M2inv(ndof2, ndof2);
358 base_matrix M3(Q, ndof1), M4(Q, ndof2);
359 base_matrix aux1(ndof2, ndof1), aux2(ndof2, ndof2);
365 for (
size_type ipt = 0; ipt < pim->nb_points_on_convex(); ++ipt) {
366 ctx1.set_ii(ipt); ctx2.set_ii(ipt);
367 scalar_type coeff = pim->coeff(ipt) * ctx1.J();
370 ctx1.grad_base_value(t1);
371 vectorize_grad_base_tensor(t1, tv1, ndof1, pf1->target_dim(), Q);
373 ctx1.base_value(t1p);
374 vectorize_base_tensor(t1p, tv1p, ndof1, pf1->target_dim(), Q);
376 ctx2.grad_base_value(t2);
377 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q);
379 ctx2.base_value(t2p);
380 vectorize_base_tensor(t2p, tv2p, ndof2, pf2->target_dim(), Q);
385 M2(j, i) += coeff * tv2.as_vector()[i+k*ndof2]
386 * tv2.as_vector()[j+k*ndof2];
390 M4(k, i) += coeff * tv2p(i, k);
395 M1(j, i) += coeff * tv1.as_vector()[i+k*ndof1]
396 * tv2.as_vector()[j+k*ndof2];
400 M3(k, i) += coeff * tv1p(i, k);
405 for (
short_type ifc = 0; ifc < pgt->structure()->nb_faces(); ++ifc) {
406 ctx1.set_face_num(ifc); ctx2.set_face_num(ifc); ctxi.set_face_num(ifc);
407 size_type first_ind = pim->ind_first_point_on_face(ifc);
408 for (
size_type ipt = 0; ipt < pim->nb_points_on_face(ifc); ++ipt) {
409 ctx1.set_ii(first_ind+ipt);
410 ctx2.set_ii(first_ind+ipt);
411 ctxi.set_ii(first_ind+ipt);
412 scalar_type coeff = pim->coeff(first_ind+ipt) * ctx1.J();
413 gmm::mult(ctx1.B(), pgt->normals()[ifc], un);
415 ctx2.grad_base_value(t2);
416 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q);
419 vectorize_base_tensor(t1, tv1p, ndof1, pf1->target_dim(), Q);
422 vectorize_base_tensor(ti, tvi, ndofi, pfi->target_dim(), Q);
427 scalar_type b(0), a = coeff *
428 (tv1p(i, k1) - (i < ndofi ? tvi(i, k1) : 0.));
430 b += a * tv2.as_vector()[j+(k1+k2*Q)*ndof2] * un[k2];
438 scalar_type coeff_p = pow(area, -1. - 2./scalar_type(N));
439 gmm::mult(gmm::transposed(M4), M4, aux2);
440 gmm::add (gmm::scaled(aux2, coeff_p), M2);
441 gmm::mult(gmm::transposed(M4), M3, aux1);
442 gmm::add (gmm::scaled(aux1, coeff_p), M1);
444 if (pf2->target_dim() == 1 && Q > 1) {
445 gmm::sub_slice I(0, ndof2/Q, Q);
446 gmm::lu_inverse(gmm::sub_matrix(M2, I, I));
448 gmm::sub_slice I2(i, ndof2/Q, Q);
449 gmm::copy(gmm::sub_matrix(M2, I, I), gmm::sub_matrix(M2inv, I2, I2));
452 { gmm::copy(M2, M2inv); gmm::lu_inverse(M2inv); }
454 gmm::mult(M2inv, M1, M);
455 gmm::clean(M, gmm::vect_norminf(M.as_vector()) * 1E-13);
460 pelementary_transformation
461 p = std::make_shared<_HHO_reconstructed_value>();
466 class _HHO_reconstructed_sym_value
467 :
public virtual_elementary_transformation {
471 virtual void give_transformation(
const mesh_fem &mf1,
const mesh_fem &mf2,
486 pfem pf1 = mf1.fem_of_element(cv);
487 pfem pf2 = mf2.fem_of_element(cv);
490 size_type degree = std::max(pf1->estimated_degree(),
491 pf2->estimated_degree());
493 papprox_integration pim
497 bgeot::vectors_to_base_matrix(G, mf1.linked_mesh().points_of_convex(cv));
499 bgeot::pgeotrans_precomp pgp
500 = HHO_pgp_pool(pgt, pim->pintegration_points());
501 pfem_precomp pfp1 = HHO_pfp_pool(pf1, pim->pintegration_points());
502 pfem_precomp pfp2 = HHO_pfp_pool(pf2, pim->pintegration_points());
503 pfem_precomp pfpi = HHO_pfp_pool(pfi, pim->pintegration_points());
505 fem_interpolation_context ctx1(pgp, pfp1, 0, G, cv);
506 fem_interpolation_context ctx2(pgp, pfp2, 0, G, cv);
507 fem_interpolation_context ctxi(pgp, pfpi, 0, G, cv);
509 size_type Q = mf1.get_qdim(), N = mf1.linked_mesh().dim();
510 GMM_ASSERT1(Q == N,
"This transformation works only for vector fields "
511 "having the same dimension as the domain");
513 size_type qmult1 = N / pf1->target_dim();
514 size_type ndof1 = pf1->nb_dof(cv) * qmult1;
515 size_type qmult2 = N / pf2->target_dim();
516 size_type ndof2 = pf2->nb_dof(cv) * qmult2;
517 size_type qmulti = N / pfi->target_dim();
518 size_type ndofi = pfi->nb_dof(cv) * qmulti;
521 base_tensor t1, t2, ti, tv1, tv2, t1p, t2p;
522 base_matrix tv1p, tv2p, tvi;
523 base_matrix M1(ndof2, ndof1), M2(ndof2, ndof2), M2inv(ndof2, ndof2);;
524 base_matrix M3(N, ndof1), M4(N, ndof2);
525 base_matrix M5(N*N, ndof1), M6(N*N, ndof2);
526 base_matrix aux1(ndof2, ndof1), aux2(ndof2, ndof2);
533 for (
size_type ipt = 0; ipt < pim->nb_points_on_convex(); ++ipt) {
534 ctx1.set_ii(ipt); ctx2.set_ii(ipt);
535 scalar_type coeff = pim->coeff(ipt) * ctx1.J();
538 ctx1.grad_base_value(t1);
539 vectorize_grad_base_tensor(t1, tv1, ndof1, pf1->target_dim(), N);
541 ctx1.base_value(t1p);
542 vectorize_base_tensor(t1p, tv1p, ndof1, pf1->target_dim(), N);
544 ctx2.grad_base_value(t2);
545 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), N);
547 ctx2.base_value(t2p);
548 vectorize_base_tensor(t2p, tv2p, ndof2, pf2->target_dim(), N);
554 M2(j, i) += coeff * tv2.as_vector()[i+(k1+k2*N)*ndof2]
555 * 0.5 * (tv2.as_vector()[j+(k1+k2*N)*ndof2] +
556 tv2.as_vector()[j+(k2+k1*N)*ndof2]);
560 M4(k, i) += coeff * tv2p(i, k);
565 M6(k1+k2*N, i) += 0.5*coeff*(tv2.as_vector()[i+(k1+k2*N)*ndof2] -
566 tv2.as_vector()[i+(k2+k1*N)*ndof2]);
572 M1(j, i) += coeff * tv1.as_vector()[i+(k1+k2*N)*ndof1]
573 * 0.5 * (tv2.as_vector()[j+(k1+k2*N)*ndof2] +
574 tv2.as_vector()[j+(k2+k1*N)*ndof2]);
578 M3(k, i) += coeff * tv1p(i, k);
584 for (
short_type ifc = 0; ifc < pgt->structure()->nb_faces(); ++ifc) {
585 ctx1.set_face_num(ifc); ctx2.set_face_num(ifc); ctxi.set_face_num(ifc);
586 size_type first_ind = pim->ind_first_point_on_face(ifc);
587 for (
size_type ipt = 0; ipt < pim->nb_points_on_face(ifc); ++ipt) {
588 ctx1.set_ii(first_ind+ipt);
589 ctx2.set_ii(first_ind+ipt);
590 ctxi.set_ii(first_ind+ipt);
591 scalar_type coeff = pim->coeff(first_ind+ipt) * ctx1.J();
592 gmm::mult(ctx1.B(), pgt->normals()[ifc], un);
594 ctx2.grad_base_value(t2);
595 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), N);
598 vectorize_base_tensor(t1, tv1p, ndof1, pf1->target_dim(), N);
601 vectorize_base_tensor(ti, tvi, ndofi, pfi->target_dim(), N);
606 scalar_type b(0), a = coeff *
607 (tv1p(i, k1) - (i < ndofi ? tvi(i, k1) : 0.));
609 b += a * 0.5 * (tv2.as_vector()[j+(k1+k2*N)*ndof2] +
610 tv2.as_vector()[j+(k2+k1*N)*ndof2]) * un[k2];
617 M5(k1+k2*N, i) += 0.5 * coeff * (tv1p(i, k1) * un[k2] -
618 tv1p(i, k2) * un[k1]);
623 scalar_type coeff_p1 = pow(area, -1. - 2./scalar_type(N));
624 scalar_type coeff_p2 = pow(area, -1. - 1./scalar_type(N));
625 gmm::mult(gmm::transposed(M4), M4, aux2);
626 gmm::add (gmm::scaled(aux2, coeff_p1), M2);
627 gmm::mult(gmm::transposed(M6), M6, aux2);
628 gmm::add (gmm::scaled(aux2, coeff_p2), M2);
629 gmm::mult(gmm::transposed(M4), M3, aux1);
630 gmm::add (gmm::scaled(aux1, coeff_p1), M1);
631 gmm::mult(gmm::transposed(M6), M5, aux1);
632 gmm::add (gmm::scaled(aux1, coeff_p2), M1);
634 gmm::copy(M2, M2inv); gmm::lu_inverse(M2inv);
636 gmm::mult(M2inv, M1, M);
637 gmm::clean(M, gmm::vect_norminf(M.as_vector()) * 1E-13);
642 pelementary_transformation
643 p = std::make_shared<_HHO_reconstructed_sym_value>();
647 #if 0 // Old single mef version
649 class _HHO_stabilization
650 :
public virtual_elementary_transformation {
654 virtual void give_transformation(
const mesh_fem &mf1,
const mesh_fem &mf2,
676 GMM_ASSERT1(&mf1 == &mf2,
"The HHO stabilization transformation is "
677 "only defined on the HHO space to itself");
680 pfem pf1 = mf1.fem_of_element(cv);
687 papprox_integration pim
691 bgeot::vectors_to_base_matrix(G, mf1.linked_mesh().points_of_convex(cv));
693 bgeot::pgeotrans_precomp pgp
694 = HHO_pgp_pool(pgt, pim->pintegration_points());
695 pfem_precomp pfp1 = HHO_pfp_pool(pf1, pim->pintegration_points());
696 pfem_precomp pfp2 = HHO_pfp_pool(pf2, pim->pintegration_points());
697 pfem_precomp pfpi = HHO_pfp_pool(pfi, pim->pintegration_points());
699 fem_interpolation_context ctx1(pgp, pfp1, 0, G, cv);
700 fem_interpolation_context ctx2(pgp, pfp2, 0, G, cv);
701 fem_interpolation_context ctxi(pgp, pfpi, 0, G, cv);
703 size_type Q = mf1.get_qdim(), N = mf1.linked_mesh().dim();
705 size_type qmult1 = Q / pf1->target_dim();
706 size_type ndof1 = pf1->nb_dof(cv) * qmult1;
707 size_type qmult2 = Q / pf2->target_dim();
708 size_type ndof2 = pf2->nb_dof(cv) * qmult2;
709 size_type qmulti = Q / pfi->target_dim();
710 size_type ndofi = pfi->nb_dof(cv) * qmulti;
713 base_tensor t1, t2, ti, tv1, tv2, t1p, t2p;
714 base_matrix tv1p, tv2p, tvi;
715 base_matrix M1(ndof2, ndof1), M2(ndof2, ndof2), M2inv(ndof2, ndof2);
716 base_matrix M3(Q, ndof1), M4(Q, ndof2);
717 base_matrix aux1(ndof2, ndof1), aux2(ndof2, ndof2);
718 base_matrix M7(ndof1, ndof1), M7inv(ndof1, ndof1), M8(ndof1, ndof2);
719 base_matrix M9(ndof1, ndof1), MD(ndof2, ndof1);
725 for (
size_type ipt = 0; ipt < pim->nb_points_on_convex(); ++ipt) {
726 ctx1.set_ii(ipt); ctx2.set_ii(ipt);
727 scalar_type coeff = pim->coeff(ipt) * ctx1.J();
730 ctx1.grad_base_value(t1);
731 vectorize_grad_base_tensor(t1, tv1, ndof1, pf1->target_dim(), Q);
733 ctx1.base_value(t1p);
734 vectorize_base_tensor(t1p, tv1p, ndof1, pf1->target_dim(), Q);
736 ctx2.grad_base_value(t2);
737 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q);
739 ctx2.base_value(t2p);
740 vectorize_base_tensor(t2p, tv2p, ndof2, pf2->target_dim(), Q);
745 M2(j, i) += coeff * tv2.as_vector()[i+k*ndof2]
746 * tv2.as_vector()[j+k*ndof2];
750 M4(k, i) += coeff * tv2p(i, k);
755 M1(j, i) += coeff * tv1.as_vector()[i+k*ndof1]
756 * tv2.as_vector()[j+k*ndof2];
760 M3(k, i) += coeff * tv1p(i, k);
765 M7(i, j) += coeff * tv1p(i, k) * tv1p(j, k);
770 M8(i, j) += coeff * tv1p(i, k) * tv2p(j, k);
775 for (
short_type ifc = 0; ifc < pgt->structure()->nb_faces(); ++ifc) {
776 ctx1.set_face_num(ifc); ctx2.set_face_num(ifc); ctxi.set_face_num(ifc);
777 size_type first_ind = pim->ind_first_point_on_face(ifc);
778 for (
size_type ipt = 0; ipt < pim->nb_points_on_face(ifc); ++ipt) {
779 ctx1.set_ii(first_ind+ipt);
780 ctx2.set_ii(first_ind+ipt);
781 ctxi.set_ii(first_ind+ipt);
782 scalar_type coeff = pim->coeff(first_ind+ipt) * ctx1.J();
783 gmm::mult(ctx1.B(), pgt->normals()[ifc], un);
786 ctx2.grad_base_value(t2);
787 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q);
789 ctx2.base_value(t2p);
790 vectorize_base_tensor(t2p, tv2p, ndof2, pf2->target_dim(), Q);
793 vectorize_base_tensor(t1, tv1p, ndof1, pf1->target_dim(), Q);
796 vectorize_base_tensor(ti, tvi, ndofi, pfi->target_dim(), Q);
802 scalar_type b(0), a = coeff *
803 (tv1p(i, k1) - (i < ndofi ? tvi(i, k1) : 0.));
805 b += a * tv2.as_vector()[j+(k1 + k2*Q)*ndof2] * un[k2];
812 M7(i, j) += coeff * normun * tv1p(i,k) * tv1p(j, k);
817 M8(i, j) += coeff * normun * tv1p(i,k) * tv2p(j, k);
822 M9(i, j) += coeff * normun * tv1p(i,k) * tvi(j, k);
827 scalar_type coeff_p = pow(area, -1. - 2./scalar_type(N));
828 gmm::mult(gmm::transposed(M4), M4, aux2);
829 gmm::add (gmm::scaled(aux2, coeff_p), M2);
830 gmm::mult(gmm::transposed(M4), M3, aux1);
831 gmm::add (gmm::scaled(aux1, coeff_p), M1);
833 if (pf2->target_dim() == 1 && Q > 1) {
834 gmm::sub_slice I(0, ndof2/Q, Q);
835 gmm::lu_inverse(gmm::sub_matrix(M2, I, I));
837 gmm::sub_slice I2(i, ndof2/Q, Q);
838 gmm::copy(gmm::sub_matrix(M2, I, I), gmm::sub_matrix(M2inv, I2, I2));
841 { gmm::copy(M2, M2inv); gmm::lu_inverse(M2inv); }
843 if (pf1->target_dim() == 1 && Q > 1) {
844 gmm::sub_slice I(0, ndof1/Q, Q);
845 gmm::lu_inverse(gmm::sub_matrix(M7, I, I));
847 gmm::sub_slice I2(i, ndof1/Q, Q);
848 gmm::copy(gmm::sub_matrix(M7, I, I), gmm::sub_matrix(M7inv, I2, I2));
851 { gmm::copy(M7, M7inv); gmm::lu_inverse(M7inv); }
853 gmm::mult(M2inv, M1, MD);
854 gmm::clean(MD, gmm::vect_norminf(MD.as_vector()) * 1E-13);
857 base_matrix MPB(ndof1, ndof1);
858 gmm::mult(M7inv, M9, MPB);
859 gmm::copy(gmm::identity_matrix(), M9);
860 gmm::add(gmm::scaled(MPB, scalar_type(-1)), M9);
862 base_matrix MPC(ndof1, ndof1), MPD(ndof1, ndof1);
863 gmm::mult(M8, MD, MPC);
864 gmm::mult(M7inv, MPC, MPD);
865 gmm::copy(gmm::identity_matrix(), M7);
866 gmm::add(gmm::scaled(MPD, scalar_type(-1)), M7);
868 gmm::mult(M9, M7, M);
869 gmm::clean(M, 1E-13);
874 pelementary_transformation
875 p = std::make_shared<_HHO_stabilization>();
876 md.add_elementary_transformation(name, p);
883 class _HHO_stabilization
884 :
public virtual_elementary_transformation {
888 virtual void give_transformation(
const mesh_fem &mf1,
const mesh_fem &mf2,
911 pfem pf1 = mf1.fem_of_element(cv);
916 pfem pf3 = mf2.fem_of_element(cv);
920 papprox_integration pim
924 bgeot::vectors_to_base_matrix(G, mf1.linked_mesh().points_of_convex(cv));
926 bgeot::pgeotrans_precomp pgp
927 = HHO_pgp_pool(pgt, pim->pintegration_points());
928 pfem_precomp pfp1 = HHO_pfp_pool(pf1, pim->pintegration_points());
929 pfem_precomp pfp2 = HHO_pfp_pool(pf2, pim->pintegration_points());
930 pfem_precomp pfp3 = HHO_pfp_pool(pf3, pim->pintegration_points());
931 pfem_precomp pfp1i = HHO_pfp_pool(pf1i, pim->pintegration_points());
932 pfem_precomp pfp3i = HHO_pfp_pool(pf3i, pim->pintegration_points());
934 fem_interpolation_context ctx1(pgp, pfp1, 0, G, cv);
935 fem_interpolation_context ctx2(pgp, pfp2, 0, G, cv);
936 fem_interpolation_context ctx3(pgp, pfp3, 0, G, cv);
937 fem_interpolation_context ctx1i(pgp, pfp1i, 0, G, cv);
938 fem_interpolation_context ctx3i(pgp, pfp3i, 0, G, cv);
940 size_type Q = mf1.get_qdim(), N = mf1.linked_mesh().dim();
942 size_type qmult1 = Q / pf1->target_dim();
943 size_type ndof1 = pf1->nb_dof(cv) * qmult1;
944 size_type qmult2 = Q / pf2->target_dim();
945 size_type ndof2 = pf2->nb_dof(cv) * qmult2;
946 size_type qmult3 = Q / pf3->target_dim();
947 size_type ndof3 = pf3->nb_dof(cv) * qmult3;
948 size_type qmult1i = Q / pf1i->target_dim();
949 size_type ndof1i = pf1i->nb_dof(cv) * qmult1i;
950 size_type qmult3i = Q / pf3i->target_dim();
951 size_type ndof3i = pf3i->nb_dof(cv) * qmult3i;
954 base_tensor t1, t2, t3, t1i, t3i, tv1, tv2, t1p, t2p;
955 base_matrix tv1p, tv2p, tv3p, tv1i, tv3i;
956 base_matrix M1(ndof2, ndof1), M2(ndof2, ndof2), M2inv(ndof2, ndof2);
957 base_matrix M3(Q, ndof1), M4(Q, ndof2);
958 base_matrix aux1(ndof2, ndof1), aux2(ndof2, ndof2);
959 base_matrix M7(ndof3, ndof3), M7inv(ndof3, ndof3), M8(ndof3, ndof2);
960 base_matrix M9(ndof3, ndof1), M10(ndof3, ndof3), MD(ndof2, ndof1);
966 for (
size_type ipt = 0; ipt < pim->nb_points_on_convex(); ++ipt) {
967 ctx1.set_ii(ipt); ctx2.set_ii(ipt); ctx3.set_ii(ipt);
968 scalar_type coeff = pim->coeff(ipt) * ctx1.J();
971 ctx1.grad_base_value(t1);
972 vectorize_grad_base_tensor(t1, tv1, ndof1, pf1->target_dim(), Q);
974 ctx1.base_value(t1p);
975 vectorize_base_tensor(t1p, tv1p, ndof1, pf1->target_dim(), Q);
977 ctx2.grad_base_value(t2);
978 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q);
980 ctx2.base_value(t2p);
981 vectorize_base_tensor(t2p, tv2p, ndof2, pf2->target_dim(), Q);
984 vectorize_base_tensor(t3, tv3p, ndof3, pf3->target_dim(), Q);
989 M2(j, i) += coeff * tv2.as_vector()[i+k*ndof2]
990 * tv2.as_vector()[j+k*ndof2];
994 M4(k, i) += coeff * tv2p(i, k);
999 M1(j, i) += coeff * tv1.as_vector()[i+k*ndof1]
1000 * tv2.as_vector()[j+k*ndof2];
1004 M3(k, i) += coeff * tv1p(i, k);
1009 M7(i, j) += coeff * tv3p(i, k) * tv3p(j, k);
1014 M8(i, j) += coeff * tv3p(i, k) * tv2p(j, k);
1019 M9(i, j) += coeff * tv3p(i, k) * tv1p(j, k);
1023 for (
short_type ifc = 0; ifc < pgt->structure()->nb_faces(); ++ifc) {
1024 ctx1.set_face_num(ifc); ctx2.set_face_num(ifc); ctx3.set_face_num(ifc);
1025 ctx1i.set_face_num(ifc); ctx3i.set_face_num(ifc);
1026 size_type first_ind = pim->ind_first_point_on_face(ifc);
1027 for (
size_type ipt = 0; ipt < pim->nb_points_on_face(ifc); ++ipt) {
1028 ctx1.set_ii(first_ind+ipt); ctx2.set_ii(first_ind+ipt);
1029 ctx3.set_ii(first_ind+ipt); ctx1i.set_ii(first_ind+ipt);
1030 ctx3i.set_ii(first_ind+ipt);
1031 scalar_type coeff = pim->coeff(first_ind+ipt) * ctx1.J();
1032 gmm::mult(ctx1.B(), pgt->normals()[ifc], un);
1035 ctx2.grad_base_value(t2);
1036 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q);
1038 ctx2.base_value(t2p);
1039 vectorize_base_tensor(t2p, tv2p, ndof2, pf2->target_dim(), Q);
1041 ctx1.base_value(t1);
1042 vectorize_base_tensor(t1, tv1p, ndof1, pf1->target_dim(), Q);
1044 ctx1i.base_value(t1i);
1045 vectorize_base_tensor(t1i, tv1i, ndof1i, pf1i->target_dim(), Q);
1047 ctx3i.base_value(t3i);
1048 vectorize_base_tensor(t3i, tv3i, ndof3i, pf3i->target_dim(), Q);
1050 ctx3.base_value(t3);
1051 vectorize_base_tensor(t3, tv3p, ndof3, pf3->target_dim(), Q);
1057 scalar_type b(0), a = coeff *
1058 (tv1p(i, k1) - (i < ndof1i ? tv1i(i, k1) : 0.));
1060 b += a * tv2.as_vector()[j+(k1 + k2*Q)*ndof2] * un[k2];
1067 M7(i, j) += coeff * normun * tv3p(i,k) * tv3p(j, k);
1072 M8(i, j) += coeff * normun * tv3p(i,k) * tv2p(j, k);
1077 M9(i, j) += coeff * normun * tv3p(i, k) * tv1p(j, k);
1082 M10(i, j) += coeff * normun * tv3p(i,k) * tv3i(j, k);
1087 scalar_type coeff_p = pow(area, -1. - 2./scalar_type(N));
1088 gmm::mult(gmm::transposed(M4), M4, aux2);
1089 gmm::add (gmm::scaled(aux2, coeff_p), M2);
1090 gmm::mult(gmm::transposed(M4), M3, aux1);
1091 gmm::add (gmm::scaled(aux1, coeff_p), M1);
1093 if (pf2->target_dim() == 1 && Q > 1) {
1094 gmm::sub_slice I(0, ndof2/Q, Q);
1095 gmm::lu_inverse(gmm::sub_matrix(M2, I, I));
1097 gmm::sub_slice I2(i, ndof2/Q, Q);
1098 gmm::copy(gmm::sub_matrix(M2, I, I), gmm::sub_matrix(M2inv, I2, I2));
1101 { gmm::copy(M2, M2inv); gmm::lu_inverse(M2inv); }
1103 if (pf3->target_dim() == 1 && Q > 1) {
1104 gmm::sub_slice I(0, ndof3/Q, Q);
1105 gmm::lu_inverse(gmm::sub_matrix(M7, I, I));
1107 gmm::sub_slice I2(i, ndof3/Q, Q);
1108 gmm::copy(gmm::sub_matrix(M7, I, I), gmm::sub_matrix(M7inv, I2, I2));
1111 { gmm::copy(M7, M7inv); gmm::lu_inverse(M7inv); }
1113 gmm::mult(M2inv, M1, MD);
1114 gmm::clean(MD, gmm::vect_norminf(MD.as_vector()) * 1E-13);
1117 base_matrix MPB(ndof3, ndof3);
1118 gmm::mult(M7inv, M10, MPB);
1119 gmm::copy(gmm::identity_matrix(), M10);
1120 gmm::add(gmm::scaled(MPB, scalar_type(-1)), M10);
1122 base_matrix MPC(ndof3, ndof1);
1123 gmm::mult(gmm::scaled(M8, scalar_type(-1)), MD, MPC);
1125 gmm::mult(M7inv, MPC, M9);
1126 gmm::mult(M10, M9, M);
1127 gmm::clean(M, 1E-13);
1132 pelementary_transformation
1133 p = std::make_shared<_HHO_stabilization>();
1139 class _HHO_symmetrized_stabilization
1140 :
public virtual_elementary_transformation {
1144 virtual void give_transformation(
const mesh_fem &mf1,
const mesh_fem &mf2,
1168 pfem pf1 = mf1.fem_of_element(cv);
1173 pfem pf3 = mf2.fem_of_element(cv);
1177 papprox_integration pim
1181 bgeot::vectors_to_base_matrix(G, mf1.linked_mesh().points_of_convex(cv));
1183 bgeot::pgeotrans_precomp pgp
1184 = HHO_pgp_pool(pgt, pim->pintegration_points());
1185 pfem_precomp pfp1 = HHO_pfp_pool(pf1, pim->pintegration_points());
1186 pfem_precomp pfp2 = HHO_pfp_pool(pf2, pim->pintegration_points());
1187 pfem_precomp pfp3 = HHO_pfp_pool(pf3, pim->pintegration_points());
1188 pfem_precomp pfp1i = HHO_pfp_pool(pf1i, pim->pintegration_points());
1189 pfem_precomp pfp3i = HHO_pfp_pool(pf3i, pim->pintegration_points());
1191 fem_interpolation_context ctx1(pgp, pfp1, 0, G, cv);
1192 fem_interpolation_context ctx2(pgp, pfp2, 0, G, cv);
1193 fem_interpolation_context ctx3(pgp, pfp3, 0, G, cv);
1194 fem_interpolation_context ctx1i(pgp, pfp1i, 0, G, cv);
1195 fem_interpolation_context ctx3i(pgp, pfp3i, 0, G, cv);
1197 size_type Q = mf1.get_qdim(), N = mf1.linked_mesh().dim();
1198 GMM_ASSERT1(Q == N,
"This transformation works only for vector fields "
1199 "having the same dimension as the domain");
1201 size_type qmult1 = N / pf1->target_dim();
1202 size_type ndof1 = pf1->nb_dof(cv) * qmult1;
1203 size_type qmult2 = N / pf2->target_dim();
1204 size_type ndof2 = pf2->nb_dof(cv) * qmult2;
1205 size_type qmult3 = Q / pf3->target_dim();
1206 size_type ndof3 = pf3->nb_dof(cv) * qmult3;
1207 size_type qmult1i = Q / pf1i->target_dim();
1208 size_type ndof1i = pf1i->nb_dof(cv) * qmult1i;
1209 size_type qmult3i = Q / pf3i->target_dim();
1210 size_type ndof3i = pf3i->nb_dof(cv) * qmult3i;
1213 base_tensor t1, t2, t3, t1i, t3i, tv1, tv2, t1p, t2p;
1214 base_matrix tv1p, tv2p, tv3p, tv1i, tv3i;
1215 base_matrix M1(ndof2, ndof1), M2(ndof2, ndof2), M2inv(ndof2, ndof2);
1216 base_matrix M3(N, ndof1), M4(N, ndof2);
1217 base_matrix aux1(ndof2, ndof1), aux2(ndof2, ndof2);
1218 base_matrix M5(N*N, ndof1), M6(N*N, ndof2);
1219 base_matrix M7(ndof3, ndof3), M7inv(ndof3, ndof3), M8(ndof3, ndof2);
1220 base_matrix M9(ndof3, ndof1), M10(ndof3, ndof3), MD(ndof2, ndof1);
1221 scalar_type area(0);
1227 for (
size_type ipt = 0; ipt < pim->nb_points_on_convex(); ++ipt) {
1228 ctx1.set_ii(ipt); ctx2.set_ii(ipt); ctx3.set_ii(ipt);
1229 scalar_type coeff = pim->coeff(ipt) * ctx1.J();
1232 ctx1.grad_base_value(t1);
1233 vectorize_grad_base_tensor(t1, tv1, ndof1, pf1->target_dim(), Q);
1235 ctx1.base_value(t1p);
1236 vectorize_base_tensor(t1p, tv1p, ndof1, pf1->target_dim(), Q);
1238 ctx2.grad_base_value(t2);
1239 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q);
1241 ctx2.base_value(t2p);
1242 vectorize_base_tensor(t2p, tv2p, ndof2, pf2->target_dim(), Q);
1244 ctx3.base_value(t3);
1245 vectorize_base_tensor(t3, tv3p, ndof3, pf3->target_dim(), Q);
1251 M2(j, i) += coeff * tv2.as_vector()[i+(k1+k2*N)*ndof2]
1252 * 0.5 * (tv2.as_vector()[j+(k1+k2*N)*ndof2] +
1253 tv2.as_vector()[j+(k2+k1*N)*ndof2]);
1257 M4(k, i) += coeff * tv2p(i, k);
1262 M6(k1+k2*N, i) += 0.5*coeff*(tv2.as_vector()[i+(k1+k2*N)*ndof2] -
1263 tv2.as_vector()[i+(k2+k1*N)*ndof2]);
1269 M1(j, i) += coeff * tv1.as_vector()[i+(k1+k2*N)*ndof1]
1270 * 0.5 * (tv2.as_vector()[j+(k1+k2*N)*ndof2] +
1271 tv2.as_vector()[j+(k2+k1*N)*ndof2]);
1275 M3(k, i) += coeff * tv1p(i, k);
1280 M7(i, j) += coeff * tv3p(i,k) * tv3p(j, k);
1285 M8(i, j) += coeff * tv3p(i,k) * tv2p(j, k);
1290 M9(i, j) += coeff * tv3p(i, k) * tv1p(j, k);
1295 for (
short_type ifc = 0; ifc < pgt->structure()->nb_faces(); ++ifc) {
1296 ctx1.set_face_num(ifc); ctx2.set_face_num(ifc); ctx3.set_face_num(ifc);
1297 ctx1i.set_face_num(ifc); ctx3i.set_face_num(ifc);
1298 size_type first_ind = pim->ind_first_point_on_face(ifc);
1299 for (
size_type ipt = 0; ipt < pim->nb_points_on_face(ifc); ++ipt) {
1300 ctx1.set_ii(first_ind+ipt); ctx2.set_ii(first_ind+ipt);
1301 ctx3.set_ii(first_ind+ipt); ctx1i.set_ii(first_ind+ipt);
1302 ctx3i.set_ii(first_ind+ipt);
1303 scalar_type coeff = pim->coeff(first_ind+ipt) * ctx1.J();
1304 gmm::mult(ctx1.B(), pgt->normals()[ifc], un);
1307 ctx2.grad_base_value(t2);
1308 vectorize_grad_base_tensor(t2, tv2, ndof2, pf2->target_dim(), Q);
1310 ctx2.base_value(t2p);
1311 vectorize_base_tensor(t2p, tv2p, ndof2, pf2->target_dim(), Q);
1313 ctx1.base_value(t1);
1314 vectorize_base_tensor(t1, tv1p, ndof1, pf1->target_dim(), Q);
1316 ctx1i.base_value(t1i);
1317 vectorize_base_tensor(t1i, tv1i, ndof1i, pf1i->target_dim(), Q);
1319 ctx3i.base_value(t3i);
1320 vectorize_base_tensor(t3i, tv3i, ndof3i, pf3i->target_dim(), Q);
1322 ctx3.base_value(t3);
1323 vectorize_base_tensor(t3, tv3p, ndof3, pf3->target_dim(), Q);
1328 scalar_type b(0), a = coeff *
1329 (tv1p(i, k1) - (i < ndof1i ? tv1i(i, k1) : 0.));
1331 b += a * 0.5 * (tv2.as_vector()[j+(k1 + k2*N)*ndof2] +
1332 tv2.as_vector()[j+(k2 + k1*N)*ndof2])* un[k2];
1339 M5(k1+k2*N, i) += 0.5 * coeff * (tv1p(i, k1) * un[k2] -
1340 tv1p(i, k2) * un[k1]);
1345 M7(i, j) += coeff * normun * tv3p(i,k) * tv3p(j, k);
1350 M8(i, j) += coeff * normun * tv3p(i,k) * tv2p(j, k);
1355 M9(i, j) += coeff * normun * tv3p(i, k) * tv1p(j, k);
1360 M10(i, j) += coeff * normun * tv3p(i,k) * tv3i(j, k);
1365 scalar_type coeff_p1 = pow(area, -1. - 2./scalar_type(N));
1366 scalar_type coeff_p2 = pow(area, -1. - 1./scalar_type(N));
1367 gmm::mult(gmm::transposed(M4), M4, aux2);
1368 gmm::add (gmm::scaled(aux2, coeff_p1), M2);
1369 gmm::mult(gmm::transposed(M6), M6, aux2);
1370 gmm::add (gmm::scaled(aux2, coeff_p2), M2);
1371 gmm::mult(gmm::transposed(M4), M3, aux1);
1372 gmm::add (gmm::scaled(aux1, coeff_p1), M1);
1373 gmm::mult(gmm::transposed(M6), M5, aux1);
1374 gmm::add (gmm::scaled(aux1, coeff_p2), M1);
1376 gmm::copy(M2, M2inv); gmm::lu_inverse(M2inv);
1378 if (pf3->target_dim() == 1 && Q > 1) {
1379 gmm::sub_slice I(0, ndof3/Q, Q);
1380 gmm::lu_inverse(gmm::sub_matrix(M7, I, I));
1382 gmm::sub_slice I2(i, ndof3/Q, Q);
1383 gmm::copy(gmm::sub_matrix(M7, I, I), gmm::sub_matrix(M7inv, I2, I2));
1386 { gmm::copy(M7, M7inv); gmm::lu_inverse(M7inv); }
1388 gmm::mult(M2inv, M1, MD);
1389 gmm::clean(MD, gmm::vect_norminf(MD.as_vector()) * 1E-13);
1392 base_matrix MPB(ndof3, ndof3);
1393 gmm::mult(M7inv, M10, MPB);
1394 gmm::copy(gmm::identity_matrix(), M10);
1395 gmm::add(gmm::scaled(MPB, scalar_type(-1)), M10);
1397 base_matrix MPC(ndof3, ndof1);
1398 gmm::mult(gmm::scaled(M8, scalar_type(-1)), MD, MPC);
1400 gmm::mult(M7inv, MPC, M9);
1401 gmm::mult(M10, M9, M);
1402 gmm::clean(M, 1E-13);
1407 pelementary_transformation
1408 p = std::make_shared<_HHO_symmetrized_stabilization>();