refineable_periodic_load.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 // Driver for a periodically loaded elastic body -- spatially adaptive version
27 
28 // The oomphlib headers
29 #include "generic.h"
30 #include "linear_elasticity.h"
31 
32 // The mesh
33 #include "meshes/rectangular_quadmesh.h"
34 
35 using namespace std;
36 
37 using namespace oomph;
38 
39 //===start_of_namespace=================================================
40 /// Namespace for global parameters
41 //======================================================================
42 namespace Global_Parameters
43 {
44  /// Amplitude of traction applied
45  double Amplitude = 1.0;
46 
47  /// Specify problem to be solved (boundary conditons for finite or
48  /// infinite domain).
49  bool Finite=false;
50 
51  /// Define Poisson coefficient Nu
52  double Nu = 0.3;
53 
54  /// Length of domain in x direction
55  double Lx = 1.0;
56 
57  /// Length of domain in y direction
58  double Ly = 2.0;
59 
60  /// The elasticity tensor
61  IsotropicElasticityTensor E(Nu);
62 
63  /// The exact solution for infinite depth case
64  void exact_solution(const Vector<double> &x,
65  Vector<double> &u)
66  {
67  u[0] = -Amplitude*cos(2.0*MathematicalConstants::Pi*x[0]/Lx)*
68  exp(2.0*MathematicalConstants::Pi*(x[1]-Ly))/
69  (2.0/(1.0+Nu)*MathematicalConstants::Pi);
70  u[1] = -Amplitude*sin(2.0*MathematicalConstants::Pi*x[0]/Lx)*
71  exp(2.0*MathematicalConstants::Pi*(x[1]-Ly))/
72  (2.0/(1.0+Nu)*MathematicalConstants::Pi);
73  }
74 
75  /// The traction function
76 void periodic_traction(const double &time,
77  const Vector<double> &x,
78  const Vector<double> &n,
79  Vector<double> &result)
80  {
81  result[0] = -Amplitude*cos(2.0*MathematicalConstants::Pi*x[0]/Lx);
82  result[1] = -Amplitude*sin(2.0*MathematicalConstants::Pi*x[0]/Lx);
83  }
84 } // end_of_namespace
85 
86 
87 //===start_of_problem_class=============================================
88 /// Periodic loading problem
89 //======================================================================
90 template<class ELEMENT>
91 class RefineablePeriodicLoadProblem : public Problem
92 {
93 public:
94 
95  /// Constructor: Pass number of elements in x and y directions
96  /// and lengths.
97  RefineablePeriodicLoadProblem(const unsigned &nx, const unsigned &ny,
98  const double &lx, const double &ly);
99 
100  /// Update before solve is empty
102 
103  /// Update after solve is empty
105 
106  /// Actions before adapt: Wipe the mesh of traction elements
108  {
109  // Kill the traction elements and wipe surface mesh
110  delete_traction_elements();
111 
112  // Rebuild the Problem's global mesh from its various sub-meshes
113  rebuild_global_mesh();
114  }
115 
116  /// Actions after adapt: Rebuild the mesh of traction elements
118  {
119  // Create traction elements
120  assign_traction_elements();
121 
122  // Rebuild the Problem's global mesh from its various sub-meshes
123  rebuild_global_mesh();
124  }
125 
126  /// Doc the solution
127  void doc_solution(DocInfo& doc_info);
128 
129 private:
130 
131  /// Allocate traction elements on the top surface
132  void assign_traction_elements();
133 
134  /// Kill traction elements on the top surface
136  {
137  // How many surface elements are in the surface mesh
138  unsigned n_element = Surface_mesh_pt->nelement();
139 
140  // Loop over the traction elements
141  for(unsigned e=0;e<n_element;e++)
142  {
143  // Kill surface element
144  delete Surface_mesh_pt->element_pt(e);
145  }
146 
147  // Wipe the mesh
148  Surface_mesh_pt->flush_element_and_node_storage();
149  }
150 
151  /// Pointer to the (refineable!) bulk mesh
152  TreeBasedRefineableMeshBase* Bulk_mesh_pt;
153 
154  /// Pointer to the mesh of traction elements
156 
157 }; // end_of_problem_class
158 
159 
160 //===start_of_constructor=============================================
161 /// Problem constructor: Pass number of elements in the coordinate
162 /// directions and the domain sizes.
163 //====================================================================
164 template<class ELEMENT>
166 (const unsigned &nx, const unsigned &ny,
167  const double &lx, const double& ly)
168 {
169  // Create the mesh
170  Bulk_mesh_pt = new RefineableRectangularQuadMesh<ELEMENT>(nx,ny,lx,ly);
171 
172  // Create/set error estimator
173  Bulk_mesh_pt->spatial_error_estimator_pt()=new Z2ErrorEstimator;
174 
175  // Make the mesh periodic in the x-direction by setting the nodes on
176  // right boundary (boundary 1) to be the periodic counterparts of
177  // those on the left one (boundary 3).
178  unsigned n_node = Bulk_mesh_pt->nboundary_node(1);
179  for(unsigned n=0;n<n_node;n++)
180  {
181  Bulk_mesh_pt->boundary_node_pt(1,n)
182  ->make_periodic(Bulk_mesh_pt->boundary_node_pt(3,n));
183  }
184 
185 
186  // Now establish the new neighbours (created by "wrapping around"
187  // the domain) in the TreeForst representation of the mesh
188 
189  // Get pointers to tree roots associated with elements on the
190  // left and right boundaries
191  Vector<TreeRoot*> left_root_pt(ny);
192  Vector<TreeRoot*> right_root_pt(ny);
193  for(unsigned i=0;i<ny;i++)
194  {
195  left_root_pt[i] =
196  dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(i*nx))->
197  tree_pt()->root_pt();
198  right_root_pt[i] =
199  dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(nx-1+i*nx))->
200  tree_pt()->root_pt();
201  }
202 
203  // Switch on QuadTreeNames for enumeration of directions
204  using namespace QuadTreeNames;
205 
206  //Set the neighbour and periodicity
207  for(unsigned i=0;i<ny;i++)
208  {
209  // The western neighbours of the elements on the left
210  // boundary are those on the right
211  left_root_pt[i]->neighbour_pt(W) = right_root_pt[i];
212  left_root_pt[i]->set_neighbour_periodic(W);
213 
214  // The eastern neighbours of the elements on the right
215  // boundary are those on the left
216  right_root_pt[i]->neighbour_pt(E) = left_root_pt[i];
217  right_root_pt[i]->set_neighbour_periodic(E);
218  } // done
219 
220 
221  //Create the surface mesh of traction elements
222  Surface_mesh_pt=new Mesh;
223  assign_traction_elements();
224 
225  // Set the boundary conditions for this problem: All nodes are
226  // free by default -- just pin & set the ones that have Dirichlet
227  // conditions here
228  unsigned ibound=0;
229  unsigned num_nod=Bulk_mesh_pt->nboundary_node(ibound);
230  for (unsigned inod=0;inod<num_nod;inod++)
231  {
232  // Get pointer to node
233  Node* nod_pt=Bulk_mesh_pt->boundary_node_pt(ibound,inod);
234 
235  // Pinned in x & y at the bottom and set value
236  nod_pt->pin(0);
237  nod_pt->pin(1);
238 
239  // Check which boundary conditions to set and set them
241  {
242  // Set both displacements to zero
243  nod_pt->set_value(0,0);
244  nod_pt->set_value(1,0);
245  }
246  else
247  {
248  // Extract nodal coordinates from node:
249  Vector<double> x(2);
250  x[0]=nod_pt->x(0);
251  x[1]=nod_pt->x(1);
252 
253  // Compute the value of the exact solution at the nodal point
254  Vector<double> u(2);
256 
257  // Assign these values to the nodal values at this node
258  nod_pt->set_value(0,u[0]);
259  nod_pt->set_value(1,u[1]);
260  };
261  } // end_loop_over_boundary_nodes
262 
263  // Complete the problem setup to make the elements fully functional
264 
265  // Loop over the elements
266  unsigned n_el = Bulk_mesh_pt->nelement();
267  for(unsigned e=0;e<n_el;e++)
268  {
269  // Cast to a bulk element
270  ELEMENT *el_pt = dynamic_cast<ELEMENT*>(Bulk_mesh_pt->element_pt(e));
271 
272  // Set the elasticity tensor
273  el_pt->elasticity_tensor_pt() = &Global_Parameters::E;
274  }// end loop over elements
275 
276 
277  // Do selective refinement of one element so that we can test
278  // whether periodic hanging nodes work: Choose a single element
279  // (the zero-th one) as the to-be-refined element.
280  // This creates a hanging node on the periodic boundary
281  Vector<unsigned> refine_pattern(1,0);
282  Bulk_mesh_pt->refine_selected_elements(refine_pattern);
283 
284  // Add the submeshes to the problem
285  add_sub_mesh(Bulk_mesh_pt);
286  add_sub_mesh(Surface_mesh_pt);
287 
288  // Now build the global mesh
289  build_global_mesh();
290 
291  // Assign equation numbers
292  cout << assign_eqn_numbers() << " equations assigned" << std::endl;
293 } // end of constructor
294 
295 
296 //===start_of_traction===============================================
297 /// Make traction elements along the top boundary of the bulk mesh
298 //===================================================================
299 template<class ELEMENT>
301 {
302 
303  // How many bulk elements are next to boundary 2 (the top boundary)?
304  unsigned bound=2;
305  unsigned n_neigh = Bulk_mesh_pt->nboundary_element(bound);
306 
307  // Now loop over bulk elements and create the face elements
308  for(unsigned n=0;n<n_neigh;n++)
309  {
310  // Create the face element
311  FiniteElement *traction_element_pt
312  = new LinearElasticityTractionElement<ELEMENT>
313  (Bulk_mesh_pt->boundary_element_pt(bound,n),
314  Bulk_mesh_pt->face_index_at_boundary(bound,n));
315 
316  // Add to mesh
317  Surface_mesh_pt->add_element_pt(traction_element_pt);
318  }
319 
320  // Now set function pointer to applied traction
321  unsigned n_traction = Surface_mesh_pt->nelement();
322  for(unsigned e=0;e<n_traction;e++)
323  {
324  // Cast to a surface element
325  LinearElasticityTractionElement<ELEMENT> *el_pt =
326  dynamic_cast<LinearElasticityTractionElement<ELEMENT>* >
327  (Surface_mesh_pt->element_pt(e));
328 
329  // Set the applied traction
330  el_pt->traction_fct_pt() = &Global_Parameters::periodic_traction;
331  }// end loop over traction elements
332 
333 
334 } // end of assign_traction_elements
335 
336 //==start_of_doc_solution=================================================
337 /// Doc the solution
338 //========================================================================
339 template<class ELEMENT>
341 {
342  ofstream some_file;
343  char filename[100];
344 
345  // Number of plot points
346  unsigned npts=5;
347 
348  // Output solution
349  sprintf(filename,"%s/soln.dat",doc_info.directory().c_str());
350  some_file.open(filename);
351  Bulk_mesh_pt->output(some_file,npts);
352  some_file.close();
353 
354  // Output exact solution
355  sprintf(filename,"%s/exact_soln.dat",doc_info.directory().c_str());
356  some_file.open(filename);
357  Bulk_mesh_pt->output_fct(some_file,npts,
359  some_file.close();
360 
361  // Doc error
362  double error=0.0;
363  double norm=0.0;
364  sprintf(filename,"%s/error.dat",doc_info.directory().c_str());
365  some_file.open(filename);
366  Bulk_mesh_pt->compute_error(some_file,
368  error,norm);
369  some_file.close();
370 
371 // Doc error norm:
372  cout << "\nNorm of error " << sqrt(error) << std::endl;
373  cout << "Norm of solution : " << sqrt(norm) << std::endl << std::endl;
374  cout << std::endl;
375 
376 
377 } // end_of_doc_solution
378 
379 
380 //===start_of_main======================================================
381 /// Driver code for PeriodicLoad linearly elastic problem
382 //======================================================================
383 int main(int argc, char* argv[])
384 {
385  // Number of elements in x-direction
386  unsigned nx=2;
387 
388  // Number of elements in y-direction (for (approximately) square elements)
389  unsigned ny=unsigned(double(nx)*Global_Parameters::Ly/Global_Parameters::Lx);
390 
391  // Set up doc info
392  DocInfo doc_info;
393 
394  // Set output directory
395  doc_info.set_directory("RESLT");
396 
397  // Set up problem
400 
401  // Run the simulation, allowing for up to 4 spatial adaptations
402  unsigned max_adapt=4;
403  problem.newton_solve(max_adapt);
404 
405  // Output the solution
406  problem.doc_solution(doc_info);
407 
408 } // end_of_main
void assign_traction_elements()
Allocate traction elements on the top surface.
void delete_traction_elements()
Kill traction elements on the top surface.
void actions_after_newton_solve()
Update after solve is empty.
Mesh * Surface_mesh_pt
Pointer to the mesh of traction elements.
TreeBasedRefineableMeshBase * Bulk_mesh_pt
Pointer to the (refineable!) bulk mesh.
void actions_before_adapt()
Actions before adapt: Wipe the mesh of traction elements.
void doc_solution(DocInfo &doc_info)
Doc the solution.
void actions_after_adapt()
Actions after adapt: Rebuild the mesh of traction elements.
RefineablePeriodicLoadProblem(const unsigned &nx, const unsigned &ny, const double &lx, const double &ly)
Constructor: Pass number of elements in x and y directions and lengths.
void actions_before_newton_solve()
Update before solve is empty.
Namespace for global parameters.
void periodic_traction(const double &time, const Vector< double > &x, const Vector< double > &n, Vector< double > &result)
The traction function.
double Amplitude
Amplitude of traction applied.
double Nu
Define Poisson coefficient Nu.
double Ly
Length of domain in y direction.
IsotropicElasticityTensor E(Nu)
The elasticity tensor.
bool Finite
Specify problem to be solved (boundary conditons for finite or infinite domain).
void exact_solution(const Vector< double > &x, Vector< double > &u)
The exact solution for infinite depth case.
double Lx
Length of domain in x direction.
int main(int argc, char *argv[])
Driver code for PeriodicLoad linearly elastic problem.