26 #ifndef GETFEM_HAVE_QHULL_QHULL_H
37 static void orthonormal_basis_to_unit_vec(
size_type d,
const base_node &un,
40 for (
size_type k = 0; k <= d && n < d; ++k) {
43 ut[n][k] = scalar_type(1);
47 ut[n] -= gmm::vect_sp(ut[nn], ut[n]) * ut[nn];
49 if (gmm::vect_norm2(ut[n]) < 1e-3)
continue;
53 GMM_ASSERT1(n == d,
"Gram-Schmidt algorithm to find an "
54 "orthonormal basis for the tangential displacement failed");
64 std::vector<size_type> cvs;
65 std::vector<short_type> fcs;
67 contact_node() : mf(0), cvs(0), fcs(0) {}
68 contact_node(
const mesh_fem &mf_) {mf = &mf_;}
72 struct contact_node_pair {
73 contact_node cn_s, cn_m;
76 contact_node_pair(scalar_type threshold=10.) : cn_s(), cn_m()
77 {dist2 = threshold * threshold; is_active =
false;}
81 class contact_node_pair_list :
public std::vector<contact_node_pair> {
83 void contact_node_list_from_region
84 (
const mesh_fem &mf,
size_type contact_region,
85 std::vector<contact_node> &cnl) {
88 const mesh &m = mf.linked_mesh();
90 std::map<size_type, size_type> dof_to_cnid;
92 dal::bit_vector dofs = mf.basic_dof_on_region(contact_region);
93 for (dal::bv_visitor dof(dofs); !dof.finished(); ++dof)
94 if ( dof % qdim == 0) {
95 dof_to_cnid[dof] = cnid++;
96 contact_node new_cn(mf);
98 cnl.push_back(new_cn);
100 for (mr_visitor face(m.region(contact_region));
101 !face.finished(); ++face) {
102 assert(face.is_face());
103 mesh_fem::ind_dof_face_ct
104 face_dofs = mf.ind_basic_dof_of_face_of_element(face.cv(),face.f());
105 for (
size_type it=0; it < face_dofs.size(); it += qdim ) {
107 cnid = dof_to_cnid[dof];
108 cnl[cnid].cvs.push_back(face.cv());
109 cnl[cnid].fcs.push_back(face.f());
115 contact_node_pair_list() : std::vector<contact_node_pair>() {}
117 void append_min_dist_cn_pairs(
const mesh_fem &mf1,
const mesh_fem &mf2,
119 bool slave1=
true,
bool slave2=
false) {
121 std::vector<contact_node> cnl1(0), cnl2(0);
122 contact_node_list_from_region(mf1, rg1, cnl1);
123 contact_node_list_from_region(mf2, rg2, cnl2);
127 size_type size1 = slave1 ? cnl1.size() : 0;
128 size_type size2 = slave2 ? cnl2.size() : 0;
129 this->
resize( size0 + size1 + size2 );
130 # ifndef GETFEM_HAVE_QHULL_QHULL_H
132 for (
size_type i1 = 0; i1 < cnl1.size(); ++i1) {
133 contact_node *cn1 = &cnl1[i1];
136 for (
size_type i2 = 0; i2 < cnl2.size(); ++i2) {
137 contact_node *cn2 = &cnl2[i2];
142 for (
size_type i1 = 0; i1 < cnl1.size(); ++i1, ++ii1) {
143 contact_node *cn1 = &cnl1[i1];
144 base_node node1 = cn1->mf->point_of_basic_dof(cn1->dof);
146 scalar_type dist2 = tree2.nearest_neighbor(ipt, node1);
147 if (ipt.i !=
size_type(-1) && dist2 < (*
this)[ii1].dist2) {
148 (*this)[ii1].cn_s = *cn1;
149 (*this)[ii1].cn_m = cnl2[ipt.i];
150 (*this)[ii1].dist2 = dist2;
151 (*this)[ii1].is_active =
true;
157 for (
size_type i2 = 0; i2 < cnl2.size(); ++i2, ++ii2) {
158 contact_node *cn2 = &cnl2[i2];
159 base_node node2 = cn2->mf->point_of_basic_dof(cn2->dof);
161 scalar_type dist2 = tree1.nearest_neighbor(ipt, node2);
162 if (ipt.i !=
size_type(-1) && dist2 < (*
this)[ii2].dist2) {
163 (*this)[ii2].cn_s = *cn2;
164 (*this)[ii2].cn_m = cnl1[ipt.i];
165 (*this)[ii2].dist2 = dist2;
166 (*this)[ii2].is_active =
true;
171 std::vector<base_node> pts;
172 for (
size_type i1 = 0; i1 < cnl1.size(); ++i1) {
173 contact_node *cn1 = &cnl1[i1];
174 pts.push_back(cn1->mf->point_of_basic_dof(cn1->dof));
176 for (
size_type i2 = 0; i2 < cnl2.size(); ++i2) {
177 contact_node *cn2 = &cnl2[i2];
178 pts.push_back(cn2->mf->point_of_basic_dof(cn2->dof));
180 gmm::dense_matrix<size_type> simplexes;
182 getfem::delaunay(pts, simplexes);
184 size_type nb_vertices = gmm::mat_nrows(simplexes);
185 std::vector<size_type> facet_vertices(nb_vertices);
186 std::vector< std::vector<size_type> > pt1_neighbors(size1);
187 for (
size_type i = 0; i < gmm::mat_ncols(simplexes); ++i) {
188 gmm::copy(gmm::mat_col(simplexes, i), facet_vertices);
189 for (
size_type iv1 = 0; iv1 < nb_vertices-1; ++iv1) {
191 bool v1_on_surface1 = (v1 < size1);
192 for (
size_type iv2 = iv1 + 1; iv2 < nb_vertices; ++iv2) {
194 bool v2_on_surface1 = (v2 < size1);
195 if (v1_on_surface1 ^ v2_on_surface1) {
196 bool already_in =
false;
197 size_type vv1 = (v1_on_surface1 ? v1 : v2);
198 size_type vv2 = (v2_on_surface1 ? v1 : v2);
199 for (
size_type j = 0; j < pt1_neighbors[vv1].size(); ++j)
200 if (pt1_neighbors[vv1][j] == vv2) {
204 if (!already_in) pt1_neighbors[vv1].push_back(vv2);
211 for (
size_type j = 0; j < pt1_neighbors[i1].size(); ++j) {
212 size_type i2 = pt1_neighbors[i1][j] - size1;
215 contact_node *cn1 = &cnl1[i1];
216 base_node node1 = cn1->mf->point_of_basic_dof(cn1->dof);
217 contact_node *cn2 = &cnl2[i2];
218 base_node node2 = cn2->mf->point_of_basic_dof(cn2->dof);
220 if (slave1 && dist2 < (*
this)[ii1].dist2) {
221 (*this)[ii1].cn_s = *cn1;
222 (*this)[ii1].cn_m = *cn2;
223 (*this)[ii1].dist2 = dist2;
224 (*this)[ii1].is_active =
true;
226 if (slave2 && dist2 < (*
this)[ii2].dist2) {
227 (*this)[ii2].cn_s = *cn2;
228 (*this)[ii2].cn_m = *cn1;
229 (*this)[ii2].dist2 = dist2;
230 (*this)[ii2].is_active =
true;
236 void append_min_dist_cn_pairs(
const mesh_fem &mf,
238 bool slave1=
true,
bool slave2=
false) {
239 append_min_dist_cn_pairs(mf, mf, rg1, rg2, slave1, slave2);
243 scalar_type projection_on_convex_face
245 const base_node &master_node,
const base_node &slave_node,
246 base_node &un, base_node &proj_node, base_node &proj_node_ref) {
250 if (pgt->is_linear()) {
252 un = m.normal_of_face_of_convex(cv,fc);
255 gmm::add(master_node, gmm::scaled(slave_node, -1.), proj_node);
256 gmm::copy(gmm::scaled(un, gmm::vect_sp(proj_node, un)), proj_node);
260 gic.init(m.points_of_convex(cv), pgt);
261 gic.
invert(proj_node, proj_node_ref);
262 return pgt->convex_ref()->is_in(proj_node_ref);
270 size_type nb_pts_fc = pgt->structure()->nb_points_of_face(fc);
272 bgeot::convex_ind_ct ind_pts_fc = pgt->structure()->ind_points_of_face(fc);
273 ref_mesh_face_pt_ct pts_fc = m.points_of_face_of_convex(cv, fc);
276 base_matrix base_ref_fc(P-1,N);
279 GMM_ASSERT1( dref_pts_fc.size() == P,
"Dimensions mismatch");
280 base_node vec(dref_pts_fc[0].size());
282 vec = dref_pts_fc[i+1] - dref_pts_fc[0];
283 gmm::copy(vec,gmm::mat_row(base_ref_fc,i));
287 GMM_ASSERT1( slave_node.size() == N,
"Dimensions mismatch");
288 const base_node &xx = slave_node;
289 base_node &xxp = proj_node; xxp.resize(N);
290 base_node &xp = proj_node_ref; xp.resize(P);
295 xp = gmm::mean_value(pgt->convex_ref()->points_of_face(fc));
298 base_vector val(nb_pts_fc);
299 pgt->poly_vector_val(xp, ind_pts_fc, val);
300 for (
size_type l = 0; l < nb_pts_fc; ++l)
301 gmm::add(gmm::scaled(pts_fc[l], val[l] ), xxp);
303 base_matrix G(N, nb_pts_fc);
304 vectors_to_base_matrix(G, pts_fc);
306 base_matrix K(N,P-1);
308 base_matrix grad_fc(nb_pts_fc, P);
309 base_matrix grad_fc1(nb_pts_fc, P-1);
310 base_matrix B(N,P-1), BB(N,P), CS(P-1,P-1);
312 scalar_type EPS = 10E-12;
314 while (res > EPS && --cnt) {
316 pgt->poly_vector_grad(xp, ind_pts_fc, grad_fc);
317 gmm::mult(grad_fc, gmm::transposed(base_ref_fc), grad_fc1);
320 bgeot::lu_inverse(&(*(CS.begin())), P-1);
327 pgt->poly_vector_val(xp, ind_pts_fc, val);
328 for (
size_type l = 0; l < nb_pts_fc; ++l)
329 gmm::add(gmm::scaled(pts_fc[l], val[l]), xxp);
331 gmm::mult(gmm::transposed(BB), xx - xxp, vres);
334 GMM_ASSERT1( res <= EPS,
335 "Iterative pojection on convex face did not converge");
337 pgt->poly_vector_grad(xp, ind_pts_fc, grad_fc);
338 gmm::mult(grad_fc, gmm::transposed(base_ref_fc), grad_fc1);
350 base_matrix grad_cv(nb_pts_cv, P);
351 pgt->poly_vector_grad(xp, grad_cv);
353 base_matrix GG(N, nb_pts_cv);
354 m.points_of_convex(cv, GG);
359 base_matrix bases_product(P-1, P);
360 gmm::mult(gmm::transposed(K), KK, bases_product);
363 std::vector<size_type> ind(0);
365 if (j != i ) ind.push_back(j);
366 gmm::sub_index SUBI(ind);
369 gmm::sub_interval(0, P-1), SUBI));
370 gmm::add(gmm::scaled(gmm::mat_col(KK, i), (i % 2) ? -det : +det ),
375 gmm::scale(un, 1/gmm::vect_norm2(un));
377 if (gmm::vect_sp(un, gmm::mean_value(pts_fc) -
378 gmm::mean_value(m.points_of_convex(cv))) < 0)
379 gmm::scale(un,scalar_type(-1));
381 return pgt->convex_ref()->is_in(proj_node_ref);
385 void compute_contact_matrices
386 (
const mesh_fem &mf_disp1,
const mesh_fem &mf_disp2,
387 contact_node_pair_list &cnpl, model_real_plain_vector &gap,
388 CONTACT_B_MATRIX *BN1, CONTACT_B_MATRIX *BN2 = 0,
389 CONTACT_B_MATRIX *BT1 = 0, CONTACT_B_MATRIX *BT2 = 0) {
391 GMM_ASSERT1(gmm::vect_size(gap) == cnpl.size(),
392 "Wrong number of contact node pairs or wrong size of gap");
394 GMM_ASSERT1( gmm::mat_nrows(*BN1) == cnpl.size(),
"Wrong size of BN1");
397 GMM_ASSERT1( gmm::mat_nrows(*BN2) == cnpl.size(),
"Wrong size of BN2");
399 dim_type qdim = mf_disp1.get_qdim();
403 GMM_ASSERT1( gmm::mat_nrows(*BT1) == cnpl.size() * d,
"Wrong size of BT1");
407 GMM_ASSERT1( gmm::mat_nrows(*BT2) == cnpl.size() * d,
"Wrong size of BT2");
410 for (
size_type row = 0; row < cnpl.size(); ++row) {
411 contact_node_pair *cnp = &cnpl[row];
412 if (cnp->is_active) {
413 contact_node *cn_s = &cnp->cn_s;
414 contact_node *cn_m = &cnp->cn_m;
415 const mesh &mesh_m = cn_m->mf->linked_mesh();
416 base_node slave_node = cn_s->mf->point_of_basic_dof(cn_s->dof);
417 base_node master_node = cn_m->mf->point_of_basic_dof(cn_m->dof);
418 GMM_ASSERT1(slave_node.size() == qdim && master_node.size() == qdim,
420 base_node un_sel(qdim), proj_node_sel(qdim), proj_node_ref_sel(qdim);
421 scalar_type is_in_min = 1e5;
424 std::vector<size_type>::iterator cv;
425 std::vector<short_type>::iterator fc;
426 for (cv = cn_m->cvs.begin(), fc = cn_m->fcs.begin();
427 cv != cn_m->cvs.end() && fc != cn_m->fcs.end(); cv++, fc++) {
428 base_node un(qdim), proj_node(qdim), proj_node_ref(qdim);
429 scalar_type is_in = projection_on_convex_face
430 (mesh_m, *cv, *fc, master_node, slave_node, un, proj_node, proj_node_ref);
431 if (is_in < is_in_min) {
436 proj_node_sel = proj_node;
437 proj_node_ref_sel = proj_node_ref;
440 if (is_in_min < 0.05) {
441 gap[row] =
gmm::vect_sp(slave_node-proj_node_sel, un_sel);
443 std::vector<base_node> ut(d);
444 if (BT1) orthonormal_basis_to_unit_vec(d, un_sel, &(ut[0]));
446 CONTACT_B_MATRIX *BN = 0;
447 CONTACT_B_MATRIX *BT = 0;
448 if (cn_s->mf == &mf_disp1) {
451 }
else if (cn_s->mf == &mf_disp2) {
457 (*BN)(row, cn_s->dof + k) -= un_sel[k];
461 (*BT)(row * d + n, cn_s->dof + k) -= ut[n][k];
464 const mesh_fem *mf_disp = 0;
465 if (cn_m->mf == &mf_disp1) {
469 }
else if (cn_m->mf == &mf_disp2) {
476 base_matrix M(qdim, mf_disp->nb_basic_dof_of_element(cv_sel));
477 mesh_m.points_of_convex(cv_sel, G);
478 pfem pf = mf_disp->fem_of_element(cv_sel);
480 fem_interpolation_context
481 ctx(pgt, pf, proj_node_ref_sel, G, cv_sel, fc_sel);
482 pf->interpolation (ctx, M,
int(qdim));
485 master_dofs = mf_disp->ind_basic_dof_of_element(cv_sel);
487 model_real_plain_vector MT_u(mf_disp->nb_basic_dof_of_element(cv_sel));
488 gmm::mult(gmm::transposed(M), un_sel, MT_u);
489 for (
size_type j = 0; j < master_dofs.size(); ++j)
490 (*BN)(row, master_dofs[j]) += MT_u[j];
494 gmm::mult(gmm::transposed(M), ut[n], MT_u);
495 for (
size_type j = 0; j < master_dofs.size(); ++j)
496 (*BT)(row * d + n, master_dofs[j]) += MT_u[j];
515 struct Coulomb_friction_brick :
public virtual_brick {
517 mutable CONTACT_B_MATRIX BN1, BT1, BN2, BT2;
518 mutable CONTACT_B_MATRIX DN, DDN, DT, DDT;
519 mutable CONTACT_B_MATRIX BBN1, BBT1, BBN2, BBT2;
520 mutable model_real_plain_vector gap, threshold, friction_coeff,
alpha;
521 mutable model_real_plain_vector RLN, RLT;
522 mutable scalar_type r, gamma;
523 mutable bool is_init;
524 bool Tresca_version, contact_only;
525 bool really_stationary, friction_dynamic_term;
526 bool two_variables, Hughes_stabilized;
527 int augmentation_version;
532 void init_BBN_BBT(
void)
const {
533 gmm::resize(BBN1, gmm::mat_nrows(BN1), gmm::mat_ncols(BN1));
535 if (Hughes_stabilized) {
536 gmm::resize(DDN, gmm::mat_nrows(DN), gmm::mat_ncols(DN));
540 gmm::resize(BBN2, gmm::mat_nrows(BN2), gmm::mat_ncols(BN2));
544 if (Hughes_stabilized) {
545 gmm::resize(DDT, gmm::mat_nrows(DT), gmm::mat_ncols(DT));
548 gmm::resize(BBT1, gmm::mat_nrows(BT1), gmm::mat_ncols(BT1));
551 gmm::resize(BBT2, gmm::mat_nrows(BT2), gmm::mat_ncols(BT2));
558 gmm::scale(gmm::mat_row(BBN1, i), alpha[i]);
559 if (Hughes_stabilized) gmm::scale(gmm::mat_row(DDN, i), alpha[i]);
561 gmm::scale(gmm::mat_row(BBN2, i), alpha[i]);
564 if (Hughes_stabilized)
565 gmm::scale(gmm::mat_row(DDT, d*i+k), alpha[i]);
566 gmm::scale(gmm::mat_row(BBT1, d*i+k), alpha[i]);
568 gmm::scale(gmm::mat_row(BBT2, d*i+k), alpha[i]);
574 void set_stationary(
void) { really_stationary =
true; }
576 void precomp(
const model_real_plain_vector &u1,
577 const model_real_plain_vector &u2,
578 const model_real_plain_vector &lambda_n,
579 const model_real_plain_vector &lambda_t,
580 const model_real_plain_vector &wt1,
581 const model_real_plain_vector &wt2)
const {
583 for (
size_type i = 0; i < gmm::mat_nrows(BN1); ++i) RLN[i] *= alpha[i];
586 if (Hughes_stabilized)
588 if (two_variables)
gmm::mult_add(BBN2, gmm::scaled(u2, -r), RLN);
591 if (friction_dynamic_term) {
596 if (!really_stationary) {
598 if (two_variables)
gmm::mult_add(BBT2, gmm::scaled(u2, -r), RLT);
600 if (Hughes_stabilized)
606 void basic_asm_real_tangent_terms(
const model_real_plain_vector &u1,
607 const model_real_plain_vector &u2,
608 const model_real_plain_vector &lambda_n,
609 const model_real_plain_vector &lambda_t,
610 const model_real_plain_vector &wt1,
611 const model_real_plain_vector &wt2,
612 model::real_matlist &matl,
613 model::real_veclist &vecl,
614 build_version version)
const {
615 size_type nbt = 4 + (contact_only ? 0 : 4) + (two_variables ? 3 : 0)
616 + (two_variables && !contact_only ? 2 : 0);
617 GMM_ASSERT1(matl.size() == nbt,
618 "Wrong number of terms for the contact brick");
620 const scalar_type vt1 = scalar_type(1), vt0 = scalar_type(0);
626 model_real_sparse_matrix &T_u1_u1 = matl[nt++], &T_u2_u2 = matl[nt++];
627 if (!two_variables) nt--;
628 model_real_sparse_matrix &T_u1_n = matl[nt++], &T_n_u1 = matl[nt++];
629 if (!two_variables) nt -= 2;
630 model_real_sparse_matrix &T_u2_n = matl[nt++], &T_n_u2 = matl[nt++];
632 model_real_sparse_matrix &T_n_n = matl[nt++];
633 if (contact_only) nt -= 2;
634 model_real_sparse_matrix &T_u1_t = matl[nt++], &T_t_u1 = matl[nt++];
635 if (contact_only || !two_variables) nt -= 2;
636 model_real_sparse_matrix &T_u2_t = matl[nt++], &T_t_u2 = matl[nt++];
637 if (contact_only) nt -= 2;
639 model_real_sparse_matrix &T_t_t = matl[nt++], &T_t_n = matl[nt++];
642 model_real_plain_vector &ru1 = vecl[0];
643 model_real_plain_vector &ru2 = vecl[1];
644 model_real_plain_vector &rlambda_n = vecl[nvec_lambda_n];
645 model_real_plain_vector &rlambda_t = vecl[nvec_lambda_t];
648 if (!is_init) init_BBN_BBT();
651 if (augmentation_version <= 2)
652 precomp(u1, u2, lambda_n, lambda_t, wt1, wt2);
654 if (version & model::BUILD_MATRIX) {
655 base_matrix pg(d, d);
667 switch (augmentation_version) {
669 gmm::copy(gmm::scaled(gmm::transposed(BN1), -vt1), T_u1_n);
671 gmm::copy(gmm::scaled(gmm::transposed(BN2), -vt1), T_u2_n);
675 if (two_variables)
gmm::clear(gmm::mat_col(T_u2_n, i));
676 T_n_n(i, i) = -vt1/(r*
alpha[i]);
678 if (Hughes_stabilized && RLN[i] <= vt0)
679 gmm::copy(gmm::scaled(gmm::mat_row(DN, i), -vt1),
680 gmm::mat_col(T_n_n, i));
682 if (Hughes_stabilized) {
683 model_real_sparse_matrix aux(nbc, nbc);
687 gmm::copy(gmm::transposed(T_u1_n), T_n_u1);
688 if (two_variables)
gmm::copy(gmm::transposed(T_u2_n), T_n_u2);
691 gmm::sub_interval SUBI(i*d, d);
692 scalar_type th = Tresca_version ? threshold[i]
693 : - (std::min(vt0, RLN[i])) * friction_coeff[i];
694 ball_projection_grad(gmm::sub_vector(RLT, SUBI), th, pg);
695 if (!really_stationary)
698 gmm::add(gmm::scaled(gmm::mat_row(BT1,i*d+k1),-pg(k2,k1)),
699 gmm::mat_col(T_u1_t, i*d+k2));
701 gmm::add(gmm::scaled(gmm::mat_row(BT2,i*d+k1),
703 gmm::mat_col(T_u2_t, i*d+k2));
706 if (!Tresca_version) {
708 ball_projection_grad_r(gmm::sub_vector(RLT, SUBI), th, vg);
710 T_t_n(i*d+k, i) = - friction_coeff[i] * vg[k]/(r*
alpha[i]);
713 for (
size_type k = 0; k < d; ++k) pg(k,k) -= vt1;
714 gmm::copy(gmm::scaled(pg, vt1/(r*alpha[i])),
715 gmm::sub_matrix(T_t_t,SUBI));
716 if (Hughes_stabilized) {
719 gmm::add(gmm::scaled(gmm::mat_row(DT, d*i+l), -pg(k,l)),
720 gmm::mat_col(T_t_t, d*i+k));
725 if (Hughes_stabilized) {
726 model_real_sparse_matrix aux(gmm::mat_nrows(T_t_t),
727 gmm::mat_nrows(T_t_t));
731 gmm::copy(gmm::transposed(T_u1_t), T_t_u1);
732 if (two_variables)
gmm::copy(gmm::transposed(T_u2_t), T_t_u2);
735 if (augmentation_version == 1) {
736 gmm::copy(gmm::scaled(gmm::transposed(BN1), -vt1), T_u1_n);
738 gmm::copy(gmm::scaled(gmm::transposed(BN2), -vt1), T_u2_n);
740 gmm::copy(gmm::scaled(gmm::transposed(BT1), -vt1), T_u1_t);
742 gmm::copy(gmm::scaled(gmm::transposed(BT2), -vt1), T_u2_t);
745 model_real_sparse_matrix tmp1(gmm::mat_ncols(BN1),
746 gmm::mat_ncols(BN1));
747 gmm::mult(gmm::transposed(gmm::scaled(BBN1,-r)), T_n_u1, tmp1);
750 gmm::mult(gmm::transposed(gmm::scaled(BBN2,-r)), T_n_u2, tmp1);
755 gmm::mult(gmm::transposed(gmm::scaled(BBT1,-r)), T_t_u1, tmp1);
758 gmm::mult(gmm::transposed(gmm::scaled(BBT2,-r)), T_t_u2, tmp1);
764 if (!contact_only && !Tresca_version) {
766 model_real_sparse_matrix tmp5(gmm::mat_ncols(BT1),
767 gmm::mat_ncols(BT1));
768 model_real_sparse_matrix tmp6(gmm::mat_ncols(BT1),
769 gmm::mat_ncols(BT1));
770 model_real_sparse_matrix tmp7(gmm::mat_ncols(BT2),
771 gmm::mat_ncols(BT2));
772 model_real_sparse_matrix tmp8(gmm::mat_ncols(BT2),
773 gmm::mat_ncols(BT2));
774 model_real_sparse_matrix tmp3(gmm::mat_ncols(T_t_u1),
775 gmm::mat_nrows(T_t_u1));
776 model_real_sparse_matrix tmp4(gmm::mat_ncols(T_t_u2),
777 gmm::mat_nrows(T_t_u2));
780 gmm::sub_interval SUBI(i*d, d);
781 scalar_type th = - (std::min(vt0, RLN[i])) * friction_coeff[i];
783 ball_projection_grad_r(gmm::sub_vector(RLT, SUBI), th, vg);
785 gmm::add(gmm::scaled(gmm::mat_row(BN1,i),
786 vg[k]*friction_coeff[i]), gmm::mat_col(tmp3, i*d+k));
788 gmm::add(gmm::scaled(gmm::mat_row(BN2,i),
789 vg[k]*friction_coeff[i]), gmm::mat_col(tmp4, i*d+k));
791 if (augmentation_version == 2) {
793 gmm::add(gmm::scaled(gmm::mat_row(BT1,i*d+k),
794 vg[k]*friction_coeff[i]), gmm::mat_col(T_u1_n, i));
796 gmm::add(gmm::scaled(gmm::mat_row(BT2,i*d+k),
797 vg[k]*friction_coeff[i]), gmm::mat_col(T_u2_n, i));
799 gmm::copy(gmm::scaled(gmm::mat_row(BBT1,i*d+k),
800 -r*friction_coeff[i]*vg[k]),
801 gmm::mat_col(tmp5, i*d+k));
803 gmm::mat_col(tmp6, i*d+k));
805 gmm::copy(gmm::scaled(gmm::mat_row(BBT2,i*d+k),
806 -r*friction_coeff[i]*vg[k]),
807 gmm::mat_col(tmp7, i*d+k));
809 gmm::mat_col(tmp8, i*d+k));
816 gmm::add(gmm::transposed(tmp3), T_t_u1);
818 gmm::add(gmm::transposed(tmp4), T_t_u2);
820 if (augmentation_version == 2) {
821 model_real_sparse_matrix tmp1(gmm::mat_ncols(BN1),
822 gmm::mat_ncols(BN1));
823 gmm::mult(tmp5, gmm::transposed(tmp6), gmm::transposed(tmp1));
824 gmm::add(gmm::transposed(tmp1), T_u1_u1);
826 gmm::mult(tmp7, gmm::transposed(tmp8),gmm::transposed(tmp1));
827 gmm::add(gmm::transposed(tmp1), T_u2_u2);
834 gmm::copy(gmm::scaled(gmm::transposed(BN1), -vt1), T_u1_n);
836 gmm::copy(gmm::scaled(gmm::transposed(BN2), -vt1), T_u2_n);
838 if (lambda_n[i] > vt0) {
840 if (two_variables)
gmm::clear(gmm::mat_col(T_u2_n, i));
841 T_n_n(i, i) = -vt1/r;
844 gmm::copy(gmm::scaled(BN1, -vt1), T_n_u1);
845 if (two_variables)
gmm::copy(gmm::scaled(BN2, -r), T_n_u2);
848 gmm::sub_interval SUBI(i*d, d);
849 scalar_type th = Tresca_version ? threshold[i]
850 : gmm::neg(lambda_n[i]) * friction_coeff[i];
851 ball_projection_grad(gmm::sub_vector(lambda_t, SUBI), th, pg);
852 if (!really_stationary)
855 gmm::add(gmm::scaled(gmm::mat_row(BT1,i*d+k1),-pg(k2,k1)),
856 gmm::mat_col(T_u1_t, i*d+k2));
858 gmm::add(gmm::scaled(gmm::mat_row(BT2,i*d+k1),
860 gmm::mat_col(T_u2_t, i*d+k2));
862 if (!Tresca_version) {
863 ball_projection_grad_r(gmm::sub_vector(lambda_t, SUBI),th,vg);
865 gmm::add(gmm::scaled(gmm::mat_row(BT1,i*d+k1),
866 friction_coeff[i]*vg[k1]),
867 gmm::mat_col(T_u1_n, i));
869 gmm::add(gmm::scaled(gmm::mat_row(BT2,i*d+k1),
870 friction_coeff[i]*vg[k1]),
871 gmm::mat_col(T_u2_n, i));
872 T_t_n(i*d+k1, i) = friction_coeff[i] * vg[k1] / (r*
alpha[i]);
875 for (
size_type k = 0; k < d; ++k) pg(k,k) -= vt1;
877 gmm::copy(gmm::scaled(pg, vt1/(r*alpha[i])),
878 gmm::sub_matrix(T_t_t, SUBI));
881 gmm::copy(gmm::scaled(BT1, -vt1), T_t_u1);
882 if (two_variables)
gmm::copy(gmm::scaled(BT2, -r), T_t_u2);
887 base_small_vector x(d+1), n(d+1), u(d); n[0] = vt1;
888 base_matrix g(d+1, d+1);
889 model_real_sparse_matrix T_n_u1_transp(gmm::mat_ncols(T_n_u1), nbc);
890 model_real_sparse_matrix T_n_u2_transp(gmm::mat_ncols(T_n_u2), nbc);
897 for (
size_type j=0; j < d; ++j) x[1+j] = lambda_t[i*d+j];
898 De_Saxce_projection_grad(x, n, friction_coeff[i], g);
900 gmm::add(gmm::scaled(gmm::mat_row(BN1, i), -g(0,0)),
901 gmm::mat_col(T_u1_n, i));
903 gmm::add(gmm::scaled(gmm::mat_row(BN2, i), -g(0,0)),
904 gmm::mat_col(T_u2_n, i));
905 T_n_n(i, i) = (g(0,0) - vt1)/(r*alpha[i]);
907 gmm::copy(gmm::sub_vector(RLT, gmm::sub_interval(i*d,d)), u);
911 gmm::add(gmm::scaled(gmm::mat_row(BT1, i*d+j),
912 friction_coeff[i] * u[j] / nu),
913 gmm::mat_col(T_n_u1_transp, i));
915 gmm::add(gmm::scaled(gmm::mat_row(BT2, i*d+j),
916 friction_coeff[i] * u[j] / nu),
917 gmm::mat_col(T_n_u2_transp, i));
921 gmm::add(gmm::scaled(gmm::mat_row(BT1, i*d+j), -g(0,j+1)),
922 gmm::mat_col(T_u1_n, i));
924 gmm::add(gmm::scaled(gmm::mat_row(BT2, i*d+j), -g(0,j+1)),
925 gmm::mat_col(T_u2_n, i));
927 gmm::add(gmm::scaled(gmm::mat_row(BN1, i), -g(j+1,0)),
928 gmm::mat_col(T_u1_t, i*d+j));
930 gmm::add(gmm::scaled(gmm::mat_row(BN2, i), -g(j+1,0)),
931 gmm::mat_col(T_u2_t, i*d+j));
934 gmm::add(gmm::scaled(gmm::mat_row(BT1, i*d+k), -g(1+j,1+k)),
935 gmm::mat_col(T_u1_t, i*d+j));
937 gmm::add(gmm::scaled(gmm::mat_row(BT2, i*d+k), -g(1+j,1+k)),
938 gmm::mat_col(T_u2_t, i*d+j));
939 T_t_t(i*d+j, i*d+k) = g(1+j, 1+k)/r;
941 T_t_t(i*d+j, i*d+j) -= vt1/(r*
alpha[i]);
942 T_t_n(i*d+j, i) = g(1+j,0)/(r*
alpha[i]);
946 gmm::copy(gmm::scaled(BN1, -vt1), T_n_u1);
947 if (two_variables)
gmm::copy(gmm::scaled(BN2, -vt1), T_n_u2);
948 gmm::add(gmm::transposed(T_n_u1_transp), T_n_u1);
949 if (two_variables)
gmm::add(gmm::transposed(T_n_u2_transp), T_n_u2);
950 gmm::copy(gmm::scaled(BT1, -vt1), T_t_u1);
951 if (two_variables)
gmm::copy(gmm::scaled(BT2, -vt1), T_t_u2);
956 if (version & model::BUILD_RHS) {
958 switch (augmentation_version) {
961 RLN[i] = std::min(scalar_type(0), RLN[i]);
963 scalar_type radius = Tresca_version ? threshold[i]
964 : -friction_coeff[i]*RLN[i];
966 (gmm::sub_vector(RLT, gmm::sub_interval(i*d,d)), radius);
978 rlambda_n[i] = (lambda_n[i] - RLN[i]) / (r * alpha[i]);
982 = (lambda_t[i*d+k] - RLT[i*d+k]) / (r *
alpha[i]);
987 RLN[i] = std::min(vt0, RLN[i]);
989 scalar_type radius = Tresca_version ? threshold[i]
990 : -friction_coeff[i]*RLN[i];
992 (gmm::sub_vector(RLT, gmm::sub_interval(i*d,d)), radius);
996 if (two_variables)
gmm::mult_add(gmm::transposed(BN2), RLN, ru2);
999 if (two_variables)
gmm::mult_add(gmm::transposed(BT2), RLT, ru2);
1002 rlambda_n[i] = (lambda_n[i] - RLN[i]) / (r * alpha[i]);
1006 = (lambda_t[i*d+k] - RLT[i*d+k]) / (r *
alpha[i]);
1010 if (!contact_only)
gmm::copy(lambda_t, RLT);
1012 RLN[i] = -gmm::neg(lambda_n[i]);
1013 rlambda_n[i] = gmm::pos(lambda_n[i])/r -
alpha[i]*gap[i];
1015 if (!contact_only) {
1016 scalar_type radius = Tresca_version ? threshold[i]
1017 : friction_coeff[i]*gmm::neg(lambda_n[i]);
1019 (gmm::sub_vector(RLT, gmm::sub_interval(i*d,d)), radius);
1022 gmm::mult(gmm::transposed(BN1), RLN, ru1);
1023 if (two_variables)
gmm::mult(gmm::transposed(BN2), RLN, ru2);
1026 if (!contact_only) {
1028 if (two_variables)
gmm::mult_add(gmm::transposed(BT2), RLT, ru2);
1029 gmm::add(gmm::scaled(lambda_t, vt1/r), gmm::scaled(RLT,-vt1/r),
1035 rlambda_n[i] /=
alpha[i];
1037 for (
size_type k = 0; k < d; ++k) rlambda_t[i*d+k] /= alpha[i];
1041 base_small_vector x(d+1), n(d+1);
1043 GMM_ASSERT1(!Tresca_version,
1044 "Augmentation version incompatible with Tresca friction law");
1050 gmm::copy(gmm::sub_vector(lambda_t, gmm::sub_interval(i*d,d)),
1051 gmm::sub_vector(x, gmm::sub_interval(1, d)));
1052 De_Saxce_projection(x, n, friction_coeff[i]);
1054 gmm::copy(gmm::sub_vector(x, gmm::sub_interval(1, d)),
1055 gmm::sub_vector(RLT, gmm::sub_interval(i*d,d)));
1056 rlambda_n[i] = lambda_n[i]/r - x[0]/r -
alpha[i]*gap[i]
1058 gmm::sub_interval(i*d,d)));
1061 if (two_variables)
gmm::mult_add(gmm::transposed(BT2), RLT, ru2);
1063 if (two_variables)
gmm::mult_add(gmm::transposed(BN2), RLN, ru2);
1064 gmm::add(gmm::scaled(lambda_t, vt1/r), rlambda_t);
1065 gmm::add(gmm::scaled(RLT, -vt1/r), rlambda_t);
1069 rlambda_n[i] /=
alpha[i];
1071 for (
size_type k = 0; k < d; ++k) rlambda_t[i*d+k] /= alpha[i];
1079 virtual void asm_real_tangent_terms(
const model &md,
size_type ib,
1080 const model::varnamelist &vl,
1081 const model::varnamelist &dl,
1082 const model::mimlist &mims,
1083 model::real_matlist &matl,
1084 model::real_veclist &vecl,
1085 model::real_veclist &,
1087 build_version version)
const {
1088 if (MPI_IS_MASTER()) {
1089 GMM_ASSERT1(mims.size() == 0,
"Contact brick need no mesh_im");
1090 size_type nbvar = 2 + (contact_only ? 0 : 1) + (two_variables ? 1 : 0);
1091 GMM_ASSERT1(vl.size() == nbvar,
1092 "Wrong number of variables for contact brick");
1093 size_type nbdl = 3 + (contact_only ? 0 : 1) + (Tresca_version ? 1 : 0)
1094 + (friction_dynamic_term ? 2 : 0);
1095 GMM_ASSERT1(dl.size() == nbdl,
"Wrong number of data for contact brick, "
1096 << dl.size() <<
" should be " << nbdl);
1106 const model_real_plain_vector &u1 = md.real_variable(vl[nv++]);
1107 const model_real_plain_vector &u2 = md.real_variable(vl[nv++]);
1108 if (!two_variables) nv--;
1109 const model_real_plain_vector &lambda_n = md.real_variable(vl[nv++]);
1110 if (contact_only) nv--;
1111 const model_real_plain_vector &lambda_t = md.real_variable(vl[nv]);
1115 size_type np = 0, np_wt1 = 0, np_wt2 = 0, np_alpha = 0;
1116 const model_real_plain_vector &vr = md.real_variable(dl[np++]);
1117 GMM_ASSERT1(gmm::vect_size(vr) == 1,
"Parameter r should be a scalar");
1119 const model_real_plain_vector &vgap = md.real_variable(dl[np++]);
1120 GMM_ASSERT1(gmm::vect_size(vgap) == 1 || gmm::vect_size(vgap) == nbc,
1121 "Parameter gap has a wrong size");
1123 if (gmm::vect_size(vgap) == 1)
1128 const model_real_plain_vector &valpha = md.real_variable(dl[np_alpha]);
1129 GMM_ASSERT1(gmm::vect_size(valpha)== 1 || gmm::vect_size(valpha) == nbc,
1130 "Parameter alpha has a wrong size");
1132 if (gmm::vect_size(valpha) == 1)
1136 if (!contact_only) {
1137 const model_real_plain_vector &vfr = md.real_variable(dl[np++]);
1138 GMM_ASSERT1(gmm::vect_size(vfr)==1 || gmm::vect_size(vfr) == nbc,
1139 "Parameter friction_coeff has a wrong size");
1141 if (gmm::vect_size(vfr) == 1)
1145 if (friction_dynamic_term) {
1146 const model_real_plain_vector &vg = md.real_variable(dl[np++]);
1147 GMM_ASSERT1(gmm::vect_size(vg) == 1,
1148 "Parameter gamma should be a scalar");
1151 if (two_variables) np_wt2 = np++;
1153 if (Tresca_version) {
1154 const model_real_plain_vector &vth = md.real_variable(dl[np++]);
1155 GMM_ASSERT1(gmm::vect_size(vth) == 1 || gmm::vect_size(vth) == nbc,
1156 "Parameter threshold has a wrong size");
1158 if (gmm::vect_size(vth) == 1)
1165 if (md.is_var_newer_than_brick(dl[np_alpha], ib)) is_init =
false;
1167 basic_asm_real_tangent_terms
1168 (u1, u2, lambda_n, lambda_t, md.real_variable(dl[np_wt1]),
1169 md.real_variable(dl[np_wt2]), matl, vecl, version);
1174 Coulomb_friction_brick(
int aug_version,
bool contact_only_,
1175 bool two_variables_=
false,
1176 bool Tresca_version_=
false,
1177 bool Hughes_stabilized_=
false,
1178 bool friction_dynamic_term_=
false) {
1180 if (aug_version == 4 && contact_only_) aug_version = 3;
1181 augmentation_version = aug_version;
1182 GMM_ASSERT1(aug_version >= 1 && aug_version <= 4,
1183 "Wrong augmentation version");
1184 GMM_ASSERT1(!Hughes_stabilized_ || aug_version <= 2,
1185 "The Hughes stabilized version is only for Alart-Curnier "
1187 contact_only = contact_only_;
1189 Tresca_version = Tresca_version_;
1190 really_stationary =
false;
1191 friction_dynamic_term = friction_dynamic_term_;
1192 two_variables = two_variables_;
1193 Hughes_stabilized = Hughes_stabilized_;
1194 set_flags(
"Coulomb friction brick",
false ,
1196 (augmentation_version == 2) && (contact_only||Tresca_version),
1201 void set_BN1(CONTACT_B_MATRIX &BN1_) {
1202 gmm::resize(BN1, gmm::mat_nrows(BN1_), gmm::mat_ncols(BN1_));
1207 void set_BN2(CONTACT_B_MATRIX &BN2_) {
1208 gmm::resize(BN2, gmm::mat_nrows(BN2_), gmm::mat_ncols(BN2_));
1213 void set_DN(CONTACT_B_MATRIX &DN_) {
1214 gmm::resize(DN, gmm::mat_nrows(DN_), gmm::mat_ncols(DN_));
1219 void set_DT(CONTACT_B_MATRIX &DT_) {
1220 gmm::resize(DT, gmm::mat_nrows(DT_), gmm::mat_ncols(DT_));
1225 void set_BT1(CONTACT_B_MATRIX &BT1_) {
1226 gmm::resize(BT1, gmm::mat_nrows(BT1_), gmm::mat_ncols(BT1_));
1231 CONTACT_B_MATRIX &get_BN1(
void) {
return BN1; }
1232 CONTACT_B_MATRIX &get_DN(
void) {
return DN; }
1233 CONTACT_B_MATRIX &get_DT(
void) {
return DT; }
1234 CONTACT_B_MATRIX &get_BT1(
void) {
return BT1; }
1235 const CONTACT_B_MATRIX &get_BN1(
void)
const {
return BN1; }
1236 const CONTACT_B_MATRIX &get_DN(
void)
const {
return DN; }
1237 const CONTACT_B_MATRIX &get_BT1(
void)
const {
return BT1; }
1243 pbrick pbr = md.brick_pointer(indbrick);
1245 Coulomb_friction_brick *p =
dynamic_cast<Coulomb_friction_brick *
>
1247 GMM_ASSERT1(p,
"Wrong type of brick");
1248 p->set_stationary();
1253 pbrick pbr = md.brick_pointer(indbrick);
1255 Coulomb_friction_brick *p =
dynamic_cast<Coulomb_friction_brick *
>
1257 GMM_ASSERT1(p,
"Wrong type of brick");
1258 return p->get_BN1();
1264 pbrick pbr = md.brick_pointer(indbrick);
1266 Coulomb_friction_brick *p =
dynamic_cast<Coulomb_friction_brick *
>
1268 GMM_ASSERT1(p,
"Wrong type of brick");
1274 pbrick pbr = md.brick_pointer(indbrick);
1276 Coulomb_friction_brick *p =
dynamic_cast<Coulomb_friction_brick *
>
1278 GMM_ASSERT1(p,
"Wrong type of brick");
1285 pbrick pbr = md.brick_pointer(indbrick);
1287 Coulomb_friction_brick *p =
dynamic_cast<Coulomb_friction_brick *
>
1289 GMM_ASSERT1(p,
"Wrong type of brick");
1290 return p->get_BT1();
1298 (
model &md,
const std::string &varname_u,
const std::string &multname_n,
1299 const std::string &dataname_r, CONTACT_B_MATRIX &BN,
1300 std::string dataname_gap, std::string dataname_alpha,
1301 int aug_version,
bool Hughes_stabilized) {
1303 auto pbr_ = std::make_shared<Coulomb_friction_brick>
1304 (aug_version,
true,
false,
false, Hughes_stabilized);
1309 tl.push_back(model::term_description(varname_u, varname_u,
false));
1310 tl.push_back(model::term_description(varname_u, multname_n,
false));
1311 tl.push_back(model::term_description(multname_n, varname_u,
false));
1312 tl.push_back(model::term_description(multname_n, multname_n,
false));
1313 model::varnamelist dl(1, dataname_r);
1315 if (dataname_gap.size() == 0) {
1316 dataname_gap = md.
new_name(
"contact_gap_on_" + varname_u);
1318 (dataname_gap, model_real_plain_vector(1, scalar_type(0)));
1320 dl.push_back(dataname_gap);
1322 if (dataname_alpha.size() == 0) {
1323 dataname_alpha = md.
new_name(
"contact_parameter_alpha_on_"+ multname_n);
1325 (dataname_alpha, model_real_plain_vector(1, scalar_type(1)));
1327 dl.push_back(dataname_alpha);
1329 model::varnamelist vl(1, varname_u);
1330 vl.push_back(multname_n);
1341 (
model &md,
const std::string &varname_u1,
const std::string &varname_u2,
1342 const std::string &multname_n,
1343 const std::string &dataname_r, CONTACT_B_MATRIX &BN1, CONTACT_B_MATRIX &BN2,
1344 std::string dataname_gap, std::string dataname_alpha,
1345 int aug_version,
bool Hughes_stabilized) {
1347 auto pbr_ = std::make_shared<Coulomb_friction_brick>
1348 (aug_version,
true,
true,
false, Hughes_stabilized);
1354 tl.push_back(model::term_description(varname_u1, varname_u1,
false));
1355 tl.push_back(model::term_description(varname_u2, varname_u2,
false));
1356 tl.push_back(model::term_description(varname_u1, multname_n,
false));
1357 tl.push_back(model::term_description(multname_n, varname_u1,
false));
1358 tl.push_back(model::term_description(varname_u2, multname_n,
false));
1359 tl.push_back(model::term_description(multname_n, varname_u2,
false));
1360 tl.push_back(model::term_description(multname_n, multname_n,
false));
1361 model::varnamelist dl(1, dataname_r);
1363 if (dataname_gap.size() == 0) {
1364 dataname_gap = md.
new_name(
"contact_gap_on_" + varname_u1);
1366 (dataname_gap, model_real_plain_vector(1, scalar_type(0)));
1368 dl.push_back(dataname_gap);
1370 if (dataname_alpha.size() == 0) {
1371 dataname_alpha = md.
new_name(
"contact_parameter_alpha_on_"+ multname_n);
1373 (dataname_alpha, model_real_plain_vector(1, scalar_type(1)));
1375 dl.push_back(dataname_alpha);
1377 model::varnamelist vl(1, varname_u1);
1378 vl.push_back(varname_u2);
1379 vl.push_back(multname_n);
1390 (
model &md,
const std::string &varname_u,
const std::string &multname_n,
1391 const std::string &multname_t,
const std::string &dataname_r,
1392 CONTACT_B_MATRIX &BN, CONTACT_B_MATRIX &BT,
1393 std::string dataname_friction_coeff,
1394 std::string dataname_gap, std::string dataname_alpha,
1395 int aug_version,
bool Tresca_version,
const std::string dataname_threshold,
1396 std::string dataname_gamma, std::string dataname_wt,
bool Hughes_stabilized) {
1398 bool dynamic_terms = (dataname_gamma.size() > 0);
1400 auto pbr_ = std::make_shared<Coulomb_friction_brick>
1401 (aug_version,
false,
false, Tresca_version, Hughes_stabilized,
1408 tl.push_back(model::term_description(varname_u, varname_u,
false));
1409 tl.push_back(model::term_description(varname_u, multname_n,
false));
1410 tl.push_back(model::term_description(multname_n, varname_u,
false));
1411 tl.push_back(model::term_description(multname_n, multname_n,
false));
1412 tl.push_back(model::term_description(varname_u, multname_t,
false));
1413 tl.push_back(model::term_description(multname_t, varname_u,
false));
1414 tl.push_back(model::term_description(multname_t, multname_t,
false));
1415 tl.push_back(model::term_description(multname_t, multname_n,
1416 (aug_version == 4)));
1417 model::varnamelist dl(1, dataname_r);
1418 if (dataname_gap.size() == 0) {
1419 dataname_gap = md.
new_name(
"contact_gap_on_" + varname_u);
1421 (dataname_gap, model_real_plain_vector(1, scalar_type(0)));
1423 dl.push_back(dataname_gap);
1425 if (dataname_alpha.size() == 0) {
1426 dataname_alpha = md.
new_name(
"contact_parameter_alpha_on_"+ multname_n);
1428 (dataname_alpha, model_real_plain_vector(1, scalar_type(1)));
1430 dl.push_back(dataname_alpha);
1431 dl.push_back(dataname_friction_coeff);
1432 if (dataname_gamma.size()) {
1433 dl.push_back(dataname_gamma);
1434 dl.push_back(dataname_wt);
1437 dl.push_back(dataname_threshold);
1439 model::varnamelist vl(1, varname_u);
1440 vl.push_back(multname_n);
1441 vl.push_back(multname_t);
1454 struct Coulomb_friction_brick_rigid_obstacle
1455 :
public Coulomb_friction_brick {
1457 std::string obstacle;
1461 virtual void asm_real_tangent_terms(
const model &md,
size_type ib,
1462 const model::varnamelist &vl,
1463 const model::varnamelist &dl,
1464 const model::mimlist &mims,
1465 model::real_matlist &matl,
1466 model::real_veclist &vecl,
1467 model::real_veclist &,
1469 build_version version)
const {
1470 if (MPI_IS_MASTER()) {
1471 GMM_ASSERT1(mims.size() == 1,
"This contact brick needs one mesh_im");
1472 size_type nbvar = 2 + (contact_only ? 0 : 1);
1473 GMM_ASSERT1(vl.size() == nbvar,
1474 "Wrong number of variables for contact brick: "
1475 << vl.size() <<
" should be " << nbvar);
1476 size_type nbdl = 1 + (contact_only ? 0 : 1) + (Tresca_version ? 1 : 0)
1477 + (friction_dynamic_term ? 1 : 0);
1478 GMM_ASSERT1(dl.size() == nbdl,
1479 "Wrong number of data for contact brick: "
1480 << dl.size() <<
" should be " << nbdl);
1481 GMM_ASSERT1(!two_variables,
"internal error");
1482 const mesh_im &mim = *mims[0];
1488 const model_real_plain_vector &u1 = md.real_variable(vl[nv++]);
1489 const mesh_fem &mf_u1 = md.mesh_fem_of_variable(vl[0]);
1490 const model_real_plain_vector &lambda_n = md.real_variable(vl[nv++]);
1491 if (contact_only) nv--;
1492 const model_real_plain_vector &lambda_t = md.real_variable(vl[nv]);
1497 const model_real_plain_vector &vr = md.real_variable(dl[np++]);
1498 GMM_ASSERT1(gmm::vect_size(vr) == 1,
"Parameter r should be a scalar");
1502 if (md.is_var_mf_newer_than_brick(vl[0], ib)) {
1505 GMM_ASSERT1(!(mf_u1.is_reduced()),
1506 "This contact brick works only for pure Lagrange fems");
1507 dal::bit_vector dofs = mf_u1.basic_dof_on_region(region);
1508 for (dal::bv_visitor
id(dofs); !
id.finished(); ++id) {
1509 size_type cv = mf_u1.first_convex_of_basic_dof(
id);
1510 GMM_ASSERT1(mf_u1.fem_of_element(cv)->is_lagrange(),
1511 "This contact brick works only for pure Lagrange fems");
1513 size_type d = mf_u1.get_qdim() - 1, i = 0, j = 0;
1514 nbc = dofs.card() / (d+1);
1517 base_node Pmin, Pmax;
1518 mf_u1.linked_mesh().bounding_box(Pmin, Pmax);
1519 scalar_type l = scalar_type(0);
1520 for (i = 0; i < Pmin.size(); ++i)
1521 l = std::max(l, gmm::abs(Pmax[i] - Pmin[i]));
1523 CONTACT_B_MATRIX MM(mf_u1.nb_dof(), mf_u1.nb_dof());
1527 for (dal::bv_visitor
id(dofs); !
id.finished(); ++id, ++i)
1528 if ((i % (d+1)) == 0)
alpha[j++] = MM(
id,
id) / l;
1530 getfem::ga_workspace gw;
1532 getfem::model_real_plain_vector pt(N);
1533 gw.add_fixed_size_constant(
"X", pt);
1534 if (N >= 1) gw.add_macro(
"x",
"X(1)");
1535 if (N >= 2) gw.add_macro(
"y",
"X(2)");
1536 if (N >= 3) gw.add_macro(
"z",
"X(3)");
1537 if (N >= 4) gw.add_macro(
"w",
"X(4)");
1539 getfem::ga_function f(gw, obstacle);
1545 if (!contact_only) {
1549 base_node grad(d+1), ut[3];
1552 for (dal::bv_visitor
id(dofs); !
id.finished(); ++id, ++i) {
1553 if ((i % (d+1)) == 0) {
1554 gmm::copy(mf_u1.point_of_basic_dof(
id), pt);
1557 gap[j] = (f.eval())[0];
1560 size_type cv = mf_u1.first_convex_of_basic_dof(
id);
1562 = mf_u1.linked_mesh().convex_radius_estimate(cv) * 1E-3;
1565 grad[k] = ((f.eval())[0] - gap[j]) / eps;
1572 BN1(j,
id + k) = un[k];
1575 if (!contact_only) {
1577 orthonormal_basis_to_unit_vec(d, un, ut);
1581 BT1(j*d+nn,
id + k) = ut[nn][k];
1588 GMM_ASSERT1(gmm::vect_size(md.real_variable(vl[1])) == nbc,
1589 "Wrong size of multiplier for the contact condition");
1592 GMM_ASSERT1(gmm::vect_size(md.real_variable(vl[2])) == nbc*d,
1593 "Wrong size of multiplier for the friction condition");
1598 nbc = gmm::mat_nrows(BN1);
1600 if (!contact_only) {
1601 const model_real_plain_vector &vfr = md.real_variable(dl[np++]);
1602 GMM_ASSERT1(gmm::vect_size(vfr)==1 || gmm::vect_size(vfr) == nbc,
1603 "Parameter friction_coeff has a wrong size");
1605 if (gmm::vect_size(vfr) == 1)
1609 if (friction_dynamic_term) {
1610 const model_real_plain_vector &vg = md.real_variable(dl[np++]);
1611 GMM_ASSERT1(gmm::vect_size(vg) == 1,
1612 "Parameter gamma should be a scalar");
1616 if (Tresca_version) {
1617 const model_real_plain_vector &vth = md.real_variable(dl[np++]);
1618 GMM_ASSERT1(gmm::vect_size(vth) == 1 || gmm::vect_size(vth) == nbc,
1619 "Parameter threshold has a wrong size");
1621 if (gmm::vect_size(vth) == 1)
1628 basic_asm_real_tangent_terms
1629 (u1, u1, lambda_n, lambda_t, md.real_variable(dl[np_wt1]),
1630 md.real_variable(dl[np_wt1]), matl, vecl, version);
1635 Coulomb_friction_brick_rigid_obstacle
1636 (
int aug_version,
bool contact_only_,
const std::string &obs)
1637 : Coulomb_friction_brick(aug_version, contact_only_), obstacle(obs) {}
1648 (
model &md,
const mesh_im &mim,
const std::string &varname_u,
1649 const std::string &multname_n,
const std::string &dataname_r,
1650 size_type region,
const std::string &obstacle,
int aug_version) {
1651 pbrick pbr = std::make_shared<Coulomb_friction_brick_rigid_obstacle>
1652 (aug_version,
true, obstacle);
1655 tl.push_back(model::term_description(varname_u, varname_u,
false));
1656 tl.push_back(model::term_description(varname_u, multname_n,
false));
1657 tl.push_back(model::term_description(multname_n, varname_u,
false));
1658 tl.push_back(model::term_description(multname_n, multname_n,
false));
1659 model::varnamelist dl(1, dataname_r);
1661 model::varnamelist vl(1, varname_u);
1662 vl.push_back(multname_n);
1664 return md.
add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
1674 (
model &md,
const mesh_im &mim,
const std::string &varname_u,
1675 const std::string &multname_n,
const std::string &multname_t,
1676 const std::string &dataname_r,
const std::string &dataname_friction_coeff,
1677 size_type region,
const std::string &obstacle,
int aug_version) {
1678 pbrick pbr = std::make_shared<Coulomb_friction_brick_rigid_obstacle>
1679 (aug_version,
false, obstacle);
1682 tl.push_back(model::term_description(varname_u, varname_u,
false));
1683 tl.push_back(model::term_description(varname_u, multname_n,
false));
1684 tl.push_back(model::term_description(multname_n, varname_u,
false));
1685 tl.push_back(model::term_description(multname_n, multname_n,
false));
1686 tl.push_back(model::term_description(varname_u, multname_t,
false));
1687 tl.push_back(model::term_description(multname_t, varname_u,
false));
1688 tl.push_back(model::term_description(multname_t, multname_t,
false));
1689 tl.push_back(model::term_description(multname_t, multname_n,
1690 (aug_version == 4)));
1691 model::varnamelist dl(1, dataname_r);
1692 dl.push_back(dataname_friction_coeff);
1694 model::varnamelist vl(1, varname_u);
1695 vl.push_back(multname_n);
1696 vl.push_back(multname_t);
1698 return md.
add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
1711 struct Coulomb_friction_brick_nonmatching_meshes
1712 :
public Coulomb_friction_brick {
1714 std::vector<size_type> rg1, rg2;
1718 bool slave1, slave2;
1722 virtual void asm_real_tangent_terms(
const model &md,
size_type ib,
1723 const model::varnamelist &vl,
1724 const model::varnamelist &dl,
1725 const model::mimlist &mims,
1726 model::real_matlist &matl,
1727 model::real_veclist &vecl,
1728 model::real_veclist &,
1730 build_version version)
const {
1731 if (MPI_IS_MASTER()) {
1732 GMM_ASSERT1(mims.size() == 2,
"This contact brick needs two mesh_im");
1733 const mesh_im &mim1 = *mims[0];
1734 const mesh_im &mim2 = *mims[1];
1742 std::string varname_u1 = vl[nv];
1743 const model_real_plain_vector &u1 = md.real_variable(varname_u1);
1744 const mesh_fem &mf_u1 = md.mesh_fem_of_variable(varname_u1);
1745 if (two_variables) nv++;
1746 std::string varname_u2 = vl[nv++];
1747 const model_real_plain_vector &u2 = md.real_variable(varname_u2);
1748 const mesh_fem &mf_u2 = md.mesh_fem_of_variable(varname_u2);
1749 const model_real_plain_vector &lambda_n = md.real_variable(vl[nv]);
1750 if (!contact_only) nv++;
1751 const model_real_plain_vector &lambda_t = md.real_variable(vl[nv]);
1756 const model_real_plain_vector &vr = md.real_variable(dl[0]);
1757 GMM_ASSERT1(gmm::vect_size(vr) == 1,
"Parameter r should be a scalar");
1759 if (!contact_only) {
1760 const model_real_plain_vector &vfr = md.real_variable(dl[1]);
1761 GMM_ASSERT1(gmm::vect_size(vfr)==1 || gmm::vect_size(vfr) == nbc,
1762 "Parameter friction_coeff has a wrong size");
1763 gmm::resize(friction_coeff, nbc);
1764 if (gmm::vect_size(vfr) == 1)
1765 gmm::fill(friction_coeff, vfr[0]);
1767 gmm::copy(vfr, friction_coeff);
1771 if ( md.is_var_mf_newer_than_brick(varname_u1, ib)
1772 || md.is_var_mf_newer_than_brick(varname_u2, ib)) {
1775 const mesh_fem &mf_u = i ? mf_u2 : mf_u1;
1777 GMM_ASSERT1(!(mf_u.is_reduced()),
1778 "This contact brick works only for pure Lagrange fems");
1779 dal::bit_vector dofs = mf_u.basic_dof_on_region(region);
1780 for (dal::bv_visitor
id(dofs); !
id.finished(); ++id) {
1781 size_type cv = mf_u.first_convex_of_basic_dof(
id);
1782 GMM_ASSERT1(mf_u.fem_of_element(cv)->is_lagrange(),
1783 "This contact brick works only for pure Lagrange fems");
1787 contact_node_pair_list cnpl;
1788 for (
size_type it = 0; it < rg1.size() && it < rg2.size(); ++it)
1789 cnpl.append_min_dist_cn_pairs
1790 (mf_u1, mf_u2, rg1[it], rg2[it], slave1, slave2);
1796 if (!two_variables) {
1797 compute_contact_matrices(mf_u1, mf_u2, cnpl, gap, &BN1);
1800 compute_contact_matrices(mf_u1, mf_u2, cnpl, gap, &BN1, &BN2);
1805 if (!two_variables) {
1806 compute_contact_matrices(mf_u1, mf_u2, cnpl, gap, &BN1, 0, &BT1);
1811 compute_contact_matrices(mf_u1, mf_u2, cnpl, gap, &BN1, &BN2, &BT1, &BT2);
1816 scalar_type l = scalar_type(0);
1818 const mesh_fem &mf_u = i ? mf_u2 : mf_u1;
1819 base_node Pmin, Pmax;
1820 mf_u.linked_mesh().bounding_box(Pmin, Pmax);
1821 for (
size_type j = 0; j < Pmin.size(); ++j)
1822 l = std::max(l, gmm::abs(Pmax[j] - Pmin[j]));
1826 for (
size_type it = 0; it < rg1.size() && it < rg2.size(); ++it) {
1827 for (
size_type swap = 0; swap <= 1; ++swap) {
1828 if (swap ? slave2 : slave1) {
1829 size_type rg = swap ? rg2[it] : rg1[it];
1830 const mesh_fem &mf_u = swap ? mf_u2 : mf_u1;
1831 const mesh_im &mim = swap ? mim2 : mim1;
1832 CONTACT_B_MATRIX MM(mf_u.nb_dof(), mf_u.nb_dof());
1835 dal::bit_vector rg_dofs = mf_u.basic_dof_on_region(rg);
1836 for (dal::bv_visitor
id(rg_dofs); !
id.finished(); ++id)
1837 if (
id % qdim == 0)
alpha[mult_id++] = MM(
id,
id) / l;
1843 const model_real_plain_vector dummy_wt;
1844 basic_asm_real_tangent_terms
1845 (u1, u2, lambda_n, lambda_t, dummy_wt, dummy_wt, matl, vecl, version);
1849 Coulomb_friction_brick_nonmatching_meshes
1850 (
int aug_version,
bool contact_only_,
bool two_variables_,
1851 const std::vector<size_type> &rg1_,
const std::vector<size_type> &rg2_,
1852 bool slave1_=
true,
bool slave2_=
false)
1853 : Coulomb_friction_brick(aug_version, contact_only_, two_variables_),
1854 rg1(rg1_), rg2(rg2_), slave1(slave1_), slave2(slave2_) {}
1866 const std::string &varname_u1,
const std::string &varname_u2,
1867 std::string &multname_n,
const std::string &dataname_r,
1868 const std::vector<size_type> &rg1,
const std::vector<size_type> &rg2,
1869 bool slave1,
bool slave2,
int aug_version) {
1871 bool two_variables = (varname_u1.compare(varname_u2) != 0);
1873 pbrick pbr = std::make_shared<Coulomb_friction_brick_nonmatching_meshes>
1874 (aug_version,
true, two_variables, rg1, rg2, slave1, slave2);
1880 for (
size_type it = 0; it < rg1.size() && it < rg2.size(); ++it) {
1881 for (
size_type swap = 0; swap <= 1; ++swap) {
1882 if (swap ? slave2 : slave1) {
1883 const mesh_fem &mf = swap ? mf_u2 : mf_u1;
1884 size_type rg = swap ? rg2[it] : rg1[it];
1886 nbc += rg_dofs.card() / mf.
get_qdim();
1891 if (multname_n.size() == 0)
1892 multname_n = md.
new_name(
"contact_multiplier");
1894 GMM_ASSERT1(multname_n.compare(md.
new_name(multname_n)) == 0,
1895 "The given name for the multiplier is already reserved in the model");
1899 tl.push_back(model::term_description(varname_u1, varname_u1,
false));
1900 if (two_variables) {
1901 tl.push_back(model::term_description(varname_u2, varname_u2,
false));
1903 tl.push_back(model::term_description(varname_u1, multname_n,
false));
1904 tl.push_back(model::term_description(multname_n, varname_u1,
false));
1905 if (two_variables) {
1906 tl.push_back(model::term_description(varname_u2, multname_n,
false));
1907 tl.push_back(model::term_description(multname_n, varname_u2,
false));
1909 tl.push_back(model::term_description(multname_n, multname_n,
false));
1912 model::varnamelist vl;
1913 vl.push_back(varname_u1);
1914 if (two_variables) vl.push_back(varname_u2);
1915 vl.push_back(multname_n);
1918 model::varnamelist dl;
1919 dl.push_back(dataname_r);
1922 ml.push_back(&mim1);
1923 ml.push_back(&mim2);
1936 const std::string &varname_u1,
const std::string &varname_u2,
1937 std::string &multname_n, std::string &multname_t,
1938 const std::string &dataname_r,
const std::string &dataname_friction_coeff,
1939 const std::vector<size_type> &rg1,
const std::vector<size_type> &rg2,
1940 bool slave1,
bool slave2,
int aug_version) {
1942 bool two_variables = (varname_u1.compare(varname_u2) != 0);
1944 pbrick pbr = std::make_shared<Coulomb_friction_brick_nonmatching_meshes>
1945 (aug_version,
false, two_variables, rg1, rg2, slave1, slave2);
1951 for (
size_type it = 0; it < rg1.size() && it < rg2.size(); ++it) {
1952 for (
size_type swap = 0; swap <= 1; ++swap) {
1953 if (swap ? slave2 : slave1) {
1954 const mesh_fem &mf = swap ? mf_u2 : mf_u1;
1955 size_type rg = swap ? rg2[it] : rg1[it];
1957 nbc += rg_dofs.card() / mf.
get_qdim();
1962 if (multname_n.size() == 0)
1963 multname_n = md.
new_name(
"contact_normal_multiplier");
1965 GMM_ASSERT1(multname_n.compare(md.
new_name(multname_n)) == 0,
1966 "The given name for the multiplier is already reserved in the model");
1968 if (multname_t.size() == 0)
1969 multname_t = md.
new_name(
"contact_tangent_multiplier");
1971 GMM_ASSERT1(multname_t.compare(md.
new_name(multname_t)) == 0,
1972 "The given name for the multiplier is already reserved in the model");
1976 tl.push_back(model::term_description(varname_u1, varname_u1,
false));
1977 if (two_variables) {
1978 tl.push_back(model::term_description(varname_u2, varname_u2,
false));
1981 tl.push_back(model::term_description(varname_u1, multname_n,
false));
1982 tl.push_back(model::term_description(multname_n, varname_u1,
false));
1983 if (two_variables) {
1984 tl.push_back(model::term_description(varname_u2, multname_n,
false));
1985 tl.push_back(model::term_description(multname_n, varname_u2,
false));
1987 tl.push_back(model::term_description(multname_n, multname_n,
false));
1989 tl.push_back(model::term_description(varname_u1, multname_t,
false));
1990 tl.push_back(model::term_description(multname_t, varname_u1,
false));
1991 if (two_variables) {
1992 tl.push_back(model::term_description(varname_u2, multname_t,
false));
1993 tl.push_back(model::term_description(multname_t, varname_u2,
false));
1995 tl.push_back(model::term_description(multname_t, multname_t,
false));
1996 tl.push_back(model::term_description(multname_t, multname_n,
1997 (aug_version == 4)));
2000 model::varnamelist vl;
2001 vl.push_back(varname_u1);
2002 if (two_variables) vl.push_back(varname_u2);
2003 vl.push_back(multname_n);
2004 vl.push_back(multname_t);
2007 model::varnamelist dl;
2008 dl.push_back(dataname_r);
2009 dl.push_back(dataname_friction_coeff);
2012 ml.push_back(&mim1);
2013 ml.push_back(&mim2);
Simple implementation of a KD-tree.
dref_convex_pt_ct dir_points_of_face(short_type i) const
Direct points for a given face.
does the inversion of the geometric transformation for a given convex
bool invert(const base_node &n, base_node &n_ref, scalar_type IN_EPS=1e-12, bool project_into_element=false)
given the node on the real element, returns the node on the reference element (even if it is outside ...
Balanced tree over a set of points.
void add_point_with_id(const base_node &n, size_type i)
insert a new point, with an associated number.
Describe a finite element method linked to a mesh.
virtual dim_type get_qdim() const
Return the Q dimension.
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.
Describe an integration method linked to a mesh.
`‘Model’' variables store the variables, the data and the description of a model.
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.
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 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.
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.
std::string new_name(const std::string &name)
Gives a non already existing variable name begining by name.
void touch_brick(size_type ib)
Force the re-computation of a brick for the next assembly.
The virtual brick has to be derived to describe real model bricks.
indexed array reference (given a container X, and a set of indexes I, this class provides a pseudo-co...
Miscelleanous assembly routines for common terms. Use the low-level generic assembly....
void mult_add(const L1 &l1, const L2 &l2, L3 &l3)
*/
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 fill(L &l, typename gmm::linalg_traits< L >::value_type x)
*/
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2_sqr(const V &v)
squared Euclidean norm of a vector.
void clear(L &l)
clear (fill with zeros) a vector or matrix.
void resize(V &v, size_type n)
*/
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*/
strongest_value_type< V1, V2 >::value_type vect_sp(const V1 &v1, const V2 &v2)
*/
void add(const L1 &l1, L2 &l2)
*/
linalg_traits< DenseMatrixLU >::value_type lu_det(const DenseMatrixLU &LU, const Pvector &pvector)
Compute the matrix determinant (via a LU factorization)
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)
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
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
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 .
GEneric Tool for Finite Element Methods.
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.
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.
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.
void contact_brick_set_stationary(model &md, size_type indbrick)
Can be used to set the stationary option.
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.
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.
std::shared_ptr< const virtual_brick > pbrick
type of pointer on a brick
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_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.
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.
store a point and the associated index for the kdtree.