GetFEM  5.4.3
getfem_contact_and_friction_large_sliding.cc
1 /*===========================================================================
2 
3  Copyright (C) 2013-2020 Yves Renard, Konstantinos Poulios.
4 
5  This file is a part of GetFEM
6 
7  GetFEM is free software; you can redistribute it and/or modify it
8  under the terms of the GNU Lesser General Public License as published
9  by the Free Software Foundation; either version 3 of the License, or
10  (at your option) any later version along with the GCC Runtime Library
11  Exception either version 3.1 or (at your option) any later version.
12  This program is distributed in the hope that it will be useful, but
13  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15  License and GCC Runtime Library Exception for more details.
16  You should have received a copy of the GNU Lesser General Public License
17  along with this program; if not, write to the Free Software Foundation,
18  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 
20 ===========================================================================*/
21 
22 #include "getfem/bgeot_rtree.h"
25 #include "getfem/getfem_contact_and_friction_large_sliding.h"
28 
29 namespace getfem {
30 
31 
32  //=========================================================================
33  // Augmented friction law
34  //=========================================================================
35 
36 
37 #define FRICTION_LAW 1
38 
39 
40 #if FRICTION_LAW == 1 // Complete law with friction
41 
42  template <typename VEC, typename VEC2, typename VECR>
43  void aug_friction(const VEC &lambda, scalar_type g, const VEC &Vs,
44  const VEC &n, scalar_type r, const VEC2 &f, VECR &F) {
45  scalar_type nn = gmm::vect_norm2(n);
46  scalar_type lambdan = gmm::vect_sp(lambda, n)/nn;
47  scalar_type lambdan_aug = gmm::neg(lambdan + r * g);
48  size_type i = gmm::vect_size(f);
49  scalar_type tau = ((i >= 3) ? f[2] : scalar_type(0)) + f[0]*lambdan_aug;
50  if (i >= 2) tau = std::min(tau, f[1]);
51 
52  if (tau > scalar_type(0)) {
53  gmm::add(lambda, gmm::scaled(Vs, -r), F);
54  scalar_type mu = gmm::vect_sp(F, n)/nn;
55  gmm::add(gmm::scaled(n, -mu/nn), F);
56  scalar_type norm = gmm::vect_norm2(F);
57  if (norm > tau) gmm::scale(F, tau / norm);
58  } else { gmm::clear(F); }
59 
60  gmm::add(gmm::scaled(n, -lambdan_aug/nn), F);
61  }
62 
63  template <typename VEC, typename VEC2, typename VECR, typename MAT>
64  void aug_friction_grad(const VEC &lambda, scalar_type g, const VEC &Vs,
65  const VEC &n, scalar_type r, const VEC2 &f, VECR &F,
66  MAT &dlambda, VECR &dg, MAT &dn, MAT &dVs) {
67  size_type N = gmm::vect_size(lambda);
68  scalar_type nn = gmm::vect_norm2(n);
69  scalar_type lambdan = gmm::vect_sp(lambda, n)/nn;
70  scalar_type lambdan_aug = gmm::neg(lambdan + r * g);
71  size_type i = gmm::vect_size(f);
72  scalar_type tau = ((i >= 3) ? f[2] : scalar_type(0)) + f[0]*lambdan_aug;
73  if (i >= 2) tau = std::min(tau, f[1]);
74  scalar_type norm(0);
75 
76  if (tau > scalar_type(0)) {
77  gmm::add(lambda, gmm::scaled(Vs, -r), F);
78  scalar_type mu = gmm::vect_sp(F, n)/nn;
79  gmm::add(gmm::scaled(n, -mu/nn), F);
80  norm = gmm::vect_norm2(F);
81  gmm::copy(gmm::identity_matrix(), dn);
82  gmm::scale(dn, -mu/nn);
83  gmm::rank_one_update(dn, gmm::scaled(n, mu/(nn*nn*nn)), n);
84  gmm::rank_one_update(dn, gmm::scaled(n, scalar_type(-1)/(nn*nn)), F);
85  gmm::copy(gmm::identity_matrix(), dVs);
86  gmm::rank_one_update(dVs, n, gmm::scaled(n, scalar_type(-1)/(nn*nn)));
87 
88  if (norm > tau) {
89  gmm::rank_one_update(dVs, F,
90  gmm::scaled(F, scalar_type(-1)/(norm*norm)));
91  gmm::scale(dVs, tau / norm);
92  gmm::copy(gmm::scaled(F, scalar_type(1)/norm), dg);
93  gmm::rank_one_update(dn, gmm::scaled(F, mu/(norm*norm*nn)), F);
94  gmm::scale(dn, tau / norm);
95  gmm::scale(F, tau / norm);
96  } else gmm::clear(dg);
97 
98  } else { gmm::clear(dg); gmm::clear(dVs); gmm::clear(F); gmm::clear(dn); }
99  // At this stage, F = P_{B_T}, dVs = d_v P_{B_T}, dn = d_n P_{B_T}
100  // and dg = d_tau P_{B_T}.
101 
102  gmm::copy(dVs, dlambda);
103  if (norm > tau && ((i <= 1) || tau < f[1]) && ((i <= 2) || tau > f[2])) {
104  gmm::rank_one_update(dn, dg, gmm::scaled(lambda, -f[0]/nn));
105  gmm::rank_one_update(dn, dg, gmm::scaled(n, f[0]*lambdan/(nn*nn)));
106  gmm::rank_one_update(dlambda, dg, gmm::scaled(n, -f[0]/nn));
107  gmm::scale(dg, -f[0]*r);
108  } else gmm::clear(dg);
109  if (lambdan_aug > scalar_type(0)) {
110  gmm::add(gmm::scaled(n, r/nn), dg);
111  gmm::rank_one_update(dlambda, n, gmm::scaled(n, scalar_type(1)/(nn*nn)));
112  gmm::rank_one_update(dn, gmm::scaled(n, scalar_type(1)/(nn*nn)), lambda);
113  gmm::rank_one_update(dn,
114  gmm::scaled(n,(lambdan_aug-lambdan)/(nn*nn*nn)), n);
115  for (size_type j = 0; j < N; ++j) dn(j,j) -= lambdan_aug/nn;
116  }
117  gmm::add(gmm::scaled(n, -lambdan_aug/nn), F);
118 
119  gmm::scale(dVs, -r);
120  }
121 
122 #elif FRICTION_LAW == 2 // Contact only
123 
124  template <typename VEC, typename VEC2, typename VECR>
125  void aug_friction(const VEC &lambda, scalar_type g, const VEC &,
126  const VEC &n, scalar_type r, const VEC2 &, VECR &F) {
127  scalar_type nn = gmm::vect_norm2(n);
128  scalar_type lambdan = gmm::vect_sp(lambda, n)/nn;
129  scalar_type lambdan_aug = gmm::neg(lambdan + r * g);
130  gmm::copy(gmm::scaled(n, -lambdan_aug/nn), F);
131  }
132 
133  template <typename VEC, typename VEC2, typename VECR, typename MAT>
134  void aug_friction_grad(const VEC &lambda, scalar_type g, const VEC &,
135  const VEC &n, scalar_type r, const VEC2 &, VECR &F,
136  MAT &dlambda, VECR &dg, MAT &dn, MAT &dVs) {
137  size_type N = gmm::vect_size(lambda);
138  scalar_type nn = gmm::vect_norm2(n);
139  scalar_type lambdan = gmm::vect_sp(lambda, n)/nn;
140  scalar_type lambdan_aug = gmm::neg(lambdan + r * g);
141 
142  gmm::clear(dg); gmm::clear(dVs); gmm::clear(F);
143  gmm::clear(dn); gmm::clear(dlambda);
144  // At this stage, F = P_{B_T}, dVs = d_v P_{B_T}, dn = d_n P_{B_T}
145  // and dg = d_tau P_{B_T}.
146 
147  if (lambdan_aug > scalar_type(0)) {
148  gmm::add(gmm::scaled(n, r/nn), dg);
149  gmm::rank_one_update(dlambda, n, gmm::scaled(n, scalar_type(1)/(nn*nn)));
150  gmm::rank_one_update(dn, gmm::scaled(n, scalar_type(1)/(nn*nn)), lambda);
151  gmm::rank_one_update(dn,
152  gmm::scaled(n,(lambdan_aug-lambdan)/(nn*nn*nn)), n);
153  for (size_type j = 0; j < N; ++j) dn(j,j) -= lambdan_aug/nn;
154  }
155  gmm::add(gmm::scaled(n, -lambdan_aug/nn), F);
156 
157  gmm::scale(dVs, -r);
158  }
159 
160 
161 
162 #elif FRICTION_LAW == 3 // Dummy law for test
163 
164  template <typename VEC, typename VEC2, typename VECR>
165  void aug_friction(const VEC &lambda, scalar_type g, const VEC &Vs,
166  const VEC &n, scalar_type r, const VEC2 &f, VECR &F) {
167  gmm::copy(gmm::scaled(lambda, g*r*f[0]), F); // dummy
168  gmm::copy(gmm::scaled(Vs, g*r*f[0]), F); // dummy
169 
170  gmm::copy(n, F);
171  }
172 
173  template <typename VEC, typename VEC2, typename VECR, typename MAT>
174  void aug_friction_grad(const VEC &lambda, scalar_type g, const VEC &Vs,
175  const VEC &n, scalar_type r, const VEC2 &f, VECR &F,
176  MAT &dlambda, VECR &dg, MAT &dn, MAT &dVs) {
177  gmm::copy(gmm::scaled(lambda, g*r*f[0]), F); // dummy
178  gmm::copy(gmm::scaled(Vs, g*r*f[0]), F); // dummy
179 
180  gmm::copy(n, F);
181  gmm::clear(dlambda);
182  gmm::clear(dg);
183  gmm::clear(dVs);
184  gmm::copy(gmm::identity_matrix(), dn);
185  }
186 
187 #elif FRICTION_LAW == 4 // Dummy law for test
188 
189  template <typename VEC, typename VEC2, typename VECR>
190  void aug_friction(const VEC &lambda, scalar_type g, const VEC &Vs,
191  const VEC &n, scalar_type r, const VEC2 &f, VECR &F) {
192  gmm::copy(gmm::scaled(lambda, g*r*f[0]*n[0]*Vs[0]), F); // dummy
193  gmm::copy(lambda, F);
194  }
195 
196  template <typename VEC, typename VEC2, typename VECR, typename MAT>
197  void aug_friction_grad(const VEC &lambda, scalar_type g, const VEC &Vs,
198  const VEC &n, scalar_type r, const VEC2 &f, VECR &F,
199  MAT &dlambda, VECR &dg, MAT &dn, MAT &dVs) {
200  gmm::copy(gmm::scaled(lambda, g*r*f[0]*n[0]*Vs[0]), F); // dummy
201  gmm::clear(dn);
202  gmm::clear(dg);
203  gmm::clear(dVs);
204  gmm::copy(lambda, F);
205  gmm::copy(gmm::identity_matrix(), dlambda);
206  }
207 
208 #elif FRICTION_LAW == 5 // Dummy law for test
209 
210  template <typename VEC, typename VEC2, typename VECR>
211  void aug_friction(const VEC &lambda, scalar_type g, const VEC &Vs,
212  const VEC &n, scalar_type r, const VEC2 &f, VECR &F) {
213  gmm::copy(gmm::scaled(lambda, g*r*f[0]*n[0]*Vs[0]), F); // dummy
214  gmm::clear(F); F[0] = g;
215  }
216 
217  template <typename VEC, typename VEC2, typename VECR, typename MAT>
218  void aug_friction_grad(const VEC &lambda, scalar_type g, const VEC &Vs,
219  const VEC &n, scalar_type r, const VEC2 &f, VECR &F,
220  MAT &dlambda, VECR &dg, MAT &dn, MAT &dVs) {
221  gmm::copy(gmm::scaled(lambda, g*r*f[0]*n[0]*Vs[0]), F); // dummy
222  gmm::clear(dlambda);
223  gmm::clear(dn);
224  gmm::clear(dg);
225  gmm::clear(dVs);
226  gmm::clear(F); F[0] = g;
227  dg[0] = 1.;
228  }
229 
230 #endif
231 
232 
233  //=========================================================================
234  //
235  // Large sliding brick. Work in progress
236  //
237  //=========================================================================
238 
239  // For the moment, with raytrace detection and integral unsymmetric
240  // Alart-Curnier augmented Lagrangian
241 
242 
243  struct integral_large_sliding_contact_brick : public virtual_brick {
244 
245  multi_contact_frame &mcf;
246  bool with_friction;
247 
248 
249  virtual void asm_real_tangent_terms(const model &md, size_type /* ib */,
250  const model::varnamelist &vl,
251  const model::varnamelist &dl,
252  const model::mimlist &mims,
253  model::real_matlist &matl,
254  model::real_veclist &vecl,
255  model::real_veclist &,
256  size_type region,
257  build_version version) const;
258 
259  integral_large_sliding_contact_brick(multi_contact_frame &mcff,
260  bool with_fric)
261  : mcf(mcff), with_friction(with_fric) {
262  set_flags("Integral large sliding contact brick",
263  false /* is linear*/, false /* is symmetric */,
264  false /* is coercive */, true /* is real */,
265  false /* is complex */);
266  }
267 
268  };
269 
270 
271  struct gauss_point_precomp {
272  size_type N;
273  fem_precomp_pool fppool;
274  const multi_contact_frame &mcf;
275  const model &md;
276  const multi_contact_frame::contact_pair *cp;
277 
278  const base_node &x(void) const { return cp->slave_point; }
279  const base_node &nx(void) const { return cp->slave_n; }
280  const base_node &y(void) const { return cp->master_point; }
281  const base_node &y_ref(void) const { return cp->master_point_ref; }
282  const base_node &ny(void) const { return cp->master_n; }
283  scalar_type g(void) const { return cp->signed_dist; }
284 
285  base_matrix I_nxnx_;
286  bool I_nxnx_computed;
287  const base_matrix &I_nxnx(void) {
288  if (!I_nxnx_computed) {
289  gmm::copy(gmm::identity_matrix(), I_nxnx_);
290  gmm::rank_one_update(I_nxnx_, nx(), gmm::scaled(nx(),scalar_type(-1)));
291  I_nxnx_computed = true;
292  }
293  return I_nxnx_;
294  }
295 
296  base_matrix I_nyny_;
297  bool I_nyny_computed;
298  const base_matrix &I_nyny(void) {
299  if (!I_nyny_computed) {
300  gmm::copy(gmm::identity_matrix(), I_nyny_);
301  gmm::rank_one_update(I_nyny_, ny(), gmm::scaled(ny(),scalar_type(-1)));
302  I_nyny_computed = true;
303  }
304  return I_nyny_;
305  }
306 
307  base_matrix I_nxny_;
308  bool I_nxny_computed;
309  const base_matrix &I_nxny(void) {
310  if (!I_nxny_computed) {
311  gmm::copy(gmm::identity_matrix(), I_nxny_);
312  gmm::rank_one_update(I_nxny_, nx(),
313  gmm::scaled(ny(),scalar_type(-1)/nxny));
314  I_nxny_computed = true;
315  }
316  return I_nxny_;
317  }
318 
319  scalar_type nxny;
320  scalar_type nxdotny(void) const { return nxny; }
321 
322  bool isrigid_;
323  bool isrigid(void) { return isrigid_; }
324 
325  base_tensor base_ux, base_uy, base_lx, base_ly;
326  base_matrix vbase_ux_, vbase_uy_, vbase_lx_, vbase_ly_;
327  bool vbase_ux_init, vbase_uy_init, vbase_lx_init, vbase_ly_init;
328  base_tensor grad_base_ux, grad_base_uy, vgrad_base_ux_, vgrad_base_uy_;
329  bool vgrad_base_ux_init, vgrad_base_uy_init;
330  bool have_lx, have_ly;
331 
332  fem_interpolation_context ctx_ux_, ctx_uy_, ctx_lx_, ctx_ly_;
333  bool ctx_ux_init, ctx_uy_init, ctx_lx_init, ctx_ly_init;
334  base_matrix Gx, Gy;
335  const mesh_fem *mf_ux_, *mf_uy_, *mf_lx_, *mf_ly_;
336  gmm::sub_interval I_ux_, I_uy_, I_lx_, I_ly_;
337  pfem pf_ux, pf_uy, pf_lx, pf_ly;
338  size_type ndof_ux_, qdim_ux, ndof_uy_, qdim_uy, ndof_lx_, qdim_lx;
339  size_type ndof_ly_, qdim_ly, cvx_, cvy_, ibx, iby;
340  short_type fx, fy;
341  bgeot::pgeometric_trans pgtx, pgty;
342  const mesh_im *mim;
343  pintegration_method pim;
344  scalar_type weight_;
345 
346  scalar_type weight(void) { return weight_; }
347 
348  const mesh &meshx(void) const { return mf_ux_->linked_mesh(); }
349  const mesh &meshy(void) const { return mf_uy_->linked_mesh(); }
350  const mesh_fem *mf_ux(void) const { return mf_ux_; }
351  const mesh_fem *mf_uy(void) const { return mf_uy_; }
352  const mesh_fem *mf_lx(void) const { return mf_lx_; }
353  const mesh_fem *mf_ly(void) const { return mf_ly_; }
354  size_type ndof_ux(void) const { return ndof_ux_; }
355  size_type ndof_uy(void) const { return ndof_uy_; }
356  size_type ndof_lx(void) const { return ndof_lx_; }
357  size_type ndof_ly(void) const { return ndof_ly_; }
358  size_type cvx(void) const { return cvx_; }
359  size_type cvy(void) const { return cvy_; }
360  const gmm::sub_interval I_ux(void) const { return I_ux_; }
361  const gmm::sub_interval I_uy(void) const { return I_uy_; }
362  const gmm::sub_interval I_lx(void) const { return I_lx_; }
363  const gmm::sub_interval I_ly(void) const { return I_ly_; }
364 
365 
366  fem_interpolation_context &ctx_ux(void) {
367  if (!ctx_ux_init) {
368  bgeot::vectors_to_base_matrix(Gx, meshx().points_of_convex(cvx_));
369  pfem_precomp pfp_ux
370  = fppool(pf_ux, pim->approx_method()->pintegration_points());
371  ctx_ux_ = fem_interpolation_context(pgtx, pfp_ux, cp->slave_ind_pt,
372  Gx, cvx_, fx);
373  ctx_ux_init = true;
374  }
375  return ctx_ux_;
376  }
377 
378  fem_interpolation_context &ctx_lx(void) {
379  GMM_ASSERT1(have_lx, "No multiplier defined on the slave surface");
380  if (!ctx_lx_init) {
381  pfem_precomp pfp_lx
382  = fppool(pf_lx, pim->approx_method()->pintegration_points());
383  ctx_lx_ = fem_interpolation_context(pgtx, pfp_lx, cp->slave_ind_pt,
384  ctx_ux().G(), cvx_, fx);
385  ctx_lx_init = true;
386  }
387  return ctx_lx_;
388  }
389 
390  fem_interpolation_context &ctx_uy(void) {
391  GMM_ASSERT1(!isrigid(), "Rigid obstacle master node: no fem defined");
392  if (!ctx_uy_init) {
393  bgeot::vectors_to_base_matrix(Gy, meshy().points_of_convex(cvy_));
394  ctx_uy_ = fem_interpolation_context(pgty, pf_uy, y_ref(), Gy, cvy_, fy);
395  ctx_uy_init = true;
396  }
397  return ctx_uy_;
398  }
399 
400  fem_interpolation_context &ctx_ly(void) {
401  GMM_ASSERT1(have_ly, "No multiplier defined on the master surface");
402  if (!ctx_ly_init) {
403  ctx_ly_ = fem_interpolation_context(pgty, pf_ly, y_ref(),
404  ctx_uy().G(), cvy_, fy);
405  ctx_ly_init = true;
406  }
407  return ctx_ly_;
408  }
409 
410  const base_matrix &vbase_ux(void) {
411  if (!vbase_ux_init) {
412  ctx_ux().base_value(base_ux);
413  vectorize_base_tensor(base_ux, vbase_ux_, ndof_ux_, qdim_ux, N);
414  vbase_ux_init = true;
415  }
416  return vbase_ux_;
417  }
418 
419  const base_matrix &vbase_uy(void) {
420  if (!vbase_uy_init) {
421  ctx_uy().base_value(base_uy);
422  vectorize_base_tensor(base_uy, vbase_uy_, ndof_uy_, qdim_uy, N);
423  vbase_uy_init = true;
424  }
425  return vbase_uy_;
426  }
427 
428  const base_matrix &vbase_lx(void) {
429  if (!vbase_lx_init) {
430  ctx_lx().base_value(base_lx);
431  vectorize_base_tensor(base_lx, vbase_lx_, ndof_lx_, qdim_lx, N);
432  vbase_lx_init = true;
433  }
434  return vbase_lx_;
435  }
436 
437  const base_matrix &vbase_ly(void) {
438  if (!vbase_ly_init) {
439  ctx_ly().base_value(base_ly);
440  vectorize_base_tensor(base_ly, vbase_ly_, ndof_ly_, qdim_ly, N);
441  vbase_ly_init = true;
442  }
443  return vbase_ly_;
444  }
445 
446  const base_tensor &vgrad_base_ux(void) {
447  if (!vgrad_base_ux_init) {
448  ctx_ux().grad_base_value(grad_base_ux);
449  vectorize_grad_base_tensor(grad_base_ux, vgrad_base_ux_, ndof_ux_,
450  qdim_ux, N);
451  vgrad_base_ux_init = true;
452  }
453  return vgrad_base_ux_;
454  }
455 
456  const base_tensor &vgrad_base_uy(void) {
457  if (!vgrad_base_uy_init) {
458  ctx_uy().grad_base_value(grad_base_uy);
459  vectorize_grad_base_tensor(grad_base_uy, vgrad_base_uy_, ndof_uy_,
460  qdim_uy, N);
461  vgrad_base_uy_init = true;
462  }
463  return vgrad_base_uy_;
464  }
465 
466  base_small_vector lambda_x_, lambda_y_;
467  bool lambda_x_init, lambda_y_init;
468  base_vector coeff;
469 
470  const base_small_vector &lx(void) {
471  if (!lambda_x_init) {
472  pfem pf = ctx_lx().pf();
473  slice_vector_on_basic_dof_of_element(*mf_lx_,mcf.mult_of_boundary(ibx),
474  cvx_, coeff);
475  pf->interpolation(ctx_lx(), coeff, lambda_x_, dim_type(N));
476  lambda_x_init = true;
477  }
478  return lambda_x_;
479  }
480 
481  const base_small_vector &ly(void) {
482  if (!lambda_y_init) {
483  pfem pf = ctx_ly().pf();
484  slice_vector_on_basic_dof_of_element(*mf_ly_,mcf.mult_of_boundary(iby),
485  cvy_, coeff);
486  pf->interpolation(ctx_ly(), coeff, lambda_y_, dim_type(N));
487  lambda_y_init = true;
488  }
489  return lambda_y_;
490  }
491 
492  base_matrix grad_phix_, grad_phix_inv_, grad_phiy_, grad_phiy_inv_;
493  bool grad_phix_init, grad_phix_inv_init;
494  bool grad_phiy_init, grad_phiy_inv_init;
495 
496  const base_matrix &grad_phix(void) {
497  if (!grad_phix_init) {
498  pfem pf = ctx_ux().pf();
499  slice_vector_on_basic_dof_of_element(*mf_ux_, mcf.disp_of_boundary(ibx),
500  cvx_, coeff);
501  pf->interpolation_grad(ctx_ux(), coeff, grad_phix_, dim_type(N));
502  gmm::add(gmm::identity_matrix(), grad_phix_);
503  grad_phix_init = true;
504  }
505  return grad_phix_;
506  }
507 
508  const base_matrix &grad_phix_inv(void) {
509  if (!grad_phix_inv_init) {
510  gmm::copy(grad_phix(), grad_phix_inv_);
511  /* scalar_type J = */ gmm::lu_inverse(grad_phix_inv_);
512  // if (J <= scalar_type(0)) GMM_WARNING1("Inverted element !" << J);
513  grad_phix_inv_init = true;
514  }
515  return grad_phix_inv_;
516  }
517 
518  const base_matrix &grad_phiy(void) {
519  if (!grad_phiy_init) {
520  pfem pf = ctx_uy().pf();
521  slice_vector_on_basic_dof_of_element(*mf_uy_, mcf.disp_of_boundary(iby),
522  cvy_, coeff);
523  pf->interpolation_grad(ctx_uy(), coeff, grad_phiy_, dim_type(N));
524  gmm::add(gmm::identity_matrix(), grad_phiy_);
525  grad_phiy_init = true;
526  }
527  return grad_phiy_;
528  }
529 
530  const base_matrix &grad_phiy_inv(void) {
531  if (!grad_phiy_inv_init) {
532  gmm::copy(grad_phiy(), grad_phiy_inv_);
533  /* scalar_type J = */ gmm::lu_inverse(grad_phiy_inv_);
534  // if (J <= scalar_type(0)) GMM_WARNING1("Inverted element !" << J);
535  grad_phiy_inv_init = true;
536  }
537  return grad_phiy_inv_;
538  }
539 
540  scalar_type alpha;
541  base_small_vector x0_, y0_, nx0_, Vs_;
542  bool x0_init, y0_init, nx0_init, Vs_init;
543  base_matrix grad_phiy0_;
544  bool grad_phiy0_init;
545 
546  const base_small_vector &x0(void) {
547  if (!x0_init) {
548  const model_real_plain_vector &all_x0 = mcf.disp0_of_boundary(ibx);
549  if (all_x0.size()) {
550  pfem pf = ctx_ux().pf();
551  slice_vector_on_basic_dof_of_element(*mf_ux_, all_x0, cvx_, coeff);
552  pf->interpolation(ctx_ux(), coeff, x0_, dim_type(N));
553  } else gmm::clear(x0_);
554  gmm::add(ctx_ux().xreal(), x0_);
555  x0_init = true;
556  }
557  return x0_;
558  }
559 
560  const base_small_vector &y0(void) {
561  if (!y0_init) {
562  if (!isrigid()) {
563  const model_real_plain_vector &all_y0 = mcf.disp0_of_boundary(iby);
564  if (all_y0.size()) {
565  pfem pf = ctx_uy().pf();
566  slice_vector_on_basic_dof_of_element(*mf_uy_, all_y0, cvy_, coeff);
567  pf->interpolation(ctx_uy(), coeff, y0_, dim_type(N));
568  } else gmm::clear(y0_);
569  gmm::add(ctx_uy().xreal(), y0_);
570  } else gmm::copy(y(), y0_);
571  y0_init = true;
572  }
573  return y0_;
574  }
575 
576  const base_small_vector &nx0(void) {
577  if (!nx0_init) {
578  const model_real_plain_vector &all_x0 = mcf.disp0_of_boundary(ibx);
579  if (all_x0.size()) {
580  pfem pf = ctx_ux().pf();
581  slice_vector_on_basic_dof_of_element(*mf_ux_, all_x0, cvx_, coeff);
582  base_small_vector nx00_(N);
583  base_matrix grad_phix0_(N,N);
584  compute_normal(ctx_ux(), fx, false, coeff, nx00_, nx0_, grad_phix0_);
585  nx0_ /= gmm::vect_norm2(nx0_);
586  } else gmm::clear(nx0_);
587  nx0_init = true;
588  }
589  return nx0_;
590  }
591 
592  const base_small_vector &Vs(void) { // relative velocity
593  if (!Vs_init) {
594  if (alpha != scalar_type(0)) {
595 #ifdef CONSIDER_FRAME_INDIFFERENCE
596  if (!isrigid()) {
597  gmm::add(y0(), gmm::scaled(x0(), scalar_type(-1)), Vs_);
598  gmm::add(gmm::scaled(nx0(), -g()), Vs_);
599  } else
600 #endif
601  {
602  gmm::add(x(), gmm::scaled(y(), scalar_type(-1)), Vs_);
603  gmm::add(gmm::scaled(x0(), scalar_type(-1)), Vs_);
604  gmm::add(y0(), Vs_);
605  }
606  gmm::scale(Vs_, alpha);
607  } else gmm::clear(Vs_);
608  Vs_init = true;
609  }
610  return Vs_;
611  }
612 
613  const base_matrix &grad_phiy0(void) { // grad_phiy of previous time step
614  // To be verified ...
615  if (!grad_phiy0_init) {
616  const model_real_plain_vector &all_y0 = mcf.disp0_of_boundary(iby);
617  if (!isrigid() && all_y0.size()) {
618  pfem pf = ctx_uy().pf();
619  slice_vector_on_basic_dof_of_element(*mf_uy_, all_y0, cvy_, coeff);
620  pf->interpolation_grad(ctx_uy(), coeff, grad_phiy0_, dim_type(N));
621  gmm::add(gmm::identity_matrix(), grad_phiy0_);
622  } else gmm::copy(gmm::identity_matrix(), grad_phiy0_);
623  grad_phiy0_init = true;
624  }
625  return grad_phiy0_;
626  }
627 
628  base_small_vector un;
629 
630  void set_pair(const multi_contact_frame::contact_pair &cp_) {
631  cp = &cp_;
632  I_nxnx_computed = I_nyny_computed = I_nxny_computed = false;
633  ctx_ux_init = ctx_uy_init = ctx_lx_init = ctx_ly_init = false;
634  vbase_ux_init = vbase_uy_init = vbase_lx_init = vbase_ly_init = false;
635  vgrad_base_ux_init = vgrad_base_uy_init = false;
636  lambda_x_init = lambda_y_init = false;
637  have_lx = have_ly = false;
638  grad_phix_init = grad_phiy_init = false;
639  grad_phix_inv_init = grad_phiy_inv_init = false;
640  x0_init = y0_init = Vs_init = grad_phiy0_init = false;
641  nxny = gmm::vect_sp(nx(), ny());
642  isrigid_ = (cp->irigid_obstacle != size_type(-1));
643 
644  cvx_ = cp->slave_ind_element;
645  ibx = cp->slave_ind_boundary;
646  mf_ux_ = &(mcf.mfdisp_of_boundary(ibx));
647  pf_ux = mf_ux_->fem_of_element(cvx_);
648  qdim_ux = pf_ux->target_dim();
649  ndof_ux_ = pf_ux->nb_dof(cvx_) * N / qdim_ux;
650  fx = cp->slave_ind_face;
651  pgtx = meshx().trans_of_convex(cvx_);
652  mim = &(mcf.mim_of_boundary(ibx));
653  pim = mim->int_method_of_element(cvx_);
654  weight_ = pim->approx_method()->coeff(cp->slave_ind_pt) * ctx_ux().J();
655  gmm::mult(ctx_ux().B(), pgtx->normals()[fx], un);
656  weight_ *= gmm::vect_norm2(un);
657  const std::string &name_ux = mcf.varname_of_boundary(ibx);
658  I_ux_ = md.interval_of_variable(name_ux);
659 
660  const std::string &name_lx = mcf.multname_of_boundary(ibx);
661  have_lx = (name_lx.size() > 0);
662  if (have_lx) {
663  mf_lx_ = &(mcf.mfmult_of_boundary(ibx));
664  I_lx_ = md.interval_of_variable(name_lx);
665  pf_lx = mf_lx_->fem_of_element(cvx_);
666  qdim_lx = pf_lx->target_dim();
667  ndof_lx_ = pf_lx->nb_dof(cvx_) * N / qdim_lx;
668  }
669 
670  if (!isrigid_) {
671  cvy_ = cp->master_ind_element;
672  iby = cp->master_ind_boundary;
673  fy = cp->master_ind_face;
674  mf_uy_ = &(mcf.mfdisp_of_boundary(iby));
675  pf_uy = mf_uy_->fem_of_element(cvy_);
676  qdim_uy = pf_uy->target_dim();
677  ndof_uy_ = pf_uy->nb_dof(cvy_) * N / qdim_uy;
678  pgty = meshy().trans_of_convex(cvy_);
679 
680  const std::string &name_uy = mcf.varname_of_boundary(iby);
681  I_uy_ = md.interval_of_variable(name_uy);
682  const std::string &name_ly = mcf.multname_of_boundary(iby);
683  have_ly = (name_ly.size() > 0);
684  if (have_ly) {
685  mf_ly_ = &(mcf.mfmult_of_boundary(iby));
686  I_ly_ = md.interval_of_variable(name_ly);
687  pf_ly = mf_ly_->fem_of_element(cvy_);
688  qdim_ly = pf_ly->target_dim();
689  ndof_ly_ = pf_ly->nb_dof(cvy_) * N / qdim_ly;
690  }
691  }
692  }
693 
694  gauss_point_precomp(size_type N_, const model &md_,
695  const multi_contact_frame &mcf_, scalar_type alpha_) :
696  N(N_), mcf(mcf_), md(md_),
697  I_nxnx_(N,N), I_nyny_(N,N), I_nxny_(N,N),
698  lambda_x_(N), lambda_y_(N),
699  grad_phix_(N, N), grad_phix_inv_(N, N),
700  grad_phiy_(N, N), grad_phiy_inv_(N, N), alpha(alpha_),
701  x0_(N), y0_(N), nx0_(N), Vs_(N), grad_phiy0_(N, N), un(N) {}
702 
703  };
704 
705 /* static void do_test_F(size_type N) { */
706 
707 /* base_matrix dlambdaF(N, N), dnF(N, N), dVsF(N, N); */
708 /* base_small_vector F(N), dgF(N); */
709 
710 /* scalar_type EPS = 5E-9; */
711 /* for (size_type k = 0; k < 100; ++k) { */
712 /* base_small_vector lambda_r(N), Vs_r(N), nx_r(N), f_coeff_r(3); */
713 /* base_small_vector F2(N), F3(N); */
714 /* scalar_type g_r = gmm::random(1.), r_r = gmm::random(); */
715 /* gmm::fill_random(lambda_r); */
716 /* gmm::fill_random(Vs_r); */
717 /* gmm::fill_random(nx_r); */
718 /* gmm::scale(nx_r, 1./gmm::vect_norm2(nx_r)); */
719 /* f_coeff_r[0] = gmm::random(); */
720 /* f_coeff_r[1] = gmm::random(); */
721 /* f_coeff_r[2] = gmm::random(); */
722 
723 /* aug_friction(lambda_r, g_r, Vs_r, nx_r, r_r, f_coeff_r, F); */
724 /* aug_friction_grad(lambda_r, g_r, Vs_r, nx_r, r_r, f_coeff_r, F2, */
725 /* dlambdaF, dgF, dnF, dVsF); */
726 /* GMM_ASSERT1(gmm::vect_dist2(F2, F) < 1E-7, "bad F"); */
727 
728 /* base_small_vector dlambda(N); */
729 /* gmm::fill_random(dlambda); */
730 
731 
732 /* gmm::add(gmm::scaled(dlambda, EPS), nx_r); */
733 /* aug_friction(lambda_r, g_r, Vs_r, nx_r, r_r, f_coeff_r, F2); */
734 
735 /* gmm::mult(dnF, gmm::scaled(dlambda, EPS), F, F3); */
736 /* if (gmm::vect_dist2(F2, F3)/EPS > 1E-4) { */
737 /* cout << "lambda_r = " << lambda_r << " Vs_r = " << Vs_r */
738 /* << " nx_r = " << nx_r << endl << "g_r = " << g_r */
739 /* << " r_r = " << r_r << " f = " << f_coeff_r << endl; */
740 /* cout << "diff = " << gmm::vect_dist2(F2, F3)/EPS << endl; */
741 /* GMM_ASSERT1(false, "bad n derivative"); */
742 /* } */
743 
744 /* gmm::add(gmm::scaled(dlambda, -EPS), nx_r); */
745 
746 
747 /* gmm::add(gmm::scaled(dlambda, EPS), lambda_r); */
748 /* aug_friction(lambda_r, g_r, Vs_r, nx_r, r_r, f_coeff_r, F2); */
749 /* gmm::mult(dlambdaF, gmm::scaled(dlambda, EPS), F, F3); */
750 /* if (gmm::vect_dist2(F2, F3)/EPS > 1E-6) { */
751 /* cout << "diff = " << gmm::vect_dist2(F2, F3)/EPS << endl; */
752 /* GMM_ASSERT1(false, "bad lambda derivative"); */
753 /* } */
754 /* gmm::add(gmm::scaled(dlambda, -EPS), lambda_r); */
755 
756 
757 /* gmm::add(gmm::scaled(dlambda, EPS), Vs_r); */
758 /* aug_friction(lambda_r, g_r, Vs_r, nx_r, r_r, f_coeff_r, F2); */
759 /* gmm::mult(dVsF, gmm::scaled(dlambda, EPS), F, F3); */
760 /* if (gmm::vect_dist2(F2, F3)/EPS > 1E-6) { */
761 /* cout << "diff = " << gmm::vect_dist2(F2, F3)/EPS << endl; */
762 /* GMM_ASSERT1(false, "bad Vs derivative"); */
763 /* } */
764 /* gmm::add(gmm::scaled(dlambda, -EPS), Vs_r); */
765 
766 
767 /* g_r += EPS; */
768 /* aug_friction(lambda_r, g_r, Vs_r, nx_r, r_r, f_coeff_r, F2); */
769 /* gmm::add(gmm::scaled(dgF, EPS), F, F3); */
770 /* if (gmm::vect_dist2(F2, F3)/EPS > 1E-6) { */
771 /* cout << "diff = " << gmm::vect_dist2(F2, F3)/EPS << endl; */
772 /* GMM_ASSERT1(false, "bad g derivative"); */
773 /* } */
774 /* g_r -= EPS; */
775 /* } */
776 /* } */
777 
778 
779  void integral_large_sliding_contact_brick::asm_real_tangent_terms
780  (const model &md, size_type /* ib */, const model::varnamelist &vl,
781  const model::varnamelist &dl, const model::mimlist &/* mims */,
782  model::real_matlist &matl, model::real_veclist &vecl,
783  model::real_veclist &, size_type /* region */,
784  build_version version) const {
785 
786  // Data : r, friction_coeff.
787  GMM_ASSERT1((with_friction && dl.size() >= 2 && dl.size() <= 3)
788  || (!with_friction && dl.size() >= 1 && dl.size() <= 2),
789  "Wrong number of data for integral large sliding contact brick");
790 
791  GMM_ASSERT1(vl.size() == mcf.nb_variables() + mcf.nb_multipliers(),
792  "For the moment, it is not allowed to add boundaries to "
793  "the multi contact frame object after a model brick has "
794  "been added.");
795 
796  const model_real_plain_vector &vr = md.real_variable(dl[0]);
797  GMM_ASSERT1(gmm::vect_size(vr) == 1, "Large sliding contact "
798  "brick: parameter r should be a scalar");
799  scalar_type r = vr[0];
800 
801  model_real_plain_vector f_coeff;
802  if (with_friction) {
803  f_coeff = md.real_variable(dl[1]);
804  GMM_ASSERT1(gmm::vect_size(f_coeff) <= 3,
805  "Large sliding contact "
806  "brick: the friction law has less than 3 parameters");
807  }
808  if (gmm::vect_size(f_coeff) == 0) // default: no friction
809  { f_coeff.resize(1); f_coeff[0] = scalar_type(0); }
810 
811  scalar_type alpha(0);
812  size_type ind = with_friction ? 2:1;
813  if (dl.size() >= ind+1) {
814  GMM_ASSERT1(md.real_variable(dl[ind]).size() == 1,
815  "Large sliding contact "
816  "brick: parameter alpha should be a scalar");
817  alpha = md.real_variable(dl[ind])[0];
818  }
819 
820  GMM_ASSERT1(matl.size() == 1,
821  "Large sliding contact brick should have only one term");
822  model_real_sparse_matrix &M = matl[0]; gmm::clear(M);
823  model_real_plain_vector &V = vecl[0]; gmm::clear(V);
824 
825  mcf.set_raytrace(true);
826  mcf.set_nodes_mode(0);
827  mcf.compute_contact_pairs();
828 
829  size_type N = mcf.dim();
830  base_matrix Melem;
831  base_matrix dlambdaF(N, N), dnF(N, N), dVsF(N, N);
832  base_small_vector F(N), dgF(N);
833 
834  scalar_type FMULT = 1.;
835 
836  // Stabilization for non-contact zones
837  for (size_type i = 0; i < mcf.nb_boundaries(); ++i)
838  if (mcf.is_self_contact() || mcf.is_slave_boundary(i)) {
839  size_type region = mcf.region_of_boundary(i);
840  const std::string &name_lx = mcf.multname_of_boundary(i);
841  GMM_ASSERT1(name_lx.size() > 0, "This brick need "
842  "multipliers defined on the multi_contact_frame object");
843  const mesh_fem &mflambda = mcf.mfmult_of_boundary(i);
844  const mesh_im &mim = mcf.mim_of_boundary(i);
845  const gmm::sub_interval &I = md.interval_of_variable(name_lx);
846 
847  if (version & model::BUILD_MATRIX) { // LXLX term
848  model_real_sparse_matrix M1(mflambda.nb_dof(), mflambda.nb_dof());
849  asm_mass_matrix(M1, mim, mflambda, region);
850  gmm::add(gmm::scaled(M1, FMULT/r), gmm::sub_matrix(M, I, I));
851  }
852 
853  if (version & model::BUILD_RHS) { // LX term
854  model_real_plain_vector V1(mflambda.nb_dof());
856  (V1, mim, mflambda, mflambda,
857  md.real_variable(mcf.multname_of_boundary(i)), region);
858  gmm::add(gmm::scaled(V1, -FMULT/r), gmm::sub_vector(V, I));
859  }
860  }
861 
862  gauss_point_precomp gpp(N, md, mcf, alpha);
863 
864  // do_test_F(2); do_test_F(3);
865 
866  base_matrix auxNN1(N, N), auxNN2(N, N);
867  base_small_vector auxN1(N), auxN2(N);
868 
869  // Iterations on the contact pairs
870  for (size_type icp = 0; icp < mcf.nb_contact_pairs(); ++icp) {
871  const multi_contact_frame::contact_pair &cp = mcf.get_contact_pair(icp);
872  gpp.set_pair(cp);
873  const base_small_vector &nx = gpp.nx(), &ny = gpp.ny();
874  const mesh_fem *mf_ux = gpp.mf_ux(), *mf_lx = gpp.mf_lx(), *mf_uy(0);
875  size_type ndof_ux = gpp.ndof_ux(), ndof_uy(0), ndof_lx = gpp.ndof_lx();
876  size_type cvx = gpp.cvx(), cvy(0);
877  const gmm::sub_interval &I_ux = gpp.I_ux(), &I_lx = gpp.I_lx();
878  gmm::sub_interval I_uy;
879  bool isrigid = gpp.isrigid();
880  if (!isrigid) {
881  ndof_uy = gpp.ndof_uy(); I_uy = gpp.I_uy();
882  mf_uy = gpp.mf_uy(); cvy = gpp.cvy();
883  }
884  scalar_type weight = gpp.weight(), g = gpp.g();
885  const base_small_vector &lambda = gpp.lx();
886 
887  base_vector auxUX(ndof_ux), auxUY(ndof_uy);
888 
889  if (version & model::BUILD_MATRIX) {
890 
891  base_matrix auxUYN(ndof_uy, N);
892  base_matrix auxLXN1(ndof_lx, N), auxLXN2(ndof_lx, N);
893 
894  aug_friction_grad(lambda, g, gpp.Vs(), nx, r, f_coeff, F, dlambdaF,
895  dgF, dnF, dVsF);
896 
897 
898  const base_tensor &vgrad_base_ux = gpp.vgrad_base_ux();
899  base_matrix graddeltaunx(ndof_ux, N);
900  for (size_type i = 0; i < ndof_ux; ++i)
901  for (size_type j = 0; j < N; ++j)
902  for (size_type k = 0; k < N; ++k)
903  graddeltaunx(i, j) += nx[k] * vgrad_base_ux(i, k, j);
904 
905 #define CONSIDER_TERM1
906 #define CONSIDER_TERM2
907 #define CONSIDER_TERM3
908 
909 
910 #ifdef CONSIDER_TERM1
911  // Term -\delta\lambda(X) . \delta v(X)
912  gmm::resize(Melem, ndof_ux, ndof_lx); gmm::clear(Melem);
913  gmm::mult(gpp.vbase_ux(), gmm::transposed(gpp.vbase_lx()), Melem);
914  gmm::scale(Melem, -weight);
915  mat_elem_assembly(M, I_ux, I_lx, Melem, *mf_ux, cvx, *mf_lx, cvx);
916 #endif
917 
918 #ifdef CONSIDER_TERM2
919 
920  if (!isrigid) {
921  // Term \delta\lambda(X) . \delta v(Y)
922  gmm::resize(Melem, ndof_uy, ndof_lx); gmm::clear(Melem);
923  gmm::mult(gpp.vbase_uy(), gmm::transposed(gpp.vbase_lx()), Melem);
924  gmm::scale(Melem, weight);
925  mat_elem_assembly(M, I_uy, I_lx, Melem, *mf_uy, cvy, *mf_lx, cvx);
926 
927  // Term \lambda(X) . (\nabla \delta v(Y) (\nabla phi)^(-1)\delta y
928  gmm::clear(auxUYN);
929  const base_tensor &vgrad_base_uy = gpp.vgrad_base_uy();
930  for (size_type i = 0; i < ndof_uy; ++i)
931  for (size_type j = 0; j < N; ++j)
932  for (size_type k = 0; k < N; ++k)
933  auxUYN(i, j) += lambda[k] * vgrad_base_uy(i, k, j);
934  base_matrix lgraddeltavgradphiyinv(ndof_uy, N);
935  gmm::mult(auxUYN, gpp.grad_phiy_inv(), lgraddeltavgradphiyinv);
936 
937  // first sub term
938  gmm::resize(Melem, ndof_uy, ndof_uy); gmm::clear(Melem);
939  gmm::mult(lgraddeltavgradphiyinv, gpp.I_nxny(), auxUYN);
940  gmm::mult(auxUYN, gmm::transposed(gpp.vbase_uy()), Melem);
941  // Caution: re-use of auxUYN in second sub term
942  gmm::scale(Melem, -weight);
943  mat_elem_assembly(M, I_uy, I_uy, Melem, *mf_uy, cvy, *mf_uy, cvy);
944 
945  // Second sub term
946  gmm::resize(Melem, ndof_uy, ndof_ux); gmm::clear(Melem);
947  // Caution: re-use of auxUYN
948  // gmm::mult(lgraddeltavgradphiyinv, gpp.I_nxny(), auxUYN);
949  gmm::mult(auxUYN, gmm::transposed(gpp.vbase_ux()), Melem);
950 
951  // Third sub term
952  base_matrix auxUYUX(ndof_uy, ndof_ux);
953  gmm::mult(gpp.I_nxny(), gmm::transposed(gpp.grad_phix_inv()), auxNN1);
954  gmm::mult(lgraddeltavgradphiyinv, auxNN1, auxUYN);
955  gmm::mult(auxUYN, gmm::transposed(graddeltaunx), auxUYUX);
956  gmm::scale(auxUYUX, -g);
957  gmm::add(auxUYUX, Melem);
958  gmm::scale(Melem, weight);
959  mat_elem_assembly(M, I_uy, I_ux, Melem, *mf_uy, cvy, *mf_ux, cvx);
960  }
961 
962 #endif
963 
964 
965 #ifdef CONSIDER_TERM3
966 
967  // LXLX term
968  // Term (1/r)(I-dlambdaF)\delta\lambda\delta\mu
969  // the I of (I-dlambdaF) is skipped because globally added before
970  gmm::resize(Melem, ndof_lx, ndof_lx); gmm::clear(Melem);
971  gmm::copy(gmm::scaled(dlambdaF, scalar_type(-1)/r), auxNN1);
972  gmm::mult(gpp.vbase_lx(), auxNN1, auxLXN1);
973  gmm::mult(auxLXN1, gmm::transposed(gpp.vbase_lx()), Melem);
974  gmm::scale(Melem, weight*FMULT);
975  mat_elem_assembly(M, I_lx, I_lx, Melem, *mf_lx, cvx, *mf_lx, cvx);
976 
977  // LXUX term
978  // Term -(1/r)dnF\delta nx\delta\mu
979  gmm::resize(Melem, ndof_lx, ndof_ux); gmm::clear(Melem);
980  gmm::mult(gpp.vbase_lx(), dnF, auxLXN1);
981  gmm::mult(auxLXN1, gpp.I_nxnx(), auxLXN2);
982  gmm::mult(auxLXN2, gmm::transposed(gpp.grad_phix_inv()), auxLXN1);
983  gmm::mult(auxLXN1, gmm::transposed(graddeltaunx), Melem);
984  gmm::scale(Melem, scalar_type(1)/r);
985  // assembly factorized with the next term
986 
987  // Term -(1/r)dgF\delta g\delta\mu
988  base_vector deltamudgF(ndof_lx);
989  gmm::mult(gpp.vbase_lx(),
990  gmm::scaled(dgF, scalar_type(1)/(r*gpp.nxdotny())),
991  deltamudgF);
992 
993  // first sub term
994  gmm::mult(gpp.vbase_ux(), ny, auxUX);
995 
996  // second sub term
997  gmm::mult(gpp.I_nxnx(), gmm::scaled(ny, -g), auxN1);
998  gmm::mult(gpp.grad_phix_inv(), auxN1, auxN2);
999  gmm::mult_add(graddeltaunx, auxN2, auxUX); // auxUX -> \delta u(X) - g Dn_x
1000  gmm::rank_one_update(Melem, deltamudgF, auxUX);
1001  gmm::scale(Melem, weight*FMULT);
1002  mat_elem_assembly(M, I_lx, I_ux, Melem, *mf_lx, cvx, *mf_ux, cvx);
1003 
1004  if (!isrigid) {
1005  // LXUY term
1006  // third sub term
1007  gmm::resize(Melem, ndof_lx, ndof_uy); gmm::clear(Melem);
1008  gmm::mult(gpp.vbase_uy(), ny, auxUY); // auxUY -> \delta u(Y)
1009  gmm::rank_one_update(Melem, deltamudgF, auxUY);
1010  gmm::scale(Melem, -weight*FMULT);
1011  mat_elem_assembly(M, I_lx, I_uy, Melem, *mf_lx, cvx, *mf_uy, cvy);
1012  }
1013 
1014  if (alpha != scalar_type(0)) {
1015  // Term -(1/r) d_Vs F \delta Vs\delta\mu
1016 
1017  if (!isrigid) {
1018 #ifdef CONSIDER_FRAME_INDIFFERENCE
1019  base_matrix gphiy0gphiyinv(N, N);
1020  gmm::mult(gpp.grad_phiy0(), gpp.grad_phiy_inv(), gphiy0gphiyinv);
1021  gmm::mult(gphiy0gphiyinv, gpp.I_nxny(), auxNN1);
1022  gmm::rank_one_update(auxNN1, gpp.nx0(),
1023  gmm::scaled(gpp.ny(),scalar_type(1)/gpp.nxdotny()));
1024  gmm::mult(dVsF, auxNN1, auxNN2);
1025  // Caution: auxNN2 re-used in the second sub term
1026 
1027  // LXUX term
1028  // first sub term
1029  gmm::resize(Melem, ndof_lx, ndof_ux); gmm::clear(Melem);
1030  gmm::mult(gpp.vbase_lx(), gmm::transposed(auxNN2), auxLXN1);
1031  // Caution: auxLXN1 re-used in the third sub term
1032  gmm::mult(auxLXN1, gmm::transposed(gpp.vbase_ux()), Melem);
1033 
1034  // second sub term
1035  base_matrix auxLXUX(ndof_lx, ndof_ux);
1036  gmm::mult(auxNN2, gpp.I_nxnx(), auxNN1);
1037  gmm::mult(auxNN1, gmm::transposed(gpp.grad_phix_inv()), auxNN2);
1038  gmm::mult(gpp.vbase_lx(), gmm::transposed(auxNN2), auxLXN2);
1039  gmm::mult(auxLXN2, gmm::transposed(graddeltaunx), auxLXUX);
1040  gmm::scale(auxLXUX, -g);
1041  gmm::add(auxLXUX, Melem);
1042  gmm::scale(Melem, -weight*alpha*FMULT/r);
1043  mat_elem_assembly(M, I_lx, I_ux, Melem, *mf_lx, cvx, *mf_ux, cvx);
1044 
1045  // LXUY term
1046  // third sub term
1047  gmm::resize(Melem, ndof_lx, ndof_uy); gmm::clear(Melem);
1048  // Caution: auxLXN1 re-used
1049  gmm::mult(auxLXN1, gmm::transposed(gpp.vbase_uy()), Melem);
1050  gmm::scale(Melem, weight*alpha*FMULT/r);
1051  mat_elem_assembly(M, I_lx, I_uy, Melem, *mf_lx, cvx, *mf_uy, cvy);
1052 #else
1053  base_matrix I_gphiy0gphiyinv(N, N);
1054  gmm::mult(gmm::scaled(gpp.grad_phiy0(), scalar_type(-1)),
1055  gpp.grad_phiy_inv(), I_gphiy0gphiyinv);
1056  gmm::add(gmm::identity_matrix(), I_gphiy0gphiyinv);
1057 
1058  // LXUX term
1059  // first sub term
1060  gmm::resize(Melem, ndof_lx, ndof_ux); gmm::clear(Melem);
1061  gmm::mult(I_gphiy0gphiyinv, gpp.I_nxny(), auxNN1);
1062  for (size_type j = 0; j < N; ++j) auxNN1(j,j) -= scalar_type(1);
1063  gmm::mult(dVsF, auxNN1, auxNN2);
1064  gmm::mult(gpp.vbase_lx(), gmm::transposed(auxNN2), auxLXN2);
1065  // Caution: auxLXN2 re-used in the third sub term
1066  gmm::mult(auxLXN2, gmm::transposed(gpp.vbase_ux()), Melem);
1067 
1068  // second sub term
1069  base_matrix auxLXUX(ndof_lx, ndof_ux);
1070  gmm::mult(dVsF, I_gphiy0gphiyinv, auxNN1);
1071  gmm::mult(auxNN1, gpp.I_nxny(), auxNN2);
1072  gmm::mult(auxNN2, gmm::transposed(gpp.grad_phix_inv()), auxNN1);
1073  gmm::mult(gpp.vbase_lx(), gmm::transposed(auxNN1), auxLXN1);
1074  gmm::mult(auxLXN1, gmm::transposed(graddeltaunx), auxLXUX);
1075  gmm::scale(auxLXUX, -g);
1076  gmm::add(auxLXUX, Melem);
1077  gmm::scale(Melem, weight*alpha*FMULT/r);
1078  mat_elem_assembly(M, I_lx, I_ux, Melem, *mf_lx, cvx, *mf_ux, cvx);
1079 
1080  // LXUY term
1081  // third sub term
1082  gmm::resize(Melem, ndof_lx, ndof_uy); gmm::clear(Melem);
1083  // Caution: auxLXN2 re-used
1084  gmm::mult(auxLXN2, gmm::transposed(gpp.vbase_uy()), Melem);
1085  gmm::scale(Melem, -weight*alpha*FMULT/r);
1086  mat_elem_assembly(M, I_lx, I_uy, Melem, *mf_lx, cvx, *mf_uy, cvy);
1087 #endif
1088  } else {
1089  // LXUX term
1090  gmm::mult(gpp.vbase_lx(), gmm::transposed(dVsF), auxLXN1);
1091  gmm::mult(auxLXN1, gmm::transposed(gpp.vbase_ux()), Melem);
1092  gmm::scale(Melem, -weight*alpha*FMULT/r);
1093  mat_elem_assembly(M, I_lx, I_ux, Melem, *mf_lx, cvx, *mf_ux, cvx);
1094  }
1095  }
1096 #endif
1097  }
1098 
1099  if (version & model::BUILD_RHS) {
1100 
1101  if (!(version & model::BUILD_MATRIX))
1102  aug_friction(lambda, g, gpp.Vs(), nx, r, f_coeff, F);
1103 
1104 #ifdef CONSIDER_TERM1
1105 
1106  // Term lambda.\delta v(X)
1107  gmm::mult(gpp.vbase_ux(), lambda, auxUX);
1108  gmm::scale(auxUX, weight);
1109  vec_elem_assembly(V, I_ux, auxUX, *mf_ux, cvx);
1110 #endif
1111 
1112 #ifdef CONSIDER_TERM2
1113 
1114  // Term -lambda.\delta v(Y)
1115  if (!isrigid) {
1116  gmm::mult(gpp.vbase_uy(), lambda, auxUY);
1117  gmm::scale(auxUY, -weight);
1118  vec_elem_assembly(V, I_uy, auxUY, *mf_uy, cvy);
1119  }
1120 #endif
1121 
1122 #ifdef CONSIDER_TERM3
1123 
1124  // Term -(1/r)(lambda - F).\delta \mu
1125  // (1/r)(lambda).\delta \mu is skipped because globally added before
1126  base_vector auxLX(ndof_lx);
1127  gmm::mult(gpp.vbase_lx(), gmm::scaled(F, weight*FMULT/r), auxLX);
1128  vec_elem_assembly(V, I_lx, auxLX, *mf_lx, cvx);
1129 #endif
1130  }
1131 
1132  }
1133  }
1134 
1135 
1137  (model &md, multi_contact_frame &mcf,
1138  const std::string &dataname_r, const std::string &dataname_friction_coeff,
1139  const std::string &dataname_alpha) {
1140 
1141  bool with_friction = (dataname_friction_coeff.size() > 0);
1142  pbrick pbri
1143  = std::make_shared<integral_large_sliding_contact_brick>(mcf,
1144  with_friction);
1145 
1146  model::termlist tl; // A unique global unsymmetric term
1147  tl.push_back(model::term_description(true, false));
1148 
1149  model::varnamelist dl(1, dataname_r);
1150  if (with_friction) dl.push_back(dataname_friction_coeff);
1151  if (dataname_alpha.size()) dl.push_back(dataname_alpha);
1152 
1153  model::varnamelist vl;
1154 
1155  bool selfcontact = mcf.is_self_contact();
1156 
1157  dal::bit_vector uvar, mvar;
1158  for (size_type i = 0; i < mcf.nb_boundaries(); ++i) {
1159  size_type ind_u = mcf.ind_varname_of_boundary(i);
1160  if (!(uvar.is_in(ind_u))) {
1161  vl.push_back(mcf.varname(ind_u));
1162  uvar.add(ind_u);
1163  }
1164  size_type ind_lambda = mcf.ind_multname_of_boundary(i);
1165 
1166  if (selfcontact || mcf.is_slave_boundary(i))
1167  GMM_ASSERT1(ind_lambda != size_type(-1), "Large sliding contact "
1168  "brick: a multiplier should be associated to each slave "
1169  "boundary in the multi_contact_frame object.");
1170  if (ind_lambda != size_type(-1) && !(mvar.is_in(ind_lambda))) {
1171  vl.push_back(mcf.multname(ind_lambda));
1172  mvar.add(ind_u);
1173  }
1174  }
1175 
1176  return md.add_brick(pbri, vl, dl, tl, model::mimlist(), size_type(-1));
1177  }
1178 
1179 
1180 
1181  //=========================================================================
1182  //
1183  // Large sliding brick with field extension principle.
1184  // Deprecated. To be adapated to the high-level generic assembly
1185  //
1186  //=========================================================================
1187 
1188 #if 0
1189 
1190 #if GETFEM_HAVE_MUPARSER_MUPARSER_H
1191 #include <muParser/muParser.h>
1192 #elif GETFEM_HAVE_MUPARSER_H
1193 #include <muParser.h>
1194 #endif
1195 
1196  //=========================================================================
1197  // 1)- Structure which stores the contact boundaries and rigid obstacles
1198  //=========================================================================
1199 
1200 
1201  struct contact_frame {
1202  bool frictionless;
1203  size_type N;
1204  scalar_type friction_coef;
1205  std::vector<const model_real_plain_vector *> Us;
1206  std::vector<model_real_plain_vector> ext_Us;
1207  std::vector<const model_real_plain_vector *> lambdas;
1208  std::vector<model_real_plain_vector> ext_lambdas;
1209  struct contact_boundary {
1210  size_type region; // Boundary number
1211  const getfem::mesh_fem *mfu; // F.e.m. for the displacement.
1212  size_type ind_U; // Index of displacement.
1213  const getfem::mesh_fem *mflambda; // F.e.m. for the multiplier.
1214  size_type ind_lambda; // Index of multiplier.
1215  };
1216  std::vector<contact_boundary> contact_boundaries;
1217 
1218  gmm::dense_matrix< model_real_sparse_matrix * > UU;
1219  gmm::dense_matrix< model_real_sparse_matrix * > UL;
1220  gmm::dense_matrix< model_real_sparse_matrix * > LU;
1221  gmm::dense_matrix< model_real_sparse_matrix * > LL;
1222 
1223  std::vector< model_real_plain_vector *> Urhs;
1224  std::vector< model_real_plain_vector *> Lrhs;
1225 
1226 
1227 
1228  std::vector<std::string> coordinates;
1229  base_node pt_eval;
1230 #if GETFEM_HAVE_MUPARSER_MUPARSER_H || GETFEM_HAVE_MUPARSER_H
1231  std::vector<mu::Parser> obstacles_parsers;
1232 #endif
1233  std::vector<std::string> obstacles;
1234  std::vector<std::string> obstacles_velocities;
1235 
1236  size_type add_U(const getfem::mesh_fem &mfu,
1237  const model_real_plain_vector &U) {
1238  size_type i = 0;
1239  for (; i < Us.size(); ++i) if (Us[i] == &U) return i;
1240  Us.push_back(&U);
1241  model_real_plain_vector ext_U(mfu.nb_basic_dof()); // means that the structure has to be build each time ... to be changed. ATTENTION : la meme variable ne doit pas etre etendue dans deux vecteurs differents.
1242  mfu.extend_vector(U, ext_U);
1243  ext_Us.push_back(ext_U);
1244  return i;
1245  }
1246 
1247  size_type add_lambda(const getfem::mesh_fem &mfl,
1248  const model_real_plain_vector &l) {
1249  size_type i = 0;
1250  for (; i < lambdas.size(); ++i) if (lambdas[i] == &l) return i;
1251  lambdas.push_back(&l);
1252  model_real_plain_vector ext_l(mfl.nb_basic_dof()); // means that the structure has to be build each time ... to be changed. ATTENTION : la meme variable ne doit pas etre etendue dans deux vecteurs differents.
1253  mfl.extend_vector(l, ext_l);
1254  ext_lambdas.push_back(ext_l);
1255  return i;
1256  }
1257 
1258  void extend_vectors(void) {
1259  for (size_type i = 0; i < contact_boundaries.size(); ++i) {
1260  size_type ind_U = contact_boundaries[i].ind_U;
1261  contact_boundaries[i].mfu->extend_vector(*(Us[ind_U]), ext_Us[ind_U]);
1262  size_type ind_lambda = contact_boundaries[i].ind_lambda;
1263  contact_boundaries[i].mflambda->extend_vector(*(lambdas[ind_lambda]),
1264  ext_lambdas[ind_lambda]);
1265  }
1266  }
1267 
1268 
1269  const getfem::mesh_fem &mfu_of_boundary(size_type n) const
1270  { return *(contact_boundaries[n].mfu); }
1271  const getfem::mesh_fem &mflambda_of_boundary(size_type n) const
1272  { return *(contact_boundaries[n].mflambda); }
1273  const model_real_plain_vector &disp_of_boundary(size_type n) const
1274  { return ext_Us[contact_boundaries[n].ind_U]; }
1275  const model_real_plain_vector &lambda_of_boundary(size_type n) const
1276  { return ext_lambdas[contact_boundaries[n].ind_lambda]; }
1277  size_type region_of_boundary(size_type n) const
1278  { return contact_boundaries[n].region; }
1279  model_real_sparse_matrix &UU_matrix(size_type n, size_type m) const
1280  { return *(UU(contact_boundaries[n].ind_U, contact_boundaries[m].ind_U)); }
1281  model_real_sparse_matrix &LU_matrix(size_type n, size_type m) const {
1282  return *(LU(contact_boundaries[n].ind_lambda,
1283  contact_boundaries[m].ind_U));
1284  }
1285  model_real_sparse_matrix &UL_matrix(size_type n, size_type m) const {
1286  return *(UL(contact_boundaries[n].ind_U,
1287  contact_boundaries[m].ind_lambda));
1288  }
1289  model_real_sparse_matrix &LL_matrix(size_type n, size_type m) const {
1290  return *(LL(contact_boundaries[n].ind_lambda,
1291  contact_boundaries[m].ind_lambda));
1292  }
1293  model_real_plain_vector &U_vector(size_type n) const
1294  { return *(Urhs[contact_boundaries[n].ind_U]); }
1295  model_real_plain_vector &L_vector(size_type n) const
1296  { return *(Lrhs[contact_boundaries[n].ind_lambda]); }
1297 
1298  contact_frame(size_type NN) : N(NN), coordinates(N), pt_eval(N) {
1299  if (N > 0) coordinates[0] = "x";
1300  if (N > 1) coordinates[1] = "y";
1301  if (N > 2) coordinates[2] = "z";
1302  if (N > 3) coordinates[3] = "w";
1303  GMM_ASSERT1(N <= 4, "Complete the definition for contact in "
1304  "dimension greater than 4");
1305  }
1306 
1307  size_type add_obstacle(const std::string &obs) {
1308  size_type ind = obstacles.size();
1309  obstacles.push_back(obs);
1310  obstacles_velocities.push_back("");
1311 #if GETFEM_HAVE_MUPARSER_MUPARSER_H || GETFEM_HAVE_MUPARSER_H
1312 
1313  mu::Parser mu;
1314  obstacles_parsers.push_back(mu);
1315  obstacles_parsers[ind].SetExpr(obstacles[ind]);
1316  for (size_type k = 0; k < N; ++k)
1317  obstacles_parsers[ind].DefineVar(coordinates[k], &pt_eval[k]);
1318 #else
1319  GMM_ASSERT1(false, "You have to link muparser with getfem to deal "
1320  "with rigid body obstacles");
1321 #endif
1322  return ind;
1323  }
1324 
1325  size_type add_boundary(const getfem::mesh_fem &mfu,
1326  const model_real_plain_vector &U,
1327  const getfem::mesh_fem &mfl,
1328  const model_real_plain_vector &l,
1329  size_type reg) {
1330  contact_boundary cb;
1331  cb.region = reg;
1332  cb.mfu = &mfu;
1333  cb.mflambda = &mfl;
1334  cb.ind_U = add_U(mfu, U);
1335  cb.ind_lambda = add_lambda(mfl, l);
1336  size_type ind = contact_boundaries.size();
1337  contact_boundaries.push_back(cb);
1338  gmm::resize(UU, ind+1, ind+1);
1339  gmm::resize(UL, ind+1, ind+1);
1340  gmm::resize(LU, ind+1, ind+1);
1341  gmm::resize(LL, ind+1, ind+1);
1342  gmm::resize(Urhs, ind+1);
1343  gmm::resize(Lrhs, ind+1);
1344  return ind;
1345  }
1346 
1347  };
1348 
1349 
1350  //=========================================================================
1351  // 2)- Structure which computes the contact pairs, rhs and tangent terms
1352  //=========================================================================
1353 
1354  struct contact_elements {
1355 
1356  contact_frame &cf; // contact frame description.
1357 
1358  // list des enrichissements pour ses points : y0, d0, element ...
1359  bgeot::rtree element_boxes; // influence regions of boundary elements
1360  // list des enrichissements of boundary elements
1361  std::vector<size_type> boundary_of_elements;
1362  std::vector<size_type> ind_of_elements;
1363  std::vector<size_type> face_of_elements;
1364  std::vector<base_node> unit_normal_of_elements;
1365 
1366  contact_elements(contact_frame &ccf) : cf(ccf) {}
1367  void init(void);
1368  bool add_point_contribution(size_type boundary_num,
1371  scalar_type weight, scalar_type f_coeff,
1372  scalar_type r, model::build_version version);
1373  };
1374 
1375 
1376  void contact_elements::init(void) {
1377  fem_precomp_pool fppool;
1378  // compute the influence regions of boundary elements. To be run
1379  // before the assembly of contact terms.
1380  element_boxes.clear();
1381  unit_normal_of_elements.resize(0);
1382  boundary_of_elements.resize(0);
1383  ind_of_elements.resize(0);
1384  face_of_elements.resize(0);
1385 
1386  size_type N = 0;
1387  base_matrix G;
1388  model_real_plain_vector coeff;
1389  cf.extend_vectors();
1390  for (size_type i = 0; i < cf.contact_boundaries.size(); ++i) {
1391  size_type bnum = cf.region_of_boundary(i);
1392  const mesh_fem &mfu = cf.mfu_of_boundary(i);
1393  const model_real_plain_vector &U = cf.disp_of_boundary(i);
1394  const mesh &m = mfu.linked_mesh();
1395  if (i == 0) N = m.dim();
1396  GMM_ASSERT1(m.dim() == N,
1397  "Meshes are of mixed dimensions, cannot deal with that");
1398  base_node val(N), bmin(N), bmax(N), n0(N), n(N), n_mean(N);
1399  base_matrix grad(N,N);
1400  mesh_region region = m.region(bnum);
1401  GMM_ASSERT1(mfu.get_qdim() == N,
1402  "Wrong mesh_fem qdim to compute contact pairs");
1403 
1404  dal::bit_vector points_already_interpolated;
1405  std::vector<base_node> transformed_points(m.nb_max_points());
1406  for (getfem::mr_visitor v(region,m); !v.finished(); ++v) {
1407  size_type cv = v.cv();
1408  bgeot::pgeometric_trans pgt = m.trans_of_convex(cv);
1409  pfem pf_s = mfu.fem_of_element(cv);
1410  size_type nbd_t = pgt->nb_points();
1411  slice_vector_on_basic_dof_of_element(mfu, U, cv, coeff);
1412  bgeot::vectors_to_base_matrix
1413  (G, mfu.linked_mesh().points_of_convex(cv));
1414 
1415  pfem_precomp pfp = fppool(pf_s, &(pgt->geometric_nodes()));
1416  fem_interpolation_context ctx(pgt, pfp, size_type(-1), G, cv);
1417 
1418  size_type nb_pt_on_face = 0;
1419  gmm::clear(n_mean);
1420  for (short_type ip = 0; ip < nbd_t; ++ip) {
1421  size_type ind = m.ind_points_of_convex(cv)[ip];
1422 
1423  // computation of transformed vertex
1424  if (!(points_already_interpolated.is_in(ind))) {
1425  ctx.set_ii(ip);
1426  pf_s->interpolation(ctx, coeff, val, dim_type(N));
1427  val += ctx.xreal();
1428  transformed_points[ind] = val;
1429  points_already_interpolated.add(ind);
1430  } else {
1431  val = transformed_points[ind];
1432  }
1433  // computation of unit normal vector if the vertex is on the face
1434  bool is_on_face = false;
1435  bgeot::pconvex_structure cvs = pgt->structure();
1436  for (size_type k = 0; k < cvs->nb_points_of_face(v.f()); ++k)
1437  if (cvs->ind_points_of_face(v.f())[k] == ip) is_on_face = true;
1438  if (is_on_face) {
1439  ctx.set_ii(ip);
1440  n0 = bgeot::compute_normal(ctx, v.f());
1441  pf_s->interpolation_grad(ctx, coeff, grad, dim_type(N));
1442  gmm::add(gmm::identity_matrix(), grad);
1443  scalar_type J = bgeot::lu_inverse(&(*(grad.begin())), N);
1444  if (J <= scalar_type(0)) GMM_WARNING1("Inverted element ! " << J);
1445  gmm::mult(gmm::transposed(grad), n0, n);
1446  n /= gmm::vect_norm2(n);
1447  n_mean += n;
1448  ++nb_pt_on_face;
1449  }
1450 
1451  if (ip == 0) // computation of bounding box
1452  bmin = bmax = val;
1453  else {
1454  for (size_type k = 0; k < N; ++k) {
1455  bmin[k] = std::min(bmin[k], val[k]);
1456  bmax[k] = std::max(bmax[k], val[k]);
1457  }
1458  }
1459  }
1460 
1461  GMM_ASSERT1(nb_pt_on_face,
1462  "This element has not vertex on considered face !");
1463 
1464  // Computation of influence box :
1465  // offset of the bounding box relatively to its "diameter"
1466  scalar_type h = bmax[0] - bmin[0];
1467  for (size_type k = 1; k < N; ++k)
1468  h = std::max(h, bmax[k] - bmin[k]);
1469  for (size_type k = 0; k < N; ++k)
1470  { bmin[k] -= h; bmax[k] += h; }
1471 
1472  // Store the influence box and additional information.
1473  element_boxes.add_box(bmin, bmax, unit_normal_of_elements.size());
1474  n_mean /= gmm::vect_norm2(n_mean);
1475  unit_normal_of_elements.push_back(n_mean);
1476  boundary_of_elements.push_back(i);
1477  ind_of_elements.push_back(cv);
1478  face_of_elements.push_back(v.f());
1479  }
1480  }
1481  element_boxes.build_tree();
1482  }
1483 
1484 
1485 
1486  bool contact_elements::add_point_contribution
1487  (size_type boundary_num, getfem::fem_interpolation_context &ctxu,
1488  getfem::fem_interpolation_context &ctxl, scalar_type weight,
1489  scalar_type /*f_coeff*/, scalar_type r, model::build_version version) {
1490  const mesh_fem &mfu = cf.mfu_of_boundary(boundary_num);
1491  const mesh_fem &mfl = cf.mflambda_of_boundary(boundary_num);
1492  const model_real_plain_vector &U = cf.disp_of_boundary(boundary_num);
1493  const model_real_plain_vector &L = cf.lambda_of_boundary(boundary_num);
1494  size_type N = mfu.get_qdim();
1495  base_node x0 = ctxu.xreal();
1496  bool noisy = false;
1497 
1498  // ----------------------------------------------------------
1499  // Computation of the point coordinates and the unit normal
1500  // vector in real configuration
1501  // ----------------------------------------------------------
1502 
1503  base_node n0 = bgeot::compute_normal(ctxu, ctxu.face_num());
1504  scalar_type face_factor = gmm::vect_norm2(n0);
1505  size_type cv = ctxu.convex_num();
1506  base_small_vector n(N), val(N), h(N);
1507  base_matrix gradinv(N,N), grad(N,N), gradtot(N,N), G;
1508  size_type cvnbdofu = mfu.nb_basic_dof_of_element(cv);
1509  size_type cvnbdofl = mfl.nb_basic_dof_of_element(cv);
1510  base_vector coeff(cvnbdofu);
1511  slice_vector_on_basic_dof_of_element(mfu, U, cv, coeff);
1512  ctxu.pf()->interpolation(ctxu, coeff, val, dim_type(N));
1513  base_node x = x0 + val;
1514 
1515  ctxu.pf()->interpolation_grad(ctxu, coeff, gradinv, dim_type(N));
1516  gmm::add(gmm::identity_matrix(), gradinv);
1517  scalar_type J = bgeot::lu_inverse(&(*(grad_inv.begin())), N); // remplacer par une resolution...
1518  if (J <= scalar_type(0)) {
1519  GMM_WARNING1("Inverted element !");
1520 
1521  GMM_ASSERT1(!(version & model::BUILD_MATRIX), "Impossible to build "
1522  "tangent matrix for large sliding contact");
1523  if (version & model::BUILD_RHS) {
1524  base_vector Velem(cvnbdofl);
1525  for (size_type i = 0; i < cvnbdofl; ++i) Velem[i] = 1E200;
1526  vec_elem_assembly(cf.L_vector(boundary_num), Velem, mfl, cv);
1527  return false;
1528  }
1529  }
1530 
1531  gmm::mult(gmm::transposed(gradinv), n0, n);
1532  n /= gmm::vect_norm2(n);
1533 
1534  // ----------------------------------------------------------
1535  // Selection of influence boxes
1536  // ----------------------------------------------------------
1537 
1538  bgeot::rtree::pbox_set bset;
1539  element_boxes.find_boxes_at_point(x, bset);
1540 
1541  if (noisy) cout << "Number of boxes found : " << bset.size() << endl;
1542 
1543  // ----------------------------------------------------------
1544  // Eliminates some influence boxes with the mean normal
1545  // criterion : should at least eliminate the original element.
1546  // ----------------------------------------------------------
1547 
1548  bgeot::rtree::pbox_set::iterator it = bset.begin(), itnext;
1549  for (; it != bset.end(); it = itnext) {
1550  itnext = it; ++itnext;
1551  if (gmm::vect_sp(unit_normal_of_elements[(*it)->id], n)
1552  >= -scalar_type(1)/scalar_type(20)) bset.erase(it);
1553  }
1554 
1555  if (noisy)
1556  cout << "Number of boxes satisfying the unit normal criterion : "
1557  << bset.size() << endl;
1558 
1559 
1560  // ----------------------------------------------------------
1561  // For each remaining influence box, compute y0, the corres-
1562  // ponding unit normal vector and eliminate wrong auto-contact
1563  // situations with a test on |x0-y0|
1564  // ----------------------------------------------------------
1565 
1566  it = bset.begin();
1567  std::vector<base_node> y0s;
1568  std::vector<base_small_vector> n0_y0s;
1569  std::vector<scalar_type> d0s;
1570  std::vector<scalar_type> d1s;
1571  std::vector<size_type> elt_nums;
1572  std::vector<fem_interpolation_context> ctx_y0s;
1573  for (; it != bset.end(); ++it) {
1574  size_type boundary_num_y0 = boundary_of_elements[(*it)->id];
1575  size_type cv_y0 = ind_of_elements[(*it)->id];
1576  short_type face_y0 = short_type(face_of_elements[(*it)->id]);
1577  const mesh_fem &mfu_y0 = cf.mfu_of_boundary(boundary_num_y0);
1578  pfem pf_s_y0 = mfu_y0.fem_of_element(cv_y0);
1579  const model_real_plain_vector &U_y0
1580  = cf.disp_of_boundary(boundary_num_y0);
1581  const mesh &m_y0 = mfu_y0.linked_mesh();
1582  bgeot::pgeometric_trans pgt_y0 = m_y0.trans_of_convex(cv_y0);
1583  bgeot::pconvex_structure cvs_y0 = pgt_y0->structure();
1584 
1585  // Find an interior point (in order to promote the more interior
1586  // y0 in case of locally non invertible transformation.
1587  size_type ind_dep_point = 0;
1588  for (; ind_dep_point < cvs_y0->nb_points(); ++ind_dep_point) {
1589  bool is_on_face = false;
1590  for (size_type k = 0;
1591  k < cvs_y0->nb_points_of_face(face_y0); ++k)
1592  if (cvs_y0->ind_points_of_face(face_y0)[k]
1593  == ind_dep_point) is_on_face = true;
1594  if (!is_on_face) break;
1595  }
1596  GMM_ASSERT1(ind_dep_point < cvs_y0->nb_points(),
1597  "No interior point found !");
1598 
1599  base_node y0_ref = pgt_y0->convex_ref()->points()[ind_dep_point];
1600 
1601  slice_vector_on_basic_dof_of_element(mfu_y0, U_y0, cv_y0, coeff);
1602  // if (pf_s_y0->need_G())
1603  bgeot::vectors_to_base_matrix(G, m_y0.points_of_convex(cv_y0));
1604 
1605  fem_interpolation_context ctx_y0(pgt_y0, pf_s_y0, y0_ref, G, cv_y0);
1606 
1607  size_type newton_iter = 0;
1608  for(;;) { // Newton algorithm to invert geometric transformation
1609 
1610  pf_s_y0->interpolation(ctx_y0, coeff, val, dim_type(N));
1611  val += ctx_y0.xreal() - x;
1612  scalar_type init_res = gmm::vect_norm2(val);
1613 
1614  if (init_res < 1E-12) break;
1615  if (newton_iter > 100) {
1616  GMM_WARNING1("Newton has failed to invert transformation"); // il faudrait faire qlq chose d'autre ... !
1617  GMM_ASSERT1(!(version & model::BUILD_MATRIX), "Impossible to build "
1618  "tangent matrix for large sliding contact");
1619  if (version & model::BUILD_RHS) {
1620  base_vector Velem(cvnbdofl);
1621  for (size_type i = 0; i < cvnbdofl; ++i) Velem[i] = 1E200;
1622  vec_elem_assembly(cf.L_vector(boundary_num), Velem, mfl, cv);
1623  return false;
1624  }
1625  }
1626 
1627  pf_s_y0->interpolation_grad(ctx_y0, coeff, grad, dim_type(N));
1628  gmm::add(gmm::identity_matrix(), grad);
1629  gmm::mult(grad, ctx_y0.K(), gradtot);
1630 
1631  std::vector<long> ipvt(N);
1632  size_type info = gmm::lu_factor(gradtot, ipvt);
1633  GMM_ASSERT1(!info, "Singular system, pivot = " << info); // il faudrait faire qlq chose d'autre ... perturber par exemple
1634  gmm::lu_solve(gradtot, ipvt, h, val);
1635 
1636  // line search
1637  bool ok = false;
1638  scalar_type alpha;
1639  for (alpha = 1; alpha >= 1E-5; alpha/=scalar_type(2)) {
1640 
1641  ctx_y0.set_xref(y0_ref - alpha*h);
1642  pf_s_y0->interpolation(ctx_y0, coeff, val, dim_type(N));
1643  val += ctx_y0.xreal() - x;
1644 
1645  if (gmm::vect_norm2(val) < init_res) { ok = true; break; }
1646  }
1647  if (!ok)
1648  GMM_WARNING1("Line search has failed to invert transformation");
1649  y0_ref -= alpha*h;
1650  ctx_y0.set_xref(y0_ref);
1651  newton_iter++;
1652  }
1653 
1654  base_node y0 = ctx_y0.xreal();
1655  base_node n0_y0 = bgeot::compute_normal(ctx_y0, face_y0);
1656  scalar_type d0_ref = pgt_y0->convex_ref()->is_in_face(face_y0, y0_ref);
1657  scalar_type d0 = d0_ref / gmm::vect_norm2(n0_y0);
1658 
1659 
1660  scalar_type d1 = d0_ref; // approximatively a distance to the element
1661  short_type ifd = short_type(-1);
1662 
1663  for (short_type k = 0; k < pgt_y0->structure()->nb_faces(); ++k) {
1664  scalar_type dd = pgt_y0->convex_ref()->is_in_face(k, y0_ref);
1665  if (dd > scalar_type(0) && dd > gmm::abs(d1)) { d1 = dd; ifd = k; }
1666  }
1667 
1668  if (ifd != short_type(-1)) {
1669  d1 /= gmm::vect_norm2(bgeot::compute_normal(ctx_y0, ifd));
1670  if (gmm::abs(d1) < gmm::abs(d0)) d1 = d0;
1671  } else d1 = d0;
1672 
1673 // size_type iptf = m_y0.ind_points_of_face_of_convex(cv_y0, face_y0)[0];
1674 // base_node ptf = x0 - m_y0.points()[iptf];
1675 // scalar_type d2 = gmm::vect_sp(ptf, n0_y0) / gmm::vect_norm2(n0_y0);
1676 
1677  if (noisy) cout << "gmm::vect_norm2(n0_y0) = " << gmm::vect_norm2(n0_y0) << endl;
1678  // Eliminates wrong auto-contact situations
1679  if (noisy) cout << "autocontact status : x0 = " << x0 << " y0 = " << y0 << " " << gmm::vect_dist2(y0, x0) << " : " << d0*0.75 << " : " << d1*0.75 << endl;
1680  if (noisy) cout << "n = " << n << " unit_normal_of_elements[(*it)->id] = " << unit_normal_of_elements[(*it)->id] << endl;
1681 
1682  if (d0 < scalar_type(0)
1683  && ((&U_y0 == &U
1684  && (gmm::vect_dist2(y0, x0) < gmm::abs(d1)*scalar_type(3)/scalar_type(4)))
1685  || gmm::abs(d1) > 0.05)) {
1686  if (noisy) cout << "Eliminated x0 = " << x0 << " y0 = " << y0
1687  << " d0 = " << d0 << endl;
1688  continue;
1689  }
1690 
1691 // if (d0 < scalar_type(0) && &(U_y0) == &U
1692 // && gmm::vect_dist2(y0, x0) < gmm::abs(d1) * scalar_type(2)
1693 // && d2 < -ctxu.J() / scalar_type(2)) {
1694 // if (noisy) cout << "Eliminated x0 = " << x0 << " y0 = " << y0
1695 // << " d0 = " << d0 << endl;
1696 // continue;
1697 // }
1698 
1699  y0s.push_back(ctx_y0.xreal()); // useful ?
1700  elt_nums.push_back((*it)->id);
1701  d0s.push_back(d0);
1702  d1s.push_back(d1);
1703  ctx_y0s.push_back(ctx_y0);
1704  n0_y0 /= gmm::vect_norm2(n0_y0);
1705  n0_y0s.push_back(n0_y0);
1706 
1707  if (noisy) cout << "dist0 = " << d0 << " dist0 * area = "
1708  << pgt_y0->convex_ref()->is_in(y0_ref) << endl;
1709  }
1710 
1711  // ----------------------------------------------------------
1712  // Compute the distance to rigid obstacles and selects the
1713  // nearest boundary/obstacle.
1714  // ----------------------------------------------------------
1715 
1716  dim_type state = 0;
1717  scalar_type d0 = 1E100, d1 = 1E100;
1718  base_small_vector grad_obs(N);
1719 
1720  size_type ibound = size_type(-1);
1721  for (size_type k = 0; k < y0s.size(); ++k)
1722  if (d1s[k] < d1) { d0 = d0s[k]; d1 = d1s[k]; ibound = k; state = 1; }
1723 
1724 
1725  size_type irigid_obstacle = size_type(-1);
1726 #if GETFEM_HAVE_MUPARSER_MUPARSER_H || GETFEM_HAVE_MUPARSER_H
1727  gmm::copy(x, cf.pt_eval);
1728  for (size_type i = 0; i < cf.obstacles.size(); ++i) {
1729  scalar_type d0_o = scalar_type(cf.obstacles_parsers[i].Eval());
1730  if (d0_o < d0) { d0 = d0_o; irigid_obstacle = i; state = 2; }
1731  }
1732  if (state == 2) {
1733  scalar_type EPS = face_factor * 1E-9;
1734  for (size_type k = 0; k < N; ++k) {
1735  cf.pt_eval[k] += EPS;
1736  grad_obs[k] =
1737  (scalar_type(cf.obstacles_parsers[irigid_obstacle].Eval())-d0)/EPS;
1738  cf.pt_eval[k] -= EPS;
1739  }
1740  }
1741 
1742 #else
1743  if (cf.obstacles.size() > 0)
1744  GMM_WARNING1("Rigid obstacles are ignored. Recompile with "
1745  "muParser to account for rigid obstacles");
1746 #endif
1747 
1748 
1749  // ----------------------------------------------------------
1750  // Print the found contact state ...
1751  // ----------------------------------------------------------
1752 
1753 
1754  if (noisy && state == 1) {
1755  cout << "Point : " << x0 << " of boundary " << boundary_num
1756  << " and element " << cv << " state = " << int(state);
1757  if (version & model::BUILD_RHS) cout << " RHS";
1758  if (version & model::BUILD_MATRIX) cout << " MATRIX";
1759  }
1760  if (state == 1) {
1761  size_type boundary_num_y0 = boundary_of_elements[elt_nums[ibound]];
1762  const mesh_fem &mfu_y0 = cf.mfu_of_boundary(boundary_num_y0);
1763  const mesh &m_y0 = mfu_y0.linked_mesh();
1764  size_type cv_y0 = ind_of_elements[elt_nums[ibound]];
1765 
1766  if (noisy) cout << " y0 = " << y0s[ibound] << " of element "
1767  << cv_y0 << " of boundary " << boundary_num_y0 << endl;
1768  for (size_type k = 0; k < m_y0.nb_points_of_convex(cv_y0); ++k)
1769  if (noisy) cout << "point " << k << " : "
1770  << m_y0.points()[m_y0.ind_points_of_convex(cv_y0)[k]] << endl;
1771  if (boundary_num_y0 == 0 && boundary_num == 0 && d0 < 0.0 && (version & model::BUILD_MATRIX)) GMM_ASSERT1(false, "oups");
1772  }
1773  if (noisy) cout << " d0 = " << d0 << endl;
1774 
1775  // ----------------------------------------------------------
1776  // Add the contributions to the tangent matrices and rhs
1777  // ----------------------------------------------------------
1778 
1779  GMM_ASSERT1(ctxu.pf()->target_dim() == 1 && ctxl.pf()->target_dim() == 1,
1780  "Large sliding contact assembly procedure has to be adapted "
1781  "to intrinsic vectorial elements. To be done.");
1782 
1783  // Eviter les calculs inutiles dans le cas state == 2 ... a voir a la fin
1784  // regarder aussi si on peut factoriser des mat_elem_assembly ...
1785 
1786  base_matrix Melem;
1787  base_vector Velem;
1788 
1789  base_tensor tl, tu;
1790  ctxl.base_value(tl);
1791  ctxu.base_value(tu);
1792 
1793  base_small_vector lambda(N);
1794  slice_vector_on_basic_dof_of_element(mfl, L, cv, coeff);
1795  ctxl.pf()->interpolation(ctxl, coeff, lambda, dim_type(N));
1796  GMM_ASSERT1(!(isnan(lambda[0])), "internal error");
1797 
1798  // Unstabilized frictionless case for the moment
1799 
1800  // auxiliary variables
1801  scalar_type aux1, aux2;
1802 
1803  if (state) {
1804 
1805  // zeta = lambda + d0 * r * n
1806  base_small_vector zeta(N);
1807  gmm::add(lambda, gmm::scaled(n, r*d0), zeta);
1808 
1809  base_tensor tgradu;
1810  ctxu.grad_base_value(tgradu);
1811 
1812  // variables for y0
1813  base_tensor tu_y0;
1814  size_type boundary_num_y0 = 0, cv_y0 = 0, cvnbdofu_y0 = 0;
1815  if (state == 1) {
1816  ctx_y0s[ibound].base_value(tu_y0);
1817  boundary_num_y0 = boundary_of_elements[elt_nums[ibound]];
1818  cv_y0 = ind_of_elements[elt_nums[ibound]];
1819  cvnbdofu_y0 = cf.mfu_of_boundary(boundary_num_y0).nb_basic_dof_of_element(cv_y0);
1820  }
1821  const mesh_fem &mfu_y0 = (state == 1) ?
1822  cf.mfu_of_boundary(boundary_num_y0) : mfu;
1823 
1824  if (version & model::BUILD_RHS) {
1825  // Rhs term Lx
1826  gmm::resize(Velem, cvnbdofl); gmm::clear(Velem);
1827 
1828  // Rhs term Lx: (1/r)\int (\lambda - P(\zeta)).\mu
1829  base_small_vector vecaux(N);
1830  gmm::copy(zeta, vecaux);
1831  De_Saxce_projection(vecaux, n, scalar_type(0));
1832  gmm::scale(vecaux, -scalar_type(1));
1833  gmm::add(lambda, vecaux);
1834  for (size_type i = 0; i < cvnbdofl; ++i)
1835  Velem[i] = tl[i/N] * vecaux[i%N] * weight/r;
1836  vec_elem_assembly(cf.L_vector(boundary_num), Velem, mfl, cv);
1837 
1838  // Rhs terms Ux, Uy: \int \lambda.(\psi(x_0) - \psi(y_0))
1839  gmm::resize(Velem, cvnbdofu); gmm::clear(Velem);
1840  for (size_type i = 0; i < cvnbdofu; ++i)
1841  Velem[i] = tu[i/N] * lambda[i%N] * weight;
1842  vec_elem_assembly(cf.U_vector(boundary_num), Velem, mfu, cv);
1843 
1844  if (state == 1) {
1845  gmm::resize(Velem, cvnbdofu_y0); gmm::clear(Velem);
1846  for (size_type i = 0; i < cvnbdofu_y0; ++i)
1847  Velem[i] = -tu_y0[i/N] * lambda[i%N] * weight;
1848  vec_elem_assembly(cf.U_vector(boundary_num_y0), Velem, mfu_y0, cv_y0);
1849  }
1850  }
1851 
1852  if (version & model::BUILD_MATRIX) {
1853 
1854  base_small_vector gradinv_n(N);
1855  gmm::mult(gradinv, n, gradinv_n);
1856 
1857  // de Saxce projection gradient and normal gradient at zeta
1858  base_matrix pgrad(N,N), pgradn(N,N);
1859  De_Saxce_projection_grad(zeta, n, scalar_type(0), pgrad);
1860  De_Saxce_projection_gradn(zeta, n, scalar_type(0), pgradn);
1861 
1862  base_small_vector pgrad_n(N), pgradn_n(N);
1863  gmm::mult(pgrad, n, pgrad_n);
1864  gmm::mult(pgradn, n, pgradn_n);
1865  base_matrix gradinv_pgrad(N,N), gradinv_pgradn(N,N);
1866  gmm::mult(gradinv, gmm::transposed(pgrad), gradinv_pgrad);
1867  gmm::mult(gradinv, gmm::transposed(pgradn), gradinv_pgradn);
1868 
1869  // Tangent term LxLx
1870  gmm::resize(Melem, cvnbdofl, cvnbdofl); gmm::clear(Melem);
1871  // -(1/r) \int \delta\lambda.\mu
1872  for (size_type i = 0; i < cvnbdofl; i += N) {
1873  aux1 = -tl[i/N] * weight/r;
1874  for (size_type j = 0; j < cvnbdofl; j += N) {
1875  aux2 = aux1 * tl[j/N];
1876  for (size_type k = 0; k < N; k++) Melem(i+k,j+k) = aux2;
1877  } // Melem(i+k,j+k) = -tl[i/N] * tl[j/N] * weight/r;
1878  }
1879  // (1/r) \int \nabla P(\zeta) (d\zeta/d\lambda)(\delta\lambda) . \mu
1880  for (size_type i = 0, ii = 0; i < cvnbdofl; ++i, ii = i%N)
1881  for (size_type j = 0, jj = 0; j < cvnbdofl; ++j, jj = j%N)
1882  Melem(i,j) += tl[i/N] * tl[j/N] * pgrad(ii,jj) * weight/r;
1883  mat_elem_assembly(cf.LL_matrix(boundary_num, boundary_num),
1884  Melem, mfl, cv, mfl, cv);
1885 
1886  // Tangent term UxLx
1887  gmm::resize(Melem, cvnbdofu, cvnbdofl); gmm::clear(Melem);
1888  // \int -\delta\lambda.\psi(x_0)
1889  for (size_type i = 0; i < cvnbdofu; i += N) {
1890  aux1 = -tu[i/N] * weight;
1891  for (size_type j = 0; j < cvnbdofl; j += N) {
1892  aux2 = aux1 * tl[j/N];
1893  for (size_type k = 0; k < N; k++) Melem(i+k,j+k) = aux2;
1894  }
1895  }
1896  mat_elem_assembly(cf.UL_matrix(boundary_num, boundary_num),
1897  Melem, mfu, cv, mfl, cv);
1898 
1899  // Tangent term LxUx
1900  if (0) { // DISABLED
1901  gmm::resize(Melem, cvnbdofl, cvnbdofu); gmm::clear(Melem);
1902  // \int d_0(\nabla P(\zeta))(dn/du)(\delta u).\mu
1903  for (size_type i = 0, ii = 0; i < cvnbdofl; ++i, ii = i%N)
1904  for (size_type j = 0, jj = 0; j < cvnbdofu; ++j, jj = j%N) {
1905  aux1 = aux2 = scalar_type(0);
1906  for (size_type k = 0; k < N; ++k) {
1907  aux1 += tgradu[j/N+N*k] * gradinv_n[k];
1908  aux2 += tgradu[j/N+N*k] * gradinv_pgrad(k,ii);
1909  }
1910  Melem(i,j) = d0 * tl[i/N] * (pgrad_n[ii] * aux1 - aux2) * n[jj] * weight;
1911  }
1912 
1913  // (1/r)\int \nabla_n P(zeta) (dn/du)(\delta u) . \mu
1914  // On peut certainement factoriser d'avantage ce terme avec le
1915  // precedent. Attendre la version avec frottement.
1916  for (size_type i = 0, ii = 0; i < cvnbdofl; ++i, ii = i%N)
1917  for (size_type j = 0, jj = 0; j < cvnbdofu; ++j, jj = j%N) {
1918  aux1 = aux2 = scalar_type(0);
1919  for (size_type k = 0; k < N; ++k) {
1920  aux1 += tgradu[j/N+N*k] * gradinv_n[k];
1921  aux2 += tgradu[j/N+N*k] * gradinv_pgradn(k,ii);
1922  }
1923  Melem(i,j) += tl[i/N] * (pgradn_n[ii] * aux1 - aux2) * n[jj] * weight / r;
1924  }
1925  mat_elem_assembly(cf.LU_matrix(boundary_num, boundary_num),
1926  Melem, mfl, cv, mfu, cv);
1927  } // DISABLED
1928 
1929  if (state == 1) {
1930 
1931  base_tensor tgradu_y0;
1932  ctx_y0s[ibound].grad_base_value(tgradu_y0);
1933 
1934  base_matrix gradinv_y0(N,N);
1935  base_small_vector ntilde_y0(N);
1936  { // calculate gradinv_y0 and ntilde_y0
1937  base_matrix grad_y0(N,N);
1938  base_vector coeff_y0(cvnbdofu_y0);
1939  const model_real_plain_vector &U_y0
1940  = cf.disp_of_boundary(boundary_num_y0);
1941  slice_vector_on_basic_dof_of_element(mfu_y0, U_y0, cv_y0, coeff_y0);
1942  ctx_y0s[ibound].pf()->interpolation_grad(ctx_y0s[ibound], coeff_y0,
1943  grad_y0, dim_type(N));
1944  gmm::add(gmm::identity_matrix(), grad_y0);
1945 
1946  gmm::copy(grad_y0, gradinv_y0);
1947  gmm::lu_inverse(gradinv_y0); // a proteger contre la non-inversibilite
1948  gmm::mult(gmm::transposed(gradinv_y0), n0_y0s[ibound], ntilde_y0); // (not unit) normal vector
1949  }
1950 
1951  // Tangent term UyLx: \int \delta\lambda.\psi(y_0)
1952  gmm::resize(Melem, cvnbdofu_y0, cvnbdofl); gmm::clear(Melem);
1953  for (size_type i = 0; i < cvnbdofu_y0; i += N) {
1954  aux1 = tu_y0[i/N] * weight;
1955  for (size_type j = 0; j < cvnbdofl; j += N) {
1956  aux2 = aux1 * tl[j/N];
1957  for (size_type k = 0; k < N; k++) Melem(i+k,j+k) = aux2;
1958  }
1959  }
1960  mat_elem_assembly(cf.UL_matrix(boundary_num_y0, boundary_num),
1961  Melem, mfu_y0, cv_y0, mfl, cv);
1962 
1963  // Tangent terms UyUx, UyUy
1964  // \int \lambda.((\nabla \psi(y_0))(I+\nabla u(y_0))^{-1}(\delta u(x_0) - \delta u(y_0)))
1965 
1966  // Tangent term UyUx
1967  gmm::resize(Melem, cvnbdofu_y0, cvnbdofu); gmm::clear(Melem);
1968  // \int \lambda.((\nabla \psi(y_0))(I+\nabla u(y_0))^{-1}\delta u(x_0))
1969  for (size_type i = 0, ii = 0; i < cvnbdofu_y0; ++i, ii = i%N)
1970  for (size_type j = 0, jj = 0; j < cvnbdofu; ++j, jj = j%N) {
1971  aux1 = scalar_type(0);
1972  for (size_type k = 0; k < N; ++k)
1973  aux1 += tgradu_y0[i/N+N*k]* gradinv_y0(k,jj);
1974  Melem(i,j) = lambda[ii] * aux1 * tu[j/N] * weight;
1975  }
1976  mat_elem_assembly(cf.UU_matrix(boundary_num_y0, boundary_num),
1977  Melem, mfu_y0, cv_y0, mfu, cv);
1978 
1979  // Tangent term UyUy
1980  gmm::resize(Melem, cvnbdofu_y0, cvnbdofu_y0); gmm::clear(Melem);
1981  // -\int \lambda.((\nabla \psi(y_0))(I+\nabla u(y_0))^{-1}\delta u(y_0))
1982  for (size_type i = 0, ii = 0; i < cvnbdofu_y0; ++i, ii = i%N)
1983  for (size_type j = 0, jj = 0; j < cvnbdofu_y0; ++j, jj = j%N) {
1984  aux1 = scalar_type(0);
1985  for (size_type k = 0; k < N; ++k)
1986  aux1 += tgradu_y0[i/N+N*k] * gradinv_y0(k,jj);
1987  Melem(i,j) = - lambda[ii] * aux1 * tu_y0[j/N] * weight;
1988  }
1989  mat_elem_assembly(cf.UU_matrix(boundary_num_y0, boundary_num_y0),
1990  Melem, mfu_y0, cv_y0, mfu_y0, cv_y0);
1991 
1992  // Tangent term LxUy
1993  gmm::resize(Melem, cvnbdofl, cvnbdofu_y0); gmm::clear(Melem);
1994  // -\int (I+\nabla u(y_0))^{-T}\nabla \delta(y_0).\delta u(y_0)(\nabla P(\zeta) n . \mu)
1995  for (size_type i = 0; i < cvnbdofl; ++i) {
1996  aux1 = tl[i/N] * pgrad_n[i%N] * weight;
1997  for (size_type j = 0; j < cvnbdofu_y0; ++j)
1998  Melem(i,j) = - aux1 * tu_y0[j/N] * ntilde_y0[j%N];
1999  }
2000  mat_elem_assembly(cf.LU_matrix(boundary_num, boundary_num_y0),
2001  Melem, mfl, cv, mfu_y0, cv_y0);
2002 
2003  // Addition to tangent term LxUx
2004  gmm::resize(Melem, cvnbdofl, cvnbdofu); gmm::clear(Melem);
2005  // \int (I+\nabla u(y_0))^{-T}\nabla \delta(y_0).\delta u(x_0)(\nabla P(\zeta) n . \mu)
2006  for (size_type i = 0; i < cvnbdofl; ++i) {
2007  aux1 = tl[i/N] * pgrad_n[i%N] * weight;
2008  for (size_type j = 0; j < cvnbdofu; ++j)
2009  Melem(i,j) = aux1 * tu[j/N] * ntilde_y0[j%N];
2010  }
2011  }
2012  else {
2013  // Addition to tangent term LxUx
2014  gmm::resize(Melem, cvnbdofl, cvnbdofu); gmm::clear(Melem);
2015  // \int (I+\nabla u(y_0))^{-T}\nabla \delta(y_0).\delta u(x_0)(\nabla P(\zeta) n . \mu)
2016  for (size_type i = 0; i < cvnbdofl; ++i) {
2017  aux1 = tl[i/N] * pgrad_n[i%N] * weight;
2018  for (size_type j = 0; j < cvnbdofu; ++j)
2019  Melem(i,j) = aux1 * tu[j/N] * grad_obs[j%N];
2020  }
2021  }
2022  mat_elem_assembly(cf.LU_matrix(boundary_num, boundary_num),
2023  Melem, mfl, cv, mfu, cv);
2024 
2025  }
2026 
2027  } else { // state == 0
2028 
2029  // Rhs term Lx: (1/r)\int \lambda.\mu
2030  if (version & model::BUILD_RHS) {
2031  gmm::resize(Velem, cvnbdofl); gmm::clear(Velem);
2032  for (size_type i = 0; i < cvnbdofl; ++i)
2033  Velem[i] = tl[i/N] * lambda[i%N] * weight/r;
2034  vec_elem_assembly(cf.L_vector(boundary_num), Velem, mfl, cv);
2035  }
2036 
2037  // Tangent term LxLx: -(1/r)\int \delta\lambda.\mu
2038  if (version & model::BUILD_MATRIX) {
2039  gmm::resize(Melem, cvnbdofl, cvnbdofl); gmm::clear(Melem);
2040  for (size_type i = 0; i < cvnbdofl; i += N) {
2041  aux1 = -tl[i/N] * weight/r;
2042  for (size_type j = 0; j < cvnbdofl; j += N) {
2043  aux2 = aux1 * tl[j/N];
2044  for (size_type k = 0; k < N; k++) Melem(i+k,j+k) = aux2;
2045  } // Melem(i+k,j+k) = -tl[i/N] * tl[j/N] * weight/r;
2046  }
2047  mat_elem_assembly(cf.LL_matrix(boundary_num, boundary_num),
2048  Melem, mfl, cv, mfl, cv);
2049  }
2050  }
2051 
2052  return true;
2053  }
2054 
2055  //=========================================================================
2056  // 3)- Large sliding contact brick
2057  //=========================================================================
2058 
2059  struct integral_large_sliding_contact_brick_field_extension : public virtual_brick {
2060 
2061 
2062  struct contact_boundary {
2063  size_type region;
2064  std::string varname;
2065  std::string multname;
2066  const mesh_im *mim;
2067  };
2068 
2069  std::vector<contact_boundary> boundaries;
2070  std::vector<std::string> obstacles;
2071 
2072  void add_boundary(const std::string &varn, const std::string &multn,
2073  const mesh_im &mim, size_type region) {
2074  contact_boundary cb;
2075  cb.region = region; cb.varname = varn; cb.multname = multn; cb.mim=&mim;
2076  boundaries.push_back(cb);
2077  }
2078 
2079  void add_obstacle(const std::string &obs)
2080  { obstacles.push_back(obs); }
2081 
2082  void build_contact_frame(const model &md, contact_frame &cf) const {
2083  for (size_type i = 0; i < boundaries.size(); ++i) {
2084  const contact_boundary &cb = boundaries[i];
2085  cf.add_boundary(md.mesh_fem_of_variable(cb.varname),
2086  md.real_variable(cb.varname),
2087  md.mesh_fem_of_variable(cb.multname),
2088  md.real_variable(cb.multname), cb.region);
2089  }
2090  for (size_type i = 0; i < obstacles.size(); ++i)
2091  cf.add_obstacle(obstacles[i]);
2092  }
2093 
2094 
2095  virtual void asm_real_tangent_terms(const model &md, size_type /* ib */,
2096  const model::varnamelist &vl,
2097  const model::varnamelist &dl,
2098  const model::mimlist &mims,
2099  model::real_matlist &matl,
2100  model::real_veclist &vecl,
2101  model::real_veclist &,
2102  size_type region,
2103  build_version version) const;
2104 
2105  integral_large_sliding_contact_brick_field_extension() {
2106  set_flags("Integral large sliding contact brick",
2107  false /* is linear*/, false /* is symmetric */,
2108  false /* is coercive */, true /* is real */,
2109  false /* is complex */);
2110  }
2111 
2112  };
2113 
2114 
2115 
2116 
2117  void integral_large_sliding_contact_brick_field_extension::asm_real_tangent_terms
2118  (const model &md, size_type /* ib */, const model::varnamelist &vl,
2119  const model::varnamelist &dl, const model::mimlist &/* mims */,
2120  model::real_matlist &matl, model::real_veclist &vecl,
2121  model::real_veclist &, size_type /* region */,
2122  build_version version) const {
2123 
2124  fem_precomp_pool fppool;
2125  base_matrix G;
2126  size_type N = md.mesh_fem_of_variable(vl[0]).linked_mesh().dim();
2127  contact_frame cf(N);
2128  build_contact_frame(md, cf);
2129 
2130  size_type Nvar = vl.size(), Nu = cf.Urhs.size(), Nl = cf.Lrhs.size();
2131  GMM_ASSERT1(Nvar == Nu+Nl, "Wrong size of variable list for integral "
2132  "large sliding contact brick");
2133  GMM_ASSERT1(matl.size() == Nvar*Nvar, "Wrong size of terms for "
2134  "integral large sliding contact brick");
2135 
2136  if (version & model::BUILD_MATRIX) {
2137  for (size_type i = 0; i < Nvar; ++i)
2138  for (size_type j = 0; j < Nvar; ++j) {
2139  gmm::clear(matl[i*Nvar+j]);
2140  if (i < Nu && j < Nu) cf.UU(i,j) = &(matl[i*Nvar+j]);
2141  if (i >= Nu && j < Nu) cf.LU(i-Nu,j) = &(matl[i*Nvar+j]);
2142  if (i < Nu && j >= Nu) cf.UL(i,j-Nu) = &(matl[i*Nvar+j]);
2143  if (i >= Nu && j >= Nu) cf.LL(i-Nu,j-Nu) = &(matl[i*Nvar+j]);
2144  }
2145  }
2146  if (version & model::BUILD_RHS) {
2147  for (size_type i = 0; i < vl.size(); ++i) {
2148  if (i < Nu) cf.Urhs[i] = &(vecl[i*Nvar]);
2149  else cf.Lrhs[i-Nu] = &(vecl[i*Nvar]);
2150  }
2151  }
2152 
2153  // Data : r, [friction_coeff,]
2154  GMM_ASSERT1(dl.size() == 2, "Wrong number of data for integral large "
2155  "sliding contact brick");
2156 
2157  const model_real_plain_vector &vr = md.real_variable(dl[0]);
2158  GMM_ASSERT1(gmm::vect_size(vr) == 1, "Parameter r should be a scalar");
2159 
2160  const model_real_plain_vector &f_coeff = md.real_variable(dl[1]);
2161  GMM_ASSERT1(gmm::vect_size(f_coeff) == 1,
2162  "Friction coefficient should be a scalar");
2163 
2164  contact_elements ce(cf);
2165  ce.init();
2166 
2167  for (size_type bnum = 0; bnum < boundaries.size(); ++bnum) {
2168  mesh_region rg(boundaries[bnum].region);
2169  const mesh_fem &mfu=md.mesh_fem_of_variable(boundaries[bnum].varname);
2170  const mesh_fem &mfl=md.mesh_fem_of_variable(boundaries[bnum].multname);
2171  const mesh_im &mim = *(boundaries[bnum].mim);
2172  const mesh &m = mfu.linked_mesh();
2173  mfu.linked_mesh().intersect_with_mpi_region(rg);
2174 
2175  for (getfem::mr_visitor v(rg, m); !v.finished(); ++v) {
2176  // cout << "boundary " << bnum << " element " << v.cv() << endl;
2177  size_type cv = v.cv();
2178  bgeot::pgeometric_trans pgt = m.trans_of_convex(cv);
2179  pfem pf_s = mfu.fem_of_element(cv);
2180  pfem pf_sl = mfl.fem_of_element(cv);
2181  pintegration_method pim = mim.int_method_of_element(cv);
2182  bgeot::vectors_to_base_matrix(G, m.points_of_convex(cv));
2183 
2184  pfem_precomp pfpu
2185  = fppool(pf_s, pim->approx_method()->pintegration_points());
2186  pfem_precomp pfpl
2187  = fppool(pf_sl, pim->approx_method()->pintegration_points());
2188  fem_interpolation_context ctxu(pgt, pfpu, size_type(-1), G, cv, v.f());
2189  fem_interpolation_context ctxl(pgt, pfpl, size_type(-1), G, cv, v.f());
2190 
2191  for (size_type k = 0;
2192  k < pim->approx_method()->nb_points_on_face(v.f()); ++k) {
2193  size_type ind
2194  = pim->approx_method()->ind_first_point_on_face(v.f()) + k;
2195  ctxu.set_ii(ind);
2196  ctxl.set_ii(ind);
2197  if (!(ce.add_point_contribution
2198  (bnum, ctxu, ctxl,pim->approx_method()->coeff(ind),
2199  f_coeff[0], vr[0], version))) return;
2200  }
2201  }
2202  }
2203  }
2204 
2205 
2206  // r ne peut pas etre variable pour le moment.
2207  // dataname_friction_coeff ne peut pas etre variable non plus ...
2208 
2209  size_type add_integral_large_sliding_contact_brick_field_extension
2210  (model &md, const mesh_im &mim, const std::string &varname_u,
2211  const std::string &multname, const std::string &dataname_r,
2212  const std::string &dataname_friction_coeff, size_type region) {
2213 
2214  auto pbr
2215  =std::make_shared<integral_large_sliding_contact_brick_field_extension>();
2216 
2217  pbr->add_boundary(varname_u, multname, mim, region);
2218 
2219  model::termlist tl;
2220  tl.push_back(model::term_description(varname_u, varname_u, false));
2221  tl.push_back(model::term_description(varname_u, multname, false));
2222  tl.push_back(model::term_description(multname, varname_u, false));
2223  tl.push_back(model::term_description(multname, multname, false));
2224 
2225  model::varnamelist dl(1, dataname_r);
2226  dl.push_back(dataname_friction_coeff);
2227 
2228  model::varnamelist vl(1, varname_u);
2229  vl.push_back(multname);
2230 
2231  return md.add_brick(pbr, vl, dl, tl, model::mimlist(1, &mim), region);
2232  }
2233 
2234 
2235  void add_boundary_to_large_sliding_contact_brick
2236  (model &md, size_type indbrick, const mesh_im &mim,
2237  const std::string &varname_u, const std::string &multname,
2238  size_type region) {
2239  dim_type N = md.mesh_fem_of_variable(varname_u).linked_mesh().dim();
2240  pbrick pbr = md.brick_pointer(indbrick);
2241  md.touch_brick(indbrick);
2242  integral_large_sliding_contact_brick_field_extension *p
2243  = dynamic_cast<integral_large_sliding_contact_brick_field_extension *>
2244  (const_cast<virtual_brick *>(pbr.get()));
2245  GMM_ASSERT1(p, "Wrong type of brick");
2246  p->add_boundary(varname_u, multname, mim, region);
2247  md.add_mim_to_brick(indbrick, mim);
2248 
2249  contact_frame cf(N);
2250  p->build_contact_frame(md, cf);
2251 
2252  model::varnamelist vl;
2253  size_type nvaru = 0;
2254  for (size_type i = 0; i < cf.contact_boundaries.size(); ++i)
2255  if (cf.contact_boundaries[i].ind_U >= nvaru)
2256  { vl.push_back(p->boundaries[i].varname); ++nvaru; }
2257 
2258  size_type nvarl = 0;
2259  for (size_type i = 0; i < cf.contact_boundaries.size(); ++i)
2260  if (cf.contact_boundaries[i].ind_lambda >= nvarl)
2261  { vl.push_back(p->boundaries[i].multname); ++nvarl; }
2262  md.change_variables_of_brick(indbrick, vl);
2263 
2264  model::termlist tl;
2265  for (size_type i = 0; i < vl.size(); ++i)
2266  for (size_type j = 0; j < vl.size(); ++j)
2267  tl.push_back(model::term_description(vl[i], vl[j], false));
2268 
2269  md.change_terms_of_brick(indbrick, tl);
2270  }
2271 
2273  (model &md, size_type indbrick, const std::string &obs) { // The velocity field should be added to an (optional) parameter ... (and optionally represented by a rigid motion only ... the velocity should be modifiable ...
2274  pbrick pbr = md.brick_pointer(indbrick);
2275  md.touch_brick(indbrick);
2276  integral_large_sliding_contact_brick_field_extension *p
2277  = dynamic_cast<integral_large_sliding_contact_brick_field_extension *>
2278  (const_cast<virtual_brick *>(pbr.get()));
2279  GMM_ASSERT1(p, "Wrong type of brick");
2280  p->add_obstacle(obs);
2281  }
2282 
2283 #endif
2284 
2285  // ----------------------------------------------------------------------
2286  //
2287  // Brick for large sliding contact with friction using raytracing contact
2288  // detection and the high-level generic assemly
2289  //
2290  // ----------------------------------------------------------------------
2291 
2292  struct intergral_large_sliding_contact_brick_raytracing
2293  : public virtual_brick {
2294 
2295  struct contact_boundary {
2296  size_type region;
2297  std::string varname_u;
2298  std::string varname_lambda;
2299  std::string varname_w;
2300  bool is_master;
2301  bool is_slave;
2302  const mesh_im *mim;
2303 
2304  std::string expr;
2305  };
2306 
2307  std::vector<contact_boundary> boundaries;
2308  std::string transformation_name;
2309  std::string u_group;
2310  std::string w_group;
2311  std::string friction_coeff;
2312  std::string alpha;
2313  std::string augmentation_param;
2314  model::varnamelist vl, dl;
2315  model::mimlist ml;
2316 
2317  bool sym_version, frame_indifferent;
2318 
2319  void add_contact_boundary(model &md, const mesh_im &mim, size_type region,
2320  bool is_master, bool is_slave,
2321  const std::string &u,
2322  const std::string &lambda,
2323  const std::string &w = "") {
2324  std::string test_u = "Test_" + sup_previous_and_dot_to_varname(u);
2325  std::string test_u_group = "Test_" + sup_previous_and_dot_to_varname(u_group);
2326  std::string test_lambda = "Test_" + sup_previous_and_dot_to_varname(lambda);
2327  GMM_ASSERT1(is_slave || is_master, "The contact boundary should be "
2328  "either master, slave or both");
2329  const mesh_fem *mf = md.pmesh_fem_of_variable(u);
2330  GMM_ASSERT1(mf, "The displacement variable should be a f.e.m. one");
2331  GMM_ASSERT1(&(mf->linked_mesh()) == &(mim.linked_mesh()),
2332  "The displacement variable and the integration method "
2333  "should share the same mesh");
2334  if (is_slave) {
2335  const mesh_fem *mf_l = md.pmesh_fem_of_variable(lambda);
2336  const im_data *mimd_l = md.pim_data_of_variable(lambda);
2337  GMM_ASSERT1(mf_l || mimd_l,
2338  "The multiplier variable should be defined on a "
2339  "mesh_fem or an im_data");
2340  GMM_ASSERT1(&(mf_l ? mf_l->linked_mesh() : mimd_l->linked_mesh())
2341  == &(mim.linked_mesh()),
2342  "The displacement and the multiplier fields "
2343  "should be defined on the same mesh");
2344  }
2345 
2346  if (w.size()) {
2347  const mesh_fem *mf2 = md.pmesh_fem_of_variable(w);
2348  GMM_ASSERT1(!mf2 || &(mf2->linked_mesh()) == &(mf->linked_mesh()),
2349  "The data for the sliding velocity should be defined on "
2350  " the same mesh as the displacement variable");
2351  }
2352 
2353  for (size_type i = 0; i < boundaries.size(); ++i) {
2354  const contact_boundary &cb = boundaries[i];
2355  if (&(md.mesh_fem_of_variable(cb.varname_u).linked_mesh())
2356  == &(mf->linked_mesh()) && cb.region == region)
2357  GMM_ASSERT1(false, "This contact boundary has already been added");
2358  }
2359  if (is_master)
2361  (md, transformation_name, mf->linked_mesh(), u_group, region);
2362  else
2364  (md, transformation_name, mf->linked_mesh(), u_group, region);
2365 
2366  boundaries.push_back(contact_boundary());
2367  contact_boundary &cb = boundaries.back();
2368  cb.region = region;
2369  cb.varname_u = u;
2370  if (is_slave) cb.varname_lambda = lambda;
2371  cb.varname_w = w;
2372  cb.is_master = is_master;
2373  cb.is_slave = is_slave;
2374  cb.mim = &mim;
2375  if (is_slave) {
2376  std::string n, n0, Vs, g, Y;
2377  n = "Transformed_unit_vector(Grad_"+u+", Normal)";
2378  n0 = "Transformed_unit_vector(Grad_"+w+", Normal)";
2379 
2380  // Coulomb_friction_coupled_projection(lambda,
2381  // Transformed_unit_vector(Grad_u, Normal),
2382  // (u-Interpolate(ug,trans)-(w-Interpolate(wg,trans)))*alpha,
2383  // (Interpolate(X,trans)+Interpolate(ug,trans)-X-u).
2384  // Transformed_unit_vector(Grad_u, Normal), f, r)
2385  Y = "Interpolate(X,"+transformation_name+")";
2386  g = "("+Y+"+Interpolate("+u_group+","+transformation_name+")-X-"+u+")."+n;
2387  Vs = "("+u+"-Interpolate("+u_group+","+transformation_name+")";
2388  if (w.size()) {
2389  Vs += "-"+w+"+Interpolate("+w_group+","+transformation_name+")";
2390  if (frame_indifferent)
2391  Vs += "+("+g+")*("+n+"-"+n0+")";
2392  }
2393  Vs += ")*"+alpha;
2394 
2395  std::string coupled_projection_def =
2396  "Coulomb_friction_coupled_projection("
2397  + lambda+","+n+","+Vs+","+g+","+friction_coeff+","
2398  + augmentation_param+")";
2399 
2400  // Coulomb_friction_coupled_projection(lambda,
2401  // Transformed_unit_vector(Grad_u, Normal), (u-w)*alpha,
2402  // (Interpolate(X,trans)-X-u).Transformed_unit_vector(Grad_u,
2403  // Normal), f, r)
2404  g = "(Interpolate(X,"+transformation_name+")-X-"+u+")."+n;
2405  if (frame_indifferent && w.size())
2406  Vs = "("+u+"-"+w+"+"+g+"*("+n+"-"+n0+"))*"+alpha;
2407  else
2408  Vs = "("+u+(w.size() ? ("-"+w):"")+")*"+alpha;
2409 
2410  std::string coupled_projection_rig =
2411  "Coulomb_friction_coupled_projection("
2412  + lambda+","+n+","+Vs+","+g+","+ friction_coeff+","
2413  + augmentation_param+")";
2414 
2415  cb.expr =
2416  // -lambda.Test_u for non-symmetric version
2417  (sym_version ? "" : ("-"+lambda+"."+test_u))
2418  // -coupled_projection_def.Test_u and -coupled_projection_rig.Test_u
2419  // for symmetric version
2420  + (sym_version ? ("+ Interpolate_filter("+transformation_name+",-"
2421  +coupled_projection_def+"."+test_u+",1)") : "")
2422  + (sym_version ? ("+ Interpolate_filter("+transformation_name+",-"
2423  +coupled_projection_rig+"."+test_u+",2)") : "")
2424  // Interpolate_filter(trans,
2425  // lambda.Interpolate(Test_ug, contact_trans), 1)
2426  // or
2427  // Interpolate_filter(trans,
2428  // coupled_projection_def.Interpolate(Test_ug, contact_trans), 1)
2429  + "+ Interpolate_filter("+transformation_name+","
2430  + (sym_version ? coupled_projection_def : lambda)
2431  + ".Interpolate("+test_u_group+"," + transformation_name+"), 1)"
2432  // -(1/r)*lambda.Test_lambda
2433  + "-(1/"+augmentation_param+")*"+lambda+"."+test_lambda
2434  // Interpolate_filter(trans,
2435  // (1/r)*coupled_projection_rig.Test_lambda, 2)
2436  + "+ Interpolate_filter("+transformation_name+","
2437  + "(1/"+augmentation_param+")*"+ coupled_projection_rig
2438  + "."+test_lambda+", 2)"
2439  // Interpolate_filter(trans,
2440  // (1/r)*coupled_projection_def.Test_lambda, 1)
2441  + "+ Interpolate_filter("+transformation_name+","
2442  + "(1/"+augmentation_param+")*" + coupled_projection_def + "."
2443  + test_lambda+", 1)";
2444  }
2445  }
2446 
2447  virtual void asm_real_tangent_terms(const model &md, size_type ,
2448  const model::varnamelist &,
2449  const model::varnamelist &,
2450  const model::mimlist &,
2451  model::real_matlist &,
2452  model::real_veclist &,
2453  model::real_veclist &,
2454  size_type,
2455  build_version) const {
2456  // GMM_ASSERT1(mims.size() == 1,
2457  // "Generic linear assembly brick needs one and only one "
2458  // "mesh_im"); // to be verified ...
2459 
2460  for (const contact_boundary &cb : boundaries) {
2461  if (cb.is_slave)
2462  md.add_generic_expression(cb.expr, *(cb.mim), cb.region);
2463  }
2464  }
2465 
2466 
2467  intergral_large_sliding_contact_brick_raytracing
2468  (const std::string &r,
2469  const std::string &f_coeff,const std::string &ug,
2470  const std::string &wg, const std::string &tr,
2471  const std::string &alpha_ = "1", bool sym_v = false,
2472  bool frame_indiff = false) {
2473  transformation_name = tr;
2474  u_group = ug; w_group = wg;
2475  friction_coeff = f_coeff;
2476  alpha = alpha_;
2477  augmentation_param = r;
2478  sym_version = sym_v;
2479  frame_indifferent = frame_indiff;
2480 
2481  set_flags("Integral large sliding contact bick raytracing",
2482  false /* is linear*/,
2483  false /* is symmetric */, false /* is coercive */,
2484  true /* is real */, false /* is complex */);
2485  }
2486 
2487  };
2488 
2489 
2491  (model &md, size_type indbrick) {
2492  pbrick pbr = md.brick_pointer(indbrick);
2493  intergral_large_sliding_contact_brick_raytracing *p
2494  = dynamic_cast<intergral_large_sliding_contact_brick_raytracing *>
2495  (const_cast<virtual_brick *>(pbr.get()));
2496  GMM_ASSERT1(p, "Wrong type of brick");
2497  return p->transformation_name;
2498  }
2499 
2501  (model &md, size_type indbrick) {
2502  pbrick pbr = md.brick_pointer(indbrick);
2503  intergral_large_sliding_contact_brick_raytracing *p
2504  = dynamic_cast<intergral_large_sliding_contact_brick_raytracing *>
2505  (const_cast<virtual_brick *>(pbr.get()));
2506  GMM_ASSERT1(p, "Wrong type of brick");
2507  return p->u_group;
2508  }
2509 
2511  (model &md, size_type indbrick) {
2512  pbrick pbr = md.brick_pointer(indbrick);
2513  intergral_large_sliding_contact_brick_raytracing *p
2514  = dynamic_cast<intergral_large_sliding_contact_brick_raytracing *>
2515  (const_cast<virtual_brick *>(pbr.get()));
2516  GMM_ASSERT1(p, "Wrong type of brick");
2517  return p->w_group;
2518  }
2519 
2521  (model &md, size_type indbrick, const std::string &expr, size_type N) {
2522  pbrick pbr = md.brick_pointer(indbrick);
2523  intergral_large_sliding_contact_brick_raytracing *p
2524  = dynamic_cast<intergral_large_sliding_contact_brick_raytracing *>
2525  (const_cast<virtual_brick *>(pbr.get()));
2526  GMM_ASSERT1(p, "Wrong type of brick");
2528  (md, p->transformation_name, expr, N);
2529  }
2530 
2532  (model &md, size_type indbrick, const mesh_im &mim, size_type region,
2533  bool is_master, bool is_slave, const std::string &u,
2534  const std::string &lambda, const std::string &w) {
2535 
2536  pbrick pbr = md.brick_pointer(indbrick);
2537  intergral_large_sliding_contact_brick_raytracing *p
2538  = dynamic_cast<intergral_large_sliding_contact_brick_raytracing *>
2539  (const_cast<virtual_brick *>(pbr.get()));
2540  GMM_ASSERT1(p, "Wrong type of brick");
2541 
2542  bool found_u = false, found_lambda = false;
2543  for (const auto & v : p->vl) {
2544  if (v.compare(u) == 0) found_u = true;
2545  if (v.compare(lambda) == 0) found_lambda = true;
2546  }
2547  if (!found_u) p->vl.push_back(u);
2548  GMM_ASSERT1(!is_slave || lambda.size(),
2549  "You should define a multiplier on each slave boundary");
2550  if (is_slave && !found_lambda) p->vl.push_back(lambda);
2551  if (!found_u || (is_slave && !found_lambda))
2552  md.change_variables_of_brick(indbrick, p->vl);
2553 
2554  std::vector<std::string> ug = md.variable_group(p->u_group);
2555  found_u = false;
2556  for (const auto &uu : ug)
2557  if (uu.compare(u) == 0) { found_u = true; break; }
2558  if (!found_u) {
2559  ug.push_back(u);
2560  md.define_variable_group(p->u_group, ug);
2561  }
2562 
2563  if (w.size()) {
2564  bool found_w = false;
2565  for (const auto &ww : p->dl)
2566  if (ww.compare(w) == 0) { found_w = true; break; }
2567  if (!found_w) {
2568  p->dl.push_back(w);
2569  md.change_data_of_brick(indbrick, p->dl);
2570  }
2571  std::vector<std::string> wg = md.variable_group(p->w_group);
2572  found_w = false;
2573  for (const auto &ww : wg)
2574  if (ww.compare(w) == 0) { found_w = true; break; }
2575  if (!found_w) {
2576  wg.push_back(w);
2577  md.define_variable_group(p->w_group, wg);
2578  }
2579  }
2580 
2581  bool found_mim = false;
2582  for (const auto &pmim : p->ml)
2583  if (pmim == &mim) { found_mim = true; break; }
2584  if (!found_mim) {
2585  p->ml.push_back(&mim);
2586  md.change_mims_of_brick(indbrick, p->ml);
2587  }
2588 
2589  p->add_contact_boundary(md, mim, region, is_master, is_slave,
2590  u, lambda, w);
2591  }
2592 
2594  (model &md, const std::string &augm_param,
2595  scalar_type release_distance, const std::string &f_coeff,
2596  const std::string &alpha, bool sym_v, bool frame_indifferent) {
2597 
2598  char ugroupname[50], wgroupname[50], transname[50];
2599  for (int i = 0; i < 10000; ++i) {
2600  snprintf(ugroupname, 49, "disp__group_raytracing_%d", i);
2601  if (!(md.variable_group_exists(ugroupname))
2602  && !(md.variable_exists(ugroupname)))
2603  break;
2604  }
2605  md.define_variable_group(ugroupname, std::vector<std::string>());
2606 
2607  for (int i = 0; i < 10000; ++i) {
2608  snprintf(wgroupname, 49, "w__group_raytracing_%d", i);
2609  if (!(md.variable_group_exists(wgroupname))
2610  && !(md.variable_exists(wgroupname)))
2611  break;
2612  }
2613  md.define_variable_group(wgroupname, std::vector<std::string>());
2614 
2615  for (int i = 0; i < 10000; ++i) {
2616  snprintf(transname, 49, "trans__raytracing_%d", i);
2617  if (!(md.interpolate_transformation_exists(transname)))
2618  break;
2619  }
2620  add_raytracing_transformation(md, transname, release_distance);
2621 
2622  model::varnamelist vl, dl;
2623  if (md.variable_exists(augm_param)) dl.push_back(augm_param);
2624  if (md.variable_exists(f_coeff)) dl.push_back(f_coeff);
2625  if (md.variable_exists(alpha)) dl.push_back(alpha);
2626 
2627  auto p = std::make_shared<intergral_large_sliding_contact_brick_raytracing>
2628  (augm_param, f_coeff, ugroupname, wgroupname, transname, alpha,
2629  sym_v, frame_indifferent);
2630  pbrick pbr(p);
2631  p->dl = dl;
2632 
2633  return md.add_brick(pbr, p->vl, p->dl, model::termlist(), model::mimlist(),
2634  size_type(-1));
2635  }
2636 
2637 
2638 
2639  struct Nitsche_large_sliding_contact_brick_raytracing
2640  : public virtual_brick {
2641 
2642  struct contact_boundary {
2643  size_type region;
2644  std::string varname_u;
2645  std::string sigma_u;
2646  std::string varname_w;
2647  bool is_master;
2648  bool is_slave;
2649  bool is_unbiased;
2650  const mesh_im *mim;
2651 
2652  std::string expr;
2653  };
2654 
2655  std::vector<contact_boundary> boundaries;
2656  std::string transformation_name;
2657  std::string u_group;
2658  std::string w_group;
2659  std::string friction_coeff;
2660  std::string alpha;
2661  std::string Nitsche_param;
2662  model::varnamelist vl, dl;
2663  model::mimlist ml;
2664 
2665  bool sym_version, frame_indifferent, unbiased;
2666 
2667  void add_contact_boundary(model &md, const mesh_im &mim, size_type region,
2668  bool is_master, bool is_slave, bool is_unbiased,
2669  const std::string &u,
2670  const std::string &sigma_u,
2671  const std::string &w = "") {
2672  std::string test_u = "Test_" + sup_previous_and_dot_to_varname(u);
2673  std::string test_u_group = "Test_" + sup_previous_and_dot_to_varname(u_group);
2674  GMM_ASSERT1(is_slave || is_master, "The contact boundary should be "
2675  "either master, slave or both");
2676  if (is_unbiased) {
2677  GMM_ASSERT1((is_slave && is_master), "The contact boundary should be "
2678  "both master and slave for the unbiased version");
2679  is_slave=true; is_master=true;
2680  }
2681  const mesh_fem *mf = md.pmesh_fem_of_variable(u);
2682  GMM_ASSERT1(mf, "The displacement variable should be a f.e.m. one");
2683  GMM_ASSERT1(&(mf->linked_mesh()) == &(mim.linked_mesh()),
2684  "The displacement variable and the integration method "
2685  "should share the same mesh");
2686 
2687  if (w.size()) {
2688  const mesh_fem *mf2 = md.pmesh_fem_of_variable(w);
2689  GMM_ASSERT1(!mf2 || &(mf2->linked_mesh()) == &(mf->linked_mesh()),
2690  "The data for the sliding velocity should be defined on "
2691  " the same mesh as the displacement variable");
2692  }
2693 
2694  for (size_type i = 0; i < boundaries.size(); ++i) {
2695  const contact_boundary &cb = boundaries[i];
2696  if (&(md.mesh_fem_of_variable(cb.varname_u).linked_mesh())
2697  == &(mf->linked_mesh()) && cb.region == region)
2698  GMM_ASSERT1(false, "This contact boundary has already been added");
2699  }
2700  if (is_master)
2702  (md, transformation_name, mf->linked_mesh(), u_group, region);
2703  else
2705  (md, transformation_name, mf->linked_mesh(), u_group, region);
2706 
2707  boundaries.push_back(contact_boundary());
2708  contact_boundary &cb = boundaries.back();
2709  cb.region = region;
2710  cb.varname_u = u;
2711  if (is_slave) cb.sigma_u = sigma_u;
2712  cb.varname_w = w;
2713  cb.is_master = is_master;
2714  cb.is_slave = is_slave;
2715  cb.is_unbiased= is_unbiased;
2716  cb.mim = &mim;
2717  if (is_slave) {
2718  std::string n, n0, Vs, g, Y, gamma;
2719 
2720  gamma ="("+Nitsche_param+"/element_size)";
2721  n = "Transformed_unit_vector(Grad_"+u+", Normal)";
2722  n0 = "Transformed_unit_vector(Grad_"+w+", Normal)";
2723 
2724  // For deformable bodies:
2725  // Coulomb_friction_coupled_projection(sigma(u),
2726  // Transformed_unit_vector(Grad_u, Normal),
2727  // (u-Interpolate(ug,trans)-(w-Interpolate(wg,trans)))*alpha,
2728  // (Interpolate(X,trans)+Interpolate(ug,trans)-X-u).
2729  // Transformed_unit_vector(Grad_u, Normal), f, r)
2730  Y = "Interpolate(X,"+transformation_name+")";
2731  g = "("+Y+"+Interpolate("+u_group+","+transformation_name+")-X-"+u+")."+n;
2732  Vs = "("+u+"-Interpolate("+u_group+","+transformation_name+")";
2733  if (w.size()) {
2734  Vs += "-"+w+"+Interpolate("+w_group+","+transformation_name+")";
2735  if (frame_indifferent)
2736  Vs += "+("+g+")*("+n+"-"+n0+")";
2737  }
2738  Vs += ")*"+alpha;
2739 
2740  std::string coupled_projection_def =
2741  "Coulomb_friction_coupled_projection("
2742  + sigma_u +","+n+","+Vs+","+g+","+friction_coeff+","
2743  + gamma +")";
2744 
2745  // For regid obstacle:
2746  // Coulomb_friction_coupled_projection(sigma(u),
2747  // Transformed_unit_vector(Grad_u, Normal), (u-w)*alpha,
2748  // (Interpolate(X,trans)-X-u).Transformed_unit_vector(Grad_u,
2749  // Normal), f, r)
2750  g = "(Interpolate(X,"+transformation_name+")-X-"+u+")."+n;
2751  if (frame_indifferent && w.size())
2752  Vs = "("+u+"-"+w+"+"+g+"*("+n+"-"+n0+"))*"+alpha;
2753  else
2754  Vs = "("+u+(w.size() ? ("-"+w):"")+")*"+alpha;
2755 
2756  std::string coupled_projection_rig =
2757  "Coulomb_friction_coupled_projection("
2758  + sigma_u +","+n+","+Vs+","+g+","+ friction_coeff+","
2759  + gamma +")";
2760 
2761  cb.expr =
2762  // 0.5* for non-biaised version
2763  (is_unbiased ? "-0.5*" : "-")
2764  // -coupled_projection_def.Test_u
2765  + ("Interpolate_filter("+transformation_name+","
2766  +coupled_projection_def+"."+test_u+",1) ")
2767  +(is_unbiased ? "":"-Interpolate_filter("+transformation_name+","
2768  +coupled_projection_rig+"."+test_u+",2) ")
2769  // Interpolate_filter(trans,
2770  // lambda.Interpolate(Test_ug, contact_trans), 1)
2771  // or
2772  // Interpolate_filter(trans,
2773  // coupled_projection_def.Interpolate(Test_ug, contact_trans), 1)
2774  + (is_unbiased ? "+ 0.5*" : "+ ")
2775  +"Interpolate_filter("+transformation_name+","
2776  +coupled_projection_def +".Interpolate("+test_u_group+"," + transformation_name+"), 1)"
2777  +(is_unbiased ? "":"+ Interpolate_filter("+transformation_name+","
2778  +coupled_projection_rig +".Interpolate("+test_u_group+"," + transformation_name+"), 2)");
2779  }
2780  }
2781 
2782  virtual void asm_real_tangent_terms(const model &md, size_type ,
2783  const model::varnamelist &,
2784  const model::varnamelist &,
2785  const model::mimlist &,
2786  model::real_matlist &,
2787  model::real_veclist &,
2788  model::real_veclist &,
2789  size_type,
2790  build_version) const {
2791  // GMM_ASSERT1(mims.size() == 1,
2792  // "Generic linear assembly brick needs one and only one "
2793  // "mesh_im"); // to be verified ...
2794 
2795  for (const contact_boundary &cb : boundaries) {
2796  if (cb.is_slave)
2797  md.add_generic_expression(cb.expr, *(cb.mim), cb.region);
2798  }
2799  }
2800 
2801 
2802  Nitsche_large_sliding_contact_brick_raytracing
2803  ( bool unbia,
2804  const std::string &Nitsche_parameter,
2805  const std::string &f_coeff,const std::string &ug,
2806  const std::string &wg, const std::string &tr,
2807  const std::string &alpha_ = "1", bool sym_v = false,
2808  bool frame_indiff = false) {
2809  transformation_name = tr;
2810  u_group = ug; w_group = wg;
2811  friction_coeff = f_coeff;
2812  alpha = alpha_;
2813  Nitsche_param = Nitsche_parameter;
2814  sym_version = sym_v;
2815  frame_indifferent = frame_indiff;
2816  unbiased = unbia;
2817 
2818  set_flags("Integral large sliding contact bick raytracing",
2819  false /* is linear*/,
2820  false /* is symmetric */, false /* is coercive */,
2821  true /* is real */, false /* is complex */);
2822  }
2823 
2824  };
2825 
2826 
2828  (model &md, size_type indbrick) {
2829  pbrick pbr = md.brick_pointer(indbrick);
2830  Nitsche_large_sliding_contact_brick_raytracing *p
2831  = dynamic_cast<Nitsche_large_sliding_contact_brick_raytracing *>
2832  (const_cast<virtual_brick *>(pbr.get()));
2833  GMM_ASSERT1(p, "Wrong type of brick");
2834  return p->transformation_name;
2835  }
2836 
2838  (model &md, size_type indbrick) {
2839  pbrick pbr = md.brick_pointer(indbrick);
2840  Nitsche_large_sliding_contact_brick_raytracing *p
2841  = dynamic_cast<Nitsche_large_sliding_contact_brick_raytracing *>
2842  (const_cast<virtual_brick *>(pbr.get()));
2843  GMM_ASSERT1(p, "Wrong type of brick");
2844  return p->u_group;
2845  }
2846 
2848  (model &md, size_type indbrick) {
2849  pbrick pbr = md.brick_pointer(indbrick);
2850  Nitsche_large_sliding_contact_brick_raytracing *p
2851  = dynamic_cast<Nitsche_large_sliding_contact_brick_raytracing *>
2852  (const_cast<virtual_brick *>(pbr.get()));
2853  GMM_ASSERT1(p, "Wrong type of brick");
2854  return p->w_group;
2855  }
2856 
2858  (model &md, size_type indbrick, const std::string &expr, size_type N) {
2859  pbrick pbr = md.brick_pointer(indbrick);
2860  Nitsche_large_sliding_contact_brick_raytracing *p
2861  = dynamic_cast<Nitsche_large_sliding_contact_brick_raytracing *>
2862  (const_cast<virtual_brick *>(pbr.get()));
2863  GMM_ASSERT1(p, "Wrong type of brick");
2865  (md, p->transformation_name, expr, N);
2866  }
2867 
2869  (model &md, size_type indbrick, const mesh_im &mim, size_type region,
2870  bool is_master, bool is_slave, bool is_unbiased, const std::string &u,
2871  const std::string &sigma_u, const std::string &w) {
2872 
2873  pbrick pbr = md.brick_pointer(indbrick);
2874  Nitsche_large_sliding_contact_brick_raytracing *p
2875  = dynamic_cast<Nitsche_large_sliding_contact_brick_raytracing *>
2876  (const_cast<virtual_brick *>(pbr.get()));
2877  GMM_ASSERT1(p, "Wrong type of brick");
2878 
2879  bool found_u = false, found_sigma = false;
2880  for (const auto & v : p->vl) {
2881  if (v.compare(u) == 0) found_u = true;
2882  if (v.compare(sigma_u) == 0) found_sigma = true;
2883  }
2884  if (!found_u) p->vl.push_back(u);
2885  GMM_ASSERT1(!is_slave || sigma_u.size(),
2886  "You should define an expression of sigma(u) on each slave boundary");
2887  // if (is_slave && !found_sigma) p->vl.push_back(sigma_u);
2888  if (!found_u)
2889  md.change_variables_of_brick(indbrick, p->vl);
2890 
2891  std::vector<std::string> ug = md.variable_group(p->u_group);
2892  found_u = false;
2893  for (const auto &uu : ug)
2894  if (uu.compare(u) == 0) { found_u = true; break; }
2895  if (!found_u) {
2896  ug.push_back(u);
2897  md.define_variable_group(p->u_group, ug);
2898  }
2899 
2900  if (w.size()) {
2901  bool found_w = false;
2902  for (const auto &ww : p->dl)
2903  if (ww.compare(w) == 0) { found_w = true; break; }
2904  if (!found_w) {
2905  p->dl.push_back(w);
2906  md.change_data_of_brick(indbrick, p->dl);
2907  }
2908  std::vector<std::string> wg = md.variable_group(p->w_group);
2909  found_w = false;
2910  for (const auto &ww : wg)
2911  if (ww.compare(w) == 0) { found_w = true; break; }
2912  if (!found_w) {
2913  wg.push_back(w);
2914  md.define_variable_group(p->w_group, wg);
2915  }
2916  }
2917 
2918  bool found_mim = false;
2919  for (const auto &pmim : p->ml)
2920  if (pmim == &mim) { found_mim = true; break; }
2921  if (!found_mim) {
2922  p->ml.push_back(&mim);
2923  md.change_mims_of_brick(indbrick, p->ml);
2924  }
2925 
2926  p->add_contact_boundary(md, mim, region, is_master, is_slave,is_unbiased,
2927  u, sigma_u, w);
2928  }
2929 
2931  (model &md, bool is_unbiased, const std::string &Nitsche_param,
2932  scalar_type release_distance, const std::string &f_coeff,
2933  const std::string &alpha, bool sym_v, bool frame_indifferent) {
2934 
2935  char ugroupname[50], wgroupname[50], transname[50];
2936  for (int i = 0; i < 10000; ++i) {
2937  snprintf(ugroupname, 49, "disp__group_raytracing_%d", i);
2938  if (!(md.variable_group_exists(ugroupname))
2939  && !(md.variable_exists(ugroupname)))
2940  break;
2941  }
2942  md.define_variable_group(ugroupname, std::vector<std::string>());
2943 
2944  for (int i = 0; i < 10000; ++i) {
2945  snprintf(wgroupname, 49, "w__group_raytracing_%d", i);
2946  if (!(md.variable_group_exists(wgroupname))
2947  && !(md.variable_exists(wgroupname)))
2948  break;
2949  }
2950  md.define_variable_group(wgroupname, std::vector<std::string>());
2951 
2952  for (int i = 0; i < 10000; ++i) {
2953  snprintf(transname, 49, "trans__raytracing_%d", i);
2954  if (!(md.interpolate_transformation_exists(transname)))
2955  break;
2956  }
2957  add_raytracing_transformation(md, transname, release_distance);
2958 
2959  model::varnamelist vl, dl;
2960  if (md.variable_exists(Nitsche_param)) dl.push_back(Nitsche_param);
2961  if (md.variable_exists(f_coeff)) dl.push_back(f_coeff);
2962  if (md.variable_exists(alpha)) dl.push_back(alpha);
2963 
2964  auto p = std::make_shared<Nitsche_large_sliding_contact_brick_raytracing>
2965  (is_unbiased, Nitsche_param , f_coeff, ugroupname, wgroupname, transname, alpha,
2966  sym_v, frame_indifferent);
2967  pbrick pbr(p);
2968  p->dl = dl;
2969 
2970  return md.add_brick(pbr, p->vl, p->dl, model::termlist(), model::mimlist(),
2971  size_type(-1));
2972  }
2973 
2974 }
2975 
2976 
2977 
2978 
2979 
2980  /* end of namespace getfem. */
region-tree for window/point search on a set of rectangles.
const base_node & xreal() const
coordinates of the current point, in the real convex.
void set_ii(size_type ii__)
change the current point (assuming a geotrans_precomp_ is used)
Balanced tree of n-dimensional rectangles.
Definition: bgeot_rtree.h:98
structure passed as the argument of fem interpolation functions.
Definition: getfem_fem.h:750
Describe a finite element method linked to a mesh.
virtual size_type nb_basic_dof() const
Return the total number of basic degrees of freedom (before the optional reduction).
Describe an integration method linked to a mesh.
"iterator" class for regions.
`‘Model’' variables store the variables, the data and the description of a model.
bool interpolate_transformation_exists(const std::string &name) const
Tests if name corresponds to an interpolate transformation.
void change_mims_of_brick(size_type ib, const mimlist &ml)
Change the mim list of a brick.
size_type add_brick(pbrick pbr, const varnamelist &varnames, const varnamelist &datanames, const termlist &terms, const mimlist &mims, size_type region)
Add a brick to the model.
void change_data_of_brick(size_type ib, const varnamelist &vl)
Change the data list of a brick.
void change_variables_of_brick(size_type ib, const varnamelist &vl)
Change the variable list of a brick.
bool variable_exists(const std::string &name) const
States if a name corresponds to a declared variable.
The virtual brick has to be derived to describe real model bricks.
Miscelleanous assembly routines for common terms. Use the low-level generic assembly....
Comomon tools for unilateral contact and Coulomb friction bricks.
Unilateral contact and Coulomb friction condition brick.
void mult_add(const L1 &l1, const L2 &l2, L3 &l3)
*‍/
Definition: gmm_blas.h:1791
void copy(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:978
number_traits< typename linalg_traits< V >::value_type >::magnitude_type vect_norm2(const V &v)
Euclidean norm of a vector.
Definition: gmm_blas.h:558
void clear(L &l)
clear (fill with zeros) a vector or matrix.
Definition: gmm_blas.h:59
number_traits< typename linalg_traits< V1 >::value_type >::magnitude_type vect_dist2(const V1 &v1, const V2 &v2)
Euclidean distance between two vectors.
Definition: gmm_blas.h:598
void resize(V &v, size_type n)
*‍/
Definition: gmm_blas.h:210
void mult(const L1 &l1, const L2 &l2, L3 &l3)
*‍/
Definition: gmm_blas.h:1664
strongest_value_type< V1, V2 >::value_type vect_sp(const V1 &v1, const V2 &v2)
*‍/
Definition: gmm_blas.h:264
void add(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:1277
computation of the condition number of dense matrices.
void lu_inverse(const DenseMatrixLU &LU, const Pvector &pvector, const DenseMatrix &AInv_)
Given an LU factored matrix, build the inverse of the matrix.
Definition: gmm_dense_lu.h:212
size_type lu_factor(DenseMatrix &A, Pvector &ipvt)
LU Factorization of a general (dense) matrix (real or complex).
Definition: gmm_dense_lu.h:93
void lu_solve(const DenseMatrix &LU, const Pvector &pvector, VectorX &x, const VectorB &b)
LU Solve : Solve equation Ax=b, given an LU factored matrix.
Definition: gmm_dense_lu.h:130
void asm_mass_matrix(const MAT &M, const mesh_im &mim, const mesh_fem &mf1, const mesh_region &rg=mesh_region::all_convexes())
generic mass matrix assembly (on the whole mesh or on the specified convex set or boundary)
void asm_source_term(const VECT1 &B, const mesh_im &mim, const mesh_fem &mf, const mesh_fem &mf_data, const VECT2 &F, const mesh_region &rg=mesh_region::all_convexes())
source term (for both volumic sources and boundary (Neumann) sources).
size_type convex_num() const
get the current convex number
Definition: getfem_fem.cc:53
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
Definition: getfem_fem.h:244
void grad_base_value(base_tensor &t, bool withM=true) const
fill the tensor with the gradient of the base functions (taken at point this->xref())
Definition: getfem_fem.cc:203
void base_value(base_tensor &t, bool withM=true) const
fill the tensor with the values of the base functions (taken at point this->xref())
Definition: getfem_fem.cc:121
short_type face_num() const
get the current face number
Definition: getfem_fem.cc:62
const pfem pf() const
get the current FEM descriptor
Definition: getfem_fem.h:782
gmm::uint16_type short_type
used as the common short type integer in the library
Definition: bgeot_config.h:73
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
Definition: bgeot_poly.h:49
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 .
Definition: bgeot_poly.cc:47
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...
const std::string & transformation_name_of_large_sliding_contact_brick(model &md, size_type indbrick)
Gives the name of the raytracing interpolate transformation for an existing large sliding contact bri...
const std::string & sliding_data_group_name_of_Nitsche_large_sliding_contact_brick(model &md, size_type indbrick)
Gives the name of the group of variables corresponding to the sliding data for an existing large slid...
size_type add_integral_large_sliding_contact_brick_raytracing(model &md, const std::string &augm_param, scalar_type release_distance, const std::string &f_coeff="0", const std::string &alpha="1", bool sym_v=false, bool frame_indifferent=false)
Adds a large sliding contact with friction brick to the model.
size_type add_integral_large_sliding_contact_brick_raytrace(model &md, multi_contact_frame &mcf, const std::string &dataname_r, const std::string &dataname_friction_coeff=std::string(), const std::string &dataname_alpha=std::string())
Adds a large sliding contact with friction brick to the model.
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...
size_type add_Nitsche_large_sliding_contact_brick_raytracing(model &md, bool is_unbiased, const std::string &Nitsche_param, scalar_type release_distance, const std::string &f_coeff="0", const std::string &alpha="1", bool sym_v=false, bool frame_indifferent=false)
Adds a large sliding contact with friction brick to the model based on Nitsche's method.
void add_rigid_obstacle_to_Nitsche_large_sliding_contact_brick(model &md, size_type indbrick, const std::string &expr, size_type N)
Adds a rigid obstacle to an existing large sliding contact with friction brick.
const std::string & sliding_data_group_name_of_large_sliding_contact_brick(model &md, size_type indbrick)
Gives the name of the group of variables corresponding to the sliding data for an existing large slid...
void add_contact_boundary_to_Nitsche_large_sliding_contact_brick(model &md, size_type indbrick, const mesh_im &mim, size_type region, bool is_master, bool is_slave, bool is_unbiased, const std::string &u, const std::string &lambda="", const std::string &w="")
Adds a contact boundary to an existing large sliding contact with friction brick.
void add_rigid_obstacle_to_large_sliding_contact_brick(model &md, size_type indbrick, const std::string &expr, size_type N)
Adds a rigid obstacle to an existing large sliding contact with friction brick.
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.
std::shared_ptr< const virtual_brick > pbrick
type of pointer on a brick
Definition: getfem_models.h:49
const std::string & transformation_name_of_Nitsche_large_sliding_contact_brick(model &md, size_type indbrick)
Gives the name of the raytracing interpolate transformation for an existing large sliding contact bri...
const std::string & displacement_group_name_of_large_sliding_contact_brick(model &md, size_type indbrick)
Gives the name of the group of variables corresponding to the displacement for an existing large slid...
const std::string & displacement_group_name_of_Nitsche_large_sliding_contact_brick(model &md, size_type indbrick)
Gives the name of the group of variables corresponding to the displacement for an existing large slid...
void add_slave_contact_boundary_to_raytracing_transformation(model &md, const std::string &transname, const mesh &m, const std::string &dispname, size_type region)
Add a slave boundary with corresponding displacement variable 'dispname' on a specific boundary 'regi...
void add_contact_boundary_to_large_sliding_contact_brick(model &md, size_type indbrick, const mesh_im &mim, size_type region, bool is_master, bool is_slave, const std::string &u, const std::string &lambda="", const std::string &w="")
Adds a contact boundary to an existing large sliding contact with friction brick.