22 #define protected public 25 #include "libmesh/libmesh.h" 26 #include "libmesh/replicated_mesh.h" 27 #include "libmesh/point.h" 28 #include "libmesh/elem.h" 29 #include "libmesh/face_quad4.h" 30 #include "libmesh/equation_systems.h" 31 #include "libmesh/dof_map.h" 63 "[quad],[quad4],[structural],[2D],[element]")
66 coords << -1.0, 1.0, 1.0, -1.0,
80 SECTION(
"Number of shape functions equal number of nodes")
82 REQUIRE(fe->get_phi().size() == test_elem.
n_nodes);
86 SECTION(
"Shape functions sum to one at quadrature points")
89 const std::vector<std::vector<Real>>& phi = fe->get_phi();
91 uint n_qps = phi[0].size();
93 for (uint i=0; i<n_qps; i++)
96 for (uint j=0; j<phi.size(); j++)
99 phi_j_sum += phi[j][i];
101 REQUIRE(phi_j_sum == Approx(1.0));
106 SECTION(
"Shape function value is 1 at it's node and zero at other nodes")
110 std::vector<libMesh::Point> pts;
111 pts.reserve(test_elem.
n_nodes);
112 for (uint i=0; i<test_elem.
n_nodes; i++)
114 pts.push_back(libMesh::Point(coords(0,i), coords(1,i), coords(2,i)));
118 fe->_initialized =
false;
119 fe->init(test_elem.
geom_elem,
true, &pts);
122 const std::vector<std::vector<Real>>& phi = fe->get_phi();
124 uint n_qps = phi[0].size();
126 for (uint i=0; i<n_qps; i++)
128 for (uint j=0; j<phi.size(); j++)
133 REQUIRE(phi[j][i] == Approx(1.0));
137 REQUIRE(phi[j][i] == Approx(0.0));
144 SECTION(
"Shape function derivatives sum to zero at quadrature points")
147 const std::vector<std::vector<libMesh::RealVectorValue>>& dphi = fe->get_dphi();
149 uint n_qps = dphi[0].size();
151 for (uint i=0; i<n_qps; i++)
153 Real dphi_i_dx_sum = 0.0;
154 Real dphi_i_dy_sum = 0.0;
155 for (uint j=0; j<dphi.size(); j++)
157 dphi_i_dx_sum += dphi[j][i](0);
158 dphi_i_dy_sum += dphi[j][i](1);
160 REQUIRE(dphi_i_dx_sum == Approx(0.0));
161 REQUIRE(dphi_i_dy_sum == Approx(0.0));
166 SECTION(
"Shape function xi derivative finite difference check")
169 const std::vector<std::vector<libMesh::RealVectorValue>>& dphi = fe->get_dphi();
171 uint n_qps = dphi[0].size();
177 for (uint i=0; i<n_qps; i++)
179 for (uint j=0; j<test_elem.
n_nodes; j++)
181 dphi_dxi_0(j,i) = dphi[j][i](0);
186 const std::vector<libMesh::Point>& q_pts = fe->get_qpoints();
189 Real delta = 0.0001220703125;
190 std::vector<libMesh::Point> pts;
191 pts.reserve(test_elem.
n_nodes);
194 for (uint i=0; i<test_elem.
n_nodes; i++)
196 pts.push_back(libMesh::Point(q_pts[i](0)+delta, q_pts[i](1), q_pts[i](2)));
200 fe->_initialized =
false;
201 fe->init(test_elem.
geom_elem,
true, &pts);
202 const std::vector<std::vector<Real>>& phi_xih = fe->get_phi();
203 for (uint i=0; i<n_qps; i++)
205 for (uint j=0; j<test_elem.
n_nodes; j++)
207 phi_xi_h(j,i) = phi_xih[j][i];
212 for (uint i=0; i<test_elem.
n_nodes; i++)
214 pts[i] = libMesh::Point(q_pts[i](0)-delta, q_pts[i](1), q_pts[i](2));
218 fe->_initialized =
false;
219 fe->init(test_elem.
geom_elem,
true, &pts);
220 const std::vector<std::vector<Real>>& phi_xin = fe->get_phi();
221 for (uint i=0; i<n_qps; i++)
223 for (uint j=0; j<test_elem.
n_nodes; j++)
225 phi_xi_n(j,i) = phi_xin[j][i];
231 for (uint i=0; i<n_qps; i++)
233 for (uint j=0; j<test_elem.
n_nodes; j++)
235 dphi_dxi_fd(j,i) = (phi_xi_h(j,i) - phi_xi_n(j,i))/(2.0*delta) ;
244 REQUIRE_THAT( dPhi_dxi, Catch::Approx<double>(dPhi_dxi_fd) );
248 SECTION(
"Shape function eta derivative finite difference check")
251 const std::vector<std::vector<libMesh::RealVectorValue>>& dphi = fe->get_dphi();
253 uint n_qps = dphi[0].size();
259 for (uint i=0; i<n_qps; i++)
261 for (uint j=0; j<test_elem.
n_nodes; j++)
263 dphi_deta_0(j,i) = dphi[j][i](1);
268 const std::vector<libMesh::Point>& q_pts = fe->get_qpoints();
271 Real delta = 0.0001220703125;
272 std::vector<libMesh::Point> pts;
273 pts.reserve(test_elem.
n_nodes);
276 for (uint i=0; i<test_elem.
n_nodes; i++)
278 pts.push_back(libMesh::Point(q_pts[i](0), q_pts[i](1)+delta, q_pts[i](2)));
282 fe->_initialized =
false;
283 fe->init(test_elem.
geom_elem,
true, &pts);
284 const std::vector<std::vector<Real>>& phi_etah = fe->get_phi();
285 for (uint i=0; i<n_qps; i++)
287 for (uint j=0; j<test_elem.
n_nodes; j++)
289 phi_eta_h(j,i) = phi_etah[j][i];
294 for (uint i=0; i<test_elem.
n_nodes; i++)
296 pts[i] = libMesh::Point(q_pts[i](0), q_pts[i](1)-delta, q_pts[i](2));
300 fe->_initialized =
false;
301 fe->init(test_elem.
geom_elem,
true, &pts);
302 const std::vector<std::vector<Real>>& phi_etan = fe->get_phi();
303 for (uint i=0; i<n_qps; i++)
305 for (uint j=0; j<test_elem.
n_nodes; j++)
307 phi_eta_n(j,i) = phi_etan[j][i];
313 for (uint i=0; i<n_qps; i++)
315 for (uint j=0; j<test_elem.
n_nodes; j++)
317 dphi_deta_fd(j,i) = (phi_eta_h(j,i) - phi_eta_n(j,i))/(2.0*delta) ;
326 REQUIRE_THAT( dPhi_deta, Catch::Approx<double>(dPhi_deta_fd) );
libMesh::LibMeshInit * p_global_init
libMesh::Elem * reference_elem
Pointer to the actual libMesh element object.
Real get_shoelace_area(RealMatrixX X)
Calcualtes the area of a 2D polygon using the shoelace formula.
MAST::Solid2DSectionElementPropertyCard section
void set_strain(MAST::StrainType strain)
sets the type of strain to be used, which is LINEAR_STRAIN by default
int n_nodes
Number of nodes per element in the test mesh.
virtual std::unique_ptr< MAST::FEBase > init_fe(bool init_grads, bool init_second_order_derivative, int extra_quadrature_order=0) const
initializes the finite element shape function and quadrature object with the order of quadrature rule...
std::vector< double > eigen_matrix_to_std_vector(RealMatrixX M)
Converts an Eigen Matrix object to a std::vector.
Matrix< Real, Dynamic, Dynamic > RealMatrixX
TEST_CASE("quad4_structural_shape_functions", "[quad],[quad4],[structural],[2D],[element]")
References https://studiumbook.com/properties-of-shape-function-fea/ https://www.ccg.msm.cam.ac.uk/images/FEMOR_Lecture_2.pdf
virtual int extra_quadrature_order(const MAST::GeomElem &elem) const
returns the extra quadrature order (on top of the system) that this element should use...