helical_pipe.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-2024 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 helical
27 /// 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_MyHelicalCylinder==============================================
42 /// The arguemts are the radius of the tube, its curvature in the x,y plane
43 /// and the pitch of the helix
44 //=========================================================================
45 class MyHelicalCylinder : public GeomObject
46 {
47 public:
48 
49 /// Constructor
50  MyHelicalCylinder(const double &radius, const double& delta,
51  const double& pitch) :
52  GeomObject(3,3),Radius(radius),Delta(delta),P(pitch)
53  {
54  //Set the value of pi
55  Pi = MathematicalConstants::Pi;
56  }
57 
58 /// Destructor
60 
61 /// Lagrangian coordinate xi
62 void position (const Vector<double>& xi, Vector<double>& r) const
63 {
64  r[0] = (1.0/Delta)*cos(xi[0]) + xi[2]*Radius*cos(xi[0])*cos(xi[1]);
65  r[1] = (1.0/Delta)*sin(xi[0]) + xi[2]*Radius*sin(xi[0])*cos(xi[1]);
66  r[2] = P*xi[0]/(2.0*Pi) - xi[2]*Radius*sin(xi[1]);
67 }
68 
69 
70 /// Return the position of the tube as a function of time
71 /// (doesn't move as a function of time)
72 void position(const unsigned& t,
73  const Vector<double>& xi, Vector<double>& r) const
74  {
75  position(xi,r);
76  }
77 
78 private:
79  double Pi;
80  double Radius;
81  double Delta;
82  double P;
83 };
84 
85 //=start_of_namespace================================================
86 /// Namespace for physical parameters
87 //===================================================================
89 {
90  /// Reynolds number
91  double Re=50;
92 
93  double Delta=0.5;
94  double Pitch = 1.0;
95 } // end_of_namespace
96 
97 
98 //=start_of_problem_class=============================================
99 /// Entry flow problem in tapered tube domain
100 //====================================================================
101 template<class ELEMENT>
102 class SteadyHelicalProblem : public Problem
103 {
104 
105 public:
106 
107  /// Constructor: Pass DocInfo object and target errors
108  SteadyHelicalProblem(DocInfo& doc_info, const double& min_error_target,
109  const double& max_error_target);
110 
111  /// Destructor (empty)
113 
114  /// Update the problem specs before solve
115  void actions_before_newton_solve();
116 
117  /// After adaptation: Pin redudant pressure dofs.
119  {
120  // Pin redudant pressure dofs
121  RefineableNavierStokesEquations<3>::
122  pin_redundant_nodal_pressures(mesh_pt()->element_pt());
123  }
124 
125  /// Doc the solution
126  void doc_solution();
127 
128  /// Overload generic access function by one that returns
129  /// a pointer to the specific mesh
130  RefineableTubeMesh<ELEMENT>* mesh_pt()
131  {
132  return dynamic_cast<RefineableTubeMesh<ELEMENT>*>(Problem::mesh_pt());
133  }
134 
135 private:
136 
137  /// Exponent for bluntness of velocity profile
138  int Alpha;
139 
140  /// Doc info object
141  DocInfo Doc_info;
142 
143  /// Pointer to GeomObject that specifies the domain boundary
144  GeomObject*Wall_pt;
145 
146 }; // end_of_problem_class
147 
148 
149 
150 
151 //=start_of_constructor===================================================
152 /// Constructor: Pass DocInfo object and error targets
153 //========================================================================
154 template<class ELEMENT>
156  const double& min_error_target,
157  const double& max_error_target)
158  : Doc_info(doc_info)
159 {
160  //Increase the value of the maximum residuals so that the first
161  //newton step converges.
162  Max_residuals = 100.0;
163 
164  // Setup mesh:
165  //------------
166 
167  //Build geometric object that forms the domain boundary: a tapered curved tube
170 
171 // Create GeomObject that specifies the domain boundary
172 Wall_pt=new MyHelicalCylinder(1.0,d,p);
173 
174 //Define pi
175  const double pi = MathematicalConstants::Pi;
176 
177 
178 //Set the centerline coordinates for the start and end of the helix
179  Vector<double> centreline_limits(2);
180  centreline_limits[0] = 0.0;
181  centreline_limits[1] = pi;
182 
183  //Set the positions of the angles that divide the outer ring of elements
184  Vector<double> theta_positions(4);
185  theta_positions[0] = -0.75*pi;
186  theta_positions[1] = -0.25*pi;
187  theta_positions[2] = 0.25*pi;
188  theta_positions[3] = 0.75*pi;
189 
190  //Define the radial fraction for the central box in the domain
191  Vector<double> radial_frac(4,0.5);
192 
193  // Number of layers in the mesh
194  unsigned nlayer=6;
195 
196  // Build and assign mesh
197  Problem::mesh_pt()=
198  new RefineableTubeMesh<ELEMENT>(Wall_pt,
199  centreline_limits,
200  theta_positions,
201  radial_frac,
202  nlayer);
203 
204  // Set error estimator
205  Z2ErrorEstimator* error_estimator_pt=new Z2ErrorEstimator;
206  mesh_pt()->spatial_error_estimator_pt()=error_estimator_pt;
207 
208  // Error targets for adaptive refinement
209  mesh_pt()->max_permitted_error()=max_error_target;
210  mesh_pt()->min_permitted_error()=min_error_target;
211 
212  // Set the boundary conditions for this problem: All nodal values are
213  // free by default -- just pin the ones that have Dirichlet conditions
214  // here.
215  //Choose the conventional form by setting gamma to zero
216  //The boundary conditions will be pseudo-traction free (d/dn = 0)
217  ELEMENT::Gamma[0] = 0.0;
218  ELEMENT::Gamma[1] = 0.0;
219  ELEMENT::Gamma[2] = 0.0;
220 
221  unsigned num_bound = mesh_pt()->nboundary();
222  for(unsigned ibound=0;ibound<num_bound;ibound++)
223  {
224  unsigned num_nod= mesh_pt()->nboundary_node(ibound);
225  for (unsigned inod=0;inod<num_nod;inod++)
226  {
227  // Boundary 0 is the inlet symmetry boundary:
228  // Boundary 1 is the tube wall
229  // Pin all values
230  if((ibound==0) || (ibound==1))
231  {
232  mesh_pt()->boundary_node_pt(ibound,inod)->pin(0);
233  mesh_pt()->boundary_node_pt(ibound,inod)->pin(1);
234  mesh_pt()->boundary_node_pt(ibound,inod)->pin(2);
235  }
236 
237  //Boundary 2 is the outflow boundary, pin z,
238  //leave traction free
239  if(ibound==2)
240  {
241  //mesh_pt()->boundary_node_pt(ibound,inod)->pin(2);
242  }
243  }
244  } // end loop over boundaries
245 
246  // Loop over the elements to set up element-specific
247  // things that cannot be handled by constructor
248  unsigned n_element = mesh_pt()->nelement();
249  for(unsigned i=0;i<n_element;i++)
250  {
251  // Upcast from GeneralisedElement to the present element
252  ELEMENT* el_pt = dynamic_cast<ELEMENT*>(mesh_pt()->element_pt(i));
253 
254  //Set the Reynolds number, etc
255  el_pt->re_pt() = &Global_Physical_Variables::Re;
256  }
257 
258  // Pin redudant pressure dofs
259  RefineableNavierStokesEquations<3>::
260  pin_redundant_nodal_pressures(mesh_pt()->element_pt());
261 
262  //Attach the boundary conditions to the mesh
263  cout <<"Number of equations: " << assign_eqn_numbers() << std::endl;
264 
265 } // end_of_constructor
266 
267 
268 //=start_of_actions_before_newton_solve==========================================
269 /// Set the inflow boundary conditions
270 //========================================================================
271 template<class ELEMENT>
273 {
274 
275  // (Re-)assign velocity profile at inflow values
276  //--------------------------------------------
277  unsigned ibound=0;
278  unsigned num_nod= mesh_pt()->nboundary_node(ibound);
279  for (unsigned inod=0;inod<num_nod;inod++)
280  {
281  // Recover coordinates
282  double x=mesh_pt()->boundary_node_pt(ibound,inod)->x(0) -
284  double z=mesh_pt()->boundary_node_pt(ibound,inod)->x(2);
285  double r=sqrt(x*x+z*z);
286 
287  // Bluntish profile for axial velocity (component 1)
288  mesh_pt()->boundary_node_pt(ibound,inod)->
289  set_value(1,(1.0-pow(r,2.0)));
290  }
291 
292 } // end_of_actions_before_newton_solve
293 
294 
295 //=start_of_doc_solution==================================================
296 /// Doc the solution
297 //========================================================================
298 template<class ELEMENT>
300 {
301 
302  ofstream some_file;
303  char filename[100];
304 
305  // Number of plot points
306  unsigned npts;
307  npts=5;
308 
309  //Need high precision for large radii of curvature
310  //some_file.precision(10);
311  // Output solution
312  sprintf(filename,"%s/soln_Re%g.dat",Doc_info.directory().c_str(),
314  some_file.open(filename);
315  mesh_pt()->output(some_file,npts);
316  some_file.close();
317 
318 } // end_of_doc_solution
319 
320 
321 
322 
323 /// /////////////////////////////////////////////////////////////////////
324 /// /////////////////////////////////////////////////////////////////////
325 /// /////////////////////////////////////////////////////////////////////
326 
327 
328 //=start_of_main=======================================================
329 /// Driver for 3D entry flow into a tapered tube. If there are
330 /// any command line arguments, we regard this as a validation run
331 /// and perform only a single adaptation
332 //=====================================================================
333 int main(int argc, char* argv[])
334 {
335 
336  // Store command line arguments
337  CommandLineArgs::setup(argc,argv);
338 
339  // Allow (up to) two rounds of fully automatic adapation in response to
340  //-----------------------------------------------------------------------
341  // error estimate
342  //---------------
343  unsigned max_adapt;
344  double max_error_target,min_error_target;
345 
346  // Set max number of adaptations in black-box Newton solver and
347  // error targets for adaptation
348  if (CommandLineArgs::Argc==1)
349  {
350  // Up to two adaptations
351  max_adapt=2;
352 
353  // Error targets for adaptive refinement
354  max_error_target=0.005;
355  min_error_target=0.0005;
356  }
357  // Validation run: Only one adaptation. Relax error targets
358  // to ensure that not all elements are refined so we're getting
359  // some hanging nodes.
360  else
361  {
362  // Validation run: Just one round of adaptation
363  max_adapt=1;
364 
365  // Error targets for adaptive refinement
366  max_error_target=0.02;
367  min_error_target=0.002;
368  }
369  // end max_adapt setup
370 
371 
372  // Set up doc info
373  DocInfo doc_info;
374 
375  // Do Taylor-Hood elements
376  //------------------------
377  {
378  // Set output directory
379  doc_info.set_directory("RESLT_TH");
380 
381  // Step number
382  doc_info.number()=0;
383 
384  // Build problem
386  problem(doc_info,min_error_target,max_error_target);
387 
388  cout << " Doing Taylor-Hood elements " << std::endl;
389 
390  // Solve the problem
391  problem.newton_solve(max_adapt);
392  // Doc solution after solving
393  problem.doc_solution();
394  }
395 
396  // Do Crouzeix-Raviart elements
397  //------------------------
398  {
399  // Set output directory
400  doc_info.set_directory("RESLT_CR");
401 
402  // Step number
403  doc_info.number()=0;
404 
405  // Build problem
407  problem(doc_info,min_error_target,max_error_target);
408 
409  cout << " Doing Crouzeix-Raviart elements " << std::endl;
410 
411  // Solve the problem
412  problem.newton_solve(max_adapt);
413  // Doc solution after solving
414  problem.doc_solution();
415  }
416 
417 } // end_of_main
418 
419 
The arguemts are the radius of the tube, its curvature in the x,y plane and the pitch of the helix.
Definition: helical_pipe.cc:46
MyHelicalCylinder(const double &radius, const double &delta, const double &pitch)
Constructor.
Definition: helical_pipe.cc:50
virtual ~MyHelicalCylinder()
Destructor.
Definition: helical_pipe.cc:59
void position(const Vector< double > &xi, Vector< double > &r) const
Lagrangian coordinate xi.
Definition: helical_pipe.cc:62
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: helical_pipe.cc:72
Entry flow problem in tapered tube domain.
DocInfo Doc_info
Doc info object.
GeomObject * Wall_pt
Pointer to GeomObject that specifies the domain boundary.
void actions_before_newton_solve()
Update the problem specs before solve.
void actions_after_adapt()
After adaptation: Pin redudant pressure dofs.
RefineableTubeMesh< ELEMENT > * mesh_pt()
Overload generic access function by one that returns a pointer to the specific mesh.
SteadyHelicalProblem(DocInfo &doc_info, const double &min_error_target, const double &max_error_target)
Constructor: Pass DocInfo object and target errors.
~SteadyHelicalProblem()
Destructor (empty)
int Alpha
Exponent for bluntness of velocity profile.
void doc_solution()
Doc the solution.
int main(int argc, char *argv[])
///////////////////////////////////////////////////////////////////// ///////////////////////////////...
Namespace for physical parameters.
Definition: curved_pipe.cc:86
double Re
Reynolds number.
Definition: curved_pipe.cc:88
double Delta
The desired curvature of the pipe.
Definition: curved_pipe.cc:91