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-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 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
39using namespace std;
40using 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//====================================================================
84template<class ELEMENT>
85class UnstructuredSolidProblem : public Problem
86{
87
88public:
89
90 /// Constructor:
92
93 /// Destructor (empty)
95
96 /// Set the problem to be incompressible
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
107
108 /// Add on the traction elements after adaptation
109 void actions_after_adapt();
110
111private:
112
113 /// Bulk mesh
114 RefineableSolidTriangleMesh<ELEMENT>* Solid_mesh_pt;
115
116 /// Pointer to mesh of traction elements
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//========================================================================
132template<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
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//========================================================================
269template<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 snprintf(filename, sizeof(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 snprintf(filename, sizeof(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 snprintf(filename, sizeof(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//=======================================================================
308template<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//========================================================================
330template<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//=======================================================================
347template<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//========================================================================
419int 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.