full_tube.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 3D navier stokes steady entry flow problem in a
27 /// complete straight tube
28 
29 //Generic routines
30 #include "generic.h"
31 #include "navier_stokes.h"
32 
33 // The mesh
34 #include "meshes/tube_mesh.h"
35 
36 using namespace std;
37 
38 using namespace oomph;
39 
40 
41 //=start_of_MyCylinder===================================
42 //A geometric object that represents the geometry of the domain
43 //================================================================
44 class MyCylinder : public GeomObject
45 {
46 public:
47 
48  /// Constructor that takes the radius of the tube as its argument
49  MyCylinder(const double &radius) :
50  GeomObject(3,3), Radius(radius) { }
51 
52 /// Destructor
53 virtual~MyCylinder(){}
54 
55 /// Lagrangian coordinate xi
56 void position (const Vector<double>& xi, Vector<double>& r) const
57 {
58  r[0] = xi[2]*Radius*cos(xi[1]);
59  r[1] = xi[0];
60  r[2] = -xi[2]*Radius*sin(xi[1]);
61 }
62 
63 
64 /// Return the position of the tube as a function of time
65 /// (doesn't move as a function of time)
66 void position(const unsigned& t,
67  const Vector<double>& xi, Vector<double>& r) const
68  {
69  position(xi,r);
70  }
71 
72 private:
73 
74  /// Storage for the radius of the tube
75  double Radius;
76 
77 };
78 
79 //=start_of_namespace================================================
80 /// Namespace for physical parameters
81 //===================================================================
83 {
84  /// Reynolds number
85  double Re=25;
86 
87 } // end_of_namespace
88 
89 
90 //=start_of_problem_class=============================================
91 /// Entry flow problem in tapered tube domain
92 //====================================================================
93 template<class ELEMENT>
94 class SteadyTubeProblem : public Problem
95 {
96 
97 public:
98 
99  /// Constructor: Pass DocInfo object and target errors
100  SteadyTubeProblem(DocInfo& doc_info, const double& min_error_target,
101  const double& max_error_target);
102 
103  /// Destructor (empty)
105 
106  /// Update the problem specs before solve
107  void actions_before_newton_solve();
108 
109  /// After adaptation: Pin redudant pressure dofs.
111  {
112  // Pin redudant pressure dofs
113  RefineableNavierStokesEquations<3>::
114  pin_redundant_nodal_pressures(mesh_pt()->element_pt());
115  }
116 
117  /// Doc the solution
118  void doc_solution();
119 
120  /// Overload generic access function by one that returns
121  /// a pointer to the specific mesh
122  RefineableTubeMesh<ELEMENT>* mesh_pt()
123  {
124  return dynamic_cast<RefineableTubeMesh<ELEMENT>*>(Problem::mesh_pt());
125  }
126 
127 private:
128 
129  /// Doc info object
130  DocInfo Doc_info;
131 
132  /// Pointer to GeomObject that specifies the domain volume
133  GeomObject *Volume_pt;
134 
135 }; // end_of_problem_class
136 
137 
138 
139 
140 //=start_of_constructor===================================================
141 /// Constructor: Pass DocInfo object and error targets
142 //========================================================================
143 template<class ELEMENT>
145  const double& min_error_target,
146  const double& max_error_target)
147  : Doc_info(doc_info)
148 {
149 
150  // Setup mesh:
151  //------------
152 
153  // Create GeomObject that specifies the domain geometry
154  //The radius of the tube is one
155  Volume_pt=new MyCylinder(1.0);
156 
157  //Define pi
158  const double pi = MathematicalConstants::Pi;
159 
160  //Set the centerline coordinates spanning the mesh
161  //Tube is on length pi
162  Vector<double> centreline_limits(2);
163  centreline_limits[0] = 0.0;
164  centreline_limits[1] = pi;
165 
166  //Set the positions of the angles that divide the outer ring
167  //These must be in the range -pi,pi, ordered from smallest to
168  //largest
169  Vector<double> theta_positions(4);
170  theta_positions[0] = -0.75*pi;
171  theta_positions[1] = -0.25*pi;
172  theta_positions[2] = 0.25*pi;
173  theta_positions[3] = 0.75*pi;
174 
175  //Define the radial fraction of the central box (always halfway
176  //along the radius)
177  Vector<double> radial_frac(4,0.5);
178 
179  // Number of layers in the initial mesh
180  unsigned nlayer=6;
181 
182  // Build and assign mesh
183  Problem::mesh_pt()= new RefineableTubeMesh<ELEMENT>(Volume_pt,
184  centreline_limits,
185  theta_positions,
186  radial_frac,
187  nlayer);
188 
189  // Set error estimator
190  Z2ErrorEstimator* error_estimator_pt=new Z2ErrorEstimator;
191  mesh_pt()->spatial_error_estimator_pt()=error_estimator_pt;
192 
193  // Error targets for adaptive refinement
194  mesh_pt()->max_permitted_error()=max_error_target;
195  mesh_pt()->min_permitted_error()=min_error_target;
196 
197  // Set the boundary conditions for this problem: All nodal values are
198  // free by default -- just pin the ones that have Dirichlet conditions
199  // here.
200  //Choose the conventional form by setting gamma to zero
201  //The boundary conditions will be pseudo-traction free (d/dn = 0)
202  ELEMENT::Gamma[0] = 0.0;
203  ELEMENT::Gamma[1] = 0.0;
204  ELEMENT::Gamma[2] = 0.0;
205 
206  //Loop over the boundaries
207  unsigned num_bound = mesh_pt()->nboundary();
208  for(unsigned ibound=0;ibound<num_bound;ibound++)
209  {
210  unsigned num_nod= mesh_pt()->nboundary_node(ibound);
211  for (unsigned inod=0;inod<num_nod;inod++)
212  {
213  // Boundary 0 is the inlet symmetry boundary:
214  // Boundary 1 is the tube wall
215  // Pin all values
216  if((ibound==0) || (ibound==1))
217  {
218  mesh_pt()->boundary_node_pt(ibound,inod)->pin(0);
219  mesh_pt()->boundary_node_pt(ibound,inod)->pin(1);
220  mesh_pt()->boundary_node_pt(ibound,inod)->pin(2);
221  }
222  }
223  } // end loop over boundaries
224 
225  // Loop over the elements to set up element-specific
226  // things that cannot be handled by constructor
227  unsigned n_element = mesh_pt()->nelement();
228  for(unsigned i=0;i<n_element;i++)
229  {
230  // Upcast from GeneralisedElement to the present element
231  ELEMENT* el_pt = dynamic_cast<ELEMENT*>(mesh_pt()->element_pt(i));
232 
233  //Set the Reynolds number, etc
234  el_pt->re_pt() = &Global_Physical_Variables::Re;
235  }
236 
237  // Pin redudant pressure dofs
238  RefineableNavierStokesEquations<3>::
239  pin_redundant_nodal_pressures(mesh_pt()->element_pt());
240 
241  //Attach the boundary conditions to the mesh
242  cout <<"Number of equations: " << assign_eqn_numbers() << std::endl;
243 
244 } // end_of_constructor
245 
246 
247 //=start_of_actions_before_newton_solve===================================
248 /// Set the inflow boundary conditions
249 //========================================================================
250 template<class ELEMENT>
252 {
253 
254  // (Re-)assign velocity profile at inflow values
255  //--------------------------------------------
256  unsigned ibound=0;
257  unsigned num_nod= mesh_pt()->nboundary_node(ibound);
258  for (unsigned inod=0;inod<num_nod;inod++)
259  {
260  // Recover coordinates of tube relative to centre position
261  double x=mesh_pt()->boundary_node_pt(ibound,inod)->x(0);
262  double z=mesh_pt()->boundary_node_pt(ibound,inod)->x(2);
263  //Calculate the radius
264  double r=sqrt(x*x+z*z);
265 
266  // Blunt profile for axial velocity (component 1 at the inlet)
267  mesh_pt()->boundary_node_pt(ibound,inod)->
268  set_value(1,(1.0-pow(r,10.0)));
269  }
270 
271 } // end_of_actions_before_newton_solve
272 
273 
274 //=start_of_doc_solution==================================================
275 /// Doc the solution
276 //========================================================================
277 template<class ELEMENT>
279 {
280  //Output file stream
281  ofstream some_file;
282  char filename[100];
283 
284  // Number of plot points
285  unsigned npts;
286  npts=5;
287 
288  //Need high precision for large radii of curvature
289  //some_file.precision(10);
290  // Output solution labelled by the Reynolds number
291  sprintf(filename,"%s/soln_Re%g.dat",Doc_info.directory().c_str(),
293  some_file.open(filename);
294  mesh_pt()->output(some_file,npts);
295  some_file.close();
296 
297 } // end_of_doc_solution
298 
299 
300 
301 
302 /// /////////////////////////////////////////////////////////////////////
303 /// /////////////////////////////////////////////////////////////////////
304 /// /////////////////////////////////////////////////////////////////////
305 
306 
307 //=start_of_main=======================================================
308 /// Driver for 3D entry flow into a straight tube.
309 //=====================================================================
310 int main(int argc, char* argv[])
311 {
312  //The purpose of this code is to test that the position of nodes on
313  //curvilinear boundaries are correctly updated after nodes that were
314  //hanging become non-hanging.
315  unsigned max_adapt=1;
316  double max_error_target=0.02 , min_error_target=0.002;
317 
318 
319  // Set up doc info
320  DocInfo doc_info;
321 
322  // Do Taylor-Hood elements
323  //------------------------
324  {
325  // Set output directory
326  doc_info.set_directory("RESLT_TH");
327 
328  // Step number
329  doc_info.number()=0;
330 
331  // Build problem
333  problem(doc_info,min_error_target,max_error_target);
334 
335  cout << " Doing Taylor-Hood elements " << std::endl;
336 
337  for(unsigned i=0;i<2;i++)
338  {
339  // Solve the problem
340  problem.newton_solve(max_adapt);
341  // Doc solution after solving
342  problem.doc_solution();
343 
345  ++doc_info.number();
346  }
347  }
348 
349  exit(1);
350  // Do Crouzeix-Raviart elements
351  //------------------------
352  {
353  // Set output directory
354  doc_info.set_directory("RESLT_CR");
355 
356  // Step number
357  doc_info.number()=0;
358 
359  // Build problem
361  problem(doc_info,min_error_target,max_error_target);
362 
363  cout << " Doing Crouzeix-Raviart elements " << std::endl;
364 
365  for(unsigned i=0;i<2;i++)
366  {
367  // Solve the problem
368  problem.newton_solve(max_adapt);
369  // Doc solution after solving
370  problem.doc_solution();
371 
373  ++doc_info.number();
374  }
375  }
376 } // end_of_main
377 
378 
double Radius
Storage for the radius of the tube.
Definition: full_tube.cc:75
void position(const unsigned &t, const Vector< double > &xi, Vector< double > &r) const
Return the position of the tube as a function of time (doesn't move as a function of time)
Definition: full_tube.cc:66
MyCylinder(const double &radius)
Constructor that takes the radius of the tube as its argument.
Definition: full_tube.cc:49
virtual ~MyCylinder()
Destructor.
Definition: full_tube.cc:53
void position(const Vector< double > &xi, Vector< double > &r) const
Lagrangian coordinate xi.
Definition: full_tube.cc:56
Entry flow problem in tapered tube domain.
Definition: full_tube.cc:95
~SteadyTubeProblem()
Destructor (empty)
Definition: full_tube.cc:104
DocInfo Doc_info
Doc info object.
Definition: full_tube.cc:130
SteadyTubeProblem(DocInfo &doc_info, const double &min_error_target, const double &max_error_target)
Constructor: Pass DocInfo object and target errors.
Definition: full_tube.cc:144
void actions_before_newton_solve()
Update the problem specs before solve.
Definition: full_tube.cc:251
RefineableTubeMesh< ELEMENT > * mesh_pt()
Overload generic access function by one that returns a pointer to the specific mesh.
Definition: full_tube.cc:122
void doc_solution()
Doc the solution.
Definition: full_tube.cc:278
void actions_after_adapt()
After adaptation: Pin redudant pressure dofs.
Definition: full_tube.cc:110
GeomObject * Volume_pt
Pointer to GeomObject that specifies the domain volume.
Definition: full_tube.cc:133
int main(int argc, char *argv[])
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
Definition: full_tube.cc:310
Namespace for physical parameters.
Definition: full_tube.cc:83
double Re
Reynolds number.
Definition: full_tube.cc:85