29 bool boundary_has_fem_nodes(
bool slave_flag,
int nodes_mode) {
30 return (slave_flag && nodes_mode) ||
31 (!slave_flag && nodes_mode == 2);
36 const model_real_plain_vector &coeff,
37 base_node &n0, base_node &n,
40 if (in_reference_conf) {
43 ctx.pf()->interpolation_grad(ctx, coeff, grad, dim_type(ctx.N()));
44 gmm::add(gmm::identity_matrix(), grad);
45 scalar_type J = bgeot::lu_inverse(&(*(grad.begin())), ctx.N());
46 if (J <= scalar_type(0)) {GMM_WARNING1(
"Inverted element !" << J);
48 gmm::scale(n, gmm::sgn(J));
54 gmm::scale(n, gmm::sgn(J));}
66 (
const model_real_plain_vector *U,
const std::string &name,
67 const model_real_plain_vector *w,
const std::string &wname) {
70 for (; i < Us.size(); ++i)
if (Us[i] == U)
return i;
73 Unames.push_back(name);
74 Wnames.push_back(wname);
75 ext_Us.resize(Us.size());
76 ext_Ws.resize(Us.size());
81 (
const model_real_plain_vector *lambda,
const std::string &name) {
84 for (; i < lambdas.size(); ++i)
if (lambdas[i] == lambda)
return i;
85 lambdas.push_back(lambda);
86 lambdanames.push_back(name);
87 ext_lambdas.resize(lambdas.size());
91 void multi_contact_frame::extend_vectors() {
92 dal::bit_vector iU, ilambda;
93 for (
size_type i = 0; i < contact_boundaries.size(); ++i) {
94 size_type ind_U = contact_boundaries[i].ind_U;
96 const mesh_fem &mf = *(contact_boundaries[i].mfu);
98 mf.extend_vector(*(Us[ind_U]), ext_Us[ind_U]);
101 mf.extend_vector(*(Ws[ind_U]), ext_Ws[ind_U]);
105 size_type ind_lambda = contact_boundaries[i].ind_lambda;
106 if (ind_lambda !=
size_type(-1) && !(ilambda[ind_lambda])) {
107 const mesh_fem &mf = *(contact_boundaries[i].mflambda);
108 gmm::resize(ext_lambdas[ind_lambda], mf.nb_basic_dof());
109 mf.extend_vector(*(lambdas[ind_lambda]), ext_lambdas[ind_lambda]);
110 ilambda.add(ind_lambda);
115 void multi_contact_frame::normal_cone_simplification() {
117 scalar_type threshold = ::cos(cut_angle);
118 for (
size_type i = 0; i < boundary_points_info.size(); ++i) {
119 normal_cone &nc = boundary_points_info[i].normals;
121 base_small_vector n_mean = nc[0];
122 for (
size_type j = 1; j < nc.size(); ++j) n_mean += nc[j];
124 GMM_ASSERT1(nn_mean != scalar_type(0),
"oupssss");
125 if (nn_mean != scalar_type(0)) {
126 gmm::scale(n_mean, scalar_type(1)/nn_mean);
128 for (
size_type j = 0; j < nc.size(); ++j)
129 if (gmm::vect_sp(n_mean, nc[j]) < threshold)
130 { reduce =
false;
break; }
132 boundary_points_info[i].normals = normal_cone(n_mean);
140 bool multi_contact_frame::test_normal_cones_compatibility
141 (
const normal_cone &nc1,
const normal_cone &nc2) {
142 for (
size_type i = 0; i < nc1.size(); ++i)
143 for (
size_type j = 0; j < nc2.size(); ++j)
144 if (gmm::vect_sp(nc1[i], nc2[j]) < scalar_type(0))
149 bool multi_contact_frame::test_normal_cones_compatibility
150 (
const base_small_vector &n,
const normal_cone &nc2) {
151 for (
size_type j = 0; j < nc2.size(); ++j)
152 if (gmm::vect_sp(n, nc2[j]) < scalar_type(0))
159 const mesh_fem &mf1 = mfdisp_of_boundary(ib1);
160 const mesh_fem &mf2 = mfdisp_of_boundary(ib2);
161 if ( &(mf1.linked_mesh()) != &(mf2.linked_mesh()))
return false;
162 GMM_ASSERT1(!(mf1.is_reduced()) && !(mf2.is_reduced()),
163 "Nodal strategy can only be applied for non reduced fems");
164 const mesh::ind_cv_ct &ic1 = mf1.convex_to_basic_dof(idof1);
165 const mesh::ind_cv_ct &ic2 = mf2.convex_to_basic_dof(idof2);
167 for (
size_type i = 0; i < ic1.size(); ++i) aux_dof_cv.add(ic1[i]);
168 for (
size_type i = 0; i < ic2.size(); ++i)
169 if (aux_dof_cv.is_in(ic2[i])) { lk =
true;
break; }
170 for (
size_type i = 0; i < ic1.size(); ++i) aux_dof_cv.sup(ic1[i]);
176 const mesh_fem &mf1 = mfdisp_of_boundary(ib1);
177 const mesh_fem &mf2 = mfdisp_of_boundary(ib2);
178 if ( &(mf1.linked_mesh()) != &(mf2.linked_mesh()))
return false;
179 GMM_ASSERT1(!(mf1.is_reduced()) && !(mf2.is_reduced()),
180 "Nodal strategy can only be applied for non reduced fems");
181 const mesh::ind_cv_ct &ic1 = mf1.convex_to_basic_dof(idof1);
182 for (
size_type i = 0; i < ic1.size(); ++i)
183 if (cv == ic1[i])
return true;
187 void multi_contact_frame::add_potential_contact_face
190 std::vector<face_info> &sfi = potential_pairs[ip];
191 for (
size_type k = 0; k < sfi.size(); ++k)
192 if (sfi[k].ind_boundary == ib &&
193 sfi[k].ind_element == ie &&
194 sfi[k].ind_face == iff) found =
true;
196 if (!found) sfi.push_back(face_info(ib, ie, iff));
199 void multi_contact_frame::clear_aux_info() {
200 boundary_points = std::vector<base_node>();
201 boundary_points_info = std::vector<boundary_point>();
202 element_boxes.clear();
203 element_boxes_info = std::vector<influence_box>();
204 potential_pairs = std::vector<std::vector<face_info> >();
207 multi_contact_frame::multi_contact_frame(
size_type NN, scalar_type r_dist,
208 bool dela,
bool selfc,
210 bool rayt,
int nmode,
bool refc)
211 : N(NN), self_contact(selfc), ref_conf(refc), use_delaunay(dela),
212 nodes_mode(nmode), raytrace(rayt), release_distance(r_dist),
213 cut_angle(cut_a), EPS(1E-8), md(0), coordinates(N), pt(N) {
214 if (N > 0) coordinates[0] =
"x";
215 if (N > 1) coordinates[1] =
"y";
216 if (N > 2) coordinates[2] =
"z";
217 if (N > 3) coordinates[3] =
"w";
218 GMM_ASSERT1(N <= 4,
"Complete the definition for contact in "
219 "dimension greater than 4");
222 multi_contact_frame::multi_contact_frame(
const model &mdd,
size_type NN,
224 bool dela,
bool selfc,
226 bool rayt,
int nmode,
bool refc)
227 : N(NN), self_contact(selfc), ref_conf(refc),
228 use_delaunay(dela), nodes_mode(nmode), raytrace(rayt),
229 release_distance(r_dist), cut_angle(cut_a), EPS(1E-8), md(&mdd),
230 coordinates(N), pt(N) {
231 if (N > 0) coordinates[0] =
"x";
232 if (N > 1) coordinates[1] =
"y";
233 if (N > 2) coordinates[2] =
"z";
234 if (N > 3) coordinates[3] =
"w";
235 GMM_ASSERT1(N <= 4,
"Complete the definition for contact in "
236 "dimension greater than 4");
239 size_type multi_contact_frame::add_obstacle(
const std::string &obs) {
241 obstacles.push_back(obs);
242 obstacles_velocities.push_back(
"");
243 obstacles_gw.push_back(ga_workspace());
244 pt.resize(N); ptx.resize(1); pty.resize(1); ptz.resize(1); ptw.resize(1);
245 obstacles_gw.back().add_fixed_size_constant(
"X", pt);
246 if (N >= 4) obstacles_gw.back().add_fixed_size_constant(
"w", ptw);
247 if (N >= 3) obstacles_gw.back().add_fixed_size_constant(
"z", ptz);
248 if (N >= 2) obstacles_gw.back().add_fixed_size_constant(
"y", pty);
249 if (N >= 1) obstacles_gw.back().add_fixed_size_constant(
"x", ptx);
250 obstacles_f.push_back(ga_function(obstacles_gw.back(), obs));
251 obstacles_f.back().compile();
257 size_type multi_contact_frame::add_master_boundary
258 (
const mesh_im &mim,
const mesh_fem *mfu,
259 const model_real_plain_vector *U,
size_type reg,
260 const mesh_fem *mflambda,
const model_real_plain_vector *lambda,
261 const model_real_plain_vector *w,
262 const std::string &vvarname,
263 const std::string &mmultname,
const std::string &wname) {
264 GMM_ASSERT1(mfu->linked_mesh().dim() == N,
265 "Mesh dimension is " << mfu->linked_mesh().dim()
266 <<
"should be " << N <<
".");
267 GMM_ASSERT1(&(mfu->linked_mesh()) == &(mim.linked_mesh()),
268 "Integration and finite element are not on the same mesh !");
270 GMM_ASSERT1(&(mflambda->linked_mesh()) == &(mim.linked_mesh()),
271 "Integration and finite element are not on the same mesh !");
272 contact_boundary cb(reg, mfu, mim, add_U(U, vvarname, w, wname),
273 mflambda, add_lambda(lambda, mmultname));
274 contact_boundaries.push_back(cb);
275 return size_type(contact_boundaries.size() - 1);
278 size_type multi_contact_frame::add_slave_boundary
279 (
const mesh_im &mim,
const mesh_fem *mfu,
280 const model_real_plain_vector *U,
size_type reg,
281 const mesh_fem *mflambda,
const model_real_plain_vector *lambda,
282 const model_real_plain_vector *w,
283 const std::string &vvarname,
284 const std::string &mmultname,
const std::string &wname) {
286 = add_master_boundary(mim, mfu, U, reg, mflambda, lambda, w,
287 vvarname, mmultname, wname);
288 contact_boundaries[ind].slave =
true;
293 size_type multi_contact_frame::add_master_boundary
294 (
const mesh_im &mim,
size_type reg,
const std::string &vvarname,
295 const std::string &mmultname,
const std::string &wname) {
296 GMM_ASSERT1(md,
"This multi contact frame object is not linked "
298 const mesh_fem *mfl(0);
299 const model_real_plain_vector *l(0);
300 if (mmultname.size()) {
301 mfl = &(md->mesh_fem_of_variable(mmultname));
302 l = &(md->real_variable(mmultname));
304 const model_real_plain_vector *w(0);
305 if (wname.compare(vvarname) == 0) {
306 GMM_ASSERT1(md->n_iter_of_variable(vvarname) > 1,
"More than one "
307 "versions of the displacement variable were expected here");
308 w = &(md->real_variable(vvarname,1));
310 else if (wname.size()) {
311 GMM_ASSERT1(&(md->mesh_fem_of_variable(wname))
312 == &(md->mesh_fem_of_variable(vvarname)),
"The previous "
313 "displacement should be defined on the same mesh_fem as the "
315 w = &(md->real_variable(wname));
317 return add_master_boundary(mim, &(md->mesh_fem_of_variable(vvarname)),
318 &(md->real_variable(vvarname)), reg, mfl, l, w,
319 vvarname, mmultname, wname);
322 size_type multi_contact_frame::add_slave_boundary
323 (
const mesh_im &mim,
size_type reg,
const std::string &vvarname,
324 const std::string &mmultname,
const std::string &wname) {
325 GMM_ASSERT1(md,
"This multi contact frame object is not linked "
327 const mesh_fem *mfl(0);
328 const model_real_plain_vector *l(0);
329 if (mmultname.size()) {
330 mfl = &(md->mesh_fem_of_variable(mmultname));
331 l = &(md->real_variable(mmultname));
333 const model_real_plain_vector *w(0);
334 if (wname.compare(vvarname) == 0) {
335 GMM_ASSERT1(md->n_iter_of_variable(vvarname) > 1,
"More than one "
336 "versions of the displacement variable were expected here");
337 w = &(md->real_variable(vvarname,1));
339 else if (wname.size()) {
340 GMM_ASSERT1(&(md->mesh_fem_of_variable(wname))
341 == &(md->mesh_fem_of_variable(vvarname)),
"The previous "
342 "displacement should be defined on the same mesh_fem as the "
344 w = &(md->real_variable(wname));
346 return add_slave_boundary(mim, &(md->mesh_fem_of_variable(vvarname)),
347 &(md->real_variable(vvarname)), reg, mfl, l, w,
348 vvarname, mmultname, wname);
352 void multi_contact_frame::compute_boundary_points(
bool slave_only) {
353 fem_precomp_pool fppool;
355 model_real_plain_vector coeff;
357 for (
size_type i = 0; i < contact_boundaries.size(); ++i)
358 if (!slave_only || is_slave_boundary(i)) {
360 const mesh_fem &mfu = mfdisp_of_boundary(i);
361 const mesh_im &mim = mim_of_boundary(i);
362 const model_real_plain_vector &U = disp_of_boundary(i);
363 const mesh &m = mfu.linked_mesh();
365 boundary_has_fem_nodes(is_slave_boundary(i), nodes_mode);
367 base_node val(N), bmin(N), bmax(N);
368 base_small_vector n0(N), n(N), n_mean(N);
369 base_matrix grad(N,N);
370 mesh_region region = m.region(bnum);
371 GMM_ASSERT1(mfu.get_qdim() == N,
"Wrong mesh_fem qdim");
374 dal::bit_vector dof_already_interpolated;
375 std::vector<size_type> dof_ind(mfu.nb_basic_dof());
379 pfem pf_s = mfu.fem_of_element(cv);
383 mfu.linked_mesh().points_of_convex(cv, G);
387 std::vector<size_type> indpt, indpfp;
389 dim_type qqdim = mfu.get_qdim() / pf_s->target_dim();
390 pfp = fppool(pf_s, pf_s->node_tab(cv));
391 nbptf = pf_s->node_convex(cv).structure()->nb_points_of_face(v.f());
392 indpt.resize(nbptf); indpfp.resize(nbptf);
395 mfu.ind_basic_dof_of_face_of_element(cv,v.f())[ip*qqdim];
397 pf_s->node_convex(cv).structure()->ind_points_of_face(v.f())[ip];
401 pintegration_method pim = mim.int_method_of_element(cv);
402 GMM_ASSERT1(pim,
"Integration method should be defined");
403 pfp = fppool(pf_s, pim->approx_method()->pintegration_points());
404 nbptf = pim->approx_method()->nb_points_on_face(v.f());
405 indpt.resize(nbptf); indpfp.resize(nbptf);
407 indpt[ip] = indpfp[ip] =
408 pim->approx_method()->ind_first_point_on_face(v.f())+ip;
410 fem_interpolation_context ctx(pgt,pfp,
size_type(-1),G,cv,v.f());
413 ctx.set_ii(indpfp[ip]);
416 if (!(on_fem_nodes && dof_already_interpolated[ind])) {
418 pf_s->interpolation(ctx, coeff, val, dim_type(N));
423 if (on_fem_nodes) dof_ind[ind] = boundary_points.size();
431 if (on_fem_nodes && dof_already_interpolated[ind]) {
432 boundary_points_info[dof_ind[ind]].normals.add_normal(n);
434 boundary_points.push_back(val);
435 boundary_points_info.push_back(boundary_point(ctx.xreal(), i, cv,
439 if (on_fem_nodes) dof_already_interpolated.add(ind);
445 void multi_contact_frame::compute_potential_contact_pairs_delaunay() {
447 compute_boundary_points();
448 normal_cone_simplification();
449 potential_pairs = std::vector<std::vector<face_info> >();
450 potential_pairs.resize(boundary_points.size());
452 gmm::dense_matrix<size_type> simplexes;
453 base_small_vector rr(N);
459 bgeot::qhull_delaunay(boundary_points, simplexes);
462 for (
size_type is = 0; is < gmm::mat_ncols(simplexes); ++is) {
466 size_type ipt1 = simplexes(i, is), ipt2 = simplexes(j, is);
467 boundary_point *pt_info1 = &(boundary_points_info[ipt1]);
468 boundary_point *pt_info2 = &(boundary_points_info[ipt2]);
471 bool sl1 = is_slave_boundary(ib1);
472 bool sl2 = is_slave_boundary(ib2);
474 std::swap(ipt1, ipt2);
475 std::swap(pt_info1, pt_info2);
481 const mesh_fem &mf1 = mfdisp_of_boundary(ib1);
482 const mesh_fem &mf2 = mfdisp_of_boundary(ib2);
490 || (self_contact && !sl1 && !sl2))
492 && test_normal_cones_compatibility(pt_info1->normals,
498 && (( &(mf1.linked_mesh()) != &(mf2.linked_mesh()))
499 || (pt_info1->ind_element != pt_info2->ind_element)))
500 || ((nodes_mode == 2)
501 && !(are_dof_linked(ib1, pt_info1->ind_pt,
502 ib2, pt_info2->ind_pt)))
508 if (boundary_has_fem_nodes(sl2, nodes_mode)) {
509 const mesh::ind_cv_ct &ic2
510 = mf2.convex_to_basic_dof(pt_info2->ind_pt);
511 for (
size_type k = 0; k < ic2.size(); ++k) {
512 mesh_region::face_bitset fbs
513 = mf2.linked_mesh().region(ir2).faces_of_convex(ic2[k]);
514 short_type nbf = mf2.linked_mesh().nb_faces_of_convex(ic2[k]);
517 add_potential_contact_face(ipt1,
518 pt_info2->ind_boundary,
522 add_potential_contact_face(ipt1, pt_info2->ind_boundary,
523 pt_info2->ind_element,
526 if (self_contact && !sl1 && !sl2) {
527 if (boundary_has_fem_nodes(sl2, nodes_mode)) {
528 const mesh::ind_cv_ct &ic1
529 = mf1.convex_to_basic_dof(pt_info1->ind_pt);
530 for (
size_type k = 0; k < ic1.size(); ++k) {
531 mesh_region::face_bitset fbs
532 = mf1.linked_mesh().region(ir1).faces_of_convex(ic1[k]);
533 short_type nbf = mf1.linked_mesh().nb_faces_of_convex(ic1[k]);
536 add_potential_contact_face(ipt2,
537 pt_info1->ind_boundary,
541 add_potential_contact_face(ipt2, pt_info1->ind_boundary,
542 pt_info1->ind_element,
553 void multi_contact_frame::compute_influence_boxes() {
554 fem_precomp_pool fppool;
557 model_real_plain_vector coeff;
559 for (
size_type i = 0; i < contact_boundaries.size(); ++i)
560 if (!is_slave_boundary(i)) {
562 const mesh_fem &mfu = mfdisp_of_boundary(i);
563 const model_real_plain_vector &U = disp_of_boundary(i);
564 const mesh &m = mfu.linked_mesh();
566 base_node val(N), bmin(N), bmax(N);
567 base_small_vector n0(N), n(N), n_mean(N);
568 base_matrix grad(N,N);
569 mesh_region region = m.region(bnum);
570 GMM_ASSERT1(mfu.get_qdim() == N,
"Wrong mesh_fem qdim");
572 dal::bit_vector points_already_interpolated;
573 std::vector<base_node> transformed_points(m.nb_max_points());
577 pfem pf_s = mfu.fem_of_element(cv);
578 pfem_precomp pfp = fppool(pf_s, pgt->pgeometric_nodes());
581 mfu.linked_mesh().points_of_convex(cv, G);
582 fem_interpolation_context ctx(pgt,pfp,
size_type(-1), G, cv);
585 dal::bit_vector points_on_face;
587 for (
size_type k = 0; k < cvs->nb_points_of_face(v.f()); ++k)
588 points_on_face.add(cvs->ind_points_of_face(v.f())[k]);
593 size_type ind = m.ind_points_of_convex(cv)[ip];
597 if (!(points_already_interpolated.is_in(ind))) {
599 pf_s->interpolation(ctx, coeff, val, dim_type(N));
601 transformed_points[ind] = val;
603 transformed_points[ind] = ctx.xreal();
605 points_already_interpolated.add(ind);
607 val = transformed_points[ind];
610 if (points_on_face[ip]) {
621 bmin[k] = std::min(bmin[k], val[k]);
622 bmax[k] = std::max(bmax[k], val[k]);
629 GMM_ASSERT1(nb_pt_on_face,
630 "This element has no vertex on considered face !");
634 scalar_type h = bmax[0] - bmin[0];
635 for (
size_type k = 1; k < N; ++k) h = std::max(h, bmax[k]-bmin[k]);
636 if (h < release_distance/scalar_type(40) && !avert) {
637 GMM_WARNING1(
"Found an element whose size is smaller than 1/40 "
638 "of the release distance. You should probably "
639 "adapt the release distance.");
643 { bmin[k] -= release_distance; bmax[k] += release_distance; }
646 element_boxes.add_box(bmin, bmax, element_boxes_info.size());
648 element_boxes_info.push_back(influence_box(i, cv, v.f(), n_mean));
651 element_boxes.build_tree();
654 void multi_contact_frame::compute_potential_contact_pairs_influence_boxes() {
655 compute_influence_boxes();
656 compute_boundary_points(!self_contact);
657 normal_cone_simplification();
658 potential_pairs = std::vector<std::vector<face_info> >();
659 potential_pairs.resize(boundary_points.size());
661 for (
size_type ip = 0; ip < boundary_points.size(); ++ip) {
663 bgeot::rtree::pbox_set bset;
664 element_boxes.find_boxes_at_point(boundary_points[ip], bset);
665 boundary_point *pt_info = &(boundary_points_info[ip]);
666 const mesh_fem &mf1 = mfdisp_of_boundary(pt_info->ind_boundary);
669 bgeot::rtree::pbox_set::iterator it = bset.begin();
670 for (; it != bset.end(); ++it) {
671 influence_box &ibx = element_boxes_info[(*it)->id];
673 const mesh_fem &mf2 = mfdisp_of_boundary(ib2);
678 test_normal_cones_compatibility(ibx.mean_normal,
682 && (((nodes_mode < 2)
683 && (( &(mf1.linked_mesh()) != &(mf2.linked_mesh()))
684 || (pt_info->ind_element != ibx.ind_element)))
685 || ((nodes_mode == 2)
686 && !(is_dof_linked(ib1, pt_info->ind_pt,
687 ibx.ind_boundary, ibx.ind_element)))
691 add_potential_contact_face(ip, ibx.ind_boundary, ibx.ind_element,
699 struct proj_pt_surf_cost_function_object {
702 const base_node &x0, &x;
703 fem_interpolation_context &ctx;
704 const model_real_plain_vector &coeff;
705 const std::vector<base_small_vector> &ti;
707 mutable base_node dxy;
708 mutable base_matrix grad, gradtot;
710 scalar_type operator()(
const base_small_vector& a)
const {
712 for (
size_type i= 0; i < N-1; ++i) xx += a[i] * ti[i];
715 ctx.pf()->interpolation(ctx, coeff, dxy, dim_type(N));
716 dxy += ctx.xreal() - x;
718 dxy = ctx.xreal() - x;
722 scalar_type operator()(
const base_small_vector& a,
723 base_small_vector &grada)
const {
725 for (
size_type i = 0; i < N-1; ++i) xx += a[i] * ti[i];
728 ctx.pf()->interpolation(ctx, coeff, dxy, dim_type(N));
729 dxy += ctx.xreal() - x;
730 ctx.pf()->interpolation_grad(ctx, coeff, grad, dim_type(N));
731 gmm::add(gmm::identity_matrix(), grad);
734 dxy = ctx.xreal() - x;
738 grada[i] = gmm::vect_sp(gradtot, ti[i], dxy);
741 void operator()(
const base_small_vector& a,
742 base_matrix &hessa)
const {
743 base_small_vector b = a;
744 base_small_vector grada(N-1), gradb(N-1);
750 hessa(j, i) = (gradb[j] - grada[j])/EPS;
755 proj_pt_surf_cost_function_object
756 (
const base_node &x00,
const base_node &xx,
757 fem_interpolation_context &ctxx,
758 const model_real_plain_vector &coefff,
759 const std::vector<base_small_vector> &tii,
760 scalar_type EPSS,
bool rc)
761 : N(gmm::vect_size(x00)), EPS(EPSS), x0(x00), x(xx),
762 ctx(ctxx), coeff(coefff), ti(tii), ref_conf(rc),
763 dxy(N), grad(N,N), gradtot(N,N) {}
767 struct raytrace_pt_surf_cost_function_object {
769 const base_node &x0, &x;
770 fem_interpolation_context &ctx;
771 const model_real_plain_vector &coeff;
772 const std::vector<base_small_vector> &ti;
773 const std::vector<base_small_vector> &Ti;
775 mutable base_node dxy;
776 mutable base_matrix grad, gradtot;
778 void operator()(
const base_small_vector& a,
779 base_small_vector &res)
const {
781 for (
size_type i = 0; i < N-1; ++i) xx += a[i] * ti[i];
784 ctx.pf()->interpolation(ctx, coeff, dxy, dim_type(N));
785 dxy += ctx.xreal() - x;
787 dxy = ctx.xreal() - x;
789 res[i] = gmm::vect_sp(dxy, Ti[i]);
792 void operator()(
const base_small_vector& a,
793 base_matrix &hessa)
const {
795 for (
size_type i = 0; i < N-1; ++i) xx += a[i] * ti[i];
798 ctx.pf()->interpolation_grad(ctx, coeff, grad, dim_type(N));
799 gmm::add(gmm::identity_matrix(), grad);
810 raytrace_pt_surf_cost_function_object
811 (
const base_node &x00,
const base_node &xx,
812 fem_interpolation_context &ctxx,
813 const model_real_plain_vector &coefff,
814 const std::vector<base_small_vector> &tii,
815 const std::vector<base_small_vector> &Tii,
817 : N(gmm::vect_size(x00)), x0(x00), x(xx),
818 ctx(ctxx), coeff(coefff), ti(tii), Ti(Tii), ref_conf(rc),
819 dxy(N), grad(N,N), gradtot(N,N) {}
832 void multi_contact_frame::compute_contact_pairs() {
833 base_matrix G, grad(N,N);
834 model_real_plain_vector coeff;
835 base_small_vector a(N-1), ny(N);
837 std::vector<base_small_vector> ti(N-1), Ti(N-1);
843 contact_pairs = std::vector<contact_pair>();
845 if (!ref_conf) extend_vectors();
847 bool only_slave(
true), only_master(
true);
848 for (
size_type i = 0; i < contact_boundaries.size(); ++i)
849 if (is_slave_boundary(i)) only_master =
false;
850 else only_slave =
false;
852 if (only_master && !self_contact) {
853 GMM_WARNING1(
"There is only master boundary and no self-contact to detect. Exiting");
858 compute_boundary_points();
859 potential_pairs.resize(boundary_points.size());
861 else if (use_delaunay)
862 compute_potential_contact_pairs_delaunay();
864 compute_potential_contact_pairs_influence_boxes();
870 for (
size_type ip = 0; ip < potential_pairs.size(); ++ip) {
871 bool first_pair_found =
false;
872 const base_node &x = boundary_points[ip];
873 boundary_point &bpinfo = boundary_points_info[ip];
875 bool slx = is_slave_boundary(ibx);
876 scalar_type d0 = 1E300, d1, d2;
878 base_small_vector nx = bpinfo.normals[0];
880 if (bpinfo.normals.size() > 1) {
881 for (
size_type i = 1; i < bpinfo.normals.size(); ++i)
882 gmm::add(bpinfo.normals[i], nx);
884 GMM_ASSERT1(nnx != scalar_type(0),
"Invalid normal cone");
885 gmm::scale(nx, scalar_type(1)/nnx);
889 if (self_contact || slx) {
894 if (N >= 4) ptw[0] = pt[3];
895 if (N >= 3) ptz[0] = pt[2];
896 if (N >= 2) pty[0] = pt[1];
897 if (N >= 1) ptx[0] = pt[0];
898 for (
size_type i = 0; i < obstacles.size(); ++i) {
899 d1 = (obstacles_f[i].eval())[0];
900 if (gmm::abs(d1) < release_distance && d1 < d0) {
902 for (
size_type j=0; j < bpinfo.normals.size(); ++j) {
903 gmm::add(gmm::scaled(bpinfo.normals[j], EPS), pt);
904 if (N >= 4) ptw[0] = pt[3];
905 if (N >= 3) ptz[0] = pt[2];
906 if (N >= 2) pty[0] = pt[1];
907 if (N >= 1) ptx[0] = pt[0];
908 d2 = (obstacles_f[i].eval())[0];
909 if (d2 < d1) { d0 = d1; irigid_obstacle = i;
break; }
911 if (N >= 4) ptw[0] = pt[3];
912 if (N >= 3) ptz[0] = pt[2];
913 if (N >= 2) pty[0] = pt[1];
914 if (N >= 1) ptx[0] = pt[0];
922 if (N >= 4) ptw[0] = pt[3];
923 if (N >= 3) ptz[0] = pt[2];
924 if (N >= 2) pty[0] = pt[1];
925 if (N >= 1) ptx[0] = pt[0];
928 scalar_type
alpha(0), beta(0);
931 while (++nit < 50 && nb_fail < 3) {
935 case 4: ptw[0] += EPS;
break;
936 case 3: ptz[0] += EPS;
break;
937 case 2: pty[0] += EPS;
break;
938 case 1: ptx[0] += EPS;
break;
940 d2 = (obstacles_f[irigid_obstacle].eval())[0];
941 ny[k] = (d2 - d1) / EPS;
944 case 4: ptw[0] -= EPS;
break;
945 case 3: ptz[0] -= EPS;
break;
946 case 2: pty[0] -= EPS;
break;
947 case 1: ptx[0] -= EPS;
break;
951 if (gmm::abs(d1) < 1E-13)
955 for (scalar_type lambda(1); lambda >= 1E-3; lambda /= scalar_type(2)) {
958 gmm::add(x, gmm::scaled(nx, alpha), pt);
960 gmm::add(gmm::scaled(ny, -d1/gmm::vect_norm2_sqr(ny)), y, pt);
962 if (N >= 4) ptw[0] = pt[3];
963 if (N >= 3) ptz[0] = pt[2];
964 if (N >= 2) pty[0] = pt[1];
965 if (N >= 1) ptx[0] = pt[0];
966 d2 = (obstacles_f[irigid_obstacle].eval())[0];
971 if (gmm::abs(d2) < gmm::abs(d1))
break;
974 gmm::abs(beta - d1 / gmm::vect_sp(ny, nx)) > scalar_type(500))
979 if (gmm::abs(d1) > 1E-8) {
980 GMM_WARNING1(
"Projection/raytrace on rigid obstacle failed");
985 if (gmm::vect_dist2(y, x) > release_distance)
992 contact_pair ct(x, nx, bpinfo, y, ny, irigid_obstacle, d0);
994 contact_pairs.push_back(ct);
995 first_pair_found =
true;
1001 for (
size_type ipf = 0; ipf < potential_pairs[ip].size(); ++ipf) {
1020 const face_info &fi = potential_pairs[ip][ipf];
1025 const mesh_fem &mfu = mfdisp_of_boundary(ib);
1026 const mesh &m = mfu.linked_mesh();
1027 pfem pf_s = mfu.fem_of_element(cv);
1033 m.points_of_convex(cv, G);
1035 const auto face_pts = pf_s->ref_convex(cv)->points_of_face(iff);
1036 const base_node &x0 = face_pts[0];
1037 fem_interpolation_context ctx(pgt, pf_s, x0, G, cv, iff);
1039 const base_small_vector &n0 = pf_s->ref_convex(cv)->normals()[iff];
1042 scalar_type norm(0);
1043 while(norm < 1E-5) {
1047 ti[k] -= gmm::vect_sp(ti[k], ti[l]) * ti[l];
1053 bool converged =
false;
1054 scalar_type residual(0);
1059 base_small_vector res(N-1), res2(N-1), dir(N-1), b(N-1);
1061 base_matrix hessa(N-1, N-1);
1066 scalar_type norm(0);
1067 while (norm < 1E-5) {
1071 Ti[k] -= gmm::vect_sp(Ti[k], Ti[l]) * Ti[l];
1077 raytrace_pt_surf_cost_function_object pps(x0, x, ctx, coeff, ti, Ti,
1082 scalar_type residual2(0), det(0);
1083 bool exited =
false;
1085 for (;residual > 2E-12 && niter <= 30; ++niter) {
1089 det = gmm::abs(bgeot::lu_inverse(&(*(hessa.begin())),N-1,
false));
1090 if (det > 1E-15)
break;
1092 a[i] += gmm::random() * 1E-7;
1093 if (++subiter > 4)
break;
1095 if (det <= 1E-15)
break;
1097 gmm::mult(hessa, gmm::scaled(res, scalar_type(-1)), dir);
1099 if (gmm::vect_norm2(dir) > scalar_type(10)) nbfail++;
1100 if (nbfail >= 4)
break;
1103 scalar_type lambda(1);
1105 gmm::add(a, gmm::scaled(dir, lambda), b);
1108 if (residual2 < residual)
break;
1109 lambda /= ((j < 3) ? scalar_type(2) : scalar_type(5));
1112 residual = residual2;
1119 if (niter > 1 && dist_ref > 15)
break;
1120 if (niter > 5 && dist_ref > 8)
break;
1121 if ((niter > 1 && dist_ref > 7) || nbfail == 3) exited =
true;
1124 GMM_ASSERT1(!((exited && converged &&
1125 pf_s->ref_convex(cv)->is_in(ctx.xref()) < 1E-6)),
1126 "A non conformal case !! " << gmm::vect_norm2(res)
1127 <<
" : " << nbfail <<
" : " << niter);
1131 proj_pt_surf_cost_function_object pps(x0, x, ctx, coeff, ti,
1138 base_small_vector grada(N-1), dir(N-1), b(N-1);
1140 base_matrix hessa(N-1, N-1);
1143 scalar_type dist = pps(a, grada);
1149 det = gmm::abs(bgeot::lu_inverse(&(*(hessa.begin())),N-1,
false));
1150 if (det > 1E-15)
break;
1152 a[i] += gmm::random() * 1E-7;
1153 if (++subiter > 4)
break;
1155 if (det <= 1E-15)
break;
1157 gmm::mult(hessa, gmm::scaled(grada, scalar_type(-1)), dir);
1160 for (scalar_type lambda(1);
1161 lambda >= 1E-3; lambda /= scalar_type(2)) {
1162 gmm::add(a, gmm::scaled(dir, lambda), b);
1163 if (pps(b) < dist)
break;
1164 gmm::add(a, gmm::scaled(dir, -lambda), b);
1165 if (pps(b) < dist)
break;
1168 dist = pps(a, grada);
1176 gmm::bfgs(pps, pps, a, 10, iter, 0, 0.5);
1177 residual = gmm::abs(iter.get_res());
1178 converged = (residual < 2E-5);
1182 bool is_in = (pf_s->ref_convex(cv)->is_in(ctx.xref()) < 1E-6);
1184 if (is_in || (!converged && !raytrace)) {
1186 ctx.pf()->interpolation(ctx, coeff, y, dim_type(N));
1196 if (!raytrace && nbwarn < 4) {
1197 GMM_WARNING3(
"Projection or raytrace algorithm did not converge "
1198 "for point " << x <<
" residual " << residual
1199 <<
" projection computed " << y);
1215 if (!is_in)
continue;
1219 if (signed_dist > release_distance)
continue;
1222 base_small_vector ny0(N);
1225 signed_dist *= gmm::sgn(gmm::vect_sp(x - y, ny));
1229 if (first_pair_found && contact_pairs.back().signed_dist < signed_dist)
1233 if (!(test_normal_cones_compatibility(ny, bpinfo.normals)))
1238 if (&m == &(mfdisp_of_boundary(ibx).linked_mesh())) {
1240 base_small_vector diff = bpinfo.ref_point - ctx.xreal();
1243 if ( (ref_dist < scalar_type(4) * release_distance)
1244 && (gmm::vect_sp(diff, ny0) < - 0.01 * ref_dist) )
1248 contact_pair ct(x, nx, bpinfo, ctx.xref(), y, ny, fi, signed_dist);
1249 if (first_pair_found) {
1250 contact_pairs.back() = ct;
1252 contact_pairs.push_back(ct);
1253 first_pair_found =
true;
1270 class raytracing_interpolate_transformation
1271 :
public virtual_interpolate_transformation {
1274 struct contact_boundary {
1277 std::string dispname;
1278 mutable const model_real_plain_vector *U;
1279 mutable model_real_plain_vector U_unred;
1283 : region(-1), mfu(0), dispname(
""), U(0), U_unred(0), slave(false) {}
1284 contact_boundary(
size_type r,
const mesh_fem *mf,
const std::string &dn,
1286 : region(r), mfu(mf), dispname(dn), slave(sl) {}
1289 struct face_box_info {
1293 base_small_vector mean_normal;
1295 : ind_boundary(-1), ind_element(-1), ind_face(-1), mean_normal(0) {}
1298 : ind_boundary(ib), ind_element(ie), ind_face(iff), mean_normal(n) {}
1301 scalar_type release_distance;
1304 std::vector<contact_boundary> contact_boundaries;
1305 typedef std::map<const mesh *, std::vector<size_type> > mesh_boundary_cor;
1306 mesh_boundary_cor boundary_for_mesh;
1310 const ga_workspace *parent_workspace;
1313 mutable base_vector X;
1314 mutable ga_function f, der_f;
1315 mutable bool compiled;
1317 void compile()
const {
1319 f = ga_function(*md, expr);
1320 else if (parent_workspace)
1321 f = ga_function(*parent_workspace, expr);
1323 f = ga_function(expr);
1325 f.workspace().add_fixed_size_variable(
"X", gmm::sub_interval(0, N), X);
1326 if (N >= 1) f.workspace().add_macro(
"x",
"X(1)");
1327 if (N >= 2) f.workspace().add_macro(
"y",
"X(2)");
1328 if (N >= 3) f.workspace().add_macro(
"z",
"X(3)");
1329 if (N >= 4) f.workspace().add_macro(
"w",
"X(4)");
1332 der_f.derivative(
"X");
1338 base_vector &point()
const {
return X; }
1340 const base_tensor &eval()
const {
1341 if (!compiled) compile();
1344 const base_tensor &eval_derivative()
const {
1345 if (!compiled) compile();
1346 return der_f.eval();
1350 : md(0), parent_workspace(0), expr(
""), X(0), f(), der_f() {}
1351 obstacle(
const model &md_,
const std::string &expr_,
size_type N)
1352 : md(&md_), parent_workspace(0), expr(expr_), X(N),
1353 f(), der_f(), compiled(false) {}
1354 obstacle(
const ga_workspace &parent_workspace_,
1356 : md(0), parent_workspace(&parent_workspace_), expr(expr_), X(N),
1357 f(), der_f(), compiled(false) {}
1358 obstacle(
const obstacle &obs)
1359 : md(obs.md), parent_workspace(obs.parent_workspace), expr(obs.expr),
1360 X(obs.X), f(), der_f(), compiled(false) {}
1361 obstacle &operator =(
const obstacle& obs) {
1363 parent_workspace = obs.parent_workspace;
1367 der_f = ga_function();
1374 std::vector<obstacle> obstacles;
1377 mutable std::vector<face_box_info> face_boxes_info;
1380 void compute_face_boxes()
const {
1381 fem_precomp_pool fppool;
1383 model_real_plain_vector coeff;
1385 face_boxes_info.resize(0);
1387 for (
size_type i = 0; i < contact_boundaries.size(); ++i) {
1388 const contact_boundary &cb = contact_boundaries[i];
1391 const mesh_fem &mfu = *(cb.mfu);
1392 const model_real_plain_vector &U = *(cb.U);
1393 const mesh &m = mfu.linked_mesh();
1396 base_node val(N), bmin(N), bmax(N);
1397 base_small_vector n0_x(N), n_x(N), n0_y(N), n_y(N), n_mean(N);
1398 base_matrix grad(N,N);
1399 mesh_region region = m.region(bnum);
1400 GMM_ASSERT1(mfu.get_qdim() == N,
"Wrong mesh_fem qdim");
1402 dal::bit_vector points_already_interpolated;
1403 std::vector<base_node> transformed_points(m.nb_max_points());
1407 pfem pf_s = mfu.fem_of_element(cv);
1408 pfem_precomp pfp = fppool(pf_s, pgt->pgeometric_nodes());
1410 mfu.linked_mesh().points_of_convex(cv, G);
1411 fem_interpolation_context ctx(pgt, pfp,
size_type(-1), G, cv);
1414 size_type nb_pt_on_face = cvs->nb_points_of_face(v.f());
1415 GMM_ASSERT1(nb_pt_on_face >= 2,
"This element has less than two "
1416 "vertices on considered face !");
1419 for (
size_type k = 0; k < nb_pt_on_face; ++k) {
1420 size_type ip = cvs->ind_points_of_face(v.f())[k];
1421 size_type ind = m.ind_points_of_convex(cv)[ip];
1425 if (!(points_already_interpolated.is_in(ind))) {
1426 pf_s->interpolation(ctx, coeff, val, dim_type(N));
1428 transformed_points[ind] = val;
1429 points_already_interpolated.add(ind);
1431 val = transformed_points[ind];
1442 bmin[l] = std::min(bmin[l], val[l]);
1443 bmax[l] = std::max(bmax[l], val[l]);
1449 scalar_type h = bmax[0] - bmin[0];
1450 for (
size_type k = 1; k < N; ++k) h = std::max(h, bmax[k]-bmin[k]);
1452 { bmin[k] -= h * 0.15; bmax[k] += h * 0.15; }
1455 face_boxes.add_box(bmin, bmax, face_boxes_info.size());
1457 face_boxes_info.push_back(face_box_info(i, cv, v.f(), n_mean));
1461 face_boxes.build_tree();
1466 void add_rigid_obstacle(
const model &md,
const std::string &expr,
1468 obstacles.push_back(obstacle(md, expr, N));
1471 void add_rigid_obstacle(
const ga_workspace &parent_workspace,
1473 obstacles.push_back(obstacle(parent_workspace, expr, N));
1476 void add_contact_boundary(
const model &md,
const mesh &m,
1477 const std::string dispname,
1479 const mesh_fem *mf = 0;
1480 if (md.variable_group_exists(dispname)) {
1481 for (
const std::string &t : md.variable_group(dispname)) {
1482 const mesh_fem *mf2 = md.pmesh_fem_of_variable(t);
1483 if (mf2 && &(mf2->linked_mesh()) == &m)
1484 { mf = mf2;
break; }
1487 mf = md.pmesh_fem_of_variable(dispname);
1489 GMM_ASSERT1(mf,
"Displacement should be a fem variable");
1490 contact_boundary cb(region, mf, dispname, slave);
1491 boundary_for_mesh[&(mf->linked_mesh())]
1492 .push_back(contact_boundaries.size());
1493 contact_boundaries.push_back(cb);
1496 void add_contact_boundary(
const ga_workspace &workspace,
const mesh &m,
1497 const std::string dispname,
1499 const mesh_fem *mf = 0;
1500 if (workspace.variable_group_exists(dispname)) {
1501 for (
const std::string &t : workspace.variable_group(dispname)) {
1502 const mesh_fem *mf2 = workspace.associated_mf(t);
1503 if (mf2 && &(mf2->linked_mesh()) == &m)
1504 { mf = mf2;
break; }
1507 mf = workspace.associated_mf(dispname);
1509 GMM_ASSERT1(mf,
"Displacement should be a fem variable");
1510 contact_boundary cb(region, mf, dispname, slave);
1511 boundary_for_mesh[&(mf->linked_mesh())]
1512 .push_back(contact_boundaries.size());
1513 contact_boundaries.push_back(cb);
1516 void extract_variables(
const ga_workspace &workspace,
1517 std::set<var_trans_pair> &vars,
1518 bool ignore_data,
const mesh &m_x,
1519 const std::string &interpolate_name)
const {
1521 bool expand_groups = !ignore_data;
1526 mesh_boundary_cor::const_iterator it = boundary_for_mesh.find(&m_x);
1527 GMM_ASSERT1(it != boundary_for_mesh.end(),
"Raytracing interpolate "
1528 "transformation: Mesh with no declared contact boundary");
1529 for (
const size_type &boundary_ind : it->second) {
1530 const contact_boundary &cb = contact_boundaries[boundary_ind];
1531 const std::string &dispname_x
1532 = workspace.variable_in_group(cb.dispname, m_x);
1533 if (!ignore_data || !(workspace.is_constant(dispname_x)))
1534 vars.insert(var_trans_pair(dispname_x,
""));
1537 for (
const contact_boundary &cb : contact_boundaries) {
1539 if (expand_groups && workspace.variable_group_exists(cb.dispname)
1540 && (!ignore_data || !(workspace.is_constant(cb.dispname)))) {
1541 for (
const std::string &t : workspace.variable_group(cb.dispname))
1542 vars.insert(var_trans_pair(t, interpolate_name));
1544 if (!ignore_data || !(workspace.is_constant(cb.dispname)))
1545 vars.insert(var_trans_pair(cb.dispname, interpolate_name));
1551 void init(
const ga_workspace &workspace)
const {
1552 for (
const contact_boundary &cb : contact_boundaries) {
1553 const mesh_fem &mfu = *(cb.mfu);
1554 const std::string dispname_x
1555 = workspace.variable_in_group(cb.dispname, mfu.linked_mesh());
1557 if (mfu.is_reduced()) {
1559 mfu.extend_vector(workspace.value(dispname_x), cb.U_unred);
1560 cb.U = &(cb.U_unred);
1562 cb.U = &(workspace.value(dispname_x));
1565 compute_face_boxes();
1568 void finalize()
const {
1570 face_boxes_info = std::vector<face_box_info>();
1571 for (
const contact_boundary &cb : contact_boundaries)
1572 cb.U_unred = model_real_plain_vector();
1575 int transform(
const ga_workspace &workspace,
const mesh &m_x,
1576 fem_interpolation_context &ctx_x,
1577 const base_small_vector &,
1580 base_small_vector &N_y,
1581 std::map<var_trans_pair, base_tensor> &derivatives,
1582 bool compute_derivatives)
const {
1585 GMM_ASSERT1(face_x !=
short_type(-1),
"The contact transformation can "
1586 "only be applied to a boundary");
1591 mesh_boundary_cor::const_iterator it = boundary_for_mesh.find(&m_x);
1592 GMM_ASSERT1(it != boundary_for_mesh.end(),
1593 "Mesh with no declared contact boundary");
1595 for (
const size_type &boundary_ind : it->second) {
1596 const contact_boundary &cb = contact_boundaries[boundary_ind];
1597 if (m_x.region(cb.region).is_in(cv_x, face_x))
1598 { ib_x = boundary_ind;
break; }
1601 "No contact region found for this point");
1602 const contact_boundary &cb_x = contact_boundaries[ib_x];
1603 const mesh_fem &mfu_x = *(cb_x.mfu);
1604 pfem pfu_x = mfu_x.fem_of_element(cv_x);
1605 size_type N = mfu_x.linked_mesh().dim();
1606 GMM_ASSERT1(mfu_x.get_qdim() == N,
1607 "Displacment field with wrong dimension");
1609 model_real_plain_vector coeff_x, coeff_y, stored_coeff_y;
1610 base_small_vector a(N-1), b(N-1), pt_x(N), pt_y(N), n_x(N);
1611 base_small_vector stored_pt_y(N), stored_n_y(N), stored_pt_y_ref(N);
1612 base_small_vector n0_x, n_y(N), n0_y, res(N-1), res2(N-1), dir(N-1);
1613 base_matrix G_x, G_y, grad(N,N), hessa(N-1, N-1);
1614 std::vector<base_small_vector> ti(N-1), Ti(N-1);
1615 scalar_type stored_signed_distance(0);
1616 std::string stored_dispname;
1617 scalar_type d0 = 1E300, d1, d2;
1618 const mesh *stored_m_y(0);
1621 fem_interpolation_context stored_ctx_y;
1627 m_x.points_of_convex(cv_x, G_x);
1628 ctx_x.set_pf(pfu_x);
1629 pfu_x->interpolation(ctx_x, coeff_x, pt_x, dim_type(N));
1630 pt_x += ctx_x.xreal();
1639 bool first_pair_found =
false;
1641 for (
size_type i = 0; i < obstacles.size(); ++i) {
1642 const obstacle &obs = obstacles[i];
1644 const base_tensor &t = obs.eval();
1646 GMM_ASSERT1(t.size() == 1,
"Obstacle level set function as to be "
1647 "a scalar valued one");
1650 if (gmm::abs(d1) < release_distance && d1 < d0) {
1651 const base_tensor &t_der = obs.eval_derivative();
1652 GMM_ASSERT1(t_der.size() == n_x.size(),
"Bad derivative size");
1653 if (gmm::vect_sp(t_der.as_vector(), n_x) < scalar_type(0)) {
1655 irigid_obstacle = i;
1663 const obstacle &obs = obstacles[irigid_obstacle];
1667 scalar_type
alpha(0), beta(0);
1670 while (gmm::abs(d1) > 1E-13 && ++nit < 50 && nb_fail < 3) {
1671 if (nit != 1)
gmm::copy(obs.eval_derivative().as_vector(), n_y);
1673 for (scalar_type lambda(1); lambda >= 1E-3; lambda/=scalar_type(2)) {
1675 gmm::add(pt_x, gmm::scaled(n_x, alpha), obs.point());
1677 if (gmm::abs(d2) < gmm::abs(d1))
break;
1679 if (gmm::abs(beta - d1 / gmm::vect_sp(n_y, n_x)) > scalar_type(500))
1681 beta =
alpha; d1 = d2;
1685 if (gmm::abs(d1) > 1E-8) {
1686 GMM_WARNING1(
"Raytrace on rigid obstacle failed");
1688 else if (gmm::vect_dist2(pt_y, pt_x) <= release_distance) {
1691 stored_pt_y = stored_pt_y_ref = pt_y;
1693 stored_signed_distance = d0;
1694 first_pair_found =
true;
1702 bgeot::rtree::pbox_set bset;
1703 base_node bmin(pt_x), bmax(pt_x);
1705 { bmin[i] -= release_distance; bmax[i] += release_distance; }
1707 face_boxes.find_line_intersecting_boxes(pt_x, n_x, bmin, bmax, bset);
1713 for (
const auto &pbox : bset) {
1714 face_box_info &fbox_y = face_boxes_info[pbox->id];
1716 const contact_boundary &cb_y = contact_boundaries[ib_y];
1717 const mesh_fem &mfu_y = *(cb_y.mfu);
1718 const mesh &m_y = mfu_y.linked_mesh();
1720 pfem pfu_y = mfu_y.fem_of_element(cv_y);
1726 if (gmm::vect_sp(fbox_y.mean_normal, n_x) >= scalar_type(0) ||
1727 (cv_x == cv_y && &m_x == &m_y))
1734 m_y.points_of_convex(cv_y, G_y);
1736 const auto face_pts = pfu_y->ref_convex(cv_y)->points_of_face(face_y);
1737 const base_node &Y0 = face_pts[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) {
1749 ti[k] -= gmm::vect_sp(ti[k], ti[l]) * ti[l];
1759 scalar_type norm(0);
1760 while (norm < 1E-5) {
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;
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);
1907 bgeot::lu_inverse(&(*(F_y_inv.begin())), N);
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);
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,
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];
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];
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;
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 const auto face_pts = pfu_y->ref_convex(cv_y)->points_of_face(face_y);
2167 const base_node &Y0 = face_pts[0];
2168 fem_interpolation_context ctx_y(pgt_y, pfu_y, Y0, G_y, cv_y, face_y);
2170 const base_small_vector &NY0
2171 = pfu_y->ref_convex(cv_y)->normals()[face_y];
2177 scalar_type norm(0);
2178 while(norm < 1E-5) {
2182 ti[k] -= gmm::vect_sp(ti[k], ti[l]) * ti[l];
2188 proj_pt_surf_cost_function_object pps(Y0, pt_x, ctx_y, coeff_y, ti,
2190 base_small_vector grada(N-1);
2193 scalar_type dist = pps(a, grada);
2200 det = gmm::abs(gmm::lu_inverse(hessa,
false));
2201 if (det > 1E-15)
break;
2203 a[i] += gmm::random() * 1E-7;
2204 if (++subiter > 4)
break;
2206 if (det <= 1E-15)
break;
2208 gmm::mult(hessa, gmm::scaled(grada, scalar_type(-1)), dir);
2211 for (scalar_type lambda(1);
2212 lambda >= 1E-3; lambda /= scalar_type(2)) {
2213 gmm::add(a, gmm::scaled(dir, lambda), b);
2214 if (pps(b) < dist)
break;
2215 gmm::add(a, gmm::scaled(dir, -lambda), b);
2216 if (pps(b) < dist)
break;
2220 dist = pps(a, grada);
2227 gmm::bfgs(pps, pps, a, 10, iter, 0, 0.5);
2228 residual = gmm::abs(iter.get_res());
2229 converged = (residual < 2E-5);
2232 bool is_in = (pfu_y->ref_convex(cv_y)->is_in(ctx_y.xref()) < 1E-6);
2240 if (is_in || (!converged )) {
2242 ctx_y.pf()->interpolation(ctx_y, coeff_y, pt_y, dim_type(N));
2243 pt_y += ctx_y.xreal();
2245 pt_y = ctx_y.xreal();
2252 GMM_WARNING3(
"Projection algorithm did not converge "
2253 "for point " << pt_x <<
" residual " << residual
2254 <<
" projection computed " << pt_y);
2270 if (!is_in)
continue;
2276 if (signed_dist > release_distance)
continue;
2279 base_small_vector ny0(N);
2280 compute_normal(ctx_y, face_y, ref_conf, coeff_y, ny0, n_y, grad);
2282 signed_dist *= gmm::sgn(gmm::vect_sp(pt_x - pt_y, n_y));
2286 if (first_pair_found && stored_signed_distance < signed_dist)
2290 if (gmm::vect_sp(n_y, n_x) >= scalar_type(0))
continue;
2296 base_small_vector diff = ctx_x.xreal() - ctx_y.xreal();
2299 if ( (ref_dist < scalar_type(4) * release_distance)
2300 && (gmm::vect_sp(diff, ny0) < - 0.01 * ref_dist) )
2304 stored_pt_y = pt_y; stored_pt_y_ref = ctx_y.xref();
2305 stored_m_y = &m_y; stored_cv_y = cv_y; stored_face_y = face_y;
2307 stored_ctx_y = ctx_y;
2308 stored_coeff_y = coeff_y;
2309 stored_signed_distance = signed_dist;
2310 stored_dispname = cb_y.dispname;
2311 first_pair_found =
true;
2323 P_ref = stored_pt_y; N_y = stored_n_y;
2325 }
else if (first_pair_found) {
2326 *m_t = stored_m_y; cv = stored_cv_y; face_num = stored_face_y;
2327 P_ref = stored_pt_y_ref;
2336 if (compute_derivatives) {
2337 if (ret_type >= 1) {
2338 fem_interpolation_context &ctx_y = stored_ctx_y;
2340 if (ret_type == 1) cv_y = ctx_y.convex_num();
2343 base_matrix I_nyny(N,N);
2344 gmm::copy(gmm::identity_matrix(), I_nyny);
2345 gmm::rank_one_update(I_nyny, stored_n_y,
2346 gmm::scaled(stored_n_y,scalar_type(-1)));
2349 base_matrix F_y(N,N), F_y_inv(N,N), M1(N, N), M2(N, N);
2351 if (ret_type == 1) {
2353 pfu_y->interpolation_grad(ctx_y, stored_coeff_y, F_y, dim_type(N));
2354 gmm::add(gmm::identity_matrix(), F_y);
2359 gmm::copy(gmm::identity_matrix(), F_y_inv);
2363 base_tensor base_ux;
2364 base_matrix vbase_ux;
2365 ctx_x.base_value(base_ux);
2366 size_type qdim_ux = pfu_x->target_dim();
2367 size_type ndof_ux = pfu_x->nb_dof(cv_x) * N / qdim_ux;
2368 vectorize_base_tensor(base_ux, vbase_ux, ndof_ux, qdim_ux, N);
2370 base_tensor base_uy;
2371 base_matrix vbase_uy;
2373 if (ret_type == 1) {
2374 ctx_y.base_value(base_uy);
2375 size_type qdim_uy = pfu_y->target_dim();
2376 ndof_uy = pfu_y->nb_dof(cv_y) * N / qdim_uy;
2377 vectorize_base_tensor(base_uy, vbase_uy, ndof_uy, qdim_uy, N);
2380 base_tensor grad_base_ux, vgrad_base_ux;
2381 ctx_x.grad_base_value(grad_base_ux);
2382 vectorize_grad_base_tensor(grad_base_ux, vgrad_base_ux, ndof_ux,
2390 base_matrix der_x(ndof_ux, N);
2391 gmm::mult(vbase_ux, gmm::transposed(M1), der_x);
2394 base_matrix der_y(ndof_uy, N);
2395 if (ret_type == 1) {
2396 gmm::mult(vbase_uy, gmm::transposed(M1), der_y);
2397 gmm::scale(der_y, scalar_type(-1));
2400 const std::string &dispname_x
2401 = workspace.variable_in_group(cb_x.dispname, m_x);
2403 for (
auto&& d : derivatives) {
2404 if (dispname_x.compare(d.first.varname) == 0 &&
2405 d.first.transname.size() == 0) {
2406 d.second.adjust_sizes(ndof_ux, N);
2407 gmm::copy(der_x.as_vector(), d.second.as_vector());
2408 }
else if (ret_type == 1 &&
2409 stored_dispname.compare(d.first.varname) == 0 &&
2410 d.first.transname.size() != 0) {
2411 d.second.adjust_sizes(ndof_uy, N);
2412 gmm::copy(der_y.as_vector(), d.second.as_vector());
2414 d.second.adjust_sizes(0, 0);
2417 for (
auto&& d : derivatives)
2418 d.second.adjust_sizes(0, 0);
2423 projection_interpolate_transformation(
const scalar_type &d)
2424 :raytracing_interpolate_transformation(d), release_distance(d) {}
2427 (
model &md,
const std::string &transname, scalar_type d) {
2428 pinterpolate_transformation
2429 p = std::make_shared<raytracing_interpolate_transformation>(d);
2434 (ga_workspace &workspace,
const std::string &transname, scalar_type d) {
2435 pinterpolate_transformation
2436 p = std::make_shared<raytracing_interpolate_transformation>(d);
2437 workspace.add_interpolate_transformation(transname, p);
2441 (
model &md,
const std::string &transname,
const mesh &m,
2442 const std::string &dispname,
size_type region) {
2443 raytracing_interpolate_transformation *p
2444 =
dynamic_cast<raytracing_interpolate_transformation *
>
2445 (
const_cast<virtual_interpolate_transformation *
>
2447 p->add_contact_boundary(md, m, dispname, region,
false);
2451 (
model &md,
const std::string &transname,
const mesh &m,
2452 const std::string &dispname,
size_type region) {
2453 raytracing_interpolate_transformation *p
2454 =
dynamic_cast<raytracing_interpolate_transformation *
>
2455 (
const_cast<virtual_interpolate_transformation *
>
2457 p->add_contact_boundary(md, m, dispname, region,
true);
2461 (ga_workspace &workspace,
const std::string &transname,
const mesh &m,
2462 const std::string &dispname,
size_type region) {
2463 raytracing_interpolate_transformation *p
2464 =
dynamic_cast<raytracing_interpolate_transformation *
>
2465 (
const_cast<virtual_interpolate_transformation *
>
2466 (&(*(workspace.interpolate_transformation(transname)))));
2467 p->add_contact_boundary(workspace, m, dispname, region,
false);
2471 (ga_workspace &workspace,
const std::string &transname,
const mesh &m,
2472 const std::string &dispname,
size_type region) {
2473 raytracing_interpolate_transformation *p
2474 =
dynamic_cast<raytracing_interpolate_transformation *
>
2475 (
const_cast<virtual_interpolate_transformation *
>
2476 (&(*(workspace.interpolate_transformation(transname)))));
2477 p->add_contact_boundary(workspace, m, dispname, region,
true);
2481 (
model &md,
const std::string &transname,
2483 raytracing_interpolate_transformation *p
2484 =
dynamic_cast<raytracing_interpolate_transformation *
>
2485 (
const_cast<virtual_interpolate_transformation *
>
2487 p->add_rigid_obstacle(md, expr, N);
2491 (ga_workspace &workspace,
const std::string &transname,
2493 raytracing_interpolate_transformation *p
2494 =
dynamic_cast<raytracing_interpolate_transformation *
>
2495 (
const_cast<virtual_interpolate_transformation *
>
2496 (&(*(workspace.interpolate_transformation(transname)))));
2497 p->add_rigid_obstacle(workspace, expr, N);
2501 (
model &md,
const std::string &transname, scalar_type d) {
2502 pinterpolate_transformation
2503 p = std::make_shared<projection_interpolate_transformation>(d);
2508 (ga_workspace &workspace,
const std::string &transname, scalar_type d) {
2509 pinterpolate_transformation
2510 p = std::make_shared<projection_interpolate_transformation>(d);
2511 workspace.add_interpolate_transformation(transname, p);
2515 (
model &md,
const std::string &transname,
const mesh &m,
2516 const std::string &dispname,
size_type region) {
2517 projection_interpolate_transformation *p
2518 =
dynamic_cast<projection_interpolate_transformation *
>
2519 (
const_cast<virtual_interpolate_transformation *
>
2521 p->add_contact_boundary(md, m, dispname, region,
false);
2525 (
model &md,
const std::string &transname,
const mesh &m,
2526 const std::string &dispname,
size_type region) {
2527 projection_interpolate_transformation *p
2528 =
dynamic_cast<projection_interpolate_transformation *
>
2529 (
const_cast<virtual_interpolate_transformation *
>
2531 p->add_contact_boundary(md, m, dispname, region,
true);
2535 (ga_workspace &workspace,
const std::string &transname,
const mesh &m,
2536 const std::string &dispname,
size_type region) {
2537 projection_interpolate_transformation *p
2538 =
dynamic_cast<projection_interpolate_transformation *
>
2539 (
const_cast<virtual_interpolate_transformation *
>
2540 (&(*(workspace.interpolate_transformation(transname)))));
2541 p->add_contact_boundary(workspace, m, dispname, region,
false);
2545 (ga_workspace &workspace,
const std::string &transname,
const mesh &m,
2546 const std::string &dispname,
size_type region) {
2547 projection_interpolate_transformation *p
2548 =
dynamic_cast<projection_interpolate_transformation *
>
2549 (
const_cast<virtual_interpolate_transformation *
>
2550 (&(*(workspace.interpolate_transformation(transname)))));
2551 p->add_contact_boundary(workspace, m, dispname, region,
true);
2555 (
model &md,
const std::string &transname,
2557 projection_interpolate_transformation *p
2558 =
dynamic_cast<projection_interpolate_transformation *
>
2559 (
const_cast<virtual_interpolate_transformation *
>
2561 p->add_rigid_obstacle(md, expr, N);
2565 (ga_workspace &workspace,
const std::string &transname,
2567 projection_interpolate_transformation *p
2568 =
dynamic_cast<projection_interpolate_transformation *
>
2569 (
const_cast<virtual_interpolate_transformation *
>
2570 (&(*(workspace.interpolate_transformation(transname)))));
2571 p->add_rigid_obstacle(workspace, expr, N);
2584 static void ga_init_vector(bgeot::multi_index &mi,
size_type N)
2585 { mi.resize(1); mi[0] = N; }
2591 struct Transformed_unit_vector :
public ga_nonlinear_operator {
2592 bool result_size(
const arg_list &args, bgeot::multi_index &sizes)
const {
2593 if (args.size() != 2 || args[0]->sizes().size() != 2
2594 || args[1]->size() != args[0]->sizes()[0]
2595 || args[0]->sizes()[0] != args[0]->sizes()[1])
return false;
2596 ga_init_vector(sizes, args[0]->sizes()[0]);
2601 void value(
const arg_list &args, base_tensor &result)
const {
2603 base_matrix F(N, N);
2604 gmm::copy(args[0]->as_vector(), F.as_vector());
2605 gmm::add(gmm::identity_matrix(), F);
2606 bgeot::lu_inverse(&(*(F.begin())), N);
2607 gmm::mult(gmm::transposed(F), args[1]->as_vector(), result.as_vector());
2608 gmm::scale(result.as_vector(),
2609 scalar_type(1)/gmm::vect_norm2(result.as_vector()));
2620 void derivative(
const arg_list &args,
size_type nder,
2621 base_tensor &result)
const {
2623 base_matrix F(N, N), G(N, N);
2624 base_small_vector ndef(N), aux(N);
2625 gmm::copy(args[0]->as_vector(), F.as_vector());
2626 gmm::add(gmm::identity_matrix(), F);
2627 bgeot::lu_inverse(&(*(F.begin())), N);
2628 gmm::mult(gmm::transposed(F), args[1]->as_vector(), ndef);
2630 gmm::scale(ndef, scalar_type(1)/norm_ndef);
2633 gmm::rank_one_update(G, gmm::scaled(ndef, scalar_type(-1)), aux);
2634 base_tensor::iterator it = result.begin();
2640 *it = -G(i, k) * ndef[j];
2645 *it = (F(j,i) - ndef[i]*ndef[j])/norm_ndef;
2647 default: GMM_ASSERT1(
false,
"Internal error");
2649 GMM_ASSERT1(it == result.end(),
"Internal error");
2654 base_tensor &)
const {
2655 GMM_ASSERT1(
false,
"Sorry, second derivative not implemented");
2661 struct Coulomb_friction_coupled_projection :
public ga_nonlinear_operator {
2662 bool result_size(
const arg_list &args, bgeot::multi_index &sizes)
const {
2663 if (args.size() != 6)
return false;
2665 if (N == 0 || args[1]->size() != N || args[2]->size() != N
2666 || args[3]->size() != 1 || args[4]->size() > 3
2667 || args[4]->size() == 0 || args[5]->size() != 1 )
return false;
2668 ga_init_vector(sizes, N);
2673 void value(
const arg_list &args, base_tensor &result)
const {
2674 const base_vector &lambda = *(args[0]);
2675 const base_vector &n = *(args[1]);
2676 const base_vector &Vs = *(args[2]);
2677 base_vector &F = result;
2678 scalar_type g = (*(args[3]))[0];
2679 const base_vector &f = *(args[4]);
2680 scalar_type r = (*(args[5]))[0];
2685 scalar_type lambdan_aug = gmm::neg(lambdan + r * g);
2687 scalar_type tau = ((s_f >= 3) ? f[2] : scalar_type(0)) + f[0]*lambdan_aug;
2688 if (s_f >= 2) tau = std::min(tau, f[1]);
2690 if (tau > scalar_type(0)) {
2691 gmm::add(lambda, gmm::scaled(Vs, -r), F);
2693 gmm::add(gmm::scaled(n, -mu/nn), F);
2695 if (norm > tau) gmm::scale(F, tau / norm);
2698 gmm::add(gmm::scaled(n, -lambdan_aug/nn), F);
2709 void derivative(
const arg_list &args,
size_type nder,
2710 base_tensor &result)
const {
2712 const base_vector &lambda = *(args[0]);
2713 const base_vector &n = *(args[1]);
2714 const base_vector &Vs = *(args[2]);
2715 base_vector F(N), dg(N);
2716 base_matrix dVs(N,N), dn(N,N);
2717 scalar_type g = (*(args[3]))[0];
2718 const base_vector &f = *(args[4]);
2719 scalar_type r = (*(args[5]))[0];
2723 scalar_type lambdan_aug = gmm::neg(lambdan + r * g);
2725 scalar_type tau = ((s_f >= 3) ? f[2] : scalar_type(0))+f[0]*lambdan_aug;
2726 if (s_f >= 2) tau = std::min(tau, f[1]);
2727 scalar_type norm(0);
2729 if (tau > scalar_type(0)) {
2730 gmm::add(lambda, gmm::scaled(Vs, -r), F);
2732 gmm::add(gmm::scaled(n, -mu/nn), F);
2735 gmm::scale(dn, -mu/nn);
2736 gmm::rank_one_update(dn, gmm::scaled(n, mu/(nn*nn*nn)), n);
2737 gmm::rank_one_update(dn, gmm::scaled(n, scalar_type(-1)/(nn*nn)), F);
2739 gmm::rank_one_update(dVs, n, gmm::scaled(n, scalar_type(-1)/(nn*nn)));
2742 gmm::rank_one_update(dVs, F,
2743 gmm::scaled(F, scalar_type(-1)/(norm*norm)));
2744 gmm::scale(dVs, tau / norm);
2745 gmm::copy(gmm::scaled(F, scalar_type(1)/norm), dg);
2746 gmm::rank_one_update(dn, gmm::scaled(F, mu/(norm*norm*nn)), F);
2747 gmm::scale(dn, tau / norm);
2748 gmm::scale(F, tau / norm);
2756 base_tensor::iterator it = result.begin();
2759 if (norm > tau && ((s_f <= 1) || tau < f[1]) &&
2760 ((s_f <= 2) || tau > f[2]))
2761 gmm::rank_one_update(dVs, dg, gmm::scaled(n, -f[0]/nn));
2762 if (lambdan_aug > scalar_type(0))
2763 gmm::rank_one_update(dVs, n, gmm::scaled(n, scalar_type(1)/(nn*nn)));
2769 if (norm > tau && ((s_f <= 1) || tau < f[1])
2770 && ((s_f <= 2) || tau > f[2])) {
2771 gmm::rank_one_update(dn, dg, gmm::scaled(lambda, -f[0]/nn));
2772 gmm::rank_one_update(dn, dg, gmm::scaled(n, f[0]*lambdan/(nn*nn)));
2774 if (lambdan_aug > scalar_type(0)) {
2775 gmm::rank_one_update(dn, gmm::scaled(n, scalar_type(1)/(nn*nn)),
2777 gmm::rank_one_update(dn,
2778 gmm::scaled(n,(lambdan_aug-lambdan)/(nn*nn*nn)), n);
2779 for (
size_type j = 0; j < N; ++j) dn(j,j) -= lambdan_aug/nn;
2786 gmm::scale(dVs, -r);
2792 if (norm > tau && ((s_f <= 1) || tau < f[1])
2793 && ((s_f <= 2) || tau > f[2]))
2794 gmm::scale(dg, -f[0]*r);
2797 if (lambdan_aug > scalar_type(0))
2798 gmm::add(gmm::scaled(n, r/nn), dg);
2803 if (norm > tau && ((s_f <= 1) || tau < f[1])
2804 && ((s_f <= 2) || tau > f[2]))
2805 gmm::scale(dg, -f[0]*g);
2809 if (lambdan_aug > scalar_type(0))
2810 gmm::add(gmm::scaled(n, g/nn), dg);
2816 base_small_vector dtau_df(s_f);
2817 if ((s_f <= 1) || tau < f[1]) dtau_df[0] = lambdan_aug;
2818 if (s_f >= 2 && tau == f[1]) dtau_df[1] = 1;
2819 if (s_f >= 3 && tau < f[1]) dtau_df[2] = 1;
2822 *it = dg[i] * dtau_df[j];
2825 GMM_ASSERT1(it == result.end(),
"Internal error");
2830 base_tensor &)
const {
2831 GMM_ASSERT1(
false,
"Sorry, second derivative not implemented");
2835 static bool init_predef_operators() {
2837 ga_predef_operator_tab &PREDEF_OPERATORS
2840 PREDEF_OPERATORS.add_method(
"Transformed_unit_vector",
2841 std::make_shared<Transformed_unit_vector>());
2842 PREDEF_OPERATORS.add_method(
"Coulomb_friction_coupled_projection",
2843 std::make_shared<Coulomb_friction_coupled_projection>());
2849 bool predef_operators_contact_initialized
2850 = init_predef_operators();
Balanced tree of n-dimensional rectangles.
static T & instance()
Instance from the current thread.
Describe a finite element method linked to a mesh.
"iterator" class for regions.
Describe a mesh (collection of convexes (elements) and points).
`‘Model’' variables store the variables, the data and the description of a model.
void add_interpolate_transformation(const std::string &name, pinterpolate_transformation ptrans)
Add an interpolate transformation to the model to be used with the generic assembly.
pinterpolate_transformation interpolate_transformation(const std::string &name) const
Get a pointer to the interpolate transformation name.
The Iteration object calculates whether the solution has reached the desired accuracy,...
A language for generic assembly of pde boundary value problems.
void mult_add(const L1 &l1, const L2 &l2, L3 &l3)
*/
void copy(const L1 &l1, L2 &l2)
*/
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2(const V &v)
Euclidean norm of a vector.
void fill_random(L &l)
fill a vector or matrix with random value (uniform [-1,1]).
void clear(L &l)
clear (fill with zeros) a vector or matrix.
number_traits< typename linalg_traits< V1 >::value_type >::magnitude_type vect_dist2(const V1 &v1, const V2 &v2)
Euclidean distance between two vectors.
void resize(V &v, size_type n)
*/
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*/
strongest_value_type< V1, V2 >::value_type vect_sp(const V1 &v1, const V2 &v2)
*/
void add(const L1 &l1, L2 &l2)
*/
void lu_inverse(const DenseMatrixLU &LU, const Pvector &pvector, const DenseMatrix &AInv_)
Given an LU factored matrix, build the inverse of the matrix.
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
gmm::uint16_type short_type
used as the common short type integer in the library
std::shared_ptr< const convex_structure > pconvex_structure
Pointer on a convex structure description.
base_small_vector compute_normal(const geotrans_interpolation_context &c, size_type face)
norm of returned vector is the ratio between the face surface on the real element and the face surfac...
size_t size_type
used as the common size type in the library
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation
size_type alpha(short_type n, short_type d)
Return the value of which is the number of monomials of a polynomial of variables and degree .
GEneric Tool for Finite Element Methods.
void add_rigid_obstacle_to_raytracing_transformation(model &md, const std::string &transname, const std::string &expr, size_type N)
Add a rigid obstacle whose geometry corresponds to the zero level-set of the high-level generic assem...
void add_master_contact_boundary_to_projection_transformation(model &md, const std::string &transname, const mesh &m, const std::string &dispname, size_type region)
Add a master boundary with corresponding displacement variable 'dispname' on a specific boundary 'reg...
void add_raytracing_transformation(model &md, const std::string &transname, scalar_type release_distance)
Add a raytracing interpolate transformation called 'transname' to a model to be used by the generic a...
void add_rigid_obstacle_to_projection_transformation(model &md, const std::string &transname, const std::string &expr, size_type N)
Add a rigid obstacle whose geometry corresponds to the zero level-set of the high-level generic assem...
void add_master_contact_boundary_to_raytracing_transformation(model &md, const std::string &transname, const mesh &m, const std::string &dispname, size_type region)
Add a master boundary with corresponding displacement variable 'dispname' on a specific boundary 'reg...
void slice_vector_on_basic_dof_of_element(const mesh_fem &mf, const VEC1 &vec, size_type cv, VEC2 &coeff, size_type qmult1=size_type(-1), size_type qmult2=size_type(-1))
Given a mesh_fem.
void add_projection_transformation(model &md, const std::string &transname, scalar_type release_distance)
Add a projection interpolate transformation called 'transname' to a model to be used by the generic a...
void add_slave_contact_boundary_to_projection_transformation(model &md, const std::string &transname, const mesh &m, const std::string &dispname, size_type region)
Add a slave boundary with corresponding displacement variable 'dispname' on a specific boundary 'regi...
void add_slave_contact_boundary_to_raytracing_transformation(model &md, const std::string &transname, const mesh &m, const std::string &dispname, size_type region)
Add a slave boundary with corresponding displacement variable 'dispname' on a specific boundary 'regi...