refineable_linearised_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: 1097 $
7 //LIC//
8 //LIC// $LastChangedDate: 2015-12-17 11:53:17 +0000 (Thu, 17 Dec 2015) $
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 linearised axisymmetric Navier-Stokes elements
31 
32 #ifndef OOMPH_REFINEABLE_LINEARISED_NAVIER_STOKES_ELEMENTS_HEADER
33 #define OOMPH_REFINEABLE_LINEARISED_NAVIER_STOKES_ELEMENTS_HEADER
34 
35 // Config header generated by autoconfig
36 #ifdef HAVE_CONFIG_H
37 #include <oomph-lib-config.h>
38 #endif
39 
40 // oomph-lib includes
41 #include "../generic/refineable_quad_element.h"
42 #include "../generic/error_estimator.h"
44 
45 namespace oomph
46 {
47 
48  //=======================================================================
49  /// \short Refineable version of the linearised axisymmetric
50  /// Navier--Stokes equations
51  //=======================================================================
53  public virtual LinearisedNavierStokesEquations,
54  public virtual RefineableElement,
55  public virtual ElementWithZ2ErrorEstimator
56  {
57  protected:
58 
59  /// \short Pointer to n_p-th pressure node (Default: NULL,
60  /// indicating that pressure is not based on nodal interpolation).
61  virtual Node* pressure_node_pt(const unsigned& n_p) {return NULL;}
62 
63  /// \short Unpin all pressure dofs in the element
64  virtual void unpin_elemental_pressure_dofs()=0;
65 
66  /// \short Pin unused nodal pressure dofs (empty by default, because
67  /// by default pressure dofs are not associated with nodes)
69 
70  public:
71 
72  /// \short Empty Constructor
77 
78  /// Number of 'flux' terms for Z2 error estimation
79  unsigned num_Z2_flux_terms()
80  {
81  // 3 diagonal strain rates, 3 off diagonal real and imaginary parts
82  return 2* (DIM+((DIM*DIM)-DIM)/2);
83  }
84 
85  /// \short Get 'flux' for Z2 error recovery: Upper triangular entries
86  /// in strain rate tensor.
88  {
89 #ifdef PARANOID
90  unsigned num_entries=2*(DIM+((DIM*DIM)-DIM)/2);
91  if (flux.size()!=num_entries)
92  {
93  std::ostringstream error_message;
94  error_message << "The flux vector has the wrong number of entries, "
95  << flux.size() << ", whereas it should be "
96  << num_entries << std::endl;
97  throw OomphLibError(
98  error_message.str(),
99  "RefineableLinearisedNavierStokesEquations::get_Z2_flux()",
100  OOMPH_EXCEPTION_LOCATION);
101  }
102 #endif
103 
104  // Get strain rate matrix
105  DenseMatrix<double> real_strainrate(DIM);
106  this->strain_rate(s,real_strainrate,0);
107  DenseMatrix<double> imag_strainrate(DIM);
108  this->strain_rate(s,imag_strainrate,1);
109 
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]=real_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]=real_strainrate(i,j);
127  icount++;
128  }
129  }
130 
131  // Start with diagonal terms
132  for(unsigned i=0;i<DIM;i++)
133  {
134  flux[icount]=imag_strainrate(i,i);
135  icount++;
136  }
137 
138  // Off diagonals row by row
139  for(unsigned i=0;i<DIM;i++)
140  {
141  for(unsigned j=i+1;j<DIM;j++)
142  {
143  flux[icount]=imag_strainrate(i,j);
144  icount++;
145  }
146  }
147  }
148 
149  /// Further build: pass the pointers down to the sons
151  {
152  // Find the father element
154  cast_father_element_pt
156  (this->father_element_pt());
157 
158  // Set the viscosity ratio pointer
159  this->Viscosity_Ratio_pt = cast_father_element_pt->viscosity_ratio_pt();
160 
161  // Set the density ratio pointer
162  this->Density_Ratio_pt = cast_father_element_pt->density_ratio_pt();
163 
164  // Set pointer to global Reynolds number
165  this->Re_pt = cast_father_element_pt->re_pt();
166 
167  // Set pointer to global Reynolds number x Strouhal number (=Womersley)
168  this->ReSt_pt = cast_father_element_pt->re_st_pt();
169 
170  if(cast_father_element_pt->normalisation_element_pt()!=0)
171  {
172  //Pass down the normalisation element
174  cast_father_element_pt->normalisation_element_pt());
175  }
176 
177  // Set the ALE_is_disabled flag
178  this->ALE_is_disabled = cast_father_element_pt->ALE_is_disabled;
179  }
180 
181  /// \short Loop over all elements in Vector (which typically contains
182  /// all the elements in a fluid mesh) and pin the nodal pressure degrees
183  /// of freedom that are not being used. Function uses
184  /// the member function
185  /// - \c RefineableLinearisedNavierStokesEquations::
186  /// pin_all_nodal_pressure_dofs()
187  /// .
188  /// which is empty by default and should be implemented for
189  /// elements with nodal pressure degrees of freedom
190  /// (e.g. for refineable Taylor-Hood.)
192  const Vector<GeneralisedElement*>& element_pt)
193  {
194  // Loop over all elements to brutally pin all nodal pressure degrees of
195  // freedom
196  const unsigned n_element=element_pt.size();
197  for(unsigned e=0;e<n_element;e++)
198  {
201  }
202  }
203 
204  /// Unpin all pressure dofs in elements listed in Vector
206  element_pt)
207  {
208  // Loop over all elements to brutally unpin all nodal pressure degrees of
209  // freedom and internal pressure degrees of freedom
210  const unsigned n_element = element_pt.size();
211  for(unsigned e=0;e<n_element;e++)
212  {
214  (element_pt[e])->unpin_elemental_pressure_dofs();
215  }
216  }
217 
218 
219  private:
220 
221  /// \short Add element's contribution to the elemental residual vector
222  /// and/or Jacobian matrix
223  /// flag=1: compute both
224  /// flag=0: compute only residual vector
226  Vector<double> &residuals,
227  DenseMatrix<double> &jacobian,
228  DenseMatrix<double> &mass_matrix,
229  unsigned flag);
230 
231  }; // End of RefineableLinearisedNavierStokesEquations class defn
232 
233 
234 
235 //////////////////////////////////////////////////////////////////////////////
236 //////////////////////////////////////////////////////////////////////////////
237 //////////////////////////////////////////////////////////////////////////////
238 
239 
240  //=======================================================================
241  /// \short Refineable version of linearised axisymmetric quadratic
242  /// Crouzeix-Raviart elements
243  //=======================================================================
247  public virtual RefineableQElement<2>
248  {
249  private:
250 
251  /// Unpin all the internal pressure freedoms
253  {
254  const unsigned n_pres = this->npres_linearised_nst();
255  // Loop over pressure dofs and unpin
256  for(unsigned l=0;l<n_pres;l++)
257  {
258  // There are two pressure components
259  for(unsigned i=0;i<2;i++)
260  {
261  this->internal_data_pt(P_linearised_nst_internal_index[i])
262  ->unpin(l);
263  }
264  }
265  }
266 
267  public:
268 
269  /// Constructor
273  RefineableQElement<2>(),
275 
276  /// Number of continuously interpolated values: 4*DIM (velocities)
277  unsigned ncont_interpolated_values() const { return 4*DIM; }
278 
279  /// Rebuild from sons: Reconstruct pressure from the (merged) sons
280  void rebuild_from_sons(Mesh* &mesh_pt)
281  {
282  using namespace QuadTreeNames;
283 
284  // Central pressure value:
285  // -----------------------
286 
287  // Use average of the sons central pressure values
288  // Other options: Take average of the four (discontinuous)
289  // pressure values at the father's midpoint]
290 
291  Vector<double> av_press(2,0.0);
292 
293  // Loop over the sons
294  for(unsigned ison=0;ison<4;ison++)
295  {
296  // Loop over the two pressure components
297  for(unsigned i=0;i<2;i++)
298  {
299  // Add the sons midnode pressure
300  av_press[i] += quadtree_pt()->son_pt(ison)->object_pt()->
301  internal_data_pt(P_linearised_nst_internal_index[i])->value(0);
302  }
303  }
304 
305  // Use the average
306  for(unsigned i=0;i<2;i++)
307  {
308  internal_data_pt(P_linearised_nst_internal_index[i])
309  ->set_value(0,0.25*av_press[i]);
310  }
311 
312  Vector<double> slope1(2,0.0), slope2(2,0.0);
313 
314  // Loop over pressure components
315  for(unsigned i=0;i<2;i++)
316  {
317  // Slope in s_0 direction
318  // ----------------------
319 
320  // Use average of the 2 FD approximations based on the
321  // elements central pressure values
322  // [Other options: Take average of the four
323  // pressure derivatives]
324 
325  slope1[i] = quadtree_pt()->son_pt(SE)->object_pt()->
326  internal_data_pt(P_linearised_nst_internal_index[i])->value(0) -
327  quadtree_pt()->son_pt(SW)->object_pt()->
328  internal_data_pt(P_linearised_nst_internal_index[i])->value(0);
329 
330  slope2[i] = quadtree_pt()->son_pt(NE)->object_pt()->
331  internal_data_pt(P_linearised_nst_internal_index[i])->value(0) -
332  quadtree_pt()->son_pt(NW)->object_pt()->
333  internal_data_pt(P_linearised_nst_internal_index[i])->value(0);
334 
335  // Use the average
336  internal_data_pt(P_linearised_nst_internal_index[i])->
337  set_value(1,0.5*(slope1[i]+slope2[i]));
338 
339  // Slope in s_1 direction
340  // ----------------------
341 
342  // Use average of the 2 FD approximations based on the
343  // elements central pressure values
344  // [Other options: Take average of the four
345  // pressure derivatives]
346 
347  slope1[i] = quadtree_pt()->son_pt(NE)->object_pt()->
348  internal_data_pt(P_linearised_nst_internal_index[i])->value(0) -
349  quadtree_pt()->son_pt(SE)->object_pt()->
350  internal_data_pt(P_linearised_nst_internal_index[i])->value(0);
351 
352  slope2[i] = quadtree_pt()->son_pt(NW)->object_pt()->
353  internal_data_pt(P_linearised_nst_internal_index[i])->value(0) -
354  quadtree_pt()->son_pt(SW)->object_pt()->
355  internal_data_pt(P_linearised_nst_internal_index[i])->value(0);
356 
357  // Use the average
358  internal_data_pt(P_linearised_nst_internal_index[i])->
359  set_value(2,0.5*(slope1[i]+slope2[i]));
360  } // End of loop over pressure components
361  }
362 
363  /// \short Order of recovery shape functions for Z2 error estimation:
364  /// Same order as shape functions.
365  unsigned nrecovery_order() { return 2; }
366 
367  /// \short Number of vertex nodes in the element
368  unsigned nvertex_node() const
370 
371  /// \short Pointer to the j-th vertex node in the element
372  Node* vertex_node_pt(const unsigned& j) const
373  {
375  }
376 
377  /// \short Get the function value u in Vector.
378  /// Note: Given the generality of the interface (this function
379  /// is usually called from black-box documentation or interpolation
380  /// routines), the values Vector sets its own size in here.
382  Vector<double>& values)
383  {
384  // Determine size of values Vector: U^C, U^S, W^C, W^S, V^C, V^S
385  const unsigned n_values = 4*DIM;
386 
387  // Set size of values Vector and initialise to zero
388  values.resize(n_values,0.0);
389 
390  // Calculate velocities: values[0],...
391  for(unsigned i=0;i<n_values;i++)
392  {
393  values[i] = interpolated_u_linearised_nst(s,i);
394  }
395  }
396 
397  /// \short Get all function values [U^C,U^S,...,P^S] at previous timestep t
398  /// (t=0: present; t>0: previous timestep).
399  /// \n
400  /// Note: Given the generality of the interface (this function is
401  /// usually called from black-box documentation or interpolation
402  /// routines), the values Vector sets its own size in here.
403  /// \n
404  /// Note: No pressure history is kept, so pressure is always
405  /// the current value.
406  void get_interpolated_values(const unsigned& t, const Vector<double>&s,
407  Vector<double>& values)
408  {
409  // Set size of Vector: U^C, U^S, W^C, W^S, V^C, V^S
410  values.resize(4*DIM);
411 
412  // Initialise to zero
413  for(unsigned i=0;i<4*DIM;i++) { values[i]=0.0; }
414 
415  // Determine number of nodes in element
416  const unsigned n_node = nnode();
417 
418  // Shape functions
419  Shape psif(n_node);
420  shape(s,psif);
421 
422  // Calculate velocities: values[0],...
423  for(unsigned i=0;i<(4*DIM);i++)
424  {
425  // Get the local index at which the i-th velocity is stored
426  const unsigned u_local_index = u_index_linearised_nst(i);
427  for(unsigned l=0;l<n_node;l++)
428  {
429  values[i] += nodal_value(t,l,u_local_index)*psif[l];
430  }
431  }
432  }
433 
434  /// \short Perform additional hanging node procedures for variables
435  /// that are not interpolated by all nodes. Empty
437 
438  /// Further build for Crouzeix_Raviart interpolates the internal
439  /// pressure dofs from father element: Make sure pressure values and
440  /// dp/ds agree between fathers and sons at the midpoints of the son
441  /// elements.
443  {
444  // Call the generic further build
446 
447  using namespace QuadTreeNames;
448 
449  // What type of son am I? Ask my quadtree representation...
450  int son_type=quadtree_pt()->son_type();
451 
452  // Pointer to my father (in element impersonation)
453  RefineableElement* father_el_pt=
454  quadtree_pt()->father_pt()->object_pt();
455 
456  Vector<double> s_father(2);
457 
458  // Son midpoint is located at the following coordinates in father element:
459 
460  // South west son
461  if(son_type==SW)
462  {
463  s_father[0]=-0.5;
464  s_father[1]=-0.5;
465  }
466  // South east son
467  else if(son_type==SE)
468  {
469  s_father[0]= 0.5;
470  s_father[1]=-0.5;
471  }
472  // North east son
473  else if(son_type==NE)
474  {
475  s_father[0]=0.5;
476  s_father[1]=0.5;
477  }
478 
479  // North west son
480  else if(son_type==NW)
481  {
482  s_father[0]=-0.5;
483  s_father[1]= 0.5;
484  }
485 
486  // Pressure values in father element
487  // ---------------------------------
488 
489  // Find pointer to father element
491  cast_father_el_pt=
493  (father_el_pt);
494 
495  // Set up storage for pressure in father element
496  Vector<double> press(2,0.0);
497 
498  // Loop over pressure components
499  for(unsigned i=0;i<2;i++)
500  {
501  // Get pressure from father element
502  press[i]
503  = cast_father_el_pt->interpolated_p_linearised_nst(s_father,i);
504 
505  // Pressure value gets copied straight into internal dof:
506  internal_data_pt(P_linearised_nst_internal_index[i])->
507  set_value(0,press[i]);
508 
509  // The slopes get copied from father
510  internal_data_pt(P_linearised_nst_internal_index[i])->
511  set_value(1,0.5*cast_father_el_pt
512  ->internal_data_pt(P_linearised_nst_internal_index[i])
513  ->value(1));
514 
515  internal_data_pt(P_linearised_nst_internal_index[i])->
516  set_value(2,0.5*cast_father_el_pt
517  ->internal_data_pt(P_linearised_nst_internal_index[i])
518  ->value(2));
519  } // End of loop over pressure components
520  }
521 
522  }; // End of RefineableLinearisedQCrouzeixRaviartElement defn
523 
524 
525 
526 ///////////////////////////////////////////////////////////////////////////
527 ///////////////////////////////////////////////////////////////////////////
528 ///////////////////////////////////////////////////////////////////////////
529 
530 
531 
532  //=======================================================================
533  /// \short Face geometry of the refineable linearised axisym
534  /// Crouzeix-Raviart elements
535  //=======================================================================
536  template<>
538  public virtual FaceGeometry<LinearisedQCrouzeixRaviartElement>
539  {
540  public:
543  };
544 
545 
546 
547  //=======================================================================
548  /// \short Face geometry of face geometric of the refineable linearised
549  /// axisym Crouzeix-Raviart elements
550  //=======================================================================
551  template<>
554  public virtual FaceGeometry
555  <FaceGeometry<LinearisedQCrouzeixRaviartElement> >
556  {
557  public:
561  };
562 
563 
564 
565 //////////////////////////////////////////////////////////////////////////////
566 //////////////////////////////////////////////////////////////////////////////
567 //////////////////////////////////////////////////////////////////////////////
568 
569 
570 
571  //=======================================================================
572  /// \short Refineable version of linearised axisymmetric quadratic
573  /// Taylor-Hood elements
574  //=======================================================================
578  public virtual RefineableQElement<2>
579  {
580  private:
581 
582  /// Pointer to n_p-th pressure node
583  Node* pressure_node_pt(const unsigned &n_p)
584  { return this->node_pt(this->Pconv[n_p]); }
585 
586  /// Unpin all pressure dofs
588  {
589  // Determine number of nodes in element
590  const unsigned n_node = this->nnode();
591 
592  // Get nodal indeces of the two pressure components
593  Vector<int> p_index(2);
594  for(unsigned i=0;i<2;i++)
595  {
596  p_index[i] = this->p_index_linearised_nst(i);
597  }
598 
599  // Loop over nodes and unpin both pressure components
600  for(unsigned n=0;n<n_node;n++)
601  {
602  for(unsigned i=0;i<2;i++) { this->node_pt(n)->unpin(p_index[i]); }
603  }
604  }
605 
606  /// Unpin the proper nodal pressure dofs
608  {
609  // Determine number of nodes in element
610  const unsigned n_node = this->nnode();
611 
612  // Get nodal indeces of the two pressure components
613  Vector<int> p_index(2);
614  for(unsigned i=0;i<2;i++)
615  {
616  p_index[i] = this->p_index_linearised_nst(i);
617  }
618 
619  // Loop over all nodes and pin all the nodal pressures
620  for(unsigned n=0;n<n_node;n++)
621  {
622  for(unsigned i=0;i<2;i++) { this->node_pt(n)->pin(p_index[i]); }
623  }
624 
625  // Loop over all actual pressure nodes and unpin if they're not hanging
626  const unsigned n_pres = this->npres_linearised_nst();
627  for(unsigned l=0;l<n_pres;l++)
628  {
629  Node* nod_pt = this->node_pt(this->Pconv[l]);
630  for(unsigned i=0;i<2;i++)
631  {
632  if(!nod_pt->is_hanging(p_index[i])) { nod_pt->unpin(p_index[i]); }
633  }
634  }
635  }
636 
637  public:
638 
639  /// \short Constructor:
643  RefineableQElement<2>(),
645 
646  /// \short Number of values (pinned or dofs) required at node n.
647  /// Bumped up to 8 so we don't have to worry if a hanging mid-side node
648  /// gets shared by a corner node (which has extra degrees of freedom)
649  unsigned required_nvalue(const unsigned &n) const { return 8; }
650 
651  /// \short Number of continuously interpolated values: 8
652  /// (6 velocities + 2 pressures)
653  unsigned ncont_interpolated_values() const { return 8; }
654 
655  /// Rebuild from sons: empty
656  void rebuild_from_sons(Mesh* &mesh_pt) {}
657 
658  /// \short Order of recovery shape functions for Z2 error estimation:
659  /// Same order as shape functions.
660  unsigned nrecovery_order() { return 2; }
661 
662  /// Number of vertex nodes in the element
663  unsigned nvertex_node() const
665 
666  /// Pointer to the j-th vertex node in the element
667  Node* vertex_node_pt(const unsigned& j) const
668  {
670  }
671 
672  /// \short Get the function value u in Vector.
673  /// Note: Given the generality of the interface (this function
674  /// is usually called from black-box documentation or interpolation
675  /// routines), the values Vector sets its own size in here.
677  Vector<double> &values)
678  {
679  // Determine size of values Vector:
680  // U^C, U^S, W^C, W^S, V^C, V^S, P^C, P^S
681  const unsigned n_values = 2*(DIM+1);
682 
683  // Set size of values Vector and initialise to zero
684  values.resize(n_values,0.0);
685 
686  // Calculate velocities: values[0],...
687  for(unsigned i=0;i<(2*DIM);i++)
688  {
689  values[i] = interpolated_u_linearised_nst(s,i);
690  }
691 
692  // Calculate pressure: values[DIM], values[DIM+1]
693  for(unsigned i=0;i<2;i++)
694  {
695  values[DIM+i] = interpolated_p_linearised_nst(s,i);
696  }
697  }
698 
699  /// \short Get the function value u in Vector.
700  /// Note: Given the generality of the interface (this function
701  /// is usually called from black-box documentation or interpolation
702  /// routines), the values Vector sets its own size in here.
703  void get_interpolated_values(const unsigned &t,
704  const Vector<double> &s,
705  Vector<double> &values)
706  {
707  // Set size of values Vector: U^C, U^S, W^C, W^S, V^C, V^S, P^C, P^S
708  values.resize(2*(DIM+1));
709 
710  // Initialise all entries to zero
711  for(unsigned i=0;i<2*(DIM+1);i++) { values[i]=0.0; }
712 
713  // Determine number of nodes in element
714  const unsigned n_node = nnode();
715 
716  // Shape functions
717  Shape psif(n_node);
718  shape(s,psif);
719 
720  // Calculate velocities: values[0],...
721  for(unsigned i=0;i<(2*DIM);i++)
722  {
723  // Get the nodal coordinate of the velocity
724  const unsigned u_nodal_index = u_index_linearised_nst(i);
725  for(unsigned l=0;l<n_node;l++)
726  {
727  values[i] += nodal_value(t,l,u_nodal_index)*psif[l];
728  }
729  }
730 
731  // Calculate pressure: values[DIM], values[DIM+1]
732  // (no history is carried in the pressure)
733  for(unsigned i=0;i<2;i++)
734  {
735  values[DIM+i] = interpolated_p_linearised_nst(s,i);
736  }
737  }
738 
739  /// \short Perform additional hanging node procedures for variables
740  /// that are not interpolated by all nodes. The two pressure components
741  /// are stored at the 6th and 7th location in each node
743  {
744  for(unsigned i=0;i<2;i++)
745  {
746  this->setup_hang_for_value((2*DIM)+i);
747  }
748  }
749 
750  /// \short The velocities are isoparametric and so the "nodes"
751  /// interpolating the velocities are the geometric nodes. The
752  /// pressure "nodes" are a subset of the nodes, so when n_value==6
753  /// or 7, the n-th pressure node is returned.
754  Node* interpolating_node_pt(const unsigned &n,
755  const int &n_value)
756 
757  {
758  // The only different nodes are the pressure nodes
759  if(n_value==(2*DIM) || n_value==((2*DIM)+1))
760  {
761  return this->node_pt(this->Pconv[n]);
762  }
763 
764  // The other variables are interpolated via the usual nodes
765  else { return this->node_pt(n); }
766  }
767 
768  /// \short The pressure nodes are the corner nodes, so when n_value==6
769  /// or 7, the fraction is the same as the 1d node number, 0 or 1.
770  double local_one_d_fraction_of_interpolating_node(const unsigned &n1d,
771  const unsigned &i,
772  const int &n_value)
773  {
774  if(n_value==(2*DIM) || n_value==((2*DIM)+1))
775  {
776  // The pressure nodes are just located on the boundaries at 0 or 1
777  return double(n1d);
778  }
779  // Otherwise the velocity nodes are the same as the geometric ones
780  else
781  {
782  return this->local_one_d_fraction_of_node(n1d,i);
783  }
784  }
785 
786  /// \short The velocity nodes are the same as the geometric nodes.
787  /// The pressure nodes must be calculated by using the same methods
788  /// as the geometric nodes, but by recalling that there are only two
789  /// pressure nodes per edge.
791  const int &n_value)
792  {
793  // If we are calculating pressure nodes
794  if(n_value==static_cast<int>(2*DIM)
795  || n_value==static_cast<int>((2*DIM)+1))
796  {
797  // Storage for the index of the pressure node
798  unsigned total_index = 0;
799  // The number of nodes along each 1d edge is 2.
800  const unsigned NNODE_1D = 2;
801  // Storage for the index along each boundary
802  // Note that it's only a 2D spatial element
803  Vector<int> index(2);
804  // Loop over the coordinates
805  for(unsigned i=0;i<2;i++)
806  {
807  // If we are at the lower limit, the index is zero
808  if(s[i]==-1.0) { index[i] = 0; }
809 
810  // If we are at the upper limit, the index is the number of nodes
811  // minus 1
812  else if(s[i] == 1.0) { index[i] = NNODE_1D-1; }
813 
814  // Otherwise, we have to calculate the index in general
815  else
816  {
817  // For uniformly spaced nodes the 0th node number would be
818  double float_index = 0.5*(1.0 + s[i])*(NNODE_1D-1);
819  index[i] = int(float_index);
820  //What is the excess. This should be safe because the
821  //taking the integer part rounds down
822  double excess = float_index - index[i];
823  //If the excess is bigger than our tolerance there is no node,
824  //return null
825  if((excess > FiniteElement::Node_location_tolerance) && (
826  (1.0 - excess) > FiniteElement::Node_location_tolerance))
827  {
828  return 0;
829  }
830  }
831  ///Construct the general pressure index from the components.
832  total_index += index[i]*
833  static_cast<unsigned>(pow(static_cast<float>(NNODE_1D),
834  static_cast<int>(i)));
835  }
836  // If we've got here we have a node, so let's return a pointer to it
837  return this->node_pt(this->Pconv[total_index]);
838  }
839  // Otherwise velocity nodes are the same as pressure nodes
840  else
841  {
842  return this->get_node_at_local_coordinate(s);
843  }
844  }
845 
846 
847  /// \short The number of 1d pressure nodes is 2, the number of 1d
848  /// velocity nodes is the same as the number of 1d geometric nodes.
849  unsigned ninterpolating_node_1d(const int &n_value)
850  {
851  if(n_value==(2*DIM) || n_value==((2*DIM)+1)) { return 2; }
852  else { return this->nnode_1d(); }
853  }
854 
855  /// \short The number of pressure nodes is 4. The number of
856  /// velocity nodes is the same as the number of geometric nodes.
857  unsigned ninterpolating_node(const int &n_value)
858  {
859  if(n_value==(2*DIM) || n_value==((2*DIM)+1)) { return 4; }
860  else { return this->nnode(); }
861  }
862 
863  /// \short The basis interpolating the pressure is given by pshape().
864  //// The basis interpolating the velocity is shape().
866  Shape &psi,
867  const int &n_value) const
868  {
869  if(n_value==(2*DIM) || n_value==((2*DIM)+1))
870  {
871  return this->pshape_linearised_nst(s,psi);
872  }
873  else { return this->shape(s,psi); }
874  }
875 
876  }; // End of RefineableLinearisedQTaylorHoodElement class defn
877 
878 
879 
880 ///////////////////////////////////////////////////////////////////////////
881 ///////////////////////////////////////////////////////////////////////////
882 ///////////////////////////////////////////////////////////////////////////
883 
884 
885 
886  //=======================================================================
887  /// \short Face geometry of the refineable linearised axisym
888  /// Taylor-Hood elements
889  //=======================================================================
890  template<>
892  public virtual FaceGeometry<LinearisedQTaylorHoodElement>
893  {
894  public:
896  };
897 
898 
899 
900  //=======================================================================
901  /// \short Face geometry of face geometric of the refineable linearised
902  /// axisym Taylor-Hood elements
903  //=======================================================================
904  template<>
907  public virtual FaceGeometry<FaceGeometry
908  <LinearisedQTaylorHoodElement> >
909  {
910  public:
913  };
914 
915 
916 
917 } // End of namespace oomph
918 
919 #endif
Node * vertex_node_pt(const unsigned &j) const
Pointer to the j-th vertex node in the element.
void unpin(const unsigned &i)
Unpin the i-th stored variable.
Definition: nodes.h:386
unsigned ncont_interpolated_values() const
Number of continuously interpolated values: 8 (6 velocities + 2 pressures)
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
Node * pressure_node_pt(const unsigned &n_p)
Pointer to n_p-th pressure node.
void set_eigenfunction_normalisation_element(LinearisedNavierStokesEigenfunctionNormalisationElement *const &normalisation_el_pt)
the boolean flag check_nodal_data is set to false.
Base class for finite elements that can compute the quantities that are required for the Z2 error est...
virtual RefineableElement * father_element_pt() const
Return a pointer to the father element.
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
double * Density_Ratio_pt
Pointer to the density ratio (relative to the density used in the definition of the Reynolds number) ...
void pin_elemental_redundant_nodal_pressure_dofs()
Unpin the proper nodal pressure dofs.
cstr elem_len * i
Definition: cfortran.h:607
static void unpin_all_pressure_dofs(const Vector< GeneralisedElement *> &element_pt)
Unpin all pressure dofs in elements listed in Vector.
void get_interpolated_values(const unsigned &t, const Vector< double > &s, Vector< double > &values)
Get all function values [U^C,U^S,...,P^S] at previous timestep t (t=0: present; t>0: previous timeste...
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 *& viscosity_ratio_pt()
Pointer to the viscosity ratio.
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...
char t
Definition: cfortran.h:572
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:852
void rebuild_from_sons(Mesh *&mesh_pt)
Rebuild from sons: Reconstruct pressure from the (merged) sons.
Node * vertex_node_pt(const unsigned &j) const
Pointer to the j-th vertex node in the element.
bool is_hanging() const
Test whether the node is geometrically hanging.
Definition: nodes.h:1207
double * Re_pt
Pointer to global Reynolds number.
unsigned nvertex_node() const
Number of vertex nodes in the element.
e
Definition: cfortran.h:575
double *& re_pt()
Pointer to Reynolds number.
double interpolated_p_linearised_nst(const Vector< double > &s, const unsigned &i) const
Return the i-th component of the FE interpolated pressure p[i] at local coordinate s...
void pin(const unsigned &i)
Pin the i-th stored variable.
Definition: nodes.h:383
double *& re_st_pt()
Pointer to product of Reynolds and Strouhal number (=Womersley number)
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...
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...
unsigned ncont_interpolated_values() const
Number of continuously interpolated values: 4*DIM (velocities)
void rebuild_from_sons(Mesh *&mesh_pt)
Rebuild from sons: empty.
unsigned num_Z2_flux_terms()
Number of &#39;flux&#39; terms for Z2 error estimation.
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...
void further_setup_hanging_nodes()
Perform additional hanging node procedures for variables that are not interpolated by all nodes...
virtual unsigned u_index_linearised_nst(const unsigned &i) const
Return the index at which the i-th unknown velocity component is stored. The default value...
virtual unsigned nvertex_node() const
Definition: elements.h:2374
static char t char * s
Definition: cfortran.h:572
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
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==6 or 7, the fraction is the same as the 1d ...
virtual unsigned npres_linearised_nst() const =0
Return the number of pressure degrees of freedom associated with a single pressure component in the e...
void strain_rate(const Vector< double > &s, DenseMatrix< double > &strain_rate, const unsigned &real) const
Strain-rate tensor: where (in that order)
unsigned nrecovery_order()
Order of recovery shape functions for Z2 error estimation: Same order as shape functions.
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
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 * Viscosity_Ratio_pt
Pointer to the viscosity ratio (relative to the viscosity used in the definition of the Reynolds numb...
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
double *& density_ratio_pt()
Pointer to the density ratio.
virtual void pshape_linearised_nst(const Vector< double > &s, Shape &psi) const =0
Compute the pressure shape functions at local coordinate s.
unsigned nrecovery_order()
Order of recovery shape functions for Z2 error estimation: Same order as shape functions.
virtual void pin_elemental_redundant_nodal_pressure_dofs()
Pin unused nodal pressure dofs (empty by default, because by default pressure dofs are not associated...
double interpolated_u_linearised_nst(const Vector< double > &s, const unsigned &i) const
Compute the element&#39;s residual Vector and the jacobian matrix. Virtual function can be overloaded by ...
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...
void further_setup_hanging_nodes()
Perform additional hanging node procedures for variables that are not interpolated by all nodes...
unsigned nvertex_node() const
Number of vertex nodes in the element.
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 ...
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
void further_build()
Further build: pass the pointers down to the sons.
virtual void unpin_elemental_pressure_dofs()=0
Unpin all pressure dofs in the element.
virtual int p_index_linearised_nst(const unsigned &i) const
Which nodal value represents the pressure?
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...
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...
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
Refineable version of linearised axisymmetric quadratic Crouzeix-Raviart elements.
Refineable version of the linearised axisymmetric Navier–Stokes equations.
A class for elements that solve the linearised version of the unsteady Navier–Stokes equations in cy...
void unpin_elemental_pressure_dofs()
Unpin all the internal pressure freedoms.
unsigned required_nvalue(const unsigned &n) const
Number of values (pinned or dofs) required at node n. Bumped up to 8 so we don&#39;t have to worry if a h...
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
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 ...
Refineable version of linearised axisymmetric quadratic Taylor-Hood elements.
unsigned nnode() const
Return the number of nodes.
Definition: elements.h:2146
LinearisedNavierStokesEigenfunctionNormalisationElement * normalisation_element_pt()
Pointer to normalisation element.
void fill_in_generic_residual_contribution_linearised_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 flag=1: compute bo...
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...
A general mesh class.
Definition: mesh.h:74
double * ReSt_pt
Pointer to global Reynolds number x Strouhal number (=Womersley)
bool ALE_is_disabled
Boolean flag to indicate if ALE formulation is disabled when the time-derivatives are computed...