axisymmetric_advection_navier_stokes_elements.h
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 #ifndef AXISYMMETRIC_ADVECTION_NAVIER_STOKES_ELEMENTS_HEADER
27 #define AXISYMMETRIC_ADVECTION_NAVIER_STOKES_ELEMENTS_HEADER
28 
29 //Oomph-lib headers, we require the generic, advection-diffusion-reaction,
30 //navier-stokes elements and fluid interface elements
31 #include "generic.h"
32 #include "axisym_advection_diffusion.h"
33 #include "axisym_navier_stokes.h"
34 
35 namespace oomph
36 {
37 
38 //======================class definition==============================
39 /// A class that solves the Boussinesq approximation of the Navier--Stokes
40 /// and energy equations by coupling two pre-existing classes.
41 /// The QAdvectionDiffusionReactionElement with
42 /// bi-quadratic interpolation for the
43 /// scalar variables (temperature and concentration) and
44 /// QCrouzeixRaviartElement which solves the Navier--Stokes equations
45 /// using bi-quadratic interpolation for the velocities and a discontinuous
46 /// bi-linear interpolation for the pressure. Note that we are free to
47 /// choose the order in which we store the variables at the nodes. In this
48 /// case we choose to store the variables in the order fluid velocities
49 /// followed by temperature. We must, therefore, overload the function
50 /// AdvectionDiffusionReactionEquations<2,DIM>::u_index_adv_diff_react()
51 /// to indicate that
52 /// the temperature is stored at the DIM-th position not the 0-th. We do not
53 /// need to overload the corresponding function in the
54 /// NavierStokesEquations<DIM> class because the velocities are stored
55 /// first.
56 //=========================================================================
58  public virtual QAxisymAdvectionDiffusionElement<3>,
59  public virtual AxisymmetricQCrouzeixRaviartElement
60 {
61 
62 public:
63 
64  /// Constructor: call the underlying constructors and
65  /// initialise the pointer to the Rayleigh number to point
66  /// to the default value of 0.0.
68  QAxisymAdvectionDiffusionElement<3>(),
69  AxisymmetricQCrouzeixRaviartElement() {}
70 
71 
72  /// The required number of values stored at the nodes is the sum of the
73  /// required values of the two single-physics elements. Note that this step is
74  /// generic for any multi-physics element of this type.
75  unsigned required_nvalue(const unsigned &n) const
76  {return (QAxisymAdvectionDiffusionElement<3>::required_nvalue(n) +
77  AxisymmetricQCrouzeixRaviartElement::required_nvalue(n));}
78 
79  /// Final override for disable ALE
80  void disable_ALE()
81  {
82  //Disable ALE in both sets of equations
83  AxisymmetricNavierStokesEquations::disable_ALE();
84  AxisymAdvectionDiffusionEquations::enable_ALE();
85  }
86 
87  /// Final override for enable ALE
88  void enable_ALE()
89  {
90  //Enable ALE in both sets of equations
91  AxisymmetricNavierStokesEquations::enable_ALE();
92  AxisymAdvectionDiffusionEquations::enable_ALE();
93  }
94 
95 
96  /// Number of scalars/fields output by this element. Reimplements
97  /// broken virtual function in base class.
98  unsigned nscalar_paraview() const
99  {
100  return AxisymmetricNavierStokesEquations::nscalar_paraview()
101  + AxisymAdvectionDiffusionEquations::nscalar_paraview();
102  }
103 
104  /// Write values of the i-th scalar field at the plot points. Needs
105  /// to be implemented for each new specific element type.
106  void scalar_value_paraview(std::ofstream& file_out,
107  const unsigned& i,
108  const unsigned& nplot) const
109  {
110  AxisymmetricNavierStokesEquations::scalar_value_paraview(file_out,i,nplot);
111  AxisymAdvectionDiffusionEquations::scalar_value_paraview(file_out,i,nplot);
112  }
113 
114 
115  std::string scalar_name_paraview(const unsigned& i) const
116  {
117  return AxisymmetricNavierStokesEquations::scalar_name_paraview(i);
118  //AxisymAdvectionDiffusionEquations::scalar_name_paraview(i);
119  }
120 
121 
122 
123  /// Overload the standard output function with the broken default
124  void output(std::ostream &outfile) {FiniteElement::output(outfile);}
125 
126  /// Output function:
127  /// Output x, y, u, v, p, theta at Nplot^DIM plot points
128  // Start of output function
129  void output(std::ostream &outfile, const unsigned &nplot)
130  {
131  //vector of local coordinates
132  Vector<double> s(2);
133 
134  // Tecplot header info
135  outfile << this->tecplot_zone_string(nplot);
136 
137  // Loop over plot points
138  unsigned num_plot_points=this->nplot_points(nplot);
139  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
140  {
141  // Get local coordinates of plot point
142  this->get_s_plot(iplot,nplot,s);
143 
144  // Output the position of the plot point
145  for(unsigned i=0;i<2;i++)
146  {outfile << this->interpolated_x(s,i) << " ";}
147 
148  // Output the fluid velocities at the plot point
149  for(unsigned i=0;i<3;i++)
150  {outfile << this->interpolated_u_axi_nst(s,i) << " ";}
151 
152  // Output the fluid pressure at the plot point
153  outfile << this->interpolated_p_axi_nst(s) << " ";
154 
155  //Output the solute concentration
156  outfile << this->interpolated_u_axi_adv_diff(s) << " ";
157 
158  outfile << "\n";
159  }
160  outfile << std::endl;
161 
162  // Write tecplot footer (e.g. FE connectivity lists)
163  this->write_tecplot_zone_footer(outfile,nplot);
164  } //End of output function
165 
166 
167  /// C-style output function: Broken default
168  void output(FILE* file_pt)
169  {FiniteElement::output(file_pt);}
170 
171  /// C-style output function: Broken default
172  void output(FILE* file_pt, const unsigned &n_plot)
173  {FiniteElement::output(file_pt,n_plot);}
174 
175  /// Output function for an exact solution: Broken default
176  void output_fct(std::ostream &outfile, const unsigned &Nplot,
177  FiniteElement::SteadyExactSolutionFctPt
178  exact_soln_pt)
179  {FiniteElement::output_fct(outfile,Nplot,exact_soln_pt);}
180 
181 
182  /// Output function for a time-dependent exact solution:
183  /// Broken default.
184  void output_fct(std::ostream &outfile, const unsigned &Nplot,
185  const double& time,
186  FiniteElement::UnsteadyExactSolutionFctPt
187  exact_soln_pt)
188  {
189  FiniteElement::
190  output_fct(outfile,Nplot,time,exact_soln_pt);
191  }
192 
193  /// Overload the index at which the temperature and solute
194  /// concentration variables are stored.
195  // We choose to store them after the fluid velocities.
196  inline unsigned u_index_axi_adv_diff() const {return 3;}
197 
198 
199  //Compute norm overload to NS version
200  void compute_norm(double &norm)
201  {AxisymmetricQCrouzeixRaviartElement::compute_norm(norm);}
202 
203 
204  /// Validate against exact solution at given time
205  /// Solution is provided via function pointer.
206  /// Plot at a given number of plot points and compute L2 error
207  /// and L2 norm of velocity solution over element
208  /// Call the broken default
209  void compute_error(std::ostream &outfile,
210  FiniteElement::UnsteadyExactSolutionFctPt exact_soln_pt,
211  const double& time,
212  double& error, double& norm)
213  {FiniteElement::compute_error(outfile,exact_soln_pt,
214  time,error,norm);}
215 
216  /// Validate against exact solution.
217  /// Solution is provided via function pointer.
218  /// Plot at a given number of plot points and compute L2 error
219  /// and L2 norm of velocity solution over element
220  /// Call the broken default
221  void compute_error(std::ostream &outfile,
222  FiniteElement::SteadyExactSolutionFctPt exact_soln_pt,
223  double& error, double& norm)
224  {FiniteElement::compute_error(outfile,exact_soln_pt,error,norm);}
225 
226  /// Overload the wind function in the advection-diffusion equations.
227  /// This provides the coupling from the Navier--Stokes equations to the
228  /// advection-diffusion equations because the wind is the fluid velocity.
229  void get_wind_axi_adv_diff(const unsigned& ipt,
230  const Vector<double> &s, const Vector<double>& x,
231  Vector<double>& wind) const
232  {
233  //The wind function is simply the velocity at the points
234  this->interpolated_u_axi_nst(s,wind);
235  }
236 
237  /// Calculate the element's contribution to the residual vector.
238  /// Recall that fill_in_* functions MUST NOT initialise the entries
239  /// in the vector to zero. This allows us to call the
240  /// fill_in_* functions of the constituent single-physics elements
241  /// sequentially, without wiping out any previously computed entries.
242  void fill_in_contribution_to_residuals(Vector<double> &residuals)
243  {
244  //Fill in the residuals of the Navier-Stokes equations
245  AxisymmetricNavierStokesEquations::fill_in_contribution_to_residuals(residuals);
246 
247  //Fill in the residuals of the advection-diffusion eqautions
248  AxisymAdvectionDiffusionEquations::fill_in_contribution_to_residuals(residuals);
249  }
250 
251 
252 #ifdef USE_FD_JACOBIAN_FOR_ADVECTION_DIFFUSION_NAVIER_STOKES_ELEMENT
253 
254 
255  /// Compute the element's residual vector and the Jacobian matrix.
256  /// Jacobian is computed by finite-differencing.
257  void fill_in_contribution_to_jacobian(Vector<double> &residuals,
258  DenseMatrix<double> &jacobian)
259  {
260  // This function computes the Jacobian by finite-differencing
261  FiniteElement::fill_in_contribution_to_jacobian(residuals,jacobian);
262  }
263 
264 #else
265 
266  /// Helper function to get the off-diagonal blocks of the Jacobian
267  /// matrix by finite differences
268  void fill_in_off_diagonal_jacobian_blocks_by_fd(Vector<double> &residuals,
269  DenseMatrix<double> &jacobian)
270  {
271  //Local storage for the index in the nodes at which the
272  //Navier-Stokes velocities are stored (we know that this should be 0,1,2)
273  unsigned u_nodal_nst[3];
274  for(unsigned i=0;i<3;i++)
275  {u_nodal_nst[i] = this->u_index_nst(i);}
276 
277  //Local storage for the index at which the temperature and
278  //solute are stored
279  unsigned C_nodal_adv_diff = this->u_index_axi_adv_diff();
280 
281 
282  //Find the total number of unknowns in the elements
283  unsigned n_dof = this->ndof();
284 
285  //Temporary storage for residuals
286  Vector<double> newres(n_dof);
287 
288  //Storage for local unknown and local equation
289  int local_unknown =0, local_eqn = 0;
290 
291  //Set the finite difference step
292  double fd_step = FiniteElement::Default_fd_jacobian_step;
293 
294  //Find the number of nodes
295  unsigned n_node = this->nnode();
296 
297  //Calculate the contribution of the Navier--Stokes velocities to the
298  //advection-diffusion equations
299 
300  //Loop over the nodes
301  for(unsigned n=0;n<n_node;n++)
302  {
303  //There are 3 values of the velocities
304  for(unsigned i=0;i<3;i++)
305  {
306  //Get the local velocity equation number
307  local_unknown = this->nodal_local_eqn(n,u_nodal_nst[i]);
308 
309  //If it's not pinned
310  if(local_unknown >= 0)
311  {
312  //Get a pointer to the velocity value
313  double *value_pt = this->node_pt(n)->value_pt(u_nodal_nst[i]);
314 
315  //Save the old value
316  double old_var = *value_pt;
317 
318  //Increment the value
319  *value_pt += fd_step;
320 
321  //Get the altered advection-diffusion residuals.
322  //Do this using fill_in because get_residuals has never been
323  //overloaded, and will actually compute all residuals which
324  //is slightly inefficient.
325  for(unsigned m=0;m<n_dof;m++) {newres[m] = 0.0;}
326  AxisymAdvectionDiffusionEquations::
327  fill_in_contribution_to_residuals(newres);
328 
329  //Now fill in the Advection-Diffusion-Reaction sub-block
330  //of the jacobian
331  for(unsigned m=0;m<n_node;m++)
332  {
333  //Local equation for temperature or solute
334  local_eqn = this->nodal_local_eqn(m,C_nodal_adv_diff);
335 
336  //If it's not a boundary condition
337  if(local_eqn >= 0)
338  {
339  double sum = (newres[local_eqn] - residuals[local_eqn])/fd_step;
340  jacobian(local_eqn,local_unknown) = sum;
341  }
342  }
343 
344  //Reset the nodal data
345  *value_pt = old_var;
346  }
347  }
348 
349  } //End of loop over nodes
350 
351 }
352 
353  /// Compute the element's residual Vector and the Jacobian matrix.
354  /// Use finite-differencing only for the off-diagonal blocks.
355  void fill_in_contribution_to_jacobian(Vector<double> &residuals,
356  DenseMatrix<double> &jacobian)
357  {
358 
359  //Calculate the Navier-Stokes contributions (diagonal block and residuals)
360  AxisymmetricNavierStokesEquations::
361  fill_in_contribution_to_jacobian(residuals,jacobian);
362 
363  //Calculate the advection-diffusion contributions
364  //(diagonal block and residuals)
365  AxisymAdvectionDiffusionEquations::
366  fill_in_contribution_to_jacobian(residuals,jacobian);
367 
368  //Add in the off-diagonal blocks
369  fill_in_off_diagonal_jacobian_blocks_by_fd(residuals,jacobian);
370  } //End of jacobian calculation
371 
372 #endif
373 
374 
375  /// Add the element's contribution to its residuals vector,
376  /// jacobian matrix and mass matrix
378  Vector<double> &residuals, DenseMatrix<double> &jacobian,
379  DenseMatrix<double> &mass_matrix)
380  {
381  AxisymmetricNavierStokesEquations::
382  fill_in_contribution_to_jacobian_and_mass_matrix(
383  residuals,jacobian,mass_matrix);
384 
385  AxisymAdvectionDiffusionEquations::
386  fill_in_contribution_to_jacobian_and_mass_matrix(
387  residuals,jacobian,mass_matrix);
388 
389  fill_in_off_diagonal_jacobian_blocks_by_fd(residuals,jacobian);
390  }
391 
392 
393 };
394 
395 
396 //=======================================================================
397 /// Face geometry of the 2D DoubleBuoyant Crouzeix_Raviart elements
398 //=======================================================================
399 template<>
401 public virtual QElement<1,3>
402 {
403  public:
404  FaceGeometry() : QElement<1,3>() {}
405 };
406 
407 //=======================================================================
408 /// Face geometry of the 2D DoubleBuoyant Crouzeix_Raviart elements
409 //=======================================================================
410 template<>
411 class FaceGeometry<FaceGeometry<AxisymmetricQAdvectionCrouzeixRaviartElement> >:
412 public virtual PointElement
413 {
414  public:
415  FaceGeometry() : PointElement() {}
416 };
417 
418 } //End of the oomph namespace
419 
420 #endif
A class that solves the Boussinesq approximation of the Navier–Stokes and energy equations by couplin...
void scalar_value_paraview(std::ofstream &file_out, const unsigned &i, const unsigned &nplot) const
Write values of the i-th scalar field at the plot points. Needs to be implemented for each new specif...
void output(std::ostream &outfile)
Overload the standard output function with the broken default.
void output_fct(std::ostream &outfile, const unsigned &Nplot, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt)
Output function for an exact solution: Broken default.
void output_fct(std::ostream &outfile, const unsigned &Nplot, const double &time, FiniteElement::UnsteadyExactSolutionFctPt exact_soln_pt)
Output function for a time-dependent exact solution: Broken default.
void compute_error(std::ostream &outfile, FiniteElement::UnsteadyExactSolutionFctPt exact_soln_pt, const double &time, double &error, double &norm)
Validate against exact solution at given time Solution is provided via function pointer....
unsigned required_nvalue(const unsigned &n) const
The required number of values stored at the nodes is the sum of the required values of the two single...
void output(std::ostream &outfile, const unsigned &nplot)
Output function: Output x, y, u, v, p, theta at Nplot^DIM plot points.
void fill_in_contribution_to_jacobian_and_mass_matrix(Vector< double > &residuals, DenseMatrix< double > &jacobian, DenseMatrix< double > &mass_matrix)
Add the element's contribution to its residuals vector, jacobian matrix and mass matrix.
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Calculate the element's contribution to the residual vector. Recall that fill_in_* functions MUST NOT...
unsigned u_index_axi_adv_diff() const
Overload the index at which the temperature and solute concentration variables are stored.
void get_wind_axi_adv_diff(const unsigned &ipt, const Vector< double > &s, const Vector< double > &x, Vector< double > &wind) const
Overload the wind function in the advection-diffusion equations. This provides the coupling from the ...
void compute_error(std::ostream &outfile, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt, double &error, double &norm)
Validate against exact solution. Solution is provided via function pointer. Plot at a given number of...
void fill_in_contribution_to_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Compute the element's residual vector and the Jacobian matrix. Jacobian is computed by finite-differe...
void fill_in_off_diagonal_jacobian_blocks_by_fd(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Helper function to get the off-diagonal blocks of the Jacobian matrix by finite differences.
void output(FILE *file_pt)
C-style output function: Broken default.
AxisymmetricQAdvectionCrouzeixRaviartElement()
Constructor: call the underlying constructors and initialise the pointer to the Rayleigh number to po...
void output(FILE *file_pt, const unsigned &n_plot)
C-style output function: Broken default.
unsigned nscalar_paraview() const
Number of scalars/fields output by this element. Reimplements broken virtual function in base class.