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