elastic_mesh_update.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 // Solve Poisson equation in deformable fish-shaped domain.
27 // Mesh deformation is driven by pseudo-elasticity approach.
28 
29 // Generic oomph-lib headers
30 #include "generic.h"
31 
32 // Poisson equations
33 #include "poisson.h"
34 
35 // Solid mechanics
36 #include "solid.h"
37 
38 // The fish mesh
39 #include "meshes/fish_mesh.h"
40 
41 using namespace std;
42 
43 using namespace oomph;
44 
45 /// ////////////////////////////////////////////////////////////////////
46 /// ////////////////////////////////////////////////////////////////////
47 /// ////////////////////////////////////////////////////////////////////
48 
49 
50 
51 //====================================================================
52 /// Namespace for const source term in Poisson equation
53 //====================================================================
54 namespace ConstSourceForPoisson
55 {
56  /// Strength of source function: default value 1.0
57  double Strength=1.0;
58 
59 /// Const source function
60  void get_source(const Vector<double>& x, double& source)
61  {
62  source = -Strength;
63  }
64 
65 }
66 
67 /// ////////////////////////////////////////////////////////////////////
68 /// ////////////////////////////////////////////////////////////////////
69 /// ////////////////////////////////////////////////////////////////////
70 
71 //=========================================================================
72 /// Refineable fish mesh upgraded to become a solid mesh
73 //=========================================================================
74 template<class ELEMENT>
75 class ElasticFishMesh : public virtual RefineableFishMesh<ELEMENT>,
76  public virtual SolidMesh
77 {
78 
79 public:
80 
81  /// Constructor: Build underlying adaptive fish mesh and then
82  /// set current Eulerian coordinates to be the Lagrangian ones.
83  /// Pass pointer to geometric objects that specify the
84  /// fish's back in the "current" and "undeformed" configurations,
85  /// and pointer to timestepper (defaults to Static)
86  // Note: FishMesh is virtual base and its constructor is automatically
87  // called first! --> this is where we need to build the mesh;
88  // the constructors of the derived meshes don't call the
89  // base constructor again and simply add the extra functionality.
90  ElasticFishMesh(GeomObject* back_pt, GeomObject* undeformed_back_pt,
91  TimeStepper* time_stepper_pt=&Mesh::Default_TimeStepper) :
92  FishMesh<ELEMENT>(back_pt,time_stepper_pt),
93  RefineableFishMesh<ELEMENT>(back_pt,time_stepper_pt)
94  {
95  // Mesh has been built, adaptivity etc has been set up -->
96  // assign the Lagrangian coordinates so that the current
97  // configuration becomes the stress-free initial configuration
98  set_lagrangian_nodal_coordinates();
99 
100  // Build "undeformed" domain: This is a "deep" copy of the
101  // Domain that we used to create set the Eulerian coordinates
102  // in the initial mesh -- the original domain (accessible via
103  // the private member data Domain_pt) will be used to update
104  // the position of boundary nodes; the copy that we're
105  // creating here will be used to determine the Lagrangian coordinates
106  // of any newly created SolidNodes during mesh refinement
107  double xi_nose = this->Domain_pt->xi_nose();
108  double xi_tail = this->Domain_pt->xi_tail();
109  Undeformed_domain_pt=new FishDomain(undeformed_back_pt,xi_nose,xi_tail);
110 
111  // Loop over all elements and set the undeformed macro element pointer
112  unsigned n_element=this->nelement();
113  for (unsigned e=0;e<n_element;e++)
114  {
115  // Get pointer to full element type
116  ELEMENT* el_pt=dynamic_cast<ELEMENT*>(this->element_pt(e));
117 
118  // Set pointer to macro element so the curvlinear boundaries
119  // of the undeformed mesh/domain get picked up during adaptive
120  // mesh refinement
121  el_pt->set_undeformed_macro_elem_pt(
122  Undeformed_domain_pt->macro_element_pt(e));
123  }
124 
125  }
126 
127  /// Destructor: Kill "undeformed" Domain
129  {
130  delete Undeformed_domain_pt;
131  }
132 
133 private:
134 
135  /// Pointer to "undeformed" Domain -- used to determine the
136  /// Lagrangian coordinates of any newly created SolidNodes during
137  /// Mesh refinement
139 
140 };
141 
142 
143 
144 
145 /// ////////////////////////////////////////////////////////////////////
146 /// ////////////////////////////////////////////////////////////////////
147 /// ////////////////////////////////////////////////////////////////////
148 
149 
150 
151 
152 //================================================================
153 /// Global variables
154 //================================================================
156 {
157  /// Pointer to constitutive law
158  ConstitutiveLaw* Constitutive_law_pt;
159 
160  /// Poisson's ratio
161  double Nu=0.3;
162 
163 }
164 
165 
166 /// ////////////////////////////////////////////////////////////////////
167 /// ////////////////////////////////////////////////////////////////////
168 /// ////////////////////////////////////////////////////////////////////
169 
170 
171 
172 //======================================================================
173 /// Solve Poisson equation on deforming fish-shaped domain.
174 /// Mesh update via pseudo-elasticity.
175 //======================================================================
176 template<class ELEMENT>
177 class DeformableFishPoissonProblem : public Problem
178 {
179 
180 public:
181 
182  /// Constructor:
184 
185  /// Run simulation
186  void run();
187 
188  /// Access function for the specific mesh
190  {return dynamic_cast<ElasticFishMesh<ELEMENT>*>(Problem::mesh_pt());}
191 
192  /// Doc the solution
193  void doc_solution(DocInfo& doc_info);
194 
195  /// Update function (empty)
197 
198  /// Update before solve: We're dealing with a static problem so
199  /// the nodal positions before the next solve merely serve as
200  /// initial conditions. For meshes that are very strongly refined
201  /// near the boundary, the update of the displacement boundary
202  /// conditions (which only moves the SolidNodes *on* the boundary),
203  /// can lead to strongly distorted meshes. This can cause the
204  /// Newton method to fail --> the overall method is actually more robust
205  /// if we use the nodal positions as determined by the Domain/MacroElement-
206  /// based mesh update as initial guesses.
208  {
209  bool update_all_solid_nodes=true;
210  mesh_pt()->node_update(update_all_solid_nodes);
211 
212  // Now set the Eulerian equal to the Lagrangian coordinates
213  mesh_pt()->set_lagrangian_nodal_coordinates();
214 
215  }
216 
217  /// Update after adapt: Pin all redundant solid pressure nodes (if required)
219  {
220  // Pin the redundant solid pressures (if any)
221  PVDEquationsBase<2>::pin_redundant_nodal_solid_pressures(
222  mesh_pt()->element_pt());
223  }
224 
225 private:
226 
227 
228  /// Node at which the solution of the Poisson equation is documented
229  Node* Doc_node_pt;
230 
231  /// Trace file
232  ofstream Trace_file;
233 
234  // Geometric object that represents the deformable fish back
235  Circle* Fish_back_pt;
236 
237 };
238 
239 //======================================================================
240 /// Constructor:
241 //======================================================================
242 template<class ELEMENT>
244 {
245 
246  // Set coordinates and radius for the circle that will become the fish back
247  double x_c=0.5;
248  double y_c=0.0;
249  double r_back=1.0;
250 
251  // Build geometric object that will become the deformable fish back
252  //GeomObject* fish_back_pt=new ElasticFishBackElement(x_c,y_c,r_back);
253  Fish_back_pt=new Circle(x_c,y_c,r_back);
254 
255  // Build geometric object that specifies the fish back in the
256  // undeformed configuration (basically a deep copy of the previous one)
257  GeomObject* undeformed_fish_back_pt=new Circle(x_c,y_c,r_back);
258 
259  // Build fish mesh with geometric object that specifies the deformable
260  // and undeformed fish back
261  Problem::mesh_pt()=new ElasticFishMesh<ELEMENT>(Fish_back_pt,
262  undeformed_fish_back_pt);
263 
264 
265  // Choose a node at which the solution is documented: Choose
266  // the central node that is shared by all four elements in
267  // the base mesh because it exists at all refinement levels.
268 
269  // How many nodes does element 0 have?
270  unsigned nnod=mesh_pt()->finite_element_pt(0)->nnode();
271 
272  // The central node is the last node in element 0:
273  Doc_node_pt=mesh_pt()->finite_element_pt(0)->node_pt(nnod-1);
274 
275  // Doc
276  cout << std::endl << "Control node is located at: "
277  << Doc_node_pt->x(0) << " " << Doc_node_pt->x(1) << std::endl << std::endl;
278 
279 
280  // Set error estimator
281  Z2ErrorEstimator* error_estimator_pt=new Z2ErrorEstimator;
282  mesh_pt()->spatial_error_estimator_pt()=error_estimator_pt;
283 
284  // Change/doc targets for mesh adaptation
285  if (CommandLineArgs::Argc>1)
286  {
287  mesh_pt()->max_permitted_error()=0.05;
288  mesh_pt()->min_permitted_error()=0.005;
289  }
290  mesh_pt()->doc_adaptivity_targets(cout);
291 
292 
293  // Specify BC/source fct for Poisson problem:
294  //-------------------------------------------
295 
296  // Set the Poisson boundary conditions for this problem: All nodes are
297  // free by default -- just pin the ones that have Dirichlet conditions
298  // here.
299  unsigned num_bound = mesh_pt()->nboundary();
300  for(unsigned ibound=0;ibound<num_bound;ibound++)
301  {
302  unsigned num_nod=mesh_pt()->nboundary_node(ibound);
303  for (unsigned inod=0;inod<num_nod;inod++)
304  {
305  mesh_pt()->boundary_node_pt(ibound,inod)->pin(0);
306  }
307  }
308 
309  // Set homogeneous boundary conditions for the Poisson equation
310  // on all boundaries
311  for(unsigned ibound=0;ibound<num_bound;ibound++)
312  {
313  // Loop over the nodes on boundary
314  unsigned num_nod=mesh_pt()->nboundary_node(ibound);
315  for (unsigned inod=0;inod<num_nod;inod++)
316  {
317  mesh_pt()->boundary_node_pt(ibound,inod)->set_value(0,0.0);
318  }
319  }
320 
321  /// Loop over elements and set pointers to source function
322  unsigned n_element = mesh_pt()->nelement();
323  for(unsigned i=0;i<n_element;i++)
324  {
325  // Upcast from FiniteElement to the present element
326  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(mesh_pt()->element_pt(i));
327 
328  //Set the source function pointer
329  el_pt->source_fct_pt() = &ConstSourceForPoisson::get_source;
330  }
331 
332 
333  // Specify BC/source fct etc for (pseudo-)Solid problem
334  //-----------------------------------------------------
335 
336  // Pin all nodal positions
337  for(unsigned ibound=0;ibound<num_bound;ibound++)
338  {
339  unsigned num_nod=mesh_pt()->nboundary_node(ibound);
340  for (unsigned inod=0;inod<num_nod;inod++)
341  {
342  for (unsigned i=0;i<2;i++)
343  {
344  mesh_pt()->boundary_node_pt(ibound,inod)->pin_position(i);
345  }
346  }
347  }
348 
349  //Loop over the elements in the mesh to set Solid parameters/function pointers
350  for(unsigned i=0;i<n_element;i++)
351  {
352  //Cast to a solid element
353  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(mesh_pt()->element_pt(i));
354 
355  // Set the constitutive law
356  el_pt->constitutive_law_pt() =
358  }
359 
360  // Pin the redundant solid pressures (if any)
361  PVDEquationsBase<2>::pin_redundant_nodal_solid_pressures(
362  mesh_pt()->element_pt());
363 
364 
365  //Attach the boundary conditions to the mesh
366  cout << assign_eqn_numbers() << std::endl;
367 
368  // Refine the problem uniformly (this automatically passes the
369  // function pointers/parameters to the finer elements
370  refine_uniformly();
371 
372  // The non-pinned positions of the newly SolidNodes will have been
373  // determined by interpolation. Update all solid nodes based on
374  // the Mesh's Domain/MacroElement representation.
375  bool update_all_solid_nodes=true;
376  mesh_pt()->node_update(update_all_solid_nodes);
377 
378  // Now set the Eulerian equal to the Lagrangian coordinates
379  mesh_pt()->set_lagrangian_nodal_coordinates();
380 
381 }
382 
383 
384 //==================================================================
385 /// Doc the solution
386 //==================================================================
387 template<class ELEMENT>
389 {
390  ofstream some_file;
391  char filename[100];
392 
393  // Number of plot points
394  unsigned npts = 5;
395 
396  // Call output function for all elements
397  sprintf(filename,"%s/soln%i.dat",doc_info.directory().c_str(),
398  doc_info.number());
399  some_file.open(filename);
400  mesh_pt()->output(some_file,npts);
401  some_file.close();
402 
403 
404  // Write vertical position of the fish back, and solution at
405  // control node to trace file
406  Trace_file
407  << static_cast<Circle*>(mesh_pt()->fish_back_pt())->y_c()
408  << " " << Doc_node_pt->value(0) << std::endl;
409 
410 }
411 
412 
413 //==================================================================
414 /// Run the problem
415 //==================================================================
416 template<class ELEMENT>
418 {
419 
420  // Output
421  DocInfo doc_info;
422 
423  // Set output directory
424  doc_info.set_directory("RESLT");
425 
426  // Step number
427  doc_info.number()=0;
428 
429  // Open trace file
430  char filename[100];
431  sprintf(filename,"%s/trace.dat",doc_info.directory().c_str());
432  Trace_file.open(filename);
433 
434  Trace_file << "VARIABLES=\"y<sub>circle</sub>\",\"u<sub>control</sub>\""
435  << std::endl;
436 
437  //Parameter incrementation
438  unsigned nstep=5;
439  for(unsigned i=0;i<nstep;i++)
440  {
441  //Solve the problem with Newton's method, allowing for up to 2
442  //rounds of adaptation
443  newton_solve(2);
444 
445  // Doc solution
446  doc_solution(doc_info);
447  doc_info.number()++;
448 
449  // Increment width of fish domain
450  Fish_back_pt->y_c()+=0.3;
451  }
452 
453 }
454 
455 //======================================================================
456 /// Driver for simple elastic problem.
457 /// If there are any command line arguments, we regard this as a
458 /// validation run and perform only a single step.
459 //======================================================================
460 int main(int argc, char* argv[])
461 {
462 
463  // Store command line arguments
464  CommandLineArgs::setup(argc,argv);
465 
466  //Set physical parameters
468 
469  // Define a constitutive law (based on strain energy function)
471  new GeneralisedHookean(&Global_Physical_Variables::Nu);
472 
473  // Set up the problem: Choose a hybrid element that combines the
474  // 3x3 node refineable quad Poisson element with a displacement-based
475  // solid-mechanics element (for the pseudo-elastic mesh update in response
476  // to changes in the boundary shape)
478  RefineablePseudoSolidNodeUpdateElement<RefineableQPoissonElement<2,3>,
479  RefineableQPVDElement<2,3> >
480  > problem;
481 
482  problem.run();
483 
484 
485 }
486 
487 
488 
489 
490 
491 
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
void actions_after_newton_solve()
Update function (empty)
ElasticFishMesh< ELEMENT > * mesh_pt()
Access function for the specific mesh.
Node * Doc_node_pt
Node at which the solution of the Poisson equation is documented.
void actions_before_newton_solve()
Update before solve: We're dealing with a static problem so the nodal positions before the next solve...
void actions_after_adapt()
Update after adapt: Pin all redundant solid pressure nodes (if required)
void doc_solution(DocInfo &doc_info)
Doc the solution.
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
ElasticFishMesh(GeomObject *back_pt, GeomObject *undeformed_back_pt, TimeStepper *time_stepper_pt=&Mesh::Default_TimeStepper)
Constructor: Build underlying adaptive fish mesh and then set current Eulerian coordinates to be the ...
virtual ~ElasticFishMesh()
Destructor: Kill "undeformed" Domain.
Domain * Undeformed_domain_pt
Pointer to "undeformed" Domain – used to determine the Lagrangian coordinates of any newly created So...
int main(int argc, char *argv[])
Driver for simple elastic problem. If there are any command line arguments, we regard this as a valid...
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
void get_source(const Vector< double > &x, double &source)
Const source function.
double Strength
Strength of source function: default value 1.0.
//////////////////////////////////////////////////////////////////// ////////////////////////////////...
double Nu
Poisson's ratio.
ConstitutiveLaw * Constitutive_law_pt
Pointer to constitutive law.
Definition: circle.h:34