コード例 #1
0
ファイル: miscellaneous_ex10.C プロジェクト: YSB330/libmesh
void assemble_poisson(EquationSystems & es,
                      const std::string & system_name)
{
  libmesh_assert_equal_to (system_name, "Poisson");

  const MeshBase & mesh = es.get_mesh();
  const unsigned int dim = mesh.mesh_dimension();
  LinearImplicitSystem & system = es.get_system<LinearImplicitSystem>("Poisson");

  const DofMap & dof_map = system.get_dof_map();

  FEType fe_type = dof_map.variable_type(0);
  UniquePtr<FEBase> fe (FEBase::build(dim, fe_type));
  QGauss qrule (dim, FIFTH);
  fe->attach_quadrature_rule (&qrule);
  UniquePtr<FEBase> fe_face (FEBase::build(dim, fe_type));
  QGauss qface(dim-1, FIFTH);
  fe_face->attach_quadrature_rule (&qface);

  const std::vector<Real> & JxW = fe->get_JxW();
  const std::vector<std::vector<Real> > & phi = fe->get_phi();
  const std::vector<std::vector<RealGradient> > & dphi = fe->get_dphi();

  DenseMatrix<Number> Ke;
  DenseVector<Number> Fe;

  std::vector<dof_id_type> dof_indices;

  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)
    {
      const Elem * elem = *el;

      dof_map.dof_indices (elem, dof_indices);

      fe->reinit (elem);

      Ke.resize (dof_indices.size(),
                 dof_indices.size());

      Fe.resize (dof_indices.size());

      for (unsigned int qp=0; qp<qrule.n_points(); qp++)
        {
          for (unsigned int i=0; i<phi.size(); i++)
            {
              Fe(i) += JxW[qp]*phi[i][qp];
              for (unsigned int j=0; j<phi.size(); j++)
                Ke(i,j) += JxW[qp]*(dphi[i][qp]*dphi[j][qp]);
            }
        }

      dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices);

      system.matrix->add_matrix (Ke, dof_indices);
      system.rhs->add_vector    (Fe, dof_indices);
    }
}
コード例 #2
0
void AssembleOptimization::assemble_A_and_F()
{
  A_matrix->zero();
  F_vector->zero();

  const MeshBase & mesh = _sys.get_mesh();

  const unsigned int dim = mesh.mesh_dimension();
  const unsigned int u_var = _sys.variable_number ("u");

  const DofMap & dof_map = _sys.get_dof_map();
  FEType fe_type = dof_map.variable_type(u_var);
  UniquePtr<FEBase> fe (FEBase::build(dim, fe_type));
  QGauss qrule (dim, fe_type.default_quadrature_order());
  fe->attach_quadrature_rule (&qrule);

  const std::vector<Real> & JxW = fe->get_JxW();
  const std::vector<std::vector<Real> > & phi = fe->get_phi();
  const std::vector<std::vector<RealGradient> > & dphi = fe->get_dphi();

  std::vector<dof_id_type> dof_indices;

  DenseMatrix<Number> Ke;
  DenseVector<Number> Fe;

  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)
    {
      const Elem * elem = *el;

      dof_map.dof_indices (elem, dof_indices);

      const unsigned int n_dofs = dof_indices.size();

      fe->reinit (elem);

      Ke.resize (n_dofs, n_dofs);
      Fe.resize (n_dofs);

      for (unsigned int qp=0; qp<qrule.n_points(); qp++)
        {
          for (unsigned int dof_i=0; dof_i<n_dofs; dof_i++)
            {
              for (unsigned int dof_j=0; dof_j<n_dofs; dof_j++)
                {
                  Ke(dof_i, dof_j) += JxW[qp] * (dphi[dof_j][qp]* dphi[dof_i][qp]);
                }
              Fe(dof_i) += JxW[qp] * phi[dof_i][qp];
            }
        }

      A_matrix->add_matrix (Ke, dof_indices);
      F_vector->add_vector (Fe, dof_indices);
    }

  A_matrix->close();
  F_vector->close();
}
コード例 #3
0
ファイル: optimization_ex1.C プロジェクト: vityurkiv/Ox
void AssembleOptimization::assemble_A_and_F()
{
  A_matrix->zero();
  F_vector->zero();

  const MeshBase & mesh = _sys.get_mesh();

  const unsigned int dim = mesh.mesh_dimension();
  const unsigned int u_var = _sys.variable_number ("u");

  const DofMap & dof_map = _sys.get_dof_map();
  FEType fe_type = dof_map.variable_type(u_var);
  UniquePtr<FEBase> fe (FEBase::build(dim, fe_type));
  QGauss qrule (dim, fe_type.default_quadrature_order());
  fe->attach_quadrature_rule (&qrule);

  const std::vector<Real> & JxW = fe->get_JxW();
  const std::vector<std::vector<Real> > & phi = fe->get_phi();
  const std::vector<std::vector<RealGradient> > & dphi = fe->get_dphi();

  std::vector<dof_id_type> dof_indices;

  DenseMatrix<Number> Ke;
  DenseVector<Number> Fe;

  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)
    {
      const Elem * elem = *el;

      dof_map.dof_indices (elem, dof_indices);

      const unsigned int n_dofs = dof_indices.size();

      fe->reinit (elem);

      Ke.resize (n_dofs, n_dofs);
      Fe.resize (n_dofs);

      for (unsigned int qp=0; qp<qrule.n_points(); qp++)
        {
          for (unsigned int dof_i=0; dof_i<n_dofs; dof_i++)
            {
              for (unsigned int dof_j=0; dof_j<n_dofs; dof_j++)
                {
                  Ke(dof_i, dof_j) += JxW[qp] * (dphi[dof_j][qp]* dphi[dof_i][qp]);
                }
              Fe(dof_i) += JxW[qp] * phi[dof_i][qp];
            }
        }

      // This will zero off-diagonal entries of Ke corresponding to
      // Dirichlet dofs.
      dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices);

      // We want the diagonal of constrained dofs to be zero too
      for (unsigned int local_dof_index=0; local_dof_index<n_dofs; local_dof_index++)
        {
          dof_id_type global_dof_index = dof_indices[local_dof_index];
          if (dof_map.is_constrained_dof(global_dof_index))
            {
              Ke(local_dof_index, local_dof_index) = 0.;
            }
        }

      A_matrix->add_matrix (Ke, dof_indices);
      F_vector->add_vector (Fe, dof_indices);
    }

  A_matrix->close();
  F_vector->close();
}
コード例 #4
0
ファイル: biharmonic_jr.C プロジェクト: friedmud/libmesh
void Biharmonic::JR::bounds(NumericVector<Number> & XL,
                            NumericVector<Number> & XU,
                            NonlinearImplicitSystem &)
{
  // sys is actually ignored, since it should be the same as *this.

  // Declare a performance log.  Give it a descriptive
  // string to identify what part of the code we are
  // logging, since there may be many PerfLogs in an
  // application.
  PerfLog perf_log ("Biharmonic bounds", false);

  // A reference to the DofMap object for this system.  The DofMap
  // object handles the index translation from node and element numbers
  // to degree of freedom numbers.  We will talk more about the DofMap
  // in future examples.
  const DofMap & dof_map = get_dof_map();

  // Get a constant reference to the Finite Element type
  // for the first (and only) variable in the system.
  FEType fe_type = dof_map.variable_type(0);

  // Build a Finite Element object of the specified type.  Since the
  // FEBase::build() member dynamically creates memory we will
  // store the object as a UniquePtr<FEBase>.  This can be thought
  // of as a pointer that will clean up after itself.
  UniquePtr<FEBase> fe (FEBase::build(_biharmonic._dim, fe_type));

  // Define data structures to contain the bound vectors contributions.
  DenseVector<Number> XLe, XUe;

  // These 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<dof_id_type> dof_indices;

  MeshBase::const_element_iterator       el     = _biharmonic._mesh.active_local_elements_begin();
  const MeshBase::const_element_iterator end_el = _biharmonic._mesh.active_local_elements_end();

  for ( ; el != end_el; ++el)
    {
      // Extract the shape function to be evaluated at the nodes
      const std::vector<std::vector<Real> > & phi = fe->get_phi();

      // Get the degree of freedom indices for the current element.
      // They are in 1-1 correspondence with shape functions phi
      // and define where in the global vector this element will.
      dof_map.dof_indices (*el, dof_indices);

      // Resize the local bounds vectors (zeroing them out in the process).
      XLe.resize(dof_indices.size());
      XUe.resize(dof_indices.size());

      // Extract the element node coordinates in the reference frame
      std::vector<Point> nodes;
      fe->get_refspace_nodes((*el)->type(), nodes);

      // Evaluate the shape functions at the nodes
      fe->reinit(*el, &nodes);

      // Construct the bounds based on the value of the i-th phi at the nodes.
      // Observe that this doesn't really work in general: we rely on the fact
      // that for Hermite elements each shape function is nonzero at most at a
      // single node.
      // More generally the bounds must be constructed by inspecting a "mass-like"
      // matrix (m_{ij}) of the shape functions (i) evaluated at their corresponding nodes (j).
      // The constraints imposed on the dofs (d_i) are then are -1 \leq \sum_i d_i m_{ij} \leq 1,
      // since \sum_i d_i m_{ij} is the value of the solution at the j-th node.
      // Auxiliary variables will need to be introduced to reduce this to a "box" constraint.
      // Additional complications will arise since m might be singular (as is the case for Hermite,
      // which, however, is easily handled by inspection).
      for (unsigned int i=0; i<phi.size(); ++i)
        {
          // FIXME: should be able to define INF and pass it to the solve
          Real infinity = 1.0e20;
          Real bound = infinity;
          for (unsigned int j = 0; j < nodes.size(); ++j)
            {
              if (phi[i][j])
                {
                  bound = 1.0/std::abs(phi[i][j]);
                  break;
                }
            }

          // The value of the solution at this node must be between 1.0 and -1.0.
          // Based on the value of phi(i)(i) the nodal coordinate must be between 1.0/phi(i)(i) and its negative.
          XLe(i) = -bound;
          XUe(i) = bound;
        }
      // The element bound vectors are now built for this element.
      // Insert them into the global vectors, potentially overwriting
      // the same dof contributions from other elements: no matter --
      // the bounds are always -1.0 and 1.0.
      XL.insert(XLe, dof_indices);
      XU.insert(XUe, dof_indices);
    }
}
コード例 #5
0
ファイル: biharmonic_jr.C プロジェクト: friedmud/libmesh
void Biharmonic::JR::residual_and_jacobian(const NumericVector<Number> & u,
                                           NumericVector<Number> * R,
                                           SparseMatrix<Number> * J,
                                           NonlinearImplicitSystem &)
{
#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
  if (!R && !J)
    return;

  // Declare a performance log.  Give it a descriptive
  // string to identify what part of the code we are
  // logging, since there may be many PerfLogs in an
  // application.
  PerfLog perf_log ("Biharmonic Residual and Jacobian", false);

  // A reference to the DofMap object for this system.  The DofMap
  // object handles the index translation from node and element numbers
  // to degree of freedom numbers.  We will talk more about the DofMap
  // in future examples.
  const DofMap & dof_map = get_dof_map();

  // Get a constant reference to the Finite Element type
  // for the first (and only) variable in the system.
  FEType fe_type = dof_map.variable_type(0);

  // Build a Finite Element object of the specified type.  Since the
  // FEBase::build() member dynamically creates memory we will
  // store the object as a UniquePtr<FEBase>.  This can be thought
  // of as a pointer that will clean up after itself.
  UniquePtr<FEBase> fe (FEBase::build(_biharmonic._dim, fe_type));

  // Quadrature rule for numerical integration.
  // With 2D triangles, the Clough quadrature rule puts a Gaussian
  // quadrature rule on each of the 3 subelements
  UniquePtr<QBase> qrule(fe_type.default_quadrature_rule(_biharmonic._dim));

  // Tell the finite element object to use our quadrature rule.
  fe->attach_quadrature_rule (qrule.get());

  // Here we define some references to element-specific data that
  // will be used to assemble the linear system.
  // We begin with the element Jacobian * quadrature weight at each
  // integration point.
  const std::vector<Real> & JxW = fe->get_JxW();

  // The element shape functions evaluated at the quadrature points.
  const std::vector<std::vector<Real> > & phi = fe->get_phi();

  // The element shape functions' derivatives evaluated at the quadrature points.
  const std::vector<std::vector<RealGradient> > & dphi = fe->get_dphi();

  // The element shape functions'  second derivatives evaluated at the quadrature points.
  const std::vector<std::vector<RealTensor> > & d2phi = fe->get_d2phi();

  // For efficiency we will compute shape function laplacians n times,
  // not n^2
  std::vector<Real> Laplacian_phi_qp;

  // Define data structures to contain the element matrix
  // and right-hand-side vector contribution.  Following
  // basic finite element terminology we will denote these
  // "Je" and "Re". More detail is in example 3.
  DenseMatrix<Number> Je;
  DenseVector<Number> Re;

  // 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<dof_id_type> dof_indices;

  // Old solution
  const NumericVector<Number> & u_old = *old_local_solution;

  // Now we will loop over all the elements in the mesh.  We will
  // compute the element matrix and right-hand-side contribution.  See
  // example 3 for a discussion of the element iterators.

  MeshBase::const_element_iterator       el     = _biharmonic._mesh.active_local_elements_begin();
  const MeshBase::const_element_iterator end_el = _biharmonic._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);

      // Compute the element-specific data for the current
      // element.  This involves computing the location of the
      // quadrature points (q_point) and the shape function
      // values/derivatives (phi, dphi, d2phi) for the current element.
      fe->reinit (elem);

      // Zero the element matrix, the right-hand side and the Laplacian matrix
      // before summing them.
      if (J)
        Je.resize(dof_indices.size(), dof_indices.size());

      if (R)
        Re.resize(dof_indices.size());

      Laplacian_phi_qp.resize(dof_indices.size());

      for (unsigned int qp=0; qp<qrule->n_points(); qp++)
        {
          // AUXILIARY QUANTITIES:
          // Residual and Jacobian share a few calculations:
          // at the very least, in the case of interfacial energy only with a constant mobility,
          // both calculations use Laplacian_phi_qp; more is shared the case of a concentration-dependent
          // mobility and bulk potentials.
          Number
            u_qp = 0.0,
            u_old_qp = 0.0,
            Laplacian_u_qp = 0.0,
            Laplacian_u_old_qp = 0.0;

          Gradient
            grad_u_qp(0.0, 0.0, 0.0),
            grad_u_old_qp(0.0, 0.0, 0.0);

          Number
            M_qp = 1.0,
            M_old_qp = 1.0,
            M_prime_qp = 0.0,
            M_prime_old_qp = 0.0;

          for (unsigned int i=0; i<phi.size(); i++)
            {
              Laplacian_phi_qp[i] = d2phi[i][qp](0, 0);
              grad_u_qp(0) += u(dof_indices[i])*dphi[i][qp](0);
              grad_u_old_qp(0) += u_old(dof_indices[i])*dphi[i][qp](0);

              if (_biharmonic._dim > 1)
                {
                  Laplacian_phi_qp[i] += d2phi[i][qp](1, 1);
                  grad_u_qp(1) += u(dof_indices[i])*dphi[i][qp](1);
                  grad_u_old_qp(1) += u_old(dof_indices[i])*dphi[i][qp](1);
                }
              if (_biharmonic._dim > 2)
                {
                  Laplacian_phi_qp[i] += d2phi[i][qp](2, 2);
                  grad_u_qp(2) += u(dof_indices[i])*dphi[i][qp](2);
                  grad_u_old_qp(2) += u_old(dof_indices[i])*dphi[i][qp](2);
                }
              u_qp     += phi[i][qp]*u(dof_indices[i]);
              u_old_qp += phi[i][qp]*u_old(dof_indices[i]);
              Laplacian_u_qp     += Laplacian_phi_qp[i]*u(dof_indices[i]);
              Laplacian_u_old_qp += Laplacian_phi_qp[i]*u_old(dof_indices[i]);
            } // for i

          if (_biharmonic._degenerate)
            {
              M_qp           = 1.0 - u_qp*u_qp;
              M_old_qp       = 1.0 - u_old_qp*u_old_qp;
              M_prime_qp     = -2.0*u_qp;
              M_prime_old_qp = -2.0*u_old_qp;
            }

          // ELEMENT RESIDUAL AND JACOBIAN
          for (unsigned int i=0; i<phi.size(); i++)
            {
              // RESIDUAL
              if (R)
                {
                  Number ri = 0.0, ri_old = 0.0;
                  ri     -= Laplacian_phi_qp[i]*M_qp*_biharmonic._kappa*Laplacian_u_qp;
                  ri_old -= Laplacian_phi_qp[i]*M_old_qp*_biharmonic._kappa*Laplacian_u_old_qp;

                  if (_biharmonic._degenerate)
                    {
                      ri       -= (dphi[i][qp]*grad_u_qp)*M_prime_qp*(_biharmonic._kappa*Laplacian_u_qp);
                      ri_old   -= (dphi[i][qp]*grad_u_old_qp)*M_prime_old_qp*(_biharmonic._kappa*Laplacian_u_old_qp);
                    }

                  if (_biharmonic._cahn_hillard)
                    {
                      if (_biharmonic._energy == DOUBLE_WELL || _biharmonic._energy == LOG_DOUBLE_WELL)
                        {
                          ri += Laplacian_phi_qp[i]*M_qp*_biharmonic._theta_c*(u_qp*u_qp - 1.0)*u_qp;
                          ri_old += Laplacian_phi_qp[i]*M_old_qp*_biharmonic._theta_c*(u_old_qp*u_old_qp - 1.0)*u_old_qp;
                          if (_biharmonic._degenerate)
                            {
                              ri     += (dphi[i][qp]*grad_u_qp)*M_prime_qp*_biharmonic._theta_c*(u_qp*u_qp - 1.0)*u_qp;
                              ri_old += (dphi[i][qp]*grad_u_old_qp)*M_prime_old_qp*_biharmonic._theta_c*(u_old_qp*u_old_qp - 1.0)*u_old_qp;
                            }
                        }// if (_biharmonic._energy == DOUBLE_WELL || _biharmonic._energy == LOG_DOUBLE_WELL)

                      if (_biharmonic._energy == DOUBLE_OBSTACLE || _biharmonic._energy == LOG_DOUBLE_OBSTACLE)
                        {
                          ri -= Laplacian_phi_qp[i]*M_qp*_biharmonic._theta_c*u_qp;
                          ri_old -= Laplacian_phi_qp[i]*M_old_qp*_biharmonic._theta_c*u_old_qp;
                          if (_biharmonic._degenerate)
                            {
                              ri     -= (dphi[i][qp]*grad_u_qp)*M_prime_qp*_biharmonic._theta_c*u_qp;
                              ri_old -= (dphi[i][qp]*grad_u_old_qp)*M_prime_old_qp*_biharmonic._theta_c*u_old_qp;
                            }
                        } // if (_biharmonic._energy == DOUBLE_OBSTACLE || _biharmonic._energy == LOG_DOUBLE_OBSTACLE)

                      if (_biharmonic._energy == LOG_DOUBLE_WELL || _biharmonic._energy == LOG_DOUBLE_OBSTACLE)
                        {
                          switch(_biharmonic._log_truncation)
                            {
                            case 2:
                              break;
                            case 3:
                              break;
                            default:
                              break;
                            }// switch(_biharmonic._log_truncation)
                        }// if (_biharmonic._energy == LOG_DOUBLE_WELL || _biharmonic._energy == LOG_DOUBLE_OBSTACLE)
                    }// if (_biharmonic._cahn_hillard)
                  Re(i) += JxW[qp]*((u_qp-u_old_qp)*phi[i][qp]-_biharmonic._dt*0.5*((2.0-_biharmonic._cnWeight)*ri + _biharmonic._cnWeight*ri_old));
                } // if (R)

              // JACOBIAN
              if (J)
                {
                  Number M_prime_prime_qp = 0.0;
                  if (_biharmonic._degenerate) M_prime_prime_qp = -2.0;
                  for (unsigned int j=0; j<phi.size(); j++)
                    {
                      Number ri_j = 0.0;
                      ri_j -= Laplacian_phi_qp[i]*M_qp*_biharmonic._kappa*Laplacian_phi_qp[j];
                      if (_biharmonic._degenerate)
                        {
                          ri_j -=
                            Laplacian_phi_qp[i]*M_prime_qp*phi[j][qp]*_biharmonic._kappa*Laplacian_u_qp               +
                            (dphi[i][qp]*dphi[j][qp])*M_prime_qp*(_biharmonic._kappa*Laplacian_u_qp)                  +
                            (dphi[i][qp]*grad_u_qp)*(M_prime_prime_qp*phi[j][qp])*(_biharmonic._kappa*Laplacian_u_qp) +
                            (dphi[i][qp]*grad_u_qp)*(M_prime_qp)*(_biharmonic._kappa*Laplacian_phi_qp[j]);
                        }

                      if (_biharmonic._cahn_hillard)
                        {
                          if (_biharmonic._energy == DOUBLE_WELL || _biharmonic._energy == LOG_DOUBLE_WELL)
                            {
                              ri_j +=
                                Laplacian_phi_qp[i]*M_prime_qp*phi[j][qp]*_biharmonic._theta_c*(u_qp*u_qp - 1.0)*u_qp +
                                Laplacian_phi_qp[i]*M_qp*_biharmonic._theta_c*(3.0*u_qp*u_qp - 1.0)*phi[j][qp]        +
                                (dphi[i][qp]*dphi[j][qp])*M_prime_qp*_biharmonic._theta_c*(u_qp*u_qp - 1.0)*u_qp      +
                                (dphi[i][qp]*grad_u_qp)*M_prime_prime_qp*_biharmonic._theta_c*(u_qp*u_qp - 1.0)*u_qp  +
                                (dphi[i][qp]*grad_u_qp)*M_prime_qp*_biharmonic._theta_c*(3.0*u_qp*u_qp - 1.0)*phi[j][qp];
                            }// if (_biharmonic._energy == DOUBLE_WELL || _biharmonic._energy == LOG_DOUBLE_WELL)

                          if (_biharmonic._energy == DOUBLE_OBSTACLE || _biharmonic._energy == LOG_DOUBLE_OBSTACLE)
                            {
                              ri_j -=
                                Laplacian_phi_qp[i]*M_prime_qp*phi[j][qp]*_biharmonic._theta_c*u_qp                   +
                                Laplacian_phi_qp[i]*M_qp*_biharmonic._theta_c*phi[j][qp]                              +
                                (dphi[i][qp]*dphi[j][qp])*M_prime_qp*_biharmonic._theta_c*u_qp                        +
                                (dphi[i][qp]*grad_u_qp)*M_prime_prime_qp*_biharmonic._theta_c*u_qp                    +
                                (dphi[i][qp]*grad_u_qp)*M_prime_qp*_biharmonic._theta_c*phi[j][qp];
                            } // if (_biharmonic._energy == DOUBLE_OBSTACLE || _biharmonic._energy == LOG_DOUBLE_OBSTACLE)

                          if (_biharmonic._energy == LOG_DOUBLE_WELL || _biharmonic._energy == LOG_DOUBLE_OBSTACLE)
                            {
                              switch(_biharmonic._log_truncation)
                                {
                                case 2:
                                  break;
                                case 3:
                                  break;
                                default:
                                  break;
                                }// switch(_biharmonic._log_truncation)
                            }// if (_biharmonic._energy == LOG_DOUBLE_WELL || _biharmonic._energy == LOG_DOUBLE_OBSTACLE)
                        }// if (_biharmonic._cahn_hillard)
                      Je(i,j) += JxW[qp]*(phi[i][qp]*phi[j][qp] - 0.5*_biharmonic._dt*(2.0-_biharmonic._cnWeight)*ri_j);
                    } // for j
                } // if (J)
            } // for i
        } // for qp

      // 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 SparseMatrix::add_matrix()
      // and NumericVector::add_vector() members do this for us.
      // Start logging the insertion of the local (element)
      // matrix and vector into the global matrix and vector
      if (R)
        {
          // If the mesh has hanging nodes (e.g., as a result of refinement), those need to be constrained.
          dof_map.constrain_element_vector(Re, dof_indices);
          R->add_vector(Re, dof_indices);
        }

      if (J)
        {
          // If the mesh has hanging nodes (e.g., as a result of refinement), those need to be constrained.
          dof_map.constrain_element_matrix(Je, dof_indices);
          J->add_matrix(Je, dof_indices);
        }
    } // for el
#endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
}
コード例 #6
0
ファイル: miscellaneous_ex11.C プロジェクト: GENGCHN/libmesh
// We now define the matrix and rhs vector assembly function
// for the shell system.  This function implements the
// linear Kirchhoff-Love theory for thin shells.  At the
// end we also take into account the boundary conditions
// here, using the penalty method.
void assemble_shell (EquationSystems& es, const std::string& system_name)
{
  // It is a good idea to make sure we are assembling
  // the proper system.
  libmesh_assert_equal_to (system_name, "Shell");

  // Get a constant reference to the mesh object.
  const MeshBase& mesh = es.get_mesh();

  // Get a reference to the shell system object.
  LinearImplicitSystem & system = es.get_system<LinearImplicitSystem> ("Shell");

  // Get the shell parameters that we need during assembly.
  const Real h  = es.parameters.get<Real> ("thickness");
  const Real E  = es.parameters.get<Real> ("young's modulus");
  const Real nu = es.parameters.get<Real> ("poisson ratio");
  const Real q  = es.parameters.get<Real> ("uniform load");

  // Compute the membrane stiffness \p K and the bending
  // rigidity \p D from these parameters.
  const Real K = E * h     /     (1-nu*nu);
  const Real D = E * h*h*h / (12*(1-nu*nu));

  // Numeric ids corresponding to each variable in the system.
  const unsigned int u_var = system.variable_number ("u");
  const unsigned int v_var = system.variable_number ("v");
  const unsigned int w_var = system.variable_number ("w");

  // Get the Finite Element type for "u".  Note this will be
  // the same as the type for "v" and "w".
  FEType fe_type = system.variable_type (u_var);

  // Build a Finite Element object of the specified type.
  UniquePtr<FEBase> fe (FEBase::build(2, fe_type));

  // A Gauss quadrature rule for numerical integration.
  // For subdivision shell elements, a single Gauss point per
  // element is sufficient, hence we use extraorder = 0.
  const int extraorder = 0;
  UniquePtr<QBase> qrule (fe_type.default_quadrature_rule (2, extraorder));

  // Tell the finite element object to use our quadrature rule.
  fe->attach_quadrature_rule (qrule.get());

  // The element Jacobian * quadrature weight at each integration point.
  const std::vector<Real>& JxW = fe->get_JxW();

  // The surface tangents in both directions at the quadrature points.
  const std::vector<RealGradient>& dxyzdxi  = fe->get_dxyzdxi();
  const std::vector<RealGradient>& dxyzdeta = fe->get_dxyzdeta();

  // The second partial derivatives at the quadrature points.
  const std::vector<RealGradient>& d2xyzdxi2    = fe->get_d2xyzdxi2();
  const std::vector<RealGradient>& d2xyzdeta2   = fe->get_d2xyzdeta2();
  const std::vector<RealGradient>& d2xyzdxideta = fe->get_d2xyzdxideta();

  // The element shape function and its derivatives evaluated at the
  // quadrature points.
  const std::vector<std::vector<Real> >&          phi = fe->get_phi();
  const std::vector<std::vector<RealGradient> >& dphi = fe->get_dphi();
  const std::vector<std::vector<RealTensor> >&  d2phi = fe->get_d2phi();

  // 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.
  const DofMap & dof_map = system.get_dof_map();

  // Define data structures to contain the element stiffness 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), Kuw(Ke),
    Kvu(Ke), Kvv(Ke), Kvw(Ke),
    Kwu(Ke), Kwv(Ke), Kww(Ke);

  DenseSubVector<Number>
    Fu(Fe),
    Fv(Fe),
    Fw(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<dof_id_type> dof_indices;
  std::vector<dof_id_type> dof_indices_u;
  std::vector<dof_id_type> dof_indices_v;
  std::vector<dof_id_type> dof_indices_w;

  // Now we will loop over all the elements in the mesh.  We will
  // compute the element matrix and right-hand-side contribution.
  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;

    // The ghost elements at the boundaries need to be excluded
    // here, as they don't belong to the physical shell,
    // but serve for a proper boundary treatment only.
    libmesh_assert_equal_to (elem->type(), TRI3SUBDIVISION);
    const Tri3Subdivision* sd_elem = static_cast<const Tri3Subdivision*> (elem);
    if (sd_elem->is_ghost())
      continue;

    // 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_w, w_var);

    const std::size_t n_dofs   = dof_indices.size();
    const std::size_t n_u_dofs = dof_indices_u.size();
    const std::size_t n_v_dofs = dof_indices_v.size();
    const std::size_t n_w_dofs = dof_indices_w.size();

    // Compute the element-specific data for the current
    // element.  This involves computing the location of the
    // quadrature points and the shape functions
    // (phi, dphi, d2phi) for the current element.
    fe->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.
    Ke.resize (n_dofs, n_dofs);
    Fe.resize (n_dofs);

    // Reposition the submatrices...  The idea is this:
    //
    //         -           -          -  -
    //        | Kuu Kuv Kuw |        | Fu |
    //   Ke = | Kvu Kvv Kvw |;  Fe = | Fv |
    //        | Kwu Kwv Kww |        | Fw |
    //         -           -          -  -
    //
    // 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);
    Kuw.reposition (u_var*n_u_dofs, w_var*n_u_dofs, n_u_dofs, n_w_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);
    Kvw.reposition (v_var*n_v_dofs, w_var*n_v_dofs, n_v_dofs, n_w_dofs);

    Kwu.reposition (w_var*n_w_dofs, u_var*n_w_dofs, n_w_dofs, n_u_dofs);
    Kwv.reposition (w_var*n_w_dofs, v_var*n_w_dofs, n_w_dofs, n_v_dofs);
    Kww.reposition (w_var*n_w_dofs, w_var*n_w_dofs, n_w_dofs, n_w_dofs);

    Fu.reposition (u_var*n_u_dofs, n_u_dofs);
    Fv.reposition (v_var*n_u_dofs, n_v_dofs);
    Fw.reposition (w_var*n_u_dofs, n_w_dofs);

    // Now we will build the element matrix and right-hand-side.
    for (unsigned int qp=0; qp<qrule->n_points(); ++qp)
    {
      // First, we compute the external force resulting
      // from a load q distributed uniformly across the plate.
      // Since the load is supposed to be transverse to the plate,
      // it affects the z-direction, i.e. the "w" variable.
      for (unsigned int i=0; i<n_u_dofs; ++i)
        Fw(i) += JxW[qp] * phi[i][qp] * q;

      // Next, we assemble the stiffness matrix.  This is only valid
      // for the linear theory, i.e., for small deformations, where
      // reference and deformed surface metrics are indistinguishable.

      // Get the three surface basis vectors.
      const RealVectorValue & a1 = dxyzdxi[qp];
      const RealVectorValue & a2 = dxyzdeta[qp];
            RealVectorValue   a3 = a1.cross(a2);
      const Real jac = a3.size(); // the surface Jacobian
      libmesh_assert_greater (jac, 0);
      a3 /= jac; // the shell director a3 is normalized to unit length

      // Get the derivatives of the surface tangents.
      const RealVectorValue & a11 = d2xyzdxi2[qp];
      const RealVectorValue & a22 = d2xyzdeta2[qp];
      const RealVectorValue & a12 = d2xyzdxideta[qp];

      // Compute the three covariant components of the first
      // fundamental form of the surface.
      const RealVectorValue a(a1*a1, a2*a2, a1*a2);

      // The elastic H matrix in Voigt's notation, computed from the
      // covariant components of the first fundamental form rather
      // than the contravariant components, exploiting that the
      // contravariant first fundamental form is the inverse of the
      // covatiant first fundamental form (hence the determinant etc.).
      RealTensorValue H;
      H(0,0)          =  a(1) * a(1);
      H(0,1) = H(1,0) =   nu  * a(1) * a(0) + (1-nu) * a(2) * a(2);
      H(0,2) = H(2,0) = -a(1) * a(2);
      H(1,1)          =  a(0) * a(0);
      H(1,2) = H(2,1) = -a(0) * a(2);
      H(2,2)          = 0.5 * ((1-nu) * a(1) * a(0) + (1+nu) * a(2) * a(2));
      const Real det = a(0) * a(1) - a(2) * a(2);
      libmesh_assert_not_equal_to (det * det, 0);
      H /= det * det;

      // Precompute come cross products for the bending part below.
      const RealVectorValue a11xa2 = a11.cross(a2);
      const RealVectorValue a22xa2 = a22.cross(a2);
      const RealVectorValue a12xa2 = a12.cross(a2);
      const RealVectorValue a1xa11 =  a1.cross(a11);
      const RealVectorValue a1xa22 =  a1.cross(a22);
      const RealVectorValue a1xa12 =  a1.cross(a12);
      const RealVectorValue a2xa3  =  a2.cross(a3);
      const RealVectorValue a3xa1  =  a3.cross(a1);

      // Loop over all pairs of nodes I,J.
      for (unsigned int i=0; i<n_u_dofs; ++i)
      {
        for (unsigned int j=0; j<n_u_dofs; ++j)
        {
          // The membrane strain matrices in Voigt's notation.
          RealTensorValue MI, MJ;
          for (unsigned int k=0; k<3; ++k)
          {
            MI(0,k) = dphi[i][qp](0) * a1(k);
            MI(1,k) = dphi[i][qp](1) * a2(k);
            MI(2,k) = dphi[i][qp](1) * a1(k)
                    + dphi[i][qp](0) * a2(k);

            MJ(0,k) = dphi[j][qp](0) * a1(k);
            MJ(1,k) = dphi[j][qp](1) * a2(k);
            MJ(2,k) = dphi[j][qp](1) * a1(k)
                    + dphi[j][qp](0) * a2(k);
          }

          // The bending strain matrices in Voigt's notation.
          RealTensorValue BI, BJ;
          for (unsigned int k=0; k<3; ++k)
          {
            const Real term_ik = dphi[i][qp](0) * a2xa3(k)
                               + dphi[i][qp](1) * a3xa1(k);
            BI(0,k) = -d2phi[i][qp](0,0) * a3(k)
                      +(dphi[i][qp](0) * a11xa2(k)
                      + dphi[i][qp](1) * a1xa11(k)
                      + (a3*a11) * term_ik) / jac;
            BI(1,k) = -d2phi[i][qp](1,1) * a3(k)
                      +(dphi[i][qp](0) * a22xa2(k)
                      + dphi[i][qp](1) * a1xa22(k)
                      + (a3*a22) * term_ik) / jac;
            BI(2,k) = 2 * (-d2phi[i][qp](0,1) * a3(k)
                           +(dphi[i][qp](0) * a12xa2(k)
                           + dphi[i][qp](1) * a1xa12(k)
                           + (a3*a12) * term_ik) / jac);

            const Real term_jk = dphi[j][qp](0) * a2xa3(k)
                               + dphi[j][qp](1) * a3xa1(k);
            BJ(0,k) = -d2phi[j][qp](0,0) * a3(k)
                      +(dphi[j][qp](0) * a11xa2(k)
                      + dphi[j][qp](1) * a1xa11(k)
                      + (a3*a11) * term_jk) / jac;
            BJ(1,k) = -d2phi[j][qp](1,1) * a3(k)
                      +(dphi[j][qp](0) * a22xa2(k)
                      + dphi[j][qp](1) * a1xa22(k)
                      + (a3*a22) * term_jk) / jac;
            BJ(2,k) = 2 * (-d2phi[j][qp](0,1) * a3(k)
                           +(dphi[j][qp](0) * a12xa2(k)
                           + dphi[j][qp](1) * a1xa12(k)
                           + (a3*a12) * term_jk) / jac);
          }

          // The total stiffness matrix coupling the nodes
          // I and J is a sum of membrane and bending
          // contributions according to the following formula.
          const RealTensorValue KIJ = JxW[qp] * K * MI.transpose() * H * MJ
                                    + JxW[qp] * D * BI.transpose() * H * BJ;

          // Insert the components of the coupling stiffness
          // matrix \p KIJ into the corresponding directional
          // submatrices.
          Kuu(i,j) += KIJ(0,0);
          Kuv(i,j) += KIJ(0,1);
          Kuw(i,j) += KIJ(0,2);

          Kvu(i,j) += KIJ(1,0);
          Kvv(i,j) += KIJ(1,1);
          Kvw(i,j) += KIJ(1,2);

          Kwu(i,j) += KIJ(2,0);
          Kwv(i,j) += KIJ(2,1);
          Kww(i,j) += KIJ(2,2);
        }
      }

    } // end of the quadrature point qp-loop

    // 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 NumericMatrix::add_matrix()
    // and \p NumericVector::add_vector() members do this for us.
    system.matrix->add_matrix (Ke, dof_indices);
    system.rhs->add_vector    (Fe, dof_indices);
  } // end of non-ghost element loop

  // Next, we apply the boundary conditions.  In this case,
  // all boundaries are clamped by the penalty method, using
  // the special "ghost" nodes along the boundaries.  Note
  // that there are better ways to implement boundary conditions
  // for subdivision shells.  We use the simplest way here,
  // which is known to be overly restrictive and will lead to
  // a slightly too small deformation of the plate.
  el = mesh.active_local_elements_begin();

  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;

    // For the boundary conditions, we only need to loop over
    // the ghost elements.
    libmesh_assert_equal_to (elem->type(), TRI3SUBDIVISION);
    const Tri3Subdivision* gh_elem = static_cast<const Tri3Subdivision*> (elem);
    if (!gh_elem->is_ghost())
      continue;

    // Find the side which is part of the physical plate boundary,
    // that is, the boundary of the original mesh without ghosts.
    for (unsigned int s=0; s<elem->n_sides(); ++s)
    {
      const Tri3Subdivision* nb_elem = static_cast<const Tri3Subdivision*> (elem->neighbor(s));
      if (nb_elem == NULL || nb_elem->is_ghost())
        continue;

      /*
       * Determine the four nodes involved in the boundary
       * condition treatment of this side.  The \p MeshTools::Subdiv
       * namespace provides lookup tables \p next and \p prev
       * for an efficient determination of the next and previous
       * nodes of an element, respectively.
       *
       *      n4
       *     /  \
       *    / gh \
       *  n2 ---- n3
       *    \ nb /
       *     \  /
       *      n1
       */
      Node* nodes [4]; // n1, n2, n3, n4
      nodes[1] = gh_elem->get_node(s); // n2
      nodes[2] = gh_elem->get_node(MeshTools::Subdivision::next[s]); // n3
      nodes[3] = gh_elem->get_node(MeshTools::Subdivision::prev[s]); // n4

      // The node in the interior of the domain, \p n1, is the
      // hardest to find.  Walk along the edges of element \p nb until
      // we have identified it.
      unsigned int n_int = 0;
      nodes[0] = nb_elem->get_node(0);
      while (nodes[0]->id() == nodes[1]->id() || nodes[0]->id() == nodes[2]->id())
        nodes[0] = nb_elem->get_node(++n_int);

      // The penalty value.  \f$ \frac{1}{\epsilon} \f$
      const Real penalty = 1.e10;

      // With this simple method, clamped boundary conditions are
      // obtained by penalizing the displacements of all four nodes.
      // This ensures that the displacement field vanishes on the
      // boundary side \p s.
      for (unsigned int n=0; n<4; ++n)
      {
        const dof_id_type u_dof = nodes[n]->dof_number (system.number(), u_var, 0);
        const dof_id_type v_dof = nodes[n]->dof_number (system.number(), v_var, 0);
        const dof_id_type w_dof = nodes[n]->dof_number (system.number(), w_var, 0);
        system.matrix->add (u_dof, u_dof, penalty);
        system.matrix->add (v_dof, v_dof, penalty);
        system.matrix->add (w_dof, w_dof, penalty);
      }
    }
  } // end of ghost element loop
}
コード例 #7
0
// We now define the matrix assembly function for the
// Poisson system.  We need to first compute element
// matrices and right-hand sides, and then take into
// account the boundary conditions.
void assemble_poisson(EquationSystems& es,
                      const std::string& system_name)
{
  // It is a good idea to make sure we are assembling
  // the proper system.
  libmesh_assert_equal_to (system_name, "Poisson");


  // Declare a performance log.  Give it a descriptive
  // string to identify what part of the code we are
  // logging, since there may be many PerfLogs in an
  // application.
  PerfLog perf_log ("Matrix Assembly");

  // Get a constant reference to the mesh object.
  const MeshBase& mesh = es.get_mesh();

  // The dimension that we are running
  const unsigned int dim = mesh.mesh_dimension();

  // Get a reference to the LinearImplicitSystem we are solving
  LinearImplicitSystem& system = es.get_system<LinearImplicitSystem>("Poisson");

  // 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 = system.get_dof_map();

  // Get a constant reference to the Finite Element type
  // for the first (and only) variable in the system.
  FEType fe_type = dof_map.variable_type(0);

  // Build a Finite Element object of the specified type.  Since the
  // \p FEBase::build() member dynamically creates memory we will
  // store the object as an \p UniquePtr<FEBase>.  This can be thought
  // of as a pointer that will clean up after itself.
  UniquePtr<FEBase> fe (FEBase::build(dim, fe_type));

  // A 5th order Gauss quadrature rule for numerical integration.
  QGauss qrule (dim, FIFTH);

  // Tell the finite element object to use our quadrature rule.
  fe->attach_quadrature_rule (&qrule);

  // Declare a special finite element object for
  // boundary integration.
  UniquePtr<FEBase> fe_face (FEBase::build(dim, fe_type));

  // Boundary integration requires one quadraure rule,
  // with dimensionality one less than the dimensionality
  // of the element.
  QGauss qface(dim-1, FIFTH);

  // Tell the finte element object to use our
  // quadrature rule.
  fe_face->attach_quadrature_rule (&qface);

  // Here we define some references to cell-specific data that
  // will be used to assemble the linear system.
  // We begin with the element Jacobian * quadrature weight at each
  // integration point.
  const std::vector<Real>& JxW = fe->get_JxW();

  // The physical XY locations of the quadrature points on the element.
  // These might be useful for evaluating spatially varying material
  // properties at the quadrature points.
  const std::vector<Point>& q_point = fe->get_xyz();

  // The element shape functions evaluated at the quadrature points.
  const std::vector<std::vector<Real> >& phi = fe->get_phi();

  // The element shape function gradients evaluated at the quadrature
  // points.
  const std::vector<std::vector<RealGradient> >& dphi = fe->get_dphi();

  // 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". More detail is in example 3.
  DenseMatrix<Number> Ke;
  DenseVector<Number> 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<dof_id_type> dof_indices;

  // Now we will loop over all the elements in the mesh.
  // We will compute the element matrix and right-hand-side
  // contribution.  See example 3 for a discussion of the
  // element iterators.
  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)
    {
      // Start logging the shape function initialization.
      // This is done through a simple function call with
      // the name of the event to log.
      perf_log.push("elem init");

      // 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);

      // 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->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 (dof_indices.size(),
                 dof_indices.size());

      Fe.resize (dof_indices.size());

      // Stop logging the shape function initialization.
      // If you forget to stop logging an event the PerfLog
      // object will probably catch the error and abort.
      perf_log.pop("elem init");

      // Now we will build the element matrix.  This involves
      // a double loop to integrate the test funcions (i) against
      // the trial functions (j).
      //
      // We have split the numeric integration into two loops
      // so that we can log the matrix and right-hand-side
      // computation seperately.
      //
      // Now start logging the element matrix computation
      perf_log.push ("Ke");

      for (unsigned int qp=0; qp<qrule.n_points(); qp++)
        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]);


      // Stop logging the matrix computation
      perf_log.pop ("Ke");

      // Now 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.
      //
      // Start logging the right-hand-side computation
      perf_log.push ("Fe");

      for (unsigned int qp=0; qp<qrule.n_points(); qp++)
        {
          // fxy is the forcing function for the Poisson equation.
          // In this case we set fxy to be a finite difference
          // Laplacian approximation to the (known) exact solution.
          //
          // We will use the second-order accurate FD Laplacian
          // approximation, which in 2D on a structured grid is
          //
          // u_xx + u_yy = (u(i-1,j) + u(i+1,j) +
          //                u(i,j-1) + u(i,j+1) +
          //                -4*u(i,j))/h^2
          //
          // Since the value of the forcing function depends only
          // on the location of the quadrature point (q_point[qp])
          // we will compute it here, outside of the i-loop
          const Real x = q_point[qp](0);
#if LIBMESH_DIM > 1
          const Real y = q_point[qp](1);
#else
          const Real y = 0.;
#endif
#if LIBMESH_DIM > 2
          const Real z = q_point[qp](2);
#else
          const Real z = 0.;
#endif
          const Real eps = 1.e-3;

          const Real uxx = (exact_solution(x-eps,y,z) +
                            exact_solution(x+eps,y,z) +
                            -2.*exact_solution(x,y,z))/eps/eps;

          const Real uyy = (exact_solution(x,y-eps,z) +
                            exact_solution(x,y+eps,z) +
                            -2.*exact_solution(x,y,z))/eps/eps;

          const Real uzz = (exact_solution(x,y,z-eps) +
                            exact_solution(x,y,z+eps) +
                            -2.*exact_solution(x,y,z))/eps/eps;

          Real fxy;
          if(dim==1)
            {
              // In 1D, compute the rhs by differentiating the
              // exact solution twice.
              const Real pi = libMesh::pi;
              fxy = (0.25*pi*pi)*sin(.5*pi*x);
            }
          else
            {
              fxy = - (uxx + uyy + ((dim==2) ? 0. : uzz));
            }

          // Add the RHS contribution
          for (unsigned int i=0; i<phi.size(); i++)
            Fe(i) += JxW[qp]*fxy*phi[i][qp];
        }

      // Stop logging the right-hand-side computation
      perf_log.pop ("Fe");

      // If this assembly program were to be used on an adaptive mesh,
      // we would have to apply any hanging node constraint equations
      // Also, note that here we call heterogenously_constrain_element_matrix_and_vector
      // to impose a inhomogeneous Dirichlet boundary conditions.
      dof_map.heterogenously_constrain_element_matrix_and_vector (Ke, Fe, dof_indices);

      // 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 SparseMatrix::add_matrix()
      // and \p NumericVector::add_vector() members do this for us.
      // Start logging the insertion of the local (element)
      // matrix and vector into the global matrix and vector
      perf_log.push ("matrix insertion");

      system.matrix->add_matrix (Ke, dof_indices);
      system.rhs->add_vector    (Fe, dof_indices);

      // Start logging the insertion of the local (element)
      // matrix and vector into the global matrix and vector
      perf_log.pop ("matrix insertion");
    }

  // That's it.  We don't need to do anything else to the
  // PerfLog.  When it goes out of scope (at this function return)
  // it will print its log to the screen. Pretty easy, huh?
}
コード例 #8
0
void assemble_mass(EquationSystems & es,
                   const std::string & system_name)
{

  // It is a good idea to make sure we are assembling
  // the proper system.
  libmesh_assert_equal_to (system_name, "Eigensystem");

#ifdef LIBMESH_HAVE_SLEPC

  // Get a constant reference to the mesh object.
  const MeshBase & mesh = es.get_mesh();

  // The dimension that we are running.
  const unsigned int dim = mesh.mesh_dimension();

  // Get a reference to our system.
  EigenSystem & eigen_system = es.get_system<EigenSystem> (system_name);

  // Get a constant reference to the Finite Element type
  // for the first (and only) variable in the system.
  FEType fe_type = eigen_system.get_dof_map().variable_type(0);

  // A reference to the two system matrices
  SparseMatrix<Number> & matrix_A = *eigen_system.matrix_A;
  SparseMatrix<Number> & matrix_B = *eigen_system.matrix_B;

  // Build a Finite Element object of the specified type.  Since the
  // FEBase::build() member dynamically creates memory we will
  // store the object as a UniquePtr<FEBase>.  This can be thought
  // of as a pointer that will clean up after itself.
  UniquePtr<FEBase> fe (FEBase::build(dim, fe_type));

  // A  Gauss quadrature rule for numerical integration.
  // Use the default quadrature order.
  QGauss qrule (dim, fe_type.default_quadrature_order());

  // Tell the finite element object to use our quadrature rule.
  fe->attach_quadrature_rule (&qrule);

  // The element Jacobian * quadrature weight at each integration point.
  const std::vector<Real> & JxW = fe->get_JxW();

  // The element shape functions evaluated at the quadrature points.
  const std::vector<std::vector<Real> > & phi = fe->get_phi();

  // The element shape function gradients evaluated at the quadrature
  // points.
  const std::vector<std::vector<RealGradient> > & dphi = fe->get_dphi();

  // A reference to the DofMap object for this system.  The DofMap
  // object handles the index translation from node and element numbers
  // to degree of freedom numbers.
  const DofMap & dof_map = eigen_system.get_dof_map();

  // The element mass and stiffness matrices.
  DenseMatrix<Number> Me;
  DenseMatrix<Number> Ke;

  // 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<dof_id_type> dof_indices;

  // 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.  In case users
  // later modify this program to include refinement, we will
  // be safe and will only consider the active elements;
  // hence we use a variant of the 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);

      // 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->reinit (elem);

      // Zero the element matrices 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 (dof_indices.size(), dof_indices.size());
      Me.resize (dof_indices.size(), dof_indices.size());

      // Now loop over the quadrature points.  This handles
      // the numeric integration.
      //
      // We will build the element matrix.  This involves
      // a double loop to integrate the test funcions (i) against
      // the trial functions (j).
      for (unsigned int qp=0; qp<qrule.n_points(); qp++)
        for (unsigned int i=0; i<phi.size(); i++)
          for (unsigned int j=0; j<phi.size(); j++)
            {
              Me(i,j) += JxW[qp]*phi[i][qp]*phi[j][qp];
              Ke(i,j) += JxW[qp]*(dphi[i][qp]*dphi[j][qp]);
            }

      // On an unrefined mesh, constrain_element_matrix does
      // nothing.  If this assembly function is ever repurposed to
      // run on a refined mesh, getting the hanging node constraints
      // right will be important.  Note that, even with
      // asymmetric_constraint_rows = false, the constrained dof
      // diagonals still exist in the matrix, with diagonal entries
      // that are there to ensure non-singular matrices for linear
      // solves but which would generate positive non-physical
      // eigenvalues for eigensolves.
      // dof_map.constrain_element_matrix(Ke, dof_indices, false);
      // dof_map.constrain_element_matrix(Me, dof_indices, false);

      // Finally, simply add the element contribution to the
      // overall matrices A and B.
      matrix_A.add_matrix (Ke, dof_indices);
      matrix_B.add_matrix (Me, dof_indices);
    } // end of element loop


#else
  // Avoid compiler warnings
  libmesh_ignore(es);
#endif // LIBMESH_HAVE_SLEPC
}
コード例 #9
0
ファイル: adaptivity_ex4.C プロジェクト: GENGCHN/libmesh
// We now define the matrix assembly function for the
// Biharmonic system.  We need to first compute element
// matrices and right-hand sides, and then take into
// account the boundary conditions, which will be handled
// via a penalty method.
void assemble_biharmonic(EquationSystems& es,
                         const std::string& system_name)
{
#ifdef LIBMESH_ENABLE_AMR
#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES

  // It is a good idea to make sure we are assembling
  // the proper system.
  libmesh_assert_equal_to (system_name, "Biharmonic");

  // Declare a performance log.  Give it a descriptive
  // string to identify what part of the code we are
  // logging, since there may be many PerfLogs in an
  // application.
  PerfLog perf_log ("Matrix Assembly",false);

  // Get a constant reference to the mesh object.
  const MeshBase& mesh = es.get_mesh();

  // The dimension that we are running
  const unsigned int dim = mesh.mesh_dimension();

  // Get a reference to the LinearImplicitSystem we are solving
  LinearImplicitSystem& system = es.get_system<LinearImplicitSystem>("Biharmonic");

  // 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 = system.get_dof_map();

  // Get a constant reference to the Finite Element type
  // for the first (and only) variable in the system.
  FEType fe_type = dof_map.variable_type(0);

  // Build a Finite Element object of the specified type.  Since the
  // \p FEBase::build() member dynamically creates memory we will
  // store the object as an \p UniquePtr<FEBase>.  This can be thought
  // of as a pointer that will clean up after itself.
  UniquePtr<FEBase> fe (FEBase::build(dim, fe_type));

  // Quadrature rule for numerical integration.
  // With 2D triangles, the Clough quadrature rule puts a Gaussian
  // quadrature rule on each of the 3 subelements
  UniquePtr<QBase> qrule(fe_type.default_quadrature_rule(dim));

  // Tell the finite element object to use our quadrature rule.
  fe->attach_quadrature_rule (qrule.get());

  // Declare a special finite element object for
  // boundary integration.
  UniquePtr<FEBase> fe_face (FEBase::build(dim, fe_type));

  // Boundary integration requires another quadraure rule,
  // with dimensionality one less than the dimensionality
  // of the element.
  // In 1D, the Clough and Gauss quadrature rules are identical.
  UniquePtr<QBase> qface(fe_type.default_quadrature_rule(dim-1));

  // Tell the finte element object to use our
  // quadrature rule.
  fe_face->attach_quadrature_rule (qface.get());

  // Here we define some references to cell-specific data that
  // will be used to assemble the linear system.
  // We begin with the element Jacobian * quadrature weight at each
  // integration point.
  const std::vector<Real>& JxW = fe->get_JxW();

  // The physical XY locations of the quadrature points on the element.
  // These might be useful for evaluating spatially varying material
  // properties at the quadrature points.
  const std::vector<Point>& q_point = fe->get_xyz();

  // The element shape functions evaluated at the quadrature points.
  const std::vector<std::vector<Real> >& phi = fe->get_phi();

  // The element shape function second derivatives evaluated at the
  // quadrature points.  Note that for the simple biharmonic, shape
  // function first derivatives are unnecessary.
  const std::vector<std::vector<RealTensor> >& d2phi = fe->get_d2phi();

  // For efficiency we will compute shape function laplacians n times,
  // not n^2
  std::vector<Real> shape_laplacian;

  // 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". More detail is in example 3.
  DenseMatrix<Number> Ke;
  DenseVector<Number> 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<dof_id_type> dof_indices;

  // Now we will loop over all the elements in the mesh.  We will
  // compute the element matrix and right-hand-side contribution.  See
  // example 3 for a discussion of the element iterators.

  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)
    {
      // Start logging the shape function initialization.
      // This is done through a simple function call with
      // the name of the event to log.
      perf_log.push("elem init");

      // 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);

      // 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->reinit (elem);

      // Zero the element matrix and right-hand side before
      // summing them.
      Ke.resize (dof_indices.size(),
                 dof_indices.size());

      Fe.resize (dof_indices.size());

      // Make sure there is enough room in this cache
      shape_laplacian.resize(dof_indices.size());

      // Stop logging the shape function initialization.
      // If you forget to stop logging an event the PerfLog
      // object will probably catch the error and abort.
      perf_log.pop("elem init");

      // Now we will build the element matrix.  This involves
      // a double loop to integrate laplacians of the test funcions
      // (i) against laplacians of the trial functions (j).
      //
      // This step is why we need the Clough-Tocher elements -
      // these C1 differentiable elements have square-integrable
      // second derivatives.
      //
      // Now start logging the element matrix computation
      perf_log.push ("Ke");

      for (unsigned int qp=0; qp<qrule->n_points(); qp++)
        {
          for (unsigned int i=0; i<phi.size(); i++)
            {
              shape_laplacian[i] = d2phi[i][qp](0,0)+d2phi[i][qp](1,1);
              if (dim == 3)
                shape_laplacian[i] += d2phi[i][qp](2,2);
            }
          for (unsigned int i=0; i<phi.size(); i++)
            for (unsigned int j=0; j<phi.size(); j++)
              Ke(i,j) += JxW[qp]*
                shape_laplacian[i]*shape_laplacian[j];
        }

      // Stop logging the matrix computation
      perf_log.pop ("Ke");


      // 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.  Note that this is a fourth-order
      // problem: Dirichlet boundary conditions include *both*
      // boundary values and boundary normal fluxes.
      {
        // Start logging the boundary condition computation
        perf_log.push ("BCs");

        // The penalty values, for solution boundary trace and flux.
        const Real penalty = 1e10;
        const Real penalty2 = 1e10;

        // 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)
            {
              // The value of the shape functions at the quadrature
              // points.
              const std::vector<std::vector<Real> >&  phi_face =
                fe_face->get_phi();

              // The value of the shape function derivatives at the
              // quadrature points.
              const std::vector<std::vector<RealGradient> >& dphi_face =
                fe_face->get_dphi();

              // The Jacobian * Quadrature Weight at the quadrature
              // points on the face.
              const std::vector<Real>& JxW_face = fe_face->get_JxW();

              // The XYZ locations (in physical space) of the
              // quadrature points on the face.  This is where
              // we will interpolate the boundary value function.
              const std::vector<Point>& qface_point = fe_face->get_xyz();

              const std::vector<Point>& face_normals =
                fe_face->get_normals();

              // Compute the shape function values on the element
              // face.
              fe_face->reinit(elem, s);

              // Loop over the face quagrature points for integration.
              for (unsigned int qp=0; qp<qface->n_points(); qp++)
                {
                  // The boundary value.
                  Number value = exact_solution(qface_point[qp],
                                                es.parameters, "null",
                                                "void");
                  Gradient flux = exact_2D_derivative(qface_point[qp],
                                                      es.parameters,
                                                      "null", "void");

                  // Matrix contribution of the L2 projection.
                  // Note that the basis function values are
                  // integrated against test function values while
                  // basis fluxes are integrated against test function
                  // fluxes.
                  for (unsigned int i=0; i<phi_face.size(); i++)
                    for (unsigned int j=0; j<phi_face.size(); j++)
                      Ke(i,j) += JxW_face[qp] *
                        (penalty * phi_face[i][qp] *
                         phi_face[j][qp] + penalty2
                         * (dphi_face[i][qp] *
                            face_normals[qp]) *
                         (dphi_face[j][qp] *
                          face_normals[qp]));

                  // Right-hand-side contribution of the L2
                  // projection.
                  for (unsigned int i=0; i<phi_face.size(); i++)
                    Fe(i) += JxW_face[qp] *
                      (penalty * value * phi_face[i][qp]
                       + penalty2 *
                       (flux * face_normals[qp])
                       * (dphi_face[i][qp]
                          * face_normals[qp]));

                }
            }

        // Stop logging the boundary condition computation
        perf_log.pop ("BCs");
      }

      for (unsigned int qp=0; qp<qrule->n_points(); qp++)
        for (unsigned int i=0; i<phi.size(); i++)
          Fe(i) += JxW[qp]*phi[i][qp]*forcing_function(q_point[qp]);

      // 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 SparseMatrix::add_matrix()
      // and \p NumericVector::add_vector() members do this for us.
      // Start logging the insertion of the local (element)
      // matrix and vector into the global matrix and vector
      perf_log.push ("matrix insertion");

      dof_map.constrain_element_matrix_and_vector(Ke, Fe, dof_indices);
      system.matrix->add_matrix (Ke, dof_indices);
      system.rhs->add_vector    (Fe, dof_indices);

      // Stop logging the insertion of the local (element)
      // matrix and vector into the global matrix and vector
      perf_log.pop ("matrix insertion");
    }

  // That's it.  We don't need to do anything else to the
  // PerfLog.  When it goes out of scope (at this function return)
  // it will print its log to the screen. Pretty easy, huh?

#else

#endif // #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
#endif // #ifdef LIBMESH_ENABLE_AMR
}
コード例 #10
0
ファイル: InitialCondition.C プロジェクト: mellis13/moose
void
InitialCondition::compute()
{
  // -- NOTE ----
  // The following code is a copy from libMesh project_vector.C plus it adds some features, so we can couple variable values
  // and we also do not call any callbacks, but we use our initial condition system directly.
  // ------------

  // The element matrix and RHS for projections.
  // Note that Ke is always real-valued, whereas Fe may be complex valued if complex number support is enabled
  DenseMatrix<Real> Ke;
  DenseVector<Number> Fe;
  // The new element coefficients
  DenseVector<Number> Ue;

  const FEType & fe_type = _var.feType();

  // The dimension of the current element
  const unsigned int dim = _current_elem->dim();
  // The element type
  const ElemType elem_type = _current_elem->type();
  // The number of nodes on the new element
  const unsigned int n_nodes = _current_elem->n_nodes();
  // The global DOF indices
  std::vector<dof_id_type> dof_indices;
  // Side/edge DOF indices
  std::vector<unsigned int> side_dofs;

  // Get FE objects of the appropriate type
  // We cannot use the FE object in Assembly, since the following code is messing with the quadrature rules
  // for projections and would screw it up. However, if we implement projections from one mesh to another,
  // this code should use that implementation.
  UniquePtr<FEBase> fe (FEBase::build(dim, fe_type));

  // Prepare variables for projection
  UniquePtr<QBase> qrule     (fe_type.default_quadrature_rule(dim));
  UniquePtr<QBase> qedgerule (fe_type.default_quadrature_rule(1));
  UniquePtr<QBase> qsiderule (fe_type.default_quadrature_rule(dim-1));

  // The values of the shape functions at the quadrature points
  const std::vector<std::vector<Real> > & phi = fe->get_phi();

  // The gradients of the shape functions at the quadrature points on the child element.
  const std::vector<std::vector<RealGradient> > * dphi = NULL;

  const FEContinuity cont = fe->get_continuity();

  if (cont == C_ONE)
  {
    const std::vector<std::vector<RealGradient> > & ref_dphi = fe->get_dphi();
    dphi = &ref_dphi;
  }

  // The Jacobian * quadrature weight at the quadrature points
  const std::vector<Real> & JxW =  fe->get_JxW();
  // The XYZ locations of the quadrature points
  const std::vector<Point>& xyz_values = fe->get_xyz();

  // Update the DOF indices for this element based on the current mesh
  _var.prepareIC();
  dof_indices = _var.dofIndices();

  // The number of DOFs on the element
  const unsigned int n_dofs = dof_indices.size();
  if (n_dofs == 0)
    return;

  // Fixed vs. free DoFs on edge/face projections
  std::vector<char> dof_is_fixed(n_dofs, false); // bools
  std::vector<int> free_dof(n_dofs, 0);

  // Zero the interpolated values
  Ue.resize (n_dofs);
  Ue.zero();

  // In general, we need a series of
  // projections to ensure a unique and continuous
  // solution.  We start by interpolating nodes, then
  // hold those fixed and project edges, then
  // hold those fixed and project faces, then
  // hold those fixed and project interiors

  _fe_problem.sizeZeroes(n_nodes, _tid);

  // Interpolate node values first
  unsigned int current_dof = 0;
  for (unsigned int n = 0; n != n_nodes; ++n)
  {
    // FIXME: this should go through the DofMap,
    // not duplicate dof_indices code badly!
    const unsigned int nc = FEInterface::n_dofs_at_node (dim, fe_type, elem_type, n);
    if (!_current_elem->is_vertex(n))
    {
      current_dof += nc;
      continue;
    }
    if (cont == DISCONTINUOUS)
    {
      libmesh_assert(nc == 0);
    }
    // Assume that C_ZERO elements have a single nodal
    // value shape function
    else if (cont == C_ZERO)
    {
      libmesh_assert(nc == 1);
      _qp = n;
      _current_node = _current_elem->get_node(n);
      Ue(current_dof) = value(*_current_node);
      dof_is_fixed[current_dof] = true;
      current_dof++;
    }
    // The hermite element vertex shape functions are weird
    else if (fe_type.family == HERMITE)
    {
      _qp = n;
      _current_node = _current_elem->get_node(n);
      Ue(current_dof) = value(*_current_node);
      dof_is_fixed[current_dof] = true;
      current_dof++;
      Gradient grad = gradient(*_current_node);
      // x derivative
      Ue(current_dof) = grad(0);
      dof_is_fixed[current_dof] = true;
      current_dof++;
      if (dim > 1)
      {
        // We'll finite difference mixed derivatives
        Point nxminus = _current_elem->point(n),
              nxplus = _current_elem->point(n);
        nxminus(0) -= TOLERANCE;
        nxplus(0) += TOLERANCE;
        Gradient gxminus = gradient(nxminus);
        Gradient gxplus = gradient(nxplus);
        // y derivative
        Ue(current_dof) = grad(1);
        dof_is_fixed[current_dof] = true;
        current_dof++;
        // xy derivative
        Ue(current_dof) = (gxplus(1) - gxminus(1)) / 2. / TOLERANCE;
        dof_is_fixed[current_dof] = true;
        current_dof++;

        if (dim > 2)
        {
          // z derivative
          Ue(current_dof) = grad(2);
          dof_is_fixed[current_dof] = true;
          current_dof++;
          // xz derivative
          Ue(current_dof) = (gxplus(2) - gxminus(2)) / 2. / TOLERANCE;
          dof_is_fixed[current_dof] = true;
          current_dof++;
          // We need new points for yz
          Point nyminus = _current_elem->point(n),
                nyplus = _current_elem->point(n);
          nyminus(1) -= TOLERANCE;
          nyplus(1) += TOLERANCE;
          Gradient gyminus = gradient(nyminus);
          Gradient gyplus = gradient(nyplus);
          // xz derivative
          Ue(current_dof) = (gyplus(2) - gyminus(2)) / 2. / TOLERANCE;
          dof_is_fixed[current_dof] = true;
          current_dof++;
          // Getting a 2nd order xyz is more tedious
          Point nxmym = _current_elem->point(n),
                nxmyp = _current_elem->point(n),
                nxpym = _current_elem->point(n),
                nxpyp = _current_elem->point(n);
          nxmym(0) -= TOLERANCE;
          nxmym(1) -= TOLERANCE;
          nxmyp(0) -= TOLERANCE;
          nxmyp(1) += TOLERANCE;
          nxpym(0) += TOLERANCE;
          nxpym(1) -= TOLERANCE;
          nxpyp(0) += TOLERANCE;
          nxpyp(1) += TOLERANCE;
          Gradient gxmym = gradient(nxmym);
          Gradient gxmyp = gradient(nxmyp);
          Gradient gxpym = gradient(nxpym);
          Gradient gxpyp = gradient(nxpyp);
          Number gxzplus = (gxpyp(2) - gxmyp(2)) / 2. / TOLERANCE;
          Number gxzminus = (gxpym(2) - gxmym(2)) / 2. / TOLERANCE;
          // xyz derivative
          Ue(current_dof) = (gxzplus - gxzminus) / 2. / TOLERANCE;
          dof_is_fixed[current_dof] = true;
          current_dof++;
        }
      }
    }
    // Assume that other C_ONE elements have a single nodal
    // value shape function and nodal gradient component
    // shape functions
    else if (cont == C_ONE)
    {
      libmesh_assert(nc == 1 + dim);
      _current_node = _current_elem->get_node(n);
      Ue(current_dof) = value(*_current_node);
      dof_is_fixed[current_dof] = true;
      current_dof++;
      Gradient grad = gradient(*_current_node);
      for (unsigned int i=0; i != dim; ++i)
      {
        Ue(current_dof) = grad(i);
        dof_is_fixed[current_dof] = true;
        current_dof++;
      }
    }
    else
      libmesh_error();
  } // loop over nodes

  // From here on out we won't be sampling at nodes anymore
  _current_node = NULL;

  // In 3D, project any edge values next
  if (dim > 2 && cont != DISCONTINUOUS)
    for (unsigned int e=0; e != _current_elem->n_edges(); ++e)
    {
      FEInterface::dofs_on_edge(_current_elem, dim, fe_type, e, side_dofs);

      // Some edge dofs are on nodes and already
      // fixed, others are free to calculate
      unsigned int free_dofs = 0;
      for (unsigned int i=0; i != side_dofs.size(); ++i)
        if (!dof_is_fixed[side_dofs[i]])
          free_dof[free_dofs++] = i;

      // There may be nothing to project
      if (!free_dofs)
        continue;

      Ke.resize (free_dofs, free_dofs); Ke.zero();
      Fe.resize (free_dofs); Fe.zero();
      // The new edge coefficients
      DenseVector<Number> Uedge(free_dofs);

      // Initialize FE data on the edge
      fe->attach_quadrature_rule (qedgerule.get());
      fe->edge_reinit (_current_elem, e);
      const unsigned int n_qp = qedgerule->n_points();
      _fe_problem.sizeZeroes(n_qp, _tid);

      // Loop over the quadrature points
      for (unsigned int qp = 0; qp < n_qp; qp++)
      {
        // solution at the quadrature point
        Number fineval = value(xyz_values[qp]);
        // solution grad at the quadrature point
        Gradient finegrad;
        if (cont == C_ONE)
          finegrad = gradient(xyz_values[qp]);

        // Form edge projection matrix
        for (unsigned int sidei = 0, freei = 0; sidei != side_dofs.size(); ++sidei)
        {
          unsigned int i = side_dofs[sidei];
          // fixed DoFs aren't test functions
          if (dof_is_fixed[i])
            continue;
          for (unsigned int sidej = 0, freej = 0; sidej != side_dofs.size(); ++sidej)
          {
            unsigned int j = side_dofs[sidej];
            if (dof_is_fixed[j])
              Fe(freei) -= phi[i][qp] * phi[j][qp] * JxW[qp] * Ue(j);
            else
              Ke(freei,freej) += phi[i][qp] * phi[j][qp] * JxW[qp];
            if (cont == C_ONE)
            {
              if (dof_is_fixed[j])
                Fe(freei) -= ((*dphi)[i][qp] * (*dphi)[j][qp]) * JxW[qp] * Ue(j);
              else
                Ke(freei,freej) += ((*dphi)[i][qp] * (*dphi)[j][qp]) * JxW[qp];
            }
            if (!dof_is_fixed[j])
              freej++;
          }
          Fe(freei) += phi[i][qp] * fineval * JxW[qp];
          if (cont == C_ONE)
            Fe(freei) += (finegrad * (*dphi)[i][qp]) * JxW[qp];
          freei++;
        }
      }

      Ke.cholesky_solve(Fe, Uedge);

      // Transfer new edge solutions to element
      for (unsigned int i=0; i != free_dofs; ++i)
      {
        Number &ui = Ue(side_dofs[free_dof[i]]);
        libmesh_assert(std::abs(ui) < TOLERANCE || std::abs(ui - Uedge(i)) < TOLERANCE);
        ui = Uedge(i);
        dof_is_fixed[side_dofs[free_dof[i]]] = true;
      }
    }

  // Project any side values (edges in 2D, faces in 3D)
  if (dim > 1 && cont != DISCONTINUOUS)
    for (unsigned int s=0; s != _current_elem->n_sides(); ++s)
    {
      FEInterface::dofs_on_side(_current_elem, dim, fe_type, s, side_dofs);

      // Some side dofs are on nodes/edges and already
      // fixed, others are free to calculate
      unsigned int free_dofs = 0;
      for (unsigned int i=0; i != side_dofs.size(); ++i)
        if (!dof_is_fixed[side_dofs[i]])
          free_dof[free_dofs++] = i;

      // There may be nothing to project
      if (!free_dofs)
        continue;

      Ke.resize (free_dofs, free_dofs); Ke.zero();
      Fe.resize (free_dofs); Fe.zero();
      // The new side coefficients
      DenseVector<Number> Uside(free_dofs);

      // Initialize FE data on the side
      fe->attach_quadrature_rule (qsiderule.get());
      fe->reinit (_current_elem, s);
      const unsigned int n_qp = qsiderule->n_points();
      _fe_problem.sizeZeroes(n_qp, _tid);

      // Loop over the quadrature points
      for (unsigned int qp = 0; qp < n_qp; qp++)
      {
        // solution at the quadrature point
        Number fineval = value(xyz_values[qp]);
        // solution grad at the quadrature point
        Gradient finegrad;
        if (cont == C_ONE)
          finegrad = gradient(xyz_values[qp]);

        // Form side projection matrix
        for (unsigned int sidei = 0, freei = 0; sidei != side_dofs.size(); ++sidei)
        {
          unsigned int i = side_dofs[sidei];
          // fixed DoFs aren't test functions
          if (dof_is_fixed[i])
            continue;
          for (unsigned int sidej = 0, freej = 0; sidej != side_dofs.size(); ++sidej)
          {
            unsigned int j = side_dofs[sidej];
            if (dof_is_fixed[j])
              Fe(freei) -= phi[i][qp] * phi[j][qp] * JxW[qp] * Ue(j);
            else
              Ke(freei,freej) += phi[i][qp] * phi[j][qp] * JxW[qp];
            if (cont == C_ONE)
            {
              if (dof_is_fixed[j])
                Fe(freei) -= ((*dphi)[i][qp] * (*dphi)[j][qp]) * JxW[qp] * Ue(j);
              else
                Ke(freei,freej) += ((*dphi)[i][qp] * (*dphi)[j][qp]) * JxW[qp];
            }
            if (!dof_is_fixed[j])
              freej++;
          }
          Fe(freei) += (fineval * phi[i][qp]) * JxW[qp];
          if (cont == C_ONE)
            Fe(freei) += (finegrad * (*dphi)[i][qp]) * JxW[qp];
          freei++;
        }
      }

      Ke.cholesky_solve(Fe, Uside);

      // Transfer new side solutions to element
      for (unsigned int i=0; i != free_dofs; ++i)
      {
        Number &ui = Ue(side_dofs[free_dof[i]]);
        libmesh_assert(std::abs(ui) < TOLERANCE || std::abs(ui - Uside(i)) < TOLERANCE);
        ui = Uside(i);
        dof_is_fixed[side_dofs[free_dof[i]]] = true;
      }
    }

  // Project the interior values, finally

  // Some interior dofs are on nodes/edges/sides and
  // already fixed, others are free to calculate
  unsigned int free_dofs = 0;
  for (unsigned int i=0; i != n_dofs; ++i)
    if (!dof_is_fixed[i])
      free_dof[free_dofs++] = i;

  // There may be nothing to project
  if (free_dofs)
  {
    Ke.resize (free_dofs, free_dofs); Ke.zero();
    Fe.resize (free_dofs); Fe.zero();
    // The new interior coefficients
    DenseVector<Number> Uint(free_dofs);

    // Initialize FE data
    fe->attach_quadrature_rule (qrule.get());
    fe->reinit (_current_elem);
    const unsigned int n_qp = qrule->n_points();
    _fe_problem.sizeZeroes(n_qp, _tid);

    // Loop over the quadrature points
    for (unsigned int qp=0; qp<n_qp; qp++)
    {
      // solution at the quadrature point
      Number fineval = value(xyz_values[qp]);
      // solution grad at the quadrature point
      Gradient finegrad;
      if (cont == C_ONE)
        finegrad = gradient(xyz_values[qp]);

      // Form interior projection matrix
      for (unsigned int i=0, freei=0; i != n_dofs; ++i)
      {
        // fixed DoFs aren't test functions
        if (dof_is_fixed[i])
          continue;
        for (unsigned int j=0, freej=0; j != n_dofs; ++j)
        {
          if (dof_is_fixed[j])
            Fe(freei) -= phi[i][qp] * phi[j][qp] * JxW[qp] * Ue(j);
          else
            Ke(freei,freej) += phi[i][qp] * phi[j][qp] * JxW[qp];
          if (cont == C_ONE)
          {
            if (dof_is_fixed[j])
              Fe(freei) -= ((*dphi)[i][qp] * (*dphi)[j][qp]) * JxW[qp] * Ue(j);
            else
              Ke(freei,freej) += ((*dphi)[i][qp] * (*dphi)[j][qp]) * JxW[qp];
          }
          if (!dof_is_fixed[j])
            freej++;
        }
        Fe(freei) += phi[i][qp] * fineval * JxW[qp];
        if (cont == C_ONE)
          Fe(freei) += (finegrad * (*dphi)[i][qp]) * JxW[qp];
        freei++;
      }
    }
    Ke.cholesky_solve(Fe, Uint);

    // Transfer new interior solutions to element
    for (unsigned int i=0; i != free_dofs; ++i)
    {
      Number &ui = Ue(free_dof[i]);
      libmesh_assert(std::abs(ui) < TOLERANCE || std::abs(ui - Uint(i)) < TOLERANCE);
      ui = Uint(i);
      dof_is_fixed[free_dof[i]] = true;
    }
  } // if there are free interior dofs

  // Make sure every DoF got reached!
  for (unsigned int i=0; i != n_dofs; ++i)
    libmesh_assert(dof_is_fixed[i]);

  NumericVector<Number> & solution = _var.sys().solution();

  // 'first' and 'last' are no longer used, see note about subdomain-restricted variables below
  // const dof_id_type
  //   first = solution.first_local_index(),
  //   last  = solution.last_local_index();

  // Lock the new_vector since it is shared among threads.
  {
    Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);

    for (unsigned int i = 0; i < n_dofs; i++)
      // We may be projecting a new zero value onto
      // an old nonzero approximation - RHS
      // if (Ue(i) != 0.)

      // This is commented out because of subdomain restricted variables.
      // It can be the case that if a subdomain restricted variable's boundary
      // aligns perfectly with a processor boundary that the variable will get
      // no value.  To counteract this we're going to let every processor set a
      // value at every node and then let PETSc figure it out.
      // Later we can choose to do something different / better.
//      if ((dof_indices[i] >= first) && (dof_indices[i] < last))
      {
        solution.set(dof_indices[i], Ue(i));
        if (cont == C_ZERO)
          _var.setNodalValue(Ue(i), i);
      }
  }
}
コード例 #11
0
ファイル: adaptivity_ex3.C プロジェクト: GENGCHN/libmesh
// We now define the matrix assembly function for the
// Laplace system.  We need to first compute element
// matrices and right-hand sides, and then take into
// account the boundary conditions, which will be handled
// via a penalty method.
void assemble_laplace(EquationSystems& es,
                      const std::string& system_name)
{
#ifdef LIBMESH_ENABLE_AMR
  // It is a good idea to make sure we are assembling
  // the proper system.
  libmesh_assert_equal_to (system_name, "Laplace");


  // Declare a performance log.  Give it a descriptive
  // string to identify what part of the code we are
  // logging, since there may be many PerfLogs in an
  // application.
  PerfLog perf_log ("Matrix Assembly",false);

  // Get a constant reference to the mesh object.
  const MeshBase& mesh = es.get_mesh();

  // The dimension that we are running
  const unsigned int mesh_dim = mesh.mesh_dimension();

  // Get a reference to the LinearImplicitSystem we are solving
  LinearImplicitSystem& system = es.get_system<LinearImplicitSystem>("Laplace");

  // 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 = system.get_dof_map();

  // Get a constant reference to the Finite Element type
  // for the first (and only) variable in the system.
  FEType fe_type = dof_map.variable_type(0);

  // Build a Finite Element object of the specified type.  Since the
  // \p FEBase::build() member dynamically creates memory we will
  // store the object as an \p UniquePtr<FEBase>.  This can be thought
  // of as a pointer that will clean up after itself.
  UniquePtr<FEBase> fe      (FEBase::build(mesh_dim, fe_type));
  UniquePtr<FEBase> fe_face (FEBase::build(mesh_dim, fe_type));

  // Quadrature rules for numerical integration.
  UniquePtr<QBase> qrule(fe_type.default_quadrature_rule(mesh_dim));
  UniquePtr<QBase> qface(fe_type.default_quadrature_rule(mesh_dim-1));

  // Tell the finite element object to use our quadrature rule.
  fe->attach_quadrature_rule      (qrule.get());
  fe_face->attach_quadrature_rule (qface.get());

  // Here we define some references to cell-specific data that
  // will be used to assemble the linear system.
  // We begin with the element Jacobian * quadrature weight at each
  // integration point.
  const std::vector<Real>& JxW      = fe->get_JxW();
  const std::vector<Real>& JxW_face = fe_face->get_JxW();

  // The physical XY locations of the quadrature points on the element.
  // These might be useful for evaluating spatially varying material
  // properties or forcing functions at the quadrature points.
  const std::vector<Point>& q_point = fe->get_xyz();

  // The element shape functions evaluated at the quadrature points.
  // For this simple problem we usually only need them on element
  // boundaries.
  const std::vector<std::vector<Real> >& phi = fe->get_phi();
  const std::vector<std::vector<Real> >& psi = fe_face->get_phi();

  // The element shape function gradients evaluated at the quadrature
  // points.
  const std::vector<std::vector<RealGradient> >& dphi = fe->get_dphi();

  // The XY locations of the quadrature points used for face integration
  const std::vector<Point>& qface_points = fe_face->get_xyz();

  // 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". More detail is in example 3.
  DenseMatrix<Number> Ke;
  DenseVector<Number> 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<dof_id_type> dof_indices;

  // Now we will loop over all the elements in the mesh.  We will
  // compute the element matrix and right-hand-side contribution.  See
  // example 3 for a discussion of the element iterators.  Here we use
  // the \p const_active_local_elem_iterator to indicate we only want
  // to loop over elements that are assigned to the local processor
  // which are "active" in the sense of AMR.  This allows each
  // processor to compute its components of the global matrix for
  // active elements while ignoring parent elements which have been
  // refined.
  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)
    {
      // Start logging the shape function initialization.
      // This is done through a simple function call with
      // the name of the event to log.
      perf_log.push("elem init");

      // 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);

      // 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->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 (dof_indices.size(),
                 dof_indices.size());

      Fe.resize (dof_indices.size());

      // Stop logging the shape function initialization.
      // If you forget to stop logging an event the PerfLog
      // object will probably catch the error and abort.
      perf_log.pop("elem init");

      // Now we will build the element matrix.  This involves
      // a double loop to integrate the test funcions (i) against
      // the trial functions (j).
      //
      // Now start logging the element matrix computation
      perf_log.push ("Ke");

      for (unsigned int qp=0; qp<qrule->n_points(); qp++)
        for (unsigned int i=0; i<dphi.size(); i++)
          for (unsigned int j=0; j<dphi.size(); j++)
            Ke(i,j) += JxW[qp]*(dphi[i][qp]*dphi[j][qp]);

      // We need a forcing function to make the 1D case interesting
      if (mesh_dim == 1)
        for (unsigned int qp=0; qp<qrule->n_points(); qp++)
          {
            Real x = q_point[qp](0);
            Real f = singularity ? sqrt(3.)/9.*pow(-x, -4./3.) :
              cos(x);
            for (unsigned int i=0; i<dphi.size(); ++i)
              Fe(i) += JxW[qp]*phi[i][qp]*f;
          }

      // Stop logging the matrix computation
      perf_log.pop ("Ke");


      // 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.
      //
      // This approach adds the L2 projection of the boundary
      // data in penalty form to the weak statement.  This is
      // a more generic approach for applying Dirichlet BCs
      // which is applicable to non-Lagrange finite element
      // discretizations.
      {
        // Start logging the boundary condition computation
        perf_log.push ("BCs");

        // The penalty value.
        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)
            {
              fe_face->reinit(elem,s);

              for (unsigned int qp=0; qp<qface->n_points(); qp++)
                {
                  const Number value = exact_solution (qface_points[qp],
                                                       es.parameters,
                                                       "null",
                                                       "void");

                  // RHS contribution
                  for (unsigned int i=0; i<psi.size(); i++)
                    Fe(i) += penalty*JxW_face[qp]*value*psi[i][qp];

                  // Matrix contribution
                  for (unsigned int i=0; i<psi.size(); i++)
                    for (unsigned int j=0; j<psi.size(); j++)
                      Ke(i,j) += penalty*JxW_face[qp]*psi[i][qp]*psi[j][qp];
                }
            }

        // Stop logging the boundary condition computation
        perf_log.pop ("BCs");
      }


      // 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 SparseMatrix::add_matrix()
      // and \p NumericVector::add_vector() members do this for us.
      // Start logging the insertion of the local (element)
      // matrix and vector into the global matrix and vector
      perf_log.push ("matrix insertion");

      dof_map.constrain_element_matrix_and_vector(Ke, Fe, dof_indices);
      system.matrix->add_matrix (Ke, dof_indices);
      system.rhs->add_vector    (Fe, dof_indices);

      // Start logging the insertion of the local (element)
      // matrix and vector into the global matrix and vector
      perf_log.pop ("matrix insertion");
    }

  // That's it.  We don't need to do anything else to the
  // PerfLog.  When it goes out of scope (at this function return)
  // it will print its log to the screen. Pretty easy, huh?
#endif // #ifdef LIBMESH_ENABLE_AMR
}
コード例 #12
0
ファイル: miscellaneous_ex3.C プロジェクト: rppawlo/libmesh
// Jacobian assembly function for the Laplace-Young system
void LaplaceYoung::jacobian (const NumericVector<Number>& soln,
                             SparseMatrix<Number>& jacobian,
                             NonlinearImplicitSystem& sys)
{
  // Get a reference to the equation system.
  EquationSystems &es = sys.get_equation_systems();

  // Get a constant reference to the mesh object.
  const MeshBase& mesh = es.get_mesh();

  // The dimension that we are running
  const unsigned int dim = mesh.mesh_dimension();

  // Get a reference to the NonlinearImplicitSystem we are solving
  NonlinearImplicitSystem& system =
    es.get_system<NonlinearImplicitSystem>("Laplace-Young");

  // 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 = system.get_dof_map();

  // Get a constant reference to the Finite Element type
  // for the first (and only) variable in the system.
  FEType fe_type = dof_map.variable_type(0);

  // Build a Finite Element object of the specified type.  Since the
  // \p FEBase::build() member dynamically creates memory we will
  // store the object as an \p UniquePtr<FEBase>.  This can be thought
  // of as a pointer that will clean up after itself.
  UniquePtr<FEBase> fe (FEBase::build(dim, fe_type));

  // A 5th order Gauss quadrature rule for numerical integration.
  QGauss qrule (dim, FIFTH);

  // Tell the finite element object to use our quadrature rule.
  fe->attach_quadrature_rule (&qrule);

  // Here we define some references to cell-specific data that
  // will be used to assemble the linear system.
  // We begin with the element Jacobian * quadrature weight at each
  // integration point.
  const std::vector<Real>& JxW = fe->get_JxW();

  // The element shape functions evaluated at the quadrature points.
  const std::vector<std::vector<Real> >& phi = fe->get_phi();

  // The element shape function gradients evaluated at the quadrature
  // points.
  const std::vector<std::vector<RealGradient> >& dphi = fe->get_dphi();

  // Define data structures to contain the Jacobian element matrix.
  // Following basic finite element terminology we will denote these
  // "Ke". More detail is in example 3.
  DenseMatrix<Number> Ke;

  // 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<dof_id_type> dof_indices;

  // Now we will loop over all the active elements in the mesh which
  // are local to this processor.
  // We will compute the element Jacobian contribution.
  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);

      // 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->reinit (elem);

      // Zero the element Jacobian 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 (dof_indices.size(),
                 dof_indices.size());

      // Now we will build the element Jacobian.  This involves
      // a double loop to integrate the test funcions (i) against
      // the trial functions (j). Note that the Jacobian depends
      // on the current solution x, which we access using the soln
      // vector.
      //
      for (unsigned int qp=0; qp<qrule.n_points(); qp++)
        {
          Gradient grad_u;

          for (unsigned int i=0; i<phi.size(); i++)
            grad_u += dphi[i][qp]*soln(dof_indices[i]);

          const Number
            sa = 1. + grad_u*grad_u,
            K  = 1. / std::sqrt(sa),
            dK = -K / sa;

          for (unsigned int i=0; i<phi.size(); i++)
            for (unsigned int j=0; j<phi.size(); j++)
                Ke(i,j) += JxW[qp]*(
                                    K * (dphi[i][qp]*dphi[j][qp]) +
                                    dK * (grad_u*dphi[j][qp]) * (grad_u*dphi[i][qp]) +
                                    _kappa * phi[i][qp] * phi[j][qp]
                                    );
        }

      dof_map.constrain_element_matrix (Ke, dof_indices);

      // Add the element matrix to the system Jacobian.
      jacobian.add_matrix (Ke, dof_indices);
    }

  // That's it.
}
コード例 #13
0
ファイル: miscellaneous_ex3.C プロジェクト: rppawlo/libmesh
// Residual assembly function for the Laplace-Young system
void LaplaceYoung::residual (const NumericVector<Number>& soln,
                             NumericVector<Number>& residual,
                             NonlinearImplicitSystem& sys)
{
  EquationSystems &es = sys.get_equation_systems();

  // Get a constant reference to the mesh object.
  const MeshBase& mesh = es.get_mesh();

  // The dimension that we are running
  const unsigned int dim = mesh.mesh_dimension();
  libmesh_assert_equal_to (dim, 2);

  // Get a reference to the NonlinearImplicitSystem we are solving
  NonlinearImplicitSystem& system =
    es.get_system<NonlinearImplicitSystem>("Laplace-Young");

  // 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 = system.get_dof_map();

  // Get a constant reference to the Finite Element type
  // for the first (and only) variable in the system.
  FEType fe_type = dof_map.variable_type(0);

  // Build a Finite Element object of the specified type.  Since the
  // \p FEBase::build() member dynamically creates memory we will
  // store the object as an \p UniquePtr<FEBase>.  This can be thought
  // of as a pointer that will clean up after itself.
  UniquePtr<FEBase> fe (FEBase::build(dim, fe_type));

  // A 5th order Gauss quadrature rule for numerical integration.
  QGauss qrule (dim, FIFTH);

  // Tell the finite element object to use our quadrature rule.
  fe->attach_quadrature_rule (&qrule);

  // Declare a special finite element object for
  // boundary integration.
  UniquePtr<FEBase> fe_face (FEBase::build(dim, fe_type));

  // Boundary integration requires one quadraure rule,
  // with dimensionality one less than the dimensionality
  // of the element.
  QGauss qface(dim-1, FIFTH);

  // Tell the finte element object to use our
  // quadrature rule.
  fe_face->attach_quadrature_rule (&qface);

  // Here we define some references to cell-specific data that
  // will be used to assemble the linear system.
  // We begin with the element Jacobian * quadrature weight at each
  // integration point.
  const std::vector<Real>& JxW = fe->get_JxW();

  // The element shape functions evaluated at the quadrature points.
  const std::vector<std::vector<Real> >& phi = fe->get_phi();

  // The element shape function gradients evaluated at the quadrature
  // points.
  const std::vector<std::vector<RealGradient> >& dphi = fe->get_dphi();

  // Define data structures to contain the resdual contributions
  DenseVector<Number> Re;

  // 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<dof_id_type> dof_indices;

  // Now we will loop over all the active elements in the mesh which
  // are local to this processor.
  // We will compute the element residual.
  residual.zero();

  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);

      // 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->reinit (elem);

      // 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).
      Re.resize (dof_indices.size());

      // Now we will build the residual. This involves
      // the construction of the matrix K and multiplication of it
      // with the current solution x. We rearrange this into two loops:
      // In the first, we calculate only the contribution of
      // K_ij*x_j which is independent of the row i. In the second loops,
      // we multiply with the row-dependent part and add it to the element
      // residual.

      for (unsigned int qp=0; qp<qrule.n_points(); qp++)
        {
          Number u = 0;
          Gradient grad_u;

          for (unsigned int j=0; j<phi.size(); j++)
            {
              u      += phi[j][qp]*soln(dof_indices[j]);
              grad_u += dphi[j][qp]*soln(dof_indices[j]);
            }

          const Number K = 1./std::sqrt(1. + grad_u*grad_u);

          for (unsigned int i=0; i<phi.size(); i++)
            Re(i) += JxW[qp]*(
                              K*(dphi[i][qp]*grad_u) +
                              _kappa*phi[i][qp]*u
                              );
        }

      // At this point the interior element integration has
      // been completed.  However, we have not yet addressed
      // boundary conditions.

      // 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 side=0; side<elem->n_sides(); side++)
        if (elem->neighbor(side) == NULL)
          {
            // The value of the shape functions at the quadrature
            // points.
            const std::vector<std::vector<Real> >&  phi_face = fe_face->get_phi();

            // The Jacobian * Quadrature Weight at the quadrature
            // points on the face.
            const std::vector<Real>& JxW_face = fe_face->get_JxW();

            // Compute the shape function values on the element face.
            fe_face->reinit(elem, side);

            // Loop over the face quadrature points for integration.
            for (unsigned int qp=0; qp<qface.n_points(); qp++)
              {
                // This is the right-hand-side contribution (f),
                // which has to be subtracted from the current residual
                for (unsigned int i=0; i<phi_face.size(); i++)
                  Re(i) -= JxW_face[qp]*_sigma*phi_face[i][qp];
              }
          }

      dof_map.constrain_element_vector (Re, dof_indices);
      residual.add_vector (Re, dof_indices);
    }

  // That's it.
}
コード例 #14
0
  /**
   * Assemble the system matrix and right-hand side vector.
   */
  void assemble()
  {
    const MeshBase& mesh = es.get_mesh();

    const unsigned int dim = mesh.mesh_dimension();

    LinearImplicitSystem& system = es.get_system<LinearImplicitSystem>("Elasticity");

    const unsigned int u_var = system.variable_number ("u");

    const DofMap& dof_map = system.get_dof_map();
    FEType fe_type = dof_map.variable_type(u_var);
    UniquePtr<FEBase> fe (FEBase::build(dim, fe_type));
    QGauss qrule (dim, fe_type.default_quadrature_order());
    fe->attach_quadrature_rule (&qrule);

    UniquePtr<FEBase> fe_face (FEBase::build(dim, fe_type));
    QGauss qface(dim-1, fe_type.default_quadrature_order());
    fe_face->attach_quadrature_rule (&qface);

    const std::vector<Real>& JxW = fe->get_JxW();
    const std::vector<std::vector<Real> >& phi = fe->get_phi();
    const std::vector<std::vector<RealGradient> >& dphi = fe->get_dphi();

    DenseMatrix<Number> Ke;
    DenseSubMatrix<Number> Ke_var[3][3] =
      {
        {DenseSubMatrix<Number>(Ke), DenseSubMatrix<Number>(Ke), DenseSubMatrix<Number>(Ke)},
        {DenseSubMatrix<Number>(Ke), DenseSubMatrix<Number>(Ke), DenseSubMatrix<Number>(Ke)},
        {DenseSubMatrix<Number>(Ke), DenseSubMatrix<Number>(Ke), DenseSubMatrix<Number>(Ke)}
      };

    DenseVector<Number> Fe;
    DenseSubVector<Number> Fe_var[3] =
      {DenseSubVector<Number>(Fe), DenseSubVector<Number>(Fe), DenseSubVector<Number>(Fe)};

    std::vector<dof_id_type> dof_indices;
    std::vector< std::vector<dof_id_type> > dof_indices_var(3);

    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)
      {
        const Elem* elem = *el;

        dof_map.dof_indices (elem, dof_indices);
        for(unsigned int var=0; var<3; var++)
          {
            dof_map.dof_indices (elem, dof_indices_var[var], var);
          }

        const unsigned int n_dofs   = dof_indices.size();
        const unsigned int n_var_dofs = dof_indices_var[0].size();

        fe->reinit (elem);

        Ke.resize (n_dofs,n_dofs);
        for(unsigned int var_i=0; var_i<3; var_i++)
          for(unsigned int var_j=0; var_j<3; var_j++)
            {
              Ke_var[var_i][var_j].reposition (var_i*n_var_dofs, var_j*n_var_dofs, n_var_dofs, n_var_dofs);
            }

        Fe.resize (n_dofs);
        for(unsigned int var=0; var<3; var++)
          {
            Fe_var[var].reposition (var*n_var_dofs, n_var_dofs);
          }

        for (unsigned int qp=0; qp<qrule.n_points(); qp++)
          {

            // assemble \int_Omega C_ijkl u_k,l v_i,j \dx
            for (unsigned int dof_i=0; dof_i<n_var_dofs; dof_i++)
              for (unsigned int dof_j=0; dof_j<n_var_dofs; dof_j++)
                {
                  for(unsigned int i=0; i<3; i++)
                    for(unsigned int j=0; j<3; j++)
                      for(unsigned int k=0; k<3; k++)
                        for(unsigned int l=0; l<3; l++)
                          {
                            Ke_var[i][k](dof_i,dof_j) += JxW[qp] *
                              elasticity_tensor(i,j,k,l) *
                              dphi[dof_j][qp](l) *
                              dphi[dof_i][qp](j);
                          }
                }

            // assemble \int_Omega f_i v_i \dx
            DenseVector<Number> f_vec(3);
            f_vec(0) =  0.;
            f_vec(1) =  0.;
            f_vec(2) = -1.;
            for (unsigned int dof_i=0; dof_i<n_var_dofs; dof_i++)
              {
                for(unsigned int i=0; i<3; i++)
                  {
                    Fe_var[i](dof_i) += JxW[qp] *
                      ( f_vec(i) * phi[dof_i][qp] );
                  }
              }
          }

        // assemble \int_\Gamma g_i v_i \ds
        DenseVector<Number> g_vec(3);
        g_vec(0) = 0.;
        g_vec(1) = 0.;
        g_vec(2) = -1.;
        {
          for (unsigned int side=0; side<elem->n_sides(); side++)
            if (elem->neighbor(side) == NULL)
              {
                const std::vector<std::vector<Real> >&  phi_face = fe_face->get_phi();
                const std::vector<Real>& JxW_face = fe_face->get_JxW();

                fe_face->reinit(elem, side);

                for (unsigned int qp=0; qp<qface.n_points(); qp++)
                  {
                    // Apply a traction
                    if( mesh.get_boundary_info().has_boundary_id
                          (elem, side, BOUNDARY_ID_MAX_X)
                        )
                      {

                        for (unsigned int dof_i=0; dof_i<n_var_dofs; dof_i++)
                          {
                            for(unsigned int i=0; i<3; i++)
                              {
                                Fe_var[i](dof_i) += JxW_face[qp] *
                                  ( g_vec(i) * phi_face[dof_i][qp] );
                              }
                          }

                      }
                  }
              }
        }

        dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices);

        system.matrix->add_matrix (Ke, dof_indices);
        system.rhs->add_vector    (Fe, dof_indices);
      }
  }
コード例 #15
0
// We now define the matrix assembly function for the
// Poisson system.  We need to first compute element
// matrices and right-hand sides, and then take into
// account the boundary conditions, which will be handled
// via a penalty method.
void assemble_poisson(EquationSystems & es,
                      const std::string & system_name)
{

    // It is a good idea to make sure we are assembling
    // the proper system.
    libmesh_assert_equal_to (system_name, "Poisson");


    // Get a constant reference to the mesh object.
    const MeshBase & mesh = es.get_mesh();

    // The dimension that we are running
    const unsigned int dim = mesh.mesh_dimension();

    // Get a reference to the LinearImplicitSystem we are solving
    LinearImplicitSystem & system = es.get_system<LinearImplicitSystem> ("Poisson");

    // A reference to the  DofMap object for this system.  The  DofMap
    // object handles the index translation from node and element numbers
    // to degree of freedom numbers.  We will talk more about the  DofMap
    // in future examples.
    const DofMap & dof_map = system.get_dof_map();

    // Get a constant reference to the Finite Element type
    // for the first (and only) variable in the system.
    FEType fe_type = dof_map.variable_type(0);

    // Build a Finite Element object of the specified type.  Since the
    // FEBase::build() member dynamically creates memory we will
    // store the object as a UniquePtr<FEBase>.  This can be thought
    // of as a pointer that will clean up after itself.  Introduction Example 4
    // describes some advantages of  UniquePtr's in the context of
    // quadrature rules.
    UniquePtr<FEBase> fe (FEBase::build(dim, fe_type));

    // A 5th order Gauss quadrature rule for numerical integration.
    QGauss qrule (dim, FIFTH);

    // Tell the finite element object to use our quadrature rule.
    fe->attach_quadrature_rule (&qrule);

    // Declare a special finite element object for
    // boundary integration.
    UniquePtr<FEBase> fe_face (FEBase::build(dim, fe_type));

    // Boundary integration requires one quadraure rule,
    // with dimensionality one less than the dimensionality
    // of the element.
    QGauss qface(dim-1, FIFTH);

    // Tell the finite element object to use our
    // quadrature rule.
    fe_face->attach_quadrature_rule (&qface);

    // Here we define some references to cell-specific data that
    // will be used to assemble the linear system.
    //
    // The element Jacobian * quadrature weight at each integration point.
    const std::vector<Real> & JxW = fe->get_JxW();

    // The physical XY locations of the quadrature points on the element.
    // These might be useful for evaluating spatially varying material
    // properties at the quadrature points.
    const std::vector<Point> & q_point = fe->get_xyz();

    // The element shape functions evaluated at the quadrature points.
    const std::vector<std::vector<Real> > & phi = fe->get_phi();

    // The element shape function gradients evaluated at the quadrature
    // points.
    const std::vector<std::vector<RealGradient> > & dphi = fe->get_dphi();

    // 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".  These datatypes are templated on
    //  Number, which allows the same code to work for real
    // or complex numbers.
    DenseMatrix<Number> Ke;
    DenseVector<Number> 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<dof_id_type> dof_indices;

    // Now we will loop over all the elements in the mesh.
    // We will compute the element matrix and right-hand-side
    // contribution.
    //
    // Element iterators are a nice way to iterate through all the
    // elements, or all the elements that have some property.  The
    // iterator el will iterate from the first to the last element on
    // the local processor.  The iterator end_el tells us when to stop.
    // It is smart to make this one const so that we don't accidentally
    // mess it up!  In case users later modify this program to include
    // refinement, we will be safe and will only consider the active
    // elements; hence we use a variant of the 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();

    // Loop over the elements.  Note that  ++el is preferred to
    // el++ since the latter requires an unnecessary temporary
    // object.
    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);

        // 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->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).

        // The  DenseMatrix::resize() and the  DenseVector::resize()
        // members will automatically zero out the matrix  and vector.
        Ke.resize (dof_indices.size(),
                   dof_indices.size());

        Fe.resize (dof_indices.size());

        // Now loop over the quadrature points.  This handles
        // the numeric integration.
        for (unsigned int qp=0; qp<qrule.n_points(); qp++)
        {

            // Now we will build the element matrix.  This involves
            // a double loop to integrate the test funcions (i) against
            // the trial functions (j).
            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]);
                }

            // This is the end of the matrix summation loop
            // Now 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.
            {
                const Real x = q_point[qp](0);
                const Real y = q_point[qp](1);
                const Real eps = 1.e-3;


                // "fxy" is the forcing function for the Poisson equation.
                // In this case we set fxy to be a finite difference
                // Laplacian approximation to the (known) exact solution.
                //
                // We will use the second-order accurate FD Laplacian
                // approximation, which in 2D is
                //
                // 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
                //
                // Since the value of the forcing function depends only
                // on the location of the quadrature point (q_point[qp])
                // we will compute it here, outside of the i-loop
                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];
            }
        }

        // We have now reached the end of the RHS summation,
        // and the end of quadrature point loop, so
        // 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.
        //
        // There are several ways Dirichlet boundary conditions
        // can be imposed.  A simple approach, which works for
        // interpolary bases like the standard Lagrange polynomials,
        // is to assign function values to the
        // degrees of freedom living on the domain boundary. This
        // works well for interpolary bases, but is more difficult
        // when non-interpolary (e.g Legendre or Hierarchic) bases
        // are used.
        //
        // Dirichlet boundary conditions can also be imposed with a
        // "penalty" method.  In this case essentially the L2 projection
        // of the boundary values are added to the matrix. The
        // projection is multiplied by some large factor so that, in
        // floating point arithmetic, the existing (smaller) entries
        // in the matrix and right-hand-side are effectively ignored.
        //
        // This amounts to adding a term of the form (in latex notation)
        //
        // \frac{1}{\epsilon} \int_{\delta \Omega} \phi_i \phi_j = \frac{1}{\epsilon} \int_{\delta \Omega} u \phi_i
        //
        // where
        //
        // \frac{1}{\epsilon} is the penalty parameter, defined such that \epsilon << 1
        {

            // The following loop is 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 side=0; side<elem->n_sides(); side++)
                if (elem->neighbor_ptr(side) == libmesh_nullptr)
                {
                    // The value of the shape functions at the quadrature
                    // points.
                    const std::vector<std::vector<Real> > & phi_face = fe_face->get_phi();

                    // The Jacobian * Quadrature Weight at the quadrature
                    // points on the face.
                    const std::vector<Real> & JxW_face = fe_face->get_JxW();

                    // The XYZ locations (in physical space) of the
                    // quadrature points on the face.  This is where
                    // we will interpolate the boundary value function.
                    const std::vector<Point> & qface_point = fe_face->get_xyz();

                    // Compute the shape function values on the element
                    // face.
                    fe_face->reinit(elem, side);

                    // Loop over the face quadrature points for integration.
                    for (unsigned int qp=0; qp<qface.n_points(); qp++)
                    {
                        // The location on the boundary of the current
                        // face quadrature point.
                        const Real xf = qface_point[qp](0);
                        const Real yf = qface_point[qp](1);

                        // The penalty value.  \frac{1}{\epsilon}
                        // in the discussion above.
                        const Real penalty = 1.e10;

                        // The boundary value.
                        const Real value = exact_solution(xf, yf);

                        // Matrix contribution of the L2 projection.
                        for (unsigned int i=0; i<phi_face.size(); i++)
                            for (unsigned int j=0; j<phi_face.size(); j++)
                                Ke(i,j) += JxW_face[qp]*penalty*phi_face[i][qp]*phi_face[j][qp];

                        // Right-hand-side contribution of the L2
                        // projection.
                        for (unsigned int i=0; i<phi_face.size(); i++)
                            Fe(i) += JxW_face[qp]*penalty*value*phi_face[i][qp];
                    }
                }
        }

        // We have now finished the quadrature point loop,
        // and have therefore applied all the boundary conditions.

        // If this assembly program were to be used on an adaptive mesh,
        // we would have to apply any hanging node constraint equations
        dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices);

        // 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  SparseMatrix::add_matrix()
        // and  NumericVector::add_vector() members do this for us.
        system.matrix->add_matrix (Ke, dof_indices);
        system.rhs->add_vector    (Fe, dof_indices);
    }

    // All done!
}
コード例 #16
0
void ExactErrorEstimator::estimate_error (const System & system,
                                          ErrorVector & error_per_cell,
                                          const NumericVector<Number> * solution_vector,
                                          bool estimate_parent_error)
{
  // Ignore the fact that this variable is unused when !LIBMESH_ENABLE_AMR
  libmesh_ignore(estimate_parent_error);

  // The current mesh
  const MeshBase & mesh = system.get_mesh();

  // The dimensionality of the mesh
  const unsigned int dim = mesh.mesh_dimension();

  // The number of variables in the system
  const unsigned int n_vars = system.n_vars();

  // The DofMap for this system
  const DofMap & dof_map = system.get_dof_map();

  // Resize the error_per_cell vector to be
  // the number of elements, initialize it to 0.
  error_per_cell.resize (mesh.max_elem_id());
  std::fill (error_per_cell.begin(), error_per_cell.end(), 0.);

  // Prepare current_local_solution to localize a non-standard
  // solution vector if necessary
  if (solution_vector && solution_vector != system.solution.get())
    {
      NumericVector<Number> * newsol =
        const_cast<NumericVector<Number> *>(solution_vector);
      System & sys = const_cast<System &>(system);
      newsol->swap(*sys.solution);
      sys.update();
    }

  // Loop over all the variables in the system
  for (unsigned int var=0; var<n_vars; var++)
    {
      // Possibly skip this variable
      if (error_norm.weight(var) == 0.0) continue;

      // The (string) name of this variable
      const std::string & var_name = system.variable_name(var);

      // The type of finite element to use for this variable
      const FEType & fe_type = dof_map.variable_type (var);

      UniquePtr<FEBase> fe (FEBase::build (dim, fe_type));

      // Build an appropriate Gaussian quadrature rule
      UniquePtr<QBase> qrule =
        fe_type.default_quadrature_rule (dim,
                                         _extra_order);

      fe->attach_quadrature_rule (qrule.get());

      // Prepare a global solution and a MeshFunction of the fine system if we need one
      UniquePtr<MeshFunction> fine_values;
      UniquePtr<NumericVector<Number> > fine_soln = NumericVector<Number>::build(system.comm());
      if (_equation_systems_fine)
        {
          const System & fine_system = _equation_systems_fine->get_system(system.name());

          std::vector<Number> global_soln;
          // FIXME - we're assuming that the fine system solution gets
          // used even when a different vector is used for the coarse
          // system
          fine_system.update_global_solution(global_soln);
          fine_soln->init
            (cast_int<numeric_index_type>(global_soln.size()), true,
             SERIAL);
          (*fine_soln) = global_soln;

          fine_values = UniquePtr<MeshFunction>
            (new MeshFunction(*_equation_systems_fine,
                              *fine_soln,
                              fine_system.get_dof_map(),
                              fine_system.variable_number(var_name)));
          fine_values->init();
        } else {
        // Initialize functors if we're using them
        for (unsigned int i=0; i != _exact_values.size(); ++i)
          if (_exact_values[i])
            _exact_values[i]->init();

        for (unsigned int i=0; i != _exact_derivs.size(); ++i)
          if (_exact_derivs[i])
            _exact_derivs[i]->init();

        for (unsigned int i=0; i != _exact_hessians.size(); ++i)
          if (_exact_hessians[i])
            _exact_hessians[i]->init();
      }

      // Request the data we'll need to compute with
      fe->get_JxW();
      fe->get_phi();
      fe->get_dphi();
#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
      fe->get_d2phi();
#endif
      fe->get_xyz();

#ifdef LIBMESH_ENABLE_AMR
      // If we compute on parent elements, we'll want to do so only
      // once on each, so we need to keep track of which we've done.
      std::vector<bool> computed_var_on_parent;

      if (estimate_parent_error)
        computed_var_on_parent.resize(error_per_cell.size(), false);
#endif

      // TODO: this ought to be threaded (and using subordinate
      // MeshFunction objects in each thread rather than a single
      // master)

      // Iterate over all the active elements in the mesh
      // that live on this processor.
      MeshBase::const_element_iterator
        elem_it  = mesh.active_local_elements_begin();
      const MeshBase::const_element_iterator
        elem_end = mesh.active_local_elements_end();

      for (;elem_it != elem_end; ++elem_it)
        {
          // e is necessarily an active element on the local processor
          const Elem * elem = *elem_it;
          const dof_id_type e_id = elem->id();

#ifdef LIBMESH_ENABLE_AMR
          // See if the parent of element e has been examined yet;
          // if not, we may want to compute the estimator on it
          const Elem * parent = elem->parent();

          // We only can compute and only need to compute on
          // parents with all active children
          bool compute_on_parent = true;
          if (!parent || !estimate_parent_error)
            compute_on_parent = false;
          else
            for (unsigned int c=0; c != parent->n_children(); ++c)
              if (!parent->child_ptr(c)->active())
                compute_on_parent = false;

          if (compute_on_parent &&
              !computed_var_on_parent[parent->id()])
            {
              computed_var_on_parent[parent->id()] = true;

              // Compute a projection onto the parent
              DenseVector<Number> Uparent;
              FEBase::coarsened_dof_values(*(system.current_local_solution),
                                           dof_map, parent, Uparent,
                                           var, false);

              error_per_cell[parent->id()] +=
                static_cast<ErrorVectorReal>
                (find_squared_element_error(system, var_name,
                                            parent, Uparent,
                                            fe.get(),
                                            fine_values.get()));
            }
#endif

          // Get the local to global degree of freedom maps
          std::vector<dof_id_type> dof_indices;
          dof_map.dof_indices (elem, dof_indices, var);
          const unsigned int n_dofs =
            cast_int<unsigned int>(dof_indices.size());
          DenseVector<Number> Uelem(n_dofs);
          for (unsigned int i=0; i != n_dofs; ++i)
            Uelem(i) = system.current_solution(dof_indices[i]);

          error_per_cell[e_id] +=
            static_cast<ErrorVectorReal>
            (find_squared_element_error(system, var_name, elem,
                                        Uelem, fe.get(),
                                        fine_values.get()));

        } // End loop over active local elements
    } // End loop over variables



  // Each processor has now computed the error contribuions
  // for its local elements.  We need to sum the vector
  // and then take the square-root of each component.  Note
  // that we only need to sum if we are running on multiple
  // processors, and we only need to take the square-root
  // if the value is nonzero.  There will in general be many
  // zeros for the inactive elements.

  // First sum the vector of estimated error values
  this->reduce_error(error_per_cell, system.comm());

  // Compute the square-root of each component.
  {
    LOG_SCOPE("std::sqrt()", "ExactErrorEstimator");
    for (dof_id_type i=0; i<error_per_cell.size(); i++)
      if (error_per_cell[i] != 0.)
        {
          libmesh_assert_greater (error_per_cell[i], 0.);
          error_per_cell[i] = std::sqrt(error_per_cell[i]);
        }
  }

  // If we used a non-standard solution before, now is the time to fix
  // the current_local_solution
  if (solution_vector && solution_vector != system.solution.get())
    {
      NumericVector<Number> * newsol =
        const_cast<NumericVector<Number> *>(solution_vector);
      System & sys = const_cast<System &>(system);
      newsol->swap(*sys.solution);
      sys.update();
    }
}
コード例 #17
0
ファイル: actual.C プロジェクト: vegnesh/Ep_solution
void assemble_elasticity(EquationSystems & es,
                         const std::string & system_name)
{
  libmesh_assert_equal_to (system_name, "Elasticity");

  const MeshBase & mesh = es.get_mesh();

  const unsigned int dim = mesh.mesh_dimension();
  
  Real pival = libMesh::pi;
  Real sigma = 1000.0;
  Real omega = 2.0*pival*27e6;
  Real Mu0 = 4e-7*pival;
  char *filename = "coordinates_custom.dat";

  LinearImplicitSystem & system = es.get_system<LinearImplicitSystem>("Elasticity");

  const unsigned int u_var = system.variable_number ("u");
  const unsigned int v_var = system.variable_number ("v");

  const DofMap & dof_map = system.get_dof_map();
  FEType fe_type = dof_map.variable_type(0);
  UniquePtr<FEBase> fe (FEBase::build(dim, fe_type));
  QGauss qrule (dim, fe_type.default_quadrature_order());
  fe->attach_quadrature_rule (&qrule);
  

  UniquePtr<FEBase> fe_face (FEBase::build(dim, fe_type));
  QGauss qface(dim-1, fe_type.default_quadrature_order());
  fe_face->attach_quadrature_rule (&qface);

  const std::vector<Real> & JxW = fe->get_JxW();
  const std::vector<std::vector<Real>> & phi = fe->get_phi();
  const std::vector<std::vector<RealGradient> > & dphi = fe->get_dphi();
  const std::vector<Point> & q_point = fe->get_xyz();

  DenseMatrix<Number> Ke;
  DenseVector<Number> Fe;

  DenseSubMatrix<Number>
    Kuu(Ke), Kuv(Ke),
    Kvu(Ke), Kvv(Ke);

  DenseSubVector<Number>
    Fu(Fe),
    Fv(Fe);

  std::vector<dof_id_type> dof_indices;
  std::vector<dof_id_type> dof_indices_u;
  std::vector<dof_id_type> dof_indices_v;

  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)
    {
      const Elem * elem = *el;

      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);

      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();

      fe->reinit (elem);

      Ke.resize (n_dofs, n_dofs);
      Fe.resize (n_dofs);

      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);

      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);

      Fu.reposition (u_var*n_u_dofs, n_u_dofs);
      Fv.reposition (v_var*n_u_dofs, n_v_dofs);
      const Real eps = 1.e-3;
      
      for (unsigned int qp=0; qp<qrule.n_points(); qp++)
        {
          const Real x = q_point[qp](0);
          const Real y = q_point[qp](1);
          Real fxyz = 0.0;
          Real fxy = 0.0;
          for (unsigned int i=0; i<n_u_dofs; i++)
            for (unsigned int j=0; j<n_u_dofs; j++)
              {
                  Kuu(i,j) += JxW[qp]*(dphi[i][qp]*dphi[j][qp] + phi[i][qp]*phi[j][qp]/x/x)*x ; 
              }
          if (  x<=0.3 && y>=0.0 && y<=1.0 )
       {  
          Real Kfactor = Mu0*sigma*omega;  
          for (unsigned int i=0; i<n_u_dofs; i++)
            for (unsigned int j=0; j<n_v_dofs; j++)
              {
               Kuv(i,j) += (-1.0)*(JxW[qp]*(phi[i][qp]*phi[j][qp])*Kfactor*x);          
              }

          for (unsigned int i=0; i<n_v_dofs; i++)
            for (unsigned int j=0; j<n_u_dofs; j++)
              {
               Kvu(i,j) += JxW[qp]*(phi[i][qp]*phi[j][qp])*Kfactor*x ;
              }

              fxyz = -Kfactor*solev(x,y,filename)*Mu0*omega/2.0/pival;
        }
          for (unsigned int i=0; i<n_v_dofs; i++)
            for (unsigned int j=0; j<n_v_dofs; j++)
              {
               Kvv(i,j) +=JxW[qp]*(dphi[i][qp]*dphi[j][qp] + phi[i][qp]*phi[j][qp]/x/x )*x ;            
              }
        //     Real fxyz = exact_solution(x,y)*pival*pival/2.0 + pival*0.5*sin(0.5*pival*x)*sin(0.5*pival*y)/x + exact_solution(x,y)/x/x + Kfactor*exact_solution2(x,y);
        //     Real fxy = exact_solution2(x,y)*pival*pival/2.0 - pival*0.5*cos(0.5*pival*x)*cos(0.5*pival*y)/x + exact_solution2(x,y)/x/x + Kfactor*exact_solution(x,y);
          
                  for (unsigned int i=0; i<n_u_dofs; i++)
                  Fu(i) += JxW[qp]*fxyz*phi[i][qp]*x;
                  for (unsigned int i = 0;i<n_v_dofs;i++)
                  Fv(i) += JxW[qp]*fxy*phi[i][qp]*x;
        }
 	
        for (unsigned int s=0; s<elem->n_sides(); s++)
          if (elem->neighbor(s) == libmesh_nullptr)
            {
	const std::vector<std::vector<Real> > & phi_face = fe_face->get_phi();
	const std::vector<Real> & JxW_face = fe_face->get_JxW();
	const std::vector<Point> & qface_point = fe_face->get_xyz();
	const std::vector<Point>& qface_normals = fe_face->get_normals();
	fe_face->reinit(elem, s);
    	UniquePtr<Elem> side (elem->build_side(s));
	/*	  for (unsigned int qp=0; qp<qface.n_points(); qp++)
                {
                  // The location on the boundary of the current
                  // face quadrature point.
                  const Real xf = qface_point[qp](0);
                  const Real yf = qface_point[qp](1);

                  // The penalty value.  \frac{1}{\epsilon}
                  // in the discussion above.
                  const Real penalty = 1.e10;

                  // The boundary value.
                  const Real value = exact_solution(xf, yf);

                  // Matrix contribution of the L2 projection.
                  for (unsigned int i=0; i<phi_face.size(); i++)
                    for (unsigned int j=0; j<phi_face.size(); j++)
                      Ke(i,j) += JxW_face[qp]*penalty*phi_face[i][qp]*phi_face[j][qp]*xf;

                  // Right-hand-side contribution of the L2
                  // projection.
                  for (unsigned int i=0; i<phi_face.size(); i++)
                    Fe(i) += JxW_face[qp]*penalty*value*phi_face[i][qp]*xf;
                }*/
      	double check = 0;
    		    {
    		      for (unsigned int ns=0; ns<side->n_nodes(); ns++)
    			{ const Real penalty = 1.e10;
    			  for (unsigned int n=0; n<elem->n_nodes(); n++)
    			    if (elem->node(n) == side->node(ns))
    			      { 
				Node *node = elem->get_node(n);

				Point poi = *node;
				const Real xf = poi(0);
		                const Real yf = poi(1);

    				for(unsigned int j=0; j<n_u_dofs; ++j)
    				  Kuu(n,j) = 0.;
                                for(unsigned int j=0; j<n_v_dofs; ++j)
                                  Kvv(n,j) = 0.;
				
    				Kuu(n,n) = 1.;
                                Kvv(n,n) = 1.;
                                Fu(n) = 0.0;
                                Fv(n) = 0.0;
//    				Fu(n)   = exact_solution(xf,yf);			
//                              Fv(n)   = exact_solution2(xf,yf);
			      }
    			}
      		    }
            }
      
      dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices);

      system.matrix->add_matrix (Ke, dof_indices);
      system.rhs->add_vector    (Fe, dof_indices);
    }
}
コード例 #18
0
ファイル: miscellaneous_ex9.C プロジェクト: dknez/libmesh
void assemble_poisson(EquationSystems & es,
                      const ElementIdMap & lower_to_upper)
{
  const MeshBase & mesh = es.get_mesh();
  const unsigned int dim = mesh.mesh_dimension();

  Real R = es.parameters.get<Real>("R");

  LinearImplicitSystem & system = es.get_system<LinearImplicitSystem>("Poisson");

  const DofMap & dof_map = system.get_dof_map();

  FEType fe_type = dof_map.variable_type(0);

  UniquePtr<FEBase> fe (FEBase::build(dim, fe_type));
  UniquePtr<FEBase> fe_elem_face (FEBase::build(dim, fe_type));
  UniquePtr<FEBase> fe_neighbor_face (FEBase::build(dim, fe_type));

  QGauss qrule (dim, fe_type.default_quadrature_order());
  QGauss qface(dim-1, fe_type.default_quadrature_order());

  fe->attach_quadrature_rule (&qrule);
  fe_elem_face->attach_quadrature_rule (&qface);
  fe_neighbor_face->attach_quadrature_rule (&qface);

  const std::vector<Real> & JxW = fe->get_JxW();
  const std::vector<std::vector<Real> > & phi = fe->get_phi();
  const std::vector<std::vector<RealGradient> > & dphi = fe->get_dphi();

  const std::vector<Real> & JxW_face = fe_elem_face->get_JxW();

  const std::vector<Point> & qface_points = fe_elem_face->get_xyz();

  const std::vector<std::vector<Real> > & phi_face          = fe_elem_face->get_phi();
  const std::vector<std::vector<Real> > & phi_neighbor_face = fe_neighbor_face->get_phi();

  DenseMatrix<Number> Ke;
  DenseVector<Number> Fe;

  DenseMatrix<Number> Kne;
  DenseMatrix<Number> Ken;
  DenseMatrix<Number> Kee;
  DenseMatrix<Number> Knn;

  std::vector<dof_id_type> dof_indices;

  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)
    {
      const Elem * elem = *el;

      dof_map.dof_indices (elem, dof_indices);
      const unsigned int n_dofs = dof_indices.size();

      fe->reinit (elem);

      Ke.resize (n_dofs, n_dofs);
      Fe.resize (n_dofs);

      // Assemble element interior terms for the matrix
      for (unsigned int qp=0; qp<qrule.n_points(); qp++)
        for (unsigned int i=0; i<n_dofs; i++)
          for (unsigned int j=0; j<n_dofs; j++)
            Ke(i,j) += JxW[qp]*(dphi[i][qp]*dphi[j][qp]);

      // Boundary flux provides forcing in this example
      {
        for (unsigned int side=0; side<elem->n_sides(); side++)
          if (elem->neighbor(side) == NULL)
            {
              if (mesh.get_boundary_info().has_boundary_id (elem, side, MIN_Z_BOUNDARY))
                {
                  fe_elem_face->reinit(elem, side);

                  for (unsigned int qp=0; qp<qface.n_points(); qp++)
                    for (unsigned int i=0; i<phi.size(); i++)
                      Fe(i) += JxW_face[qp] * phi_face[i][qp];
                }

            }
      }

      // Add boundary terms on the crack
      {
        for (unsigned int side=0; side<elem->n_sides(); side++)
          if (elem->neighbor(side) == NULL)
            {
              // Found the lower side of the crack. Assemble terms due to lower and upper in here.
              if (mesh.get_boundary_info().has_boundary_id (elem, side, CRACK_BOUNDARY_LOWER))
                {
                  fe_elem_face->reinit(elem, side);

                  ElementIdMap::const_iterator ltu_it =
                    lower_to_upper.find(std::make_pair(elem->id(), side));
                  dof_id_type upper_elem_id = ltu_it->second;
                  const Elem * neighbor = mesh.elem(upper_elem_id);

                  std::vector<Point> qface_neighbor_points;
                  FEInterface::inverse_map (elem->dim(), fe->get_fe_type(),
                                            neighbor, qface_points, qface_neighbor_points);
                  fe_neighbor_face->reinit(neighbor, &qface_neighbor_points);

                  std::vector<dof_id_type> neighbor_dof_indices;
                  dof_map.dof_indices (neighbor, neighbor_dof_indices);
                  const unsigned int n_neighbor_dofs = neighbor_dof_indices.size();

                  Kne.resize (n_neighbor_dofs, n_dofs);
                  Ken.resize (n_dofs, n_neighbor_dofs);
                  Kee.resize (n_dofs, n_dofs);
                  Knn.resize (n_neighbor_dofs, n_neighbor_dofs);

                  // Lower-to-lower coupling term
                  for (unsigned int qp=0; qp<qface.n_points(); qp++)
                    for (unsigned int i=0; i<n_dofs; i++)
                      for (unsigned int j=0; j<n_dofs; j++)
                        Kee(i,j) -= JxW_face[qp] * (1./R)*(phi_face[i][qp] * phi_face[j][qp]);

                  // Lower-to-upper coupling term
                  for (unsigned int qp=0; qp<qface.n_points(); qp++)
                    for (unsigned int i=0; i<n_dofs; i++)
                      for (unsigned int j=0; j<n_neighbor_dofs; j++)
                        Ken(i,j) += JxW_face[qp] * (1./R)*(phi_face[i][qp] * phi_neighbor_face[j][qp]);

                  // Upper-to-upper coupling term
                  for (unsigned int qp=0; qp<qface.n_points(); qp++)
                    for (unsigned int i=0; i<n_neighbor_dofs; i++)
                      for (unsigned int j=0; j<n_neighbor_dofs; j++)
                        Knn(i,j) -= JxW_face[qp] * (1./R)*(phi_neighbor_face[i][qp] * phi_neighbor_face[j][qp]);

                  // Upper-to-lower coupling term
                  for (unsigned int qp=0; qp<qface.n_points(); qp++)
                    for (unsigned int i=0; i<n_neighbor_dofs; i++)
                      for (unsigned int j=0; j<n_dofs; j++)
                        Kne(i,j) += JxW_face[qp] * (1./R)*(phi_neighbor_face[i][qp] * phi_face[j][qp]);

                  system.matrix->add_matrix(Kne, neighbor_dof_indices, dof_indices);
                  system.matrix->add_matrix(Ken, dof_indices, neighbor_dof_indices);
                  system.matrix->add_matrix(Kee, dof_indices);
                  system.matrix->add_matrix(Knn, neighbor_dof_indices);
                }
            }
      }

      dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices);

      system.matrix->add_matrix (Ke, dof_indices);
      system.rhs->add_vector    (Fe, dof_indices);
    }
}
コード例 #19
0
void LinearElasticityWithContact::residual_and_jacobian (
  const NumericVector<Number>& soln,
  NumericVector<Number>* residual,
  SparseMatrix<Number>* jacobian,
  NonlinearImplicitSystem& /*sys*/)
{
  EquationSystems& es = _sys.get_equation_systems();
  const Real young_modulus = es.parameters.get<Real>("young_modulus");
  const Real poisson_ratio = es.parameters.get<Real>("poisson_ratio");
  const Real forcing_magnitude = es.parameters.get<Real>("forcing_magnitude");

  const MeshBase& mesh = _sys.get_mesh();
  const unsigned int dim = mesh.mesh_dimension();

  const unsigned int u_var = _sys.variable_number ("u");

  DofMap& dof_map = _sys.get_dof_map();

  FEType fe_type = dof_map.variable_type(u_var);
  UniquePtr<FEBase> fe (FEBase::build(dim, fe_type));
  QGauss qrule (dim, fe_type.default_quadrature_order());
  fe->attach_quadrature_rule (&qrule);

  UniquePtr<FEBase> fe_face (FEBase::build(dim, fe_type));
  QGauss qface (dim-1, fe_type.default_quadrature_order());
  fe_face->attach_quadrature_rule (&qface);

  UniquePtr<FEBase> fe_neighbor_face (FEBase::build(dim, fe_type));
  fe_neighbor_face->attach_quadrature_rule (&qface);

  const std::vector<Real>& JxW = fe->get_JxW();
  const std::vector<std::vector<Real> >& phi = fe->get_phi();
  const std::vector<std::vector<RealGradient> >& dphi = fe->get_dphi();

  const std::vector<Real>& JxW_face = fe_face->get_JxW();
  const std::vector<std::vector<Real> >& phi_face = fe_face->get_phi();
  const std::vector<Point>& face_normals = fe_face->get_normals();
  const std::vector<Point>& face_xyz = fe_face->get_xyz();

  const std::vector<std::vector<Real> >& phi_neighbor_face = fe_neighbor_face->get_phi();

  // 1. Move mesh_clone based on soln.
  // 2. Compute and store all contact forces.
  // 3. Augment the sparsity pattern.
  {
    UniquePtr<MeshBase> mesh_clone = mesh.clone();
    move_mesh(*mesh_clone, soln);

    _augment_sparsity.clear_contact_element_map();
    clear_contact_data();

    MeshBase::const_element_iterator       el     = mesh_clone->active_elements_begin();
    const MeshBase::const_element_iterator end_el = mesh_clone->active_elements_end();

    for ( ; el != end_el; ++el)
    {
      const Elem* elem = *el;

      for (unsigned int side=0; side<elem->n_sides(); side++)
      {
        if (elem->neighbor(side) == NULL)
        {
          bool on_lower_contact_surface =
            mesh_clone->get_boundary_info().has_boundary_id
                (elem, side, CONTACT_BOUNDARY_LOWER);

          bool on_upper_contact_surface =
            mesh_clone->get_boundary_info().has_boundary_id
                (elem, side, CONTACT_BOUNDARY_UPPER);

          if( on_lower_contact_surface && on_upper_contact_surface )
          {
            libmesh_error_msg("Should not be on both surfaces at the same time");
          }

          if( on_lower_contact_surface || on_upper_contact_surface )
          {
            fe_face->reinit(elem, side);

            // Let's stash xyz and normals because we reinit on other_elem below
            std::vector<Point> face_normals_stashed = fe_face->get_normals();
            std::vector<Point> face_xyz_stashed = fe_face->get_xyz();

            for (unsigned int qp=0; qp<qface.n_points(); qp++)
            {
              Point line_point = face_xyz_stashed[qp];
              Point line_direction = face_normals_stashed[qp];

              // find an element which the line intersects, based on the plane
              // defined by the normal at the centroid of the other element
              bool found_other_elem = false;

              // Note that here we loop over all elements (not just local elements)
              // to be sure we find the appropriate other element.
              MeshBase::const_element_iterator       other_el     = mesh_clone->active_elements_begin();
              const MeshBase::const_element_iterator other_end_el = mesh_clone->active_elements_end();
              for ( ; other_el != other_end_el; ++other_el)
              {
                const Elem* other_elem = *other_el;

                if( other_elem->close_to_point(line_point, _contact_proximity_tol) )
                {
                  for (unsigned int other_side=0; other_side<other_elem->n_sides(); other_side++)
                    if (other_elem->neighbor(other_side) == NULL)
                    {
                      boundary_id_type other_surface_id =
                        on_lower_contact_surface ?
                          CONTACT_BOUNDARY_UPPER : CONTACT_BOUNDARY_LOWER;

                      if( mesh_clone->get_boundary_info().has_boundary_id
                            (other_elem, other_side, other_surface_id) )
                      {
                        UniquePtr<Elem> other_side_elem = other_elem->build_side(other_side);

                        // Define a plane based on the normal at the centroid of other_side_elem
                        // and check where line_point + s * line_direction (s \in R) intersects
                        // this plane.

                        const Point reference_centroid (
                          FEInterface::inverse_map (
                            other_elem->dim(),
                            _sys.get_dof_map().variable_type(0),
                            other_elem,
                            other_side_elem->centroid()));

                        std::vector<Point> reference_centroid_vector;
                        reference_centroid_vector.push_back(reference_centroid);

                        fe_face->reinit(
                          other_elem,
                          other_side,
                          TOLERANCE,
                          &reference_centroid_vector);

                        Point plane_normal = face_normals[0];
                        Point plane_point = face_xyz[0];

                        // line_direction.dot(plane_normal) == 0.0 if the line and plane are
                        // parallel. Ignore this case since it should give zero contact force.
                        if( (line_direction * plane_normal) != 0. )
                        {
                          // The signed distance between the line and the plane
                          Real signed_distance =
                            ( (plane_point - line_point) * plane_normal) /
                              (line_direction * plane_normal);

                          Point intersection_point = line_point + signed_distance * line_direction;

                          // Note that signed_distance = (intersection_point - line_point) dot line_direction
                          // since line_direction is a unit vector.

                          if(other_side_elem->close_to_point(intersection_point, _contains_point_tol))
                          {
                            // If the signed distance is negative then we have overlapping elements
                            // i.e. we have detected contact.
                            if(signed_distance < 0.0)
                            {
                              // We need to store the intersection point, and the element/side
                              // that it belongs to. We can use this to calculate the contact
                              // force later on.

                              std::vector<Point> intersection_point_vec;
                              intersection_point_vec.push_back(intersection_point);
                              std::vector<Point> inverse_intersection_point_vec;

                              FEInterface::inverse_map(
                                other_elem->dim(),
                                fe->get_fe_type(),
                                other_elem,
                                intersection_point_vec,
                                inverse_intersection_point_vec);

                              IntersectionPointData contact_intersection_pt_data(
                                other_elem->id(),
                                other_side,
                                intersection_point,
                                inverse_intersection_point_vec[0],
                                line_point,
                                line_direction);

                              set_contact_data(
                                elem->id(),
                                side,
                                qp,
                                contact_intersection_pt_data);

                              // We also need to keep track of which elements
                              // are coupled in order to augment the sparsity pattern
                              // appropriately later on.
                              _augment_sparsity.add_contact_element(
                                elem->id(),
                                other_elem->id());
                            }

                            // If we've found an element that contains
                            // intersection_point then we're done for
                            // the current quadrature point hence break
                            // out to the next qp.
                            found_other_elem = true;
                            break;
                          }
                        }
                      }
                    }
                }

                if(found_other_elem)
                {
                  break;
                }
              } // end for other_el
            } // end for qp
          } // end if on_contact_surface
        } // end if nieghbor(side_) != NULL
      } // end for side
    } // end for el
  }

  // Clear the Jacobian matrix and reinitialize it so that
  // we get the updated sparsity pattern
  if(jacobian)
  {
    dof_map.clear_sparsity();
    dof_map.compute_sparsity(mesh);

#ifdef LIBMESH_HAVE_PETSC
    PetscMatrix<Number>* petsc_jacobian = cast_ptr<PetscMatrix<Number>*>(jacobian);
    petsc_jacobian->update_preallocation_and_zero();
#else
    libmesh_error();
#endif
  }

  if(residual)
  {
    residual->zero();
  }

  // Do jacobian and residual assembly, including contact forces
  DenseVector<Number> Re;
  DenseSubVector<Number> Re_var[3] =
    {DenseSubVector<Number>(Re), DenseSubVector<Number>(Re), DenseSubVector<Number>(Re)};

  DenseMatrix<Number> Ke;
  DenseSubMatrix<Number> Ke_var[3][3] =
    {
      {DenseSubMatrix<Number>(Ke), DenseSubMatrix<Number>(Ke), DenseSubMatrix<Number>(Ke)},
      {DenseSubMatrix<Number>(Ke), DenseSubMatrix<Number>(Ke), DenseSubMatrix<Number>(Ke)},
      {DenseSubMatrix<Number>(Ke), DenseSubMatrix<Number>(Ke), DenseSubMatrix<Number>(Ke)}
    };

  DenseMatrix<Number> Ke_en;
  DenseSubMatrix<Number> Ke_var_en[3][3] =
    {
      {DenseSubMatrix<Number>(Ke_en), DenseSubMatrix<Number>(Ke_en), DenseSubMatrix<Number>(Ke_en)},
      {DenseSubMatrix<Number>(Ke_en), DenseSubMatrix<Number>(Ke_en), DenseSubMatrix<Number>(Ke_en)},
      {DenseSubMatrix<Number>(Ke_en), DenseSubMatrix<Number>(Ke_en), DenseSubMatrix<Number>(Ke_en)}
    };

  std::vector<dof_id_type> dof_indices;
  std::vector< std::vector<dof_id_type> > dof_indices_var(3);

  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)
  {
    const Elem* elem = *el;

    dof_map.dof_indices (elem, dof_indices);
    for(unsigned int var=0; var<3; var++)
    {
      dof_map.dof_indices (elem, dof_indices_var[var], var);
    }

    const unsigned int n_dofs   = dof_indices.size();
    const unsigned int n_var_dofs = dof_indices_var[0].size();

    fe->reinit (elem);

    Re.resize (n_dofs);
    for(unsigned int var=0; var<3; var++)
    {
      Re_var[var].reposition (var*n_var_dofs, n_var_dofs);
    }

    Ke.resize (n_dofs,n_dofs);
    for(unsigned int var_i=0; var_i<3; var_i++)
      for(unsigned int var_j=0; var_j<3; var_j++)
      {
        Ke_var[var_i][var_j].reposition (var_i*n_var_dofs, var_j*n_var_dofs, n_var_dofs, n_var_dofs);
      }

    for (unsigned int qp=0; qp<qrule.n_points(); qp++)
    {
      DenseMatrix<Number> grad_u(3,3);
      for(unsigned int var_i=0; var_i<3; var_i++)
      {
        for(unsigned int var_j=0; var_j<3; var_j++)
        {
          for (unsigned int j=0; j<n_var_dofs; j++)
          {
            // Row is variable u, v, or w column is x, y, or z
            grad_u(var_i,var_j) += dphi[j][qp](var_j)*soln(dof_indices_var[var_i][j]);
          }
        }
      }

      // - C_ijkl u_k,l v_i,j
      for (unsigned int dof_i=0; dof_i<n_var_dofs; dof_i++)
      {
        for(unsigned int i=0; i<3; i++)
          for(unsigned int j=0; j<3; j++)
            for(unsigned int k=0; k<3; k++)
              for(unsigned int l=0; l<3; l++)
                {
                  Re_var[i](dof_i) -= JxW[qp] *
                    elasticity_tensor(young_modulus,poisson_ratio,i,j,k,l) *
                    grad_u(k,l) * dphi[dof_i][qp](j);
                }
      }

      if( (elem->subdomain_id() == TOP_SUBDOMAIN) )
      {
        // assemble \int_Omega f_i v_i \dx
        DenseVector<Number> f_vec(3);
        f_vec(0) =  forcing_magnitude/10.;
        f_vec(1) =  0.0;
        f_vec(2) = -forcing_magnitude;
        for (unsigned int dof_i=0; dof_i<n_var_dofs; dof_i++)
        {
          for(unsigned int i=0; i<3; i++)
          {
            Re_var[i](dof_i) += JxW[qp] *
              ( f_vec(i) * phi[dof_i][qp] );
          }
        }
      }

      // assemble \int_Omega C_ijkl u_k,l v_i,j \dx
      for (unsigned int dof_i=0; dof_i<n_var_dofs; dof_i++)
        for (unsigned int dof_j=0; dof_j<n_var_dofs; dof_j++)
        {
          for(unsigned int i=0; i<3; i++)
            for(unsigned int j=0; j<3; j++)
              for(unsigned int k=0; k<3; k++)
                for(unsigned int l=0; l<3; l++)
                {
                  Ke_var[i][k](dof_i,dof_j) -= JxW[qp] *
                    elasticity_tensor(young_modulus,poisson_ratio,i,j,k,l) *
                    dphi[dof_j][qp](l) *
                    dphi[dof_i][qp](j);
                }
        }
    }

    // Add contribution due to contact penalty forces
    for (unsigned int side=0; side<elem->n_sides(); side++)
      if (elem->neighbor(side) == NULL)
      {
        bool on_lower_contact_surface =
          mesh.get_boundary_info().has_boundary_id
              (elem, side, CONTACT_BOUNDARY_LOWER);

        bool on_upper_contact_surface =
          mesh.get_boundary_info().has_boundary_id
              (elem, side, CONTACT_BOUNDARY_UPPER);

        if( on_lower_contact_surface && on_upper_contact_surface )
        {
          libmesh_error_msg("Should not be on both surfaces at the same time");
        }

        if( on_lower_contact_surface || on_upper_contact_surface )
        {
          fe_face->reinit(elem, side);
          for (unsigned int qp=0; qp<qface.n_points(); qp++)
          {
            bool contact_detected =
              is_contact_detected(
                elem->id(),
                side,
                qp);

            if(contact_detected)
            {
              IntersectionPointData intersection_pt_data =
                get_contact_data(
                  elem->id(),
                  side,
                  qp);
              Point intersection_point = intersection_pt_data._intersection_point;
              Point line_point = intersection_pt_data._line_point;
              Point line_direction = intersection_pt_data._line_direction;

              // signed_distance = (intersection_point - line_point) dot line_direction,
              // hence we use this to get the contact force
              Real contact_force =
                get_contact_penalty() *
                ( (intersection_point - line_point) * line_direction );

              for (unsigned int dof_i=0; dof_i<n_var_dofs; dof_i++)
              {
                for(unsigned int i=0; i<3; i++)
                {
                  Re_var[i](dof_i) += JxW_face[qp] *
                    ( contact_force * face_normals[qp](i) * phi_face[dof_i][qp] );
                }
              }

              // Differentiate contact_force wrt solution coefficients to get
              // the Jacobian entries.
              //
              // Note that intersection_point and line_point
              // are linear functions of the solution.
              //
              // Also, line_direction is a function of the solution, but let's
              // neglect that for now to make it easier to get the Jacobian.
              // This is probably fine anyway, since this approximation will
              // have negligible effect as we approach convergence.

              // dofs local to this element, due to differentiating line_point
              for (unsigned int dof_i=0; dof_i<n_var_dofs; dof_i++)
                for (unsigned int dof_j=0; dof_j<n_var_dofs; dof_j++)
                {
                  for(unsigned int i=0; i<3; i++)
                    for(unsigned int j=0; j<3; j++)
                    {
                      Ke_var[i][j](dof_i,dof_j) += JxW_face[qp] *
                        ( get_contact_penalty() * (-phi_face[dof_j][qp] * line_direction(j)) *
                           face_normals[qp](i) * phi_face[dof_i][qp] );
                    }
                }

              // contribution due to dofs on the remote element, due to
              // differentiating intersection_point
              {
                dof_id_type neighbor_elem_id = intersection_pt_data._neighbor_element_id;
                const Elem* contact_neighbor = mesh.elem(neighbor_elem_id);

                unsigned char neighbor_side_index = intersection_pt_data._neighbor_side_index;

                std::vector<Point> inverse_intersection_point_vec;
                inverse_intersection_point_vec.push_back(
                  intersection_pt_data._inverse_mapped_intersection_point);

                fe_neighbor_face->reinit(
                  contact_neighbor,
                  neighbor_side_index,
                  TOLERANCE,
                  &inverse_intersection_point_vec);

                std::vector<dof_id_type> neighbor_dof_indices;
                std::vector< std::vector<unsigned int> > neighbor_dof_indices_var(3);
                dof_map.dof_indices (contact_neighbor, neighbor_dof_indices);
                for(unsigned int var=0; var<3; var++)
                {
                  dof_map.dof_indices (contact_neighbor, neighbor_dof_indices_var[var], var);
                }
                const unsigned int n_neighbor_dofs = neighbor_dof_indices.size();
                const unsigned int n_neighbor_var_dofs = neighbor_dof_indices_var[0].size();

                Ke_en.resize (n_dofs,n_neighbor_dofs);
                for(unsigned int var_i=0; var_i<3; var_i++)
                  for(unsigned int var_j=0; var_j<3; var_j++)
                  {
                    Ke_var_en[var_i][var_j].reposition(
                      var_i*n_var_dofs,
                      var_j*n_neighbor_var_dofs,
                      n_var_dofs,
                      n_neighbor_var_dofs);
                  }

                for (unsigned int dof_i=0; dof_i<n_var_dofs; dof_i++)
                  for (unsigned int dof_j=0; dof_j<n_neighbor_var_dofs; dof_j++)
                  {
                    for(unsigned int i=0; i<3; i++)
                      for(unsigned int j=0; j<3; j++)
                      {
                        Ke_var_en[i][j](dof_i,dof_j) += JxW_face[qp] *
                          ( get_contact_penalty() * (phi_neighbor_face[dof_j][0] * line_direction(j)) *
                            face_normals[qp](i) * phi_face[dof_i][qp] );
                      }
                  }

                if(jacobian)
                {
                  jacobian->add_matrix(Ke_en,dof_indices,neighbor_dof_indices);
                }
              }

            }

          }
        }
      }

    dof_map.constrain_element_matrix_and_vector (Ke, Re, dof_indices);

    if(jacobian)
    {
      jacobian->add_matrix (Ke, dof_indices);
    }

    if(residual)
    {
      residual->add_vector (Re, dof_indices);
    }
  }

}
コード例 #20
0
ファイル: transient_ex2.C プロジェクト: YSB330/libmesh
// This function assembles the system matrix and right-hand-side
// for our wave equation.
void assemble_wave(EquationSystems & es,
                   const std::string & system_name)
{
  // It is a good idea to make sure we are assembling
  // the proper system.
  libmesh_assert_equal_to (system_name, "Wave");

  // Get a constant reference to the mesh object.
  const MeshBase & mesh = es.get_mesh();

  // The dimension that we are running.
  const unsigned int dim = mesh.mesh_dimension();

  // Copy the speed of sound and fluid density
  // to a local variable.
  const Real speed = es.parameters.get<Real>("speed");
  const Real rho   = es.parameters.get<Real>("fluid density");

  // Get a reference to our system, as before.
  NewmarkSystem & t_system = es.get_system<NewmarkSystem> (system_name);

  // Get a constant reference to the Finite Element type
  // for the first (and only) variable in the system.
  FEType fe_type = t_system.get_dof_map().variable_type(0);

  // In here, we will add the element matrices to the
  // @e additional matrices "stiffness_mass" and "damping"
  // and the additional vector "force", not to the members
  // "matrix" and "rhs".  Therefore, get writable
  // references to them.
  SparseMatrix<Number> & stiffness = t_system.get_matrix("stiffness");
  SparseMatrix<Number> & damping   = t_system.get_matrix("damping");
  SparseMatrix<Number> & mass      = t_system.get_matrix("mass");
  NumericVector<Number> & force    = t_system.get_vector("force");

  // Some solver packages (PETSc) are especially picky about
  // allocating sparsity structure and truly assigning values
  // to this structure.  Namely, matrix additions, as performed
  // later, exhibit acceptable performance only for identical
  // sparsity structures.  Therefore, explicitly zero the
  // values in the collective matrix, so that matrix additions
  // encounter identical sparsity structures.
  SparseMatrix<Number> & matrix = *t_system.matrix;
  DenseMatrix<Number> zero_matrix;

  // Build a Finite Element object of the specified type.  Since the
  // \p FEBase::build() member dynamically creates memory we will
  // store the object as an \p UniquePtr<FEBase>.  This can be thought
  // of as a pointer that will clean up after itself.
  UniquePtr<FEBase> fe (FEBase::build(dim, fe_type));

  // A 2nd order Gauss quadrature rule for numerical integration.
  QGauss qrule (dim, SECOND);

  // Tell the finite element object to use our quadrature rule.
  fe->attach_quadrature_rule (&qrule);

  // The element Jacobian * quadrature weight at each integration point.
  const std::vector<Real> & JxW = fe->get_JxW();

  // The element shape functions evaluated at the quadrature points.
  const std::vector<std::vector<Real> > & phi = fe->get_phi();

  // The element shape function gradients evaluated at the quadrature
  // points.
  const std::vector<std::vector<RealGradient> > & dphi = fe->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.
  const DofMap & dof_map = t_system.get_dof_map();

  // The element mass, damping and stiffness matrices
  // and the element contribution to the rhs.
  DenseMatrix<Number> Ke, Ce, Me;
  DenseVector<Number> 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<dof_id_type> dof_indices;

  // Now we will loop over all the elements in the mesh.
  // We will compute the element matrix and right-hand-side
  // contribution.
  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);

      // 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->reinit (elem);

      // Zero the element matrices and rhs 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 HEX8
      // and now have a PRISM6).
      {
        const unsigned int n_dof_indices = dof_indices.size();

        Ke.resize          (n_dof_indices, n_dof_indices);
        Ce.resize          (n_dof_indices, n_dof_indices);
        Me.resize          (n_dof_indices, n_dof_indices);
        zero_matrix.resize (n_dof_indices, n_dof_indices);
        Fe.resize          (n_dof_indices);
      }

      // Now loop over the quadrature points.  This handles
      // the numeric integration.
      for (unsigned int qp=0; qp<qrule.n_points(); qp++)
        {
          // Now we will build the element matrix.  This involves
          // a double loop to integrate the test funcions (i) against
          // the trial functions (j).
          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]);
                Me(i,j) += JxW[qp]*phi[i][qp]*phi[j][qp]
                  *1./(speed*speed);
              } // end of the matrix summation loop
        } // end of quadrature point loop

      // Now compute the contribution to the element matrix and the
      // right-hand-side vector if the current element lies on the
      // boundary.
      {
        // In this example no natural boundary conditions will
        // be considered.  The code is left here so it can easily
        // be extended.
        //
        // don't do this for any side
        for (unsigned int side=0; side<elem->n_sides(); side++)
          if (!true)
            // if (elem->neighbor(side) == libmesh_nullptr)
            {
              // Declare a special finite element object for
              // boundary integration.
              UniquePtr<FEBase> fe_face (FEBase::build(dim, fe_type));

              // Boundary integration requires one quadraure rule,
              // with dimensionality one less than the dimensionality
              // of the element.
              QGauss qface(dim-1, SECOND);

              // Tell the finte element object to use our
              // quadrature rule.
              fe_face->attach_quadrature_rule (&qface);

              // The value of the shape functions at the quadrature
              // points.
              const std::vector<std::vector<Real> > &  phi_face = fe_face->get_phi();

              // The Jacobian * Quadrature Weight at the quadrature
              // points on the face.
              const std::vector<Real> & JxW_face = fe_face->get_JxW();

              // Compute the shape function values on the element
              // face.
              fe_face->reinit(elem, side);

              // Here we consider a normal acceleration acc_n=1 applied to
              // the whole boundary of our mesh.
              const Real acc_n_value = 1.0;

              // Loop over the face quadrature points for integration.
              for (unsigned int qp=0; qp<qface.n_points(); qp++)
                {
                  // Right-hand-side contribution due to prescribed
                  // normal acceleration.
                  for (unsigned int i=0; i<phi_face.size(); i++)
                    {
                      Fe(i) += acc_n_value*rho
                        *phi_face[i][qp]*JxW_face[qp];
                    }
                } // end face quadrature point loop
            } // end if (elem->neighbor(side) == libmesh_nullptr)

        // In this example the Dirichlet boundary conditions will be
        // imposed via panalty method after the
        // system is assembled.

      } // end boundary condition section

      // If this assembly program were to be used on an adaptive mesh,
      // we would have to apply any hanging node constraint equations
      // by uncommenting the following lines:
      // std::vector<unsigned int> dof_indicesC = dof_indices;
      // std::vector<unsigned int> dof_indicesM = dof_indices;
      // dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices);
      // dof_map.constrain_element_matrix (Ce, dof_indicesC);
      // dof_map.constrain_element_matrix (Me, dof_indicesM);

      // Finally, simply add the contributions to the additional
      // matrices and vector.
      stiffness.add_matrix (Ke, dof_indices);
      damping.add_matrix   (Ce, dof_indices);
      mass.add_matrix      (Me, dof_indices);

      force.add_vector     (Fe, dof_indices);

      // For the overall matrix, explicitly zero the entries where
      // we added values in the other ones, so that we have
      // identical sparsity footprints.
      matrix.add_matrix(zero_matrix, dof_indices);

    } // end of element loop
}
コード例 #21
0
ファイル: adaptivity_ex2.C プロジェクト: dknez/libmesh
// This function defines the assembly routine which
// will be called at each time step.  It is responsible
// for computing the proper matrix entries for the
// element stiffness matrices and right-hand sides.
void assemble_cd (EquationSystems & es,
                  const std::string & system_name)
{
#ifdef LIBMESH_ENABLE_AMR
  // It is a good idea to make sure we are assembling
  // the proper system.
  libmesh_assert_equal_to (system_name, "Convection-Diffusion");

  // Get a constant reference to the mesh object.
  const MeshBase & mesh = es.get_mesh();

  // The dimension that we are running
  const unsigned int dim = mesh.mesh_dimension();

  // Get a reference to the Convection-Diffusion system object.
  TransientLinearImplicitSystem & system =
    es.get_system<TransientLinearImplicitSystem> ("Convection-Diffusion");

  // Get the Finite Element type for the first (and only)
  // variable in the system.
  FEType fe_type = system.variable_type(0);

  // Build a Finite Element object of the specified type.  Since the
  // \p FEBase::build() member dynamically creates memory we will
  // store the object as an \p UniquePtr<FEBase>.  This can be thought
  // of as a pointer that will clean up after itself.
  UniquePtr<FEBase> fe      (FEBase::build(dim, fe_type));
  UniquePtr<FEBase> fe_face (FEBase::build(dim, fe_type));

  // A Gauss quadrature rule for numerical integration.
  // Let the \p FEType object decide what order rule is appropriate.
  QGauss qrule (dim,   fe_type.default_quadrature_order());
  QGauss qface (dim-1, fe_type.default_quadrature_order());

  // Tell the finite element object to use our quadrature rule.
  fe->attach_quadrature_rule      (&qrule);
  fe_face->attach_quadrature_rule (&qface);

  // Here we define some references to cell-specific data that
  // will be used to assemble the linear system.  We will start
  // with the element Jacobian * quadrature weight at each integration point.
  const std::vector<Real> & JxW      = fe->get_JxW();
  const std::vector<Real> & JxW_face = fe_face->get_JxW();

  // The element shape functions evaluated at the quadrature points.
  const std::vector<std::vector<Real> > & phi = fe->get_phi();
  const std::vector<std::vector<Real> > & psi = fe_face->get_phi();

  // The element shape function gradients evaluated at the quadrature
  // points.
  const std::vector<std::vector<RealGradient> > & dphi = fe->get_dphi();

  // The XY locations of the quadrature points used for face integration
  const std::vector<Point> & qface_points = fe_face->get_xyz();

  // 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 = 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;

  // 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<dof_id_type> dof_indices;

  // Here we extract the velocity & parameters that we put in the
  // EquationSystems object.
  const RealVectorValue velocity =
    es.parameters.get<RealVectorValue> ("velocity");

  const Real diffusivity =
    es.parameters.get<Real> ("diffusivity");

  const Real dt = es.parameters.get<Real> ("dt");

  // 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);

      // 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->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 (dof_indices.size(),
                 dof_indices.size());

      Fe.resize (dof_indices.size());

      // 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 myst 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 old solution & its gradient.
          Number   u_old = 0.;
          Gradient grad_u_old;

          // Compute the old solution & its gradient.
          for (unsigned int l=0; l<phi.size(); l++)
            {
              u_old += phi[l][qp]*system.old_solution (dof_indices[l]);

              // This will work,
              // grad_u_old += dphi[l][qp]*system.old_solution (dof_indices[l]);
              // but we can do it without creating a temporary like this:
              grad_u_old.add_scaled (dphi[l][qp], system.old_solution (dof_indices[l]));
            }

          // Now compute the element matrix and RHS contributions.
          for (unsigned int i=0; i<phi.size(); i++)
            {
              // The RHS contribution
              Fe(i) += JxW[qp]*(
                                // Mass matrix term
                                u_old*phi[i][qp] +
                                -.5*dt*(
                                        // Convection term
                                        // (grad_u_old may be complex, so the
                                        // order here is important!)
                                        (grad_u_old*velocity)*phi[i][qp] +

                                        // Diffusion term
                                        diffusivity*(grad_u_old*dphi[i][qp]))
                                );

              for (unsigned int j=0; j<phi.size(); j++)
                {
                  // The matrix contribution
                  Ke(i,j) += JxW[qp]*(
                                      // Mass-matrix
                                      phi[i][qp]*phi[j][qp] +
                                      .5*dt*(
                                             // Convection term
                                             (velocity*dphi[j][qp])*phi[i][qp] +
                                             // Diffusion term
                                             diffusivity*(dphi[i][qp]*dphi[j][qp]))
                                      );
                }
            }
        }

      // 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 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.
      {
        // The penalty value.
        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)
            {
              fe_face->reinit(elem, s);

              for (unsigned int qp=0; qp<qface.n_points(); qp++)
                {
                  const Number value = exact_solution (qface_points[qp](0),
                                                       qface_points[qp](1),
                                                       system.time);

                  // RHS contribution
                  for (unsigned int i=0; i<psi.size(); i++)
                    Fe(i) += penalty*JxW_face[qp]*value*psi[i][qp];

                  // Matrix contribution
                  for (unsigned int i=0; i<psi.size(); i++)
                    for (unsigned int j=0; j<psi.size(); j++)
                      Ke(i,j) += penalty*JxW_face[qp]*psi[i][qp]*psi[j][qp];
                }
            }
      }


      // We have now built the element matrix and RHS vector in terms
      // of the element degrees of freedom.  However, it is possible
      // that some of the element DOFs are constrained to enforce
      // solution continuity, i.e. they are not really "free".  We need
      // to constrain those DOFs in terms of non-constrained DOFs to
      // ensure a continuous solution.  The
      // \p DofMap::constrain_element_matrix_and_vector() method does
      // just that.
      dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices);

      // 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 SparseMatrix::add_matrix()
      // and \p NumericVector::add_vector() members do this for us.
      system.matrix->add_matrix (Ke, dof_indices);
      system.rhs->add_vector    (Fe, dof_indices);

    }
  // Finished computing the sytem matrix and right-hand side.
#endif // #ifdef LIBMESH_ENABLE_AMR
}
コード例 #22
0
// Here we define the matrix assembly routine for
// the Helmholtz system.  This function will be
// called to form the stiffness matrix and right-hand side.
void assemble_helmholtz(EquationSystems & es,
                        const std::string & system_name)
{

  // It is a good idea to make sure we are assembling
  // the proper system.
  libmesh_assert_equal_to (system_name, "Helmholtz");

  // Get a constant reference to the mesh object.
  const MeshBase & mesh = es.get_mesh();

  // The dimension that we are in
  const unsigned int dim = mesh.mesh_dimension();

  // Get a reference to our system, as before
  FrequencySystem & f_system =
    es.get_system<FrequencySystem> (system_name);

  // A const reference to the DofMap object for this system.  The DofMap
  // object handles the index translation from node and element numbers
  // to degree of freedom numbers.
  const DofMap & dof_map = f_system.get_dof_map();

  // Get a constant reference to the Finite Element type
  // for the first (and only) variable in the system.
  const FEType & fe_type = dof_map.variable_type(0);

  // For the admittance boundary condition,
  // get the fluid density
  const Real rho = es.parameters.get<Real>("rho");

  // In here, we will add the element matrices to the
  // <i>additional</i> matrices "stiffness_mass", "damping",
  // and the additional vector "rhs", not to the members
  // "matrix" and "rhs".  Therefore, get writable
  // references to them
  SparseMatrix<Number> & stiffness = f_system.get_matrix("stiffness");
  SparseMatrix<Number> & damping = f_system.get_matrix("damping");
  SparseMatrix<Number> & mass = f_system.get_matrix("mass");
  NumericVector<Number> & freq_indep_rhs = f_system.get_vector("rhs");

  // Some solver packages (PETSc) are especially picky about
  // allocating sparsity structure and truly assigning values
  // to this structure.  Namely, matrix additions, as performed
  // later, exhibit acceptable performance only for identical
  // sparsity structures.  Therefore, explicitly zero the
  // values in the collective matrix, so that matrix additions
  // encounter identical sparsity structures.
  SparseMatrix<Number> & matrix = *f_system.matrix;

  // ------------------------------------------------------------------
  // Finite Element related stuff
  //
  // Build a Finite Element object of the specified type.  Since the
  // FEBase::build() member dynamically creates memory we will
  // store the object as a UniquePtr<FEBase>.  This can be thought
  // of as a pointer that will clean up after itself.
  UniquePtr<FEBase> fe (FEBase::build(dim, fe_type));

  // A 5th order Gauss quadrature rule for numerical integration.
  QGauss qrule (dim, FIFTH);

  // Tell the finite element object to use our quadrature rule.
  fe->attach_quadrature_rule (&qrule);

  // The element Jacobian// quadrature weight at each integration point.
  const std::vector<Real> & JxW = fe->get_JxW();

  // The element shape functions evaluated at the quadrature points.
  const std::vector<std::vector<Real> > & phi = fe->get_phi();

  // The element shape function gradients evaluated at the quadrature
  // points.
  const std::vector<std::vector<RealGradient> > & dphi = fe->get_dphi();

  // Now this is slightly different from example 4.
  // We will not add directly to the global matrix,
  // but to the additional matrices "stiffness_mass" and "damping".
  // The same holds for the right-hand-side vector Fe, which we will
  // later on store in the additional vector "rhs".
  // The zero_matrix is used to explicitly induce the same sparsity
  // structure in the overall matrix.
  // see later on. (At least) the mass, and stiffness matrices, however,
  // are inherently real.  Therefore, store these as one complex
  // matrix.  This will definitely save memory.
  DenseMatrix<Number> Ke, Ce, Me, zero_matrix;
  DenseVector<Number> 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<dof_id_type> dof_indices;

  // Now we will loop over all the elements in the mesh.
  // We will compute the element matrix and right-hand-side
  // contribution.

  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)
    {
      // Start logging the element initialization.
      START_LOG("elem init", "assemble_helmholtz");

      // 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);

      // 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->reinit (elem);

      // Zero & resize the element matrix and right-hand side before
      // summing them, with different element types in the mesh this
      // is quite necessary.
      {
        const unsigned int n_dof_indices = dof_indices.size();

        Ke.resize          (n_dof_indices, n_dof_indices);
        Ce.resize          (n_dof_indices, n_dof_indices);
        Me.resize          (n_dof_indices, n_dof_indices);
        zero_matrix.resize (n_dof_indices, n_dof_indices);
        Fe.resize          (n_dof_indices);
      }

      // Stop logging the element initialization.
      STOP_LOG("elem init", "assemble_helmholtz");

      // Now loop over the quadrature points.  This handles
      // the numeric integration.
      START_LOG("stiffness & mass", "assemble_helmholtz");

      for (unsigned int qp=0; qp<qrule.n_points(); qp++)
        {
          // Now we will build the element matrix.  This involves
          // a double loop to integrate the test funcions (i) against
          // the trial functions (j).  Note the braces on the rhs
          // of Ke(i,j): these are quite necessary to finally compute
          // Real*(Point*Point) = Real, and not something else...
          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]);
                Me(i,j) += JxW[qp]*(phi[i][qp]*phi[j][qp]);
              }
        }

      STOP_LOG("stiffness & mass", "assemble_helmholtz");

      // Now compute the contribution to the element matrix
      // (due to mixed boundary conditions) if the current
      // element lies on the boundary.
      //
      // 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 side=0; side<elem->n_sides(); side++)
        if (elem->neighbor(side) == libmesh_nullptr)
          {
            LOG_SCOPE("damping", "assemble_helmholtz");

            // Declare a special finite element object for
            // boundary integration.
            UniquePtr<FEBase> fe_face (FEBase::build(dim, fe_type));

            // Boundary integration requires one quadraure rule,
            // with dimensionality one less than the dimensionality
            // of the element.
            QGauss qface(dim-1, SECOND);

            // Tell the finte element object to use our
            // quadrature rule.
            fe_face->attach_quadrature_rule (&qface);

            // The value of the shape functions at the quadrature
            // points.
            const std::vector<std::vector<Real> > & phi_face =
              fe_face->get_phi();

            // The Jacobian// Quadrature Weight at the quadrature
            // points on the face.
            const std::vector<Real> & JxW_face = fe_face->get_JxW();

            // Compute the shape function values on the element
            // face.
            fe_face->reinit(elem, side);

            // For the Robin BCs consider a normal admittance an=1
            // at some parts of the bounfdary
            const Real an_value = 1.;

            // Loop over the face quadrature points for integration.
            for (unsigned int qp=0; qp<qface.n_points(); qp++)
              {

                // Element matrix contributrion due to precribed
                // admittance boundary conditions.
                for (unsigned int i=0; i<phi_face.size(); i++)
                  for (unsigned int j=0; j<phi_face.size(); j++)
                    Ce(i,j) += rho*an_value*JxW_face[qp]*phi_face[i][qp]*phi_face[j][qp];
              }
          }

      // If this assembly program were to be used on an adaptive mesh,
      // we would have to apply any hanging node constraint equations
      // by uncommenting the following lines:
      // std::vector<unsigned int> dof_indicesC = dof_indices;
      // std::vector<unsigned int> dof_indicesM = dof_indices;
      // dof_map.constrain_element_matrix (Ke, dof_indices);
      // dof_map.constrain_element_matrix (Ce, dof_indicesC);
      // dof_map.constrain_element_matrix (Me, dof_indicesM);


      // Finally, simply add the contributions to the additional
      // matrices and vector.
      stiffness.add_matrix (Ke, dof_indices);
      damping.add_matrix (Ce, dof_indices);
      mass.add_matrix (Me, dof_indices);

      // For the overall matrix, explicitly zero the entries where
      // we added values in the other ones, so that we have
      // identical sparsity footprints.
      matrix.add_matrix(zero_matrix, dof_indices);

    } // loop el


  // It now remains to compute the rhs. Here, we simply
  // get the normal velocities values on the boundary from the
  // mesh data.
  {
    LOG_SCOPE("rhs", "assemble_helmholtz");

    // get a reference to the mesh data.
    const MeshData & mesh_data = es.get_mesh_data();

    // We will now loop over all nodes. In case nodal data
    // for a certain node is available in the MeshData, we simply
    // adopt the corresponding value for the rhs vector.
    // Note that normal data was given in the mesh data file,
    // i.e. one value per node
    libmesh_assert_equal_to (mesh_data.n_val_per_node(), 1);

    MeshBase::const_node_iterator       node_it  = mesh.nodes_begin();
    const MeshBase::const_node_iterator node_end = mesh.nodes_end();

    for ( ; node_it != node_end; ++node_it)
      {
        // the current node pointer
        const Node * node = *node_it;

        // check if the mesh data has data for the current node
        // and do for all components
        if (mesh_data.has_data(node))
          for (unsigned int comp=0; comp<node->n_comp(0, 0); comp++)
            {
              // the dof number
              unsigned int dn = node->dof_number(0, 0, comp);

              // set the nodal value
              freq_indep_rhs.set(dn, mesh_data.get_data(node)[0]);
            }
      }
  }

  // All done!
}
コード例 #23
0
ファイル: miscellaneous_ex4.C プロジェクト: kerstipj/libmesh
// This function defines the assembly routine.  It is responsible for
// computing the proper matrix entries for the element stiffness
// matrices and right-hand sides.
void assemble (EquationSystems & es,
               const std::string & system_name)
{
#ifdef LIBMESH_ENABLE_AMR
  // It is a good idea to make sure we are assembling
  // the proper system.
  libmesh_assert_equal_to (system_name, "System");

  // Get a constant reference to the mesh object.
  const MeshBase & mesh = es.get_mesh();

  // The dimension that we are running
  const unsigned int dim = mesh.mesh_dimension();

  // Get a reference to the Convection-Diffusion system object.
  LinearImplicitSystem & system =
    es.get_system<LinearImplicitSystem> ("System");

  // Get the Finite Element type for the first (and only)
  // variable in the system.
  FEType fe_type = system.variable_type(0);

  // Build a Finite Element object of the specified type.  Since the
  // FEBase::build() member dynamically creates memory we will
  // store the object as a UniquePtr<FEBase>.  This can be thought
  // of as a pointer that will clean up after itself.
  UniquePtr<FEBase> fe      (FEBase::build(dim, fe_type));
  UniquePtr<FEBase> fe_face (FEBase::build(dim, fe_type));

  // A Gauss quadrature rule for numerical integration.
  // Let the FEType object decide what order rule is appropriate.
  QGauss qrule (dim,   fe_type.default_quadrature_order());
  QGauss qface (dim-1, fe_type.default_quadrature_order());

  // Tell the finite element object to use our quadrature rule.
  fe->attach_quadrature_rule      (&qrule);
  fe_face->attach_quadrature_rule (&qface);

  // Here we define some references to cell-specific data that
  // will be used to assemble the linear system.  We will start
  // with the element Jacobian * quadrature weight at each integration point.
  const std::vector<Real> & JxW      = fe->get_JxW();
  const std::vector<Real> & JxW_face = fe_face->get_JxW();

  // The element shape functions evaluated at the quadrature points.
  const std::vector<std::vector<Real> > & phi = fe->get_phi();
  const std::vector<std::vector<Real> > & psi = fe_face->get_phi();

  // The element shape function gradients evaluated at the quadrature
  // points.
  const std::vector<std::vector<RealGradient> > & dphi = fe->get_dphi();

  // The XY locations of the quadrature points used for face integration
  //const std::vector<Point>& qface_points = fe_face->get_xyz();

  // A reference to the DofMap object for this system.  The DofMap
  // object handles the index translation from node and element numbers
  // to degree of freedom numbers.  We will talk more about the DofMap
  // in future examples.
  const DofMap & dof_map = 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;

  // Analogous data structures for thw two vectors v and w that form
  // the tensor shell matrix.
  DenseVector<Number> Ve;
  DenseVector<Number> We;

  // 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<dof_id_type> dof_indices;

  // 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 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);

      // 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->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 (dof_indices.size(),
                 dof_indices.size());

      Fe.resize (dof_indices.size());
      Ve.resize (dof_indices.size());
      We.resize (dof_indices.size());

      // 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 myst 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++)
        {
          // Now compute the element matrix and RHS contributions.
          for (unsigned int i=0; i<phi.size(); i++)
            {
              // The RHS contribution
              Fe(i) += JxW[qp]*phi[i][qp];

              for (unsigned int j=0; j<phi.size(); j++)
                {
                  // The matrix contribution
                  Ke(i,j) += JxW[qp]*(
                                      // Stiffness matrix
                                      (dphi[i][qp]*dphi[j][qp])
                                      );
                }

              // V and W are the same for this example.
              Ve(i) += JxW[qp]*phi[i][qp];
              We(i) += JxW[qp]*phi[i][qp];
            }
        }

      // 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 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.
      {
        // The penalty value.
        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) == libmesh_nullptr)
            {
              fe_face->reinit(elem, s);

              for (unsigned int qp=0; qp<qface.n_points(); qp++)
                {
                  // Matrix contribution
                  for (unsigned int i=0; i<psi.size(); i++)
                    for (unsigned int j=0; j<psi.size(); j++)
                      Ke(i,j) += penalty*JxW_face[qp]*psi[i][qp]*psi[j][qp];
                }
            }
      }


      // We have now built the element matrix and RHS vector in terms
      // of the element degrees of freedom.  However, it is possible
      // that some of the element DOFs are constrained to enforce
      // solution continuity, i.e. they are not really "free".  We need
      // to constrain those DOFs in terms of non-constrained DOFs to
      // ensure a continuous solution.  The
      // DofMap::constrain_element_matrix_and_vector() method does
      // just that.

      // However, constraining both the sparse matrix (and right hand
      // side) plus the rank 1 matrix is tricky.  The dof_indices
      // vector has to be backuped for that because the constraining
      // functions modify it.

      std::vector<dof_id_type> dof_indices_backup(dof_indices);
      dof_map.constrain_element_matrix_and_vector (Ke, Fe, dof_indices);
      dof_indices = dof_indices_backup;
      dof_map.constrain_element_dyad_matrix(Ve, We, dof_indices);

      // 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 SparseMatrix::add_matrix()
      // and NumericVector::add_vector() members do this for us.
      system.matrix->add_matrix (Ke, dof_indices);
      system.get_matrix("Preconditioner").add_matrix (Ke, dof_indices);
      system.rhs->add_vector (Fe, dof_indices);
      system.get_vector("v").add_vector(Ve, dof_indices);
      system.get_vector("w").add_vector(We, dof_indices);
    }
  // Finished computing the sytem matrix and right-hand side.

  // Matrices and vectors must be closed manually.  This is necessary
  // because the matrix is not directly used as the system matrix (in
  // which case the solver closes it) but as a part of a shell matrix.
  system.matrix->close();
  system.get_matrix("Preconditioner").close();
  system.rhs->close();
  system.get_vector("v").close();
  system.get_vector("w").close();

#endif // #ifdef LIBMESH_ENABLE_AMR
}