gen_axisym_advection_diffusion_elements.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 //Non-inline functions for GeneralisedAxisymAdvection Diffusion elements
32 
33 namespace oomph
34 {
35 
36 ///2D GeneralisedAdvection Diffusion elements
37 
38 
39 /// Default value for Peclet number
41 
42 //======================================================================
43 /// \short Compute element residual Vector and/or element Jacobian matrix
44 ///
45 /// flag=1: compute both
46 /// flag=0: compute only residual Vector
47 ///
48 /// Pure version without hanging nodes
49 //======================================================================
52  Vector<double> &residuals,
53  DenseMatrix<double> &jacobian,
54  DenseMatrix<double>
55  &mass_matrix,
56  unsigned flag)
57 {
58  //Find out how many nodes there are
59  const unsigned n_node = nnode();
60 
61  //Get the nodal index at which the unknown is stored
62  const unsigned u_nodal_index = u_index_cons_axisym_adv_diff();
63 
64  //Set up memory for the shape and test functions
65  Shape psi(n_node), test(n_node);
66  DShape dpsidx(n_node,2), dtestdx(n_node,2);
67 
68  //Set the value of n_intpt
69  const unsigned n_intpt = integral_pt()->nweight();
70 
71  //Set the Vector to hold local coordinates
72  Vector<double> s(2);
73 
74  //Get Peclet number
75  const double peclet = pe();
76 
77  //Get the Peclet*Strouhal number
78  const double peclet_st = pe_st();
79 
80  //Integers used to store the local equation number and local unknown
81  //indices for the residuals and jacobians
82  int local_eqn=0, local_unknown=0;
83 
84  //Loop over the integration points
85  for(unsigned ipt=0;ipt<n_intpt;ipt++)
86  {
87 
88  //Assign values of s
89  for(unsigned i=0;i<2;i++) s[i] = integral_pt()->knot(ipt,i);
90 
91  //Get the integral weight
92  double w = integral_pt()->weight(ipt);
93 
94  //Call the derivatives of the shape and test functions
95  double J =
97  ipt,psi,dpsidx,test,dtestdx);
98 
99  //Premultiply the weights and the Jacobian
100  double W = w*J;
101 
102  //Calculate local values of the solution and its derivatives
103  //Allocate
104  double interpolated_u=0.0;
105  double dudt=0.0;
106  Vector<double> interpolated_x(2,0.0);
107  Vector<double> interpolated_dudx(2,0.0);
108  Vector<double> mesh_velocity(2,0.0);
109 
110 
111  //Calculate function value and derivatives:
112  //-----------------------------------------
113  // Loop over nodes
114  for(unsigned l=0;l<n_node;l++)
115  {
116  //Get the value at the node
117  double u_value = raw_nodal_value(l,u_nodal_index);
118  interpolated_u += u_value*psi(l);
119  dudt += du_dt_cons_axisym_adv_diff(l)*psi(l);
120  // Loop over directions
121  for(unsigned j=0;j<2;j++)
122  {
123  interpolated_x[j] += raw_nodal_position(l,j)*psi(l);
124  interpolated_dudx[j] += u_value*dpsidx(l,j);
125  }
126  }
127 
128  // Mesh velocity?
129  if (!ALE_is_disabled)
130  {
131  for(unsigned l=0;l<n_node;l++)
132  {
133  for(unsigned j=0;j<2;j++)
134  {
135  mesh_velocity[j] += raw_dnodal_position_dt(l,j)*psi(l);
136  }
137  }
138  }
139 
140 
141  //Get source function
142  //-------------------
143  double source;
144  get_source_cons_axisym_adv_diff(ipt,interpolated_x,source);
145 
146 
147  //Get wind (three components because this could come from a NS computation)
148  //--------
149  Vector<double> wind(3);
150  get_wind_cons_axisym_adv_diff(ipt,s,interpolated_x,wind);
151 
152  //Get the conserved wind (non-divergence free)
153  Vector<double> conserved_wind(3);
154  get_conserved_wind_cons_axisym_adv_diff(ipt,s,interpolated_x,conserved_wind);
155 
156  //Get diffusivity tensor
157  DenseMatrix<double> D(3,3);
158  get_diff_cons_axisym_adv_diff(ipt,s,interpolated_x,D);
159 
160  //r is the first position component
161  double r = interpolated_x[0];
162 
163  // Assemble residuals and Jacobian
164  //--------------------------------
165 
166  // Loop over the test functions
167  for(unsigned l=0;l<n_node;l++)
168  {
169  //Set the local equation number
170  local_eqn = nodal_local_eqn(l,u_nodal_index);
171 
172  /*IF it's not a boundary condition*/
173  if(local_eqn >= 0)
174  {
175  // Add body force/source term and time derivative
176  residuals[local_eqn] -= (peclet_st*dudt + source)*r*test(l)*W;
177 
178  // The Generalised Advection Diffusion bit itself
179  // Only loop over the non azimuthal directions
180  for(unsigned k=0;k<2;k++)
181  {
182  //Terms that multiply the test function
183  //divergence-free wind
184  double tmp = peclet*wind[k];
185  //If the mesh is moving need to subtract the mesh velocity
186  if(!ALE_is_disabled) {tmp -= peclet_st*mesh_velocity[k];}
187  tmp *= interpolated_dudx[k];
188 
189  //Terms that multiply the derivative of the test function
190  //Advective term
191  double tmp2 = -conserved_wind[k]*interpolated_u;
192  //Now the diuffusive term
193  for(unsigned j=0;j<2;j++)
194  {
195  tmp2 += D(k,j)*interpolated_dudx[j];
196  }
197  //Now construct the contribution to the residuals
198  residuals[local_eqn] -= (tmp*test(l) + tmp2*dtestdx(l,k))*r*W;
199  }
200 
201  // Calculate the jacobian
202  //-----------------------
203  if(flag)
204  {
205  //Loop over the velocity shape functions again
206  for(unsigned l2=0;l2<n_node;l2++)
207  {
208  //Set the number of the unknown
209  local_unknown = nodal_local_eqn(l2,u_nodal_index);
210 
211  //If at a non-zero degree of freedom add in the entry
212  if(local_unknown >= 0)
213  {
214  //Mass matrix term
215  jacobian(local_eqn,local_unknown)
216  -= peclet_st*test(l)*psi(l2)*
217  node_pt(l2)->time_stepper_pt()->weight(1,0)*r*W;
218 
219  //Add the mass matrix term
220  if(flag==2)
221  {
222  mass_matrix(local_eqn,local_unknown)
223  += peclet_st*test(l)*psi(l2)*r*W;
224  }
225 
226  //Add contribution to Elemental Matrix
227  for(unsigned k=0;k<2;k++)
228  {
229  //Temporary term used in assembly
230  double tmp = -peclet*wind[k];
231  if(!ALE_is_disabled)
232  {tmp -= peclet_st*mesh_velocity[k];}
233  tmp *= dpsidx(l2,k);
234 
235  double tmp2 = -conserved_wind[k]*psi(l2);
236  //Now the diffusive term
237  for(unsigned j=0;j<2;j++)
238  {
239  tmp2 += D(k,j)*dpsidx(l2,j);
240  }
241 
242  //Now assemble Jacobian term
243  jacobian(local_eqn,local_unknown)
244  -= (tmp*test(l) + tmp2*dtestdx(l,k))*r*W;
245  }
246  }
247  }
248  }
249  }
250  }
251 
252 
253  } // End of loop over integration points
254 }
255 
256 
257 
258 //======================================================================
259 /// Self-test: Return 0 for OK
260 //======================================================================
262 {
263 
264  bool passed=true;
265 
266  // Check lower-level stuff
267  if (FiniteElement::self_test()!=0)
268  {
269  passed=false;
270  }
271 
272  // Return verdict
273  if (passed)
274  {
275  return 0;
276  }
277  else
278  {
279  return 1;
280  }
281 
282 }
283 
284 
285 
286 //======================================================================
287 /// \short Output function:
288 ///
289 /// r,z,u,w_r,w_z
290 ///
291 /// nplot points in each coordinate direction
292 //======================================================================
294  std::ostream &outfile,
295  const unsigned &nplot)
296  {
297  //Vector of local coordinates
298  Vector<double> s(2);
299 
300  // Tecplot header info
301  outfile << tecplot_zone_string(nplot);
302 
303  const unsigned n_node = this->nnode();
304  Shape psi(n_node);
305  DShape dpsidx(n_node,2);
306 
307  // Loop over plot points
308  unsigned num_plot_points=nplot_points(nplot);
309  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
310  {
311  // Get local coordinates of plot point
312  get_s_plot(iplot,nplot,s);
313 
314  // Get Eulerian coordinate of plot point
315  Vector<double> x(2);
316  interpolated_x(s,x);
317 
318  for(unsigned i=0;i<2;i++)
319  {
320  outfile << x[i] << " ";
321  }
322  outfile << interpolated_u_cons_axisym_adv_diff(s) << " ";
323 
324  //Get the gradients
325  /*(void)this->dshape_eulerian(s,psi,dpsidx);
326  Vector<double> interpolated_dudx(2,0.0);
327  for(unsigned n=0;n<n_node;n++)
328  {
329  const double u_ = this->nodal_value(n,0);
330  for(unsigned i=0;i<2;i++)
331  {
332  interpolated_dudx[i] += u_*dpsidx(n,i);
333  }
334  }
335 
336  for(unsigned i=0;i<2;i++)
337  {
338  outfile << interpolated_dudx[i] << " ";
339  }*/
340 
341  // Get the wind
342  Vector<double> wind(3);
343  // Dummy integration point variable needed
344  unsigned ipt=0;
345  get_wind_cons_axisym_adv_diff(ipt,s,x,wind);
346  for(unsigned i=0;i<3;i++)
347  {
348  outfile << wind[i] << " ";
349  }
350  outfile << std::endl;
351 
352  }
353 
354  // Write tecplot footer (e.g. FE connectivity lists)
355  write_tecplot_zone_footer(outfile,nplot);
356 
357 }
358 
359 
360 //======================================================================
361 /// C-style output function:
362 ///
363 /// r,z,u
364 ///
365 /// nplot points in each coordinate direction
366 //======================================================================
368  const unsigned &nplot)
369 {
370  //Vector of local coordinates
371  Vector<double> s(2);
372 
373  // Tecplot header info
374  fprintf(file_pt,"%s",tecplot_zone_string(nplot).c_str());
375 
376  // Loop over plot points
377  unsigned num_plot_points=nplot_points(nplot);
378  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
379  {
380 
381  // Get local coordinates of plot point
382  get_s_plot(iplot,nplot,s);
383 
384  for(unsigned i=0;i<2;i++)
385  {
386  fprintf(file_pt,"%g ",interpolated_x(s,i));
387 
388  }
389  fprintf(file_pt,"%g \n",interpolated_u_cons_axisym_adv_diff(s));
390  }
391 
392  // Write tecplot footer (e.g. FE connectivity lists)
393  write_tecplot_zone_footer(file_pt,nplot);
394 
395 }
396 
397 
398 
399 //======================================================================
400  /// \short Output exact solution
401  ///
402  /// Solution is provided via function pointer.
403  /// Plot at a given number of plot points.
404  ///
405  /// r,z,,u_exact
406 //======================================================================
408  std::ostream &outfile,
409  const unsigned &nplot,
411  {
412 
413  //Vector of local coordinates
414  Vector<double> s(2);
415 
416  // Vector for coordintes
417  Vector<double> x(2);
418 
419  // Tecplot header info
420  outfile << tecplot_zone_string(nplot);
421 
422  // Exact solution Vector (here a scalar)
423  Vector<double> exact_soln(1);
424 
425  // Loop over plot points
426  unsigned num_plot_points=nplot_points(nplot);
427  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
428  {
429 
430  // Get local coordinates of plot point
431  get_s_plot(iplot,nplot,s);
432 
433  // Get x position as Vector
434  interpolated_x(s,x);
435 
436  // Get exact solution at this point
437  (*exact_soln_pt)(x,exact_soln);
438 
439  //Output x,y,...,u_exact
440  for(unsigned i=0;i<2;i++)
441  {
442  outfile << x[i] << " ";
443  }
444  outfile << exact_soln[0] << std::endl;
445  }
446 
447  // Write tecplot footer (e.g. FE connectivity lists)
448  write_tecplot_zone_footer(outfile,nplot);
449 
450  }
451 
452 
453 
454 
455 //======================================================================
456  /// \short Validate against exact solution
457  ///
458  /// Solution is provided via function pointer.
459  /// Plot error at a given number of plot points.
460  ///
461 //======================================================================
463  std::ostream &outfile,
465  double& error, double& norm)
466 {
467 
468  // Initialise
469  error=0.0;
470  norm=0.0;
471 
472  //Vector of local coordinates
473  Vector<double> s(2);
474 
475  // Vector for coordintes
476  Vector<double> x(2);
477 
478  //Find out how many nodes there are in the element
479  unsigned n_node = nnode();
480 
481  Shape psi(n_node);
482 
483  //Set the value of n_intpt
484  unsigned n_intpt = integral_pt()->nweight();
485 
486  // Tecplot header info
487  outfile << "ZONE" << std::endl;
488 
489  // Exact solution Vector (here a scalar)
490  Vector<double> exact_soln(1);
491 
492  //Loop over the integration points
493  for(unsigned ipt=0;ipt<n_intpt;ipt++)
494  {
495 
496  //Assign values of s
497  for(unsigned i=0;i<2;i++)
498  {
499  s[i] = integral_pt()->knot(ipt,i);
500  }
501 
502  //Get the integral weight
503  double w = integral_pt()->weight(ipt);
504 
505  // Get jacobian of mapping
506  double J=J_eulerian(s);
507 
508  //Premultiply the weights and the Jacobian
509  double W = w*J;
510 
511  // Get x position as Vector
512  interpolated_x(s,x);
513 
514  // Get FE function value
516 
517  // Get exact solution at this point
518  (*exact_soln_pt)(x,exact_soln);
519 
520  //Output x,y,...,error
521  for(unsigned i=0;i<2;i++)
522  {
523  outfile << x[i] << " ";
524  }
525  outfile << exact_soln[0] << " " << exact_soln[0]-u_fe << std::endl;
526 
527  // Add to error and norm
528  norm+=exact_soln[0]*exact_soln[0]*x[0]*W;
529  error+=(exact_soln[0]-u_fe)*(exact_soln[0]-u_fe)*x[0]*W;
530  }
531 
532 }
533 
534 //======================================================================
535 /// \short Calculate the integrated value of the unknown over the element
536 ///
537 //======================================================================
539 {
540 
541  // Initialise
542  double sum = 0.0;
543 
544  //Find out how many nodes there are in the element
545  const unsigned n_node = this->nnode();
546 
547  //Find the index at which the concentration is stored
548  const unsigned u_nodal_index = this->u_index_cons_axisym_adv_diff();
549 
550  //Allocate memory for the shape functions
551  Shape psi(n_node);
552 
553  //Set the value of n_intpt
554  const unsigned n_intpt = integral_pt()->nweight();
555 
556  //Loop over the integration points
557  for(unsigned ipt=0;ipt<n_intpt;ipt++)
558  {
559  //Get the integral weight
560  const double w = integral_pt()->weight(ipt);
561 
562  //Get the shape functions
563  this->shape_at_knot(ipt,psi);
564 
565  //Calculate the concentration
566  double interpolated_u = 0.0;
567  for(unsigned l=0;l<n_node;l++)
568  {interpolated_u += this->nodal_value(l,u_nodal_index)*psi(l);}
569 
570  //calculate the r coordinate
571  double r = 0.0;
572  for(unsigned l=0;l<n_node;l++)
573  {r += this->nodal_position(l,0)*psi(l);}
574 
575  // Get jacobian of mapping
576  const double J=J_eulerian_at_knot(ipt);
577 
578  //Add the values to the sum
579  sum += interpolated_u*r*w*J;
580  }
581 
582  //return the sum
583  return sum;
584 }
585 
586 
587 //======================================================================
588 // Set the data for the number of Variables at each node
589 //======================================================================
590  template<unsigned NNODE_1D>
592  Initial_Nvalue = 1;
593 
594 //====================================================================
595 // Force build of templates
596 //====================================================================
600 
601 }
bool ALE_is_disabled
Boolean flag to indicate if ALE formulation is disabled when time-derivatives are computed...
const double & pe() const
Peclet number.
virtual void get_diff_cons_axisym_adv_diff(const unsigned &ipt, const Vector< double > &s, const Vector< double > &x, DenseMatrix< double > &D) const
Get diffusivity tensor at (Eulerian) position x and/or local coordinate s. This function is virtual t...
cstr elem_len * i
Definition: cfortran.h:607
void output_fct(std::ostream &outfile, const unsigned &nplot, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt)
Output exact soln: r,z,u_exact at nplot^2 plot points.
virtual unsigned self_test()
Self-test: Check inversion of element & do self-test for GeneralisedElement. Return 0 if OK...
Definition: elements.cc:4333
virtual void get_wind_cons_axisym_adv_diff(const unsigned &ipt, const Vector< double > &s, const Vector< double > &x, Vector< double > &wind) const
Get wind at (Eulerian) position x and/or local coordinate s. This function is virtual to allow overlo...
virtual double dshape_and_dtest_eulerian_at_knot_cons_axisym_adv_diff(const unsigned &ipt, Shape &psi, DShape &dpsidx, Shape &test, DShape &dtestdx) const =0
Shape/test functions and derivs w.r.t. to global coords at integration point ipt; return Jacobian of ...
virtual void get_conserved_wind_cons_axisym_adv_diff(const unsigned &ipt, const Vector< double > &s, const Vector< double > &x, Vector< double > &wind) const
Get additional (conservative) wind at (Eulerian) position x and/or local coordinate s...
void(* SteadyExactSolutionFctPt)(const Vector< double > &, Vector< double > &)
Function pointer for function that computes vector-valued steady "exact solution" as ...
Definition: elements.h:1723
unsigned self_test()
Self-test: Return 0 for OK.
const double & pe_st() const
Peclet number multiplied by Strouhal number.
virtual void fill_in_generic_residual_contribution_cons_axisym_adv_diff(Vector< double > &residuals, DenseMatrix< double > &jacobian, DenseMatrix< double > &mass_matrix, unsigned flag)
Add the element&#39;s contribution to its residual vector only (if flag=and/or element Jacobian matrix...
static char t char * s
Definition: cfortran.h:572
QGeneralisedAxisymAdvectionDiffusionElement elements are linear/quadrilateral/brick-shaped Advection ...
void output(std::ostream &outfile)
Output with default number of plot points.
double integrate_u()
Integrate the concentration over the element.
void compute_error(std::ostream &outfile, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt, double &error, double &norm)
Get error against and norm of exact solution.
static double Default_peclet_number
Static default value for the Peclet number.
double du_dt_cons_axisym_adv_diff(const unsigned &n) const
du/dt at local node n.
virtual unsigned u_index_cons_axisym_adv_diff() const
A class for all elements that solve the Advection Diffusion equations in conservative form using isop...
virtual void get_source_cons_axisym_adv_diff(const unsigned &ipt, const Vector< double > &x, double &source) const
Get source term at (Eulerian) position x. This function is virtual to allow overloading in multi-phys...
double interpolated_u_cons_axisym_adv_diff(const Vector< double > &s) const
Return FE representation of function value u(s) at local coordinate s.