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