action functions
|
Please note that the library has not been "officially" released. While we continue to work on the documentation, these web pages are likely to contain broken links and documents in draft form. Please send an email to if you wish to be informed of the library's "official" release. |
00001 //LIC// ==================================================================== 00002 //LIC// This file forms part of oomph-lib, the object-oriented, 00003 //LIC// multi-physics finite-element library, available 00004 //LIC// at http://www.oomph-lib.org. 00005 //LIC// 00006 //LIC// Version 0.90. August 3, 2009. 00007 //LIC// 00008 //LIC// Copyright (C) 2006-2009 Matthias Heil and Andrew Hazel 00009 //LIC// 00010 //LIC// This library is free software; you can redistribute it and/or 00011 //LIC// modify it under the terms of the GNU Lesser General Public 00012 //LIC// License as published by the Free Software Foundation; either 00013 //LIC// version 2.1 of the License, or (at your option) any later version. 00014 //LIC// 00015 //LIC// This library is distributed in the hope that it will be useful, 00016 //LIC// but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 //LIC// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 //LIC// Lesser General Public License for more details. 00019 //LIC// 00020 //LIC// You should have received a copy of the GNU Lesser General Public 00021 //LIC// License along with this library; if not, write to the Free Software 00022 //LIC// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 00023 //LIC// 02110-1301 USA. 00024 //LIC// 00025 //LIC// The authors may be contacted at oomph-lib@maths.man.ac.uk. 00026 //LIC// 00027 //LIC//==================================================================== 00028 //Header file for Navier Stokes elements 00029 00030 #ifndef OOMPH_NAVIER_STOKES_ELEMENTS_HEADER 00031 #define OOMPH_NAVIER_STOKES_ELEMENTS_HEADER 00032 00033 // Config header generated by autoconfig 00034 #ifdef HAVE_CONFIG_H 00035 #include <oomph-lib-config.h> 00036 #endif 00037 00038 00039 //OOMPH-LIB headers 00040 #include "../generic/Qelements.h" 00041 #include "../generic/fsi.h" 00042 00043 namespace oomph 00044 { 00045 00046 00047 //====================================================================== 00048 /// A class for elements that solve the cartesian Navier--Stokes equations, 00049 /// templated by the dimension DIM. 00050 /// This contains the generic maths -- any concrete implementation must 00051 /// be derived from this. 00052 /// 00053 /// We're solving: 00054 /// 00055 /// \f$ { Re \left( St \frac{\partial u_i}{\partial t} + 00056 /// (u_j - u_j^{M}) \frac{\partial u_i}{\partial x_j} \right) = 00057 /// - \frac{\partial p}{\partial x_i} - R_\rho B_i(x_j) - 00058 /// \frac{Re}{Fr} G_i + 00059 /// \frac{\partial }{\partial x_j} \left[ R_\mu \left( 00060 /// \frac{\partial u_i}{\partial x_j} + 00061 /// \frac{\partial u_j}{\partial x_i} \right) \right] } \f$ 00062 /// 00063 /// and 00064 /// 00065 /// \f$ {\Large \frac{\partial u_i}{\partial x_i} = Q } \f$ 00066 /// 00067 /// We also provide all functions required to use this element 00068 /// in FSI problems, by deriving it from the FSIFluidElement base 00069 /// class. 00070 //====================================================================== 00071 template <unsigned DIM> 00072 class NavierStokesEquations : public virtual FSIFluidElement 00073 { 00074 00075 public: 00076 00077 /// \short Function pointer to body force function fct(t,x,f(x)) 00078 /// x is a Vector! 00079 typedef void (*NavierStokesBodyForceFctPt)(const double& time, 00080 const Vector<double>& x, 00081 Vector<double>& body_force); 00082 00083 /// \short Function pointer to source function fct(t,x) 00084 /// x is a Vector! 00085 typedef double (*NavierStokesSourceFctPt)(const double& time, 00086 const Vector<double>& x); 00087 00088 private: 00089 00090 /// \short Static "magic" number that indicates that the pressure is 00091 /// not stored at a node 00092 static int Pressure_not_stored_at_node; 00093 00094 /// Static default value for the physical constants (all initialised to zero) 00095 static double Default_Physical_Constant_Value; 00096 00097 /// Static default value for the physical ratios (all are initialised to one) 00098 static double Default_Physical_Ratio_Value; 00099 00100 /// Static default value for the gravity vector 00101 static Vector<double> Default_Gravity_vector; 00102 00103 protected: 00104 00105 //Physical constants 00106 00107 /// \short Pointer to the viscosity ratio (relative to the 00108 /// viscosity used in the definition of the Reynolds number) 00109 double *Viscosity_Ratio_pt; 00110 00111 /// \short Pointer to the density ratio (relative to the density used in the 00112 /// definition of the Reynolds number) 00113 double *Density_Ratio_pt; 00114 00115 // Pointers to global physical constants 00116 00117 /// Pointer to global Reynolds number 00118 double *Re_pt; 00119 00120 /// Pointer to global Reynolds number x Strouhal number (=Womersley) 00121 double *ReSt_pt; 00122 00123 /// \short Pointer to global Reynolds number x inverse Froude number 00124 /// (= Bond number / Capillary number) 00125 double *ReInvFr_pt; 00126 00127 /// Pointer to global gravity Vector 00128 Vector<double> *G_pt; 00129 00130 /// Pointer to body force function 00131 NavierStokesBodyForceFctPt Body_force_fct_pt; 00132 00133 /// Pointer to volumetric source function 00134 NavierStokesSourceFctPt Source_fct_pt; 00135 00136 /// \short Boolean flag to indicate if ALE formulation is disabled when 00137 /// time-derivatives are computed. Only set to true if you're sure 00138 /// that the mesh is stationary. 00139 bool ALE_is_disabled; 00140 00141 /// \short Access function for the local equation number information for 00142 /// the pressure. 00143 /// p_local_eqn[n] = local equation number or < 0 if pinned 00144 virtual int p_local_eqn(const unsigned &n)=0; 00145 00146 /// \short Compute the shape functions and derivatives 00147 /// w.r.t. global coords at local coordinate s. 00148 /// Return Jacobian of mapping between local and global coordinates. 00149 virtual double dshape_and_dtest_eulerian_nst(const Vector<double> &s, 00150 Shape &psi, 00151 DShape &dpsidx, Shape &test, 00152 DShape &dtestdx) const=0; 00153 00154 /// \short Compute the shape functions and derivatives 00155 /// w.r.t. global coords at ipt-th integration point 00156 /// Return Jacobian of mapping between local and global coordinates. 00157 virtual double dshape_and_dtest_eulerian_at_knot_nst(const unsigned &ipt, 00158 Shape &psi, 00159 DShape &dpsidx, 00160 Shape &test, 00161 DShape &dtestdx) const=0; 00162 00163 /// Compute the pressure shape functions at local coordinate s 00164 virtual void pshape_nst(const Vector<double> &s, Shape &psi) const=0; 00165 00166 /// \short Compute the pressure shape and test functions 00167 /// at local coordinate s 00168 virtual void pshape_nst(const Vector<double> &s, Shape &psi, 00169 Shape &test) const=0; 00170 00171 00172 /// \short Calculate the body force at a given time and local and/or 00173 /// Eulerian position. This function is virtual so that it can be 00174 /// overloaded in multi-physics elements where the body force might 00175 /// depend on another variable. 00176 virtual void get_body_force_nst(const double& time, 00177 const unsigned& ipt, 00178 const Vector<double> &s, 00179 const Vector<double> &x, 00180 Vector<double> &result) 00181 { 00182 //If the function pointer is zero return zero 00183 if(Body_force_fct_pt == 0) 00184 { 00185 //Loop over dimensions and set body forces to zero 00186 for(unsigned i=0;i<DIM;i++) {result[i] = 0.0;} 00187 } 00188 //Otherwise call the function 00189 else 00190 { 00191 (*Body_force_fct_pt)(time,x,result); 00192 } 00193 } 00194 00195 /// Get gradient of body force term at (Eulerian) position x. This function is 00196 /// virtual to allow overloading in multi-physics problems where 00197 /// the strength of the source function might be determined by 00198 /// another system of equations. Computed via function pointer 00199 /// (if set) or by finite differencing (default) 00200 inline virtual void get_body_force_gradient_nst( 00201 const double& time, 00202 const unsigned& ipt, 00203 const Vector<double>& s, 00204 const Vector<double>& x, 00205 DenseMatrix<double>& d_body_force_dx) 00206 { 00207 // hierher: Implement function pointer version 00208 /* //If no gradient function has been set, FD it */ 00209 /* if(Body_force_fct_gradient_pt==0) */ 00210 { 00211 // Reference value 00212 Vector<double> body_force(DIM,0.0); 00213 get_body_force_nst(time,ipt,s,x,body_force); 00214 00215 // FD it 00216 double eps_fd=GeneralisedElement::Default_fd_jacobian_step; 00217 Vector<double> body_force_pls(DIM,0.0); 00218 Vector<double> x_pls(x); 00219 for (unsigned i=0;i<DIM;i++) 00220 { 00221 x_pls[i]+=eps_fd; 00222 get_body_force_nst(time,ipt,s,x_pls,body_force_pls); 00223 for (unsigned j=0;j<DIM;j++) 00224 { 00225 d_body_force_dx(j,i)=(body_force_pls[j]-body_force[j])/eps_fd; 00226 } 00227 x_pls[i]=x[i]; 00228 } 00229 } 00230 /* else */ 00231 /* { */ 00232 /* // Get gradient */ 00233 /* (*Source_fct_gradient_pt)(time,x,gradient); */ 00234 /* } */ 00235 } 00236 00237 00238 00239 /// \short Calculate the source fct at given time and 00240 /// Eulerian position 00241 virtual double get_source_nst(const double& time, const unsigned& ipt, 00242 const Vector<double> &x) 00243 { 00244 //If the function pointer is zero return zero 00245 if (Source_fct_pt == 0) {return 0;} 00246 //Otherwise call the function 00247 else {return (*Source_fct_pt)(time,x);} 00248 } 00249 00250 00251 /// Get gradient of source term at (Eulerian) position x. This function is 00252 /// virtual to allow overloading in multi-physics problems where 00253 /// the strength of the source function might be determined by 00254 /// another system of equations. Computed via function pointer 00255 /// (if set) or by finite differencing (default) 00256 inline virtual void get_source_gradient_nst( 00257 const double& time, 00258 const unsigned& ipt, 00259 const Vector<double>& x, 00260 Vector<double>& gradient) 00261 { 00262 // hierher: Implement function pointer version 00263 /* //If no gradient function has been set, FD it */ 00264 /* if(Source_fct_gradient_pt==0) */ 00265 { 00266 // Reference value 00267 double source=get_source_nst(time,ipt,x); 00268 00269 // FD it 00270 double eps_fd=GeneralisedElement::Default_fd_jacobian_step; 00271 double source_pls=0.0; 00272 Vector<double> x_pls(x); 00273 for (unsigned i=0;i<DIM;i++) 00274 { 00275 x_pls[i]+=eps_fd; 00276 source_pls=get_source_nst(time,ipt,x_pls); 00277 gradient[i]=(source_pls-source)/eps_fd; 00278 x_pls[i]=x[i]; 00279 } 00280 } 00281 /* else */ 00282 /* { */ 00283 /* // Get gradient */ 00284 /* (*Source_fct_gradient_pt)(time,x,gradient); */ 00285 /* } */ 00286 } 00287 00288 00289 00290 00291 00292 00293 00294 00295 ///\short Compute the residuals for the Navier--Stokes equations; 00296 /// flag=1(or 0): do (or don't) compute the Jacobian as well. 00297 virtual void fill_in_generic_residual_contribution_nst( 00298 Vector<double> &residuals, DenseMatrix<double> &jacobian, 00299 DenseMatrix<double> &mass_matrix, unsigned flag); 00300 00301 00302 public: 00303 00304 /// \short Constructor: NULL the body force and source function 00305 /// and make sure the ALE terms are included by default. 00306 NavierStokesEquations() : Body_force_fct_pt(0), Source_fct_pt(0), 00307 ALE_is_disabled(false) 00308 { 00309 //Set all the Physical parameter pointers to the default value zero 00310 Re_pt = &Default_Physical_Constant_Value; 00311 ReSt_pt = &Default_Physical_Constant_Value; 00312 ReInvFr_pt = &Default_Physical_Constant_Value; 00313 G_pt = &Default_Gravity_vector; 00314 //Set the Physical ratios to the default value of 1 00315 Viscosity_Ratio_pt = &Default_Physical_Ratio_Value; 00316 Density_Ratio_pt = &Default_Physical_Ratio_Value; 00317 } 00318 00319 /// Vector to decide whether the stress-divergence form is used or not 00320 // N.B. This needs to be public so that the intel compiler gets things correct 00321 // somehow the access function messes things up when going to refineable 00322 // navier--stokes 00323 static Vector<double> Gamma; 00324 00325 //Access functions for the physical constants 00326 00327 /// Reynolds number 00328 const double &re() const {return *Re_pt;} 00329 00330 /// Product of Reynolds and Strouhal number (=Womersley number) 00331 const double &re_st() const {return *ReSt_pt;} 00332 00333 /// Pointer to Reynolds number 00334 double* &re_pt() {return Re_pt;} 00335 00336 /// Pointer to product of Reynolds and Strouhal number (=Womersley number) 00337 double* &re_st_pt() {return ReSt_pt;} 00338 00339 /// \short Viscosity ratio for element: Element's viscosity relative to the 00340 /// viscosity used in the definition of the Reynolds number 00341 const double &viscosity_ratio() const {return *Viscosity_Ratio_pt;} 00342 00343 /// Pointer to Viscosity Ratio 00344 double* &viscosity_ratio_pt() {return Viscosity_Ratio_pt;} 00345 00346 /// \short Density ratio for element: Element's density relative to the 00347 /// viscosity used in the definition of the Reynolds number 00348 const double &density_ratio() const {return *Density_Ratio_pt;} 00349 00350 /// Pointer to Density ratio 00351 double* &density_ratio_pt() {return Density_Ratio_pt;} 00352 00353 /// Global inverse Froude number 00354 const double &re_invfr() const {return *ReInvFr_pt;} 00355 00356 /// Pointer to global inverse Froude number 00357 double* &re_invfr_pt() {return ReInvFr_pt;} 00358 00359 /// Vector of gravitational components 00360 const Vector<double> &g() const {return *G_pt;} 00361 00362 /// Pointer to Vector of gravitational components 00363 Vector<double>* &g_pt() {return G_pt;} 00364 00365 /// Access function for the body-force pointer 00366 NavierStokesBodyForceFctPt& body_force_fct_pt() 00367 {return Body_force_fct_pt;} 00368 00369 /// Access function for the body-force pointer. Const version 00370 NavierStokesBodyForceFctPt body_force_fct_pt() const 00371 {return Body_force_fct_pt;} 00372 00373 ///Access function for the source-function pointer 00374 NavierStokesSourceFctPt& source_fct_pt() {return Source_fct_pt;} 00375 00376 ///Access function for the source-function pointer. Const version 00377 NavierStokesSourceFctPt source_fct_pt() const {return Source_fct_pt;} 00378 00379 ///Function to return number of pressure degrees of freedom 00380 virtual unsigned npres_nst() const=0; 00381 00382 /// \short Velocity i at local node n. Uses suitably interpolated value 00383 /// for hanging nodes. The use of u_index_nst() permits the use of this 00384 /// element as the basis for multi-physics elements. The default 00385 /// is to assume that the i-th velocity component is stored at the 00386 /// i-th location of the node 00387 double u_nst(const unsigned &n, const unsigned &i) const 00388 {return nodal_value(n,u_index_nst(i));} 00389 00390 /// \short Velocity i at local node n at timestep t (t=0: present; 00391 /// t>0: previous). Uses suitably interpolated value for hanging nodes. 00392 double u_nst(const unsigned &t, const unsigned &n, 00393 const unsigned &i) const 00394 {return nodal_value(t,n,u_index_nst(i));} 00395 00396 /// \short Return the index at which the i-th unknown velocity component 00397 /// is stored. The default value, i, is appropriate for single-physics 00398 /// problems. 00399 /// In derived multi-physics elements, this function should be overloaded 00400 /// to reflect the chosen storage scheme. Note that these equations require 00401 /// that the unknowns are always stored at the same indices at each node. 00402 virtual inline unsigned u_index_nst(const unsigned &i) const {return i;} 00403 00404 00405 /// \short i-th component of du/dt at local node n. 00406 /// Uses suitably interpolated value for hanging nodes. 00407 double du_dt_nst(const unsigned &n, const unsigned &i) const 00408 { 00409 // Get the data's timestepper 00410 TimeStepper* time_stepper_pt = this->node_pt(n)->time_stepper_pt(); 00411 00412 //Initialise dudt 00413 double dudt=0.0; 00414 00415 //Loop over the timesteps, if there is a non Steady timestepper 00416 if (!time_stepper_pt->is_steady()) 00417 { 00418 //Find the index at which the dof is stored 00419 const unsigned u_nodal_index = this->u_index_nst(i); 00420 00421 // Number of timsteps (past & present) 00422 const unsigned n_time = time_stepper_pt->ntstorage(); 00423 // Loop over the timesteps 00424 for(unsigned t=0;t<n_time;t++) 00425 { 00426 dudt+=time_stepper_pt->weight(1,t)*nodal_value(t,n,u_nodal_index); 00427 } 00428 } 00429 00430 return dudt; 00431 } 00432 00433 /// \short Disable ALE, i.e. assert the mesh is not moving -- you do this 00434 /// at your own risk! 00435 void disable_ALE() 00436 { 00437 ALE_is_disabled=true; 00438 } 00439 00440 /// \short (Re-)enable ALE, i.e. take possible mesh motion into account 00441 /// when evaluating the time-derivative. Note: By default, ALE is 00442 /// enabled, at the expense of possibly creating unnecessary work 00443 /// in problems where the mesh is, in fact, stationary. 00444 void enable_ALE() 00445 { 00446 ALE_is_disabled=false; 00447 } 00448 00449 /// \short Pressure at local pressure "node" n_p 00450 /// Uses suitably interpolated value for hanging nodes. 00451 virtual double p_nst(const unsigned &n_p)const=0; 00452 00453 /// Pin p_dof-th pressure dof and set it to value specified by p_value. 00454 virtual void fix_pressure(const unsigned &p_dof, const double &p_value)=0; 00455 00456 /// \short Return the index at which the pressure is stored if it is 00457 /// stored at the nodes. If not stored at the nodes this will return 00458 /// a negative number. 00459 virtual int p_nodal_index_nst() const {return Pressure_not_stored_at_node;} 00460 00461 /// Integral of pressure over element 00462 double pressure_integral() const; 00463 00464 /// \short Return integral of dissipation over element 00465 double dissipation() const; 00466 00467 /// \short Return dissipation at local coordinate s 00468 double dissipation(const Vector<double>& s) const; 00469 00470 /// \short Compute the vorticity vector at local coordinate s 00471 void get_vorticity(const Vector<double>& s, Vector<double>& vorticity) const; 00472 00473 /// \short Get integral of kinetic energy over element 00474 double kin_energy() const; 00475 00476 /// \short Get integral of time derivative of kinetic energy over element 00477 double d_kin_energy_dt() const; 00478 00479 /// Strain-rate tensor: 1/2 (du_i/dx_j + du_j/dx_i) 00480 void strain_rate(const Vector<double>& s, 00481 DenseMatrix<double>& strain_rate) const; 00482 00483 /// \short Compute traction (on the viscous scale) exerted onto 00484 /// the fluid at local coordinate s. N has to be outer unit normal 00485 /// to the fluid. 00486 void get_traction(const Vector<double>& s, const Vector<double>& N, 00487 Vector<double>& traction); 00488 00489 /// \short This implements a pure virtual function defined 00490 /// in the FSIFluidElement class. The function computes 00491 /// the traction (on the viscous scale), at the element's local 00492 /// coordinate s, that the fluid element exerts onto an adjacent 00493 /// solid element. The number of arguments is imposed by 00494 /// the interface defined in the FSIFluidElement -- only the 00495 /// unit normal N (pointing into the fluid!) is actually used 00496 /// in the computation. 00497 void get_load(const Vector<double> &s, 00498 const Vector<double> &N, 00499 Vector<double> &load) 00500 { 00501 // Note: get_traction() computes the traction onto the fluid 00502 // if N is the outer unit normal onto the fluid; here we're 00503 // exepcting N to point into the fluid so we're getting the 00504 // traction onto the adjacent wall instead! 00505 get_traction(s,N,load); 00506 } 00507 00508 /// Compute the diagonal of the velocity mass matrix 00509 void get_velocity_mass_matrix_diagonal(Vector<double> &mass_diag); 00510 00511 /// \short Output function: x,y,[z],u,v,[w],p 00512 /// in tecplot format. Default number of plot points 00513 void output(std::ostream &outfile) 00514 { 00515 unsigned nplot=5; 00516 output(outfile,nplot); 00517 } 00518 00519 /// \short Output function: x,y,[z],u,v,[w],p 00520 /// in tecplot format. nplot points in each coordinate direction 00521 void output(std::ostream &outfile, const unsigned &nplot); 00522 00523 /// \short C-style output function: x,y,[z],u,v,[w],p 00524 /// in tecplot format. Default number of plot points 00525 void output(FILE* file_pt) 00526 { 00527 unsigned nplot=5; 00528 output(file_pt,nplot); 00529 } 00530 00531 /// \short C-style output function: x,y,[z],u,v,[w],p 00532 /// in tecplot format. nplot points in each coordinate direction 00533 void output(FILE* file_pt, const unsigned &nplot); 00534 00535 /// \short Full output function: 00536 /// x,y,[z],u,v,[w],p,du/dt,dv/dt,[dw/dt],dissipation 00537 /// in tecplot format. Default number of plot points 00538 void full_output(std::ostream &outfile) 00539 { 00540 unsigned nplot=5; 00541 full_output(outfile,nplot); 00542 } 00543 00544 /// \short Full output function: 00545 /// x,y,[z],u,v,[w],p,du/dt,dv/dt,[dw/dt],dissipation 00546 /// in tecplot format. nplot points in each coordinate direction 00547 void full_output(std::ostream &outfile, const unsigned &nplot); 00548 00549 00550 /// \short Output function: x,y,[z],u,v,[w] in tecplot format. 00551 /// nplot points in each coordinate direction at timestep t 00552 /// (t=0: present; t>0: previous timestep) 00553 void output_veloc(std::ostream &outfile, const unsigned &nplot, 00554 const unsigned& t); 00555 00556 00557 /// \short Output function: x,y,[z], [omega_x,omega_y,[and/or omega_z]] 00558 /// in tecplot format. nplot points in each coordinate direction 00559 void output_vorticity(std::ostream &outfile, 00560 const unsigned &nplot); 00561 00562 /// \short Output exact solution specified via function pointer 00563 /// at a given number of plot points. Function prints as 00564 /// many components as are returned in solution Vector 00565 void output_fct(std::ostream &outfile, const unsigned &nplot, 00566 FiniteElement::SteadyExactSolutionFctPt exact_soln_pt); 00567 00568 /// \short Output exact solution specified via function pointer 00569 /// at a given time and at a given number of plot points. 00570 /// Function prints as many components as are returned in solution Vector. 00571 void output_fct(std::ostream &outfile, const unsigned &nplot, 00572 const double& time, 00573 FiniteElement::UnsteadyExactSolutionFctPt exact_soln_pt); 00574 00575 /// \short Validate against exact solution at given time 00576 /// Solution is provided via function pointer. 00577 /// Plot at a given number of plot points and compute L2 error 00578 /// and L2 norm of velocity solution over element 00579 void compute_error(std::ostream &outfile, 00580 FiniteElement::UnsteadyExactSolutionFctPt exact_soln_pt, 00581 const double& time, 00582 double& error, double& norm); 00583 00584 /// \short Validate against exact solution. 00585 /// Solution is provided via function pointer. 00586 /// Plot at a given number of plot points and compute L2 error 00587 /// and L2 norm of velocity solution over element 00588 void compute_error(std::ostream &outfile, 00589 FiniteElement::SteadyExactSolutionFctPt exact_soln_pt, 00590 double& error, double& norm); 00591 00592 /// Compute the element's residual Vector 00593 void fill_in_contribution_to_residuals(Vector<double> &residuals) 00594 { 00595 //Call the generic residuals function with flag set to 0 00596 //and using a dummy matrix argument 00597 fill_in_generic_residual_contribution_nst( 00598 residuals,GeneralisedElement::Dummy_matrix, 00599 GeneralisedElement::Dummy_matrix,0); 00600 } 00601 00602 ///\short Compute the element's residual Vector and the jacobian matrix 00603 /// Virtual function can be overloaded by hanging-node version 00604 void fill_in_contribution_to_jacobian(Vector<double> &residuals, 00605 DenseMatrix<double> &jacobian) 00606 { 00607 //Call the generic routine with the flag set to 1 00608 fill_in_generic_residual_contribution_nst(residuals,jacobian, 00609 GeneralisedElement::Dummy_matrix,1); 00610 } 00611 00612 /// Add the element's contribution to its residuals vector, 00613 /// jacobian matrix and mass matrix 00614 void fill_in_contribution_to_jacobian_and_mass_matrix( 00615 Vector<double> &residuals, DenseMatrix<double> &jacobian, 00616 DenseMatrix<double> &mass_matrix) 00617 { 00618 //Call the generic routine with the flag set to 2 00619 fill_in_generic_residual_contribution_nst(residuals,jacobian,mass_matrix,2); 00620 } 00621 00622 00623 /// \short Compute derivatives of elemental residual vector with respect 00624 /// to nodal coordinates. Overwrites default implementation in 00625 /// FiniteElement base class. 00626 /// dresidual_dnodal_coordinates(l,i,j) = d res(l) / dX_{ij} 00627 virtual void get_dresidual_dnodal_coordinates(RankThreeTensor<double>& 00628 dresidual_dnodal_coordinates); 00629 00630 /// Compute vector of FE interpolated velocity u at local coordinate s 00631 void interpolated_u_nst(const Vector<double> &s, Vector<double>& veloc) const 00632 { 00633 //Find number of nodes 00634 unsigned n_node = nnode(); 00635 //Local shape function 00636 Shape psi(n_node); 00637 //Find values of shape function 00638 shape(s,psi); 00639 00640 for (unsigned i=0;i<DIM;i++) 00641 { 00642 //Index at which the nodal value is stored 00643 unsigned u_nodal_index = u_index_nst(i); 00644 //Initialise value of u 00645 veloc[i] = 0.0; 00646 //Loop over the local nodes and sum 00647 for(unsigned l=0;l<n_node;l++) 00648 { 00649 veloc[i] += nodal_value(l,u_nodal_index)*psi[l]; 00650 } 00651 } 00652 } 00653 00654 /// Return FE interpolated velocity u[i] at local coordinate s 00655 double interpolated_u_nst(const Vector<double> &s, const unsigned &i) const 00656 { 00657 //Find number of nodes 00658 unsigned n_node = nnode(); 00659 //Local shape function 00660 Shape psi(n_node); 00661 //Find values of shape function 00662 shape(s,psi); 00663 00664 //Get nodal index at which i-th velocity is stored 00665 unsigned u_nodal_index = u_index_nst(i); 00666 00667 //Initialise value of u 00668 double interpolated_u = 0.0; 00669 //Loop over the local nodes and sum 00670 for(unsigned l=0;l<n_node;l++) 00671 { 00672 interpolated_u += nodal_value(l,u_nodal_index)*psi[l]; 00673 } 00674 00675 return(interpolated_u); 00676 } 00677 00678 /// \short Compute the derivatives of the i-th component of 00679 /// velocity at point s with respect 00680 /// to all data that can affect its value. In addition, return the global 00681 /// equation numbers corresponding to the data. The function is virtual 00682 /// so that it can be overloaded in the refineable version 00683 virtual void dinterpolated_u_nst_ddata(const Vector<double> &s, 00684 const unsigned &i, 00685 Vector<double> &du_ddata, 00686 Vector<unsigned> &global_eqn_number) 00687 { 00688 //Find number of nodes 00689 unsigned n_node = nnode(); 00690 //Local shape function 00691 Shape psi(n_node); 00692 //Find values of shape function 00693 shape(s,psi); 00694 00695 //Find the index at which the velocity component is stored 00696 const unsigned u_nodal_index = u_index_nst(i); 00697 00698 //Find the number of dofs associated with interpolated u 00699 unsigned n_u_dof=0; 00700 for(unsigned l=0;l<n_node;l++) 00701 { 00702 int global_eqn = this->node_pt(l)->eqn_number(u_nodal_index); 00703 //If it's positive add to the count 00704 if(global_eqn >= 0) {++n_u_dof;} 00705 } 00706 00707 //Now resize the storage schemes 00708 du_ddata.resize(n_u_dof,0.0); 00709 global_eqn_number.resize(n_u_dof,0); 00710 00711 //Loop over th nodes again and set the derivatives 00712 unsigned count=0; 00713 //Loop over the local nodes and sum 00714 for(unsigned l=0;l<n_node;l++) 00715 { 00716 //Get the global equation number 00717 int global_eqn = this->node_pt(l)->eqn_number(u_nodal_index); 00718 if (global_eqn >= 0) 00719 { 00720 //Set the global equation number 00721 global_eqn_number[count] = global_eqn; 00722 //Set the derivative with respect to the unknown 00723 du_ddata[count] = psi[l]; 00724 //Increase the counter 00725 ++count; 00726 } 00727 } 00728 } 00729 00730 00731 /// Return FE interpolated pressure at local coordinate s 00732 double interpolated_p_nst(const Vector<double> &s) const 00733 { 00734 //Find number of nodes 00735 unsigned n_pres = npres_nst(); 00736 //Local shape function 00737 Shape psi(n_pres); 00738 //Find values of shape function 00739 pshape_nst(s,psi); 00740 00741 //Initialise value of p 00742 double interpolated_p = 0.0; 00743 //Loop over the local nodes and sum 00744 for(unsigned l=0;l<n_pres;l++) 00745 { 00746 interpolated_p += p_nst(l)*psi[l]; 00747 } 00748 00749 return(interpolated_p); 00750 } 00751 00752 }; 00753 00754 ////////////////////////////////////////////////////////////////////////////// 00755 ////////////////////////////////////////////////////////////////////////////// 00756 ////////////////////////////////////////////////////////////////////////////// 00757 00758 00759 //========================================================================== 00760 /// Crouzeix_Raviart elements are Navier--Stokes elements with quadratic 00761 /// interpolation for velocities and positions, but a discontinuous linear 00762 /// pressure interpolation. They can be used within oomph-lib's 00763 /// block preconditioning framework. 00764 //========================================================================== 00765 template <unsigned DIM> 00766 class QCrouzeixRaviartElement : public virtual QElement<DIM,3>, 00767 public virtual NavierStokesEquations<DIM> 00768 { 00769 private: 00770 00771 /// Static array of ints to hold required number of variables at nodes 00772 static const unsigned Initial_Nvalue[]; 00773 00774 protected: 00775 00776 /// Internal index that indicates at which internal data the pressure 00777 /// is stored 00778 unsigned P_nst_internal_index; 00779 00780 00781 /// \short Velocity shape and test functions and their derivs 00782 /// w.r.t. to global coords at local coordinate s (taken from geometry) 00783 ///Return Jacobian of mapping between local and global coordinates. 00784 inline double dshape_and_dtest_eulerian_nst(const Vector<double> &s, 00785 Shape &psi, 00786 DShape &dpsidx, Shape &test, 00787 DShape &dtestdx) const; 00788 00789 /// \short Velocity shape and test functions and their derivs 00790 /// w.r.t. to global coords at ipt-th integation point (taken from geometry) 00791 ///Return Jacobian of mapping between local and global coordinates. 00792 inline double dshape_and_dtest_eulerian_at_knot_nst(const unsigned &ipt, 00793 Shape &psi, 00794 DShape &dpsidx, 00795 Shape &test, 00796 DShape &dtestdx) const; 00797 00798 /// Pressure shape functions at local coordinate s 00799 inline void pshape_nst(const Vector<double> &s, Shape &psi) const; 00800 00801 /// Pressure shape and test functions at local coordinte s 00802 inline void pshape_nst(const Vector<double> &s, Shape &psi, 00803 Shape &test) const; 00804 00805 /// Return the local equation numbers for the pressure values. 00806 inline int p_local_eqn(const unsigned &n) 00807 {return this->internal_local_eqn(P_nst_internal_index,n);} 00808 00809 public: 00810 00811 /// Constructor, there are DIM+1 internal values (for the pressure) 00812 QCrouzeixRaviartElement() : QElement<DIM,3>(), NavierStokesEquations<DIM>() 00813 { 00814 //Allocate and add one Internal data object that stored DIM+1 pressure 00815 //values; 00816 P_nst_internal_index = this->add_internal_data(new Data(DIM+1)); 00817 } 00818 00819 /// \short Number of values (pinned or dofs) required at local node n. 00820 virtual unsigned required_nvalue(const unsigned &n) const; 00821 00822 00823 /// \short Return the i-th pressure value 00824 /// (Discontinous pressure interpolation -- no need to cater for hanging 00825 /// nodes). 00826 double p_nst(const unsigned &i) const 00827 {return this->internal_data_pt(P_nst_internal_index)->value(i);} 00828 00829 /// Return number of pressure values 00830 unsigned npres_nst() const {return DIM+1;} 00831 00832 /// Pin p_dof-th pressure dof and set it to value specified by p_value. 00833 void fix_pressure(const unsigned &p_dof, const double &p_value) 00834 { 00835 this->internal_data_pt(P_nst_internal_index)->pin(p_dof); 00836 this->internal_data_pt(P_nst_internal_index)->set_value(p_dof,p_value); 00837 } 00838 00839 /// \short Add to the set \c paired_load_data pairs containing 00840 /// - the pointer to a Data object 00841 /// and 00842 /// - the index of the value in that Data object 00843 /// . 00844 /// for all values (pressures, velocities) that affect the 00845 /// load computed in the \c get_load(...) function. 00846 void identify_load_data( 00847 std::set<std::pair<Data*,unsigned> > &paired_load_data); 00848 00849 /// \short Add to the set \c paired_pressure_data pairs 00850 /// containing 00851 /// - the pointer to a Data object 00852 /// and 00853 /// - the index of the value in that Data object 00854 /// . 00855 /// for all pressure values that affect the 00856 /// load computed in the \c get_load(...) function. 00857 void identify_pressure_data( 00858 std::set<std::pair<Data*,unsigned> > &paired_pressure_data); 00859 00860 /// Redirect output to NavierStokesEquations output 00861 void output(std::ostream &outfile) 00862 {NavierStokesEquations<DIM>::output(outfile);} 00863 00864 /// Redirect output to NavierStokesEquations output 00865 void output(std::ostream &outfile, const unsigned &nplot) 00866 {NavierStokesEquations<DIM>::output(outfile,nplot);} 00867 00868 00869 /// Redirect output to NavierStokesEquations output 00870 void output(FILE* file_pt) {NavierStokesEquations<DIM>::output(file_pt);} 00871 00872 /// Redirect output to NavierStokesEquations output 00873 void output(FILE* file_pt, const unsigned &nplot) 00874 {NavierStokesEquations<DIM>::output(file_pt,nplot);} 00875 00876 00877 /// \short Full output function: 00878 /// x,y,[z],u,v,[w],p,du/dt,dv/dt,[dw/dt],dissipation 00879 /// in tecplot format. Default number of plot points 00880 void full_output(std::ostream &outfile) 00881 {NavierStokesEquations<DIM>::full_output(outfile);} 00882 00883 /// \short Full output function: 00884 /// x,y,[z],u,v,[w],p,du/dt,dv/dt,[dw/dt],dissipation 00885 /// in tecplot format. nplot points in each coordinate direction 00886 void full_output(std::ostream &outfile, const unsigned &nplot) 00887 {NavierStokesEquations<DIM>::full_output(outfile,nplot);} 00888 00889 00890 /// \short The number of "blocks" that degrees of freedom in this element 00891 /// are sub-divided into: Velocity and pressure. 00892 unsigned ndof_types() 00893 { 00894 return DIM+1; 00895 } 00896 00897 /// \short Create a list of pairs for all unknowns in this element, 00898 /// so that the first entry in each pair contains the global equation 00899 /// number of the unknown, while the second one contains the number 00900 /// of the "block" that this unknown is associated with. 00901 /// (Function can obviously only be called if the equation numbering 00902 /// scheme has been set up.) Velocity=0; Pressure=1 00903 void get_dof_numbers_for_unknowns( 00904 std::list<std::pair<unsigned long,unsigned> >& dof_lookup_list); 00905 00906 }; 00907 00908 //Inline functions 00909 00910 //======================================================================= 00911 /// 2D 00912 /// Derivatives of the shape functions and test functions w.r.t. to global 00913 /// (Eulerian) coordinates. Return Jacobian of mapping between 00914 /// local and global coordinates. 00915 //======================================================================= 00916 template<> 00917 inline double QCrouzeixRaviartElement<2>::dshape_and_dtest_eulerian_nst( 00918 const Vector<double> &s, Shape &psi, 00919 DShape &dpsidx, Shape &test, 00920 DShape &dtestdx) const 00921 { 00922 //Call the geometrical shape functions and derivatives 00923 double J = this->dshape_eulerian(s,psi,dpsidx); 00924 //Loop over the test functions and derivatives and set them equal to the 00925 //shape functions 00926 for(unsigned i=0;i<9;i++) 00927 { 00928 test[i] = psi[i]; 00929 dtestdx(i,0) = dpsidx(i,0); 00930 dtestdx(i,1) = dpsidx(i,1); 00931 } 00932 //Return the jacobian 00933 return J; 00934 } 00935 00936 00937 //======================================================================= 00938 /// 3D 00939 /// Derivatives of the shape functions and test functions w.r.t. to global 00940 /// (Eulerian) coordinates. Return Jacobian of mapping between 00941 /// local and global coordinates. 00942 //======================================================================= 00943 template<> 00944 inline double QCrouzeixRaviartElement<3>::dshape_and_dtest_eulerian_nst( 00945 const Vector<double> &s, Shape &psi, 00946 DShape &dpsidx, Shape &test, 00947 DShape &dtestdx) const 00948 { 00949 //Call the geometrical shape functions and derivatives 00950 double J = this->dshape_eulerian(s,psi,dpsidx); 00951 //Loop over the test functions and derivatives and set them equal to the 00952 //shape functions 00953 for(unsigned i=0;i<27;i++) 00954 { 00955 test[i] = psi[i]; 00956 dtestdx(i,0) = dpsidx(i,0); 00957 dtestdx(i,1) = dpsidx(i,1); 00958 dtestdx(i,2) = dpsidx(i,2); 00959 } 00960 //Return the jacobian 00961 return J; 00962 } 00963 00964 00965 00966 //======================================================================= 00967 /// 2D 00968 /// Derivatives of the shape functions and test functions w.r.t. to global 00969 /// (Eulerian) coordinates. Return Jacobian of mapping between 00970 /// local and global coordinates. 00971 //======================================================================= 00972 template<> 00973 inline double QCrouzeixRaviartElement<2>::dshape_and_dtest_eulerian_at_knot_nst( 00974 const unsigned &ipt, Shape &psi, 00975 DShape &dpsidx, Shape &test, 00976 DShape &dtestdx) const 00977 { 00978 //Call the geometrical shape functions and derivatives 00979 double J = this->dshape_eulerian_at_knot(ipt,psi,dpsidx); 00980 //Loop over the test functions and derivatives and set them equal to the 00981 //shape functions 00982 for(unsigned i=0;i<9;i++) 00983 { 00984 test[i] = psi[i]; 00985 dtestdx(i,0) = dpsidx(i,0); 00986 dtestdx(i,1) = dpsidx(i,1); 00987 } 00988 //Return the jacobian 00989 return J; 00990 } 00991 00992 00993 //======================================================================= 00994 /// 3D 00995 /// Derivatives of the shape functions and test functions w.r.t. to global 00996 /// (Eulerian) coordinates. Return Jacobian of mapping between 00997 /// local and global coordinates. 00998 //======================================================================= 00999 template<> 01000 inline double QCrouzeixRaviartElement<3>:: 01001 dshape_and_dtest_eulerian_at_knot_nst( 01002 const unsigned &ipt, Shape &psi, 01003 DShape &dpsidx, Shape &test, 01004 DShape &dtestdx) const 01005 { 01006 //Call the geometrical shape functions and derivatives 01007 double J = this->dshape_eulerian_at_knot(ipt,psi,dpsidx); 01008 //Loop over the test functions and derivatives and set them equal to the 01009 //shape functions 01010 for(unsigned i=0;i<27;i++) 01011 { 01012 test[i] = psi[i]; 01013 dtestdx(i,0) = dpsidx(i,0); 01014 dtestdx(i,1) = dpsidx(i,1); 01015 dtestdx(i,2) = dpsidx(i,2); 01016 } 01017 //Return the jacobian 01018 return J; 01019 } 01020 01021 01022 01023 //======================================================================= 01024 /// 2D : 01025 /// Pressure shape functions 01026 //======================================================================= 01027 template<> 01028 inline void QCrouzeixRaviartElement<2>::pshape_nst(const Vector<double> &s, 01029 Shape &psi) 01030 const 01031 { 01032 psi[0] = 1.0; 01033 psi[1] = s[0]; 01034 psi[2] = s[1]; 01035 } 01036 01037 ///Define the pressure shape and test functions 01038 template<> 01039 inline void QCrouzeixRaviartElement<2>::pshape_nst(const Vector<double> &s, 01040 Shape &psi, 01041 Shape &test) const 01042 { 01043 //Call the pressure shape functions 01044 pshape_nst(s,psi); 01045 //Loop over the test functions and set them equal to the shape functions 01046 for(unsigned i=0;i<3;i++) test[i] = psi[i]; 01047 } 01048 01049 01050 //======================================================================= 01051 /// 3D : 01052 /// Pressure shape functions 01053 //======================================================================= 01054 template<> 01055 inline void QCrouzeixRaviartElement<3>::pshape_nst(const Vector<double> &s, 01056 Shape &psi) 01057 const 01058 { 01059 psi[0] = 1.0; 01060 psi[1] = s[0]; 01061 psi[2] = s[1]; 01062 psi[3] = s[2]; 01063 } 01064 01065 ///Define the pressure shape and test functions 01066 template<> 01067 inline void QCrouzeixRaviartElement<3>::pshape_nst(const Vector<double> &s, 01068 Shape &psi, 01069 Shape &test) const 01070 { 01071 //Call the pressure shape functions 01072 pshape_nst(s,psi); 01073 //Loop over the test functions and set them equal to the shape functions 01074 for(unsigned i=0;i<4;i++) test[i] = psi[i]; 01075 } 01076 01077 01078 //======================================================================= 01079 /// Face geometry of the 2D Crouzeix_Raviart elements 01080 //======================================================================= 01081 template<> 01082 class FaceGeometry<QCrouzeixRaviartElement<2> >: public virtual QElement<1,3> 01083 { 01084 public: 01085 FaceGeometry() : QElement<1,3>() {} 01086 }; 01087 01088 //======================================================================= 01089 /// Face geometry of the 3D Crouzeix_Raviart elements 01090 //======================================================================= 01091 template<> 01092 class FaceGeometry<QCrouzeixRaviartElement<3> >: public virtual QElement<2,3> 01093 { 01094 01095 public: 01096 FaceGeometry() : QElement<2,3>() {} 01097 }; 01098 01099 //======================================================================= 01100 /// Face geometry of the FaceGeometry of the 2D Crouzeix_Raviart elements 01101 //======================================================================= 01102 template<> 01103 class FaceGeometry<FaceGeometry<QCrouzeixRaviartElement<2> > >: 01104 public virtual PointElement 01105 { 01106 public: 01107 FaceGeometry() : PointElement() {} 01108 }; 01109 01110 01111 //======================================================================= 01112 /// Face geometry of the FaceGeometry of the 3D Crouzeix_Raviart elements 01113 //======================================================================= 01114 template<> 01115 class FaceGeometry<FaceGeometry<QCrouzeixRaviartElement<3> > >: 01116 public virtual QElement<1,3> 01117 { 01118 public: 01119 FaceGeometry() : QElement<1,3>() {} 01120 }; 01121 01122 01123 01124 //////////////////////////////////////////////////////////////////////////// 01125 //////////////////////////////////////////////////////////////////////////// 01126 01127 01128 //======================================================================= 01129 /// Taylor--Hood elements are Navier--Stokes elements 01130 /// with quadratic interpolation for velocities and positions and 01131 /// continous linear pressure interpolation. They can be used 01132 /// within oomph-lib's block-preconditioning framework. 01133 //======================================================================= 01134 template <unsigned DIM> 01135 class QTaylorHoodElement : public virtual QElement<DIM,3>, 01136 public virtual NavierStokesEquations<DIM> 01137 { 01138 private: 01139 01140 /// Static array of ints to hold number of variables at node 01141 static const unsigned Initial_Nvalue[]; 01142 01143 protected: 01144 01145 /// \short Static array of ints to hold conversion from pressure 01146 /// node numbers to actual node numbers 01147 static const unsigned Pconv[]; 01148 01149 /// \short Velocity shape and test functions and their derivs 01150 /// w.r.t. to global coords at local coordinate s (taken from geometry) 01151 /// Return Jacobian of mapping between local and global coordinates. 01152 inline double dshape_and_dtest_eulerian_nst(const Vector<double> &s, 01153 Shape &psi, 01154 DShape &dpsidx, Shape &test, 01155 DShape &dtestdx) const; 01156 01157 /// \short Velocity shape and test functions and their derivs 01158 /// w.r.t. to global coords at local coordinate s (taken from geometry) 01159 /// Return Jacobian of mapping between local and global coordinates. 01160 inline double dshape_and_dtest_eulerian_at_knot_nst(const unsigned &ipt, 01161 Shape &psi, 01162 DShape &dpsidx, 01163 Shape &test, 01164 DShape &dtestdx) const; 01165 01166 /// Pressure shape functions at local coordinate s 01167 inline void pshape_nst(const Vector<double> &s, Shape &psi) const; 01168 01169 /// Pressure shape and test functions at local coordinte s 01170 inline void pshape_nst(const Vector<double> &s, Shape &psi, 01171 Shape &test) const; 01172 01173 /// Return the local equation numbers for the pressure values. 01174 inline int p_local_eqn(const unsigned &n) 01175 {return this->nodal_local_eqn(Pconv[n],p_nodal_index_nst());} 01176 01177 public: 01178 01179 /// Constructor, no internal data points 01180 QTaylorHoodElement() : QElement<DIM,3>(), NavierStokesEquations<DIM>() {} 01181 01182 /// \short Number of values (pinned or dofs) required at node n. Can 01183 /// be overwritten for hanging node version 01184 inline virtual unsigned required_nvalue(const unsigned &n) const 01185 {return Initial_Nvalue[n];} 01186 01187 /// \short Set the value at which the pressure is stored in the nodes 01188 int p_nodal_index_nst() const {return static_cast<int>(DIM);} 01189 01190 /// \short Access function for the pressure values at local pressure 01191 /// node n_p (const version) 01192 double p_nst(const unsigned &n_p) const 01193 {return this->nodal_value(Pconv[n_p],this->p_nodal_index_nst());} 01194 01195 /// Return number of pressure values 01196 unsigned npres_nst() const 01197 {return static_cast<unsigned>(pow(2.0,static_cast<int>(DIM)));} 01198 01199 /// Pin p_dof-th pressure dof and set it to value specified by p_value. 01200 void fix_pressure(const unsigned &p_dof, const double &p_value) 01201 { 01202 this->node_pt(Pconv[p_dof])->pin(this->p_nodal_index_nst()); 01203 this->node_pt(Pconv[p_dof])->set_value(this->p_nodal_index_nst(),p_value); 01204 } 01205 01206 01207 /// \short Add to the set \c paired_load_data pairs containing 01208 /// - the pointer to a Data object 01209 /// and 01210 /// - the index of the value in that Data object 01211 /// . 01212 /// for all values (pressures, velocities) that affect the 01213 /// load computed in the \c get_load(...) function. 01214 void identify_load_data( 01215 std::set<std::pair<Data*,unsigned> > &paired_load_data); 01216 01217 01218 /// \short Add to the set \c paired_pressure_data pairs 01219 /// containing 01220 /// - the pointer to a Data object 01221 /// and 01222 /// - the index of the value in that Data object 01223 /// . 01224 /// for all pressure values that affect the 01225 /// load computed in the \c get_load(...) function. 01226 void identify_pressure_data( 01227 std::set<std::pair<Data*,unsigned> > &paired_pressure_data); 01228 01229 01230 /// Redirect output to NavierStokesEquations output 01231 void output(std::ostream &outfile) 01232 {NavierStokesEquations<DIM>::output(outfile);} 01233 01234 /// Redirect output to NavierStokesEquations output 01235 void output(std::ostream &outfile, const unsigned &nplot) 01236 {NavierStokesEquations<DIM>::output(outfile,nplot);} 01237 01238 /// Redirect output to NavierStokesEquations output 01239 void output(FILE* file_pt) {NavierStokesEquations<DIM>::output(file_pt);} 01240 01241 /// Redirect output to NavierStokesEquations output 01242 void output(FILE* file_pt, const unsigned &nplot) 01243 {NavierStokesEquations<DIM>::output(file_pt,nplot);} 01244 01245 01246 /// \short Returns the number of "blocks" that degrees of freedom 01247 /// in this element are sub-divided into: Velocity and pressure. 01248 unsigned ndof_types() 01249 { 01250 return DIM+1; 01251 } 01252 01253 /// \short Create a list of pairs for all unknowns in this element, 01254 /// so that the first entry in each pair contains the global equation 01255 /// number of the unknown, while the second one contains the number 01256 /// of the "block" that this unknown is associated with. 01257 /// (Function can obviously only be called if the equation numbering 01258 /// scheme has been set up.) Velocity=0; Pressure=1 01259 void get_dof_numbers_for_unknowns( 01260 std::list<std::pair<unsigned long, unsigned> >& block_lookup_list); 01261 01262 01263 }; 01264 01265 //Inline functions 01266 01267 //========================================================================== 01268 /// 2D : 01269 /// Derivatives of the shape functions and test functions w.r.t to 01270 /// global (Eulerian) coordinates. Return Jacobian of mapping between 01271 /// local and global coordinates. 01272 //========================================================================== 01273 template<> 01274 inline double QTaylorHoodElement<2>::dshape_and_dtest_eulerian_nst( 01275 const Vector<double> &s, 01276 Shape &psi, 01277 DShape &dpsidx, Shape &test, 01278 DShape &dtestdx) const 01279 { 01280 //Call the geometrical shape functions and derivatives 01281 double J = this->dshape_eulerian(s,psi,dpsidx); 01282 //Loop over the test functions and derivatives and set them equal to the 01283 //shape functions 01284 for(unsigned i=0;i<9;i++) 01285 { 01286 test[i] = psi[i]; 01287 dtestdx(i,0) = dpsidx(i,0); 01288 dtestdx(i,1) = dpsidx(i,1); 01289 } 01290 //Return the jacobian 01291 return J; 01292 } 01293 01294 01295 //========================================================================== 01296 /// 3D : 01297 /// Derivatives of the shape functions and test functions w.r.t to 01298 /// global (Eulerian) coordinates. Return Jacobian of mapping between 01299 /// local and global coordinates. 01300 //========================================================================== 01301 template<> 01302 inline double QTaylorHoodElement<3>::dshape_and_dtest_eulerian_nst( 01303 const Vector<double> &s, 01304 Shape &psi, 01305 DShape &dpsidx, Shape &test, 01306 DShape &dtestdx) const 01307 { 01308 //Call the geometrical shape functions and derivatives 01309 double J = this->dshape_eulerian(s,psi,dpsidx); 01310 //Loop over the test functions and derivatives and set them equal to the 01311 //shape functions 01312 for(unsigned i=0;i<27;i++) 01313 { 01314 test[i] = psi[i]; 01315 dtestdx(i,0) = dpsidx(i,0); 01316 dtestdx(i,1) = dpsidx(i,1); 01317 dtestdx(i,2) = dpsidx(i,2); 01318 } 01319 //Return the jacobian 01320 return J; 01321 } 01322 01323 01324 //========================================================================== 01325 /// 2D : 01326 /// Derivatives of the shape functions and test functions w.r.t to 01327 /// global (Eulerian) coordinates. Return Jacobian of mapping between 01328 /// local and global coordinates. 01329 //========================================================================== 01330 template<> 01331 inline double QTaylorHoodElement<2>::dshape_and_dtest_eulerian_at_knot_nst( 01332 const unsigned &ipt,Shape &psi, DShape &dpsidx, Shape &test, 01333 DShape &dtestdx) const 01334 { 01335 //Call the geometrical shape functions and derivatives 01336 double J = this->dshape_eulerian_at_knot(ipt,psi,dpsidx); 01337 //Loop over the test functions and derivatives and set them equal to the 01338 //shape functions 01339 for(unsigned i=0;i<9;i++) 01340 { 01341 test[i] = psi[i]; 01342 dtestdx(i,0) = dpsidx(i,0); 01343 dtestdx(i,1) = dpsidx(i,1); 01344 } 01345 //Return the jacobian 01346 return J; 01347 } 01348 01349 01350 //========================================================================== 01351 /// 3D : 01352 /// Derivatives of the shape functions and test functions w.r.t to 01353 /// global (Eulerian) coordinates. Return Jacobian of mapping between 01354 /// local and global coordinates. 01355 //========================================================================== 01356 template<> 01357 inline double QTaylorHoodElement<3>::dshape_and_dtest_eulerian_at_knot_nst( 01358 const unsigned &ipt,Shape &psi, DShape &dpsidx, Shape &test, 01359 DShape &dtestdx) const 01360 { 01361 //Call the geometrical shape functions and derivatives 01362 double J = this->dshape_eulerian_at_knot(ipt,psi,dpsidx); 01363 //Loop over the test functions and derivatives and set them equal to the 01364 //shape functions 01365 for(unsigned i=0;i<27;i++) 01366 { 01367 test[i] = psi[i]; 01368 dtestdx(i,0) = dpsidx(i,0); 01369 dtestdx(i,1) = dpsidx(i,1); 01370 dtestdx(i,2) = dpsidx(i,2); 01371 } 01372 //Return the jacobian 01373 return J; 01374 } 01375 01376 01377 //========================================================================== 01378 /// 2D : 01379 /// Pressure shape functions 01380 //========================================================================== 01381 template<> 01382 inline void QTaylorHoodElement<2>::pshape_nst(const Vector<double> &s, 01383 Shape &psi) 01384 const 01385 { 01386 //Local storage 01387 double psi1[2], psi2[2]; 01388 //Call the OneDimensional Shape functions 01389 OneDimLagrange::shape<2>(s[0],psi1); 01390 OneDimLagrange::shape<2>(s[1],psi2); 01391 01392 //Now let's loop over the nodal points in the element 01393 //s1 is the "x" coordinate, s2 the "y" 01394 for(unsigned i=0;i<2;i++) 01395 { 01396 for(unsigned j=0;j<2;j++) 01397 { 01398 /*Multiply the two 1D functions together to get the 2D function*/ 01399 psi[2*i + j] = psi2[i]*psi1[j]; 01400 } 01401 } 01402 } 01403 01404 //========================================================================== 01405 /// 3D : 01406 /// Pressure shape functions 01407 //========================================================================== 01408 template<> 01409 inline void QTaylorHoodElement<3>::pshape_nst(const Vector<double> &s, 01410 Shape &psi) 01411 const 01412 { 01413 //Local storage 01414 double psi1[2], psi2[2], psi3[2]; 01415 //Call the OneDimensional Shape functions 01416 OneDimLagrange::shape<2>(s[0],psi1); 01417 OneDimLagrange::shape<2>(s[1],psi2); 01418 OneDimLagrange::shape<2>(s[2],psi3); 01419 01420 //Now let's loop over the nodal points in the element 01421 //s0 is the "x" coordinate, s1 the "y", s2 is the "z" 01422 for(unsigned i=0;i<2;i++) 01423 { 01424 for(unsigned j=0;j<2;j++) 01425 { 01426 for(unsigned k=0;k<2;k++) 01427 { 01428 /*Multiply the three 1D functions together to get the 3D function*/ 01429 psi[4*i + 2*j + k] = psi3[i]*psi2[j]*psi1[k]; 01430 } 01431 } 01432 } 01433 } 01434 01435 01436 //========================================================================== 01437 /// 2D : 01438 /// Pressure shape and test functions 01439 //========================================================================== 01440 template<> 01441 inline void QTaylorHoodElement<2>::pshape_nst(const Vector<double> &s, 01442 Shape &psi, 01443 Shape &test) const 01444 { 01445 //Call the pressure shape functions 01446 pshape_nst(s,psi); 01447 //Loop over the test functions and set them equal to the shape functions 01448 for(unsigned i=0;i<4;i++) test[i] = psi[i]; 01449 } 01450 01451 01452 //========================================================================== 01453 /// 3D : 01454 /// Pressure shape and test functions 01455 //========================================================================== 01456 template<> 01457 inline void QTaylorHoodElement<3>::pshape_nst(const Vector<double> &s, 01458 Shape &psi, 01459 Shape &test) const 01460 { 01461 //Call the pressure shape functions 01462 pshape_nst(s,psi); 01463 //Loop over the test functions and set them equal to the shape functions 01464 for(unsigned i=0;i<8;i++) test[i] = psi[i]; 01465 } 01466 01467 01468 01469 //======================================================================= 01470 /// Face geometry of the 2D Taylor_Hood elements 01471 //======================================================================= 01472 template<> 01473 class FaceGeometry<QTaylorHoodElement<2> >: public virtual QElement<1,3> 01474 { 01475 public: 01476 FaceGeometry() : QElement<1,3>() {} 01477 }; 01478 01479 //======================================================================= 01480 /// Face geometry of the 3D Taylor_Hood elements 01481 //======================================================================= 01482 template<> 01483 class FaceGeometry<QTaylorHoodElement<3> >: public virtual QElement<2,3> 01484 { 01485 01486 public: 01487 FaceGeometry() : QElement<2,3>() {} 01488 }; 01489 01490 01491 //======================================================================= 01492 /// Face geometry of the FaceGeometry of the 2D Taylor Hoodelements 01493 //======================================================================= 01494 template<> 01495 class FaceGeometry<FaceGeometry<QTaylorHoodElement<2> > >: 01496 public virtual PointElement 01497 { 01498 public: 01499 FaceGeometry() : PointElement() {} 01500 }; 01501 01502 01503 //======================================================================= 01504 /// Face geometry of the FaceGeometry of the 3D Taylor_Hood elements 01505 //======================================================================= 01506 template<> 01507 class FaceGeometry<FaceGeometry<QTaylorHoodElement<3> > >: 01508 public virtual QElement<1,3> 01509 { 01510 public: 01511 FaceGeometry() : QElement<1,3>() {} 01512 }; 01513 01514 } 01515 01516 #endif
1.4.7