27 #ifndef GETFEM_HAVE_QHULL_QHULL_H 38 static void orthonormal_basis_to_unit_vec(
size_type d,
const base_node &un,
41 for (
size_type k = 0; k <= d && n < d; ++k) {
44 ut[n][k] = scalar_type(1);
46 ut[n] -= gmm::vect_sp(un, ut[n]) * un;
48 ut[n] -= gmm::vect_sp(ut[nn], ut[n]) * ut[nn];
50 if (gmm::vect_norm2(ut[n]) < 1e-3)
continue;
54 GMM_ASSERT1(n == d,
"Gram-Schmidt algorithm to find an " 55 "orthonormal basis for the tangential displacement failed");
65 std::vector<size_type> cvs;
66 std::vector<short_type> fcs;
68 contact_node() : mf(0), cvs(0), fcs(0) {}
69 contact_node(
const mesh_fem &mf_) {mf = &mf_;}
73 struct contact_node_pair {
74 contact_node cn_s, cn_m;
77 contact_node_pair(scalar_type threshold=10.) : cn_s(), cn_m()
78 {dist2 = threshold * threshold; is_active =
false;}
82 class contact_node_pair_list :
public std::vector<contact_node_pair> {
84 void contact_node_list_from_region
85 (
const mesh_fem &mf,
size_type contact_region,
86 std::vector<contact_node> &cnl) {
89 const mesh &m = mf.linked_mesh();
91 std::map<size_type, size_type> dof_to_cnid;
93 dal::bit_vector dofs = mf.basic_dof_on_region(contact_region);
94 for (dal::bv_visitor dof(dofs); !dof.finished(); ++dof)
95 if ( dof % qdim == 0) {
96 dof_to_cnid[dof] = cnid++;
97 contact_node new_cn(mf);
99 cnl.push_back(new_cn);
101 for (mr_visitor face(m.region(contact_region));
102 !face.finished(); ++face) {
103 assert(face.is_face());
104 mesh_fem::ind_dof_face_ct
105 face_dofs = mf.ind_basic_dof_of_face_of_element(face.cv(),face.f());
106 for (
size_type it=0; it < face_dofs.size(); it += qdim ) {
108 cnid = dof_to_cnid[dof];
109 cnl[cnid].cvs.push_back(face.cv());
110 cnl[cnid].fcs.push_back(face.f());
116 contact_node_pair_list() :
std::vector<contact_node_pair>() {}
118 void append_min_dist_cn_pairs(
const mesh_fem &mf1,
const mesh_fem &mf2,
120 bool slave1=
true,
bool slave2=
false) {
122 std::vector<contact_node> cnl1(0), cnl2(0);
123 contact_node_list_from_region(mf1, rg1, cnl1);
124 contact_node_list_from_region(mf2, rg2, cnl2);
128 size_type size1 = slave1 ? cnl1.size() : 0;
129 size_type size2 = slave2 ? cnl2.size() : 0;
130 this->
resize( size0 + size1 + size2 );
131 # ifndef GETFEM_HAVE_QHULL_QHULL_H 133 for (
size_type i1 = 0; i1 < cnl1.size(); ++i1) {
134 contact_node *cn1 = &cnl1[i1];
137 for (
size_type i2 = 0; i2 < cnl2.size(); ++i2) {
138 contact_node *cn2 = &cnl2[i2];
143 for (
size_type i1 = 0; i1 < cnl1.size(); ++i1, ++ii1) {
144 contact_node *cn1 = &cnl1[i1];
145 base_node node1 = cn1->mf->point_of_basic_dof(cn1->dof);
147 scalar_type dist2 = tree2.nearest_neighbor(ipt, node1);
148 if (ipt.i !=
size_type(-1) && dist2 < (*
this)[ii1].dist2) {
149 (*this)[ii1].cn_s = *cn1;
150 (*this)[ii1].cn_m = cnl2[ipt.i];
151 (*this)[ii1].dist2 = dist2;
152 (*this)[ii1].is_active =
true;
158 for (
size_type i2 = 0; i2 < cnl2.size(); ++i2, ++ii2) {
159 contact_node *cn2 = &cnl2[i2];
160 base_node node2 = cn2->mf->point_of_basic_dof(cn2->dof);
162 scalar_type dist2 = tree1.nearest_neighbor(ipt, node2);
163 if (ipt.i !=
size_type(-1) && dist2 < (*
this)[ii2].dist2) {
164 (*this)[ii2].cn_s = *cn2;
165 (*this)[ii2].cn_m = cnl1[ipt.i];
166 (*this)[ii2].dist2 = dist2;
167 (*this)[ii2].is_active =
true;
172 std::vector<base_node> pts;
173 for (
size_type i1 = 0; i1 < cnl1.size(); ++i1) {
174 contact_node *cn1 = &cnl1[i1];
175 pts.push_back(cn1->mf->point_of_basic_dof(cn1->dof));
177 for (
size_type i2 = 0; i2 < cnl2.size(); ++i2) {
178 contact_node *cn2 = &cnl2[i2];
179 pts.push_back(cn2->mf->point_of_basic_dof(cn2->dof));
181 gmm::dense_matrix<size_type> simplexes;
183 getfem::delaunay(pts, simplexes);
185 size_type nb_vertices = gmm::mat_nrows(simplexes);
186 std::vector<size_type> facet_vertices(nb_vertices);
187 std::vector< std::vector<size_type> > pt1_neighbours(size1);
188 for (
size_type i = 0; i < gmm::mat_ncols(simplexes); ++i) {
189 gmm::copy(gmm::mat_col(simplexes, i), facet_vertices);
190 for (
size_type iv1 = 0; iv1 < nb_vertices-1; ++iv1) {
192 bool v1_on_surface1 = (v1 < size1);
193 for (
size_type iv2 = iv1 + 1; iv2 < nb_vertices; ++iv2) {
195 bool v2_on_surface1 = (v2 < size1);
196 if (v1_on_surface1 ^ v2_on_surface1) {
197 bool already_in =
false;
198 size_type vv1 = (v1_on_surface1 ? v1 : v2);
199 size_type vv2 = (v2_on_surface1 ? v1 : v2);
200 for (
size_type j = 0; j < pt1_neighbours[vv1].size(); ++j)
201 if (pt1_neighbours[vv1][j] == vv2) {
205 if (!already_in) pt1_neighbours[vv1].push_back(vv2);
212 for (
size_type j = 0; j < pt1_neighbours[i1].size(); ++j) {
213 size_type i2 = pt1_neighbours[i1][j] - size1;
216 contact_node *cn1 = &cnl1[i1];
217 base_node node1 = cn1->mf->point_of_basic_dof(cn1->dof);
218 contact_node *cn2 = &cnl2[i2];
219 base_node node2 = cn2->mf->point_of_basic_dof(cn2->dof);
221 if (slave1 && dist2 < (*
this)[ii1].dist2) {
222 (*this)[ii1].cn_s = *cn1;
223 (*this)[ii1].cn_m = *cn2;
224 (*this)[ii1].dist2 = dist2;
225 (*this)[ii1].is_active =
true;
227 if (slave2 && dist2 < (*
this)[ii2].dist2) {
228 (*this)[ii2].cn_s = *cn2;
229 (*this)[ii2].cn_m = *cn1;
230 (*this)[ii2].dist2 = dist2;
231 (*this)[ii2].is_active =
true;
237 void append_min_dist_cn_pairs(
const mesh_fem &mf,
239 bool slave1=
true,
bool slave2=
false) {
240 append_min_dist_cn_pairs(mf, mf, rg1, rg2, slave1, slave2);
244 scalar_type projection_on_convex_face
246 const base_node &master_node,
const base_node &slave_node,
247 base_node &un, base_node &proj_node, base_node &proj_node_ref) {
251 if (pgt->is_linear()) {
253 un = m.normal_of_face_of_convex(cv,fc);
256 gmm::add(master_node, gmm::scaled(slave_node, -1.), proj_node);
257 gmm::copy(gmm::scaled(un, gmm::vect_sp(proj_node, un)), proj_node);
258 gmm::add(slave_node, proj_node);
261 gic.init(m.points_of_convex(cv), pgt);
262 gic.
invert(proj_node, proj_node_ref);
263 return pgt->convex_ref()->is_in(proj_node_ref);
271 size_type nb_pts_fc = pgt->structure()->nb_points_of_face(fc);
273 bgeot::convex_ind_ct ind_pts_fc = pgt->structure()->ind_points_of_face(fc);
274 ref_mesh_face_pt_ct pts_fc = m.points_of_face_of_convex(cv, fc);
277 base_matrix base_ref_fc(P-1,N);
279 dref_convex_pt_ct dref_pts_fc = pgt->convex_ref()->dir_points_of_face(fc);
280 GMM_ASSERT1( dref_pts_fc.size() == P,
"Dimensions mismatch");
281 base_node vec(dref_pts_fc[0].size());
283 vec = dref_pts_fc[i+1] - dref_pts_fc[0];
284 gmm::copy(vec,gmm::mat_row(base_ref_fc,i));
288 GMM_ASSERT1( slave_node.size() == N,
"Dimensions mismatch");
289 const base_node &xx = slave_node;
290 base_node &xxp = proj_node; xxp.resize(N);
291 base_node &xp = proj_node_ref; xp.resize(P);
296 xp = gmm::mean_value(pgt->convex_ref()->points_of_face(fc));
299 base_vector val(nb_pts_fc);
300 pgt->poly_vector_val(xp, ind_pts_fc, val);
301 for (
size_type l = 0; l < nb_pts_fc; ++l)
302 gmm::add(gmm::scaled(pts_fc[l], val[l] ), xxp);
304 base_matrix G(N, nb_pts_fc);
305 vectors_to_base_matrix(G, pts_fc);
307 base_matrix K(N,P-1);
309 base_matrix grad_fc(nb_pts_fc, P);
310 base_matrix grad_fc1(nb_pts_fc, P-1);
311 base_matrix B(N,P-1), BB(N,P), CS(P-1,P-1);
313 scalar_type EPS = 10E-12;
315 while (res > EPS && --cnt) {
317 pgt->poly_vector_grad(xp, ind_pts_fc, grad_fc);
318 gmm::mult(grad_fc, gmm::transposed(base_ref_fc), grad_fc1);
319 gmm::mult(G, grad_fc1, K);
320 gmm::mult(gmm::transposed(K), K, CS);
321 bgeot::lu_inverse(&(*(CS.begin())), P-1);
323 gmm::mult(B, base_ref_fc, BB);
328 pgt->poly_vector_val(xp, ind_pts_fc, val);
329 for (
size_type l = 0; l < nb_pts_fc; ++l)
330 gmm::add(gmm::scaled(pts_fc[l], val[l]), xxp);
332 gmm::mult(gmm::transposed(BB), xx - xxp, vres);
335 GMM_ASSERT1( res <= EPS,
336 "Iterative pojection on convex face did not converge");
338 pgt->poly_vector_grad(xp, ind_pts_fc, grad_fc);
339 gmm::mult(grad_fc, gmm::transposed(base_ref_fc), grad_fc1);
340 gmm::mult(G, grad_fc1, K);
351 base_matrix grad_cv(nb_pts_cv, P);
352 pgt->poly_vector_grad(xp, grad_cv);
354 base_matrix GG(N, nb_pts_cv);
355 m.points_of_convex(cv, GG);
357 gmm::mult(GG, grad_cv, KK);
360 base_matrix bases_product(P-1, P);
361 gmm::mult(gmm::transposed(K), KK, bases_product);
364 std::vector<size_type> ind(0);
366 if (j != i ) ind.push_back(j);
367 gmm::sub_index SUBI(ind);
369 = gmm::lu_det(gmm::sub_matrix(bases_product,
370 gmm::sub_interval(0, P-1), SUBI));
371 gmm::add(gmm::scaled(gmm::mat_col(KK, i), (i % 2) ? -det : +det ),
376 gmm::scale(un, 1/gmm::vect_norm2(un));
378 if (gmm::vect_sp(un, gmm::mean_value(pts_fc) -
379 gmm::mean_value(m.points_of_convex(cv))) < 0)
380 gmm::scale(un,scalar_type(-1));
382 return pgt->convex_ref()->is_in(proj_node_ref);
386 void compute_contact_matrices
387 (
const mesh_fem &mf_disp1,
const mesh_fem &mf_disp2,
388 contact_node_pair_list &cnpl, model_real_plain_vector &gap,
389 CONTACT_B_MATRIX *BN1, CONTACT_B_MATRIX *BN2 = 0,
390 CONTACT_B_MATRIX *BT1 = 0, CONTACT_B_MATRIX *BT2 = 0) {
392 GMM_ASSERT1(gmm::vect_size(gap) == cnpl.size(),
393 "Wrong number of contact node pairs or wrong size of gap");
395 GMM_ASSERT1( gmm::mat_nrows(*BN1) == cnpl.size(),
"Wrong size of BN1");
398 GMM_ASSERT1( gmm::mat_nrows(*BN2) == cnpl.size(),
"Wrong size of BN2");
400 dim_type qdim = mf_disp1.get_qdim();
404 GMM_ASSERT1( gmm::mat_nrows(*BT1) == cnpl.size() * d,
"Wrong size of BT1");
408 GMM_ASSERT1( gmm::mat_nrows(*BT2) == cnpl.size() * d,
"Wrong size of BT2");
410 gmm::fill(gap, scalar_type(10));
411 for (
size_type row = 0; row < cnpl.size(); ++row) {
412 contact_node_pair *cnp = &cnpl[row];
413 if (cnp->is_active) {
414 contact_node *cn_s = &cnp->cn_s;
415 contact_node *cn_m = &cnp->cn_m;
416 const mesh &mesh_m = cn_m->mf->linked_mesh();
417 base_node slave_node = cn_s->mf->point_of_basic_dof(cn_s->dof);
418 base_node master_node = cn_m->mf->point_of_basic_dof(cn_m->dof);
419 GMM_ASSERT1(slave_node.size() == qdim && master_node.size() == qdim,
421 base_node un_sel(qdim), proj_node_sel(qdim), proj_node_ref_sel(qdim);
422 scalar_type is_in_min = 1e5;
425 std::vector<size_type>::iterator cv;
426 std::vector<short_type>::iterator fc;
427 for (cv = cn_m->cvs.begin(), fc = cn_m->fcs.begin();
428 cv != cn_m->cvs.end() && fc != cn_m->fcs.end(); cv++, fc++) {
429 base_node un(qdim), proj_node(qdim), proj_node_ref(qdim);
430 scalar_type is_in = projection_on_convex_face
431 (mesh_m, *cv, *fc, master_node, slave_node, un, proj_node, proj_node_ref);
432 if (is_in < is_in_min) {
437 proj_node_sel = proj_node;
438 proj_node_ref_sel = proj_node_ref;
441 if (is_in_min < 0.05) {
442 gap[row] = gmm::vect_sp(slave_node-proj_node_sel, un_sel);
444 std::vector<base_node> ut(d);
445 if (BT1) orthonormal_basis_to_unit_vec(d, un_sel, &(ut[0]));
447 CONTACT_B_MATRIX *BN = 0;
448 CONTACT_B_MATRIX *BT = 0;
449 if (cn_s->mf == &mf_disp1) {
452 }
else if (cn_s->mf == &mf_disp2) {
458 (*BN)(row, cn_s->dof + k) -= un_sel[k];
462 (*BT)(row * d + n, cn_s->dof + k) -= ut[n][k];
465 const mesh_fem *mf_disp = 0;
466 if (cn_m->mf == &mf_disp1) {
470 }
else if (cn_m->mf == &mf_disp2) {
477 base_matrix M(qdim, mf_disp->nb_basic_dof_of_element(cv_sel));
478 mesh_m.points_of_convex(cv_sel, G);
479 pfem pf = mf_disp->fem_of_element(cv_sel);
481 fem_interpolation_context
482 ctx(pgt, pf, proj_node_ref_sel, G, cv_sel, fc_sel);
483 pf->interpolation (ctx, M,
int(qdim));
486 master_dofs = mf_disp->ind_basic_dof_of_element(cv_sel);
488 model_real_plain_vector MT_u(mf_disp->nb_basic_dof_of_element(cv_sel));
489 gmm::mult(gmm::transposed(M), un_sel, MT_u);
490 for (
size_type j = 0; j < master_dofs.size(); ++j)
491 (*BN)(row, master_dofs[j]) += MT_u[j];
495 gmm::mult(gmm::transposed(M), ut[n], MT_u);
496 for (
size_type j = 0; j < master_dofs.size(); ++j)
497 (*BT)(row * d + n, master_dofs[j]) += MT_u[j];
516 struct Coulomb_friction_brick :
public virtual_brick {
518 mutable CONTACT_B_MATRIX BN1, BT1, BN2, BT2;
519 mutable CONTACT_B_MATRIX DN, DDN, DT, DDT;
520 mutable CONTACT_B_MATRIX BBN1, BBT1, BBN2, BBT2;
521 mutable model_real_plain_vector gap, threshold, friction_coeff,
alpha;
522 mutable model_real_plain_vector RLN, RLT;
523 mutable scalar_type r, gamma;
524 mutable bool is_init;
525 bool Tresca_version, contact_only;
526 bool really_stationary, friction_dynamic_term;
527 bool two_variables, Hughes_stabilized;
528 int augmentation_version;
533 void init_BBN_BBT(
void)
const {
534 gmm::resize(BBN1, gmm::mat_nrows(BN1), gmm::mat_ncols(BN1));
535 gmm::copy(BN1, BBN1);
536 if (Hughes_stabilized) {
537 gmm::resize(DDN, gmm::mat_nrows(DN), gmm::mat_ncols(DN));
541 gmm::resize(BBN2, gmm::mat_nrows(BN2), gmm::mat_ncols(BN2));
542 gmm::copy(BN2, BBN2);
545 if (Hughes_stabilized) {
546 gmm::resize(DDT, gmm::mat_nrows(DT), gmm::mat_ncols(DT));
549 gmm::resize(BBT1, gmm::mat_nrows(BT1), gmm::mat_ncols(BT1));
550 gmm::copy(BT1, BBT1);
552 gmm::resize(BBT2, gmm::mat_nrows(BT2), gmm::mat_ncols(BT2));
553 gmm::copy(BT2, BBT2);
559 gmm::scale(gmm::mat_row(BBN1, i), alpha[i]);
560 if (Hughes_stabilized) gmm::scale(gmm::mat_row(DDN, i), alpha[i]);
562 gmm::scale(gmm::mat_row(BBN2, i), alpha[i]);
565 if (Hughes_stabilized)
566 gmm::scale(gmm::mat_row(DDT, d*i+k), alpha[i]);
567 gmm::scale(gmm::mat_row(BBT1, d*i+k), alpha[i]);
569 gmm::scale(gmm::mat_row(BBT2, d*i+k), alpha[i]);
575 void set_stationary(
void) { really_stationary =
true; }
577 void precomp(
const model_real_plain_vector &u1,
578 const model_real_plain_vector &u2,
579 const model_real_plain_vector &lambda_n,
580 const model_real_plain_vector &lambda_t,
581 const model_real_plain_vector &wt1,
582 const model_real_plain_vector &wt2)
const {
583 gmm::copy(gmm::scaled(gap, r), RLN);
584 for (
size_type i = 0; i < gmm::mat_nrows(BN1); ++i) RLN[i] *= alpha[i];
585 gmm::add(lambda_n, RLN);
587 if (Hughes_stabilized)
589 if (two_variables)
gmm::mult_add(BBN2, gmm::scaled(u2, -r), RLN);
591 gmm::copy(lambda_t, RLT);
592 if (friction_dynamic_term) {
597 if (!really_stationary) {
599 if (two_variables)
gmm::mult_add(BBT2, gmm::scaled(u2, -r), RLT);
601 if (Hughes_stabilized)
607 void basic_asm_real_tangent_terms(
const model_real_plain_vector &u1,
608 const model_real_plain_vector &u2,
609 const model_real_plain_vector &lambda_n,
610 const model_real_plain_vector &lambda_t,
611 const model_real_plain_vector &wt1,
612 const model_real_plain_vector &wt2,
613 model::real_matlist &matl,
614 model::real_veclist &vecl,
615 build_version version)
const {
616 size_type nbt = 4 + (contact_only ? 0 : 4) + (two_variables ? 3 : 0)
617 + (two_variables && !contact_only ? 2 : 0);
618 GMM_ASSERT1(matl.size() == nbt,
619 "Wrong number of terms for the contact brick");
621 const scalar_type vt1 = scalar_type(1), vt0 = scalar_type(0);
627 model_real_sparse_matrix &T_u1_u1 = matl[nt++], &T_u2_u2 = matl[nt++];
628 if (!two_variables) nt--;
629 model_real_sparse_matrix &T_u1_n = matl[nt++], &T_n_u1 = matl[nt++];
630 if (!two_variables) nt -= 2;
631 model_real_sparse_matrix &T_u2_n = matl[nt++], &T_n_u2 = matl[nt++];
633 model_real_sparse_matrix &T_n_n = matl[nt++];
634 if (contact_only) nt -= 2;
635 model_real_sparse_matrix &T_u1_t = matl[nt++], &T_t_u1 = matl[nt++];
636 if (contact_only || !two_variables) nt -= 2;
637 model_real_sparse_matrix &T_u2_t = matl[nt++], &T_t_u2 = matl[nt++];
638 if (contact_only) nt -= 2;
640 model_real_sparse_matrix &T_t_t = matl[nt++], &T_t_n = matl[nt++];
643 model_real_plain_vector &ru1 = vecl[0];
644 model_real_plain_vector &ru2 = vecl[1];
645 model_real_plain_vector &rlambda_n = vecl[nvec_lambda_n];
646 model_real_plain_vector &rlambda_t = vecl[nvec_lambda_t];
649 if (!is_init) init_BBN_BBT();
652 if (augmentation_version <= 2)
653 precomp(u1, u2, lambda_n, lambda_t, wt1, wt2);
655 if (version & model::BUILD_MATRIX) {
656 base_matrix pg(d, d);
668 switch (augmentation_version) {
670 gmm::copy(gmm::scaled(gmm::transposed(BN1), -vt1), T_u1_n);
672 gmm::copy(gmm::scaled(gmm::transposed(BN2), -vt1), T_u2_n);
676 if (two_variables)
gmm::clear(gmm::mat_col(T_u2_n, i));
677 T_n_n(i, i) = -vt1/(r*alpha[i]);
679 if (Hughes_stabilized && RLN[i] <= vt0)
680 gmm::copy(gmm::scaled(gmm::mat_row(DN, i), -vt1),
681 gmm::mat_col(T_n_n, i));
683 if (Hughes_stabilized) {
684 model_real_sparse_matrix aux(nbc, nbc);
685 gmm::copy(gmm::transposed(T_n_n), aux);
686 gmm::copy(aux, T_n_n);
688 gmm::copy(gmm::transposed(T_u1_n), T_n_u1);
689 if (two_variables) gmm::copy(gmm::transposed(T_u2_n), T_n_u2);
692 gmm::sub_interval SUBI(i*d, d);
693 scalar_type th = Tresca_version ? threshold[i]
694 : - (std::min(vt0, RLN[i])) * friction_coeff[i];
695 ball_projection_grad(gmm::sub_vector(RLT, SUBI), th, pg);
696 if (!really_stationary)
699 gmm::add(gmm::scaled(gmm::mat_row(BT1,i*d+k1),-pg(k2,k1)),
700 gmm::mat_col(T_u1_t, i*d+k2));
702 gmm::add(gmm::scaled(gmm::mat_row(BT2,i*d+k1),
704 gmm::mat_col(T_u2_t, i*d+k2));
707 if (!Tresca_version) {
709 ball_projection_grad_r(gmm::sub_vector(RLT, SUBI), th, vg);
711 T_t_n(i*d+k, i) = - friction_coeff[i] * vg[k]/(r*alpha[i]);
714 for (
size_type k = 0; k < d; ++k) pg(k,k) -= vt1;
715 gmm::copy(gmm::scaled(pg, vt1/(r*alpha[i])),
716 gmm::sub_matrix(T_t_t,SUBI));
717 if (Hughes_stabilized) {
720 gmm::add(gmm::scaled(gmm::mat_row(DT, d*i+l), -pg(k,l)),
721 gmm::mat_col(T_t_t, d*i+k));
726 if (Hughes_stabilized) {
727 model_real_sparse_matrix aux(gmm::mat_nrows(T_t_t),
728 gmm::mat_nrows(T_t_t));
729 gmm::copy(gmm::transposed(T_t_t), aux);
730 gmm::copy(aux, T_t_t);
732 gmm::copy(gmm::transposed(T_u1_t), T_t_u1);
733 if (two_variables) gmm::copy(gmm::transposed(T_u2_t), T_t_u2);
736 if (augmentation_version == 1) {
737 gmm::copy(gmm::scaled(gmm::transposed(BN1), -vt1), T_u1_n);
739 gmm::copy(gmm::scaled(gmm::transposed(BN2), -vt1), T_u2_n);
741 gmm::copy(gmm::scaled(gmm::transposed(BT1), -vt1), T_u1_t);
743 gmm::copy(gmm::scaled(gmm::transposed(BT2), -vt1), T_u2_t);
746 model_real_sparse_matrix tmp1(gmm::mat_ncols(BN1),
747 gmm::mat_ncols(BN1));
748 gmm::mult(gmm::transposed(gmm::scaled(BBN1,-r)), T_n_u1, tmp1);
749 gmm::add(tmp1, T_u1_u1);
751 gmm::mult(gmm::transposed(gmm::scaled(BBN2,-r)), T_n_u2, tmp1);
752 gmm::add(tmp1, T_u2_u2);
756 gmm::mult(gmm::transposed(gmm::scaled(BBT1,-r)), T_t_u1, tmp1);
757 gmm::add(tmp1, T_u1_u1);
759 gmm::mult(gmm::transposed(gmm::scaled(BBT2,-r)), T_t_u2, tmp1);
760 gmm::add(tmp1, T_u2_u2);
765 if (!contact_only && !Tresca_version) {
767 model_real_sparse_matrix tmp5(gmm::mat_ncols(BT1),
768 gmm::mat_ncols(BT1));
769 model_real_sparse_matrix tmp6(gmm::mat_ncols(BT1),
770 gmm::mat_ncols(BT1));
771 model_real_sparse_matrix tmp7(gmm::mat_ncols(BT2),
772 gmm::mat_ncols(BT2));
773 model_real_sparse_matrix tmp8(gmm::mat_ncols(BT2),
774 gmm::mat_ncols(BT2));
775 model_real_sparse_matrix tmp3(gmm::mat_ncols(T_t_u1),
776 gmm::mat_nrows(T_t_u1));
777 model_real_sparse_matrix tmp4(gmm::mat_ncols(T_t_u2),
778 gmm::mat_nrows(T_t_u2));
781 gmm::sub_interval SUBI(i*d, d);
782 scalar_type th = - (std::min(vt0, RLN[i])) * friction_coeff[i];
784 ball_projection_grad_r(gmm::sub_vector(RLT, SUBI), th, vg);
786 gmm::add(gmm::scaled(gmm::mat_row(BN1,i),
787 vg[k]*friction_coeff[i]), gmm::mat_col(tmp3, i*d+k));
789 gmm::add(gmm::scaled(gmm::mat_row(BN2,i),
790 vg[k]*friction_coeff[i]), gmm::mat_col(tmp4, i*d+k));
792 if (augmentation_version == 2) {
794 gmm::add(gmm::scaled(gmm::mat_row(BT1,i*d+k),
795 vg[k]*friction_coeff[i]), gmm::mat_col(T_u1_n, i));
797 gmm::add(gmm::scaled(gmm::mat_row(BT2,i*d+k),
798 vg[k]*friction_coeff[i]), gmm::mat_col(T_u2_n, i));
800 gmm::copy(gmm::scaled(gmm::mat_row(BBT1,i*d+k),
801 -r*friction_coeff[i]*vg[k]),
802 gmm::mat_col(tmp5, i*d+k));
803 gmm::copy(gmm::mat_row(BN1,i),
804 gmm::mat_col(tmp6, i*d+k));
806 gmm::copy(gmm::scaled(gmm::mat_row(BBT2,i*d+k),
807 -r*friction_coeff[i]*vg[k]),
808 gmm::mat_col(tmp7, i*d+k));
809 gmm::copy(gmm::mat_row(BN2,i),
810 gmm::mat_col(tmp8, i*d+k));
817 gmm::add(gmm::transposed(tmp3), T_t_u1);
819 gmm::add(gmm::transposed(tmp4), T_t_u2);
821 if (augmentation_version == 2) {
822 model_real_sparse_matrix tmp1(gmm::mat_ncols(BN1),
823 gmm::mat_ncols(BN1));
824 gmm::mult(tmp5, gmm::transposed(tmp6), gmm::transposed(tmp1));
825 gmm::add(gmm::transposed(tmp1), T_u1_u1);
827 gmm::mult(tmp7, gmm::transposed(tmp8),gmm::transposed(tmp1));
828 gmm::add(gmm::transposed(tmp1), T_u2_u2);
835 gmm::copy(gmm::scaled(gmm::transposed(BN1), -vt1), T_u1_n);
837 gmm::copy(gmm::scaled(gmm::transposed(BN2), -vt1), T_u2_n);
839 if (lambda_n[i] > vt0) {
841 if (two_variables)
gmm::clear(gmm::mat_col(T_u2_n, i));
842 T_n_n(i, i) = -vt1/r;
845 gmm::copy(gmm::scaled(BN1, -vt1), T_n_u1);
846 if (two_variables) gmm::copy(gmm::scaled(BN2, -r), T_n_u2);
849 gmm::sub_interval SUBI(i*d, d);
850 scalar_type th = Tresca_version ? threshold[i]
851 : gmm::neg(lambda_n[i]) * friction_coeff[i];
852 ball_projection_grad(gmm::sub_vector(lambda_t, SUBI), th, pg);
853 if (!really_stationary)
856 gmm::add(gmm::scaled(gmm::mat_row(BT1,i*d+k1),-pg(k2,k1)),
857 gmm::mat_col(T_u1_t, i*d+k2));
859 gmm::add(gmm::scaled(gmm::mat_row(BT2,i*d+k1),
861 gmm::mat_col(T_u2_t, i*d+k2));
863 if (!Tresca_version) {
864 ball_projection_grad_r(gmm::sub_vector(lambda_t, SUBI),th,vg);
866 gmm::add(gmm::scaled(gmm::mat_row(BT1,i*d+k1),
867 friction_coeff[i]*vg[k1]),
868 gmm::mat_col(T_u1_n, i));
870 gmm::add(gmm::scaled(gmm::mat_row(BT2,i*d+k1),
871 friction_coeff[i]*vg[k1]),
872 gmm::mat_col(T_u2_n, i));
873 T_t_n(i*d+k1, i) = friction_coeff[i] * vg[k1] / (r*alpha[i]);
876 for (
size_type k = 0; k < d; ++k) pg(k,k) -= vt1;
878 gmm::copy(gmm::scaled(pg, vt1/(r*alpha[i])),
879 gmm::sub_matrix(T_t_t, SUBI));
882 gmm::copy(gmm::scaled(BT1, -vt1), T_t_u1);
883 if (two_variables) gmm::copy(gmm::scaled(BT2, -r), T_t_u2);
888 base_small_vector x(d+1), n(d+1), u(d); n[0] = vt1;
889 base_matrix g(d+1, d+1);
890 model_real_sparse_matrix T_n_u1_transp(gmm::mat_ncols(T_n_u1), nbc);
891 model_real_sparse_matrix T_n_u2_transp(gmm::mat_ncols(T_n_u2), nbc);
893 gmm::mult(BT1, u1, RLT);
898 for (
size_type j=0; j < d; ++j) x[1+j] = lambda_t[i*d+j];
899 De_Saxce_projection_grad(x, n, friction_coeff[i], g);
901 gmm::add(gmm::scaled(gmm::mat_row(BN1, i), -g(0,0)),
902 gmm::mat_col(T_u1_n, i));
904 gmm::add(gmm::scaled(gmm::mat_row(BN2, i), -g(0,0)),
905 gmm::mat_col(T_u2_n, i));
906 T_n_n(i, i) = (g(0,0) - vt1)/(r*alpha[i]);
908 gmm::copy(gmm::sub_vector(RLT, gmm::sub_interval(i*d,d)), u);
912 gmm::add(gmm::scaled(gmm::mat_row(BT1, i*d+j),
913 friction_coeff[i] * u[j] / nu),
914 gmm::mat_col(T_n_u1_transp, i));
916 gmm::add(gmm::scaled(gmm::mat_row(BT2, i*d+j),
917 friction_coeff[i] * u[j] / nu),
918 gmm::mat_col(T_n_u2_transp, i));
922 gmm::add(gmm::scaled(gmm::mat_row(BT1, i*d+j), -g(0,j+1)),
923 gmm::mat_col(T_u1_n, i));
925 gmm::add(gmm::scaled(gmm::mat_row(BT2, i*d+j), -g(0,j+1)),
926 gmm::mat_col(T_u2_n, i));
928 gmm::add(gmm::scaled(gmm::mat_row(BN1, i), -g(j+1,0)),
929 gmm::mat_col(T_u1_t, i*d+j));
931 gmm::add(gmm::scaled(gmm::mat_row(BN2, i), -g(j+1,0)),
932 gmm::mat_col(T_u2_t, i*d+j));
935 gmm::add(gmm::scaled(gmm::mat_row(BT1, i*d+k), -g(1+j,1+k)),
936 gmm::mat_col(T_u1_t, i*d+j));
938 gmm::add(gmm::scaled(gmm::mat_row(BT2, i*d+k), -g(1+j,1+k)),
939 gmm::mat_col(T_u2_t, i*d+j));
940 T_t_t(i*d+j, i*d+k) = g(1+j, 1+k)/r;
942 T_t_t(i*d+j, i*d+j) -= vt1/(r*alpha[i]);
943 T_t_n(i*d+j, i) = g(1+j,0)/(r*alpha[i]);
947 gmm::copy(gmm::scaled(BN1, -vt1), T_n_u1);
948 if (two_variables) gmm::copy(gmm::scaled(BN2, -vt1), T_n_u2);
949 gmm::add(gmm::transposed(T_n_u1_transp), T_n_u1);
950 if (two_variables) gmm::add(gmm::transposed(T_n_u2_transp), T_n_u2);
951 gmm::copy(gmm::scaled(BT1, -vt1), T_t_u1);
952 if (two_variables) gmm::copy(gmm::scaled(BT2, -vt1), T_t_u2);
957 if (version & model::BUILD_RHS) {
959 switch (augmentation_version) {
962 RLN[i] = std::min(scalar_type(0), RLN[i]);
964 scalar_type radius = Tresca_version ? threshold[i]
965 : -friction_coeff[i]*RLN[i];
967 (gmm::sub_vector(RLT, gmm::sub_interval(i*d,d)), radius);
979 rlambda_n[i] = (lambda_n[i] - RLN[i]) / (r * alpha[i]);
983 = (lambda_t[i*d+k] - RLT[i*d+k]) / (r * alpha[i]);
988 RLN[i] = std::min(vt0, RLN[i]);
990 scalar_type radius = Tresca_version ? threshold[i]
991 : -friction_coeff[i]*RLN[i];
993 (gmm::sub_vector(RLT, gmm::sub_interval(i*d,d)), radius);
997 if (two_variables)
gmm::mult_add(gmm::transposed(BN2), RLN, ru2);
1000 if (two_variables)
gmm::mult_add(gmm::transposed(BT2), RLT, ru2);
1003 rlambda_n[i] = (lambda_n[i] - RLN[i]) / (r * alpha[i]);
1007 = (lambda_t[i*d+k] - RLT[i*d+k]) / (r * alpha[i]);
1011 if (!contact_only) gmm::copy(lambda_t, RLT);
1013 RLN[i] = -gmm::neg(lambda_n[i]);
1014 rlambda_n[i] = gmm::pos(lambda_n[i])/r - alpha[i]*gap[i];
1016 if (!contact_only) {
1017 scalar_type radius = Tresca_version ? threshold[i]
1018 : friction_coeff[i]*gmm::neg(lambda_n[i]);
1020 (gmm::sub_vector(RLT, gmm::sub_interval(i*d,d)), radius);
1023 gmm::mult(gmm::transposed(BN1), RLN, ru1);
1024 if (two_variables) gmm::mult(gmm::transposed(BN2), RLN, ru2);
1027 if (!contact_only) {
1029 if (two_variables)
gmm::mult_add(gmm::transposed(BT2), RLT, ru2);
1030 gmm::add(gmm::scaled(lambda_t, vt1/r), gmm::scaled(RLT,-vt1/r),
1036 rlambda_n[i] /= alpha[i];
1038 for (
size_type k = 0; k < d; ++k) rlambda_t[i*d+k] /= alpha[i];
1042 base_small_vector x(d+1), n(d+1);
1044 GMM_ASSERT1(!Tresca_version,
1045 "Augmentation version incompatible with Tresca friction law");
1046 gmm::mult(BBT1, u1, rlambda_t);
1051 gmm::copy(gmm::sub_vector(lambda_t, gmm::sub_interval(i*d,d)),
1052 gmm::sub_vector(x, gmm::sub_interval(1, d)));
1053 De_Saxce_projection(x, n, friction_coeff[i]);
1055 gmm::copy(gmm::sub_vector(x, gmm::sub_interval(1, d)),
1056 gmm::sub_vector(RLT, gmm::sub_interval(i*d,d)));
1057 rlambda_n[i] = lambda_n[i]/r - x[0]/r - alpha[i]*gap[i]
1059 gmm::sub_interval(i*d,d)));
1062 if (two_variables)
gmm::mult_add(gmm::transposed(BT2), RLT, ru2);
1064 if (two_variables)
gmm::mult_add(gmm::transposed(BN2), RLN, ru2);
1065 gmm::add(gmm::scaled(lambda_t, vt1/r), rlambda_t);
1066 gmm::add(gmm::scaled(RLT, -vt1/r), rlambda_t);
1070 rlambda_n[i] /= alpha[i];
1072 for (
size_type k = 0; k < d; ++k) rlambda_t[i*d+k] /= alpha[i];
1080 virtual void asm_real_tangent_terms(
const model &md,
size_type ib,
1081 const model::varnamelist &vl,
1082 const model::varnamelist &dl,
1083 const model::mimlist &mims,
1084 model::real_matlist &matl,
1085 model::real_veclist &vecl,
1086 model::real_veclist &,
1088 build_version version)
const {
1089 if (MPI_IS_MASTER()) {
1090 GMM_ASSERT1(mims.size() == 0,
"Contact brick need no mesh_im");
1091 size_type nbvar = 2 + (contact_only ? 0 : 1) + (two_variables ? 1 : 0);
1092 GMM_ASSERT1(vl.size() == nbvar,
1093 "Wrong number of variables for contact brick");
1094 size_type nbdl = 3 + (contact_only ? 0 : 1) + (Tresca_version ? 1 : 0)
1095 + (friction_dynamic_term ? 2 : 0);
1096 GMM_ASSERT1(dl.size() == nbdl,
"Wrong number of data for contact brick, " 1097 << dl.size() <<
" should be " << nbdl);
1107 const model_real_plain_vector &u1 = md.real_variable(vl[nv++]);
1108 const model_real_plain_vector &u2 = md.real_variable(vl[nv++]);
1109 if (!two_variables) nv--;
1110 const model_real_plain_vector &lambda_n = md.real_variable(vl[nv++]);
1111 if (contact_only) nv--;
1112 const model_real_plain_vector &lambda_t = md.real_variable(vl[nv]);
1116 size_type np = 0, np_wt1 = 0, np_wt2 = 0, np_alpha = 0;
1117 const model_real_plain_vector &vr = md.real_variable(dl[np++]);
1118 GMM_ASSERT1(gmm::vect_size(vr) == 1,
"Parameter r should be a scalar");
1120 const model_real_plain_vector &vgap = md.real_variable(dl[np++]);
1121 GMM_ASSERT1(gmm::vect_size(vgap) == 1 || gmm::vect_size(vgap) == nbc,
1122 "Parameter gap has a wrong size");
1124 if (gmm::vect_size(vgap) == 1)
1125 gmm::fill(gap, vgap[0]);
1127 gmm::copy(vgap, gap);
1129 const model_real_plain_vector &valpha = md.real_variable(dl[np_alpha]);
1130 GMM_ASSERT1(gmm::vect_size(valpha)== 1 || gmm::vect_size(valpha) == nbc,
1131 "Parameter alpha has a wrong size");
1133 if (gmm::vect_size(valpha) == 1)
1134 gmm::fill(alpha, valpha[0]);
1136 gmm::copy(valpha, alpha);
1137 if (!contact_only) {
1138 const model_real_plain_vector &vfr = md.real_variable(dl[np++]);
1139 GMM_ASSERT1(gmm::vect_size(vfr)==1 || gmm::vect_size(vfr) == nbc,
1140 "Parameter friction_coeff has a wrong size");
1142 if (gmm::vect_size(vfr) == 1)
1143 gmm::fill(friction_coeff, vfr[0]);
1145 gmm::copy(vfr, friction_coeff);
1146 if (friction_dynamic_term) {
1147 const model_real_plain_vector &vg = md.real_variable(dl[np++]);
1148 GMM_ASSERT1(gmm::vect_size(vg) == 1,
1149 "Parameter gamma should be a scalar");
1152 if (two_variables) np_wt2 = np++;
1154 if (Tresca_version) {
1155 const model_real_plain_vector &vth = md.real_variable(dl[np++]);
1156 GMM_ASSERT1(gmm::vect_size(vth) == 1 || gmm::vect_size(vth) == nbc,
1157 "Parameter threshold has a wrong size");
1159 if (gmm::vect_size(vth) == 1)
1160 gmm::fill(threshold, vth[0]);
1162 gmm::copy(vth, threshold);
1166 if (md.is_var_newer_than_brick(dl[np_alpha], ib)) is_init =
false;
1168 basic_asm_real_tangent_terms
1169 (u1, u2, lambda_n, lambda_t, md.real_variable(dl[np_wt1]),
1170 md.real_variable(dl[np_wt2]), matl, vecl, version);
1175 Coulomb_friction_brick(
int aug_version,
bool contact_only_,
1176 bool two_variables_=
false,
1177 bool Tresca_version_=
false,
1178 bool Hughes_stabilized_=
false,
1179 bool friction_dynamic_term_=
false) {
1181 if (aug_version == 4 && contact_only_) aug_version = 3;
1182 augmentation_version = aug_version;
1183 GMM_ASSERT1(aug_version >= 1 && aug_version <= 4,
1184 "Wrong augmentation version");
1185 GMM_ASSERT1(!Hughes_stabilized_ || aug_version <= 2,
1186 "The Hughes stabilized version is only for Alart-Curnier " 1188 contact_only = contact_only_;
1190 Tresca_version = Tresca_version_;
1191 really_stationary =
false;
1192 friction_dynamic_term = friction_dynamic_term_;
1193 two_variables = two_variables_;
1194 Hughes_stabilized = Hughes_stabilized_;
1195 set_flags(
"Coulomb friction brick",
false ,
1197 (augmentation_version == 2) && (contact_only||Tresca_version),
1202 void set_BN1(CONTACT_B_MATRIX &BN1_) {
1203 gmm::resize(BN1, gmm::mat_nrows(BN1_), gmm::mat_ncols(BN1_));
1204 gmm::copy(BN1_, BN1);
1208 void set_BN2(CONTACT_B_MATRIX &BN2_) {
1209 gmm::resize(BN2, gmm::mat_nrows(BN2_), gmm::mat_ncols(BN2_));
1210 gmm::copy(BN2_, BN2);
1214 void set_DN(CONTACT_B_MATRIX &DN_) {
1215 gmm::resize(DN, gmm::mat_nrows(DN_), gmm::mat_ncols(DN_));
1220 void set_DT(CONTACT_B_MATRIX &DT_) {
1221 gmm::resize(DT, gmm::mat_nrows(DT_), gmm::mat_ncols(DT_));
1226 void set_BT1(CONTACT_B_MATRIX &BT1_) {
1227 gmm::resize(BT1, gmm::mat_nrows(BT1_), gmm::mat_ncols(BT1_));
1228 gmm::copy(BT1_, BT1);
1232 CONTACT_B_MATRIX &get_BN1(
void) {
return BN1; }
1233 CONTACT_B_MATRIX &get_DN(
void) {
return DN; }
1234 CONTACT_B_MATRIX &get_DT(
void) {
return DT; }
1235 CONTACT_B_MATRIX &get_BT1(
void) {
return BT1; }
1236 const CONTACT_B_MATRIX &get_BN1(
void)
const {
return BN1; }
1237 const CONTACT_B_MATRIX &get_DN(
void)
const {
return DN; }
1238 const CONTACT_B_MATRIX &get_BT1(
void)
const {
return BT1; }
1244 pbrick pbr = md.brick_pointer(indbrick);
1246 Coulomb_friction_brick *p =
dynamic_cast<Coulomb_friction_brick *
> 1248 GMM_ASSERT1(p,
"Wrong type of brick");
1249 p->set_stationary();
1254 pbrick pbr = md.brick_pointer(indbrick);
1256 Coulomb_friction_brick *p =
dynamic_cast<Coulomb_friction_brick *
> 1258 GMM_ASSERT1(p,
"Wrong type of brick");
1259 return p->get_BN1();
1265 pbrick pbr = md.brick_pointer(indbrick);
1267 Coulomb_friction_brick *p =
dynamic_cast<Coulomb_friction_brick *
> 1269 GMM_ASSERT1(p,
"Wrong type of brick");
1275 pbrick pbr = md.brick_pointer(indbrick);
1277 Coulomb_friction_brick *p =
dynamic_cast<Coulomb_friction_brick *
> 1279 GMM_ASSERT1(p,
"Wrong type of brick");
1286 pbrick pbr = md.brick_pointer(indbrick);
1288 Coulomb_friction_brick *p =
dynamic_cast<Coulomb_friction_brick *
> 1290 GMM_ASSERT1(p,
"Wrong type of brick");
1291 return p->get_BT1();
1299 (
model &md,
const std::string &varname_u,
const std::string &multname_n,
1300 const std::string &dataname_r, CONTACT_B_MATRIX &BN,
1301 std::string dataname_gap, std::string dataname_alpha,
1302 int aug_version,
bool Hughes_stabilized) {
1304 auto pbr_ = std::make_shared<Coulomb_friction_brick>
1305 (aug_version,
true,
false,
false, Hughes_stabilized);
1310 tl.push_back(model::term_description(varname_u, varname_u,
false));
1311 tl.push_back(model::term_description(varname_u, multname_n,
false));
1312 tl.push_back(model::term_description(multname_n, varname_u,
false));
1313 tl.push_back(model::term_description(multname_n, multname_n,
false));
1314 model::varnamelist dl(1, dataname_r);
1316 if (dataname_gap.size() == 0) {
1317 dataname_gap = md.
new_name(
"contact_gap_on_" + varname_u);
1319 (dataname_gap, model_real_plain_vector(1, scalar_type(0)));
1321 dl.push_back(dataname_gap);
1323 if (dataname_alpha.size() == 0) {
1324 dataname_alpha = md.
new_name(
"contact_parameter_alpha_on_"+ multname_n);
1326 (dataname_alpha, model_real_plain_vector(1, scalar_type(1)));
1328 dl.push_back(dataname_alpha);
1330 model::varnamelist vl(1, varname_u);
1331 vl.push_back(multname_n);
1342 (
model &md,
const std::string &varname_u1,
const std::string &varname_u2,
1343 const std::string &multname_n,
1344 const std::string &dataname_r, CONTACT_B_MATRIX &BN1, CONTACT_B_MATRIX &BN2,
1345 std::string dataname_gap, std::string dataname_alpha,
1346 int aug_version,
bool Hughes_stabilized) {
1348 auto pbr_ = std::make_shared<Coulomb_friction_brick>
1349 (aug_version,
true,
true,
false, Hughes_stabilized);
1355 tl.push_back(model::term_description(varname_u1, varname_u1,
false));
1356 tl.push_back(model::term_description(varname_u2, varname_u2,
false));
1357 tl.push_back(model::term_description(varname_u1, multname_n,
false));
1358 tl.push_back(model::term_description(multname_n, varname_u1,
false));
1359 tl.push_back(model::term_description(varname_u2, multname_n,
false));
1360 tl.push_back(model::term_description(multname_n, varname_u2,
false));
1361 tl.push_back(model::term_description(multname_n, multname_n,
false));
1362 model::varnamelist dl(1, dataname_r);
1364 if (dataname_gap.size() == 0) {
1365 dataname_gap = md.
new_name(
"contact_gap_on_" + varname_u1);
1367 (dataname_gap, model_real_plain_vector(1, scalar_type(0)));
1369 dl.push_back(dataname_gap);
1371 if (dataname_alpha.size() == 0) {
1372 dataname_alpha = md.
new_name(
"contact_parameter_alpha_on_"+ multname_n);
1374 (dataname_alpha, model_real_plain_vector(1, scalar_type(1)));
1376 dl.push_back(dataname_alpha);
1378 model::varnamelist vl(1, varname_u1);
1379 vl.push_back(varname_u2);
1380 vl.push_back(multname_n);
1391 (
model &md,
const std::string &varname_u,
const std::string &multname_n,
1392 const std::string &multname_t,
const std::string &dataname_r,
1393 CONTACT_B_MATRIX &BN, CONTACT_B_MATRIX &BT,
1394 std::string dataname_friction_coeff,
1395 std::string dataname_gap, std::string dataname_alpha,
1396 int aug_version,
bool Tresca_version,
const std::string dataname_threshold,
1397 std::string dataname_gamma, std::string dataname_wt,
bool Hughes_stabilized) {
1399 bool dynamic_terms = (dataname_gamma.size() > 0);
1401 auto pbr_ = std::make_shared<Coulomb_friction_brick>
1402 (aug_version,
false,
false, Tresca_version, Hughes_stabilized,
1409 tl.push_back(model::term_description(varname_u, varname_u,
false));
1410 tl.push_back(model::term_description(varname_u, multname_n,
false));
1411 tl.push_back(model::term_description(multname_n, varname_u,
false));
1412 tl.push_back(model::term_description(multname_n, multname_n,
false));
1413 tl.push_back(model::term_description(varname_u, multname_t,
false));
1414 tl.push_back(model::term_description(multname_t, varname_u,
false));
1415 tl.push_back(model::term_description(multname_t, multname_t,
false));
1416 tl.push_back(model::term_description(multname_t, multname_n,
1417 (aug_version == 4)));
1418 model::varnamelist dl(1, dataname_r);
1419 if (dataname_gap.size() == 0) {
1420 dataname_gap = md.
new_name(
"contact_gap_on_" + varname_u);
1422 (dataname_gap, model_real_plain_vector(1, scalar_type(0)));
1424 dl.push_back(dataname_gap);
1426 if (dataname_alpha.size() == 0) {
1427 dataname_alpha = md.
new_name(
"contact_parameter_alpha_on_"+ multname_n);
1429 (dataname_alpha, model_real_plain_vector(1, scalar_type(1)));
1431 dl.push_back(dataname_alpha);
1432 dl.push_back(dataname_friction_coeff);
1433 if (dataname_gamma.size()) {
1434 dl.push_back(dataname_gamma);
1435 dl.push_back(dataname_wt);
1438 dl.push_back(dataname_threshold);
1440 model::varnamelist vl(1, varname_u);
1441 vl.push_back(multname_n);
1442 vl.push_back(multname_t);
1455 struct Coulomb_friction_brick_rigid_obstacle
1456 :
public Coulomb_friction_brick {
1458 std::string obstacle;
1462 virtual void asm_real_tangent_terms(
const model &md,
size_type ib,
1463 const model::varnamelist &vl,
1464 const model::varnamelist &dl,
1465 const model::mimlist &mims,
1466 model::real_matlist &matl,
1467 model::real_veclist &vecl,
1468 model::real_veclist &,
1470 build_version version)
const {
1471 if (MPI_IS_MASTER()) {
1472 GMM_ASSERT1(mims.size() == 1,
"This contact brick needs one mesh_im");
1473 size_type nbvar = 2 + (contact_only ? 0 : 1);
1474 GMM_ASSERT1(vl.size() == nbvar,
1475 "Wrong number of variables for contact brick: " 1476 << vl.size() <<
" should be " << nbvar);
1477 size_type nbdl = 1 + (contact_only ? 0 : 1) + (Tresca_version ? 1 : 0)
1478 + (friction_dynamic_term ? 1 : 0);
1479 GMM_ASSERT1(dl.size() == nbdl,
1480 "Wrong number of data for contact brick: " 1481 << dl.size() <<
" should be " << nbdl);
1482 GMM_ASSERT1(!two_variables,
"internal error");
1483 const mesh_im &mim = *mims[0];
1489 const model_real_plain_vector &u1 = md.
real_variable(vl[nv++]);
1491 const model_real_plain_vector &lambda_n = md.
real_variable(vl[nv++]);
1492 if (contact_only) nv--;
1493 const model_real_plain_vector &lambda_t = md.
real_variable(vl[nv]);
1498 const model_real_plain_vector &vr = md.
real_variable(dl[np++]);
1499 GMM_ASSERT1(gmm::vect_size(vr) == 1,
"Parameter r should be a scalar");
1503 if (md.is_var_mf_newer_than_brick(vl[0], ib)) {
1507 "This contact brick works only for pure Lagrange fems");
1509 for (dal::bv_visitor
id(dofs); !
id.finished(); ++id) {
1512 "This contact brick works only for pure Lagrange fems");
1515 nbc = dofs.card() / (d+1);
1518 base_node Pmin, Pmax;
1520 scalar_type l = scalar_type(0);
1521 for (i = 0; i < Pmin.size(); ++i)
1522 l = std::max(l, gmm::abs(Pmax[i] - Pmin[i]));
1526 gmm::resize(alpha, nbc);
1528 for (dal::bv_visitor
id(dofs); !
id.finished(); ++id, ++i)
1529 if ((i % (d+1)) == 0) alpha[j++] = MM(
id,
id) / l;
1532 getfem::ga_workspace gw;
1533 getfem::ga_function f(gw, obstacle);
1536 getfem::model_real_plain_vector pt(N);
1537 gw.add_fixed_size_constant(
"X", pt);
1538 if (N >= 1) gw.add_macro(
"x",
"X(1)");
1539 if (N >= 2) gw.add_macro(
"y",
"X(2)");
1540 if (N >= 3) gw.add_macro(
"z",
"X(3)");
1541 if (N >= 4) gw.add_macro(
"w",
"X(4)");
1545 gmm::resize(gap, nbc);
1546 gmm::resize(BN1, nbc, mf_u1.
nb_dof());
1548 if (!contact_only) {
1549 gmm::resize(BT1, d*nbc, mf_u1.
nb_dof());
1552 base_node grad(d+1), ut[3];
1555 for (dal::bv_visitor
id(dofs); !
id.finished(); ++id, ++i) {
1556 if ((i % (d+1)) == 0) {
1560 gap[j] = (f.eval())[0];
1568 grad[k] = ((f.eval())[0] - gap[j]) / eps;
1572 base_node un = - grad / gmm::vect_norm2(grad);
1575 BN1(j,
id + k) = un[k];
1578 if (!contact_only) {
1580 orthonormal_basis_to_unit_vec(d, un, ut);
1584 BT1(j*d+nn,
id + k) = ut[nn][k];
1592 "Wrong size of multiplier for the contact condition");
1595 GMM_ASSERT1(gmm::vect_size(md.
real_variable(vl[2])) == nbc*d,
1596 "Wrong size of multiplier for the friction condition");
1601 nbc = gmm::mat_nrows(BN1);
1603 if (!contact_only) {
1604 const model_real_plain_vector &vfr = md.
real_variable(dl[np++]);
1605 GMM_ASSERT1(gmm::vect_size(vfr)==1 || gmm::vect_size(vfr) == nbc,
1606 "Parameter friction_coeff has a wrong size");
1607 gmm::resize(friction_coeff, nbc);
1608 if (gmm::vect_size(vfr) == 1)
1609 gmm::fill(friction_coeff, vfr[0]);
1611 gmm::copy(vfr, friction_coeff);
1612 if (friction_dynamic_term) {
1613 const model_real_plain_vector &vg = md.
real_variable(dl[np++]);
1614 GMM_ASSERT1(gmm::vect_size(vg) == 1,
1615 "Parameter gamma should be a scalar");
1619 if (Tresca_version) {
1620 const model_real_plain_vector &vth = md.
real_variable(dl[np++]);
1621 GMM_ASSERT1(gmm::vect_size(vth) == 1 || gmm::vect_size(vth) == nbc,
1622 "Parameter threshold has a wrong size");
1623 gmm::resize(threshold, nbc);
1624 if (gmm::vect_size(vth) == 1)
1625 gmm::fill(threshold, vth[0]);
1627 gmm::copy(vth, threshold);
1631 basic_asm_real_tangent_terms
1638 Coulomb_friction_brick_rigid_obstacle
1639 (
int aug_version,
bool contact_only_,
const std::string &obs)
1640 : Coulomb_friction_brick(aug_version, contact_only_), obstacle(obs) {}
1652 const std::string &multname_n,
const std::string &dataname_r,
1653 size_type region,
const std::string &obstacle,
int aug_version) {
1654 pbrick pbr = std::make_shared<Coulomb_friction_brick_rigid_obstacle>
1655 (aug_version,
true, obstacle);
1658 tl.push_back(model::term_description(varname_u, varname_u,
false));
1659 tl.push_back(model::term_description(varname_u, multname_n,
false));
1660 tl.push_back(model::term_description(multname_n, varname_u,
false));
1661 tl.push_back(model::term_description(multname_n, multname_n,
false));
1662 model::varnamelist dl(1, dataname_r);
1664 model::varnamelist vl(1, varname_u);
1665 vl.push_back(multname_n);
1667 return md.
add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
1678 const std::string &multname_n,
const std::string &multname_t,
1679 const std::string &dataname_r,
const std::string &dataname_friction_coeff,
1680 size_type region,
const std::string &obstacle,
int aug_version) {
1681 pbrick pbr = std::make_shared<Coulomb_friction_brick_rigid_obstacle>
1682 (aug_version,
false, obstacle);
1685 tl.push_back(model::term_description(varname_u, varname_u,
false));
1686 tl.push_back(model::term_description(varname_u, multname_n,
false));
1687 tl.push_back(model::term_description(multname_n, varname_u,
false));
1688 tl.push_back(model::term_description(multname_n, multname_n,
false));
1689 tl.push_back(model::term_description(varname_u, multname_t,
false));
1690 tl.push_back(model::term_description(multname_t, varname_u,
false));
1691 tl.push_back(model::term_description(multname_t, multname_t,
false));
1692 tl.push_back(model::term_description(multname_t, multname_n,
1693 (aug_version == 4)));
1694 model::varnamelist dl(1, dataname_r);
1695 dl.push_back(dataname_friction_coeff);
1697 model::varnamelist vl(1, varname_u);
1698 vl.push_back(multname_n);
1699 vl.push_back(multname_t);
1701 return md.
add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
1714 struct Coulomb_friction_brick_nonmatching_meshes
1715 :
public Coulomb_friction_brick {
1717 std::vector<size_type> rg1, rg2;
1721 bool slave1, slave2;
1725 virtual void asm_real_tangent_terms(
const model &md,
size_type ib,
1726 const model::varnamelist &vl,
1727 const model::varnamelist &dl,
1728 const model::mimlist &mims,
1729 model::real_matlist &matl,
1730 model::real_veclist &vecl,
1731 model::real_veclist &,
1733 build_version version)
const {
1734 if (MPI_IS_MASTER()) {
1735 GMM_ASSERT1(mims.size() == 2,
"This contact brick needs two mesh_im");
1736 const mesh_im &mim1 = *mims[0];
1737 const mesh_im &mim2 = *mims[1];
1745 std::string varname_u1 = vl[nv];
1746 const model_real_plain_vector &u1 = md.
real_variable(varname_u1);
1748 if (two_variables) nv++;
1749 std::string varname_u2 = vl[nv++];
1750 const model_real_plain_vector &u2 = md.
real_variable(varname_u2);
1752 const model_real_plain_vector &lambda_n = md.
real_variable(vl[nv]);
1753 if (!contact_only) nv++;
1754 const model_real_plain_vector &lambda_t = md.
real_variable(vl[nv]);
1759 const model_real_plain_vector &vr = md.
real_variable(dl[0]);
1760 GMM_ASSERT1(gmm::vect_size(vr) == 1,
"Parameter r should be a scalar");
1762 if (!contact_only) {
1763 const model_real_plain_vector &vfr = md.
real_variable(dl[1]);
1764 GMM_ASSERT1(gmm::vect_size(vfr)==1 || gmm::vect_size(vfr) == nbc,
1765 "Parameter friction_coeff has a wrong size");
1766 gmm::resize(friction_coeff, nbc);
1767 if (gmm::vect_size(vfr) == 1)
1768 gmm::fill(friction_coeff, vfr[0]);
1770 gmm::copy(vfr, friction_coeff);
1774 if ( md.is_var_mf_newer_than_brick(varname_u1, ib)
1775 || md.is_var_mf_newer_than_brick(varname_u2, ib)) {
1778 const mesh_fem &mf_u = i ? mf_u2 : mf_u1;
1781 "This contact brick works only for pure Lagrange fems");
1783 for (dal::bv_visitor
id(dofs); !
id.finished(); ++id) {
1786 "This contact brick works only for pure Lagrange fems");
1790 contact_node_pair_list cnpl;
1791 for (
size_type it = 0; it < rg1.size() && it < rg2.size(); ++it)
1792 cnpl.append_min_dist_cn_pairs
1793 (mf_u1, mf_u2, rg1[it], rg2[it], slave1, slave2);
1796 gmm::resize(gap, nbc);
1797 gmm::resize(BN1, nbc, mf_u1.
nb_dof());
1799 if (!two_variables) {
1800 compute_contact_matrices(mf_u1, mf_u2, cnpl, gap, &BN1);
1802 gmm::resize(BN2, nbc, mf_u2.
nb_dof());
1803 compute_contact_matrices(mf_u1, mf_u2, cnpl, gap, &BN1, &BN2);
1807 gmm::resize(BT1, nbc * d, mf_u1.
nb_dof());
1808 if (!two_variables) {
1809 compute_contact_matrices(mf_u1, mf_u2, cnpl, gap, &BN1, 0, &BT1);
1812 gmm::resize(BN2, nbc, mf_u2.
nb_dof());
1813 gmm::resize(BT2, nbc * d, mf_u2.
nb_dof());
1814 compute_contact_matrices(mf_u1, mf_u2, cnpl, gap, &BN1, &BN2, &BT1, &BT2);
1819 scalar_type l = scalar_type(0);
1821 const mesh_fem &mf_u = i ? mf_u2 : mf_u1;
1822 base_node Pmin, Pmax;
1824 for (
size_type j = 0; j < Pmin.size(); ++j)
1825 l = std::max(l, gmm::abs(Pmax[j] - Pmin[j]));
1827 gmm::resize(alpha, nbc);
1829 for (
size_type it = 0; it < rg1.size() && it < rg2.size(); ++it) {
1830 for (
size_type swap = 0; swap <= 1; ++swap) {
1831 if (swap ? slave2 : slave1) {
1832 size_type rg = swap ? rg2[it] : rg1[it];
1833 const mesh_fem &mf_u = swap ? mf_u2 : mf_u1;
1834 const mesh_im &mim = swap ? mim2 : mim1;
1839 for (dal::bv_visitor
id(rg_dofs); !
id.finished(); ++id)
1840 if (
id % qdim == 0) alpha[mult_id++] = MM(
id,
id) / l;
1846 const model_real_plain_vector dummy_wt;
1847 basic_asm_real_tangent_terms
1848 (u1, u2, lambda_n, lambda_t, dummy_wt, dummy_wt, matl, vecl, version);
1852 Coulomb_friction_brick_nonmatching_meshes
1853 (
int aug_version,
bool contact_only_,
bool two_variables_,
1854 const std::vector<size_type> &rg1_,
const std::vector<size_type> &rg2_,
1855 bool slave1_=
true,
bool slave2_=
false)
1856 : Coulomb_friction_brick(aug_version, contact_only_, two_variables_),
1857 rg1(rg1_), rg2(rg2_), slave1(slave1_), slave2(slave2_) {}
1869 const std::string &varname_u1,
const std::string &varname_u2,
1870 std::string &multname_n,
const std::string &dataname_r,
1871 const std::vector<size_type> &rg1,
const std::vector<size_type> &rg2,
1872 bool slave1,
bool slave2,
int aug_version) {
1874 bool two_variables = (varname_u1.compare(varname_u2) != 0);
1876 pbrick pbr = std::make_shared<Coulomb_friction_brick_nonmatching_meshes>
1877 (aug_version,
true, two_variables, rg1, rg2, slave1, slave2);
1883 for (
size_type it = 0; it < rg1.size() && it < rg2.size(); ++it) {
1884 for (
size_type swap = 0; swap <= 1; ++swap) {
1885 if (swap ? slave2 : slave1) {
1886 const mesh_fem &mf = swap ? mf_u2 : mf_u1;
1887 size_type rg = swap ? rg2[it] : rg1[it];
1889 nbc += rg_dofs.card() / mf.
get_qdim();
1894 if (multname_n.size() == 0)
1895 multname_n = md.
new_name(
"contact_multiplier");
1897 GMM_ASSERT1(multname_n.compare(md.
new_name(multname_n)) == 0,
1898 "The given name for the multiplier is already reserved in the model");
1902 tl.push_back(model::term_description(varname_u1, varname_u1,
false));
1903 if (two_variables) {
1904 tl.push_back(model::term_description(varname_u2, varname_u2,
false));
1906 tl.push_back(model::term_description(varname_u1, multname_n,
false));
1907 tl.push_back(model::term_description(multname_n, varname_u1,
false));
1908 if (two_variables) {
1909 tl.push_back(model::term_description(varname_u2, multname_n,
false));
1910 tl.push_back(model::term_description(multname_n, varname_u2,
false));
1912 tl.push_back(model::term_description(multname_n, multname_n,
false));
1915 model::varnamelist vl;
1916 vl.push_back(varname_u1);
1917 if (two_variables) vl.push_back(varname_u2);
1918 vl.push_back(multname_n);
1921 model::varnamelist dl;
1922 dl.push_back(dataname_r);
1925 ml.push_back(&mim1);
1926 ml.push_back(&mim2);
1939 const std::string &varname_u1,
const std::string &varname_u2,
1940 std::string &multname_n, std::string &multname_t,
1941 const std::string &dataname_r,
const std::string &dataname_friction_coeff,
1942 const std::vector<size_type> &rg1,
const std::vector<size_type> &rg2,
1943 bool slave1,
bool slave2,
int aug_version) {
1945 bool two_variables = (varname_u1.compare(varname_u2) != 0);
1947 pbrick pbr = std::make_shared<Coulomb_friction_brick_nonmatching_meshes>
1948 (aug_version,
false, two_variables, rg1, rg2, slave1, slave2);
1954 for (
size_type it = 0; it < rg1.size() && it < rg2.size(); ++it) {
1955 for (
size_type swap = 0; swap <= 1; ++swap) {
1956 if (swap ? slave2 : slave1) {
1957 const mesh_fem &mf = swap ? mf_u2 : mf_u1;
1958 size_type rg = swap ? rg2[it] : rg1[it];
1960 nbc += rg_dofs.card() / mf.
get_qdim();
1965 if (multname_n.size() == 0)
1966 multname_n = md.
new_name(
"contact_normal_multiplier");
1968 GMM_ASSERT1(multname_n.compare(md.
new_name(multname_n)) == 0,
1969 "The given name for the multiplier is already reserved in the model");
1971 if (multname_t.size() == 0)
1972 multname_t = md.
new_name(
"contact_tangent_multiplier");
1974 GMM_ASSERT1(multname_t.compare(md.
new_name(multname_t)) == 0,
1975 "The given name for the multiplier is already reserved in the model");
1979 tl.push_back(model::term_description(varname_u1, varname_u1,
false));
1980 if (two_variables) {
1981 tl.push_back(model::term_description(varname_u2, varname_u2,
false));
1984 tl.push_back(model::term_description(varname_u1, multname_n,
false));
1985 tl.push_back(model::term_description(multname_n, varname_u1,
false));
1986 if (two_variables) {
1987 tl.push_back(model::term_description(varname_u2, multname_n,
false));
1988 tl.push_back(model::term_description(multname_n, varname_u2,
false));
1990 tl.push_back(model::term_description(multname_n, multname_n,
false));
1992 tl.push_back(model::term_description(varname_u1, multname_t,
false));
1993 tl.push_back(model::term_description(multname_t, varname_u1,
false));
1994 if (two_variables) {
1995 tl.push_back(model::term_description(varname_u2, multname_t,
false));
1996 tl.push_back(model::term_description(multname_t, varname_u2,
false));
1998 tl.push_back(model::term_description(multname_t, multname_t,
false));
1999 tl.push_back(model::term_description(multname_t, multname_n,
2000 (aug_version == 4)));
2003 model::varnamelist vl;
2004 vl.push_back(varname_u1);
2005 if (two_variables) vl.push_back(varname_u2);
2006 vl.push_back(multname_n);
2007 vl.push_back(multname_t);
2010 model::varnamelist dl;
2011 dl.push_back(dataname_r);
2012 dl.push_back(dataname_friction_coeff);
2015 ml.push_back(&mim1);
2016 ml.push_back(&mim2);
virtual size_type nb_dof() const
Return the total number of degrees of freedom.
indexed array reference (given a container X, and a set of indexes I, this class provides a pseudo-co...
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2_sqr(const V &v)
squared Euclidean norm of a vector.
void asm_mass_matrix(const MAT &M, const mesh_im &mim, const mesh_fem &mf1, const mesh_region &rg=mesh_region::all_convexes())
generic mass matrix assembly (on the whole mesh or on the specified convex set or boundary) ...
void add_initialized_fixed_size_data(const std::string &name, const VECT &v)
Add a fixed size data (assumed to be a vector) to the model and initialized with v.
virtual pfem fem_of_element(size_type cv) const
Return the basic fem associated with an element (if no fem is associated, the function will crash! us...
does the inversion of the geometric transformation for a given convex
Describe an integration method linked to a mesh.
size_type add_nodal_contact_with_rigid_obstacle_brick(model &md, const mesh_im &mim, const std::string &varname_u, const std::string &multname_n, const std::string &dataname_r, size_type region, const std::string &obstacle, int aug_version=1)
Add a frictionless contact condition with a rigid obstacle to the model.
Balanced tree over a set of points.
const mesh_fem & mesh_fem_of_variable(const std::string &name) const
Gives the access to the mesh_fem of a variable if any.
void contact_brick_set_stationary(model &md, size_type indbrick)
Can be used to set the stationary option.
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2(const V &v)
Euclidean norm of a vector.
CONTACT_B_MATRIX & contact_brick_set_DN(model &md, size_type indbrick)
Can be used to change the matrix DN of a basic contact/friction brick.
``Model'' variables store the variables, the data and the description of a model. ...
size_t size_type
used as the common size type in the library
virtual dal::bit_vector basic_dof_on_region(const mesh_region &b) const
Get a list of basic dof lying on a given mesh_region.
size_type add_nodal_contact_between_nonmatching_meshes_brick(model &md, const mesh_im &mim1, const mesh_im &mim2, const std::string &varname_u1, const std::string &varname_u2, std::string &multname_n, const std::string &dataname_r, const std::vector< size_type > &rg1, const std::vector< size_type > &rg2, bool slave1=true, bool slave2=false, int aug_version=1)
Add a frictionless contact condition between two faces of one or two elastic bodies.
size_type add_brick(pbrick pbr, const varnamelist &varnames, const varnamelist &datanames, const termlist &terms, const mimlist &mims, size_type region)
Add a brick to the model.
virtual scalar_type convex_radius_estimate(size_type ic) const
Return an estimate of the convex largest dimension.
virtual dim_type get_qdim() const
Return the Q dimension.
bool invert(const base_node &n, base_node &n_ref, scalar_type IN_EPS=1e-12)
given the node on the real element, returns the node on the reference element (even if it is outside ...
virtual base_node point_of_basic_dof(size_type cv, size_type i) const
Return the geometrical location of a degree of freedom.
CONTACT_B_MATRIX & contact_brick_set_DT(model &md, size_type indbrick)
Can be used to change the matrix DT of a basic contact/friction brick.
void resize(V &v, size_type n)
*/
bool is_reduced() const
Return true if a reduction matrix is applied to the dofs.
GEneric Tool for Finite Element Methods.
size_type add_basic_contact_brick_two_deformable_bodies(model &md, const std::string &varname_u1, const std::string &varname_u2, const std::string &multname_n, const std::string &dataname_r, CONTACT_B_MATRIX &BN1, CONTACT_B_MATRIX &BN2, std::string dataname_gap="", std::string dataname_alpha="", int aug_version=1, bool Hughes_stabilized=false)
Add a frictionless contact condition to the model between two deformable bodies.
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
Describe a finite element method linked to a mesh.
void clear(L &l)
clear (fill with zeros) a vector or matrix.
gmm::uint16_type short_type
used as the common short type integer in the library
void add_point_with_id(const base_node &n, size_type i)
insert a new point, with an associated number.
The virtual brick has to be derived to describe real model bricks.
virtual size_type first_convex_of_basic_dof(size_type d) const
Shortcut for convex_to_dof(d)[0].
void bounding_box(base_node &Pmin, base_node &Pmax) const
Return the bounding box [Pmin - Pmax] of the mesh.
void touch_brick(size_type ib)
Force the re-computation of a brick for the next assembly.
CONTACT_B_MATRIX & contact_brick_set_BN(model &md, size_type indbrick)
Can be used to change the matrix BN of a basic contact/friction brick.
store a point and the associated index for the kdtree.
std::string new_name(const std::string &name)
Gives a non already existing variable name begining by name.
void mult_add(const L1 &l1, const L2 &l2, L3 &l3)
*/
const mesh & linked_mesh() const
Return a reference to the underlying mesh.
const model_real_plain_vector & real_variable(const std::string &name, size_type niter) const
Gives the access to the vector value of a variable.
Simple implementation of a KD-tree.
CONTACT_B_MATRIX & contact_brick_set_BT(model &md, size_type indbrick)
Can be used to change the matrix BT of a basic contact/friction brick.
size_type alpha(short_type n, short_type d)
Return the value of which is the number of monomials of a polynomial of variables and degree ...
Miscelleanous assembly routines for common terms. Use the low-level generic assembly. Prefer the high-level one.
void resize(M &v, size_type m, size_type n)
*/
void add_fixed_size_variable(const std::string &name, size_type size, size_type niter=1)
Add a fixed size variable to the model assumed to be a vector.
size_type add_basic_contact_brick(model &md, const std::string &varname_u, const std::string &multname_n, const std::string &dataname_r, CONTACT_B_MATRIX &BN, std::string dataname_gap="", std::string dataname_alpha="", int aug_version=1, bool Hughes_stabilized=false)
Add a frictionless contact condition to the model.
std::shared_ptr< const virtual_brick > pbrick
type of pointer on a brick
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation