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);
48 gmm::mult(gmm::transposed(grad), n0, n);
49 gmm::scale(n, gmm::sgn(J));
54 gmm::mult(gmm::transposed(grad), n0, n);
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);
249 case 4: obstacles_gw.back().add_fixed_size_constant(
"w", ptw);
250 case 3: obstacles_gw.back().add_fixed_size_constant(
"z", ptz);
251 case 2: obstacles_gw.back().add_fixed_size_constant(
"y", pty);
252 case 1: obstacles_gw.back().add_fixed_size_constant(
"x", ptx);
254 obstacles_f.push_back(ga_function(obstacles_gw.back(), obs));
255 obstacles_f.back().compile();
261 size_type multi_contact_frame::add_master_boundary
262 (
const mesh_im &mim,
const mesh_fem *mfu,
263 const model_real_plain_vector *U,
size_type reg,
264 const mesh_fem *mflambda,
const model_real_plain_vector *lambda,
265 const model_real_plain_vector *w,
266 const std::string &vvarname,
267 const std::string &mmultname,
const std::string &wname) {
268 GMM_ASSERT1(mfu->linked_mesh().dim() == N,
269 "Mesh dimension is " << mfu->linked_mesh().dim()
270 <<
"should be " << N <<
".");
271 GMM_ASSERT1(&(mfu->linked_mesh()) == &(mim.linked_mesh()),
272 "Integration and finite element are not on the same mesh !");
274 GMM_ASSERT1(&(mflambda->linked_mesh()) == &(mim.linked_mesh()),
275 "Integration and finite element are not on the same mesh !");
276 contact_boundary cb(reg, mfu, mim, add_U(U, vvarname, w, wname),
277 mflambda, add_lambda(lambda, mmultname));
278 contact_boundaries.push_back(cb);
279 return size_type(contact_boundaries.size() - 1);
282 size_type multi_contact_frame::add_slave_boundary
283 (
const mesh_im &mim,
const mesh_fem *mfu,
284 const model_real_plain_vector *U,
size_type reg,
285 const mesh_fem *mflambda,
const model_real_plain_vector *lambda,
286 const model_real_plain_vector *w,
287 const std::string &vvarname,
288 const std::string &mmultname,
const std::string &wname) {
290 = add_master_boundary(mim, mfu, U, reg, mflambda, lambda, w,
291 vvarname, mmultname, wname);
292 contact_boundaries[ind].slave =
true;
297 size_type multi_contact_frame::add_master_boundary
298 (
const mesh_im &mim,
size_type reg,
const std::string &vvarname,
299 const std::string &mmultname,
const std::string &wname) {
300 GMM_ASSERT1(md,
"This multi contact frame object is not linked " 302 const mesh_fem *mfl(0);
303 const model_real_plain_vector *l(0);
304 if (mmultname.size()) {
305 mfl = &(md->mesh_fem_of_variable(mmultname));
306 l = &(md->real_variable(mmultname));
308 const model_real_plain_vector *w(0);
309 if (wname.compare(vvarname) == 0) {
310 GMM_ASSERT1(md->n_iter_of_variable(vvarname) > 1,
"More than one " 311 "versions of the displacement variable were expected here");
312 w = &(md->real_variable(vvarname,1));
314 else if (wname.size()) {
315 GMM_ASSERT1(&(md->mesh_fem_of_variable(wname))
316 == &(md->mesh_fem_of_variable(vvarname)),
"The previous " 317 "displacement should be defined on the same mesh_fem as the " 319 w = &(md->real_variable(wname));
321 return add_master_boundary(mim, &(md->mesh_fem_of_variable(vvarname)),
322 &(md->real_variable(vvarname)), reg, mfl, l, w,
323 vvarname, mmultname, wname);
326 size_type multi_contact_frame::add_slave_boundary
327 (
const mesh_im &mim,
size_type reg,
const std::string &vvarname,
328 const std::string &mmultname,
const std::string &wname) {
329 GMM_ASSERT1(md,
"This multi contact frame object is not linked " 331 const mesh_fem *mfl(0);
332 const model_real_plain_vector *l(0);
333 if (mmultname.size()) {
334 mfl = &(md->mesh_fem_of_variable(mmultname));
335 l = &(md->real_variable(mmultname));
337 const model_real_plain_vector *w(0);
338 if (wname.compare(vvarname) == 0) {
339 GMM_ASSERT1(md->n_iter_of_variable(vvarname) > 1,
"More than one " 340 "versions of the displacement variable were expected here");
341 w = &(md->real_variable(vvarname,1));
343 else if (wname.size()) {
344 GMM_ASSERT1(&(md->mesh_fem_of_variable(wname))
345 == &(md->mesh_fem_of_variable(vvarname)),
"The previous " 346 "displacement should be defined on the same mesh_fem as the " 348 w = &(md->real_variable(wname));
350 return add_slave_boundary(mim, &(md->mesh_fem_of_variable(vvarname)),
351 &(md->real_variable(vvarname)), reg, mfl, l, w,
352 vvarname, mmultname, wname);
356 void multi_contact_frame::compute_boundary_points(
bool slave_only) {
357 fem_precomp_pool fppool;
359 model_real_plain_vector coeff;
361 for (
size_type i = 0; i < contact_boundaries.size(); ++i)
362 if (!slave_only || is_slave_boundary(i)) {
364 const mesh_fem &mfu = mfdisp_of_boundary(i);
365 const mesh_im &mim = mim_of_boundary(i);
366 const model_real_plain_vector &U = disp_of_boundary(i);
367 const mesh &m = mfu.linked_mesh();
369 boundary_has_fem_nodes(is_slave_boundary(i), nodes_mode);
371 base_node val(N), bmin(N), bmax(N);
372 base_small_vector n0(N), n(N), n_mean(N);
373 base_matrix grad(N,N);
374 mesh_region region = m.region(bnum);
375 GMM_ASSERT1(mfu.get_qdim() == N,
"Wrong mesh_fem qdim");
378 dal::bit_vector dof_already_interpolated;
379 std::vector<size_type> dof_ind(mfu.nb_basic_dof());
383 pfem pf_s = mfu.fem_of_element(cv);
387 mfu.linked_mesh().points_of_convex(cv, G);
391 std::vector<size_type> indpt, indpfp;
393 dim_type qqdim = mfu.get_qdim() / pf_s->target_dim();
394 pfp = fppool(pf_s, pf_s->node_tab(cv));
395 nbptf = pf_s->node_convex(cv).structure()->nb_points_of_face(v.f());
396 indpt.resize(nbptf); indpfp.resize(nbptf);
399 mfu.ind_basic_dof_of_face_of_element(cv,v.f())[ip*qqdim];
401 pf_s->node_convex(cv).structure()->ind_points_of_face(v.f())[ip];
405 pintegration_method pim = mim.int_method_of_element(cv);
406 GMM_ASSERT1(pim,
"Integration method should be defined");
407 pfp = fppool(pf_s, pim->approx_method()->pintegration_points());
408 nbptf = pim->approx_method()->nb_points_on_face(v.f());
409 indpt.resize(nbptf); indpfp.resize(nbptf);
411 indpt[ip] = indpfp[ip] =
412 pim->approx_method()->ind_first_point_on_face(v.f())+ip;
414 fem_interpolation_context ctx(pgt,pfp,
size_type(-1),G,cv,v.f());
417 ctx.set_ii(indpfp[ip]);
420 if (!(on_fem_nodes && dof_already_interpolated[ind])) {
422 pf_s->interpolation(ctx, coeff, val, dim_type(N));
427 if (on_fem_nodes) dof_ind[ind] = boundary_points.size();
435 if (on_fem_nodes && dof_already_interpolated[ind]) {
436 boundary_points_info[dof_ind[ind]].normals.add_normal(n);
438 boundary_points.push_back(val);
439 boundary_points_info.push_back(boundary_point(ctx.xreal(), i, cv,
443 if (on_fem_nodes) dof_already_interpolated.add(ind);
449 void multi_contact_frame::compute_potential_contact_pairs_delaunay() {
451 compute_boundary_points();
452 normal_cone_simplification();
453 potential_pairs = std::vector<std::vector<face_info> >();
454 potential_pairs.resize(boundary_points.size());
456 gmm::dense_matrix<size_type> simplexes;
457 base_small_vector rr(N);
463 bgeot::qhull_delaunay(boundary_points, simplexes);
466 for (
size_type is = 0; is < gmm::mat_ncols(simplexes); ++is) {
470 size_type ipt1 = simplexes(i, is), ipt2 = simplexes(j, is);
471 boundary_point *pt_info1 = &(boundary_points_info[ipt1]);
472 boundary_point *pt_info2 = &(boundary_points_info[ipt2]);
475 bool sl1 = is_slave_boundary(ib1);
476 bool sl2 = is_slave_boundary(ib2);
478 std::swap(ipt1, ipt2);
479 std::swap(pt_info1, pt_info2);
485 const mesh_fem &mf1 = mfdisp_of_boundary(ib1);
486 const mesh_fem &mf2 = mfdisp_of_boundary(ib2);
494 || (self_contact && !sl1 && !sl2))
496 && test_normal_cones_compatibility(pt_info1->normals,
502 && (( &(mf1.linked_mesh()) != &(mf2.linked_mesh()))
503 || (pt_info1->ind_element != pt_info2->ind_element)))
504 || ((nodes_mode == 2)
505 && !(are_dof_linked(ib1, pt_info1->ind_pt,
506 ib2, pt_info2->ind_pt)))
512 if (boundary_has_fem_nodes(sl2, nodes_mode)) {
513 const mesh::ind_cv_ct &ic2
514 = mf2.convex_to_basic_dof(pt_info2->ind_pt);
515 for (
size_type k = 0; k < ic2.size(); ++k) {
516 mesh_region::face_bitset fbs
517 = mf2.linked_mesh().region(ir2).faces_of_convex(ic2[k]);
518 short_type nbf = mf2.linked_mesh().nb_faces_of_convex(ic2[k]);
521 add_potential_contact_face(ipt1,
522 pt_info2->ind_boundary,
526 add_potential_contact_face(ipt1, pt_info2->ind_boundary,
527 pt_info2->ind_element,
530 if (self_contact && !sl1 && !sl2) {
531 if (boundary_has_fem_nodes(sl2, nodes_mode)) {
532 const mesh::ind_cv_ct &ic1
533 = mf1.convex_to_basic_dof(pt_info1->ind_pt);
534 for (
size_type k = 0; k < ic1.size(); ++k) {
535 mesh_region::face_bitset fbs
536 = mf1.linked_mesh().region(ir1).faces_of_convex(ic1[k]);
537 short_type nbf = mf1.linked_mesh().nb_faces_of_convex(ic1[k]);
540 add_potential_contact_face(ipt2,
541 pt_info1->ind_boundary,
545 add_potential_contact_face(ipt2, pt_info1->ind_boundary,
546 pt_info1->ind_element,
557 void multi_contact_frame::compute_influence_boxes() {
558 fem_precomp_pool fppool;
561 model_real_plain_vector coeff;
563 for (
size_type i = 0; i < contact_boundaries.size(); ++i)
564 if (!is_slave_boundary(i)) {
566 const mesh_fem &mfu = mfdisp_of_boundary(i);
567 const model_real_plain_vector &U = disp_of_boundary(i);
568 const mesh &m = mfu.linked_mesh();
570 base_node val(N), bmin(N), bmax(N);
571 base_small_vector n0(N), n(N), n_mean(N);
572 base_matrix grad(N,N);
573 mesh_region region = m.region(bnum);
574 GMM_ASSERT1(mfu.get_qdim() == N,
"Wrong mesh_fem qdim");
576 dal::bit_vector points_already_interpolated;
577 std::vector<base_node> transformed_points(m.nb_max_points());
581 pfem pf_s = mfu.fem_of_element(cv);
582 pfem_precomp pfp = fppool(pf_s, pgt->pgeometric_nodes());
585 mfu.linked_mesh().points_of_convex(cv, G);
586 fem_interpolation_context ctx(pgt,pfp,
size_type(-1), G, cv);
589 dal::bit_vector points_on_face;
591 for (
size_type k = 0; k < cvs->nb_points_of_face(v.f()); ++k)
592 points_on_face.add(cvs->ind_points_of_face(v.f())[k]);
597 size_type ind = m.ind_points_of_convex(cv)[ip];
601 if (!(points_already_interpolated.is_in(ind))) {
603 pf_s->interpolation(ctx, coeff, val, dim_type(N));
605 transformed_points[ind] = val;
607 transformed_points[ind] = ctx.xreal();
609 points_already_interpolated.add(ind);
611 val = transformed_points[ind];
614 if (points_on_face[ip]) {
625 bmin[k] = std::min(bmin[k], val[k]);
626 bmax[k] = std::max(bmax[k], val[k]);
633 GMM_ASSERT1(nb_pt_on_face,
634 "This element has no vertex on considered face !");
638 scalar_type h = bmax[0] - bmin[0];
639 for (
size_type k = 1; k < N; ++k) h = std::max(h, bmax[k]-bmin[k]);
640 if (h < release_distance/scalar_type(40) && !avert) {
641 GMM_WARNING1(
"Found an element whose size is smaller than 1/40 " 642 "of the release distance. You should probably " 643 "adapt the release distance.");
647 { bmin[k] -= release_distance; bmax[k] += release_distance; }
650 element_boxes.add_box(bmin, bmax, element_boxes_info.size());
652 element_boxes_info.push_back(influence_box(i, cv, v.f(), n_mean));
657 void multi_contact_frame::compute_potential_contact_pairs_influence_boxes() {
658 compute_influence_boxes();
659 compute_boundary_points(!self_contact);
660 normal_cone_simplification();
661 potential_pairs = std::vector<std::vector<face_info> >();
662 potential_pairs.resize(boundary_points.size());
664 for (
size_type ip = 0; ip < boundary_points.size(); ++ip) {
666 bgeot::rtree::pbox_set bset;
667 element_boxes.find_boxes_at_point(boundary_points[ip], bset);
668 boundary_point *pt_info = &(boundary_points_info[ip]);
669 const mesh_fem &mf1 = mfdisp_of_boundary(pt_info->ind_boundary);
672 bgeot::rtree::pbox_set::iterator it = bset.begin();
673 for (; it != bset.end(); ++it) {
674 influence_box &ibx = element_boxes_info[(*it)->id];
676 const mesh_fem &mf2 = mfdisp_of_boundary(ib2);
681 test_normal_cones_compatibility(ibx.mean_normal,
685 && (((nodes_mode < 2)
686 && (( &(mf1.linked_mesh()) != &(mf2.linked_mesh()))
687 || (pt_info->ind_element != ibx.ind_element)))
688 || ((nodes_mode == 2)
689 && !(is_dof_linked(ib1, pt_info->ind_pt,
690 ibx.ind_boundary, ibx.ind_element)))
694 add_potential_contact_face(ip, ibx.ind_boundary, ibx.ind_element,
702 struct proj_pt_surf_cost_function_object {
705 const base_node &x0, &x;
706 fem_interpolation_context &ctx;
707 const model_real_plain_vector &coeff;
708 const std::vector<base_small_vector> &ti;
710 mutable base_node dxy;
711 mutable base_matrix grad, gradtot;
713 scalar_type operator()(
const base_small_vector& a)
const {
715 for (
size_type i= 0; i < N-1; ++i) xx += a[i] * ti[i];
718 ctx.pf()->interpolation(ctx, coeff, dxy, dim_type(N));
719 dxy += ctx.xreal() - x;
721 dxy = ctx.xreal() - x;
725 scalar_type operator()(
const base_small_vector& a,
726 base_small_vector &grada)
const {
728 for (
size_type i = 0; i < N-1; ++i) xx += a[i] * ti[i];
731 ctx.pf()->interpolation(ctx, coeff, dxy, dim_type(N));
732 dxy += ctx.xreal() - x;
733 ctx.pf()->interpolation_grad(ctx, coeff, grad, dim_type(N));
734 gmm::add(gmm::identity_matrix(), grad);
735 gmm::mult(grad, ctx.K(), gradtot);
737 dxy = ctx.xreal() - x;
738 gmm::copy(ctx.K(), gradtot);
741 grada[i] = gmm::vect_sp(gradtot, ti[i], dxy);
744 void operator()(
const base_small_vector& a,
745 base_matrix &hessa)
const {
746 base_small_vector b = a;
747 base_small_vector grada(N-1), gradb(N-1);
753 hessa(j, i) = (gradb[j] - grada[j])/EPS;
758 proj_pt_surf_cost_function_object
759 (
const base_node &x00,
const base_node &xx,
760 fem_interpolation_context &ctxx,
761 const model_real_plain_vector &coefff,
762 const std::vector<base_small_vector> &tii,
763 scalar_type EPSS,
bool rc)
764 : N(
gmm::vect_size(x00)), EPS(EPSS), x0(x00), x(xx),
765 ctx(ctxx), coeff(coefff), ti(tii), ref_conf(rc),
766 dxy(N), grad(N,N), gradtot(N,N) {}
770 struct raytrace_pt_surf_cost_function_object {
772 const base_node &x0, &x;
773 fem_interpolation_context &ctx;
774 const model_real_plain_vector &coeff;
775 const std::vector<base_small_vector> &ti;
776 const std::vector<base_small_vector> &Ti;
778 mutable base_node dxy;
779 mutable base_matrix grad, gradtot;
781 void operator()(
const base_small_vector& a,
782 base_small_vector &res)
const {
784 for (
size_type i = 0; i < N-1; ++i) xx += a[i] * ti[i];
787 ctx.pf()->interpolation(ctx, coeff, dxy, dim_type(N));
788 dxy += ctx.xreal() - x;
790 dxy = ctx.xreal() - x;
792 res[i] = gmm::vect_sp(dxy, Ti[i]);
795 void operator()(
const base_small_vector& a,
796 base_matrix &hessa)
const {
798 for (
size_type i = 0; i < N-1; ++i) xx += a[i] * ti[i];
801 ctx.pf()->interpolation_grad(ctx, coeff, grad, dim_type(N));
802 gmm::add(gmm::identity_matrix(), grad);
803 gmm::mult(grad, ctx.K(), gradtot);
805 gmm::copy(ctx.K(), gradtot);
809 hessa(j, i) = gmm::vect_sp(gradtot, ti[i], Ti[j]);
813 raytrace_pt_surf_cost_function_object
814 (
const base_node &x00,
const base_node &xx,
815 fem_interpolation_context &ctxx,
816 const model_real_plain_vector &coefff,
817 const std::vector<base_small_vector> &tii,
818 const std::vector<base_small_vector> &Tii,
820 : N(
gmm::vect_size(x00)), x0(x00), x(xx),
821 ctx(ctxx), coeff(coefff), ti(tii), Ti(Tii), ref_conf(rc),
822 dxy(N), grad(N,N), gradtot(N,N) {}
835 void multi_contact_frame::compute_contact_pairs() {
836 base_matrix G, grad(N,N);
837 model_real_plain_vector coeff;
838 base_small_vector a(N-1), ny(N);
840 std::vector<base_small_vector> ti(N-1), Ti(N-1);
846 contact_pairs = std::vector<contact_pair>();
848 if (!ref_conf) extend_vectors();
850 bool only_slave(
true), only_master(
true);
851 for (
size_type i = 0; i < contact_boundaries.size(); ++i)
852 if (is_slave_boundary(i)) only_master =
false;
853 else only_slave =
false;
855 if (only_master && !self_contact) {
856 GMM_WARNING1(
"There is only master boundary and no self-contact to detect. Exiting");
861 compute_boundary_points();
862 potential_pairs.resize(boundary_points.size());
864 else if (use_delaunay)
865 compute_potential_contact_pairs_delaunay();
867 compute_potential_contact_pairs_influence_boxes();
873 for (
size_type ip = 0; ip < potential_pairs.size(); ++ip) {
874 bool first_pair_found =
false;
875 const base_node &x = boundary_points[ip];
876 boundary_point &bpinfo = boundary_points_info[ip];
878 bool slx = is_slave_boundary(ibx);
879 scalar_type d0 = 1E300, d1, d2;
881 base_small_vector nx = bpinfo.normals[0];
883 if (bpinfo.normals.size() > 1) {
884 for (
size_type i = 1; i < bpinfo.normals.size(); ++i)
885 gmm::add(bpinfo.normals[i], nx);
887 GMM_ASSERT1(nnx != scalar_type(0),
"Invalid normal cone");
888 gmm::scale(nx, scalar_type(1)/nnx);
892 if (self_contact || slx) {
899 case 4: ptw[0] = pt[3];
900 case 3: ptz[0] = pt[2];
901 case 2: pty[0] = pt[1];
902 case 1: ptx[0] = pt[0];
904 for (
size_type i = 0; i < obstacles.size(); ++i) {
905 d1 = (obstacles_f[i].eval())[0];
906 if (gmm::abs(d1) < release_distance && d1 < d0) {
908 for (
size_type j=0; j < bpinfo.normals.size(); ++j) {
909 gmm::add(gmm::scaled(bpinfo.normals[j], EPS), pt);
912 case 4: ptw[0] = pt[3];
913 case 3: ptz[0] = pt[2];
914 case 2: pty[0] = pt[1];
915 case 1: ptx[0] = pt[0];
917 d2 = (obstacles_f[i].eval())[0];
918 if (d2 < d1) { d0 = d1; irigid_obstacle = i;
break; }
922 case 4: ptw[0] = pt[3];
923 case 3: ptz[0] = pt[2];
924 case 2: pty[0] = pt[1];
925 case 1: ptx[0] = pt[0];
936 case 4: ptw[0] = pt[3];
937 case 3: ptz[0] = pt[2];
938 case 2: pty[0] = pt[1];
939 case 1: ptx[0] = pt[0];
943 scalar_type
alpha(0), beta(0);
946 while (++nit < 50 && nb_fail < 3) {
950 case 4: ptw[0] += EPS;
break;
951 case 3: ptz[0] += EPS;
break;
952 case 2: pty[0] += EPS;
break;
953 case 1: ptx[0] += EPS;
break;
955 d2 = (obstacles_f[irigid_obstacle].eval())[0];
956 ny[k] = (d2 - d1) / EPS;
959 case 4: ptw[0] -= EPS;
break;
960 case 3: ptz[0] -= EPS;
break;
961 case 2: pty[0] -= EPS;
break;
962 case 1: ptx[0] -= EPS;
break;
966 if (gmm::abs(d1) < 1E-13)
970 for (scalar_type lambda(1); lambda >= 1E-3; lambda /= scalar_type(2)) {
972 alpha = beta - lambda * d1 / gmm::vect_sp(ny, nx);
973 gmm::add(x, gmm::scaled(nx, alpha), pt);
975 gmm::add(gmm::scaled(ny, -d1/gmm::vect_norm2_sqr(ny)), y, pt);
979 case 4: ptw[0] = pt[3];
980 case 3: ptz[0] = pt[2];
981 case 2: pty[0] = pt[1];
982 case 1: ptx[0] = pt[0];
984 d2 = (obstacles_f[irigid_obstacle].eval())[0];
989 if (gmm::abs(d2) < gmm::abs(d1))
break;
992 gmm::abs(beta - d1 / gmm::vect_sp(ny, nx)) > scalar_type(500))
994 gmm::copy(pt, y); beta =
alpha; d1 = d2;
997 if (gmm::abs(d1) > 1E-8) {
998 GMM_WARNING1(
"Projection/raytrace on rigid obstacle failed");
1003 if (gmm::vect_dist2(y, x) > release_distance)
1010 contact_pair ct(x, nx, bpinfo, y, ny, irigid_obstacle, d0);
1012 contact_pairs.push_back(ct);
1013 first_pair_found =
true;
1019 for (
size_type ipf = 0; ipf < potential_pairs[ip].size(); ++ipf) {
1038 const face_info &fi = potential_pairs[ip][ipf];
1043 const mesh_fem &mfu = mfdisp_of_boundary(ib);
1044 const mesh &m = mfu.linked_mesh();
1045 pfem pf_s = mfu.fem_of_element(cv);
1052 m.points_of_convex(cv, G);
1054 const base_node &x0 = pf_s->ref_convex(cv)->points_of_face(iff)[0];
1055 fem_interpolation_context ctx(pgt, pf_s, x0, G, cv, iff);
1057 const base_small_vector &n0 = pf_s->ref_convex(cv)->normals()[iff];
1060 scalar_type norm(0);
1061 while(norm < 1E-5) {
1063 ti[k] -= gmm::vect_sp(ti[k], n0) * n0;
1065 ti[k] -= gmm::vect_sp(ti[k], ti[l]) * ti[l];
1071 bool converged =
false;
1072 scalar_type residual(0);
1077 base_small_vector res(N-1), res2(N-1), dir(N-1), b(N-1);
1079 base_matrix hessa(N-1, N-1);
1084 scalar_type norm(0);
1085 while (norm < 1E-5) {
1087 Ti[k] -= gmm::vect_sp(Ti[k], nx) * nx;
1089 Ti[k] -= gmm::vect_sp(Ti[k], Ti[l]) * Ti[l];
1095 raytrace_pt_surf_cost_function_object pps(x0, x, ctx, coeff, ti, Ti,
1100 scalar_type residual2(0), det(0);
1101 bool exited =
false;
1103 for (;residual > 2E-12 && niter <= 30; ++niter) {
1107 det = gmm::abs(bgeot::lu_inverse(&(*(hessa.begin())),N-1,
false));
1108 if (det > 1E-15)
break;
1110 a[i] += gmm::random() * 1E-7;
1111 if (++subiter > 4)
break;
1113 if (det <= 1E-15)
break;
1115 gmm::mult(hessa, gmm::scaled(res, scalar_type(-1)), dir);
1117 if (gmm::vect_norm2(dir) > scalar_type(10)) nbfail++;
1118 if (nbfail >= 4)
break;
1121 scalar_type lambda(1);
1123 gmm::add(a, gmm::scaled(dir, lambda), b);
1126 if (residual2 < residual)
break;
1127 lambda /= ((j < 3) ? scalar_type(2) : scalar_type(5));
1130 residual = residual2;
1131 gmm::copy(res2, res);
1137 if (niter > 1 && dist_ref > 15)
break;
1138 if (niter > 5 && dist_ref > 8)
break;
1139 if ((niter > 1 && dist_ref > 7) || nbfail == 3) exited =
true;
1142 GMM_ASSERT1(!((exited && converged &&
1143 pf_s->ref_convex(cv)->is_in(ctx.xref()) < 1E-6)),
1144 "A non conformal case !! " << gmm::vect_norm2(res)
1145 <<
" : " << nbfail <<
" : " << niter);
1149 proj_pt_surf_cost_function_object pps(x0, x, ctx, coeff, ti,
1156 base_small_vector grada(N-1), dir(N-1), b(N-1);
1158 base_matrix hessa(N-1, N-1);
1161 scalar_type dist = pps(a, grada);
1167 det = gmm::abs(bgeot::lu_inverse(&(*(hessa.begin())),N-1,
false));
1168 if (det > 1E-15)
break;
1170 a[i] += gmm::random() * 1E-7;
1171 if (++subiter > 4)
break;
1173 if (det <= 1E-15)
break;
1175 gmm::mult(hessa, gmm::scaled(grada, scalar_type(-1)), dir);
1178 for (scalar_type lambda(1);
1179 lambda >= 1E-3; lambda /= scalar_type(2)) {
1180 gmm::add(a, gmm::scaled(dir, lambda), b);
1181 if (pps(b) < dist)
break;
1182 gmm::add(a, gmm::scaled(dir, -lambda), b);
1183 if (pps(b) < dist)
break;
1186 dist = pps(a, grada);
1194 gmm::bfgs(pps, pps, a, 10, iter, 0, 0.5);
1195 residual = gmm::abs(iter.get_res());
1196 converged = (residual < 2E-5);
1200 bool is_in = (pf_s->ref_convex(cv)->is_in(ctx.xref()) < 1E-6);
1202 if (is_in || (!converged && !raytrace)) {
1204 ctx.pf()->interpolation(ctx, coeff, y, dim_type(N));
1214 if (!raytrace && nbwarn < 4) {
1215 GMM_WARNING3(
"Projection or raytrace algorithm did not converge " 1216 "for point " << x <<
" residual " << residual
1217 <<
" projection computed " << y);
1233 if (!is_in)
continue;
1237 if (signed_dist > release_distance)
continue;
1240 base_small_vector ny0(N);
1243 signed_dist *= gmm::sgn(gmm::vect_sp(x - y, ny));
1247 if (first_pair_found && contact_pairs.back().signed_dist < signed_dist)
1251 if (!(test_normal_cones_compatibility(ny, bpinfo.normals)))
1256 if (&m == &(mfdisp_of_boundary(ibx).linked_mesh())) {
1258 base_small_vector diff = bpinfo.ref_point - ctx.xreal();
1261 if ( (ref_dist < scalar_type(4) * release_distance)
1262 && (gmm::vect_sp(diff, ny0) < - 0.01 * ref_dist) )
1266 contact_pair ct(x, nx, bpinfo, ctx.xref(), y, ny, fi, signed_dist);
1267 if (first_pair_found) {
1268 contact_pairs.back() = ct;
1270 contact_pairs.push_back(ct);
1271 first_pair_found =
true;
1288 class raytracing_interpolate_transformation
1289 :
public virtual_interpolate_transformation {
1292 struct contact_boundary {
1295 std::string dispname;
1296 mutable const model_real_plain_vector *U;
1297 mutable model_real_plain_vector U_unred;
1301 : region(-1), mfu(0), dispname(
""), U(0), U_unred(0), slave(false) {}
1302 contact_boundary(
size_type r,
const mesh_fem *mf,
const std::string &dn,
1304 : region(r), mfu(mf), dispname(dn), slave(sl) {}
1307 struct face_box_info {
1311 base_small_vector mean_normal;
1313 : ind_boundary(-1), ind_element(-1), ind_face(-1), mean_normal(0) {}
1316 : ind_boundary(ib), ind_element(ie), ind_face(iff), mean_normal(n) {}
1319 scalar_type release_distance;
1322 std::vector<contact_boundary> contact_boundaries;
1323 typedef std::map<const mesh *, std::vector<size_type> > mesh_boundary_cor;
1324 mesh_boundary_cor boundary_for_mesh;
1328 const ga_workspace *parent_workspace;
1331 mutable base_vector X;
1332 mutable ga_function f, der_f;
1333 mutable bool compiled;
1335 void compile()
const {
1337 f = ga_function(*md, expr);
1338 else if (parent_workspace)
1339 f = ga_function(*parent_workspace, expr);
1341 f = ga_function(expr);
1343 f.workspace().add_fixed_size_variable(
"X", gmm::sub_interval(0, N), X);
1344 if (N >= 1) f.workspace().add_macro(
"x",
"X(1)");
1345 if (N >= 2) f.workspace().add_macro(
"y",
"X(2)");
1346 if (N >= 3) f.workspace().add_macro(
"z",
"X(3)");
1347 if (N >= 4) f.workspace().add_macro(
"w",
"X(4)");
1350 der_f.derivative(
"X");
1356 base_vector &point()
const {
return X; }
1358 const base_tensor &eval()
const {
1359 if (!compiled) compile();
1362 const base_tensor &eval_derivative()
const {
1363 if (!compiled) compile();
1364 return der_f.eval();
1368 : md(0), parent_workspace(0), expr(
""), X(0), f(), der_f() {}
1369 obstacle(
const model &md_,
const std::string &expr_,
size_type N)
1370 : md(&md_), parent_workspace(0), expr(expr_), X(N),
1371 f(), der_f(), compiled(false) {}
1372 obstacle(
const ga_workspace &parent_workspace_,
1374 : md(0), parent_workspace(&parent_workspace_), expr(expr_), X(N),
1375 f(), der_f(), compiled(false) {}
1376 obstacle(
const obstacle &obs)
1377 : md(obs.md), parent_workspace(obs.parent_workspace), expr(obs.expr),
1378 X(obs.X), f(), der_f(), compiled(false) {}
1379 obstacle &operator =(
const obstacle& obs) {
1381 parent_workspace = obs.parent_workspace;
1385 der_f = ga_function();
1392 std::vector<obstacle> obstacles;
1395 mutable std::vector<face_box_info> face_boxes_info;
1398 void compute_face_boxes()
const {
1399 fem_precomp_pool fppool;
1401 model_real_plain_vector coeff;
1403 face_boxes_info.resize(0);
1405 for (
size_type i = 0; i < contact_boundaries.size(); ++i) {
1406 const contact_boundary &cb = contact_boundaries[i];
1409 const mesh_fem &mfu = *(cb.mfu);
1410 const model_real_plain_vector &U = *(cb.U);
1411 const mesh &m = mfu.linked_mesh();
1414 base_node val(N), bmin(N), bmax(N);
1415 base_small_vector n0_x(N), n_x(N), n0_y(N), n_y(N), n_mean(N);
1416 base_matrix grad(N,N);
1417 mesh_region region = m.region(bnum);
1418 GMM_ASSERT1(mfu.get_qdim() == N,
"Wrong mesh_fem qdim");
1420 dal::bit_vector points_already_interpolated;
1421 std::vector<base_node> transformed_points(m.nb_max_points());
1425 pfem pf_s = mfu.fem_of_element(cv);
1426 pfem_precomp pfp = fppool(pf_s, pgt->pgeometric_nodes());
1428 mfu.linked_mesh().points_of_convex(cv, G);
1429 fem_interpolation_context ctx(pgt, pfp,
size_type(-1), G, cv);
1432 size_type nb_pt_on_face = cvs->nb_points_of_face(v.f());
1433 GMM_ASSERT1(nb_pt_on_face >= 2,
"This element has less than two " 1434 "vertices on considered face !");
1437 for (
size_type k = 0; k < nb_pt_on_face; ++k) {
1438 size_type ip = cvs->ind_points_of_face(v.f())[k];
1439 size_type ind = m.ind_points_of_convex(cv)[ip];
1443 if (!(points_already_interpolated.is_in(ind))) {
1444 pf_s->interpolation(ctx, coeff, val, dim_type(N));
1446 transformed_points[ind] = val;
1447 points_already_interpolated.add(ind);
1449 val = transformed_points[ind];
1460 bmin[l] = std::min(bmin[l], val[l]);
1461 bmax[l] = std::max(bmax[l], val[l]);
1467 scalar_type h = bmax[0] - bmin[0];
1468 for (
size_type k = 1; k < N; ++k) h = std::max(h, bmax[k]-bmin[k]);
1470 { bmin[k] -= h * 0.15; bmax[k] += h * 0.15; }
1473 face_boxes.add_box(bmin, bmax, face_boxes_info.size());
1475 face_boxes_info.push_back(face_box_info(i, cv, v.f(), n_mean));
1484 void add_rigid_obstacle(
const model &md,
const std::string &expr,
1486 obstacles.push_back(obstacle(md, expr, N));
1489 void add_rigid_obstacle(
const ga_workspace &parent_workspace,
1491 obstacles.push_back(obstacle(parent_workspace, expr, N));
1494 void add_contact_boundary(
const model &md,
const mesh &m,
1495 const std::string dispname,
1497 const mesh_fem *mf = 0;
1498 if (md.variable_group_exists(dispname)) {
1499 for (
const std::string &t : md.variable_group(dispname)) {
1500 const mesh_fem *mf2 = md.pmesh_fem_of_variable(t);
1501 if (mf2 && &(mf2->linked_mesh()) == &m)
1502 { mf = mf2;
break; }
1505 mf = md.pmesh_fem_of_variable(dispname);
1507 GMM_ASSERT1(mf,
"Displacement should be a fem variable");
1508 contact_boundary cb(region, mf, dispname, slave);
1509 boundary_for_mesh[&(mf->linked_mesh())]
1510 .push_back(contact_boundaries.size());
1511 contact_boundaries.push_back(cb);
1514 void add_contact_boundary(
const ga_workspace &workspace,
const mesh &m,
1515 const std::string dispname,
1517 const mesh_fem *mf = 0;
1518 if (workspace.variable_group_exists(dispname)) {
1519 for (
const std::string &t : workspace.variable_group(dispname)) {
1520 const mesh_fem *mf2 = workspace.associated_mf(t);
1521 if (mf2 && &(mf2->linked_mesh()) == &m)
1522 { mf = mf2;
break; }
1525 mf = workspace.associated_mf(dispname);
1527 GMM_ASSERT1(mf,
"Displacement should be a fem variable");
1528 contact_boundary cb(region, mf, dispname, slave);
1529 boundary_for_mesh[&(mf->linked_mesh())]
1530 .push_back(contact_boundaries.size());
1531 contact_boundaries.push_back(cb);
1534 void extract_variables(
const ga_workspace &workspace,
1535 std::set<var_trans_pair> &vars,
1536 bool ignore_data,
const mesh &m_x,
1537 const std::string &interpolate_name)
const {
1539 bool expand_groups = !ignore_data;
1544 mesh_boundary_cor::const_iterator it = boundary_for_mesh.find(&m_x);
1545 GMM_ASSERT1(it != boundary_for_mesh.end(),
"Raytracing interpolate " 1546 "transformation: Mesh with no declared contact boundary");
1547 for (
const size_type &boundary_ind : it->second) {
1548 const contact_boundary &cb = contact_boundaries[boundary_ind];
1549 const std::string &dispname_x
1550 = workspace.variable_in_group(cb.dispname, m_x);
1551 if (!ignore_data || !(workspace.is_constant(dispname_x)))
1552 vars.insert(var_trans_pair(dispname_x,
""));
1555 for (
const contact_boundary &cb : contact_boundaries) {
1557 if (expand_groups && workspace.variable_group_exists(cb.dispname)
1558 && (!ignore_data || !(workspace.is_constant(cb.dispname)))) {
1559 for (
const std::string &t : workspace.variable_group(cb.dispname))
1560 vars.insert(var_trans_pair(t, interpolate_name));
1562 if (!ignore_data || !(workspace.is_constant(cb.dispname)))
1563 vars.insert(var_trans_pair(cb.dispname, interpolate_name));
1569 void init(
const ga_workspace &workspace)
const {
1570 for (
const contact_boundary &cb : contact_boundaries) {
1571 const mesh_fem &mfu = *(cb.mfu);
1572 const std::string dispname_x
1573 = workspace.variable_in_group(cb.dispname, mfu.linked_mesh());
1575 if (mfu.is_reduced()) {
1577 mfu.extend_vector(workspace.value(dispname_x), cb.U_unred);
1578 cb.U = &(cb.U_unred);
1580 cb.U = &(workspace.value(dispname_x));
1583 compute_face_boxes();
1586 void finalize()
const {
1588 face_boxes_info = std::vector<face_box_info>();
1589 for (
const contact_boundary &cb : contact_boundaries)
1590 cb.U_unred = model_real_plain_vector();
1593 int transform(
const ga_workspace &workspace,
const mesh &m_x,
1594 fem_interpolation_context &ctx_x,
1595 const base_small_vector &,
1598 base_small_vector &N_y,
1599 std::map<var_trans_pair, base_tensor> &derivatives,
1600 bool compute_derivatives)
const {
1603 GMM_ASSERT1(face_x !=
short_type(-1),
"The contact transformation can " 1604 "only be applied to a boundary");
1609 mesh_boundary_cor::const_iterator it = boundary_for_mesh.find(&m_x);
1610 GMM_ASSERT1(it != boundary_for_mesh.end(),
1611 "Mesh with no declared contact boundary");
1613 for (
const size_type &boundary_ind : it->second) {
1614 const contact_boundary &cb = contact_boundaries[boundary_ind];
1615 if (m_x.region(cb.region).is_in(cv_x, face_x))
1616 { ib_x = boundary_ind;
break; }
1619 "No contact region found for this point");
1620 const contact_boundary &cb_x = contact_boundaries[ib_x];
1621 const mesh_fem &mfu_x = *(cb_x.mfu);
1622 pfem pfu_x = mfu_x.fem_of_element(cv_x);
1623 size_type N = mfu_x.linked_mesh().dim();
1624 GMM_ASSERT1(mfu_x.get_qdim() == N,
1625 "Displacment field with wrong dimension");
1627 model_real_plain_vector coeff_x, coeff_y, stored_coeff_y;
1628 base_small_vector a(N-1), b(N-1), pt_x(N), pt_y(N), n_x(N);
1629 base_small_vector stored_pt_y(N), stored_n_y(N), stored_pt_y_ref(N);
1630 base_small_vector n0_x, n_y(N), n0_y, res(N-1), res2(N-1), dir(N-1);
1631 base_matrix G_x, G_y, grad(N,N), hessa(N-1, N-1);
1632 std::vector<base_small_vector> ti(N-1), Ti(N-1);
1633 scalar_type stored_signed_distance(0);
1634 std::string stored_dispname;
1635 scalar_type d0 = 1E300, d1, d2;
1636 const mesh *stored_m_y(0);
1639 fem_interpolation_context stored_ctx_y;
1645 m_x.points_of_convex(cv_x, G_x);
1646 ctx_x.set_pf(pfu_x);
1647 pfu_x->interpolation(ctx_x, coeff_x, pt_x, dim_type(N));
1648 pt_x += ctx_x.xreal();
1657 bool first_pair_found =
false;
1659 for (
size_type i = 0; i < obstacles.size(); ++i) {
1660 const obstacle &obs = obstacles[i];
1661 gmm::copy(pt_x, obs.point());
1662 const base_tensor &t = obs.eval();
1664 GMM_ASSERT1(t.size() == 1,
"Obstacle level set function as to be " 1665 "a scalar valued one");
1668 if (gmm::abs(d1) < release_distance && d1 < d0) {
1669 const base_tensor &t_der = obs.eval_derivative();
1670 GMM_ASSERT1(t_der.size() == n_x.size(),
"Bad derivative size");
1671 if (gmm::vect_sp(t_der.as_vector(), n_x) < scalar_type(0)) {
1673 irigid_obstacle = i;
1674 gmm::copy(t_der.as_vector(), n_y);
1681 const obstacle &obs = obstacles[irigid_obstacle];
1682 gmm::copy(pt_x, obs.point());
1683 gmm::copy(pt_x, pt_y);
1685 scalar_type
alpha(0), beta(0);
1688 while (gmm::abs(d1) > 1E-13 && ++nit < 50 && nb_fail < 3) {
1689 if (nit != 1) gmm::copy(obs.eval_derivative().as_vector(), n_y);
1691 for (scalar_type lambda(1); lambda >= 1E-3; lambda/=scalar_type(2)) {
1692 alpha = beta - lambda * d1 / gmm::vect_sp(n_y, n_x);
1693 gmm::add(pt_x, gmm::scaled(n_x, alpha), obs.point());
1695 if (gmm::abs(d2) < gmm::abs(d1))
break;
1697 if (gmm::abs(beta - d1 / gmm::vect_sp(n_y, n_x)) > scalar_type(500))
1699 beta =
alpha; d1 = d2;
1701 gmm::copy(obs.point(), pt_y);
1703 if (gmm::abs(d1) > 1E-8) {
1704 GMM_WARNING1(
"Raytrace on rigid obstacle failed");
1706 else if (gmm::vect_dist2(pt_y, pt_x) <= release_distance) {
1709 stored_pt_y = stored_pt_y_ref = pt_y;
1711 stored_signed_distance = d0;
1712 first_pair_found =
true;
1720 bgeot::rtree::pbox_set bset;
1721 base_node bmin(pt_x), bmax(pt_x);
1723 { bmin[i] -= release_distance; bmax[i] += release_distance; }
1725 face_boxes.find_line_intersecting_boxes(pt_x, n_x, bmin, bmax, bset);
1731 for (
const auto &pbox : bset) {
1732 face_box_info &fbox_y = face_boxes_info[pbox->id];
1734 const contact_boundary &cb_y = contact_boundaries[ib_y];
1735 const mesh_fem &mfu_y = *(cb_y.mfu);
1736 const mesh &m_y = mfu_y.linked_mesh();
1738 pfem pfu_y = mfu_y.fem_of_element(cv_y);
1744 if (gmm::vect_sp(fbox_y.mean_normal, n_x) >= scalar_type(0) ||
1745 (cv_x == cv_y && &m_x == &m_y))
1752 m_y.points_of_convex(cv_y, G_y);
1754 = pfu_y->ref_convex(cv_y)->points_of_face(face_y)[0];
1755 fem_interpolation_context ctx_y(pgt_y, pfu_y, Y0, G_y, cv_y, face_y);
1757 const base_small_vector &NY0
1758 = pfu_y->ref_convex(cv_y)->normals()[face_y];
1761 scalar_type norm(0);
1762 while(norm < 1E-5) {
1764 ti[k] -= gmm::vect_sp(ti[k], NY0) * NY0;
1766 ti[k] -= gmm::vect_sp(ti[k], ti[l]) * ti[l];
1776 scalar_type norm(0);
1777 while (norm < 1E-5) {
1779 Ti[k] -= gmm::vect_sp(Ti[k], n_x) * n_x;
1781 Ti[k] -= gmm::vect_sp(Ti[k], Ti[l]) * Ti[l];
1789 raytrace_pt_surf_cost_function_object pps(Y0, pt_x, ctx_y, coeff_y,
1793 scalar_type residual2(0), det(0);
1794 bool exited =
false;
1796 for (;residual > 2E-12 && niter <= 30; ++niter) {
1798 for (
size_type subiter(0); subiter <= 4; ++subiter) {
1800 det = gmm::abs(bgeot::lu_inverse(&(*(hessa.begin())), N-1,
false));
1801 if (det > 1E-15)
break;
1803 a[i] += gmm::random() * 1E-7;
1805 if (det <= 1E-15)
break;
1807 gmm::mult(hessa, gmm::scaled(res, scalar_type(-1)), dir);
1809 if (gmm::vect_norm2(dir) > scalar_type(10)) nbfail++;
1810 if (nbfail >= 4)
break;
1813 scalar_type lambda(1);
1815 gmm::add(a, gmm::scaled(dir, lambda), b);
1818 if (residual2 < residual)
break;
1819 lambda /= ((j < 3) ? scalar_type(2) : scalar_type(5));
1822 residual = residual2;
1823 gmm::copy(res2, res);
1827 if (niter > 1 && dist_ref > 15)
break;
1828 if (niter > 5 && dist_ref > 8)
break;
1829 if ( nbfail == 3) exited =
true;
1832 bool is_in = (pfu_y->ref_convex(cv_y)->is_in(ctx_y.xref()) < 1E-6);
1837 ctx_y.pf()->interpolation(ctx_y, coeff_y, pt_y, dim_type(N));
1838 pt_y += ctx_y.xreal();
1843 if (!converged)
continue;
1846 if (!is_in)
continue;
1850 if (signed_dist > release_distance)
continue;
1855 signed_dist *= gmm::sgn(gmm::vect_sp(pt_x - pt_y, n_y));
1859 if (first_pair_found && stored_signed_distance < signed_dist)
1863 if (gmm::vect_sp(n_y, n_x) >= scalar_type(0))
continue;
1868 base_small_vector diff = ctx_x.xreal() - ctx_y.xreal();
1870 if ( (ref_dist < scalar_type(4) * release_distance)
1871 && (gmm::vect_sp(diff, n0_y) < - 0.01 * ref_dist) )
1875 stored_pt_y = pt_y; stored_pt_y_ref = ctx_y.xref();
1876 stored_m_y = &m_y; stored_cv_y = cv_y; stored_face_y = face_y;
1878 stored_ctx_y = ctx_y;
1879 stored_coeff_y = coeff_y;
1880 stored_signed_distance = signed_dist;
1881 stored_dispname = cb_y.dispname;
1882 first_pair_found =
true;
1891 P_ref = stored_pt_y; N_y = stored_n_y;
1893 }
else if (first_pair_found) {
1894 *m_t = stored_m_y; cv = stored_cv_y; face_num = stored_face_y;
1895 P_ref = stored_pt_y_ref; N_y = stored_n_y;
1904 if (compute_derivatives) {
1905 if (ret_type >= 1) {
1906 fem_interpolation_context &ctx_y = stored_ctx_y;
1908 if (ret_type == 1) cv_y = ctx_y.convex_num();
1910 base_matrix I_nxny(N,N);
1911 gmm::copy(gmm::identity_matrix(), I_nxny);
1912 gmm::rank_one_update(I_nxny, n_x,
1913 gmm::scaled(stored_n_y,scalar_type(-1)
1914 / gmm::vect_sp(n_x, stored_n_y)));
1917 base_matrix F_y(N,N), F_y_inv(N,N), M1(N, N), M2(N, N);
1919 if (ret_type == 1) {
1921 pfu_y->interpolation_grad(ctx_y, stored_coeff_y, F_y, dim_type(N));
1922 gmm::add(gmm::identity_matrix(), F_y);
1923 gmm::copy(F_y, F_y_inv);
1924 bgeot::lu_inverse(&(*(F_y_inv.begin())), N);
1926 gmm::copy(gmm::identity_matrix(), F_y);
1927 gmm::copy(gmm::identity_matrix(), F_y_inv);
1931 base_matrix F_x(N,N), F_x_inv(N,N);
1932 pfu_x->interpolation_grad(ctx_x, coeff_x, F_x, dim_type(N));
1933 gmm::add(gmm::identity_matrix(), F_x);
1934 gmm::copy(F_x, F_x_inv);
1935 bgeot::lu_inverse(&(*(F_x_inv.begin())), N);
1938 base_tensor base_ux;
1939 base_matrix vbase_ux;
1940 ctx_x.base_value(base_ux);
1941 size_type qdim_ux = pfu_x->target_dim();
1942 size_type ndof_ux = pfu_x->nb_dof(cv_x) * N / qdim_ux;
1943 vectorize_base_tensor(base_ux, vbase_ux, ndof_ux, qdim_ux, N);
1945 base_tensor base_uy;
1946 base_matrix vbase_uy;
1948 if (ret_type == 1) {
1949 ctx_y.base_value(base_uy);
1950 size_type qdim_uy = pfu_y->target_dim();
1951 ndof_uy = pfu_y->nb_dof(cv_y) * N / qdim_uy;
1952 vectorize_base_tensor(base_uy, vbase_uy, ndof_uy, qdim_uy, N);
1955 base_tensor grad_base_ux, vgrad_base_ux;
1956 ctx_x.grad_base_value(grad_base_ux);
1957 vectorize_grad_base_tensor(grad_base_ux, vgrad_base_ux, ndof_ux,
1965 gmm::mult(F_y_inv, I_nxny, M1);
1966 base_matrix der_x(ndof_ux, N);
1967 gmm::mult(vbase_ux, gmm::transposed(M1), der_x);
1970 base_matrix der_y(ndof_uy, N);
1971 if (ret_type == 1) {
1972 gmm::mult(vbase_uy, gmm::transposed(M1), der_y);
1973 gmm::scale(der_y, scalar_type(-1));
1977 gmm::mult(M1, gmm::transposed(F_x_inv), M2);
1982 der_x(i, j) -= M2(j, k) * vgrad_base_ux(i, l, k)
1983 * n_x[l] * stored_signed_distance;
1985 const std::string &dispname_x
1986 = workspace.variable_in_group(cb_x.dispname, m_x);
1988 for (
auto&& d : derivatives) {
1989 if (dispname_x.compare(d.first.varname) == 0 &&
1990 d.first.transname.size() == 0) {
1991 d.second.adjust_sizes(ndof_ux, N);
1992 gmm::copy(der_x.as_vector(), d.second.as_vector());
1993 }
else if (ret_type == 1 &&
1994 stored_dispname.compare(d.first.varname) == 0 &&
1995 d.first.transname.size() != 0) {
1996 d.second.adjust_sizes(ndof_uy, N);
1997 gmm::copy(der_y.as_vector(), d.second.as_vector());
1999 d.second.adjust_sizes(0, 0);
2002 for (
auto&& d : derivatives)
2003 d.second.adjust_sizes(0, 0);
2009 raytracing_interpolate_transformation(scalar_type d)
2010 : release_distance(d) {}
2018 class projection_interpolate_transformation
2019 :
public raytracing_interpolate_transformation {
2021 scalar_type release_distance;
2024 int transform(
const ga_workspace &workspace,
const mesh &m_x,
2025 fem_interpolation_context &ctx_x,
2026 const base_small_vector &,
2029 base_small_vector &N_y,
2030 std::map<var_trans_pair, base_tensor> &derivatives,
2031 bool compute_derivatives)
const {
2034 GMM_ASSERT1(face_x !=
short_type(-1),
"The contact transformation can " 2035 "only be applied to a boundary");
2040 mesh_boundary_cor::const_iterator it = boundary_for_mesh.find(&m_x);
2041 GMM_ASSERT1(it != boundary_for_mesh.end(),
2042 "Mesh with no declared contact boundary");
2044 for (
const auto &boundary_ind : it->second) {
2045 const contact_boundary &cb = contact_boundaries[boundary_ind];
2046 if (m_x.region(cb.region).is_in(cv_x, face_x))
2047 { ib_x = boundary_ind;
break; }
2050 "No contact region found for this point");
2051 const contact_boundary &cb_x = contact_boundaries[ib_x];
2052 const mesh_fem &mfu_x = *(cb_x.mfu);
2053 pfem pfu_x = mfu_x.fem_of_element(cv_x);
2054 size_type N = mfu_x.linked_mesh().dim();
2055 GMM_ASSERT1(mfu_x.get_qdim() == N,
2056 "Displacment field with wrong dimension");
2058 model_real_plain_vector coeff_x, coeff_y, stored_coeff_y;
2059 base_small_vector a(N-1), b(N-1), pt_x(N), pt_y(N), n_x(N);
2060 base_small_vector stored_pt_y(N), stored_n_y(N), stored_pt_y_ref(N);
2061 base_small_vector n0_x, n_y(N), n0_y, res(N-1), res2(N-1), dir(N-1);
2062 base_matrix G_x, G_y, grad(N,N), hessa(N-1, N-1);
2063 std::vector<base_small_vector> ti(N-1);
2064 scalar_type stored_signed_distance(0);
2065 std::string stored_dispname;
2066 scalar_type d0 = 1E300, d1, d2(0);
2067 const mesh *stored_m_y(0);
2070 fem_interpolation_context stored_ctx_y;
2078 bgeot::vectors_to_base_matrix(G_x, m_x.points_of_convex(cv_x));
2079 ctx_x.set_pf(pfu_x);
2080 pfu_x->interpolation(ctx_x, coeff_x, pt_x, dim_type(N));
2081 pt_x += ctx_x.xreal();
2090 bool first_pair_found =
false;
2092 for (
size_type i = 0; i < obstacles.size(); ++i) {
2093 const obstacle &obs = obstacles[i];
2094 gmm::copy(pt_x, obs.point());
2095 const base_tensor &t = obs.eval();
2097 GMM_ASSERT1(t.size() == 1,
"Obstacle level set function as to be " 2098 "a scalar valued one");
2101 if (gmm::abs(d1) < release_distance && d1 < d0) {
2102 const base_tensor &t_der = obs.eval_derivative();
2103 GMM_ASSERT1(t_der.size() == n_x.size(),
"Bad derivative size");
2104 if (gmm::vect_sp(t_der.as_vector(), n_x) < scalar_type(0))
2105 { d0 = d1; irigid_obstacle = i; gmm::copy(t_der.as_vector(),n_y); }
2111 const obstacle &obs = obstacles[irigid_obstacle];
2112 gmm::copy(pt_x, obs.point());
2113 gmm::copy(pt_x, pt_y);
2115 scalar_type
alpha(0), beta(0);
2118 while (gmm::abs(d1) > 1E-13 && ++nit < 50 && nb_fail < 3) {
2119 if (nit != 1) gmm::copy(obs.eval_derivative().as_vector(), n_y);
2121 for (scalar_type lambda(1); lambda >= 1E-3; lambda/=scalar_type(2)) {
2122 gmm::add(gmm::scaled(n_y, -d1/gmm::vect_norm2_sqr(n_y)), pt_y, pt_x);
2124 if (gmm::abs(d2) < gmm::abs(d1))
break;
2126 if (gmm::abs(beta - d1 / gmm::vect_sp(n_y, n_x)) > scalar_type(500))
2128 beta =
alpha; d1 = d2;
2130 gmm::copy(obs.point(), pt_y);
2132 if (gmm::abs(d1) > 1E-8) {
2133 GMM_WARNING1(
"Raytrace on rigid obstacle failed");
2135 else if (gmm::vect_dist2(pt_y, pt_x) <= release_distance) {
2138 stored_pt_y = stored_pt_y_ref = pt_y; stored_n_y = n_y,
2139 stored_signed_distance = d0;
2140 first_pair_found =
true;
2148 bgeot::rtree::pbox_set bset;
2149 base_node bmin(pt_x), bmax(pt_x);
2151 { bmin[i] -= release_distance; bmax[i] += release_distance; }
2153 face_boxes.find_line_intersecting_boxes(pt_x, n_x, bmin, bmax, bset);
2158 for (
const auto &pbox : bset) {
2159 face_box_info &fbox_y = face_boxes_info[pbox->id];
2161 const contact_boundary &cb_y = contact_boundaries[ib_y];
2162 const mesh_fem &mfu_y = *(cb_y.mfu);
2163 const mesh &m_y = mfu_y.linked_mesh();
2164 bool ref_conf=
false;
2166 pfem pfu_y = mfu_y.fem_of_element(cv_y);
2172 if (gmm::vect_sp(fbox_y.mean_normal, n_x) >= scalar_type(0) ||
2173 (cv_x == cv_y && &m_x == &m_y))
2179 bgeot::vectors_to_base_matrix(G_y, m_y.points_of_convex(cv_y));
2181 = pfu_y->ref_convex(cv_y)->points_of_face(face_y)[0];
2182 fem_interpolation_context ctx_y(pgt_y, pfu_y, Y0, G_y, cv_y, face_y);
2184 const base_small_vector &NY0
2185 = pfu_y->ref_convex(cv_y)->normals()[face_y];
2191 scalar_type norm(0);
2192 while(norm < 1E-5) {
2194 ti[k] -= gmm::vect_sp(ti[k], NY0) * NY0;
2196 ti[k] -= gmm::vect_sp(ti[k], ti[l]) * ti[l];
2202 proj_pt_surf_cost_function_object pps(Y0, pt_x, ctx_y, coeff_y, ti,
2204 base_small_vector grada(N-1);
2207 scalar_type dist = pps(a, grada);
2214 det = gmm::abs(gmm::lu_inverse(hessa,
false));
2215 if (det > 1E-15)
break;
2217 a[i] += gmm::random() * 1E-7;
2218 if (++subiter > 4)
break;
2220 if (det <= 1E-15)
break;
2222 gmm::mult(hessa, gmm::scaled(grada, scalar_type(-1)), dir);
2225 for (scalar_type lambda(1);
2226 lambda >= 1E-3; lambda /= scalar_type(2)) {
2227 gmm::add(a, gmm::scaled(dir, lambda), b);
2228 if (pps(b) < dist)
break;
2229 gmm::add(a, gmm::scaled(dir, -lambda), b);
2230 if (pps(b) < dist)
break;
2234 dist = pps(a, grada);
2241 gmm::bfgs(pps, pps, a, 10, iter, 0, 0.5);
2242 residual = gmm::abs(iter.get_res());
2243 converged = (residual < 2E-5);
2246 bool is_in = (pfu_y->ref_convex(cv_y)->is_in(ctx_y.xref()) < 1E-6);
2254 if (is_in || (!converged )) {
2256 ctx_y.pf()->interpolation(ctx_y, coeff_y, pt_y, dim_type(N));
2257 pt_y += ctx_y.xreal();
2259 pt_y = ctx_y.xreal();
2266 GMM_WARNING3(
"Projection algorithm did not converge " 2267 "for point " << pt_x <<
" residual " << residual
2268 <<
" projection computed " << pt_y);
2284 if (!is_in)
continue;
2290 if (signed_dist > release_distance)
continue;
2293 base_small_vector ny0(N);
2294 compute_normal(ctx_y, face_y, ref_conf, coeff_y, ny0, n_y, grad);
2296 signed_dist *= gmm::sgn(gmm::vect_sp(pt_x - pt_y, n_y));
2300 if (first_pair_found && stored_signed_distance < signed_dist)
2304 if (gmm::vect_sp(n_y, n_x) >= scalar_type(0))
continue;
2310 base_small_vector diff = ctx_x.xreal() - ctx_y.xreal();
2313 if ( (ref_dist < scalar_type(4) * release_distance)
2314 && (gmm::vect_sp(diff, ny0) < - 0.01 * ref_dist) )
2318 stored_pt_y = pt_y; stored_pt_y_ref = ctx_y.xref();
2319 stored_m_y = &m_y; stored_cv_y = cv_y; stored_face_y = face_y;
2321 stored_ctx_y = ctx_y;
2322 stored_coeff_y = coeff_y;
2323 stored_signed_distance = signed_dist;
2324 stored_dispname = cb_y.dispname;
2325 first_pair_found =
true;
2337 P_ref = stored_pt_y; N_y = stored_n_y;
2339 }
else if (first_pair_found) {
2340 *m_t = stored_m_y; cv = stored_cv_y; face_num = stored_face_y;
2341 P_ref = stored_pt_y_ref;
2350 if (compute_derivatives) {
2351 if (ret_type >= 1) {
2352 fem_interpolation_context &ctx_y = stored_ctx_y;
2354 if (ret_type == 1) cv_y = ctx_y.convex_num();
2357 base_matrix I_nyny(N,N);
2358 gmm::copy(gmm::identity_matrix(), I_nyny);
2359 gmm::rank_one_update(I_nyny, stored_n_y,
2360 gmm::scaled(stored_n_y,scalar_type(-1)));
2363 base_matrix F_y(N,N), F_y_inv(N,N), M1(N, N), M2(N, N);
2365 if (ret_type == 1) {
2367 pfu_y->interpolation_grad(ctx_y, stored_coeff_y, F_y, dim_type(N));
2368 gmm::add(gmm::identity_matrix(), F_y);
2369 gmm::copy(F_y, F_y_inv);
2370 gmm::lu_inverse(F_y_inv);
2372 gmm::copy(gmm::identity_matrix(), F_y);
2373 gmm::copy(gmm::identity_matrix(), F_y_inv);
2377 base_tensor base_ux;
2378 base_matrix vbase_ux;
2379 ctx_x.base_value(base_ux);
2380 size_type qdim_ux = pfu_x->target_dim();
2381 size_type ndof_ux = pfu_x->nb_dof(cv_x) * N / qdim_ux;
2382 vectorize_base_tensor(base_ux, vbase_ux, ndof_ux, qdim_ux, N);
2384 base_tensor base_uy;
2385 base_matrix vbase_uy;
2387 if (ret_type == 1) {
2388 ctx_y.base_value(base_uy);
2389 size_type qdim_uy = pfu_y->target_dim();
2390 ndof_uy = pfu_y->nb_dof(cv_y) * N / qdim_uy;
2391 vectorize_base_tensor(base_uy, vbase_uy, ndof_uy, qdim_uy, N);
2394 base_tensor grad_base_ux, vgrad_base_ux;
2395 ctx_x.grad_base_value(grad_base_ux);
2396 vectorize_grad_base_tensor(grad_base_ux, vgrad_base_ux, ndof_ux,
2403 gmm::mult(F_y_inv, I_nyny, M1);
2404 base_matrix der_x(ndof_ux, N);
2405 gmm::mult(vbase_ux, gmm::transposed(M1), der_x);
2408 base_matrix der_y(ndof_uy, N);
2409 if (ret_type == 1) {
2410 gmm::mult(vbase_uy, gmm::transposed(M1), der_y);
2411 gmm::scale(der_y, scalar_type(-1));
2414 const std::string &dispname_x
2415 = workspace.variable_in_group(cb_x.dispname, m_x);
2417 for (
auto&& d : derivatives) {
2418 if (dispname_x.compare(d.first.varname) == 0 &&
2419 d.first.transname.size() == 0) {
2420 d.second.adjust_sizes(ndof_ux, N);
2421 gmm::copy(der_x.as_vector(), d.second.as_vector());
2422 }
else if (ret_type == 1 &&
2423 stored_dispname.compare(d.first.varname) == 0 &&
2424 d.first.transname.size() != 0) {
2425 d.second.adjust_sizes(ndof_uy, N);
2426 gmm::copy(der_y.as_vector(), d.second.as_vector());
2428 d.second.adjust_sizes(0, 0);
2431 for (
auto&& d : derivatives)
2432 d.second.adjust_sizes(0, 0);
2437 projection_interpolate_transformation(
const scalar_type &d)
2438 :raytracing_interpolate_transformation(d), release_distance(d) {}
2441 (
model &md,
const std::string &transname, scalar_type d) {
2442 pinterpolate_transformation
2443 p = std::make_shared<raytracing_interpolate_transformation>(d);
2448 (ga_workspace &workspace,
const std::string &transname, scalar_type d) {
2449 pinterpolate_transformation
2450 p = std::make_shared<raytracing_interpolate_transformation>(d);
2451 workspace.add_interpolate_transformation(transname, p);
2456 const std::string &dispname,
size_type region) {
2457 raytracing_interpolate_transformation *p
2458 =
dynamic_cast<raytracing_interpolate_transformation *
> 2459 (
const_cast<virtual_interpolate_transformation *
> 2461 p->add_contact_boundary(md, m, dispname, region,
false);
2466 const std::string &dispname,
size_type region) {
2467 raytracing_interpolate_transformation *p
2468 =
dynamic_cast<raytracing_interpolate_transformation *
> 2469 (
const_cast<virtual_interpolate_transformation *
> 2471 p->add_contact_boundary(md, m, dispname, region,
true);
2475 (ga_workspace &workspace,
const std::string &transname,
const mesh &m,
2476 const std::string &dispname,
size_type region) {
2477 raytracing_interpolate_transformation *p
2478 =
dynamic_cast<raytracing_interpolate_transformation *
> 2479 (
const_cast<virtual_interpolate_transformation *
> 2480 (&(*(workspace.interpolate_transformation(transname)))));
2481 p->add_contact_boundary(workspace, m, dispname, region,
false);
2485 (ga_workspace &workspace,
const std::string &transname,
const mesh &m,
2486 const std::string &dispname,
size_type region) {
2487 raytracing_interpolate_transformation *p
2488 =
dynamic_cast<raytracing_interpolate_transformation *
> 2489 (
const_cast<virtual_interpolate_transformation *
> 2490 (&(*(workspace.interpolate_transformation(transname)))));
2491 p->add_contact_boundary(workspace, m, dispname, region,
true);
2495 (
model &md,
const std::string &transname,
2497 raytracing_interpolate_transformation *p
2498 =
dynamic_cast<raytracing_interpolate_transformation *
> 2499 (
const_cast<virtual_interpolate_transformation *
> 2501 p->add_rigid_obstacle(md, expr, N);
2505 (ga_workspace &workspace,
const std::string &transname,
2507 raytracing_interpolate_transformation *p
2508 =
dynamic_cast<raytracing_interpolate_transformation *
> 2509 (
const_cast<virtual_interpolate_transformation *
> 2510 (&(*(workspace.interpolate_transformation(transname)))));
2511 p->add_rigid_obstacle(workspace, expr, N);
2515 (
model &md,
const std::string &transname, scalar_type d) {
2516 pinterpolate_transformation
2517 p = std::make_shared<projection_interpolate_transformation>(d);
2522 (ga_workspace &workspace,
const std::string &transname, scalar_type d) {
2523 pinterpolate_transformation
2524 p = std::make_shared<projection_interpolate_transformation>(d);
2525 workspace.add_interpolate_transformation(transname, p);
2530 const std::string &dispname,
size_type region) {
2531 projection_interpolate_transformation *p
2532 =
dynamic_cast<projection_interpolate_transformation *
> 2533 (
const_cast<virtual_interpolate_transformation *
> 2535 p->add_contact_boundary(md, m, dispname, region,
false);
2540 const std::string &dispname,
size_type region) {
2541 projection_interpolate_transformation *p
2542 =
dynamic_cast<projection_interpolate_transformation *
> 2543 (
const_cast<virtual_interpolate_transformation *
> 2545 p->add_contact_boundary(md, m, dispname, region,
true);
2549 (ga_workspace &workspace,
const std::string &transname,
const mesh &m,
2550 const std::string &dispname,
size_type region) {
2551 projection_interpolate_transformation *p
2552 =
dynamic_cast<projection_interpolate_transformation *
> 2553 (
const_cast<virtual_interpolate_transformation *
> 2554 (&(*(workspace.interpolate_transformation(transname)))));
2555 p->add_contact_boundary(workspace, m, dispname, region,
false);
2559 (ga_workspace &workspace,
const std::string &transname,
const mesh &m,
2560 const std::string &dispname,
size_type region) {
2561 projection_interpolate_transformation *p
2562 =
dynamic_cast<projection_interpolate_transformation *
> 2563 (
const_cast<virtual_interpolate_transformation *
> 2564 (&(*(workspace.interpolate_transformation(transname)))));
2565 p->add_contact_boundary(workspace, m, dispname, region,
true);
2569 (
model &md,
const std::string &transname,
2571 projection_interpolate_transformation *p
2572 =
dynamic_cast<projection_interpolate_transformation *
> 2573 (
const_cast<virtual_interpolate_transformation *
> 2575 p->add_rigid_obstacle(md, expr, N);
2579 (ga_workspace &workspace,
const std::string &transname,
2581 projection_interpolate_transformation *p
2582 =
dynamic_cast<projection_interpolate_transformation *
> 2583 (
const_cast<virtual_interpolate_transformation *
> 2584 (&(*(workspace.interpolate_transformation(transname)))));
2585 p->add_rigid_obstacle(workspace, expr, N);
2598 static void ga_init_vector(bgeot::multi_index &mi,
size_type N)
2599 { mi.resize(1); mi[0] = N; }
2605 struct Transformed_unit_vector :
public ga_nonlinear_operator {
2606 bool result_size(
const arg_list &args, bgeot::multi_index &sizes)
const {
2607 if (args.size() != 2 || args[0]->sizes().size() != 2
2608 || args[1]->size() != args[0]->sizes()[0]
2609 || args[0]->sizes()[0] != args[0]->sizes()[1])
return false;
2610 ga_init_vector(sizes, args[0]->sizes()[0]);
2615 void value(
const arg_list &args, base_tensor &result)
const {
2617 base_matrix F(N, N);
2618 gmm::copy(args[0]->as_vector(), F.as_vector());
2619 gmm::add(gmm::identity_matrix(), F);
2620 bgeot::lu_inverse(&(*(F.begin())), N);
2621 gmm::mult(gmm::transposed(F), args[1]->as_vector(), result.as_vector());
2622 gmm::scale(result.as_vector(),
2623 scalar_type(1)/gmm::vect_norm2(result.as_vector()));
2634 void derivative(
const arg_list &args,
size_type nder,
2635 base_tensor &result)
const {
2637 base_matrix F(N, N), G(N, N);
2638 base_small_vector ndef(N), aux(N);
2639 gmm::copy(args[0]->as_vector(), F.as_vector());
2640 gmm::add(gmm::identity_matrix(), F);
2641 bgeot::lu_inverse(&(*(F.begin())), N);
2642 gmm::mult(gmm::transposed(F), args[1]->as_vector(), ndef);
2643 scalar_type norm_ndef = gmm::vect_norm2(ndef);
2644 gmm::scale(ndef, scalar_type(1)/norm_ndef);
2645 gmm::copy(gmm::transposed(F), G);
2646 gmm::mult(F, ndef, aux);
2647 gmm::rank_one_update(G, gmm::scaled(ndef, scalar_type(-1)), aux);
2648 base_tensor::iterator it = result.begin();
2654 *it = -G(i, k) * ndef[j];
2659 *it = (F(j,i) - ndef[i]*ndef[j])/norm_ndef;
2661 default: GMM_ASSERT1(
false,
"Internal error");
2663 GMM_ASSERT1(it == result.end(),
"Internal error");
2668 base_tensor &)
const {
2669 GMM_ASSERT1(
false,
"Sorry, second derivative not implemented");
2675 struct Coulomb_friction_coupled_projection :
public ga_nonlinear_operator {
2676 bool result_size(
const arg_list &args, bgeot::multi_index &sizes)
const {
2677 if (args.size() != 6)
return false;
2679 if (N == 0 || args[1]->size() != N || args[2]->size() != N
2680 || args[3]->size() != 1 || args[4]->size() > 3
2681 || args[4]->size() == 0 || args[5]->size() != 1 )
return false;
2682 ga_init_vector(sizes, N);
2687 void value(
const arg_list &args, base_tensor &result)
const {
2688 const base_vector &lambda = *(args[0]);
2689 const base_vector &n = *(args[1]);
2690 const base_vector &Vs = *(args[2]);
2691 base_vector &F = result;
2692 scalar_type g = (*(args[3]))[0];
2693 const base_vector &f = *(args[4]);
2694 scalar_type r = (*(args[5]))[0];
2697 scalar_type nn = gmm::vect_norm2(n);
2698 scalar_type lambdan = gmm::vect_sp(lambda, n)/nn;
2699 scalar_type lambdan_aug = gmm::neg(lambdan + r * g);
2701 scalar_type tau = ((s_f >= 3) ? f[2] : scalar_type(0)) + f[0]*lambdan_aug;
2702 if (s_f >= 2) tau = std::min(tau, f[1]);
2704 if (tau > scalar_type(0)) {
2705 gmm::add(lambda, gmm::scaled(Vs, -r), F);
2706 scalar_type mu = gmm::vect_sp(F, n)/nn;
2707 gmm::add(gmm::scaled(n, -mu/nn), F);
2708 scalar_type norm = gmm::vect_norm2(F);
2709 if (norm > tau) gmm::scale(F, tau / norm);
2710 }
else { gmm::clear(F); }
2712 gmm::add(gmm::scaled(n, -lambdan_aug/nn), F);
2723 void derivative(
const arg_list &args,
size_type nder,
2724 base_tensor &result)
const {
2726 const base_vector &lambda = *(args[0]);
2727 const base_vector &n = *(args[1]);
2728 const base_vector &Vs = *(args[2]);
2729 base_vector F(N), dg(N);
2730 base_matrix dVs(N,N), dn(N,N);
2731 scalar_type g = (*(args[3]))[0];
2732 const base_vector &f = *(args[4]);
2733 scalar_type r = (*(args[5]))[0];
2735 scalar_type nn = gmm::vect_norm2(n);
2736 scalar_type lambdan = gmm::vect_sp(lambda, n)/nn;
2737 scalar_type lambdan_aug = gmm::neg(lambdan + r * g);
2739 scalar_type tau = ((s_f >= 3) ? f[2] : scalar_type(0))+f[0]*lambdan_aug;
2740 if (s_f >= 2) tau = std::min(tau, f[1]);
2741 scalar_type norm(0);
2743 if (tau > scalar_type(0)) {
2744 gmm::add(lambda, gmm::scaled(Vs, -r), F);
2745 scalar_type mu = gmm::vect_sp(F, n)/nn;
2746 gmm::add(gmm::scaled(n, -mu/nn), F);
2747 norm = gmm::vect_norm2(F);
2748 gmm::copy(gmm::identity_matrix(), dn);
2749 gmm::scale(dn, -mu/nn);
2750 gmm::rank_one_update(dn, gmm::scaled(n, mu/(nn*nn*nn)), n);
2751 gmm::rank_one_update(dn, gmm::scaled(n, scalar_type(-1)/(nn*nn)), F);
2752 gmm::copy(gmm::identity_matrix(), dVs);
2753 gmm::rank_one_update(dVs, n, gmm::scaled(n, scalar_type(-1)/(nn*nn)));
2756 gmm::rank_one_update(dVs, F,
2757 gmm::scaled(F, scalar_type(-1)/(norm*norm)));
2758 gmm::scale(dVs, tau / norm);
2759 gmm::copy(gmm::scaled(F, scalar_type(1)/norm), dg);
2760 gmm::rank_one_update(dn, gmm::scaled(F, mu/(norm*norm*nn)), F);
2761 gmm::scale(dn, tau / norm);
2762 gmm::scale(F, tau / norm);
2770 base_tensor::iterator it = result.begin();
2773 if (norm > tau && ((s_f <= 1) || tau < f[1]) &&
2774 ((s_f <= 2) || tau > f[2]))
2775 gmm::rank_one_update(dVs, dg, gmm::scaled(n, -f[0]/nn));
2776 if (lambdan_aug > scalar_type(0))
2777 gmm::rank_one_update(dVs, n, gmm::scaled(n, scalar_type(1)/(nn*nn)));
2783 if (norm > tau && ((s_f <= 1) || tau < f[1])
2784 && ((s_f <= 2) || tau > f[2])) {
2785 gmm::rank_one_update(dn, dg, gmm::scaled(lambda, -f[0]/nn));
2786 gmm::rank_one_update(dn, dg, gmm::scaled(n, f[0]*lambdan/(nn*nn)));
2788 if (lambdan_aug > scalar_type(0)) {
2789 gmm::rank_one_update(dn, gmm::scaled(n, scalar_type(1)/(nn*nn)),
2791 gmm::rank_one_update(dn,
2792 gmm::scaled(n,(lambdan_aug-lambdan)/(nn*nn*nn)), n);
2793 for (
size_type j = 0; j < N; ++j) dn(j,j) -= lambdan_aug/nn;
2800 gmm::scale(dVs, -r);
2806 if (norm > tau && ((s_f <= 1) || tau < f[1])
2807 && ((s_f <= 2) || tau > f[2]))
2808 gmm::scale(dg, -f[0]*r);
2811 if (lambdan_aug > scalar_type(0))
2812 gmm::add(gmm::scaled(n, r/nn), dg);
2817 if (norm > tau && ((s_f <= 1) || tau < f[1])
2818 && ((s_f <= 2) || tau > f[2]))
2819 gmm::scale(dg, -f[0]*g);
2822 gmm::mult_add(dVs, gmm::scaled(Vs, scalar_type(-1)), dg);
2823 if (lambdan_aug > scalar_type(0))
2824 gmm::add(gmm::scaled(n, g/nn), dg);
2830 base_small_vector dtau_df(s_f);
2831 if ((s_f <= 1) || tau < f[1]) dtau_df[0] = lambdan_aug;
2832 if (s_f >= 2 && tau == f[1]) dtau_df[1] = 1;
2833 if (s_f >= 3 && tau < f[1]) dtau_df[2] = 1;
2836 *it = dg[i] * dtau_df[j];
2839 GMM_ASSERT1(it == result.end(),
"Internal error");
2844 base_tensor &)
const {
2845 GMM_ASSERT1(
false,
"Sorry, second derivative not implemented");
2849 static bool init_predef_operators() {
2851 ga_predef_operator_tab &PREDEF_OPERATORS
2854 PREDEF_OPERATORS.add_method(
"Transformed_unit_vector",
2855 std::make_shared<Transformed_unit_vector>());
2856 PREDEF_OPERATORS.add_method(
"Coulomb_friction_coupled_projection",
2857 std::make_shared<Coulomb_friction_coupled_projection>());
2863 bool predef_operators_contact_initialized
2864 = init_predef_operators();
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...
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...
The Iteration object calculates whether the solution has reached the desired accuracy, or whether the maximum number of iterations has been reached.
Describe a mesh (collection of convexes (elements) and points).
void fill_random(L &l, double cfill)
*/
number_traits< typename linalg_traits< V1 >::value_type >::magnitude_type vect_dist2(const V1 &v1, const V2 &v2)
Euclidean distance between two vectors.
pinterpolate_transformation interpolate_transformation(const std::string &name) const
Get a pointer to the interpolate transformation name.
static T & instance()
Instance from the current thread.
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2(const V &v)
Euclidean norm of a vector.
``Model'' variables store the variables, the data and the description of a model. ...
std::shared_ptr< const convex_structure > pconvex_structure
Pointer on a convex structure description.
size_t size_type
used as the common size type in the library
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...
"iterator" class for regions.
void add_interpolate_transformation(const std::string &name, pinterpolate_transformation ptrans)
Add a interpolate transformation to the model to be used with the generic assembly.
A langage for generic assembly of pde boundary value problems.
GEneric Tool for Finite Element Methods.
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
Describe a finite element method linked to a mesh.
void clear(L &l)
clear (fill with zeros) a vector or matrix.
gmm::uint16_type short_type
used as the common short type integer in the library
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...
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_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...
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 ...
Balanced tree of n-dimensional rectangles.
void resize(M &v, size_type m, size_type n)
*/
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...
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation