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-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 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 
38 using namespace std;
39 
40 using namespace oomph;
41 
42 
43 //================================================================
44 /// Function-type-object to compare finite elements based on
45 /// their x coordinate
46 //================================================================
48 {
49 
50 public:
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 //=========================================================================
66 class WarpedLine : public GeomObject
67 {
68 
69 public:
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 
120 private:
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 //======================================================================
157 template<class ELEMENT>
159 {
160 
161 public:
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
177  void actions_before_adapt();
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 
185 private:
186 
187  /// Create elements that enforce prescribed boundary motion
188  /// by Lagrange multiplilers
189  void create_lagrange_multiplier_elements();
190 
191  /// Delete elements that enforce prescribed boundary motion
192  /// by Lagrange multiplilers
193  void delete_lagrange_multiplier_elements();
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 //======================================================================
210 template<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 //========================================================================
297 template<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 //========================================================================
314 template<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 //=======================================================================
336 template<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 //=======================================================================
411 template<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 //==================================================================
434 template<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  sprintf(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  sprintf(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 //======================================================================
484 int 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.
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.
ElasticRefineableRectangularQuadMesh< ELEMENT > *& solid_mesh_pt()
Access function for the solid mesh.
void actions_before_newton_solve()
Update function (empty)
void create_lagrange_multiplier_elements()
Create elements that enforce prescribed boundary motion by Lagrange multiplilers.
DocInfo Doc_info
DocInfo object for output.
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.