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);
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);
733 gmm::mult(grad, ctx.K(), gradtot);
735 dxy = ctx.xreal() - x;
736 gmm::copy(ctx.K(), gradtot);
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);
801 gmm::mult(grad, ctx.K(), gradtot);
803 gmm::copy(ctx.K(), gradtot);
807 hessa(j, i) = gmm::vect_sp(gradtot, ti[i], Ti[j]);
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)) {
958 alpha = beta - lambda * d1 / gmm::vect_sp(ny, nx);
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))
977 gmm::copy(pt, y); beta =
alpha; d1 = d2;
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);
1035 m.points_of_convex(cv, G);
1037 const base_node &x0 = pf_s->ref_convex(cv)->points_of_face(iff)[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) {
1046 ti[k] -= gmm::vect_sp(ti[k], n0) * n0;
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) {
1070 Ti[k] -= gmm::vect_sp(Ti[k], nx) * nx;
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;
1114 gmm::copy(res2, res);
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];
1644 gmm::copy(pt_x, obs.point());
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;
1657 gmm::copy(t_der.as_vector(), n_y);
1664 const obstacle &obs = obstacles[irigid_obstacle];
1665 gmm::copy(pt_x, obs.point());
1666 gmm::copy(pt_x, pt_y);
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)) {
1675 alpha = beta - lambda * d1 / gmm::vect_sp(n_y, n_x);
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;
1684 gmm::copy(obs.point(), pt_y);
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 = pfu_y->ref_convex(cv_y)->points_of_face(face_y)[0];
1738 fem_interpolation_context ctx_y(pgt_y, pfu_y, Y0, G_y, cv_y, face_y);
1740 const base_small_vector &NY0
1741 = pfu_y->ref_convex(cv_y)->normals()[face_y];
1744 scalar_type norm(0);
1745 while(norm < 1E-5) {
1747 ti[k] -= gmm::vect_sp(ti[k], NY0) * NY0;
1749 ti[k] -= gmm::vect_sp(ti[k], ti[l]) * ti[l];
1759 scalar_type norm(0);
1760 while (norm < 1E-5) {
1762 Ti[k] -= gmm::vect_sp(Ti[k], n_x) * n_x;
1764 Ti[k] -= gmm::vect_sp(Ti[k], Ti[l]) * Ti[l];
1772 raytrace_pt_surf_cost_function_object pps(Y0, pt_x, ctx_y, coeff_y,
1776 scalar_type residual2(0), det(0);
1777 bool exited =
false;
1779 for (;residual > 2E-12 && niter <= 30; ++niter) {
1781 for (
size_type subiter(0); subiter <= 4; ++subiter) {
1783 det = gmm::abs(bgeot::lu_inverse(&(*(hessa.begin())), N-1,
false));
1784 if (det > 1E-15)
break;
1786 a[i] += gmm::random() * 1E-7;
1788 if (det <= 1E-15)
break;
1790 gmm::mult(hessa, gmm::scaled(res, scalar_type(-1)), dir);
1792 if (gmm::vect_norm2(dir) > scalar_type(10)) nbfail++;
1793 if (nbfail >= 4)
break;
1796 scalar_type lambda(1);
1798 gmm::add(a, gmm::scaled(dir, lambda), b);
1801 if (residual2 < residual)
break;
1802 lambda /= ((j < 3) ? scalar_type(2) : scalar_type(5));
1805 residual = residual2;
1806 gmm::copy(res2, res);
1810 if (niter > 1 && dist_ref > 15)
break;
1811 if (niter > 5 && dist_ref > 8)
break;
1812 if ( nbfail == 3) exited =
true;
1815 bool is_in = (pfu_y->ref_convex(cv_y)->is_in(ctx_y.xref()) < 1E-6);
1820 ctx_y.pf()->interpolation(ctx_y, coeff_y, pt_y, dim_type(N));
1821 pt_y += ctx_y.xreal();
1826 if (!converged)
continue;
1829 if (!is_in)
continue;
1833 if (signed_dist > release_distance)
continue;
1838 signed_dist *= gmm::sgn(gmm::vect_sp(pt_x - pt_y, n_y));
1842 if (first_pair_found && stored_signed_distance < signed_dist)
1846 if (gmm::vect_sp(n_y, n_x) >= scalar_type(0))
continue;
1851 base_small_vector diff = ctx_x.xreal() - ctx_y.xreal();
1853 if ( (ref_dist < scalar_type(4) * release_distance)
1854 && (gmm::vect_sp(diff, n0_y) < - 0.01 * ref_dist) )
1858 stored_pt_y = pt_y; stored_pt_y_ref = ctx_y.xref();
1859 stored_m_y = &m_y; stored_cv_y = cv_y; stored_face_y = face_y;
1861 stored_ctx_y = ctx_y;
1862 stored_coeff_y = coeff_y;
1863 stored_signed_distance = signed_dist;
1864 stored_dispname = cb_y.dispname;
1865 first_pair_found =
true;
1874 P_ref = stored_pt_y; N_y = stored_n_y;
1876 }
else if (first_pair_found) {
1877 *m_t = stored_m_y; cv = stored_cv_y; face_num = stored_face_y;
1878 P_ref = stored_pt_y_ref; N_y = stored_n_y;
1887 if (compute_derivatives) {
1888 if (ret_type >= 1) {
1889 fem_interpolation_context &ctx_y = stored_ctx_y;
1891 if (ret_type == 1) cv_y = ctx_y.convex_num();
1893 base_matrix I_nxny(N,N);
1894 gmm::copy(gmm::identity_matrix(), I_nxny);
1895 gmm::rank_one_update(I_nxny, n_x,
1896 gmm::scaled(stored_n_y,scalar_type(-1)
1897 / gmm::vect_sp(n_x, stored_n_y)));
1900 base_matrix F_y(N,N), F_y_inv(N,N), M1(N, N), M2(N, N);
1902 if (ret_type == 1) {
1904 pfu_y->interpolation_grad(ctx_y, stored_coeff_y, F_y, dim_type(N));
1905 gmm::add(gmm::identity_matrix(), F_y);
1906 gmm::copy(F_y, F_y_inv);
1907 bgeot::lu_inverse(&(*(F_y_inv.begin())), N);
1909 gmm::copy(gmm::identity_matrix(), F_y);
1910 gmm::copy(gmm::identity_matrix(), F_y_inv);
1914 base_matrix F_x(N,N), F_x_inv(N,N);
1915 pfu_x->interpolation_grad(ctx_x, coeff_x, F_x, dim_type(N));
1916 gmm::add(gmm::identity_matrix(), F_x);
1917 gmm::copy(F_x, F_x_inv);
1918 bgeot::lu_inverse(&(*(F_x_inv.begin())), N);
1921 base_tensor base_ux;
1922 base_matrix vbase_ux;
1923 ctx_x.base_value(base_ux);
1924 size_type qdim_ux = pfu_x->target_dim();
1925 size_type ndof_ux = pfu_x->nb_dof(cv_x) * N / qdim_ux;
1926 vectorize_base_tensor(base_ux, vbase_ux, ndof_ux, qdim_ux, N);
1928 base_tensor base_uy;
1929 base_matrix vbase_uy;
1931 if (ret_type == 1) {
1932 ctx_y.base_value(base_uy);
1933 size_type qdim_uy = pfu_y->target_dim();
1934 ndof_uy = pfu_y->nb_dof(cv_y) * N / qdim_uy;
1935 vectorize_base_tensor(base_uy, vbase_uy, ndof_uy, qdim_uy, N);
1938 base_tensor grad_base_ux, vgrad_base_ux;
1939 ctx_x.grad_base_value(grad_base_ux);
1940 vectorize_grad_base_tensor(grad_base_ux, vgrad_base_ux, ndof_ux,
1948 gmm::mult(F_y_inv, I_nxny, M1);
1949 base_matrix der_x(ndof_ux, N);
1950 gmm::mult(vbase_ux, gmm::transposed(M1), der_x);
1953 base_matrix der_y(ndof_uy, N);
1954 if (ret_type == 1) {
1955 gmm::mult(vbase_uy, gmm::transposed(M1), der_y);
1956 gmm::scale(der_y, scalar_type(-1));
1960 gmm::mult(M1, gmm::transposed(F_x_inv), M2);
1965 der_x(i, j) -= M2(j, k) * vgrad_base_ux(i, l, k)
1966 * n_x[l] * stored_signed_distance;
1968 const std::string &dispname_x
1969 = workspace.variable_in_group(cb_x.dispname, m_x);
1971 for (
auto&& d : derivatives) {
1972 if (dispname_x.compare(d.first.varname) == 0 &&
1973 d.first.transname.size() == 0) {
1974 d.second.adjust_sizes(ndof_ux, N);
1975 gmm::copy(der_x.as_vector(), d.second.as_vector());
1976 }
else if (ret_type == 1 &&
1977 stored_dispname.compare(d.first.varname) == 0 &&
1978 d.first.transname.size() != 0) {
1979 d.second.adjust_sizes(ndof_uy, N);
1980 gmm::copy(der_y.as_vector(), d.second.as_vector());
1982 d.second.adjust_sizes(0, 0);
1985 for (
auto&& d : derivatives)
1986 d.second.adjust_sizes(0, 0);
1992 raytracing_interpolate_transformation(scalar_type d)
1993 : release_distance(d) {}
2003 class projection_interpolate_transformation
2004 :
public raytracing_interpolate_transformation {
2006 scalar_type release_distance;
2009 int transform(
const ga_workspace &workspace,
const mesh &m_x,
2010 fem_interpolation_context &ctx_x,
2011 const base_small_vector &,
2014 base_small_vector &N_y,
2015 std::map<var_trans_pair, base_tensor> &derivatives,
2016 bool compute_derivatives)
const {
2019 GMM_ASSERT1(face_x !=
short_type(-1),
"The contact transformation can "
2020 "only be applied to a boundary");
2025 mesh_boundary_cor::const_iterator it = boundary_for_mesh.find(&m_x);
2026 GMM_ASSERT1(it != boundary_for_mesh.end(),
2027 "Mesh with no declared contact boundary");
2029 for (
const auto &boundary_ind : it->second) {
2030 const contact_boundary &cb = contact_boundaries[boundary_ind];
2031 if (m_x.region(cb.region).is_in(cv_x, face_x))
2032 { ib_x = boundary_ind;
break; }
2035 "No contact region found for this point");
2036 const contact_boundary &cb_x = contact_boundaries[ib_x];
2037 const mesh_fem &mfu_x = *(cb_x.mfu);
2038 pfem pfu_x = mfu_x.fem_of_element(cv_x);
2039 size_type N = mfu_x.linked_mesh().dim();
2040 GMM_ASSERT1(mfu_x.get_qdim() == N,
2041 "Displacment field with wrong dimension");
2043 model_real_plain_vector coeff_x, coeff_y, stored_coeff_y;
2044 base_small_vector a(N-1), b(N-1), pt_x(N), pt_y(N), n_x(N);
2045 base_small_vector stored_pt_y(N), stored_n_y(N), stored_pt_y_ref(N);
2046 base_small_vector n0_x, n_y(N), n0_y, res(N-1), res2(N-1), dir(N-1);
2047 base_matrix G_x, G_y, grad(N,N), hessa(N-1, N-1);
2048 std::vector<base_small_vector> ti(N-1);
2049 scalar_type stored_signed_distance(0);
2050 std::string stored_dispname;
2051 scalar_type d0 = 1E300, d1, d2(0);
2052 const mesh *stored_m_y(0);
2055 fem_interpolation_context stored_ctx_y;
2063 bgeot::vectors_to_base_matrix(G_x, m_x.points_of_convex(cv_x));
2064 ctx_x.set_pf(pfu_x);
2065 pfu_x->interpolation(ctx_x, coeff_x, pt_x, dim_type(N));
2066 pt_x += ctx_x.xreal();
2075 bool first_pair_found =
false;
2077 for (
size_type i = 0; i < obstacles.size(); ++i) {
2078 const obstacle &obs = obstacles[i];
2079 gmm::copy(pt_x, obs.point());
2080 const base_tensor &t = obs.eval();
2082 GMM_ASSERT1(t.size() == 1,
"Obstacle level set function as to be "
2083 "a scalar valued one");
2086 if (gmm::abs(d1) < release_distance && d1 < d0) {
2087 const base_tensor &t_der = obs.eval_derivative();
2088 GMM_ASSERT1(t_der.size() == n_x.size(),
"Bad derivative size");
2089 if (gmm::vect_sp(t_der.as_vector(), n_x) < scalar_type(0))
2090 { d0 = d1; irigid_obstacle = i; gmm::copy(t_der.as_vector(),n_y); }
2096 const obstacle &obs = obstacles[irigid_obstacle];
2097 gmm::copy(pt_x, obs.point());
2098 gmm::copy(pt_x, pt_y);
2100 scalar_type
alpha(0), beta(0);
2103 while (gmm::abs(d1) > 1E-13 && ++nit < 50 && nb_fail < 3) {
2104 if (nit != 1) gmm::copy(obs.eval_derivative().as_vector(), n_y);
2106 for (scalar_type lambda(1); lambda >= 1E-3; lambda/=scalar_type(2)) {
2107 gmm::add(gmm::scaled(n_y, -d1/gmm::vect_norm2_sqr(n_y)), pt_y, pt_x);
2109 if (gmm::abs(d2) < gmm::abs(d1))
break;
2111 if (gmm::abs(beta - d1 / gmm::vect_sp(n_y, n_x)) > scalar_type(500))
2113 beta =
alpha; d1 = d2;
2115 gmm::copy(obs.point(), pt_y);
2117 if (gmm::abs(d1) > 1E-8) {
2118 GMM_WARNING1(
"Raytrace on rigid obstacle failed");
2120 else if (gmm::vect_dist2(pt_y, pt_x) <= release_distance) {
2123 stored_pt_y = stored_pt_y_ref = pt_y; stored_n_y = n_y,
2124 stored_signed_distance = d0;
2125 first_pair_found =
true;
2133 bgeot::rtree::pbox_set bset;
2134 base_node bmin(pt_x), bmax(pt_x);
2136 { bmin[i] -= release_distance; bmax[i] += release_distance; }
2138 face_boxes.find_line_intersecting_boxes(pt_x, n_x, bmin, bmax, bset);
2143 for (
const auto &pbox : bset) {
2144 face_box_info &fbox_y = face_boxes_info[pbox->id];
2146 const contact_boundary &cb_y = contact_boundaries[ib_y];
2147 const mesh_fem &mfu_y = *(cb_y.mfu);
2148 const mesh &m_y = mfu_y.linked_mesh();
2149 bool ref_conf=
false;
2151 pfem pfu_y = mfu_y.fem_of_element(cv_y);
2157 if (gmm::vect_sp(fbox_y.mean_normal, n_x) >= scalar_type(0) ||
2158 (cv_x == cv_y && &m_x == &m_y))
2164 bgeot::vectors_to_base_matrix(G_y, m_y.points_of_convex(cv_y));
2166 = pfu_y->ref_convex(cv_y)->points_of_face(face_y)[0];
2167 fem_interpolation_context ctx_y(pgt_y, pfu_y, Y0, G_y, cv_y, face_y);
2169 const base_small_vector &NY0
2170 = pfu_y->ref_convex(cv_y)->normals()[face_y];
2176 scalar_type norm(0);
2177 while(norm < 1E-5) {
2179 ti[k] -= gmm::vect_sp(ti[k], NY0) * NY0;
2181 ti[k] -= gmm::vect_sp(ti[k], ti[l]) * ti[l];
2187 proj_pt_surf_cost_function_object pps(Y0, pt_x, ctx_y, coeff_y, ti,
2189 base_small_vector grada(N-1);
2192 scalar_type dist = pps(a, grada);
2199 det = gmm::abs(gmm::lu_inverse(hessa,
false));
2200 if (det > 1E-15)
break;
2202 a[i] += gmm::random() * 1E-7;
2203 if (++subiter > 4)
break;
2205 if (det <= 1E-15)
break;
2207 gmm::mult(hessa, gmm::scaled(grada, scalar_type(-1)), dir);
2210 for (scalar_type lambda(1);
2211 lambda >= 1E-3; lambda /= scalar_type(2)) {
2212 gmm::add(a, gmm::scaled(dir, lambda), b);
2213 if (pps(b) < dist)
break;
2214 gmm::add(a, gmm::scaled(dir, -lambda), b);
2215 if (pps(b) < dist)
break;
2219 dist = pps(a, grada);
2226 gmm::bfgs(pps, pps, a, 10, iter, 0, 0.5);
2227 residual = gmm::abs(iter.get_res());
2228 converged = (residual < 2E-5);
2231 bool is_in = (pfu_y->ref_convex(cv_y)->is_in(ctx_y.xref()) < 1E-6);
2239 if (is_in || (!converged )) {
2241 ctx_y.pf()->interpolation(ctx_y, coeff_y, pt_y, dim_type(N));
2242 pt_y += ctx_y.xreal();
2244 pt_y = ctx_y.xreal();
2251 GMM_WARNING3(
"Projection algorithm did not converge "
2252 "for point " << pt_x <<
" residual " << residual
2253 <<
" projection computed " << pt_y);
2269 if (!is_in)
continue;
2275 if (signed_dist > release_distance)
continue;
2278 base_small_vector ny0(N);
2279 compute_normal(ctx_y, face_y, ref_conf, coeff_y, ny0, n_y, grad);
2281 signed_dist *= gmm::sgn(gmm::vect_sp(pt_x - pt_y, n_y));
2285 if (first_pair_found && stored_signed_distance < signed_dist)
2289 if (gmm::vect_sp(n_y, n_x) >= scalar_type(0))
continue;
2295 base_small_vector diff = ctx_x.xreal() - ctx_y.xreal();
2298 if ( (ref_dist < scalar_type(4) * release_distance)
2299 && (gmm::vect_sp(diff, ny0) < - 0.01 * ref_dist) )
2303 stored_pt_y = pt_y; stored_pt_y_ref = ctx_y.xref();
2304 stored_m_y = &m_y; stored_cv_y = cv_y; stored_face_y = face_y;
2306 stored_ctx_y = ctx_y;
2307 stored_coeff_y = coeff_y;
2308 stored_signed_distance = signed_dist;
2309 stored_dispname = cb_y.dispname;
2310 first_pair_found =
true;
2322 P_ref = stored_pt_y; N_y = stored_n_y;
2324 }
else if (first_pair_found) {
2325 *m_t = stored_m_y; cv = stored_cv_y; face_num = stored_face_y;
2326 P_ref = stored_pt_y_ref;
2335 if (compute_derivatives) {
2336 if (ret_type >= 1) {
2337 fem_interpolation_context &ctx_y = stored_ctx_y;
2339 if (ret_type == 1) cv_y = ctx_y.convex_num();
2342 base_matrix I_nyny(N,N);
2343 gmm::copy(gmm::identity_matrix(), I_nyny);
2344 gmm::rank_one_update(I_nyny, stored_n_y,
2345 gmm::scaled(stored_n_y,scalar_type(-1)));
2348 base_matrix F_y(N,N), F_y_inv(N,N), M1(N, N), M2(N, N);
2350 if (ret_type == 1) {
2352 pfu_y->interpolation_grad(ctx_y, stored_coeff_y, F_y, dim_type(N));
2353 gmm::add(gmm::identity_matrix(), F_y);
2354 gmm::copy(F_y, F_y_inv);
2355 gmm::lu_inverse(F_y_inv);
2357 gmm::copy(gmm::identity_matrix(), F_y);
2358 gmm::copy(gmm::identity_matrix(), F_y_inv);
2362 base_tensor base_ux;
2363 base_matrix vbase_ux;
2364 ctx_x.base_value(base_ux);
2365 size_type qdim_ux = pfu_x->target_dim();
2366 size_type ndof_ux = pfu_x->nb_dof(cv_x) * N / qdim_ux;
2367 vectorize_base_tensor(base_ux, vbase_ux, ndof_ux, qdim_ux, N);
2369 base_tensor base_uy;
2370 base_matrix vbase_uy;
2372 if (ret_type == 1) {
2373 ctx_y.base_value(base_uy);
2374 size_type qdim_uy = pfu_y->target_dim();
2375 ndof_uy = pfu_y->nb_dof(cv_y) * N / qdim_uy;
2376 vectorize_base_tensor(base_uy, vbase_uy, ndof_uy, qdim_uy, N);
2379 base_tensor grad_base_ux, vgrad_base_ux;
2380 ctx_x.grad_base_value(grad_base_ux);
2381 vectorize_grad_base_tensor(grad_base_ux, vgrad_base_ux, ndof_ux,
2388 gmm::mult(F_y_inv, I_nyny, M1);
2389 base_matrix der_x(ndof_ux, N);
2390 gmm::mult(vbase_ux, gmm::transposed(M1), der_x);
2393 base_matrix der_y(ndof_uy, N);
2394 if (ret_type == 1) {
2395 gmm::mult(vbase_uy, gmm::transposed(M1), der_y);
2396 gmm::scale(der_y, scalar_type(-1));
2399 const std::string &dispname_x
2400 = workspace.variable_in_group(cb_x.dispname, m_x);
2402 for (
auto&& d : derivatives) {
2403 if (dispname_x.compare(d.first.varname) == 0 &&
2404 d.first.transname.size() == 0) {
2405 d.second.adjust_sizes(ndof_ux, N);
2406 gmm::copy(der_x.as_vector(), d.second.as_vector());
2407 }
else if (ret_type == 1 &&
2408 stored_dispname.compare(d.first.varname) == 0 &&
2409 d.first.transname.size() != 0) {
2410 d.second.adjust_sizes(ndof_uy, N);
2411 gmm::copy(der_y.as_vector(), d.second.as_vector());
2413 d.second.adjust_sizes(0, 0);
2416 for (
auto&& d : derivatives)
2417 d.second.adjust_sizes(0, 0);
2422 projection_interpolate_transformation(
const scalar_type &d)
2423 :raytracing_interpolate_transformation(d), release_distance(d) {}
2426 (
model &md,
const std::string &transname, scalar_type d) {
2427 pinterpolate_transformation
2428 p = std::make_shared<raytracing_interpolate_transformation>(d);
2433 (ga_workspace &workspace,
const std::string &transname, scalar_type d) {
2434 pinterpolate_transformation
2435 p = std::make_shared<raytracing_interpolate_transformation>(d);
2436 workspace.add_interpolate_transformation(transname, p);
2441 const std::string &dispname,
size_type region) {
2442 raytracing_interpolate_transformation *p
2443 =
dynamic_cast<raytracing_interpolate_transformation *
>
2444 (
const_cast<virtual_interpolate_transformation *
>
2446 p->add_contact_boundary(md, m, dispname, region,
false);
2451 const std::string &dispname,
size_type region) {
2452 raytracing_interpolate_transformation *p
2453 =
dynamic_cast<raytracing_interpolate_transformation *
>
2454 (
const_cast<virtual_interpolate_transformation *
>
2456 p->add_contact_boundary(md, m, dispname, region,
true);
2460 (ga_workspace &workspace,
const std::string &transname,
const mesh &m,
2461 const std::string &dispname,
size_type region) {
2462 raytracing_interpolate_transformation *p
2463 =
dynamic_cast<raytracing_interpolate_transformation *
>
2464 (
const_cast<virtual_interpolate_transformation *
>
2465 (&(*(workspace.interpolate_transformation(transname)))));
2466 p->add_contact_boundary(workspace, m, dispname, region,
false);
2470 (ga_workspace &workspace,
const std::string &transname,
const mesh &m,
2471 const std::string &dispname,
size_type region) {
2472 raytracing_interpolate_transformation *p
2473 =
dynamic_cast<raytracing_interpolate_transformation *
>
2474 (
const_cast<virtual_interpolate_transformation *
>
2475 (&(*(workspace.interpolate_transformation(transname)))));
2476 p->add_contact_boundary(workspace, m, dispname, region,
true);
2480 (
model &md,
const std::string &transname,
2482 raytracing_interpolate_transformation *p
2483 =
dynamic_cast<raytracing_interpolate_transformation *
>
2484 (
const_cast<virtual_interpolate_transformation *
>
2486 p->add_rigid_obstacle(md, expr, N);
2490 (ga_workspace &workspace,
const std::string &transname,
2492 raytracing_interpolate_transformation *p
2493 =
dynamic_cast<raytracing_interpolate_transformation *
>
2494 (
const_cast<virtual_interpolate_transformation *
>
2495 (&(*(workspace.interpolate_transformation(transname)))));
2496 p->add_rigid_obstacle(workspace, expr, N);
2500 (
model &md,
const std::string &transname, scalar_type d) {
2501 pinterpolate_transformation
2502 p = std::make_shared<projection_interpolate_transformation>(d);
2507 (ga_workspace &workspace,
const std::string &transname, scalar_type d) {
2508 pinterpolate_transformation
2509 p = std::make_shared<projection_interpolate_transformation>(d);
2510 workspace.add_interpolate_transformation(transname, p);
2515 const std::string &dispname,
size_type region) {
2516 projection_interpolate_transformation *p
2517 =
dynamic_cast<projection_interpolate_transformation *
>
2518 (
const_cast<virtual_interpolate_transformation *
>
2520 p->add_contact_boundary(md, m, dispname, region,
false);
2525 const std::string &dispname,
size_type region) {
2526 projection_interpolate_transformation *p
2527 =
dynamic_cast<projection_interpolate_transformation *
>
2528 (
const_cast<virtual_interpolate_transformation *
>
2530 p->add_contact_boundary(md, m, dispname, region,
true);
2534 (ga_workspace &workspace,
const std::string &transname,
const mesh &m,
2535 const std::string &dispname,
size_type region) {
2536 projection_interpolate_transformation *p
2537 =
dynamic_cast<projection_interpolate_transformation *
>
2538 (
const_cast<virtual_interpolate_transformation *
>
2539 (&(*(workspace.interpolate_transformation(transname)))));
2540 p->add_contact_boundary(workspace, m, dispname, region,
false);
2544 (ga_workspace &workspace,
const std::string &transname,
const mesh &m,
2545 const std::string &dispname,
size_type region) {
2546 projection_interpolate_transformation *p
2547 =
dynamic_cast<projection_interpolate_transformation *
>
2548 (
const_cast<virtual_interpolate_transformation *
>
2549 (&(*(workspace.interpolate_transformation(transname)))));
2550 p->add_contact_boundary(workspace, m, dispname, region,
true);
2554 (
model &md,
const std::string &transname,
2556 projection_interpolate_transformation *p
2557 =
dynamic_cast<projection_interpolate_transformation *
>
2558 (
const_cast<virtual_interpolate_transformation *
>
2560 p->add_rigid_obstacle(md, expr, N);
2564 (ga_workspace &workspace,
const std::string &transname,
2566 projection_interpolate_transformation *p
2567 =
dynamic_cast<projection_interpolate_transformation *
>
2568 (
const_cast<virtual_interpolate_transformation *
>
2569 (&(*(workspace.interpolate_transformation(transname)))));
2570 p->add_rigid_obstacle(workspace, expr, N);
2583 static void ga_init_vector(bgeot::multi_index &mi,
size_type N)
2584 { mi.resize(1); mi[0] = N; }
2590 struct Transformed_unit_vector :
public ga_nonlinear_operator {
2591 bool result_size(
const arg_list &args, bgeot::multi_index &sizes)
const {
2592 if (args.size() != 2 || args[0]->sizes().size() != 2
2593 || args[1]->size() != args[0]->sizes()[0]
2594 || args[0]->sizes()[0] != args[0]->sizes()[1])
return false;
2595 ga_init_vector(sizes, args[0]->sizes()[0]);
2600 void value(
const arg_list &args, base_tensor &result)
const {
2602 base_matrix F(N, N);
2603 gmm::copy(args[0]->as_vector(), F.as_vector());
2604 gmm::add(gmm::identity_matrix(), F);
2605 bgeot::lu_inverse(&(*(F.begin())), N);
2606 gmm::mult(gmm::transposed(F), args[1]->as_vector(), result.as_vector());
2607 gmm::scale(result.as_vector(),
2608 scalar_type(1)/gmm::vect_norm2(result.as_vector()));
2619 void derivative(
const arg_list &args,
size_type nder,
2620 base_tensor &result)
const {
2622 base_matrix F(N, N), G(N, N);
2623 base_small_vector ndef(N), aux(N);
2624 gmm::copy(args[0]->as_vector(), F.as_vector());
2625 gmm::add(gmm::identity_matrix(), F);
2626 bgeot::lu_inverse(&(*(F.begin())), N);
2627 gmm::mult(gmm::transposed(F), args[1]->as_vector(), ndef);
2629 gmm::scale(ndef, scalar_type(1)/norm_ndef);
2630 gmm::copy(gmm::transposed(F), G);
2631 gmm::mult(F, ndef, aux);
2632 gmm::rank_one_update(G, gmm::scaled(ndef, scalar_type(-1)), aux);
2633 base_tensor::iterator it = result.begin();
2639 *it = -G(i, k) * ndef[j];
2644 *it = (F(j,i) - ndef[i]*ndef[j])/norm_ndef;
2646 default: GMM_ASSERT1(
false,
"Internal error");
2648 GMM_ASSERT1(it == result.end(),
"Internal error");
2653 base_tensor &)
const {
2654 GMM_ASSERT1(
false,
"Sorry, second derivative not implemented");
2660 struct Coulomb_friction_coupled_projection :
public ga_nonlinear_operator {
2661 bool result_size(
const arg_list &args, bgeot::multi_index &sizes)
const {
2662 if (args.size() != 6)
return false;
2664 if (N == 0 || args[1]->size() != N || args[2]->size() != N
2665 || args[3]->size() != 1 || args[4]->size() > 3
2666 || args[4]->size() == 0 || args[5]->size() != 1 )
return false;
2667 ga_init_vector(sizes, N);
2672 void value(
const arg_list &args, base_tensor &result)
const {
2673 const base_vector &lambda = *(args[0]);
2674 const base_vector &n = *(args[1]);
2675 const base_vector &Vs = *(args[2]);
2676 base_vector &F = result;
2677 scalar_type g = (*(args[3]))[0];
2678 const base_vector &f = *(args[4]);
2679 scalar_type r = (*(args[5]))[0];
2683 scalar_type lambdan = gmm::vect_sp(lambda, n)/nn;
2684 scalar_type lambdan_aug = gmm::neg(lambdan + r * g);
2686 scalar_type tau = ((s_f >= 3) ? f[2] : scalar_type(0)) + f[0]*lambdan_aug;
2687 if (s_f >= 2) tau = std::min(tau, f[1]);
2689 if (tau > scalar_type(0)) {
2690 gmm::add(lambda, gmm::scaled(Vs, -r), F);
2691 scalar_type mu = gmm::vect_sp(F, n)/nn;
2692 gmm::add(gmm::scaled(n, -mu/nn), F);
2694 if (norm > tau) gmm::scale(F, tau / norm);
2697 gmm::add(gmm::scaled(n, -lambdan_aug/nn), F);
2708 void derivative(
const arg_list &args,
size_type nder,
2709 base_tensor &result)
const {
2711 const base_vector &lambda = *(args[0]);
2712 const base_vector &n = *(args[1]);
2713 const base_vector &Vs = *(args[2]);
2714 base_vector F(N), dg(N);
2715 base_matrix dVs(N,N), dn(N,N);
2716 scalar_type g = (*(args[3]))[0];
2717 const base_vector &f = *(args[4]);
2718 scalar_type r = (*(args[5]))[0];
2721 scalar_type lambdan = gmm::vect_sp(lambda, n)/nn;
2722 scalar_type lambdan_aug = gmm::neg(lambdan + r * g);
2724 scalar_type tau = ((s_f >= 3) ? f[2] : scalar_type(0))+f[0]*lambdan_aug;
2725 if (s_f >= 2) tau = std::min(tau, f[1]);
2726 scalar_type norm(0);
2728 if (tau > scalar_type(0)) {
2729 gmm::add(lambda, gmm::scaled(Vs, -r), F);
2730 scalar_type mu = gmm::vect_sp(F, n)/nn;
2731 gmm::add(gmm::scaled(n, -mu/nn), F);
2733 gmm::copy(gmm::identity_matrix(), dn);
2734 gmm::scale(dn, -mu/nn);
2735 gmm::rank_one_update(dn, gmm::scaled(n, mu/(nn*nn*nn)), n);
2736 gmm::rank_one_update(dn, gmm::scaled(n, scalar_type(-1)/(nn*nn)), F);
2737 gmm::copy(gmm::identity_matrix(), dVs);
2738 gmm::rank_one_update(dVs, n, gmm::scaled(n, scalar_type(-1)/(nn*nn)));
2741 gmm::rank_one_update(dVs, F,
2742 gmm::scaled(F, scalar_type(-1)/(norm*norm)));
2743 gmm::scale(dVs, tau / norm);
2744 gmm::copy(gmm::scaled(F, scalar_type(1)/norm), dg);
2745 gmm::rank_one_update(dn, gmm::scaled(F, mu/(norm*norm*nn)), F);
2746 gmm::scale(dn, tau / norm);
2747 gmm::scale(F, tau / norm);
2755 base_tensor::iterator it = result.begin();
2758 if (norm > tau && ((s_f <= 1) || tau < f[1]) &&
2759 ((s_f <= 2) || tau > f[2]))
2760 gmm::rank_one_update(dVs, dg, gmm::scaled(n, -f[0]/nn));
2761 if (lambdan_aug > scalar_type(0))
2762 gmm::rank_one_update(dVs, n, gmm::scaled(n, scalar_type(1)/(nn*nn)));
2768 if (norm > tau && ((s_f <= 1) || tau < f[1])
2769 && ((s_f <= 2) || tau > f[2])) {
2770 gmm::rank_one_update(dn, dg, gmm::scaled(lambda, -f[0]/nn));
2771 gmm::rank_one_update(dn, dg, gmm::scaled(n, f[0]*lambdan/(nn*nn)));
2773 if (lambdan_aug > scalar_type(0)) {
2774 gmm::rank_one_update(dn, gmm::scaled(n, scalar_type(1)/(nn*nn)),
2776 gmm::rank_one_update(dn,
2777 gmm::scaled(n,(lambdan_aug-lambdan)/(nn*nn*nn)), n);
2778 for (
size_type j = 0; j < N; ++j) dn(j,j) -= lambdan_aug/nn;
2785 gmm::scale(dVs, -r);
2791 if (norm > tau && ((s_f <= 1) || tau < f[1])
2792 && ((s_f <= 2) || tau > f[2]))
2793 gmm::scale(dg, -f[0]*r);
2796 if (lambdan_aug > scalar_type(0))
2797 gmm::add(gmm::scaled(n, r/nn), dg);
2802 if (norm > tau && ((s_f <= 1) || tau < f[1])
2803 && ((s_f <= 2) || tau > f[2]))
2804 gmm::scale(dg, -f[0]*g);
2808 if (lambdan_aug > scalar_type(0))
2809 gmm::add(gmm::scaled(n, g/nn), dg);
2815 base_small_vector dtau_df(s_f);
2816 if ((s_f <= 1) || tau < f[1]) dtau_df[0] = lambdan_aug;
2817 if (s_f >= 2 && tau == f[1]) dtau_df[1] = 1;
2818 if (s_f >= 3 && tau < f[1]) dtau_df[2] = 1;
2821 *it = dg[i] * dtau_df[j];
2824 GMM_ASSERT1(it == result.end(),
"Internal error");
2829 base_tensor &)
const {
2830 GMM_ASSERT1(
false,
"Sorry, second derivative not implemented");
2834 static bool init_predef_operators() {
2836 ga_predef_operator_tab &PREDEF_OPERATORS
2839 PREDEF_OPERATORS.add_method(
"Transformed_unit_vector",
2840 std::make_shared<Transformed_unit_vector>());
2841 PREDEF_OPERATORS.add_method(
"Coulomb_friction_coupled_projection",
2842 std::make_shared<Coulomb_friction_coupled_projection>());
2848 bool predef_operators_contact_initialized
2849 = init_predef_operators();