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-2025 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
44using namespace std;
45
46using namespace oomph;
47
48///////////////////////////////////////////////////////////////////////
49///////////////////////////////////////////////////////////////////////
50///////////////////////////////////////////////////////////////////////
51
52
53
54//====================================================================
55/// Namespace for const source term in Poisson equation
56//====================================================================
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 {
66 }
67
68}
69
70///////////////////////////////////////////////////////////////////////
71///////////////////////////////////////////////////////////////////////
72///////////////////////////////////////////////////////////////////////
73
74//=========================================================================
75/// Refineable fish mesh upgraded to become a solid mesh
76//=========================================================================
77template<class ELEMENT>
78class ElasticFishMesh : public virtual RefineableFishMesh<ELEMENT>,
79 public virtual SolidMesh
80{
81
82public:
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) :
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
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 {
134 }
135
136private:
137
138 /// Pointer to "undeformed" Domain -- used to determine the
139 /// Lagrangian coordinates of any newly created SolidNodes during
140 /// Mesh refinement
142
143};
144
145
146
147
148///////////////////////////////////////////////////////////////////////
149///////////////////////////////////////////////////////////////////////
150///////////////////////////////////////////////////////////////////////
151
152
153
154
155//================================================================
156/// Global variables
157//================================================================
159{
160 /// Pointer to constitutive law
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//======================================================================
179template<class ELEMENT>
180class DeformableFishPoissonProblem : public Problem
181{
182
183public:
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
224private:
225
226
227 /// Node at which the solution of the Poisson equation is documented
229
230 /// Trace file
232
233 // Geometric object/generalised element that represents the deformable
234 // fish back
236
237};
238
239
240
241//======================================================================
242/// Constructor:
243//======================================================================
244template<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
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,
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
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
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//==================================================================
390template<class ELEMENT>
392{
394 char filename[100];
395
396 // Number of plot points
397 unsigned npts = 5;
398
399 // Call output function for all elements
400 snprintf(filename, sizeof(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//==================================================================
419template<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 snprintf(filename, sizeof(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//======================================================================
463int 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)
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)
484 > problem;
485
486 problem.run();
487
488
489}
490
491
492
493
494
495
void demo_fish_poisson(const string &directory_name)
Demonstrate how to solve 2D Poisson problem in deformable fish-shaped domain with mesh adaptation.
int main()
Driver.
Definition circle.cc:40
Solve Poisson equation on deforming fish-shaped domain. Mesh update via pseudo-elasticity.
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
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.
Refineable fish mesh upgraded to become a solid mesh.
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...
GeneralCircle "upgraded" to a GeneralisedElement: Circular ring whose position is given by.
Namespace for const source term in Poisson equation.
void get_source(const Vector< double > &x, double &source)
Const source function.
double Strength
Strength of source function: default value 1.0.
ConstitutiveLaw * Constitutive_law_pt
Pointer to constitutive law.
Definition circle.h:34