contact_elements.h
Go to the documentation of this file.
1 //LIC// ====================================================================
2 //LIC// This file forms part of oomph-lib, the object-oriented,
3 //LIC// multi-physics finite-element library, available
4 //LIC// at http://www.oomph-lib.org.
5 //LIC//
6 //LIC// Copyright (C) 2006-2022 Matthias Heil and Andrew Hazel
7 //LIC//
8 //LIC// This library is free software; you can redistribute it and/or
9 //LIC// modify it under the terms of the GNU Lesser General Public
10 //LIC// License as published by the Free Software Foundation; either
11 //LIC// version 2.1 of the License, or (at your option) any later version.
12 //LIC//
13 //LIC// This library is distributed in the hope that it will be useful,
14 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 //LIC// Lesser General Public License for more details.
17 //LIC//
18 //LIC// You should have received a copy of the GNU Lesser General Public
19 //LIC// License along with this library; if not, write to the Free Software
20 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 //LIC// 02110-1301 USA.
22 //LIC//
23 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
24 //LIC//
25 //LIC//====================================================================
26 // Header file for elements that enforce solid contact
27 
28 #ifndef OOMPH_CONTACT_ELEMENTS_HEADER
29 #define OOMPH_CONTACT_ELEMENTS_HEADER
30 
31 // Config header generated by autoconfig
32 #ifdef HAVE_CONFIG_H
33 #include <oomph-lib-config.h>
34 #endif
35 
36 //Standard libray headers
37 #include <cmath>
38 
39 // oomph-lib includes
40 #include "generic.h" // ../generic/Qelements.h"
41 
42 namespace oomph
43 {
44 
45 
46 //=========================================================
50 //=========================================================
51  template <unsigned DIM, unsigned NPTS_1D>
52  class PiecewiseGauss : public Gauss<DIM,NPTS_1D>
53  {
54  private:
55 
57  double Lower, Upper, Range;
58 
59  public:
60 
63  PiecewiseGauss(const double& lower, const double& upper) :
64  Lower(lower), Upper(upper)
65  {
66  //Set the range of integration
67  Range = upper - lower;
68  }
69 
72  {
73  BrokenCopy::broken_copy("PiecewiseGauss");
74  }
75 
77  virtual unsigned nweight() const
78  {
79  return 3*Gauss<DIM,NPTS_1D>::nweight();
80  }
81 
83  double knot(const unsigned &i, const unsigned &j) const
84  {
86  {
87  double range=0.25*Range;
88  double lower=Lower+0.0;
89  //double upper=Lower+0.25*Range;
90  unsigned ii=i;
91  return (lower+(0.5*(1.0+Gauss<DIM,NPTS_1D>::knot(ii,j))*range));
92  }
93  else if (i<2*Gauss<DIM,NPTS_1D>::nweight())
94  {
95  double range=0.5*Range;
96  double lower=Lower+0.25*Range;
97  //double upper=Lower+0.75*Range;
98  unsigned ii=i-Gauss<DIM,NPTS_1D>::nweight();
99  return (lower+(0.5*(1.0+Gauss<DIM,NPTS_1D>::knot(ii,j))*range));
100  }
101  else
102  {
103  double range=0.25*Range;
104  double lower=Lower+0.75*Range;
105  //double upper=Upper;
106  unsigned ii=i-2*Gauss<DIM,NPTS_1D>::nweight();
107  return (lower+(0.5*(1.0+Gauss<DIM,NPTS_1D>::knot(ii,j))*range));
108  }
109  }
110 
112  double weight(const unsigned &i) const
113  {
115  {
116  double range=0.25*Range;
117  unsigned ii=i;
118  return Gauss<DIM,NPTS_1D>::weight(ii)*
119  pow(0.5*range,static_cast<int>(DIM));
120  }
121  else if (i<2*Gauss<DIM,NPTS_1D>::nweight())
122  {
123  double range=0.5*Range;
124  unsigned ii=i-Gauss<DIM,NPTS_1D>::nweight();
125  return Gauss<DIM,NPTS_1D>::weight(ii)*
126  pow(0.5*range,static_cast<int>(DIM));
127  }
128 
129  else
130  {
131  double range=0.25*Range;
132  unsigned ii=i-2*Gauss<DIM,NPTS_1D>::nweight();
133  return Gauss<DIM,NPTS_1D>::weight(ii)*
134  pow(0.5*range,static_cast<int>(DIM));
135  }
136  }
137 
138 };
139 
140 
141 
145 
146 
147 //======================================================================
151 //======================================================================
153  {
154 
155  public:
156 
159 
161  virtual ~Penetrator(){};
162 
171  virtual void penetration(const Vector<double>& x,
172  const Vector<double>& n,
173  double& d,
174  bool& intersection) const = 0;
175 
177  virtual void output(std::ostream &outfile, const unsigned& nplot) const =0;
178 
182  {
183  throw OomphLibError(
184  "This is a broken virtual function. Please implement/overload. ",
187  }
188 
196  {
198  return dummy;
199  }
200 
205  virtual void surface_coordinate(const Vector<double>& x,
206  Vector<double>& zeta) const
207  {
208  throw OomphLibError(
209  "This is a broken virtual function. Please implement/overload. ",
212  }
213 
214 
215  };
216 
217 
218 //======================================================================
220 //======================================================================
221 class HeatedPenetrator : public virtual Penetrator
222  {
223 
224  public:
225 
228 
230  virtual ~HeatedPenetrator(){};
231 
235  virtual double temperature(const Vector<double>& x) const=0;
236 
237  };
238 
239 
243 
244 
245 //======================================================================
247 //======================================================================
248 class CircularPenetrator : public virtual Penetrator
249  {
250 
251  public:
252 
254  CircularPenetrator(Vector<double>* r_c_pt, const double& r)
255  {
256  Centre_pt=r_c_pt;
257  Radius=r;
258 
259  // Back up original centre
260  unsigned n=r_c_pt->size();
261  Orig_centre.resize(n);
262  for (unsigned i=0;i<n;i++)
263  {
264  Orig_centre[i]=(*r_c_pt)[i];
265  }
266  }
267 
270 
273  const Vector<double>& n,
274  double& d,
275  bool& intersection)const
276  {
277 
278  // Vector from potential contact point to centre of penetrator
279  Vector<double> l(2);
280  l[0]=(*Centre_pt)[0]-x[0];
281  l[1]=(*Centre_pt)[1]-x[1];
282 
283  // Distance from potential contact point to centre of penetrator
284  double ll=sqrt(l[0]*l[0]+l[1]*l[1]);
285 
286  // Projection of vector from potential contact point to centre of penetrator
287  // onto outer unit normal on potential contact point
288  double project=n[0]*l[0]+n[1]*l[1];
289  double project_squared=project*project;
290 
291  // Final term in square root
292  double b_squared=ll*ll-Radius*Radius;
293 
294  // Is square root negative? In this case we have no intersection
295  if (project_squared<b_squared)
296  {
297  d = 0.0;
298  intersection = false;
299  //return -10*std::numeric_limits<double>::min();
300  }
301  else
302  {
303  double sqr=sqrt(project_squared-b_squared);
304  d = -std::min(project-sqr,project+sqr);
305  intersection = true;
306  }
307  }
308 
309 
310 
312  void output(std::ostream &outfile, const unsigned& nplot) const
313  {
314  for (unsigned j=0;j<nplot;j++)
315  {
316  double phi=2.0*MathematicalConstants::Pi*double(j)/double(nplot-1);
317  outfile << (*Centre_pt)[0]+Radius*cos(phi) << " "
318  << (*Centre_pt)[1]+Radius*sin(phi)
319  << std::endl;
320  }
321  }
322 
323 
326  Vector<double>& r) const
327  {
328  double phi=zeta[0];
329  r[0]=(*Centre_pt)[0]+Radius*cos(phi);
330  r[1]=(*Centre_pt)[1]+Radius*sin(phi);
331  }
332 
333 
334 
339  {
340  zeta[0]=atan2(x[1]-(*Centre_pt)[1],x[0]-(*Centre_pt)[0]);
341  }
342 
343 
346  {
347  unsigned n=Orig_centre.size();
348  Vector<double> displ(n);
349  for (unsigned i=0;i<n;i++)
350  {
351  displ[i]=(*Centre_pt)[i]-Orig_centre[i];
352  }
353  return displ;
354  }
355 
356 
359  void set_original_centre(const Vector<double>& orig_centre)
360  {
361  Orig_centre=orig_centre;
362  }
363 
364 
365  protected:
366 
370 
371 
375 
377  double Radius;
378 
379  };
380 
381 
385 
386 
387 //======================================================================
389 //======================================================================
391  public virtual CircularPenetrator
392  {
393 
394  public:
395 
397  HeatedCircularPenetrator(Vector<double>* r_c_pt, const double& r) :
398  CircularPenetrator(r_c_pt,r) {}
399 
402 
403 
408  double temperature(const Vector<double>& x) const
409  {
410  double phi=atan2(x[1]-(*Centre_pt)[1],x[0]-(*Centre_pt)[0]);
411  return cos(phi-0.5*MathematicalConstants::Pi);
412  }
413 
414  };
415 
416 
417 
421 
422 
423 
424 //====================================================================
426 //====================================================================
427 namespace PolygonHelper
428 {
429 
433  const Vector<Vector<double> >& polygon_vertex)
434  {
435 
436  // Total number of vertices
437  unsigned nvertex=polygon_vertex.size();
438 
439 // faire: obviously polygons should ALWAYS be designed to be closed, so
440 // such testing should only need to be done once upon implementation of
441 // the polygon, not everytime we want to check number of intersections
442 // hierher #ifdef PARANOID
443 
444  // Make sure the polygon closes exactly:
445  double d0=polygon_vertex[nvertex-1][0]-polygon_vertex[0][0];
446  double d1=polygon_vertex[nvertex-1][1]-polygon_vertex[0][1];
447  if (sqrt(d0*d0+d1*d1)>0.0)
448  {
449  std::stringstream junk;
450  junk << "First and last point of polygon don't coincide!\n"
451  << "First point at: "
452  << polygon_vertex[0][0] << " "
453  << polygon_vertex[0][1] << "\n"
454  << "Last point at: "
455  << polygon_vertex[nvertex-1][0] << " "
456  << polygon_vertex[nvertex-1][1] << "\n";
457  throw OomphLibError(
458  junk.str(),
461  }
462 
463 // #endif
464 
465  // Counter for number of intersections
466  unsigned intersect_counter=0;
467 
468  //Get first vertex
469  Vector<double> p1=polygon_vertex[0];
470  for (unsigned i=1;i<=nvertex;i++)
471  {
472  // Get second vertex by wrap-around
473  Vector<double> p2 = polygon_vertex[i%nvertex];
474 
475  if (point[1] > std::min(p1[1],p2[1]))
476  {
477  if (point[1] <= std::max(p1[1],p2[1]))
478  {
479  if (point[0] <= std::max(p1[0],p2[0]))
480  {
481  if (p1[1] != p2[1])
482  {
483  double xintersect =
484  (point[1]-p1[1])*(p2[0]-p1[0])/
485  (p2[1]-p1[1])+p1[0];
486  if ( (p1[0] == p2[0]) ||
487  (point[0] <= xintersect) )
488  {
489  intersect_counter++;
490  }
491  }
492  }
493  }
494  }
495  p1 = p2;
496  }
497 
498  // Even number of intersections: outside
499  if (intersect_counter%2==0)
500  {
501  return false;
502  }
503  return true;
504  }
505 
506 
507 }
508 
509 
513 
514 //======================================================================
516 //======================================================================
518 {
519 
520  public:
521  //Constructor null pointer for traction
525  {}
526 
527 
530 
532  virtual void resulting_contact_force(Vector<double> &contact_force)=0;
533 
534  //typedef for traction function pointer, passed in from driver code
535  typedef void (*TractionFctPt)(const double& t,
536  const Vector<double>& x,
537  Vector<double>& p);
538 
539  //Refer to this in the residuals, instead of worrying about pointers
540  //and nullity
542  Vector<double>& p)
543  {
544  //p will be same size as x as tractions are same dim
545  unsigned n = x.size();
546  if (Traction_fct_pt==0)
547  {
548  p.assign(n,0.0);
549  }
550  else
551  {
552  // Get time from timestepper of first node
553  double time=node_pt(0)->time_stepper_pt()->time_pt()->time();
554 
555  (*Traction_fct_pt)(time,x,p);
556  }
557  }
558 
562  {
564  {
565  return true;
566  }
567  else
568  {
570  }
571  }
572 
573 
577  {
579  {
580  return true;
581  }
582  else
583  {
585  }
586  }
587 
588 
592  {
594  {
595  return true;
596  }
597  else
598  {
600  }
601  }
602 
607 
610  {return Use_isoparametric_flag_pt;}
614  {return Use_isoparametric_flag_pt;}
615 
623 
631 
632 
633  protected:
634 
636  enum{Nodal_data,
639 
640  //create an instance of a traction pointer
642 
643 
646 
649 
652 };
653 
654 
658 
659 
660 
661 //======================================================================
669 //======================================================================
670 template <class ELEMENT>
671 class SurfaceContactElementBase : public virtual FaceGeometry<ELEMENT>,
672  //public virtual SolidFaceElement,
673  public virtual FaceElement,
674  public virtual TemplateFreeContactElementBase
675  {
676 
677  public:
678 
682  const int &face_index,
683  const unsigned &id=0,
684  const bool& called_from_refineable_constructor=
685  false) :
686  FaceGeometry<ELEMENT>(), FaceElement()
687  {
688 
689  // By default we only to proper non-penetration (without "stick", i.e.
690  // we don't allow negative contact pressures)
691  Enable_stick=false;
692 
693  // Initialise pointer to penetrator
694  Penetrator_pt=0;
695 
696  //Attach the geometrical information to the element. N.B. This function
697  //also assigns nbulk_value from the required_nvalue of the bulk element
698  element_pt->build_face_element(face_index,this);
699 
700 
701 #ifdef PARANOID
702  {
703  //Check that the bulk element is not a refineable 3d element
704  if (!called_from_refineable_constructor)
705  {
706  if(element_pt->dim()==3)
707  {
708  //Is it refineable
709  RefineableElement* ref_el_pt=
710  dynamic_cast<RefineableElement*>(element_pt);
711  if(ref_el_pt!=0)
712  {
713  if (this->has_hanging_nodes())
714  {
715  throw OomphLibError(
716  "This face element will not work correctly if nodes are hanging.\nUse the refineable version instead. ",
719  }
720  }
721  }
722  }
723  }
724 #endif
725 
726  // Store the ID of the FaceElement -- this is used to distinguish
727  // it from any others
728  Contact_id=id;
729 
730  // We need one additional value for each FaceElement node:
731  // the normal traction (Lagrange multiplier) to be
732  // exerted onto the solid
733  unsigned n_nod=nnode();
734  Vector<unsigned> n_additional_values(n_nod,1);
735 
736  // Now add storage for Lagrange multipliers and set the map containing
737  // the position of the first entry of this face element's
738  // additional values.
739  add_additional_values(n_additional_values,id);
740 
741 #ifdef PARANOID
742  // Check spatial dimension
743  if (element_pt->dim()!=2)
744  {
745  //Issue a warning
746  throw OomphLibError(
747  "This element will almost certainly not work in non-2D problems, though it should be easy enough to upgrade... Volunteers?\n",
750  }
751 #endif
752 
753  // Always use piecewise Gauss -- it "over-integrates" for isoparametric formulations
754  // but is likely to be better for discontinuous basis fcts.
755  //Only implemented for 1,3 (1 is from surface of 2D bulk) (3 for quadratic elements)
756 #ifdef PARANOID
757  // Bit hacky... Only really works for three-noded 1D elements
758  if (n_nod!=3)
759  {
760  //Issue a warning
761  throw OomphLibError(
762  "Piecwise Gauss used here isn't appropriate for non-3-node elements.\n",
765  }
766 #endif
768  }
769 
770 
773 
777  {
778  Enable_stick=true;
779  }
780 
781  // final overrider
782  double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
783  {
785  }
786 
787  //Explicit overload for s_min
788  double s_min() const
789  {
791  }
792 
793  double s_max() const
794  {
796  }
797 
801  {
802  Enable_stick=false;
803  }
804 
808  {
809  return Enable_stick;
810  }
811 
812 
815  {
817  }
818 
819  // fiare: we are currently using FD, but this may be useful if that ever changes
820  // some parts of the jacobian are known a priori
821  // hierher FD the lot for now
822  // /// Fill in contribution from Jacobian
823  // void fill_in_contribution_to_jacobian(Vector<double> &residuals,
824  // DenseMatrix<double> &jacobian)
825  // {
826  // //Call the residuals
827  // fill_in_contribution_to_residuals_surface_contact(residuals);
828 
829  // //Call the generic FD jacobian calculation
830  // FaceGeometry<ELEMENT>::fill_in_jacobian_from_solid_position_by_fd(jacobian);
831 
832  // //Derivs w.r.t. to any external data (e.g. during displacement control)
833  // this->fill_in_jacobian_from_external_by_fd(residuals,jacobian);
834  // }
835 
836 
839  {
840  return Penetrator_pt;
841  }
842 
845  {
848  eq_data(Penetrator_pt->equilibrium_data());
849  unsigned n=eq_data.size();
850  Penetrator_eq_data_data_index.resize(n,-1);
851  Penetrator_eq_data_index.resize(n,-1);
852  Penetrator_eq_data_type.resize(n,-1);
853  for (unsigned i=0;i<n;i++)
854  {
855  if (eq_data[i].first!=0)
856  {
857  bool is_duplicate=false;
858  unsigned nnod=nnode();
859  for (unsigned j=0;j<nnod;j++)
860  {
861  if (eq_data[i].first==node_pt(j))
862  {
865  Penetrator_eq_data_index[i]=eq_data[i].second;
866  is_duplicate=true;
867  break;
868  }
869  if (eq_data[i].first==
870  dynamic_cast<SolidNode*>(node_pt(j))->variable_position_pt())
871  {
874  Penetrator_eq_data_index[i]=eq_data[i].second;
875  is_duplicate=true;
876  break;
877  }
878  }
879 
880  if (!is_duplicate)
881  {
884  this->add_external_data(eq_data[i].first);
885  Penetrator_eq_data_index[i]=eq_data[i].second;
886  }
887  }
888  }
889  }
890 
892  void output(FILE* file_pt)
893  {FiniteElement::output(file_pt);}
894 
896  void output(FILE* file_pt, const unsigned &n_plot)
897  {FiniteElement::output(file_pt,n_plot);}
898 
900  void output(std::ostream &outfile)
901  {
902  unsigned n_plot=5;
903  FiniteElement::output(outfile,n_plot);
904  }
905 
907  void output(std::ostream &outfile, const unsigned &n_plot)
908  {
909  FiniteElement::output(outfile,n_plot);
910  }
911 
913  void shape_p(const Vector<double>& s, Shape &psi) const
914  {
915  if (this->use_isoparametric_flag())
916  {
918  }
919  else
920  {
921  const double smin=this->s_min();
922  const double smax=this->s_max();
923  const double sl=smin+0.25*(smax-smin);
924  const double sr=smin+0.75*(smax-smin);
925  if (s[0]<=sl)
926  {
927  psi[0]=1.0;
928  psi[1]=0.0;
929  psi[2]=0.0;
930  }
931  else if (s[0]<=sr)
932  {
933  psi[0]=0.0;
934  psi[1]=1.0;
935  psi[2]=0.0;
936  }
937  else
938  {
939  psi[0]=0.0;
940  psi[1]=0.0;
941  psi[2]=1.0;
942  }
943  }
944  }
945 
948  void shape_i(const Vector<double>& s, Shape &psi) const
949  {
950  const double smin=this->s_min();
951  const double smax=this->s_max();
952  const double sl=smin+0.25*(smax-smin);
953  const double sr=smin+0.75*(smax-smin);
954  if (s[0]<=sl)
955  {
956  psi[0]=1.0;
957  psi[1]=0.0;
958  psi[2]=0.0;
959  }
960  else if (s[0]<=sr)
961  {
962  psi[0]=0.0;
963  psi[1]=1.0;
964  psi[2]=0.0;
965  }
966  else
967  {
968  psi[0]=0.0;
969  psi[1]=0.0;
970  psi[2]=1.0;
971  }
972  }
973 
974 
975  protected:
976 
981  {
982  // Initialise pressure
983  double p=0;
984 
985  //Find out how many nodes there are
986  unsigned n_node = nnode();
987 
988  //Set up memory for the shape functions
989  Shape psi(n_node);
990 
991  // Evaluate shape function
992  shape_p(s,psi);
993 
994  // Build up Lagrange multiplier (pressure)
995  for (unsigned j=0;j<n_node;j++)
996  {
997  // Cast to a boundary node
998  BoundaryNodeBase *bnod_pt =
999  dynamic_cast<BoundaryNodeBase*>(node_pt(j));
1000 
1001  // Get the index of the first nodal value associated with
1002  // this FaceElement
1003  unsigned first_index=
1005 
1006  // Pressure (Lagrange multiplier) is the first (and only) additional
1007  // value created by this face element
1008  p+=node_pt(j)->value(first_index)*psi[j];
1009  }
1010  return p;
1011  }
1012 
1018  Vector<double>& residuals)=0;
1019 
1022  const Vector<double>& n,
1023  double& d,
1024  bool& intersection) const
1025  {
1026  Penetrator_pt->penetration(x,n,d,intersection);
1027  }
1028 
1031 
1035  unsigned Contact_id;
1036 
1040 
1041 
1048 
1056 
1064 
1065 
1066 };
1067 
1068 
1072 
1073 
1074 //======================================================================
1082 //======================================================================
1083 template <class ELEMENT>
1085 public virtual SurfaceContactElementBase<ELEMENT>
1086 {
1087 
1088  public:
1089 
1093  const int &face_index,
1094  const unsigned &id=0,
1095  const bool& called_from_refineable_constructor=
1096  false) :
1097 // FaceGeometry<ELEMENT>(), FaceElement(),
1098  SurfaceContactElementBase<ELEMENT>(element_pt,
1099  face_index,
1100  id,
1101  called_from_refineable_constructor)
1102  {}
1103 
1106 
1107 
1109  void output(std::ostream &outfile)
1110  {
1111  unsigned n_plot=5;
1112  this->output(outfile,n_plot);
1113  }
1114 
1116  void output(std::ostream &outfile, const unsigned &n_plot)
1117  {
1118 
1119  unsigned n_dim = this->nodal_dimension();
1120 
1121  Vector<double> x(n_dim);
1122  Vector<double> xi(n_dim);
1123  Vector<double> s(n_dim-1);
1124  Vector<double> r_pen(n_dim);
1125  Vector<double> unit_normal(n_dim);
1126 
1127  // Tecplot header info
1128  outfile << this->tecplot_zone_string(n_plot);
1129 
1130  // Loop over plot points
1131  unsigned num_plot_points=this->nplot_points(n_plot);
1132  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
1133  {
1134  // Get local coordinates of plot point
1135  this->get_s_plot(iplot,n_plot,s);
1136 
1137  // Get Eulerian and Lagrangian coordinates and outer unit normal
1138  this->interpolated_x(s,x);
1139  this->interpolated_xi(s,xi);
1140  this->outer_unit_normal(s,unit_normal);
1141 
1142  // Get penetration
1143  double d=0.0;
1144  bool intersection = false;
1145  this->penetration(x,unit_normal,d,intersection);
1146 
1147  //Output the x,y,..
1148  for(unsigned i=0;i<n_dim;i++)
1149  {outfile << x[i] << " ";}//1,2
1150 
1151  // Penetration
1152  outfile << std::max(d,-100.0) << " ";//3
1153 
1154  // Lagrange multiplier-like pressure
1155  double p=this->get_interpolated_lagrange_p(s);
1156  outfile << p << " "; //4
1157 
1158 
1159  // Plot Lagrange multiplier like pressure
1160  outfile << -unit_normal[0]*p << " ";//5
1161  outfile << -unit_normal[1]*p << " ";//6
1162 
1163  // Plot vector from current point to boundary of penetrator
1164  double d_tmp=d;
1165  if (!intersection) d_tmp=0.0;
1166  outfile << -d_tmp*unit_normal[0] << " ";
1167  outfile << -d_tmp*unit_normal[1] << " ";
1168 
1169  // Output normal
1170  for(unsigned i=0;i<n_dim;i++)
1171  {outfile << unit_normal[i] << " ";}
1172 
1173 
1174  //Output the displacements
1175  for(unsigned i=0;i<n_dim;i++)
1176  {outfile << x[i]-xi[i] << " ";}
1177 
1178  outfile << std::endl;
1179  }
1180 
1181  // Write tecplot footer (e.g. FE connectivity lists)
1182  this->write_tecplot_zone_footer(outfile,n_plot);
1183 
1184  }
1185 
1187  void resulting_contact_force(Vector<double> &contact_force);
1188 
1189 };
1190 
1194 
1195 
1196 
1197 //=====================================================================
1199 //=====================================================================
1200 template<class ELEMENT>
1203 {
1204 
1205  // Spatial dimension of problem
1206  unsigned n_dim = this->nodal_dimension();
1207 
1208  // Contribution to contact force
1209  Vector<double> contact_force(n_dim,0.0);
1210 
1211  // Create vector of local residuals (start assembling contributions
1212  // from zero -- necessary so we can over-write pseudo-hijacked
1213  // contributions at the end.
1214  unsigned n_dof=this->ndof();
1215  Vector<double> local_residuals(n_dof,0.0);
1216  {
1217 
1218  //Find out how many nodes there are
1219  unsigned n_node = this->nnode();
1220 
1221  //Find out how many positional dofs there are
1222  unsigned n_position_type = this->nnodal_position_type();
1223 
1224  //Integer to hold the local equation number
1225  int local_eqn=0;
1226 
1227  //Set up memory for the shape functions
1228  //Note that in this case, the number of lagrangian coordinates is always
1229  //equal to the dimension of the nodes
1230  Shape psi(n_node,n_position_type);
1231  DShape dpsids(n_node,n_position_type,n_dim-1);
1232 
1233  // Separate shape functions for Lagrange multiplier
1234  Shape psi_p(n_node);
1235  Vector<double> s(n_dim-1);
1236 
1237  //Seperate shape for top hat function
1238  Shape psi_i(n_node);
1239 
1240  // Contribution to integrated pressure
1241  Vector<double> pressure_integral(n_node,0.0);
1242 
1243  // Contribution to weighted penetration integral
1244  Vector<double> penetration_integral(n_node,0.0);
1245 
1246  //Set the value of n_intpt
1247  unsigned n_intpt = this->integral_pt()->nweight();
1248 
1249  //Loop over the integration points
1250  for(unsigned ipt=0;ipt<n_intpt;ipt++)
1251  {
1252  //Get the integral weight
1253  double w = this->integral_pt()->weight(ipt);
1254 
1255  //Only need to call the local derivatives
1256  this->dshape_local_at_knot(ipt,psi,dpsids);
1257 
1258  // Separate shape function for Lagrange multiplier
1259  for(unsigned i=0;i<n_dim-1;i++)
1260  {
1261  s[i] = this->integral_pt()->knot(ipt,i);
1262  }
1263  this->shape_p(s,psi_p);
1264 
1265  //If we are using collocation for both, then we don't need to set up the integration shape
1266  if(!(this->use_collocated_penetration_flag()
1267  && this->use_collocated_contact_pressure_flag()))
1268  {
1269  this->shape_i(s,psi_i);
1270  }
1271 
1272  // Interpolated Lagrange multiplier (pressure acting on solid
1273  // to enforce melting)
1274  double interpolated_lambda_p=0.0;
1275 
1276  //Calculate the Eulerian and Lagrangian coordinates
1277  Vector<double> interpolated_x(n_dim,0.0);
1278 
1279  //Also calculate the surface Vectors (derivatives wrt local coordinates)
1280  DenseMatrix<double> interpolated_A(n_dim-1,n_dim,0.0);
1281 
1282  //Calculate displacements and derivatives
1283  for(unsigned l=0;l<n_node;l++)
1284  {
1285 
1286  // Cast to a boundary node
1287  BoundaryNodeBase *bnod_pt =
1288  dynamic_cast<BoundaryNodeBase*>(this->node_pt(l));
1289 
1290  // Get the index of the nodal value associated with
1291  // this FaceElement
1292  unsigned first_index=
1293  bnod_pt->index_of_first_value_assigned_by_face_element(this->Contact_id);
1294 
1295  // Add to Lagrange multiplier (acting as pressure on solid
1296  // to enforce motion to ensure non-penetration)
1297  interpolated_lambda_p+=this->node_pt(l)->value(first_index)*psi_p[l];
1298 
1299  //Loop over positional dofs
1300  for(unsigned k=0;k<n_position_type;k++)
1301  {
1302  //Loop over displacement components (deformed position)
1303  for(unsigned i=0;i<n_dim;i++)
1304  {
1305  //Calculate the Eulerian and Lagrangian positions
1306  interpolated_x[i] +=
1307  this->nodal_position_gen(l,this->bulk_position_type(k),i)*psi(l,k);
1308 
1309  //Loop over LOCAL derivative directions, to calculate the tangent(s)
1310  for(unsigned j=0;j<n_dim-1;j++)
1311  {
1312  interpolated_A(j,i) +=
1313  this->nodal_position_gen(l,this->bulk_position_type(k),i)*dpsids(l,k,j);
1314  }
1315  }
1316  }
1317  }
1318 
1319  //Now find the local deformed metric tensor from the tangent Vectors
1320  DenseMatrix<double> A(n_dim-1);
1321  for(unsigned i=0;i<n_dim-1;i++)
1322  {
1323  for(unsigned j=0;j<n_dim-1;j++)
1324  {
1325  //Initialise surface metric tensor to zero
1326  A(i,j) = 0.0;
1327  //Take the dot product
1328  for(unsigned k=0;k<n_dim;k++)
1329  {
1330  A(i,j) += interpolated_A(i,k)*interpolated_A(j,k);
1331  }
1332  }
1333  }
1334 
1335  //Get the outer unit normal
1336  Vector<double> interpolated_normal(n_dim);
1337  this->outer_unit_normal(ipt,interpolated_normal);
1338 
1339  //Find the determinant of the metric tensor
1340  double Adet =0.0;
1341  switch(n_dim)
1342  {
1343  case 2:
1344  Adet = A(0,0);
1345  break;
1346  case 3:
1347  Adet = A(0,0)*A(1,1) - A(0,1)*A(1,0);
1348  break;
1349  default:
1350  throw OomphLibError(
1351  "Wrong dimension in SurfaceContactElement",
1352  "SurfaceContactElement::fill_in_contribution_to_residuals()",
1354  }
1355 
1356  //Premultiply the weights and the square-root of the determinant of
1357  //the metric tensor
1358  double W = w*sqrt(Adet);
1359 
1360  // Calculate the "load" -- Lagrange multiplier acts as traction to
1361  // to enforce required surface displacement
1362  Vector<double> traction(n_dim);
1363  for (unsigned i=0;i<n_dim;i++)
1364  {
1365  traction[i]=-interpolated_lambda_p*interpolated_normal[i];
1366  }
1367 
1368 
1369  // Accumulate contribution to total contact force
1370  for(unsigned i=0;i<n_dim;i++)
1371  {
1372  contact_force[i]+=traction[i]*W;
1373  }
1374 
1375  //=====LOAD TERMS FROM PRINCIPLE OF VIRTUAL DISPLACEMENTS========
1376 
1377  //Loop over the test functions, nodes of the element
1378  for(unsigned l=0;l<n_node;l++)
1379  {
1380  //Loop of types of dofs
1381  for(unsigned k=0;k<n_position_type;k++)
1382  {
1383  //Loop over the displacement components
1384  for(unsigned i=0;i<n_dim;i++)
1385  {
1386  local_eqn = this->position_local_eqn(l,this->bulk_position_type(k),i);
1387  /*IF it's not a boundary condition*/
1388  if(local_eqn >= 0)
1389  {
1390  //Add the loading terms to the residuals
1391  local_residuals[local_eqn] -= traction[i]*psi(l,k)*W;
1392  }
1393  }
1394  } //End of if not boundary condition
1395  } //End of loop over shape functions
1396 //faire!!!!
1397  //=====CONTRIBUTION TO CONTACT PRESSURE/LAGRANGE MULTIPLIER EQNS ========
1398 
1399  if(!this->use_collocated_contact_pressure_flag())
1400  {
1401  //Loop over the nodes
1402  for(unsigned l=0;l<n_node;l++)
1403  {
1404  // Contribution to integrated pressure
1405  pressure_integral[l]+=interpolated_lambda_p*psi_i[l]*W;
1406  }
1407  }
1408 
1409  if(!this->use_collocated_penetration_flag())
1410  {
1411  //Get local penetration
1412  double d = 0.0;
1413  bool intersection = false;
1414  this->penetration(interpolated_x,interpolated_normal,d,intersection);
1415  if(!intersection)
1416  {
1417  //if there is no intersection then we set d as -infinity
1418  d = -DBL_MAX;
1419  }
1420 
1421  //Loop over the nodes
1422  for(unsigned l=0;l<n_node;l++)
1423  {
1424  // Contribution to integrated penetration
1425  penetration_integral[l]+=d*psi_i[l]*W;
1426  }
1427  }
1428  } //End of loop over integration points
1429 
1430 
1431 
1432 
1433 
1434  // Determine contact pressure/Lagrange multiplier:
1435  //------------------------------------------------
1436 
1437  // Storage for nodal coordinate
1438  Vector<double> x(n_dim);
1439 
1440  //Loop over the nodes
1441  for(unsigned l=0;l<n_node;l++)
1442  {
1443  // get the node pt
1444  Node* nod_pt = this->node_pt(l);
1445 
1446  // Cast to a boundary node
1447  BoundaryNodeBase *bnod_pt =
1448  dynamic_cast<BoundaryNodeBase*>(nod_pt);
1449 
1450  // Get the index of the first nodal value associated with
1451  // this FaceElement
1452  unsigned first_index=
1453  bnod_pt->index_of_first_value_assigned_by_face_element(this->Contact_id);
1454 
1455  // Equation for Lagrange multiplier
1456  local_eqn = this->nodal_local_eqn(l,first_index);
1457 
1458  /*IF it's not a boundary condition*/
1459  if(local_eqn >= 0)
1460  {
1461  //Set to integrated discretisations for now
1462  double d=penetration_integral[l];
1463  double contact_pressure=pressure_integral[l];
1464 
1465  //overwrite appropriate measure if using collocation
1466  if(this->use_collocated_penetration_flag()
1467  || this->use_collocated_contact_pressure_flag())
1468  {//If so, we are gonna need information about the node
1469 
1470  // Nodal position
1471  x[0]=nod_pt->x(0);
1472  x[1]=nod_pt->x(1);
1473 
1474  // Get outer unit normal
1475  Vector<double> s(1);
1476  this->local_coordinate_of_node(l,s);
1477  Vector<double> unit_normal(2);
1478  this->outer_unit_normal(s,unit_normal);
1479 
1480  if(this->use_collocated_penetration_flag())
1481  {
1482  // Get penetration
1483  bool intersection = false;
1484  this->penetration(x,unit_normal,d,intersection);
1485 
1486  //If there is no intersection, d = -max, ie the penetrator is infinitely far away
1487  if(!intersection)
1488  {
1489  d = -DBL_MAX;
1490  }
1491  }
1492 
1493  if(this->use_collocated_contact_pressure_flag())
1494  {
1495  contact_pressure=nod_pt->value(first_index);
1496  }
1497  }
1498 
1499  //Now that we have the appropriate discretisations of penetration and contact pressure,
1500  //use the semi-smooth residual scheme
1501 
1502  // Contact/non-penetration residual
1503  if (this->Enable_stick)
1504  {
1505  // Enforce contact
1506  local_residuals[local_eqn]-=d;
1507  }
1508  else
1509  {
1510  // Piecewise linear variation for non-penetration constraint
1511  if (-d>contact_pressure)
1512  {
1513  local_residuals[local_eqn]+=contact_pressure;
1514  }
1515  else
1516  {
1517  local_residuals[local_eqn]-=d;
1518  }
1519  }
1520  }
1521  }
1522  }
1523 
1524 // faire: we need to go through this
1525  // Now deal with the penetrator equilibrium equations (if any!)
1526  unsigned n=this->Penetrator_eq_data_type.size();
1527  for (unsigned i=0;i<n;i++)
1528  {
1529  if (this->Penetrator_eq_data_type[i]>=0)
1530  {
1531  switch(unsigned(this->Penetrator_eq_data_type[i]))
1532  {
1533 
1535  {
1536  int local_eqn=this->external_local_eqn(
1537  this->Penetrator_eq_data_data_index[i],
1538  this->Penetrator_eq_data_index[i]);
1539  if (local_eqn>=0)
1540  {
1541  local_residuals[local_eqn]+=contact_force[i];
1542  }
1543  }
1544  break;
1545 
1547  {
1548  // position type (dummy -- hierher paranoid check)
1549  unsigned k=0;
1550  int local_eqn=this->position_local_eqn(
1551  this->Penetrator_eq_data_data_index[i],k,
1552  this->Penetrator_eq_data_index[i]);
1553  if (local_eqn>=0)
1554  {
1555  local_residuals[local_eqn]+=contact_force[i];
1556  }
1557  }
1558  break;
1559 
1560 
1562  {
1563  int local_eqn=this->nodal_local_eqn(
1564  this->Penetrator_eq_data_data_index[i],
1565  this->Penetrator_eq_data_index[i]);
1566  if (local_eqn>=0)
1567  {
1568  local_residuals[local_eqn]+=contact_force[i];
1569  }
1570  }
1571  break;
1572 
1573  default:
1574 
1575 
1576  std::stringstream junk;
1577  junk << "Never get here: "
1578  << "unsigned(Penetrator_eq_data_type[i]) = "
1579  << unsigned(this->Penetrator_eq_data_type[i]);
1580  throw OomphLibError(
1581  junk.str(),
1584 
1585  }
1586  }
1587  }
1588 
1589  // Now add local contribution to existing entries
1590  for (unsigned j=0;j<n_dof;j++)
1591  {
1592  residuals[j]+=local_residuals[j];
1593  }
1594 
1595 }
1596 
1597 
1598 
1599 
1600 //=====================================================================
1602 //=====================================================================
1603 template<class ELEMENT>
1605  Vector<double> &contact_force)
1606 {
1607  //Find out how many nodes there are
1608  unsigned n_node = this->nnode();
1609 
1610  //Find out how many positional dofs there are
1611  unsigned n_position_type = this->nnodal_position_type();
1612 
1613  //Find out the dimension of the node
1614  unsigned n_dim = this->nodal_dimension();
1615 
1616  // Initialise
1617  for (unsigned i=0;i<n_dim;i++)
1618  {
1619  contact_force[i]=0.0;
1620  }
1621 
1622  //Set up memory for the shape functions
1623  //Note that in this case, the number of lagrangian coordinates is always
1624  //equal to the dimension of the nodes
1625  Shape psi(n_node,n_position_type);
1626  DShape dpsids(n_node,n_position_type,n_dim-1);
1627 
1628  // Separate shape functions for Lagrange multiplier
1629  Shape psi_p(n_node);
1630  Vector<double> s(n_dim-1);
1631 
1632  //Set the value of n_intpt
1633  unsigned n_intpt = this->integral_pt()->nweight();
1634 
1635  //Loop over the integration points
1636  for(unsigned ipt=0;ipt<n_intpt;ipt++)
1637  {
1638  //Get the integral weight
1639  double w = this->integral_pt()->weight(ipt);
1640 
1641  //Only need to call the local derivatives
1642  this->dshape_local_at_knot(ipt,psi,dpsids);
1643 
1644  // Separate shape function for Lagrange multiplier
1645  for(unsigned i=0;i<n_dim-1;i++)
1646  {
1647  s[i] = this->integral_pt()->knot(ipt,i);
1648  }
1649  this->shape_p(s,psi_p);
1650 
1651  // Interpolated Lagrange multiplier (pressure acting on solid
1652  // to enforce melting)
1653  double interpolated_lambda_p=0.0;
1654 
1655  //Calculate the Eulerian and Lagrangian coordinates
1656  Vector<double> interpolated_x(n_dim,0.0);
1657 
1658  //Also calculate the surface Vectors (derivatives wrt local coordinates)
1659  DenseMatrix<double> interpolated_A(n_dim-1,n_dim,0.0);
1660 
1661  //Calculate displacements and derivatives
1662  for(unsigned l=0;l<n_node;l++)
1663  {
1664  // Cast to a boundary node
1665  BoundaryNodeBase *bnod_pt =
1666  dynamic_cast<BoundaryNodeBase*>(this->node_pt(l));
1667 
1668  // Get the index of the nodal value associated with
1669  // this FaceElement
1670  unsigned first_index=
1671  bnod_pt->index_of_first_value_assigned_by_face_element(this->Contact_id);
1672 
1673  // Add to Lagrange multiplier (acting as pressure on solid
1674  // to enforce motion to ensure non-penetration)
1675  interpolated_lambda_p+=this->node_pt(l)->value(first_index)*psi_p[l];
1676 
1677  //Loop over positional dofs
1678  for(unsigned k=0;k<n_position_type;k++)
1679  {
1680  //Loop over displacement components (deformed position)
1681  for(unsigned i=0;i<n_dim;i++)
1682  {
1683  //Calculate the Eulerian and Lagrangian positions
1684  interpolated_x[i] +=
1685  this->nodal_position_gen(l,this->bulk_position_type(k),i)*psi(l,k);
1686 
1687  //Loop over LOCAL derivative directions, to calculate the tangent(s)
1688  for(unsigned j=0;j<n_dim-1;j++)
1689  {
1690  interpolated_A(j,i) +=
1691  this->nodal_position_gen(l,this->bulk_position_type(k),i)*dpsids(l,k,j);
1692  }
1693  }
1694  }
1695  }
1696 
1697  //Now find the local deformed metric tensor from the tangent Vectors
1698  DenseMatrix<double> A(n_dim-1);
1699  for(unsigned i=0;i<n_dim-1;i++)
1700  {
1701  for(unsigned j=0;j<n_dim-1;j++)
1702  {
1703  //Initialise surface metric tensor to zero
1704  A(i,j) = 0.0;
1705  //Take the dot product
1706  for(unsigned k=0;k<n_dim;k++)
1707  {
1708  A(i,j) += interpolated_A(i,k)*interpolated_A(j,k);
1709  }
1710  }
1711  }
1712 
1713  //Get the outer unit normal
1714  Vector<double> interpolated_normal(n_dim);
1715  this->outer_unit_normal(ipt,interpolated_normal);
1716 
1717  //Find the determinant of the metric tensor
1718  double Adet =0.0;
1719  switch(n_dim)
1720  {
1721  case 2:
1722  Adet = A(0,0);
1723  break;
1724  case 3:
1725  Adet = A(0,0)*A(1,1) - A(0,1)*A(1,0);
1726  break;
1727  default:
1728  throw OomphLibError(
1729  "Wrong dimension in SurfaceContactElement",
1730  "SurfaceContactElement::contact_force()",
1732  }
1733 
1734  //Premultiply the weights and the square-root of the determinant of
1735  //the metric tensor
1736  double W = w*sqrt(Adet);
1737 
1738  // Calculate the "load" -- Lagrange multiplier acts as traction to
1739  // to enforce required surface displacement
1740  Vector<double> traction(n_dim);
1741  for (unsigned i=0;i<n_dim;i++)
1742  {
1743  traction[i]=-interpolated_lambda_p*interpolated_normal[i];
1744  }
1745 
1746  // Add to resulting force
1747  for (unsigned i=0;i<n_dim;i++)
1748  {
1749  contact_force[i]+=traction[i]*W;
1750  }
1751  }
1752 
1753 }
1754 
1755 
1759 
1760 
1761 //======================================================================
1769 //======================================================================
1770 template <class ELEMENT>
1772 public virtual SurfaceContactElementBase<ELEMENT>
1773 {
1774 
1775  public:
1776 
1780  const int &face_index,
1781  const unsigned &id=0,
1782  const bool& called_from_refineable_constructor=
1783  false) :
1784 // FaceGeometry<ELEMENT>(), FaceElement(),
1785  SurfaceContactElementBase<ELEMENT>(element_pt,
1786  face_index,
1787  id,
1788  called_from_refineable_constructor)
1789  {
1790  //Find the dimension of the problem
1791  unsigned n_dim = element_pt->nodal_dimension();
1792 
1793  //Find the index at which the displacemenet unknowns are stored
1794  ELEMENT* cast_element_pt = dynamic_cast<ELEMENT*>(element_pt);
1795  this->U_index_linear_elasticity_traction.resize(n_dim);
1796  for(unsigned i=0;i<n_dim;i++)
1797  {
1799  cast_element_pt->u_index_linear_elasticity(i);
1800  }
1801  }
1802 
1805 
1808  residuals);
1809 
1810 
1812  void output(std::ostream &outfile)
1813  {
1814  unsigned n_plot=5;
1815  this->output(outfile,n_plot);
1816  }
1817 
1819  void output(std::ostream &outfile, const unsigned &n_plot)
1820  {
1821  unsigned n_dim = this->nodal_dimension();
1822 
1823  Vector<double> x(n_dim);
1824  Vector<double> disp(n_dim);
1825  Vector<double> x_def(n_dim);
1826  Vector<double> s(n_dim-1);
1827  Vector<double> r_pen(n_dim);
1828  Vector<double> unit_normal(n_dim);
1829 
1830  // Tecplot header info
1831  outfile << this->tecplot_zone_string(n_plot);
1832 
1833  // Loop over plot points
1834  unsigned num_plot_points=this->nplot_points(n_plot);
1835  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
1836  {
1837  // Get local coordinates of plot point
1838  this->get_s_plot(iplot,n_plot,s);
1839 
1840  // Get coordinates and outer unit normal
1841  this->interpolated_x(s,x);
1842  this->outer_unit_normal(s,unit_normal);
1843 
1844  // Displacement
1845  this->interpolated_u_linear_elasticity(s,disp);
1846 
1847  // Deformed position
1848  for(unsigned i=0;i<n_dim;i++)
1849  {
1850  x_def[i]=x[i]+disp[i];
1851  }
1852 
1853  // Get penetration based on deformed position
1854  double d= 0.0;
1855  bool intersection = false;
1856  this->penetration(x_def,unit_normal,d,intersection);
1857 
1858  //Output the x,y,..
1859  for(unsigned i=0;i<n_dim;i++)
1860  {outfile << x[i] << " ";} // col 1,2
1861 
1862  // Penetration
1863  outfile << std::max(d,-100.0) << " "; // col 3
1864 
1865  // Lagrange multiplier-like pressure
1866  double p=this->get_interpolated_lagrange_p(s);
1867  outfile << p << " "; // col 4
1868 
1869 
1870  // Plot Lagrange multiplier like pressure
1871  outfile << -unit_normal[0]*p << " "; // col 5
1872  outfile << -unit_normal[1]*p << " "; // col 6
1873 
1874  // Plot vector from current point to boundary of penetrator
1875  double d_tmp=d;
1876  if (!intersection) d_tmp=0.0;
1877  outfile << -d_tmp*unit_normal[0] << " "; // col 7
1878  outfile << -d_tmp*unit_normal[1] << " "; // col 8
1879 
1880  // Output normal
1881  for(unsigned i=0;i<n_dim;i++)
1882  {outfile << unit_normal[i] << " ";} // col 9, 10
1883 
1884  //Output the displacements
1885  for(unsigned i=0;i<n_dim;i++)
1886  {
1887  outfile << disp[i] << " "; // col 11, 12
1888  }
1889 
1890  //Output the deformed position
1891  for(unsigned i=0;i<n_dim;i++)
1892  {
1893  outfile << x_def[i] << " "; // col 13, 14
1894  }
1895  outfile << std::endl;
1896  }
1897 
1898  // Write tecplot footer (e.g. FE connectivity lists)
1899  this->write_tecplot_zone_footer(outfile,n_plot);
1900 
1901  }
1902 
1904  void resulting_contact_force(Vector<double> &contact_force);
1905 
1906  protected:
1907 
1910  Vector<double>& disp) const
1911  {
1912  //Find the dimension of the problem
1913  unsigned n_dim = this->nodal_dimension();
1914 
1915  //Find number of nodes
1916  unsigned n_node = this->nnode();
1917 
1918  //Local shape function
1919  Shape psi(n_node);
1920 
1921  //Find values of shape function
1922  this->shape(s,psi);
1923 
1924  // Get displacements
1925  for (unsigned i=0;i<n_dim;i++)
1926  {
1927  //Index at which the nodal value is stored
1928  unsigned u_nodal_index = this->U_index_linear_elasticity_traction[i];
1929 
1930  //Initialise value of u
1931  disp[i] = 0.0;
1932 
1933  //Loop over the local nodes and sum
1934  for(unsigned l=0;l<n_node;l++)
1935  {
1936  disp[i] += this->nodal_value(l,u_nodal_index)*psi[l];
1937  }
1938  }
1939  }
1940 
1941 
1944 
1945 };
1946 
1950 
1951 
1952 
1953 //=====================================================================
1955 //=====================================================================
1956 template<class ELEMENT>
1959 {
1960 
1961  // Spatial dimension of problem
1962  unsigned n_dim = this->nodal_dimension();
1963 
1964  // Contribution to contact force
1965  Vector<double> contact_force(n_dim,0.0);
1966 
1967  // Create vector of local residuals (start assembling contributions
1968  // from zero -- necessary so we can over-write pseudo-hijacked
1969  // contributions at the end.
1970  unsigned n_dof=this->ndof();
1971  Vector<double> local_residuals(n_dof,0.0);
1972 
1973  {
1974  //Find out how many nodes there are
1975  unsigned n_node = this->nnode();
1976 
1977  //Integer to hold the local equation number
1978  int local_eqn=0;
1979 
1980  //Set up memory for the shape functions
1981  Shape psi(n_node);
1982  DShape dpsids(n_node,n_dim-1);
1983 
1984  // Separate shape functions for Lagrange multiplier
1985  Shape psi_p(n_node);
1986  Vector<double> s(n_dim-1);
1987 
1988  //Seperate shape for top hat function
1989  Shape psi_i(n_node);
1990 
1991  // Contribution to integrated pressure
1992  Vector<double> pressure_integral(n_node,0.0);
1993 
1994  // Contribution to weighted penetration integral
1995  Vector<double> penetration_integral(n_node,0.0);
1996 
1997  // Deformed position
1998  Vector<double> x_def(n_dim,0.0);
1999 
2000  //Set the value of n_intpt
2001  unsigned n_intpt = this->integral_pt()->nweight();
2002 
2003  //Loop over the integration points
2004  for(unsigned ipt=0;ipt<n_intpt;ipt++)
2005  {
2006  //Get the integral weight
2007  double w = this->integral_pt()->weight(ipt);
2008 
2009  //Only need to call the local derivatives
2010  this->dshape_local_at_knot(ipt,psi,dpsids);
2011 
2012  // Separate shape function for Lagrange multiplier
2013  for(unsigned i=0;i<n_dim-1;i++)
2014  {
2015  s[i] = this->integral_pt()->knot(ipt,i);
2016  }
2017  this->shape_p(s,psi_p);
2018 
2019  //If we are using collocation for both, then we don't need to set up the integration shape
2020  if(!(this->use_collocated_penetration_flag()
2021  && this->use_collocated_contact_pressure_flag())){
2022  this->shape_i(s,psi_i);
2023  }
2024 
2025  // Interpolated Lagrange multiplier (pressure acting on solid)
2026  double interpolated_lambda_p=0.0;
2027 
2028  // Displacement
2029  Vector<double> disp(n_dim,0.0);
2030 
2031  //Calculate the coordinates
2032  Vector<double> interpolated_x(n_dim,0.0);
2033 
2034  //Also calculate the surface Vectors (derivatives wrt local coordinates)
2035  DenseMatrix<double> interpolated_A(n_dim-1,n_dim,0.0);
2036 
2037  //Calculate displacements and derivatives
2038  for(unsigned l=0;l<n_node;l++)
2039  {
2040  // Cast to a boundary node
2041  BoundaryNodeBase *bnod_pt =
2042  dynamic_cast<BoundaryNodeBase*>(this->node_pt(l));
2043 
2044  // Get the index of the nodal value associated with
2045  // this FaceElement
2046  unsigned first_index=
2047  bnod_pt->index_of_first_value_assigned_by_face_element(this->Contact_id);
2048 
2049  // Add to Lagrange multiplier (acting as pressure on solid
2050  // to enforce motion to ensure non-penetration)
2051  interpolated_lambda_p+=this->node_pt(l)->value(first_index)*psi_p[l];
2052 
2053  //Loop over displacement components
2054  for(unsigned i=0;i<n_dim;i++)
2055  {
2056  //Calculate the positions
2057  interpolated_x[i]+=this->nodal_position(l,i)*psi(l);
2058 
2059  //Index at which the displacement nodal value is stored
2060  unsigned u_nodal_index=this->U_index_linear_elasticity_traction[i];
2061  disp[i] += this->nodal_value(l,u_nodal_index)*psi(l);
2062 
2063  // Loop over LOCAL derivative directions, to calculate the
2064  // tangent(s)
2065  for(unsigned j=0;j<n_dim-1;j++)
2066  {
2067  interpolated_A(j,i)+=this->nodal_position(l,i)*dpsids(l,j);
2068  }
2069  }
2070  //std::cout<<interpolated_lambda_p; //test for no contact
2071  }
2072 
2073  //Now find the local deformed metric tensor from the tangent Vectors
2074  DenseMatrix<double> A(n_dim-1);
2075  for(unsigned i=0;i<n_dim-1;i++)
2076  {
2077  for(unsigned j=0;j<n_dim-1;j++)
2078  {
2079  //Initialise surface metric tensor to zero
2080  A(i,j) = 0.0;
2081  //Take the dot product
2082  for(unsigned k=0;k<n_dim;k++)
2083  {
2084  A(i,j) += interpolated_A(i,k)*interpolated_A(j,k);
2085  }
2086  }
2087  }
2088 
2089  //Get the outer unit normal
2090  Vector<double> interpolated_normal(n_dim);
2091  this->outer_unit_normal(ipt,interpolated_normal);
2092 
2093  //Find the determinant of the metric tensor
2094  double Adet =0.0;
2095  switch(n_dim)
2096  {
2097  case 2:
2098  Adet = A(0,0);
2099  break;
2100  case 3:
2101  Adet = A(0,0)*A(1,1) - A(0,1)*A(1,0);
2102  break;
2103  default:
2104  throw OomphLibError(
2105  "Wrong dimension in SurfaceContactElement",
2106  "LinearSurfaceContactElement::fill_in_contribution_to_residuals()",
2108  }
2109 
2110  //Premultiply the weights and the square-root of the determinant of
2111  //the metric tensor
2112  double W = w*sqrt(Adet);
2113 
2114  // Calculate the "load" -- Lagrange multiplier acts as traction to
2115  // to enforce required surface displacement and the
2116  // deformed position
2117  Vector<double> traction(n_dim);
2118  for (unsigned i=0;i<n_dim;i++)
2119  {
2120  traction[i]=-interpolated_lambda_p*interpolated_normal[i];
2121  x_def[i]=interpolated_x[i]+disp[i];
2122  }
2123 
2124 
2125  // Accumulate contribution to total contact force
2126  for(unsigned i=0;i<n_dim;i++)
2127  {
2128  contact_force[i]+=traction[i]*W;
2129  }
2130 
2131  //=====LOAD TERMS FROM PRINCIPLE OF VIRTUAL DISPLACEMENTS AND BOUNDARY CONDITIONS========
2132 
2133  //holder for externally imposed traction
2134  Vector<double> p(n_dim,0.0);
2135 
2136  //Get vector of traction from the function which has been passed in
2137  this->traction_fct(interpolated_x,p);
2138 
2139  //Loop over the test functions, nodes of the element
2140  for(unsigned l=0;l<n_node;l++)
2141  {
2142  //Loop over the displacement components
2143  for(unsigned i=0;i<n_dim;i++)
2144  {
2145  local_eqn = this->nodal_local_eqn(l,i);
2146  /*IF it's not a boundary condition*/
2147  if(local_eqn >= 0)
2148  {
2149 
2150  //Add the loading terms from penetrator and imposed externally to the residuals
2151  local_residuals[local_eqn] -= (traction[i]+p[i])*psi(l)*W;
2152  } //End of if not boundary condition
2153  }
2154  } //End of loop over shape functions
2155 
2156  //=====CONTRIBUTION TO CONTACT PRESSURE/LAGRANGE MULTIPLIER EQNS ========
2157 
2158  if(!this->use_collocated_contact_pressure_flag())
2159  {
2160  //Loop over the nodes
2161  for(unsigned l=0;l<n_node;l++)
2162  {
2163  // Contribution to integrated pressure
2164  pressure_integral[l]+=interpolated_lambda_p*psi_i[l]*W;
2165  }
2166  }
2167 
2168  if(!this->use_collocated_penetration_flag())
2169  {
2170  //Get local penetration
2171  double d = 0.0;
2172  bool intersection = false;
2173  this->penetration(x_def,interpolated_normal,d,intersection);
2174  if(!intersection)
2175  {
2176  //if there is no intersection then we set d as -infinity
2177  d = -DBL_MAX;
2178  }
2179 
2180  //Loop over the nodes
2181  for(unsigned l=0;l<n_node;l++)
2182  {
2183  // Contribution to integrated penetration
2184  penetration_integral[l]+=d*psi_i[l]*W;
2185  }
2186  }
2187  } //End of loop over integration points
2188 
2189 
2190  // Determine contact pressure/Lagrange multiplier
2191  //-----------------------------------------------
2192 
2193  // Storage for nodal coordinate
2194  Vector<double> x(n_dim);
2195 
2196  //Loop over the nodes
2197  for(unsigned l=0;l<n_node;l++)
2198  {
2199  // get the node pt
2200  Node* nod_pt = this->node_pt(l);
2201 
2202  // Cast to a boundary node
2203  BoundaryNodeBase *bnod_pt =
2204  dynamic_cast<BoundaryNodeBase*>(nod_pt);
2205 
2206  // Get the index of the first nodal value associated with
2207  // this FaceElement
2208  unsigned first_index=
2209  bnod_pt->index_of_first_value_assigned_by_face_element(this->Contact_id);
2210 
2211  // Equation for Lagrange multiplier
2212  local_eqn = this->nodal_local_eqn(l,first_index);
2213 
2214  /*IF it's not a boundary condition*/
2215  if(local_eqn >= 0)
2216  {
2217  //Set to integrated discretisations for now
2218  double d=penetration_integral[l];
2219  double contact_pressure=pressure_integral[l];
2220 
2221  //overwrite appropriate measure if using collocation
2222  if(this->use_collocated_penetration_flag()
2223  || this->use_collocated_contact_pressure_flag())
2224  {//If so, we are gonna need information about the node
2225 
2226  // Nodal position
2227  x[0]=nod_pt->x(0);
2228  x[1]=nod_pt->x(1);
2229 
2230  // Get outer unit normal
2231  Vector<double> s(1);
2232  this->local_coordinate_of_node(l,s);
2233  Vector<double> unit_normal(2);
2234  this->outer_unit_normal(s,unit_normal);
2235 
2236  // Displacement
2237  Vector<double> disp(2);
2238  this->interpolated_u_linear_elasticity(s,disp);
2239 
2240  // Deformed position
2241  Vector<double> x_def(2);
2242  x_def[0]=x[0]+disp[0];
2243  x_def[1]=x[1]+disp[1];
2244 
2245  if(this->use_collocated_penetration_flag())
2246  {
2247  // Get penetration
2248  bool intersection = false;
2249  this->penetration(x_def,unit_normal,d,intersection);
2250 
2251  //If there is no intersection, d = -max, ie the penetrator is infinitely far away
2252  if(!intersection)
2253  {
2254  d = -DBL_MAX;
2255  }
2256  }
2257 
2258  if(this->use_collocated_contact_pressure_flag())
2259  {
2260  contact_pressure=nod_pt->value(first_index);
2261  }
2262  }
2263 
2264  //Now that we have the appropriate discretisations of penetration and contact pressure,
2265  //use the semi-smooth residual scheme
2266 
2267  // Contact/non-penetration residual
2268  if (this->Enable_stick)
2269  {
2270  // Enforce contact
2271  local_residuals[local_eqn]-=d;
2272  }
2273  else
2274  {
2275  // Piecewise linear variation for non-penetration constraint
2276  if (-d>contact_pressure)
2277  {
2278  local_residuals[local_eqn]+=contact_pressure;
2279  }
2280  else
2281  {
2282  local_residuals[local_eqn]-=d;
2283  }
2284  }
2285  }
2286  }
2287  }
2288 
2289 //faire: equilibrium again
2290  // Now deal with the penetrator equilibrium equations (if any!)
2291  unsigned n=this->Penetrator_eq_data_type.size();
2292  for (unsigned i=0;i<n;i++)
2293  {
2294  if (this->Penetrator_eq_data_type[i]>=0)
2295  {
2296  switch(unsigned(this->Penetrator_eq_data_type[i]))
2297  {
2298 
2300  {
2301  int local_eqn=this->external_local_eqn(
2302  this->Penetrator_eq_data_data_index[i],
2303  this->Penetrator_eq_data_index[i]);
2304  if (local_eqn>=0)
2305  {
2306  local_residuals[local_eqn]+=contact_force[i];
2307  }
2308  }
2309  break;
2310 
2311 
2312 // hierher this case should not arise because the nodal positions
2313  // will not be affected by the force balance.
2314 /* case TemplateFreeContactElementBase::Nodal_position_data: */
2315 /* { */
2316 /* // position type (dummy -- hierher paranoid check) */
2317 /* unsigned k=0; */
2318 /* int local_eqn=position_local_eqn( */
2319 /* this->Penetrator_eq_data_data_index[i],k, */
2320 /* this->Penetrator_eq_data_index[i]); */
2321 /* if (local_eqn>=0) */
2322 /* { */
2323 /* local_residuals[local_eqn]=contact_force[i]; */
2324 /* } */
2325 /* } */
2326 /* break; */
2327 
2329  {
2330  int local_eqn=this->nodal_local_eqn(
2331  this->Penetrator_eq_data_data_index[i],
2332  this->Penetrator_eq_data_index[i]);
2333  if (local_eqn>=0)
2334  {
2335  local_residuals[local_eqn]+=contact_force[i];
2336  }
2337  }
2338  break;
2339 
2340  default:
2341 
2342 
2343  std::stringstream junk;
2344  junk << "Never get here: "
2345  << "unsigned(Penetrator_eq_data_type[i]) = "
2346  << unsigned(this->Penetrator_eq_data_type[i]);
2347  throw OomphLibError(
2348  junk.str(),
2351 
2352  }
2353  }
2354  }
2355 
2356  // Now add local contribution to existing entries
2357  for (unsigned j=0;j<n_dof;j++)
2358  {
2359  residuals[j]+=local_residuals[j];
2360  }
2361 
2362 }
2363 
2364 
2365 
2366 
2367 //=====================================================================
2369 //=====================================================================
2370 template<class ELEMENT>
2372  Vector<double> &contact_force)
2373 {
2374 
2375  //Find out how many nodes there are
2376  unsigned n_node = this->nnode();
2377 
2378  //Find out the dimension of the node
2379  unsigned n_dim = this->nodal_dimension();
2380 
2381  // Initialise
2382  for (unsigned i=0;i<n_dim;i++)
2383  {
2384  contact_force[i]=0.0;
2385  }
2386 
2387  //Set up memory for the shape functions
2388  Shape psi(n_node);
2389  DShape dpsids(n_node,n_dim-1);
2390 
2391  // Separate shape functions for Lagrange multiplier
2392  Shape psi_p(n_node);
2393  Vector<double> s(n_dim-1);
2394 
2395  //Set the value of n_intpt
2396  unsigned n_intpt = this->integral_pt()->nweight();
2397 
2398  //Loop over the integration points
2399  for(unsigned ipt=0;ipt<n_intpt;ipt++)
2400  {
2401  //Get the integral weight
2402  double w = this->integral_pt()->weight(ipt);
2403 
2404  //Only need to call the local derivatives
2405  this->dshape_local_at_knot(ipt,psi,dpsids);
2406 
2407  // Separate shape function for Lagrange multiplier
2408  for(unsigned i=0;i<n_dim-1;i++)
2409  {
2410  s[i] = this->integral_pt()->knot(ipt,i);
2411  }
2412  this->shape_p(s,psi_p);
2413 
2414  // Interpolated Lagrange multiplier (pressure acting on solid
2415  // to enforce melting)
2416  double interpolated_lambda_p=0.0;
2417 
2418  //Calculate the coordinates
2419  Vector<double> interpolated_x(n_dim,0.0);
2420 
2421  // Displacement
2422  Vector<double> disp(n_dim,0.0);
2423 
2424  //Also calculate the surface Vectors (derivatives wrt local coordinates)
2425  DenseMatrix<double> interpolated_A(n_dim-1,n_dim,0.0);
2426 
2427  //Calculate displacements and derivatives
2428  for(unsigned l=0;l<n_node;l++)
2429  {
2430  // Cast to a boundary node
2431  BoundaryNodeBase *bnod_pt =
2432  dynamic_cast<BoundaryNodeBase*>(this->node_pt(l));
2433 
2434  // Get the index of the nodal value associated with
2435  // this FaceElement
2436  unsigned first_index=
2437  bnod_pt->index_of_first_value_assigned_by_face_element(this->Contact_id);
2438 
2439  // Add to Lagrange multiplier (acting as pressure on solid
2440  // to enforce motion to ensure non-penetration)
2441  interpolated_lambda_p+=this->node_pt(l)->value(first_index)*psi_p[l];
2442 
2443  //Loop over displacement components
2444  for(unsigned i=0;i<n_dim;i++)
2445  {
2446  //Calculate the positions
2447  interpolated_x[i] += this->nodal_position(l,i)*psi(l);
2448 
2449  //Index at which the displacement nodal value is stored
2450  unsigned u_nodal_index=this->U_index_linear_elasticity_traction[i];
2451  disp[i] += this->nodal_value(l,u_nodal_index)*psi(l);
2452 
2453  //Loop over LOCAL derivative directions, to calculate the tangent(s)
2454  for(unsigned j=0;j<n_dim-1;j++)
2455  {
2456  interpolated_A(j,i) += this->nodal_position(l,i)*dpsids(l,j);
2457  }
2458  }
2459  }
2460 
2461 
2462  //Now find the local deformed metric tensor from the tangent Vectors
2463  DenseMatrix<double> A(n_dim-1);
2464  for(unsigned i=0;i<n_dim-1;i++)
2465  {
2466  for(unsigned j=0;j<n_dim-1;j++)
2467  {
2468  //Initialise surface metric tensor to zero
2469  A(i,j) = 0.0;
2470  //Take the dot product
2471  for(unsigned k=0;k<n_dim;k++)
2472  {
2473  A(i,j) += interpolated_A(i,k)*interpolated_A(j,k);
2474  }
2475  }
2476  }
2477 
2478  //Get the outer unit normal
2479  Vector<double> interpolated_normal(n_dim);
2480  this->outer_unit_normal(ipt,interpolated_normal);
2481 
2482  //Find the determinant of the metric tensor
2483  double Adet =0.0;
2484  switch(n_dim)
2485  {
2486  case 2:
2487  Adet = A(0,0);
2488  break;
2489  case 3:
2490  Adet = A(0,0)*A(1,1) - A(0,1)*A(1,0);
2491  break;
2492  default:
2493  throw OomphLibError(
2494  "Wrong dimension in SurfaceContactElement",
2495  "SurfaceContactElement::contact_force()",
2497  }
2498 
2499  //Premultiply the weights and the square-root of the determinant of
2500  //the metric tensor
2501  double W = w*sqrt(Adet);
2502 
2503  // Calculate the "load" -- Lagrange multiplier acts as traction to
2504  // to enforce required surface displacement
2505  Vector<double> traction(n_dim);
2506  for (unsigned i=0;i<n_dim;i++)
2507  {
2508  traction[i]=-interpolated_lambda_p*interpolated_normal[i];
2509  }
2510 
2511  // Add to resulting force
2512  for (unsigned i=0;i<n_dim;i++)
2513  {
2514  contact_force[i]+=traction[i]*W;
2515  }
2516  }
2517 
2518 }
2519 
2520 
2524 
2525 
2526 }
2527 
2528 
2529 #endif
AnnoyingScalar cos(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:136
AnnoyingScalar atan2(const AnnoyingScalar &y, const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:139
AnnoyingScalar sin(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:137
AnnoyingScalar sqrt(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:134
int i
Definition: BiCGSTAB_step_by_step.cpp:9
const unsigned n
Definition: CG3DPackingUnitTest.cpp:11
Vector3f p1
Definition: MatrixBase_all.cpp:2
RowVector3d w
Definition: Matrix_resize_int.cpp:3
float * p
Definition: Tutorial_Map_using.cpp:9
float BLASFUNC() smax(int *, float *, int *)
float BLASFUNC() smin(int *, float *, int *)
Matrix< SCALARA, Dynamic, Dynamic, opt_A > A
Definition: bench_gemm.cpp:47
Definition: nodes.h:1996
unsigned index_of_first_value_assigned_by_face_element(const unsigned &face_id=0) const
Definition: nodes.h:2061
Penetrator – here implemented as a circle.
Definition: contact_elements.h:249
void output(std::ostream &outfile, const unsigned &nplot) const
Output coordinates of penetrator at nplot plot points.
Definition: contact_elements.h:312
virtual ~CircularPenetrator()
Destructor.
Definition: contact_elements.h:269
void surface_coordinate(const Vector< double > &x, Vector< double > &zeta) const
Definition: contact_elements.h:338
Vector< double > rigid_body_displacement() const
Get rigid body displacement of reference point in penetrator.
Definition: contact_elements.h:345
Vector< double > Orig_centre
Definition: contact_elements.h:374
double Radius
Radius of penetrator.
Definition: contact_elements.h:377
void position_from_zeta(const Vector< double > &zeta, Vector< double > &r) const
Get position to surface, r, in terms of surface coordinate zeta.
Definition: contact_elements.h:325
void set_original_centre(const Vector< double > &orig_centre)
Definition: contact_elements.h:359
void penetration(const Vector< double > &x, const Vector< double > &n, double &d, bool &intersection) const
Get penetration for given point x.
Definition: contact_elements.h:272
Vector< double > * Centre_pt
Definition: contact_elements.h:369
CircularPenetrator(Vector< double > *r_c_pt, const double &r)
Constructor: Pass pointer to centre and radius.
Definition: contact_elements.h:254
Definition: shape.h:278
TimeStepper *& time_stepper_pt()
Return the pointer to the timestepper.
Definition: nodes.h:238
Definition: elements.h:4338
int & face_index()
Definition: elements.h:4626
void outer_unit_normal(const Vector< double > &s, Vector< double > &unit_normal) const
Compute outer unit normal at the specified local coordinate.
Definition: elements.cc:6006
void add_additional_values(const Vector< unsigned > &nadditional_values, const unsigned &id)
Definition: elements.h:4428
double interpolated_x(const Vector< double > &s, const unsigned &i) const
Definition: elements.h:4528
Definition: elements.h:4998
Definition: elements.h:1313
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2175
double nodal_value(const unsigned &n, const unsigned &i) const
Definition: elements.h:2593
virtual void output(std::ostream &outfile)
Definition: elements.h:3050
virtual std::string tecplot_zone_string(const unsigned &nplot) const
Definition: elements.h:3161
virtual void build_face_element(const int &face_index, FaceElement *face_element_pt)
Definition: elements.cc:5132
virtual void shape(const Vector< double > &s, Shape &psi) const =0
unsigned dim() const
Definition: elements.h:2611
unsigned nnode() const
Return the number of nodes.
Definition: elements.h:2210
virtual void get_s_plot(const unsigned &i, const unsigned &nplot, Vector< double > &s, const bool &shifted_to_interior=false) const
Definition: elements.h:3148
virtual double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
Definition: elements.h:2722
virtual unsigned nplot_points(const unsigned &nplot) const
Definition: elements.h:3186
unsigned nodal_dimension() const
Return the required Eulerian dimension of the nodes in this element.
Definition: elements.h:2484
virtual void write_tecplot_zone_footer(std::ostream &outfile, const unsigned &nplot) const
Definition: elements.h:3174
virtual void set_integration_scheme(Integral *const &integral_pt)
Set the spatial integration scheme.
Definition: elements.cc:3210
bool has_hanging_nodes() const
Definition: elements.h:2470
Definition: integral.h:145
unsigned add_external_data(Data *const &data_pt, const bool &fd=true)
Definition: elements.cc:307
Heated circular penetrator.
Definition: contact_elements.h:392
virtual ~HeatedCircularPenetrator()
Destructor.
Definition: contact_elements.h:401
double temperature(const Vector< double > &x) const
Definition: contact_elements.h:408
HeatedCircularPenetrator(Vector< double > *r_c_pt, const double &r)
Constructor: Pass pointer to centre and radius.
Definition: contact_elements.h:397
Base class for "heated" penetrator.
Definition: contact_elements.h:222
HeatedPenetrator()
Constructor.
Definition: contact_elements.h:227
virtual double temperature(const Vector< double > &x) const =0
virtual ~HeatedPenetrator()
Destructor.
Definition: contact_elements.h:230
Definition: contact_elements.h:1773
void resulting_contact_force(Vector< double > &contact_force)
Resulting contact force.
Definition: contact_elements.h:2371
LinearSurfaceContactElement(FiniteElement *const &element_pt, const int &face_index, const unsigned &id=0, const bool &called_from_refineable_constructor=false)
Definition: contact_elements.h:1779
Vector< unsigned > U_index_linear_elasticity_traction
Index at which the i-th displacement component is stored.
Definition: contact_elements.h:1943
void output(std::ostream &outfile)
Output function.
Definition: contact_elements.h:1812
LinearSurfaceContactElement()
Default constructor.
Definition: contact_elements.h:1804
void fill_in_contribution_to_residuals_surface_contact(Vector< double > &residuals)
Return the residuals for the SurfaceContactElement equations.
Definition: contact_elements.h:1958
void output(std::ostream &outfile, const unsigned &n_plot)
Output function.
Definition: contact_elements.h:1819
void interpolated_u_linear_elasticity(const Vector< double > &s, Vector< double > &disp) const
Compute vector of FE interpolated displacement u at local coordinate s.
Definition: contact_elements.h:1909
Definition: nodes.h:906
double & x(const unsigned &i)
Return the i-th nodal coordinate.
Definition: nodes.h:1060
double value(const unsigned &i) const
Definition: nodes.cc:2408
Definition: contact_elements.h:1086
void resulting_contact_force(Vector< double > &contact_force)
Resulting contact force.
Definition: contact_elements.h:1604
void output(std::ostream &outfile)
Output function.
Definition: contact_elements.h:1109
void output(std::ostream &outfile, const unsigned &n_plot)
Output function.
Definition: contact_elements.h:1116
NonlinearSurfaceContactElement(FiniteElement *const &element_pt, const int &face_index, const unsigned &id=0, const bool &called_from_refineable_constructor=false)
Definition: contact_elements.h:1092
void fill_in_contribution_to_residuals_surface_contact(Vector< double > &residuals)
Return the residuals for the SurfaceContactElement equations.
Definition: contact_elements.h:1202
Definition: oomph_definitions.h:222
Definition: contact_elements.h:153
virtual Vector< std::pair< Data *, unsigned > > equilibrium_data()
Definition: contact_elements.h:195
virtual void surface_coordinate(const Vector< double > &x, Vector< double > &zeta) const
Definition: contact_elements.h:205
virtual ~Penetrator()
Destructor.
Definition: contact_elements.h:161
virtual void output(std::ostream &outfile, const unsigned &nplot) const =0
Output coordinates of penetrator at nplot plot points.
virtual void penetration(const Vector< double > &x, const Vector< double > &n, double &d, bool &intersection) const =0
Penetrator()
Constructor.
Definition: contact_elements.h:158
virtual Vector< double > rigid_body_displacement() const
Definition: contact_elements.h:181
Definition: contact_elements.h:53
double knot(const unsigned &i, const unsigned &j) const
Return the rescaled knot values s[j] at integration point i.
Definition: contact_elements.h:83
double Range
Definition: contact_elements.h:57
PiecewiseGauss(const double &lower, const double &upper)
Definition: contact_elements.h:63
double Lower
Store for the lower and upper limits of integration and the range.
Definition: contact_elements.h:57
PiecewiseGauss(const PiecewiseGauss &dummy)
Broken copy constructor.
Definition: contact_elements.h:71
double Upper
Definition: contact_elements.h:57
double weight(const unsigned &i) const
Return the rescaled weight at integration point i.
Definition: contact_elements.h:112
virtual unsigned nweight() const
Return the number of integration points of the scheme.
Definition: contact_elements.h:77
Definition: refineable_elements.h:97
Definition: shape.h:76
Definition: nodes.h:1686
Definition: contact_elements.h:675
Vector< int > Penetrator_eq_data_type
Definition: contact_elements.h:1047
bool is_stick_enabled()
Definition: contact_elements.h:807
double get_interpolated_lagrange_p(const Vector< double > &s)
Definition: contact_elements.h:980
unsigned Contact_id
Definition: contact_elements.h:1035
Vector< int > Penetrator_eq_data_index
Definition: contact_elements.h:1055
SurfaceContactElementBase()
Default constructor.
Definition: contact_elements.h:772
void output(std::ostream &outfile)
Output function.
Definition: contact_elements.h:900
void set_penetrator_pt(Penetrator *penetrator_pt)
Set pointer to penetrator.
Definition: contact_elements.h:844
void shape_i(const Vector< double > &s, Shape &psi) const
Definition: contact_elements.h:948
void shape_p(const Vector< double > &s, Shape &psi) const
Shape fct for lagrange multiplier.
Definition: contact_elements.h:913
void output(std::ostream &outfile, const unsigned &n_plot)
Output function.
Definition: contact_elements.h:907
bool Enable_stick
Definition: contact_elements.h:1039
void output(FILE *file_pt)
C_style output function.
Definition: contact_elements.h:892
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Return the residuals.
Definition: contact_elements.h:814
Penetrator * penetrator_pt() const
Pointer to penetrator.
Definition: contact_elements.h:838
double s_max() const
Max. value of local coordinate.
Definition: contact_elements.h:793
SurfaceContactElementBase(FiniteElement *const &element_pt, const int &face_index, const unsigned &id=0, const bool &called_from_refineable_constructor=false)
value of the index and its limit
Definition: contact_elements.h:681
Vector< int > Penetrator_eq_data_data_index
Definition: contact_elements.h:1063
virtual void fill_in_contribution_to_residuals_surface_contact(Vector< double > &residuals)=0
double zeta_nodal(const unsigned &n, const unsigned &k, const unsigned &i) const
Definition: contact_elements.h:782
Penetrator * Penetrator_pt
Pointer to penetrator.
Definition: contact_elements.h:1030
void penetration(const Vector< double > &x, const Vector< double > &n, double &d, bool &intersection) const
Work out penetration of point.
Definition: contact_elements.h:1021
void enable_stick()
Definition: contact_elements.h:776
void output(FILE *file_pt, const unsigned &n_plot)
C-style output function.
Definition: contact_elements.h:896
void disable_stick()
Definition: contact_elements.h:800
double s_min() const
Min value of local coordinate.
Definition: contact_elements.h:788
Template-free base class for contact elements.
Definition: contact_elements.h:518
TractionFctPt Traction_fct_pt
Definition: contact_elements.h:641
bool * Use_collocated_contact_pressure_flag_pt
Set options for basis/test functions for penetration and pressure.
Definition: contact_elements.h:651
virtual ~TemplateFreeContactElementBase()
Destructor.
Definition: contact_elements.h:529
virtual void resulting_contact_force(Vector< double > &contact_force)=0
Resulting contact force.
bool * use_isoparametric_flag_pt() const
Definition: contact_elements.h:613
void traction_fct(const Vector< double > &x, Vector< double > &p)
Definition: contact_elements.h:541
bool use_isoparametric_flag() const
Definition: contact_elements.h:561
bool use_collocated_penetration_flag()
Definition: contact_elements.h:576
bool *& use_isoparametric_flag_pt()
Access function: Pointer to flag to use isoparametric.
Definition: contact_elements.h:609
TractionFctPt traction_fct_pt() const
Access function: Pointer to body force function (const version)
Definition: contact_elements.h:606
bool *& use_collocated_penetration_flag_pt()
Access function: Pointer to flag to use collocated penetration.
Definition: contact_elements.h:617
bool * use_collocated_penetration_flag_pt() const
Definition: contact_elements.h:621
bool use_collocated_contact_pressure_flag()
Definition: contact_elements.h:591
TemplateFreeContactElementBase()
Definition: contact_elements.h:522
void(* TractionFctPt)(const double &t, const Vector< double > &x, Vector< double > &p)
Definition: contact_elements.h:535
TractionFctPt & traction_fct_pt()
Access function: Pointer to body force function.
Definition: contact_elements.h:604
bool * Use_isoparametric_flag_pt
Set whether or not to use isoparametric basis function for pressure.
Definition: contact_elements.h:645
bool * Use_collocated_penetration_flag_pt
Set options for basis/test functions for penetration and pressure.
Definition: contact_elements.h:648
bool * use_collocated_contact_pressure_flag_pt() const
Definition: contact_elements.h:629
@ Nodal_position_data
Definition: contact_elements.h:637
@ External_data
Definition: contact_elements.h:638
@ Nodal_data
Definition: contact_elements.h:636
bool *& use_collocated_contact_pressure_flag_pt()
Access function: Pointer to flag to use collocated contact pressure.
Definition: contact_elements.h:625
Time *const & time_pt() const
Access function for the pointer to time (const version)
Definition: timesteppers.h:572
double & time()
Return the current value of the continuous time.
Definition: timesteppers.h:123
#define min(a, b)
Definition: datatypes.h:22
#define max(a, b)
Definition: datatypes.h:23
RealScalar s
Definition: level1_cplx_impl.h:130
char char char int int * k
Definition: level2_impl.h:374
#define DIM
Definition: linearised_navier_stokes_elements.h:44
EIGEN_STRONG_INLINE EIGEN_DEVICE_FUNC bfloat16 pow(const bfloat16 &a, const bfloat16 &b)
Definition: BFloat16.h:625
EIGEN_STRONG_INLINE const Eigen::CwiseBinaryOp< Eigen::internal::scalar_zeta_op< typename DerivedX::Scalar >, const DerivedX, const DerivedQ > zeta(const Eigen::ArrayBase< DerivedX > &x, const Eigen::ArrayBase< DerivedQ > &q)
Definition: SpecialFunctionsArrayAPI.h:152
r
Definition: UniformPSDSelfTest.py:20
std::string lower(std::string s)
returns the input string after converting upper-case characters to lower case
Definition: StringHelpers.cc:11
void broken_copy(const std::string &class_name)
Issue error message and terminate execution.
Definition: oomph_utilities.cc:212
const double Pi
50 digits from maple
Definition: oomph_utilities.h:157
void shape(const double &s, double *Psi)
Definition: shape.h:564
bool point_is_in_polygon(const Vector< double > &point, const Vector< Vector< double > > &polygon_vertex)
Definition: contact_elements.h:432
@ W
Definition: quadtree.h:63
DRAIG: Change all instances of (SPATIAL_DIM) to (DIM-1).
Definition: AnisotropicHookean.h:10
list x
Definition: plotDoE.py:28
t
Definition: plotPSD.py:36
#define OOMPH_EXCEPTION_LOCATION
Definition: oomph_definitions.h:61
#define OOMPH_CURRENT_FUNCTION
Definition: oomph_definitions.h:86
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2