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 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
1.4.7