multi_domain_ref_b_convection.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// Version 1.0; svn revision $LastChangedRevision$
7 //LIC//
8 //LIC// $LastChangedDate$
9 //LIC//
10 //LIC// Copyright (C) 2006-2016 Matthias Heil and Andrew Hazel
11 //LIC//
12 //LIC// This library is free software; you can redistribute it and/or
13 //LIC// modify it under the terms of the GNU Lesser General Public
14 //LIC// License as published by the Free Software Foundation; either
15 //LIC// version 2.1 of the License, or (at your option) any later version.
16 //LIC//
17 //LIC// This library is distributed in the hope that it will be useful,
18 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 //LIC// Lesser General Public License for more details.
21 //LIC//
22 //LIC// You should have received a copy of the GNU Lesser General Public
23 //LIC// License along with this library; if not, write to the Free Software
24 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
25 //LIC// 02110-1301 USA.
26 //LIC//
27 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk.
28 //LIC//
29 //LIC//====================================================================
30 //Driver for a multi-physics problem that couples a Navier--Stokes
31 //mesh to an advection diffusion mesh, giving Boussinesq convection
32 
33 //Oomph-lib headers, we require the generic, advection-diffusion,
34 //and navier-stokes elements.
35 #include "generic.h"
36 #include "advection_diffusion.h"
37 #include "navier_stokes.h"
38 #include "multi_physics.h"
39 
40 
41 // Both meshes are the standard rectangular quadmesh
42 #include "meshes/rectangular_quadmesh.h"
43 
44 // Use the oomph and std namespaces
45 using namespace oomph;
46 using namespace std;
47 
48 
49 
50 //======start_of_namespace============================================
51 /// Namespace for the physical parameters in the problem
52 //====================================================================
54 {
55 
56  /// Peclet number (identically one from our non-dimensionalisation)
57  double Peclet=1.0;
58 
59  /// 1/Prandtl number
60  double Inverse_Prandtl=1.0;
61 
62  /// \short Rayleigh number, set to be greater than
63  /// the threshold for linear instability
64  double Rayleigh = 1800.0;
65 
66  /// Gravity vector
67  Vector<double> Direction_of_gravity(2);
68 
69 } // end_of_namespace
70 
71 
72 //////////////////////////////////////////////////////////////////////
73 //////////////////////////////////////////////////////////////////////
74 //////////////////////////////////////////////////////////////////////
75 
76 
77 
78 //=======start_of_problem_class=======================================
79 /// 2D Convection problem on two rectangular domains, discretised
80 /// with refineable Navier-Stokes and Advection-Diffusion elements.
81 /// The specific type of element is specified via the template parameters.
82 //====================================================================
83 template<class NST_ELEMENT,class AD_ELEMENT>
84 class RefineableConvectionProblem : public Problem
85 {
86 
87 public:
88 
89  ///Constructor
91 
92  /// Destructor. Empty
94 
95  /// \short Update the problem specs before solve:
96  void actions_before_newton_solve();
97 
98  /// Update the problem after solve (empty)
100 
101  /// \short Access function to the NST mesh.
102  /// Casts the pointer to the base Mesh object to
103  /// the actual mesh type.
104  RefineableRectangularQuadMesh<NST_ELEMENT>* nst_mesh_pt()
105  {
106  return dynamic_cast<RefineableRectangularQuadMesh<NST_ELEMENT>*>
107  (Nst_mesh_pt);
108  } // end_of_nst_mesh
109 
110  /// \short Access function to the AD mesh.
111  /// Casts the pointer to the base Mesh object to
112  /// the actual mesh type.
113  RefineableRectangularQuadMesh<AD_ELEMENT>* adv_diff_mesh_pt()
114  {
115  return dynamic_cast<RefineableRectangularQuadMesh<AD_ELEMENT>*>
116  (Adv_diff_mesh_pt);
117  } // end_of_ad_mesh
118 
119  /// Actions before adapt:(empty)
121 
122  /// \short Actions after adaptation, reset all sources, then
123  /// re-pin a single pressure degree of freedom
125  {
126  //Unpin all the pressures in NST mesh to avoid pinning two pressures
127  RefineableNavierStokesEquations<2>::
128  unpin_all_pressure_dofs(nst_mesh_pt()->element_pt());
129 
130  //Pin the zero-th pressure dof in the zero-th element and set
131  // its value to zero
132  fix_pressure(0,0,0.0);
133 
134  // Set external elements for the multi-domain solution.
135  Multi_domain_functions::
136  setup_multi_domain_interactions<NST_ELEMENT,AD_ELEMENT>
137  (this,nst_mesh_pt(),adv_diff_mesh_pt());
138 
139  } //end_of_actions_after_adapt
140 
141 
142  ///Fix pressure in element e at pressure dof pdof and set to pvalue
143  void fix_pressure(const unsigned &e, const unsigned &pdof,
144  const double &pvalue)
145  {
146  //Cast to specific element and fix pressure in NST element
147  if (nst_mesh_pt()->nelement()>0)
148  {
149  dynamic_cast<NST_ELEMENT*>(nst_mesh_pt()->element_pt(e))->
150  fix_pressure(pdof,pvalue);
151  }
152  } // end_of_fix_pressure
153 
154 
155  /// \short Set the
156  /// boundary condition on the upper wall to be perturbed slightly
157  /// to force the solution into the symmetry broken state.
158  void enable_imperfection() {Imperfect = true;}
159 
160  /// \short Set th
161  /// boundary condition on the upper wall to be unperturbed.
162  void disable_imperfection() {Imperfect = false;}
163 
164  /// \short Doc the solution.
165  void doc_solution();
166 
167 private:
168 
169  /// DocInfo object
170  DocInfo Doc_info;
171 
172  /// Is the boundary condition imperfect or not
173  bool Imperfect;
174 
175 protected:
176 
177  /// Navier Stokes mesh
178  RefineableRectangularQuadMesh<NST_ELEMENT>* Nst_mesh_pt;
179 
180  /// Advection diffusion mesh
181  RefineableRectangularQuadMesh<AD_ELEMENT>* Adv_diff_mesh_pt;
182 
183 }; // end of problem class
184 
185 
186 //=======start_of_constructor=============================================
187 /// Constructor for adaptive thermal convection problem
188 //========================================================================
189 template<class NST_ELEMENT,class AD_ELEMENT>
192 {
193  // Set output directory
194  Doc_info.set_directory("RESLT");
195 
196  // # of elements in x-direction
197  unsigned n_x=9;
198 
199  // # of elements in y-direction
200  unsigned n_y=8;
201 
202  // Domain length in x-direction
203  double l_x=3.0;
204 
205  // Domain length in y-direction
206  double l_y=1.0;
207 
208  // Build the meshes
209  Nst_mesh_pt =
210  new RefineableRectangularQuadMesh<NST_ELEMENT>(n_x,n_y,l_x,l_y);
211  Adv_diff_mesh_pt =
212  new RefineableRectangularQuadMesh<AD_ELEMENT>(n_x,n_y,l_x,l_y);
213 
214  // Create/set error estimator
215  Nst_mesh_pt->spatial_error_estimator_pt()=new Z2ErrorEstimator;
216  Adv_diff_mesh_pt->spatial_error_estimator_pt()=new Z2ErrorEstimator;
217 
218  // Set error targets for adaptive refinement
219  Nst_mesh_pt->max_permitted_error()=0.5e-3;
220  Nst_mesh_pt->min_permitted_error()=0.5e-4;
221  Adv_diff_mesh_pt->max_permitted_error()=0.5e-3;
222  Adv_diff_mesh_pt->min_permitted_error()=0.5e-4;
223 
224 
225  // Set the boundary conditions for this problem: All nodes are
226  // free by default -- only need to pin the ones that have Dirichlet
227  // conditions here
228 
229  //Loop over the boundaries of the NST mesh
230  unsigned num_bound = nst_mesh_pt()->nboundary();
231  for(unsigned ibound=0;ibound<num_bound;ibound++)
232  {
233  //Set the maximum index to be pinned (all values by default)
234  unsigned val_max;
235 
236  //Loop over the number of nodes on the boundry
237  unsigned num_nod= nst_mesh_pt()->nboundary_node(ibound);
238  for (unsigned inod=0;inod<num_nod;inod++)
239  {
240 
241  //If we are on the side-walls, the v-velocity and temperature
242  //satisfy natural boundary conditions, so we only pin the
243  //first value
244  if((ibound==1) || (ibound==3))
245  {
246  val_max=1;
247  }
248  else
249  {
250  val_max=nst_mesh_pt()->boundary_node_pt(ibound,inod)->nvalue();
251  }
252 
253  //Loop over the desired values stored at the nodes and pin
254  for(unsigned j=0;j<val_max;j++)
255  {
256  nst_mesh_pt()->boundary_node_pt(ibound,inod)->pin(j);
257  }
258  }
259  }
260 
261  // Pin the zero-th pressure value in the zero-th element and
262  // set its value to zero.
263  fix_pressure(0,0,0.0);
264 
265  //Loop over the boundaries of the AD mesh
266  num_bound = adv_diff_mesh_pt()->nboundary();
267  for(unsigned ibound=0;ibound<num_bound;ibound++)
268  {
269  //Set the maximum index to be pinned (all values by default)
270  unsigned val_max;
271 
272  //Loop over the number of nodes on the boundry
273  unsigned num_nod= adv_diff_mesh_pt()->nboundary_node(ibound);
274  for (unsigned inod=0;inod<num_nod;inod++)
275  {
276  //If we are on the side-walls, the v-velocity and temperature
277  //satisfy natural boundary conditions, so we don't pin anything
278  // in this mesh
279  if ((ibound==1) || (ibound==3))
280  {
281  val_max=0;
282  }
283  else // pin all values
284  {
285  val_max=adv_diff_mesh_pt()->boundary_node_pt(ibound,inod)->nvalue();
286  //Loop over the desired values stored at the nodes and pin
287  for(unsigned j=0;j<val_max;j++)
288  {
289  adv_diff_mesh_pt()->boundary_node_pt(ibound,inod)->pin(j);
290  }
291  }
292  }
293  } // end of loop over AD mesh boundaries
294 
295  // Complete the build of all elements so they are fully functional
296 
297  // Loop over the elements to set up element-specific
298  // things that cannot be handled by the (argument-free!) ELEMENT
299  // constructor.
300  unsigned n_nst_element = nst_mesh_pt()->nelement();
301  for(unsigned i=0;i<n_nst_element;i++)
302  {
303  // Upcast from GeneralsedElement to the present element
304  NST_ELEMENT *el_pt = dynamic_cast<NST_ELEMENT*>
305  (nst_mesh_pt()->element_pt(i));
306 
307  // Set the Reynolds number (1/Pr in our non-dimensionalisation)
309 
310  // Set ReSt (also 1/Pr in our non-dimensionalisation)
311  el_pt->re_st_pt() = &Global_Physical_Variables::Inverse_Prandtl;
312 
313  // Set the Rayleigh number
314  el_pt->ra_pt() = &Global_Physical_Variables::Rayleigh;
315 
316  //Set Gravity vector
318 
319  // We can ignore the external geometric data in the "external"
320  // advection diffusion element when computing the Jacobian matrix
321  // because the interaction does not involve spatial gradients of
322  // the temperature (and also because the mesh isn't moving!)
323  el_pt->ignore_external_geometric_data();
324  }
325 
326  unsigned n_ad_element = adv_diff_mesh_pt()->nelement();
327  for(unsigned i=0;i<n_ad_element;i++)
328  {
329  // Upcast from GeneralsedElement to the present element
330  AD_ELEMENT *el_pt = dynamic_cast<AD_ELEMENT*>
331  (adv_diff_mesh_pt()->element_pt(i));
332 
333  // Set the Peclet number
334  el_pt->pe_pt() = &Global_Physical_Variables::Peclet;
335 
336  // Set the Peclet number multiplied by the Strouhal number
337  el_pt->pe_st_pt() =&Global_Physical_Variables::Peclet;
338 
339  // We can ignore the external geometric data in the "external"
340  // Navier Stokes element when computing the Jacobian matrix
341  // because the interaction does not involve spatial gradients of
342  // the velocities (and also because the mesh isn't moving!)
343  el_pt->ignore_external_geometric_data();
344 
345  } // end of setup for all AD elements
346 
347  // combine the submeshes
348  add_sub_mesh(Nst_mesh_pt);
349  add_sub_mesh(Adv_diff_mesh_pt);
350  build_global_mesh();
351 
352  // Set external elements for the multi-domain solution.
353  Multi_domain_functions::
354  setup_multi_domain_interactions<NST_ELEMENT,AD_ELEMENT>
355  (this,nst_mesh_pt(),adv_diff_mesh_pt());
356 
357  // Setup equation numbering scheme
358  cout << "Number of equations: " << assign_eqn_numbers() << endl;
359 
360 } // end of constructor
361 
362 
363 //===================start_actions_before_newton_solve====================
364 /// Update the problem specs before solve: (Re-)set boundary conditions
365 /// to include an imperfection (or not) depending on the control flag.
366 //========================================================================
367 template<class NST_ELEMENT,class AD_ELEMENT>
369 {
370  // Loop over the boundaries on the NST mesh
371  unsigned num_bound = nst_mesh_pt()->nboundary();
372  for(unsigned ibound=0;ibound<num_bound;ibound++)
373  {
374  // Loop over the nodes on boundary
375  unsigned num_nod=nst_mesh_pt()->nboundary_node(ibound);
376  for(unsigned inod=0;inod<num_nod;inod++)
377  {
378  // Get pointer to node
379  Node* nod_pt=nst_mesh_pt()->boundary_node_pt(ibound,inod);
380 
381  //Set the number of velocity components
382  unsigned vel_max=2;
383  //If we are on the side walls we only pin the x-velocity.
384  if((ibound==1) || (ibound==3)) {vel_max = 1;}
385  //Set the pinned velocities to zero
386  for(unsigned j=0;j<vel_max;j++) {nod_pt->set_value(j,0.0);}
387 
388  //If we are on the top boundary
389  if(ibound==2)
390  {
391  //Add small velocity imperfection if desired
392  if(Imperfect)
393  {
394  //Read out the x position
395  double x = nod_pt->x(0);
396  //Set a sinusoidal perturbation in the vertical velocity
397  //This perturbation is mass conserving
398  double value = sin(2.0*3.141592654*x/3.0);
399  nod_pt->set_value(1,value);
400  }
401  }
402 
403  }
404  }
405 
406  // Loop over all the boundaries on the AD mesh
407  num_bound=adv_diff_mesh_pt()->nboundary();
408  for(unsigned ibound=0;ibound<num_bound;ibound++)
409  {
410  // Loop over the nodes on boundary
411  unsigned num_nod=adv_diff_mesh_pt()->nboundary_node(ibound);
412  for(unsigned inod=0;inod<num_nod;inod++)
413  {
414  // Get pointer to node
415  Node* nod_pt=adv_diff_mesh_pt()->boundary_node_pt(ibound,inod);
416 
417  //If we are on the top boundary, set the temperature
418  //to -0.5 (cooled)
419  if(ibound==2) {nod_pt->set_value(0,-0.5);}
420 
421  //If we are on the bottom boundary, set the temperature
422  //to 0.5 (heated)
423  if(ibound==0) {nod_pt->set_value(0,0.5);}
424  }
425  }
426 
427 
428 } // end of actions before solve
429 
430 
431 
432 //====================start_of_doc_solution===============================
433 /// Doc the solution
434 //========================================================================
435 template<class NST_ELEMENT,class AD_ELEMENT>
437 {
438  //Declare an output stream and filename
439  ofstream some_file;
440  char filename[100];
441 
442  // Number of plot points: npts x npts
443  unsigned npts=5;
444 
445  // Output Navier-Stokes solution
446  sprintf(filename,"%s/fluid_soln%i.dat",Doc_info.directory().c_str(),
447  Doc_info.number());
448  some_file.open(filename);
449  nst_mesh_pt()->output(some_file,npts);
450  some_file.close();
451 
452  // Output advection diffusion solution
453  sprintf(filename,"%s/temperature_soln%i.dat",Doc_info.directory().c_str(),
454  Doc_info.number());
455  some_file.open(filename);
456  adv_diff_mesh_pt()->output(some_file,npts);
457  some_file.close();
458 
459 
460  Doc_info.number()++;
461 } // end of doc
462 
463 
464 //===============start_of_main========================================
465 /// Driver code for 2D Boussinesq convection problem with
466 /// adaptivity.
467 //====================================================================
468 int main()
469 {
470 
471 
472  // Set the direction of gravity
475 
476  // Create the problem with 2D nine-node refineable elements.
479  RefineableQCrouzeixRaviartElement<2>,
480  RefineableQAdvectionDiffusionElement<2,3> > ,
482  RefineableQAdvectionDiffusionElement<2,3>,
483  RefineableQCrouzeixRaviartElement<2> >
484  > problem;
485 
486  // Apply a perturbation to the upper boundary condition to
487  // force the solution into the symmetry-broken state.
488  problem.enable_imperfection();
489 
490  //Solve the problem with (up to) two levels of adaptation
491  problem.newton_solve(2);
492 
493  //Document the solution
494  problem.doc_solution();
495 
496  // Make the boundary conditions perfect and solve again.
497  // Now the slightly perturbed symmetry broken state computed
498  // above is used as the initial condition and the Newton solver
499  // converges to the symmetry broken solution, even without
500  // the perturbation
501  problem.disable_imperfection();
502  problem.newton_solve(2);
503  problem.doc_solution();
504 
505 } // end of main
506 
507 
508 
509 
510 
511 
512 
513 
514 
void actions_after_adapt()
Actions after adaptation, reset all sources, then re-pin a single pressure degree of freedom...
bool Imperfect
Is the boundary condition imperfect or not.
double Peclet
Peclet number (identically one from our non-dimensionalisation)
RefineableRectangularQuadMesh< AD_ELEMENT > * Adv_diff_mesh_pt
Advection diffusion mesh.
void actions_after_newton_solve()
Update the problem after solve (empty)
void fix_pressure(const unsigned &e, const unsigned &pdof, const double &pvalue)
Fix pressure in element e at pressure dof pdof and set to pvalue.
RefineableRectangularQuadMesh< AD_ELEMENT > * adv_diff_mesh_pt()
Access function to the AD mesh. Casts the pointer to the base Mesh object to the actual mesh type...
void actions_before_adapt()
Actions before adapt:(empty)
void actions_before_newton_solve()
Update the problem specs before solve:
Namespace for the physical parameters in the problem.
Vector< double > Direction_of_gravity(2)
Gravity vector.
RefineableRectangularQuadMesh< NST_ELEMENT > * Nst_mesh_pt
Navier Stokes mesh.
void enable_imperfection()
Set the boundary condition on the upper wall to be perturbed slightly to force the solution into the ...
double Inverse_Prandtl
1/Prandtl number
void disable_imperfection()
Set th boundary condition on the upper wall to be unperturbed.
double Rayleigh
Rayleigh number, set to be greater than the threshold for linear instability.
RefineableRectangularQuadMesh< NST_ELEMENT > * nst_mesh_pt()
Access function to the NST mesh. Casts the pointer to the base Mesh object to the actual mesh type...