📄 ex3.php
字号:
<div class ="fragment"><pre> const DofMap& dof_map = system.get_dof_map(); </pre></div><div class = "comment">Get a constant reference to the Finite Element typefor the first (and only) variable in the system.</div><div class ="fragment"><pre> FEType fe_type = dof_map.variable_type(0); </pre></div><div class = "comment">Build a Finite Element object of the specified type. Since theFEBase::build() member dynamically creates memory we willstore the object as an AutoPtr<FEBase>. This can be thoughtof as a pointer that will clean up after itself. Example 4describes some advantages of AutoPtr's in the context ofquadrature rules.</div><div class ="fragment"><pre> AutoPtr<FEBase> fe (FEBase::build(dim, fe_type)); </pre></div><div class = "comment">A 5th order Gauss quadrature rule for numerical integration.</div><div class ="fragment"><pre> QGauss qrule (dim, FIFTH); </pre></div><div class = "comment">Tell the finite element object to use our quadrature rule.</div><div class ="fragment"><pre> fe->attach_quadrature_rule (&qrule); </pre></div><div class = "comment">Declare a special finite element object forboundary integration.</div><div class ="fragment"><pre> AutoPtr<FEBase> fe_face (FEBase::build(dim, fe_type)); </pre></div><div class = "comment">Boundary integration requires one quadraure rule,with dimensionality one less than the dimensionalityof the element.</div><div class ="fragment"><pre> QGauss qface(dim-1, FIFTH); </pre></div><div class = "comment">Tell the finite element object to use ourquadrature rule.</div><div class ="fragment"><pre> fe_face->attach_quadrature_rule (&qface); </pre></div><div class = "comment">Here we define some references to cell-specific data thatwill be used to assemble the linear system.<br><br>The element Jacobian * quadrature weight at each integration point. </div><div class ="fragment"><pre> const std::vector<Real>& JxW = fe->get_JxW(); </pre></div><div class = "comment">The physical XY locations of the quadrature points on the element.These might be useful for evaluating spatially varying materialproperties at the quadrature points.</div><div class ="fragment"><pre> const std::vector<Point>& q_point = fe->get_xyz(); </pre></div><div class = "comment">The element shape functions evaluated at the quadrature points.</div><div class ="fragment"><pre> const std::vector<std::vector<Real> >& phi = fe->get_phi(); </pre></div><div class = "comment">The element shape function gradients evaluated at the quadraturepoints.</div><div class ="fragment"><pre> const std::vector<std::vector<RealGradient> >& dphi = fe->get_dphi(); </pre></div><div class = "comment">Define data structures to contain the element matrixand right-hand-side vector contribution. Followingbasic finite element terminology we will denote these"Ke" and "Fe". These datatypes are templated onNumber, which allows the same code to work for realor complex numbers.</div><div class ="fragment"><pre> DenseMatrix<Number> Ke; DenseVector<Number> Fe; </pre></div><div class = "comment">This vector will hold the degree of freedom indices forthe element. These define where in the global systemthe element degrees of freedom get mapped.</div><div class ="fragment"><pre> std::vector<unsigned int> dof_indices; </pre></div><div class = "comment">Now we will loop over all the elements in the mesh.We will compute the element matrix and right-hand-sidecontribution.<br><br>Element iterators are a nice way to iterate throughall the elements, or all the elements that have some property.There are many types of element iterators, but here we willuse the most basic type, the const_elem_iterator. The iteratorel will iterate from the first to the last element. Theiterator end_el tells us when to stop. It is smart to makethis one const so that we don't accidentally mess it up!const_elem_iterator el (mesh.elements_begin());const const_elem_iterator end_el (mesh.elements_end());<br><br></div><div class ="fragment"><pre> MeshBase::const_element_iterator el = mesh.elements_begin(); const MeshBase::const_element_iterator end_el = mesh.elements_end(); </pre></div><div class = "comment">Loop over the elements. Note that ++el is preferred toel++ since the latter requires an unnecessary temporaryobject.</div><div class ="fragment"><pre> for ( ; el != end_el ; ++el) {</pre></div><div class = "comment">Store a pointer to the element we are currentlyworking on. This allows for nicer syntax later.</div><div class ="fragment"><pre> const Elem* elem = *el; </pre></div><div class = "comment">Get the degree of freedom indices for thecurrent element. These define where in the globalmatrix and right-hand-side this element willcontribute to.</div><div class ="fragment"><pre> dof_map.dof_indices (elem, dof_indices); </pre></div><div class = "comment">Compute the element-specific data for the currentelement. This involves computing the location of thequadrature points (q_point) and the shape functions(phi, dphi) for the current element.</div><div class ="fragment"><pre> fe->reinit (elem); </pre></div><div class = "comment">Zero the element matrix and right-hand side beforesumming them. We use the resize member here becausethe number of degrees of freedom might have changed fromthe last element. Note that this will be the case if theelement type is different (i.e. the last element was atriangle, now we are on a quadrilateral).<br><br>The DenseMatrix::resize() and the DenseVector::resize()members will automatically zero out the matrix and vector.</div><div class ="fragment"><pre> Ke.resize (dof_indices.size(), dof_indices.size()); Fe.resize (dof_indices.size()); </pre></div><div class = "comment">Now loop over the quadrature points. This handlesthe numeric integration.</div><div class ="fragment"><pre> for (unsigned int qp=0; qp<qrule.n_points(); qp++) { </pre></div><div class = "comment">Now we will build the element matrix. This involvesa double loop to integrate the test funcions (i) againstthe trial functions (j).</div><div class ="fragment"><pre> for (unsigned int i=0; i<phi.size(); i++) for (unsigned int j=0; j<phi.size(); j++) { Ke(i,j) += JxW[qp]*(dphi[i][qp]*dphi[j][qp]); } </pre></div><div class = "comment">This is the end of the matrix summation loopNow we build the element right-hand-side contribution.This involves a single loop in which we integrate the"forcing function" in the PDE against the test functions.</div><div class ="fragment"><pre> { const Real x = q_point[qp](0); const Real y = q_point[qp](1); const Real eps = 1.e-3; </pre></div><div class = "comment">"fxy" is the forcing function for the Poisson equation.In this case we set fxy to be a finite differenceLaplacian approximation to the (known) exact solution.<br><br>We will use the second-order accurate FD Laplacianapproximation, which in 2D is<br><br>u_xx + u_yy = (u(i,j-1) + u(i,j+1) +u(i-1,j) + u(i+1,j) +-4*u(i,j))/h^2<br><br>Since the value of the forcing function depends onlyon the location of the quadrature point (q_point[qp])we will compute it here, outside of the i-loop</div><div class ="fragment"><pre> const Real fxy = -(exact_solution(x,y-eps) + exact_solution(x,y+eps) + exact_solution(x-eps,y) + exact_solution(x+eps,y) - 4.*exact_solution(x,y))/eps/eps; for (unsigned int i=0; i<phi.size(); i++) Fe(i) += JxW[qp]*fxy*phi[i][qp]; } } </pre></div><div class = "comment">We have now reached the end of the RHS summation,and the end of quadrature point loop, sothe interior element integration hasbeen completed. However, we have not yet addressedboundary conditions. For this example we will onlyconsider simple Dirichlet boundary conditions.<br><br>There are several ways Dirichlet boundary conditionscan be imposed. A simple approach, which works forinterpolary bases like the standard Lagrange polynomials,is to assign function values to thedegrees of freedom living on the domain boundary. Thisworks well for interpolary bases, but is more difficultwhen non-interpolary (e.g Legendre or Hierarchic) basesare used.<br><br>Dirichlet boundary conditions can also be imposed with a"penalty" method. In this case essentially the L2 projectionof the boundary values are added to the matrix. Theprojection is multiplied by some large factor so that, infloating point arithmetic, the existing (smaller) entriesin the matrix and right-hand-side are effectively ignored.<br><br>This amounts to adding a term of the form (in latex notation)<br><br>\frac{1}{\epsilon} \int_{\delta \Omega} \phi_i \phi_j = \frac{1}{\epsilon} \int_{\delta \Omega} u \phi_i<br><br>where<br><br>\frac{1}{\epsilon} is the penalty parameter, defined such that \epsilon << 1</div><div class ="fragment"><pre> { </pre></div><div class = "comment">The following loop is over the sides of the element.If the element has no neighbor on a side then thatside MUST live on a boundary of the domain.</div><div class ="fragment"><pre> for (unsigned int side=0; side<elem->n_sides(); side++) if (elem->neighbor(side) == NULL) {</pre></div><div class = "comment">The value of the shape functions at the quadraturepoints.</div><div class ="fragment"><pre> const std::vector<std::vector<Real> >& phi_face = fe_face->get_phi(); </pre></div><div class = "comment">The Jacobian * Quadrature Weight at the quadrature
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -