GetFEM  5.5
getfem_level_set_contact.cc
1 /*===========================================================================
2 
3  Copyright (C) 2012-2026 Andriy Andreykiv
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, see https://www.gnu.org/licenses/.
18 
19 ===========================================================================*/
20 
24 #include <algorithm>
28 #include <math.h>
29 
30 level_set_contact::contact_body::contact_body(model& _md, std::string _var_name):
31  var_name(_var_name),
32  is_deformed(false),
33  own_mesh(const_cast<mesh&>(_md.mesh_fem_of_variable(_var_name).
34  linked_mesh())),
35  own_mesh_fem(_md.mesh_fem_of_variable(_var_name)),
36  md(_md)
37 {}
38 
39 
40 
42  getfem::model& _md, const std::string& _var_name,
43  getfem::mesh_im* _pmim_ls) : contact_body(_md,_var_name),
44  ls_name("ls_on_"+_var_name),
45  ls_mesh_fem(_md.mesh_fem_of_variable(_var_name)),
46  pmim(_pmim_ls)
47 
48 {
49  ls_mesh_fem.set_qdim(size_type(1));
50  model_real_plain_vector LS(ls_mesh_fem.nb_dof());
51  boundary_level_set_field(get_mesh(),ls_mesh_fem,
52  *pmim,LS);
53  md.add_initialized_fem_data(ls_name,ls_mesh_fem,LS);
54 }
55 
56 
58  getfem::model& _md, std::string _var_name, std::string _ls_name):
59 contact_body(_md,_var_name),
60  ls_name(_ls_name),
61  pmim(0)
62 { }
63 
65 {
66  for(size_type i=0;i<ls_values().size();i++)
67  ls_values()[i]+=off;
68 }
69 
71  model& _md,
72  const std::string& _var_name,
73  size_type _mult_order,
74  size_type _mult_mim_order) :
75 
76  contact_body(_md,_var_name),
77  mult_mim_order(_mult_mim_order),
78  mult_int_method(""),
79  mult_mf_order(_mult_order),
80  integration(PER_ELEMENT),
81  regularized_tollerance(0),
82  small_weight_multiplier(0),
83  max_contact_angle(45)
84 {
85  //store existing elements in VOLUME_ELEMENTS region
86  //before boundary elements are created
87  VOLUME_ELEMENTS = getfem::mesh_region::free_region_id(get_mesh());
88  get_mesh().region(VOLUME_ELEMENTS).add(get_mesh().convex_index());
89 
90  //create boundary elements (current mesh_fem should be automatically
91  // extended with these elements)
92  BOUNDARY_ELEMENTS = getfem::mesh_region::free_region_id(get_mesh());
93  get_mesh().region(BOUNDARY_ELEMENTS).clear();
94 
95  masters.push_back(this);
96 }
97 
99  model& _md,
100  const std::string& _var_name,
101  size_type _mult_order,
102  const std::string& _mult_mim_method,
103  contact_integration _integration,
104  scalar_type _regularized_tollerance,
105  scalar_type _small_weight_multiplier,
106  scalar_type _max_contact_angle):
107 
108  contact_body(_md,_var_name),
109  mult_mim_order(size_type(-1)),
110  mult_int_method(_mult_mim_method),
111  mult_mf_order(_mult_order),
112  integration(_integration),
113  regularized_tollerance(_regularized_tollerance),
114  small_weight_multiplier(_small_weight_multiplier),
115  max_contact_angle(_max_contact_angle)
116 {
117  //store existing elements in VOLUME_ELEMENTS region
118  //before boundary elements are created
119  VOLUME_ELEMENTS = getfem::mesh_region::free_region_id(get_mesh());
120  get_mesh().region(VOLUME_ELEMENTS).add(get_mesh().convex_index());
121 
122  //create boundary elements (current mesh_fem should be automatically
123  // extended with these elements)
124  BOUNDARY_ELEMENTS = getfem::mesh_region::free_region_id(get_mesh());
125  get_mesh().region(BOUNDARY_ELEMENTS).clear();
126  masters.push_back(this);
127 }
128 
129 
132  const std::string& slave_var_name) const
133 {
134  auto it = contact_table.find(slave_var_name);
135  if (it!=contact_table.end()) return *(it->second);
136  GMM_ASSERT1(false,"did not find info on slave contact body, \
137  defined on variable "+slave_var_name);
138 }
139 
142  const std::string& slave_var_name)
143 {
144  auto it = contact_table.find(slave_var_name);
145  if (it!=contact_table.end()) return *(it->second);
146  GMM_ASSERT1(false,"did not find info on slave contact body, \
147  defined on variable "+slave_var_name);
148 }
149 
150 
151 level_set_contact::face_type level_set_contact::master_contact_body::
153 {
154  auto it = border_faces.find(i);
155  if (it!=border_faces.end()) return it->second;
156  GMM_ASSERT1(false,"did not find a face, corresponding to element "<<i);
157 }
158 
159 
161  add_slave(slave_contact_body& scb, size_type assumed_contact_region)
162 {
163  //check input
164  GMM_ASSERT1(&md==&scb.get_model(),
165  "Model objects of master and slave are not the same");
166  if (assumed_contact_region!=size_type(-1))
167  GMM_ASSERT1(get_mesh().region(assumed_contact_region).is_boundary(),
168  "Assumed_contact_region must be on the boundary");
169 
170  //add surface elements where contact will be computed
171  size_type assumed_contact_elems = getfem::mesh_region::free_region_id(get_mesh());
172  getfem::mesh_region& contact_elems = get_mesh().region(assumed_contact_elems);
173  getfem::mesh_region& boundary_elems = get_mesh().region(BOUNDARY_ELEMENTS);
174  std::shared_ptr<getfem::mr_visitor> i;
175  getfem::mesh_region outer_faces;
176  outer_faces.clear();
177  getfem::outer_faces_of_mesh(get_mesh(), outer_faces);
178 
179  if (assumed_contact_region==size_type(-1)){ //all faces will be searched for contact
180  i = std::make_shared<getfem::mr_visitor>(outer_faces);
181  }
182  else // only specified faces will be searched
183  {
184  getfem::mesh_region& assumed_region = get_mesh().
185  region(assumed_contact_region);
186  i = std::make_shared<getfem::mr_visitor>(assumed_region);
187  }
188 
189  for (; !i->finished(); ++(*i)){
190  getfem::size_type new_elem =
191  get_mesh().add_convex(
193  get_mesh().trans_of_convex(i->cv())),
194  get_mesh().ind_points_of_face_of_convex(
195  i->cv(), i->f()).begin());
196 
197 
198  border_faces[new_elem] = face_type(*i);
199  contact_elems.add(new_elem);
200  boundary_elems.add(new_elem);
201  }
202 
203  GMM_ASSERT1(get_mesh().region(BOUNDARY_ELEMENTS).index().card()!=0,
204  "No boundary elements added !!!");
205 
206  GMM_ASSERT1(get_mesh().region(assumed_contact_elems).index().card()!=0,
207  "No contact elements added !!!");
208 
209  //creating Lagrange multiplier
210  std::string mult_name = md.new_name("mult_on_"+get_var_name()+
211  "_and_"+scb.get_var_name());
212  const mesh_fem &mf_mult =
213  getfem::classical_mesh_fem(get_mesh(),
214  bgeot::dim_type(mult_mf_order), bgeot::dim_type(1));
215  md.add_multiplier(mult_name,mf_mult,get_var_name());
216 
217  //adding variable to store level set, projected from the slave
218  const mesh_fem& mf_ls =
219  getfem::classical_mesh_fem(get_mesh(),bgeot::dim_type(mult_mf_order+1));
220  plain_vector LS(mf_ls.nb_dof());
221  md.add_initialized_fem_data("ls_on"+get_var_name()+
222  "_from_"+scb.get_var_name(),mf_ls,LS);
223 
224  //register contact pair
225  contact_table[scb.get_var_name()] =
226  std::make_shared<contact_pair_info>(*this,scb,mult_name,assumed_contact_elems);
227 
228 }
229 
230 std::vector<level_set_contact::master_contact_body*>
231  level_set_contact::master_contact_body::masters;
232 
233 
235 {
236  if (masters.size()==0) GMM_WARNING3("Running contact detection, while no \
237  contact bodies are registered");
238  bool contact_surfaces_changed = false;
239  for(size_type i=0;i<masters.size();i++)
240  if (masters[i]->master_contact_changed())
241  contact_surfaces_changed=true;
242 
243  return contact_surfaces_changed;
244 }
245 
247 {
248  if (masters.size()==0) GMM_WARNING3("Clearing contact lists, while no \
249  contact bodies are registered");
250  for(size_type i=0;i<masters.size();i++)
251  masters[i]->clear_contact_history();
252 }
253 
255 {
256  std::map<std::string, std::shared_ptr<contact_pair_info> >::
257  iterator it = contact_table.begin();
258  for(;it!=contact_table.end();it++)
259  it->second->clear_contact_history();
260 }
261 
263 {
264  bool contact_surfaces_changed = false;
265  std::map<std::string, std::shared_ptr<contact_pair_info> >::
266  iterator it = contact_table.begin();
267  for(;it!=contact_table.end();it++)
268  if (it->second->contact_changed())
269  contact_surfaces_changed=true;
270 
271  return contact_surfaces_changed;
272 }
273 
274 std::shared_ptr<getfem::mesh_im> level_set_contact::master_contact_body::
276 {
277 
278  std::shared_ptr<getfem::mesh_im> pmim_contact;
279 
280  pmim_contact = std::make_shared<mesh_im>(get_mesh());
281  if (mult_mim_order!=size_type(-1)){
282  pmim_contact->set_integration_method
283  (get_mesh().region(region_id).index(),
284  bgeot::dim_type(contact_mim_order()));
285  }
286  else
287  {
288  pmim_contact->set_integration_method
289  (get_mesh().region(region_id).index(), contact_int_method());
290  }
291 
292  return pmim_contact;
293 }
294 
295 
296 level_set_contact::contact_pair_update::contact_pair_update(
297  master_contact_body& _mcb,
298  slave_contact_body& _scb,
299  update_depth ud):
300 mcb(_mcb), scb(_scb)
301 
302 {
303 
304  GMM_ASSERT1(!mcb.is_mesh_deformed(),"Trying to deform \
305  already deformed Master Contact Body");
306  GMM_ASSERT1(!scb.is_mesh_deformed(),"Trying to deform \
307  already deformed Slave Contact Body");
308 
309  const model_real_plain_vector&
310  Umaster=mcb.get_model().real_variable(mcb.get_var_name());
311  // size_type dof_check = Umaster.size();
312  // size_type node_check = mcb.get_mesh().nb_points();
313  def_master = std::make_shared<getfem::temporary_mesh_deformator<>>
314  (mcb.get_mesh_fem(),Umaster);
315  mcb.is_deformed=true;
316  if (&mcb.get_mesh()!=&scb.get_mesh()){
317  // not deforming the slave if the master and the slave are the same
318  const model_real_plain_vector&
319  Uslave=scb.get_model().real_variable(scb.get_var_name());
320  def_slave = std::make_shared<getfem::temporary_mesh_deformator<>>
321  (scb.get_mesh_fem(),Uslave);
322  scb.is_deformed=true;
323  }
324  if (ud == FULL_UPDATE) mcb.update_for_slave(scb.get_var_name());
325 }
326 
327 level_set_contact::contact_pair_update::~contact_pair_update(){
328  mcb.is_deformed=false;
329  scb.is_deformed=false;
330 }
331 
332 
333 
334 level_set_contact::contact_pair_info::contact_pair_info(
335  master_contact_body& underformed_mcb,
336  slave_contact_body& underformed_scb,
337  const std::string& _mult_name,
338  size_type _GIVEN_CONTACT_REGION) :
339 
340  master_cb(underformed_mcb),
341  slave_cb(underformed_scb),
342  mult_name(_mult_name),
343  GIVEN_CONTACT_REGION(_GIVEN_CONTACT_REGION),
344 
345  ACTIVE_CONTACT_REGION(getfem::mesh_region::free_region_id(master_cb.get_mesh())),
346  members_are_computed(false),
347  init_cont_detect_done(false)
348 
349 {
350  //input check (if mult_name is incorrect, exception will be generated)
351  // const mesh_fem& mf_mult=
352  // master_cb.get_model().mesh_fem_of_variable(mult_name);
353  GMM_ASSERT1(master_cb.get_mesh().
354  region(GIVEN_CONTACT_REGION).index().card()!=0,
355  "provided contact region for contact_pair_info class is empty!!!");
356 }
357 
359 {
360  old_contact_elm_list.clear();
361  pre_old_ct_list.clear();
362 }
363 
365 {
366  //deform master and slave meshes
368  temp_mesh_deformation(master_cb,slave_cb,DEFORM_MESHES_ONLY);
369 
370  // create mf on the boundary of the master (copy from the master)
371  mesh_fem mf_scalar(master_cb.get_mesh());
372  for(size_type i=0;i<mf_scalar.linked_mesh().nb_convex();i++)
373  mf_scalar.set_finite_element(i,master_cb.get_mesh_fem().fem_of_element(i));
374 
375  mf_scalar.set_qdim(1);
376  getfem::partial_mesh_fem mf_boundary(mf_scalar);
377  mf_boundary.adapt(mf_scalar.dof_on_region(GIVEN_CONTACT_REGION));
378 
379  // interpolate level set from the slave to the master
380  model_real_plain_vector LS_on_contour(mf_boundary.nb_dof());
381  getfem::interpolation(slave_cb.get_ls_mesh_fem(), mf_boundary,
382  slave_cb.ls_values(), LS_on_contour);
383  model_real_plain_vector LS(mf_scalar.nb_dof());
384  mf_boundary.extend_vector(LS_on_contour,LS);
385  gmm::copy(LS,master_cb.get_model().set_real_variable
386  ("ls_on"+master_cb.get_var_name()+"_from_"+slave_cb.get_var_name()));
387 
388  // interpolate the gradient of the level set onto the master surfaces
389  // (this is to obtain the normal direction of the level set)
390  mesh_fem mf_gradient_ls(slave_cb.get_mesh());
391  mf_gradient_ls.set_classical_discontinuous_finite_element(bgeot::dim_type(master_cb.mult_mf_order));
392  mesh_fem mf_gradient_ls_vect(mf_gradient_ls);
393  mf_gradient_ls_vect.set_qdim(slave_cb.get_mesh().dim());
394  plain_vector GradLS(mf_gradient_ls.nb_dof()*slave_cb.get_mesh().dim());
395  getfem::compute_gradient(slave_cb.get_ls_mesh_fem(), mf_gradient_ls, slave_cb.ls_values(), GradLS);
396  getfem::partial_mesh_fem mf_boundary_vect(master_cb.get_mesh_fem());
397  mf_boundary_vect.adapt(master_cb.get_mesh_fem().dof_on_region(GIVEN_CONTACT_REGION));
398  plain_vector GradLS_boundary(mf_boundary.nb_dof()*slave_cb.get_mesh().dim());
399  getfem::interpolation(mf_gradient_ls_vect,mf_boundary_vect,GradLS,GradLS_boundary);
400 
401  size_type dim = slave_cb.get_mesh().dim();
402  const scalar_type TINY = 1e-15;
403  for(size_type i=0;i<mf_boundary.nb_dof();i++){ //normalizing the projected ls field
404  bgeot::base_node ls_node(dim);
405  for(size_type j=0;j<dim;j++) ls_node[j]=GradLS_boundary[dim*i+j];
406  ls_node/= (gmm::vect_norm2(ls_node)+TINY);
407  for(size_type j=0;j<dim;j++) GradLS_boundary[dim*i+j]=ls_node[j];
408  }
409  plain_vector normLS_master(master_cb.get_mesh_fem().nb_dof());
410  mf_boundary_vect.extend_vector(GradLS_boundary,normLS_master);
411 
412 
413  // extend Lagrange Multiplier onto the whole boundary of the master
414  const mesh_fem& mf_mult =
415  master_cb.get_model().mesh_fem_of_variable(mult_name);
416  const model_real_plain_vector& lambda =
417  master_cb.get_model().real_variable(mult_name);
418  model_real_plain_vector lambda_full(mf_mult.nb_basic_dof());
419  if (lambda.size()>0) mf_mult.extend_vector(lambda,lambda_full);
420  // update contact region
421  dal::bit_vector cc = master_cb.get_mesh().
422  region(GIVEN_CONTACT_REGION).index();
423  master_cb.get_mesh().region(ACTIVE_CONTACT_REGION).clear();
424  master_cb.get_mesh().region(ACTIVE_CONTACT_REGION).add(cc);
426  for (o << cc; o != bgeot::size_type(-1); o << cc) {
427  getfem::mesh_fem::ind_dof_ct dof_ls = mf_scalar.ind_basic_dof_of_element(o);
428  getfem::mesh_fem::ind_dof_ct dof_lm = mf_mult.ind_basic_dof_of_element(o);
429 
430  //measure the angle between ls countour and the master face
431  face_type face = master_cb.ext_face_of_elem(o);
432  bgeot::base_node unit_face_normal =
433  master_cb.get_mesh().normal_of_face_of_convex(face.cv,face.f);
434  unit_face_normal/=gmm::vect_norm2(unit_face_normal);
435  scalar_type cosine_alpha = 0;
436  for (size_type j = 0; j < dof_ls.size(); j++){
437  bgeot::base_node ls_grad_node(dim);
438  for(size_type k=0; k<dim; k++)
439  ls_grad_node[k]=normLS_master[dim*dof_ls[j]+k];
440  cosine_alpha += gmm::vect_sp(ls_grad_node,unit_face_normal);
441  }
442  cosine_alpha /= scalar_type(dof_ls.size());
443  scalar_type alpha = acos(cosine_alpha)*360/(2*M_PI); // now this is average angle
444  // between master surface and ls zero contour
445 
446  scalar_type LS_extreeme = LS[dof_ls[0]];
447  if (master_cb.integration==master_contact_body::PER_ELEMENT)
448  for (size_type j = 0; j < dof_ls.size(); j++)
449  LS_extreeme=std::min(LS[dof_ls[j]],LS_extreeme);
450  else
451  for (size_type j = 0; j < dof_ls.size(); j++)
452  LS_extreeme=std::max(LS[dof_ls[j]],LS_extreeme);
453 
454  scalar_type LM_sum = 0;
455  for (size_type j = 0; j < dof_lm.size(); j++)
456  LM_sum+=lambda_full[dof_lm[j]];
457 
458  const scalar_type TINY_2 = 1e-9;
459 
460  if (LS_extreeme+LM_sum < TINY_2 || alpha > master_cb.max_contact_angle)
461  master_cb.get_mesh().region(ACTIVE_CONTACT_REGION).sup(o);
462  }
463 
464  // check whether contact areas have changed
465  bool contact_surface_changed;
466  const dal::bit_vector& current_contact_elm_list =
467  master_cb.get_mesh().region(ACTIVE_CONTACT_REGION).index();
468  GMM_TRACE2("Current contact elements: "<< current_contact_elm_list);
469  GMM_TRACE2("Old contact elements: "<< old_contact_elm_list);
470  GMM_TRACE2("Pre-old contact elements: "<< pre_old_ct_list);
471 
472  if (current_contact_elm_list == old_contact_elm_list &&
473  current_contact_elm_list.card() == old_contact_elm_list.card()) {
474  contact_surface_changed = false;
475  GMM_TRACE2(" the contact area has not changed");
476  } else {
477  if (current_contact_elm_list == pre_old_ct_list &&
478  current_contact_elm_list.card() == pre_old_ct_list.card()) {
479  contact_surface_changed = false;
480  GMM_TRACE2(" the contact area has changed, but cycling, \
481  so exiting active set search");
482  } else {
483  contact_surface_changed = true;
484  GMM_TRACE2(" the contact area has changed");
485  pre_old_ct_list = old_contact_elm_list;
486  old_contact_elm_list = current_contact_elm_list;
487  }
488  }
489 
490  init_cont_detect_done = true;
491  force_update();
492 
493 
494  //building integration method
495  pmim_contact = master_cb.build_mesh_im_on_boundary(ACTIVE_CONTACT_REGION);
496  n_integrated_elems = pmim_contact->convex_index().card();
497  GMM_ASSERT1(n_integrated_elems==current_contact_elm_list.card(),
498  "Failure in integration method: The number of integrated elements "
499  "does not correspond to the number of contact elements");
500 
501  return contact_surface_changed;
502 
503 }
504 
505 
506 
508 {
509  GMM_ASSERT1(master_cb.is_mesh_deformed(),"Master mesh is not deformed, \
510  cannot calucalte contact info");
511 
512  GMM_ASSERT1(slave_cb.is_mesh_deformed(),"Slave mesh is not deformed, \
513  cannot calucalte contact info");
514 
515  GMM_ASSERT1(master_cb.get_mesh().region(ACTIVE_CONTACT_REGION).index().card()>0,
516  "Internal error: Contact area is empty");
517 
518  //pinterpolated_fem for level set
519  pinterpolated_fem = std::make_shared<mesh_fem>(master_cb.get_mesh());
520 
521  pinterpolated_fem_U = std::shared_ptr<mesh_fem>();
522 
523  if (ifem_srf.get()) getfem::del_interpolated_fem(ifem_srf);
524 
525  ifem_srf = getfem::new_interpolated_fem(slave_cb.get_ls_mesh_fem(),
526  *pmim_contact, 0, dal::bit_vector(), false);
527  pinterpolated_fem->set_finite_element(
528  master_cb.get_mesh().region(ACTIVE_CONTACT_REGION).index(),ifem_srf);
529  pinterpolated_fem->set_qdim(1);
530 
531 
532  //pinterpolated_fem_U
533  pinterpolated_fem_U = std::make_shared<mesh_fem>(master_cb.get_mesh());
534  pinterpolated_fem_U->set_finite_element(master_cb.get_mesh().
535  region(ACTIVE_CONTACT_REGION).index(),ifem_srf);
536  pinterpolated_fem_U->set_qdim(master_cb.get_mesh().dim());
537 
538  //slave_ls_dofs
539  std::vector<size_type> index(pinterpolated_fem->nb_dof());
540  dal::bit_vector cc =
541  master_cb.get_mesh().region(ACTIVE_CONTACT_REGION).index();
542  for (dal::bv_visitor icv(cc); !icv.finished(); ++icv){
543  for (size_type j = 0; j < pinterpolated_fem->nb_basic_dof_of_element(icv);
544  ++j)
545  {index[pinterpolated_fem->ind_basic_dof_of_element(icv)[j]]
546  = ifem_srf->index_of_global_dof(icv, j);}
547  }
548 
549  slave_ls_dofs = std::make_shared<gmm::unsorted_sub_index>(index);
550 
551  //slave_U_dofs
552  std::vector<size_type> indexU(pinterpolated_fem_U->nb_dof());
553  size_type dim = pinterpolated_fem_U->get_qdim();
554  for(size_type d=0;d<dim;d++)
555  for(size_type i=0;i<pinterpolated_fem->nb_dof();i++)
556  indexU[dim*i+d] = dim*index[i]+d;
557  slave_U_dofs = std::make_shared<gmm::unsorted_sub_index>(indexU);
558 
559  members_are_computed=true;
560 }
561 
562 
563 
565  model& md,
566  master_contact_body& mcb,
567  slave_contact_body& scb,
568  size_type rg) {
569  //level set contact class
570  getfem::pbrick pbr = std::make_shared<level_set_contact_brick>(md,mcb,scb,rg);
571 
572  //term description
573  const std::string& name_Um = mcb.get_var_name();
574  const std::string& name_Us = scb.get_var_name();
575  const std::string& name_LM = mcb.get_pair_info(name_Us).get_mult_name();
576  model::termlist terms;
577  terms.push_back(model::term_description(name_Um,name_Um,false));
578  terms.push_back(model::term_description(name_Us,name_Us,false));
579  terms.push_back(model::term_description(name_LM,name_LM,false));
580  terms.push_back(model::term_description(name_Um,name_Us,true));
581  terms.push_back(model::term_description(name_Um,name_LM,true));
582  terms.push_back(model::term_description(name_Us,name_LM,true));
583 
584  //variables
585  model::varnamelist variables;
586  variables.push_back(name_Um);
587  variables.push_back(name_Us);
588  variables.push_back(name_LM);
589 
590  //empty data and integration method lists
591  //(we don't have any properties or initial data,
592  //while integration methods are created per iteration)
593  model::varnamelist datalist;
594  model::mimlist mimlist;
595 
596  //register the brick with the model and return its number
597  return md.add_brick(pbr,variables,datalist,terms,mimlist,rg);
598 }
599 
600 
601 level_set_contact::level_set_contact_brick::
602  level_set_contact_brick(
603  model& _md,
604  master_contact_body& _mcb,
605  slave_contact_body& _scb,
606  size_type rg) :
607 md(_md),mcb(_mcb),scb(_scb), given_contact_id(rg)
608 {
609  GMM_ASSERT1(&md == &mcb.get_model(),
610  "Master body is defined on a different model then the input");
611 
612  //register master/slave pair
613  mcb.add_slave(scb,given_contact_id);
614 
615  //Reduce computation to own MPI region
616  contact_region_id = mcb.get_pair_info(scb.get_var_name()).contact_region();
617  getfem::mesh_region& contact_region_ = mcb.get_mesh().region(contact_region_id);
618  mcb.get_mesh().intersect_with_mpi_region(contact_region_);
619  contact_region_id = contact_region_.id(); //probably not needed, but still
620 
621 
622  set_flags("Level set contact brick",
623  false /* is linear*/,
624  true /* is symmetric */,
625  false /* is coercive */,
626  true /* is real */,
627  false /* is complex */);
628 
629 }
630 
632  const model &mdd, size_type /* ib */,
633  const model::varnamelist &vl,
634  const model::varnamelist &/* dl */,
635  const model::mimlist &/* mims */,
636  model::real_matlist &matl,
637  model::real_veclist &vecl,
638  model::real_veclist &,
639  size_type region,
640  build_version version) const {
641  //input check
642  GMM_ASSERT1(vl.size() == 3,
643  "Level set contact brick needs three variables");
644  GMM_ASSERT1(matl.size() == 6,
645  "Level set contact brick needs six matrices");
646  GMM_ASSERT1(vecl.size() == 6,
647  "Level set contact brick assembles size RHSs");
648  GMM_ASSERT1(region==given_contact_id,
649  "Assumed contact region has changed!!! \
650  This implementation does not handle this \
651  for efficiency reasons!!");
652 
653  if (version & model::BUILD_MATRIX )
654  for(size_type i=0;i<matl.size();i++) gmm::clear(matl[i]);
655  if (version & model::BUILD_RHS )
656  for(size_type i=0;i<vecl.size();i++) gmm::clear(vecl[i]);
657 
658  const getfem::mesh_region& active_contact_region =
659  mcb.get_mesh().region(contact_region_id);
660  if (active_contact_region.index().card()==0) return; //no contact -> no contact assembly
661 
662  //deform the meshes, update contact info
663  contact_pair_update cp_update(mcb,scb,FULL_UPDATE);
664 
665  //extract DOF vectors
666  const plain_vector &LM = mdd.real_variable(vl[2]);
667 
668  //Assemble Tangent Matrix
669  if (version & model::BUILD_MATRIX ) {
670  GMM_TRACE2("Level set contact brick stiffness matrix assembly on "
671  << mcb.get_pair_info(scb.get_var_name()).num_of_integr_elems()
672  << " elements");
673  asm_level_set_contact_tangent_matrix(matl,mcb,scb,LM,active_contact_region);
674  }
675 
676  //Assemble RHS
677  if (version & model::BUILD_RHS ) {
678  GMM_TRACE2("Level set contact brick RHS assembly on "
679  << mcb.get_pair_info(scb.get_var_name()).num_of_integr_elems()
680  << " elements");
681  asm_level_set_contact_rhs(vecl,mcb,scb,LM,active_contact_region);
682  for(size_type i=0;i<vecl.size();i++)
683  gmm::scale(vecl[i], scalar_type(-1));
684  }
685 }
686 
687 
688 void level_set_contact::NormalTerm::compute(
690  bgeot::base_tensor &t)
691 {
692  size_type cv = ctx.convex_num();
693  size_type cv_volume = mcb.ext_face_of_elem(cv).cv;
694  bgeot::short_type f_volume = mcb.ext_face_of_elem(cv).f;
695  bgeot::base_node un = mcb.get_mesh().normal_of_face_of_convex
696  (cv_volume, bgeot::short_type(f_volume), ctx.xref());
697  un /= gmm::vect_norm2(un);
698 
699  if (version == 1) {
700  for (size_type i = 0; i < dim; i++) t[i] = un[i];
701  } else {
702  for (size_type i = 0; i < dim; i++)
703  for (size_type j = 0; j < dim; j++)
704  if (i == j) t(i, j) = 1.0 - un[i] * un[j];
705  else t(i, j) =-un[i] * un[j];
706  }
707 }
708 
709 
710 level_set_contact::HFunction::HFunction(
711  const mesh_fem &lsmf_,
712  const plain_vector &LS_U_,
713  scalar_type epsilon,
714  scalar_type small_h_):
715 
716 lsmf(lsmf_),
717  LS_U(LS_U_),
718  m_Epsilon(epsilon),
719  small_h(small_h_),
720  sizes_(1)
721 {sizes_[0]=1;}
722 
723 const bgeot::multi_index& level_set_contact::HFunction::
724  sizes(size_type) const { return sizes_;}
725 
726 void level_set_contact::HFunction::
727 prepare(getfem::fem_interpolation_context& /*ctx*/, size_type /*nl_part*/) {}
728 
729 void level_set_contact::HFunction::compute(getfem::fem_interpolation_context& ctx,
730  bgeot::base_tensor &t)
731 {
732  size_type cv = ctx.convex_num();
733  plain_vector U;
734  slice_vector_on_basic_dof_of_element(lsmf, LS_U, cv, U);
735  // plain_vector U(lsmf.nb_basic_dof_of_element(cv));
736  // gmm::copy(gmm::sub_vector(LS_U,gmm::sub_index(lsmf.ind_basic_dof_of_element(cv))),U);
737  plain_vector ls_interpolated(1);
738  ctx.pf()->interpolation(ctx,U,ls_interpolated,1);
739  t[0] = hRegularized(ls_interpolated[0],m_Epsilon,small_h);
740 }
741 
742 bgeot::scalar_type level_set_contact::HFunction::
743  hRegularized(scalar_type f, scalar_type epsilon, scalar_type small_h_)
744 {
745  if (f>epsilon) return 1.0;
746  if (f<(-epsilon)) return small_h_;
747  return 0.5+0.125*(9.0*f/(epsilon)-5.0*pow(f/(epsilon),scalar_type(3)));
748 }
749 
750 
751 level_set_contact::Unity::Unity(const mesh_fem &mf_):mf(mf_),sizes_(1)
752 {sizes_[0]=1;}
753 const bgeot::multi_index& level_set_contact::Unity::sizes(size_type) const {return sizes_;}
754 void level_set_contact::Unity::
755 prepare(getfem::fem_interpolation_context& /*ctx*/, size_type /*nl_part*/) {}
756 void level_set_contact::Unity::
757 compute(getfem::fem_interpolation_context& /*ctx*/, bgeot::base_tensor &t){t[0]=1.0;}
758 
759 
760 void level_set_contact::
761  solve_with_contact(
762  SOLVE_FUNCTION sf,
763  getfem::model& md,
764  gmm::iteration& it_newton,
765  gmm::iteration& it_staggered,
766  const std::string& lsolver_name,
767  getfem::abstract_newton_line_search &ls)
768 {
769  bool active_set_converged = false;
770  it_staggered.set_iteration(0);
772 
773  do {
774  active_set_converged = !master_contact_body::any_contact_change();
775  it_newton.set_iteration(0);
776  getfem::rmodel_plsolver_type plsolver=getfem::select_linear_solver<sparse_matrix,plain_vector>(md,lsolver_name);
777  (*sf)(md,it_newton,plsolver,ls);
778  GMM_TRACE2("Newton converged? - "<<it_newton.converged());
779  GMM_TRACE2("active set converged? - "<<active_set_converged);
780  GMM_ASSERT1(it_newton.converged(),"Newton method did not converge");
781  it_staggered++;
782 
783  } while(!active_set_converged &&
784  !it_staggered.finished(it_staggered.get_resmax()+1.0));
785 
786  if (active_set_converged && it_newton.converged()) it_staggered.enforce_converged();
787 }
788 
791  bgeot::pgeometric_trans pelem_trans)
792 {
793  std::string name = bgeot::name_of_geometric_trans(pelem_trans);
794  std::stringstream fname;
795  fname<<name.substr(0,5);
796  GMM_ASSERT1((fname.str()=="GT_QK" || fname.str()=="GT_PK"),
797  "Cannot handle other transformations but QK or PK,\
798  Sorry, to be implemented" );
799  std::stringstream str1(name.substr(6,1));
800  size_type dim;
801  str1>>dim;
802 
803  std::istringstream str2(name.substr(8,1));
804  size_type order;
805  str2>>order;
806 
807  fname<<"("<<dim-1<<","<<order<<")";
808  return bgeot::geometric_trans_descriptor(fname.str());
809 }
const base_node & xref() const
coordinates of the current point, in the reference convex.
structure passed as the argument of fem interpolation functions.
Definition: getfem_fem.h:749
Describe a finite element method linked to a mesh.
virtual ind_dof_ct ind_basic_dof_of_element(size_type cv) const
Give an array of the dof numbers a of convex.
void set_classical_discontinuous_finite_element(size_type cv, dim_type fem_degree, scalar_type alpha=0, bool complete=false)
Similar to set_classical_finite_element, but uses discontinuous lagrange elements.
virtual size_type nb_dof() const
Return the total number of degrees of freedom.
const mesh & linked_mesh() const
Return a reference to the underlying mesh.
void set_finite_element(size_type cv, pfem pf)
Set the finite element method of a convex.
virtual size_type nb_basic_dof() const
Return the total number of basic degrees of freedom (before the optional reduction).
virtual void set_qdim(dim_type q)
Change the Q dimension.
dal::bit_vector dof_on_region(const mesh_region &b) const
Get a list of dof lying on a given mesh_region.
Describe an integration method linked to a mesh.
structure used to hold a set of convexes and/or convex faces.
const dal::bit_vector & index() const
Index of the region convexes, or the convexes from the partition on the current thread.
static size_type free_region_id(const getfem::mesh &m)
Extract the next region number that does not yet exists in the mesh.
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.
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 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...
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.
a subclass of mesh_fem which allows to eliminate a number of dof of the original mesh_fem.
void adapt(const dal::bit_vector &kept_dof, const dal::bit_vector &rejected_elt=dal::bit_vector())
build the mesh_fem keeping only the dof of the original mesh_fem which are listed in kept_dof.
size_type nb_dof(void) const
Return the total number of degrees of freedom.
The Iteration object calculates whether the solution has reached the desired accuracy,...
Definition: gmm_iter.h:52
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
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,...
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,...
bool master_contact_changed(void)
contact detection for all slaves
static bool any_contact_change()
contact detection for all masters/slave couples
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.
face_type ext_face_of_elem(size_type cv) const
gives a face, corresponding to newly created boundary element
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.
Compute the gradient of a field on a getfem::mesh_fem.
FEM which interpolates a mesh_fem on a different mesh.
Define level-sets.
Non frictional level set based large sliding contact; for details see: A. Andreykiv et al....
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 ...
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.
a subclass of mesh_im which is conformal to a number of level sets.
Keep informations about a mesh crossed by level-sets.
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
size_type convex_num() const
get the current convex number
Definition: getfem_fem.cc:52
const pfem pf() const
get the current FEM descriptor
Definition: getfem_fem.h:781
gmm::uint16_type short_type
used as the common short type integer in the library
Definition: bgeot_config.h:72
std::string name_of_geometric_trans(pgeometric_trans p)
Get the string name of a geometric transformation.
pgeometric_trans geometric_trans_descriptor(std::string name)
Get the geometric transformation from its string name.
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
GEneric Tool for Finite Element Methods.
void compute_gradient(const mesh_fem &mf, const mesh_fem &mf_target, const VECT1 &UU, VECT2 &VV)
Compute the gradient of a field on a getfem::mesh_fem.
void del_interpolated_fem(const pfem &pf)
release an interpolated fem
pfem new_interpolated_fem(const mesh_fem &mef, const mesh_im &mim, pinterpolated_func pif=0, dal::bit_vector blocked_dof=dal::bit_vector(), bool store_val=true)
create a new interpolated FEM.
void interpolation(const mesh_fem &mf_source, const mesh_fem &mf_target, const VECTU &U, VECTV &V, int extrapolation=0, double EPS=1E-10, mesh_region rg_source=mesh_region::all_convexes(), mesh_region rg_target=mesh_region::all_convexes())
interpolation/extrapolation of (mf_source, U) on mf_target.
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:48
const mesh_fem & classical_mesh_fem(const mesh &mesh, dim_type degree, dim_type qdim=1, bool complete=false)
Gives the descriptor of a classical finite element method of degree K on mesh.