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