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-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// 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
35using namespace std;
36
37using namespace oomph;
38
39//===start_of_namespace=================================================
40/// Namespace for global parameters
41//======================================================================
42namespace 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
76void 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//======================================================================
90template<class ELEMENT>
91class RefineablePeriodicLoadProblem : public Problem
92{
93public:
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
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
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
129private:
130
131 /// Allocate traction elements on the top surface
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//====================================================================
164template<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//===================================================================
299template<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//========================================================================
339template<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 snprintf(filename, sizeof(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 snprintf(filename, sizeof(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 snprintf(filename, sizeof(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//======================================================================
383int 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.