Real FE<2,L2_HIERARCHIC>::shape(const Elem * elem,
                                const Order order,
                                const unsigned int i,
                                const Point & p)
{
  libmesh_assert(elem);

  const Order totalorder = static_cast<Order>(order+elem->p_level());
  libmesh_assert_greater (totalorder, 0);

  switch (elem->type())
    {
    case TRI3:
    case TRI6:
      {
        const Real zeta1 = p(0);
        const Real zeta2 = p(1);
        const Real zeta0 = 1. - zeta1 - zeta2;

        libmesh_assert_less (i, (totalorder+1u)*(totalorder+2u)/2);
        libmesh_assert (elem->type() == TRI6 || totalorder < 2);

        // Vertex DoFs
        if (i == 0)
          return zeta0;
        else if (i == 1)
          return zeta1;
        else if (i == 2)
          return zeta2;
        // Edge DoFs
        else if (i < totalorder + 2u)
          {
            // Avoid returning NaN on vertices!
            if (zeta0 + zeta1 == 0.)
              return 0.;

            const unsigned int basisorder = i - 1;
            // Get factors to account for edge-flipping
            Real f0 = 1;
            if (basisorder%2 && (elem->point(0) > elem->point(1)))
              f0 = -1.;

            Real edgeval = (zeta1 - zeta0) / (zeta1 + zeta0);
            Real crossfunc = zeta0 + zeta1;
            for (unsigned int n=1; n != basisorder; ++n)
              crossfunc *= (zeta0 + zeta1);

            return f0 * crossfunc *
              FE<1,L2_HIERARCHIC>::shape(EDGE3, totalorder,
                                         basisorder, edgeval);
          }
        else if (i < 2u*totalorder + 1)
          {
            // Avoid returning NaN on vertices!
            if (zeta1 + zeta2 == 0.)
              return 0.;

            const unsigned int basisorder = i - totalorder;
            // Get factors to account for edge-flipping
            Real f1 = 1;
            if (basisorder%2 && (elem->point(1) > elem->point(2)))
              f1 = -1.;

            Real edgeval = (zeta2 - zeta1) / (zeta2 + zeta1);
            Real crossfunc = zeta2 + zeta1;
            for (unsigned int n=1; n != basisorder; ++n)
              crossfunc *= (zeta2 + zeta1);

            return f1 * crossfunc *
              FE<1,L2_HIERARCHIC>::shape(EDGE3, totalorder,
                                         basisorder, edgeval);
          }
        else if (i < 3u*totalorder)
          {
            // Avoid returning NaN on vertices!
            if (zeta0 + zeta2 == 0.)
              return 0.;

            const unsigned int basisorder = i - (2u*totalorder) + 1;
            // Get factors to account for edge-flipping
            Real f2 = 1;
            if (basisorder%2 && (elem->point(2) > elem->point(0)))
              f2 = -1.;

            Real edgeval = (zeta0 - zeta2) / (zeta0 + zeta2);
            Real crossfunc = zeta0 + zeta2;
            for (unsigned int n=1; n != basisorder; ++n)
              crossfunc *= (zeta0 + zeta2);

            return f2 * crossfunc *
              FE<1,L2_HIERARCHIC>::shape(EDGE3, totalorder,
                                         basisorder, edgeval);
          }
        // Interior DoFs
        else
          {
            const unsigned int basisnum = i - (3u*totalorder);
            unsigned int exp0 = triangular_number_column[basisnum] + 1;
            unsigned int exp1 = triangular_number_row[basisnum] + 1 -
              triangular_number_column[basisnum];

            Real returnval = 1;
            for (unsigned int n = 0; n != exp0; ++n)
              returnval *= zeta0;
            for (unsigned int n = 0; n != exp1; ++n)
              returnval *= zeta1;
            returnval *= zeta2;
            return returnval;
          }
      }

      // Hierarchic shape functions on the quadrilateral.
    case QUAD4:
      libmesh_assert_less (totalorder, 2);
    case QUAD8:
    case QUAD9:
      {
        // Compute quad shape functions as a tensor-product
        const Real xi  = p(0);
        const Real eta = p(1);

        libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u));

        // Example i, i0, i1 values for totalorder = 5:
        //                                    0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
        //  static const unsigned int i0[] = {0, 1, 1, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 0, 0, 0, 0, 2, 3, 3, 2, 4, 4, 4, 3, 2, 5, 5, 5, 5, 4, 3, 2};
        //  static const unsigned int i1[] = {0, 0, 1, 1, 0, 0, 0, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 2, 2, 3, 3, 2, 3, 4, 4, 4, 2, 3, 4, 5, 5, 5, 5};

        unsigned int i0, i1;

        // Vertex DoFs
        if (i == 0)
          { i0 = 0; i1 = 0; }
        else if (i == 1)
          { i0 = 1; i1 = 0; }
        else if (i == 2)
          { i0 = 1; i1 = 1; }
        else if (i == 3)
          { i0 = 0; i1 = 1; }
        // Edge DoFs
        else if (i < totalorder + 3u)
          { i0 = i - 2; i1 = 0; }
        else if (i < 2u*totalorder + 2)
          { i0 = 1; i1 = i - totalorder - 1; }
        else if (i < 3u*totalorder + 1)
          { i0 = i - 2u*totalorder; i1 = 1; }
        else if (i < 4u*totalorder)
          { i0 = 0; i1 = i - 3u*totalorder + 1; }
        // Interior DoFs
        else
          {
            unsigned int basisnum = i - 4*totalorder;
            i0 = square_number_column[basisnum] + 2;
            i1 = square_number_row[basisnum] + 2;
          }

        // Flip odd degree of freedom values if necessary
        // to keep continuity on sides
        Real f = 1.;

        if ((i0%2) && (i0 > 2) && (i1 == 0))
          f = (elem->point(0) > elem->point(1))?-1.:1.;
        else if ((i0%2) && (i0>2) && (i1 == 1))
          f = (elem->point(3) > elem->point(2))?-1.:1.;
        else if ((i0 == 0) && (i1%2) && (i1>2))
          f = (elem->point(0) > elem->point(3))?-1.:1.;
        else if ((i0 == 1) && (i1%2) && (i1>2))
          f = (elem->point(1) > elem->point(2))?-1.:1.;

        return f*(FE<1,L2_HIERARCHIC>::shape(EDGE3, totalorder, i0, xi)*
                  FE<1,L2_HIERARCHIC>::shape(EDGE3, totalorder, i1, eta));
      }

    default:
      libmesh_error_msg("ERROR: Unsupported element type = " << elem->type());
    }

  return 0.;
}
Exemple #2
0
void DivaIO::write_stream (std::ostream& out_file)
{
  /*
    From Kelly: ([email protected])

    Ok, the following is the format:

    #points #triangles #quads #tets #prisms #pyramids #hexs
    loop over all points (written out x y z x y z ...)
    loop over all triangles (written out i1 i2 i3) (These are indices into
    the points going from
    1 to #points)
    loop over all quads (written out i1 i2 i3 i4) (Same numbering scheme)
    loop over all triangles and quads (write out b1) (This is a boundary
    condition for each
    triangle and each
    hex. You can put
    anything you want
    here)
    loop over all tets (written out i1 i2 i3 i4) (Same)
    loop over all pyramids (written out i1 i2 i3 i4 i5) (Same)
    loop over all prisms (written out i1 i2 i3 i4 i5 i6) (Same)
    loop over all hexs (written out i1 i2 i3 i4 i5 i6 i7 i8) (Same)

  */

  // Be sure the stream has been created successfully.
  libmesh_assert (out_file.good());

  // Can't use a constant mesh reference since we have to
  // sync the boundary info.
  libmesh_here();
  libMesh::err << "WARNING...  Sure you want to do this?"
	        << std::endl;
  MeshBase& the_mesh = const_cast<MeshBase&>
    (MeshOutput<MeshBase>::mesh());

  if (the_mesh.mesh_dimension() < 3)
    {
      libMesh::err << "WARNING: DIVA only supports 3D meshes.\n\n"
		    << "Exiting without producing output.\n";
      return;
    }



  BoundaryMesh boundary_mesh (the_mesh.comm(),
			      the_mesh.mesh_dimension()-1);
  the_mesh.boundary_info->sync(boundary_mesh);


  /**
   * Write the header
   */
  out_file << the_mesh.n_nodes()
           << ' '
           << (MeshTools::n_active_elem_of_type(boundary_mesh,TRI3) +
               MeshTools::n_active_elem_of_type(boundary_mesh,TRI6)*4)
           << ' '
           << (MeshTools::n_active_elem_of_type(boundary_mesh, QUAD4) +
               MeshTools::n_active_elem_of_type(boundary_mesh, QUAD8) +
               MeshTools::n_active_elem_of_type(boundary_mesh, QUAD9)*4)
           << ' '
           << (MeshTools::n_active_elem_of_type(the_mesh, TET4) +
               MeshTools::n_active_elem_of_type(the_mesh, TET10)*8)
           << ' '
           << MeshTools::n_active_elem_of_type(the_mesh, PYRAMID5)
           << ' '
           << (MeshTools::n_active_elem_of_type(the_mesh, PRISM6) +
               MeshTools::n_active_elem_of_type(the_mesh, PRISM18)*8)
           << ' '
           << (MeshTools::n_active_elem_of_type(the_mesh, HEX8)  +
               MeshTools::n_active_elem_of_type(the_mesh, HEX20) +
               MeshTools::n_active_elem_of_type(the_mesh, HEX27)*8)
           << ' '
           << '\n';

  boundary_mesh.clear();


  /**
   * Write the nodes
   */
  for (unsigned int v=0; v<the_mesh.n_nodes(); v++)
    the_mesh.point(v).write_unformatted(out_file);


  /**
   * Write the BC faces
   */
  {
    /**
     * Write the triangles
     */
    for(unsigned int e=0; e<the_mesh.n_elem(); e++)
      if (the_mesh.elem(e)->active())
	for (unsigned int s=0; s<the_mesh.elem(e)->n_sides(); s++)
	  if (the_mesh.elem(e)->neighbor(s) == NULL)
	    {
	      const AutoPtr<Elem> side(the_mesh.elem(e)->build_side(s));

	      if (side->type() == TRI3)
		{
		  out_file << side->node(0)+1 << " "
                           << side->node(1)+1 << " "
                           << side->node(2)+1 << '\n';
		}
	      else if (side->type() == TRI6)
		{
		  out_file << side->node(0)+1 << " "
                           << side->node(3)+1 << " "
                           << side->node(5)+1 << '\n'

                           << side->node(3)+1 << " "
                           << side->node(1)+1 << " "
                           << side->node(4)+1 << '\n'

                           << side->node(5)+1 << " "
                           << side->node(4)+1 << " "
                           << side->node(2)+1 << '\n'

                           << side->node(3)+1 << " "
                           << side->node(4)+1 << " "
                           << side->node(5)+1 << '\n';
		}
	    }


    /**
     * Write the quadrilaterals
     */
    for(unsigned int e=0; e<the_mesh.n_elem(); e++)
      if (the_mesh.elem(e)->active())
	for (unsigned int s=0; s<the_mesh.elem(e)->n_sides(); s++)
	  if (the_mesh.elem(e)->neighbor(s) == NULL)
	    {
	      const AutoPtr<Elem> side(the_mesh.elem(e)->build_side(s));

	      if ((side->type() == QUAD4) ||
		  (side->type() == QUAD8)  )
		{
		  out_file << side->node(0)+1 << " "
                           << side->node(1)+1 << " "
                           << side->node(2)+1 << " "
                           << side->node(3)+1 << '\n';
		}
	      else if (side->type() == QUAD9)
		{
		  out_file << side->node(0)+1 << " "
                           << side->node(4)+1 << " "
                           << side->node(8)+1 << " "
                           << side->node(7)+1 << '\n'

                           << side->node(4)+1 << " "
                           << side->node(1)+1 << " "
                           << side->node(5)+1 << " "
                           << side->node(8)+1 << '\n'

                           << side->node(7)+1 << " "
                           << side->node(8)+1 << " "
                           << side->node(6)+1 << " "
                           << side->node(3)+1 << '\n'

                           << side->node(8)+1 << " "
                           << side->node(5)+1 << " "
                           << side->node(2)+1 << " "
                           << side->node(6)+1 << '\n';
		}
	    }
  }



  /**
   * Write the BC IDs
   */
  {
    /**
     * Write the triangles
     */
    for(unsigned int e=0; e<the_mesh.n_elem(); e++)
      if (the_mesh.elem(e)->active())
	for (unsigned int s=0; s<the_mesh.elem(e)->n_sides(); s++)
	  if (the_mesh.elem(e)->neighbor(s) == NULL)
	    {
	      const AutoPtr<Elem> side(the_mesh.elem(e)->build_side(s));

	      if ((side->type() == TRI3) ||
		  (side->type() == TRI6)  )

		out_file << the_mesh.boundary_info->boundary_id(the_mesh.elem(e), s)
                         << '\n';
	    }


    /**
     * Write the quadrilaterals
     */
    for(unsigned int e=0; e<the_mesh.n_elem(); e++)
      if (the_mesh.elem(e)->active())
	for (unsigned int s=0; s<the_mesh.elem(e)->n_sides(); s++)
	  if (the_mesh.elem(e)->neighbor(s) == NULL)
	    {
	      const AutoPtr<Elem> side(the_mesh.elem(e)->build_side(s));

	      if ((side->type() == QUAD4) ||
		  (side->type() == QUAD8) ||
		  (side->type() == QUAD9))

		out_file << the_mesh.boundary_info->boundary_id(the_mesh.elem(e), s);
	    }
  }



  /**
   * Write all the Tets
   */
  for (unsigned int e=0; e<the_mesh.n_elem(); e++)
    if (the_mesh.elem(e)->active())
      {
	if (the_mesh.elem(e)->type() == TET4)
	  {
	    out_file << the_mesh.elem(e)->node(0)+1 << " "
                     << the_mesh.elem(e)->node(1)+1 << " "
                     << the_mesh.elem(e)->node(2)+1 << " "
                     << the_mesh.elem(e)->node(3)+1 << '\n';
	  }
	else if (the_mesh.elem(e)->type() == TET10)
	  {
	    out_file << the_mesh.elem(e)->node(0)+1 << " "
                     << the_mesh.elem(e)->node(4)+1 << " "
                     << the_mesh.elem(e)->node(6)+1 << " "
                     << the_mesh.elem(e)->node(7)+1 << '\n';

	    out_file << the_mesh.elem(e)->node(4)+1 << " "
                     << the_mesh.elem(e)->node(1)+1 << " "
                     << the_mesh.elem(e)->node(5)+1 << " "
                     << the_mesh.elem(e)->node(8)+1 << '\n';

            out_file << the_mesh.elem(e)->node(6)+1 << " "
                     << the_mesh.elem(e)->node(5)+1 << " "
                     << the_mesh.elem(e)->node(2)+1 << " "
                     << the_mesh.elem(e)->node(9)+1 << '\n';

            out_file << the_mesh.elem(e)->node(7)+1 << " "
                     << the_mesh.elem(e)->node(8)+1 << " "
                     << the_mesh.elem(e)->node(9)+1 << " "
                     << the_mesh.elem(e)->node(3)+1 << '\n';

            out_file << the_mesh.elem(e)->node(4)+1 << " "
                     << the_mesh.elem(e)->node(8)+1 << " "
                     << the_mesh.elem(e)->node(6)+1 << " "
                     << the_mesh.elem(e)->node(7)+1 << '\n';

            out_file << the_mesh.elem(e)->node(4)+1 << " "
                     << the_mesh.elem(e)->node(5)+1 << " "
                     << the_mesh.elem(e)->node(6)+1 << " "
                     << the_mesh.elem(e)->node(8)+1 << '\n';

            out_file << the_mesh.elem(e)->node(6)+1 << " "
                     << the_mesh.elem(e)->node(5)+1 << " "
                     << the_mesh.elem(e)->node(9)+1 << " "
                     << the_mesh.elem(e)->node(8)+1 << '\n';

            out_file << the_mesh.elem(e)->node(6)+1 << " "
                     << the_mesh.elem(e)->node(8)+1 << " "
                     << the_mesh.elem(e)->node(9)+1 << " "
                     << the_mesh.elem(e)->node(7)+1 << '\n';
          }
      }


  /**
   * Write all the Pyramids
   */
  for (unsigned int e=0; e<the_mesh.n_elem(); e++)
    if (the_mesh.elem(e)->active())
      if (the_mesh.elem(e)->type() == PYRAMID5)
	{
	  out_file << the_mesh.elem(e)->node(0)+1 << " "
                   << the_mesh.elem(e)->node(1)+1 << " "
                   << the_mesh.elem(e)->node(2)+1 << " "
                   << the_mesh.elem(e)->node(3)+1 << " "
                   << the_mesh.elem(e)->node(4)+1 << '\n';
	}



  /**
   * Write all the Prisms
   */
  for (unsigned int e=0; e<the_mesh.n_elem(); e++)
    if (the_mesh.elem(e)->active())
      {
	if (the_mesh.elem(e)->type() == PRISM6)
	  {
	    out_file << the_mesh.elem(e)->node(0)+1 << " "
                     << the_mesh.elem(e)->node(1)+1 << " "
                     << the_mesh.elem(e)->node(2)+1 << " "
                     << the_mesh.elem(e)->node(3)+1 << " "
                     << the_mesh.elem(e)->node(4)+1 << " "
                     << the_mesh.elem(e)->node(5)+1 << '\n';
	  }
	else if (the_mesh.elem(e)->type() == PRISM18)
	  {
	    libmesh_error();
	  }
      }


  /**
   * Write all the Hexes
   */
  for (unsigned int e=0; e<the_mesh.n_elem(); e++)
    if (the_mesh.elem(e)->active())
      if ((the_mesh.elem(e)->type() == HEX8)   ||
	  (the_mesh.elem(e)->type() == HEX20) ||
	  (the_mesh.elem(e)->type() == HEX27)   )
	{
	  std::vector<dof_id_type> conn;
	  for (unsigned int se=0; se<the_mesh.elem(e)->n_sub_elem(); se++)
	    {
	      the_mesh.elem(e)->connectivity(se, TECPLOT, conn);

	      out_file << conn[0] << ' '
                       << conn[1] << ' '
                       << conn[2] << ' '
                       << conn[3] << ' '
                       << conn[4] << ' '
                       << conn[5] << ' '
                       << conn[6] << ' '
                       << conn[7] << '\n';
	    }
	}
}
Exemple #3
0
void OFFIO::read_stream(std::istream& in)
{
  // This is a serial-only process for now;
  // the Mesh should be read on processor 0 and
  // broadcast later
  libmesh_assert_equal_to (this->mesh().processor_id(), 0);

  // Get a reference to the mesh
  MeshBase& the_mesh = MeshInput<MeshBase>::mesh();

  // Clear any existing mesh data
  the_mesh.clear();

  // Check the input buffer
  libmesh_assert (in.good());

  unsigned int nn, ne, nf;

  std::string label;

  // Read the first string.  It should say "OFF"
  in >> label;

  libmesh_assert_equal_to (label, "OFF");

  // read the number of nodes, faces, and edges
  in >> nn >> nf >> ne;


  Real x=0., y=0., z=0.;

  // Read the nodes
  for (unsigned int n=0; n<nn; n++)
    {
      libmesh_assert (in.good());

      in >> x
         >> y
         >> z;

      the_mesh.add_point ( Point(x,y,z), n );
    }

  unsigned int nv, nid;

  // Read the elements
  for (unsigned int e=0; e<nf; e++)
    {
      libmesh_assert (in.good());

      // The number of vertices in the element
      in >> nv;

      libmesh_assert(nv == 2 || nv == 3);
      if (e == 0)
        {
          the_mesh.set_mesh_dimension(nv-1);
          if (nv == 3)
            {
#if LIBMESH_DIM < 2
              libmesh_error_msg("Cannot open dimension 2 mesh file when configured without 2D support.");
#endif
            }
        }

      Elem* elem;
      switch (nv)
        {
        case 2:
          elem = new Edge2;
          break;

        case 3:
          elem = new Tri3;
          break;

        default:
          libmesh_error_msg("Unsupported nv = " << nv);
        }

      elem->set_id(e);
      the_mesh.add_elem (elem);

      for (unsigned int i=0; i<nv; i++)
        {
          in >> nid;
          elem->set_node(i) = the_mesh.node_ptr(nid);
        }
    }
}
Exemple #4
0
void CheckpointIO::write_connectivity (Xdr &io) const
{
  libmesh_assert (io.writing());

  // convenient reference to our mesh
  const MeshBase &mesh = MeshOutput<MeshBase>::mesh();

  // We will only write active elements and their parents.
  unsigned int n_active_levels = n_active_levels_on_processor(mesh);

  std::vector<xdr_id_type> n_elem_at_level(n_active_levels);

  // Find the number of elements at each level
  for (unsigned int level=0; level<n_active_levels; level++)
    {
      MeshBase::const_element_iterator it  = mesh.level_elements_begin(level);
      MeshBase::const_element_iterator end = mesh.level_elements_end(level);

      n_elem_at_level[level] = MeshTools::n_elem(it, end);
    }

  io.data(n_active_levels, "# n_active_levels");

  for(unsigned int level=0; level < n_active_levels; level++)
    {
      std::ostringstream comment;
      comment << "# n_elem at level ";
      comment << level ;
      io.data (n_elem_at_level[level], comment.str().c_str());

      MeshBase::const_element_iterator it  = mesh.level_elements_begin(level);
      MeshBase::const_element_iterator end = mesh.level_elements_end(level);
      for (; it != end; ++it)
        {
          Elem & elem = *(*it);

          unsigned int n_nodes = elem.n_nodes();

          // id type pid subdomain_id parent_id
          std::vector<largest_id_type> elem_data(5);

          elem_data[0] = elem.id();
          elem_data[1] = elem.type();
          elem_data[2] = elem.processor_id();
          elem_data[3] = elem.subdomain_id();

          if(elem.parent() != NULL)
            elem_data[4] = elem.parent()->id();
          else
            elem_data[4] = DofObject::invalid_processor_id;

          std::vector<largest_id_type> conn_data(n_nodes);

          for(unsigned int i=0; i<n_nodes; i++)
            conn_data[i] = elem.node(i);

          io.data_stream(&elem_data[0],
                         cast_int<unsigned int>(elem_data.size()),
                         cast_int<unsigned int>(elem_data.size()));

#ifdef LIBMESH_ENABLE_UNIQUE_ID
          largest_id_type unique_id = elem.unique_id();

          io.data(unique_id, "# unique id");
#endif

#ifdef LIBMESH_ENABLE_AMR
          unsigned int p_level = elem.p_level();

          io.data(p_level, "# p_level");
#endif

          io.data_stream(&conn_data[0],
                         cast_int<unsigned int>(conn_data.size()),
                         cast_int<unsigned int>(conn_data.size()));
        }
    }
}
void
MAST::ComplexAssemblyBase::
residual_and_jacobian_field_split (const libMesh::NumericVector<Real>& X_R,
                                   const libMesh::NumericVector<Real>& X_I,
                                   libMesh::NumericVector<Real>& R_R,
                                   libMesh::NumericVector<Real>& R_I,
                                   libMesh::SparseMatrix<Real>&  J_R,
                                   libMesh::SparseMatrix<Real>&  J_I) {

    libmesh_assert(_system);
    libmesh_assert(_discipline);
    libmesh_assert(_elem_ops);

    MAST::NonlinearSystem& nonlin_sys = _system->system();
    
    R_R.zero();
    R_I.zero();
    J_R.zero();
    J_I.zero();
    
    // iterate over each element, initialize it and get the relevant
    // analysis quantities
    RealVectorX    sol, vec_re;
    RealMatrixX    mat_re;
    ComplexVectorX delta_sol, vec;
    ComplexMatrixX mat;
    
    std::vector<libMesh::dof_id_type> dof_indices;
    const libMesh::DofMap& dof_map = _system->system().get_dof_map();
    
    
    std::unique_ptr<libMesh::NumericVector<Real> >
    localized_base_solution,
    localized_real_solution,
    localized_imag_solution;
    
    
    // localize the base solution, if it was provided
    if (_base_sol)
        localized_base_solution.reset(build_localized_vector(nonlin_sys,
                                                              *_base_sol).release());
    
    
    // localize sol to real vector
    localized_real_solution.reset(build_localized_vector(nonlin_sys,
                                                              X_R).release());
    // localize sol to imag vector
    localized_imag_solution.reset(build_localized_vector(nonlin_sys,
                                                              X_I).release());
    
    
    // if a solution function is attached, initialize it
    //if (_sol_function)
    //    _sol_function->init( X);
    
    
    libMesh::MeshBase::const_element_iterator       el     =
    nonlin_sys.get_mesh().active_local_elements_begin();
    const libMesh::MeshBase::const_element_iterator end_el =
    nonlin_sys.get_mesh().active_local_elements_end();
    
    MAST::ComplexAssemblyElemOperations&
    ops = dynamic_cast<MAST::ComplexAssemblyElemOperations&>(*_elem_ops);

    for ( ; el != end_el; ++el) {
        
        const libMesh::Elem* elem = *el;
        
        dof_map.dof_indices (elem, dof_indices);
        
        ops.init(*elem);
        
        // get the solution
        unsigned int ndofs = (unsigned int)dof_indices.size();
        sol.setZero(ndofs);
        delta_sol.setZero(ndofs);
        vec.setZero(ndofs);
        mat.setZero(ndofs, ndofs);
        
        // first set the velocity to be zero
        ops.set_elem_velocity(sol);
        
        // next, set the base solution, if provided
        if (_base_sol)
            for (unsigned int i=0; i<dof_indices.size(); i++)
                sol(i) = (*localized_base_solution)(dof_indices[i]);
        
        ops.set_elem_solution(sol);
        
        // set the value of the small-disturbance solution
        for (unsigned int i=0; i<dof_indices.size(); i++)
            delta_sol(i) = Complex((*localized_real_solution)(dof_indices[i]),
                                   (*localized_imag_solution)(dof_indices[i]));
        
        ops.set_elem_complex_solution(delta_sol);
        
        
//        if (_sol_function)
//            physics_elem->attach_active_solution_function(*_sol_function);
        
        
        // perform the element level calculations
        ops.elem_calculations(true,
                                             vec,
                                             mat);
        ops.clear_elem();

        vec *= -1.;
        
        //physics_elem->detach_active_solution_function();
        
        // extract the real or the imaginary part of the matrix/vector
        //  The complex system of equations
        //     (J_R + i J_I) (x_R + i x_I) + (r_R + i r_I) = 0
        //  is rewritten as
        //     [ J_R   -J_I] {x_R}  +  {r_R}  = {0}
        //     [ J_I    J_R] {x_I}  +  {r_I}  = {0}
        //
        DenseRealVector v;
        DenseRealMatrix m;

        // copy the real part of the residual and Jacobian
        MAST::copy(v, vec.real());
        MAST::copy(m, mat.real());
        
        dof_map.constrain_element_matrix_and_vector(m, v, dof_indices);
        R_R.add_vector(v, dof_indices);
        J_R.add_matrix(m, dof_indices);

        
        // copy the imag part of the residual and Jacobian
        v.zero();
        m.zero();
        MAST::copy(v, vec.imag());
        MAST::copy(m, mat.imag());
        
        dof_map.constrain_element_matrix_and_vector(m, v, dof_indices);
        R_I.add_vector(v, dof_indices);
        J_I.add_matrix(m, dof_indices);
    }
    
    
    // if a solution function is attached, clear it
    //if (_sol_function)
    //    _sol_function->clear();
    
    R_R.close();
    R_I.close();
    J_R.close();
    J_I.close();
    
    libMesh::out << "R_R: " << R_R.l2_norm() << "   R_I: " << R_I.l2_norm() << std::endl;
}
Exemple #6
0
  //---------------------------------------------------------------
  // this function is called by PETSc to evaluate the residual at X
  PetscErrorCode
  __libmesh_petsc_snes_residual (SNES snes, Vec x, Vec r, void * ctx)
  {
    LOG_SCOPE("residual()", "PetscNonlinearSolver");

    PetscErrorCode ierr=0;

    libmesh_assert(x);
    libmesh_assert(r);
    libmesh_assert(ctx);

    // No way to safety-check this cast, since we got a void *...
    PetscNonlinearSolver<Number> * solver =
      static_cast<PetscNonlinearSolver<Number> *> (ctx);

    // Get the current iteration number from the snes object,
    // store it in the PetscNonlinearSolver object for possible use
    // by the user's residual function.
    {
      PetscInt n_iterations = 0;
      ierr = SNESGetIterationNumber(snes, &n_iterations);
      CHKERRABORT(solver->comm().get(),ierr);
      solver->_current_nonlinear_iteration_number = cast_int<unsigned>(n_iterations);
    }

    NonlinearImplicitSystem & sys = solver->system();

    PetscVector<Number> & X_sys = *cast_ptr<PetscVector<Number> *>(sys.solution.get());
    PetscVector<Number> X_global(x, sys.comm()), R(r, sys.comm());

    // Use the system's update() to get a good local version of the
    // parallel solution.  This operation does not modify the incoming
    // "x" vector, it only localizes information from "x" into
    // sys.current_local_solution.
    X_global.swap(X_sys);
    sys.update();
    X_global.swap(X_sys);

    // Enforce constraints (if any) exactly on the
    // current_local_solution.  This is the solution vector that is
    // actually used in the computation of the residual below, and is
    // not locked by debug-enabled PETSc the way that "x" is.
    sys.get_dof_map().enforce_constraints_exactly(sys, sys.current_local_solution.get());

    if (solver->_zero_out_residual)
      R.zero();

    //-----------------------------------------------------------------------------
    // if the user has provided both function pointers and objects only the pointer
    // will be used, so catch that as an error
    if (solver->residual && solver->residual_object)
      libmesh_error_msg("ERROR: cannot specifiy both a function and object to compute the Residual!");

    if (solver->matvec && solver->residual_and_jacobian_object)
      libmesh_error_msg("ERROR: cannot specifiy both a function and object to compute the combined Residual & Jacobian!");

    if (solver->residual != libmesh_nullptr)
      solver->residual(*sys.current_local_solution.get(), R, sys);

    else if (solver->residual_object != libmesh_nullptr)
      solver->residual_object->residual(*sys.current_local_solution.get(), R, sys);

    else if (solver->matvec != libmesh_nullptr)
      solver->matvec (*sys.current_local_solution.get(), &R, libmesh_nullptr, sys);

    else if (solver->residual_and_jacobian_object != libmesh_nullptr)
      solver->residual_and_jacobian_object->residual_and_jacobian (*sys.current_local_solution.get(), &R, libmesh_nullptr, sys);

    else
      libmesh_error_msg("Error! Unable to compute residual and/or Jacobian!");

    R.close();

    return ierr;
  }
void CondensedEigenSystem::solve()
{
  START_LOG("solve()", "CondensedEigenSystem");

  // If we haven't initialized any condensed dofs,
  // just use the default eigen_system
  if(!condensed_dofs_initialized)
  {
    STOP_LOG("solve()", "CondensedEigenSystem");
    Parent::solve();
    return;
  }

  // A reference to the EquationSystems
  EquationSystems& es = this->get_equation_systems();

  // check that necessary parameters have been set
  libmesh_assert (es.parameters.have_parameter<unsigned int>("eigenpairs"));
  libmesh_assert (es.parameters.have_parameter<unsigned int>("basis vectors"));

  if (this->assemble_before_solve)
    // Assemble the linear system
    this->assemble ();

  // If we reach here, then there should be some non-condensed dofs
  libmesh_assert(!local_non_condensed_dofs_vector.empty());

  // Now condense the matrices
  matrix_A->create_submatrix(*condensed_matrix_A,
                             local_non_condensed_dofs_vector,
                             local_non_condensed_dofs_vector);

  matrix_B->create_submatrix(*condensed_matrix_B,
                             local_non_condensed_dofs_vector,
                             local_non_condensed_dofs_vector);

  // Get the tolerance for the solver and the maximum
  // number of iterations. Here, we simply adopt the linear solver
  // specific parameters.
  const Real tol            =
    es.parameters.get<Real>("linear solver tolerance");

  const unsigned int maxits =
    es.parameters.get<unsigned int>("linear solver maximum iterations");

  const unsigned int nev    =
    es.parameters.get<unsigned int>("eigenpairs");

  const unsigned int ncv    =
    es.parameters.get<unsigned int>("basis vectors");

  std::pair<unsigned int, unsigned int> solve_data;

  // call the solver depending on the type of eigenproblem
  if ( generalized() )
    {
      //in case of a generalized eigenproblem
      solve_data = eigen_solver->solve_generalized
        (*condensed_matrix_A,*condensed_matrix_B, nev, ncv, tol, maxits);
    }

  else
    {
      libmesh_assert (matrix_B == NULL);

      //in case of a standard eigenproblem
      solve_data = eigen_solver->solve_standard (*condensed_matrix_A, nev, ncv, tol, maxits);
    }

  set_n_converged(solve_data.first);
  set_n_iterations(solve_data.second);

  STOP_LOG("solve()", "CondensedEigenSystem");
}
Exemple #8
0
Real FE<3,XYZ>::shape_second_deriv(const Elem* elem,
			           const Order libmesh_dbg_var(order),
			           const unsigned int i,
			           const unsigned int j,
			           const Point& point_in)
{
#if LIBMESH_DIM == 3

  libmesh_assert(elem);
  libmesh_assert_less (j, 6);

  // Only recompute the centroid if the element
  // has changed from the last one we computed.
  // This avoids repeated centroid calculations
  // when called in succession with the same element.
  if (elem->id() != old_elem_id)
    {
      centroid = elem->centroid();
      old_elem_id = elem->id();
      max_distance = Point(0.,0.,0.);
      for (unsigned int p = 0; p < elem->n_nodes(); p++)
        for (unsigned int d = 0; d < 3; d++)
        {
           const Real distance = std::abs(centroid(d) - elem->point(p)(d));
           max_distance(d) = std::max(distance, max_distance(d));
        }
    }

  // Using static globals for old_elem_id, etc. will fail
  // horribly with more than one thread.
  libmesh_assert_equal_to (libMesh::n_threads(), 1);

  const Real x  = point_in(0);
  const Real y  = point_in(1);
  const Real z  = point_in(2);
  const Real xc = centroid(0);
  const Real yc = centroid(1);
  const Real zc = centroid(2);
  const Real distx = max_distance(0);
  const Real disty = max_distance(1);
  const Real distz = max_distance(2);
  const Real dx = (x - xc)/distx;
  const Real dy = (y - yc)/disty;
  const Real dz = (z - zc)/distz;
  const Real dist2x = pow(distx,2.);
  const Real dist2y = pow(disty,2.);
  const Real dist2z = pow(distz,2.);
  const Real distxy = distx * disty;
  const Real distxz = distx * distz;
  const Real distyz = disty * distz;

#ifndef NDEBUG
  // totalorder is only used in the assertion below, so
  // we avoid declaring it when asserts are not active.
  const unsigned int totalorder = static_cast<Order>(order + elem->p_level());
#endif
  libmesh_assert_less (i, (static_cast<unsigned int>(totalorder)+1)*
              (static_cast<unsigned int>(totalorder)+2)*
              (static_cast<unsigned int>(totalorder)+3)/6);

    // monomials. since they are hierarchic we only need one case block.
  switch (j)
    {
      // d^2()/dx^2
    case 0:
      {
        switch (i)
  	{
  	  // constant
  	case 0:

  	  // linear
  	case 1:
  	case 2:
  	case 3:
  	  return 0.;

  	  // quadratic
  	case 4:
  	  return 2./dist2x;

  	case 5:
  	case 6:
  	case 7:
  	case 8:
  	case 9:
  	  return 0.;

  	  // cubic
  	case 10:
  	  return 6.*dx/dist2x;

  	case 11:
  	  return 2.*dy/dist2x;

  	case 12:
  	case 13:
  	  return 0.;

  	case 14:
  	  return 2.*dz/dist2x;

  	case 15:
  	case 16:
  	case 17:
  	case 18:
  	case 19:
  	  return 0.;

  	  // quartics
  	case 20:
  	  return 12.*dx*dx/dist2x;

  	case 21:
  	  return 6.*dx*dy/dist2x;

  	case 22:
  	  return 2.*dy*dy/dist2x;

  	case 23:
  	case 24:
  	  return 0.;

  	case 25:
  	  return 6.*dx*dz/dist2x;

  	case 26:
  	  return 2.*dy*dz/dist2x;

  	case 27:
  	case 28:
  	  return 0.;

  	case 29:
  	  return 2.*dz*dz/dist2x;

  	case 30:
  	case 31:
  	case 32:
  	case 33:
  	case 34:
  	  return 0.;

  	default:
          unsigned int o = 0;
          for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { }
          unsigned int i2 = i - (o*(o+1)*(o+2)/6);
          unsigned int block=o, nz = 0;
          for (; block < i2; block += (o-nz+1)) { nz++; }
          const unsigned int nx = block - i2;
          const unsigned int ny = o - nx - nz;
          Real val = nx * (nx - 1);
          for (unsigned int index=2; index < nx; index++)
            val *= dx;
          for (unsigned int index=0; index != ny; index++)
            val *= dy;
          for (unsigned int index=0; index != nz; index++)
            val *= dz;
          return val/dist2x;
  	}
      }


      // d^2()/dxdy
    case 1:
      {
        switch (i)
  	{
  	  // constant
  	case 0:

  	  // linear
  	case 1:
  	case 2:
  	case 3:
  	  return 0.;

  	  // quadratic
  	case 4:
  	  return 0.;

  	case 5:
  	  return 1./distxy;

  	case 6:
  	case 7:
  	case 8:
  	case 9:
  	  return 0.;

  	  // cubic
  	case 10:
  	  return 0.;

  	case 11:
  	  return 2.*dx/distxy;

  	case 12:
  	  return 2.*dy/distxy;

  	case 13:
  	case 14:
  	  return 0.;

  	case 15:
  	  return dz/distxy;

  	case 16:
  	case 17:
  	case 18:
  	case 19:
  	  return 0.;

  	  // quartics
  	case 20:
  	  return 0.;

  	case 21:
  	  return 3.*dx*dx/distxy;

  	case 22:
  	  return 4.*dx*dy/distxy;

  	case 23:
  	  return 3.*dy*dy/distxy;

  	case 24:
  	case 25:
  	  return 0.;

  	case 26:
  	  return 2.*dx*dz/distxy;

  	case 27:
  	  return 2.*dy*dz/distxy;

  	case 28:
  	case 29:
  	  return 0.;

  	case 30:
  	  return dz*dz/distxy;

  	case 31:
  	case 32:
  	case 33:
  	case 34:
  	  return 0.;

  	default:
          unsigned int o = 0;
          for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { }
          unsigned int i2 = i - (o*(o+1)*(o+2)/6);
          unsigned int block=o, nz = 0;
          for (; block < i2; block += (o-nz+1)) { nz++; }
          const unsigned int nx = block - i2;
          const unsigned int ny = o - nx - nz;
          Real val = nx * ny;
          for (unsigned int index=1; index < nx; index++)
            val *= dx;
          for (unsigned int index=1; index < ny; index++)
            val *= dy;
          for (unsigned int index=0; index != nz; index++)
            val *= dz;
          return val/distxy;
  	}
      }


      // d^2()/dy^2
    case 2:
      {
        switch (i)
  	{
  	  // constant
  	case 0:

  	  // linear
  	case 1:
  	case 2:
  	case 3:
  	  return 0.;

  	  // quadratic
  	case 4:
  	case 5:
  	  return 0.;

  	case 6:
  	  return 2./dist2y;

  	case 7:
  	case 8:
  	case 9:
  	  return 0.;

  	  // cubic
  	case 10:
  	case 11:
  	  return 0.;

  	case 12:
  	  return 2.*dx/dist2y;
  	case 13:
  	  return 6.*dy/dist2y;

  	case 14:
  	case 15:
  	  return 0.;

  	case 16:
  	  return 2.*dz/dist2y;

  	case 17:
  	case 18:
  	case 19:
  	  return 0.;

  	  // quartics
  	case 20:
  	case 21:
  	  return 0.;

  	case 22:
  	  return 2.*dx*dx/dist2y;

  	case 23:
  	  return 6.*dx*dy/dist2y;

  	case 24:
  	  return 12.*dy*dy/dist2y;

  	case 25:
  	case 26:
  	  return 0.;

  	case 27:
  	  return 2.*dx*dz/dist2y;

  	case 28:
  	  return 6.*dy*dz/dist2y;

  	case 29:
  	case 30:
  	  return 0.;

  	case 31:
  	  return 2.*dz*dz/dist2y;

  	case 32:
  	case 33:
  	case 34:
  	  return 0.;

  	default:
          unsigned int o = 0;
          for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { }
          unsigned int i2 = i - (o*(o+1)*(o+2)/6);
          unsigned int block=o, nz = 0;
          for (; block < i2; block += (o-nz+1)) { nz++; }
          const unsigned int nx = block - i2;
          const unsigned int ny = o - nx - nz;
          Real val = ny * (ny - 1);
          for (unsigned int index=0; index != nx; index++)
            val *= dx;
          for (unsigned int index=2; index < ny; index++)
            val *= dy;
          for (unsigned int index=0; index != nz; index++)
            val *= dz;
          return val/dist2y;
  	}
      }


      // d^2()/dxdz
    case 3:
      {
        switch (i)
  	{
  	  // constant
  	case 0:

  	  // linear
  	case 1:
  	case 2:
  	case 3:
  	  return 0.;

  	  // quadratic
  	case 4:
  	case 5:
  	case 6:
  	  return 0.;

  	case 7:
  	  return 1./distxz;

  	case 8:
  	case 9:
  	  return 0.;

  	  // cubic
  	case 10:
  	case 11:
  	case 12:
  	case 13:
  	  return 0.;

  	case 14:
  	  return 2.*dx/distxz;

  	case 15:
  	  return dy/distxz;

  	case 16:
  	  return 0.;

  	case 17:
  	  return 2.*dz/distxz;

  	case 18:
  	case 19:
  	  return 0.;

  	  // quartics
  	case 20:
  	case 21:
  	case 22:
  	case 23:
  	case 24:
  	  return 0.;

  	case 25:
  	  return 3.*dx*dx/distxz;

  	case 26:
  	  return 2.*dx*dy/distxz;

  	case 27:
  	  return dy*dy/distxz;

  	case 28:
  	  return 0.;

  	case 29:
  	  return 4.*dx*dz/distxz;

  	case 30:
  	  return 2.*dy*dz/distxz;

  	case 31:
  	  return 0.;

  	case 32:
  	  return 3.*dz*dz/distxz;

  	case 33:
  	case 34:
  	  return 0.;

  	default:
          unsigned int o = 0;
          for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { }
          unsigned int i2 = i - (o*(o+1)*(o+2)/6);
          unsigned int block=o, nz = 0;
          for (; block < i2; block += (o-nz+1)) { nz++; }
          const unsigned int nx = block - i2;
          const unsigned int ny = o - nx - nz;
          Real val = nx * nz;
          for (unsigned int index=1; index < nx; index++)
            val *= dx;
          for (unsigned int index=0; index != ny; index++)
            val *= dy;
          for (unsigned int index=1; index < nz; index++)
            val *= dz;
          return val/distxz;
  	}
      }

      // d^2()/dydz
    case 4:
      {
        switch (i)
  	{
  	  // constant
  	case 0:

  	  // linear
  	case 1:
  	case 2:
  	case 3:
  	  return 0.;

  	  // quadratic
  	case 4:
  	case 5:
  	case 6:
  	case 7:
  	  return 0.;

  	case 8:
  	  return 1./distyz;

  	case 9:
  	  return 0.;

  	  // cubic
  	case 10:
  	case 11:
  	case 12:
  	case 13:
  	case 14:
  	  return 0.;

  	case 15:
  	  return dx/distyz;

  	case 16:
  	  return 2.*dy/distyz;

  	case 17:
  	  return 0.;

  	case 18:
  	  return 2.*dz/distyz;

  	case 19:
  	  return 0.;

  	  // quartics
  	case 20:
  	case 21:
  	case 22:
  	case 23:
  	case 24:
  	case 25:
  	  return 0.;

  	case 26:
  	  return dx*dx/distyz;

  	case 27:
  	  return 2.*dx*dy/distyz;

  	case 28:
  	  return 3.*dy*dy/distyz;

  	case 29:
  	  return 0.;

  	case 30:
  	  return 2.*dx*dz/distyz;

  	case 31:
  	  return 4.*dy*dz/distyz;

  	case 32:
  	  return 0.;

  	case 33:
  	  return 3.*dz*dz/distyz;

  	case 34:
  	  return 0.;

  	default:
          unsigned int o = 0;
          for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { }
          unsigned int i2 = i - (o*(o+1)*(o+2)/6);
          unsigned int block=o, nz = 0;
          for (; block < i2; block += (o-nz+1)) { nz++; }
          const unsigned int nx = block - i2;
          const unsigned int ny = o - nx - nz;
          Real val = ny * nz;
          for (unsigned int index=0; index != nx; index++)
            val *= dx;
          for (unsigned int index=1; index < ny; index++)
            val *= dy;
          for (unsigned int index=1; index < nz; index++)
            val *= dz;
          return val/distyz;
  	}
      }


      // d^2()/dz^2
    case 5:
      {
        switch (i)
  	{
  	  // constant
  	case 0:

  	  // linear
  	case 1:
  	case 2:
  	case 3:
  	  return 0.;

  	  // quadratic
  	case 4:
  	case 5:
  	case 6:
  	case 7:
  	case 8:
  	  return 0.;

  	case 9:
  	  return 2./dist2z;

  	  // cubic
  	case 10:
  	case 11:
  	case 12:
  	case 13:
  	case 14:
  	case 15:
  	case 16:
  	  return 0.;

  	case 17:
  	  return 2.*dx/dist2z;

  	case 18:
  	  return 2.*dy/dist2z;

  	case 19:
  	  return 6.*dz/dist2z;

  	  // quartics
  	case 20:
  	case 21:
  	case 22:
  	case 23:
  	case 24:
  	case 25:
  	case 26:
  	case 27:
  	case 28:
  	  return 0.;

  	case 29:
  	  return 2.*dx*dx/dist2z;

  	case 30:
  	  return 2.*dx*dy/dist2z;

  	case 31:
  	  return 2.*dy*dy/dist2z;

  	case 32:
  	  return 6.*dx*dz/dist2z;

  	case 33:
  	  return 6.*dy*dz/dist2z;

  	case 34:
  	  return 12.*dz*dz/dist2z;

  	default:
          unsigned int o = 0;
          for (; i >= (o+1)*(o+2)*(o+3)/6; o++) { }
          unsigned int i2 = i - (o*(o+1)*(o+2)/6);
          unsigned int block=o, nz = 0;
          for (; block < i2; block += (o-nz+1)) { nz++; }
          const unsigned int nx = block - i2;
          const unsigned int ny = o - nx - nz;
          Real val = nz * (nz - 1);
          for (unsigned int index=0; index != nx; index++)
            val *= dx;
          for (unsigned int index=0; index != ny; index++)
            val *= dy;
          for (unsigned int index=2; index < nz; index++)
            val *= dz;
          return val/dist2z;
  	}
      }


    default:
      libmesh_error();
    }

#endif

  libmesh_error();
  return 0.;
}
  void AxisymmetricHeatTransfer<Conductivity>::element_time_derivative( bool compute_jacobian,
									AssemblyContext& context,
									CachedValues& /*cache*/ )
  {
#ifdef GRINS_USE_GRVY_TIMERS
    this->_timer->BeginTimer("AxisymmetricHeatTransfer::element_time_derivative");
#endif

    // The number of local degrees of freedom in each variable.
    const unsigned int n_T_dofs = context.get_dof_indices(_T_var).size();
    const unsigned int n_u_dofs = context.get_dof_indices(_u_r_var).size();

    //TODO: check n_T_dofs is same as n_u_dofs, n_v_dofs, n_w_dofs

    // We get some references to cell-specific data that
    // will be used to assemble the linear system.

    // Element Jacobian * quadrature weights for interior integration.
    const std::vector<libMesh::Real> &JxW =
      context.get_element_fe(_T_var)->get_JxW();

    // The temperature shape functions at interior quadrature points.
    const std::vector<std::vector<libMesh::Real> >& T_phi =
      context.get_element_fe(_T_var)->get_phi();

    // The velocity shape functions at interior quadrature points.
    const std::vector<std::vector<libMesh::Real> >& vel_phi =
      context.get_element_fe(_u_r_var)->get_phi();

    // The temperature shape function gradients (in global coords.)
    // at interior quadrature points.
    const std::vector<std::vector<libMesh::RealGradient> >& T_gradphi =
      context.get_element_fe(_T_var)->get_dphi();

    // Physical location of the quadrature points
    const std::vector<libMesh::Point>& u_qpoint =
      context.get_element_fe(_u_r_var)->get_xyz();

    // The subvectors and submatrices we need to fill:
    libMesh::DenseSubVector<Number> &FT = context.get_elem_residual(_T_var); // R_{T}

    libMesh::DenseSubMatrix<Number> &KTT = context.get_elem_jacobian(_T_var, _T_var); // R_{T},{T}

    libMesh::DenseSubMatrix<Number> &KTr = context.get_elem_jacobian(_T_var, _u_r_var); // R_{T},{r}
    libMesh::DenseSubMatrix<Number> &KTz = context.get_elem_jacobian(_T_var, _u_z_var); // R_{T},{z}


    // Now we will build the element Jacobian and residual.
    // Constructing the residual requires the solution and its
    // gradient from the previous timestep.  This must be
    // calculated at each quadrature point by summing the
    // solution degree-of-freedom values by the appropriate
    // weight functions.
    unsigned int n_qpoints = context.get_element_qrule().n_points();

    for (unsigned int qp=0; qp != n_qpoints; qp++)
      {
	const libMesh::Number r = u_qpoint[qp](0);
      
	// Compute the solution & its gradient at the old Newton iterate.
	libMesh::Number T, u_r, u_z;
	T = context.interior_value(_T_var, qp);
	u_r = context.interior_value(_u_r_var, qp);
	u_z = context.interior_value(_u_z_var, qp);

	libMesh::Gradient grad_T;
	grad_T = context.interior_gradient(_T_var, qp);

	libMesh::NumberVectorValue U (u_r,u_z);

	libMesh::Number k = this->_k( T );
	libMesh::Number dk_dT = this->_k.deriv( T );

	// First, an i-loop over the  degrees of freedom.
	for (unsigned int i=0; i != n_T_dofs; i++)
	  {
	    FT(i) += JxW[qp]*r*
	      (-_rho*_Cp*T_phi[i][qp]*(U*grad_T)    // convection term
	       -k*(T_gradphi[i][qp]*grad_T) );  // diffusion term

	    if (compute_jacobian && context.get_elem_solution_derivative())
	      {
		libmesh_assert (context.get_elem_solution_derivative() == 1.0);

		for (unsigned int j=0; j != n_T_dofs; j++)
		  {
		    // TODO: precompute some terms like:
		    //   _rho*_Cp*T_phi[i][qp]*(vel_phi[j][qp]*T_grad_phi[j][qp])

		    KTT(i,j) += JxW[qp]*r*
		      (-_rho*_Cp*T_phi[i][qp]*(U*T_gradphi[j][qp])  // convection term
		       -k*(T_gradphi[i][qp]*T_gradphi[j][qp])); // diffusion term
		  } // end of the inner dof (j) loop

		//if( dk_dT != 0.0 )
		{
		  for (unsigned int j=0; j != n_T_dofs; j++)
		    {
		      // TODO: precompute some terms like:
		      KTT(i,j) -= JxW[qp]*r*( dk_dT*T_phi[j][qp]*T_gradphi[i][qp]*grad_T );
		    }
		}

		// Matrix contributions for the Tu, Tv and Tw couplings (n_T_dofs same as n_u_dofs, n_v_dofs and n_w_dofs)
		for (unsigned int j=0; j != n_u_dofs; j++)
		  {
		    KTr(i,j) += JxW[qp]*r*(-_rho*_Cp*T_phi[i][qp]*(vel_phi[j][qp]*grad_T(0)));
		    KTz(i,j) += JxW[qp]*r*(-_rho*_Cp*T_phi[i][qp]*(vel_phi[j][qp]*grad_T(1)));
		  } // end of the inner dof (j) loop

	      } // end - if (compute_jacobian && context.get_elem_solution_derivative())

	  } // end of the outer dof (i) loop
      } // end of the quadrature point (qp) loop

#ifdef GRINS_USE_GRVY_TIMERS
    this->_timer->EndTimer("AxisymmetricHeatTransfer::element_time_derivative");
#endif

    return;
  }
Exemple #10
0
PetscVector<T>&
PetscVector<T>::operator = (const PetscVector<T>& v)
{
  this->_restore_array();
  v._restore_array();

  libmesh_assert_equal_to (this->size(), v.size());
  libmesh_assert_equal_to (this->local_size(), v.local_size());
  libmesh_assert (v.closed());

  PetscErrorCode ierr = 0;

  if (((this->type()==PARALLEL) && (v.type()==GHOSTED)) ||
      ((this->type()==GHOSTED) && (v.type()==PARALLEL)) ||
      ((this->type()==GHOSTED) && (v.type()==SERIAL))   ||
      ((this->type()==SERIAL) && (v.type()==GHOSTED)))
  {
    /* Allow assignment of a ghosted to a parallel vector since this
       causes no difficulty.  See discussion in libmesh-devel of
       June 24, 2010.  */
    ierr = VecCopy (v._vec, this->_vec);
    CHKERRABORT(libMesh::COMM_WORLD,ierr);
  }
  else
  {
    /* In all other cases, we assert that both vectors are of equal
       type.  */
    libmesh_assert_equal_to (this->_type, v._type);
    libmesh_assert (this->_global_to_local_map == v._global_to_local_map);

    if (v.size() != 0)
    {
      if(this->type() != GHOSTED)
      {
        ierr = VecCopy (v._vec, this->_vec);
        CHKERRABORT(libMesh::COMM_WORLD,ierr);
      }
      else
      {
        Vec loc_vec;
        Vec v_loc_vec;
        ierr = VecGhostGetLocalForm (_vec,&loc_vec);
        CHKERRABORT(libMesh::COMM_WORLD,ierr);
        ierr = VecGhostGetLocalForm (v._vec,&v_loc_vec);
        CHKERRABORT(libMesh::COMM_WORLD,ierr);

        ierr = VecCopy (v_loc_vec, loc_vec);
        CHKERRABORT(libMesh::COMM_WORLD,ierr);

        ierr = VecGhostRestoreLocalForm (v._vec,&v_loc_vec);
        CHKERRABORT(libMesh::COMM_WORLD,ierr);
        ierr = VecGhostRestoreLocalForm (_vec,&loc_vec);
        CHKERRABORT(libMesh::COMM_WORLD,ierr);
      }
    }
  }

  close();

  return *this;
}
Exemple #11
0
void PetscVector<T>::localize (NumericVector<T>& v_local_in,
			       const std::vector<numeric_index_type>& send_list) const
{
  // FIXME: Workaround for a strange bug at large-scale.
  // If we have ghosting, PETSc lets us just copy the solution, and
  // doing so avoids a segfault?
  if (v_local_in.type() == GHOSTED &&
      this->type() == PARALLEL)
    {
      v_local_in = *this;
      return;
    }

  // Normal code path begins here

  this->_restore_array();

  // Make sure the NumericVector passed in is really a PetscVector
  PetscVector<T>* v_local = libmesh_cast_ptr<PetscVector<T>*>(&v_local_in);

  libmesh_assert(v_local);
  libmesh_assert_equal_to (v_local->size(), this->size());
  libmesh_assert_less_equal (send_list.size(), v_local->size());

  PetscErrorCode ierr=0;
  const numeric_index_type n_sl = send_list.size();

  IS is;
  VecScatter scatter;

  std::vector<PetscInt> idx(n_sl + this->local_size());

  for (numeric_index_type i=0; i<n_sl; i++)
    idx[i] = static_cast<PetscInt>(send_list[i]);
  for (numeric_index_type i = 0; i != this->local_size(); ++i)
    idx[n_sl+i] = i + this->first_local_index();

  // Create the index set & scatter object
  if (idx.empty())
    ierr = ISCreateLibMesh(libMesh::COMM_WORLD,
                           n_sl+this->local_size(), PETSC_NULL, PETSC_USE_POINTER, &is);
  else
    ierr = ISCreateLibMesh(libMesh::COMM_WORLD,
			   n_sl+this->local_size(), &idx[0], PETSC_USE_POINTER, &is);
           CHKERRABORT(libMesh::COMM_WORLD,ierr);

  ierr = VecScatterCreate(_vec,          is,
			  v_local->_vec, is,
			  &scatter);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);


  // Perform the scatter
#if PETSC_VERSION_LESS_THAN(2,3,3)

  ierr = VecScatterBegin(_vec, v_local->_vec, INSERT_VALUES,
			 SCATTER_FORWARD, scatter);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  ierr = VecScatterEnd  (_vec, v_local->_vec, INSERT_VALUES,
			 SCATTER_FORWARD, scatter);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

#else

  // API argument order change in PETSc 2.3.3
  ierr = VecScatterBegin(scatter, _vec, v_local->_vec,
                         INSERT_VALUES, SCATTER_FORWARD);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  ierr = VecScatterEnd  (scatter, _vec, v_local->_vec,
                         INSERT_VALUES, SCATTER_FORWARD);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

#endif


  // Clean up
  ierr = LibMeshISDestroy (&is);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  ierr = LibMeshVecScatterDestroy(&scatter);
         CHKERRABORT(libMesh::COMM_WORLD,ierr);

  // Make sure ghost dofs are up to date
  if (v_local->type() == GHOSTED)
    v_local->close();
}
void
MAST::NPSOLOptimizationInterface::optimize() {
    
#if MAST_ENABLE_NPSOL == 1
    // make sure that functions have been provided
    libmesh_assert(_funobj);
    libmesh_assert(_funcon);
    
    int
    N      =  _feval->n_vars(),
    NCLIN  =  0,
    NCNLN  =  _feval->n_eq()+_feval->n_ineq(),
    NCTOTL =  N+NCLIN+NCNLN,
    LDA    =  std::max(NCLIN, 1),
    LDJ    =  std::max(NCNLN, 1),
    LDR    =  N,
    INFORM =  0,           // on exit: Reports result of call to NPSOL
                           // < 0 either funobj or funcon has set this to -ve
                           // 0 => converged to point x
                           // 1 => x satisfies optimality conditions, but sequence of iterates has not converged
                           // 2 => Linear constraints and bounds cannot be satisfied. No feasible solution
                           // 3 => Nonlinear constraints and bounds cannot be satisfied. No feasible solution
                           // 4 => Major iter limit was reached
                           // 6 => x does not satisfy first-order optimality to required accuracy
                           // 7 => function derivatives seem to be incorrect
                           // 9 => input parameter invalid
    ITER   = 0,            // iter count
    LENIW  = 3*N + NCLIN + 2*NCNLN,
    LENW   = 2*N*N + N*NCLIN + 2*N*NCNLN + 20*N + 11*NCLIN + 21*NCNLN;
    
    Real
    F      =  0.;          // on exit: final objective

    std::vector<int>
    IW      (LENIW,  0),
    ISTATE  (NCTOTL, 0);    // status of constraints l <= r(x) <= u,
                            // -2 => lower bound is violated by more than delta
                            // -1 => upper bound is violated by more than delta
                            // 0  => both bounds are satisfied by more than delta
                            // 1  => lower bound is active (to within delta)
                            // 2  => upper bound is active (to within delta)
                            // 3  => boundars are equal and equality constraint is satisfied
    
    std::vector<Real>
    A       (LDA,    0.),   // this is used for liear constraints, not currently handled
    BL      (NCTOTL, 0.),
    BU      (NCTOTL, 0.),
    C       (NCNLN,  0.),   // on exit: nonlinear constraints
    CJAC    (LDJ* N, 0.),   //
                            // on exit: CJAC(i,j) is the partial derivative of ith nonlinear constraint
    CLAMBDA (NCTOTL, 0.),   // on entry: need not be initialized for cold start
                            // on exit: QP multiplier from the QP subproblem, >=0 if istate(j)=1, <0 if istate(j)=2
    G       (N,      0.),   // on exit: objective gradient
    R       (LDR*N,  0.),   // on entry: need not be initialized if called with Cold Statrt
                            // on exit: information about Hessian, if Hessian=Yes, R is upper Cholesky factor of approx H
    X       (N,      0.),   // on entry: initial point
                            // on exit: final estimate of solution
    W       (LENW,   0.),   // workspace
    xmin    (N,      0.),
    xmax    (N,      0.);
    
    
    // now setup the lower and upper limits for the variables and constraints
    _feval->init_dvar(X, xmin, xmax);
    for (unsigned int i=0; i<N; i++) {
        BL[i] = xmin[i];
        BU[i] = xmax[i];
    }
    
    // all constraints are assumed to be g_i(x) <= 0, so that the upper
    // bound is 0 and lower bound is -infinity
    for (unsigned int i=0; i<NCNLN; i++) {
        BL[i+N] = -1.e20;
        BU[i+N] =     0.;
    }
    
    std::string nm;
//    nm = "List";
//    npoptn_(nm.c_str(), (int)nm.length());
//    nm = "Verify level 3";
//    npoptn_(nm.c_str(), (int)nm.length());
    
    npsol_(&N,
           &NCLIN,
           &NCNLN,
           &LDA,
           &LDJ,
           &LDR,
           &A[0],
           &BL[0],
           &BU[0],
           _funcon,
           _funobj,
           &INFORM,
           &ITER,
           &ISTATE[0],
           &C[0],
           &CJAC[0],
           &CLAMBDA[0],
           &F,
           &G[0],
           &R[0],
           &X[0],
           &IW[0],
           &LENIW,
           &W[0],
           &LENW);
    
#endif // MAST_ENABLE_NPSOL 1
}
Exemple #13
0
unsigned int NewtonSolver::solve()
{
  START_LOG("solve()", "NewtonSolver");

  // Reset any prior solve result
  _solve_result = INVALID_SOLVE_RESULT;

  NumericVector<Number> & newton_iterate = *(_system.solution);

  UniquePtr<NumericVector<Number> > linear_solution_ptr = newton_iterate.zero_clone();
  NumericVector<Number> & linear_solution = *linear_solution_ptr;
  NumericVector<Number> & rhs = *(_system.rhs);

  newton_iterate.close();
  linear_solution.close();
  rhs.close();

#ifdef LIBMESH_ENABLE_CONSTRAINTS
  _system.get_dof_map().enforce_constraints_exactly(_system);
#endif

  SparseMatrix<Number> & matrix = *(_system.matrix);

  // Set starting linear tolerance
  Real current_linear_tolerance = initial_linear_tolerance;

  // Start counting our linear solver steps
  _inner_iterations = 0;

  // Now we begin the nonlinear loop
  for (_outer_iterations=0; _outer_iterations<max_nonlinear_iterations;
       ++_outer_iterations)
    {
      if (verbose)
        libMesh::out << "Assembling the System" << std::endl;

      _system.assembly(true, true);
      rhs.close();
      Real current_residual = rhs.l2_norm();

      if (libmesh_isnan(current_residual))
        {
          libMesh::out << "  Nonlinear solver DIVERGED at step "
                       << _outer_iterations
                       << " with residual Not-a-Number"
                       << std::endl;
          libmesh_convergence_failure();
          continue;
        }

      if (current_residual <= absolute_residual_tolerance)
        {
          if (verbose)
            libMesh::out << "Linear solve unnecessary; residual "
                         << current_residual
                         << " meets absolute tolerance "
                         << absolute_residual_tolerance
                         << std::endl;

          // We're not doing a solve, but other code may reuse this
          // matrix.
          matrix.close();

          _solve_result |= CONVERGED_ABSOLUTE_RESIDUAL;
          if (current_residual == 0)
            {
              if (relative_residual_tolerance > 0)
                _solve_result |= CONVERGED_RELATIVE_RESIDUAL;
              if (absolute_step_tolerance > 0)
                _solve_result |= CONVERGED_ABSOLUTE_STEP;
              if (relative_step_tolerance > 0)
                _solve_result |= CONVERGED_RELATIVE_STEP;
            }

          break;
        }

      // Prepare to take incomplete steps
      Real last_residual = current_residual;

      max_residual_norm = std::max (current_residual,
                                    max_residual_norm);

      // Compute the l2 norm of the whole solution
      Real norm_total = newton_iterate.l2_norm();

      max_solution_norm = std::max(max_solution_norm, norm_total);

      if (verbose)
        libMesh::out << "Nonlinear Residual: "
                     << current_residual << std::endl;

      // Make sure our linear tolerance is low enough
      current_linear_tolerance = std::min (current_linear_tolerance,
                                           current_residual * linear_tolerance_multiplier);

      // But don't let it be too small
      if (current_linear_tolerance < minimum_linear_tolerance)
        {
          current_linear_tolerance = minimum_linear_tolerance;
        }

      // If starting the nonlinear solve with a really good initial guess, we dont want to set an absurd linear tolerance
      current_linear_tolerance = std::max(current_linear_tolerance, absolute_residual_tolerance / current_residual / 10.0);

      // At this point newton_iterate is the current guess, and
      // linear_solution is now about to become the NEGATIVE of the next
      // Newton step.

      // Our best initial guess for the linear_solution is zero!
      linear_solution.zero();

      if (verbose)
        libMesh::out << "Linear solve starting, tolerance "
                     << current_linear_tolerance << std::endl;

      // Solve the linear system.
      const std::pair<unsigned int, Real> rval =
        linear_solver->solve (matrix, _system.request_matrix("Preconditioner"),
                              linear_solution, rhs, current_linear_tolerance,
                              max_linear_iterations);

      if (track_linear_convergence)
        {
          LinearConvergenceReason linear_c_reason = linear_solver->get_converged_reason();

          // Check if something went wrong during the linear solve
          if (linear_c_reason < 0)
            {
              // The linear solver failed somehow
              _solve_result |= DiffSolver::DIVERGED_LINEAR_SOLVER_FAILURE;
              // Print a message
              libMesh::out << "Linear solver failed during Newton step, dropping out."
                           << std::endl;
              break;
            }
        }

      // We may need to localize a parallel solution
      _system.update ();
      // The linear solver may not have fit our constraints exactly
#ifdef LIBMESH_ENABLE_CONSTRAINTS
      _system.get_dof_map().enforce_constraints_exactly
        (_system, &linear_solution, /* homogeneous = */ true);
#endif

      const unsigned int linear_steps = rval.first;
      libmesh_assert_less_equal (linear_steps, max_linear_iterations);
      _inner_iterations += linear_steps;

      const bool linear_solve_finished =
        !(linear_steps == max_linear_iterations);

      if (verbose)
        libMesh::out << "Linear solve finished, step " << linear_steps
                     << ", residual " << rval.second
                     << std::endl;

      // Compute the l2 norm of the nonlinear update
      Real norm_delta = linear_solution.l2_norm();

      if (verbose)
        libMesh::out << "Trying full Newton step" << std::endl;
      // Take a full Newton step
      newton_iterate.add (-1., linear_solution);
      newton_iterate.close();

      if (this->linear_solution_monitor.get())
        {
          // Compute the l2 norm of the whole solution
          norm_total = newton_iterate.l2_norm();
          rhs.close();
          (*this->linear_solution_monitor)(linear_solution, norm_delta,
                                           newton_iterate, norm_total,
                                           rhs, rhs.l2_norm(), _outer_iterations);
        }

      // Check residual with full Newton step, if that's useful for determining
      // whether to line search, whether to quit early, or whether to die after
      // hitting our max iteration count
      if (this->require_residual_reduction ||
          this->require_finite_residual ||
          _outer_iterations+1 < max_nonlinear_iterations ||
          !continue_after_max_iterations)
        {
          _system.assembly(true, false);

          rhs.close();
          current_residual = rhs.l2_norm();
          if (verbose)
            libMesh::out << "  Current Residual: "
                         << current_residual << std::endl;

          // don't fiddle around if we've already converged
          if (test_convergence(current_residual, norm_delta,
                               linear_solve_finished &&
                               current_residual <= last_residual))
            {
              if (!quiet)
                print_convergence(_outer_iterations, current_residual,
                                  norm_delta, linear_solve_finished &&
                                  current_residual <= last_residual);
              _outer_iterations++;
              break; // out of _outer_iterations for loop
            }
        }

      // since we're not converged, backtrack if necessary
      Real steplength =
        this->line_search(std::sqrt(TOLERANCE),
                          last_residual, current_residual,
                          newton_iterate, linear_solution);
      norm_delta *= steplength;

      // Check to see if backtracking failed,
      // and break out of the nonlinear loop if so...
      if (_solve_result == DiffSolver::DIVERGED_BACKTRACKING_FAILURE)
        {
          _outer_iterations++;
          break; // out of _outer_iterations for loop
        }

      if (_outer_iterations + 1 >= max_nonlinear_iterations)
        {
          libMesh::out << "  Nonlinear solver reached maximum step "
                       << max_nonlinear_iterations << ", latest evaluated residual "
                       << current_residual << std::endl;
          if (continue_after_max_iterations)
            {
              _solve_result = DiffSolver::DIVERGED_MAX_NONLINEAR_ITERATIONS;
              libMesh::out << "  Continuing..." << std::endl;
            }
          else
            {
              libmesh_convergence_failure();
            }
          continue;
        }

      // Compute the l2 norm of the whole solution
      norm_total = newton_iterate.l2_norm();

      max_solution_norm = std::max(max_solution_norm, norm_total);

      // Print out information for the
      // nonlinear iterations.
      if (verbose)
        libMesh::out << "  Nonlinear step: |du|/|u| = "
                     << norm_delta / norm_total
                     << ", |du| = " << norm_delta
                     << std::endl;

      // Terminate the solution iteration if the difference between
      // this iteration and the last is sufficiently small.
      if (test_convergence(current_residual, norm_delta / steplength,
                           linear_solve_finished))
        {
          if (!quiet)
            print_convergence(_outer_iterations, current_residual,
                              norm_delta / steplength,
                              linear_solve_finished);
          _outer_iterations++;
          break; // out of _outer_iterations for loop
        }
    } // end nonlinear loop

  // The linear solver may not have fit our constraints exactly
#ifdef LIBMESH_ENABLE_CONSTRAINTS
  _system.get_dof_map().enforce_constraints_exactly(_system);
#endif

  // We may need to localize a parallel solution
  _system.update ();

  STOP_LOG("solve()", "NewtonSolver");

  // Make sure we are returning something sensible as the
  // _solve_result, except in the edge case where we weren't really asked to
  // solve.
  libmesh_assert (_solve_result != DiffSolver::INVALID_SOLVE_RESULT ||
                  !max_nonlinear_iterations);

  return _solve_result;
}
Exemple #14
0
Real FE<1,XYZ>::shape(const Elem* elem,
		      const Order libmesh_dbg_var(order),
		      const unsigned int i,
		      const Point& p)
{
  libmesh_assert (elem != NULL);
  libmesh_assert (i <= order + elem->p_level());

  // Only recompute the centroid if the element
  // has changed from the last one we computed.
  // This avoids repeated centroid calculations
  // when called in succession with the same element.
  if (elem->id() != old_elem_id)
    {
      centroid = elem->centroid();
      old_elem_id = elem->id();
      max_distance = 0.;
      for (unsigned int p = 0; p < elem->n_nodes(); p++)
      {
        const Real distance = std::abs(centroid(0) - elem->point(p)(0));
        max_distance = std::max(distance, max_distance);
      }
    }

  // Using static globals for old_elem_id, etc. will fail
  // horribly with more than one thread.
  libmesh_assert(libMesh::n_threads() == 1);

  const Real x  = p(0);
  const Real xc = centroid(0);
  const Real dx = (x - xc)/max_distance;

  // monomials. since they are hierarchic we only need one case block.
  switch (i)
    {
    case 0:
      return 1.;

    case 1:
      return dx;

    case 2:
      return dx*dx;

    case 3:
      return dx*dx*dx;

    case 4:
      return dx*dx*dx*dx;

    default:
      Real val = 1.;
      for (unsigned int index = 0; index != i; ++index)
        val *= dx;
      return val;
    }

  libmesh_error();
  return 0.;

}
void InfFE<Dim,T_radial,T_base>::init_face_shape_functions(const std::vector<Point>&,
                                                           const Elem* inf_side)
{
  libmesh_assert(inf_side);

  // Currently, this makes only sense in 3-D!
  libmesh_assert_equal_to (Dim, 3);

  // Initialiize the radial shape functions
  this->init_radial_shape_functions(inf_side);

  // Initialize the base shape functions
  this->update_base_elem(inf_side);

  // Initialize the base quadratur rule
  base_qrule->init(base_elem->type(), inf_side->p_level());

  // base_fe still corresponds to the (dim-1)-dimensional base of the InfFE object,
  // so update the fe_base.
  {
    libmesh_assert_equal_to (Dim, 3);

    UniquePtr<FEBase> ap_fb(FEBase::build(Dim-2, this->fe_type));

    delete base_fe;
    base_fe = ap_fb.release();
    base_fe->attach_quadrature_rule(base_qrule);
  }

  // initialize the shape functions on the base
  base_fe->init_base_shape_functions(base_fe->qrule->get_points(),
                                     base_elem);

  // the number of quadrature points
  const unsigned int n_radial_qp =
    cast_int<unsigned int>(som.size());
  const unsigned int n_base_qp   = base_qrule->n_points();
  const unsigned int n_total_qp  = n_radial_qp * n_base_qp;

  // the quadratur weigths
  _total_qrule_weights.resize(n_total_qp);

  // now inite the shapes for boundary work
  {

    // The element type and order to use in the base map
    const Order    base_mapping_order     ( base_elem->default_order() );
    const ElemType base_mapping_elem_type ( base_elem->type()          );

    // the number of mapping shape functions
    // (Lagrange shape functions are used for mapping in the base)
    const unsigned int n_radial_mapping_sf =
      cast_int<unsigned int>(radial_map.size());
    const unsigned int n_base_mapping_shape_functions = Base::n_base_mapping_sf(base_mapping_elem_type,
                                                                                base_mapping_order);

    const unsigned int n_total_mapping_shape_functions =
      n_radial_mapping_sf * n_base_mapping_shape_functions;


    // initialize the node and shape numbering maps
    {
      _radial_node_index.resize    (n_total_mapping_shape_functions);
      _base_node_index.resize      (n_total_mapping_shape_functions);

      const ElemType inf_face_elem_type (inf_side->type());

      // fill the node index map
      for (unsigned int n=0; n<n_total_mapping_shape_functions; n++)
        {
          compute_node_indices (inf_face_elem_type,
                                n,
                                _base_node_index[n],
                                _radial_node_index[n]);

          libmesh_assert_less (_base_node_index[n], n_base_mapping_shape_functions);
          libmesh_assert_less (_radial_node_index[n], n_radial_mapping_sf);
        }

    }

    // rezise map data fields
    {
      std::vector<std::vector<Real> >& psi_map = this->_fe_map->get_psi();
      std::vector<std::vector<Real> >& dpsidxi_map = this->_fe_map->get_dpsidxi();
      std::vector<std::vector<Real> >& d2psidxi2_map = this->_fe_map->get_d2psidxi2();
      psi_map.resize          (n_total_mapping_shape_functions);
      dpsidxi_map.resize      (n_total_mapping_shape_functions);
      d2psidxi2_map.resize    (n_total_mapping_shape_functions);

      //  if (Dim == 3)
      {
        std::vector<std::vector<Real> >& dpsideta_map = this->_fe_map->get_dpsideta();
        std::vector<std::vector<Real> >& d2psidxideta_map = this->_fe_map->get_d2psidxideta();
        std::vector<std::vector<Real> >& d2psideta2_map = this->_fe_map->get_d2psideta2();
        dpsideta_map.resize     (n_total_mapping_shape_functions);
        d2psidxideta_map.resize (n_total_mapping_shape_functions);
        d2psideta2_map.resize   (n_total_mapping_shape_functions);
      }

      for (unsigned int i=0; i<n_total_mapping_shape_functions; i++)
        {
          psi_map[i].resize         (n_total_qp);
          dpsidxi_map[i].resize     (n_total_qp);
          d2psidxi2_map[i].resize   (n_total_qp);

          // if (Dim == 3)
          {
            std::vector<std::vector<Real> >& dpsideta_map = this->_fe_map->get_dpsideta();
            std::vector<std::vector<Real> >& d2psidxideta_map = this->_fe_map->get_d2psidxideta();
            std::vector<std::vector<Real> >& d2psideta2_map = this->_fe_map->get_d2psideta2();
            dpsideta_map[i].resize     (n_total_qp);
            d2psidxideta_map[i].resize (n_total_qp);
            d2psideta2_map[i].resize   (n_total_qp);
          }
        }
    }


    // compute shape maps
    {
      const std::vector<std::vector<Real> >& S_map  = (base_fe->get_fe_map()).get_phi_map();
      const std::vector<std::vector<Real> >& Ss_map = (base_fe->get_fe_map()).get_dphidxi_map();

      std::vector<std::vector<Real> >& psi_map = this->_fe_map->get_psi();
      std::vector<std::vector<Real> >& dpsidxi_map = this->_fe_map->get_dpsidxi();
      std::vector<std::vector<Real> >& dpsideta_map = this->_fe_map->get_dpsideta();

      for (unsigned int rp=0; rp<n_radial_qp; rp++)  // over radial qp's
        for (unsigned int bp=0; bp<n_base_qp; bp++)  // over base qp's
          for (unsigned int ti=0; ti<n_total_mapping_shape_functions; ti++)  // over all mapping shapes
            {
              // let the index vectors take care of selecting the appropriate base/radial mapping shape
              const unsigned int bi = _base_node_index  [ti];
              const unsigned int ri = _radial_node_index[ti];
              psi_map          [ti][bp+rp*n_base_qp] = S_map [bi][bp] * radial_map   [ri][rp];
              dpsidxi_map      [ti][bp+rp*n_base_qp] = Ss_map[bi][bp] * radial_map   [ri][rp];
              dpsideta_map     [ti][bp+rp*n_base_qp] = S_map [bi][bp] * dradialdv_map[ri][rp];

              // second derivatives are not implemented for infinite elements
              // d2psidxi2_map    [ti][bp+rp*n_base_qp] = 0.;
              // d2psidxideta_map [ti][bp+rp*n_base_qp] = 0.;
              // d2psideta2_map   [ti][bp+rp*n_base_qp] = 0.;
            }

    }

  }

  // quadrature rule weights
  {
    const std::vector<Real>&   radial_qw = radial_qrule->get_weights();
    const std::vector<Real>&   base_qw   = base_qrule->get_weights();

    libmesh_assert_equal_to (radial_qw.size(), n_radial_qp);
    libmesh_assert_equal_to (base_qw.size(), n_base_qp);

    for (unsigned int rp=0; rp<n_radial_qp; rp++)
      for (unsigned int bp=0; bp<n_base_qp; bp++)
        {
          _total_qrule_weights[  bp+rp*n_base_qp ] = radial_qw[rp] * base_qw[bp];
        }
  }

}
Exemple #16
0
Real Prism6::volume () const
{
  // The volume of the prism is computed by splitting
  // it into 2 tetrahedra and 3 pyramids with bilinear bases.
  // Then the volume formulae for the tetrahedron and pyramid
  // are applied and summed to obtain the prism's volume.

  static const unsigned char sub_pyr[3][4] =
    {
      {0, 1, 4, 3},
      {1, 2, 5, 4},
      {0, 3, 5, 2}
    };

  static const unsigned char sub_tet[2][3] =
    {
      {0, 1, 2},
      {5, 4, 3}
    };

  // The centroid is a convenient point to use
  // for the apex of all the pyramids.
  const Point R = this->centroid();

  // temporary storage for Nodes which form the base of the
  // subelements
  Node* base[4];

  // volume accumulation variable
  Real vol=0.;

  // Add up the sub-pyramid volumes
  for (unsigned int n=0; n<3; ++n)
    {
      // Set the nodes of the pyramid base
      for (unsigned int i=0; i<4; ++i)
	base[i] = this->_nodes[sub_pyr[n][i]];

      // Compute diff vectors
      Point a ( *base[0] - R );
      Point b ( *base[1] - *base[3] );
      Point c ( *base[2] - *base[0] );
      Point d ( *base[3] - *base[0] );
      Point e ( *base[1] - *base[0] );

      // Compute pyramid volume
      Real sub_vol = (1./6.)*(a*(b.cross(c))) + (1./12.)*(c*(d.cross(e)));

      libmesh_assert (sub_vol>0.);

      vol += sub_vol;
    }


  // Add up the sub-tet volumes
  for (unsigned int n=0; n<2; ++n)
    {
      // Set the nodes of the pyramid base
      for (unsigned int i=0; i<3; ++i)
	base[i] = this->_nodes[sub_tet[n][i]];

      // The volume of a tetrahedron is 1/6 the box product formed
      // by its base and apex vectors
      Point a ( R - *base[0] );

      // b is the vector pointing from 0 to 1
      Point b ( *base[1] - *base[0] );

      // c is the vector pointing from 0 to 2
      Point c ( *base[2] - *base[0] );

      Real sub_vol =  (1.0 / 6.0) * (a * (b.cross(c)));

      libmesh_assert (sub_vol>0.);

      vol += sub_vol;
    }


  // Done with all sub-volumes, so return
  return vol;
}
void InfFE<Dim,T_radial,T_base>::reinit(const Elem* inf_elem,
                                        const unsigned int s,
                                        const Real tolerance,
                                        const std::vector<Point>* const pts,
                                        const std::vector<Real>* const weights)
{
  if (weights != NULL)
    libmesh_not_implemented_msg("ERROR: User-specified weights for infinite elements are not implemented!");

  if (pts != NULL)
    libmesh_not_implemented_msg("ERROR: User-specified points for infinite elements are not implemented!");

  // We don't do this for 1D elements!
  libmesh_assert_not_equal_to (Dim, 1);

  libmesh_assert(inf_elem);
  libmesh_assert(qrule);

  // Don't do this for the base
  libmesh_assert_not_equal_to (s, 0);

  // Build the side of interest
  const UniquePtr<Elem> side(inf_elem->build_side(s));

  // set the element type
  elem_type = inf_elem->type();

  // eventually initialize radial quadrature rule
  bool radial_qrule_initialized = false;

  if (current_fe_type.radial_order != fe_type.radial_order)
    {
      current_fe_type.radial_order = fe_type.radial_order;
      radial_qrule->init(EDGE2, inf_elem->p_level());
      radial_qrule_initialized = true;
    }

  // Initialize the face shape functions
  if (this->get_type() != inf_elem->type() ||
      base_fe->shapes_need_reinit()        ||
      radial_qrule_initialized)
    this->init_face_shape_functions (qrule->get_points(), side.get());


  // compute the face map
  this->_fe_map->compute_face_map(this->dim, _total_qrule_weights, side.get());

  // make a copy of the Jacobian for integration
  const std::vector<Real> JxW_int(this->_fe_map->get_JxW());

  // Find where the integration points are located on the
  // full element.
  std::vector<Point> qp; this->inverse_map (inf_elem, this->_fe_map->get_xyz(),
                                            qp, tolerance);

  // compute the shape function and derivative values
  // at the points qp
  this->reinit  (inf_elem, &qp);

  // copy back old data
  this->_fe_map->get_JxW() = JxW_int;

}
void ParmetisPartitioner::initialize (const MeshBase& mesh,
                                      const unsigned int n_sbdmns)
{
  const dof_id_type n_active_local_elem = mesh.n_active_local_elem();

  // Set parameters.
  _pmetis->wgtflag = 2;                                      // weights on vertices only
  _pmetis->ncon    = 1;                                      // one weight per vertex
  _pmetis->numflag = 0;                                      // C-style 0-based numbering
  _pmetis->nparts  = static_cast<Parmetis::idx_t>(n_sbdmns); // number of subdomains to create
  _pmetis->edgecut = 0;                                      // the numbers of edges cut by the
                                                             // partition

  // Initialize data structures for ParMETIS
  _pmetis->vtxdist.resize (mesh.n_processors()+1); std::fill (_pmetis->vtxdist.begin(), _pmetis->vtxdist.end(), 0);
  _pmetis->tpwgts.resize  (_pmetis->nparts);       std::fill (_pmetis->tpwgts.begin(),  _pmetis->tpwgts.end(),  1./_pmetis->nparts);
  _pmetis->ubvec.resize   (_pmetis->ncon);         std::fill (_pmetis->ubvec.begin(),   _pmetis->ubvec.end(),   1.05);
  _pmetis->part.resize    (n_active_local_elem);   std::fill (_pmetis->part.begin(),    _pmetis->part.end(), 0);
  _pmetis->options.resize (5);
  _pmetis->vwgt.resize    (n_active_local_elem);

  // Set the options
  _pmetis->options[0] = 1;  // don't use default options
  _pmetis->options[1] = 0;  // default (level of timing)
  _pmetis->options[2] = 15; // random seed (default)
  _pmetis->options[3] = 2;  // processor distribution and subdomain distribution are decoupled

  // Find the number of active elements on each processor.  We cannot use
  // mesh.n_active_elem_on_proc(pid) since that only returns the number of
  // elements assigned to pid which are currently stored on the calling
  // processor. This will not in general be correct for parallel meshes
  // when (pid!=mesh.processor_id()).
  _n_active_elem_on_proc.resize(mesh.n_processors());
  mesh.comm().allgather(n_active_local_elem, _n_active_elem_on_proc);

  // count the total number of active elements in the mesh.  Note we cannot
  // use mesh.n_active_elem() in general since this only returns the number
  // of active elements which are stored on the calling processor.
  // We should not use n_active_elem for any allocation because that will
  // be inheritly unscalable, but it can be useful for libmesh_assertions.
  dof_id_type n_active_elem=0;

  // Set up the vtxdist array.  This will be the same on each processor.
  // ***** Consult the Parmetis documentation. *****
  libmesh_assert_equal_to (_pmetis->vtxdist.size(),
                           cast_int<std::size_t>(mesh.n_processors()+1));
  libmesh_assert_equal_to (_pmetis->vtxdist[0], 0);

  for (processor_id_type pid=0; pid<mesh.n_processors(); pid++)
    {
      _pmetis->vtxdist[pid+1] = _pmetis->vtxdist[pid] + _n_active_elem_on_proc[pid];
      n_active_elem += _n_active_elem_on_proc[pid];
    }
  libmesh_assert_equal_to (_pmetis->vtxdist.back(), static_cast<Parmetis::idx_t>(n_active_elem));

  // ParMetis expects the elements to be numbered in contiguous blocks
  // by processor, i.e. [0, ne0), [ne0, ne0+ne1), ...
  // Since we only partition active elements we should have no expectation
  // that we currently have such a distribution.  So we need to create it.
  // Also, at the same time we are going to map all the active elements into a globally
  // unique range [0,n_active_elem) which is *independent* of the current partitioning.
  // This can be fed to ParMetis as the initial partitioning of the subdomains (decoupled
  // from the partitioning of the objects themselves).  This allows us to get the same
  // resultant partitioning independed of the input partitioning.
  MeshTools::BoundingBox bbox =
    MeshTools::bounding_box(mesh);

  _global_index_by_pid_map.clear();

  // Maps active element ids into a contiguous range independent of partitioning.
  // (only needs local scope)
  vectormap<dof_id_type, dof_id_type> global_index_map;

  {
    std::vector<dof_id_type> global_index;

    // create the mapping which is contiguous by processor
    dof_id_type pid_offset=0;
    for (processor_id_type pid=0; pid<mesh.n_processors(); pid++)
      {
        MeshBase::const_element_iterator       it  = mesh.active_pid_elements_begin(pid);
        const MeshBase::const_element_iterator end = mesh.active_pid_elements_end(pid);

        // note that we may not have all (or any!) the active elements which belong on this processor,
        // but by calling this on all processors a unique range in [0,_n_active_elem_on_proc[pid])
        // is constructed.  Only the indices for the elements we pass in are returned in the array.
        MeshCommunication().find_global_indices (mesh.comm(),
                                                 bbox, it, end,
                                                 global_index);

        for (dof_id_type cnt=0; it != end; ++it)
          {
            const Elem *elem = *it;
            libmesh_assert (!_global_index_by_pid_map.count(elem->id()));
            libmesh_assert_less (cnt, global_index.size());
            libmesh_assert_less (global_index[cnt], _n_active_elem_on_proc[pid]);

            _global_index_by_pid_map.insert(std::make_pair(elem->id(), global_index[cnt++] + pid_offset));
          }

        pid_offset += _n_active_elem_on_proc[pid];
      }

    // create the unique mapping for all active elements independent of partitioning
    {
      MeshBase::const_element_iterator       it  = mesh.active_elements_begin();
      const MeshBase::const_element_iterator end = mesh.active_elements_end();

      // Calling this on all processors a unique range in [0,n_active_elem) is constructed.
      // Only the indices for the elements we pass in are returned in the array.
      MeshCommunication().find_global_indices (mesh.comm(),
                                               bbox, it, end,
                                               global_index);

      for (dof_id_type cnt=0; it != end; ++it)
        {
          const Elem *elem = *it;
          libmesh_assert (!global_index_map.count(elem->id()));
          libmesh_assert_less (cnt, global_index.size());
          libmesh_assert_less (global_index[cnt], n_active_elem);

          global_index_map.insert(std::make_pair(elem->id(), global_index[cnt++]));
        }
    }
    // really, shouldn't be close!
    libmesh_assert_less_equal (global_index_map.size(), n_active_elem);
    libmesh_assert_less_equal (_global_index_by_pid_map.size(), n_active_elem);

    // At this point the two maps should be the same size.  If they are not
    // then the number of active elements is not the same as the sum over all
    // processors of the number of active elements per processor, which means
    // there must be some unpartitioned objects out there.
    if (global_index_map.size() != _global_index_by_pid_map.size())
      libmesh_error_msg("ERROR:  ParmetisPartitioner cannot handle unpartitioned objects!");
  }

  // Finally, we need to initialize the vertex (partition) weights and the initial subdomain
  // mapping.  The subdomain mapping will be independent of the processor mapping, and is
  // defined by a simple mapping of the global indices we just found.
  {
    std::vector<dof_id_type> subdomain_bounds(mesh.n_processors());

    const dof_id_type first_local_elem = _pmetis->vtxdist[mesh.processor_id()];

    for (processor_id_type pid=0; pid<mesh.n_processors(); pid++)
      {
        dof_id_type tgt_subdomain_size = 0;

        // watch out for the case that n_subdomains < n_processors
        if (pid < static_cast<unsigned int>(_pmetis->nparts))
          {
            tgt_subdomain_size = n_active_elem/std::min
              (cast_int<Parmetis::idx_t>(mesh.n_processors()), _pmetis->nparts);

            if (pid < n_active_elem%_pmetis->nparts)
              tgt_subdomain_size++;
          }
        if (pid == 0)
          subdomain_bounds[0] = tgt_subdomain_size;
        else
          subdomain_bounds[pid] = subdomain_bounds[pid-1] + tgt_subdomain_size;
      }

    libmesh_assert_equal_to (subdomain_bounds.back(), n_active_elem);

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

        libmesh_assert (_global_index_by_pid_map.count(elem->id()));
        const dof_id_type global_index_by_pid =
          _global_index_by_pid_map[elem->id()];
        libmesh_assert_less (global_index_by_pid, n_active_elem);

        const dof_id_type local_index =
          global_index_by_pid - first_local_elem;

        libmesh_assert_less (local_index, n_active_local_elem);
        libmesh_assert_less (local_index, _pmetis->vwgt.size());

        // TODO:[BSK] maybe there is a better weight?
        _pmetis->vwgt[local_index] = elem->n_nodes();

        // find the subdomain this element belongs in
        libmesh_assert (global_index_map.count(elem->id()));
        const dof_id_type global_index =
          global_index_map[elem->id()];

        libmesh_assert_less (global_index, subdomain_bounds.back());

        const unsigned int subdomain_id =
          std::distance(subdomain_bounds.begin(),
                        std::lower_bound(subdomain_bounds.begin(),
                                         subdomain_bounds.end(),
                                         global_index));
        libmesh_assert_less (subdomain_id, static_cast<unsigned int>(_pmetis->nparts));
        libmesh_assert_less (local_index, _pmetis->part.size());

        _pmetis->part[local_index] = subdomain_id;
      }
  }
}
Real AdaptiveTimeSolver::error_order () const
{
  libmesh_assert(core_time_solver.get());

  return core_time_solver->error_order();
}
void ParmetisPartitioner::build_graph (const MeshBase& mesh)
{
  // build the graph in distributed CSR format.  Note that
  // the edges in the graph will correspond to
  // face neighbors
  const dof_id_type n_active_local_elem  = mesh.n_active_local_elem();

  // If we have boundary elements in this mesh, we want to account for
  // the connectivity between them and interior elements.  We can find
  // interior elements from boundary elements, but we need to build up
  // a lookup map to do the reverse.

  typedef LIBMESH_BEST_UNORDERED_MAP<const Elem *, const Elem *>
    map_type;
  map_type interior_to_boundary_map;

  {
    MeshBase::const_element_iterator       elem_it  = mesh.active_elements_begin();
    const MeshBase::const_element_iterator elem_end = mesh.active_elements_end();

    for (; elem_it != elem_end; ++elem_it)
      {
        const Elem* elem = *elem_it;

        // If we don't have an interior_parent then there's nothing to look us
        // up.
        if ((elem->dim() >= LIBMESH_DIM) ||
            !elem->interior_parent())
          continue;

        // get all relevant interior elements
        std::set<const Elem*> neighbor_set;
        elem->find_interior_neighbors(neighbor_set);

        std::set<const Elem*>::iterator n_it = neighbor_set.begin();
        for (; n_it != neighbor_set.end(); ++n_it)
          {
            // FIXME - non-const versions of the Elem set methods
            // would be nice
            Elem* neighbor = const_cast<Elem*>(*n_it);

#if defined(LIBMESH_HAVE_UNORDERED_MAP) || defined(LIBMESH_HAVE_TR1_UNORDERED_MAP) || defined(LIBMESH_HAVE_HASH_MAP) || defined(LIBMESH_HAVE_EXT_HASH_MAP)
            interior_to_boundary_map.insert
              (std::make_pair(neighbor, elem));
#else
            interior_to_boundary_map.insert
              (interior_to_boundary_map.begin(),
               std::make_pair(neighbor, elem));
#endif
          }
      }
  }

#ifdef LIBMESH_ENABLE_AMR
  std::vector<const Elem*> neighbors_offspring;
#endif

  std::vector<std::vector<dof_id_type> > graph(n_active_local_elem);
  dof_id_type graph_size=0;

  const dof_id_type first_local_elem = _pmetis->vtxdist[mesh.processor_id()];

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

      libmesh_assert (_global_index_by_pid_map.count(elem->id()));
      const dof_id_type global_index_by_pid =
        _global_index_by_pid_map[elem->id()];

      const dof_id_type local_index =
        global_index_by_pid - first_local_elem;
      libmesh_assert_less (local_index, n_active_local_elem);

      std::vector<dof_id_type> &graph_row = graph[local_index];

      // Loop over the element's neighbors.  An element
      // adjacency corresponds to a face neighbor
      for (unsigned int ms=0; ms<elem->n_neighbors(); ms++)
        {
          const Elem* neighbor = elem->neighbor(ms);

          if (neighbor != NULL)
            {
              // If the neighbor is active treat it
              // as a connection
              if (neighbor->active())
                {
                  libmesh_assert(_global_index_by_pid_map.count(neighbor->id()));
                  const dof_id_type neighbor_global_index_by_pid =
                    _global_index_by_pid_map[neighbor->id()];

                  graph_row.push_back(neighbor_global_index_by_pid);
                  graph_size++;
                }

#ifdef LIBMESH_ENABLE_AMR

              // Otherwise we need to find all of the
              // neighbor's children that are connected to
              // us and add them
              else
                {
                  // The side of the neighbor to which
                  // we are connected
                  const unsigned int ns =
                    neighbor->which_neighbor_am_i (elem);
                  libmesh_assert_less (ns, neighbor->n_neighbors());

                  // Get all the active children (& grandchildren, etc...)
                  // of the neighbor

                  // FIXME - this is the wrong thing, since we
                  // should be getting the active family tree on
                  // our side only.  But adding too many graph
                  // links may cause hanging nodes to tend to be
                  // on partition interiors, which would reduce
                  // communication overhead for constraint
                  // equations, so we'll leave it.

                  neighbor->active_family_tree (neighbors_offspring);

                  // Get all the neighbor's children that
                  // live on that side and are thus connected
                  // to us
                  for (unsigned int nc=0; nc<neighbors_offspring.size(); nc++)
                    {
                      const Elem* child =
                        neighbors_offspring[nc];

                      // This does not assume a level-1 mesh.
                      // Note that since children have sides numbered
                      // coincident with the parent then this is a sufficient test.
                      if (child->neighbor(ns) == elem)
                        {
                          libmesh_assert (child->active());
                          libmesh_assert (_global_index_by_pid_map.count(child->id()));
                          const dof_id_type child_global_index_by_pid =
                            _global_index_by_pid_map[child->id()];

                          graph_row.push_back(child_global_index_by_pid);
                          graph_size++;
                        }
                    }
                }

#endif /* ifdef LIBMESH_ENABLE_AMR */


            }
        }

      if ((elem->dim() < LIBMESH_DIM) &&
          elem->interior_parent())
        {
          // get all relevant interior elements
          std::set<const Elem*> neighbor_set;
          elem->find_interior_neighbors(neighbor_set);

          std::set<const Elem*>::iterator n_it = neighbor_set.begin();
          for (; n_it != neighbor_set.end(); ++n_it)
            {
              // FIXME - non-const versions of the Elem set methods
              // would be nice
              Elem* neighbor = const_cast<Elem*>(*n_it);

              const dof_id_type neighbor_global_index_by_pid =
                _global_index_by_pid_map[neighbor->id()];

              graph_row.push_back(neighbor_global_index_by_pid);
              graph_size++;
            }
        }

      // Check for any boundary neighbors
      typedef map_type::iterator map_it_type;
      std::pair<map_it_type, map_it_type>
        bounds = interior_to_boundary_map.equal_range(elem);

      for (map_it_type it = bounds.first; it != bounds.second; ++it)
        {
          const Elem* neighbor = it->second;

          const dof_id_type neighbor_global_index_by_pid =
            _global_index_by_pid_map[neighbor->id()];

          graph_row.push_back(neighbor_global_index_by_pid);
          graph_size++;
        }
    }

  // Reserve space in the adjacency array
  _pmetis->xadj.clear();
  _pmetis->xadj.reserve (n_active_local_elem + 1);
  _pmetis->adjncy.clear();
  _pmetis->adjncy.reserve (graph_size);

  for (std::size_t r=0; r<graph.size(); r++)
    {
      _pmetis->xadj.push_back(_pmetis->adjncy.size());
      std::vector<dof_id_type> graph_row; // build this emtpy
      graph_row.swap(graph[r]); // this will deallocate at the end of scope
      _pmetis->adjncy.insert(_pmetis->adjncy.end(),
                             graph_row.begin(),
                             graph_row.end());
    }

  // The end of the adjacency array for the last elem
  _pmetis->xadj.push_back(_pmetis->adjncy.size());

  libmesh_assert_equal_to (_pmetis->xadj.size(), n_active_local_elem+1);
  libmesh_assert_equal_to (_pmetis->adjncy.size(), graph_size);
}
void TwostepTimeSolver::solve()
{
  libmesh_assert(core_time_solver.get());

  // The core_time_solver will handle any first_solve actions
  first_solve = false;

  // We may have to repeat timesteps entirely if our error is bad
  // enough
  bool max_tolerance_met = false;

  // Calculating error values each time
  Real single_norm(0.), double_norm(0.), error_norm(0.),
    relative_error(0.);

  while (!max_tolerance_met)
    {
      // If we've been asked to reduce deltat if necessary, make sure
      // the core timesolver does so
      core_time_solver->reduce_deltat_on_diffsolver_failure =
        this->reduce_deltat_on_diffsolver_failure;

      if (!quiet)
        {
          libMesh::out << "\n === Computing adaptive timestep === "
                       << std::endl;
        }

      // Use the double-length timestep first (so the
      // old_nonlinear_solution won't have to change)
      core_time_solver->solve();

      // Save a copy of the double-length nonlinear solution
      // and the old nonlinear solution
      UniquePtr<NumericVector<Number> > double_solution =
        _system.solution->clone();
      UniquePtr<NumericVector<Number> > old_solution =
        _system.get_vector("_old_nonlinear_solution").clone();

      double_norm = calculate_norm(_system, *double_solution);
      if (!quiet)
        {
          libMesh::out << "Double norm = " << double_norm << std::endl;
        }

      // Then reset the initial guess for our single-length calcs
      *(_system.solution) = _system.get_vector("_old_nonlinear_solution");

      // Call two single-length timesteps
      // Be sure that the core_time_solver does not change the
      // timestep here.  (This is unlikely because it just succeeded
      // with a timestep twice as large!)
      // FIXME: even if diffsolver failure is unlikely, we ought to
      // do *something* if it happens
      core_time_solver->reduce_deltat_on_diffsolver_failure = 0;

      Real old_time = _system.time;
      Real old_deltat = _system.deltat;
      _system.deltat *= 0.5;
      core_time_solver->solve();
      core_time_solver->advance_timestep();
      core_time_solver->solve();

      single_norm = calculate_norm(_system, *_system.solution);
      if (!quiet)
        {
          libMesh::out << "Single norm = " << single_norm << std::endl;
        }

      // Reset the core_time_solver's reduce_deltat... value.
      core_time_solver->reduce_deltat_on_diffsolver_failure =
        this->reduce_deltat_on_diffsolver_failure;

      // But then back off just in case our advance_timestep() isn't
      // called.
      // FIXME: this probably doesn't work with multistep methods
      _system.get_vector("_old_nonlinear_solution") = *old_solution;
      _system.time = old_time;
      _system.deltat = old_deltat;

      // Find the relative error
      *double_solution -= *(_system.solution);
      error_norm  = calculate_norm(_system, *double_solution);
      relative_error = error_norm / _system.deltat /
        std::max(double_norm, single_norm);

      // If the relative error makes no sense, we're done
      if (!double_norm && !single_norm)
        return;

      if (!quiet)
        {
          libMesh::out << "Error norm = " << error_norm << std::endl;
          libMesh::out << "Local relative error = "
                       << (error_norm /
                           std::max(double_norm, single_norm))
                       << std::endl;
          libMesh::out << "Global relative error = "
                       << (error_norm / _system.deltat /
                           std::max(double_norm, single_norm))
                       << std::endl;
          libMesh::out << "old delta t = " << _system.deltat << std::endl;
        }

      // If our upper tolerance is negative, that means we want to set
      // it based on the first successful time step
      if (this->upper_tolerance < 0)
        this->upper_tolerance = -this->upper_tolerance * relative_error;

      // If we haven't met our upper error tolerance, we'll have to
      // repeat this timestep entirely
      if (this->upper_tolerance && relative_error > this->upper_tolerance)
        {
          // Reset the initial guess for our next try
          *(_system.solution) =
            _system.get_vector("_old_nonlinear_solution");

          // Chop delta t in half
          _system.deltat /= 2.;

          if (!quiet)
            {
              libMesh::out << "Failed to meet upper error tolerance"
                           << std::endl;
              libMesh::out << "Retrying with delta t = "
                           << _system.deltat << std::endl;
            }
        }
      else
        max_tolerance_met = true;
    }


  // Otherwise, compare the relative error to the tolerance
  // and adjust deltat
  last_deltat = _system.deltat;

  // If our target tolerance is negative, that means we want to set
  // it based on the first successful time step
  if (this->target_tolerance < 0)
    this->target_tolerance = -this->target_tolerance * relative_error;

  const Real global_shrink_or_growth_factor =
    std::pow(this->target_tolerance / relative_error,
             static_cast<Real>(1. / core_time_solver->error_order()));

  const Real local_shrink_or_growth_factor =
    std::pow(this->target_tolerance /
             (error_norm/std::max(double_norm, single_norm)),
             static_cast<Real>(1. / (core_time_solver->error_order()+1.)));

  if (!quiet)
    {
      libMesh::out << "The global growth/shrink factor is: "
                   << global_shrink_or_growth_factor << std::endl;
      libMesh::out << "The local growth/shrink factor is: "
                   << local_shrink_or_growth_factor << std::endl;
    }

  // The local s.o.g. factor is based on the expected **local**
  // truncation error for the timestepping method, the global
  // s.o.g. factor is based on the method's **global** truncation
  // error.  You can shrink/grow the timestep to attempt to satisfy
  // either a global or local time-discretization error tolerance.

  Real shrink_or_growth_factor =
    this->global_tolerance ? global_shrink_or_growth_factor :
    local_shrink_or_growth_factor;

  if (this->max_growth && this->max_growth < shrink_or_growth_factor)
    {
      if (!quiet && this->global_tolerance)
        {
          libMesh::out << "delta t is constrained by max_growth" << std::endl;
        }
      shrink_or_growth_factor = this->max_growth;
    }

  _system.deltat *= shrink_or_growth_factor;

  // Restrict deltat to max-allowable value if necessary
  if ((this->max_deltat != 0.0) && (_system.deltat > this->max_deltat))
    {
      if (!quiet)
        {
          libMesh::out << "delta t is constrained by maximum-allowable delta t."
                       << std::endl;
        }
      _system.deltat = this->max_deltat;
    }

  // Restrict deltat to min-allowable value if necessary
  if ((this->min_deltat != 0.0) && (_system.deltat < this->min_deltat))
    {
      if (!quiet)
        {
          libMesh::out << "delta t is constrained by minimum-allowable delta t."
                       << std::endl;
        }
      _system.deltat = this->min_deltat;
    }

  if (!quiet)
    {
      libMesh::out << "new delta t = " << _system.deltat << std::endl;
    }
}
void ParmetisPartitioner::assign_partitioning (MeshBase& mesh)
{
  // This function must be run on all processors at once
  libmesh_parallel_only(mesh.comm());

  const dof_id_type
    first_local_elem = _pmetis->vtxdist[mesh.processor_id()];

  std::vector<std::vector<dof_id_type> >
    requested_ids(mesh.n_processors()),
    requests_to_fill(mesh.n_processors());

  MeshBase::element_iterator elem_it  = mesh.active_elements_begin();
  MeshBase::element_iterator elem_end = mesh.active_elements_end();

  for (; elem_it != elem_end; ++elem_it)
    {
      Elem *elem = *elem_it;

      // we need to get the index from the owning processor
      // (note we cannot assign it now -- we are iterating
      // over elements again and this will be bad!)
      libmesh_assert_less (elem->processor_id(), requested_ids.size());
      requested_ids[elem->processor_id()].push_back(elem->id());
    }

  // Trade with all processors (including self) to get their indices
  for (processor_id_type pid=0; pid<mesh.n_processors(); pid++)
    {
      // Trade my requests with processor procup and procdown
      const processor_id_type procup = (mesh.processor_id() + pid) % mesh.n_processors();
      const processor_id_type procdown = (mesh.n_processors() +
                                          mesh.processor_id() - pid) % mesh.n_processors();

      mesh.comm().send_receive (procup,   requested_ids[procup],
                                procdown, requests_to_fill[procdown]);

      // we can overwrite these requested ids in-place.
      for (std::size_t i=0; i<requests_to_fill[procdown].size(); i++)
        {
          const dof_id_type requested_elem_index =
            requests_to_fill[procdown][i];

          libmesh_assert(_global_index_by_pid_map.count(requested_elem_index));

          const dof_id_type global_index_by_pid =
            _global_index_by_pid_map[requested_elem_index];

          const dof_id_type local_index =
            global_index_by_pid - first_local_elem;

          libmesh_assert_less (local_index, _pmetis->part.size());
          libmesh_assert_less (local_index, mesh.n_active_local_elem());

          const unsigned int elem_procid =
            static_cast<unsigned int>(_pmetis->part[local_index]);

          libmesh_assert_less (elem_procid, static_cast<unsigned int>(_pmetis->nparts));

          requests_to_fill[procdown][i] = elem_procid;
        }

      // Trade back
      mesh.comm().send_receive (procdown, requests_to_fill[procdown],
                                procup,   requested_ids[procup]);
    }

  // and finally assign the partitioning.
  // note we are iterating in exactly the same order
  // used to build up the request, so we can expect the
  // required entries to be in the proper sequence.
  elem_it  = mesh.active_elements_begin();
  elem_end = mesh.active_elements_end();

  for (std::vector<unsigned int> counters(mesh.n_processors(), 0);
       elem_it != elem_end; ++elem_it)
    {
      Elem *elem = *elem_it;

      const processor_id_type current_pid = elem->processor_id();

      libmesh_assert_less (counters[current_pid], requested_ids[current_pid].size());

      const processor_id_type elem_procid =
        requested_ids[current_pid][counters[current_pid]++];

      libmesh_assert_less (elem_procid, static_cast<unsigned int>(_pmetis->nparts));
      elem->processor_id() = elem_procid;
    }
}
Exemple #23
0
void CheckpointIO::read_connectivity (Xdr &io)
{
  // convenient reference to our mesh
  MeshBase &mesh = MeshInput<MeshBase>::mesh();

  unsigned int n_active_levels;
  io.data(n_active_levels, "# n_active_levels");

  // Keep track of the highest dimensional element we've added to the mesh
  unsigned int highest_elem_dim = 1;

  for(unsigned int level=0; level < n_active_levels; level++)
    {
      xdr_id_type n_elem_at_level = 0;
      io.data (n_elem_at_level, "");

      for (unsigned int i=0; i<n_elem_at_level; i++)
        {
          // id type pid subdomain_id parent_id
          std::vector<largest_id_type> elem_data(5);
          io.data_stream
            (&elem_data[0], cast_int<unsigned int>(elem_data.size()),
             cast_int<unsigned int>(elem_data.size()));

#ifdef LIBMESH_ENABLE_UNIQUE_ID
          largest_id_type unique_id = 0;
          io.data(unique_id, "# unique id");
#endif

#ifdef LIBMESH_ENABLE_AMR
          unsigned int p_level = 0;

          io.data(p_level, "# p_level");
#endif

          unsigned int n_nodes = Elem::type_to_n_nodes_map[elem_data[1]];

          // Snag the node ids this element was connected to
          std::vector<largest_id_type> conn_data(n_nodes);
          io.data_stream
            (&conn_data[0], cast_int<unsigned int>(conn_data.size()),
             cast_int<unsigned int>(conn_data.size()));

          const dof_id_type id                 =
            cast_int<dof_id_type>      (elem_data[0]);
          const ElemType elem_type             =
            static_cast<ElemType>      (elem_data[1]);
          const processor_id_type proc_id      =
            cast_int<processor_id_type>(elem_data[2]);
          const subdomain_id_type subdomain_id =
            cast_int<subdomain_id_type>(elem_data[3]);
          const dof_id_type parent_id          =
            cast_int<dof_id_type>      (elem_data[4]);

          Elem * parent = (parent_id == DofObject::invalid_processor_id) ? NULL : mesh.elem(parent_id);

          // Create the element
          Elem * elem = Elem::build(elem_type, parent).release();

#ifdef LIBMESH_ENABLE_UNIQUE_ID
          elem->set_unique_id() = unique_id;
#endif

          if(elem->dim() > highest_elem_dim)
            highest_elem_dim = elem->dim();

          elem->set_id()       = id;
          elem->processor_id() = proc_id;
          elem->subdomain_id() = subdomain_id;

#ifdef LIBMESH_ENABLE_AMR
          elem->hack_p_level(p_level);

          // Set parent connections
          if(parent)
            {
              parent->add_child(elem);
              parent->set_refinement_flag (Elem::INACTIVE);
              elem->set_refinement_flag   (Elem::JUST_REFINED);
            }
#endif

          libmesh_assert(elem->n_nodes() == conn_data.size());

          // Connect all the nodes to this element
          for (unsigned int n=0; n<conn_data.size(); n++)
            elem->set_node(n) =
              mesh.node_ptr(cast_int<dof_id_type>(conn_data[n]));

          mesh.add_elem(elem);
        }
    }

  mesh.set_mesh_dimension(cast_int<unsigned char>(highest_elem_dim));
}
Exemple #24
0
void LaspackVector<T>::scale (const T factor)
{
  libmesh_assert (this->initialized());

  Asgn_VV(&_vec, Mul_SV (factor, &_vec));
}
void
MAST::ComplexAssemblyBase::
residual_and_jacobian_blocked (const libMesh::NumericVector<Real>& X,
                               libMesh::NumericVector<Real>& R,
                               libMesh::SparseMatrix<Real>&  J,
                               MAST::Parameter* p) {

    libmesh_assert(_system);
    libmesh_assert(_discipline);
    libmesh_assert(_elem_ops);

    START_LOG("residual_and_jacobian()", "ComplexSolve");
    
    MAST::NonlinearSystem& nonlin_sys = _system->system();
    
    R.zero();
    J.zero();
    
    // iterate over each element, initialize it and get the relevant
    // analysis quantities
    RealVectorX
    sol;
    ComplexVectorX
    delta_sol,
    vec;
    ComplexMatrixX
    mat,
    dummy;

    // get the petsc vector and matrix objects
    Mat
    jac_bmat = dynamic_cast<libMesh::PetscMatrix<Real>&>(J).mat();
    
    PetscInt ierr;
    
    std::vector<libMesh::dof_id_type> dof_indices;
    const libMesh::DofMap& dof_map = nonlin_sys.get_dof_map();
    const std::vector<libMesh::dof_id_type>&
    send_list = nonlin_sys.get_dof_map().get_send_list();
    
    
    
    std::unique_ptr<libMesh::NumericVector<Real> >
    localized_base_solution,
    localized_complex_sol(libMesh::NumericVector<Real>::build(nonlin_sys.comm()).release());
    
    // prepare a send list for localization of the complex solution
    std::vector<libMesh::dof_id_type>
    complex_send_list(2*send_list.size());
    
    for (unsigned int i=0; i<send_list.size(); i++) {
        complex_send_list[2*i  ] = 2*send_list[i];
        complex_send_list[2*i+1] = 2*send_list[i]+1;
    }

    localized_complex_sol->init(2*nonlin_sys.n_dofs(),
                                2*nonlin_sys.n_local_dofs(),
                                complex_send_list,
                                false,
                                libMesh::GHOSTED);
    X.localize(*localized_complex_sol, complex_send_list);
    
    // localize the base solution, if it was provided
    if (_base_sol)
        localized_base_solution.reset(build_localized_vector(nonlin_sys,
                                                             *_base_sol).release());
    
    

    // if a solution function is attached, initialize it
    //if (_sol_function)
    //    _sol_function->init( X);
    
    
    libMesh::MeshBase::const_element_iterator       el     =
    nonlin_sys.get_mesh().active_local_elements_begin();
    const libMesh::MeshBase::const_element_iterator end_el =
    nonlin_sys.get_mesh().active_local_elements_end();
    
    MAST::ComplexAssemblyElemOperations&
    ops = dynamic_cast<MAST::ComplexAssemblyElemOperations&>(*_elem_ops);

    for ( ; el != end_el; ++el) {
        
        const libMesh::Elem* elem = *el;
        
        dof_map.dof_indices (elem, dof_indices);
        
        ops.init(*elem);
        
        // get the solution
        unsigned int ndofs = (unsigned int)dof_indices.size();
        sol.setZero(ndofs);
        delta_sol.setZero(ndofs);
        vec.setZero(ndofs);
        mat.setZero(ndofs, ndofs);
        
        // first set the velocity to be zero
        ops.set_elem_velocity(sol);
        
        // next, set the base solution, if provided
        if (_base_sol)
            for (unsigned int i=0; i<dof_indices.size(); i++)
                sol(i) = (*localized_base_solution)(dof_indices[i]);
        
        ops.set_elem_solution(sol);
        
        // set the value of the small-disturbance solution
        for (unsigned int i=0; i<dof_indices.size(); i++) {
            
            // get the complex block for this dof
            delta_sol(i) = Complex((*localized_complex_sol)(2*dof_indices[i]),
                                   (*localized_complex_sol)(2*dof_indices[i]+1));
        }
        
        ops.set_elem_complex_solution(delta_sol);
        
        
//        if (_sol_function)
//            physics_elem->attach_active_solution_function(*_sol_function);
        
        
        // perform the element level calculations
        ops.elem_calculations(true, vec, mat);
        
        // if sensitivity was requested, then ask the element for sensitivity
        // of the residual
        if (p) {
            
            // set the sensitivity of complex sol to zero
            delta_sol.setZero();
            ops.set_elem_complex_solution_sensitivity(delta_sol);
            vec.setZero();
            ops.elem_sensitivity_calculations(*p, vec);
        }
        
        ops.clear_elem();

        //physics_elem->detach_active_solution_function();
        
        // extract the real or the imaginary part of the matrix/vector
        //  The complex system of equations
        //     (J_R + i J_I) (x_R + i x_I) + (r_R + i r_I) = 0
        //  is rewritten as
        //     [ J_R   -J_I] {x_R}  +  {r_R}  = {0}
        //     [ J_I    J_R] {x_I}  +  {r_I}  = {0}
        //
        DenseRealVector v_R, v_I;
        DenseRealMatrix m_R, m_I1, m_I2;
        std::vector<Real> vals(4);
        
        // copy the real part of the residual and Jacobian
        MAST::copy( m_R, mat.real());
        MAST::copy(m_I1, mat.imag()); m_I1 *= -1.;   // this is the -J_I component
        MAST::copy(m_I2, mat.imag());                // this is the J_I component
        MAST::copy( v_R, vec.real());
        MAST::copy( v_I, vec.imag());
        dof_map.constrain_element_matrix(m_R,  dof_indices);
        dof_map.constrain_element_matrix(m_I1, dof_indices);
        dof_map.constrain_element_matrix(m_I2, dof_indices);
        dof_map.constrain_element_vector(v_R,  dof_indices);
        dof_map.constrain_element_vector(v_I,  dof_indices);
        
        
        for (unsigned int i=0; i<dof_indices.size(); i++) {
            
            R.add(2*dof_indices[i],     v_R(i));
            R.add(2*dof_indices[i]+1,   v_I(i));
            
            for (unsigned int j=0; j<dof_indices.size(); j++) {
                vals[0] = m_R (i,j);
                vals[1] = m_I1(i,j);
                vals[2] = m_I2(i,j);
                vals[3] = m_R (i,j);
                ierr = MatSetValuesBlocked(jac_bmat,
                                           1, (PetscInt*)&dof_indices[i],
                                           1, (PetscInt*)&dof_indices[j],
                                           &vals[0],
                                           ADD_VALUES);
            }
        }
    }
    
    
    // if a solution function is attached, clear it
    //if (_sol_function)
    //    _sol_function->clear();
    
    R.close();
    J.close();
    
    libMesh::out << "R: " << R.l2_norm() << std::endl;
    STOP_LOG("residual_and_jacobian()", "ComplexSolve");
}
Exemple #26
0
Real LaspackVector<T>::linfty_norm () const
{
  libmesh_assert (this->closed());

  return static_cast<Real>(MaxNorm_V(const_cast<QVector*>(&_vec)));
}
Exemple #27
0
void UNVIO::node_in (std::istream& in_file)
{
  START_LOG("node_in()","UNVIO");

  if (this->verbose())
    libMesh::out << "  Reading nodes" << std::endl;

  // adjust the \p istream to our position
  const bool ok = this->beginning_of_dataset(in_file, _label_dataset_nodes);

  if (!ok)
    {
      libMesh::err << "ERROR: Could not find node dataset!" << std::endl;
      libmesh_error();
    }

  MeshBase& mesh = MeshInput<MeshBase>::mesh();

  unsigned int node_lab;           // label of the node
  unsigned int exp_coord_sys_num,  // export coordinate system number       (not supported yet)
    disp_coord_sys_num, // displacement coordinate system number (not supported yet)
    color;              // color                                 (not supported yet)

  // allocate the correct amount
  // of memory for the node vector
  this->_assign_nodes.reserve (this->_n_nodes);


  // always 3 coordinates in the UNV file, no matter
  // which dimensionality libMesh is in
  //std::vector<Real> xyz (3);
  Point xyz;

  // depending on whether we have to convert each
  // coordinate (float), we offer two versions.
  // Note that \p count_nodes() already verified
  // whether this file uses "D" of "e"
  if (this->_need_D_to_e)
    {
      // ok, convert...
      std::string num_buf;

      for(dof_id_type i=0; i<this->_n_nodes; i++)
        {
          libmesh_assert (!in_file.eof());

          in_file >> node_lab                // read the node label
                  >> exp_coord_sys_num       // (not supported yet)
                  >> disp_coord_sys_num      // (not supported yet)
                  >> color;                  // (not supported yet)

          // take care of the
          // floating-point data
          for (unsigned int d=0; d<3; d++)
            {
              in_file >> num_buf;
              xyz(d) = this->D_to_e (num_buf);
            }

          // set up the id map
          this->_assign_nodes.push_back (node_lab);

          // add node to the Mesh &
          // tell the MeshData object the foreign node id
          // (note that mesh.add_point() returns a pointer to the new node)
          this->_mesh_data.add_foreign_node_id (mesh.add_point(xyz,i), node_lab);
        }
    }
void EigenSparseVector<T>::scale (const T factor)
{
  libmesh_assert (this->initialized());

  _vec *= factor;
}
Exemple #29
0
int XdrMGF::dataBlk(Real* array, int numvar, int size)
{
    int totalSize = numvar*size;

    // If this function is called by coord(),
    // numvar is the problem dimension, and
    // size is the number of nodes in the problem.

    //libMesh::out << "Total amount of data to be written: " << totalSize << std::endl;

    switch (m_type)
    {

#ifdef LIBMESH_HAVE_XDR

    case (XdrMGF::DECODE):
    case (XdrMGF::ENCODE):
    {
        // FIXME - this is probably broken for Real == long double
        // RHS
        xdr_vector(mp_xdr_handle,
                   (char *) &array[0],
                   totalSize,
                   sizeof(Real),
                   (xdrproc_t) xdr_REAL);
    }

#endif

    case (XdrMGF::W_ASCII):
    {
        // Save stream flags
        std::ios_base::fmtflags out_flags = mp_out.flags();

        // We will use scientific notation with a precision of 16
        // digits in the following output.  The desired precision and
        // format will automatically determine the width.
        mp_out << std::scientific
               << std::setprecision(16);

        for (int i=0; i<size; i++)
        {
            for (int j=0; j<numvar; j++)
                mp_out << array[i*numvar + j] << " \t";

            mp_out << '\n';
        }

        // Restore stream flags
        mp_out.flags(out_flags);

        mp_out.flush();
        break;
    }

    case (XdrMGF::R_ASCII):
    {
        libmesh_assert (mp_in.good());

        for (int i=0; i<size; i++)
        {
            libmesh_assert (mp_in.good());

            for (int j=0; j<numvar; j++)
                mp_in >> array[i*numvar + j];

            mp_in.ignore(); // Read newline
        }

        break;
    }

    default:
        // Unknown access type
        libmesh_error();
    }

    return totalSize;
}
Real FE<2,L2_HIERARCHIC>::shape_deriv(const Elem * elem,
                                      const Order order,
                                      const unsigned int i,
                                      const unsigned int j,
                                      const Point & p)
{
  libmesh_assert(elem);

  const ElemType type = elem->type();

  const Order totalorder = static_cast<Order>(order+elem->p_level());

  libmesh_assert_greater (totalorder, 0);

  switch (type)
    {
      // 1st & 2nd-order Hierarchics.
    case TRI3:
    case TRI6:
      {
        const Real eps = 1.e-6;

        libmesh_assert_less (j, 2);

        switch (j)
          {
            //  d()/dxi
          case 0:
            {
              const Point pp(p(0)+eps, p(1));
              const Point pm(p(0)-eps, p(1));

              return (FE<2,L2_HIERARCHIC>::shape(elem, order, i, pp) -
                      FE<2,L2_HIERARCHIC>::shape(elem, order, i, pm))/2./eps;
            }

            // d()/deta
          case 1:
            {
              const Point pp(p(0), p(1)+eps);
              const Point pm(p(0), p(1)-eps);

              return (FE<2,L2_HIERARCHIC>::shape(elem, order, i, pp) -
                      FE<2,L2_HIERARCHIC>::shape(elem, order, i, pm))/2./eps;
            }


          default:
            libmesh_error_msg("Invalid derivative index j = " << j);
          }
      }

    case QUAD4:
      libmesh_assert_less (totalorder, 2);
    case QUAD8:
    case QUAD9:
      {
        // Compute quad shape functions as a tensor-product
        const Real xi  = p(0);
        const Real eta = p(1);

        libmesh_assert_less (i, (totalorder+1u)*(totalorder+1u));

        // Example i, i0, i1 values for totalorder = 5:
        //                                    0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
        //  static const unsigned int i0[] = {0, 1, 1, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 0, 0, 0, 0, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5, 2, 3, 4, 5};
        //  static const unsigned int i1[] = {0, 0, 1, 1, 0, 0, 0, 0, 2, 3, 4, 5, 1, 1, 1, 1, 2, 3, 4, 5, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5};

        unsigned int i0, i1;

        // Vertex DoFs
        if (i == 0)
          { i0 = 0; i1 = 0; }
        else if (i == 1)
          { i0 = 1; i1 = 0; }
        else if (i == 2)
          { i0 = 1; i1 = 1; }
        else if (i == 3)
          { i0 = 0; i1 = 1; }
        // Edge DoFs
        else if (i < totalorder + 3u)
          { i0 = i - 2; i1 = 0; }
        else if (i < 2u*totalorder + 2)
          { i0 = 1; i1 = i - totalorder - 1; }
        else if (i < 3u*totalorder + 1u)
          { i0 = i - 2u*totalorder; i1 = 1; }
        else if (i < 4u*totalorder)
          { i0 = 0; i1 = i - 3u*totalorder + 1; }
        // Interior DoFs
        else
          {
            unsigned int basisnum = i - 4*totalorder;
            i0 = square_number_column[basisnum] + 2;
            i1 = square_number_row[basisnum] + 2;
          }

        // Flip odd degree of freedom values if necessary
        // to keep continuity on sides
        Real f = 1.;

        if ((i0%2) && (i0 > 2) && (i1 == 0))
          f = (elem->point(0) > elem->point(1))?-1.:1.;
        else if ((i0%2) && (i0>2) && (i1 == 1))
          f = (elem->point(3) > elem->point(2))?-1.:1.;
        else if ((i0 == 0) && (i1%2) && (i1>2))
          f = (elem->point(0) > elem->point(3))?-1.:1.;
        else if ((i0 == 1) && (i1%2) && (i1>2))
          f = (elem->point(1) > elem->point(2))?-1.:1.;

        switch (j)
          {
            // d()/dxi
          case 0:
            return f*(FE<1,L2_HIERARCHIC>::shape_deriv(EDGE3, totalorder, i0, 0, xi)*
                      FE<1,L2_HIERARCHIC>::shape      (EDGE3, totalorder, i1,    eta));

            // d()/deta
          case 1:
            return f*(FE<1,L2_HIERARCHIC>::shape      (EDGE3, totalorder, i0,    xi)*
                      FE<1,L2_HIERARCHIC>::shape_deriv(EDGE3, totalorder, i1, 0, eta));

          default:
            libmesh_error_msg("Invalid derivative index j = " << j);
          }
      }

    default:
      libmesh_error_msg("ERROR: Unsupported element type = " << type);
    }

  return 0.;
}