GetFEM  5.5
getfem_level_set_contact.h
Go to the documentation of this file.
1 /* -*- c++ -*- (enables emacs c++ mode) */
2 /*===========================================================================
3 
4  Copyright (C) 2012-2026 Andriy Andreykiv
5 
6  This file is a part of GetFEM
7 
8  GetFEM is free software; you can redistribute it and/or modify it
9  under the terms of the GNU Lesser General Public License as published
10  by the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version along with the GCC Runtime Library
12  Exception either version 3.1 or (at your option) any later version.
13  This program is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
16  License and GCC Runtime Library Exception for more details.
17  You should have received a copy of the GNU Lesser General Public License
18  along with this program. If not, see https://www.gnu.org/licenses/.
19 
20  As a special exception, you may use this file as it is a part of a free
21  software library without restriction. Specifically, if other files
22  instantiate templates or use macros or inline functions from this file,
23  or you compile this file and link it with other files to produce an
24  executable, this file does not by itself cause the resulting executable
25  to be covered by the GNU Lesser General Public License. This exception
26  does not however invalidate any other reasons why the executable file
27  might be covered by the GNU Lesser General Public License.
28 
29 ===========================================================================*/
30 
31 /** @file getfem_level_set_contact.h
32  @author "Andriy Andreykiv" <andriy.andreykiv@gmail.com>
33  @date July, 2012.
34  @brief Non frictional level set based large sliding contact;
35  for details see:
36  A. Andreykiv et al. A level set based large sliding contact
37  algorithm for an easy analysis of implant positioning
38  2012 International Journal for Numerical Methods in Engineering,
39  89, pp. 1317-1336
40  2D and 3D Examples of the usage: test_contact.cpp
41  */
42 
43 
44 #pragma once
45 
46 #ifndef GETFEM_LEVEL_SET_CONTACT_H__
47 #define GETFEM_LEVEL_SET_CONTACT_H__
48 
50 #include <getfem/getfem_models.h>
53 #include <gmm/gmm_except.h>
54 
55 namespace level_set_contact {
56 
57  using getfem::mesh_fem;
58  using getfem::mesh_im;
59  using getfem::mesh;
60  using getfem::model;
61  using getfem::size_type;
62  using getfem::scalar_type;
63  using getfem::model_real_plain_vector;
64  typedef getfem::model_real_plain_vector plain_vector;
65  typedef getfem::model_real_sparse_matrix sparse_matrix;
66 
67 
68  /**build a level set function on mesh with zero on the boundary.
69  Solves Laplace equation with zero Dirichlet on the boundary.
70  Used to create simple level sets for contact testing*/
71  template<class VECT> void boundary_level_set_field(
72  const getfem::mesh& _mesh,
73  const getfem::mesh_fem& mf,
74  const getfem::mesh_im& mim,
75  VECT& LS)
76  {
77  getfem::mesh& mesh = const_cast<getfem::mesh&>(_mesh);
78  //model and vars
79  getfem::model md;
80  md.add_fem_variable("LS",mf);
81  getfem::model_real_plain_vector RHS(mf.nb_dof());
82 
83  //calculating the size of the LS RHS based on the size of the geometry
84  getfem::base_node Pmin(mesh.dim()),Pmax(mesh.dim()),range(mesh.dim());
85  mesh.bounding_box(Pmin,Pmax);
86  gmm::add(Pmax,gmm::scaled(Pmin,-1.0),range);
87  getfem::scalar_type mesh_size = *(std::max_element(range.begin(),range.end()));
88  gmm::fill(RHS,mesh_size*5.0);
89  md.add_initialized_fem_data("RHS",mf,RHS);
90 
91  //border region
92  getfem::mesh_region border_faces;
93  getfem::outer_faces_of_mesh(mesh, border_faces);
95  for (getfem::mr_visitor i(border_faces); !i.finished(); ++i)
96  mesh.region(BORDER).add(i.cv(),i.f());
97 
98  //describing the PDE problem
99  getfem::add_Laplacian_brick(md,mim,"LS");
101  getfem::add_source_term_brick(md,mim,"LS","RHS");
102 
103  //solving
104  gmm::iteration iter;
105  GMM_TRACE2("building scalar level set with laplace equation..");
106  getfem::standard_solve(md,iter);
107 
108  //extracting the result
109  gmm::copy(md.real_variable("LS"),LS);
110 
111  //so, now the mesh is as it was, hence const is still valid
112  mesh.sup_region(BORDER);
113  GMM_TRACE2("..done");
114  }
115 
116 
117  /**base class for the master and the slave contact bodies.*/
119 
120  const std::string var_name;
121  bool is_deformed;
122  friend class contact_pair_update;
123 
124  protected:
125  mesh& own_mesh;
126  const mesh_fem& own_mesh_fem;
127  model& md;
128 
129  public:
130 
131  contact_body(model& _md, std::string _var_name);
132  inline std::string get_var_name() const {return var_name;}
133  inline mesh& get_mesh() {return own_mesh;}
134  inline const mesh& get_mesh()const {return own_mesh;}
135  inline const mesh_fem& get_mesh_fem() const {return own_mesh_fem;}
136  inline const model& get_model() const {return md;}
137  inline bool is_mesh_deformed() const {return is_deformed;}
138  };
139 
140 
141  /** Contact body that will be projected on the boundary
142  of the master. */
144 
145  std::string ls_name;
146  mesh_fem ls_mesh_fem;
147  mesh_im* pmim;
148 
149  public:
150 
151  /**default constructor. Level set field will have zero value
152  right on the boundary of the contact body*/
153  slave_contact_body(model& _md, const std::string& _var_name,
154  mesh_im* _pmim);
155 
156  /**Level set field is provided via the model variable name*/
157  slave_contact_body(model& _md, std::string _var_name,
158  std::string _ls_name);
159  inline std::string get_ls_name() const {return ls_name;}
160  inline const plain_vector& ls_values() const
161  {return md.real_variable(ls_name);}
162  inline plain_vector& ls_values()
163  {return md.set_real_variable(ls_name);}
164  inline const mesh_fem& get_ls_mesh_fem() const {return md.mesh_fem_of_variable(ls_name);}
165  template<class VECTOR> void set_level_set(const VECTOR& ls)
166  {gmm::copy(ls,md.set_real_variable(ls_name));}
167 
168  /**adds a fixed value "off" to the level set field */
169  void offset_level_set(scalar_type off);
170  };
171 
172 
173  class master_contact_body;
174 
175  /**Prepares the final information needed to pass to the contact
176  brick for every contact pair to assemble tangent terms*/
178 
179  //obtain on construction
180  master_contact_body& master_cb;
181  slave_contact_body& slave_cb;
182  const std::string mult_name;
183  const size_type GIVEN_CONTACT_REGION;
184 
185  //to be built
186  dal::bit_vector old_contact_elm_list;
187  dal::bit_vector pre_old_ct_list;
188  size_type ACTIVE_CONTACT_REGION;
189  mutable std::shared_ptr<mesh_im> pmim_contact;
190  mutable getfem::pfem ifem_srf;
191  mutable std::shared_ptr<mesh_fem> pinterpolated_fem;
192  mutable std::shared_ptr<mesh_fem> pinterpolated_fem_U;
193  mutable std::shared_ptr<gmm::unsorted_sub_index> slave_ls_dofs;
194  mutable std::shared_ptr<gmm::unsorted_sub_index> slave_U_dofs;
195  mutable size_type n_integrated_elems;
196 
197  // state of the object
198  mutable bool members_are_computed;
199  mutable bool init_cont_detect_done;
200  public:
201 
202  // accessors
203  inline const mesh_fem& slave_scalar_fem() const {
204  if (dependecies_changed()) update();
205  return *pinterpolated_fem;
206  }
207  inline const mesh_fem& slave_vector_fem() const {
208  if (dependecies_changed()) update();
209  return *pinterpolated_fem_U;
210  }
211  inline const gmm::unsorted_sub_index& slave_scalar_dofs() const {
212  if (dependecies_changed()) update();
213  return *slave_ls_dofs;
214  }
215  inline const gmm::unsorted_sub_index& slave_vector_dofs() const {
216  if (dependecies_changed()) update();
217  return *slave_U_dofs;
218  }
219  inline const mesh_im& contact_mesh_im() const {
220  if (dependecies_changed()) update();
221  return *pmim_contact;
222  }
223 
224  inline size_type contact_region() const
225  {return ACTIVE_CONTACT_REGION;}
226 
227  inline const std::string& get_mult_name() const
228  {return mult_name;}
229 
230  inline size_type num_of_integr_elems() const {return n_integrated_elems;}
231  // update
232  inline bool dependecies_changed() const
233  {return !members_are_computed;}
234  inline void force_update() const
235  {members_are_computed=false;}
236 
237  /** Actual master/slave contact detection. Level set field is projected on the
238  boundary of the master and only the elements which nodes satisfy
239  level_set + Multiplier > 0
240  become contact elements*/
241  bool contact_changed();
242 
243  /**clearing contact element lists*/
244  void clear_contact_history();
245 
246  /** updating contact information (mesh_fem's, mesh_im's)
247  with the deformation. Contact detection is not performed*/
248  void update(void) const;
249 
250  contact_pair_info(master_contact_body& underformed_mcb,
251  slave_contact_body& underformed_scb, const std::string& _mult_name,
252  size_type _GIVEN_CONTACT_REGION);
253 
254  private:
255  /**prohibiting copying*/
257  contact_pair_info& operator=(const contact_pair_info&);
258 
259 
260  };
261 
262  struct face_type{
264  face_type(size_type _cv=0, bgeot::short_type _f=0):cv(_cv),f(_f){}
265  face_type(const getfem::mr_visitor& i): cv(i.cv()),f(i.f()){}
266  };
267 
268  /**Determines geometric transformation on the face of the element
269  based on the geometric transformation of the element itself. Works
270  only for PK and QK elements*/
272 
273 
274  /** Master contact body which surface will be used to project contact
275  stresses and stiffness terms. It contains and manages the slaves and
276  knows other masters.
277  Master contact body must be created with mesh_fem that allows automatic
278  addition of mesh_fem description on new elements (use mesh_fem::set_auto_add or
279  use set_classical_finite_element). This feature is used when new boundary
280  elements are created from faces. At the same time the mesh_im object that
281  is used to add for instance some structural bricks on the volume (elastostatic,
282  nonlinear_elastostatic, updated_lagrangian) should be either created before
283  master contact body, or set on master_contact_body::volume_region() if it's
284  created after. This is to avoid integration of the volume integrals on the
285  boundary elemenents of lower dimension. */
287 
288 
289  const size_type mult_mim_order;
290  const std::string mult_int_method;
291  size_type BOUNDARY_ELEMENTS, VOLUME_ELEMENTS;
292  std::vector<size_type> face_to_belem_ind;
293  static std::vector<master_contact_body*> masters;
294  std::map<std::string, std::shared_ptr<contact_pair_info> > contact_table;
295  std::map<size_type,face_type> border_faces;
296 
297  protected:
298 
299  /**contact detection for all slaves*/
300  bool master_contact_changed(void);
301 
302  /** clearing previous contact elem lists*/
303  void clear_contact_history(void);
304 
305  public:
306 
307  enum contact_integration{PER_ELEMENT=1,REGULARIZED_LEVEL_SET=2};
308 
309  /**approximation order for Lagrange multiplier on the contact surface*/
311 
312  /**integration approach for contact elements that are partially
313  crossed by level sets:
314  PER_ELEMENT - a whole element is incuded into contact (default)
315  REGULARIZED_LEVEL_SET - Gauss points where projected value of the level
316  set is < zero are set to zero or small value
317  (with gradual transition)*/
318  const contact_integration integration;
319 
320  /**width of transition for a regularazied Heaviside function in
321  case of REGULARIZED_LEVEL_SET*/
322  const scalar_type regularized_tollerance;
323 
324  /**in case of REGULARIZED_LEVEL_SET this value
325  scales weight of Gauss points that have negative level
326  set value*/
327  const scalar_type small_weight_multiplier;
328 
329  /**if the angle (in degrees) between contact element and
330  level set contour exceed this value, this element is not included in
331  contact algorithm*/
332  const scalar_type max_contact_angle;
333 
334 
335  /** create master contact body with a model,
336  name where masters displacements are defined, order for
337  Lagrange multiplier, order for the integration method*/
339  const std::string& _var_name,
340  size_type _mult_order, size_type _mult_mim_order);
341 
342  /**the same as above, but specifically provide itegration
343  * method on the contact surface (_mult_int_method), additionally,
344  * specify if surface contact elements have to be cut by the level set.
345  * The later ensures that contact surface is strictly a domain
346  * that overlaps with the slave, hence this allows smooth growth of the contact
347  * surface. The level set cutting is done using regularized Heaviside function
348  */
350  const std::string& _var_name,
351  size_type _mult_order,
352  const std::string& _mult_int_method,
353  contact_integration _integration = PER_ELEMENT,
354  scalar_type _regularized_tollerance = 1e-6,
355  scalar_type _small_weight_multiplier = 0.001,
356  scalar_type _max_contact_angle = 45);
357 
358  /** associate a slave contact body with this master. \
359  specify a region of expected contact interaction. \
360  (takes the whole master boundary if not specified)*/
361  void add_slave(slave_contact_body& scb,
362  size_type slave_contact_region = -1);
363 
364  /** order of integration of boundary contact terms*/
365  inline size_type contact_mim_order() const
366  {
367  GMM_ASSERT1(mult_mim_order!=size_type(-1),
368  "master body was not created with "
369  "order of integration for contact area");
370  return mult_mim_order;
371  }
372 
373  /** integration method on the contact surface,
374  * use it when the master is created with a specific
375  * integration method and not the approx_order*/
376  inline getfem::pintegration_method contact_int_method() const
377  {
378  GMM_ASSERT1(mult_mim_order==size_type(-1),
379  "master body was not created with integration "
380  "method for contact area");
381  return getfem::int_method_descriptor(mult_int_method);
382  }
383 
384  /** region of all volume elements without the boundary*/
385  inline size_type volume_region() const
386  {return VOLUME_ELEMENTS;}
387 
388  /**boundary elements, added after creation of
389  the master contact body */
390  inline size_type boundary_region() const
391  {return BOUNDARY_ELEMENTS;}
392 
393  /**access to a structure that contains all the info
394  about contact pair between this master and a slave, defined
395  on @param slave_var_name*/
396  const contact_pair_info& get_pair_info(const std::string& slave_var_name) const;
397 
398  /**the same as above, but non-const*/
399  contact_pair_info& get_pair_info(const std::string& slave_var_name);
400 
401 
402  /**contact detection for all masters/slave couples
403  @return true if any of the contact areas where changed
404  (which requires new Newton method run)*/
405  static bool any_contact_change();
406 
407  /** should be used in the beginning of a step
408  to clean data structures that store previous
409  contact element lists (used to verify if contact surface
410  is converged to one list)
411  */
412  static void clear_all_contact_history();
413 
414  inline void update_for_slave(std::string slave_var_name)
415  { contact_table[slave_var_name]->update(); }
416 
417  /** return a pointer to mesh_im used for contact surface calculations
418  */
419  std::shared_ptr<mesh_im> build_mesh_im_on_boundary(size_type region);
420 
421  /**gives a face, corresponding to newly created
422  boundary element @param cv*/
423  face_type ext_face_of_elem(size_type cv) const;
424 
425  private:
426  /**prohibiting copying*/
428  master_contact_body& operator=(const master_contact_body&);
429 
430  };
431 
432  enum update_depth{DEFORM_MESHES_ONLY,FULL_UPDATE};
433 
434  /**temporary object that updates contact pair,
435  deformes meshes and undeformes when it selfdestructs*/
437  std::shared_ptr<getfem::temporary_mesh_deformator<> > def_master;
438  std::shared_ptr<getfem::temporary_mesh_deformator<> > def_slave;
439  master_contact_body& mcb;
440  slave_contact_body& scb;
441  public:
443  slave_contact_body& _scb,
444  update_depth ud = FULL_UPDATE);
445 
447  };
448 
449 
450  /** adding level set based normal contact brick to the model.
451  The contact is etablished between the
452  @param mcb - master contact body and
453  @param scb - slave contact body, defined on
454  @param md - model object
455  @param rg - optional assumed contact region
456  helping to narrow down contact search
457  Note, this contact algorithm is note stabilized, hence,
458  master contact body mesh should be coarser than slave's mesh.
459  Otherwise this contact constraint will violate inf-sub condition
460  and the solver will fail (or diverge, if it's iterative)
461  */
463  master_contact_body& mcb,
464  slave_contact_body& scb,
465  size_type rg = -1);
466 
467 
468  /** assembles normal contact terms on the boundary of
469  two contact bodies (master/slave)*/
471 
472  model& md;
473  master_contact_body& mcb;
474  slave_contact_body& scb;
475 
476  /**id of the region of faces where contact has to be checked*/
477  size_type given_contact_id;
478 
479  /**id of the region of boundary elements,
480  corresponding to the above faces*/
481  size_type contact_region_id;
482 
483  /**actual region object, with id = contact_region_id*/
484  getfem::mesh_region contact_region;
485 
486  public:
487  virtual void asm_real_tangent_terms(
488  const model &md, size_type /* ib */,
489  const model::varnamelist &vl,
490  const model::varnamelist &dl,
491  const model::mimlist &mims,
492  model::real_matlist &matl,
493  model::real_veclist &vecl,
494  model::real_veclist &,
495  size_type region,
496  build_version version) const;
497 
499  model& _md,
500  master_contact_body& _mcb,
501  slave_contact_body& scb,
502  size_type rg = -1);
503  };
504 
505 
506  /** A term, used in level set contact assemblies that
507  builds a surface projection matrix R = N^t X N
508  (where N is normal vector to the boundary)
509  */
511  { private:
512  const master_contact_body& mcb;
513  bgeot::multi_index sizes_;
514  bgeot::size_type version;
515  bgeot::size_type dim;
516 
517  public:
518 
519  NormalTerm(const master_contact_body& _mcb, size_type version_ = 1) :
520  mcb(_mcb),
521  sizes_(version_),
522  version(version_),
523  dim(_mcb.get_mesh().dim()) {
524 
525  GMM_ASSERT1(dim==2 || dim==3, "NormalTerm: wrong space dimension ");
526  GMM_ASSERT1(version==1 || version==2,"NormalTerm:: wrong version ");
527 
528  if (version == 1)
529  if (dim == 2)
530  sizes_[0] = 2;
531  else
532  sizes_[0] = 3;
533  else
534  if (dim == 2) {
535  sizes_[0] = 2;
536  sizes_[1] = 2;
537  }
538  else {
539  sizes_[0] = 3;
540  sizes_[1] = 3;
541  }
542  }
543  const bgeot::multi_index &sizes(size_type) const {return sizes_;};
544  void compute(getfem::fem_interpolation_context& ctx, bgeot::base_tensor &t);
545  void prepare(getfem::fem_interpolation_context& /* ctx */, size_type /* nl_part */) {}
546 
547  };
548 
549  /** Regularized Heaviside function.
550  Can be used instead of mesh_im_level_set in assemblies.
551  It's more stable, as it never fails in comparison to Delauney method
552  (used inside mesh_im_level_set), but less accurate, as it has a
553  transition zone from 1 to 0 of epsilon width.
554  The idea is taken from one of the articles of Ted Belytschko on XFem*/
556  {
557  private:
558  const mesh_fem &lsmf;
559  const plain_vector &LS_U;
560  scalar_type m_Epsilon;
561  scalar_type small_h;
562  bgeot::multi_index sizes_;
563 
564 
565  public:
566  HFunction(
567  const mesh_fem &lsmf_,
568  const plain_vector &LS_U_,
569  scalar_type epsilon=1e-9,
570  scalar_type small_h_=0);
571  const bgeot::multi_index &sizes(size_type) const;
572  void prepare(getfem::fem_interpolation_context& ctx, size_type nl_part);
573  void compute(getfem::fem_interpolation_context& ctx, bgeot::base_tensor &t);
574  scalar_type hRegularized(scalar_type x, scalar_type epsion, scalar_type small);
575  };
576 
577  //A dummy nonlinear term, does nothing
578  class Unity : public getfem::nonlinear_elem_term
579  {
580  private:
581  const mesh_fem &mf;
582  bgeot::multi_index sizes_;
583 
584  public:
585  Unity(const mesh_fem &mf_);
586  const bgeot::multi_index &sizes(size_type) const;
587  void prepare(getfem::fem_interpolation_context& ctx, size_type nl_part);
588  void compute(getfem::fem_interpolation_context& ctx, bgeot::base_tensor &t);
589  };
590 
591 
592 
593  template<typename MAT, typename VECT>
594  void asm_level_set_contact_tangent_matrix(
595  std::vector<MAT>& matl,
596  const master_contact_body& mcb,
597  const slave_contact_body& scb,
598  const VECT& LM,
599  const getfem::mesh_region& contact_region)
600  {
601  //extract matrix references
602  MAT& Kmm = matl[0];
603  MAT& Kss = matl[1];
604  //MAT& Kll = matl[2] remains zero
605  MAT& Kms = matl[3];
606  MAT& Kml = matl[4];
607  MAT& Ksl = matl[5];
608 
609  const std::string& mult_name =
610  mcb.get_pair_info(scb.get_var_name()).get_mult_name();
611  const std::string ls_name = "ls_on"+mcb.get_var_name()+"_from_"+scb.get_var_name();
612 
613  //extract mfs, and mims
614  const mesh_fem& mf_U_line = mcb.get_mesh_fem();
615  const mesh_fem& mf_lambda = mcb.get_model().mesh_fem_of_variable(mult_name);
616  const mesh_fem& mf_interpolate =
617  mcb.get_pair_info(scb.get_var_name()).slave_scalar_fem();
618  const mesh_fem& mf_U_interpolate =
619  mcb.get_pair_info(scb.get_var_name()).slave_vector_fem();
620  const mesh_fem& mf_master_ls = mcb.get_model().mesh_fem_of_variable(ls_name);
621  const mesh_im& mim_line =
622  mcb.get_pair_info(scb.get_var_name()).contact_mesh_im();
623 
624  //build temp vectors for interpolated fems
625  plain_vector LS_small(mf_interpolate.nb_dof());
626  gmm::copy(gmm::sub_vector(scb.ls_values(),
627  mcb.get_pair_info(scb.get_var_name()).slave_scalar_dofs()),LS_small);
628 
629  //nonlinear term to compute normal vector and R matrix
630  NormalTerm R_matrix(mcb,2);
631 
632  //nonlinear term that describes regularized integration or dummy (unity) multiplier
633  std::shared_ptr<getfem::nonlinear_elem_term> integration;
634  if (mcb.integration==master_contact_body::REGULARIZED_LEVEL_SET) {
635  integration = std::make_shared<HFunction>
636  (mf_master_ls,mcb.get_model().real_variable(ls_name),
637  mcb.regularized_tollerance,mcb.small_weight_multiplier);
638  } else { integration = std::make_shared<Unity>(mf_master_ls); }
639 
640 
641  //temp matrices due to different DOF indeces of the slave
642  sparse_matrix Kms_small(mf_U_interpolate.nb_dof(), mf_U_line.nb_dof());
643  sparse_matrix Kss_small(mf_U_interpolate.nb_dof(),mf_U_interpolate.nb_dof());
644  sparse_matrix Ksl_small(mf_U_interpolate.nb_dof(),mf_lambda.nb_dof());
645 
646  //assembly
647  getfem::generic_assembly assem_boundary;
648 
649  assem_boundary.set(
650  "F=data$1(#3);"
651  "L=data$2(#1);"
652  "Kmm1 = comp(Base(#1).Grad(#3).vBase(#2).NonLin$1(#2).vGrad(#2).NonLin$2(#5))(i,j,k,:,k,m,n,:,n,m,1).L(i).F(j);"
653  "Kmm2 = comp(Base(#1).NonLin$1(#2).vGrad(#2).Grad(#3).vBase(#2).NonLin$2(#5))(i,m,n,:,n,m,j,k,:,k,1).L(i).F(j);"
654  "Kmm3 = comp(Base(#1).Base(#3).NonLin$1(#2).vGrad(#2).NonLin$1(#2).vGrad(#2).NonLin$2(#5))(i,j,k,l,:,l,k,m,n,:,n,m,1).L(i).F(j);"
655  "Kmm4 = (-1.0)*comp(Base(#1).Base(#3).NonLin$1(#2).vGrad(#2).vGrad(#2).NonLin$2(#5))(i,j,m,n,:,n,l,:,l,m,1).L(i).F(j);"
656  "M$1(#2,#2)+= sym(Kmm1+Kmm2+Kmm3+Kmm4);"
657  "Ksm1=(-1.0)*comp(Base(#1).Grad(#3).vBase(#4).NonLin$1(#2).vGrad(#2).NonLin$2(#5))(i,j,k,:,k,m,n,:,n,m,1).L(i).F(j);"
658  "Ksm2=(-1.0)*comp(Base(#1).Grad(#3).vGrad(#4).vBase(#2).NonLin$2(#5))(i,j,m,:,m,n,:,n,1).L(i).F(j);"
659  "M$2(#4,#2)+= Ksm1+Ksm2;"
660  "Kml1=comp(Base(#3).NonLin$1(#2).vGrad(#2).Base(#1).NonLin$2(#5))(i,m,n,:,n,m,:,1).F(i);"
661  "Kml2=comp(Grad(#3).vBase(#2).Base(#1).NonLin$2(#5))(i,j,:,j,:,1).F(i);"
662  "M$3(#2,#1)+= Kml1+Kml2;"
663  "Kss_part = comp(Base(#1).Grad(#3).vGrad(#4).vBase(#4).NonLin$2(#5))(i,j,m,:,m,n,:,n,1).L(i).F(j);"
664  "M$4(#4,#4)+=sym(Kss_part{1,2}+Kss_part{2,1});"
665  "M$5(#4,#1)+=(-1.0)*comp(Grad(#3).vBase(#4).Base(#1).NonLin$2(#5))(i,k,:,k,:,1).F(i);"
666  ); /* Here we don't compute matrices that contain Hessian of
667  the level set function, as Getfem does not compute Hessian
668  for interpolated_fem class that we use for level set function */
669  assem_boundary.push_mi(mim_line); //mim on the contact surface
670  assem_boundary.push_mf(mf_lambda); //mf 1 Lambda
671  assem_boundary.push_mf(mf_U_line); //mf 2 Umaster
672  assem_boundary.push_mf(mf_interpolate); //mf 3 LSslave
673  assem_boundary.push_mf(mf_U_interpolate);//mf 4 Uslave
674  assem_boundary.push_mf(mf_master_ls); //mf 5 ls_on_master
675  assem_boundary.push_nonlinear_term(&R_matrix); //matrix of the normal products
676  assem_boundary.push_nonlinear_term(integration.get()); //term to limit integration domain
677  assem_boundary.push_data(LS_small); // data Level set on interpolated
678  assem_boundary.push_data(LM); // data Lagrange mult values
679  assem_boundary.push_mat(Kmm); // result mat 1
680  assem_boundary.push_mat(Kms_small); // .. mat 2
681  assem_boundary.push_mat(Kml); // .. mat 3
682  assem_boundary.push_mat(Kss_small); // .. mat 4
683  assem_boundary.push_mat(Ksl_small); // .. mat 5
684  assem_boundary.assembly(contact_region);
685 
686  //transfering from interpolated mesh_fem into full slave mesh_fem mat's
687  const gmm::sub_interval& Um_dof = gmm::sub_interval(0,mf_U_line.nb_dof());
688  const gmm::unsorted_sub_index& Us_dof =
689  mcb.get_pair_info(scb.get_var_name()).slave_vector_dofs();
690  const gmm::sub_interval& LM_dof = gmm::sub_interval(0,mf_lambda.nb_dof());
691  gmm::copy(gmm::transposed(Kms_small),gmm::sub_matrix(Kms,Um_dof,Us_dof));
692  gmm::copy(Kss_small,gmm::sub_matrix(Kss,Us_dof,Us_dof));
693  gmm::copy(Ksl_small,gmm::sub_matrix(Ksl,Us_dof,LM_dof));
694 
695  }
696 
697  template<typename VECT0,typename VECT1>
698  void asm_level_set_contact_rhs(
699  std::vector<VECT0>& vecl,
700  const master_contact_body& mcb,
701  const slave_contact_body& scb,
702  const VECT1& LM,
703  const getfem::mesh_region& contact_region)
704  {
705  //extract vector references
706  VECT0& RHS_Um = vecl[0];
707  VECT0& RHS_Us = vecl[1];
708  VECT0& RHS_LM = vecl[2];
709  // vecl[3, 4 and 5] remain zero
710 
711 
712  const std::string& mult_name =
713  mcb.get_pair_info(scb.get_var_name()).get_mult_name();
714  const std::string ls_name = "ls_on"+mcb.get_var_name()+"_from_"+scb.get_var_name();
715 
716  //extract mfs, and mims
717  const mesh_fem& mf_U_line = mcb.get_mesh_fem();
718  const mesh_fem& mf_lambda =
719  mcb.get_model().mesh_fem_of_variable(mult_name);
720  const mesh_fem& mf_interpolate =
721  mcb.get_pair_info(scb.get_var_name()).slave_scalar_fem();
722  const mesh_fem& mf_U_interpolate =
723  mcb.get_pair_info(scb.get_var_name()).slave_vector_fem();
724  const mesh_fem& mf_master_ls = mcb.get_model().mesh_fem_of_variable(ls_name);
725  const mesh_im& mim_line =
726  mcb.get_pair_info(scb.get_var_name()).contact_mesh_im();
727 
728  //build temp vectors for interpolated fems
729  plain_vector LS_small(mf_interpolate.nb_dof());
730  gmm::copy(gmm::sub_vector(scb.ls_values(),
731  mcb.get_pair_info(scb.get_var_name()).slave_scalar_dofs()),LS_small);
732 
733  //nonlinear term to compute normal vector and R matrix
734  NormalTerm R_matrix(mcb,2);
735 
736  //nonlinear term that describes regularized integration or dummy (unity) multiplier
737  std::shared_ptr<getfem::nonlinear_elem_term> integration;
738  if (mcb.integration==master_contact_body::REGULARIZED_LEVEL_SET) {
739  integration = std::make_shared<HFunction>
740  (mf_master_ls,mcb.get_model().real_variable(ls_name),
741  mcb.regularized_tollerance,mcb.small_weight_multiplier);
742  } else { integration = std::make_shared<Unity>(mf_master_ls); }
743 
744  // temp RHS vector due to diff DOF indeces for mesh_fem object of the slave
745  plain_vector RHS_Us_small(mf_U_interpolate.nb_dof());
746 
747  getfem::generic_assembly assem_boundary;
748  assem_boundary.set(
749  "F=data$1(#3);"
750  "L=data$2(#1);"
751  "RHS_L_Us_1=comp(Base(#1).Base(#3).NonLin$1(#2).vGrad(#2).NonLin$2(#5))(i,j,m,n,:,n,m,1).L(i).F(j);"
752  "RHS_L_Us_2=comp(Base(#1).Grad(#3).vBase(#2).NonLin$2(#5))(i,j,k,:,k,1).L(i).F(j);"
753  "V$1(#2)+=RHS_L_Us_1+RHS_L_Us_2;"
754  "V$2(#4)+=(-1.0)*comp(Base(#1).Grad(#3).vBase(#4).NonLin$2(#5))(i,j,k,:,k,1).L(i).F(j);"
755  "V$3(#1)+=comp(Base(#1).Base(#3).NonLin$2(#5))(:,i,1).F(i);"
756  );
757  assem_boundary.push_mi(mim_line); //mim on the contact surface
758  assem_boundary.push_mf(mf_lambda); //mf 1 Lambda
759  assem_boundary.push_mf(mf_U_line); //mf 2 Umaster
760  assem_boundary.push_mf(mf_interpolate); //mf 3 LSslave
761  assem_boundary.push_mf(mf_U_interpolate);//mf 4 Uslave
762  assem_boundary.push_mf(mf_master_ls); //mf 5 ls_on_master
763  assem_boundary.push_nonlinear_term(&R_matrix); //matrix of the normal products
764  assem_boundary.push_nonlinear_term(integration.get()); //term to limit integration domain
765  assem_boundary.push_data(LS_small); // data Level set on interpolated
766  assem_boundary.push_data(LM); // data Lagrange mult values
767  assem_boundary.push_vec(RHS_Um); // result vec 1
768  assem_boundary.push_vec(RHS_Us_small); // .. vec 2
769  assem_boundary.push_vec(RHS_LM); // .. vec 3
770  assem_boundary.assembly(contact_region);
771 
772  //transfering from interpolated mesh_fem into full slave mesh_fem RHS
773  const gmm::unsorted_sub_index& Us_dof =
774  mcb.get_pair_info(scb.get_var_name()).slave_vector_dofs();
775  gmm::copy(RHS_Us_small, gmm::sub_vector(RHS_Us,Us_dof));
776 
777  }
778 
779 
780 
781  typedef void(*SOLVE_FUNCTION)(
782  getfem::model &md,
783  gmm::iteration &iter,
784  getfem::rmodel_plsolver_type solver,
785  getfem::abstract_newton_line_search &ls);
786 
787  /** Solves a model that has contact in it.
788  Function checks wheather the contact area has converged
789  @param sf - a pointer to a newton solver function,
790  can be, for instance, getfem::standard_solve
791  @param it_newton - iteration object for newton method
792  @param it_staggered - iteration object for staggered calculation
793  between conact detection and newton method (only max
794  num. of iterations should be provided)
795  @param lsolver - solver for a linear system
796  @param ls - reference to line search method*/
797 
798  void solve_with_contact(
799  SOLVE_FUNCTION sf,
800  getfem::model& md,
801  gmm::iteration& it_newton,
802  gmm::iteration& it_staggered,
803  const std::string& lsolver,
804  getfem::abstract_newton_line_search &ls);
805 
806 } //end of the namespace level_set_contact
807 
808 #endif //GETFEM_LEVEL_SET_CONTACT_H__
structure passed as the argument of fem interpolation functions.
Definition: getfem_fem.h:749
Generic assembly of vectors, matrices.
void push_vec(VEC &v)
Add a new output vector.
void push_data(const VEC &d)
Add a new data (dense array)
void push_mat(const MAT &m)
Add a new output matrix (fake const version..)
void assembly(const mesh_region &region=mesh_region::all_convexes())
do the assembly on the specified region (boundary or set of convexes)
void push_nonlinear_term(pnonlinear_elem_term net)
Add a new non-linear term.
void push_mi(const mesh_im &im_)
Add a new mesh_im.
void push_mf(const mesh_fem &mf_)
Add a new mesh_fem.
Describe a finite element method linked to a mesh.
virtual size_type nb_dof() const
Return the total number of degrees of freedom.
Describe an integration method linked to a mesh.
"iterator" class for regions.
structure used to hold a set of convexes and/or convex faces.
static size_type free_region_id(const getfem::mesh &m)
Extract the next region number that does not yet exists in the mesh.
Describe a mesh (collection of convexes (elements) and points).
Definition: getfem_mesh.h:98
void bounding_box(base_node &Pmin, base_node &Pmax) const
Return the bounding box [Pmin - Pmax] of the mesh.
Definition: getfem_mesh.cc:260
void sup_region(size_type b)
Remove the region of index b.
Definition: getfem_mesh.h:446
const mesh_region region(size_type id) const
Return the region of index 'id'.
Definition: getfem_mesh.h:420
`‘Model’' variables store the variables, the data and the description of a model.
void add_fem_variable(const std::string &name, const mesh_fem &mf, size_type niter=1)
Add a variable being the dofs of a finite element method to the model.
const mesh_fem & mesh_fem_of_variable(const std::string &name) const
Gives the access to the mesh_fem of a variable if any.
void add_initialized_fem_data(const std::string &name, const mesh_fem &mf, const VECT &v)
Add an initialized fixed size data to the model, assumed to be a vector field if the size of the vect...
model_real_plain_vector & set_real_variable(const std::string &name, size_type niter) const
Gives the write access to the vector value of a variable.
const model_real_plain_vector & real_variable(const std::string &name, size_type niter) const
Gives the access to the vector value of a variable.
abstract class for integration of non-linear terms into the mat_elem computations the nonlinear term ...
The virtual brick has to be derived to describe real model bricks.
The Iteration object calculates whether the solution has reached the desired accuracy,...
Definition: gmm_iter.h:52
Regularized Heaviside function.
A term, used in level set contact assemblies that builds a surface projection matrix R = N^t X N (whe...
base class for the master and the slave contact bodies.
Prepares the final information needed to pass to the contact brick for every contact pair to assemble...
void update(void) const
updating contact information (mesh_fem's, mesh_im's) with the deformation.
bool contact_changed()
Actual master/slave contact detection.
void clear_contact_history()
clearing contact element lists
temporary object that updates contact pair, deformes meshes and undeformes when it selfdestructs
assembles normal contact terms on the boundary of two contact bodies (master/slave)
virtual void asm_real_tangent_terms(const model &md, size_type, const model::varnamelist &vl, const model::varnamelist &dl, const model::mimlist &mims, model::real_matlist &matl, model::real_veclist &vecl, model::real_veclist &, size_type region, build_version version) const
Assembly of bricks real tangent terms.
Master contact body which surface will be used to project contact stresses and stiffness terms.
const contact_pair_info & get_pair_info(const std::string &slave_var_name) const
access to a structure that contains all the info about contact pair between this master and a slave,...
const size_type mult_mf_order
approximation order for Lagrange multiplier on the contact surface
master_contact_body(model &_md, const std::string &_var_name, size_type _mult_order, size_type _mult_mim_order)
create master contact body with a model, name where masters displacements are defined,...
size_type contact_mim_order() const
order of integration of boundary contact terms
bool master_contact_changed(void)
contact detection for all slaves
static bool any_contact_change()
contact detection for all masters/slave couples
size_type volume_region() const
region of all volume elements without the boundary
const scalar_type small_weight_multiplier
in case of REGULARIZED_LEVEL_SET this value scales weight of Gauss points that have negative level se...
const scalar_type max_contact_angle
if the angle (in degrees) between contact element and level set contour exceed this value,...
std::shared_ptr< mesh_im > build_mesh_im_on_boundary(size_type region)
return a pointer to mesh_im used for contact surface calculations
void clear_contact_history(void)
clearing previous contact elem lists
void add_slave(slave_contact_body &scb, size_type slave_contact_region=-1)
associate a slave contact body with this master.
const contact_integration integration
integration approach for contact elements that are partially crossed by level sets: PER_ELEMENT - a w...
const scalar_type regularized_tollerance
width of transition for a regularazied Heaviside function in case of REGULARIZED_LEVEL_SET
face_type ext_face_of_elem(size_type cv) const
gives a face, corresponding to newly created boundary element
size_type boundary_region() const
boundary elements, added after creation of the master contact body
getfem::pintegration_method contact_int_method() const
integration method on the contact surface, use it when the master is created with a specific integrat...
static void clear_all_contact_history()
should be used in the beginning of a step to clean data structures that store previous contact elemen...
Contact body that will be projected on the boundary of the master.
void offset_level_set(scalar_type off)
adds a fixed value "off" to the level set field
slave_contact_body(model &_md, const std::string &_var_name, mesh_im *_pmim)
default constructor.
Miscelleanous assembly routines for common terms. Use the low-level generic assembly....
A class adaptor to deform a mesh.
void boundary_level_set_field(const getfem::mesh &_mesh, const getfem::mesh_fem &mf, const getfem::mesh_im &mim, VECT &LS)
build a level set function on mesh with zero on the boundary.
bgeot::pgeometric_trans face_trans_of_elem(bgeot::pgeometric_trans pelem_trans)
Determines geometric transformation on the face of the element based on the geometric transformation ...
void solve_with_contact(SOLVE_FUNCTION sf, getfem::model &md, gmm::iteration &it_newton, gmm::iteration &it_staggered, const std::string &lsolver, getfem::abstract_newton_line_search &ls)
Solves a model that has contact in it.
size_type add_level_set_normal_contact_brick(model &md, master_contact_body &mcb, slave_contact_body &scb, size_type rg=-1)
adding level set based normal contact brick to the model.
Standard solvers for model bricks.
Model representation in Getfem.
void copy(const L1 &l1, L2 &l2)
*‍/
Definition: gmm_blas.h:976
Definition of basic exceptions.
void APIDECL outer_faces_of_mesh(const mesh &m, const dal::bit_vector &cvlst, convex_face_ct &flist)
returns a list of "exterior" faces of a mesh (i.e.
Definition: getfem_mesh.cc:821
std::shared_ptr< const getfem::virtual_fem > pfem
type of pointer on a fem description
Definition: getfem_fem.h:243
gmm::uint16_type short_type
used as the common short type integer in the library
Definition: bgeot_config.h:72
size_t size_type
used as the common size type in the library
Definition: bgeot_poly.h:48
std::shared_ptr< const bgeot::geometric_trans > pgeometric_trans
pointer type for a geometric transformation
size_type APIDECL add_Laplacian_brick(model &md, const mesh_im &mim, const std::string &varname, size_type region=size_type(-1))
Add a Laplacian term on the variable varname (in fact with a minus : :math:-\text{div}(\nabla u)).
pintegration_method int_method_descriptor(std::string name, bool throw_if_not_found=true)
Get an integration method from its name .
size_type APIDECL add_Dirichlet_condition_with_penalization(model &md, const mesh_im &mim, const std::string &varname, scalar_type penalization_coeff, size_type region, const std::string &dataname=std::string(), const mesh_fem *mf_mult=0)
Add a Dirichlet condition on the variable varname and the mesh region region.
size_type APIDECL add_source_term_brick(model &md, const mesh_im &mim, const std::string &varname, const std::string &dataexpr, size_type region=size_type(-1), const std::string &directdataname=std::string())
Add a source term on the variable varname.
void standard_solve(model &md, gmm::iteration &iter, rmodel_plsolver_type lsolver, abstract_newton_line_search &ls)
A default solver for the model brick system.