airy_cantilever.cc
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-2023 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 //Driver for Airy cantilever beam problem
27 
28 //Oomph-lib includes
29 #include "generic.h"
30 #include "solid.h"
31 #include "constitutive.h"
32 
33 //The mesh
34 #include "meshes/rectangular_quadmesh.h"
35 
36 using namespace std;
37 
38 using namespace oomph;
39 
40 namespace oomph
41 {
42 
43 //=================start_wrapper==================================
44 /// Wrapper class for solid elements to modify their output
45 /// functions.
46 //================================================================
47 template <class ELEMENT>
48 class MySolidElement : public virtual ELEMENT
49 {
50 
51 public:
52 
53  /// Constructor: Call constructor of underlying element
54  MySolidElement() : ELEMENT() {};
55 
56  /// Overload output function:
57  void output(std::ostream &outfile, const unsigned &n_plot)
58  {
59 
60  // Element dimension
61  unsigned el_dim = this->dim();
62 
63  Vector<double> s(el_dim);
64  Vector<double> x(el_dim);
65  DenseMatrix<double> sigma(el_dim,el_dim);
66 
67  switch(el_dim)
68  {
69 
70  case 2:
71 
72  //Tecplot header info
73  outfile << "ZONE I=" << n_plot << ", J=" << n_plot << std::endl;
74 
75  //Loop over element nodes
76  for(unsigned l2=0;l2<n_plot;l2++)
77  {
78  s[1] = -1.0 + l2*2.0/(n_plot-1);
79  for(unsigned l1=0;l1<n_plot;l1++)
80  {
81  s[0] = -1.0 + l1*2.0/(n_plot-1);
82 
83  // Get Eulerian coordinates and stress
84  this->interpolated_x(s,x);
85  this->get_stress(s,sigma);
86 
87  //Output the x,y,..
88  for(unsigned i=0;i<el_dim;i++)
89  {outfile << x[i] << " ";}
90 
91  // Output stress
92  outfile << sigma(0,0) << " "
93  << sigma(1,0) << " "
94  << sigma(1,1) << " "
95  << std::endl;
96  }
97  }
98 
99  break;
100 
101  default:
102 
103  std::ostringstream error_message;
104  error_message << "Output for dim !=2 not implemented" << std::endl;
105  throw OomphLibError(error_message.str(),
106  OOMPH_CURRENT_FUNCTION,
107  OOMPH_EXCEPTION_LOCATION);
108  }
109 
110  }
111 
112 };
113 
114 
115 
116 //===========start_face_geometry==============================================
117 /// FaceGeometry of wrapped element is the same as the underlying element
118 //============================================================================
119 template<class ELEMENT>
120 class FaceGeometry<MySolidElement<ELEMENT> > :
121  public virtual FaceGeometry<ELEMENT>
122 {
123 public:
124 
125  /// Constructor [this was only required explicitly
126  /// from gcc 4.5.2 onwards...]
127  FaceGeometry() : FaceGeometry<ELEMENT>() {}
128 
129 };
130 
131 
132 }
133 
134 
135 
136 
137 
138 
139 /// ////////////////////////////////////////////////////////////////////
140 /// ////////////////////////////////////////////////////////////////////
141 /// ////////////////////////////////////////////////////////////////////
142 
143 
144 
145 //=======start_namespace==========================================
146 /// Global variables
147 //================================================================
149 {
150 
151  /// Half height of beam
152  double H=0.5;
153 
154  /// Length of beam
155  double L=10.0;
156 
157  /// Pointer to constitutive law
158  ConstitutiveLaw* Constitutive_law_pt;
159 
160  /// Elastic modulus
161  double E=1.0;
162 
163  /// Poisson's ratio
164  double Nu=0.3;
165 
166  /// Uniform pressure
167  double P = 0.0;
168 
169  /// Constant pressure load. The arguments to this function are imposed
170  /// on us by the SolidTractionElements which allow the traction to
171  /// depend on the Lagrangian and Eulerian coordinates x and xi, and on the
172  /// outer unit normal to the surface. Here we only need the outer unit
173  /// normal.
174  void constant_pressure(const Vector<double> &xi, const Vector<double> &x,
175  const Vector<double> &n, Vector<double> &traction)
176  {
177  unsigned dim = traction.size();
178  for(unsigned i=0;i<dim;i++)
179  {
180  traction[i] = -P*n[i];
181  }
182  } // end traction
183 
184 
185  /// Non-dim gravity
186  double Gravity=0.0;
187 
188  /// Non-dimensional gravity as body force
189  void gravity(const double& time,
190  const Vector<double> &xi,
191  Vector<double> &b)
192  {
193  b[0]=0.0;
194  b[1]=-Gravity;
195  }
196 
197 } //end namespace
198 
199 
200 
201 //=============begin_problem============================================
202 /// Problem class for the cantilever "beam" structure.
203 //======================================================================
204 template<class ELEMENT>
205 class CantileverProblem : public Problem
206 {
207 
208 public:
209 
210  /// Constructor:
212 
213  /// Update function (empty)
215 
216  /// Update function (empty)
218 
219  /// Access function for the solid mesh
220  ElasticRefineableRectangularQuadMesh<ELEMENT>*& solid_mesh_pt()
221  {return Solid_mesh_pt;}
222 
223  /// Access function to the mesh of surface traction elements
224  SolidMesh*& traction_mesh_pt(){return Traction_mesh_pt;}
225 
226  /// Actions before adapt: Wipe the mesh of traction elements
227  void actions_before_adapt();
228 
229  /// Actions after adapt: Rebuild the mesh of traction elements
230  void actions_after_adapt();
231 
232  /// Doc the solution
233  void doc_solution();
234 
235 private:
236 
237  /// Pass pointer to traction function to the
238  /// elements in the traction mesh
239  void set_traction_pt();
240 
241  /// Create traction elements
242  void create_traction_elements();
243 
244  /// Delete traction elements
245  void delete_traction_elements();
246 
247  /// Trace file
248  ofstream Trace_file;
249 
250  /// Pointers to node whose position we're tracing
252 
253  /// Pointer to solid mesh
254  ElasticRefineableRectangularQuadMesh<ELEMENT>* Solid_mesh_pt;
255 
256  /// Pointer to mesh of traction elements
257  SolidMesh* Traction_mesh_pt;
258 
259  /// DocInfo object for output
260  DocInfo Doc_info;
261 
262 };
263 
264 
265 //===========start_of_constructor=======================================
266 /// Constructor:
267 //======================================================================
268 template<class ELEMENT>
270 {
271 
272  // Create the mesh
273 
274  // # of elements in x-direction
275  unsigned n_x=20;
276 
277  // # of elements in y-direction
278  unsigned n_y=2;
279 
280  // Domain length in x-direction
281  double l_x= Global_Physical_Variables::L;
282 
283  // Domain length in y-direction
284  double l_y=2.0*Global_Physical_Variables::H;
285 
286  // Shift mesh downwards so that centreline is at y=0:
287  Vector<double> origin(2);
288  origin[0]=0.0;
289  origin[1]=-0.5*l_y;
290 
291  //Now create the mesh
292  solid_mesh_pt() = new ElasticRefineableRectangularQuadMesh<ELEMENT>(
293  n_x,n_y,l_x,l_y,origin);
294 
295  // Set error estimator
296  solid_mesh_pt()->spatial_error_estimator_pt()=new Z2ErrorEstimator;
297 
298  //Assign the physical properties to the elements before any refinement
299  //Loop over the elements in the main mesh
300  unsigned n_element =solid_mesh_pt()->nelement();
301  for(unsigned i=0;i<n_element;i++)
302  {
303  //Cast to a solid element
304  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(solid_mesh_pt()->element_pt(i));
305 
306  // Set the constitutive law
307  el_pt->constitutive_law_pt() =
309 
310  //Set the body force
311  el_pt->body_force_fct_pt() = Global_Physical_Variables::gravity;
312  }
313 
314 
315  // Choose a control node: The last node in the solid mesh
316  unsigned nnod=solid_mesh_pt()->nnode();
317  Trace_node_pt=solid_mesh_pt()->node_pt(nnod-1);
318 
319  // Refine the mesh uniformly
320  solid_mesh_pt()->refine_uniformly();
321 
322  // Construct the traction element mesh
323  Traction_mesh_pt=new SolidMesh;
324  create_traction_elements();
325 
326  // Pass pointer to traction function to the elements
327  // in the traction mesh
328  set_traction_pt();
329 
330  // Solid mesh is first sub-mesh
331  add_sub_mesh(solid_mesh_pt());
332 
333  // Add traction sub-mesh
334  add_sub_mesh(traction_mesh_pt());
335 
336  // Build combined "global" mesh
337  build_global_mesh();
338 
339  // Pin the left boundary (boundary 3) in both directions
340  unsigned n_side = mesh_pt()->nboundary_node(3);
341 
342  // Loop over the nodes
343  for(unsigned i=0;i<n_side;i++)
344  {
345  solid_mesh_pt()->boundary_node_pt(3,i)->pin_position(0);
346  solid_mesh_pt()->boundary_node_pt(3,i)->pin_position(1);
347  }
348 
349  // Pin the redundant solid pressures (if any)
350  PVDEquationsBase<2>::pin_redundant_nodal_solid_pressures(
351  solid_mesh_pt()->element_pt());
352 
353  //Attach the boundary conditions to the mesh
354  cout << assign_eqn_numbers() << std::endl;
355 
356  // Set output directory
357  Doc_info.set_directory("RESLT");
358 
359  // Open trace file
360  char filename[100];
361  sprintf(filename,"%s/trace.dat",Doc_info.directory().c_str());
362  Trace_file.open(filename);
363 
364 
365 } //end of constructor
366 
367 
368 //=====================start_of_actions_before_adapt======================
369 /// Actions before adapt: Wipe the mesh of traction elements
370 //========================================================================
371 template<class ELEMENT>
373 {
374  // Kill the traction elements and wipe surface mesh
375  delete_traction_elements();
376 
377  // Rebuild the Problem's global mesh from its various sub-meshes
378  rebuild_global_mesh();
379 
380 }// end of actions_before_adapt
381 
382 
383 
384 //=====================start_of_actions_after_adapt=======================
385 /// Actions after adapt: Rebuild the mesh of traction elements
386 //========================================================================
387 template<class ELEMENT>
389 {
390  // Create traction elements from all elements that are
391  // adjacent to boundary 2 and add them to surface meshes
392  create_traction_elements();
393 
394  // Rebuild the Problem's global mesh from its various sub-meshes
395  rebuild_global_mesh();
396 
397  // Pin the redundant solid pressures (if any)
398  PVDEquationsBase<2>::pin_redundant_nodal_solid_pressures(
399  solid_mesh_pt()->element_pt());
400 
401  // Set pointer to prescribed traction function for traction elements
402  set_traction_pt();
403 
404 }// end of actions_after_adapt
405 
406 
407 
408 //==================start_of_set_traction_pt==============================
409 /// Set pointer to traction function for the relevant
410 /// elements in the traction mesh
411 //========================================================================
412 template<class ELEMENT>
414 {
415  // Loop over the elements in the traction element mesh
416  // for elements on the top boundary (boundary 2)
417  unsigned n_element=traction_mesh_pt()->nelement();
418  for(unsigned i=0;i<n_element;i++)
419  {
420  //Cast to a solid traction element
421  SolidTractionElement<ELEMENT> *el_pt =
422  dynamic_cast<SolidTractionElement<ELEMENT>*>
423  (traction_mesh_pt()->element_pt(i));
424 
425  //Set the traction function
426  el_pt->traction_fct_pt() = Global_Physical_Variables::constant_pressure;
427  }
428 
429 }// end of set traction pt
430 
431 
432 
433 //============start_of_create_traction_elements==============================
434 /// Create traction elements
435 //=======================================================================
436 template<class ELEMENT>
438 {
439  // Traction elements are located on boundary 2:
440  unsigned b=2;
441 
442  // How many bulk elements are adjacent to boundary b?
443  unsigned n_element = solid_mesh_pt()->nboundary_element(b);
444 
445  // Loop over the bulk elements adjacent to boundary b
446  for(unsigned e=0;e<n_element;e++)
447  {
448  // Get pointer to the bulk element that is adjacent to boundary b
449  ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>(
450  solid_mesh_pt()->boundary_element_pt(b,e));
451 
452  //Find the index of the face of element e along boundary b
453  int face_index = solid_mesh_pt()->face_index_at_boundary(b,e);
454 
455  // Create new element and add to mesh
456  Traction_mesh_pt->add_element_pt(new SolidTractionElement<ELEMENT>
457  (bulk_elem_pt,face_index));
458  }
459 
460  // Pass the pointer to the traction function to the traction elements
461  set_traction_pt();
462 
463 } // end of create_traction_elements
464 
465 
466 
467 
468 //============start_of_delete_traction_elements==============================
469 /// Delete traction elements and wipe the traction meshes
470 //=======================================================================
471 template<class ELEMENT>
473 {
474  // How many surface elements are in the surface mesh
475  unsigned n_element = Traction_mesh_pt->nelement();
476 
477  // Loop over the surface elements
478  for(unsigned e=0;e<n_element;e++)
479  {
480  // Kill surface element
481  delete Traction_mesh_pt->element_pt(e);
482  }
483 
484  // Wipe the mesh
485  Traction_mesh_pt->flush_element_and_node_storage();
486 
487 } // end of delete_traction_elements
488 
489 
490 
491 //==============start_doc===========================================
492 /// Doc the solution
493 //==================================================================
494 template<class ELEMENT>
496 {
497 
498  ofstream some_file;
499  char filename[100];
500 
501  // Number of plot points
502  unsigned n_plot = 5;
503 
504  // Output shape of and stress in deformed body
505  //--------------------------------------------
506  sprintf(filename,"%s/soln%i.dat",Doc_info.directory().c_str(),
507  Doc_info.number());
508  some_file.open(filename);
509  solid_mesh_pt()->output(some_file,n_plot);
510  some_file.close();
511 
512 
513  // Output St. Venant solution
514  //---------------------------
515  sprintf(filename,"%s/exact_soln%i.dat",Doc_info.directory().c_str(),
516  Doc_info.number());
517  some_file.open(filename);
518 
519  // Element dimension
520  unsigned el_dim=2;
521 
522  Vector<double> s(el_dim);
523  Vector<double> x(el_dim);
524  Vector<double> xi(el_dim);
525  DenseMatrix<double> sigma(el_dim,el_dim);
526 
527  // Constants for exact (St. Venant) solution
528  double a=-1.0/4.0*Global_Physical_Variables::P;
530  double c=1.0/8.0*Global_Physical_Variables::P/
533 
534  // Loop over all elements to plot exact solution for stresses
535  unsigned nel=solid_mesh_pt()->nelement();
536  for (unsigned e=0;e<nel;e++)
537  {
538  // Get pointer to element
539  SolidFiniteElement* el_pt=dynamic_cast<SolidFiniteElement*>(
540  solid_mesh_pt()->element_pt(e));
541 
542  //Tecplot header info
543  some_file << "ZONE I=" << n_plot << ", J=" << n_plot << std::endl;
544 
545  //Loop over plot points
546  for(unsigned l2=0;l2<n_plot;l2++)
547  {
548  s[1] = -1.0 + l2*2.0/(n_plot-1);
549  for(unsigned l1=0;l1<n_plot;l1++)
550  {
551  s[0] = -1.0 + l1*2.0/(n_plot-1);
552 
553  // Get Eulerian and Lagrangian coordinates
554  el_pt->interpolated_x(s,x);
555  el_pt->interpolated_xi(s,xi);
556 
557  //Output the x,y,..
558  for(unsigned i=0;i<el_dim;i++)
559  {some_file << x[i] << " ";}
560 
561  // Change orientation of coordinate system relative
562  // to solution in lecture notes
563  double xx=Global_Physical_Variables::L-xi[0];
564  double yy=xi[1];
565 
566  // Approximate analytical (St. Venant) solution
567  sigma(0,0)=c*(6.0*xx*xx*yy-4.0*yy*yy*yy)+
568  6.0*d*yy;
569  sigma(1,1)=2.0*(a+b*yy+c*yy*yy*yy);
570  sigma(1,0)=2.0*(b*xx+3.0*c*xx*yy*yy);
571  sigma(0,1)=sigma(1,0);
572 
573  // Output stress
574  some_file << sigma(0,0) << " "
575  << sigma(1,0) << " "
576  << sigma(1,1) << " "
577  << std::endl;
578  }
579  }
580  }
581  some_file.close();
582 
583  // Write trace file: Load/displacement characteristics
584  Trace_file << Global_Physical_Variables::P << " "
585  << Trace_node_pt->x(0) << " "
586  << Trace_node_pt->x(1) << " "
587  << std::endl;
588 
589  // Increment label for output files
590  Doc_info.number()++;
591 
592 } //end doc
593 
594 
595 
596 //=======start_of_main==================================================
597 /// Driver for cantilever beam loaded by surface traction and/or
598 /// gravity
599 //======================================================================
600 int main()
601 {
602 
603  // Create generalised Hookean constitutive equations
605  new GeneralisedHookean(&Global_Physical_Variables::Nu,
607 
608  //Set up the problem
610 
611 
612  // Uncomment these as an exercise
613 
614  // CantileverProblem<MySolidElement<
615  // RefineableQPVDElementWithContinuousPressure<2> > > problem;
616 
617  // CantileverProblem<MySolidElement<
618  // RefineableQPVDElementWithPressure<2> > > problem;
619 
620  // Initial values for parameter values
623 
624  // Max. number of adaptations per solve
625  unsigned max_adapt=3;
626 
627  //Parameter incrementation
628  unsigned nstep=5;
629  double p_increment=1.0e-5;
630  for(unsigned i=0;i<nstep;i++)
631  {
632  // Increment pressure load
633  Global_Physical_Variables::P+=p_increment;
634 
635  // Solve the problem with Newton's method, allowing
636  // up to max_adapt mesh adaptations after every solve.
637  problem.newton_solve(max_adapt);
638 
639  // Doc solution
640  problem.doc_solution();
641 
642  }
643 
644 } //end of main
645 
646 
647 
648 
649 
650 
651 
652 
int main()
Driver for cantilever beam loaded by surface traction and/or gravity.
Problem class for the cantilever "beam" structure.
ElasticRefineableRectangularQuadMesh< ELEMENT > * Solid_mesh_pt
Pointer to solid mesh.
ElasticRefineableRectangularQuadMesh< ELEMENT > *& solid_mesh_pt()
Access function for the solid mesh.
void actions_before_newton_solve()
Update function (empty)
DocInfo Doc_info
DocInfo object for output.
void actions_after_newton_solve()
Update function (empty)
void actions_before_adapt()
Actions before adapt: Wipe the mesh of traction elements.
SolidMesh * Traction_mesh_pt
Pointer to mesh of traction elements.
void doc_solution()
Doc the solution.
Node * Trace_node_pt
Pointers to node whose position we're tracing.
void set_traction_pt()
Pass pointer to traction function to the elements in the traction mesh.
void create_traction_elements()
Create traction elements.
CantileverProblem()
Constructor:
void delete_traction_elements()
Delete traction elements.
ofstream Trace_file
Trace file.
void actions_after_adapt()
Actions after adapt: Rebuild the mesh of traction elements.
SolidMesh *& traction_mesh_pt()
Access function to the mesh of surface traction elements.
FaceGeometry()
Constructor [this was only required explicitly from gcc 4.5.2 onwards...].
Wrapper class for solid elements to modify their output functions.
void output(std::ostream &outfile, const unsigned &n_plot)
Overload output function:
MySolidElement()
Constructor: Call constructor of underlying element.
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
void gravity(const double &time, const Vector< double > &xi, Vector< double > &b)
Non-dimensional gravity as body force.
double E
Elastic modulus.
void constant_pressure(const Vector< double > &xi, const Vector< double > &x, const Vector< double > &n, Vector< double > &traction)
Constant pressure load. The arguments to this function are imposed on us by the SolidTractionElements...
double L
Length of beam.
double P
Uniform pressure.
double Nu
Poisson's ratio.
ConstitutiveLaw * Constitutive_law_pt
Pointer to constitutive law.
double Gravity
Non-dim gravity.
double H
Half height of beam.