⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ex13.c

📁 一个用来实现偏微分方程中网格的计算库
💻 C
📖 第 1 页 / 共 2 页
字号:
  // The element shape function gradients for the velocity  // variables evaluated at the quadrature points.  const std::vector<std::vector<RealGradient> >& dphi = fe_vel->get_dphi();  // The element shape functions for the pressure variable  // evaluated at the quadrature points.  const std::vector<std::vector<Real> >& psi = fe_pres->get_phi();  // The value of the linear shape function gradients at the quadrature points  // const std::vector<std::vector<RealGradient> >& dpsi = fe_pres->get_dphi();    // A reference to the \p DofMap object for this system.  The \p DofMap  // object handles the index translation from node and element numbers  // to degree of freedom numbers.  We will talk more about the \p DofMap  // in future examples.  const DofMap & dof_map = navier_stokes_system.get_dof_map();  // Define data structures to contain the element matrix  // and right-hand-side vector contribution.  Following  // basic finite element terminology we will denote these  // "Ke" and "Fe".  DenseMatrix<Number> Ke;  DenseVector<Number> Fe;  DenseSubMatrix<Number>    Kuu(Ke), Kuv(Ke), Kup(Ke),    Kvu(Ke), Kvv(Ke), Kvp(Ke),    Kpu(Ke), Kpv(Ke), Kpp(Ke);  DenseSubVector<Number>    Fu(Fe),    Fv(Fe),    Fp(Fe);  // This vector will hold the degree of freedom indices for  // the element.  These define where in the global system  // the element degrees of freedom get mapped.  std::vector<unsigned int> dof_indices;  std::vector<unsigned int> dof_indices_u;  std::vector<unsigned int> dof_indices_v;  std::vector<unsigned int> dof_indices_p;  // Find out what the timestep size parameter is from the system, and  // the value of theta for the theta method.  We use implicit Euler (theta=1)  // for this simulation even though it is only first-order accurate in time.  // The reason for this decision is that the second-order Crank-Nicolson  // method is notoriously oscillatory for problems with discontinuous  // initial data such as the lid-driven cavity.  Therefore,  // we sacrifice accuracy in time for stability, but since the solution  // reaches steady state relatively quickly we can afford to take small  // timesteps.  If you monitor the initial nonlinear residual for this  // simulation, you should see that it is monotonically decreasing in time.  const Real dt    = es.parameters.get<Real>("dt");  // const Real time  = es.parameters.get<Real>("time");  const Real theta = 1.;      // Now we will loop over all the elements in the mesh that  // live on the local processor. We will compute the element  // matrix and right-hand-side contribution.  Since the mesh  // will be refined we want to only consider the ACTIVE elements,  // hence we use a variant of the \p active_elem_iterator.  MeshBase::const_element_iterator       el     = mesh.active_local_elements_begin();  const MeshBase::const_element_iterator end_el = mesh.active_local_elements_end();     for ( ; el != end_el; ++el)    {          // Store a pointer to the element we are currently      // working on.  This allows for nicer syntax later.      const Elem* elem = *el;            // Get the degree of freedom indices for the      // current element.  These define where in the global      // matrix and right-hand-side this element will      // contribute to.      dof_map.dof_indices (elem, dof_indices);      dof_map.dof_indices (elem, dof_indices_u, u_var);      dof_map.dof_indices (elem, dof_indices_v, v_var);      dof_map.dof_indices (elem, dof_indices_p, p_var);      const unsigned int n_dofs   = dof_indices.size();      const unsigned int n_u_dofs = dof_indices_u.size();       const unsigned int n_v_dofs = dof_indices_v.size();       const unsigned int n_p_dofs = dof_indices_p.size();            // Compute the element-specific data for the current      // element.  This involves computing the location of the      // quadrature points (q_point) and the shape functions      // (phi, dphi) for the current element.      fe_vel->reinit  (elem);      fe_pres->reinit (elem);      // Zero the element matrix and right-hand side before      // summing them.  We use the resize member here because      // the number of degrees of freedom might have changed from      // the last element.  Note that this will be the case if the      // element type is different (i.e. the last element was a      // triangle, now we are on a quadrilateral).      Ke.resize (n_dofs, n_dofs);      Fe.resize (n_dofs);      // Reposition the submatrices...  The idea is this:      //      //         -           -          -  -      //        | Kuu Kuv Kup |        | Fu |      //   Ke = | Kvu Kvv Kvp |;  Fe = | Fv |      //        | Kpu Kpv Kpp |        | Fp |      //         -           -          -  -      //      // The \p DenseSubMatrix.repostition () member takes the      // (row_offset, column_offset, row_size, column_size).      //       // Similarly, the \p DenseSubVector.reposition () member      // takes the (row_offset, row_size)      Kuu.reposition (u_var*n_u_dofs, u_var*n_u_dofs, n_u_dofs, n_u_dofs);      Kuv.reposition (u_var*n_u_dofs, v_var*n_u_dofs, n_u_dofs, n_v_dofs);      Kup.reposition (u_var*n_u_dofs, p_var*n_u_dofs, n_u_dofs, n_p_dofs);            Kvu.reposition (v_var*n_v_dofs, u_var*n_v_dofs, n_v_dofs, n_u_dofs);      Kvv.reposition (v_var*n_v_dofs, v_var*n_v_dofs, n_v_dofs, n_v_dofs);      Kvp.reposition (v_var*n_v_dofs, p_var*n_v_dofs, n_v_dofs, n_p_dofs);            Kpu.reposition (p_var*n_u_dofs, u_var*n_u_dofs, n_p_dofs, n_u_dofs);      Kpv.reposition (p_var*n_u_dofs, v_var*n_u_dofs, n_p_dofs, n_v_dofs);      Kpp.reposition (p_var*n_u_dofs, p_var*n_u_dofs, n_p_dofs, n_p_dofs);      Fu.reposition (u_var*n_u_dofs, n_u_dofs);      Fv.reposition (v_var*n_u_dofs, n_v_dofs);      Fp.reposition (p_var*n_u_dofs, n_p_dofs);      // Now we will build the element matrix and right-hand-side.      // Constructing the RHS 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.      for (unsigned int qp=0; qp<qrule.n_points(); qp++)        {          // Values to hold the solution & its gradient at the previous timestep.          Number   u = 0., u_old = 0.;          Number   v = 0., v_old = 0.;          Number   p_old = 0.;          Gradient grad_u, grad_u_old;          Gradient grad_v, grad_v_old;                    // Compute the velocity & its gradient from the previous timestep          // and the old Newton iterate.          for (unsigned int l=0; l<n_u_dofs; l++)            {              // From the old timestep:              u_old += phi[l][qp]*navier_stokes_system.old_solution (dof_indices_u[l]);              v_old += phi[l][qp]*navier_stokes_system.old_solution (dof_indices_v[l]);              grad_u_old.add_scaled (dphi[l][qp],navier_stokes_system.old_solution (dof_indices_u[l]));              grad_v_old.add_scaled (dphi[l][qp],navier_stokes_system.old_solution (dof_indices_v[l]));              // From the previous Newton iterate:              u += phi[l][qp]*navier_stokes_system.current_solution (dof_indices_u[l]);               v += phi[l][qp]*navier_stokes_system.current_solution (dof_indices_v[l]);              grad_u.add_scaled (dphi[l][qp],navier_stokes_system.current_solution (dof_indices_u[l]));              grad_v.add_scaled (dphi[l][qp],navier_stokes_system.current_solution (dof_indices_v[l]));            }          // Compute the old pressure value at this quadrature point.          for (unsigned int l=0; l<n_p_dofs; l++)            {              p_old += psi[l][qp]*navier_stokes_system.old_solution (dof_indices_p[l]);            }          // Definitions for convenience.  It is sometimes simpler to do a          // dot product if you have the full vector at your disposal.          const NumberVectorValue U_old (u_old, v_old);          const NumberVectorValue U     (u,     v);          const Number  u_x = grad_u(0);          const Number  u_y = grad_u(1);          const Number  v_x = grad_v(0);          const Number  v_y = grad_v(1);                    // 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) += JxW[qp]*(u_old*phi[i][qp] -                            // mass-matrix term                                 (1.-theta)*dt*(U_old*grad_u_old)*phi[i][qp] + // convection term                                (1.-theta)*dt*p_old*dphi[i][qp](0)  -         // pressure term on rhs                                (1.-theta)*dt*(grad_u_old*dphi[i][qp]) +      // diffusion term on rhs                                theta*dt*(U*grad_u)*phi[i][qp]);              // Newton term                              Fv(i) += JxW[qp]*(v_old*phi[i][qp] -                             // mass-matrix term                                (1.-theta)*dt*(U_old*grad_v_old)*phi[i][qp] +  // convection term                                (1.-theta)*dt*p_old*dphi[i][qp](1) -           // pressure term on rhs                                (1.-theta)*dt*(grad_v_old*dphi[i][qp]) +       // diffusion term on rhs                                theta*dt*(U*grad_v)*phi[i][qp]);               // Newton term                          // Note that the Fp block is identically zero unless we are using              // some kind of artificial compressibility scheme...              // Matrix contributions for the uu and vv couplings.              for (unsigned int j=0; j<n_u_dofs; j++)                {                  Kuu(i,j) += JxW[qp]*(phi[i][qp]*phi[j][qp] +                // mass matrix term                                       theta*dt*(dphi[i][qp]*dphi[j][qp]) +   // diffusion term                                       theta*dt*(U*dphi[j][qp])*phi[i][qp] +  // convection term                                       theta*dt*u_x*phi[i][qp]*phi[j][qp]);   // Newton term                  Kuv(i,j) += JxW[qp]*theta*dt*u_y*phi[i][qp]*phi[j][qp];     // Newton term                                    Kvv(i,j) += JxW[qp]*(phi[i][qp]*phi[j][qp] +                // mass matrix term                                       theta*dt*(dphi[i][qp]*dphi[j][qp]) +   // diffusion term                                       theta*dt*(U*dphi[j][qp])*phi[i][qp] +  // convection term                                       theta*dt*v_y*phi[i][qp]*phi[j][qp]);   // Newton term                  Kvu(i,j) += JxW[qp]*theta*dt*v_x*phi[i][qp]*phi[j][qp];     // Newton term                }              // Matrix contributions for the up and vp couplings.              for (unsigned int j=0; j<n_p_dofs; j++)                {                  Kup(i,j) += JxW[qp]*(-theta*dt*psi[j][qp]*dphi[i][qp](0));                  Kvp(i,j) += JxW[qp]*(-theta*dt*psi[j][qp]*dphi[i][qp](1));                }            }          // Now an i-loop over the pressure degrees of freedom.  This code computes          // the matrix entries due to the continuity equation.  Note: To maintain a          // symmetric matrix, we may (or may not) multiply the continuity equation by          // negative one.  Here we do not.          for (unsigned int i=0; i<n_p_dofs; i++)            {              for (unsigned int j=0; j<n_u_dofs; j++)                {                  Kpu(i,j) += JxW[qp]*psi[i][qp]*dphi[j][qp](0);                  Kpv(i,j) += JxW[qp]*psi[i][qp]*dphi[j][qp](1);                }            }        } // end of the quadrature point qp-loop            // At this point the interior element integration has      // been completed.  However, we have not yet addressed      // boundary conditions.  For this example we will only      // consider simple Dirichlet boundary conditions imposed      // via the penalty method. The penalty method used here      // is equivalent (for Lagrange basis functions) to lumping      // the matrix resulting from the L2 projection penalty      // approach introduced in example 3.      {        // The penalty value.  \f$ \frac{1}{\epsilon \f$        const Real penalty = 1.e10;                          // The following loops over the sides of the element.        // If the element has no neighbor on a side then that        // side MUST live on a boundary of the domain.        for (unsigned int s=0; s<elem->n_sides(); s++)          if (elem->neighbor(s) == NULL)            {              // Get the boundary ID for side 's'.              // These are set internally by build_square().              // 0=bottom              // 1=right              // 2=top              // 3=left              short int bc_id = mesh.boundary_info->boundary_id (elem,s);              if (bc_id==BoundaryInfo::invalid_id)                  libmesh_error();                            AutoPtr<Elem> side (elem->build_side(s));                                          // Loop over the nodes on the side.              for (unsigned int ns=0; ns<side->n_nodes(); ns++)                {                  // Get the boundary values.                                     // Set u = 1 on the top boundary, 0 everywhere else                  const Real u_value = (bc_id==2) ? 1. : 0.;                                    // Set v = 0 everywhere                  const Real v_value = 0.;                                    // Find the node on the element matching this node on                  // the side.  That defined where in the element matrix                  // the boundary condition will be applied.                  for (unsigned int n=0; n<elem->n_nodes(); n++)                    if (elem->node(n) == side->node(ns))                      {                        // Matrix contribution.                        Kuu(n,n) += penalty;                        Kvv(n,n) += penalty;                                                            // Right-hand-side contribution.                        Fu(n) += penalty*u_value;                        Fv(n) += penalty*v_value;                      }                } // end face node loop                      } // end if (elem->neighbor(side) == NULL)                // Pin the pressure to zero at global node number "pressure_node".        // This effectively removes the non-trivial null space of constant        // pressure solutions.        const bool pin_pressure = true;        if (pin_pressure)          {            const unsigned int pressure_node = 0;            const Real p_value               = 0.0;            for (unsigned int c=0; c<elem->n_nodes(); c++)              if (elem->node(c) == pressure_node)                {                  Kpp(c,c) += penalty;                  Fp(c)    += penalty*p_value;                }          }      } // end boundary condition section                      // The element matrix and right-hand-side are now built      // for this element.  Add them to the global matrix and      // right-hand-side vector.  The \p PetscMatrix::add_matrix()      // and \p PetscVector::add_vector() members do this for us.      navier_stokes_system.matrix->add_matrix (Ke, dof_indices);      navier_stokes_system.rhs->add_vector    (Fe, dof_indices);    } // end of element loop    // That's it.  return;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -