unstructured_adaptive_solid.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// Version 1.0; svn revision $LastChangedRevision$
7 //LIC//
8 //LIC// $LastChangedDate$
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 // Driver code for a simple unstructured solid problem using a mesh
31 // generated from an input file generated by the triangle mesh generator
32 // Triangle.
33 
34 //Generic routines
35 #include "generic.h"
36 #include "solid.h"
37 #include "constitutive.h"
38 
39 
40 // The mesh
41 #include "meshes/triangle_mesh.h"
42 
43 using namespace std;
44 using namespace oomph;
45 
46 ///////////////////////////////////////////////////////////////////////
47 ///////////////////////////////////////////////////////////////////////
48 ///////////////////////////////////////////////////////////////////////
49 
50 
51 
52 //=======start_namespace==========================================
53 /// Global variables
54 //================================================================
56 {
57  /// Poisson's ratio
58  double Nu=0.3;
59 
60  /// Pointer to constitutive law
61  ConstitutiveLaw* Constitutive_law_pt=0;
62 
63  /// Uniform pressure
64  double P = 0.0;
65 
66  /// \short Constant pressure load. The arguments to this function are imposed
67  /// on us by the SolidTractionElements which allow the traction to
68  /// depend on the Lagrangian and Eulerian coordinates x and xi, and on the
69  /// outer unit normal to the surface. Here we only need the outer unit
70  /// normal.
71  void constant_pressure(const Vector<double> &xi, const Vector<double> &x,
72  const Vector<double> &n, Vector<double> &traction)
73  {
74  unsigned dim = traction.size();
75  for(unsigned i=0;i<dim;i++)
76  {
77  traction[i] = -P*n[i];
78  }
79  }
80 
81 } //end namespace
82 
83 
84 
85 //==============start_problem=========================================
86 /// Unstructured solid problem
87 //====================================================================
88 template<class ELEMENT>
89 class UnstructuredSolidProblem : public Problem
90 {
91 
92 public:
93 
94  /// \short Constructor:
96 
97  /// Destructor (empty)
99 
100  /// Set the problem to be incompressible
101  void set_incompressible() {Incompressible=true;}
102 
103  /// Doc the solution
104  void doc_solution(DocInfo& doc_info);
105 
106  /// Calculate the strain energy
107  double get_strain_energy();
108 
109  /// Remove Traction Mesh
110  void actions_before_adapt();
111 
112  /// Add on the traction elements after adaptation
113  void actions_after_adapt();
114 
115 private:
116 
117  /// Bulk mesh
118  RefineableSolidTriangleMesh<ELEMENT>* Solid_mesh_pt;
119 
120  /// Pointer to mesh of traction elements
121  SolidMesh* Traction_mesh_pt;
122 
123  /// Triangle mesh polygon for outer boundary
124  TriangleMeshPolygon* Outer_boundary_polyline_pt;
125 
126  /// Boolean flag used in an incompressible problem
128 
129 };
130 
131 
132 
133 //===============start_constructor========================================
134 /// Constructor for unstructured solid problem
135 //========================================================================
136 template<class ELEMENT>
138  Incompressible(false)
139 {
140  // Build the boundary segments for outer boundary, consisting of
141  //--------------------------------------------------------------
142  // four separeate polyline segments
143  //---------------------------------
144  Vector<TriangleMeshCurveSection*> boundary_segment_pt(4);
145 
146  // Initialize boundary segment
147  Vector<Vector<double> > bound_seg(2);
148  for(unsigned i=0;i<2;i++) {bound_seg[i].resize(2);}
149 
150  // First boundary segment
151  bound_seg[0][0]=0.0;
152  bound_seg[0][1]=0.0;
153  bound_seg[1][0]=0.0;
154  bound_seg[1][1]=5.0;
155 
156  // Specify 1st boundary id
157  unsigned bound_id = 0;
158 
159  // Build the 1st boundary segment
160  boundary_segment_pt[0] = new TriangleMeshPolyLine(bound_seg,bound_id);
161 
162  // Second boundary segment
163  bound_seg[0][0]=0.0;
164  bound_seg[0][1]=5.0;
165  bound_seg[1][0]=1.0;
166  bound_seg[1][1]=5.0;
167 
168  // Specify 2nd boundary id
169  bound_id = 1;
170 
171  // Build the 2nd boundary segment
172  boundary_segment_pt[1] = new TriangleMeshPolyLine(bound_seg,bound_id);
173 
174  // Third boundary segment
175  bound_seg[0][0]=1.0;
176  bound_seg[0][1]=5.0;
177  bound_seg[1][0]=1.0;
178  bound_seg[1][1]=0.0;
179 
180  // Specify 3rd boundary id
181  bound_id = 2;
182 
183  // Build the 3rd boundary segment
184  boundary_segment_pt[2] = new TriangleMeshPolyLine(bound_seg,bound_id);
185 
186  // Fourth boundary segment
187  bound_seg[0][0]=1.0;
188  bound_seg[0][1]=0.0;
189  bound_seg[1][0]=0.0;
190  bound_seg[1][1]=0.0;
191 
192  // Specify 4th boundary id
193  bound_id = 3;
194 
195  // Build the 4th boundary segment
196  boundary_segment_pt[3] = new TriangleMeshPolyLine(bound_seg,bound_id);
197 
198  // Create the triangle mesh polygon for outer boundary using boundary segment
199  Outer_boundary_polyline_pt = new TriangleMeshPolygon(boundary_segment_pt);
200 
201 
202  // There are no holes
203  //-------------------------------
204 
205  // Now build the mesh, based on the boundaries specified by
206  //---------------------------------------------------------
207  // polygons just created
208  //----------------------
209  double uniform_element_area=0.2;
210 
211  TriangleMeshClosedCurve* closed_curve_pt=Outer_boundary_polyline_pt;
212 
213  // Use the TriangleMeshParameters object for gathering all
214  // the necessary arguments for the TriangleMesh object
215  TriangleMeshParameters triangle_mesh_parameters(
216  closed_curve_pt);
217 
218  // Define the maximum element area
219  triangle_mesh_parameters.element_area() =
220  uniform_element_area;
221 
222  // Create the mesh
223  Solid_mesh_pt =
224  new RefineableSolidTriangleMesh<ELEMENT>(
225  triangle_mesh_parameters);
226 
227  //hierher
228  // Disable the use of an iterative solver for the projection
229  // stage during mesh adaptation
230  Solid_mesh_pt->disable_iterative_solver_for_projection();
231 
232  // Set error estimator for bulk mesh
233  Z2ErrorEstimator* error_estimator_pt=new Z2ErrorEstimator;
234  Solid_mesh_pt->spatial_error_estimator_pt()=error_estimator_pt;
235 
236 
237  // Set targets for spatial adaptivity
238  Solid_mesh_pt->max_permitted_error()=0.0001;
239  Solid_mesh_pt->min_permitted_error()=0.001;
240  Solid_mesh_pt->max_element_size()=0.2;
241  Solid_mesh_pt->min_element_size()=0.001;
242 
243  // Output mesh boundaries
244  this->Solid_mesh_pt->output_boundaries("boundaries.dat");
245 
246  // Make the traction mesh
247  Traction_mesh_pt=new SolidMesh;
248 
249  // Add sub meshes
250  add_sub_mesh(Solid_mesh_pt);
251  add_sub_mesh(Traction_mesh_pt);
252 
253  // Build the global mesh
254  build_global_mesh();
255 
256  //Call actions after adapt:
257  // 1) to build the traction elements
258  // 2) to pin the nodes on the lower boundary (boundary 3)
259  // 3) to complete the build of the elements
260  // Note there is slight duplication here because we rebuild the global mesh
261  // twice.
262  this->actions_after_adapt();
263 
264  // Setup equation numbering scheme
265  cout <<"Number of equations: " << assign_eqn_numbers() << std::endl;
266 
267 } //end constructor
268 
269 
270 //========================================================================
271 /// Doc the solution
272 //========================================================================
273 template<class ELEMENT>
275 {
276 
277  ofstream some_file;
278  char filename[100];
279 
280  // Number of plot points
281  unsigned npts;
282  npts=5;
283 
284  // Output solution
285  //----------------
286  sprintf(filename,"%s/soln%i.dat",doc_info.directory().c_str(),
287  doc_info.number());
288  some_file.open(filename);
289  Solid_mesh_pt->output(some_file,npts);
290  some_file.close();
291 
292  // Output traction
293  //----------------
294  sprintf(filename,"%s/traction%i.dat",doc_info.directory().c_str(),
295  doc_info.number());
296  some_file.open(filename);
297  Traction_mesh_pt->output(some_file,npts);
298  some_file.close();
299 
300  // Output boundaries
301  //------------------
302  sprintf(filename,"%s/boundaries.dat",doc_info.directory().c_str());
303  some_file.open(filename);
304  Solid_mesh_pt->output_boundaries(some_file);
305  some_file.close();
306 
307 }
308 
309 //================start_get_strain_energy================================
310 /// Calculate the strain energy in the entire elastic solid
311 //=======================================================================
312 template<class ELEMENT>
314 {
315  double strain_energy=0.0;
316  const unsigned n_element = Solid_mesh_pt->nelement();
317  for(unsigned e=0;e<n_element;e++)
318  {
319  //Cast to a solid element
320  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(Solid_mesh_pt->element_pt(e));
321 
322  double pot_en, kin_en;
323  el_pt->get_energy(pot_en,kin_en);
324  strain_energy += pot_en;
325  }
326 
327  return strain_energy;
328 } // end_get_strain_energy
329 
330 
331 //==============start_actions_before_adapt================================
332 /// Actions before adapt: remove the traction elements in the surface mesh
333 //========================================================================
334 template<class ELEMENT>
336 {
337  // How many surface elements are in the surface mesh
338  unsigned n_element = Traction_mesh_pt->nelement();
339 
340  // Loop over the surface elements and kill them
341  for(unsigned e=0;e<n_element;e++) {delete Traction_mesh_pt->element_pt(e);}
342 
343  // Wipe the mesh
344  Traction_mesh_pt->flush_element_and_node_storage();
345 
346 } // end_actions_before_adapt
347 
348 //=================start_actions_after_adapt=============================
349  /// Need to add on the traction elements after adaptation
350 //=======================================================================
351 template<class ELEMENT>
353 {
354  //The boundary in question is boundary 0
355  unsigned b=0;
356 
357  // How many bulk elements are adjacent to boundary b?
358  unsigned n_element = Solid_mesh_pt->nboundary_element(b);
359  // Loop over the bulk elements adjacent to boundary b
360  for(unsigned e=0;e<n_element;e++)
361  {
362  // Get pointer to the bulk element that is adjacent to boundary b
363  ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>(
364  Solid_mesh_pt->boundary_element_pt(b,e));
365 
366  //Find the index of the face of element e along boundary b
367  int face_index = Solid_mesh_pt->face_index_at_boundary(b,e);
368 
369  //Create solid traction element
370  SolidTractionElement<ELEMENT> *el_pt =
371  new SolidTractionElement<ELEMENT>(bulk_elem_pt,face_index);
372 
373  // Add to mesh
374  Traction_mesh_pt->add_element_pt(el_pt);
375 
376  //Set the traction function
377  el_pt->traction_fct_pt() = Global_Physical_Variables::constant_pressure;
378  }
379 
380  //Now rebuild the global mesh
381  this->rebuild_global_mesh();
382 
383  //(Re)set the boundary conditions
384  //Pin both positions at lower boundary (boundary 3)
385  unsigned ibound=3;
386  unsigned num_nod= mesh_pt()->nboundary_node(ibound);
387  for (unsigned inod=0;inod<num_nod;inod++)
388  {
389  // Get node
390  SolidNode* nod_pt=Solid_mesh_pt->boundary_node_pt(ibound,inod);
391 
392  // Pin both directions
393  for (unsigned i=0;i<2;i++) {nod_pt->pin_position(i);}
394  }
395  //End of set boundary conditions
396 
397  // Complete the build of all elements so they are fully functional
398  n_element = Solid_mesh_pt->nelement();
399  for(unsigned e=0;e<n_element;e++)
400  {
401  //Cast to a solid element
402  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(Solid_mesh_pt->element_pt(e));
403 
404  // Set the constitutive law
405  el_pt->constitutive_law_pt() =
407 
408  //Set the incompressibility flag if required
409  if(Incompressible)
410  {
411  //Need another dynamic cast
412  dynamic_cast<TPVDElementWithContinuousPressure<2>*>(el_pt)
413  ->set_incompressible();
414  }
415  }
416 
417 } // end_actions_after_adapt
418 
419 
420 //===========start_main===================================================
421 /// Demonstrate how to solve an unstructured solid problem
422 //========================================================================
423 int main(int argc, char **argv)
424 {
425 
426  //Doc info object
427  DocInfo doc_info;
428 
429  // Output directory
430  doc_info.set_directory("RESLT");
431 
432  // Create generalised Hookean constitutive equations
434  new GeneralisedHookean(&Global_Physical_Variables::Nu);
435 
436  {
437  std::ofstream strain("RESLT/s_energy.dat");
438  std::cout << "Running with pure displacement formulation\n";
439 
440  //Set up the problem
442 
443  //Output initial configuration
444  problem.doc_solution(doc_info);
445  doc_info.number()++;
446 
447  // Parameter study
449  double pressure_increment=0.1e-2;
450 
451  unsigned nstep=5;
452 
453  for (unsigned istep=0;istep<nstep;istep++)
454  {
455  // Solve the problem with one round of adaptivity
456  problem.newton_solve(1);
457 
458  double strain_energy = problem.get_strain_energy();
459  std::cout << "Strain energy is " << strain_energy << "\n";
460  //Output strain energy to file
461  strain << Global_Physical_Variables::P << " " << strain_energy << std::endl;
462 
463  //Output solution
464  problem.doc_solution(doc_info);
465  doc_info.number()++;
466 
467  //Reverse direction of increment
468  if(istep==2) {pressure_increment *= -1.0;}
469 
470  // Increase (or decrease) load
471  Global_Physical_Variables::P+=pressure_increment;
472  }
473 
474  strain.close();
475  } //end_displacement_formulation
476 
477 
478  //Repeat for displacement/pressure formulation
479  {
480  std::ofstream strain("RESLT_pres_disp/s_energy.dat");
481  std::cout << "Running with pressure/displacement formulation\n";
482 
483  // Change output directory
484  doc_info.set_directory("RESLT_pres_disp");
485  //Reset doc_info number
486  doc_info.number() = 0;
487 
488  //Set up the problem
490  ProjectablePVDElementWithContinuousPressure<
491  TPVDElementWithContinuousPressure<2> > > problem;
492 
493  //Output initial configuration
494  problem.doc_solution(doc_info);
495  doc_info.number()++;
496 
497  // Parameter study
499  double pressure_increment=0.1e-2;
500 
501  unsigned nstep=5;
502  for (unsigned istep=0;istep<nstep;istep++)
503  {
504  // Solve the problem
505  problem.newton_solve(1);
506 
507  double strain_energy = problem.get_strain_energy();
508  std::cout << "Strain energy is "<< strain_energy << "\n";
509  //Output strain energy to file
510  strain << Global_Physical_Variables::P << " " << strain_energy << std::endl;
511 
512  //Output solution
513  problem.doc_solution(doc_info);
514  doc_info.number()++;
515 
516  if(istep==2) {pressure_increment *= -1.0;}
517  // Increase (or decrease) pressure load
518  Global_Physical_Variables::P+=pressure_increment;
519  }
520 
521  strain.close();
522  }
523 
524 
525  //Repeat for displacement/pressure formulation
526  //enforcing incompressibility
527  {
528  std::ofstream strain("RESLT_pres_disp_incomp/s_energy.dat");
529  std::cout <<
530  "Running with pressure/displacement formulation (incompressible) \n";
531 
532  // Change output directory
533  doc_info.set_directory("RESLT_pres_disp_incomp");
534  //Reset doc_info number
535  doc_info.number() = 0;
536 
537  //Set up the problem
539  ProjectablePVDElementWithContinuousPressure<
540  TPVDElementWithContinuousPressure<2> > > problem;
541 
542  //Loop over all elements and set incompressibility flag
543  {
544  const unsigned n_element = problem.mesh_pt()->nelement();
545  for(unsigned e=0;e<n_element;e++)
546  {
547  //Cast the element to the equation base of our 2D elastiticy elements
548  PVDEquationsWithPressure<2> *cast_el_pt =
549  dynamic_cast<PVDEquationsWithPressure<2>*>(
550  problem.mesh_pt()->element_pt(e));
551 
552  //If the cast was successful, it's a bulk element,
553  //so set the incompressibilty flag
554  if(cast_el_pt) {cast_el_pt->set_incompressible();}
555  }
556  }
557 
558  //Turn on the incompressibity flag so that elements stay incompressible
559  //after refinement
560  problem.set_incompressible();
561 
562  //Output initial configuration
563  problem.doc_solution(doc_info);
564  doc_info.number()++;
565 
566  // Parameter study
568  double pressure_increment=0.1e-2;
569 
570  unsigned nstep=5;
571  for (unsigned istep=0;istep<nstep;istep++)
572  {
573  // Solve the problem
574  problem.newton_solve(1);
575 
576  double strain_energy = problem.get_strain_energy();
577  std::cout << "Strain energy is " << strain_energy << "\n";
578  //Output strain energy to file
579  strain << Global_Physical_Variables::P << " " << strain_energy << std::endl;
580 
581  //Output solution
582  problem.doc_solution(doc_info);
583  doc_info.number()++;
584 
585  if(istep==2) {pressure_increment *= -1.0;}
586  // Increase (or decrease) pressure load
587  Global_Physical_Variables::P+=pressure_increment;
588  }
589 
590  strain.close();
591  }
592 
593 } // end main
594 
595 
596 
void set_incompressible()
Set the problem to be incompressible.
int main(int argc, char **argv)
Demonstrate how to solve an unstructured solid problem.
void doc_solution(DocInfo &doc_info)
Doc the solution.
Unstructured solid problem.
void actions_before_adapt()
Remove Traction Mesh.
bool Incompressible
Boolean flag used in an incompressible problem.
SolidMesh * Traction_mesh_pt
Pointer to mesh of traction elements.
ConstitutiveLaw * Constitutive_law_pt
Pointer to constitutive law.
void actions_after_adapt()
Add on the traction elements after adaptation.
double get_strain_energy()
Calculate the strain energy.
TriangleMeshPolygon * Outer_boundary_polyline_pt
Triangle mesh polygon for outer boundary.
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...
RefineableSolidTriangleMesh< ELEMENT > * Solid_mesh_pt
Bulk mesh.
~UnstructuredSolidProblem()
Destructor (empty)
double Nu
Poisson&#39;s ratio.