30 bool boundary_has_fem_nodes(
bool slave_flag,
int nodes_mode) {
31 return (slave_flag && nodes_mode) ||
32 (!slave_flag && nodes_mode == 2);
37 const model_real_plain_vector &coeff,
38 base_node &n0, base_node &n,
41 if (in_reference_conf) {
44 ctx.pf()->interpolation_grad(ctx, coeff, grad, dim_type(ctx.N()));
45 gmm::add(gmm::identity_matrix(), grad);
46 scalar_type J = bgeot::lu_inverse(&(*(grad.begin())), ctx.N());
47 if (J <= scalar_type(0)) {GMM_WARNING1(
"Inverted element !" << J);
49 gmm::scale(n, gmm::sgn(J));
55 gmm::scale(n, gmm::sgn(J));}
67 (
const model_real_plain_vector *U,
const std::string &name,
68 const model_real_plain_vector *w,
const std::string &wname) {
71 for (; i < Us.size(); ++i)
if (Us[i] == U)
return i;
74 Unames.push_back(name);
75 Wnames.push_back(wname);
76 ext_Us.resize(Us.size());
77 ext_Ws.resize(Us.size());
82 (
const model_real_plain_vector *lambda,
const std::string &name) {
85 for (; i < lambdas.size(); ++i)
if (lambdas[i] == lambda)
return i;
86 lambdas.push_back(lambda);
87 lambdanames.push_back(name);
88 ext_lambdas.resize(lambdas.size());
92 void multi_contact_frame::extend_vectors() {
93 dal::bit_vector iU, ilambda;
94 for (
size_type i = 0; i < contact_boundaries.size(); ++i) {
95 size_type ind_U = contact_boundaries[i].ind_U;
97 const mesh_fem &mf = *(contact_boundaries[i].mfu);
99 mf.extend_vector(*(Us[ind_U]), ext_Us[ind_U]);
102 mf.extend_vector(*(Ws[ind_U]), ext_Ws[ind_U]);
106 size_type ind_lambda = contact_boundaries[i].ind_lambda;
107 if (ind_lambda !=
size_type(-1) && !(ilambda[ind_lambda])) {
108 const mesh_fem &mf = *(contact_boundaries[i].mflambda);
109 gmm::resize(ext_lambdas[ind_lambda], mf.nb_basic_dof());
110 mf.extend_vector(*(lambdas[ind_lambda]), ext_lambdas[ind_lambda]);
111 ilambda.add(ind_lambda);
116 void multi_contact_frame::normal_cone_simplification() {
118 scalar_type threshold = ::cos(cut_angle);
119 for (
size_type i = 0; i < boundary_points_info.size(); ++i) {
120 normal_cone &nc = boundary_points_info[i].normals;
122 base_small_vector n_mean = nc[0];
123 for (
size_type j = 1; j < nc.size(); ++j) n_mean += nc[j];
125 GMM_ASSERT1(nn_mean != scalar_type(0),
"oupssss");
126 if (nn_mean != scalar_type(0)) {
127 gmm::scale(n_mean, scalar_type(1)/nn_mean);
129 for (
size_type j = 0; j < nc.size(); ++j)
130 if (gmm::vect_sp(n_mean, nc[j]) < threshold)
131 { reduce =
false;
break; }
133 boundary_points_info[i].normals = normal_cone(n_mean);
141 bool multi_contact_frame::test_normal_cones_compatibility
142 (
const normal_cone &nc1,
const normal_cone &nc2) {
143 for (
size_type i = 0; i < nc1.size(); ++i)
144 for (
size_type j = 0; j < nc2.size(); ++j)
145 if (gmm::vect_sp(nc1[i], nc2[j]) < scalar_type(0))
150 bool multi_contact_frame::test_normal_cones_compatibility
151 (
const base_small_vector &n,
const normal_cone &nc2) {
152 for (
size_type j = 0; j < nc2.size(); ++j)
153 if (gmm::vect_sp(n, nc2[j]) < scalar_type(0))
160 const mesh_fem &mf1 = mfdisp_of_boundary(ib1);
161 const mesh_fem &mf2 = mfdisp_of_boundary(ib2);
162 if ( &(mf1.linked_mesh()) != &(mf2.linked_mesh()))
return false;
163 GMM_ASSERT1(!(mf1.is_reduced()) && !(mf2.is_reduced()),
164 "Nodal strategy can only be applied for non reduced fems");
165 const mesh::ind_cv_ct &ic1 = mf1.convex_to_basic_dof(idof1);
166 const mesh::ind_cv_ct &ic2 = mf2.convex_to_basic_dof(idof2);
168 for (
size_type i = 0; i < ic1.size(); ++i) aux_dof_cv.add(ic1[i]);
169 for (
size_type i = 0; i < ic2.size(); ++i)
170 if (aux_dof_cv.is_in(ic2[i])) { lk =
true;
break; }
171 for (
size_type i = 0; i < ic1.size(); ++i) aux_dof_cv.sup(ic1[i]);
177 const mesh_fem &mf1 = mfdisp_of_boundary(ib1);
178 const mesh_fem &mf2 = mfdisp_of_boundary(ib2);
179 if ( &(mf1.linked_mesh()) != &(mf2.linked_mesh()))
return false;
180 GMM_ASSERT1(!(mf1.is_reduced()) && !(mf2.is_reduced()),
181 "Nodal strategy can only be applied for non reduced fems");
182 const mesh::ind_cv_ct &ic1 = mf1.convex_to_basic_dof(idof1);
183 for (
size_type i = 0; i < ic1.size(); ++i)
184 if (cv == ic1[i])
return true;
188 void multi_contact_frame::add_potential_contact_face
191 std::vector<face_info> &sfi = potential_pairs[ip];
192 for (
size_type k = 0; k < sfi.size(); ++k)
193 if (sfi[k].ind_boundary == ib &&
194 sfi[k].ind_element == ie &&
195 sfi[k].ind_face == iff) found =
true;
197 if (!found) sfi.push_back(face_info(ib, ie, iff));
200 void multi_contact_frame::clear_aux_info() {
201 boundary_points = std::vector<base_node>();
202 boundary_points_info = std::vector<boundary_point>();
203 element_boxes.clear();
204 element_boxes_info = std::vector<influence_box>();
205 potential_pairs = std::vector<std::vector<face_info> >();
208 multi_contact_frame::multi_contact_frame(
size_type NN, scalar_type r_dist,
209 bool dela,
bool selfc,
211 bool rayt,
int nmode,
bool refc)
212 : N(NN), self_contact(selfc), ref_conf(refc), use_delaunay(dela),
213 nodes_mode(nmode), raytrace(rayt), release_distance(r_dist),
214 cut_angle(cut_a), EPS(1E-8), md(0), coordinates(N), pt(N) {
215 if (N > 0) coordinates[0] =
"x";
216 if (N > 1) coordinates[1] =
"y";
217 if (N > 2) coordinates[2] =
"z";
218 if (N > 3) coordinates[3] =
"w";
219 GMM_ASSERT1(N <= 4,
"Complete the definition for contact in "
220 "dimension greater than 4");
223 multi_contact_frame::multi_contact_frame(
const model &mdd,
size_type NN,
225 bool dela,
bool selfc,
227 bool rayt,
int nmode,
bool refc)
228 : N(NN), self_contact(selfc), ref_conf(refc),
229 use_delaunay(dela), nodes_mode(nmode), raytrace(rayt),
230 release_distance(r_dist), cut_angle(cut_a), EPS(1E-8), md(&mdd),
231 coordinates(N), pt(N) {
232 if (N > 0) coordinates[0] =
"x";
233 if (N > 1) coordinates[1] =
"y";
234 if (N > 2) coordinates[2] =
"z";
235 if (N > 3) coordinates[3] =
"w";
236 GMM_ASSERT1(N <= 4,
"Complete the definition for contact in "
237 "dimension greater than 4");
240 size_type multi_contact_frame::add_obstacle(
const std::string &obs) {
242 obstacles.push_back(obs);
243 obstacles_velocities.push_back(
"");
244 obstacles_gw.push_back(ga_workspace());
245 pt.resize(N); ptx.resize(1); pty.resize(1); ptz.resize(1); ptw.resize(1);
246 obstacles_gw.back().add_fixed_size_constant(
"X", pt);
247 if (N >= 4) obstacles_gw.back().add_fixed_size_constant(
"w", ptw);
248 if (N >= 3) obstacles_gw.back().add_fixed_size_constant(
"z", ptz);
249 if (N >= 2) obstacles_gw.back().add_fixed_size_constant(
"y", pty);
250 if (N >= 1) obstacles_gw.back().add_fixed_size_constant(
"x", ptx);
251 obstacles_f.push_back(ga_function(obstacles_gw.back(), obs));
252 obstacles_f.back().compile();
258 size_type multi_contact_frame::add_master_boundary
259 (
const mesh_im &mim,
const mesh_fem *mfu,
260 const model_real_plain_vector *U,
size_type reg,
261 const mesh_fem *mflambda,
const model_real_plain_vector *lambda,
262 const model_real_plain_vector *w,
263 const std::string &vvarname,
264 const std::string &mmultname,
const std::string &wname) {
265 GMM_ASSERT1(mfu->linked_mesh().dim() == N,
266 "Mesh dimension is " << mfu->linked_mesh().dim()
267 <<
"should be " << N <<
".");
268 GMM_ASSERT1(&(mfu->linked_mesh()) == &(mim.linked_mesh()),
269 "Integration and finite element are not on the same mesh !");
271 GMM_ASSERT1(&(mflambda->linked_mesh()) == &(mim.linked_mesh()),
272 "Integration and finite element are not on the same mesh !");
273 contact_boundary cb(reg, mfu, mim, add_U(U, vvarname, w, wname),
274 mflambda, add_lambda(lambda, mmultname));
275 contact_boundaries.push_back(cb);
276 return size_type(contact_boundaries.size() - 1);
279 size_type multi_contact_frame::add_slave_boundary
280 (
const mesh_im &mim,
const mesh_fem *mfu,
281 const model_real_plain_vector *U,
size_type reg,
282 const mesh_fem *mflambda,
const model_real_plain_vector *lambda,
283 const model_real_plain_vector *w,
284 const std::string &vvarname,
285 const std::string &mmultname,
const std::string &wname) {
287 = add_master_boundary(mim, mfu, U, reg, mflambda, lambda, w,
288 vvarname, mmultname, wname);
289 contact_boundaries[ind].slave =
true;
294 size_type multi_contact_frame::add_master_boundary
295 (
const mesh_im &mim,
size_type reg,
const std::string &vvarname,
296 const std::string &mmultname,
const std::string &wname) {
297 GMM_ASSERT1(md,
"This multi contact frame object is not linked "
299 const mesh_fem *mfl(0);
300 const model_real_plain_vector *l(0);
301 if (mmultname.size()) {
302 mfl = &(md->mesh_fem_of_variable(mmultname));
303 l = &(md->real_variable(mmultname));
305 const model_real_plain_vector *w(0);
306 if (wname.compare(vvarname) == 0) {
307 GMM_ASSERT1(md->n_iter_of_variable(vvarname) > 1,
"More than one "
308 "versions of the displacement variable were expected here");
309 w = &(md->real_variable(vvarname,1));
311 else if (wname.size()) {
312 GMM_ASSERT1(&(md->mesh_fem_of_variable(wname))
313 == &(md->mesh_fem_of_variable(vvarname)),
"The previous "
314 "displacement should be defined on the same mesh_fem as the "
316 w = &(md->real_variable(wname));
318 return add_master_boundary(mim, &(md->mesh_fem_of_variable(vvarname)),
319 &(md->real_variable(vvarname)), reg, mfl, l, w,
320 vvarname, mmultname, wname);
323 size_type multi_contact_frame::add_slave_boundary
324 (
const mesh_im &mim,
size_type reg,
const std::string &vvarname,
325 const std::string &mmultname,
const std::string &wname) {
326 GMM_ASSERT1(md,
"This multi contact frame object is not linked "
328 const mesh_fem *mfl(0);
329 const model_real_plain_vector *l(0);
330 if (mmultname.size()) {
331 mfl = &(md->mesh_fem_of_variable(mmultname));
332 l = &(md->real_variable(mmultname));
334 const model_real_plain_vector *w(0);
335 if (wname.compare(vvarname) == 0) {
336 GMM_ASSERT1(md->n_iter_of_variable(vvarname) > 1,
"More than one "
337 "versions of the displacement variable were expected here");
338 w = &(md->real_variable(vvarname,1));
340 else if (wname.size()) {
341 GMM_ASSERT1(&(md->mesh_fem_of_variable(wname))
342 == &(md->mesh_fem_of_variable(vvarname)),
"The previous "
343 "displacement should be defined on the same mesh_fem as the "
345 w = &(md->real_variable(wname));
347 return add_slave_boundary(mim, &(md->mesh_fem_of_variable(vvarname)),
348 &(md->real_variable(vvarname)), reg, mfl, l, w,
349 vvarname, mmultname, wname);
353 void multi_contact_frame::compute_boundary_points(
bool slave_only) {
354 fem_precomp_pool fppool;
356 model_real_plain_vector coeff;
358 for (
size_type i = 0; i < contact_boundaries.size(); ++i)
359 if (!slave_only || is_slave_boundary(i)) {
361 const mesh_fem &mfu = mfdisp_of_boundary(i);
362 const mesh_im &mim = mim_of_boundary(i);
363 const model_real_plain_vector &U = disp_of_boundary(i);
364 const mesh &m = mfu.linked_mesh();
366 boundary_has_fem_nodes(is_slave_boundary(i), nodes_mode);
368 base_node val(N), bmin(N), bmax(N);
369 base_small_vector n0(N), n(N), n_mean(N);
370 base_matrix grad(N,N);
371 mesh_region region = m.region(bnum);
372 GMM_ASSERT1(mfu.get_qdim() == N,
"Wrong mesh_fem qdim");
375 dal::bit_vector dof_already_interpolated;
376 std::vector<size_type> dof_ind(mfu.nb_basic_dof());
380 pfem pf_s = mfu.fem_of_element(cv);
384 mfu.linked_mesh().points_of_convex(cv, G);
388 std::vector<size_type> indpt, indpfp;
390 dim_type qqdim = mfu.get_qdim() / pf_s->target_dim();
391 pfp = fppool(pf_s, pf_s->node_tab(cv));
392 nbptf = pf_s->node_convex(cv).structure()->nb_points_of_face(v.f());
393 indpt.resize(nbptf); indpfp.resize(nbptf);
396 mfu.ind_basic_dof_of_face_of_element(cv,v.f())[ip*qqdim];
398 pf_s->node_convex(cv).structure()->ind_points_of_face(v.f())[ip];
402 pintegration_method pim = mim.int_method_of_element(cv);
403 GMM_ASSERT1(pim,
"Integration method should be defined");
404 pfp = fppool(pf_s, pim->approx_method()->pintegration_points());
405 nbptf = pim->approx_method()->nb_points_on_face(v.f());
406 indpt.resize(nbptf); indpfp.resize(nbptf);
408 indpt[ip] = indpfp[ip] =
409 pim->approx_method()->ind_first_point_on_face(v.f())+ip;
411 fem_interpolation_context ctx(pgt,pfp,
size_type(-1),G,cv,v.f());
414 ctx.set_ii(indpfp[ip]);
417 if (!(on_fem_nodes && dof_already_interpolated[ind])) {
419 pf_s->interpolation(ctx, coeff, val, dim_type(N));
424 if (on_fem_nodes) dof_ind[ind] = boundary_points.size();
432 if (on_fem_nodes && dof_already_interpolated[ind]) {
433 boundary_points_info[dof_ind[ind]].normals.add_normal(n);
435 boundary_points.push_back(val);
436 boundary_points_info.push_back(boundary_point(ctx.xreal(), i, cv,
440 if (on_fem_nodes) dof_already_interpolated.add(ind);
446 void multi_contact_frame::compute_potential_contact_pairs_delaunay() {
448 compute_boundary_points();
449 normal_cone_simplification();
450 potential_pairs = std::vector<std::vector<face_info> >();
451 potential_pairs.resize(boundary_points.size());
453 gmm::dense_matrix<size_type> simplexes;
454 base_small_vector rr(N);
460 bgeot::qhull_delaunay(boundary_points, simplexes);
463 for (
size_type is = 0; is < gmm::mat_ncols(simplexes); ++is) {
467 size_type ipt1 = simplexes(i, is), ipt2 = simplexes(j, is);
468 boundary_point *pt_info1 = &(boundary_points_info[ipt1]);
469 boundary_point *pt_info2 = &(boundary_points_info[ipt2]);
472 bool sl1 = is_slave_boundary(ib1);
473 bool sl2 = is_slave_boundary(ib2);
475 std::swap(ipt1, ipt2);
476 std::swap(pt_info1, pt_info2);
482 const mesh_fem &mf1 = mfdisp_of_boundary(ib1);
483 const mesh_fem &mf2 = mfdisp_of_boundary(ib2);
491 || (self_contact && !sl1 && !sl2))
493 && test_normal_cones_compatibility(pt_info1->normals,
499 && (( &(mf1.linked_mesh()) != &(mf2.linked_mesh()))
500 || (pt_info1->ind_element != pt_info2->ind_element)))
501 || ((nodes_mode == 2)
502 && !(are_dof_linked(ib1, pt_info1->ind_pt,
503 ib2, pt_info2->ind_pt)))
509 if (boundary_has_fem_nodes(sl2, nodes_mode)) {
510 const mesh::ind_cv_ct &ic2
511 = mf2.convex_to_basic_dof(pt_info2->ind_pt);
512 for (
size_type k = 0; k < ic2.size(); ++k) {
513 mesh_region::face_bitset fbs
514 = mf2.linked_mesh().region(ir2).faces_of_convex(ic2[k]);
515 short_type nbf = mf2.linked_mesh().nb_faces_of_convex(ic2[k]);
518 add_potential_contact_face(ipt1,
519 pt_info2->ind_boundary,
523 add_potential_contact_face(ipt1, pt_info2->ind_boundary,
524 pt_info2->ind_element,
527 if (self_contact && !sl1 && !sl2) {
528 if (boundary_has_fem_nodes(sl2, nodes_mode)) {
529 const mesh::ind_cv_ct &ic1
530 = mf1.convex_to_basic_dof(pt_info1->ind_pt);
531 for (
size_type k = 0; k < ic1.size(); ++k) {
532 mesh_region::face_bitset fbs
533 = mf1.linked_mesh().region(ir1).faces_of_convex(ic1[k]);
534 short_type nbf = mf1.linked_mesh().nb_faces_of_convex(ic1[k]);
537 add_potential_contact_face(ipt2,
538 pt_info1->ind_boundary,
542 add_potential_contact_face(ipt2, pt_info1->ind_boundary,
543 pt_info1->ind_element,
554 void multi_contact_frame::compute_influence_boxes() {
555 fem_precomp_pool fppool;
558 model_real_plain_vector coeff;
560 for (
size_type i = 0; i < contact_boundaries.size(); ++i)
561 if (!is_slave_boundary(i)) {
563 const mesh_fem &mfu = mfdisp_of_boundary(i);
564 const model_real_plain_vector &U = disp_of_boundary(i);
565 const mesh &m = mfu.linked_mesh();
567 base_node val(N), bmin(N), bmax(N);
568 base_small_vector n0(N), n(N), n_mean(N);
569 base_matrix grad(N,N);
570 mesh_region region = m.region(bnum);
571 GMM_ASSERT1(mfu.get_qdim() == N,
"Wrong mesh_fem qdim");
573 dal::bit_vector points_already_interpolated;
574 std::vector<base_node> transformed_points(m.nb_max_points());
578 pfem pf_s = mfu.fem_of_element(cv);
579 pfem_precomp pfp = fppool(pf_s, pgt->pgeometric_nodes());
582 mfu.linked_mesh().points_of_convex(cv, G);
583 fem_interpolation_context ctx(pgt,pfp,
size_type(-1), G, cv);
586 dal::bit_vector points_on_face;
588 for (
size_type k = 0; k < cvs->nb_points_of_face(v.f()); ++k)
589 points_on_face.add(cvs->ind_points_of_face(v.f())[k]);
594 size_type ind = m.ind_points_of_convex(cv)[ip];
598 if (!(points_already_interpolated.is_in(ind))) {
600 pf_s->interpolation(ctx, coeff, val, dim_type(N));
602 transformed_points[ind] = val;
604 transformed_points[ind] = ctx.xreal();
606 points_already_interpolated.add(ind);
608 val = transformed_points[ind];
611 if (points_on_face[ip]) {
622 bmin[k] = std::min(bmin[k], val[k]);
623 bmax[k] = std::max(bmax[k], val[k]);
630 GMM_ASSERT1(nb_pt_on_face,
631 "This element has no vertex on considered face !");
635 scalar_type h = bmax[0] - bmin[0];
636 for (
size_type k = 1; k < N; ++k) h = std::max(h, bmax[k]-bmin[k]);
637 if (h < release_distance/scalar_type(40) && !avert) {
638 GMM_WARNING1(
"Found an element whose size is smaller than 1/40 "
639 "of the release distance. You should probably "
640 "adapt the release distance.");
644 { bmin[k] -= release_distance; bmax[k] += release_distance; }
647 element_boxes.add_box(bmin, bmax, element_boxes_info.size());
649 element_boxes_info.push_back(influence_box(i, cv, v.f(), n_mean));
652 element_boxes.build_tree();
655 void multi_contact_frame::compute_potential_contact_pairs_influence_boxes() {
656 compute_influence_boxes();
657 compute_boundary_points(!self_contact);
658 normal_cone_simplification();
659 potential_pairs = std::vector<std::vector<face_info> >();
660 potential_pairs.resize(boundary_points.size());
662 for (
size_type ip = 0; ip < boundary_points.size(); ++ip) {
664 bgeot::rtree::pbox_set bset;
665 element_boxes.find_boxes_at_point(boundary_points[ip], bset);
666 boundary_point *pt_info = &(boundary_points_info[ip]);
667 const mesh_fem &mf1 = mfdisp_of_boundary(pt_info->ind_boundary);
670 bgeot::rtree::pbox_set::iterator it = bset.begin();
671 for (; it != bset.end(); ++it) {
672 influence_box &ibx = element_boxes_info[(*it)->id];
674 const mesh_fem &mf2 = mfdisp_of_boundary(ib2);
679 test_normal_cones_compatibility(ibx.mean_normal,
683 && (((nodes_mode < 2)
684 && (( &(mf1.linked_mesh()) != &(mf2.linked_mesh()))
685 || (pt_info->ind_element != ibx.ind_element)))
686 || ((nodes_mode == 2)
687 && !(is_dof_linked(ib1, pt_info->ind_pt,
688 ibx.ind_boundary, ibx.ind_element)))
692 add_potential_contact_face(ip, ibx.ind_boundary, ibx.ind_element,
700 struct proj_pt_surf_cost_function_object {
703 const base_node &x0, &x;
704 fem_interpolation_context &ctx;
705 const model_real_plain_vector &coeff;
706 const std::vector<base_small_vector> &ti;
708 mutable base_node dxy;
709 mutable base_matrix grad, gradtot;
711 scalar_type operator()(
const base_small_vector& a)
const {
713 for (
size_type i= 0; i < N-1; ++i) xx += a[i] * ti[i];
716 ctx.pf()->interpolation(ctx, coeff, dxy, dim_type(N));
717 dxy += ctx.xreal() - x;
719 dxy = ctx.xreal() - x;
723 scalar_type operator()(
const base_small_vector& a,
724 base_small_vector &grada)
const {
726 for (
size_type i = 0; i < N-1; ++i) xx += a[i] * ti[i];
729 ctx.pf()->interpolation(ctx, coeff, dxy, dim_type(N));
730 dxy += ctx.xreal() - x;
731 ctx.pf()->interpolation_grad(ctx, coeff, grad, dim_type(N));
732 gmm::add(gmm::identity_matrix(), grad);
735 dxy = ctx.xreal() - x;
739 grada[i] = gmm::vect_sp(gradtot, ti[i], dxy);
742 void operator()(
const base_small_vector& a,
743 base_matrix &hessa)
const {
744 base_small_vector b = a;
745 base_small_vector grada(N-1), gradb(N-1);
751 hessa(j, i) = (gradb[j] - grada[j])/EPS;
756 proj_pt_surf_cost_function_object
757 (
const base_node &x00,
const base_node &xx,
758 fem_interpolation_context &ctxx,
759 const model_real_plain_vector &coefff,
760 const std::vector<base_small_vector> &tii,
761 scalar_type EPSS,
bool rc)
762 : N(gmm::vect_size(x00)), EPS(EPSS), x0(x00), x(xx),
763 ctx(ctxx), coeff(coefff), ti(tii), ref_conf(rc),
764 dxy(N), grad(N,N), gradtot(N,N) {}
768 struct raytrace_pt_surf_cost_function_object {
770 const base_node &x0, &x;
771 fem_interpolation_context &ctx;
772 const model_real_plain_vector &coeff;
773 const std::vector<base_small_vector> &ti;
774 const std::vector<base_small_vector> &Ti;
776 mutable base_node dxy;
777 mutable base_matrix grad, gradtot;
779 void operator()(
const base_small_vector& a,
780 base_small_vector &res)
const {
782 for (
size_type i = 0; i < N-1; ++i) xx += a[i] * ti[i];
785 ctx.pf()->interpolation(ctx, coeff, dxy, dim_type(N));
786 dxy += ctx.xreal() - x;
788 dxy = ctx.xreal() - x;
790 res[i] = gmm::vect_sp(dxy, Ti[i]);
793 void operator()(
const base_small_vector& a,
794 base_matrix &hessa)
const {
796 for (
size_type i = 0; i < N-1; ++i) xx += a[i] * ti[i];
799 ctx.pf()->interpolation_grad(ctx, coeff, grad, dim_type(N));
800 gmm::add(gmm::identity_matrix(), grad);
811 raytrace_pt_surf_cost_function_object
812 (
const base_node &x00,
const base_node &xx,
813 fem_interpolation_context &ctxx,
814 const model_real_plain_vector &coefff,
815 const std::vector<base_small_vector> &tii,
816 const std::vector<base_small_vector> &Tii,
818 : N(gmm::vect_size(x00)), x0(x00), x(xx),
819 ctx(ctxx), coeff(coefff), ti(tii), Ti(Tii), ref_conf(rc),
820 dxy(N), grad(N,N), gradtot(N,N) {}
833 void multi_contact_frame::compute_contact_pairs() {
834 base_matrix G, grad(N,N);
835 model_real_plain_vector coeff;
836 base_small_vector a(N-1), ny(N);
838 std::vector<base_small_vector> ti(N-1), Ti(N-1);
844 contact_pairs = std::vector<contact_pair>();
846 if (!ref_conf) extend_vectors();
848 bool only_slave(
true), only_master(
true);
849 for (
size_type i = 0; i < contact_boundaries.size(); ++i)
850 if (is_slave_boundary(i)) only_master =
false;
851 else only_slave =
false;
853 if (only_master && !self_contact) {
854 GMM_WARNING1(
"There is only master boundary and no self-contact to detect. Exiting");
859 compute_boundary_points();
860 potential_pairs.resize(boundary_points.size());
862 else if (use_delaunay)
863 compute_potential_contact_pairs_delaunay();
865 compute_potential_contact_pairs_influence_boxes();
871 for (
size_type ip = 0; ip < potential_pairs.size(); ++ip) {
872 bool first_pair_found =
false;
873 const base_node &x = boundary_points[ip];
874 boundary_point &bpinfo = boundary_points_info[ip];
876 bool slx = is_slave_boundary(ibx);
877 scalar_type d0 = 1E300, d1, d2;
879 base_small_vector nx = bpinfo.normals[0];
881 if (bpinfo.normals.size() > 1) {
882 for (
size_type i = 1; i < bpinfo.normals.size(); ++i)
883 gmm::add(bpinfo.normals[i], nx);
885 GMM_ASSERT1(nnx != scalar_type(0),
"Invalid normal cone");
886 gmm::scale(nx, scalar_type(1)/nnx);
890 if (self_contact || slx) {
895 if (N >= 4) ptw[0] = pt[3];
896 if (N >= 3) ptz[0] = pt[2];
897 if (N >= 2) pty[0] = pt[1];
898 if (N >= 1) ptx[0] = pt[0];
899 for (
size_type i = 0; i < obstacles.size(); ++i) {
900 d1 = (obstacles_f[i].eval())[0];
901 if (gmm::abs(d1) < release_distance && d1 < d0) {
903 for (
size_type j=0; j < bpinfo.normals.size(); ++j) {
904 gmm::add(gmm::scaled(bpinfo.normals[j], EPS), pt);
905 if (N >= 4) ptw[0] = pt[3];
906 if (N >= 3) ptz[0] = pt[2];
907 if (N >= 2) pty[0] = pt[1];
908 if (N >= 1) ptx[0] = pt[0];
909 d2 = (obstacles_f[i].eval())[0];
910 if (d2 < d1) { d0 = d1; irigid_obstacle = i;
break; }
912 if (N >= 4) ptw[0] = pt[3];
913 if (N >= 3) ptz[0] = pt[2];
914 if (N >= 2) pty[0] = pt[1];
915 if (N >= 1) ptx[0] = pt[0];
923 if (N >= 4) ptw[0] = pt[3];
924 if (N >= 3) ptz[0] = pt[2];
925 if (N >= 2) pty[0] = pt[1];
926 if (N >= 1) ptx[0] = pt[0];
929 scalar_type
alpha(0), beta(0);
932 while (++nit < 50 && nb_fail < 3) {
936 case 4: ptw[0] += EPS;
break;
937 case 3: ptz[0] += EPS;
break;
938 case 2: pty[0] += EPS;
break;
939 case 1: ptx[0] += EPS;
break;
941 d2 = (obstacles_f[irigid_obstacle].eval())[0];
942 ny[k] = (d2 - d1) / EPS;
945 case 4: ptw[0] -= EPS;
break;
946 case 3: ptz[0] -= EPS;
break;
947 case 2: pty[0] -= EPS;
break;
948 case 1: ptx[0] -= EPS;
break;
952 if (gmm::abs(d1) < 1E-13)
956 for (scalar_type lambda(1); lambda >= 1E-3; lambda /= scalar_type(2)) {
959 gmm::add(x, gmm::scaled(nx, alpha), pt);
961 gmm::add(gmm::scaled(ny, -d1/gmm::vect_norm2_sqr(ny)), y, pt);
963 if (N >= 4) ptw[0] = pt[3];
964 if (N >= 3) ptz[0] = pt[2];
965 if (N >= 2) pty[0] = pt[1];
966 if (N >= 1) ptx[0] = pt[0];
967 d2 = (obstacles_f[irigid_obstacle].eval())[0];
972 if (gmm::abs(d2) < gmm::abs(d1))
break;
975 gmm::abs(beta - d1 / gmm::vect_sp(ny, nx)) > scalar_type(500))
980 if (gmm::abs(d1) > 1E-8) {
981 GMM_WARNING1(
"Projection/raytrace on rigid obstacle failed");
986 if (gmm::vect_dist2(y, x) > release_distance)
993 contact_pair ct(x, nx, bpinfo, y, ny, irigid_obstacle, d0);
995 contact_pairs.push_back(ct);
996 first_pair_found =
true;
1002 for (
size_type ipf = 0; ipf < potential_pairs[ip].size(); ++ipf) {
1021 const face_info &fi = potential_pairs[ip][ipf];
1026 const mesh_fem &mfu = mfdisp_of_boundary(ib);
1027 const mesh &m = mfu.linked_mesh();
1028 pfem pf_s = mfu.fem_of_element(cv);
1034 m.points_of_convex(cv, G);
1036 const auto face_pts = pf_s->ref_convex(cv)->points_of_face(iff);
1037 const base_node &x0 = face_pts[0];
1038 fem_interpolation_context ctx(pgt, pf_s, x0, G, cv, iff);
1040 const base_small_vector &n0 = pf_s->ref_convex(cv)->normals()[iff];
1043 scalar_type norm(0);
1044 while(norm < 1E-5) {
1048 ti[k] -= gmm::vect_sp(ti[k], ti[l]) * ti[l];
1054 bool converged =
false;
1055 scalar_type residual(0);
1060 base_small_vector res(N-1), res2(N-1), dir(N-1), b(N-1);
1062 base_matrix hessa(N-1, N-1);
1067 scalar_type norm(0);
1068 while (norm < 1E-5) {
1072 Ti[k] -= gmm::vect_sp(Ti[k], Ti[l]) * Ti[l];
1078 raytrace_pt_surf_cost_function_object pps(x0, x, ctx, coeff, ti, Ti,
1083 scalar_type residual2(0), det(0);
1084 bool exited =
false;
1086 for (;residual > 2E-12 && niter <= 30; ++niter) {
1090 det = gmm::abs(bgeot::lu_inverse(&(*(hessa.begin())),N-1,
false));
1091 if (det > 1E-15)
break;
1093 a[i] += gmm::random() * 1E-7;
1094 if (++subiter > 4)
break;
1096 if (det <= 1E-15)
break;
1098 gmm::mult(hessa, gmm::scaled(res, scalar_type(-1)), dir);
1100 if (gmm::vect_norm2(dir) > scalar_type(10)) nbfail++;
1101 if (nbfail >= 4)
break;
1104 scalar_type lambda(1);
1106 gmm::add(a, gmm::scaled(dir, lambda), b);
1109 if (residual2 < residual)
break;
1110 lambda /= ((j < 3) ? scalar_type(2) : scalar_type(5));
1113 residual = residual2;
1120 if (niter > 1 && dist_ref > 15)
break;
1121 if (niter > 5 && dist_ref > 8)
break;
1122 if ((niter > 1 && dist_ref > 7) || nbfail == 3) exited =
true;
1125 GMM_ASSERT1(!((exited && converged &&
1126 pf_s->ref_convex(cv)->is_in(ctx.xref()) < 1E-6)),
1127 "A non conformal case !! " << gmm::vect_norm2(res)
1128 <<
" : " << nbfail <<
" : " << niter);
1132 proj_pt_surf_cost_function_object pps(x0, x, ctx, coeff, ti,
1139 base_small_vector grada(N-1), dir(N-1), b(N-1);
1141 base_matrix hessa(N-1, N-1);
1144 scalar_type dist = pps(a, grada);
1150 det = gmm::abs(bgeot::lu_inverse(&(*(hessa.begin())),N-1,
false));
1151 if (det > 1E-15)
break;
1153 a[i] += gmm::random() * 1E-7;
1154 if (++subiter > 4)
break;
1156 if (det <= 1E-15)
break;
1158 gmm::mult(hessa, gmm::scaled(grada, scalar_type(-1)), dir);
1161 for (scalar_type lambda(1);
1162 lambda >= 1E-3; lambda /= scalar_type(2)) {
1163 gmm::add(a, gmm::scaled(dir, lambda), b);
1164 if (pps(b) < dist)
break;
1165 gmm::add(a, gmm::scaled(dir, -lambda), b);
1166 if (pps(b) < dist)
break;
1169 dist = pps(a, grada);
1177 gmm::bfgs(pps, pps, a, 10, iter, 0, 0.5);
1178 residual = gmm::abs(iter.get_res());
1179 converged = (residual < 2E-5);
1183 bool is_in = (pf_s->ref_convex(cv)->is_in(ctx.xref()) < 1E-6);
1185 if (is_in || (!converged && !raytrace)) {
1187 ctx.pf()->interpolation(ctx, coeff, y, dim_type(N));
1197 if (!raytrace && nbwarn < 4) {
1198 GMM_WARNING3(
"Projection or raytrace algorithm did not converge "
1199 "for point " << x <<
" residual " << residual
1200 <<
" projection computed " << y);
1216 if (!is_in)
continue;
1220 if (signed_dist > release_distance)
continue;
1223 base_small_vector ny0(N);
1226 signed_dist *= gmm::sgn(gmm::vect_sp(x - y, ny));
1230 if (first_pair_found && contact_pairs.back().signed_dist < signed_dist)
1234 if (!(test_normal_cones_compatibility(ny, bpinfo.normals)))
1239 if (&m == &(mfdisp_of_boundary(ibx).linked_mesh())) {
1241 base_small_vector diff = bpinfo.ref_point - ctx.xreal();
1244 if ( (ref_dist < scalar_type(4) * release_distance)
1245 && (gmm::vect_sp(diff, ny0) < - 0.01 * ref_dist) )
1249 contact_pair ct(x, nx, bpinfo, ctx.xref(), y, ny, fi, signed_dist);
1250 if (first_pair_found) {
1251 contact_pairs.back() = ct;
1253 contact_pairs.push_back(ct);
1254 first_pair_found =
true;
1271 class raytracing_interpolate_transformation
1272 :
public virtual_interpolate_transformation {
1275 struct contact_boundary {
1278 std::string dispname;
1279 mutable const model_real_plain_vector *U;
1280 mutable model_real_plain_vector U_unred;
1284 : region(-1), mfu(0), dispname(
""), U(0), U_unred(0), slave(false) {}
1285 contact_boundary(
size_type r,
const mesh_fem *mf,
const std::string &dn,
1287 : region(r), mfu(mf), dispname(dn), slave(sl) {}
1290 struct face_box_info {
1294 base_small_vector mean_normal;
1296 : ind_boundary(-1), ind_element(-1), ind_face(-1), mean_normal(0) {}
1299 : ind_boundary(ib), ind_element(ie), ind_face(iff), mean_normal(n) {}
1302 scalar_type release_distance;
1305 std::vector<contact_boundary> contact_boundaries;
1306 typedef std::map<const mesh *, std::vector<size_type> > mesh_boundary_cor;
1307 mesh_boundary_cor boundary_for_mesh;
1311 const ga_workspace *parent_workspace;
1314 mutable base_vector X;
1315 mutable ga_function f, der_f;
1316 mutable bool compiled;
1318 void compile()
const {
1320 f = ga_function(*md, expr);
1321 else if (parent_workspace)
1322 f = ga_function(*parent_workspace, expr);
1324 f = ga_function(expr);
1326 f.workspace().add_fixed_size_variable(
"X", gmm::sub_interval(0, N), X);
1327 if (N >= 1) f.workspace().add_macro(
"x",
"X(1)");
1328 if (N >= 2) f.workspace().add_macro(
"y",
"X(2)");
1329 if (N >= 3) f.workspace().add_macro(
"z",
"X(3)");
1330 if (N >= 4) f.workspace().add_macro(
"w",
"X(4)");
1333 der_f.derivative(
"X");
1339 base_vector &point()
const {
return X; }
1341 const base_tensor &eval()
const {
1342 if (!compiled) compile();
1345 const base_tensor &eval_derivative()
const {
1346 if (!compiled) compile();
1347 return der_f.eval();
1351 : md(0), parent_workspace(0), expr(
""), X(0), f(), der_f() {}
1352 obstacle(
const model &md_,
const std::string &expr_,
size_type N)
1353 : md(&md_), parent_workspace(0), expr(expr_), X(N),
1354 f(), der_f(), compiled(false) {}
1355 obstacle(
const ga_workspace &parent_workspace_,
1357 : md(0), parent_workspace(&parent_workspace_), expr(expr_), X(N),
1358 f(), der_f(), compiled(false) {}
1359 obstacle(
const obstacle &obs)
1360 : md(obs.md), parent_workspace(obs.parent_workspace), expr(obs.expr),
1361 X(obs.X), f(), der_f(), compiled(false) {}
1362 obstacle &operator =(
const obstacle& obs) {
1364 parent_workspace = obs.parent_workspace;
1368 der_f = ga_function();
1375 std::vector<obstacle> obstacles;
1378 mutable std::vector<face_box_info> face_boxes_info;
1381 void compute_face_boxes()
const {
1382 fem_precomp_pool fppool;
1384 model_real_plain_vector coeff;
1386 face_boxes_info.resize(0);
1388 for (
size_type i = 0; i < contact_boundaries.size(); ++i) {
1389 const contact_boundary &cb = contact_boundaries[i];
1392 const mesh_fem &mfu = *(cb.mfu);
1393 const model_real_plain_vector &U = *(cb.U);
1394 const mesh &m = mfu.linked_mesh();
1397 base_node val(N), bmin(N), bmax(N);
1398 base_small_vector n0_x(N), n_x(N), n0_y(N), n_y(N), n_mean(N);
1399 base_matrix grad(N,N);
1400 mesh_region region = m.region(bnum);
1401 GMM_ASSERT1(mfu.get_qdim() == N,
"Wrong mesh_fem qdim");
1403 dal::bit_vector points_already_interpolated;
1404 std::vector<base_node> transformed_points(m.nb_max_points());
1408 pfem pf_s = mfu.fem_of_element(cv);
1409 pfem_precomp pfp = fppool(pf_s, pgt->pgeometric_nodes());
1411 mfu.linked_mesh().points_of_convex(cv, G);
1412 fem_interpolation_context ctx(pgt, pfp,
size_type(-1), G, cv);
1415 size_type nb_pt_on_face = cvs->nb_points_of_face(v.f());
1416 GMM_ASSERT1(nb_pt_on_face >= 2,
"This element has less than two "
1417 "vertices on considered face !");
1420 for (
size_type k = 0; k < nb_pt_on_face; ++k) {
1421 size_type ip = cvs->ind_points_of_face(v.f())[k];
1422 size_type ind = m.ind_points_of_convex(cv)[ip];
1426 if (!(points_already_interpolated.is_in(ind))) {
1427 pf_s->interpolation(ctx, coeff, val, dim_type(N));
1429 transformed_points[ind] = val;
1430 points_already_interpolated.add(ind);
1432 val = transformed_points[ind];
1443 bmin[l] = std::min(bmin[l], val[l]);
1444 bmax[l] = std::max(bmax[l], val[l]);
1450 scalar_type h = bmax[0] - bmin[0];
1451 for (
size_type k = 1; k < N; ++k) h = std::max(h, bmax[k]-bmin[k]);
1453 { bmin[k] -= h * 0.15; bmax[k] += h * 0.15; }
1456 face_boxes.add_box(bmin, bmax, face_boxes_info.size());
1458 face_boxes_info.push_back(face_box_info(i, cv, v.f(), n_mean));
1462 face_boxes.build_tree();
1467 void add_rigid_obstacle(
const model &md,
const std::string &expr,
1469 obstacles.push_back(obstacle(md, expr, N));
1472 void add_rigid_obstacle(
const ga_workspace &parent_workspace,
1474 obstacles.push_back(obstacle(parent_workspace, expr, N));
1477 void add_contact_boundary(
const model &md,
const mesh &m,
1478 const std::string dispname,
1480 const mesh_fem *mf = 0;
1481 if (md.variable_group_exists(dispname)) {
1482 for (
const std::string &t : md.variable_group(dispname)) {
1483 const mesh_fem *mf2 = md.pmesh_fem_of_variable(t);
1484 if (mf2 && &(mf2->linked_mesh()) == &m)
1485 { mf = mf2;
break; }
1488 mf = md.pmesh_fem_of_variable(dispname);
1490 GMM_ASSERT1(mf,
"Displacement should be a fem variable");
1491 contact_boundary cb(region, mf, dispname, slave);
1492 boundary_for_mesh[&(mf->linked_mesh())]
1493 .push_back(contact_boundaries.size());
1494 contact_boundaries.push_back(cb);
1497 void add_contact_boundary(
const ga_workspace &workspace,
const mesh &m,
1498 const std::string dispname,
1500 const mesh_fem *mf = 0;
1501 if (workspace.variable_group_exists(dispname)) {
1502 for (
const std::string &t : workspace.variable_group(dispname)) {
1503 const mesh_fem *mf2 = workspace.associated_mf(t);
1504 if (mf2 && &(mf2->linked_mesh()) == &m)
1505 { mf = mf2;
break; }
1508 mf = workspace.associated_mf(dispname);
1510 GMM_ASSERT1(mf,
"Displacement should be a fem variable");
1511 contact_boundary cb(region, mf, dispname, slave);
1512 boundary_for_mesh[&(mf->linked_mesh())]
1513 .push_back(contact_boundaries.size());
1514 contact_boundaries.push_back(cb);
1517 void extract_variables(
const ga_workspace &workspace,
1518 std::set<var_trans_pair> &vars,
1519 bool ignore_data,
const mesh &m_x,
1520 const std::string &interpolate_name)
const {
1522 bool expand_groups = !ignore_data;
1527 mesh_boundary_cor::const_iterator it = boundary_for_mesh.find(&m_x);
1528 GMM_ASSERT1(it != boundary_for_mesh.end(),
"Raytracing interpolate "
1529 "transformation: Mesh with no declared contact boundary");
1530 for (
const size_type &boundary_ind : it->second) {
1531 const contact_boundary &cb = contact_boundaries[boundary_ind];
1532 const std::string &dispname_x
1533 = workspace.variable_in_group(cb.dispname, m_x);
1534 if (!ignore_data || !(workspace.is_constant(dispname_x)))
1535 vars.insert(var_trans_pair(dispname_x,
""));
1538 for (
const contact_boundary &cb : contact_boundaries) {
1540 if (expand_groups && workspace.variable_group_exists(cb.dispname)
1541 && (!ignore_data || !(workspace.is_constant(cb.dispname)))) {
1542 for (
const std::string &t : workspace.variable_group(cb.dispname))
1543 vars.insert(var_trans_pair(t, interpolate_name));
1545 if (!ignore_data || !(workspace.is_constant(cb.dispname)))
1546 vars.insert(var_trans_pair(cb.dispname, interpolate_name));
1552 void init(
const ga_workspace &workspace)
const {
1553 for (
const contact_boundary &cb : contact_boundaries) {
1554 const mesh_fem &mfu = *(cb.mfu);
1555 const std::string dispname_x
1556 = workspace.variable_in_group(cb.dispname, mfu.linked_mesh());
1558 if (mfu.is_reduced()) {
1560 mfu.extend_vector(workspace.value(dispname_x), cb.U_unred);
1561 cb.U = &(cb.U_unred);
1563 cb.U = &(workspace.value(dispname_x));
1566 compute_face_boxes();
1569 void finalize()
const {
1571 face_boxes_info = std::vector<face_box_info>();
1572 for (
const contact_boundary &cb : contact_boundaries)
1573 cb.U_unred = model_real_plain_vector();
1576 int transform(
const ga_workspace &workspace,
const mesh &m_x,
1577 fem_interpolation_context &ctx_x,
1578 const base_small_vector &,
1581 base_small_vector &N_y,
1582 std::map<var_trans_pair, base_tensor> &derivatives,
1583 bool compute_derivatives)
const {
1586 GMM_ASSERT1(face_x !=
short_type(-1),
"The contact transformation can "
1587 "only be applied to a boundary");
1592 mesh_boundary_cor::const_iterator it = boundary_for_mesh.find(&m_x);
1593 GMM_ASSERT1(it != boundary_for_mesh.end(),
1594 "Mesh with no declared contact boundary");
1596 for (
const size_type &boundary_ind : it->second) {
1597 const contact_boundary &cb = contact_boundaries[boundary_ind];
1598 if (m_x.region(cb.region).is_in(cv_x, face_x))
1599 { ib_x = boundary_ind;
break; }
1602 "No contact region found for this point");
1603 const contact_boundary &cb_x = contact_boundaries[ib_x];
1604 const mesh_fem &mfu_x = *(cb_x.mfu);
1605 pfem pfu_x = mfu_x.fem_of_element(cv_x);
1606 size_type N = mfu_x.linked_mesh().dim();
1607 GMM_ASSERT1(mfu_x.get_qdim() == N,
1608 "Displacment field with wrong dimension");
1610 model_real_plain_vector coeff_x, coeff_y, stored_coeff_y;
1611 base_small_vector a(N-1), b(N-1), pt_x(N), pt_y(N), n_x(N);
1612 base_small_vector stored_pt_y(N), stored_n_y(N), stored_pt_y_ref(N);
1613 base_small_vector n0_x, n_y(N), n0_y, res(N-1), res2(N-1), dir(N-1);
1614 base_matrix G_x, G_y, grad(N,N), hessa(N-1, N-1);
1615 std::vector<base_small_vector> ti(N-1), Ti(N-1);
1616 scalar_type stored_signed_distance(0);
1617 std::string stored_dispname;
1618 scalar_type d0 = 1E300, d1, d2;
1619 const mesh *stored_m_y(0);
1622 fem_interpolation_context stored_ctx_y;
1628 m_x.points_of_convex(cv_x, G_x);
1629 ctx_x.set_pf(pfu_x);
1630 pfu_x->interpolation(ctx_x, coeff_x, pt_x, dim_type(N));
1631 pt_x += ctx_x.xreal();
1640 bool first_pair_found =
false;
1642 for (
size_type i = 0; i < obstacles.size(); ++i) {
1643 const obstacle &obs = obstacles[i];
1645 const base_tensor &t = obs.eval();
1647 GMM_ASSERT1(t.size() == 1,
"Obstacle level set function as to be "
1648 "a scalar valued one");
1651 if (gmm::abs(d1) < release_distance && d1 < d0) {
1652 const base_tensor &t_der = obs.eval_derivative();
1653 GMM_ASSERT1(t_der.size() == n_x.size(),
"Bad derivative size");
1654 if (gmm::vect_sp(t_der.as_vector(), n_x) < scalar_type(0)) {
1656 irigid_obstacle = i;
1664 const obstacle &obs = obstacles[irigid_obstacle];
1668 scalar_type
alpha(0), beta(0);
1671 while (gmm::abs(d1) > 1E-13 && ++nit < 50 && nb_fail < 3) {
1672 if (nit != 1)
gmm::copy(obs.eval_derivative().as_vector(), n_y);
1674 for (scalar_type lambda(1); lambda >= 1E-3; lambda/=scalar_type(2)) {
1676 gmm::add(pt_x, gmm::scaled(n_x, alpha), obs.point());
1678 if (gmm::abs(d2) < gmm::abs(d1))
break;
1680 if (gmm::abs(beta - d1 / gmm::vect_sp(n_y, n_x)) > scalar_type(500))
1682 beta =
alpha; d1 = d2;
1686 if (gmm::abs(d1) > 1E-8) {
1687 GMM_WARNING1(
"Raytrace on rigid obstacle failed");
1689 else if (gmm::vect_dist2(pt_y, pt_x) <= release_distance) {
1692 stored_pt_y = stored_pt_y_ref = pt_y;
1694 stored_signed_distance = d0;
1695 first_pair_found =
true;
1703 bgeot::rtree::pbox_set bset;
1704 base_node bmin(pt_x), bmax(pt_x);
1706 { bmin[i] -= release_distance; bmax[i] += release_distance; }
1708 face_boxes.find_line_intersecting_boxes(pt_x, n_x, bmin, bmax, bset);
1714 for (
const auto &pbox : bset) {
1715 face_box_info &fbox_y = face_boxes_info[pbox->id];
1717 const contact_boundary &cb_y = contact_boundaries[ib_y];
1718 const mesh_fem &mfu_y = *(cb_y.mfu);
1719 const mesh &m_y = mfu_y.linked_mesh();
1721 pfem pfu_y = mfu_y.fem_of_element(cv_y);
1727 if (gmm::vect_sp(fbox_y.mean_normal, n_x) >= scalar_type(0) ||
1728 (cv_x == cv_y && &m_x == &m_y))
1735 m_y.points_of_convex(cv_y, G_y);
1737 const auto face_pts = pfu_y->ref_convex(cv_y)->points_of_face(face_y);
1738 const base_node &Y0 = face_pts[0];
1739 fem_interpolation_context ctx_y(pgt_y, pfu_y, Y0, G_y, cv_y, face_y);
1741 const base_small_vector &NY0
1742 = pfu_y->ref_convex(cv_y)->normals()[face_y];
1745 scalar_type norm(0);
1746 while(norm < 1E-5) {
1750 ti[k] -= gmm::vect_sp(ti[k], ti[l]) * ti[l];
1760 scalar_type norm(0);
1761 while (norm < 1E-5) {
1765 Ti[k] -= gmm::vect_sp(Ti[k], Ti[l]) * Ti[l];
1773 raytrace_pt_surf_cost_function_object pps(Y0, pt_x, ctx_y, coeff_y,
1777 scalar_type residual2(0), det(0);
1778 bool exited =
false;
1780 for (;residual > 2E-12 && niter <= 30; ++niter) {
1782 for (
size_type subiter(0); subiter <= 4; ++subiter) {
1784 det = gmm::abs(bgeot::lu_inverse(&(*(hessa.begin())), N-1,
false));
1785 if (det > 1E-15)
break;
1787 a[i] += gmm::random() * 1E-7;
1789 if (det <= 1E-15)
break;
1791 gmm::mult(hessa, gmm::scaled(res, scalar_type(-1)), dir);
1793 if (gmm::vect_norm2(dir) > scalar_type(10)) nbfail++;
1794 if (nbfail >= 4)
break;
1797 scalar_type lambda(1);
1799 gmm::add(a, gmm::scaled(dir, lambda), b);
1802 if (residual2 < residual)
break;
1803 lambda /= ((j < 3) ? scalar_type(2) : scalar_type(5));
1806 residual = residual2;
1811 if (niter > 1 && dist_ref > 15)
break;
1812 if (niter > 5 && dist_ref > 8)
break;
1813 if ( nbfail == 3) exited =
true;
1816 bool is_in = (pfu_y->ref_convex(cv_y)->is_in(ctx_y.xref()) < 1E-6);
1821 ctx_y.pf()->interpolation(ctx_y, coeff_y, pt_y, dim_type(N));
1822 pt_y += ctx_y.xreal();
1827 if (!converged)
continue;
1830 if (!is_in)
continue;
1834 if (signed_dist > release_distance)
continue;
1839 signed_dist *= gmm::sgn(gmm::vect_sp(pt_x - pt_y, n_y));
1843 if (first_pair_found && stored_signed_distance < signed_dist)
1847 if (gmm::vect_sp(n_y, n_x) >= scalar_type(0))
continue;
1852 base_small_vector diff = ctx_x.xreal() - ctx_y.xreal();
1854 if ( (ref_dist < scalar_type(4) * release_distance)
1855 && (gmm::vect_sp(diff, n0_y) < - 0.01 * ref_dist) )
1859 stored_pt_y = pt_y; stored_pt_y_ref = ctx_y.xref();
1860 stored_m_y = &m_y; stored_cv_y = cv_y; stored_face_y = face_y;
1862 stored_ctx_y = ctx_y;
1863 stored_coeff_y = coeff_y;
1864 stored_signed_distance = signed_dist;
1865 stored_dispname = cb_y.dispname;
1866 first_pair_found =
true;
1875 P_ref = stored_pt_y; N_y = stored_n_y;
1877 }
else if (first_pair_found) {
1878 *m_t = stored_m_y; cv = stored_cv_y; face_num = stored_face_y;
1879 P_ref = stored_pt_y_ref; N_y = stored_n_y;
1888 if (compute_derivatives) {
1889 if (ret_type >= 1) {
1890 fem_interpolation_context &ctx_y = stored_ctx_y;
1892 if (ret_type == 1) cv_y = ctx_y.convex_num();
1894 base_matrix I_nxny(N,N);
1895 gmm::copy(gmm::identity_matrix(), I_nxny);
1896 gmm::rank_one_update(I_nxny, n_x,
1897 gmm::scaled(stored_n_y,scalar_type(-1)
1898 / gmm::vect_sp(n_x, stored_n_y)));
1901 base_matrix F_y(N,N), F_y_inv(N,N), M1(N, N), M2(N, N);
1903 if (ret_type == 1) {
1905 pfu_y->interpolation_grad(ctx_y, stored_coeff_y, F_y, dim_type(N));
1906 gmm::add(gmm::identity_matrix(), F_y);
1908 bgeot::lu_inverse(&(*(F_y_inv.begin())), N);
1911 gmm::copy(gmm::identity_matrix(), F_y_inv);
1915 base_matrix F_x(N,N), F_x_inv(N,N);
1916 pfu_x->interpolation_grad(ctx_x, coeff_x, F_x, dim_type(N));
1917 gmm::add(gmm::identity_matrix(), F_x);
1919 bgeot::lu_inverse(&(*(F_x_inv.begin())), N);
1922 base_tensor base_ux;
1923 base_matrix vbase_ux;
1924 ctx_x.base_value(base_ux);
1925 size_type qdim_ux = pfu_x->target_dim();
1926 size_type ndof_ux = pfu_x->nb_dof(cv_x) * N / qdim_ux;
1927 vectorize_base_tensor(base_ux, vbase_ux, ndof_ux, qdim_ux, N);
1929 base_tensor base_uy;
1930 base_matrix vbase_uy;
1932 if (ret_type == 1) {
1933 ctx_y.base_value(base_uy);
1934 size_type qdim_uy = pfu_y->target_dim();
1935 ndof_uy = pfu_y->nb_dof(cv_y) * N / qdim_uy;
1936 vectorize_base_tensor(base_uy, vbase_uy, ndof_uy, qdim_uy, N);
1939 base_tensor grad_base_ux, vgrad_base_ux;
1940 ctx_x.grad_base_value(grad_base_ux);
1941 vectorize_grad_base_tensor(grad_base_ux, vgrad_base_ux, ndof_ux,
1950 base_matrix der_x(ndof_ux, N);
1951 gmm::mult(vbase_ux, gmm::transposed(M1), der_x);
1954 base_matrix der_y(ndof_uy, N);
1955 if (ret_type == 1) {
1956 gmm::mult(vbase_uy, gmm::transposed(M1), der_y);
1957 gmm::scale(der_y, scalar_type(-1));
1961 gmm::mult(M1, gmm::transposed(F_x_inv), M2);
1966 der_x(i, j) -= M2(j, k) * vgrad_base_ux(i, l, k)
1967 * n_x[l] * stored_signed_distance;
1969 const std::string &dispname_x
1970 = workspace.variable_in_group(cb_x.dispname, m_x);
1972 for (
auto&& d : derivatives) {
1973 if (dispname_x.compare(d.first.varname) == 0 &&
1974 d.first.transname.size() == 0) {
1975 d.second.adjust_sizes(ndof_ux, N);
1976 gmm::copy(der_x.as_vector(), d.second.as_vector());
1977 }
else if (ret_type == 1 &&
1978 stored_dispname.compare(d.first.varname) == 0 &&
1979 d.first.transname.size() != 0) {
1980 d.second.adjust_sizes(ndof_uy, N);
1981 gmm::copy(der_y.as_vector(), d.second.as_vector());
1983 d.second.adjust_sizes(0, 0);
1986 for (
auto&& d : derivatives)
1987 d.second.adjust_sizes(0, 0);
1993 raytracing_interpolate_transformation(scalar_type d)
1994 : release_distance(d) {}
2004 class projection_interpolate_transformation
2005 :
public raytracing_interpolate_transformation {
2007 scalar_type release_distance;
2010 int transform(
const ga_workspace &workspace,
const mesh &m_x,
2011 fem_interpolation_context &ctx_x,
2012 const base_small_vector &,
2015 base_small_vector &N_y,
2016 std::map<var_trans_pair, base_tensor> &derivatives,
2017 bool compute_derivatives)
const {
2020 GMM_ASSERT1(face_x !=
short_type(-1),
"The contact transformation can "
2021 "only be applied to a boundary");
2026 mesh_boundary_cor::const_iterator it = boundary_for_mesh.find(&m_x);
2027 GMM_ASSERT1(it != boundary_for_mesh.end(),
2028 "Mesh with no declared contact boundary");
2030 for (
const auto &boundary_ind : it->second) {
2031 const contact_boundary &cb = contact_boundaries[boundary_ind];
2032 if (m_x.region(cb.region).is_in(cv_x, face_x))
2033 { ib_x = boundary_ind;
break; }
2036 "No contact region found for this point");
2037 const contact_boundary &cb_x = contact_boundaries[ib_x];
2038 const mesh_fem &mfu_x = *(cb_x.mfu);
2039 pfem pfu_x = mfu_x.fem_of_element(cv_x);
2040 size_type N = mfu_x.linked_mesh().dim();
2041 GMM_ASSERT1(mfu_x.get_qdim() == N,
2042 "Displacment field with wrong dimension");
2044 model_real_plain_vector coeff_x, coeff_y, stored_coeff_y;
2045 base_small_vector a(N-1), b(N-1), pt_x(N), pt_y(N), n_x(N);
2046 base_small_vector stored_pt_y(N), stored_n_y(N), stored_pt_y_ref(N);
2047 base_small_vector n0_x, n_y(N), n0_y, res(N-1), res2(N-1), dir(N-1);
2048 base_matrix G_x, G_y, grad(N,N), hessa(N-1, N-1);
2049 std::vector<base_small_vector> ti(N-1);
2050 scalar_type stored_signed_distance(0);
2051 std::string stored_dispname;
2052 scalar_type d0 = 1E300, d1, d2(0);
2053 const mesh *stored_m_y(0);
2056 fem_interpolation_context stored_ctx_y;
2064 bgeot::vectors_to_base_matrix(G_x, m_x.points_of_convex(cv_x));
2065 ctx_x.set_pf(pfu_x);
2066 pfu_x->interpolation(ctx_x, coeff_x, pt_x, dim_type(N));
2067 pt_x += ctx_x.xreal();
2076 bool first_pair_found =
false;
2078 for (
size_type i = 0; i < obstacles.size(); ++i) {
2079 const obstacle &obs = obstacles[i];
2081 const base_tensor &t = obs.eval();
2083 GMM_ASSERT1(t.size() == 1,
"Obstacle level set function as to be "
2084 "a scalar valued one");
2087 if (gmm::abs(d1) < release_distance && d1 < d0) {
2088 const base_tensor &t_der = obs.eval_derivative();
2089 GMM_ASSERT1(t_der.size() == n_x.size(),
"Bad derivative size");
2090 if (gmm::vect_sp(t_der.as_vector(), n_x) < scalar_type(0))
2091 { d0 = d1; irigid_obstacle = i;
gmm::copy(t_der.as_vector(),n_y); }
2097 const obstacle &obs = obstacles[irigid_obstacle];
2101 scalar_type
alpha(0), beta(0);
2104 while (gmm::abs(d1) > 1E-13 && ++nit < 50 && nb_fail < 3) {
2105 if (nit != 1)
gmm::copy(obs.eval_derivative().as_vector(), n_y);
2107 for (scalar_type lambda(1); lambda >= 1E-3; lambda/=scalar_type(2)) {
2108 gmm::add(gmm::scaled(n_y, -d1/gmm::vect_norm2_sqr(n_y)), pt_y, pt_x);
2110 if (gmm::abs(d2) < gmm::abs(d1))
break;
2112 if (gmm::abs(beta - d1 / gmm::vect_sp(n_y, n_x)) > scalar_type(500))
2114 beta =
alpha; d1 = d2;
2118 if (gmm::abs(d1) > 1E-8) {
2119 GMM_WARNING1(
"Raytrace on rigid obstacle failed");
2121 else if (gmm::vect_dist2(pt_y, pt_x) <= release_distance) {
2124 stored_pt_y = stored_pt_y_ref = pt_y; stored_n_y = n_y,
2125 stored_signed_distance = d0;
2126 first_pair_found =
true;
2134 bgeot::rtree::pbox_set bset;
2135 base_node bmin(pt_x), bmax(pt_x);
2137 { bmin[i] -= release_distance; bmax[i] += release_distance; }
2139 face_boxes.find_line_intersecting_boxes(pt_x, n_x, bmin, bmax, bset);
2144 for (
const auto &pbox : bset) {
2145 face_box_info &fbox_y = face_boxes_info[pbox->id];
2147 const contact_boundary &cb_y = contact_boundaries[ib_y];
2148 const mesh_fem &mfu_y = *(cb_y.mfu);
2149 const mesh &m_y = mfu_y.linked_mesh();
2150 bool ref_conf=
false;
2152 pfem pfu_y = mfu_y.fem_of_element(cv_y);
2158 if (gmm::vect_sp(fbox_y.mean_normal, n_x) >= scalar_type(0) ||
2159 (cv_x == cv_y && &m_x == &m_y))
2165 bgeot::vectors_to_base_matrix(G_y, m_y.points_of_convex(cv_y));
2167 const auto face_pts = pfu_y->ref_convex(cv_y)->points_of_face(face_y);
2168 const base_node &Y0 = face_pts[0];
2169 fem_interpolation_context ctx_y(pgt_y, pfu_y, Y0, G_y, cv_y, face_y);
2171 const base_small_vector &NY0
2172 = pfu_y->ref_convex(cv_y)->normals()[face_y];
2178 scalar_type norm(0);
2179 while(norm < 1E-5) {
2183 ti[k] -= gmm::vect_sp(ti[k], ti[l]) * ti[l];
2189 proj_pt_surf_cost_function_object pps(Y0, pt_x, ctx_y, coeff_y, ti,
2191 base_small_vector grada(N-1);
2194 scalar_type dist = pps(a, grada);
2201 det = gmm::abs(gmm::lu_inverse(hessa,
false));
2202 if (det > 1E-15)
break;
2204 a[i] += gmm::random() * 1E-7;
2205 if (++subiter > 4)
break;
2207 if (det <= 1E-15)
break;
2209 gmm::mult(hessa, gmm::scaled(grada, scalar_type(-1)), dir);
2212 for (scalar_type lambda(1);
2213 lambda >= 1E-3; lambda /= scalar_type(2)) {
2214 gmm::add(a, gmm::scaled(dir, lambda), b);
2215 if (pps(b) < dist)
break;
2216 gmm::add(a, gmm::scaled(dir, -lambda), b);
2217 if (pps(b) < dist)
break;
2221 dist = pps(a, grada);
2228 gmm::bfgs(pps, pps, a, 10, iter, 0, 0.5);
2229 residual = gmm::abs(iter.get_res());
2230 converged = (residual < 2E-5);
2233 bool is_in = (pfu_y->ref_convex(cv_y)->is_in(ctx_y.xref()) < 1E-6);
2241 if (is_in || (!converged )) {
2243 ctx_y.pf()->interpolation(ctx_y, coeff_y, pt_y, dim_type(N));
2244 pt_y += ctx_y.xreal();
2246 pt_y = ctx_y.xreal();
2253 GMM_WARNING3(
"Projection algorithm did not converge "
2254 "for point " << pt_x <<
" residual " << residual
2255 <<
" projection computed " << pt_y);
2271 if (!is_in)
continue;
2277 if (signed_dist > release_distance)
continue;
2280 base_small_vector ny0(N);
2281 compute_normal(ctx_y, face_y, ref_conf, coeff_y, ny0, n_y, grad);
2283 signed_dist *= gmm::sgn(gmm::vect_sp(pt_x - pt_y, n_y));
2287 if (first_pair_found && stored_signed_distance < signed_dist)
2291 if (gmm::vect_sp(n_y, n_x) >= scalar_type(0))
continue;
2297 base_small_vector diff = ctx_x.xreal() - ctx_y.xreal();
2300 if ( (ref_dist < scalar_type(4) * release_distance)
2301 && (gmm::vect_sp(diff, ny0) < - 0.01 * ref_dist) )
2305 stored_pt_y = pt_y; stored_pt_y_ref = ctx_y.xref();
2306 stored_m_y = &m_y; stored_cv_y = cv_y; stored_face_y = face_y;
2308 stored_ctx_y = ctx_y;
2309 stored_coeff_y = coeff_y;
2310 stored_signed_distance = signed_dist;
2311 stored_dispname = cb_y.dispname;
2312 first_pair_found =
true;
2324 P_ref = stored_pt_y; N_y = stored_n_y;
2326 }
else if (first_pair_found) {
2327 *m_t = stored_m_y; cv = stored_cv_y; face_num = stored_face_y;
2328 P_ref = stored_pt_y_ref;
2337 if (compute_derivatives) {
2338 if (ret_type >= 1) {
2339 fem_interpolation_context &ctx_y = stored_ctx_y;
2341 if (ret_type == 1) cv_y = ctx_y.convex_num();
2344 base_matrix I_nyny(N,N);
2345 gmm::copy(gmm::identity_matrix(), I_nyny);
2346 gmm::rank_one_update(I_nyny, stored_n_y,
2347 gmm::scaled(stored_n_y,scalar_type(-1)));
2350 base_matrix F_y(N,N), F_y_inv(N,N), M1(N, N), M2(N, N);
2352 if (ret_type == 1) {
2354 pfu_y->interpolation_grad(ctx_y, stored_coeff_y, F_y, dim_type(N));
2355 gmm::add(gmm::identity_matrix(), F_y);
2360 gmm::copy(gmm::identity_matrix(), F_y_inv);
2364 base_tensor base_ux;
2365 base_matrix vbase_ux;
2366 ctx_x.base_value(base_ux);
2367 size_type qdim_ux = pfu_x->target_dim();
2368 size_type ndof_ux = pfu_x->nb_dof(cv_x) * N / qdim_ux;
2369 vectorize_base_tensor(base_ux, vbase_ux, ndof_ux, qdim_ux, N);
2371 base_tensor base_uy;
2372 base_matrix vbase_uy;
2374 if (ret_type == 1) {
2375 ctx_y.base_value(base_uy);
2376 size_type qdim_uy = pfu_y->target_dim();
2377 ndof_uy = pfu_y->nb_dof(cv_y) * N / qdim_uy;
2378 vectorize_base_tensor(base_uy, vbase_uy, ndof_uy, qdim_uy, N);
2381 base_tensor grad_base_ux, vgrad_base_ux;
2382 ctx_x.grad_base_value(grad_base_ux);
2383 vectorize_grad_base_tensor(grad_base_ux, vgrad_base_ux, ndof_ux,
2391 base_matrix der_x(ndof_ux, N);
2392 gmm::mult(vbase_ux, gmm::transposed(M1), der_x);
2395 base_matrix der_y(ndof_uy, N);
2396 if (ret_type == 1) {
2397 gmm::mult(vbase_uy, gmm::transposed(M1), der_y);
2398 gmm::scale(der_y, scalar_type(-1));
2401 const std::string &dispname_x
2402 = workspace.variable_in_group(cb_x.dispname, m_x);
2404 for (
auto&& d : derivatives) {
2405 if (dispname_x.compare(d.first.varname) == 0 &&
2406 d.first.transname.size() == 0) {
2407 d.second.adjust_sizes(ndof_ux, N);
2408 gmm::copy(der_x.as_vector(), d.second.as_vector());
2409 }
else if (ret_type == 1 &&
2410 stored_dispname.compare(d.first.varname) == 0 &&
2411 d.first.transname.size() != 0) {
2412 d.second.adjust_sizes(ndof_uy, N);
2413 gmm::copy(der_y.as_vector(), d.second.as_vector());
2415 d.second.adjust_sizes(0, 0);
2418 for (
auto&& d : derivatives)
2419 d.second.adjust_sizes(0, 0);
2424 projection_interpolate_transformation(
const scalar_type &d)
2425 :raytracing_interpolate_transformation(d), release_distance(d) {}
2428 (
model &md,
const std::string &transname, scalar_type d) {
2429 pinterpolate_transformation
2430 p = std::make_shared<raytracing_interpolate_transformation>(d);
2435 (ga_workspace &workspace,
const std::string &transname, scalar_type d) {
2436 pinterpolate_transformation
2437 p = std::make_shared<raytracing_interpolate_transformation>(d);
2438 workspace.add_interpolate_transformation(transname, p);
2442 (
model &md,
const std::string &transname,
const mesh &m,
2443 const std::string &dispname,
size_type region) {
2444 raytracing_interpolate_transformation *p
2445 =
dynamic_cast<raytracing_interpolate_transformation *
>
2446 (
const_cast<virtual_interpolate_transformation *
>
2448 p->add_contact_boundary(md, m, dispname, region,
false);
2452 (
model &md,
const std::string &transname,
const mesh &m,
2453 const std::string &dispname,
size_type region) {
2454 raytracing_interpolate_transformation *p
2455 =
dynamic_cast<raytracing_interpolate_transformation *
>
2456 (
const_cast<virtual_interpolate_transformation *
>
2458 p->add_contact_boundary(md, m, dispname, region,
true);
2462 (ga_workspace &workspace,
const std::string &transname,
const mesh &m,
2463 const std::string &dispname,
size_type region) {
2464 raytracing_interpolate_transformation *p
2465 =
dynamic_cast<raytracing_interpolate_transformation *
>
2466 (
const_cast<virtual_interpolate_transformation *
>
2467 (&(*(workspace.interpolate_transformation(transname)))));
2468 p->add_contact_boundary(workspace, m, dispname, region,
false);
2472 (ga_workspace &workspace,
const std::string &transname,
const mesh &m,
2473 const std::string &dispname,
size_type region) {
2474 raytracing_interpolate_transformation *p
2475 =
dynamic_cast<raytracing_interpolate_transformation *
>
2476 (
const_cast<virtual_interpolate_transformation *
>
2477 (&(*(workspace.interpolate_transformation(transname)))));
2478 p->add_contact_boundary(workspace, m, dispname, region,
true);
2482 (
model &md,
const std::string &transname,
2484 raytracing_interpolate_transformation *p
2485 =
dynamic_cast<raytracing_interpolate_transformation *
>
2486 (
const_cast<virtual_interpolate_transformation *
>
2488 p->add_rigid_obstacle(md, expr, N);
2492 (ga_workspace &workspace,
const std::string &transname,
2494 raytracing_interpolate_transformation *p
2495 =
dynamic_cast<raytracing_interpolate_transformation *
>
2496 (
const_cast<virtual_interpolate_transformation *
>
2497 (&(*(workspace.interpolate_transformation(transname)))));
2498 p->add_rigid_obstacle(workspace, expr, N);
2502 (
model &md,
const std::string &transname, scalar_type d) {
2503 pinterpolate_transformation
2504 p = std::make_shared<projection_interpolate_transformation>(d);
2509 (ga_workspace &workspace,
const std::string &transname, scalar_type d) {
2510 pinterpolate_transformation
2511 p = std::make_shared<projection_interpolate_transformation>(d);
2512 workspace.add_interpolate_transformation(transname, p);
2516 (
model &md,
const std::string &transname,
const mesh &m,
2517 const std::string &dispname,
size_type region) {
2518 projection_interpolate_transformation *p
2519 =
dynamic_cast<projection_interpolate_transformation *
>
2520 (
const_cast<virtual_interpolate_transformation *
>
2522 p->add_contact_boundary(md, m, dispname, region,
false);
2526 (
model &md,
const std::string &transname,
const mesh &m,
2527 const std::string &dispname,
size_type region) {
2528 projection_interpolate_transformation *p
2529 =
dynamic_cast<projection_interpolate_transformation *
>
2530 (
const_cast<virtual_interpolate_transformation *
>
2532 p->add_contact_boundary(md, m, dispname, region,
true);
2536 (ga_workspace &workspace,
const std::string &transname,
const mesh &m,
2537 const std::string &dispname,
size_type region) {
2538 projection_interpolate_transformation *p
2539 =
dynamic_cast<projection_interpolate_transformation *
>
2540 (
const_cast<virtual_interpolate_transformation *
>
2541 (&(*(workspace.interpolate_transformation(transname)))));
2542 p->add_contact_boundary(workspace, m, dispname, region,
false);
2546 (ga_workspace &workspace,
const std::string &transname,
const mesh &m,
2547 const std::string &dispname,
size_type region) {
2548 projection_interpolate_transformation *p
2549 =
dynamic_cast<projection_interpolate_transformation *
>
2550 (
const_cast<virtual_interpolate_transformation *
>
2551 (&(*(workspace.interpolate_transformation(transname)))));
2552 p->add_contact_boundary(workspace, m, dispname, region,
true);
2556 (
model &md,
const std::string &transname,
2558 projection_interpolate_transformation *p
2559 =
dynamic_cast<projection_interpolate_transformation *
>
2560 (
const_cast<virtual_interpolate_transformation *
>
2562 p->add_rigid_obstacle(md, expr, N);
2566 (ga_workspace &workspace,
const std::string &transname,
2568 projection_interpolate_transformation *p
2569 =
dynamic_cast<projection_interpolate_transformation *
>
2570 (
const_cast<virtual_interpolate_transformation *
>
2571 (&(*(workspace.interpolate_transformation(transname)))));
2572 p->add_rigid_obstacle(workspace, expr, N);
2585 static void ga_init_vector(bgeot::multi_index &mi,
size_type N)
2586 { mi.resize(1); mi[0] = N; }
2592 struct Transformed_unit_vector :
public ga_nonlinear_operator {
2593 bool result_size(
const arg_list &args, bgeot::multi_index &sizes)
const {
2594 if (args.size() != 2 || args[0]->sizes().size() != 2
2595 || args[1]->size() != args[0]->sizes()[0]
2596 || args[0]->sizes()[0] != args[0]->sizes()[1])
return false;
2597 ga_init_vector(sizes, args[0]->sizes()[0]);
2602 void value(
const arg_list &args, base_tensor &result)
const {
2604 base_matrix F(N, N);
2605 gmm::copy(args[0]->as_vector(), F.as_vector());
2606 gmm::add(gmm::identity_matrix(), F);
2607 bgeot::lu_inverse(&(*(F.begin())), N);
2608 gmm::mult(gmm::transposed(F), args[1]->as_vector(), result.as_vector());
2609 gmm::scale(result.as_vector(),
2610 scalar_type(1)/gmm::vect_norm2(result.as_vector()));
2621 void derivative(
const arg_list &args,
size_type nder,
2622 base_tensor &result)
const {
2624 base_matrix F(N, N), G(N, N);
2625 base_small_vector ndef(N), aux(N);
2626 gmm::copy(args[0]->as_vector(), F.as_vector());
2627 gmm::add(gmm::identity_matrix(), F);
2628 bgeot::lu_inverse(&(*(F.begin())), N);
2629 gmm::mult(gmm::transposed(F), args[1]->as_vector(), ndef);
2631 gmm::scale(ndef, scalar_type(1)/norm_ndef);
2634 gmm::rank_one_update(G, gmm::scaled(ndef, scalar_type(-1)), aux);
2635 base_tensor::iterator it = result.begin();
2641 *it = -G(i, k) * ndef[j];
2646 *it = (F(j,i) - ndef[i]*ndef[j])/norm_ndef;
2648 default: GMM_ASSERT1(
false,
"Internal error");
2650 GMM_ASSERT1(it == result.end(),
"Internal error");
2655 base_tensor &)
const {
2656 GMM_ASSERT1(
false,
"Sorry, second derivative not implemented");
2662 struct Coulomb_friction_coupled_projection :
public ga_nonlinear_operator {
2663 bool result_size(
const arg_list &args, bgeot::multi_index &sizes)
const {
2664 if (args.size() != 6)
return false;
2666 if (N == 0 || args[1]->size() != N || args[2]->size() != N
2667 || args[3]->size() != 1 || args[4]->size() > 3
2668 || args[4]->size() == 0 || args[5]->size() != 1 )
return false;
2669 ga_init_vector(sizes, N);
2674 void value(
const arg_list &args, base_tensor &result)
const {
2675 const base_vector &lambda = *(args[0]);
2676 const base_vector &n = *(args[1]);
2677 const base_vector &Vs = *(args[2]);
2678 base_vector &F = result;
2679 scalar_type g = (*(args[3]))[0];
2680 const base_vector &f = *(args[4]);
2681 scalar_type r = (*(args[5]))[0];
2686 scalar_type lambdan_aug = gmm::neg(lambdan + r * g);
2688 scalar_type tau = ((s_f >= 3) ? f[2] : scalar_type(0)) + f[0]*lambdan_aug;
2689 if (s_f >= 2) tau = std::min(tau, f[1]);
2691 if (tau > scalar_type(0)) {
2692 gmm::add(lambda, gmm::scaled(Vs, -r), F);
2694 gmm::add(gmm::scaled(n, -mu/nn), F);
2696 if (norm > tau) gmm::scale(F, tau / norm);
2699 gmm::add(gmm::scaled(n, -lambdan_aug/nn), F);
2710 void derivative(
const arg_list &args,
size_type nder,
2711 base_tensor &result)
const {
2713 const base_vector &lambda = *(args[0]);
2714 const base_vector &n = *(args[1]);
2715 const base_vector &Vs = *(args[2]);
2716 base_vector F(N), dg(N);
2717 base_matrix dVs(N,N), dn(N,N);
2718 scalar_type g = (*(args[3]))[0];
2719 const base_vector &f = *(args[4]);
2720 scalar_type r = (*(args[5]))[0];
2724 scalar_type lambdan_aug = gmm::neg(lambdan + r * g);
2726 scalar_type tau = ((s_f >= 3) ? f[2] : scalar_type(0))+f[0]*lambdan_aug;
2727 if (s_f >= 2) tau = std::min(tau, f[1]);
2728 scalar_type norm(0);
2730 if (tau > scalar_type(0)) {
2731 gmm::add(lambda, gmm::scaled(Vs, -r), F);
2733 gmm::add(gmm::scaled(n, -mu/nn), F);
2736 gmm::scale(dn, -mu/nn);
2737 gmm::rank_one_update(dn, gmm::scaled(n, mu/(nn*nn*nn)), n);
2738 gmm::rank_one_update(dn, gmm::scaled(n, scalar_type(-1)/(nn*nn)), F);
2740 gmm::rank_one_update(dVs, n, gmm::scaled(n, scalar_type(-1)/(nn*nn)));
2743 gmm::rank_one_update(dVs, F,
2744 gmm::scaled(F, scalar_type(-1)/(norm*norm)));
2745 gmm::scale(dVs, tau / norm);
2746 gmm::copy(gmm::scaled(F, scalar_type(1)/norm), dg);
2747 gmm::rank_one_update(dn, gmm::scaled(F, mu/(norm*norm*nn)), F);
2748 gmm::scale(dn, tau / norm);
2749 gmm::scale(F, tau / norm);
2757 base_tensor::iterator it = result.begin();
2760 if (norm > tau && ((s_f <= 1) || tau < f[1]) &&
2761 ((s_f <= 2) || tau > f[2]))
2762 gmm::rank_one_update(dVs, dg, gmm::scaled(n, -f[0]/nn));
2763 if (lambdan_aug > scalar_type(0))
2764 gmm::rank_one_update(dVs, n, gmm::scaled(n, scalar_type(1)/(nn*nn)));
2770 if (norm > tau && ((s_f <= 1) || tau < f[1])
2771 && ((s_f <= 2) || tau > f[2])) {
2772 gmm::rank_one_update(dn, dg, gmm::scaled(lambda, -f[0]/nn));
2773 gmm::rank_one_update(dn, dg, gmm::scaled(n, f[0]*lambdan/(nn*nn)));
2775 if (lambdan_aug > scalar_type(0)) {
2776 gmm::rank_one_update(dn, gmm::scaled(n, scalar_type(1)/(nn*nn)),
2778 gmm::rank_one_update(dn,
2779 gmm::scaled(n,(lambdan_aug-lambdan)/(nn*nn*nn)), n);
2780 for (
size_type j = 0; j < N; ++j) dn(j,j) -= lambdan_aug/nn;
2787 gmm::scale(dVs, -r);
2793 if (norm > tau && ((s_f <= 1) || tau < f[1])
2794 && ((s_f <= 2) || tau > f[2]))
2795 gmm::scale(dg, -f[0]*r);
2798 if (lambdan_aug > scalar_type(0))
2799 gmm::add(gmm::scaled(n, r/nn), dg);
2804 if (norm > tau && ((s_f <= 1) || tau < f[1])
2805 && ((s_f <= 2) || tau > f[2]))
2806 gmm::scale(dg, -f[0]*g);
2810 if (lambdan_aug > scalar_type(0))
2811 gmm::add(gmm::scaled(n, g/nn), dg);
2817 base_small_vector dtau_df(s_f);
2818 if ((s_f <= 1) || tau < f[1]) dtau_df[0] = lambdan_aug;
2819 if (s_f >= 2 && tau == f[1]) dtau_df[1] = 1;
2820 if (s_f >= 3 && tau < f[1]) dtau_df[2] = 1;
2823 *it = dg[i] * dtau_df[j];
2826 GMM_ASSERT1(it == result.end(),
"Internal error");
2831 base_tensor &)
const {
2832 GMM_ASSERT1(
false,
"Sorry, second derivative not implemented");
2836 static bool init_predef_operators() {
2838 ga_predef_operator_tab &PREDEF_OPERATORS
2841 PREDEF_OPERATORS.add_method(
"Transformed_unit_vector",
2842 std::make_shared<Transformed_unit_vector>());
2843 PREDEF_OPERATORS.add_method(
"Coulomb_friction_coupled_projection",
2844 std::make_shared<Coulomb_friction_coupled_projection>());
2850 bool predef_operators_contact_initialized
2851 = init_predef_operators();
Balanced tree of n-dimensional rectangles.
static T & instance()
Instance from the current thread.
Describe a finite element method linked to a mesh.
"iterator" class for regions.
Describe a mesh (collection of convexes (elements) and points).
`‘Model’' variables store the variables, the data and the description of a model.
void add_interpolate_transformation(const std::string &name, pinterpolate_transformation ptrans)
Add an interpolate transformation to the model to be used with the generic assembly.
pinterpolate_transformation interpolate_transformation(const std::string &name) const
Get a pointer to the interpolate transformation name.
The Iteration object calculates whether the solution has reached the desired accuracy,...
A language for generic assembly of pde boundary value problems.
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_random(L &l)
fill a vector or matrix with random value (uniform [-1,1]).
void clear(L &l)
clear (fill with zeros) a vector or matrix.
number_traits< typename linalg_traits< V1 >::value_type >::magnitude_type vect_dist2(const V1 &v1, const V2 &v2)
Euclidean distance between two vectors.
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)
*/
void lu_inverse(const DenseMatrixLU &LU, const Pvector &pvector, const DenseMatrix &AInv_)
Given an LU factored matrix, build the inverse of the matrix.
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
gmm::uint16_type short_type
used as the common short type integer in the library
std::shared_ptr< const convex_structure > pconvex_structure
Pointer on a convex structure description.
base_small_vector compute_normal(const geotrans_interpolation_context &c, size_type face)
norm of returned vector is the ratio between the face surface on the real element and the face surfac...
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.
void add_rigid_obstacle_to_raytracing_transformation(model &md, const std::string &transname, const std::string &expr, size_type N)
Add a rigid obstacle whose geometry corresponds to the zero level-set of the high-level generic assem...
void add_master_contact_boundary_to_projection_transformation(model &md, const std::string &transname, const mesh &m, const std::string &dispname, size_type region)
Add a master boundary with corresponding displacement variable 'dispname' on a specific boundary 'reg...
void add_raytracing_transformation(model &md, const std::string &transname, scalar_type release_distance)
Add a raytracing interpolate transformation called 'transname' to a model to be used by the generic a...
void add_rigid_obstacle_to_projection_transformation(model &md, const std::string &transname, const std::string &expr, size_type N)
Add a rigid obstacle whose geometry corresponds to the zero level-set of the high-level generic assem...
void add_master_contact_boundary_to_raytracing_transformation(model &md, const std::string &transname, const mesh &m, const std::string &dispname, size_type region)
Add a master boundary with corresponding displacement variable 'dispname' on a specific boundary 'reg...
void slice_vector_on_basic_dof_of_element(const mesh_fem &mf, const VEC1 &vec, size_type cv, VEC2 &coeff, size_type qmult1=size_type(-1), size_type qmult2=size_type(-1))
Given a mesh_fem.
void add_projection_transformation(model &md, const std::string &transname, scalar_type release_distance)
Add a projection interpolate transformation called 'transname' to a model to be used by the generic a...
void add_slave_contact_boundary_to_projection_transformation(model &md, const std::string &transname, const mesh &m, const std::string &dispname, size_type region)
Add a slave boundary with corresponding displacement variable 'dispname' on a specific boundary 'regi...
void add_slave_contact_boundary_to_raytracing_transformation(model &md, const std::string &transname, const mesh &m, const std::string &dispname, size_type region)
Add a slave boundary with corresponding displacement variable 'dispname' on a specific boundary 'regi...