prescribed_displ_lagr_mult.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 Solid deformation -- driven by boundary motion which
27// is imposed via Lagrange multipliers
28
29
30//Oomph-lib includes
31#include "generic.h"
32#include "solid.h"
33#include "constitutive.h"
34
35//The mesh
36#include "meshes/rectangular_quadmesh.h"
37
38using namespace std;
39
40using namespace oomph;
41
42
43//================================================================
44/// Function-type-object to compare finite elements based on
45/// their x coordinate
46//================================================================
48{
49
50public:
51
52 /// Comparison. Is x coordinate of el1_pt less than that of el2_pt?
53 bool operator()(FiniteElement* const& el1_pt, FiniteElement* const& el2_pt)
54 const
55 {
56 return el1_pt->node_pt(0)->x(0) < el2_pt->node_pt(0)->x(0);
57 }
58
59};
60
61
62
63//======Start_of_warped_line===============================================
64/// Warped line in 2D space
65//=========================================================================
66class WarpedLine : public GeomObject
67{
68
69public:
70
71 /// Constructor: Specify amplitude of deflection from straight horizontal line
72 WarpedLine(const double& ampl) : GeomObject(1,2)
73 {
74 Ampl=ampl;
75 }
76
77 /// Broken copy constructor
78 WarpedLine(const WarpedLine& dummy)
79 {
80 BrokenCopy::broken_copy("WarpedLine");
81 }
82
83 /// Broken assignment operator
84 void operator=(const WarpedLine&)
85 {
86 BrokenCopy::broken_assign("WarpedLine");
87 }
88
89
90 /// Empty Destructor
92
93 /// Position vector at Lagrangian coordinate zeta
94 void position(const Vector<double>& zeta, Vector<double>& r) const
95 {
96 // Position vector
97 r[0] = zeta[0]+5.0*Ampl*zeta[0]*(zeta[0]-1.0)*(zeta[0]-0.7);
98 r[1] = 1.0+Ampl*0.5*(1.0-cos(2.0*MathematicalConstants::Pi*zeta[0]));
99 }
100
101 /// Parametrised position on object: r(zeta). Evaluated at
102 /// previous timestep. t=0: current time; t>0: previous
103 /// timestep. Forward to steady version
104 void position(const unsigned& t, const Vector<double>& zeta,
105 Vector<double>& r) const
106 {
107 position(zeta,r);
108 }
109
110 /// Access to amplitude
111 double& ampl() {return Ampl;}
112
113 /// How many items of Data does the shape of the object depend on?
114 /// None.
115 unsigned ngeom_data() const
116 {
117 return 0;
118 }
119
120private:
121
122 /// Amplitude of perturbation
123 double Ampl;
124
125};
126
127
128
129///////////////////////////////////////////////////////////////////////
130///////////////////////////////////////////////////////////////////////
131///////////////////////////////////////////////////////////////////////
132
133
134//=======start_namespace==========================================
135/// Global parameters
136//================================================================
138{
139
140 /// GeomObject specifying the shape of the boundary: Initially it's flat.
142
143 /// Poisson's ratio
144 double Nu=0.3;
145
146 // Generalised Hookean constitutive equations
147 GeneralisedHookean Constitutive_law(&Global_Physical_Variables::Nu);
148
149} //end namespace
150
151
152
153//=============begin_problem============================================
154/// Problem class for deformation of elastic block by prescribed
155/// boundary motion.
156//======================================================================
157template<class ELEMENT>
159{
160
161public:
162
163 /// Constructor:
165
166 /// Update function (empty)
168
169 /// Update function (empty)
171
172 /// Access function for the solid mesh
173 ElasticRefineableRectangularQuadMesh<ELEMENT>*& solid_mesh_pt()
174 {return Solid_mesh_pt;}
175
176 /// Actions before adapt: Wipe the mesh of Lagrange multiplier elements
178
179 /// Actions after adapt: Rebuild the mesh of Lagrange multiplier elements
180 void actions_after_adapt();
181
182 /// Doc the solution
183 void doc_solution();
184
185private:
186
187 /// Create elements that enforce prescribed boundary motion
188 /// by Lagrange multiplilers
190
191 /// Delete elements that enforce prescribed boundary motion
192 /// by Lagrange multiplilers
194
195 /// Pointer to solid mesh
196 ElasticRefineableRectangularQuadMesh<ELEMENT>* Solid_mesh_pt;
197
198 /// Pointers to meshes of Lagrange multiplier elements
200
201 /// DocInfo object for output
202 DocInfo Doc_info;
203
204};
205
206
207//===========start_of_constructor=======================================
208/// Constructor:
209//======================================================================
210template<class ELEMENT>
212{
213
214 // Create the mesh
215
216 // # of elements in x-direction
217 unsigned n_x=5;
218
219 // # of elements in y-direction
220 unsigned n_y=5;
221
222 // Domain length in x-direction
223 double l_x=1.0;
224
225 // Domain length in y-direction
226 double l_y=1.0;
227
228 //Now create the mesh
229 solid_mesh_pt() = new ElasticRefineableRectangularQuadMesh<ELEMENT>(
230 n_x,n_y,l_x,l_y);
231
232 // Set error estimator
233 solid_mesh_pt()->spatial_error_estimator_pt()=new Z2ErrorEstimator;
234
235 //Assign the physical properties to the elements before any refinement
236 //Loop over the elements in the main mesh
237 unsigned n_element =solid_mesh_pt()->nelement();
238 for(unsigned i=0;i<n_element;i++)
239 {
240 //Cast to a solid element
241 ELEMENT *el_pt = dynamic_cast<ELEMENT*>(solid_mesh_pt()->element_pt(i));
242
243 // Set the constitutive law
244 el_pt->constitutive_law_pt()=&Global_Physical_Variables::Constitutive_law;
245 }
246
247 // Refine the mesh uniformly
248 solid_mesh_pt()->refine_uniformly();
249
250 // Construct the mesh of elements that enforce prescribed boundary motion
251 // by Lagrange multipliers
252 Lagrange_multiplier_mesh_pt=new SolidMesh;
253 create_lagrange_multiplier_elements();
254
255 // Solid mesh is first sub-mesh
256 add_sub_mesh(solid_mesh_pt());
257
258 // Add Lagrange multiplier sub-mesh
259 add_sub_mesh(Lagrange_multiplier_mesh_pt);
260
261 // Build combined "global" mesh
262 build_global_mesh();
263
264 // Pin nodal positions on all boundaries apart from the top one (2)
265 for (unsigned b=0;b<4;b++)
266 {
267 if (b!=2)
268 {
269 unsigned n_side = solid_mesh_pt()->nboundary_node(b);
270
271 //Loop over the nodes
272 for(unsigned i=0;i<n_side;i++)
273 {
274 solid_mesh_pt()->boundary_node_pt(b,i)->pin_position(0);
275 solid_mesh_pt()->boundary_node_pt(b,i)->pin_position(1);
276 }
277 }
278 }
279
280 // Pin the redundant solid pressures (if any)
281 PVDEquationsBase<2>::pin_redundant_nodal_solid_pressures(
282 solid_mesh_pt()->element_pt());
283
284 // Setup equation numbering scheme
285 cout << "Number of dofs: " << assign_eqn_numbers() << std::endl;
286
287 // Set output directory
288 Doc_info.set_directory("RESLT");
289
290} //end of constructor
291
292
293//=====================start_of_actions_before_adapt======================
294/// Actions before adapt: Wipe the mesh of elements that impose
295/// the prescribed boundary displacements
296//========================================================================
297template<class ELEMENT>
299{
300 // Kill the elements and wipe surface mesh
301 delete_lagrange_multiplier_elements();
302
303 // Rebuild the Problem's global mesh from its various sub-meshes
304 rebuild_global_mesh();
305
306}// end of actions_before_adapt
307
308
309
310//=====================start_of_actions_after_adapt=======================
311/// Actions after adapt: Rebuild the mesh of elements that impose
312/// the prescribed boundary displacements
313//========================================================================
314template<class ELEMENT>
316{
317 // Create the elements that impose the displacement constraint
318 // and attach them to the bulk elements that are
319 // adjacent to boundary 2
320 create_lagrange_multiplier_elements();
321
322 // Rebuild the Problem's global mesh from its various sub-meshes
323 rebuild_global_mesh();
324
325 // Pin the redundant solid pressures (if any)
326 PVDEquationsBase<2>::pin_redundant_nodal_solid_pressures(
327 solid_mesh_pt()->element_pt());
328
329}// end of actions_after_adapt
330
331
332
333//============start_of_create_lagrange_multiplier_elements===============
334/// Create elements that impose the prescribed boundary displacement
335//=======================================================================
336template<class ELEMENT>
339{
340 // Lagrange multiplier elements are located on boundary 2:
341 unsigned b=2;
342
343 // How many bulk elements are adjacent to boundary b?
344 unsigned n_element = solid_mesh_pt()->nboundary_element(b);
345
346 // Loop over the bulk elements adjacent to boundary b?
347 for(unsigned e=0;e<n_element;e++)
348 {
349 // Get pointer to the bulk element that is adjacent to boundary b
350 ELEMENT* bulk_elem_pt = dynamic_cast<ELEMENT*>(
351 solid_mesh_pt()->boundary_element_pt(b,e));
352
353 //Find the index of the face of element e along boundary b
354 int face_index = solid_mesh_pt()->face_index_at_boundary(b,e);
355
356 // Create new element and add to mesh
357 Lagrange_multiplier_mesh_pt->add_element_pt(
358 new ImposeDisplacementByLagrangeMultiplierElement<ELEMENT>(
359 bulk_elem_pt,face_index));
360 }
361
362
363 // Loop over the elements in the Lagrange multiplier element mesh
364 // for elements on the top boundary (boundary 2)
365 n_element=Lagrange_multiplier_mesh_pt->nelement();
366 for(unsigned i=0;i<n_element;i++)
367 {
368 //Cast to a Lagrange multiplier element
369 ImposeDisplacementByLagrangeMultiplierElement<ELEMENT> *el_pt =
370 dynamic_cast<ImposeDisplacementByLagrangeMultiplierElement<ELEMENT>*>
371 (Lagrange_multiplier_mesh_pt->element_pt(i));
372
373 // Set the GeomObject that defines the boundary shape and
374 // specify which bulk boundary we are attached to (needed to extract
375 // the boundary coordinate from the bulk nodes)
376 el_pt->set_boundary_shape_geom_object_pt(
378
379 // Loop over the nodes
380 unsigned nnod=el_pt->nnode();
381 for (unsigned j=0;j<nnod;j++)
382 {
383 Node* nod_pt = el_pt->node_pt(j);
384
385 // Is the node also on boundary 1 or 3?
386 if ((nod_pt->is_on_boundary(1))||(nod_pt->is_on_boundary(3)))
387 {
388 // How many nodal values were used by the "bulk" element
389 // that originally created this node?
390 unsigned n_bulk_value=el_pt->nbulk_value(j);
391
392 // The remaining ones are Lagrange multipliers and we pin them.
393 unsigned nval=nod_pt->nvalue();
394 for (unsigned j=n_bulk_value;j<nval;j++)
395 {
396 nod_pt->pin(j);
397 }
398 }
399 }
400 }
401
402} // end of create_lagrange_multiplier_elements
403
404
405
406
407//====start_of_delete_lagrange_multiplier_elements=======================
408/// Delete elements that impose the prescribed boundary displacement
409/// and wipe the associated mesh
410//=======================================================================
411template<class ELEMENT>
413{
414 // How many surface elements are in the surface mesh
415 unsigned n_element = Lagrange_multiplier_mesh_pt->nelement();
416
417 // Loop over the surface elements
418 for(unsigned e=0;e<n_element;e++)
419 {
420 // Kill surface element
421 delete Lagrange_multiplier_mesh_pt->element_pt(e);
422 }
423
424 // Wipe the mesh
425 Lagrange_multiplier_mesh_pt->flush_element_and_node_storage();
426
427} // end of delete_lagrange_multiplier_elements
428
429
430
431//==============start_doc===========================================
432/// Doc the solution
433//==================================================================
434template<class ELEMENT>
436{
437
438 ofstream some_file;
439 char filename[100];
440
441 // Number of plot points
442 unsigned n_plot = 5;
443
444
445 // Output shape of deformed body
446 //------------------------------
447 snprintf(filename, sizeof(filename), "%s/soln%i.dat",Doc_info.directory().c_str(),
448 Doc_info.number());
449 some_file.open(filename);
450 solid_mesh_pt()->output(some_file,n_plot);
451 some_file.close();
452
453 // Output Lagrange multipliers
454 //----------------------------
455 snprintf(filename, sizeof(filename), "%s/lagr%i.dat",Doc_info.directory().c_str(),
456 Doc_info.number());
457 some_file.open(filename);
458
459 // This makes sure the elements are ordered in same way every time
460 // the code is run -- necessary for validation tests.
461 std::vector<FiniteElement*> el_pt;
462 unsigned nelem=Lagrange_multiplier_mesh_pt->nelement();
463 for (unsigned e=0;e<nelem;e++)
464 {
465 el_pt.push_back(Lagrange_multiplier_mesh_pt->finite_element_pt(e));
466 }
467 std::sort(el_pt.begin(),el_pt.end(),FiniteElementComp());
468 for (unsigned e=0;e<nelem;e++)
469 {
470 el_pt[e]->output(some_file);
471 }
472 some_file.close();
473
474 // Increment label for output files
475 Doc_info.number()++;
476
477} //end doc
478
479
480
481//=======start_of_main==================================================
482/// Driver code
483//======================================================================
484int main()
485{
486
487 //Set up the problem
489
490 // Doc initial domain shape
491 problem.doc_solution();
492
493 // Max. number of adaptations per solve
494 unsigned max_adapt=1;
495
496 //Parameter incrementation
497 unsigned nstep=2;
498 for(unsigned i=0;i<nstep;i++)
499 {
500 // Increment imposed boundary displacement
502
503 // Solve the problem with Newton's method, allowing
504 // up to max_adapt mesh adaptations after every solve.
505 problem.newton_solve(max_adapt);
506
507 // Doc solution
508 problem.doc_solution();
509
510 // For maximum stability: Reset the current nodal positions to be
511 // the "stress-free" ones -- this assignment means that the
512 // parameter study no longer corresponds to a physical experiment
513 // but is what we'd do if we wanted to use the solid solve
514 // to update a fluid mesh in an FSI problem, say.
515 problem.solid_mesh_pt()->set_lagrangian_nodal_coordinates();
516
517 }
518
519} //end of main
520
521
522
523
524
525
526
527
Function-type-object to compare finite elements based on their x coordinate.
bool operator()(FiniteElement *const &el1_pt, FiniteElement *const &el2_pt) const
Comparison. Is x coordinate of el1_pt less than that of el2_pt?
Problem class for deformation of elastic block by prescribed boundary motion.
void delete_lagrange_multiplier_elements()
Delete elements that enforce prescribed boundary motion by Lagrange multiplilers.
void actions_before_adapt()
Actions before adapt: Wipe the mesh of Lagrange multiplier elements.
ElasticRefineableRectangularQuadMesh< ELEMENT > *& solid_mesh_pt()
Access function for the solid mesh.
void actions_after_newton_solve()
Update function (empty)
ElasticRefineableRectangularQuadMesh< ELEMENT > * Solid_mesh_pt
Pointer to solid mesh.
void actions_after_adapt()
Actions after adapt: Rebuild the mesh of Lagrange multiplier elements.
SolidMesh * Lagrange_multiplier_mesh_pt
Pointers to meshes of Lagrange multiplier elements.
void actions_before_newton_solve()
Update function (empty)
void create_lagrange_multiplier_elements()
Create elements that enforce prescribed boundary motion by Lagrange multiplilers.
Warped line in 2D space.
void position(const unsigned &t, const Vector< double > &zeta, Vector< double > &r) const
Parametrised position on object: r(zeta). Evaluated at previous timestep. t=0: current time; t>0: pre...
~WarpedLine()
Empty Destructor.
WarpedLine(const WarpedLine &dummy)
Broken copy constructor.
WarpedLine(const double &ampl)
Constructor: Specify amplitude of deflection from straight horizontal line.
unsigned ngeom_data() const
How many items of Data does the shape of the object depend on? None.
void position(const Vector< double > &zeta, Vector< double > &r) const
Position vector at Lagrangian coordinate zeta.
double Ampl
Amplitude of perturbation.
void operator=(const WarpedLine &)
Broken assignment operator.
double & ampl()
Access to amplitude.
WarpedLine Boundary_geom_object(0.0)
GeomObject specifying the shape of the boundary: Initially it's flat.
int main()
Driver code.