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-2025 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
36using namespace std;
37
38using namespace oomph;
39
40namespace oomph
41{
42
43//=================start_wrapper==================================
44/// Wrapper class for solid elements to modify their output
45/// functions.
46//================================================================
47template <class ELEMENT>
48class MySolidElement : public virtual ELEMENT
49{
50
51public:
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//============================================================================
119template<class ELEMENT>
120class FaceGeometry<MySolidElement<ELEMENT> > :
121 public virtual FaceGeometry<ELEMENT>
122{
123public:
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//======================================================================
204template<class ELEMENT>
205class CantileverProblem : public Problem
206{
207
208public:
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
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
235private:
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
243
244 /// 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
258
259 /// DocInfo object for output
260 DocInfo Doc_info;
261
262};
263
264
265//===========start_of_constructor=======================================
266/// Constructor:
267//======================================================================
268template<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
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 snprintf(filename, sizeof(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//========================================================================
371template<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//========================================================================
387template<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//========================================================================
412template<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//=======================================================================
436template<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//=======================================================================
471template<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//==================================================================
494template<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 snprintf(filename, sizeof(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 snprintf(filename, sizeof(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//======================================================================
600int 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.
SolidMesh *& traction_mesh_pt()
Access function to the mesh of surface traction elements.
ElasticRefineableRectangularQuadMesh< ELEMENT > * Solid_mesh_pt
Pointer to 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.
ElasticRefineableRectangularQuadMesh< ELEMENT > *& solid_mesh_pt()
Access function for the solid 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.
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.