$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 00020 // Local includes 00021 #include "libmesh/elem.h" 00022 #include "libmesh/fe.h" 00023 #include "libmesh/fe_interface.h" 00024 #include "libmesh/string_to_enum.h" 00025 00026 00027 namespace libMesh 00028 { 00029 00030 // ------------------------------------------------------------ 00031 // Clough-specific implementations 00032 00033 // Anonymous namespace for local helper functions 00034 namespace { 00035 00036 void clough_nodal_soln(const Elem* elem, 00037 const Order order, 00038 const std::vector<Number>& elem_soln, 00039 std::vector<Number>& nodal_soln, 00040 unsigned Dim) 00041 { 00042 const unsigned int n_nodes = elem->n_nodes(); 00043 00044 const ElemType elem_type = elem->type(); 00045 00046 nodal_soln.resize(n_nodes); 00047 00048 const Order totalorder = static_cast<Order>(order + elem->p_level()); 00049 00050 // FEType object to be passed to various FEInterface functions below. 00051 FEType fe_type(totalorder, CLOUGH); 00052 00053 switch (totalorder) 00054 { 00055 // Piecewise cubic shape functions with linear flux edges 00056 case SECOND: 00057 // Piecewise cubic shape functions 00058 case THIRD: 00059 { 00060 00061 const unsigned int n_sf = 00062 // FE<Dim,T>::n_shape_functions(elem_type, totalorder); 00063 FEInterface::n_shape_functions(Dim, fe_type, elem_type); 00064 00065 std::vector<Point> refspace_nodes; 00066 FEBase::get_refspace_nodes(elem_type,refspace_nodes); 00067 libmesh_assert_equal_to (refspace_nodes.size(), n_nodes); 00068 00069 for (unsigned int n=0; n<n_nodes; n++) 00070 { 00071 libmesh_assert_equal_to (elem_soln.size(), n_sf); 00072 00073 // Zero before summation 00074 nodal_soln[n] = 0; 00075 00076 // u_i = Sum (alpha_i phi_i) 00077 for (unsigned int i=0; i<n_sf; i++) 00078 nodal_soln[n] += elem_soln[i] * 00079 // FE<Dim,T>::shape(elem, order, i, mapped_point); 00080 FEInterface::shape(Dim, fe_type, elem, i, refspace_nodes[n]); 00081 } 00082 00083 return; 00084 } 00085 00086 default: 00087 libmesh_error_msg("ERROR: Invalid total order " << totalorder); 00088 } 00089 } // clough_nodal_soln() 00090 00091 00092 00093 00094 unsigned int clough_n_dofs(const ElemType t, const Order o) 00095 { 00096 if (t == INVALID_ELEM) 00097 return 0; 00098 00099 switch (o) 00100 { 00101 // Piecewise cubic shape functions with linear flux edges 00102 case SECOND: 00103 { 00104 switch (t) 00105 { 00106 case TRI6: 00107 return 9; 00108 00109 default: 00110 libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!"); 00111 } 00112 } 00113 // Piecewise cubic Clough-Tocher element 00114 case THIRD: 00115 { 00116 switch (t) 00117 { 00118 case TRI6: 00119 return 12; 00120 00121 default: 00122 libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!"); 00123 } 00124 } 00125 00126 default: 00127 libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for CLOUGH FE family!"); 00128 } 00129 00130 libmesh_error_msg("We'll never get here!"); 00131 return 0; 00132 } // clough_n_dofs() 00133 00134 00135 00136 00137 00138 unsigned int clough_n_dofs_at_node(const ElemType t, 00139 const Order o, 00140 const unsigned int n) 00141 { 00142 switch (o) 00143 { 00144 // Piecewise cubic shape functions with linear flux edges 00145 case SECOND: 00146 { 00147 switch (t) 00148 { 00149 // The 2D Clough-Tocher defined on a 6-noded triangle 00150 case TRI6: 00151 { 00152 switch (n) 00153 { 00154 case 0: 00155 case 1: 00156 case 2: 00157 return 3; 00158 00159 case 3: 00160 case 4: 00161 case 5: 00162 return 0; 00163 00164 default: 00165 libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for TRI6!"); 00166 } 00167 } 00168 00169 default: 00170 libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!"); 00171 } 00172 } 00173 // The third-order clough shape functions 00174 case THIRD: 00175 { 00176 switch (t) 00177 { 00178 // The 2D Clough-Tocher defined on a 6-noded triangle 00179 case TRI6: 00180 { 00181 switch (n) 00182 { 00183 case 0: 00184 case 1: 00185 case 2: 00186 return 3; 00187 00188 case 3: 00189 case 4: 00190 case 5: 00191 return 1; 00192 00193 default: 00194 libmesh_error_msg("ERROR: Invalid node ID " << n << " selected for TRI6!"); 00195 } 00196 } 00197 00198 default: 00199 libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!"); 00200 } 00201 } 00202 default: 00203 libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for CLOUGH FE family!"); 00204 } 00205 00206 libmesh_error_msg("We'll never get here!"); 00207 return 0; 00208 } // clough_n_dofs_at_node() 00209 00210 00211 00212 00213 unsigned int clough_n_dofs_per_elem(const ElemType t, const Order o) 00214 { 00215 switch (o) 00216 { 00217 // Piecewise cubic shape functions with linear flux edges 00218 case SECOND: 00219 // The third-order Clough-Tocher shape functions 00220 case THIRD: 00221 { 00222 switch (t) 00223 { 00224 // The 2D clough defined on a 6-noded triangle 00225 case TRI6: 00226 return 0; 00227 00228 default: 00229 libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!"); 00230 } 00231 } 00232 00233 default: 00234 libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for CLOUGH FE family!"); 00235 } 00236 00237 libmesh_error_msg("We'll never get here!"); 00238 return 0; 00239 } // clough_n_dofs_per_elem() 00240 00241 } // anonymous 00242 00243 00244 00245 00246 // Do full-specialization of nodal_soln() function for every 00247 // dimension, instead of explicit instantiation at the end of this 00248 // file. 00249 // This could be macro-ified so that it fits on one line... 00250 template <> 00251 void FE<0,CLOUGH>::nodal_soln(const Elem* elem, 00252 const Order order, 00253 const std::vector<Number>& elem_soln, 00254 std::vector<Number>& nodal_soln) 00255 { clough_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/0); } 00256 00257 template <> 00258 void FE<1,CLOUGH>::nodal_soln(const Elem* elem, 00259 const Order order, 00260 const std::vector<Number>& elem_soln, 00261 std::vector<Number>& nodal_soln) 00262 { clough_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/1); } 00263 00264 template <> 00265 void FE<2,CLOUGH>::nodal_soln(const Elem* elem, 00266 const Order order, 00267 const std::vector<Number>& elem_soln, 00268 std::vector<Number>& nodal_soln) 00269 { clough_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/2); } 00270 00271 template <> 00272 void FE<3,CLOUGH>::nodal_soln(const Elem* elem, 00273 const Order order, 00274 const std::vector<Number>& elem_soln, 00275 std::vector<Number>& nodal_soln) 00276 { clough_nodal_soln(elem, order, elem_soln, nodal_soln, /*Dim=*/3); } 00277 00278 00279 // Full specialization of n_dofs() function for every dimension 00280 template <> unsigned int FE<0,CLOUGH>::n_dofs(const ElemType t, const Order o) { return clough_n_dofs(t, o); } 00281 template <> unsigned int FE<1,CLOUGH>::n_dofs(const ElemType t, const Order o) { return clough_n_dofs(t, o); } 00282 template <> unsigned int FE<2,CLOUGH>::n_dofs(const ElemType t, const Order o) { return clough_n_dofs(t, o); } 00283 template <> unsigned int FE<3,CLOUGH>::n_dofs(const ElemType t, const Order o) { return clough_n_dofs(t, o); } 00284 00285 00286 // Full specialization of n_dofs_at_node() function for every dimension. 00287 template <> unsigned int FE<0,CLOUGH>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return clough_n_dofs_at_node(t, o, n); } 00288 template <> unsigned int FE<1,CLOUGH>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return clough_n_dofs_at_node(t, o, n); } 00289 template <> unsigned int FE<2,CLOUGH>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return clough_n_dofs_at_node(t, o, n); } 00290 template <> unsigned int FE<3,CLOUGH>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return clough_n_dofs_at_node(t, o, n); } 00291 00292 // Full specialization of n_dofs_per_elem() function for every dimension. 00293 template <> unsigned int FE<0,CLOUGH>::n_dofs_per_elem(const ElemType t, const Order o) { return clough_n_dofs_per_elem(t, o); } 00294 template <> unsigned int FE<1,CLOUGH>::n_dofs_per_elem(const ElemType t, const Order o) { return clough_n_dofs_per_elem(t, o); } 00295 template <> unsigned int FE<2,CLOUGH>::n_dofs_per_elem(const ElemType t, const Order o) { return clough_n_dofs_per_elem(t, o); } 00296 template <> unsigned int FE<3,CLOUGH>::n_dofs_per_elem(const ElemType t, const Order o) { return clough_n_dofs_per_elem(t, o); } 00297 00298 // Clough FEMs are C^1 continuous 00299 template <> FEContinuity FE<0,CLOUGH>::get_continuity() const { return C_ONE; } 00300 template <> FEContinuity FE<1,CLOUGH>::get_continuity() const { return C_ONE; } 00301 template <> FEContinuity FE<2,CLOUGH>::get_continuity() const { return C_ONE; } 00302 template <> FEContinuity FE<3,CLOUGH>::get_continuity() const { return C_ONE; } 00303 00304 // Clough FEMs are not (currently) hierarchic 00305 template <> bool FE<0,CLOUGH>::is_hierarchic() const { return false; } // FIXME - this will be changed 00306 template <> bool FE<1,CLOUGH>::is_hierarchic() const { return false; } // FIXME - this will be changed 00307 template <> bool FE<2,CLOUGH>::is_hierarchic() const { return false; } // FIXME - this will be changed 00308 template <> bool FE<3,CLOUGH>::is_hierarchic() const { return false; } // FIXME - this will be changed 00309 00310 #ifdef LIBMESH_ENABLE_AMR 00311 // compute_constraints() specializations are only needed for 2 and 3D 00312 template <> 00313 void FE<2,CLOUGH>::compute_constraints (DofConstraints &constraints, 00314 DofMap &dof_map, 00315 const unsigned int variable_number, 00316 const Elem* elem) 00317 { compute_proj_constraints(constraints, dof_map, variable_number, elem); } 00318 00319 template <> 00320 void FE<3,CLOUGH>::compute_constraints (DofConstraints &constraints, 00321 DofMap &dof_map, 00322 const unsigned int variable_number, 00323 const Elem* elem) 00324 { compute_proj_constraints(constraints, dof_map, variable_number, elem); } 00325 #endif // #ifdef LIBMESH_ENABLE_AMR 00326 00327 // Clough FEM shapes need reinit 00328 template <> bool FE<0,CLOUGH>::shapes_need_reinit() const { return true; } 00329 template <> bool FE<1,CLOUGH>::shapes_need_reinit() const { return true; } 00330 template <> bool FE<2,CLOUGH>::shapes_need_reinit() const { return true; } 00331 template <> bool FE<3,CLOUGH>::shapes_need_reinit() const { return true; } 00332 00333 } // namespace libMesh