1 // ============================================================================= 2 // PROJECT CHRONO - http://projectchrono.org 3 // 4 // Copyright (c) 2021 projectchrono.org 5 // All rights reserved. 6 // 7 // Use of this source code is governed by a BSD-style license that can be found 8 // in the LICENSE file at the top level of the distribution and at 9 // http://projectchrono.org/license-chrono.txt. 10 // 11 // ============================================================================= 12 // Authors: Radu Serban 13 // ============================================================================= 14 // Face of a hexahedron element 15 // ============================================================================= 16 17 #ifndef CH_HEXAHEDRON_FACE_H 18 #define CH_HEXAHEDRON_FACE_H 19 20 #include "chrono/fea/ChElementHexahedron.h" 21 22 namespace chrono { 23 namespace fea { 24 25 /// @addtogroup fea_elements 26 /// @{ 27 28 /// Face of a hexahedron-shaped element. 29 /// Corner nodes, obtainable with GetNodeN(), are in counterclockwise order seen from the outside. 30 /// <pre> 31 /// v 32 /// ^ 33 /// 3 o-----+-----o 2 34 /// | | | 35 /// --+-----+-----+-> u 36 /// | | | 37 /// 0 o-----+-----o 1 38 /// </pre> 39 class ChApi ChHexahedronFace : public ChLoadableUV { 40 public: 41 /// Construct the specified face (0 <= id <= 5) on the given hexahedral element. ChHexahedronFace(std::shared_ptr<ChElementHexahedron> element,char id)42 ChHexahedronFace(std::shared_ptr<ChElementHexahedron> element, char id) : m_face_id(id), m_element(element) {} 43 ~ChHexahedronFace()44 ~ChHexahedronFace() {} 45 46 // Get the specified face node (0 <= i <= 3). GetNodeN(int i)47 std::shared_ptr<ChNodeFEAxyz> GetNodeN(int i) const { 48 static int iface0[] = {0, 3, 2, 1}; 49 static int iface1[] = {0, 1, 5, 4}; 50 static int iface2[] = {1, 2, 6, 5}; 51 static int iface3[] = {2, 3, 7, 6}; 52 static int iface4[] = {3, 0, 4, 7}; 53 static int iface5[] = {4, 5, 6, 7}; 54 55 switch (m_face_id) { 56 case 0: 57 return m_element->GetHexahedronNode(iface0[i]); 58 case 1: 59 return m_element->GetHexahedronNode(iface1[i]); 60 case 2: 61 return m_element->GetHexahedronNode(iface2[i]); 62 case 3: 63 return m_element->GetHexahedronNode(iface3[i]); 64 case 4: 65 return m_element->GetHexahedronNode(iface4[i]); 66 case 5: 67 return m_element->GetHexahedronNode(iface5[i]); 68 } 69 return nullptr; 70 } 71 72 /// Fills the N shape function vector (size 4). ShapeFunctions(ChVectorN<double,4> & N,double x,double y)73 void ShapeFunctions(ChVectorN<double, 4>& N, double x, double y) { 74 N(0) = 0.25 * (1 - x) * (1 - y); 75 N(1) = 0.25 * (1 + x) * (1 - y); 76 N(2) = 0.25 * (1 + x) * (1 + y); 77 N(3) = 0.25 * (1 - x) * (1 + y); 78 } 79 80 // Functions for ChLoadable interface 81 82 /// Get the number of DOFs affected by this element (position part). LoadableGet_ndof_x()83 virtual int LoadableGet_ndof_x() override { return 4 * 3; } 84 85 /// Get the number of DOFs affected by this element (speed part). LoadableGet_ndof_w()86 virtual int LoadableGet_ndof_w() override { return 4 * 3; } 87 88 /// Get all the DOFs packed in a single vector (position part). LoadableGetStateBlock_x(int block_offset,ChState & mD)89 virtual void LoadableGetStateBlock_x(int block_offset, ChState& mD) override { 90 mD.segment(block_offset + 0, 3) = GetNodeN(0)->GetPos().eigen(); 91 mD.segment(block_offset + 3, 3) = GetNodeN(1)->GetPos().eigen(); 92 mD.segment(block_offset + 6, 3) = GetNodeN(2)->GetPos().eigen(); 93 mD.segment(block_offset + 9, 3) = GetNodeN(3)->GetPos().eigen(); 94 } 95 96 /// Get all the DOFs packed in a single vector (speed part). LoadableGetStateBlock_w(int block_offset,ChStateDelta & mD)97 virtual void LoadableGetStateBlock_w(int block_offset, ChStateDelta& mD) override { 98 mD.segment(block_offset + 0, 3) = GetNodeN(0)->GetPos_dt().eigen(); 99 mD.segment(block_offset + 3, 3) = GetNodeN(1)->GetPos_dt().eigen(); 100 mD.segment(block_offset + 6, 3) = GetNodeN(2)->GetPos_dt().eigen(); 101 mD.segment(block_offset + 9, 3) = GetNodeN(3)->GetPos_dt().eigen(); 102 } 103 104 /// Increment all DOFs using a delta. LoadableStateIncrement(const unsigned int off_x,ChState & x_new,const ChState & x,const unsigned int off_v,const ChStateDelta & Dv)105 virtual void LoadableStateIncrement(const unsigned int off_x, 106 ChState& x_new, 107 const ChState& x, 108 const unsigned int off_v, 109 const ChStateDelta& Dv) override { 110 for (int i = 0; i < 4; ++i) { 111 GetNodeN(i)->NodeIntStateIncrement(off_x + i * 3, x_new, x, off_v + i * 3, Dv); 112 } 113 } 114 115 /// Number of coordinates in the interpolated field: here the {x,y,z} displacement. Get_field_ncoords()116 virtual int Get_field_ncoords() override { return 3; } 117 118 /// Get the number of DOFs sub-blocks. GetSubBlocks()119 virtual int GetSubBlocks() override { return 4; } 120 121 /// Get the offset of the specified sub-block of DOFs in global vector. GetSubBlockOffset(int nblock)122 virtual unsigned int GetSubBlockOffset(int nblock) override { return GetNodeN(nblock)->NodeGetOffset_w(); } 123 124 /// Get the size of the specified sub-block of DOFs in global vector. GetSubBlockSize(int nblock)125 virtual unsigned int GetSubBlockSize(int nblock) override { return 3; } 126 127 /// Check if the specified sub-block of DOFs is active. IsSubBlockActive(int nblock)128 virtual bool IsSubBlockActive(int nblock) const override { return !GetNodeN(nblock)->GetFixed(); } 129 130 /// Get the pointers to the contained ChVariables, appending to the mvars vector. LoadableGetVariables(std::vector<ChVariables * > & mvars)131 virtual void LoadableGetVariables(std::vector<ChVariables*>& mvars) override { 132 for (int i = 0; i < 4; ++i) 133 mvars.push_back(&GetNodeN(i)->Variables()); 134 }; 135 136 /// Evaluate N'*F , where N is some type of shape function evaluated at U,V coordinates of the surface, each ranging 137 /// in -1..+1 F is a load, N'*F is the resulting generalized load. Returns also det[J] with J=[dx/du,..], which may 138 /// be useful in Gauss quadrature. ComputeNF(const double U,const double V,ChVectorDynamic<> & Qi,double & detJ,const ChVectorDynamic<> & F,ChVectorDynamic<> * state_x,ChVectorDynamic<> * state_w)139 virtual void ComputeNF(const double U, ///< parametric coordinate in surface 140 const double V, ///< parametric coordinate in surface 141 ChVectorDynamic<>& Qi, ///< result of N'*F, maybe with offset block_offset 142 double& detJ, ///< det[J] 143 const ChVectorDynamic<>& F, ///< Input F vector, size is = n.field coords. 144 ChVectorDynamic<>* state_x, ///< if != 0, update state (pos. part) to this, then evaluate Q 145 ChVectorDynamic<>* state_w ///< if != 0, update state (speed part) to this, then evaluate Q 146 ) override { 147 ChVectorN<double, 4> N; 148 ShapeFunctions(N, U, V); 149 150 //***TODO*** exact det of jacobian at u,v 151 detJ = ((GetNodeN(0)->GetPos() - GetNodeN(1)->GetPos()) - (GetNodeN(2)->GetPos() - GetNodeN(3)->GetPos())) 152 .Length() * 153 ((GetNodeN(1)->GetPos() - GetNodeN(2)->GetPos()) - (GetNodeN(3)->GetPos() - GetNodeN(0)->GetPos())) 154 .Length(); 155 // (approximate detJ, ok only for rectangular face) 156 157 for (int i = 0; i < 4; i++) { 158 Qi.segment(3 * i, 3) = N(i) * F.segment(0, 3); 159 } 160 } 161 162 /// If true, use quadrature over u,v in [0..1] range as triangle volumetric coords. IsTriangleIntegrationNeeded()163 virtual bool IsTriangleIntegrationNeeded() override { return false; } 164 165 /// Get the normal to the surface at the parametric coordinate u,v. 166 /// Normal must be considered pointing outside in case the surface is a boundary to a volume. ComputeNormal(const double U,const double V)167 virtual ChVector<> ComputeNormal(const double U, const double V) override { 168 ChVector<> p0 = GetNodeN(0)->GetPos(); 169 ChVector<> p1 = GetNodeN(1)->GetPos(); 170 ChVector<> p2 = GetNodeN(2)->GetPos(); 171 return Vcross(p1 - p0, p2 - p0).GetNormalized(); 172 } 173 174 private: 175 char m_face_id; ///< id of the face on the hexahedron 176 std::shared_ptr<ChElementHexahedron> m_element; ///< associated hexahedron element 177 }; 178 179 /// @} fea_elements 180 181 } // namespace fea 182 } // namespace chrono 183 184 #endif 185