refineable_axisym_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// 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 //Header file for refineable axisymmetric quad Navier Stokes elements
31 #ifndef OOMPH_REFINEABLE_AXISYMMETRIC_NAVIER_STOKES_ELEMENTS_HEADER
32 #define OOMPH_REFINEABLE_AXISYMMETRIC_NAVIER_STOKES_ELEMENTS_HEADER
33 
34 // Config header generated by autoconfig
35 #ifdef HAVE_CONFIG_H
36 #include <oomph-lib-config.h>
37 #endif
38 
39 //Oomph lib includes
40 #include "../generic/refineable_quad_element.h"
41 #include "../generic/error_estimator.h"
43 
44 namespace oomph
45 {
46 
47 
48 //======================================================================
49 ///Refineable version of the Axisymmetric Navier--Stokes equations
50 //======================================================================
52 public virtual AxisymmetricNavierStokesEquations,
53 public virtual RefineableElement,
54 public virtual ElementWithZ2ErrorEstimator
55 {
56  protected:
57 
58  /// \short Pointer to n_p-th pressure node (Default: NULL,
59  /// indicating that pressure is not based on nodal interpolation).
60  virtual Node* pressure_node_pt(const unsigned& n_p) {return NULL;}
61 
62  /// \short Unpin all pressure dofs in the element
63  virtual void unpin_elemental_pressure_dofs()=0;
64 
65 /// \short Pin unused nodal pressure dofs (empty by default, because
66  /// by default pressure dofs are not associated with nodes)
68 
69  public:
70 
71  /// \short Empty Constructor
76 
77  /// Number of 'flux' terms for Z2 error estimation
78  unsigned num_Z2_flux_terms()
79  {
80  // 3 diagonal strain rates, 3 off diagonal
81  return 6;
82  }
83 
84  /// \short Get 'flux' for Z2 error recovery: Upper triangular entries
85  /// in strain rate tensor.
87  {
88  //Specify the number of velocity dimensions
89  unsigned DIM=3;
90 
91 #ifdef PARANOID
92  unsigned num_entries=DIM+((DIM*DIM)-DIM)/2;
93  if (flux.size() < num_entries)
94  {
95  std::ostringstream error_message;
96  error_message << "The flux vector has the wrong number of entries, "
97  << flux.size() << ", whereas it should be "
98  << num_entries << std::endl;
99  throw OomphLibError(
100  error_message.str(),
101  OOMPH_CURRENT_FUNCTION,
102  OOMPH_EXCEPTION_LOCATION);
103  }
104 #endif
105 
106 
107  // Get strain rate matrix
108  DenseMatrix<double> strainrate(DIM);
109  this->strain_rate(s,strainrate);
110 
111  // Pack into flux Vector
112  unsigned icount=0;
113 
114  // Start with diagonal terms
115  for(unsigned i=0;i<DIM;i++)
116  {
117  flux[icount]=strainrate(i,i);
118  icount++;
119  }
120 
121  //Off diagonals row by row
122  for(unsigned i=0;i<DIM;i++)
123  {
124  for(unsigned j=i+1;j<DIM;j++)
125  {
126  flux[icount]=strainrate(i,j);
127  icount++;
128  }
129  }
130  }
131 
132  /// Fill in the geometric Jacobian, which in this case is r
133  double geometric_jacobian(const Vector<double> &x) {return x[0];}
134 
135 
136  /// Further build: pass the pointers down to the sons
138  {
139  //Find the father element
140  RefineableAxisymmetricNavierStokesEquations* cast_father_element_pt
142  (this->father_element_pt());
143 
144  //Set the viscosity ratio pointer
145  this->Viscosity_Ratio_pt = cast_father_element_pt->viscosity_ratio_pt();
146  //Set the density ratio pointer
147  this->Density_Ratio_pt = cast_father_element_pt->density_ratio_pt();
148  //Set pointer to global Reynolds number
149  this->Re_pt = cast_father_element_pt->re_pt();
150  //Set pointer to global Reynolds number x Strouhal number (=Womersley)
151  this->ReSt_pt = cast_father_element_pt->re_st_pt();
152  //Set pointer to global Reynolds number x inverse Froude number
153  this->ReInvFr_pt = cast_father_element_pt->re_invfr_pt();
154  //Set pointer to the global Reynolds number x inverse Rossby number
155  this->ReInvRo_pt = cast_father_element_pt->re_invro_pt();
156  //Set pointer to global gravity Vector
157  this->G_pt = cast_father_element_pt->g_pt();
158 
159  //Set pointer to body force function
160  this->Body_force_fct_pt =
161  cast_father_element_pt->axi_nst_body_force_fct_pt();
162 
163  //Set pointer to volumetric source function
164  this->Source_fct_pt = cast_father_element_pt->source_fct_pt();
165 
166  //Set the ALE_is_disabled flag
167  this->ALE_is_disabled = cast_father_element_pt->ALE_is_disabled;
168  }
169 
170  /// \short Compute the derivatives of the i-th component of
171  /// velocity at point s with respect
172  /// to all data that can affect its value. In addition, return the global
173  /// equation numbers corresponding to the data.
174  /// Overload the non-refineable version to take account of hanging node
175  /// information
177  const unsigned &i,
178  Vector<double> &du_ddata,
179  Vector<unsigned> &global_eqn_number)
180  {
181  //Find number of nodes
182  unsigned n_node = this->nnode();
183  //Local shape function
184  Shape psi(n_node);
185  //Find values of shape function at the given local coordinate
186  this->shape(s,psi);
187 
188  //Find the index at which the velocity component is stored
189  const unsigned u_nodal_index = this->u_index_axi_nst(i);
190 
191  //Storage for hang info pointer
192  HangInfo* hang_info_pt=0;
193  //Storage for global equation
194  int global_eqn = 0;
195 
196  //Find the number of dofs associated with interpolated u
197  unsigned n_u_dof=0;
198  for(unsigned l=0;l<n_node;l++)
199  {
200  unsigned n_master = 1;
201 
202  //Local bool (is the node hanging)
203  bool is_node_hanging = this->node_pt(l)->is_hanging();
204 
205  //If the node is hanging, get the number of master nodes
206  if(is_node_hanging)
207  {
208  hang_info_pt = this->node_pt(l)->hanging_pt();
209  n_master = hang_info_pt->nmaster();
210  }
211  //Otherwise there is just one master node, the node itself
212  else
213  {
214  n_master = 1;
215  }
216 
217  //Loop over the master nodes
218  for(unsigned m=0;m<n_master;m++)
219  {
220  //Get the equation number
221  if(is_node_hanging)
222  {
223  //Get the equation number from the master node
224  global_eqn = hang_info_pt->master_node_pt(m)->
225  eqn_number(u_nodal_index);
226  }
227  else
228  {
229  // Global equation number
230  global_eqn = this->node_pt(l)->eqn_number(u_nodal_index);
231  }
232 
233  //If it's positive add to the count
234  if(global_eqn >= 0) {++n_u_dof;}
235  }
236  }
237 
238  //Now resize the storage schemes
239  du_ddata.resize(n_u_dof,0.0);
240  global_eqn_number.resize(n_u_dof,0);
241 
242  //Loop over th nodes again and set the derivatives
243  unsigned count=0;
244  //Loop over the local nodes and sum
245  for(unsigned l=0;l<n_node;l++)
246  {
247  unsigned n_master = 1;
248  double hang_weight = 1.0;
249 
250  //Local bool (is the node hanging)
251  bool is_node_hanging = this->node_pt(l)->is_hanging();
252 
253  //If the node is hanging, get the number of master nodes
254  if(is_node_hanging)
255  {
256  hang_info_pt = this->node_pt(l)->hanging_pt();
257  n_master = hang_info_pt->nmaster();
258  }
259  //Otherwise there is just one master node, the node itself
260  else
261  {
262  n_master = 1;
263  }
264 
265  //Loop over the master nodes
266  for(unsigned m=0;m<n_master;m++)
267  {
268  //If the node is hanging get weight from master node
269  if(is_node_hanging)
270  {
271  //Get the hang weight from the master node
272  hang_weight = hang_info_pt->master_weight(m);
273  }
274  else
275  {
276  // Node contributes with full weight
277  hang_weight = 1.0;
278  }
279 
280  //Get the equation number
281  if(is_node_hanging)
282  {
283  //Get the equation number from the master node
284  global_eqn = hang_info_pt->master_node_pt(m)->
285  eqn_number(u_nodal_index);
286  }
287  else
288  {
289  // Local equation number
290  global_eqn = this->node_pt(l)->eqn_number(u_nodal_index);
291  }
292 
293  if (global_eqn >= 0)
294  {
295  //Set the global equation number
296  global_eqn_number[count] = global_eqn;
297  //Set the derivative with respect to the unknown
298  du_ddata[count] = psi[l]*hang_weight;
299  //Increase the counter
300  ++count;
301  }
302  }
303  }
304  }
305 
306 
307 
308  /// \short Loop over all elements in Vector (which typically contains
309  /// all the elements in a fluid mesh) and pin the nodal pressure degrees
310  /// of freedom that are not being used. Function uses
311  /// the member function
312  /// - \c RefineableAxisymmetricNavierStokesEquations::
313  /// pin_all_nodal_pressure_dofs()
314  /// .
315  /// which is empty by default and should be implemented for
316  /// elements with nodal pressure degrees of freedom
317  /// (e.g. for refineable Taylor-Hood.)
319  element_pt)
320  {
321  // Loop over all elements to brutally pin all nodal pressure degrees of
322  // freedom
323  unsigned n_element=element_pt.size();
324  for(unsigned e=0;e<n_element;e++)
325  {
328  }
329  }
330 
331  /// \short Unpin all pressure dofs in elements listed in vector.
333  element_pt)
334  {
335  // Loop over all elements to brutally unpin all nodal pressure degrees of
336  // freedom and internal pressure degrees of freedom
337  unsigned n_element = element_pt.size();
338  for(unsigned e=0;e<n_element;e++)
339  {
341  (element_pt[e])->unpin_elemental_pressure_dofs();
342  }
343  }
344 
345  /// \short Compute derivatives of elemental residual vector with respect to
346  /// nodal coordinates. This function computes these terms analytically and
347  /// overwrites the default implementation in the FiniteElement base class.
348  /// dresidual_dnodal_coordinates(l,i,j) = d res(l) / dX_{ij}
350  dresidual_dnodal_coordinates);
351 
352  private:
353 
354  /// \short Add element's contribution to the elemental residual vector
355  /// and/or Jacobian matrix and mass matrix
356  /// flag=2: compute all
357  /// flag=1: compute both residual and Jacobian
358  /// flag=0: compute only residual vector
360  Vector<double> &residuals,
361  DenseMatrix<double> &jacobian,
362  DenseMatrix<double> &mass_matrix,
363  unsigned flag);
364 
365  /// \short Add element's contribution to the derivative of the
366  /// elemental residual vector
367  /// and/or Jacobian matrix and/or mass matrix
368  /// flag=2: compute all
369  /// flag=1: compute both residual and Jacobian
370  /// flag=0: compute only residual vector
372  double* const &parameter_pt,
373  Vector<double> &dres_dparam,
374  DenseMatrix<double> &djac_dparam,
375  DenseMatrix<double> &dmass_matrix_dparam,
376  unsigned flag)
377  {
378  throw OomphLibError("Not yet implemented\n",
379  OOMPH_CURRENT_FUNCTION,
380  OOMPH_EXCEPTION_LOCATION);
381  }
382 
383  /// \short Compute the hessian tensor vector products required to
384  /// perform continuation of bifurcations analytically
386  Vector<double> const &Y,
387  DenseMatrix<double> const &C,
388  DenseMatrix<double> &product)
389  {
390  throw OomphLibError(
391  "Not yet implemented\n",
392  OOMPH_CURRENT_FUNCTION,
393  OOMPH_EXCEPTION_LOCATION);
394  }
395 
396 
397 
398 };
399 
400 //======================================================================
401 /// Refineable version of Axisymmetric Quad Taylor Hood elements.
402 /// (note that unlike the cartesian version this is not scale-able
403 /// to higher dimensions!)
404 //======================================================================
408 public virtual RefineableQElement<2>
409 {
410  private:
411 
412  /// \short Pointer to n_p-th pressure node
413  Node* pressure_node_pt(const unsigned &n_p)
414  {return this->node_pt(this->Pconv[n_p]);}
415 
416  /// Unpin all pressure dofs
418  {
419  unsigned n_node = this->nnode();
420  int p_index = this->p_nodal_index_axi_nst();
421  // loop over nodes
422  for(unsigned n=0;n<n_node;n++) {this->node_pt(n)->unpin(p_index);}
423  }
424 
425  /// Unpin the proper nodal pressure dofs
427  {
428  //Loop over all nodes
429  unsigned n_node = this->nnode();
430  int p_index = this->p_nodal_index_axi_nst();
431  // loop over all nodes and pin all the nodal pressures
432  for(unsigned n=0;n<n_node;n++) {this->node_pt(n)->pin(p_index);}
433 
434  // Loop over all actual pressure nodes and unpin if they're not hanging
435  unsigned n_pres = this->npres_axi_nst();
436  for(unsigned l=0;l<n_pres;l++)
437  {
438  Node* nod_pt = this->node_pt(this->Pconv[l]);
439  if (!nod_pt->is_hanging(p_index)) {nod_pt->unpin(p_index);}
440  }
441  }
442 
443  public:
444 
445  /// \short Constructor:
449  RefineableQElement<2>(),
451 
452  /// Number of values (pinned or dofs) required at node n.
453  // Bumped up to 4 so we don't have to worry if a hanging mid-side node
454  // gets shared by a corner node (which has extra degrees of freedom)
455  unsigned required_nvalue(const unsigned &n) const {return 4;}
456 
457  /// Number of continuously interpolated values: 4 (3 velocities + 1 pressure)
458  unsigned ncont_interpolated_values() const {return 4;}
459 
460  /// Rebuild from sons: empty
461  void rebuild_from_sons(Mesh* &mesh_pt) {}
462 
463  /// \short Order of recovery shape functions for Z2 error estimation:
464  /// Same order as shape functions.
465  unsigned nrecovery_order() {return 2;}
466 
467  /// \short Number of vertex nodes in the element
468  unsigned nvertex_node() const
470 
471  /// \short Pointer to the j-th vertex node in the element
472  Node* vertex_node_pt(const unsigned& j) const
473  {
475  }
476 
477 /// \short Get the function value u in Vector.
478 /// Note: Given the generality of the interface (this function
479 /// is usually called from black-box documentation or interpolation routines),
480 /// the values Vector sets its own size in here.
482  {
483  //Set the velocity dimension of the element
484  unsigned DIM=3;
485 
486  // Set size of values Vector: u,w,v,p and initialise to zero
487  values.resize(DIM+1,0.0);
488 
489  //Calculate velocities: values[0],...
490  for(unsigned i=0;i<DIM;i++) {values[i] = interpolated_u_axi_nst(s,i);}
491 
492  //Calculate pressure: values[DIM]
493  values[DIM] = interpolated_p_axi_nst(s);
494  }
495 
496 /// \short Get the function value u in Vector.
497 /// Note: Given the generality of the interface (this function
498 /// is usually called from black-box documentation or interpolation routines),
499 /// the values Vector sets its own size in here.
500  void get_interpolated_values(const unsigned& t, const Vector<double>&s,
501  Vector<double>& values)
502  {
503  unsigned DIM=3;
504 
505  // Set size of Vector: u,w,v,p
506  values.resize(DIM+1);
507 
508  // Initialise
509  for(unsigned i=0;i<DIM+1;i++) {values[i]=0.0;}
510 
511  //Find out how many nodes there are
512  unsigned n_node = nnode();
513 
514  // Shape functions
515  Shape psif(n_node);
516  shape(s,psif);
517 
518  //Calculate velocities: values[0],...
519  for(unsigned i=0;i<DIM;i++)
520  {
521  //Get the nodal coordinate of the velocity
522  unsigned u_nodal_index = u_index_axi_nst(i);
523  for(unsigned l=0;l<n_node;l++)
524  {
525  values[i] += nodal_value(t,l,u_nodal_index)*psif[l];
526  }
527  }
528 
529  //Calculate pressure: values[DIM]
530  //(no history is carried in the pressure)
531  values[DIM] = interpolated_p_axi_nst(s);
532  }
533 
534  /// \short Perform additional hanging node procedures for variables
535  /// that are not interpolated by all nodes. The pressures are stored
536  /// at the 3rd location in each node
538  {
539  int DIM=3;
540  this->setup_hang_for_value(DIM);
541  }
542 
543  /// \short The velocities are isoparametric and so the "nodes" interpolating
544  /// the velocities are the geometric nodes. The pressure "nodes" are a
545  /// subset of the nodes, so when n_value==DIM, the n-th pressure
546  /// node is returned.
547  Node* interpolating_node_pt(const unsigned &n,
548  const int &n_value)
549 
550  {
551  int DIM=3;
552  //The only different nodes are the pressure nodes
553  if(n_value==DIM) {return this->node_pt(this->Pconv[n]);}
554  //The other variables are interpolated via the usual nodes
555  else {return this->node_pt(n);}
556  }
557 
558  /// \short The pressure nodes are the corner nodes, so when n_value==DIM,
559  /// the fraction is the same as the 1d node number, 0 or 1.
560  double local_one_d_fraction_of_interpolating_node(const unsigned &n1d,
561  const unsigned &i,
562  const int &n_value)
563  {
564  int DIM=3;
565  if(n_value==DIM)
566  {
567  //The pressure nodes are just located on the boundaries at 0 or 1
568  return double(n1d);
569  }
570  //Otherwise the velocity nodes are the same as the geometric ones
571  else
572  {
573  return this->local_one_d_fraction_of_node(n1d,i);
574  }
575  }
576 
577  /// \short The velocity nodes are the same as the geometric nodes. The
578  /// pressure nodes must be calculated by using the same methods as
579  /// the geometric nodes, but by recalling that there are only two pressure
580  /// nodes per edge.
582  const int &n_value)
583  {
584  int DIM=3;
585  //If we are calculating pressure nodes
586  if(n_value==static_cast<int>(DIM))
587  {
588  //Storage for the index of the pressure node
589  unsigned total_index=0;
590  //The number of nodes along each 1d edge is 2.
591  unsigned NNODE_1D = 2;
592  //Storage for the index along each boundary
593  //Note that it's only a 2D spatial element
594  Vector<int> index(2);
595  //Loop over the coordinates
596  for(unsigned i=0;i<2;i++)
597  {
598  //If we are at the lower limit, the index is zero
599  if(s[i]==-1.0)
600  {
601  index[i] = 0;
602  }
603  //If we are at the upper limit, the index is the number of nodes minus 1
604  else if(s[i] == 1.0)
605  {
606  index[i] = NNODE_1D-1;
607  }
608  //Otherwise, we have to calculate the index in general
609  else
610  {
611  //For uniformly spaced nodes the 0th node number would be
612  double float_index = 0.5*(1.0 + s[i])*(NNODE_1D-1);
613  index[i] = int(float_index);
614  //What is the excess. This should be safe because the
615  //taking the integer part rounds down
616  double excess = float_index - index[i];
617  //If the excess is bigger than our tolerance there is no node,
618  //return null
619  if((excess > FiniteElement::Node_location_tolerance) && (
620  (1.0 - excess) > FiniteElement::Node_location_tolerance))
621  {
622  return 0;
623  }
624  }
625  ///Construct the general pressure index from the components.
626  total_index += index[i]*
627  static_cast<unsigned>(pow(static_cast<float>(NNODE_1D),
628  static_cast<int>(i)));
629  }
630  //If we've got here we have a node, so let's return a pointer to it
631  return this->node_pt(this->Pconv[total_index]);
632  }
633  //Otherwise velocity nodes are the same as pressure nodes
634  else
635  {
636  return this->get_node_at_local_coordinate(s);
637  }
638  }
639 
640 
641  /// \short The number of 1d pressure nodes is 2, the number of 1d velocity
642  /// nodes is the same as the number of 1d geometric nodes.
643  unsigned ninterpolating_node_1d(const int &n_value)
644  {
645  int DIM=3;
646  if(n_value==DIM) {return 2;}
647  else {return this->nnode_1d();}
648  }
649 
650  /// \short The number of pressure nodes is 4. The number of
651  /// velocity nodes is the same as the number of geometric nodes.
652  unsigned ninterpolating_node(const int &n_value)
653  {
654  int DIM=3;
655  if(n_value==DIM) {return 4;}
656  else {return this->nnode();}
657  }
658 
659  /// \short The basis interpolating the pressure is given by pshape().
660  //// The basis interpolating the velocity is shape().
662  Shape &psi,
663  const int &n_value) const
664  {
665  int DIM=3;
666  if(n_value==DIM) {return this->pshape_axi_nst(s,psi);}
667  else {return this->shape(s,psi);}
668  }
669 
670 };
671 
672 
673 ///////////////////////////////////////////////////////////////////////////
674 ///////////////////////////////////////////////////////////////////////////
675 ///////////////////////////////////////////////////////////////////////////
676 
677 //=======================================================================
678 /// Face geometry of the RefineableQuadQTaylorHoodElements
679 //=======================================================================
680 template<>
682 public virtual FaceGeometry<AxisymmetricQTaylorHoodElement>
683 {
684  public:
686 };
687 
688 
689 //=======================================================================
690 /// Face geometry of the RefineableQuadQTaylorHoodElements
691 //=======================================================================
692 template<>
694 public virtual FaceGeometry<FaceGeometry<AxisymmetricQTaylorHoodElement> >
695 {
696  public:
699 };
700 
701 
702 //======================================================================
703 /// Refineable version of Axisymmetric Quad Crouzeix Raviart elements
704 /// (note that unlike the cartesian version this is not scale-able
705 /// to higher dimensions!)
706 //======================================================================
710 public virtual RefineableQElement<2>
711 {
712  private:
713 
714  ///Unpin all the internal pressure freedoms
716  {
717  unsigned n_pres = this->npres_axi_nst();
718  // loop over pressure dofs and unpin
719  for(unsigned l=0;l<n_pres;l++)
720  {this->internal_data_pt(P_axi_nst_internal_index)->unpin(l);}
721  }
722 
723  public:
724 
725 /// \short Constructor:
729  RefineableQElement<2>(),
731 
732  /// Number of continuously interpolated values: 3 (velocities)
733  unsigned ncont_interpolated_values() const {return 3;}
734 
735  /// Rebuild from sons: Reconstruct pressure from the (merged) sons
736  void rebuild_from_sons(Mesh* &mesh_pt)
737  {
738  using namespace QuadTreeNames;
739 
740  //Central pressure value:
741  //-----------------------
742 
743  // Use average of the sons central pressure values
744  // Other options: Take average of the four (discontinuous)
745  // pressure values at the father's midpoint]
746 
747  double av_press=0.0;
748 
749  // Loop over the sons
750  for (unsigned ison=0;ison<4;ison++)
751  {
752  // Add the sons midnode pressure
753  av_press += quadtree_pt()->son_pt(ison)->object_pt()->
754  internal_data_pt(P_axi_nst_internal_index)->value(0);
755  }
756 
757  // Use the average
758  internal_data_pt(P_axi_nst_internal_index)->set_value(0,0.25*av_press);
759 
760 
761  //Slope in s_0 direction
762  //----------------------
763 
764  // Use average of the 2 FD approximations based on the
765  // elements central pressure values
766  // [Other options: Take average of the four
767  // pressure derivatives]
768 
769  double slope1= quadtree_pt()->son_pt(SE)->object_pt()->
770  internal_data_pt(P_axi_nst_internal_index)->value(0) -
771  quadtree_pt()->son_pt(SW)->object_pt()->
772  internal_data_pt(P_axi_nst_internal_index)->value(0);
773 
774  double slope2 = quadtree_pt()->son_pt(NE)->object_pt()->
775  internal_data_pt(P_axi_nst_internal_index)->value(0) -
776  quadtree_pt()->son_pt(NW)->object_pt()->
777  internal_data_pt(P_axi_nst_internal_index)->value(0);
778 
779 
780  // Use the average
781  internal_data_pt(P_axi_nst_internal_index)->
782  set_value(1,0.5*(slope1+slope2));
783 
784 
785  //Slope in s_1 direction
786  //----------------------
787 
788  // Use average of the 2 FD approximations based on the
789  // elements central pressure values
790  // [Other options: Take average of the four
791  // pressure derivatives]
792 
793  slope1 = quadtree_pt()->son_pt(NE)->object_pt()->
794  internal_data_pt(P_axi_nst_internal_index)->value(0) -
795  quadtree_pt()->son_pt(SE)->object_pt()->
796  internal_data_pt(P_axi_nst_internal_index)->value(0);
797 
798  slope2 = quadtree_pt()->son_pt(NW)->object_pt()->
799  internal_data_pt(P_axi_nst_internal_index)->value(0) -
800  quadtree_pt()->son_pt(SW)->object_pt()->
801  internal_data_pt(P_axi_nst_internal_index)->value(0);
802 
803 
804  // Use the average
805  internal_data_pt(P_axi_nst_internal_index)->
806  set_value(2,0.5*(slope1+slope2));
807 
808 
809  }
810 
811 /// \short Order of recovery shape functions for Z2 error estimation:
812 /// Same order as shape functions.
813  unsigned nrecovery_order()
814  {
815  return 2;
816  }
817 
818  /// \short Number of vertex nodes in the element
819  unsigned nvertex_node() const
821 
822  /// \short Pointer to the j-th vertex node in the element
823  Node* vertex_node_pt(const unsigned& j) const
825 
826 /// \short Get the function value u in Vector.
827 /// Note: Given the generality of the interface (this function
828 /// is usually called from black-box documentation or interpolation routines),
829 /// the values Vector sets its own size in here.
831  {
832  unsigned DIM=3;
833 
834  // Set size of Vector: u,w,v and initialise to zero
835  values.resize(DIM,0.0);
836 
837  //Calculate velocities: values[0],...
838  for(unsigned i=0;i<DIM;i++) {values[i] = interpolated_u_axi_nst(s,i);}
839  }
840 
841  /// \short Get all function values [u,v..,p] at previous timestep t
842  /// (t=0: present; t>0: previous timestep).
843  /// \n
844  /// Note: Given the generality of the interface (this function is
845  /// usually called from black-box documentation or interpolation routines),
846  /// the values Vector sets its own size in here.
847  /// \n
848  /// Note: No pressure history is kept, so pressure is always
849  /// the current value.
850  void get_interpolated_values(const unsigned& t, const Vector<double>&s,
851  Vector<double>& values)
852  {
853  unsigned DIM=3;
854 
855  // Set size of Vector: u,w,v
856  values.resize(DIM);
857 
858  // Initialise
859  for(unsigned i=0;i<DIM;i++) {values[i]=0.0;}
860 
861  //Find out how many nodes there are
862  unsigned n_node = nnode();
863 
864  // Shape functions
865  Shape psif(n_node);
866  shape(s,psif);
867 
868  //Calculate velocities: values[0],...
869  for(unsigned i=0;i<DIM;i++)
870  {
871  //Get the local index at which the i-th velocity is stored
872  unsigned u_local_index = u_index_axi_nst(i);
873  for(unsigned l=0;l<n_node;l++)
874  {
875  values[i] += nodal_value(t,l,u_local_index)*psif[l];
876  }
877  }
878  }
879 
880  /// \short Perform additional hanging node procedures for variables
881  /// that are not interpolated by all nodes. Empty
883 
884  /// Further build for Crouzeix_Raviart interpolates the internal
885  /// pressure dofs from father element: Make sure pressure values and
886  /// dp/ds agree between fathers and sons at the midpoints of the son
887  /// elements.
889  {
890  //Call the generic further build
892 
893  using namespace QuadTreeNames;
894 
895  // What type of son am I? Ask my quadtree representation...
896  int son_type=quadtree_pt()->son_type();
897 
898  // Pointer to my father (in element impersonation)
899  RefineableElement* father_el_pt=
900  quadtree_pt()->father_pt()->object_pt();
901 
902  Vector<double> s_father(2);
903 
904  // Son midpoint is located at the following coordinates in father element:
905 
906  // South west son
907  if (son_type==SW)
908  {
909  s_father[0]=-0.5;
910  s_father[1]=-0.5;
911  }
912  // South east son
913  else if (son_type==SE)
914  {
915  s_father[0]= 0.5;
916  s_father[1]=-0.5;
917  }
918  // North east son
919  else if (son_type==NE)
920  {
921  s_father[0]=0.5;
922  s_father[1]=0.5;
923  }
924 
925  // North west son
926  else if (son_type==NW)
927  {
928  s_father[0]=-0.5;
929  s_father[1]= 0.5;
930  }
931 
932  // Pressure value in father element
934  dynamic_cast<RefineableAxisymmetricQCrouzeixRaviartElement*>(father_el_pt);
935  double press=cast_father_el_pt->interpolated_p_axi_nst(s_father);
936 
937  // Pressure value gets copied straight into internal dof:
938  internal_data_pt(P_axi_nst_internal_index)->set_value(0,press);
939 
940 
941  // The slopes get copied from father
942  internal_data_pt(P_axi_nst_internal_index)->
943  set_value(1,0.5*cast_father_el_pt
944  ->internal_data_pt(P_axi_nst_internal_index)
945  ->value(1));
946 
947  internal_data_pt(P_axi_nst_internal_index)->
948  set_value(2,0.5*cast_father_el_pt
949  ->internal_data_pt(P_axi_nst_internal_index)
950  ->value(2));
951 }
952 
953 };
954 
955 
956 
957 //=======================================================================
958 /// Face geometry of the RefineableQuadQCrouzeixRaviartElements
959 //=======================================================================
960 template<>
962 public virtual FaceGeometry<AxisymmetricQCrouzeixRaviartElement>
963 {
964  public:
966 };
967 
968 
969 //=======================================================================
970 /// Face geometry of the RefineableQuadQCrouzeixRaviartElements
971 //=======================================================================
972 template<>
975 public virtual FaceGeometry<FaceGeometry<AxisymmetricQCrouzeixRaviartElement> >
976 {
977  public:
980 };
981 
982 
983 }
984 
985 #endif
virtual void pshape_axi_nst(const Vector< double > &s, Shape &psi) const =0
Compute the pressure shape functions at local coordinate s.
unsigned ncont_interpolated_values() const
Number of continuously interpolated values: 3 (velocities)
double *& re_invro_pt()
Pointer to global inverse Froude number.
void unpin(const unsigned &i)
Unpin the i-th stored variable.
Definition: nodes.h:386
double value(const unsigned &i) const
Return i-th stored value. This function is not virtual so that it can be inlined. This means that if ...
Definition: nodes.h:291
double *& re_invfr_pt()
Pointer to global inverse Froude number.
Node * interpolating_node_pt(const unsigned &n, const int &n_value)
The velocities are isoparametric and so the "nodes" interpolating the velocities are the geometric no...
void get_interpolated_values(const Vector< double > &s, Vector< double > &values)
Get the function value u in Vector. Note: Given the generality of the interface (this function is usu...
Base class for finite elements that can compute the quantities that are required for the Z2 error est...
void(*&)(const double &time, const Vector< double > &x, Vector< double > &f) axi_nst_body_force_fct_pt()
Access function for the body-force pointer.
static void pin_redundant_nodal_pressures(const Vector< GeneralisedElement *> &element_pt)
Loop over all elements in Vector (which typically contains all the elements in a fluid mesh) and pin ...
unsigned nvertex_node() const
Number of vertex nodes in the element.
virtual RefineableElement * father_element_pt() const
Return a pointer to the father element.
void fill_in_generic_dresidual_contribution_axi_nst(double *const &parameter_pt, Vector< double > &dres_dparam, DenseMatrix< double > &djac_dparam, DenseMatrix< double > &dmass_matrix_dparam, unsigned flag)
Add element&#39;s contribution to the derivative of the elemental residual vector and/or Jacobian matrix ...
void further_build()
Further build: pass the pointers down to the sons.
virtual Node * get_node_at_local_coordinate(const Vector< double > &s) const
If there is a node at this local coordinate, return the pointer to the node.
Definition: elements.cc:3806
Node * get_interpolating_node_at_local_coordinate(const Vector< double > &s, const int &n_value)
The velocity nodes are the same as the geometric nodes. The pressure nodes must be calculated by usin...
static void unpin_all_pressure_dofs(const Vector< GeneralisedElement *> &element_pt)
Unpin all pressure dofs in elements listed in vector.
unsigned nvertex_node() const
Number of vertex nodes in the element.
HangInfo *const & hanging_pt() const
Return pointer to hanging node data (this refers to the geometric hanging node status) (const version...
Definition: nodes.h:1148
cstr elem_len * i
Definition: cfortran.h:607
Node * pressure_node_pt(const unsigned &n_p)
Pointer to n_p-th pressure node.
unsigned required_nvalue(const unsigned &n) const
Number of values (pinned or dofs) required at node n.
void unpin_elemental_pressure_dofs()
Unpin all the internal pressure freedoms.
void fill_in_contribution_to_hessian_vector_products(Vector< double > const &Y, DenseMatrix< double > const &C, DenseMatrix< double > &product)
Compute the hessian tensor vector products required to perform continuation of bifurcations analytica...
Node * vertex_node_pt(const unsigned &j) const
Pointer to the j-th vertex node in the element.
bool ALE_is_disabled
Boolean flag to indicate if ALE formulation is disabled when the time-derivatives are computed...
char t
Definition: cfortran.h:572
double const & master_weight(const unsigned &i) const
Return weight for dofs on i-th master node.
Definition: nodes.h:753
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:852
unsigned nmaster() const
Return the number of master nodes.
Definition: nodes.h:733
void strain_rate(const Vector< double > &s, DenseMatrix< double > &strain_rate) const
Strain-rate tensor: where (in that order)
bool is_hanging() const
Test whether the node is geometrically hanging.
Definition: nodes.h:1207
long & eqn_number(const unsigned &i)
Return the equation number of the i-th stored variable.
Definition: nodes.h:365
double(* Source_fct_pt)(const double &time, const Vector< double > &x)
Pointer to volumetric source function.
e
Definition: cfortran.h:575
unsigned num_Z2_flux_terms()
Number of &#39;flux&#39; terms for Z2 error estimation.
virtual Node * pressure_node_pt(const unsigned &n_p)
Pointer to n_p-th pressure node (Default: NULL, indicating that pressure is not based on nodal interp...
double * Viscosity_Ratio_pt
Pointer to the viscosity ratio (relative to the viscosity used in the definition of the Reynolds numb...
void pin(const unsigned &i)
Pin the i-th stored variable.
Definition: nodes.h:383
unsigned nrecovery_order()
Order of recovery shape functions for Z2 error estimation: Same order as shape functions.
double * ReInvRo_pt
Pointer to global Reynolds number x inverse Rossby number (used when in a rotating frame) ...
Vector< double > *& g_pt()
Pointer to Vector of gravitational components.
unsigned ninterpolating_node_1d(const int &n_value)
The number of 1d pressure nodes is 2, the number of 1d velocity nodes is the same as the number of 1d...
double *& re_st_pt()
Pointer to product of Reynolds and Strouhal number (=Womersley number)
void(* Body_force_fct_pt)(const double &time, const Vector< double > &x, Vector< double > &result)
Pointer to body force function.
virtual unsigned u_index_axi_nst(const unsigned &i) const
Return the index at which the i-th unknown velocity component.
virtual void get_dresidual_dnodal_coordinates(RankThreeTensor< double > &dresidual_dnodal_coordinates)
Compute derivatives of elemental residual vector with respect to nodal coordinates. This function computes these terms analytically and overwrites the default implementation in the FiniteElement base class. dresidual_dnodal_coordinates(l,i,j) = d res(l) / dX_{ij}.
double geometric_jacobian(const Vector< double > &x)
Fill in the geometric Jacobian, which in this case is r.
virtual unsigned npres_axi_nst() const =0
Function to return number of pressure degrees of freedom.
A Rank 3 Tensor class.
Definition: matrices.h:1337
virtual void pin_elemental_redundant_nodal_pressure_dofs()
Pin unused nodal pressure dofs (empty by default, because.
virtual unsigned nvertex_node() const
Definition: elements.h:2374
static char t char * s
Definition: cfortran.h:572
double * Re_pt
Pointer to global Reynolds number.
void set_value(const unsigned &i, const double &value_)
Set the i-th stored data value to specified value. The only reason that we require an explicit set fu...
Definition: nodes.h:267
Data *& internal_data_pt(const unsigned &i)
Return a pointer to i-th internal data object.
Definition: elements.h:623
unsigned long eqn_number(const unsigned &ieqn_local) const
Return the global equation number corresponding to the ieqn_local-th local equation number...
Definition: elements.h:709
unsigned nrecovery_order()
Order of recovery shape functions for Z2 error estimation: Same order as shape functions.
void rebuild_from_sons(Mesh *&mesh_pt)
Rebuild from sons: Reconstruct pressure from the (merged) sons.
void get_Z2_flux(const Vector< double > &s, Vector< double > &flux)
Get &#39;flux&#39; for Z2 error recovery: Upper triangular entries in strain rate tensor. ...
double(*&)(const double &time, const Vector< double > &x) source_fct_pt()
Access function for the source-function pointer.
Node *const & master_node_pt(const unsigned &i) const
Return a pointer to the i-th master node.
Definition: nodes.h:736
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2109
static const double Node_location_tolerance
Default value for the tolerance to be used when locating nodes via local coordinates.
Definition: elements.h:1337
double nodal_value(const unsigned &n, const unsigned &i) const
Return the i-th value stored at local node n. Produces suitably interpolated values for hanging nodes...
Definition: elements.h:2470
Class that contains data for hanging nodes.
Definition: nodes.h:684
void interpolated_u_axi_nst(const Vector< double > &s, Vector< double > &veloc) const
Compute vector of FE interpolated velocity u at local coordinate s.
double *& density_ratio_pt()
Pointer to Density ratio.
double *& viscosity_ratio_pt()
Pointer to Viscosity Ratio.
double *& re_pt()
Pointer to Reynolds number.
virtual unsigned nnode_1d() const
Return the number of nodes along one edge of the element Default is to return zero — must be overloa...
Definition: elements.h:2151
double * ReInvFr_pt
Pointer to global Reynolds number x inverse Froude number (= Bond number / Capillary number) ...
virtual void unpin_elemental_pressure_dofs()=0
Unpin all pressure dofs in the element.
Refineable version of the Axisymmetric Navier–Stokes equations.
void get_interpolated_values(const Vector< double > &s, Vector< double > &values)
Get the function value u in Vector. Note: Given the generality of the interface (this function is usu...
double interpolated_p_axi_nst(const Vector< double > &s) const
Return FE interpolated pressure at local coordinate s.
void further_setup_hanging_nodes()
Perform additional hanging node procedures for variables that are not interpolated by all nodes...
void interpolating_basis(const Vector< double > &s, Shape &psi, const int &n_value) const
The basis interpolating the pressure is given by pshape(). / The basis interpolating the velocity is ...
virtual Node * vertex_node_pt(const unsigned &j) const
Pointer to the j-th vertex node in the element. Broken virtual function in "pure" finite elements...
Definition: elements.h:2383
Vector< double > * G_pt
Pointer to global gravity Vector.
double * ReSt_pt
Pointer to global Reynolds number x Strouhal number (=Womersley)
void further_setup_hanging_nodes()
Perform additional hanging node procedures for variables that are not interpolated by all nodes...
Node * vertex_node_pt(const unsigned &j) const
Pointer to the j-th vertex node in the element.
unsigned ncont_interpolated_values() const
Number of continuously interpolated values: 4 (3 velocities + 1 pressure)
void get_interpolated_values(const unsigned &t, const Vector< double > &s, Vector< double > &values)
Get the function value u in Vector. Note: Given the generality of the interface (this function is usu...
void rebuild_from_sons(Mesh *&mesh_pt)
Rebuild from sons: empty.
unsigned ninterpolating_node(const int &n_value)
The number of pressure nodes is 4. The number of velocity nodes is the same as the number of geometri...
virtual double local_one_d_fraction_of_node(const unsigned &n1d, const unsigned &i)
Get the local fraction of any node in the n-th position in a one dimensional expansion along the i-th...
Definition: elements.h:1818
virtual int p_nodal_index_axi_nst() const
Which nodal value represents the pressure?
unsigned nnode() const
Return the number of nodes.
Definition: elements.h:2146
void get_interpolated_values(const unsigned &t, const Vector< double > &s, Vector< double > &values)
Get all function values [u,v..,p] at previous timestep t (t=0: present; t>0: previous timestep)...
void fill_in_generic_residual_contribution_axi_nst(Vector< double > &residuals, DenseMatrix< double > &jacobian, DenseMatrix< double > &mass_matrix, unsigned flag)
Add element&#39;s contribution to the elemental residual vector and/or Jacobian matrix and mass matrix fl...
double local_one_d_fraction_of_interpolating_node(const unsigned &n1d, const unsigned &i, const int &n_value)
The pressure nodes are the corner nodes, so when n_value==DIM, the fraction is the same as the 1d nod...
virtual void shape(const Vector< double > &s, Shape &psi) const =0
Calculate the geometric shape functions at local coordinate s. This function must be overloaded for e...
void dinterpolated_u_axi_nst_ddata(const Vector< double > &s, const unsigned &i, Vector< double > &du_ddata, Vector< unsigned > &global_eqn_number)
Compute the derivatives of the i-th component of velocity at point s with respect to all data that ca...
double * Density_Ratio_pt
Pointer to the density ratio (relative to the density used in the definition of the Reynolds number) ...
A general mesh class.
Definition: mesh.h:74
void pin_elemental_redundant_nodal_pressure_dofs()
Unpin the proper nodal pressure dofs.