Example codes
and tutorials
The (Not-so) Quick Guide
List of tutorials/demo codes
Single-Physics Problems
Poisson
Adaptivity illustrated for Poisson
Advection-Diffusion
Unsteady heat equation
Linear wave equation
The Young-Laplace equation
Navier-Stokes
Free-surface Navier-Stokes
Axisymmetric Navier-Stokes
Solid mechanics
Beam structures
Shell structures
Multi-physics Problems
Fluid-structure interaction
Boussinesq convection
Steady thermoelasticity
Methods-based example codes and tutorials
Mesh generation
Linear solvers and preconditioners
Visualisation of the results
Parallel processing
How to write a new element
How to write a new refineable element
Default nonlinear solvers -- the sequence of action functions
...
Documentation
FE theory and top-down discussion of the data structure
The (Not-so) Quick Guide
Comprehensive bottom-up discussion of the data structure
List of available structured and unstructured meshes
Linear solvers and preconditioners
Visualisation of the results
Parallel processing
Coding conventions and C++ style
Creating documentation
Optimisation - robustness vs. "raw speed"
Linear vs. nonlinear problems
Storing shape functions
Changing the default "full" integration scheme
Disabling the ALE formulation of unsteady equations
C vs. C++ output
Different sparse assembly techniques and the STL memory pool
Publications
Publications
Talks
Journal publications
Theses
Picture show
Download
Copyright
Download/installation instructions
Download page
FAQ & Contact
FAQ
Change log
Bugs and other known problems
Completeness of the library & our "To-Do List"
Contact the developers
Get involved

 


Beta release!

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

oomph-lib AT maths DOT man DOT ac DOT uk

if you wish to be informed of the library's "official" release.

solid_elements.h

Go to the documentation of this file.
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 general solid mechanics elements
00029 
00030 //Include guards to prevent multiple inclusion of the header
00031 #ifndef OOMPH_ELASTICITY_ELEMENTS_HEADER
00032 #define OOMPH_ELASTICITY_ELEMENTS_HEADER
00033 
00034 // Config header generated by autoconfig
00035 #ifdef HAVE_CONFIG_H
00036   #include <oomph-lib-config.h>
00037 #endif
00038 
00039 
00040 //OOMPH-LIB headers
00041 #include "../generic/Qelements.h"
00042 #include "../generic/Telements.h"
00043 #include "../generic/mesh.h"
00044 #include "../generic/hermite_elements.h"
00045 #include "../constitutive/constitutive_laws.h"
00046 
00047 
00048 namespace oomph
00049 {
00050  
00051 
00052 //=======================================================================
00053 /// A base class for elements that solve the equations of solid mechanics, 
00054 /// based on the principle of virtual displacements in Cartesian coordinates.
00055 /// Combines a few generic functions that are shared by  PVDEquations
00056 /// and  PVDEquationsWithPressure.
00057 //=======================================================================
00058  template <unsigned DIM>
00059   class PVDEquationsBase : public virtual SolidFiniteElement
00060   {
00061     public:
00062    
00063    /// \short Function pointer to function that specifies the isotropic
00064    /// growth as a function of the Lagrangian coordinates FCT(xi,gamma(xi)) -- 
00065    /// xi is a Vector! 
00066    typedef void (*IsotropicGrowthFctPt)
00067     (const Vector<double>& xi, double& gamma);
00068    
00069    /// \short Function pointer to function that specifies the body force
00070    /// as a function of the Lagrangian coordinates and time FCT(t,xi,b) -- 
00071    /// xi and b are  Vectors! 
00072    typedef void (*BodyForceFctPt)(const double& t,
00073                                   const Vector<double>& xi, 
00074                                   Vector<double>& b);
00075    
00076    /// \short Constructor: Set null pointers for constitutive law and for
00077    /// isotropic growth function. Set physical parameter values to 
00078    /// default values, enable inertia and set body force to zero.
00079    /// Default evaluation of Jacobian: analytically rather than by FD.
00080    PVDEquationsBase() :  Isotropic_growth_fct_pt(0), Constitutive_law_pt(0),
00081     Lambda_sq_pt(&Default_lambda_sq_value), Unsteady(true), 
00082     Body_force_fct_pt(0), Evaluate_jacobian_by_fd(false) {}
00083    
00084    
00085    /// Return the constitutive law pointer
00086    ConstitutiveLaw* &constitutive_law_pt() {return Constitutive_law_pt;}
00087    
00088 
00089    ///Access function for timescale ratio (nondim density)
00090    const double& lambda_sq() const {return *Lambda_sq_pt;}
00091    
00092    
00093    /// Access function for pointer to timescale ratio (nondim density)
00094    double* &lambda_sq_pt() {return Lambda_sq_pt;}
00095    
00096    
00097    /// Access function: Pointer to isotropic growth function
00098    IsotropicGrowthFctPt& isotropic_growth_fct_pt() 
00099     {return Isotropic_growth_fct_pt;}
00100    
00101 
00102    /// Access function: Pointer to isotropic growth function (const version)
00103    IsotropicGrowthFctPt isotropic_growth_fct_pt() const
00104     {return Isotropic_growth_fct_pt;}
00105    
00106    /// Access function: Pointer to body force function
00107    BodyForceFctPt& body_force_fct_pt() {return Body_force_fct_pt;}
00108    
00109    /// Access function: Pointer to body force function (const version)
00110    BodyForceFctPt body_force_fct_pt() const {return Body_force_fct_pt;}
00111    
00112    ///Access function to flag that switches inertia on/off
00113    bool& unsteady() {return Unsteady;}
00114    
00115    ///Access function to flag that switches inertia on/off (const version)
00116    bool unsteady() const {return Unsteady;}
00117    
00118    /// \short Unpin all solid pressure dofs in the element 
00119    virtual void unpin_elemental_solid_pressure_dofs()=0;
00120 
00121    ///Pin the element's redundant solid pressures (needed for refinement)
00122    virtual void pin_elemental_redundant_nodal_solid_pressures() {}
00123     
00124    /// \short  Loop over all elements in Vector (which typically contains
00125    /// all the elements in a refineable solid mesh) and pin the nodal solid 
00126    /// pressure  degrees of freedom that are not being used. Function uses 
00127    /// the member function
00128    /// - \c PVDEquationsBase<DIM>::
00129    ///      pin_elemental_redundant_nodal_pressure_dofs()
00130    /// .
00131    /// which is empty by default and should be implemented for
00132    /// elements with nodal solid pressure degrees of freedom  
00133    /// (e.g. solid elements with continuous pressure interpolation.)
00134    static void pin_redundant_nodal_solid_pressures(
00135     const Vector<GeneralisedElement*>& element_pt)
00136     {
00137      // Loop over all elements 
00138      unsigned n_element = element_pt.size();
00139      for(unsigned e=0;e<n_element;e++)
00140       {
00141        dynamic_cast<PVDEquationsBase<DIM>*>(element_pt[e])->
00142         pin_elemental_redundant_nodal_solid_pressures();
00143       }
00144     }
00145 
00146    /// \short Unpin all pressure dofs in elements listed in vector.
00147    static void unpin_all_solid_pressure_dofs(const Vector<GeneralisedElement*>&
00148                                              element_pt)
00149     {
00150      // Loop over all elements
00151      unsigned n_element = element_pt.size();
00152      for(unsigned e=0;e<n_element;e++)
00153       {
00154        dynamic_cast<PVDEquationsBase<DIM>*>(element_pt[e])->
00155         unpin_elemental_solid_pressure_dofs();
00156       }
00157     }
00158    
00159    /// \short Return the 2nd Piola Kirchoff stress tensor, as calculated
00160    /// from the constitutive law at specified local coordinate
00161    /// (needed by \c get_principal_stress(...), so I'm afraid I will
00162    /// have to insist that you implement it...
00163    virtual void get_stress(const Vector<double> &s, 
00164                            DenseMatrix<double> &sigma)=0;
00165    
00166    /// \short Return the strain tensor
00167    void get_strain(const Vector<double> &s, DenseMatrix<double> &strain) const;
00168    
00169    /// \short Return the deformed covariant basis vectors
00170    /// at specified local coordinate: \c def_covariant_basis(i,j)
00171    /// is the j-th component of the i-th basis vector.
00172    void get_deformed_covariant_basis_vectors(const Vector<double> &s,
00173                                              DenseMatrix<double>& 
00174                                              def_covariant_basis); 
00175    
00176    
00177    /// \short Compute principal stress vectors and (scalar) principal stresses
00178    /// at specified local coordinate. \c  principal_stress_vector(i,j)
00179    /// is the j-th component of the i-th principal stress vector.
00180    void get_principal_stress(const Vector<double> &s,
00181                              DenseMatrix<double>& principal_stress_vector,
00182                              Vector<double>& principal_stress);
00183    
00184    
00185    /// \short Evaluate isotropic growth function at Lagrangian coordinate xi
00186    /// and/or local coordinate s. 
00187    /// (returns 1, i.e. no growth, if no function pointer has been set)
00188    /// This function is virtual to allow overloading in multi-physics
00189    /// problems where the growth function might be determined by 
00190    /// another system of equations
00191    virtual inline void get_isotropic_growth(const unsigned& ipt,
00192                                             const Vector<double> &s,
00193                                             const Vector<double>& xi, 
00194                                             double& gamma) const
00195     {
00196      //If no function has been set, return 1
00197      if(Isotropic_growth_fct_pt==0) {gamma = 1.0;}
00198      else
00199       {
00200        // Get isotropic growth
00201        (*Isotropic_growth_fct_pt)(xi,gamma);
00202       }
00203     }
00204 
00205    
00206    /// \short Evaluate body force at Lagrangian coordinate xi at present time
00207    /// (returns zero vector if no body force function pointer has been set)
00208    inline void body_force(const Vector<double>& xi, 
00209                           Vector<double>& b) const
00210     {
00211      //If no function has been set, return zero vector
00212      if(Body_force_fct_pt==0)
00213       {
00214        // Get spatial dimension of element
00215        unsigned n=dim();
00216        for (unsigned i=0;i<n;i++)
00217         {
00218          b[i] = 0.0;
00219         }
00220       }
00221      else
00222       {
00223        // Get body force
00224        if (time_pt()!=0)
00225         {
00226          (*Body_force_fct_pt)(time_pt()->time(),xi,b);
00227         }
00228        else
00229         {
00230          (*Body_force_fct_pt)(0.0,xi,b);
00231         }
00232       }
00233     }
00234 
00235 
00236 
00237 
00238    /// \short returns the number of DOF types associated with this element. 
00239    unsigned ndof_types()
00240     {
00241      return 2*DIM;
00242     }
00243  
00244    /// \short Create a list of pairs for all unknowns in this element,
00245    /// so that the first entry in each pair contains the global equation
00246    /// number of the unknown, while the second one contains the number
00247    /// of the "DOF" that this unknown is associated with.
00248    /// (Function can obviously only be called if the equation numbering
00249    /// scheme has been set up.)\n
00250    /// E.g. in a 3D problem there are 6 types of DOF:\n
00251    /// 0 - x displacement (without lagr mult traction)\n
00252    /// 1 - y displacement (without lagr mult traction)\n
00253    /// 2 - z displacement (without lagr mult traction)\n
00254    /// 4 - x displacement (with lagr mult traction)\n
00255    /// 5 - y displacement (with lagr mult traction)\n
00256    /// 6 - z displacement (with lagr mult traction)\n
00257    void get_dof_numbers_for_unknowns(
00258     std::list<std::pair<unsigned long,unsigned> >& block_lookup_list)
00259     {
00260      // temporary pair (used to store block lookup prior to being added to list
00261      std::pair<unsigned,unsigned> block_lookup;
00262    
00263      // number of nodes
00264      const unsigned n_node = this->nnode();
00265    
00266      //Get the number of position dofs and dimensions at the node
00267      const unsigned n_position_type = nnodal_position_type();
00268      const unsigned nodal_dim = nodal_dimension();
00269    
00270      //Integer storage for local unknown
00271      int local_unknown=0;
00272    
00273      //Loop over the nodes
00274      for(unsigned n=0;n<n_node;n++)
00275       {
00276        unsigned offset = 0;
00277        if (this->node_pt(n)->nvalue() != this->required_nvalue(n))
00278         {
00279          offset = DIM;
00280         }
00281 
00282        //Loop over position dofs
00283        for(unsigned k=0;k<n_position_type;k++)
00284         {
00285          //Loop over dimension
00286          for(unsigned i=0;i<nodal_dim;i++)
00287           {
00288            //If the variable is free
00289            local_unknown = position_local_eqn(n,k,i);
00290          
00291            // ignore pinned values
00292            if (local_unknown >= 0)
00293             {
00294              // store block lookup in temporary pair: First entry in pair
00295              // is global equation number; second entry is block type
00296              block_lookup.first = this->eqn_number(local_unknown);
00297              block_lookup.second = offset+i;
00298            
00299              // add to list
00300              block_lookup_list.push_front(block_lookup);
00301            
00302             }
00303           }
00304         }
00305       }
00306     }
00307       
00308    /// Is Jacobian evaluated by FD? Else: Analytically.
00309    bool& evaluate_jacobian_by_fd() {return Evaluate_jacobian_by_fd;}
00310    
00311   protected:
00312    
00313    /// Pointer to isotropic growth function
00314    IsotropicGrowthFctPt Isotropic_growth_fct_pt;
00315    
00316    /// Pointer to the constitutive law
00317    ConstitutiveLaw *Constitutive_law_pt;
00318 
00319    /// Timescale ratio (non-dim. density)
00320    double* Lambda_sq_pt;
00321    
00322    /// Flag that switches inertia on/off
00323    bool Unsteady;
00324 
00325    /// Pointer to body force function
00326    BodyForceFctPt Body_force_fct_pt;
00327    
00328    /// Static default value for timescale ratio (1.0 -- for natural scaling) 
00329    static double Default_lambda_sq_value;
00330    
00331    /// Use FD to evaluate Jacobian
00332    bool Evaluate_jacobian_by_fd;
00333 
00334   };
00335  
00336  
00337 //=======================================================================
00338 /// A class for elements that solve the equations of solid mechanics, based
00339 /// on the principle of virtual displacements in cartesian coordinates.
00340 //=======================================================================
00341 template <unsigned DIM>
00342 class PVDEquations : public PVDEquationsBase<DIM>
00343 {
00344 
00345     public:
00346    
00347    /// \short  Constructor
00348    PVDEquations() {}
00349    
00350    /// \short Return the 2nd Piola Kirchoff stress tensor, as calculated
00351    /// from the constitutive law at specified local coordinate
00352    void get_stress(const Vector<double> &s, DenseMatrix<double> &sigma);
00353    
00354    /// \short Fill in the residuals for the solid equations (the discretised
00355    /// principle of virtual displacements)
00356    void fill_in_contribution_to_residuals(Vector<double> &residuals)
00357     {
00358      fill_in_generic_contribution_to_residuals_pvd(
00359       residuals,GeneralisedElement::Dummy_matrix,0);
00360     }
00361    
00362    /// \short Fill in contribution to Jacobian (either by FD or analytically,
00363    /// control this via evaluate_jacobian_by_fd()
00364    void fill_in_contribution_to_jacobian(Vector<double> &residuals,
00365                                          DenseMatrix<double> &jacobian)
00366     {
00367      
00368      //Solve for the consistent acceleration in Newmark scheme? 
00369      if (this->Solve_for_consistent_newmark_accel_flag) 
00370       {        
00371        // Add the contribution to the residuals -- these are the
00372        // full residuals of whatever solid equations we're solving
00373        this->fill_in_contribution_to_residuals(residuals); 
00374 
00375        // Jacobian is not the Jacobian associated with these
00376        // residuals (treating the postions as unknowns)
00377        // but the derivatives w.r.t. to the discrete generalised
00378        // accelerations in the Newmark scheme -- the Jacobian
00379        // is therefore the associated mass matrix, multiplier
00380        // by suitable scaling factors
00381        this->fill_in_jacobian_for_newmark_accel(jacobian);
00382        return;
00383       } 
00384      
00385      // Are we assigning a solid initial condition?
00386      if (this->Solid_ic_pt!=0)
00387       {
00388        this->fill_in_jacobian_for_solid_ic(residuals,jacobian);
00389        return;
00390       }
00391      
00392      
00393      // Use FD 
00394      if ((this->Evaluate_jacobian_by_fd)) 
00395       {
00396        //Add the contribution to the residuals
00397        this->fill_in_contribution_to_residuals(residuals);
00398        
00399        //Get the solid entries in the jacobian using finite differences
00400        this->fill_in_jacobian_from_solid_position_by_fd(jacobian);
00401       }
00402      // Do it analytically
00403      else
00404       {
00405        fill_in_generic_contribution_to_residuals_pvd(residuals,jacobian,1);
00406       }
00407     }
00408    
00409 
00410    /// Output: x,y,[z],xi0,xi1,[xi2],gamma
00411    void output(std::ostream &outfile) 
00412     {
00413      unsigned n_plot=5;
00414      output(outfile,n_plot);
00415     }
00416    
00417    /// Output: x,y,[z],xi0,xi1,[xi2],gamma
00418    void output(std::ostream &outfile, const unsigned &n_plot);
00419    
00420    
00421    /// C-style output: x,y,[z],xi0,xi1,[xi2],gamma
00422    void output(FILE* file_pt) 
00423     {
00424      unsigned n_plot=5;
00425      output(file_pt,n_plot);
00426     }
00427    
00428    /// Output: x,y,[z],xi0,xi1,[xi2],gamma
00429    void output(FILE* file_pt, const unsigned &n_plot);
00430       
00431    
00432     protected:
00433    
00434    /// \short Compute element residual Vector only (if flag=and/or element 
00435    /// Jacobian matrix 
00436    virtual void fill_in_generic_contribution_to_residuals_pvd(
00437     Vector<double> &residuals, DenseMatrix<double> &jacobian, 
00438     const unsigned& flag);
00439       
00440    /// \short Return the 2nd Piola Kirchhoff stress tensor, as 
00441    /// calculated from the constitutive law: Pass metric tensors in the 
00442    /// stress free and current configurations.
00443    inline void get_stress(const DenseMatrix<double> &g, 
00444                           const DenseMatrix<double> &G,
00445                           DenseMatrix<double> &sigma)
00446     {
00447 #ifdef PARANOID
00448      //If the pointer to the constitutive law hasn't been set, issue an error
00449      if(this->Constitutive_law_pt==0)
00450       {
00451        //Write an error message
00452        std::string error_message =
00453         "Elements derived from PVDEquations must have a constitutive law:\n";
00454        error_message +=
00455         "set one using the constitutive_law_pt() member function";
00456        //Throw the error
00457        throw OomphLibError(error_message,"PVDEquations<DIM>::get_stress()",
00458                            OOMPH_EXCEPTION_LOCATION);
00459       }
00460 #endif
00461      this->Constitutive_law_pt
00462       ->calculate_second_piola_kirchhoff_stress(g,G,sigma);
00463     } 
00464    
00465 
00466     private:
00467  
00468    /// Unpin all solid pressure dofs -- empty as there are no pressures
00469    void unpin_elemental_solid_pressure_dofs(){}
00470      
00471   }; 
00472 
00473 
00474 //===========================================================================
00475 /// An Element that solves the solid mechanics equations, based on
00476 /// the principle of virtual displacements in Cartesian coordinates,
00477 /// using SolidQElements for the interpolation of the variable positions. 
00478 //============================================================================
00479  template<unsigned DIM, unsigned NNODE_1D>
00480   class QPVDElement : public virtual SolidQElement<DIM,NNODE_1D>,
00481   public virtual PVDEquations<DIM>
00482   {
00483     public:
00484    
00485    /// Constructor, there are no internal data points
00486    QPVDElement() : SolidQElement<DIM,NNODE_1D>(), PVDEquations<DIM>() { }
00487    
00488    /// Output function
00489    void output(std::ostream &outfile) {PVDEquations<DIM>::output(outfile);}
00490    
00491    /// Output function
00492    void output(std::ostream &outfile, const unsigned &n_plot)
00493     {PVDEquations<DIM>::output(outfile,n_plot);}
00494    
00495    
00496    /// C-style output function
00497    void output(FILE* file_pt) {PVDEquations<DIM>::output(file_pt);}
00498    
00499    /// C-style output function
00500    void output(FILE* file_pt, const unsigned &n_plot)
00501     {PVDEquations<DIM>::output(file_pt,n_plot);}
00502   
00503   };
00504 
00505 
00506 //============================================================================
00507 /// FaceGeometry of a 2D QPVDElement element
00508 //============================================================================
00509  template<unsigned NNODE_1D>
00510   class FaceGeometry<QPVDElement<2,NNODE_1D> > :
00511   public virtual SolidQElement<1,NNODE_1D>
00512   {
00513     public:
00514    /// Constructor must call the constructor of the underlying solid element
00515    FaceGeometry() : SolidQElement<1,NNODE_1D>() {}
00516   };
00517  
00518 
00519  //==============================================================
00520 /// FaceGeometry of the FaceGeometry of the 2D QPVDElement 
00521 //==============================================================
00522 template<unsigned NNODE_1D>
00523 class FaceGeometry<FaceGeometry<QPVDElement<2,NNODE_1D> > >:
00524  public virtual PointElement
00525 {
00526   public:
00527  //Make sure that we call the constructor of the SolidQElement
00528  //Only the Intel compiler seems to need this!
00529  FaceGeometry() : PointElement() {}
00530 };
00531 
00532 
00533 //============================================================================
00534 /// FaceGeometry of a 3D QPVDElement element
00535 //============================================================================
00536 template<unsigned NNODE_1D>
00537  class FaceGeometry<QPVDElement<3,NNODE_1D> > :
00538  public virtual SolidQElement<2,NNODE_1D>
00539  {
00540    public:
00541   /// Constructor must call the constructor of the underlying solid element
00542   FaceGeometry() : SolidQElement<2,NNODE_1D>() {}
00543  };
00544  
00545 //============================================================================
00546 /// FaceGeometry of FaceGeometry of a 3D QPVDElement element
00547 //============================================================================
00548  template<unsigned NNODE_1D>
00549   class FaceGeometry<FaceGeometry<QPVDElement<3,NNODE_1D> > > :
00550   public virtual SolidQElement<1,NNODE_1D>
00551   {
00552     public:
00553    /// Constructor must call the constructor of the underlying solid element
00554    FaceGeometry() : SolidQElement<1,NNODE_1D>() {}
00555   };
00556 
00557 //===========================================================================
00558 /// An Element that solves the principle of virtual diplacements 
00559 /// using Hermite interpolation for the variable positions.
00560 //============================================================================
00561  template<unsigned DIM>
00562   class HermitePVDElement : public virtual SolidQHermiteElement<DIM>, 
00563   public virtual PVDEquations<DIM>
00564   {
00565    
00566     public:
00567    
00568    /// Constructor, there are no internal data points
00569    HermitePVDElement() : SolidQHermiteElement<DIM>(), 
00570     PVDEquations<DIM>() { }
00571    
00572    /// SolidQHermiteElement output function
00573    void output(std::ostream &outfile)
00574     {SolidQHermiteElement<DIM>::output(outfile);}
00575    
00576    /// SolidQHermiteElement output function
00577    void output(std::ostream &outfile, const unsigned &n_plot)
00578     {SolidQHermiteElement<DIM>::output(outfile,n_plot);}
00579    
00580    /// C-style SolidQHermiteElement output function
00581    void output(FILE* file_pt) {SolidQHermiteElement<DIM>::output(file_pt);}
00582    
00583    /// C-style SolidQHermiteElement output function
00584    void output(FILE* file_pt, const unsigned &n_plot)
00585     {SolidQHermiteElement<DIM>::output(file_pt,n_plot);}
00586    
00587   };
00588 
00589 
00590 
00591 ///////////////////////////////////////////////////////////////////////
00592 ///////////////////////////////////////////////////////////////////////
00593 ///////////////////////////////////////////////////////////////////////
00594 
00595 
00596 
00597 //=========================================================================
00598 /// A class for elements that solve the equations of solid mechanics,
00599 /// based on the principle of virtual displacements, with a 
00600 /// contitutive equation that involves a pressure. This 
00601 /// formulation is required in the case of incompressible materials, in
00602 /// which the additional constraint that volume must be conserved is applied.
00603 /// In this case, the Incompressible flag must be set to true. If the 
00604 /// Incompressible flag is not set to true, we use the nearly-incompressible
00605 /// formulation of the constitutive equations.
00606 //============================================================================
00607  template <unsigned DIM>
00608   class PVDEquationsWithPressure : public PVDEquationsBase<DIM>
00609   {
00610     private:
00611    
00612    /// \short Static "magic" number that indicates that the solid pressure
00613    /// is not stored at a node
00614    static int Solid_pressure_not_stored_at_node;
00615    
00616     public:
00617    
00618    /// Constructor, by default the element is NOT incompressible.
00619    PVDEquationsWithPressure() : Incompressible(false) {}
00620    
00621    /// \short Return the 2nd Piola Kirchoff stress tensor, as calculated
00622    /// from the constitutive law at specified local coordinate
00623    void get_stress(const Vector<double> &s, DenseMatrix<double> &sigma);
00624    
00625    /// Return the boolean incompressible
00626    bool &incompressible() {return Incompressible;}
00627    
00628    /// Return the number of solid pressure degrees of freedom
00629    virtual unsigned npres_solid() const=0;
00630    
00631    /// Return the lth solid pressure
00632    virtual double solid_p(const unsigned &l)=0;
00633    
00634    /// Set the lth solid pressure to p_value
00635    virtual void set_solid_p(const unsigned &l, const double &p_value)=0;
00636    
00637    /// \short Return the index at which the solid pressure is stored if it
00638    /// is stored at the nodes. If not stored at the nodes this will return
00639    /// a negative number.
00640    virtual int solid_p_nodal_index() const 
00641     {return Solid_pressure_not_stored_at_node;}
00642 
00643    /// Fill in the residuals
00644    void fill_in_contribution_to_residuals(Vector<double> &residuals)
00645     {
00646      //Call the generic residuals function with flag set to 0
00647      //using a dummy matrix argument
00648      fill_in_generic_residual_contribution_pvd_with_pressure(
00649       residuals,GeneralisedElement::Dummy_matrix,0);
00650     }
00651    
00652    /// \short Fill in contribution to Jacobian (either by FD or analytically,
00653    /// for the positional variables; control this via 
00654    /// evaluate_jacobian_by_fd(). Note: Jacobian entries arising from
00655    /// derivatives w.r.t. pressure terms are always computed analytically.
00656    void fill_in_contribution_to_jacobian(Vector<double> &residuals,
00657                                          DenseMatrix<double> &jacobian)
00658     {
00659 
00660      //Solve for the consistent acceleration in the Newmark scheme
00661      //Note that this replaces solid entries only
00662      if ((this->Solve_for_consistent_newmark_accel_flag)||
00663          (this->Solid_ic_pt!=0))
00664       {
00665        std::string error_message ="Can't assign consistent Newmark history\n";
00666        error_message += " values for solid element with pressure dofs\n";
00667         
00668        throw OomphLibError(
00669         error_message,
00670         "PVDEquationsWithPressure<DIM>::fill_in_contribution_to_jacobian()",
00671         OOMPH_EXCEPTION_LOCATION);
00672       }
00673      
00674      // FD
00675      if (this->Evaluate_jacobian_by_fd)
00676       {
00677        // Call the generic routine with the flag set to 2: Computes residuals
00678        // and derivatives w.r.t. to pressure variables
00679        fill_in_generic_residual_contribution_pvd_with_pressure(
00680         residuals,jacobian,2);
00681        
00682        // Call the finite difference routine for the deriatives w.r.t.
00683        // the positional variables
00684        this->fill_in_jacobian_from_solid_position_by_fd(jacobian);
00685        
00686       }
00687      // Do it fully analytically
00688      else
00689       {
00690        //Call the generic routine with the flag set to 1: Get residual
00691        // and fully analytical Jacobian
00692        fill_in_generic_residual_contribution_pvd_with_pressure(
00693         residuals,jacobian,1);
00694       }
00695 
00696     }
00697    
00698    
00699    /// Return the interpolated_solid_pressure 
00700    double interpolated_solid_p(const Vector<double> &s) 
00701     {
00702      //Find number of nodes
00703      unsigned n_solid_pres = npres_solid();
00704      //Local shape function
00705      Shape psisp(n_solid_pres);
00706      //Find values of shape function
00707      solid_pshape(s,psisp);
00708      
00709      //Initialise value of solid_p
00710      double interpolated_solid_p = 0.0;
00711      //Loop over the local nodes and sum
00712      for(unsigned l=0;l<n_solid_pres;l++) 
00713       {interpolated_solid_p += solid_p(l)*psisp[l];}
00714      
00715      return(interpolated_solid_p);
00716     }
00717    
00718 
00719    /// Output: x,y,[z],xi0,xi1,[xi2],p,gamma
00720    void output(std::ostream &outfile) 
00721     {
00722      unsigned n_plot=5;
00723      output(outfile,n_plot);
00724     }
00725    
00726    /// Output: x,y,[z],xi0,xi1,[xi2],p,gamma
00727    void output(std::ostream &outfile, const unsigned &n_plot);
00728    
00729    
00730    /// C-style output: x,y,[z],xi0,xi1,[xi2],p,gamma
00731    void output(FILE* file_pt) 
00732     {
00733      unsigned n_plot=5;
00734      output(file_pt,n_plot);
00735     }
00736    
00737    /// C-style output: x,y,[z],xi0,xi1,[xi2],p,gamma
00738    void output(FILE* file_pt, const unsigned &n_plot);
00739    
00740    
00741     protected:
00742    
00743    /// \short Access function that returns local eqn number 
00744    /// information for the solid pressure
00745    virtual int solid_p_local_eqn(const unsigned &i)=0;
00746   
00747    /// \short Return the deviatoric part of the 2nd Piola Kirchhoff stress 
00748    /// tensor, as calculated from the constitutive law in the nearly 
00749    /// incompresible formulation. Also return the contravariant
00750    /// deformed metric tensor, the generalised dilatation, and the 
00751    /// inverse of the bulk modulus.
00752    void get_stress(const DenseMatrix<double> &g, const DenseMatrix<double> &G, 
00753                    DenseMatrix<double> &sigma_dev, 
00754                    DenseMatrix<double> &Gcontra, 
00755                    double &gen_dil, double &inv_kappa) 
00756     {
00757 #ifdef PARANOID
00758      //If the pointer to the constitutive law hasn't been set, issue an error
00759      if(this->Constitutive_law_pt == 0)
00760       {
00761        //Write an error message
00762        std::string error_message =
00763         "Elements derived from PVDEquationsWithPressure \n";
00764        error_message += "must have a constitutive law:\n";
00765        error_message +=
00766         "set one using the constitutive_law_pt() member function";
00767        //Throw the error
00768        throw OomphLibError(error_message,
00769                            "PVDEquationsWithPressure<DIM>::get_stress()",
00770                            OOMPH_EXCEPTION_LOCATION);
00771       }
00772 #endif
00773      this->Constitutive_law_pt->
00774       calculate_second_piola_kirchhoff_stress(g,G,sigma_dev,Gcontra,
00775                                               gen_dil,inv_kappa);
00776     }
00777    
00778    /// Return the solid pressure shape functions
00779    virtual void solid_pshape(const Vector<double> &s, Shape &psi) const=0;
00780    
00781    /// Return the stored solid shape functions at the knots
00782    void solid_pshape_at_knot(const unsigned &ipt, Shape &psi) const
00783     {
00784      //Find the dimension of the element
00785      unsigned Dim = this->dim();
00786      //Storage for local coordinates of the integration point
00787      Vector<double> s(Dim);
00788      //Set the local coordinates
00789      for(unsigned i=0;i<Dim;i++) {s[i] = this->integral_pt()->knot(ipt,i);}
00790      //Get the shape function
00791      solid_pshape(s,psi);
00792     }
00793    
00794     protected:
00795    
00796    /// Boolean to determine whether the solid is incompressible or not
00797    bool Incompressible;
00798    
00799    /// \short Returns the residuals for the discretised principle of
00800    /// virtual displacements, formulated in the incompressible/
00801    /// near-incompressible case.
00802    /// - If flag==0, compute only the residual vector.
00803    /// - If flag==1, compute residual vector and fully analytical Jacobian
00804    /// - If flag==2, also compute the pressure-related entries
00805    ///   in the Jacobian (all others need to be done by finite differencing.
00806    virtual void fill_in_generic_residual_contribution_pvd_with_pressure(
00807     Vector<double> &residuals, DenseMatrix<double> &jacobian,
00808     const unsigned& flag);
00809    
00810    /// \short  Return the deviatoric part of the 2nd Piola Kirchhoff stress 
00811    /// tensor, as calculated from the constitutive law in the 
00812    /// incompresible formulation. Also return the contravariant
00813    /// deformed metric tensor, and the 
00814    /// determinant of the deformed covariant metric tensor 
00815    /// (likely to be needed in the incompressibility constraint)
00816    void get_stress(const DenseMatrix<double> &g, const DenseMatrix<double> &G,
00817                    DenseMatrix<double> &sigma_dev, 
00818                    DenseMatrix<double> &Gcontra, 
00819                    double &detG)
00820     {
00821 #ifdef PARANOID
00822      //If the pointer to the constitutive law hasn't been set, issue an error
00823      if(this->Constitutive_law_pt == 0)
00824       {
00825        //Write an error message
00826        std::string error_message =
00827         "Elements derived from PVDEquationsWithPressure \n";
00828        error_message += "must have a constitutive law:\n";
00829        error_message +=
00830         "set one using the constitutive_law_pt() member function";
00831        //Throw the error
00832        throw OomphLibError(error_message,
00833                            "PVDEquationsWithPressure<DIM>::get_stress()",
00834                            OOMPH_EXCEPTION_LOCATION);
00835       }
00836 #endif
00837      this->Constitutive_law_pt->
00838       calculate_second_piola_kirchhoff_stress(g,G,sigma_dev,Gcontra,detG);
00839     }
00840    
00841   }; 
00842 
00843 
00844 
00845 //////////////////////////////////////////////////////////////////////////////
00846 //////////////////////////////////////////////////////////////////////////////
00847 //////////////////////////////////////////////////////////////////////////////
00848 
00849 
00850 
00851 
00852 //===========================================================================
00853 /// An Element that solves the equations of solid mechanics, using the
00854 /// principle of virtual displacements, with quadratic interpolation
00855 /// for the positions and a discontinuous linear solid pressure. This is
00856 /// analogous to the QCrouzeixRaviartElement element for fluids.
00857 //============================================================================
00858 template<unsigned DIM>
00859 class QPVDElementWithPressure : public virtual SolidQElement<DIM,3>, 
00860                                 public virtual PVDEquationsWithPressure<DIM>
00861 {
00862 
00863  /// \short Unpin all solid pressure dofs in the element 
00864  void unpin_elemental_solid_pressure_dofs()
00865   {
00866    unsigned n_pres = this->npres_solid();
00867    // loop over pressure dofs and unpin them
00868    for(unsigned l=0;l<n_pres;l++) 
00869     {this->internal_data_pt(this->P_solid_internal_index)->unpin(l);}
00870   }
00871 
00872   protected:
00873 
00874  /// \short Internal index that indicates at which internal data value the
00875  /// solid presure is stored
00876  unsigned P_solid_internal_index;
00877  
00878  /// \short Overload the access function 
00879  /// that is used to return local equation correpsonding to the i-th
00880  /// solid pressure value
00881  inline int solid_p_local_eqn(const unsigned &i)
00882   {return this->internal_local_eqn(P_solid_internal_index,i);}
00883  
00884  /// Return the pressure shape functions
00885  inline void solid_pshape(const Vector<double> &s, Shape &psi) const;
00886  
00887   public:
00888  
00889  /// \short There is internal solid data so we can't use the automatic
00890  /// assignment of consistent initial conditions for time-dependent problems.
00891  bool has_internal_solid_data() {return true;}
00892 
00893  /// Constructor, there are DIM+1 internal data points
00894  QPVDElementWithPressure() : SolidQElement<DIM,3>(), 
00895   PVDEquationsWithPressure<DIM>() 
00896   {
00897    //Allocate and add one Internal data object that stores DIM+1 pressure
00898    //values
00899    P_solid_internal_index = this->add_internal_data(new Data(DIM+1));
00900  }
00901  
00902  /// Return the lth pressure value
00903  double solid_p(const unsigned &l) 
00904   {return this->internal_data_pt(P_solid_internal_index)->value(l);}
00905  
00906  /// Set the l-th pressure value to p_value
00907  void set_solid_p(const unsigned &l, const double &p_value)
00908   {this->internal_data_pt(P_solid_internal_index)->set_value(l,p_value);}
00909 
00910  /// Return number of pressure values
00911  unsigned npres_solid() const {return DIM+1;} 
00912  
00913  /// Fix the pressure dof l to be the value pvalue
00914  void fix_solid_pressure(const unsigned &l, const double &pvalue)
00915   {
00916    this->internal_data_pt(P_solid_internal_index)->pin(l);
00917    this->internal_data_pt(P_solid_internal_index)->set_value(l,pvalue);
00918   }
00919 
00920  /// Generic FiniteElement output function
00921  void output(std::ostream &outfile) {FiniteElement::output(outfile);}
00922 
00923  /// PVDEquationsWithPressure output function
00924  void output(std::ostream &outfile, const unsigned &n_plot)
00925   {PVDEquationsWithPressure<DIM>::output(outfile,n_plot);}
00926 
00927  
00928  /// C-style Generic FiniteElement output function
00929  void output(FILE* file_pt) {FiniteElement::output(file_pt);}
00930 
00931  /// C-style PVDEquationsWithPressure output function
00932  void output(FILE* file_pt, const unsigned &n_plot)
00933   {PVDEquationsWithPressure<DIM>::output(file_pt,n_plot);}
00934 
00935 };
00936  
00937 
00938 //=====================================================================
00939 /// Pressure shape functions for 2D QPVDElementWithPressure elements
00940 //=====================================================================
00941 template<>
00942 inline void  QPVDElementWithPressure<2>::solid_pshape(const Vector<double> &s, 
00943                                                       Shape &psi) const
00944 {
00945  psi[0] = 1.0;
00946  psi[1] = s[0];
00947  psi[2] = s[1];
00948 }
00949 
00950 
00951 //=====================================================================
00952 /// Pressure shape functions for 3D QPVDElementWithPressure elements
00953 //=====================================================================
00954 template<>
00955 inline void  QPVDElementWithPressure<3>::solid_pshape(const Vector<double> &s, 
00956                                                       Shape &psi) const
00957 {
00958  psi[0] = 1.0;
00959  psi[1] = s[0];
00960  psi[2] = s[1];
00961  psi[3] = s[2];
00962 }
00963 
00964 
00965 
00966 //======================================================================
00967 /// FaceGeometry of 2D QPVDElementWithPressure
00968 //======================================================================
00969 template<>
00970 class FaceGeometry<QPVDElementWithPressure<2> >: 
00971 public virtual SolidQElement<1,3>
00972 {
00973   public:
00974  /// Constructor must call constructor of underlying solid element
00975  FaceGeometry() : SolidQElement<1,3>() {}
00976 };
00977 
00978 
00979 //======================================================================
00980 /// FaceGeometry of FaceGeometry of 2D QPVDElementWithPressure
00981 //======================================================================
00982 template<>
00983 class FaceGeometry<FaceGeometry<QPVDElementWithPressure<2> > >: 
00984 public virtual PointElement
00985 {
00986   public:
00987  /// Constructor must call constructor of underlying solid element
00988  FaceGeometry() : PointElement() {}
00989 };
00990 
00991 
00992 ///////////////////////////////////////////////////////////////////////////
00993 ///////////////////////////////////////////////////////////////////////////
00994 ///////////////////////////////////////////////////////////////////////////
00995 
00996 
00997 
00998 
00999 //===========================================================================
01000 /// An Element that solves the equations of solid mechanics, based on 
01001 /// the discretised principle of virtual displacements, using quadratic 
01002 /// interpolation
01003 /// for the positions and continuous linear solid pressure. This is analagous
01004 /// to the QTaylorHoodElement fluid element.
01005 //============================================================================
01006 template<unsigned DIM>
01007 class QPVDElementWithContinuousPressure : public virtual SolidQElement<DIM,3>,
01008                      public virtual PVDEquationsWithPressure<DIM>
01009 {
01010   private:
01011  
01012  /// Static array of ints to hold number of solid pressure values at each node
01013  static const unsigned Initial_Nvalue[];
01014 
01015  /// \short Unpin all solid pressure dofs in the element 
01016  void unpin_elemental_solid_pressure_dofs()
01017   {
01018    //find the index at which the pressure is stored
01019    int p_index = this->solid_p_nodal_index();
01020    unsigned n_node = this->nnode();
01021    // loop over nodes
01022    for(unsigned n=0;n<n_node;n++) 
01023     {this->node_pt(n)->unpin(p_index);}
01024   }
01025 
01026 protected:
01027  
01028  /// \short Static array of ints to hold conversion from pressure node
01029  /// numbers to actual node numbers
01030  static const unsigned Pconv[];
01031 
01032  /// \short Overload the access function 
01033  /// that is used to return local equation correpsonding to the i-th
01034  /// solid pressure value
01035  inline int solid_p_local_eqn(const unsigned &i)
01036   {return this->nodal_local_eqn(Pconv[i],this->solid_p_nodal_index());}
01037 
01038  /// Return the pressure shape functions
01039  inline void solid_pshape(const Vector<double> &s, Shape &psi) const;
01040  
01041 public:
01042 
01043  /// Constructor
01044  QPVDElementWithContinuousPressure() : SolidQElement<DIM,3>(), 
01045   PVDEquationsWithPressure<DIM>() 
01046   { }
01047 
01048  /// \short Set the value at which the solid pressure is stored in the nodes
01049  inline int solid_p_nodal_index() const {return 0;}
01050 
01051  /// \short Number of values (pinned or dofs) required at node n. Can
01052  /// be overwritten for hanging node version
01053  inline virtual unsigned required_nvalue(const unsigned &n) const 
01054   {return Initial_Nvalue[n];}
01055 
01056  /// Return the l-th pressure value, make sure to use the hanging
01057  /// representation if there is one!
01058  double solid_p(const unsigned &l) 
01059   {return this->nodal_value(Pconv[l],this->solid_p_nodal_index());}
01060 
01061  /// Set the l-th solid pressure value to p_value
01062  void set_solid_p(const unsigned &l, const double &p_value)
01063   {this->node_pt(Pconv[l])->set_value(this->solid_p_nodal_index(),p_value);}
01064 
01065  /// Return number of pressure values
01066  unsigned npres_solid() const 
01067   {return static_cast<unsigned>(pow(2.0,static_cast<int>(DIM)));} 
01068 
01069  /// Fix the pressure dof l to be the value pvalue 
01070  void fix_solid_pressure(const unsigned &l, const double &pvalue)
01071   {
01072    this->node_pt(Pconv[l])->pin(this->solid_p_nodal_index());
01073    this->node_pt(Pconv[l])->set_value(this->solid_p_nodal_index(),pvalue);
01074   }
01075 
01076  /// Generic FiniteElement output function
01077  void output(std::ostream &outfile) {FiniteElement::output(outfile);}
01078 
01079  /// PVDEquationsWithPressure output function
01080  void output(std::ostream &outfile, const unsigned &n_plot)
01081   {PVDEquationsWithPressure<DIM>::output(outfile,n_plot);}
01082 
01083 
01084  /// C-style generic FiniteElement output function
01085  void output(FILE* file_pt) {FiniteElement::output(file_pt);}
01086 
01087  /// C-style PVDEquationsWithPressure output function
01088  void output(FILE* file_pt, const unsigned &n_plot)
01089   {PVDEquationsWithPressure<DIM>::output(file_pt,n_plot);}
01090 
01091 };
01092 
01093 
01094 //===============================================================
01095 /// Pressure shape functions for 2D QPVDElementWithContinuousPressure
01096 /// elements
01097 //===============================================================
01098 template<>
01099 inline void  QPVDElementWithContinuousPressure<2>::solid_pshape(
01100  const Vector<double> &s, Shape &psi) const
01101 {
01102  //Local storage
01103  double psi1[2], psi2[2];
01104  //Call the OneDimensional Shape functions
01105  OneDimLagrange::shape<2>(s[0],psi1);
01106  OneDimLagrange::shape<2>(s[1],psi2);
01107 
01108  //Now let's loop over the nodal points in the element
01109  //s1 is the "x" coordinate, s2 the "y" 
01110  for(unsigned i=0;i<2;i++)
01111   {
01112    for(unsigned j=0;j<2;j++)
01113     {
01114      /*Multiply the two 1D functions together to get the 2D function*/
01115      psi[2*i + j] = psi2[i]*psi1[j];
01116     }
01117   }
01118 }
01119 
01120 //===============================================================
01121 /// Pressure shape functions for 3D QPVDElementWithContinuousPressure
01122 /// elements
01123 //===============================================================
01124 template<>
01125 inline void  QPVDElementWithContinuousPressure<3>::solid_pshape(
01126  const Vector<double> &s, Shape &psi) const
01127 {
01128  //Local storage
01129  double psi1[2], psi2[2], psi3[2];
01130  //Call the OneDimensional Shape functions
01131  OneDimLagrange::shape<2>(s[0],psi1);
01132  OneDimLagrange::shape<2>(s[1],psi2);
01133  OneDimLagrange::shape<2>(s[2],psi3);
01134 
01135  //Now let's loop over the nodal points in the element
01136  //s1 is the "x" coordinate, s2 the "y" 
01137  for(unsigned i=0;i<2;i++)
01138   {
01139    for(unsigned j=0;j<2;j++)
01140     {
01141      for(unsigned k=0;k<2;k++)
01142       {
01143        /*Multiply the two 1D functions together to get the 3D function*/
01144        psi[4*i + 2*j + k] = psi3[i]*psi2[j]*psi1[k];
01145       }
01146     }
01147   }
01148 }
01149 
01150 
01151 
01152 
01153 //===============================================================
01154 /// FaceGeometry for 2D QPVDElementWithContinuousPressure element
01155 //===============================================================
01156 template<>
01157 class FaceGeometry<QPVDElementWithContinuousPressure<2> >: 
01158 public virtual SolidQElement<1,3>
01159 {
01160   public:
01161  /// Constructor must call constructor of the underlying Solid element
01162  FaceGeometry() : SolidQElement<1,3>() {}
01163 };
01164 
01165 
01166 
01167 //===============================================================
01168 /// FaceGeometry of FaceGeometry 
01169 /// for 2D QPVDElementWithContinuousPressure element
01170 //===============================================================
01171 template<>
01172 class FaceGeometry<FaceGeometry<QPVDElementWithContinuousPressure<2> > >: 
01173 public virtual PointElement
01174 {
01175   public:
01176  /// Constructor must call constructor of the underlying Point element
01177   FaceGeometry() : PointElement() {}
01178 };
01179 
01180 
01181 //////////////////////////////////////////////////////////////////////
01182 //////////////////////////////////////////////////////////////////////
01183 //////////////////////////////////////////////////////////////////////
01184 
01185 
01186 
01187 //===========================================================================
01188 /// An Element that solves the solid mechanics equations, based on
01189 /// the principle of virtual displacements in Cartesian coordinates,
01190 /// using SolidTElements for the interpolation of the variable positions. 
01191 //============================================================================
01192 template<unsigned DIM, unsigned NNODE_1D>
01193  class TPVDElement : public virtual SolidTElement<DIM,NNODE_1D>,
01194  public virtual PVDEquations<DIM>
01195 {
01196   public:
01197  
01198  /// Constructor, there are no internal data points
01199   TPVDElement() : SolidTElement<DIM,NNODE_1D>(), PVDEquations<DIM>() { }
01200  
01201  /// Output function
01202  void output(std::ostream &outfile) {PVDEquations<DIM>::output(outfile);}
01203  
01204  /// Output function
01205  void output(std::ostream &outfile, const unsigned &n_plot)
01206  {PVDEquations<DIM>::output(outfile,n_plot);}
01207  
01208  
01209  /// C-style output function
01210  void output(FILE* file_pt) {PVDEquations<DIM>::output(file_pt);}
01211  
01212  /// C-style output function
01213  void output(FILE* file_pt, const unsigned &n_plot)
01214  {PVDEquations<DIM>::output(file_pt,n_plot);}
01215   
01216 };
01217 
01218 
01219 //============================================================================
01220 /// FaceGeometry of a 2D TPVDElement element
01221 //============================================================================
01222 template<unsigned NNODE_1D>
01223 class FaceGeometry<TPVDElement<2,NNODE_1D> > :
01224  public virtual SolidTElement<1,NNODE_1D>
01225 {
01226   public:
01227  /// Constructor must call the constructor of the underlying solid element
01228   FaceGeometry() : SolidTElement<1,NNODE_1D>() {}
01229 };
01230  
01231 
01232 //==============================================================
01233 /// FaceGeometry of the FaceGeometry of the 2D TPVDElement 
01234 //==============================================================
01235 template<unsigned NNODE_1D>
01236 class FaceGeometry<FaceGeometry<TPVDElement<2,NNODE_1D> > >:
01237  public virtual PointElement
01238 {
01239   public:
01240  //Make sure that we call the constructor of the SolidQElement
01241  //Only the Intel compiler seems to need this!
01242   FaceGeometry() : PointElement() {}
01243 };
01244 
01245 
01246 //============================================================================
01247 /// FaceGeometry of a 3D TPVDElement element
01248 //============================================================================
01249 template<unsigned NNODE_1D>
01250 class FaceGeometry<TPVDElement<3,NNODE_1D> > :
01251  public virtual SolidTElement<2,NNODE_1D>
01252 {
01253   public:
01254  /// Constructor must call the constructor of the underlying solid element
01255   FaceGeometry() : SolidTElement<2,NNODE_1D>() {}
01256 };
01257  
01258 //============================================================================
01259 /// FaceGeometry of FaceGeometry of a 3D TPVDElement element
01260 //============================================================================
01261 template<unsigned NNODE_1D>
01262 class FaceGeometry<FaceGeometry<TPVDElement<3,NNODE_1D> > > :
01263  public virtual SolidTElement<1,NNODE_1D>
01264 {
01265   public:
01266  /// Constructor must call the constructor of the underlying solid element
01267   FaceGeometry() : SolidTElement<1,NNODE_1D>() {}
01268 };
01269 
01270 
01271 
01272 //////////////////////////////////////////////////////////////////////
01273 //////////////////////////////////////////////////////////////////////
01274 //////////////////////////////////////////////////////////////////////
01275 
01276 
01277 //====================================================================
01278 /// Namespace for solid mechanics helper functions
01279 //====================================================================
01280 namespace SolidHelpers
01281 {
01282 
01283  /// \short Document the principal stresses in a 2D SolidMesh 
01284  /// pointed to by \c mesh_pt, in the directory specified
01285  /// by the DocInfo object, in a format that can be processed with 
01286  /// tecplot macro.
01287  template<class ELEMENT>
01288  void doc_2D_principal_stress(DocInfo& doc_info, SolidMesh* mesh_pt)
01289   {
01290    // Output principal stress vectors at the centre of all elements
01291    std::ofstream pos_file;
01292    std::ofstream neg_file;
01293    char filename[100];
01294    sprintf(filename,"%s/pos_principal_stress%i.dat",
01295            doc_info.directory().c_str(),
01296            doc_info.number());
01297    pos_file.open(filename);
01298    sprintf(filename,"%s/neg_principal_stress%i.dat",
01299            doc_info.directory().c_str(),
01300            doc_info.number());
01301    neg_file.open(filename);
01302    
01303    // Write dummy data in both so there's at lest one zone in each
01304    pos_file << 0.0 << " " << 0.0 << " " << 0.0 << " " << 0.0 << " " << std::endl;
01305    neg_file << 0.0 << " " << 0.0 << " " << 0.0 << " " << 0.0 << " " << std::endl;
01306    
01307    
01308    Vector<double> s(2);
01309    Vector<double> x(2);
01310    s[0]=0.0;
01311    s[1]=0.0;
01312    unsigned n_solid_element=mesh_pt->nelement();
01313    for (unsigned e=0;e<n_solid_element;e++)
01314     {
01315      ELEMENT* el_pt=dynamic_cast<ELEMENT*>(mesh_pt->element_pt(e));
01316      
01317      // Get principal stress
01318      DenseMatrix<double> principal_stress_vector(2);
01319      Vector<double> principal_stress(2);
01320      el_pt->get_principal_stress(s,principal_stress_vector,principal_stress);
01321      
01322      // Get position of centre of element
01323      el_pt->interpolated_x(s,x);
01324      
01325      // compute vectors at 45 degree for nearly hydrostatic pressure state
01326      DenseMatrix<double> rot(2);
01327      
01328      bool hydrostat=false;
01329      
01330      // Max. relative difference between principal stresses
01331      // required to classify stress state as non-hydrostatic: 1%
01332      double dev_max=1.0e-2;
01333      if (principal_stress[0]!=0.0)
01334       {
01335        if (std::abs((principal_stress[0]-principal_stress[1])/
01336                     principal_stress[0])<dev_max)
01337         {
01338          hydrostat=true;
01339          double Cos=cos(0.25*3.14159);
01340          double Sin=sin(0.25*3.14159);
01341          rot(0,0) =
01342           Cos*principal_stress_vector(0,0) - Sin*principal_stress_vector(0,1);
01343          rot(0,1) =
01344           Sin*principal_stress_vector(0,0) + Cos*principal_stress_vector(0,1);
01345          rot(1,0) =
01346           Cos*principal_stress_vector(1,0) - Sin*principal_stress_vector(1,1);
01347          rot(1,1) =
01348           Sin*principal_stress_vector(1,0) + Cos*principal_stress_vector(1,1);
01349         }
01350       }
01351      
01352      // Loop over two principal stresses:
01353      for (unsigned i=0;i<2;i++)
01354       {
01355        if (principal_stress[i]>0.0)
01356         {
01357          pos_file << x[0] << " " << x[1] << " " 
01358                   << principal_stress_vector(i,0) << " "
01359                   << principal_stress_vector(i,1) << std::endl;
01360          pos_file << x[0] << " " << x[1] << " " 
01361                   << -principal_stress_vector(i,0) << " "
01362                   << -principal_stress_vector(i,1) << std::endl;
01363          if (hydrostat)
01364           {
01365            pos_file << x[0] << " " << x[1] << " " 
01366                     << rot(i,0) << " "
01367                     << rot(i,1) << std::endl;
01368            pos_file << x[0] << " " << x[1] << " " 
01369                     << -rot(i,0) << " "
01370                     << -rot(i,1) << std::endl;
01371           }
01372         }
01373        else
01374         {
01375          neg_file << x[0] << " " << x[1] << " " 
01376                   << principal_stress_vector(i,0) << " "
01377                   << principal_stress_vector(i,1) << std::endl;
01378          neg_file << x[0] << " " << x[1] << " " 
01379                   << -principal_stress_vector(i,0) << " "
01380                   << -principal_stress_vector(i,1) << std::endl;
01381          if (hydrostat)
01382           {
01383            neg_file << x[0] << " " << x[1] << " " 
01384                     << rot(i,0) << " "
01385                     << rot(i,1) << std::endl;
01386            neg_file << x[0] << " " << x[1] << " " 
01387                     << -rot(i,0) << " "
01388                     << -rot(i,1) << std::endl;
01389           }
01390         }
01391       }
01392     }
01393    
01394    pos_file.close();
01395    neg_file.close();
01396    
01397   }
01398  
01399 };
01400 
01401 }
01402 
01403 #endif
01404 
01405 
01406 
01407 

Generated on Mon Aug 10 11:23:51 2009 by  doxygen 1.4.7