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