Toggle navigation
Documentation
Big picture
The finite element method
The data structure
Not-so-quick guide
Optimisation
Order of action functions
Example codes and tutorials
List of example codes and tutorials
Meshing
Solvers
MPI parallel processing
Post-processing/visualisation
Other
Change log
Creating documentation
Coding conventions
Index
FAQ
About
People
Contact/Get involved
Publications
Acknowledgements
Copyright
Picture show
Go
demo_drivers
solid
unstructured_adaptive_solid
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
39
using namespace
std;
40
using namespace
oomph;
41
42
///////////////////////////////////////////////////////////////////////
43
///////////////////////////////////////////////////////////////////////
44
///////////////////////////////////////////////////////////////////////
45
46
47
48
//=======start_namespace==========================================
49
/// Global variables
50
//================================================================
51
namespace
Global_Physical_Variables
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:
91
UnstructuredSolidProblem
();
92
93
/// Destructor (empty)
94
~UnstructuredSolidProblem
(){}
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
123
bool
Incompressible
;
124
125
};
126
127
128
129
//===============start_constructor========================================
130
/// Constructor for unstructured solid problem
131
//========================================================================
132
template
<
class
ELEMENT>
133
UnstructuredSolidProblem<ELEMENT>::UnstructuredSolidProblem
() :
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>
270
void
UnstructuredSolidProblem<ELEMENT>::doc_solution
(DocInfo& doc_info)
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
//=======================================================================
308
template
<
class
ELEMENT>
309
double
UnstructuredSolidProblem<ELEMENT>::get_strain_energy
()
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>
331
void
UnstructuredSolidProblem<ELEMENT>::actions_before_adapt
()
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>
348
void
UnstructuredSolidProblem<ELEMENT>::actions_after_adapt
()
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() =
402
Global_Physical_Variables::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
429
Global_Physical_Variables::Constitutive_law_pt
=
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
437
UnstructuredSolidProblem<ProjectablePVDElement<TPVDElement<2,3>
> > problem;
438
439
//Output initial configuration
440
problem.
doc_solution
(doc_info);
441
doc_info.number()++;
442
443
// Parameter study
444
Global_Physical_Variables::P
=0.0;
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
485
UnstructuredSolidProblem
<
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
494
Global_Physical_Variables::P
=0.0;
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
534
UnstructuredSolidProblem
<
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
563
Global_Physical_Variables::P
=0.0;
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
UnstructuredSolidProblem
Unstructured solid problem.
Definition
unstructured_adaptive_solid.cc:86
UnstructuredSolidProblem::UnstructuredSolidProblem
UnstructuredSolidProblem()
Constructor:
Definition
unstructured_adaptive_solid.cc:133
UnstructuredSolidProblem::~UnstructuredSolidProblem
~UnstructuredSolidProblem()
Destructor (empty)
Definition
unstructured_adaptive_solid.cc:94
UnstructuredSolidProblem::Outer_boundary_polyline_pt
TriangleMeshPolygon * Outer_boundary_polyline_pt
Triangle mesh polygon for outer boundary.
Definition
unstructured_adaptive_solid.cc:120
UnstructuredSolidProblem::Traction_mesh_pt
SolidMesh * Traction_mesh_pt
Pointer to mesh of traction elements.
Definition
unstructured_adaptive_solid.cc:117
UnstructuredSolidProblem::actions_before_adapt
void actions_before_adapt()
Remove Traction Mesh.
Definition
unstructured_adaptive_solid.cc:331
UnstructuredSolidProblem::get_strain_energy
double get_strain_energy()
Calculate the strain energy.
Definition
unstructured_adaptive_solid.cc:309
UnstructuredSolidProblem::Incompressible
bool Incompressible
Boolean flag used in an incompressible problem.
Definition
unstructured_adaptive_solid.cc:123
UnstructuredSolidProblem::set_incompressible
void set_incompressible()
Set the problem to be incompressible.
Definition
unstructured_adaptive_solid.cc:97
UnstructuredSolidProblem::doc_solution
void doc_solution(DocInfo &doc_info)
Doc the solution.
Definition
unstructured_adaptive_solid.cc:270
UnstructuredSolidProblem::actions_after_adapt
void actions_after_adapt()
Add on the traction elements after adaptation.
Definition
unstructured_adaptive_solid.cc:348
UnstructuredSolidProblem::Solid_mesh_pt
RefineableSolidTriangleMesh< ELEMENT > * Solid_mesh_pt
Bulk mesh.
Definition
unstructured_adaptive_solid.cc:114
Global_Physical_Variables
Global variables.
Definition
unstructured_adaptive_solid.cc:52
Global_Physical_Variables::constant_pressure
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...
Definition
unstructured_adaptive_solid.cc:67
Global_Physical_Variables::P
double P
Uniform pressure.
Definition
unstructured_adaptive_solid.cc:60
Global_Physical_Variables::Constitutive_law_pt
ConstitutiveLaw * Constitutive_law_pt
Pointer to constitutive law.
Definition
unstructured_adaptive_solid.cc:57
Global_Physical_Variables::Nu
double Nu
Poisson's ratio.
Definition
unstructured_adaptive_solid.cc:54
main
int main(int argc, char **argv)
Demonstrate how to solve an unstructured solid problem.
Definition
unstructured_adaptive_solid.cc:419