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 Navier Stokes elements
31 
32 #ifndef OOMPH_NAVIER_STOKES_ELEMENTS_HEADER
33 #define OOMPH_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 
41 //OOMPH-LIB headers
42 #include "../generic/Qelements.h"
43 #include "../generic/fsi.h"
44 #include "../generic/projection.h"
45 
46 namespace oomph
47 {
48 
49 
50 //======================================================================
51 /// Helper class for elements that impose Robin boundary conditions
52 /// on pressure advection diffusion problem required by Fp preconditioner
53 /// (class used to get around some templating issues)
54 //======================================================================
56 {
57  public:
58 
59  /// Constructor
61 
62  /// Empty virtual destructor
64 
65  /// \short This function returns the residuals for the
66  /// traction function. flag=1 (or 0): do (or don't) compute the
67  /// Jacobian as well.
69  Vector<double> &residuals,
70  DenseMatrix<double> &jacobian,
71  unsigned flag)=0;
72 
73 };
74 
75 
76 
77 ///////////////////////////////////////////////////////////////////////
78 ///////////////////////////////////////////////////////////////////////
79 ///////////////////////////////////////////////////////////////////////
80 
81 
82 
83 //======================================================================
84 /// A class for elements that allow the imposition of Robin boundary
85 /// conditions for the pressure advection diffusion problem in the
86 /// Fp preconditioner.
87 /// The geometrical information can be read from the FaceGeometry<ELEMENT>
88 /// class and and thus, we can be generic enough without the need to have
89 /// a separate equations class
90 //======================================================================
91 template <class ELEMENT>
92 class FpPressureAdvDiffRobinBCElement : public virtual FaceGeometry<ELEMENT>,
93  public virtual FaceElement,
95 {
96 
97  public:
98 
99  ///Constructor, which takes a "bulk" element and the value of the index
100  ///and its limit. Optional boolean flag indicates if it's called
101  // refineable constructor.
103  FiniteElement* const &element_pt,
104  const int &face_index,
105  const bool& called_from_refineable_constructor=false)
106  : FaceGeometry<ELEMENT>(), FaceElement()
107  {
108 
109  //Attach the geometrical information to the element. N.B. This function
110  //also assigns nbulk_value from the required_nvalue of the bulk element
111  element_pt->build_face_element(face_index,this);
112 
113 #ifdef PARANOID
114  {
115  //Check that the element is not a refineable 3d element
116  if (!called_from_refineable_constructor)
117  {
118  //If it's three-d
119  if(element_pt->dim()==3)
120  {
121  //Is it refineable
122  RefineableElement* ref_el_pt=
123  dynamic_cast<RefineableElement*>(element_pt);
124  if(ref_el_pt!=0)
125  {
126  if (this->has_hanging_nodes())
127  {
128  throw OomphLibError(
129  "This flux element will not work correctly if nodes are hanging\n",
130  OOMPH_CURRENT_FUNCTION,
131  OOMPH_EXCEPTION_LOCATION);
132  }
133  }
134  }
135  }
136  }
137 #endif
138 
139  }
140 
141  /// Empty destructor
143 
144  /// \short This function returns the residuals for the
145  /// traction function. flag=1 (or 0): do (or don't) compute the
146  /// Jacobian as well.
148  Vector<double> &residuals,
149  DenseMatrix<double> &jacobian,
150  unsigned flag);
151 
152 
153  ///This function returns just the residuals
155  {
156  std::ostringstream error_message;
157  error_message
158  << "fill_in_contribution_to_residuals() must not be called directly.\n"
159  << "since it uses the local equation numbering of the bulk element\n"
160  << "which calls the relevant helper function directly.\n";
161  throw OomphLibError(
162  error_message.str(),
163  OOMPH_CURRENT_FUNCTION,
164  OOMPH_EXCEPTION_LOCATION);
165  }
166 
167  ///This function returns the residuals and the jacobian
169  DenseMatrix<double> &jacobian)
170  {
171  std::ostringstream error_message;
172  error_message
173  << "fill_in_contribution_to_jacobian() must not be called directly.\n"
174  << "since it uses the local equation numbering of the bulk element\n"
175  << "which calls the relevant helper function directly.\n";
176  throw OomphLibError(
177  error_message.str(),
178  OOMPH_CURRENT_FUNCTION,
179  OOMPH_EXCEPTION_LOCATION);
180  }
181 
182  ///Overload the output function
183  void output(std::ostream &outfile) {FiniteElement::output(outfile);}
184 
185  ///Output function: x,y,[z],u,v,[w],p in tecplot format
186  void output(std::ostream &outfile, const unsigned &nplot)
187  {FiniteElement::output(outfile,nplot);}
188 
189 };
190 
191 ///////////////////////////////////////////////////////////////////////
192 ///////////////////////////////////////////////////////////////////////
193 ///////////////////////////////////////////////////////////////////////
194 
195 
196 
197 
198 //============================================================================
199 /// Get residuals and Jacobian of Robin boundary conditions in pressure
200 /// advection diffusion problem in Fp preconditoner
201 //============================================================================
202 template<class ELEMENT>
205  Vector<double> &residuals,
206  DenseMatrix<double> &jacobian,
207  unsigned flag)
208 {
209  //Storage for local coordinates in FaceElement and associted bulk element
210  unsigned my_dim=this->dim();
211  Vector<double> s(my_dim);
212  Vector<double> s_bulk(my_dim+1);
213 
214  // Storage for outer unit normal
215  Vector<double> unit_normal(my_dim+1);
216 
217  //Storage for veloc in bulk element
218  Vector<double> veloc(my_dim+1);
219 
220  //Set the value of n_intpt
221  unsigned n_intpt = this->integral_pt()->nweight();
222 
223  //Integers to store local equation numbers
224  int local_eqn=0;
225  int local_unknown=0;
226 
227  // Get cast bulk element
228  ELEMENT* bulk_el_pt=dynamic_cast<ELEMENT*>(this->bulk_element_pt());
229 
230  //Find out how many pressure dofs there are in the bulk element
231  unsigned n_pres = bulk_el_pt->npres_nst();
232 
233  // Get the Reynolds number from the bulk element
234  double re = bulk_el_pt->re();
235 
236  //Set up memory for pressure shape and test functions
237  Shape psip(n_pres), testp(n_pres);
238 
239  //Loop over the integration points
240  for(unsigned ipt=0;ipt<n_intpt;ipt++)
241  {
242  //Get the integral weight
243  double w = this->integral_pt()->weight(ipt);
244 
245  //Assign values of local coordinate in FaceElement
246  for(unsigned i=0;i<my_dim;i++) s[i] = this->integral_pt()->knot(ipt,i);
247 
248  // Find corresponding coordinate in the the bulk element
249  s_bulk=this->local_coordinate_in_bulk(s);
250 
251  /// Get outer unit normal
252  this->outer_unit_normal(ipt,unit_normal);
253 
254  // Get velocity in bulk element
255  bulk_el_pt->interpolated_u_nst(s_bulk,veloc);
256 
257  // Get normal component of veloc
258  double flux=0.0;
259  for (unsigned i=0;i<my_dim+1;i++)
260  {
261  flux+=veloc[i]*unit_normal[i];
262  }
263 
264  // Modify bc: If outflow (flux>0) apply Neumann condition instead
265  if (flux>0.0) flux=0.0;
266 
267  // Get pressure
268  double interpolated_press=bulk_el_pt->interpolated_p_nst(s_bulk);
269 
270  //Call the pressure shape and test functions in bulk element
271  bulk_el_pt->pshape_nst(s_bulk,psip,testp);
272 
273  //Find the Jacobian of the mapping within the FaceElement
274  double J = this->J_eulerian(s);
275 
276  //Premultiply the weights and the Jacobian
277  double W = w*J;
278 
279  //Loop over the pressure shape functions in bulk
280  //(wasteful but they'll be zero on the boundary)
281  for(unsigned l=0;l<n_pres;l++)
282  {
283  local_eqn=bulk_el_pt->p_local_eqn(l);
284 
285  //If not a boundary conditions
286  if(local_eqn >= 0)
287  {
288  residuals[local_eqn] -=
289  re*flux*interpolated_press*testp[l]*W;
290 
291  // Jacobian too?
292  if(flag)
293  {
294  //Loop over the shape functions in bulk
295  for(unsigned l2=0;l2<n_pres;l2++)
296  {
297  local_unknown = bulk_el_pt->p_local_eqn(l2);
298 
299  //If not a boundary conditions
300  if(local_unknown >= 0)
301  {
302  jacobian(local_eqn,local_unknown)-=
303  re*flux*psip[l2]*testp[l]*W;
304  }
305  }
306  } /*End of Jacobian calculation*/
307  } //End of if not boundary condition
308  }//End of loop over l
309  }
310 
311 }
312 
313 ///////////////////////////////////////////////////////////////////////
314 ///////////////////////////////////////////////////////////////////////
315 ///////////////////////////////////////////////////////////////////////
316 
317 
318 //======================================================================
319 /// Template-free base class for Navier-Stokes equations to avoid
320 /// casting problems
321 //======================================================================
324  public virtual FiniteElement
325 {
326 
327  public:
328 
329  /// Constructor (empty)
331 
332  /// Virtual destructor (empty)
334 
335  /// \short Compute the residuals for the associated pressure advection
336  /// diffusion problem. Used by the Fp preconditioner.
337  virtual void fill_in_pressure_advection_diffusion_residuals(Vector<double>&
338  residuals)=0;
339 
340  /// \short Compute the residuals and Jacobian for the associated
341  /// pressure advection diffusion problem. Used by the Fp preconditioner.
342  virtual void fill_in_pressure_advection_diffusion_jacobian(
343  Vector<double>& residuals, DenseMatrix<double> &jacobian)=0;
344 
345  /// \short Return the index at which the pressure is stored if it is
346  /// stored at the nodes. If not stored at the nodes this will return
347  /// a negative number.
348  virtual int p_nodal_index_nst() const =0;
349 
350  /// \short Access function for the local equation number information for
351  /// the pressure.
352  /// p_local_eqn[n] = local equation number or < 0 if pinned
353  virtual int p_local_eqn(const unsigned &n)const=0;
354 
355  /// \short Global eqn number of pressure dof that's pinned in pressure
356  /// adv diff problem
357  virtual int& pinned_fp_pressure_eqn()=0;
358 
359 
360  /// \short Pin all non-pressure dofs and backup eqn numbers of all Data
361  virtual void pin_all_non_pressure_dofs(std::map<Data*,std::vector<int> >&
362  eqn_number_backup)=0;
363 
364  /// \short Build FaceElements that apply the Robin boundary condition
365  /// to the pressure advection diffusion problem required by
366  /// Fp preconditioner
367  virtual void build_fp_press_adv_diff_robin_bc_element(const unsigned&
368  face_index)=0;
369 
370  /// \short Delete the FaceElements that apply the Robin boundary condition
371  /// to the pressure advection diffusion problem required by
372  /// Fp preconditioner
373  virtual void delete_pressure_advection_diffusion_robin_elements()=0;
374 
375 
376  /// \short Compute the diagonal of the velocity/pressure mass matrices.
377  /// If which one=0, both are computed, otherwise only the pressure
378  /// (which_one=1) or the velocity mass matrix (which_one=2 -- the
379  /// LSC version of the preconditioner only needs that one)
380  virtual void get_pressure_and_velocity_mass_matrix_diagonal(
381  Vector<double> &press_mass_diag, Vector<double> &veloc_mass_diag,
382  const unsigned& which_one=0)=0;
383 
384 };
385 
386 
387 ///////////////////////////////////////////////////////////////////////
388 ///////////////////////////////////////////////////////////////////////
389 ///////////////////////////////////////////////////////////////////////
390 
391 
392 
393 
394 
395 //======================================================================
396 /// A class for elements that solve the cartesian Navier--Stokes equations,
397 /// templated by the dimension DIM.
398 /// This contains the generic maths -- any concrete implementation must
399 /// be derived from this.
400 ///
401 /// We're solving:
402 ///
403 /// \f$ { Re \left( St \frac{\partial u_i}{\partial t} +
404 /// (u_j - u_j^{M}) \frac{\partial u_i}{\partial x_j} \right) =
405 /// - \frac{\partial p}{\partial x_i} - R_\rho B_i(x_j) -
406 /// \frac{Re}{Fr} G_i +
407 /// \frac{\partial }{\partial x_j} \left[ R_\mu \left(
408 /// \frac{\partial u_i}{\partial x_j} +
409 /// \frac{\partial u_j}{\partial x_i} \right) \right] } \f$
410 ///
411 /// and
412 ///
413 /// \f$ { \frac{\partial u_i}{\partial x_i} = Q } \f$
414 ///
415 /// We also provide all functions required to use this element
416 /// in FSI problems, by deriving it from the FSIFluidElement base
417 /// class.
418 //======================================================================
419 template <unsigned DIM>
420  class NavierStokesEquations : public virtual FSIFluidElement,
422 {
423 
424  public:
425 
426  /// \short Function pointer to body force function fct(t,x,f(x))
427  /// x is a Vector!
428  typedef void (*NavierStokesBodyForceFctPt)(const double& time,
429  const Vector<double>& x,
430  Vector<double>& body_force);
431 
432  /// \short Function pointer to source function fct(t,x)
433  /// x is a Vector!
434  typedef double (*NavierStokesSourceFctPt)(const double& time,
435  const Vector<double>& x);
436 
437 
438  /// \short Function pointer to source function fct(x) for the
439  /// pressure advection diffusion equation (only used during
440  /// validation!). x is a Vector!
441  typedef double (*NavierStokesPressureAdvDiffSourceFctPt)(
442  const Vector<double>& x);
443 
444  private:
445 
446  /// \short Static "magic" number that indicates that the pressure is
447  /// not stored at a node
449 
450  /// Static default value for the physical constants (all initialised to zero)
452 
453  /// Static default value for the physical ratios (all are initialised to one)
455 
456  /// Static default value for the gravity vector
458 
459  protected:
460 
461  //Physical constants
462 
463  /// \short Pointer to the viscosity ratio (relative to the
464  /// viscosity used in the definition of the Reynolds number)
466 
467  /// \short Pointer to the density ratio (relative to the density used in the
468  /// definition of the Reynolds number)
470 
471  // Pointers to global physical constants
472 
473  /// Pointer to global Reynolds number
474  double *Re_pt;
475 
476  /// Pointer to global Reynolds number x Strouhal number (=Womersley)
477  double *ReSt_pt;
478 
479  /// \short Pointer to global Reynolds number x inverse Froude number
480  /// (= Bond number / Capillary number)
481  double *ReInvFr_pt;
482 
483  /// Pointer to global gravity Vector
485 
486  /// Pointer to body force function
487  NavierStokesBodyForceFctPt Body_force_fct_pt;
488 
489  /// Pointer to volumetric source function
490  NavierStokesSourceFctPt Source_fct_pt;
491 
492  /// \short Pointer to source function pressure advection diffusion equation
493  /// (only to be used during validation)
494  NavierStokesPressureAdvDiffSourceFctPt Press_adv_diff_source_fct_pt;
495 
496  /// \short Boolean flag to indicate if ALE formulation is disabled when
497  /// time-derivatives are computed. Only set to true if you're sure
498  /// that the mesh is stationary.
500 
501  /// \short Storage for FaceElements that apply Robin BC for pressure adv diff
502  /// equation used in Fp preconditioner.
505 
506  /// \short Global eqn number of pressure dof that's pinned in
507  /// pressure advection diffusion problem (defaults to -1)
509 
510  /// \short Compute the shape functions and derivatives
511  /// w.r.t. global coords at local coordinate s.
512  /// Return Jacobian of mapping between local and global coordinates.
513  virtual double dshape_and_dtest_eulerian_nst(const Vector<double> &s,
514  Shape &psi,
515  DShape &dpsidx, Shape &test,
516  DShape &dtestdx) const=0;
517 
518  /// \short Compute the shape functions and derivatives
519  /// w.r.t. global coords at ipt-th integration point
520  /// Return Jacobian of mapping between local and global coordinates.
521  virtual double dshape_and_dtest_eulerian_at_knot_nst(const unsigned &ipt,
522  Shape &psi,
523  DShape &dpsidx,
524  Shape &test,
525  DShape &dtestdx) const=0;
526 
527  /// \short Shape/test functions and derivs w.r.t. to global coords at
528  /// integration point ipt; return Jacobian of mapping (J). Also compute
529  /// derivatives of dpsidx, dtestdx and J w.r.t. nodal coordinates.
530  virtual double dshape_and_dtest_eulerian_at_knot_nst(
531  const unsigned &ipt,
532  Shape &psi,
533  DShape &dpsidx,
534  RankFourTensor<double> &d_dpsidx_dX,
535  Shape &test,
536  DShape &dtestdx,
537  RankFourTensor<double> &d_dtestdx_dX,
538  DenseMatrix<double> &djacobian_dX) const=0;
539 
540  /// \short Calculate the body force at a given time and local and/or
541  /// Eulerian position. This function is virtual so that it can be
542  /// overloaded in multi-physics elements where the body force might
543  /// depend on another variable.
544  virtual void get_body_force_nst(const double& time,
545  const unsigned& ipt,
546  const Vector<double> &s,
547  const Vector<double> &x,
548  Vector<double> &result)
549  {
550  //If the function pointer is zero return zero
551  if(Body_force_fct_pt == 0)
552  {
553  //Loop over dimensions and set body forces to zero
554  for(unsigned i=0;i<DIM;i++) {result[i] = 0.0;}
555  }
556  //Otherwise call the function
557  else
558  {
559  (*Body_force_fct_pt)(time,x,result);
560  }
561  }
562 
563  /// Get gradient of body force term at (Eulerian) position x. This function is
564  /// virtual to allow overloading in multi-physics problems where
565  /// the strength of the source function might be determined by
566  /// another system of equations. Computed via function pointer
567  /// (if set) or by finite differencing (default)
568  inline virtual void get_body_force_gradient_nst(
569  const double& time,
570  const unsigned& ipt,
571  const Vector<double>& s,
572  const Vector<double>& x,
573  DenseMatrix<double>& d_body_force_dx)
574  {
575 // hierher: Implement function pointer version
576 /* //If no gradient function has been set, FD it */
577 /* if(Body_force_fct_gradient_pt==0) */
578  {
579  // Reference value
580  Vector<double> body_force(DIM,0.0);
581  get_body_force_nst(time,ipt,s,x,body_force);
582 
583  // FD it
585  Vector<double> body_force_pls(DIM,0.0);
586  Vector<double> x_pls(x);
587  for (unsigned i=0;i<DIM;i++)
588  {
589  x_pls[i]+=eps_fd;
590  get_body_force_nst(time,ipt,s,x_pls,body_force_pls);
591  for (unsigned j=0;j<DIM;j++)
592  {
593  d_body_force_dx(j,i)=(body_force_pls[j]-body_force[j])/eps_fd;
594  }
595  x_pls[i]=x[i];
596  }
597  }
598 /* else */
599 /* { */
600 /* // Get gradient */
601 /* (*Source_fct_gradient_pt)(time,x,gradient); */
602 /* } */
603  }
604 
605 
606 
607  /// \short Calculate the source fct at given time and
608  /// Eulerian position
609  virtual double get_source_nst(const double& time, const unsigned& ipt,
610  const Vector<double> &x)
611  {
612  //If the function pointer is zero return zero
613  if (Source_fct_pt == 0) {return 0;}
614  //Otherwise call the function
615  else {return (*Source_fct_pt)(time,x);}
616  }
617 
618 
619  /// Get gradient of source term at (Eulerian) position x. This function is
620  /// virtual to allow overloading in multi-physics problems where
621  /// the strength of the source function might be determined by
622  /// another system of equations. Computed via function pointer
623  /// (if set) or by finite differencing (default)
624  inline virtual void get_source_gradient_nst(
625  const double& time,
626  const unsigned& ipt,
627  const Vector<double>& x,
628  Vector<double>& gradient)
629  {
630 // hierher: Implement function pointer version
631 /* //If no gradient function has been set, FD it */
632 /* if(Source_fct_gradient_pt==0) */
633  {
634  // Reference value
635  double source=get_source_nst(time,ipt,x);
636 
637  // FD it
639  double source_pls=0.0;
640  Vector<double> x_pls(x);
641  for (unsigned i=0;i<DIM;i++)
642  {
643  x_pls[i]+=eps_fd;
644  source_pls=get_source_nst(time,ipt,x_pls);
645  gradient[i]=(source_pls-source)/eps_fd;
646  x_pls[i]=x[i];
647  }
648  }
649 /* else */
650 /* { */
651 /* // Get gradient */
652 /* (*Source_fct_gradient_pt)(time,x,gradient); */
653 /* } */
654  }
655 
656 
657  ///\short Compute the residuals for the Navier--Stokes equations.
658  /// Flag=1 (or 0): do (or don't) compute the Jacobian as well.
659  /// Flag=2: Fill in mass matrix too.
660  virtual void fill_in_generic_residual_contribution_nst(
661  Vector<double> &residuals, DenseMatrix<double> &jacobian,
662  DenseMatrix<double> &mass_matrix, unsigned flag);
663 
664 
665  /// \short Compute the residuals for the associated pressure advection
666  /// diffusion problem. Used by the Fp preconditioner.
667  /// flag=1(or 0): do (or don't) compute the Jacobian as well.
668  virtual void fill_in_generic_pressure_advection_diffusion_contribution_nst(
669  Vector<double> &residuals, DenseMatrix<double> &jacobian, unsigned flag);
670 
671  ///\short Compute the derivatives of the
672  /// residuals for the Navier--Stokes equations with respect to a parameter
673  /// Flag=1 (or 0): do (or don't) compute the Jacobian as well.
674  /// Flag=2: Fill in mass matrix too.
675  virtual void fill_in_generic_dresidual_contribution_nst(
676  double* const &parameter_pt,
677  Vector<double> &dres_dparam, DenseMatrix<double> &djac_dparam,
678  DenseMatrix<double> &dmass_matrix_dparam, unsigned flag);
679 
680  /// \short Compute the hessian tensor vector products required to
681  /// perform continuation of bifurcations analytically
683  Vector<double> const &Y,
684  DenseMatrix<double> const &C,
685  DenseMatrix<double> &product);
686 
687 
688 public:
689 
690  /// \short Constructor: NULL the body force and source function
691  /// and make sure the ALE terms are included by default.
692  NavierStokesEquations() : Body_force_fct_pt(0), Source_fct_pt(0),
693  Press_adv_diff_source_fct_pt(0), ALE_is_disabled(false),
694  Pinned_fp_pressure_eqn(-1)
695  {
696  //Set all the Physical parameter pointers to the default value zero
699  ReInvFr_pt = &Default_Physical_Constant_Value;
700  G_pt = &Default_Gravity_vector;
701  //Set the Physical ratios to the default value of 1
702  Viscosity_Ratio_pt = &Default_Physical_Ratio_Value;
703  Density_Ratio_pt = &Default_Physical_Ratio_Value;
704  }
705 
706  /// Vector to decide whether the stress-divergence form is used or not
707  // N.B. This needs to be public so that the intel compiler gets things correct
708  // somehow the access function messes things up when going to refineable
709  // navier--stokes
711 
712  //Access functions for the physical constants
713 
714  /// Reynolds number
715  const double &re() const {return *Re_pt;}
716 
717  /// Product of Reynolds and Strouhal number (=Womersley number)
718  const double &re_st() const {return *ReSt_pt;}
719 
720  /// Pointer to Reynolds number
721  double* &re_pt() {return Re_pt;}
722 
723  /// Pointer to product of Reynolds and Strouhal number (=Womersley number)
724  double* &re_st_pt() {return ReSt_pt;}
725 
726  /// \short Viscosity ratio for element: Element's viscosity relative to the
727  /// viscosity used in the definition of the Reynolds number
728  const double &viscosity_ratio() const {return *Viscosity_Ratio_pt;}
729 
730  /// Pointer to Viscosity Ratio
731  double* &viscosity_ratio_pt() {return Viscosity_Ratio_pt;}
732 
733  /// \short Density ratio for element: Element's density relative to the
734  /// viscosity used in the definition of the Reynolds number
735  const double &density_ratio() const {return *Density_Ratio_pt;}
736 
737  /// Pointer to Density ratio
738  double* &density_ratio_pt() {return Density_Ratio_pt;}
739 
740  /// Global inverse Froude number
741  const double &re_invfr() const {return *ReInvFr_pt;}
742 
743  /// Pointer to global inverse Froude number
744  double* &re_invfr_pt() {return ReInvFr_pt;}
745 
746  /// Vector of gravitational components
747  const Vector<double> &g() const {return *G_pt;}
748 
749  /// Pointer to Vector of gravitational components
750  Vector<double>* &g_pt() {return G_pt;}
751 
752  /// Access function for the body-force pointer
753  NavierStokesBodyForceFctPt& body_force_fct_pt()
754  {return Body_force_fct_pt;}
755 
756  /// Access function for the body-force pointer. Const version
757  NavierStokesBodyForceFctPt body_force_fct_pt() const
758  {return Body_force_fct_pt;}
759 
760  ///Access function for the source-function pointer
761  NavierStokesSourceFctPt& source_fct_pt() {return Source_fct_pt;}
762 
763  ///Access function for the source-function pointer. Const version
764  NavierStokesSourceFctPt source_fct_pt() const {return Source_fct_pt;}
765 
766  /// \short Access function for the source-function pointer for pressure
767  /// advection diffusion (used for validation only).
768  NavierStokesPressureAdvDiffSourceFctPt& source_fct_for_pressure_adv_diff()
769  {return Press_adv_diff_source_fct_pt;}
770 
771  /// \short Access function for the source-function pointer for pressure
772  /// advection diffusion (used for validation only). Const version.
773  NavierStokesPressureAdvDiffSourceFctPt source_fct_for_pressure_adv_diff()
774  const
775  {return Press_adv_diff_source_fct_pt;}
776 
777  /// \short Global eqn number of pressure dof that's pinned in pressure
778  /// adv diff problem
779  int& pinned_fp_pressure_eqn(){return Pinned_fp_pressure_eqn;}
780 
781  ///Function to return number of pressure degrees of freedom
782  virtual unsigned npres_nst() const=0;
783 
784  /// Compute the pressure shape functions at local coordinate s
785  virtual void pshape_nst(const Vector<double> &s, Shape &psi) const=0;
786 
787  /// \short Compute the pressure shape and test functions
788  /// at local coordinate s
789  virtual void pshape_nst(const Vector<double> &s, Shape &psi,
790  Shape &test) const=0;
791 
792  /// \short Compute the pressure shape and test functions and derivatives
793  /// w.r.t. global coords at local coordinate s.
794  /// Return Jacobian of mapping between local and global coordinates.
795  virtual double dpshape_and_dptest_eulerian_nst(const Vector<double> &s,
796  Shape &ppsi,
797  DShape &dppsidx,
798  Shape &ptest,
799  DShape &dptestdx) const=0;
800 
801  /// \short Velocity i at local node n. Uses suitably interpolated value
802  /// for hanging nodes. The use of u_index_nst() permits the use of this
803  /// element as the basis for multi-physics elements. The default
804  /// is to assume that the i-th velocity component is stored at the
805  /// i-th location of the node
806  double u_nst(const unsigned &n, const unsigned &i) const
807  {return nodal_value(n,u_index_nst(i));}
808 
809  /// \short Velocity i at local node n at timestep t (t=0: present;
810  /// t>0: previous). Uses suitably interpolated value for hanging nodes.
811  double u_nst(const unsigned &t, const unsigned &n,
812  const unsigned &i) const
813  {return nodal_value(t,n,u_index_nst(i));}
814 
815  /// \short Return the index at which the i-th unknown velocity component
816  /// is stored. The default value, i, is appropriate for single-physics
817  /// problems.
818  /// In derived multi-physics elements, this function should be overloaded
819  /// to reflect the chosen storage scheme. Note that these equations require
820  /// that the unknowns are always stored at the same indices at each node.
821  virtual inline unsigned u_index_nst(const unsigned &i) const {return i;}
822 
823  /// \short Return the number of velocity components
824  /// Used in FluidInterfaceElements
825  inline unsigned n_u_nst() const {return DIM;}
826 
827  /// \short i-th component of du/dt at local node n.
828  /// Uses suitably interpolated value for hanging nodes.
829  double du_dt_nst(const unsigned &n, const unsigned &i) const
830  {
831  // Get the data's timestepper
833 
834  //Initialise dudt
835  double dudt=0.0;
836 
837  //Loop over the timesteps, if there is a non Steady timestepper
838  if (!time_stepper_pt->is_steady())
839  {
840  //Find the index at which the dof is stored
841  const unsigned u_nodal_index = this->u_index_nst(i);
842 
843  // Number of timsteps (past & present)
844  const unsigned n_time = time_stepper_pt->ntstorage();
845  // Loop over the timesteps
846  for(unsigned t=0;t<n_time;t++)
847  {
848  dudt+=time_stepper_pt->weight(1,t)*nodal_value(t,n,u_nodal_index);
849  }
850  }
851 
852  return dudt;
853  }
854 
855  /// \short Disable ALE, i.e. assert the mesh is not moving -- you do this
856  /// at your own risk!
857  void disable_ALE()
858  {
859  ALE_is_disabled=true;
860  }
861 
862  /// \short (Re-)enable ALE, i.e. take possible mesh motion into account
863  /// when evaluating the time-derivative. Note: By default, ALE is
864  /// enabled, at the expense of possibly creating unnecessary work
865  /// in problems where the mesh is, in fact, stationary.
866  void enable_ALE()
867  {
868  ALE_is_disabled=false;
869  }
870 
871  /// \short Pressure at local pressure "node" n_p
872  /// Uses suitably interpolated value for hanging nodes.
873  virtual double p_nst(const unsigned &n_p)const=0;
874 
875  /// \short Pressure at local pressure "node" n_p at time level t
876  virtual double p_nst(const unsigned &t, const unsigned &n_p)const=0;
877 
878  /// Pin p_dof-th pressure dof and set it to value specified by p_value.
879  virtual void fix_pressure(const unsigned &p_dof, const double &p_value)=0;
880 
881  /// \short Return the index at which the pressure is stored if it is
882  /// stored at the nodes. If not stored at the nodes this will return
883  /// a negative number.
884  virtual int p_nodal_index_nst() const {return Pressure_not_stored_at_node;}
885 
886  /// Integral of pressure over element
887  double pressure_integral() const;
888 
889  /// \short Return integral of dissipation over element
890  double dissipation() const;
891 
892  /// \short Return dissipation at local coordinate s
893  double dissipation(const Vector<double>& s) const;
894 
895  /// \short Compute the vorticity vector at local coordinate s
896  void get_vorticity(const Vector<double>& s, Vector<double>& vorticity) const;
897 
898  /// \short Get integral of kinetic energy over element
899  double kin_energy() const;
900 
901  /// \short Get integral of time derivative of kinetic energy over element
902  double d_kin_energy_dt() const;
903 
904  /// Strain-rate tensor: 1/2 (du_i/dx_j + du_j/dx_i)
905  void strain_rate(const Vector<double>& s,
906  DenseMatrix<double>& strain_rate) const;
907 
908  /// \short Compute traction (on the viscous scale) exerted onto
909  /// the fluid at local coordinate s. N has to be outer unit normal
910  /// to the fluid.
911  void get_traction(const Vector<double>& s, const Vector<double>& N,
912  Vector<double>& traction);
913 
914  /// \short Compute traction (on the viscous scale) exerted onto
915  /// the fluid at local coordinate s, decomposed into pressure and
916  /// normal and tangential viscous components.
917  /// N has to be outer unit normal to the fluid.
918  void get_traction(const Vector<double>& s, const Vector<double>& N,
919  Vector<double>& traction_p,
920  Vector<double>& traction_visc_n,
921  Vector<double>& traction_visc_t);
922 
923  /// \short This implements a pure virtual function defined
924  /// in the FSIFluidElement class. The function computes
925  /// the traction (on the viscous scale), at the element's local
926  /// coordinate s, that the fluid element exerts onto an adjacent
927  /// solid element. The number of arguments is imposed by
928  /// the interface defined in the FSIFluidElement -- only the
929  /// unit normal N (pointing into the fluid!) is actually used
930  /// in the computation.
931  void get_load(const Vector<double> &s,
932  const Vector<double> &N,
933  Vector<double> &load)
934  {
935  // Note: get_traction() computes the traction onto the fluid
936  // if N is the outer unit normal onto the fluid; here we're
937  // exepcting N to point into the fluid so we're getting the
938  // traction onto the adjacent wall instead!
939  get_traction(s,N,load);
940  }
941 
942  /// \short Compute the diagonal of the velocity/pressure mass matrices.
943  /// If which one=0, both are computed, otherwise only the pressure
944  /// (which_one=1) or the velocity mass matrix (which_one=2 -- the
945  /// LSC version of the preconditioner only needs that one)
946  void get_pressure_and_velocity_mass_matrix_diagonal(
947  Vector<double> &press_mass_diag, Vector<double> &veloc_mass_diag,
948  const unsigned& which_one=0);
949 
950  /// \short Number of scalars/fields output by this element. Reimplements
951  /// broken virtual function in base class.
952  unsigned nscalar_paraview() const
953  {
954  return DIM+1;
955  }
956 
957  /// \short Write values of the i-th scalar field at the plot points. Needs
958  /// to be implemented for each new specific element type.
959  void scalar_value_paraview(std::ofstream& file_out,
960  const unsigned& i,
961  const unsigned& nplot) const
962  {
963  // Vector of local coordinates
964  Vector<double> s(DIM);
965 
966 
967  // Loop over plot points
968  unsigned num_plot_points=nplot_points_paraview(nplot);
969  for (unsigned iplot=0;iplot<num_plot_points;iplot++)
970  {
971 
972  // Get local coordinates of plot point
973  get_s_plot(iplot,nplot,s);
974 
975  // Velocities
976  if(i<DIM) {file_out << interpolated_u_nst(s,i) << std::endl;}
977 
978  // Pressure
979  else if(i==DIM) {file_out << interpolated_p_nst(s) << std::endl;}
980 
981  // Never get here
982  else
983  {
984 #ifdef PARANOID
985  std::stringstream error_stream;
986  error_stream
987  << "These Navier Stokes elements only store " << DIM+1 << " fields, "
988  << "but i is currently " << i << std::endl;
989  throw OomphLibError(
990  error_stream.str(),
991  OOMPH_CURRENT_FUNCTION,
992  OOMPH_EXCEPTION_LOCATION);
993 #endif
994  }
995  }
996  }
997 
998  /// \short Name of the i-th scalar field. Default implementation
999  /// returns V1 for the first one, V2 for the second etc. Can (should!) be
1000  /// overloaded with more meaningful names in specific elements.
1001  std::string scalar_name_paraview(const unsigned& i) const
1002  {
1003  // Velocities
1004  if(i<DIM)
1005  {
1006  return "Velocity "+StringConversion::to_string(i);
1007  }
1008  // Preussre
1009  else if(i==DIM)
1010  {
1011  return "Pressure";
1012  }
1013  // Never get here
1014  else
1015  {
1016  std::stringstream error_stream;
1017  error_stream
1018  << "These Navier Stokes elements only store " << DIM+1 << " fields,\n"
1019  << "but i is currently " << i << std::endl;
1020  throw OomphLibError(
1021  error_stream.str(),
1022  OOMPH_CURRENT_FUNCTION,
1023  OOMPH_EXCEPTION_LOCATION);
1024  // Dummy return
1025  return " ";
1026  }
1027  }
1028 
1029  /// \short Output function: x,y,[z],u,v,[w],p
1030  /// in tecplot format. Default number of plot points
1031  void output(std::ostream &outfile)
1032  {
1033  unsigned nplot=5;
1034  output(outfile,nplot);
1035  }
1036 
1037  /// \short Output function: x,y,[z],u,v,[w],p
1038  /// in tecplot format. nplot points in each coordinate direction
1039  void output(std::ostream &outfile, const unsigned &nplot);
1040 
1041  /// \short C-style output function: x,y,[z],u,v,[w],p
1042  /// in tecplot format. Default number of plot points
1043  void output(FILE* file_pt)
1044  {
1045  unsigned nplot=5;
1046  output(file_pt,nplot);
1047  }
1048 
1049  /// \short C-style output function: x,y,[z],u,v,[w],p
1050  /// in tecplot format. nplot points in each coordinate direction
1051  void output(FILE* file_pt, const unsigned &nplot);
1052 
1053  /// \short Full output function:
1054  /// x,y,[z],u,v,[w],p,du/dt,dv/dt,[dw/dt],dissipation
1055  /// in tecplot format. Default number of plot points
1056  void full_output(std::ostream &outfile)
1057  {
1058  unsigned nplot=5;
1059  full_output(outfile,nplot);
1060  }
1061 
1062  /// \short Full output function:
1063  /// x,y,[z],u,v,[w],p,du/dt,dv/dt,[dw/dt],dissipation
1064  /// in tecplot format. nplot points in each coordinate direction
1065  void full_output(std::ostream &outfile, const unsigned &nplot);
1066 
1067 
1068  /// \short Output function: x,y,[z],u,v,[w] in tecplot format.
1069  /// nplot points in each coordinate direction at timestep t
1070  /// (t=0: present; t>0: previous timestep)
1071  void output_veloc(std::ostream &outfile, const unsigned &nplot,
1072  const unsigned& t);
1073 
1074 
1075  /// \short Output function: x,y,[z], [omega_x,omega_y,[and/or omega_z]]
1076  /// in tecplot format. nplot points in each coordinate direction
1077  void output_vorticity(std::ostream &outfile,
1078  const unsigned &nplot);
1079 
1080  /// \short Output exact solution specified via function pointer
1081  /// at a given number of plot points. Function prints as
1082  /// many components as are returned in solution Vector
1083  void output_fct(std::ostream &outfile, const unsigned &nplot,
1085 
1086  /// \short Output exact solution specified via function pointer
1087  /// at a given time and at a given number of plot points.
1088  /// Function prints as many components as are returned in solution Vector.
1089  void output_fct(std::ostream &outfile, const unsigned &nplot,
1090  const double& time,
1092 
1093  /// \short Compute norm of solution: square of the L2 norm of the velocities
1094  void compute_norm(double& norm);
1095 
1096  /// \short Validate against exact solution at given time
1097  /// Solution is provided via function pointer.
1098  /// Plot at a given number of plot points and compute L2 error
1099  /// and L2 norm of velocity solution over element
1100  void compute_error(std::ostream &outfile,
1102  const double& time,
1103  double& error, double& norm);
1104 
1105  /// \short Validate against exact solution.
1106  /// Solution is provided via function pointer.
1107  /// Plot at a given number of plot points and compute L2 error
1108  /// and L2 norm of velocity solution over element
1109  void compute_error(std::ostream &outfile,
1111  double& error, double& norm);
1112 
1113  /// Compute the element's residual Vector
1115  {
1116  //Call the generic residuals function with flag set to 0
1117  //and using a dummy matrix argument
1118  fill_in_generic_residual_contribution_nst(
1121  }
1122 
1123  ///\short Compute the element's residual Vector and the jacobian matrix
1124  /// Virtual function can be overloaded by hanging-node version
1126  DenseMatrix<double> &jacobian)
1127  {
1128  //Call the generic routine with the flag set to 1
1129  fill_in_generic_residual_contribution_nst(residuals,jacobian,
1131  }
1132 
1133  /// \short Add the element's contribution to its residuals vector,
1134  /// jacobian matrix and mass matrix
1136  Vector<double> &residuals, DenseMatrix<double> &jacobian,
1137  DenseMatrix<double> &mass_matrix)
1138  {
1139  //Call the generic routine with the flag set to 2
1140  fill_in_generic_residual_contribution_nst(residuals,jacobian,mass_matrix,2);
1141  }
1142 
1143  /// Compute the element's residual Vector
1145  double* const &parameter_pt,Vector<double> &dres_dparam)
1146  {
1147  //Call the generic residuals function with flag set to 0
1148  //and using a dummy matrix argument
1149  fill_in_generic_dresidual_contribution_nst(
1150  parameter_pt,
1153  }
1154 
1155  ///\short Compute the element's residual Vector and the jacobian matrix
1156  /// Virtual function can be overloaded by hanging-node version
1158  double* const &parameter_pt,Vector<double> &dres_dparam,
1159  DenseMatrix<double> &djac_dparam)
1160  {
1161  //Call the generic routine with the flag set to 1
1162  fill_in_generic_dresidual_contribution_nst(
1163  parameter_pt,
1164  dres_dparam,djac_dparam,GeneralisedElement::Dummy_matrix,1);
1165  }
1166 
1167  /// Add the element's contribution to its residuals vector,
1168  /// jacobian matrix and mass matrix
1170  double* const &parameter_pt,
1171  Vector<double> &dres_dparam,
1172  DenseMatrix<double> &djac_dparam,
1173  DenseMatrix<double> &dmass_matrix_dparam)
1174  {
1175  //Call the generic routine with the flag set to 2
1176  fill_in_generic_dresidual_contribution_nst(
1177  parameter_pt,dres_dparam,djac_dparam,dmass_matrix_dparam,2);
1178  }
1179 
1180 
1181  /// \short Compute the residuals for the associated pressure advection
1182  /// diffusion problem. Used by the Fp preconditioner.
1184  {
1185  fill_in_generic_pressure_advection_diffusion_contribution_nst(
1186  residuals,GeneralisedElement::Dummy_matrix,0);
1187  }
1188 
1189  /// \short Compute the residuals and Jacobian for the associated
1190  /// pressure advection diffusion problem. Used by the Fp preconditioner.
1192  Vector<double>& residuals, DenseMatrix<double> &jacobian)
1193  {
1194  fill_in_generic_pressure_advection_diffusion_contribution_nst(
1195  residuals,jacobian,1);
1196  }
1197 
1198 
1199  /// \short Pin all non-pressure dofs and backup eqn numbers
1200  void pin_all_non_pressure_dofs(std::map<Data*,std::vector<int> >&
1201  eqn_number_backup)
1202  {
1203  // Loop over internal data and pin the values (having established that
1204  // pressure dofs aren't amongst those)
1205  unsigned nint=this->ninternal_data();
1206  for (unsigned j=0;j<nint;j++)
1207  {
1208  Data* data_pt=this->internal_data_pt(j);
1209  if (eqn_number_backup[data_pt].size()==0)
1210  {
1211  unsigned nvalue=data_pt->nvalue();
1212  eqn_number_backup[data_pt].resize(nvalue);
1213  for (unsigned i=0;i<nvalue;i++)
1214  {
1215  // Backup
1216  eqn_number_backup[data_pt][i]=data_pt->eqn_number(i);
1217 
1218  // Pin everything
1219  data_pt->pin(i);
1220  }
1221  }
1222  }
1223 
1224  // Now deal with nodal values
1225  unsigned nnod=this->nnode();
1226  for (unsigned j=0;j<nnod;j++)
1227  {
1228 
1229  Node* nod_pt=this->node_pt(j);
1230  if (eqn_number_backup[nod_pt].size()==0)
1231  {
1232 
1233  unsigned nvalue=nod_pt->nvalue();
1234  eqn_number_backup[nod_pt].resize(nvalue);
1235  for (unsigned i=0;i<nvalue;i++)
1236  {
1237  // Pin everything apart from the nodal pressure
1238  // value
1239  if (int(i)!=this->p_nodal_index_nst())
1240  {
1241  // Backup
1242  eqn_number_backup[nod_pt][i]=nod_pt->eqn_number(i);
1243 
1244  // Pin
1245  nod_pt->pin(i);
1246  }
1247  // Else it's a pressure value
1248  else
1249  {
1250  // Exclude non-nodal pressure based elements
1251  if (this->p_nodal_index_nst()>=0)
1252  {
1253  // Backup
1254  eqn_number_backup[nod_pt][i]=nod_pt->eqn_number(i);
1255  }
1256  }
1257  }
1258 
1259 
1260  // If it's a solid node deal with its positional data too
1261  SolidNode* solid_nod_pt=dynamic_cast<SolidNode*>(nod_pt);
1262  if (solid_nod_pt!=0)
1263  {
1264  Data* solid_posn_data_pt=solid_nod_pt->variable_position_pt();
1265  if (eqn_number_backup[solid_posn_data_pt].size()==0)
1266  {
1267  unsigned nvalue=solid_posn_data_pt->nvalue();
1268  eqn_number_backup[solid_posn_data_pt].resize(nvalue);
1269  for (unsigned i=0;i<nvalue;i++)
1270  {
1271  // Backup
1272  eqn_number_backup[solid_posn_data_pt][i]=
1273  solid_posn_data_pt->eqn_number(i);
1274 
1275  // Pin
1276  solid_posn_data_pt->pin(i);
1277  }
1278  }
1279  }
1280  }
1281  }
1282  }
1283 
1284 
1285  /// \short Build FaceElements that apply the Robin boundary condition
1286  /// to the pressure advection diffusion problem required by
1287  /// Fp preconditioner
1288  virtual void build_fp_press_adv_diff_robin_bc_element(const unsigned&
1289  face_index)=0;
1290 
1291  /// \short Output the FaceElements that apply the Robin boundary condition
1292  /// to the pressure advection diffusion problem required by
1293  /// Fp preconditioner
1295  {
1296  unsigned nel=Pressure_advection_diffusion_robin_element_pt.size();
1297  for (unsigned e=0;e<nel;e++)
1298  {
1299  FaceElement* face_el_pt=Pressure_advection_diffusion_robin_element_pt[e];
1300  outfile << "ZONE" << std::endl;
1301  Vector<double> unit_normal(DIM);
1302  Vector<double> x(DIM);
1303  Vector<double> s(DIM-1);
1304  unsigned n=face_el_pt->integral_pt()->nweight();
1305  for (unsigned ipt=0;ipt<n;ipt++)
1306  {
1307  for(unsigned i=0;i<DIM-1;i++)
1308  {
1309  s[i]=face_el_pt->integral_pt()->knot(ipt,i);
1310  }
1311  face_el_pt->interpolated_x(s,x);
1312  face_el_pt->outer_unit_normal(ipt,unit_normal);
1313  for (unsigned i=0;i<DIM;i++)
1314  {
1315  outfile << x[i] << " ";
1316  }
1317  for (unsigned i=0;i<DIM;i++)
1318  {
1319  outfile << unit_normal[i] << " ";
1320  }
1321  outfile << std::endl;
1322  }
1323  }
1324  }
1325 
1326  /// \short Delete the FaceElements that apply the Robin boundary condition
1327  /// to the pressure advection diffusion problem required by
1328  /// Fp preconditioner
1330  {
1331  unsigned nel=Pressure_advection_diffusion_robin_element_pt.size();
1332  for (unsigned e=0;e<nel;e++)
1333  {
1334  delete Pressure_advection_diffusion_robin_element_pt[e];
1335  }
1336  Pressure_advection_diffusion_robin_element_pt.clear();
1337  }
1338 
1339  /// \short Compute derivatives of elemental residual vector with respect
1340  /// to nodal coordinates. Overwrites default implementation in
1341  /// FiniteElement base class.
1342  /// dresidual_dnodal_coordinates(l,i,j) = d res(l) / dX_{ij}
1344  dresidual_dnodal_coordinates);
1345 
1346 
1347 
1348  /// Compute vector of FE interpolated velocity u at local coordinate s
1349  void interpolated_u_nst(const Vector<double> &s, Vector<double>& veloc) const
1350  {
1351  //Find number of nodes
1352  unsigned n_node = nnode();
1353  //Local shape function
1354  Shape psi(n_node);
1355  //Find values of shape function
1356  shape(s,psi);
1357 
1358  for (unsigned i=0;i<DIM;i++)
1359  {
1360  //Index at which the nodal value is stored
1361  unsigned u_nodal_index = u_index_nst(i);
1362  //Initialise value of u
1363  veloc[i] = 0.0;
1364  //Loop over the local nodes and sum
1365  for(unsigned l=0;l<n_node;l++)
1366  {
1367  veloc[i] += nodal_value(l,u_nodal_index)*psi[l];
1368  }
1369  }
1370  }
1371 
1372  /// Return FE interpolated velocity u[i] at local coordinate s
1373  double interpolated_u_nst(const Vector<double> &s, const unsigned &i) const
1374  {
1375  //Find number of nodes
1376  unsigned n_node = nnode();
1377  //Local shape function
1378  Shape psi(n_node);
1379  //Find values of shape function
1380  shape(s,psi);
1381 
1382  //Get nodal index at which i-th velocity is stored
1383  unsigned u_nodal_index = u_index_nst(i);
1384 
1385  //Initialise value of u
1386  double interpolated_u = 0.0;
1387  //Loop over the local nodes and sum
1388  for(unsigned l=0;l<n_node;l++)
1389  {
1390  interpolated_u += nodal_value(l,u_nodal_index)*psi[l];
1391  }
1392 
1393  return(interpolated_u);
1394  }
1395 
1396  /// \short Return FE interpolated velocity u[i] at local coordinate s
1397  /// at time level t (t=0: present; t>0: history)
1398  double interpolated_u_nst(const unsigned& t,
1399  const Vector<double> &s,
1400  const unsigned &i) const
1401  {
1402  //Find number of nodes
1403  unsigned n_node = nnode();
1404 
1405  //Local shape function
1406  Shape psi(n_node);
1407 
1408  //Find values of shape function
1409  shape(s,psi);
1410 
1411  //Get nodal index at which i-th velocity is stored
1412  unsigned u_nodal_index = u_index_nst(i);
1413 
1414  //Initialise value of u
1415  double interpolated_u = 0.0;
1416  //Loop over the local nodes and sum
1417  for(unsigned l=0;l<n_node;l++)
1418  {
1419  interpolated_u += nodal_value(t,l,u_nodal_index)*psi[l];
1420  }
1421 
1422  return(interpolated_u);
1423  }
1424 
1425  /// \short Compute the derivatives of the i-th component of
1426  /// velocity at point s with respect
1427  /// to all data that can affect its value. In addition, return the global
1428  /// equation numbers corresponding to the data. The function is virtual
1429  /// so that it can be overloaded in the refineable version
1431  const unsigned &i,
1432  Vector<double> &du_ddata,
1433  Vector<unsigned> &global_eqn_number)
1434  {
1435  //Find number of nodes
1436  unsigned n_node = nnode();
1437  //Local shape function
1438  Shape psi(n_node);
1439  //Find values of shape function
1440  shape(s,psi);
1441 
1442  //Find the index at which the velocity component is stored
1443  const unsigned u_nodal_index = u_index_nst(i);
1444 
1445  //Find the number of dofs associated with interpolated u
1446  unsigned n_u_dof=0;
1447  for(unsigned l=0;l<n_node;l++)
1448  {
1449  int global_eqn = this->node_pt(l)->eqn_number(u_nodal_index);
1450  //If it's positive add to the count
1451  if(global_eqn >= 0) {++n_u_dof;}
1452  }
1453 
1454  //Now resize the storage schemes
1455  du_ddata.resize(n_u_dof,0.0);
1456  global_eqn_number.resize(n_u_dof,0);
1457 
1458  //Loop over th nodes again and set the derivatives
1459  unsigned count=0;
1460  //Loop over the local nodes and sum
1461  for(unsigned l=0;l<n_node;l++)
1462  {
1463  //Get the global equation number
1464  int global_eqn = this->node_pt(l)->eqn_number(u_nodal_index);
1465  if (global_eqn >= 0)
1466  {
1467  //Set the global equation number
1468  global_eqn_number[count] = global_eqn;
1469  //Set the derivative with respect to the unknown
1470  du_ddata[count] = psi[l];
1471  //Increase the counter
1472  ++count;
1473  }
1474  }
1475  }
1476 
1477 
1478  /// Return FE interpolated pressure at local coordinate s
1479  virtual double interpolated_p_nst(const Vector<double> &s) const
1480  {
1481  //Find number of nodes
1482  unsigned n_pres = npres_nst();
1483  //Local shape function
1484  Shape psi(n_pres);
1485  //Find values of shape function
1486  pshape_nst(s,psi);
1487 
1488  //Initialise value of p
1489  double interpolated_p = 0.0;
1490  //Loop over the local nodes and sum
1491  for(unsigned l=0;l<n_pres;l++)
1492  {
1493  interpolated_p += p_nst(l)*psi[l];
1494  }
1495 
1496  return(interpolated_p);
1497  }
1498 
1499 
1500  /// Return FE interpolated pressure at local coordinate s at time level t
1501  double interpolated_p_nst(const unsigned &t, const Vector<double> &s) const
1502  {
1503  //Find number of nodes
1504  unsigned n_pres = npres_nst();
1505  //Local shape function
1506  Shape psi(n_pres);
1507  //Find values of shape function
1508  pshape_nst(s,psi);
1509 
1510  //Initialise value of p
1511  double interpolated_p = 0.0;
1512  //Loop over the local nodes and sum
1513  for(unsigned l=0;l<n_pres;l++)
1514  {
1515  interpolated_p += p_nst(t,l)*psi[l];
1516  }
1517 
1518  return(interpolated_p);
1519  }
1520 
1521 
1522  /// Return FE interpolated derivatives of velocity component u[i]
1523  /// w.r.t spatial global coordinate direction x[j] at local coordinate s
1525  const unsigned &i,
1526  const unsigned &j) const
1527  {
1528  // Determine number of nodes
1529  const unsigned n_node = nnode();
1530 
1531  // Allocate storage for local shape function and its derivatives
1532  // with respect to space
1533  Shape psif(n_node);
1534  DShape dpsifdx(n_node,DIM);
1535 
1536  // Find values of shape function (ignore jacobian)
1537  (void)this->dshape_eulerian(s,psif,dpsifdx);
1538 
1539  // Get the index at which the velocity is stored
1540  const unsigned u_nodal_index = u_index_nst(i);
1541 
1542  // Initialise value of dudx
1543  double interpolated_dudx = 0.0;
1544 
1545  // Loop over the local nodes and sum
1546  for(unsigned l=0;l<n_node;l++)
1547  {
1548  interpolated_dudx += nodal_value(l,u_nodal_index)*dpsifdx(l,j);
1549  }
1550 
1551  return(interpolated_dudx);
1552  }
1553 
1554 
1555  /// \short Output solution in data vector at local cordinates s:
1556  /// x,y [,z], u,v,[w], p
1558  {
1559  // Dimension
1560  unsigned dim=s.size();
1561 
1562  // Resize data for values
1563  data.resize(2*dim+1);
1564 
1565  // Write values in the vector
1566  for (unsigned i=0; i<dim; i++)
1567  {
1568  data[i]=interpolated_x(s,i);
1569  data[i+dim]=this->interpolated_u_nst(s,i);
1570  }
1571  data[2*dim]=this->interpolated_p_nst(s);
1572  }
1573 
1574 };
1575 
1576 //////////////////////////////////////////////////////////////////////////////
1577 //////////////////////////////////////////////////////////////////////////////
1578 //////////////////////////////////////////////////////////////////////////////
1579 
1580 
1581 //==========================================================================
1582 /// Crouzeix_Raviart elements are Navier--Stokes elements with quadratic
1583 /// interpolation for velocities and positions, but a discontinuous linear
1584 /// pressure interpolation. They can be used within oomph-lib's
1585 /// block preconditioning framework.
1586 //==========================================================================
1587 template <unsigned DIM>
1588 class QCrouzeixRaviartElement : public virtual QElement<DIM,3>,
1589  public virtual NavierStokesEquations<DIM>
1590 {
1591  private:
1592 
1593  /// Static array of ints to hold required number of variables at nodes
1594  static const unsigned Initial_Nvalue[];
1595 
1596  protected:
1597 
1598  /// Internal index that indicates at which internal data the pressure
1599  /// is stored
1601 
1602 
1603  /// \short Velocity shape and test functions and their derivs
1604  /// w.r.t. to global coords at local coordinate s (taken from geometry)
1605  ///Return Jacobian of mapping between local and global coordinates.
1606  inline double dshape_and_dtest_eulerian_nst(const Vector<double> &s,
1607  Shape &psi,
1608  DShape &dpsidx,
1609  Shape &test,
1610  DShape &dtestdx) const;
1611 
1612  /// \short Velocity shape and test functions and their derivs
1613  /// w.r.t. to global coords at ipt-th integation point (taken from geometry)
1614  ///Return Jacobian of mapping between local and global coordinates.
1615  inline double dshape_and_dtest_eulerian_at_knot_nst(const unsigned &ipt,
1616  Shape &psi,
1617  DShape &dpsidx,
1618  Shape &test,
1619  DShape &dtestdx) const;
1620 
1621  /// \short Shape/test functions and derivs w.r.t. to global coords at
1622  /// integration point ipt; return Jacobian of mapping (J). Also compute
1623  /// derivatives of dpsidx, dtestdx and J w.r.t. nodal coordinates.
1624  inline double dshape_and_dtest_eulerian_at_knot_nst(
1625  const unsigned &ipt,
1626  Shape &psi,
1627  DShape &dpsidx,
1628  RankFourTensor<double> &d_dpsidx_dX,
1629  Shape &test,
1630  DShape &dtestdx,
1631  RankFourTensor<double> &d_dtestdx_dX,
1632  DenseMatrix<double> &djacobian_dX) const;
1633 
1634 
1635 public:
1636 
1637  /// Constructor, there are DIM+1 internal values (for the pressure)
1639  {
1640  //Allocate and add one Internal data object that stored DIM+1 pressure
1641  //values;
1642  P_nst_internal_index = this->add_internal_data(new Data(DIM+1));
1643  }
1644 
1645  /// \short Number of values (pinned or dofs) required at local node n.
1646  virtual unsigned required_nvalue(const unsigned &n) const;
1647 
1648 
1649  /// Pressure shape functions at local coordinate s
1650  inline void pshape_nst(const Vector<double> &s, Shape &psi) const;
1651 
1652  /// Pressure shape and test functions at local coordinte s
1653  inline void pshape_nst(const Vector<double> &s, Shape &psi,
1654  Shape &test) const;
1655 
1656  /// \short Return the i-th pressure value
1657  /// (Discontinous pressure interpolation -- no need to cater for hanging
1658  /// nodes).
1659  double p_nst(const unsigned &i) const
1660  {return this->internal_data_pt(P_nst_internal_index)->value(i);}
1661 
1662  /// \short Return the i-th pressure value
1663  /// (Discontinous pressure interpolation -- no need to cater for hanging
1664  /// nodes).
1665  double p_nst(const unsigned &t, const unsigned &i) const
1666  {return this->internal_data_pt(P_nst_internal_index)->value(t,i);}
1667 
1668  /// Return number of pressure values
1669  unsigned npres_nst() const {return DIM+1;}
1670 
1671  /// \short Pressure shape and test functions and their derivs
1672  /// w.r.t. to global coords at local coordinate s (taken from geometry)
1673  /// Return Jacobian of mapping between local and global coordinates.
1674  inline double dpshape_and_dptest_eulerian_nst(const Vector<double> &s,
1675  Shape &ppsi,
1676  DShape &dppsidx,
1677  Shape &ptest,
1678  DShape &dptestdx) const;
1679 
1680  /// Return the local equation numbers for the pressure values.
1681  inline int p_local_eqn(const unsigned &n) const
1682  {return this->internal_local_eqn(P_nst_internal_index,n);}
1683 
1684  /// Pin p_dof-th pressure dof and set it to value specified by p_value.
1685  void fix_pressure(const unsigned &p_dof, const double &p_value)
1686  {
1687  this->internal_data_pt(P_nst_internal_index)->pin(p_dof);
1688  this->internal_data_pt(P_nst_internal_index)->set_value(p_dof,p_value);
1689  }
1690 
1691 
1692  /// \short Build FaceElements that apply the Robin boundary condition
1693  /// to the pressure advection diffusion problem required by
1694  /// Fp preconditioner
1696  face_index)
1697  {
1698  this->Pressure_advection_diffusion_robin_element_pt.push_back(
1700  this, face_index));
1701  }
1702 
1703  /// \short Add to the set \c paired_load_data pairs containing
1704  /// - the pointer to a Data object
1705  /// and
1706  /// - the index of the value in that Data object
1707  /// .
1708  /// for all values (pressures, velocities) that affect the
1709  /// load computed in the \c get_load(...) function.
1710  void identify_load_data(
1711  std::set<std::pair<Data*,unsigned> > &paired_load_data);
1712 
1713  /// \short Add to the set \c paired_pressure_data pairs
1714  /// containing
1715  /// - the pointer to a Data object
1716  /// and
1717  /// - the index of the value in that Data object
1718  /// .
1719  /// for all pressure values that affect the
1720  /// load computed in the \c get_load(...) function.
1721  void identify_pressure_data(
1722  std::set<std::pair<Data*,unsigned> > &paired_pressure_data);
1723 
1724 
1725  /// Redirect output to NavierStokesEquations output
1726  void output(std::ostream &outfile)
1728 
1729  /// Redirect output to NavierStokesEquations output
1730  void output(std::ostream &outfile, const unsigned &nplot)
1731  {NavierStokesEquations<DIM>::output(outfile,nplot);}
1732 
1733 
1734  /// Redirect output to NavierStokesEquations output
1735  void output(FILE* file_pt) {NavierStokesEquations<DIM>::output(file_pt);}
1736 
1737  /// Redirect output to NavierStokesEquations output
1738  void output(FILE* file_pt, const unsigned &nplot)
1739  {NavierStokesEquations<DIM>::output(file_pt,nplot);}
1740 
1741 
1742  /// \short Full output function:
1743  /// x,y,[z],u,v,[w],p,du/dt,dv/dt,[dw/dt],dissipation
1744  /// in tecplot format. Default number of plot points
1745  void full_output(std::ostream &outfile)
1747 
1748  /// \short Full output function:
1749  /// x,y,[z],u,v,[w],p,du/dt,dv/dt,[dw/dt],dissipation
1750  /// in tecplot format. nplot points in each coordinate direction
1751  void full_output(std::ostream &outfile, const unsigned &nplot)
1752  {NavierStokesEquations<DIM>::full_output(outfile,nplot);}
1753 
1754 
1755  /// \short The number of "DOF types" that degrees of freedom in this element
1756  /// are sub-divided into: Velocity and pressure.
1757  unsigned ndof_types() const
1758  {
1759  return DIM+1;
1760  }
1761 
1762  /// \short Create a list of pairs for all unknowns in this element,
1763  /// so that the first entry in each pair contains the global equation
1764  /// number of the unknown, while the second one contains the number
1765  /// of the "DOF type" that this unknown is associated with.
1766  /// (Function can obviously only be called if the equation numbering
1767  /// scheme has been set up.) Velocity=0; Pressure=1
1769  std::list<std::pair<unsigned long,unsigned> >& dof_lookup_list) const;
1770 
1771 };
1772 
1773 //Inline functions
1774 
1775 //=======================================================================
1776 /// Derivatives of the shape functions and test functions w.r.t. to global
1777 /// (Eulerian) coordinates. Return Jacobian of mapping between
1778 /// local and global coordinates.
1779 //=======================================================================
1780 template<unsigned DIM>
1782  const Vector<double> &s, Shape &psi,
1783  DShape &dpsidx, Shape &test,
1784  DShape &dtestdx) const
1785 {
1786  //Call the geometrical shape functions and derivatives
1787  double J = this->dshape_eulerian(s,psi,dpsidx);
1788  //The test functions are equal to the shape functions
1789  test = psi;
1790  dtestdx = dpsidx;
1791  //Return the jacobian
1792  return J;
1793 }
1794 
1795 //=======================================================================
1796 /// Derivatives of the shape functions and test functions w.r.t. to global
1797 /// (Eulerian) coordinates. Return Jacobian of mapping between
1798 /// local and global coordinates.
1799 //=======================================================================
1800 template<unsigned DIM>
1801 inline double QCrouzeixRaviartElement<DIM>::
1803  const unsigned &ipt, Shape &psi,
1804  DShape &dpsidx, Shape &test,
1805  DShape &dtestdx) const
1806 {
1807  //Call the geometrical shape functions and derivatives
1808  double J = this->dshape_eulerian_at_knot(ipt,psi,dpsidx);
1809  //The test functions are equal to the shape functions
1810  test = psi;
1811  dtestdx = dpsidx;
1812  //Return the jacobian
1813  return J;
1814 }
1815 
1816 
1817 //=======================================================================
1818 /// 2D
1819 /// Define the shape functions (psi) and test functions (test) and
1820 /// their derivatives w.r.t. global coordinates (dpsidx and dtestdx)
1821 /// and return Jacobian of mapping (J). Additionally compute the
1822 /// derivatives of dpsidx, dtestdx and J w.r.t. nodal coordinates.
1823 ///
1824 /// Galerkin: Test functions = shape functions
1825 //=======================================================================
1826 template<>
1827 inline double QCrouzeixRaviartElement<2>::
1829  const unsigned &ipt, Shape &psi, DShape &dpsidx,
1830  RankFourTensor<double> &d_dpsidx_dX,
1831  Shape &test, DShape &dtestdx,
1832  RankFourTensor<double> &d_dtestdx_dX,
1833  DenseMatrix<double> &djacobian_dX) const
1834  {
1835  // Call the geometrical shape functions and derivatives
1836  const double J = this->dshape_eulerian_at_knot(ipt,psi,dpsidx,
1837  djacobian_dX,
1838  d_dpsidx_dX);
1839 
1840  // Loop over the test functions and derivatives and set them equal to the
1841  // shape functions
1842  for(unsigned i=0;i<9;i++)
1843  {
1844  test[i] = psi[i];
1845 
1846  for(unsigned k=0;k<2;k++)
1847  {
1848  dtestdx(i,k) = dpsidx(i,k);
1849 
1850  for(unsigned p=0;p<2;p++)
1851  {
1852  for(unsigned q=0;q<9;q++)
1853  {
1854  d_dtestdx_dX(p,q,i,k) = d_dpsidx_dX(p,q,i,k);
1855  }
1856  }
1857  }
1858  }
1859 
1860  // Return the jacobian
1861  return J;
1862  }
1863 
1864 
1865 //=======================================================================
1866 /// 3D
1867 /// Define the shape functions (psi) and test functions (test) and
1868 /// their derivatives w.r.t. global coordinates (dpsidx and dtestdx)
1869 /// and return Jacobian of mapping (J). Additionally compute the
1870 /// derivatives of dpsidx, dtestdx and J w.r.t. nodal coordinates.
1871 ///
1872 /// Galerkin: Test functions = shape functions
1873 //=======================================================================
1874 template<>
1875 inline double QCrouzeixRaviartElement<3>::
1877  const unsigned &ipt, Shape &psi, DShape &dpsidx,
1878  RankFourTensor<double> &d_dpsidx_dX,
1879  Shape &test, DShape &dtestdx,
1880  RankFourTensor<double> &d_dtestdx_dX,
1881  DenseMatrix<double> &djacobian_dX) const
1882  {
1883  // Call the geometrical shape functions and derivatives
1884  const double J = this->dshape_eulerian_at_knot(ipt,psi,dpsidx,
1885  djacobian_dX,
1886  d_dpsidx_dX);
1887 
1888  // Loop over the test functions and derivatives and set them equal to the
1889  // shape functions
1890  for(unsigned i=0;i<27;i++)
1891  {
1892  test[i] = psi[i];
1893 
1894  for(unsigned k=0;k<3;k++)
1895  {
1896  dtestdx(i,k) = dpsidx(i,k);
1897 
1898  for(unsigned p=0;p<3;p++)
1899  {
1900  for(unsigned q=0;q<27;q++)
1901  {
1902  d_dtestdx_dX(p,q,i,k) = d_dpsidx_dX(p,q,i,k);
1903  }
1904  }
1905  }
1906  }
1907 
1908  // Return the jacobian
1909  return J;
1910  }
1911 
1912 
1913 
1914 //=======================================================================
1915 /// 2D :
1916 /// Pressure shape functions
1917 //=======================================================================
1918 template<>
1920  Shape &psi)
1921 const
1922 {
1923  psi[0] = 1.0;
1924  psi[1] = s[0];
1925  psi[2] = s[1];
1926 }
1927 
1928 
1929 
1930 //==========================================================================
1931 /// 2D :
1932 /// Pressure shape and test functions and derivs w.r.t. to Eulerian coords.
1933 /// Return Jacobian of mapping between local and global coordinates.
1934 //==========================================================================
1935 template<>
1937  const Vector<double> &s,
1938  Shape &ppsi,
1939  DShape &dppsidx,
1940  Shape &ptest,
1941  DShape &dptestdx) const
1942  {
1943 
1944  // Initalise with shape fcts and derivs. w.r.t. to local coordinates
1945  ppsi[0] = 1.0;
1946  ppsi[1] = s[0];
1947  ppsi[2] = s[1];
1948 
1949  dppsidx(0,0) = 0.0;
1950  dppsidx(1,0) = 1.0;
1951  dppsidx(2,0) = 0.0;
1952 
1953  dppsidx(0,1) = 0.0;
1954  dppsidx(1,1) = 0.0;
1955  dppsidx(2,1) = 1.0;
1956 
1957 
1958  //Get the values of the shape functions and their local derivatives
1959  Shape psi(9);
1960  DShape dpsi(9,2);
1961  dshape_local(s,psi,dpsi);
1962 
1963  //Allocate memory for the inverse 2x2 jacobian
1964  DenseMatrix<double> inverse_jacobian(2);
1965 
1966  //Now calculate the inverse jacobian
1967  const double det = local_to_eulerian_mapping(dpsi,inverse_jacobian);
1968 
1969  //Now set the values of the derivatives to be derivs w.r.t. to the
1970  // Eulerian coordinates
1971  transform_derivatives(inverse_jacobian,dppsidx);
1972 
1973  //The test functions are equal to the shape functions
1974  ptest = ppsi;
1975  dptestdx = dppsidx;
1976 
1977  //Return the determinant of the jacobian
1978  return det;
1979 
1980  }
1981 
1982 
1983 //=======================================================================
1984 /// Ppressure shape and test functions
1985 //=======================================================================
1986 template<unsigned DIM>
1987  inline void QCrouzeixRaviartElement<DIM>::
1989  Shape &psi,
1990  Shape &test) const
1991 {
1992  //Call the pressure shape functions
1993  this->pshape_nst(s,psi);
1994  //Test functions are equal to shape functions
1995  test = psi;
1996 }
1997 
1998 
1999 //=======================================================================
2000 /// 3D :
2001 /// Pressure shape functions
2002 //=======================================================================
2003 template<>
2005  Shape &psi)
2006 const
2007 {
2008  psi[0] = 1.0;
2009  psi[1] = s[0];
2010  psi[2] = s[1];
2011  psi[3] = s[2];
2012 }
2013 
2014 
2015 //==========================================================================
2016 /// 3D :
2017 /// Pressure shape and test functions and derivs w.r.t. to Eulerian coords.
2018 /// Return Jacobian of mapping between local and global coordinates.
2019 //==========================================================================
2020 template<>
2022  const Vector<double> &s,
2023  Shape &ppsi,
2024  DShape &dppsidx,
2025  Shape &ptest,
2026  DShape &dptestdx) const
2027  {
2028 
2029  // Initalise with shape fcts and derivs. w.r.t. to local coordinates
2030  ppsi[0] = 1.0;
2031  ppsi[1] = s[0];
2032  ppsi[2] = s[1];
2033  ppsi[3] = s[2];
2034 
2035  dppsidx(0,0) = 0.0;
2036  dppsidx(1,0) = 1.0;
2037  dppsidx(2,0) = 0.0;
2038  dppsidx(3,0) = 0.0;
2039 
2040  dppsidx(0,1) = 0.0;
2041  dppsidx(1,1) = 0.0;
2042  dppsidx(2,1) = 1.0;
2043  dppsidx(3,1) = 0.0;
2044 
2045  dppsidx(0,2) = 0.0;
2046  dppsidx(1,2) = 0.0;
2047  dppsidx(2,2) = 0.0;
2048  dppsidx(3,2) = 1.0;
2049 
2050 
2051  //Get the values of the shape functions and their local derivatives
2052  Shape psi(27);
2053  DShape dpsi(27,3);
2054  dshape_local(s,psi,dpsi);
2055 
2056  // Allocate memory for the inverse 3x3 jacobian
2057  DenseMatrix<double> inverse_jacobian(3);
2058 
2059  // Now calculate the inverse jacobian
2060  const double det = local_to_eulerian_mapping(dpsi,inverse_jacobian);
2061 
2062  // Now set the values of the derivatives to be derivs w.r.t. to the
2063  // Eulerian coordinates
2064  transform_derivatives(inverse_jacobian,dppsidx);
2065 
2066  //The test functions are equal to the shape functions
2067  ptest = ppsi;
2068  dptestdx = dppsidx;
2069 
2070  // Return the determinant of the jacobian
2071  return det;
2072 
2073  }
2074 
2075 
2076 //=======================================================================
2077 /// Face geometry of the 2D Crouzeix_Raviart elements
2078 //=======================================================================
2079 template<>
2080 class FaceGeometry<QCrouzeixRaviartElement<2> >: public virtual QElement<1,3>
2081 {
2082  public:
2083  FaceGeometry() : QElement<1,3>() {}
2084 };
2085 
2086 //=======================================================================
2087 /// Face geometry of the 3D Crouzeix_Raviart elements
2088 //=======================================================================
2089 template<>
2090 class FaceGeometry<QCrouzeixRaviartElement<3> >: public virtual QElement<2,3>
2091 {
2092 
2093  public:
2094  FaceGeometry() : QElement<2,3>() {}
2095 };
2096 
2097 //=======================================================================
2098 /// Face geometry of the FaceGeometry of the 2D Crouzeix_Raviart elements
2099 //=======================================================================
2100 template<>
2102 public virtual PointElement
2103 {
2104  public:
2106 };
2107 
2108 
2109 //=======================================================================
2110 /// Face geometry of the FaceGeometry of the 3D Crouzeix_Raviart elements
2111 //=======================================================================
2112 template<>
2114 public virtual QElement<1,3>
2115 {
2116  public:
2117  FaceGeometry() : QElement<1,3>() {}
2118 };
2119 
2120 
2121 
2122 ////////////////////////////////////////////////////////////////////////////
2123 ////////////////////////////////////////////////////////////////////////////
2124 
2125 
2126 //=======================================================================
2127 /// Taylor--Hood elements are Navier--Stokes elements
2128 /// with quadratic interpolation for velocities and positions and
2129 /// continuous linear pressure interpolation. They can be used
2130 /// within oomph-lib's block-preconditioning framework.
2131 //=======================================================================
2132 template <unsigned DIM>
2133 class QTaylorHoodElement : public virtual QElement<DIM,3>,
2134  public virtual NavierStokesEquations<DIM>
2135 {
2136  private:
2137 
2138  /// Static array of ints to hold number of variables at node
2139  static const unsigned Initial_Nvalue[];
2140 
2141  protected:
2142 
2143  /// \short Static array of ints to hold conversion from pressure
2144  /// node numbers to actual node numbers
2145  static const unsigned Pconv[];
2146 
2147  /// \short Velocity shape and test functions and their derivs
2148  /// w.r.t. to global coords at local coordinate s (taken from geometry)
2149  /// Return Jacobian of mapping between local and global coordinates.
2150  inline double dshape_and_dtest_eulerian_nst(const Vector<double> &s,
2151  Shape &psi,
2152  DShape &dpsidx, Shape &test,
2153  DShape &dtestdx) const;
2154 
2155  /// \short Velocity shape and test functions and their derivs
2156  /// w.r.t. to global coords at local coordinate s (taken from geometry)
2157  /// Return Jacobian of mapping between local and global coordinates.
2158  inline double dshape_and_dtest_eulerian_at_knot_nst(const unsigned &ipt,
2159  Shape &psi,
2160  DShape &dpsidx,
2161  Shape &test,
2162  DShape &dtestdx) const;
2163 
2164  /// \short Shape/test functions and derivs w.r.t. to global coords at
2165  /// integration point ipt; return Jacobian of mapping (J). Also compute
2166  /// derivatives of dpsidx, dtestdx and J w.r.t. nodal coordinates.
2167  inline double dshape_and_dtest_eulerian_at_knot_nst(
2168  const unsigned &ipt,
2169  Shape &psi,
2170  DShape &dpsidx,
2171  RankFourTensor<double> &d_dpsidx_dX,
2172  Shape &test,
2173  DShape &dtestdx,
2174  RankFourTensor<double> &d_dtestdx_dX,
2175  DenseMatrix<double> &djacobian_dX) const;
2176 
2177  public:
2178 
2179  /// Constructor, no internal data points
2181 
2182  /// \short Number of values (pinned or dofs) required at node n. Can
2183  /// be overwritten for hanging node version
2184  inline virtual unsigned required_nvalue(const unsigned &n) const
2185  {return Initial_Nvalue[n];}
2186 
2187 
2188  /// Pressure shape functions at local coordinate s
2189  inline void pshape_nst(const Vector<double> &s, Shape &psi) const;
2190 
2191  /// Pressure shape and test functions at local coordinte s
2192  inline void pshape_nst(const Vector<double> &s, Shape &psi,
2193  Shape &test) const;
2194 
2195  /// \short Set the value at which the pressure is stored in the nodes
2196  virtual int p_nodal_index_nst() const {return static_cast<int>(DIM);}
2197 
2198  /// Return the local equation numbers for the pressure values.
2199  inline int p_local_eqn(const unsigned &n) const
2200  {return this->nodal_local_eqn(Pconv[n],p_nodal_index_nst());}
2201 
2202  /// \short Access function for the pressure values at local pressure
2203  /// node n_p (const version)
2204  double p_nst(const unsigned &n_p) const
2205  {return this->nodal_value(Pconv[n_p],this->p_nodal_index_nst());}
2206 
2207  /// \short Access function for the pressure values at local pressure
2208  /// node n_p (const version)
2209  double p_nst(const unsigned &t, const unsigned &n_p) const
2210  {return this->nodal_value(t,Pconv[n_p],this->p_nodal_index_nst());}
2211 
2212  /// \short Pressure shape and test functions and their derivs
2213  /// w.r.t. to global coords at local coordinate s (taken from geometry).
2214  /// Return Jacobian of mapping between local and global coordinates.
2215  inline double dpshape_and_dptest_eulerian_nst(const Vector<double> &s,
2216  Shape &ppsi,
2217  DShape &dppsidx,
2218  Shape &ptest,
2219  DShape &dptestdx) const;
2220 
2221  /// Return number of pressure values
2222  unsigned npres_nst() const
2223  {return static_cast<unsigned>(pow(2.0,static_cast<int>(DIM)));}
2224 
2225  /// Pin p_dof-th pressure dof and set it to value specified by p_value.
2226  void fix_pressure(const unsigned &p_dof, const double &p_value)
2227  {
2228  this->node_pt(Pconv[p_dof])->pin(this->p_nodal_index_nst());
2229  this->node_pt(Pconv[p_dof])->set_value(this->p_nodal_index_nst(),p_value);
2230  }
2231 
2232 
2233 
2234  /// \short Build FaceElements that apply the Robin boundary condition
2235  /// to the pressure advection diffusion problem required by
2236  /// Fp preconditioner
2238  face_index)
2239  {
2240  this->Pressure_advection_diffusion_robin_element_pt.push_back(
2242  this, face_index));
2243  }
2244 
2245 
2246  /// \short Add to the set \c paired_load_data pairs containing
2247  /// - the pointer to a Data object
2248  /// and
2249  /// - the index of the value in that Data object
2250  /// .
2251  /// for all values (pressures, velocities) that affect the
2252  /// load computed in the \c get_load(...) function.
2253  void identify_load_data(
2254  std::set<std::pair<Data*,unsigned> > &paired_load_data);
2255 
2256 
2257  /// \short Add to the set \c paired_pressure_data pairs
2258  /// containing
2259  /// - the pointer to a Data object
2260  /// and
2261  /// - the index of the value in that Data object
2262  /// .
2263  /// for all pressure values that affect the
2264  /// load computed in the \c get_load(...) function.
2265  void identify_pressure_data(
2266  std::set<std::pair<Data*,unsigned> > &paired_pressure_data);
2267 
2268 
2269  /// Redirect output to NavierStokesEquations output
2270  void output(std::ostream &outfile)
2272 
2273  /// Redirect output to NavierStokesEquations output
2274  void output(std::ostream &outfile, const unsigned &nplot)
2275  {NavierStokesEquations<DIM>::output(outfile,nplot);}
2276 
2277  /// Redirect output to NavierStokesEquations output
2278  void output(FILE* file_pt) {NavierStokesEquations<DIM>::output(file_pt);}
2279 
2280  /// Redirect output to NavierStokesEquations output
2281  void output(FILE* file_pt, const unsigned &nplot)
2282  {NavierStokesEquations<DIM>::output(file_pt,nplot);}
2283 
2284 
2285  /// \short Returns the number of "DOF types" that degrees of freedom
2286  /// in this element are sub-divided into: Velocity and pressure.
2287  unsigned ndof_types() const
2288  {
2289  return DIM+1;
2290  }
2291 
2292  /// \short Create a list of pairs for all unknowns in this element,
2293  /// so that the first entry in each pair contains the global equation
2294  /// number of the unknown, while the second one contains the number
2295  /// of the "DOF type" that this unknown is associated with.
2296  /// (Function can obviously only be called if the equation numbering
2297  /// scheme has been set up.) Velocity=0; Pressure=1
2299  std::list<std::pair<unsigned long, unsigned> >& dof_lookup_list) const;
2300 
2301 
2302 };
2303 
2304 //Inline functions
2305 
2306 //==========================================================================
2307 /// Derivatives of the shape functions and test functions w.r.t to
2308 /// global (Eulerian) coordinates. Return Jacobian of mapping between
2309 /// local and global coordinates.
2310 //==========================================================================
2311 template<unsigned DIM>
2313  const Vector<double> &s,
2314  Shape &psi,
2315  DShape &dpsidx, Shape &test,
2316  DShape &dtestdx) const
2317 {
2318  //Call the geometrical shape functions and derivatives
2319  double J = this->dshape_eulerian(s,psi,dpsidx);
2320 
2321  //The test functions are equal to the shape functions
2322  test = psi;
2323  dtestdx = dpsidx;
2324 
2325  //Return the jacobian
2326  return J;
2327 }
2328 
2329 
2330 //==========================================================================
2331 /// Derivatives of the shape functions and test functions w.r.t to
2332 /// global (Eulerian) coordinates. Return Jacobian of mapping between
2333 /// local and global coordinates.
2334 //==========================================================================
2335 template<unsigned DIM>
2337  const unsigned &ipt,Shape &psi, DShape &dpsidx, Shape &test,
2338  DShape &dtestdx) const
2339 {
2340  //Call the geometrical shape functions and derivatives
2341  double J = this->dshape_eulerian_at_knot(ipt,psi,dpsidx);
2342 
2343  //The test functions are equal to the shape functions
2344  test = psi;
2345  dtestdx = dpsidx;
2346 
2347  //Return the jacobian
2348  return J;
2349 }
2350 
2351 
2352 //==========================================================================
2353 /// 2D :
2354 /// Pressure shape and test functions and derivs w.r.t. to Eulerian coords.
2355 /// Return Jacobian of mapping between local and global coordinates.
2356 //==========================================================================
2357 template<>
2359  const Vector<double> &s,
2360  Shape &ppsi,
2361  DShape &dppsidx,
2362  Shape &ptest,
2363  DShape &dptestdx) const
2364  {
2365 
2366  //Local storage
2367  double psi1[2], psi2[2];
2368  double dpsi1[2],dpsi2[2];
2369 
2370  //Call the OneDimensional Shape functions
2371  OneDimLagrange::shape<2>(s[0],psi1);
2372  OneDimLagrange::shape<2>(s[1],psi2);
2373  OneDimLagrange::dshape<2>(s[0],dpsi1);
2374  OneDimLagrange::dshape<2>(s[1],dpsi2);
2375 
2376  //Now let's loop over the nodal points in the element
2377  //s1 is the "x" coordinate, s2 the "y"
2378  for(unsigned i=0;i<2;i++)
2379  {
2380  for(unsigned j=0;j<2;j++)
2381  {
2382  /*Multiply the two 1D functions together to get the 2D function*/
2383  ppsi[2*i+j] = psi2[i]*psi1[j];
2384  dppsidx(2*i+j,0)= psi2[i]*dpsi1[j];
2385  dppsidx(2*i+j,1)=dpsi2[i]* psi1[j];
2386  }
2387  }
2388 
2389 
2390  //Get the values of the shape functions and their local derivatives
2391  Shape psi(9);
2392  DShape dpsi(9,2);
2393  dshape_local(s,psi,dpsi);
2394 
2395  // Allocate memory for the inverse 2x2 jacobian
2396  DenseMatrix<double> inverse_jacobian(2);
2397 
2398  // Now calculate the inverse jacobian
2399  const double det = local_to_eulerian_mapping(dpsi,inverse_jacobian);
2400 
2401  // Now set the values of the derivatives to be derivs w.r.t. to the
2402  // Eulerian coordinates
2403  transform_derivatives(inverse_jacobian,dppsidx);
2404 
2405  //The test functions are equal to the shape functions
2406  ptest = ppsi;
2407  dptestdx = dppsidx;
2408 
2409  // Return the determinant of the jacobian
2410  return det;
2411 
2412  }
2413 
2414 
2415 
2416 //==========================================================================
2417 /// 2D :
2418 /// Define the shape functions (psi) and test functions (test) and
2419 /// their derivatives w.r.t. global coordinates (dpsidx and dtestdx)
2420 /// and return Jacobian of mapping (J). Additionally compute the
2421 /// derivatives of dpsidx, dtestdx and J w.r.t. nodal coordinates.
2422 ///
2423 /// Galerkin: Test functions = shape functions
2424 //==========================================================================
2425 template<>
2426 inline double QTaylorHoodElement<2>::
2428  const unsigned &ipt, Shape &psi, DShape &dpsidx,
2429  RankFourTensor<double> &d_dpsidx_dX,
2430  Shape &test, DShape &dtestdx,
2431  RankFourTensor<double> &d_dtestdx_dX,
2432  DenseMatrix<double> &djacobian_dX) const
2433  {
2434  // Call the geometrical shape functions and derivatives
2435  const double J = this->dshape_eulerian_at_knot(ipt,psi,dpsidx,
2436  djacobian_dX,
2437  d_dpsidx_dX);
2438 
2439  // Loop over the test functions and derivatives and set them equal to the
2440  // shape functions
2441  for(unsigned i=0;i<9;i++)
2442  {
2443  test[i] = psi[i];
2444 
2445  for(unsigned k=0;k<2;k++)
2446  {
2447  dtestdx(i,k) = dpsidx(i,k);
2448 
2449  for(unsigned p=0;p<2;p++)
2450  {
2451  for(unsigned q=0;q<9;q++)
2452  {
2453  d_dtestdx_dX(p,q,i,k) = d_dpsidx_dX(p,q,i,k);
2454  }
2455  }
2456  }
2457  }
2458 
2459  // Return the jacobian
2460  return J;
2461  }
2462 
2463 
2464 //==========================================================================
2465 /// 3D :
2466 /// Define the shape functions (psi) and test functions (test) and
2467 /// their derivatives w.r.t. global coordinates (dpsidx and dtestdx)
2468 /// and return Jacobian of mapping (J). Additionally compute the
2469 /// derivatives of dpsidx, dtestdx and J w.r.t. nodal coordinates.
2470 ///
2471 /// Galerkin: Test functions = shape functions
2472 //==========================================================================
2473 template<>
2474  inline double QTaylorHoodElement<3>::
2476  const unsigned &ipt, Shape &psi, DShape &dpsidx,
2477  RankFourTensor<double> &d_dpsidx_dX,
2478  Shape &test, DShape &dtestdx,
2479  RankFourTensor<double> &d_dtestdx_dX,
2480  DenseMatrix<double> &djacobian_dX) const
2481  {
2482  // Call the geometrical shape functions and derivatives
2483  const double J = this->dshape_eulerian_at_knot(ipt,psi,dpsidx,
2484  djacobian_dX,
2485  d_dpsidx_dX);
2486 
2487  // Loop over the test functions and derivatives and set them equal to the
2488  // shape functions
2489  for(unsigned i=0;i<27;i++)
2490  {
2491  test[i] = psi[i];
2492 
2493  for(unsigned k=0;k<3;k++)
2494  {
2495  dtestdx(i,k) = dpsidx(i,k);
2496 
2497  for(unsigned p=0;p<3;p++)
2498  {
2499  for(unsigned q=0;q<27;q++)
2500  {
2501  d_dtestdx_dX(p,q,i,k) = d_dpsidx_dX(p,q,i,k);
2502  }
2503  }
2504  }
2505  }
2506 
2507  // Return the jacobian
2508  return J;
2509  }
2510 
2511 
2512 
2513 //==========================================================================
2514 /// 2D :
2515 /// Pressure shape functions
2516 //==========================================================================
2517 template<>
2519  Shape &psi)
2520 const
2521 {
2522  //Local storage
2523  double psi1[2], psi2[2];
2524  //Call the OneDimensional Shape functions
2525  OneDimLagrange::shape<2>(s[0],psi1);
2526  OneDimLagrange::shape<2>(s[1],psi2);
2527 
2528  //Now let's loop over the nodal points in the element
2529  //s1 is the "x" coordinate, s2 the "y"
2530  for(unsigned i=0;i<2;i++)
2531  {
2532  for(unsigned j=0;j<2;j++)
2533  {
2534  /*Multiply the two 1D functions together to get the 2D function*/
2535  psi[2*i + j] = psi2[i]*psi1[j];
2536  }
2537  }
2538 }
2539 
2540 
2541 //==========================================================================
2542 /// 3D :
2543 /// Pressure shape and test functions and derivs w.r.t. to Eulerian coords.
2544 /// Return Jacobian of mapping between local and global coordinates.
2545 //==========================================================================
2546 template<>
2548  const Vector<double> &s,
2549  Shape &ppsi,
2550  DShape &dppsidx,
2551  Shape &ptest,
2552  DShape &dptestdx) const
2553  {
2554  //Local storage
2555  double psi1[2], psi2[2], psi3[2];
2556  double dpsi1[2],dpsi2[2],dpsi3[2];
2557 
2558  //Call the OneDimensional Shape functions
2559  OneDimLagrange::shape<2>(s[0],psi1);
2560  OneDimLagrange::shape<2>(s[1],psi2);
2561  OneDimLagrange::shape<2>(s[2],psi3);
2562  OneDimLagrange::dshape<2>(s[0],dpsi1);
2563  OneDimLagrange::dshape<2>(s[1],dpsi2);
2564  OneDimLagrange::dshape<2>(s[2],dpsi3);
2565 
2566  //Now let's loop over the nodal points in the element
2567  //s0 is the "x" coordinate, s1 the "y", s2 is the "z"
2568  for(unsigned i=0;i<2;i++)
2569  {
2570  for(unsigned j=0;j<2;j++)
2571  {
2572  for(unsigned k=0;k<2;k++)
2573  {
2574  /*Multiply the three 1D functions together to get the 3D function*/
2575  ppsi[4*i + 2*j + k] = psi3[i]*psi2[j]*psi1[k];
2576  dppsidx(4*i + 2*j + k,0) = psi3[i] * psi2[j] *dpsi1[k];
2577  dppsidx(4*i + 2*j + k,1) = psi3[i] *dpsi2[j] * psi1[k];
2578  dppsidx(4*i + 2*j + k,2) = dpsi3[i] * psi2[j] * psi1[k];
2579  }
2580  }
2581  }
2582 
2583 
2584  //Get the values of the shape functions and their local derivatives
2585  Shape psi(27);
2586  DShape dpsi(27,3);
2587  dshape_local(s,psi,dpsi);
2588 
2589  // Allocate memory for the inverse 3x3 jacobian
2590  DenseMatrix<double> inverse_jacobian(3);
2591 
2592  // Now calculate the inverse jacobian
2593  const double det = local_to_eulerian_mapping(dpsi,inverse_jacobian);
2594 
2595  // Now set the values of the derivatives to be derivs w.r.t. to the
2596  // Eulerian coordinates
2597  transform_derivatives(inverse_jacobian,dppsidx);
2598 
2599  //The test functions are equal to the shape functions
2600  ptest = ppsi;
2601  dptestdx = dppsidx;
2602 
2603  // Return the determinant of the jacobian
2604  return det;
2605 
2606 }
2607 
2608 //==========================================================================
2609 /// 3D :
2610 /// Pressure shape functions
2611 //==========================================================================
2612 template<>
2614  Shape &psi)
2615 const
2616 {
2617  //Local storage
2618  double psi1[2], psi2[2], psi3[2];
2619 
2620  //Call the OneDimensional Shape functions
2621  OneDimLagrange::shape<2>(s[0],psi1);
2622  OneDimLagrange::shape<2>(s[1],psi2);
2623  OneDimLagrange::shape<2>(s[2],psi3);
2624 
2625  //Now let's loop over the nodal points in the element
2626  //s0 is the "x" coordinate, s1 the "y", s2 is the "z"
2627  for(unsigned i=0;i<2;i++)
2628  {
2629  for(unsigned j=0;j<2;j++)
2630  {
2631  for(unsigned k=0;k<2;k++)
2632  {
2633  /*Multiply the three 1D functions together to get the 3D function*/
2634  psi[4*i + 2*j + k] = psi3[i]*psi2[j]*psi1[k];
2635  }
2636  }
2637  }
2638 }
2639 
2640 
2641 //==========================================================================
2642 /// Pressure shape and test functions
2643 //==========================================================================
2644 template<unsigned DIM>
2646  Shape &psi,
2647  Shape &test) const
2648 {
2649  //Call the pressure shape functions
2650  this->pshape_nst(s,psi);
2651  //Test functions are shape functions
2652  test = psi;
2653 }
2654 
2655 
2656 //=======================================================================
2657 /// Face geometry of the 2D Taylor_Hood elements
2658 //=======================================================================
2659 template<>
2660 class FaceGeometry<QTaylorHoodElement<2> >: public virtual QElement<1,3>
2661 {
2662  public:
2663  FaceGeometry() : QElement<1,3>() {}
2664 };
2665 
2666 //=======================================================================
2667 /// Face geometry of the 3D Taylor_Hood elements
2668 //=======================================================================
2669 template<>
2670 class FaceGeometry<QTaylorHoodElement<3> >: public virtual QElement<2,3>
2671 {
2672 
2673  public:
2674  FaceGeometry() : QElement<2,3>() {}
2675 };
2676 
2677 
2678 //=======================================================================
2679 /// Face geometry of the FaceGeometry of the 2D Taylor Hoodelements
2680 //=======================================================================
2681 template<>
2683 public virtual PointElement
2684 {
2685  public:
2687 };
2688 
2689 
2690 //=======================================================================
2691 /// Face geometry of the FaceGeometry of the 3D Taylor_Hood elements
2692 //=======================================================================
2693 template<>
2695 public virtual QElement<1,3>
2696 {
2697  public:
2698  FaceGeometry() : QElement<1,3>() {}
2699 };
2700 
2701 
2702 
2703 
2704 
2705 
2706 
2707 ////////////////////////////////////////////////////////////////////
2708 ////////////////////////////////////////////////////////////////////
2709 ////////////////////////////////////////////////////////////////////
2710 
2711 
2712 //==========================================================
2713 /// Taylor Hood upgraded to become projectable
2714 //==========================================================
2715  template<class TAYLOR_HOOD_ELEMENT>
2717  public virtual ProjectableElement<TAYLOR_HOOD_ELEMENT>
2718  {
2719 
2720  public:
2721 
2722  /// \short Constructor [this was only required explicitly
2723  /// from gcc 4.5.2 onwards...]
2725 
2726 
2727  /// \short Specify the values associated with field fld.
2728  /// The information is returned in a vector of pairs which comprise
2729  /// the Data object and the value within it, that correspond to field fld.
2730  /// In the underlying Taylor Hood elements the fld-th velocities are stored
2731  /// at the fld-th value of the nodes; the pressures (the dim-th
2732  /// field) are the dim-th values at the vertex nodes etc.
2734  {
2735  // Create the vector
2736  Vector<std::pair<Data*,unsigned> > data_values;
2737 
2738  // Velocities dofs
2739  if (fld<this->dim())
2740  {
2741  // Loop over all nodes
2742  unsigned nnod=this->nnode();
2743  for (unsigned j=0;j<nnod;j++)
2744  {
2745  // Add the data value associated with the velocity components
2746  data_values.push_back(std::make_pair(this->node_pt(j),fld));
2747  }
2748  }
2749  // Pressure
2750  else
2751  {
2752  // Loop over all vertex nodes
2753  unsigned Pconv_size=this->dim()+1;
2754  for (unsigned j=0;j<Pconv_size;j++)
2755  {
2756  // Add the data value associated with the pressure components
2757  unsigned vertex_index=this->Pconv[j];
2758  data_values.push_back(std::make_pair(this->node_pt(vertex_index),fld));
2759  }
2760  }
2761 
2762  // Return the vector
2763  return data_values;
2764 
2765  }
2766 
2767  /// \short Number of fields to be projected: dim+1, corresponding to
2768  /// velocity components and pressure
2770  {
2771  return this->dim()+1;
2772  }
2773 
2774  /// \short Number of history values to be stored for fld-th field. Whatever
2775  /// the timestepper has set up for the velocity components and
2776  /// none for the pressure field.
2777  /// (Note: count includes current value!)
2778  unsigned nhistory_values_for_projection(const unsigned &fld)
2779  {
2780  if (fld==this->dim())
2781  {
2782  //pressure doesn't have history values
2783  return this->node_pt(0)->ntstorage();//1;
2784  }
2785  else
2786  {
2787  return this->node_pt(0)->ntstorage();
2788  }
2789  }
2790 
2791  /// \short Number of positional history values
2792  /// (Note: count includes current value!)
2794  {
2795  return this->node_pt(0)->position_time_stepper_pt()->ntstorage();
2796  }
2797 
2798  /// \short Return Jacobian of mapping and shape functions of field fld
2799  /// at local coordinate s
2800  double jacobian_and_shape_of_field(const unsigned &fld,
2801  const Vector<double> &s,
2802  Shape &psi)
2803  {
2804  unsigned n_dim=this->dim();
2805  unsigned n_node=this->nnode();
2806 
2807  if (fld==n_dim)
2808  {
2809  //We are dealing with the pressure
2810  this->pshape_nst(s,psi);
2811 
2812  Shape psif(n_node),testf(n_node);
2813  DShape dpsifdx(n_node,n_dim), dtestfdx(n_node,n_dim);
2814 
2815  //Domain Shape
2816  double J=this->dshape_and_dtest_eulerian_nst(s,psif,dpsifdx,
2817  testf,dtestfdx);
2818  return J;
2819  }
2820  else
2821  {
2822  Shape testf(n_node);
2823  DShape dpsifdx(n_node,n_dim), dtestfdx(n_node,n_dim);
2824 
2825  //Domain Shape
2826  double J=this->dshape_and_dtest_eulerian_nst(s,psi,dpsifdx,
2827  testf,dtestfdx);
2828  return J;
2829  }
2830  }
2831 
2832 
2833 
2834  /// \short Return interpolated field fld at local coordinate s, at time level
2835  /// t (t=0: present; t>0: history values)
2836  double get_field(const unsigned &t,
2837  const unsigned &fld,
2838  const Vector<double>& s)
2839  {
2840  unsigned n_dim =this->dim();
2841  unsigned n_node=this->nnode();
2842 
2843  //If fld=n_dim, we deal with the pressure
2844  if (fld==n_dim)
2845  {
2846  return this->interpolated_p_nst(t,s);
2847  }
2848  // Velocity
2849  else
2850  {
2851  //Find the index at which the variable is stored
2852  unsigned u_nodal_index = this->u_index_nst(fld);
2853 
2854  //Local shape function
2855  Shape psi(n_node);
2856 
2857  //Find values of shape function
2858  this->shape(s,psi);
2859 
2860  //Initialise value of u
2861  double interpolated_u = 0.0;
2862 
2863  //Sum over the local nodes at that time
2864  for(unsigned l=0;l<n_node;l++)
2865  {
2866  interpolated_u += this->nodal_value(t,l,u_nodal_index)*psi[l];
2867  }
2868  return interpolated_u;
2869  }
2870  }
2871 
2872 
2873 
2874  ///Return number of values in field fld
2875  unsigned nvalue_of_field(const unsigned &fld)
2876  {
2877  if (fld==this->dim())
2878  {
2879  return this->npres_nst();
2880  }
2881  else
2882  {
2883  return this->nnode();
2884  }
2885  }
2886 
2887 
2888  ///Return local equation number of value j in field fld.
2889  int local_equation(const unsigned &fld,
2890  const unsigned &j)
2891  {
2892  if (fld==this->dim())
2893  {
2894  return this->p_local_eqn(j);
2895  }
2896  else
2897  {
2898  const unsigned u_nodal_index = this->u_index_nst(fld);
2899  return this->nodal_local_eqn(j,u_nodal_index);
2900  }
2901  }
2902 
2903  };
2904 
2905 
2906 //=======================================================================
2907 /// Face geometry for element is the same as that for the underlying
2908 /// wrapped element
2909 //=======================================================================
2910  template<class ELEMENT>
2912  : public virtual FaceGeometry<ELEMENT>
2913  {
2914  public:
2915  FaceGeometry() : FaceGeometry<ELEMENT>() {}
2916  };
2917 
2918 
2919 //=======================================================================
2920 /// Face geometry of the Face Geometry for element is the same as
2921 /// that for the underlying wrapped element
2922 //=======================================================================
2923  template<class ELEMENT>
2925  : public virtual FaceGeometry<FaceGeometry<ELEMENT> >
2926  {
2927  public:
2929  };
2930 
2931 
2932 //==========================================================
2933 /// Crouzeix Raviart upgraded to become projectable
2934 //==========================================================
2935  template<class CROUZEIX_RAVIART_ELEMENT>
2937  public virtual ProjectableElement<CROUZEIX_RAVIART_ELEMENT>
2938  {
2939 
2940  public:
2941 
2942  /// \short Constructor [this was only required explicitly
2943  /// from gcc 4.5.2 onwards...]
2945 
2946  /// \short Specify the values associated with field fld.
2947  /// The information is returned in a vector of pairs which comprise
2948  /// the Data object and the value within it, that correspond to field fld.
2949  /// In the underlying Crouzeix Raviart elements the
2950  /// fld-th velocities are stored
2951  /// at the fld-th value of the nodes; the pressures are stored internally
2953  {
2954  // Create the vector
2955  Vector<std::pair<Data*,unsigned> > data_values;
2956 
2957  // Velocities dofs
2958  if (fld < this->dim())
2959  {
2960  // Loop over all nodes
2961  const unsigned n_node=this->nnode();
2962  for (unsigned n=0;n<n_node;n++)
2963  {
2964  // Add the data value associated with the velocity components
2965  data_values.push_back(std::make_pair(this->node_pt(n),fld));
2966  }
2967  }
2968  // Pressure
2969  else
2970  {
2971  //Need to push back the internal data
2972  const unsigned n_press = this->npres_nst();
2973  //Loop over all pressure values
2974  for(unsigned j=0;j<n_press;j++)
2975  {
2976  data_values.push_back(
2977  std::make_pair(
2978  this->internal_data_pt(this->P_nst_internal_index),j));
2979  }
2980  }
2981 
2982  // Return the vector
2983  return data_values;
2984  }
2985 
2986  /// \short Number of fields to be projected: dim+1, corresponding to
2987  /// velocity components and pressure
2989  {
2990  return this->dim()+1;
2991  }
2992 
2993  /// \short Number of history values to be stored for fld-th field. Whatever
2994  /// the timestepper has set up for the velocity components and
2995  /// none for the pressure field.
2996  /// (Note: count includes current value!)
2997  unsigned nhistory_values_for_projection(const unsigned &fld)
2998  {
2999  if (fld==this->dim())
3000  {
3001  //pressure doesn't have history values
3002  return 1;
3003  }
3004  else
3005  {
3006  return this->node_pt(0)->ntstorage();
3007  }
3008  }
3009 
3010  ///\short Number of positional history values.
3011  /// (Note: count includes current value!)
3013  {
3014  return this->node_pt(0)->position_time_stepper_pt()->ntstorage();
3015  }
3016 
3017  /// \short Return Jacobian of mapping and shape functions of field fld
3018  /// at local coordinate s
3019  double jacobian_and_shape_of_field(const unsigned &fld,
3020  const Vector<double> &s,
3021  Shape &psi)
3022  {
3023  unsigned n_dim=this->dim();
3024  unsigned n_node=this->nnode();
3025 
3026  if (fld==n_dim)
3027  {
3028  //We are dealing with the pressure
3029  this->pshape_nst(s,psi);
3030 
3031  Shape psif(n_node),testf(n_node);
3032  DShape dpsifdx(n_node,n_dim), dtestfdx(n_node,n_dim);
3033 
3034  //Domain Shape
3035  double J=this->dshape_and_dtest_eulerian_nst(s,psif,dpsifdx,
3036  testf,dtestfdx);
3037  return J;
3038  }
3039  else
3040  {
3041  Shape testf(n_node);
3042  DShape dpsifdx(n_node,n_dim), dtestfdx(n_node,n_dim);
3043 
3044  //Domain Shape
3045  double J=this->dshape_and_dtest_eulerian_nst(s,psi,dpsifdx,
3046  testf,dtestfdx);
3047  return J;
3048  }
3049  }
3050 
3051 
3052 
3053  /// \short Return interpolated field fld at local coordinate s, at time level
3054  /// t (t=0: present; t>0: history values)
3055  double get_field(const unsigned &t,
3056  const unsigned &fld,
3057  const Vector<double>& s)
3058  {
3059  unsigned n_dim =this->dim();
3060 
3061  //If fld=n_dim, we deal with the pressure
3062  if (fld==n_dim)
3063  {
3064  return this->interpolated_p_nst(s);
3065  }
3066  // Velocity
3067  else
3068  {
3069  return this->interpolated_u_nst(t,s,fld);
3070  }
3071  }
3072 
3073 
3074  ///Return number of values in field fld
3075  unsigned nvalue_of_field(const unsigned &fld)
3076  {
3077  if (fld==this->dim())
3078  {
3079  return this->npres_nst();
3080  }
3081  else
3082  {
3083  return this->nnode();
3084  }
3085  }
3086 
3087 
3088  ///Return local equation number of value j in field fld.
3089  int local_equation(const unsigned &fld,
3090  const unsigned &j)
3091  {
3092  if (fld==this->dim())
3093  {
3094  return this->p_local_eqn(j);
3095  }
3096  else
3097  {
3098  const unsigned u_nodal_index = this->u_index_nst(fld);
3099  return this->nodal_local_eqn(j,u_nodal_index);
3100  }
3101  }
3102 
3103  };
3104 
3105 
3106 //=======================================================================
3107 /// Face geometry for element is the same as that for the underlying
3108 /// wrapped element
3109 //=======================================================================
3110  template<class ELEMENT>
3112  : public virtual FaceGeometry<ELEMENT>
3113  {
3114  public:
3115  FaceGeometry() : FaceGeometry<ELEMENT>() {}
3116  };
3117 
3118 
3119 //=======================================================================
3120 /// Face geometry of the Face Geometry for element is the same as
3121 /// that for the underlying wrapped element
3122 //=======================================================================
3123  template<class ELEMENT>
3125  : public virtual FaceGeometry<FaceGeometry<ELEMENT> >
3126  {
3127  public:
3129  };
3130 
3131 
3132 }
3133 
3134 #endif
double interpolated_p_nst(const unsigned &t, const Vector< double > &s) const
Return FE interpolated pressure at local coordinate s at time level t.
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
void output_pressure_advection_diffusion_robin_elements(std::ostream &outfile)
Output the FaceElements that apply the Robin boundary condition to the pressure advection diffusion p...
bool has_hanging_nodes() const
Return boolean to indicate if any of the element&#39;s nodes are geometrically hanging.
Definition: elements.h:2356
NavierStokesBodyForceFctPt body_force_fct_pt() const
Access function for the body-force pointer. Const version.
int local_equation(const unsigned &fld, const unsigned &j)
Return local equation number of value j in field fld.
GeneralisedAxisymAdvectionDiffusionSourceFctPt Source_fct_pt
Pointer to source function:
double get_field(const unsigned &t, const unsigned &fld, const Vector< double > &s)
Return interpolated field fld at local coordinate s, at time level t (t=0: present; t>0: history valu...
int p_local_eqn(const unsigned &n) const
Return the local equation numbers for the pressure values.
FpPressureAdvDiffRobinBCElement(FiniteElement *const &element_pt, const int &face_index, const bool &called_from_refineable_constructor=false)
void full_output(std::ostream &outfile)
Full output function: x,y,[z],u,v,[w],p,du/dt,dv/dt,[dw/dt],dissipation in tecplot format...
unsigned nhistory_values_for_projection(const unsigned &fld)
Number of history values to be stored for fld-th field. Whatever the timestepper has set up for the v...
double interpolated_dudx_nst(const Vector< double > &s, const unsigned &i, const unsigned &j) const
w.r.t spatial global coordinate direction x[j] at local coordinate s
Vector< FpPressureAdvDiffRobinBCElementBase * > Pressure_advection_diffusion_robin_element_pt
Storage for FaceElements that apply Robin BC for pressure adv diff equation used in Fp preconditioner...
virtual unsigned required_nvalue(const unsigned &n) const
Number of values that must be stored at local node n by the element. The default is 0...
Definition: elements.h:2346
double du_dt_nst(const unsigned &n, const unsigned &i) const
i-th component of du/dt at local node n. Uses suitably interpolated value for hanging nodes...
double p_nst(const unsigned &n_p) const
Access function for the pressure values at local pressure node n_p (const version) ...
virtual void get_s_plot(const unsigned &i, const unsigned &nplot, Vector< double > &s, const bool &shifted_to_interior=false) const
Get cector of local coordinates of plot point i (when plotting nplot points in each "coordinate direc...
Definition: elements.h:2978
virtual double dshape_eulerian_at_knot(const unsigned &ipt, Shape &psi, DShape &dpsidx) const
Return the geometric shape functions and also first derivatives w.r.t. global coordinates at the ipt-...
Definition: elements.cc:3254
void dshape< 2 >(const double &s, double *DPsi)
Derivatives of 1D shape functions specialised to linear order (2 Nodes)
Definition: shape.h:604
void output(FILE *file_pt, const unsigned &nplot)
Redirect output to NavierStokesEquations output.
Taylor Hood upgraded to become projectable.
virtual void output(std::ostream &outfile)
Output the element data — typically the values at the nodes in a format suitable for post-processing...
Definition: elements.h:2884
QTaylorHoodElement()
Constructor, no internal data points.
void fill_in_contribution_to_djacobian_dparameter(double *const &parameter_pt, Vector< double > &dres_dparam, DenseMatrix< double > &djac_dparam)
Compute the element&#39;s residual Vector and the jacobian matrix Virtual function can be overloaded by h...
double dpshape_and_dptest_eulerian_nst(const Vector< double > &s, Shape &ppsi, DShape &dppsidx, Shape &ptest, DShape &dptestdx) const
Pressure shape and test functions and their derivs w.r.t. to global coords at local coordinate s (tak...
virtual unsigned nplot_points_paraview(const unsigned &nplot) const
Return the number of actual plot points for paraview plot with parameter nplot. Broken virtual; can b...
Definition: elements.h:2712
virtual void dinterpolated_u_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...
cstr elem_len * i
Definition: cfortran.h:607
unsigned ndof_types() const
The number of "DOF types" that degrees of freedom in this element are sub-divided into: Velocity and ...
unsigned nvalue_of_field(const unsigned &fld)
Return number of values in field fld.
int & face_index()
Index of the face (a number that uniquely identifies the face in the element)
Definition: elements.h:4412
void pin_all_non_pressure_dofs(std::map< Data *, std::vector< int > > &eqn_number_backup)
Pin all non-pressure dofs and backup eqn numbers.
static Vector< double > Default_Gravity_vector
Static default value for the gravity vector.
void fill_in_contribution_to_residuals(Vector< double > &residuals)
This function returns just the residuals.
NavierStokesPressureAdvDiffSourceFctPt & source_fct_for_pressure_adv_diff()
Access function for the source-function pointer for pressure advection diffusion (used for validation...
double * Re_pt
Pointer to global Reynolds number.
virtual void fill_in_contribution_to_hessian_vector_products(Vector< double > const &Y, DenseMatrix< double > const &C, DenseMatrix< double > &product)
Fill in contribution to the product of the Hessian (derivative of Jacobian with respect to all variab...
Definition: elements.cc:1469
NavierStokesSourceFctPt & source_fct_pt()
Access function for the source-function pointer.
unsigned npres_nst() const
Return number of pressure values.
static double Default_Physical_Constant_Value
Static default value for the physical constants (all initialised to zero)
double dshape_and_dtest_eulerian_at_knot_nst(const unsigned &ipt, Shape &psi, DShape &dpsidx, Shape &test, DShape &dtestdx) const
Velocity shape and test functions and their derivs w.r.t. to global coords at local coordinate s (tak...
unsigned npres_nst() const
Return number of pressure values.
void outer_unit_normal(const Vector< double > &s, Vector< double > &unit_normal) const
Compute outer unit normal at the specified local coordinate.
Definition: elements.cc:5873
virtual unsigned required_nvalue(const unsigned &n) const
Number of values (pinned or dofs) required at node n. Can be overwritten for hanging node version...
void build_fp_press_adv_diff_robin_bc_element(const unsigned &face_index)
Build FaceElements that apply the Robin boundary condition to the pressure advection diffusion proble...
unsigned nfields_for_projection()
Number of fields to be projected: dim+1, corresponding to velocity components and pressure...
A general Finite Element class.
Definition: elements.h:1274
void output(std::ostream &outfile, const unsigned &nplot)
Output function: x,y,[z],u,v,[w],p in tecplot format.
void(* UnsteadyExactSolutionFctPt)(const double &, const Vector< double > &, Vector< double > &)
Function pointer for function that computes Vector-valued time-dependent function as ...
Definition: elements.h:1729
virtual void get_body_force_nst(const double &time, const unsigned &ipt, const Vector< double > &s, const Vector< double > &x, Vector< double > &result)
Calculate the body force at a given time and local and/or Eulerian position. This function is virtual...
char t
Definition: cfortran.h:572
const double & density_ratio() const
Density ratio for element: Element&#39;s density relative to the viscosity used in the definition of the ...
TimeStepper *& position_time_stepper_pt()
Return a pointer to the position timestepper.
Definition: nodes.h:969
void output(FILE *file_pt)
Redirect output to NavierStokesEquations output.
double dshape_and_dtest_eulerian_nst(const Vector< double > &s, Shape &psi, DShape &dpsidx, Shape &test, DShape &dtestdx) const
Velocity shape and test functions and their derivs w.r.t. to global coords at local coordinate s (tak...
const double & re_st() const
Product of Reynolds and Strouhal number (=Womersley number)
double interpolated_x(const Vector< double > &s, const unsigned &i) const
Return FE interpolated coordinate x[i] at local coordinate s. Overloaded to get information from bulk...
Definition: elements.h:4322
static double Default_Physical_Ratio_Value
Static default value for the physical ratios (all are initialised to one)
void enable_ALE()
(Re-)enable ALE, i.e. take possible mesh motion into account when evaluating the time-derivative. Note: By default, ALE is enabled, at the expense of possibly creating unnecessary work in problems where the mesh is, in fact, stationary.
void fill_in_pressure_advection_diffusion_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Compute the residuals and Jacobian for the associated pressure advection diffusion problem...
double * ReInvFr_pt
Pointer to global Reynolds number x inverse Froude number (= Bond number / Capillary number) ...
virtual void get_body_force_gradient_nst(const double &time, const unsigned &ipt, const Vector< double > &s, const Vector< double > &x, DenseMatrix< double > &d_body_force_dx)
Nodes are derived from Data, but, in addition, have a definite (Eulerian) position in a space of a gi...
Definition: nodes.h:852
void pshape_nst(const Vector< double > &s, Shape &psi) const
Pressure shape functions at local coordinate s.
ProjectableTaylorHoodElement()
Constructor [this was only required explicitly from gcc 4.5.2 onwards...].
ProjectableCrouzeixRaviartElement()
Constructor [this was only required explicitly from gcc 4.5.2 onwards...].
void output(std::ostream &outfile)
Redirect output to NavierStokesEquations output.
double *& re_pt()
Pointer to Reynolds number.
double interpolated_u_nst(const unsigned &t, const Vector< double > &s, const unsigned &i) const
Return FE interpolated velocity u[i] at local coordinate s at time level t (t=0: present; t>0: histor...
virtual double get_source_nst(const double &time, const unsigned &ipt, const Vector< double > &x)
Calculate the source fct at given time and Eulerian position.
double u_nst(const unsigned &n, const unsigned &i) const
Velocity i at local node n. Uses suitably interpolated value for hanging nodes. The use of u_index_ns...
long & eqn_number(const unsigned &i)
Return the equation number of the i-th stored variable.
Definition: nodes.h:365
unsigned nvalue() const
Return number of values stored in data object (incl pinned ones).
Definition: nodes.h:448
e
Definition: cfortran.h:575
int local_equation(const unsigned &fld, const unsigned &j)
Return local equation number of value j in field fld.
virtual double weight(const unsigned &i) const =0
Return weight of i-th integration point.
A Rank 4 Tensor class.
Definition: matrices.h:1625
void pin(const unsigned &i)
Pin the i-th stored variable.
Definition: nodes.h:383
double size() const
Definition: elements.cc:4207
QCrouzeixRaviartElement()
Constructor, there are DIM+1 internal values (for the pressure)
virtual void fill_in_generic_residual_contribution_fp_press_adv_diff_robin_bc(Vector< double > &residuals, DenseMatrix< double > &jacobian, unsigned flag)=0
This function returns the residuals for the traction function. flag=1 (or 0): do (or don&#39;t) compute t...
void full_output(std::ostream &outfile, const unsigned &nplot)
Full output function: x,y,[z],u,v,[w],p,du/dt,dv/dt,[dw/dt],dissipation in tecplot format...
double J_eulerian(const Vector< double > &s) const
Return the Jacobian of mapping from local to global coordinates at local position s...
Definition: elements.cc:5113
virtual void compute_norm(double &norm)
Compute norm of solution – broken virtual can be overloaded by element writer to implement whatever ...
Definition: elements.h:1119
const double & re_invfr() const
Global inverse Froude number.
NavierStokesSourceFctPt Source_fct_pt
Pointer to volumetric source function.
int p_local_eqn(const unsigned &n) const
Return the local equation numbers for the pressure values.
virtual ~FpPressureAdvDiffRobinBCElementBase()
Empty virtual destructor.
Vector< double > *& g_pt()
Pointer to Vector of gravitational components.
virtual double local_to_eulerian_mapping(const DShape &dpsids, DenseMatrix< double > &jacobian, DenseMatrix< double > &inverse_jacobian) const
Calculate the mapping from local to Eulerian coordinates, given the derivatives of the shape function...
Definition: elements.h:1464
TimeStepper *& time_stepper_pt()
Access function for pointer to time stepper: Null if object is not time-dependent.
Definition: geom_objects.h:197
double *& re_st_pt()
Pointer to product of Reynolds and Strouhal number (=Womersley number)
NavierStokesSourceFctPt source_fct_pt() const
Access function for the source-function pointer. Const version.
bool ALE_is_disabled
Boolean flag to indicate if ALE formulation is disabled when time-derivatives are computed...
virtual int p_nodal_index_nst() const
Set the value at which the pressure is stored in the nodes.
void get_load(const Vector< double > &s, const Vector< double > &N, Vector< double > &load)
This implements a pure virtual function defined in the FSIFluidElement class. The function computes t...
NavierStokesEquations()
Constructor: NULL the body force and source function and make sure the ALE terms are included by defa...
static Vector< double > Gamma
Vector to decide whether the stress-divergence form is used or not.
void output(FILE *file_pt, const unsigned &nplot)
Redirect output to NavierStokesEquations output.
int Pinned_fp_pressure_eqn
Global eqn number of pressure dof that&#39;s pinned in pressure advection diffusion problem (defaults to ...
void(* SteadyExactSolutionFctPt)(const Vector< double > &, Vector< double > &)
Function pointer for function that computes vector-valued steady "exact solution" as ...
Definition: elements.h:1723
void output(FILE *file_pt)
C-style output function: x,y,[z],u,v,[w],p in tecplot format. Default number of plot points...
Vector< std::pair< Data *, unsigned > > data_values_of_field(const unsigned &fld)
Specify the values associated with field fld. The information is returned in a vector of pairs which ...
virtual ~TemplateFreeNavierStokesEquationsBase()
Virtual destructor (empty)
double jacobian_and_shape_of_field(const unsigned &fld, const Vector< double > &s, Shape &psi)
Return Jacobian of mapping and shape functions of field fld at local coordinate s.
virtual void transform_derivatives(const DenseMatrix< double > &inverse_jacobian, DShape &dbasis) const
Convert derivative w.r.t.local coordinates to derivatives w.r.t the coordinates used to assemble the ...
Definition: elements.cc:2764
virtual unsigned u_index_nst(const unsigned &i) const
Return the index at which the i-th unknown velocity component.
A Rank 3 Tensor class.
Definition: matrices.h:1337
unsigned nhistory_values_for_coordinate_projection()
Number of positional history values. (Note: count includes current value!)
unsigned nfields_for_projection()
Number of fields to be projected: dim+1, corresponding to velocity components and pressure...
double dshape_eulerian(const Vector< double > &s, Shape &psi, DShape &dpsidx) const
Compute the geometric shape functions and also first derivatives w.r.t. global coordinates at local c...
Definition: elements.cc:3227
double *& viscosity_ratio_pt()
Pointer to Viscosity Ratio.
std::string scalar_name_paraview(const unsigned &i) const
Name of the i-th scalar field. Default implementation returns V1 for the first one, V2 for the second etc. Can (should!) be overloaded with more meaningful names in specific elements.
Integral *const & integral_pt() const
Return the pointer to the integration scheme (const version)
Definition: elements.h:1908
virtual void get_dof_numbers_for_unknowns(std::list< std::pair< unsigned long, unsigned > > &dof_lookup_list) const
Create a list of pairs for the unknowns that this element is "in charge of" – ignore any unknowns as...
Definition: elements.h:1187
void delete_pressure_advection_diffusion_robin_elements()
Delete the FaceElements that apply the Robin boundary condition to the pressure advection diffusion p...
void interpolated_u_nst(const Vector< double > &s, Vector< double > &veloc) const
Compute vector of FE interpolated velocity u at local coordinate s.
void point_output_data(const Vector< double > &s, Vector< double > &data)
Output solution in data vector at local cordinates s: x,y [,z], u,v,[w], p.
double * ReSt_pt
Pointer to global Reynolds number x Strouhal number (=Womersley)
double dshape_and_dtest_eulerian_at_knot_nst(const unsigned &ipt, Shape &psi, DShape &dpsidx, Shape &test, DShape &dtestdx) const
Velocity shape and test functions and their derivs w.r.t. to global coords at ipt-th integation point...
static char t char * s
Definition: cfortran.h:572
double dpshape_and_dptest_eulerian_nst(const Vector< double > &s, Shape &ppsi, DShape &dppsidx, Shape &ptest, DShape &dptestdx) const
Pressure shape and test functions and their derivs w.r.t. to global coords at local coordinate s (tak...
void disable_ALE()
Disable ALE, i.e. assert the mesh is not moving – you do this at your own risk!
virtual double knot(const unsigned &i, const unsigned &j) const =0
Return local coordinate s[j] of i-th integration point.
int & pinned_fp_pressure_eqn()
Global eqn number of pressure dof that&#39;s pinned in pressure adv diff problem.
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
double *& re_invfr_pt()
Pointer to global inverse Froude number.
Data *& internal_data_pt(const unsigned &i)
Return a pointer to i-th internal data object.
Definition: elements.h:623
void output(FILE *file_pt)
Redirect output to NavierStokesEquations output.
double dshape_and_dtest_eulerian_nst(const Vector< double > &s, Shape &psi, DShape &dpsidx, Shape &test, DShape &dtestdx) const
Velocity shape and test functions and their derivs w.r.t. to global coords at local coordinate s (tak...
Vector< double > * G_pt
Pointer to global gravity Vector.
A class that represents a collection of data; each Data object may contain many different individual ...
Definition: nodes.h:89
virtual void dshape_local(const Vector< double > &s, Shape &psi, DShape &dpsids) const
Function to compute the geometric shape functions and derivatives w.r.t. local coordinates at local c...
Definition: elements.h:1922
Data *const & variable_position_pt() const
Pointer to variable_position data (const version)
Definition: nodes.h:1655
double p_nst(const unsigned &t, const unsigned &n_p) const
Access function for the pressure values at local pressure node n_p (const version) ...
virtual void output_fct(std::ostream &outfile, const unsigned &n_plot, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt)
Output an exact solution over the element.
Definition: elements.h:2938
unsigned n_u_nst() const
Return the number of velocity components Used in FluidInterfaceElements.
double *& density_ratio_pt()
Pointer to Density ratio.
void fill_in_contribution_to_dresiduals_dparameter(double *const &parameter_pt, Vector< double > &dres_dparam)
Compute the element&#39;s residual Vector.
Node *& node_pt(const unsigned &n)
Return a pointer to the local node n.
Definition: elements.h:2109
void scalar_value_paraview(std::ofstream &file_out, const unsigned &i, const unsigned &nplot) const
Write values of the i-th scalar field at the plot points. Needs to be implemented for each new specif...
double Default_Physical_Constant_Value
Default value for physical constants.
unsigned ndof_types() const
Returns the number of "DOF types" that degrees of freedom in this element are sub-divided into: Veloc...
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
Vector< std::pair< Data *, unsigned > > data_values_of_field(const unsigned &fld)
Specify the values associated with field fld. The information is returned in a vector of pairs which ...
unsigned ntstorage() const
Return the number of doubles required to represent history (one for steady)
Definition: timesteppers.h:562
unsigned ntstorage() const
Return total number of doubles stored per value to record time history of each value (one for steady ...
Definition: nodes.cc:847
Crouzeix Raviart upgraded to become projectable.
void output(std::ostream &outfile, const unsigned &nplot)
Redirect output to NavierStokesEquations output.
void fill_in_contribution_to_residuals(Vector< double > &residuals)
Compute the element&#39;s residual Vector.
unsigned nscalar_paraview() const
Number of scalars/fields output by this element. Reimplements broken virtual function in base class...
void output(std::ostream &outfile)
Output function: x,y,[z],u,v,[w],p in tecplot format. Default number of plot points.
unsigned dim() const
Return the spatial dimension of the element, i.e. the number of local coordinates required to paramet...
Definition: elements.h:2482
unsigned ninternal_data() const
Return the number of internal data objects.
Definition: elements.h:828
A Class for nodes that deform elastically (i.e. position is an unknown in the problem). The idea is that the Eulerian positions are stored in a Data object and the Lagrangian coordinates are stored in addition. The pointer that addresses the Eulerian positions is set to the pointer to Value in the Data object. Hence, SolidNode uses knowledge of the internal structure of Data and must be a friend of the Data class. In order to allow a mesh to deform via an elastic-style equation in deforming-domain problems, the positions are stored separately from the values, so that elastic problems may be combined with any other type of problem.
Definition: nodes.h:1569
void fill_in_contribution_to_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
Compute the element&#39;s residual Vector and the jacobian matrix Virtual function can be overloaded by h...
void output(std::ostream &outfile, const unsigned &nplot)
Redirect output to NavierStokesEquations output.
virtual unsigned nweight() const =0
Return the number of integration points of the scheme.
NavierStokesBodyForceFctPt & body_force_fct_pt()
Access function for the body-force pointer.
TimeStepper *& time_stepper_pt()
Return the pointer to the timestepper.
Definition: nodes.h:246
std::string string(const unsigned &i)
Return the i-th string or "" if the relevant string hasn&#39;t been defined.
FiniteElement *& bulk_element_pt()
Pointer to higher-dimensional "bulk" element.
Definition: elements.h:4515
double * Viscosity_Ratio_pt
Pointer to the viscosity ratio (relative to the viscosity used in the definition of the Reynolds numb...
void output(std::ostream &outfile)
Redirect output to NavierStokesEquations output.
NavierStokesPressureAdvDiffSourceFctPt Press_adv_diff_source_fct_pt
Pointer to source function pressure advection diffusion equation (only to be used during validation) ...
unsigned add_internal_data(Data *const &data_pt, const bool &fd=true)
Add a (pointer to an) internal data object to the element and return the index required to obtain it ...
Definition: elements.cc:66
virtual void build_face_element(const int &face_index, FaceElement *face_element_pt)
Function for building a lower dimensional FaceElement on the specified face of the FiniteElement...
Definition: elements.cc:5002
void output(std::ostream &outfile)
Overload the output function.
const double & viscosity_ratio() const
Viscosity ratio for element: Element&#39;s viscosity relative to the viscosity used in the definition of ...
unsigned nvalue_of_field(const unsigned &fld)
Return number of values in field fld.
double p_nst(const unsigned &t, const unsigned &i) const
Return the i-th pressure value (Discontinous pressure interpolation – no need to cater for hanging n...
double interpolated_u_nst(const Vector< double > &s, const unsigned &i) const
Return FE interpolated velocity u[i] at local coordinate s.
NavierStokesPressureAdvDiffSourceFctPt source_fct_for_pressure_adv_diff() const
Access function for the source-function pointer for pressure advection diffusion (used for validation...
void fill_in_contribution_to_djacobian_and_dmass_matrix_dparameter(double *const &parameter_pt, Vector< double > &dres_dparam, DenseMatrix< double > &djac_dparam, DenseMatrix< double > &dmass_matrix_dparam)
unsigned nhistory_values_for_coordinate_projection()
Number of positional history values (Note: count includes current value!)
bool is_steady() const
Flag to indicate if a timestepper has been made steady (possibly temporarily to switch off time-depen...
Definition: timesteppers.h:375
double jacobian_and_shape_of_field(const unsigned &fld, const Vector< double > &s, Shape &psi)
Return Jacobian of mapping and shape functions of field fld at local coordinate s.
void full_output(std::ostream &outfile)
Full output function: x,y,[z],u,v,[w],p,du/dt,dv/dt,[dw/dt],dissipation in tecplot format...
virtual int p_nodal_index_nst() const
Return the index at which the pressure is stored if it is stored at the nodes. If not stored at the n...
double * Density_Ratio_pt
Pointer to the density ratio (relative to the density used in the definition of the Reynolds number) ...
virtual void get_source_gradient_nst(const double &time, const unsigned &ipt, const Vector< double > &x, Vector< double > &gradient)
unsigned nhistory_values_for_projection(const unsigned &fld)
Number of history values to be stored for fld-th field. Whatever the timestepper has set up for the v...
void fill_in_contribution_to_jacobian_and_mass_matrix(Vector< double > &residuals, DenseMatrix< double > &jacobian, DenseMatrix< double > &mass_matrix)
Add the element&#39;s contribution to its residuals vector, jacobian matrix and mass matrix.
double get_field(const unsigned &t, const unsigned &fld, const Vector< double > &s)
Return interpolated field fld at local coordinate s, at time level t (t=0: present; t>0: history valu...
static int Pressure_not_stored_at_node
Static "magic" number that indicates that the pressure is not stored at a node.
void fill_in_pressure_advection_diffusion_residuals(Vector< double > &residuals)
Compute the residuals for the associated pressure advection diffusion problem. Used by the Fp precond...
virtual double interpolated_p_nst(const Vector< double > &s) const
Return FE interpolated pressure at local coordinate s.
NavierStokesBodyForceFctPt Body_force_fct_pt
Pointer to body force function.
void pshape_nst(const Vector< double > &s, Shape &psi) const
Pressure shape functions at local coordinate s.
unsigned nnode() const
Return the number of nodes.
Definition: elements.h:2146
Vector< double > local_coordinate_in_bulk(const Vector< double > &s) const
Return vector of local coordinates in bulk element, given the local coordinates in this FaceElement...
Definition: elements.cc:6210
Base class for time-stepping schemes. Timestepper provides an approximation of the temporal derivativ...
Definition: timesteppers.h:219
virtual void compute_error(std::ostream &outfile, FiniteElement::SteadyExactSolutionFctPt exact_soln_pt, double &error, double &norm)
Plot the error when compared against a given exact solution . Also calculates the norm of the error a...
Definition: elements.h:3033
virtual double weight(const unsigned &i, const unsigned &j) const
Access function for j-th weight for the i-th derivative.
Definition: timesteppers.h:557
void build_fp_press_adv_diff_robin_bc_element(const unsigned &face_index)
Build FaceElements that apply the Robin boundary condition to the pressure advection diffusion proble...
static double Default_fd_jacobian_step
Double used for the default finite difference step in elemental jacobian calculations.
Definition: elements.h:1164
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 fix_pressure(const unsigned &p_dof, const double &p_value)
Pin p_dof-th pressure dof and set it to value specified by p_value.
The FSIFluidElement class is a base class for all fluid finite elements that apply a load (traction) ...
Definition: fsi.h:67
static DenseMatrix< double > Dummy_matrix
Empty dense matrix used as a dummy argument to combined residual and jacobian functions in the case w...
Definition: elements.h:228
double p_nst(const unsigned &i) const
Return the i-th pressure value (Discontinous pressure interpolation – no need to cater for hanging n...
void fix_pressure(const unsigned &p_dof, const double &p_value)
Pin p_dof-th pressure dof and set it to value specified by p_value.
void fill_in_contribution_to_jacobian(Vector< double > &residuals, DenseMatrix< double > &jacobian)
This function returns the residuals and the jacobian.
std::string to_string(T object, unsigned float_precision=8)
Conversion function that should work for anything with operator<< defined (at least all basic types)...
const double & re() const
Reynolds number.
const Vector< double > & g() const
Vector of gravitational components.
double u_nst(const unsigned &t, const unsigned &n, const unsigned &i) const
Velocity i at local node n at timestep t (t=0: present; t>0: previous). Uses suitably interpolated va...
virtual void get_dresidual_dnodal_coordinates(RankThreeTensor< double > &dresidual_dnodal_coordinates)
Compute derivatives of elemental residual vector with respect to nodal coordinates. Default implementation by FD can be overwritten for specific elements. dresidual_dnodal_coordinates(l,i,j) = d res(l) / dX_{ij}.
Definition: elements.cc:3666
int nodal_local_eqn(const unsigned &n, const unsigned &i) const
Return the local equation number corresponding to the i-th value at the n-th local node...
Definition: elements.h:1386
int internal_local_eqn(const unsigned &i, const unsigned &j) const
Return the local equation number corresponding to the j-th value stored at the i-th internal data...
Definition: elements.h:268
void shape< 2 >(const double &s, double *Psi)
1D shape functions specialised to linear order (2 Nodes)
Definition: shape.h:596
virtual void fill_in_generic_residual_contribution_fp_press_adv_diff_robin_bc(Vector< double > &residuals, DenseMatrix< double > &jacobian, unsigned flag)
This function returns the residuals for the traction function. flag=1 (or 0): do (or don&#39;t) compute t...