void H1FETransformation<OutputShape>::map_phi( const unsigned int dim, const Elem* const elem, const std::vector<Point>& qp, const FEGenericBase<OutputShape>& fe, std::vector<std::vector<OutputShape> >& phi ) const { switch(dim) { case 0: { for (unsigned int i=0; i<phi.size(); i++) { libmesh_assert_equal_to ( qp.size(), phi[i].size() ); for (unsigned int p=0; p<phi[i].size(); p++) FEInterface::shape<OutputShape>(0, fe.get_fe_type(), elem, i, qp[p], phi[i][p]); } break; } case 1: { for (unsigned int i=0; i<phi.size(); i++) { libmesh_assert_equal_to ( qp.size(), phi[i].size() ); for (unsigned int p=0; p<phi[i].size(); p++) FEInterface::shape<OutputShape>(1, fe.get_fe_type(), elem, i, qp[p], phi[i][p]); } break; } case 2: { for (unsigned int i=0; i<phi.size(); i++) { libmesh_assert_equal_to ( qp.size(), phi[i].size() ); for (unsigned int p=0; p<phi[i].size(); p++) FEInterface::shape<OutputShape>(2, fe.get_fe_type(), elem, i, qp[p], phi[i][p]); } break; } case 3: { for (unsigned int i=0; i<phi.size(); i++) { libmesh_assert_equal_to ( qp.size(), phi[i].size() ); for (unsigned int p=0; p<phi[i].size(); p++) FEInterface::shape<OutputShape>(3, fe.get_fe_type(), elem, i, qp[p], phi[i][p]); } break; } default: libmesh_error(); } return; }
void LaplaceSystem::init_context(DiffContext &context) { FEMContext &c = libmesh_cast_ref<FEMContext&>(context); // Get finite element object FEGenericBase<RealGradient>* fe; c.get_element_fe<RealGradient>( u_var, fe ); // We should prerequest all the data // we will need to build the linear system. fe->get_JxW(); fe->get_phi(); fe->get_dphi(); fe->get_xyz(); FEGenericBase<RealGradient>* side_fe; c.get_side_fe<RealGradient>( u_var, side_fe ); side_fe->get_JxW(); side_fe->get_phi(); }
bool LaplaceSystem::element_time_derivative (bool request_jacobian, DiffContext &context) { FEMContext &c = libmesh_cast_ref<FEMContext&>(context); // Get finite element object FEGenericBase<RealGradient>* fe = NULL; c.get_element_fe<RealGradient>( u_var, fe ); // First we get some references to cell-specific data that // will be used to assemble the linear system. // Element Jacobian * quadrature weights for interior integration const std::vector<Real> &JxW = fe->get_JxW(); // The velocity shape functions at interior quadrature points. const std::vector<std::vector<RealGradient> >& phi = fe->get_phi(); // The velocity shape function gradients at interior // quadrature points. const std::vector<std::vector<RealTensor> >& grad_phi = fe->get_dphi(); const std::vector<Point>& qpoint = fe->get_xyz(); // The number of local degrees of freedom in each variable const unsigned int n_u_dofs = c.dof_indices_var[u_var].size(); DenseSubMatrix<Number> &Kuu = *c.elem_subjacobians[u_var][u_var]; DenseSubVector<Number> &Fu = *c.elem_subresiduals[u_var]; // Now we will build the element Jacobian and residual. // Constructing the residual requires the solution and its // gradient from the previous timestep. This must be // calculated at each quadrature point by summing the // solution degree-of-freedom values by the appropriate // weight functions. const unsigned int n_qpoints = (c.get_element_qrule())->n_points(); for (unsigned int qp=0; qp != n_qpoints; qp++) { Tensor grad_u; c.interior_gradient( u_var, qp, grad_u ); // Value of the forcing function at this quadrature point RealGradient f = this->forcing(qpoint[qp]); // First, an i-loop over the velocity degrees of freedom. // We know that n_u_dofs == n_v_dofs so we can compute contributions // for both at the same time. for (unsigned int i=0; i != n_u_dofs; i++) { Fu(i) += ( grad_u.contract(grad_phi[i][qp]) - f*phi[i][qp] )*JxW[qp]; if (request_jacobian) { // Matrix contributions for the uu and vv couplings. for (unsigned int j=0; j != n_u_dofs; j++) { Kuu(i,j) += grad_phi[j][qp].contract(grad_phi[i][qp])*JxW[qp]; } } } } // end of the quadrature point qp-loop return request_jacobian; }
bool CurlCurlSystem::element_time_derivative (bool request_jacobian, DiffContext &context) { FEMContext &c = cast_ref<FEMContext&>(context); // Get finite element object FEGenericBase<RealGradient>* fe = NULL; c.get_element_fe<RealGradient>( u_var, fe ); // First we get some references to cell-specific data that // will be used to assemble the linear system. // Element Jacobian * quadrature weights for interior integration const std::vector<Real> &JxW = fe->get_JxW(); // The velocity shape functions at interior quadrature points. const std::vector<std::vector<RealGradient> >& phi = fe->get_phi(); // The velocity shape function gradients at interior // quadrature points. const std::vector<std::vector<RealGradient> >& curl_phi = fe->get_curl_phi(); const std::vector<Point>& qpoint = fe->get_xyz(); // The number of local degrees of freedom in each variable const unsigned int n_u_dofs = c.get_dof_indices(u_var).size(); DenseSubMatrix<Number> &Kuu = c.get_elem_jacobian(u_var,u_var); DenseSubVector<Number> &Fu = c.get_elem_residual(u_var); // Now we will build the element Jacobian and residual. // Constructing the residual requires the solution and its // gradient from the previous timestep. This must be // calculated at each quadrature point by summing the // solution degree-of-freedom values by the appropriate // weight functions. const unsigned int n_qpoints = c.get_element_qrule().n_points(); // Loop over quadrature points for (unsigned int qp=0; qp != n_qpoints; qp++) { Gradient u; Gradient curl_u; c.interior_value( u_var, qp, u ); c.interior_curl( u_var, qp, curl_u ); // Value of the forcing function at this quadrature point RealGradient f = this->forcing(qpoint[qp]); // First, an i-loop over the degrees of freedom. for (unsigned int i=0; i != n_u_dofs; i++) { Fu(i) += ( curl_u*curl_phi[i][qp] + u*phi[i][qp] - f*phi[i][qp] )*JxW[qp]; if (request_jacobian) { // Matrix contributions for the uu and vv couplings. for (unsigned int j=0; j != n_u_dofs; j++) { Kuu(i,j) += ( curl_phi[j][qp]*curl_phi[i][qp] + phi[j][qp]*phi[i][qp] )*JxW[qp]; } } } } // end of the quadrature point qp-loop return request_jacobian; }
void HCurlFETransformation<OutputShape>::map_phi( const unsigned int dim, const Elem* const elem, const std::vector<Point>& qp, const FEGenericBase<OutputShape>& fe, std::vector<std::vector<OutputShape> >& phi ) const { switch(dim) { // These element transformations only make sense in 2D and 3D case 0: case 1: { libmesh_error(); } case 2: { const std::vector<Real>& dxidx_map = fe.get_fe_map().get_dxidx(); const std::vector<Real>& dxidy_map = fe.get_fe_map().get_dxidy(); const std::vector<Real>& detadx_map = fe.get_fe_map().get_detadx(); const std::vector<Real>& detady_map = fe.get_fe_map().get_detady(); // FIXME: Need to update for 2D elements in 3D space /* phi = (dx/dxi)^-T * \hat{phi} In 2D: (dx/dxi)^{-1} = [ dxi/dx dxi/dy deta/dx deta/dy ] so: dxi/dx^{-T} * \hat{phi} = [ dxi/dx deta/dx [ \hat{phi}_xi dxi/dy deta/dy ] \hat{phi}_eta ] or in indicial notation: phi_j = xi_{i,j}*\hat{phi}_i */ for (unsigned int i=0; i<phi.size(); i++) for (unsigned int p=0; p<phi[i].size(); p++) { // Need to temporarily cache reference shape functions // TODO: PB: Might be worth trying to build phi_ref separately to see // if we can get vectorization OutputShape phi_ref; FEInterface::shape<OutputShape>(2, fe.get_fe_type(), elem, i, qp[p], phi_ref); phi[i][p](0) = dxidx_map[p]*phi_ref.slice(0) + detadx_map[p]*phi_ref.slice(1); phi[i][p](1) = dxidy_map[p]*phi_ref.slice(0) + detady_map[p]*phi_ref.slice(1); } break; } case 3: { const std::vector<Real>& dxidx_map = fe.get_fe_map().get_dxidx(); const std::vector<Real>& dxidy_map = fe.get_fe_map().get_dxidy(); const std::vector<Real>& dxidz_map = fe.get_fe_map().get_dxidz(); const std::vector<Real>& detadx_map = fe.get_fe_map().get_detadx(); const std::vector<Real>& detady_map = fe.get_fe_map().get_detady(); const std::vector<Real>& detadz_map = fe.get_fe_map().get_detadz(); const std::vector<Real>& dzetadx_map = fe.get_fe_map().get_dzetadx(); const std::vector<Real>& dzetady_map = fe.get_fe_map().get_dzetady(); const std::vector<Real>& dzetadz_map = fe.get_fe_map().get_dzetadz(); /* phi = (dx/dxi)^-T * \hat{phi} In 3D: dx/dxi^-1 = [ dxi/dx dxi/dy dxi/dz deta/dx deta/dy deta/dz dzeta/dx dzeta/dy dzeta/dz] so: dxi/dx^-T * \hat{phi} = [ dxi/dx deta/dx dzeta/dx [ \hat{phi}_xi dxi/dy deta/dy dzeta/dy \hat{phi}_eta dxi/dz deta/dz dzeta/dz ] \hat{phi}_zeta ] or in indicial notation: phi_j = xi_{i,j}*\hat{phi}_i */ for (unsigned int i=0; i<phi.size(); i++) for (unsigned int p=0; p<phi[i].size(); p++) { // Need to temporarily cache reference shape functions // TODO: PB: Might be worth trying to build phi_ref separately to see // if we can get vectorization OutputShape phi_ref; FEInterface::shape<OutputShape>(3, fe.get_fe_type(), elem, i, qp[p], phi_ref); phi[i][p].slice(0) = dxidx_map[p]*phi_ref.slice(0) + detadx_map[p]*phi_ref.slice(1) + dzetadx_map[p]*phi_ref.slice(2); phi[i][p].slice(1) = dxidy_map[p]*phi_ref.slice(0) + detady_map[p]*phi_ref.slice(1) + dzetady_map[p]*phi_ref.slice(2); phi[i][p].slice(2) = dxidz_map[p]*phi_ref.slice(0) + detadz_map[p]*phi_ref.slice(1) + dzetadz_map[p]*phi_ref.slice(2); } break; } default: libmesh_error(); } // switch(dim) return; }
void HCurlFETransformation<OutputShape>::map_curl( const unsigned int dim, const Elem* const, const std::vector<Point>&, const FEGenericBase<OutputShape>& fe, std::vector<std::vector<OutputShape> >& curl_phi ) const { switch(dim) { // These element transformations only make sense in 2D and 3D case 0: case 1: { libmesh_error(); } case 2: { const std::vector<std::vector<OutputShape> >& dphi_dxi = fe.get_dphidxi(); const std::vector<std::vector<OutputShape> >& dphi_deta = fe.get_dphideta(); const std::vector<Real>& J = fe.get_fe_map().get_jacobian(); // FIXME: I don't think this is valid for 2D elements in 3D space /* In 2D: curl(phi) = J^{-1} * curl(\hat{phi}) */ for (unsigned int i=0; i<curl_phi.size(); i++) for (unsigned int p=0; p<curl_phi[i].size(); p++) { curl_phi[i][p].slice(0) = curl_phi[i][p].slice(1) = 0.0; curl_phi[i][p].slice(2) = ( dphi_dxi[i][p].slice(1) - dphi_deta[i][p].slice(0) )/J[p]; } break; } case 3: { const std::vector<std::vector<OutputShape> >& dphi_dxi = fe.get_dphidxi(); const std::vector<std::vector<OutputShape> >& dphi_deta = fe.get_dphideta(); const std::vector<std::vector<OutputShape> >& dphi_dzeta = fe.get_dphidzeta(); const std::vector<RealGradient>& dxyz_dxi = fe.get_fe_map().get_dxyzdxi(); const std::vector<RealGradient>& dxyz_deta = fe.get_fe_map().get_dxyzdeta(); const std::vector<RealGradient>& dxyz_dzeta = fe.get_fe_map().get_dxyzdzeta(); const std::vector<Real>& J = fe.get_fe_map().get_jacobian(); for (unsigned int i=0; i<curl_phi.size(); i++) for (unsigned int p=0; p<curl_phi[i].size(); p++) { Real dx_dxi = dxyz_dxi[p](0); Real dx_deta = dxyz_deta[p](0); Real dx_dzeta = dxyz_dzeta[p](0); Real dy_dxi = dxyz_dxi[p](1); Real dy_deta = dxyz_deta[p](1); Real dy_dzeta = dxyz_dzeta[p](1); Real dz_dxi = dxyz_dxi[p](2); Real dz_deta = dxyz_deta[p](2); Real dz_dzeta = dxyz_dzeta[p](2); const Real inv_jac = 1.0/J[p]; /* In 3D: curl(phi) = J^{-1} dx/dxi * curl(\hat{phi}) dx/dxi = [ dx/dxi dx/deta dx/dzeta dy/dxi dy/deta dy/dzeta dz/dxi dz/deta dz/dzeta ] curl(u) = [ du_z/deta - du_y/dzeta du_x/dzeta - du_z/dxi du_y/dxi - du_x/deta ] */ curl_phi[i][p].slice(0) = inv_jac*( dx_dxi*( dphi_deta[i][p].slice(2) - dphi_dzeta[i][p].slice(1) ) + dx_deta*( dphi_dzeta[i][p].slice(0) - dphi_dxi[i][p].slice(2) ) + dx_dzeta*( dphi_dxi[i][p].slice(1) - dphi_deta[i][p].slice(0) ) ); curl_phi[i][p].slice(1) = inv_jac*( dy_dxi*( dphi_deta[i][p].slice(2) - dphi_dzeta[i][p].slice(1) ) + dy_deta*( dphi_dzeta[i][p].slice(0)- dphi_dxi[i][p].slice(2) ) + dy_dzeta*( dphi_dxi[i][p].slice(1) - dphi_deta[i][p].slice(0) ) ); curl_phi[i][p].slice(2) = inv_jac*( dz_dxi*( dphi_deta[i][p].slice(2) - dphi_dzeta[i][p].slice(1) ) + dz_deta*( dphi_dzeta[i][p].slice(0) - dphi_dxi[i][p].slice(2) ) + dz_dzeta*( dphi_dxi[i][p].slice(1) - dphi_deta[i][p].slice(0) ) ); } break; } default: libmesh_error(); } // switch(dim) return; }
void H1FETransformation<OutputShape>::map_dphi( const unsigned int dim, const Elem* const, const std::vector<Point>&, const FEGenericBase<OutputShape>& fe, std::vector<std::vector<typename FEGenericBase<OutputShape>::OutputGradient> >& dphi, std::vector<std::vector<OutputShape> >& dphidx, std::vector<std::vector<OutputShape> >& dphidy, std::vector<std::vector<OutputShape> >& dphidz ) const { switch(dim) { case 0: // No derivatives in 0D { for (unsigned int i=0; i<dphi.size(); i++) for (unsigned int p=0; p<dphi[i].size(); p++) { dphi[i][p] = 0.; } break; } case 1: { const std::vector<std::vector<OutputShape> >& dphidxi = fe.get_dphidxi(); const std::vector<Real>& dxidx_map = fe.get_fe_map().get_dxidx(); #if LIBMESH_DIM>1 const std::vector<Real>& dxidy_map = fe.get_fe_map().get_dxidy(); #endif #if LIBMESH_DIM>2 const std::vector<Real>& dxidz_map = fe.get_fe_map().get_dxidz(); #endif for (unsigned int i=0; i<dphi.size(); i++) for (unsigned int p=0; p<dphi[i].size(); p++) { // dphi/dx = (dphi/dxi)*(dxi/dx) dphi[i][p].slice(0) = dphidx[i][p] = dphidxi[i][p]*dxidx_map[p]; #if LIBMESH_DIM>1 dphi[i][p].slice(1) = dphidy[i][p] = dphidxi[i][p]*dxidy_map[p]; #endif #if LIBMESH_DIM>2 dphi[i][p].slice(2) = dphidz[i][p] = dphidxi[i][p]*dxidz_map[p]; #endif } break; } case 2: { const std::vector<std::vector<OutputShape> >& dphidxi = fe.get_dphidxi(); const std::vector<std::vector<OutputShape> >& dphideta = fe.get_dphideta(); const std::vector<Real>& dxidx_map = fe.get_fe_map().get_dxidx(); const std::vector<Real>& dxidy_map = fe.get_fe_map().get_dxidy(); #if LIBMESH_DIM > 2 const std::vector<Real>& dxidz_map = fe.get_fe_map().get_dxidz(); #endif const std::vector<Real>& detadx_map = fe.get_fe_map().get_detadx(); const std::vector<Real>& detady_map = fe.get_fe_map().get_detady(); #if LIBMESH_DIM > 2 const std::vector<Real>& detadz_map = fe.get_fe_map().get_detadz(); #endif for (unsigned int i=0; i<dphi.size(); i++) for (unsigned int p=0; p<dphi[i].size(); p++) { // dphi/dx = (dphi/dxi)*(dxi/dx) + (dphi/deta)*(deta/dx) dphi[i][p].slice(0) = dphidx[i][p] = (dphidxi[i][p]*dxidx_map[p] + dphideta[i][p]*detadx_map[p]); // dphi/dy = (dphi/dxi)*(dxi/dy) + (dphi/deta)*(deta/dy) dphi[i][p].slice(1) = dphidy[i][p] = (dphidxi[i][p]*dxidy_map[p] + dphideta[i][p]*detady_map[p]); #if LIBMESH_DIM > 2 // dphi/dz = (dphi/dxi)*(dxi/dz) + (dphi/deta)*(deta/dz) dphi[i][p].slice(2) = dphidz[i][p] = (dphidxi[i][p]*dxidz_map[p] + dphideta[i][p]*detadz_map[p]); #endif } break; } case 3: { const std::vector<std::vector<OutputShape> >& dphidxi = fe.get_dphidxi(); const std::vector<std::vector<OutputShape> >& dphideta = fe.get_dphideta(); const std::vector<std::vector<OutputShape> >& dphidzeta = fe.get_dphidzeta(); const std::vector<Real>& dxidx_map = fe.get_fe_map().get_dxidx(); const std::vector<Real>& dxidy_map = fe.get_fe_map().get_dxidy(); const std::vector<Real>& dxidz_map = fe.get_fe_map().get_dxidz(); const std::vector<Real>& detadx_map = fe.get_fe_map().get_detadx(); const std::vector<Real>& detady_map = fe.get_fe_map().get_detady(); const std::vector<Real>& detadz_map = fe.get_fe_map().get_detadz(); const std::vector<Real>& dzetadx_map = fe.get_fe_map().get_dzetadx(); const std::vector<Real>& dzetady_map = fe.get_fe_map().get_dzetady(); const std::vector<Real>& dzetadz_map = fe.get_fe_map().get_dzetadz(); for (unsigned int i=0; i<dphi.size(); i++) for (unsigned int p=0; p<dphi[i].size(); p++) { // dphi/dx = (dphi/dxi)*(dxi/dx) + (dphi/deta)*(deta/dx) + (dphi/dzeta)*(dzeta/dx); dphi[i][p].slice(0) = dphidx[i][p] = (dphidxi[i][p]*dxidx_map[p] + dphideta[i][p]*detadx_map[p] + dphidzeta[i][p]*dzetadx_map[p]); // dphi/dy = (dphi/dxi)*(dxi/dy) + (dphi/deta)*(deta/dy) + (dphi/dzeta)*(dzeta/dy); dphi[i][p].slice(1) = dphidy[i][p] = (dphidxi[i][p]*dxidy_map[p] + dphideta[i][p]*detady_map[p] + dphidzeta[i][p]*dzetady_map[p]); // dphi/dz = (dphi/dxi)*(dxi/dz) + (dphi/deta)*(deta/dz) + (dphi/dzeta)*(dzeta/dz); dphi[i][p].slice(2) = dphidz[i][p] = (dphidxi[i][p]*dxidz_map[p] + dphideta[i][p]*detadz_map[p] + dphidzeta[i][p]*dzetadz_map[p]); } break; } default: libmesh_error(); } // switch(dim) return; }