//-----------------------------------------------------------------
// Mesh refinement methods
void MeshRefinement::flag_elements_by_error_fraction (const ErrorVector& error_per_cell,
						      const Real refine_frac,
						      const Real coarsen_frac,
						      const unsigned int max_l)
{
  parallel_only();

  // The function arguments are currently just there for
  // backwards_compatibility
  if (!_use_member_parameters)
  {
    // If the user used non-default parameters, lets warn
    // that they're deprecated
    if (refine_frac != 0.3 ||
	coarsen_frac != 0.0 ||
	max_l != libMesh::invalid_uint)
      libmesh_deprecated();

    _refine_fraction = refine_frac;
    _coarsen_fraction = coarsen_frac;
    _max_h_level = max_l;
  }

  // Check for valid fractions..
  // The fraction values must be in [0,1]
  libmesh_assert_greater_equal (_refine_fraction, 0);
  libmesh_assert_less_equal (_refine_fraction, 1);
  libmesh_assert_greater_equal (_coarsen_fraction, 0);
  libmesh_assert_less_equal (_coarsen_fraction, 1);

  // Clean up the refinement flags.  These could be left
  // over from previous refinement steps.
  this->clean_refinement_flags();

  // We're getting the minimum and maximum error values
  // for the ACTIVE elements
  Real error_min = 1.e30;
  Real error_max = 0.;

  // And, if necessary, for their parents
  Real parent_error_min = 1.e30;
  Real parent_error_max = 0.;

  // Prepare another error vector if we need to sum parent errors
  ErrorVector error_per_parent;
  if (_coarsen_by_parents)
  {
    create_parent_error_vector(error_per_cell,
			       error_per_parent,
			       parent_error_min,
			       parent_error_max);
  }

  // We need to loop over all active elements to find the minimum
  MeshBase::element_iterator       el_it  =
    _mesh.active_local_elements_begin();
  const MeshBase::element_iterator el_end =
    _mesh.active_local_elements_end();

  for (; el_it != el_end; ++el_it)
  {
    const unsigned int id  = (*el_it)->id();
    libmesh_assert_less (id, error_per_cell.size());

    error_max = std::max (error_max, error_per_cell[id]);
    error_min = std::min (error_min, error_per_cell[id]);
  }
  CommWorld.max(error_max);
  CommWorld.min(error_min);

  // Compute the cutoff values for coarsening and refinement
  const Real error_delta = (error_max - error_min);
  const Real parent_error_delta = parent_error_max - parent_error_min;

  const Real refine_cutoff  = (1.- _refine_fraction)*error_max;
  const Real coarsen_cutoff = _coarsen_fraction*error_delta + error_min;
  const Real parent_cutoff = _coarsen_fraction*parent_error_delta + error_min;

//   // Print information about the error
//   libMesh::out << " Error Information:"                     << std::endl
// 	    << " ------------------"                     << std::endl
// 	    << "   min:              " << error_min      << std::endl
// 	    << "   max:              " << error_max      << std::endl
// 	    << "   delta:            " << error_delta    << std::endl
// 	    << "     refine_cutoff:  " << refine_cutoff  << std::endl
// 	    << "     coarsen_cutoff: " << coarsen_cutoff << std::endl;



  // Loop over the elements and flag them for coarsening or
  // refinement based on the element error

  MeshBase::element_iterator       e_it  =
    _mesh.active_elements_begin();
  const MeshBase::element_iterator e_end =
    _mesh.active_elements_end();
  for (; e_it != e_end; ++e_it)
  {
    Elem* elem             = *e_it;
    const unsigned int id  = elem->id();

    libmesh_assert_less (id, error_per_cell.size());

    const float elem_error = error_per_cell[id];

    if (_coarsen_by_parents)
    {
      Elem* parent           = elem->parent();
      if (parent)
      {
	const unsigned int parentid  = parent->id();
	if (error_per_parent[parentid] >= 0. &&
	    error_per_parent[parentid] <= parent_cutoff)
	  elem->set_refinement_flag(Elem::COARSEN);
      }
    }
    // Flag the element for coarsening if its error
    // is <= coarsen_fraction*delta + error_min
    else if (elem_error <= coarsen_cutoff)
    {
      elem->set_refinement_flag(Elem::COARSEN);
    }

    // Flag the element for refinement if its error
    // is >= refinement_cutoff.
    if (elem_error >= refine_cutoff)
      if (elem->level() < _max_h_level)
	elem->set_refinement_flag(Elem::REFINE);
  }
}
Пример #2
0
void InfPrism12::connectivity(const unsigned int sc,
			      const IOPackage iop,
			      std::vector<dof_id_type>& conn) const
{
  libmesh_assert(_nodes);
  libmesh_assert_less (sc, this->n_sub_elem());
  libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);

  switch (iop)
    {
    case TECPLOT:
      {
	conn.resize(8);
	switch (sc)
	  {
	  case 0:

	    // guess this is a collapsed hex8
	    conn[0] = this->node(0)+1;
	    conn[1] = this->node(6)+1;
	    conn[2] = this->node(8)+1;
	    conn[3] = this->node(8)+1;
	    conn[4] = this->node(3)+1;
	    conn[5] = this->node(9)+1;
	    conn[6] = this->node(11)+1;
	    conn[7] = this->node(11)+1;

	    return;

	  case 1:

	    conn[0] = this->node(6)+1;
	    conn[1] = this->node(7)+1;
	    conn[2] = this->node(8)+1;
	    conn[3] = this->node(8)+1;
	    conn[4] = this->node(9)+1;
	    conn[5] = this->node(10)+1;
	    conn[6] = this->node(11)+1;
	    conn[7] = this->node(11)+1;

	    return;

	  case 2:

	    conn[0] = this->node(6)+1;
	    conn[1] = this->node(1)+1;
	    conn[2] = this->node(7)+1;
	    conn[3] = this->node(7)+1;
	    conn[4] = this->node(9)+1;
	    conn[5] = this->node(4)+1;
	    conn[6] = this->node(10)+1;
	    conn[7] = this->node(10)+1;

	    return;

	  case 3:

	    conn[0] = this->node(8)+1;
	    conn[1] = this->node(7)+1;
	    conn[2] = this->node(2)+1;
	    conn[3] = this->node(2)+1;
	    conn[4] = this->node(11)+1;
	    conn[5] = this->node(10)+1;
	    conn[6] = this->node(5)+1;
	    conn[7] = this->node(5)+1;

	    return;

	  default:
	    libmesh_error();

	  }

      }

    default:
      libmesh_error();
    }

  libmesh_error();
}
Пример #3
0
RealGradient FE<2,NEDELEC_ONE>::shape_second_deriv(const Elem* elem,
						   const Order order,
						   const unsigned int i,
						   const unsigned int j,
						   const Point&)
{
#if LIBMESH_DIM > 1
   libmesh_assert(elem);

  // j = 0 ==> d^2 phi / dxi^2
  // j = 1 ==> d^2 phi / dxi deta
  // j = 2 ==> d^2 phi / deta^2
  libmesh_assert_less (j, 3);

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

  switch (total_order)
    {
      // linear Lagrange shape functions
    case FIRST:
      {
	switch (elem->type())
	  {
	  case QUAD8:
	  case QUAD9:
	    {
	      libmesh_assert_less (i, 4);
	      // All second derivatives for linear quads are zero.
	      return RealGradient();
	    }

	  case TRI6:
	    {
	      libmesh_assert_less (i, 3);
	      // All second derivatives for linear triangles are zero.
	      return RealGradient();
	    }

	  default:
	    {
	      libMesh::err << "ERROR: Unsupported 2D element type!: " << elem->type()
			    << std::endl;
	      libmesh_error();
	    }

	  } // end switch (type)
      } // end case FIRST

      // unsupported order
    default:
      {
	libMesh::err << "ERROR: Unsupported 2D FE order!: " << total_order
		      << std::endl;
	libmesh_error();
      }

    } // end switch (order)

#endif // LIBMESH_DIM > 1

  libmesh_error();
  return RealGradient();
}
Пример #4
0
void InfHex18::connectivity(const unsigned int sc,
                            const IOPackage iop,
                            std::vector<dof_id_type>& conn) const
{
  libmesh_assert(_nodes);
  libmesh_assert_less (sc, this->n_sub_elem());
  libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);

  switch (iop)
    {
    case TECPLOT:
      {
        switch (sc)
          {
          case 0:

            conn[0] = this->node(0)+1;
            conn[1] = this->node(8)+1;
            conn[2] = this->node(16)+1;
            conn[3] = this->node(11)+1;
            conn[4] = this->node(4)+1;
            conn[5] = this->node(12)+1;
            conn[6] = this->node(17)+1;
            conn[7] = this->node(15)+1;

            return;

          case 1:

            conn[0] = this->node(8)+1;
            conn[1] = this->node(1)+1;
            conn[2] = this->node(9)+1;
            conn[3] = this->node(16)+1;
            conn[4] = this->node(12)+1;
            conn[5] = this->node(5)+1;
            conn[6] = this->node(13)+1;
            conn[7] = this->node(17)+1;

            return;

          case 2:

            conn[0] = this->node(11)+1;
            conn[1] = this->node(16)+1;
            conn[2] = this->node(10)+1;
            conn[3] = this->node(3)+1;
            conn[4] = this->node(15)+1;
            conn[5] = this->node(17)+1;
            conn[6] = this->node(14)+1;
            conn[7] = this->node(7)+1;

            return;

          case 3:

            conn[0] = this->node(16)+1;
            conn[1] = this->node(9)+1;
            conn[2] = this->node(2)+1;
            conn[3] = this->node(10)+1;
            conn[4] = this->node(17)+1;
            conn[5] = this->node(13)+1;
            conn[6] = this->node(6)+1;
            conn[7] = this->node(14)+1;

            return;

          default:
            libmesh_error_msg("Invalid sc = " << sc);
          }
      }

    default:
      libmesh_error_msg("Unsupported IO package " << iop);
    }
}
Пример #5
0
bool InfEdge2::is_node_on_side(const unsigned int n,
                               const unsigned int s) const
{
  libmesh_assert_less (s, 1);
  return (s == n);
}
Пример #6
0
AutoPtr<Elem> Tet10::build_side (const unsigned int i,
				 bool proxy) const
{
  libmesh_assert_less (i, this->n_sides());

  if (proxy)
    {
      AutoPtr<Elem> ap(new Side<Tri6,Tet10>(this,i));
      return ap;
    }

  else
    {
      AutoPtr<Elem> face(new Tri6);

      switch (i)
	{
	case 0:
	  {
	    face->set_node(0) = this->get_node(0);
	    face->set_node(1) = this->get_node(2);
	    face->set_node(2) = this->get_node(1);
	    face->set_node(3) = this->get_node(6);
	    face->set_node(4) = this->get_node(5);
	    face->set_node(5) = this->get_node(4);

	    return face;
	  }
	case 1:
	  {
	    face->set_node(0) = this->get_node(0);
	    face->set_node(1) = this->get_node(1);
	    face->set_node(2) = this->get_node(3);
	    face->set_node(3) = this->get_node(4);
	    face->set_node(4) = this->get_node(8);
	    face->set_node(5) = this->get_node(7);

	    return face;
	  }
	case 2:
	  {
	    face->set_node(0) = this->get_node(1);
	    face->set_node(1) = this->get_node(2);
	    face->set_node(2) = this->get_node(3);
	    face->set_node(3) = this->get_node(5);
	    face->set_node(4) = this->get_node(9);
	    face->set_node(5) = this->get_node(8);

	    return face;
	  }
	case 3:
	  {
	    face->set_node(0) = this->get_node(2);
	    face->set_node(1) = this->get_node(0);
	    face->set_node(2) = this->get_node(3);
	    face->set_node(3) = this->get_node(6);
	    face->set_node(4) = this->get_node(7);
	    face->set_node(5) = this->get_node(9);

	    return face;
	  }
	default:
	  {
	    libmesh_error();
	  }
	}
    }


  // We'll never get here.
  libmesh_error();
  AutoPtr<Elem> ap(NULL);  return ap;
}
Пример #7
0
void Tet10::connectivity(const unsigned int sc,
			 const IOPackage iop,
			 std::vector<unsigned int>& conn) const
{
  libmesh_assert(_nodes);
  libmesh_assert_less (sc, this->n_sub_elem());
  libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);

  switch (iop)
    {
    case TECPLOT:
      {
	conn.resize(8);
	switch (sc)
	  {


	    // Linear sub-tet 0
	  case 0:

	    conn[0] = this->node(0)+1;
	    conn[1] = this->node(4)+1;
	    conn[2] = this->node(6)+1;
	    conn[3] = this->node(6)+1;
	    conn[4] = this->node(7)+1;
	    conn[5] = this->node(7)+1;
	    conn[6] = this->node(7)+1;
	    conn[7] = this->node(7)+1;

	    return;

	    // Linear sub-tet 1
	  case 1:

	    conn[0] = this->node(4)+1;
	    conn[1] = this->node(1)+1;
	    conn[2] = this->node(5)+1;
	    conn[3] = this->node(5)+1;
	    conn[4] = this->node(8)+1;
	    conn[5] = this->node(8)+1;
	    conn[6] = this->node(8)+1;
	    conn[7] = this->node(8)+1;

	    return;

	    // Linear sub-tet 2
	  case 2:

	    conn[0] = this->node(5)+1;
	    conn[1] = this->node(2)+1;
	    conn[2] = this->node(6)+1;
	    conn[3] = this->node(6)+1;
	    conn[4] = this->node(9)+1;
	    conn[5] = this->node(9)+1;
	    conn[6] = this->node(9)+1;
	    conn[7] = this->node(9)+1;

	    return;

	    // Linear sub-tet 3
	  case 3:

	    conn[0] = this->node(7)+1;
	    conn[1] = this->node(8)+1;
	    conn[2] = this->node(9)+1;
	    conn[3] = this->node(9)+1;
	    conn[4] = this->node(3)+1;
	    conn[5] = this->node(3)+1;
	    conn[6] = this->node(3)+1;
	    conn[7] = this->node(3)+1;

	    return;

	    // Linear sub-tet 4
	  case 4:

	    conn[0] = this->node(4)+1;
	    conn[1] = this->node(8)+1;
	    conn[2] = this->node(6)+1;
	    conn[3] = this->node(6)+1;
	    conn[4] = this->node(7)+1;
	    conn[5] = this->node(7)+1;
	    conn[6] = this->node(7)+1;
	    conn[7] = this->node(7)+1;

	    return;

	    // Linear sub-tet 5
	  case 5:

	    conn[0] = this->node(4)+1;
	    conn[1] = this->node(5)+1;
	    conn[2] = this->node(6)+1;
	    conn[3] = this->node(6)+1;
	    conn[4] = this->node(8)+1;
	    conn[5] = this->node(8)+1;
	    conn[6] = this->node(8)+1;
	    conn[7] = this->node(8)+1;

	    return;

	    // Linear sub-tet 6
	  case 6:

	    conn[0] = this->node(5)+1;
	    conn[1] = this->node(9)+1;
	    conn[2] = this->node(6)+1;
	    conn[3] = this->node(6)+1;
	    conn[4] = this->node(8)+1;
	    conn[5] = this->node(8)+1;
	    conn[6] = this->node(8)+1;
	    conn[7] = this->node(8)+1;

	    return;

	    // Linear sub-tet 7
	  case 7:

	    conn[0] = this->node(7)+1;
	    conn[1] = this->node(6)+1;
	    conn[2] = this->node(9)+1;
	    conn[3] = this->node(9)+1;
	    conn[4] = this->node(8)+1;
	    conn[5] = this->node(8)+1;
	    conn[6] = this->node(8)+1;
	    conn[7] = this->node(8)+1;

	    return;


	  default:

	    libmesh_error();
	}
      }

    case VTK:
      {
        conn.resize(10);
        conn[0] = this->node(0);
        conn[1] = this->node(1);
        conn[2] = this->node(2);
        conn[3] = this->node(3);
        conn[4] = this->node(4);
        conn[5] = this->node(5);
        conn[6] = this->node(6);
        conn[7] = this->node(7);
        conn[8] = this->node(8);
        conn[9] = this->node(9);
        return;
        /*
           conn.resize(4);
           switch (sc)
           {
        // Linear sub-tet 0
        case 0:

        conn[0] = this->node(0);
        conn[1] = this->node(4);
        conn[2] = this->node(6);
        conn[3] = this->node(7);

        return;

        // Linear sub-tet 1
        case 1:

        conn[0] = this->node(4);
        conn[1] = this->node(1);
        conn[2] = this->node(5);
        conn[3] = this->node(8);

        return;

        // Linear sub-tet 2
        case 2:

        conn[0] = this->node(5);
        conn[1] = this->node(2);
        conn[2] = this->node(6);
        conn[3] = this->node(9);

        return;

        // Linear sub-tet 3
        case 3:

        conn[0] = this->node(7);
        conn[1] = this->node(8);
        conn[2] = this->node(9);
        conn[3] = this->node(3);

        return;

        // Linear sub-tet 4
        case 4:

        conn[0] = this->node(4);
        conn[1] = this->node(8);
        conn[2] = this->node(6);
        conn[3] = this->node(7);

        return;

        // Linear sub-tet 5
        case 5:

        conn[0] = this->node(4);
        conn[1] = this->node(5);
        conn[2] = this->node(6);
        conn[3] = this->node(8);

        return;

        // Linear sub-tet 6
        case 6:

        conn[0] = this->node(5);
        conn[1] = this->node(9);
        conn[2] = this->node(6);
        conn[3] = this->node(8);

        return;

        // Linear sub-tet 7
        case 7:

        conn[0] = this->node(7);
        conn[1] = this->node(6);
        conn[2] = this->node(9);
        conn[3] = this->node(8);

        return;


        default:

        libmesh_error();
      }
      */
      }

    default:
      libmesh_error();
  }

  libmesh_error();
}
Пример #8
0
AutoPtr<Elem> Prism15::build_side (const unsigned int i,
                                   bool proxy) const
{
  libmesh_assert_less (i, this->n_sides());

  if (proxy)
    {
      switch (i)
        {
        case 0:  // the triangular face at z=-1
        case 4:
          {
            AutoPtr<Elem> face(new Side<Tri6,Prism15>(this,i));
            return face;
          }

        case 1:
        case 2:
        case 3:
          {
            AutoPtr<Elem> face(new Side<Quad8,Prism15>(this,i));
            return face;
          }

        default:
          {
            libmesh_error();
          }
        }
    }

  else
    {
      // Create NULL pointer to be initialized, returned later.
      AutoPtr<Elem> face(NULL);

      switch (i)
        {
        case 0:  // the triangular face at z=-1
          {
            face.reset(new Tri6);

            face->set_node(0) = this->get_node(0);
            face->set_node(1) = this->get_node(2);
            face->set_node(2) = this->get_node(1);
            face->set_node(3) = this->get_node(8);
            face->set_node(4) = this->get_node(7);
            face->set_node(5) = this->get_node(6);

            break;
          }
        case 1:  // the quad face at y=0
          {
            face.reset(new Quad8);

            face->set_node(0) = this->get_node(0);
            face->set_node(1) = this->get_node(1);
            face->set_node(2) = this->get_node(4);
            face->set_node(3) = this->get_node(3);
            face->set_node(4) = this->get_node(6);
            face->set_node(5) = this->get_node(10);
            face->set_node(6) = this->get_node(12);
            face->set_node(7) = this->get_node(9);

            break;
          }
        case 2:  // the other quad face
          {
            face.reset(new Quad8);

            face->set_node(0) = this->get_node(1);
            face->set_node(1) = this->get_node(2);
            face->set_node(2) = this->get_node(5);
            face->set_node(3) = this->get_node(4);
            face->set_node(4) = this->get_node(7);
            face->set_node(5) = this->get_node(11);
            face->set_node(6) = this->get_node(13);
            face->set_node(7) = this->get_node(10);

            break;
          }
        case 3: // the quad face at x=0
          {
            face.reset(new Quad8);

            face->set_node(0) = this->get_node(2);
            face->set_node(1) = this->get_node(0);
            face->set_node(2) = this->get_node(3);
            face->set_node(3) = this->get_node(5);
            face->set_node(4) = this->get_node(8);
            face->set_node(5) = this->get_node(9);
            face->set_node(6) = this->get_node(14);
            face->set_node(7) = this->get_node(11);

            break;
          }
        case 4: // the triangular face at z=1
          {
            face.reset(new Tri6);

            face->set_node(0) = this->get_node(3);
            face->set_node(1) = this->get_node(4);
            face->set_node(2) = this->get_node(5);
            face->set_node(3) = this->get_node(12);
            face->set_node(4) = this->get_node(13);
            face->set_node(5) = this->get_node(14);

            break;
          }
        default:
          {
            libmesh_error();
          }
        }

      face->subdomain_id() = this->subdomain_id();
      return face;
    }

  // We'll never get here.
  libmesh_error();
  AutoPtr<Elem> ap(NULL);  return ap;
}
Пример #9
0
void Prism15::connectivity(const unsigned int libmesh_dbg_var(sc),
                           const IOPackage iop,
                           std::vector<dof_id_type>& conn) const
{
  libmesh_assert(_nodes);
  libmesh_assert_less (sc, this->n_sub_elem());
  libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);

  switch (iop)
    {
    case TECPLOT:
      {
        conn.resize(8);
        conn[0] = this->node(0)+1;
        conn[1] = this->node(1)+1;
        conn[2] = this->node(2)+1;
        conn[3] = this->node(2)+1;
        conn[4] = this->node(3)+1;
        conn[5] = this->node(4)+1;
        conn[6] = this->node(5)+1;
        conn[7] = this->node(5)+1;
        return;
      }

    case VTK:
      {
        /*
          conn.resize(6);
          conn[0] = this->node(0);
          conn[1] = this->node(2);
          conn[2] = this->node(1);
          conn[3] = this->node(3);
          conn[4] = this->node(5);
          conn[5] = this->node(4);
        */

        // VTK's VTK_QUADRATIC_WEDGE first 9 nodes match, then their
        // middle and top layers of mid-edge nodes are reversed from
        // LibMesh's.
        conn.resize(15);
        for (unsigned i=0; i<9; ++i)
          conn[i] = this->node(i);

        // top "ring" of mid-edge nodes
        conn[9]  = this->node(12);
        conn[10] = this->node(13);
        conn[11] = this->node(14);

        // middle "ring" of mid-edge nodes
        conn[12] = this->node(9);
        conn[13] = this->node(10);
        conn[14] = this->node(11);


        return;
      }

    default:
      libmesh_error();
    }

  libmesh_error();

}
Пример #10
0
// ------------------------------------------------------------
// MetisPartitioner implementation
void MetisPartitioner::_do_partition (MeshBase & mesh,
                                      const unsigned int n_pieces)
{
  libmesh_assert_greater (n_pieces, 0);
  libmesh_assert (mesh.is_serial());

  // Check for an easy return
  if (n_pieces == 1)
    {
      this->single_partition (mesh);
      return;
    }

  // What to do if the Metis library IS NOT present
#ifndef LIBMESH_HAVE_METIS

  libmesh_here();
  libMesh::err << "ERROR: The library has been built without"    << std::endl
               << "Metis support.  Using a space-filling curve"  << std::endl
               << "partitioner instead!"                         << std::endl;

  SFCPartitioner sfcp;

  sfcp.partition (mesh, n_pieces);

  // What to do if the Metis library IS present
#else

  LOG_SCOPE("partition()", "MetisPartitioner");

  const dof_id_type n_active_elem = mesh.n_active_elem();

  // build the graph
  // std::vector<Metis::idx_t> options(5);
  std::vector<Metis::idx_t> vwgt(n_active_elem);
  std::vector<Metis::idx_t> part(n_active_elem);

  Metis::idx_t
    n = static_cast<Metis::idx_t>(n_active_elem),  // number of "nodes" (elements)
                                                   //   in the graph
    //    wgtflag = 2,                             // weights on vertices only,
    //                                             //   none on edges
    //    numflag = 0,                             // C-style 0-based numbering
    nparts  = static_cast<Metis::idx_t>(n_pieces), // number of subdomains to create
    edgecut = 0;                                   // the numbers of edges cut by the
                                                   //   resulting partition

  // Set the options
  // options[0] = 0; // use default options

  // Metis will only consider the active elements.
  // We need to map the active element ids into a
  // contiguous range.  Further, we want the unique range indexing to be
  // independent of the element ordering, otherwise a circular dependency
  // can result in which the partitioning depends on the ordering which
  // depends on the partitioning...
  vectormap<dof_id_type, dof_id_type> global_index_map;
  global_index_map.reserve (n_active_elem);

  {
    std::vector<dof_id_type> global_index;

    MeshBase::element_iterator       it  = mesh.active_elements_begin();
    const MeshBase::element_iterator end = mesh.active_elements_end();

    MeshCommunication().find_global_indices (mesh.comm(),
                                             MeshTools::bounding_box(mesh),
                                             it, end, global_index);

    libmesh_assert_equal_to (global_index.size(), n_active_elem);

    for (std::size_t cnt=0; it != end; ++it)
      {
        const Elem * elem = *it;

        global_index_map.insert (std::make_pair(elem->id(), global_index[cnt++]));
      }
    libmesh_assert_equal_to (global_index_map.size(), n_active_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_MULTIMAP<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_MULTIMAP) ||         \
  defined(LIBMESH_HAVE_TR1_UNORDERED_MULTIMAP) ||       \
  defined(LIBMESH_HAVE_HASH_MULTIMAP) ||                \
  defined(LIBMESH_HAVE_EXT_HASH_MULTIMAP)
            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
          }
      }
  }


  // Invoke METIS, but only on processor 0.
  // Then broadcast the resulting decomposition
  if (mesh.processor_id() == 0)
    {
      METIS_CSR_Graph<Metis::idx_t> csr_graph;

      csr_graph.offsets.resize(n_active_elem+1, 0);

      // Local scope for these
      {
        // build the graph in CSR format.  Note that
        // the edges in the graph will correspond to
        // face neighbors

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

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

#ifndef NDEBUG
        std::size_t graph_size=0;
#endif

        // (1) first pass - get the row sizes for each element by counting the number
        // of face neighbors.  Also populate the vwght array if necessary
        for (; elem_it != elem_end; ++elem_it)
          {
            const Elem * elem = *elem_it;

            const dof_id_type elem_global_index =
              global_index_map[elem->id()];

            libmesh_assert_less (elem_global_index, vwgt.size());

            // maybe there is a better weight?
            // The weight is used to define what a balanced graph is
            if(!_weights)
              vwgt[elem_global_index] = elem->n_nodes();
            else
              vwgt[elem_global_index] = static_cast<Metis::idx_t>((*_weights)[elem->id()]);

            unsigned int num_neighbors = 0;

            // 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 != libmesh_nullptr)
                  {
                    // If the neighbor is active treat it
                    // as a connection
                    if (neighbor->active())
                      num_neighbors++;

#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());
                                num_neighbors++;
                              }
                          }
                      }

#endif /* ifdef LIBMESH_ENABLE_AMR */

                  }
              }

            // Check for any interior neighbors
            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);

                num_neighbors += neighbor_set.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);
            num_neighbors += std::distance(bounds.first, bounds.second);

            csr_graph.prep_n_nonzeros(elem_global_index, num_neighbors);
#ifndef NDEBUG
            graph_size += num_neighbors;
#endif
          }

        csr_graph.prepare_for_use();

        // (2) second pass - fill the compressed adjacency array
        elem_it  = mesh.active_elements_begin();

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

            const dof_id_type elem_global_index =
              global_index_map[elem->id()];

            unsigned int connection=0;

            // 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 != libmesh_nullptr)
                  {
                    // If the neighbor is active treat it
                    // as a connection
                    if (neighbor->active())
                      csr_graph(elem_global_index, connection++) = global_index_map[neighbor->id()];

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

                                csr_graph(elem_global_index, connection++) = global_index_map[child->id()];
                              }
                          }
                      }

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

                    csr_graph(elem_global_index, connection++) =
                      global_index_map[neighbor->id()];
                  }
              }

            // 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;
                csr_graph(elem_global_index, connection++) =
                  global_index_map[neighbor->id()];
              }
          }

        // We create a non-empty vals for a disconnected graph, to
        // work around a segfault from METIS.
        libmesh_assert_equal_to (csr_graph.vals.size(),
                                 std::max(graph_size,std::size_t(1)));
      } // done building the graph

      Metis::idx_t ncon = 1;

      // Select which type of partitioning to create

      // Use recursive if the number of partitions is less than or equal to 8
      if (n_pieces <= 8)
        Metis::METIS_PartGraphRecursive(&n, &ncon, &csr_graph.offsets[0], &csr_graph.vals[0], &vwgt[0], libmesh_nullptr,
                                        libmesh_nullptr, &nparts, libmesh_nullptr, libmesh_nullptr, libmesh_nullptr,
                                        &edgecut, &part[0]);

      // Otherwise  use kway
      else
        Metis::METIS_PartGraphKway(&n, &ncon, &csr_graph.offsets[0], &csr_graph.vals[0], &vwgt[0], libmesh_nullptr,
                                   libmesh_nullptr, &nparts, libmesh_nullptr, libmesh_nullptr, libmesh_nullptr,
                                   &edgecut, &part[0]);

    } // end processor 0 part

  // Broadcase the resutling partition
  mesh.comm().broadcast(part);

  // Assign the returned processor ids.  The part array contains
  // the processor id for each active element, but in terms of
  // the contiguous indexing we defined above
  {
    MeshBase::element_iterator       it  = mesh.active_elements_begin();
    const MeshBase::element_iterator end = mesh.active_elements_end();

    for (; it!=end; ++it)
      {
        Elem * elem = *it;

        libmesh_assert (global_index_map.count(elem->id()));

        const dof_id_type elem_global_index =
          global_index_map[elem->id()];

        libmesh_assert_less (elem_global_index, part.size());
        const processor_id_type elem_procid =
          static_cast<processor_id_type>(part[elem_global_index]);

        elem->processor_id() = elem_procid;
      }
  }
#endif
}
Пример #11
0
Real FE<3,HERMITE>::shape_second_deriv(const Elem* elem,
                                      const Order order,
                                      const unsigned int i,
                                      const unsigned int j,
                                      const Point& p)
{
  libmesh_assert(elem);

  hermite_compute_coefs(elem);

#ifdef LIBMESH_HAVE_TBB_API
  std::vector<std::vector<Real> > & dxdxi = dxdxi_tls.local();
#endif

  const ElemType type = elem->type();

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

  switch (totalorder)
    {
      // 3rd-order tricubic Hermite functions
    case THIRD:
      {
	switch (type)
	  {
	  case HEX8:
	  case HEX20:
	  case HEX27:
	    {
	      libmesh_assert_less (i, 64);

              std::vector<unsigned int> bases1D;

              Real coef = hermite_bases_3D(bases1D, dxdxi, totalorder, i);

              switch (j) // Derivative type
		{
		case 0:
                  return coef *
                    FEHermite<1>::hermite_raw_shape_second_deriv(bases1D[0],p(0)) *
                    FEHermite<1>::hermite_raw_shape(bases1D[1],p(1)) *
                    FEHermite<1>::hermite_raw_shape(bases1D[2],p(2));
                  break;
		case 1:
                  return coef *
                    FEHermite<1>::hermite_raw_shape_deriv(bases1D[0],p(0)) *
                    FEHermite<1>::hermite_raw_shape_deriv(bases1D[1],p(1)) *
                    FEHermite<1>::hermite_raw_shape(bases1D[2],p(2));
                  break;
		case 2:
                  return coef *
                    FEHermite<1>::hermite_raw_shape(bases1D[0],p(0)) *
                    FEHermite<1>::hermite_raw_shape_second_deriv(bases1D[1],p(1)) *
                    FEHermite<1>::hermite_raw_shape(bases1D[2],p(2));
                  break;
		case 3:
                  return coef *
                    FEHermite<1>::hermite_raw_shape_deriv(bases1D[0],p(0)) *
                    FEHermite<1>::hermite_raw_shape(bases1D[1],p(1)) *
                    FEHermite<1>::hermite_raw_shape_deriv(bases1D[2],p(2));
                  break;
		case 4:
                  return coef *
                    FEHermite<1>::hermite_raw_shape(bases1D[0],p(0)) *
                    FEHermite<1>::hermite_raw_shape_deriv(bases1D[1],p(1)) *
                    FEHermite<1>::hermite_raw_shape_deriv(bases1D[2],p(2));
                  break;
		case 5:
                  return coef *
                    FEHermite<1>::hermite_raw_shape(bases1D[0],p(0)) *
                    FEHermite<1>::hermite_raw_shape(bases1D[1],p(1)) *
                    FEHermite<1>::hermite_raw_shape_second_deriv(bases1D[2],p(2));
                  break;
                }

	    }
	  default:
            libMesh::err << "ERROR: Unsupported element type!" << std::endl;
	    libmesh_error();
	  }
      }
      // by default throw an error
    default:
      libMesh::err << "ERROR: Unsupported polynomial order!" << std::endl;
      libmesh_error();
    }

  libmesh_error();
  return 0.;
}
Пример #12
0
Real FE<2,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 TRISHELL3:
    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,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,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,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:
    case QUADSHELL4:
      libmesh_assert_less (totalorder, 2);
      libmesh_fallthrough();
    case QUAD8:
    case QUADSHELL8:
    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,HIERARCHIC>::shape(EDGE3, totalorder, i0, xi)*
                  FE<1,HIERARCHIC>::shape(EDGE3, totalorder, i1, eta));
      }

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

  return 0.;
}
Пример #13
0
Real FE<2,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 TRISHELL3:
    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,HIERARCHIC>::shape(elem, order, i, pp) -
                      FE<2,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,HIERARCHIC>::shape(elem, order, i, pp) -
                      FE<2,HIERARCHIC>::shape(elem, order, i, pm))/2./eps;
            }

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

    case QUAD4:
    case QUADSHELL4:
      libmesh_assert_less (totalorder, 2);
      libmesh_fallthrough();
    case QUAD8:
    case QUADSHELL8:
    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,HIERARCHIC>::shape_deriv(EDGE3, totalorder, i0, 0, xi)*
                      FE<1,HIERARCHIC>::shape      (EDGE3, totalorder, i1,    eta));

            // d()/deta
          case 1:
            return f*(FE<1,HIERARCHIC>::shape      (EDGE3, totalorder, i0,    xi)*
                      FE<1,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.;
}
Пример #14
0
void MeshRefinement::flag_elements_by_mean_stddev (const ErrorVector& error_per_cell,
						   const Real refine_frac,
						   const Real coarsen_frac,
						   const unsigned int max_l)
{
  // The function arguments are currently just there for
  // backwards_compatibility
  if (!_use_member_parameters)
    {
      // If the user used non-default parameters, lets warn
      // that they're deprecated
      if (refine_frac != 0.3 ||
          coarsen_frac != 0.0 ||
          max_l != libMesh::invalid_uint)
        libmesh_deprecated();

      _refine_fraction = refine_frac;
      _coarsen_fraction = coarsen_frac;
      _max_h_level = max_l;
    }

  // Get the mean value from the error vector
  const Real mean = error_per_cell.mean();

  // Get the standard deviation.  This equals the
  // square-root of the variance
  const Real stddev = std::sqrt (error_per_cell.variance());

  // Check for valid fractions
  libmesh_assert_greater_equal (_refine_fraction, 0);
  libmesh_assert_less_equal (_refine_fraction, 1);
  libmesh_assert_greater_equal (_coarsen_fraction, 0);
  libmesh_assert_less_equal (_coarsen_fraction, 1);

  // The refine and coarsen cutoff
  const Real refine_cutoff  =  mean + _refine_fraction  * stddev;
  const Real coarsen_cutoff =  std::max(mean - _coarsen_fraction * stddev, 0.);

  // Loop over the elements and flag them for coarsening or
  // refinement based on the element error
  MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
  const MeshBase::element_iterator elem_end = _mesh.active_elements_end();

  for (; elem_it != elem_end; ++elem_it)
    {
      Elem* elem             = *elem_it;
      const unsigned int id  = elem->id();

      libmesh_assert_less (id, error_per_cell.size());

      const float elem_error = error_per_cell[id];

      // Possibly flag the element for coarsening ...
      if (elem_error <= coarsen_cutoff)
	elem->set_refinement_flag(Elem::COARSEN);

      // ... or refinement
      if ((elem_error >= refine_cutoff) && (elem->level() < _max_h_level))
	elem->set_refinement_flag(Elem::REFINE);
    }
}
Пример #15
0
UniquePtr<Elem> InfHex16::build_side (const unsigned int i,
                                      bool proxy) const
{
  libmesh_assert_less (i, this->n_sides());

  if (proxy)
    {
      switch (i)
        {
          // base
        case 0:
          return UniquePtr<Elem>(new Side<Quad8,InfHex16>(this,i));

          // ifem sides
        case 1:
        case 2:
        case 3:
        case 4:
          return UniquePtr<Elem>(new Side<InfQuad6,InfHex16>(this,i));

        default:
          libmesh_error_msg("Invalid side i = " << i);
        }
    }

  else
    {
      // Create NULL pointer to be initialized, returned later.
      Elem* face = NULL;

      // Think of a unit cube: (-1,1) x (-1,1) x (1,1)
      switch (i)
        {
        case 0: // the base face
          {
            face = new Quad8;

            // Only here, the face element's normal points inward
            face->set_node(0) = this->get_node(0);
            face->set_node(1) = this->get_node(1);
            face->set_node(2) = this->get_node(2);
            face->set_node(3) = this->get_node(3);
            face->set_node(4) = this->get_node(8);
            face->set_node(5) = this->get_node(9);
            face->set_node(6) = this->get_node(10);
            face->set_node(7) = this->get_node(11);

            break;
          }

        case 1:  // connecting to another infinite element
          {
            face = new InfQuad6;

            face->set_node(0) = this->get_node(0);
            face->set_node(1) = this->get_node(1);
            face->set_node(2) = this->get_node(4);
            face->set_node(3) = this->get_node(5);
            face->set_node(4) = this->get_node(8);
            face->set_node(5) = this->get_node(12);

            break;
          }

        case 2:  // connecting to another infinite element
          {
            face = new InfQuad6;

            face->set_node(0) = this->get_node(1);
            face->set_node(1) = this->get_node(2);
            face->set_node(2) = this->get_node(5);
            face->set_node(3) = this->get_node(6);
            face->set_node(4) = this->get_node(9);
            face->set_node(5) = this->get_node(13);

            break;
          }

        case 3:  // connecting to another infinite element
          {
            face = new InfQuad6;

            face->set_node(0) = this->get_node(2);
            face->set_node(1) = this->get_node(3);
            face->set_node(2) = this->get_node(6);
            face->set_node(3) = this->get_node(7);
            face->set_node(4) = this->get_node(10);
            face->set_node(5) = this->get_node(14);

            break;
          }

        case 4:  // connecting to another infinite element
          {
            face = new InfQuad6;

            face->set_node(0) = this->get_node(3);
            face->set_node(1) = this->get_node(0);
            face->set_node(2) = this->get_node(7);
            face->set_node(3) = this->get_node(4);
            face->set_node(4) = this->get_node(11);
            face->set_node(5) = this->get_node(15);

            break;
          }

        default:
          libmesh_error_msg("Invalid side i = " << i);
        }

      face->subdomain_id() = this->subdomain_id();
      return UniquePtr<Elem>(face);
    }

  libmesh_error_msg("We'll never get here!");
  return UniquePtr<Elem>();
}
Пример #16
0
NumericVector<Number>& RBEvaluation::get_basis_function(unsigned int i)
{
  libmesh_assert_less (i, basis_functions.size());

  return *(basis_functions[i]);
}
Пример #17
0
void Tri6::connectivity(const unsigned int sf,
                        const IOPackage iop,
                        std::vector<dof_id_type>& conn) const
{
  libmesh_assert_less (sf, this->n_sub_elem());
  libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);

  switch (iop)
    {
    case TECPLOT:
      {
        conn.resize(4);
        switch(sf)
          {
          case 0:
            // linear sub-triangle 0
            conn[0] = this->node(0)+1;
            conn[1] = this->node(3)+1;
            conn[2] = this->node(5)+1;
            conn[3] = this->node(5)+1;

            return;

          case 1:
            // linear sub-triangle 1
            conn[0] = this->node(3)+1;
            conn[1] = this->node(1)+1;
            conn[2] = this->node(4)+1;
            conn[3] = this->node(4)+1;

            return;

          case 2:
            // linear sub-triangle 2
            conn[0] = this->node(5)+1;
            conn[1] = this->node(4)+1;
            conn[2] = this->node(2)+1;
            conn[3] = this->node(2)+1;

            return;

          case 3:
            // linear sub-triangle 3
            conn[0] = this->node(3)+1;
            conn[1] = this->node(4)+1;
            conn[2] = this->node(5)+1;
            conn[3] = this->node(5)+1;

            return;

          default:
            libmesh_error_msg("Invalid sf = " << sf);
          }
      }

    case VTK:
      {
        // VTK_QUADRATIC_TRIANGLE has same numbering as libmesh TRI6
        conn.resize(6);
        conn[0] = this->node(0);
        conn[1] = this->node(1);
        conn[2] = this->node(2);
        conn[3] = this->node(3);
        conn[4] = this->node(4);
        conn[5] = this->node(5);
        return;

        // Used to write out linear sub-triangles for VTK...
        /*
          conn.resize(3);
          switch(sf)
          {
          case 0:
          // linear sub-triangle 0
          conn[0] = this->node(0);
          conn[1] = this->node(3);
          conn[2] = this->node(5);

          return;

          case 1:
          // linear sub-triangle 1
          conn[0] = this->node(3);
          conn[1] = this->node(1);
          conn[2] = this->node(4);

          return;

          case 2:
          // linear sub-triangle 2
          conn[0] = this->node(5);
          conn[1] = this->node(4);
          conn[2] = this->node(2);

          return;

          case 3:
          // linear sub-triangle 3
          conn[0] = this->node(3);
          conn[1] = this->node(4);
          conn[2] = this->node(5);

          return;

          default:
          libmesh_error_msg("Invalid sf = " << sf);
          }
        */
      }

    default:
      libmesh_error_msg("Unsupported IO package " << iop);
    }
}
Пример #18
0
  std::string AntiochChemistry::species_name( unsigned int species_index ) const
  {
    libmesh_assert_less(species_index, _antioch_gas->n_species());

    return _antioch_gas->species_inverse_name_map().find(species_index)->second;
  }
Пример #19
0
AutoPtr<Elem> Tet10::build_edge (const unsigned int i) const
{
  libmesh_assert_less (i, this->n_edges());

  return AutoPtr<Elem>(new SideEdge<Edge3,Tet10>(this,i));
}
Пример #20
0
void Partitioner::partition_unpartitioned_elements (MeshBase & mesh,
                                                    const unsigned int n_subdomains)
{
  MeshBase::element_iterator       it  = mesh.unpartitioned_elements_begin();
  const MeshBase::element_iterator end = mesh.unpartitioned_elements_end();

  const dof_id_type n_unpartitioned_elements = MeshTools::n_elem (it, end);

  // the unpartitioned elements must exist on all processors. If the range is empty on one
  // it is empty on all, and we can quit right here.
  if (!n_unpartitioned_elements) return;

  // find the target subdomain sizes
  std::vector<dof_id_type> subdomain_bounds(mesh.n_processors());

  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 < n_subdomains)
        {
          tgt_subdomain_size = n_unpartitioned_elements/n_subdomains;

          if (pid < n_unpartitioned_elements%n_subdomains)
            tgt_subdomain_size++;

        }

      //libMesh::out << "pid, #= " << pid << ", " << tgt_subdomain_size << std::endl;
      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_unpartitioned_elements);

  // create the unique mapping for all unpartitioned elements independent of partitioning
  // determine the global indexing for all the unpartitioned elements
  std::vector<dof_id_type> global_indices;

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

  for (dof_id_type cnt=0; it != end; ++it)
    {
      Elem * elem = *it;

      libmesh_assert_less (cnt, global_indices.size());
      const dof_id_type global_index =
        global_indices[cnt++];

      libmesh_assert_less (global_index, subdomain_bounds.back());
      libmesh_assert_less (global_index, n_unpartitioned_elements);

      const processor_id_type subdomain_id =
        cast_int<processor_id_type>
        (std::distance(subdomain_bounds.begin(),
                       std::upper_bound(subdomain_bounds.begin(),
                                        subdomain_bounds.end(),
                                        global_index)));
      libmesh_assert_less (subdomain_id, n_subdomains);

      elem->processor_id() = subdomain_id;
      //libMesh::out << "assigning " << global_index << " to " << subdomain_id << std::endl;
    }
}
Пример #21
0
AutoPtr<Elem> InfHex18::build_side (const unsigned int i,
                                    bool proxy) const
{
  libmesh_assert_less (i, this->n_sides());

  if (proxy)
    {
      switch (i)
        {
          // base
        case 0:
          {
            AutoPtr<Elem> ap(new Side<Quad9,InfHex18>(this,i));
            return ap;
          }
          // ifem sides
        case 1:
        case 2:
        case 3:
        case 4:
          {
            AutoPtr<Elem> ap(new Side<InfQuad6,InfHex18>(this,i));
            return ap;
          }
        default:
          libmesh_error_msg("Invalid side i = " << i);
        }
    }

  else
    {
      // Create NULL pointer to be initialized, returned later.
      AutoPtr<Elem> face(NULL);

      // Think of a unit cube: (-1,1) x (-1,1) x (1,1)
      switch (i)
        {
        case 0: // the base face
          {
            face.reset(new Quad9);

            // This is the exception: all other face elements' normals
            // point outwards; but the base element's normal points inward
            face->set_node(0) = this->get_node(0);
            face->set_node(1) = this->get_node(1);
            face->set_node(2) = this->get_node(2);
            face->set_node(3) = this->get_node(3);
            face->set_node(4) = this->get_node(8);
            face->set_node(5) = this->get_node(9);
            face->set_node(6) = this->get_node(10);
            face->set_node(7) = this->get_node(11);
            face->set_node(8) = this->get_node(16);

            break;
          }

        case 1:  // connecting to another infinite element
          {
            face.reset(new InfQuad6);

            face->set_node(0) = this->get_node(0);
            face->set_node(1) = this->get_node(1);
            face->set_node(2) = this->get_node(4);
            face->set_node(3) = this->get_node(5);
            face->set_node(4) = this->get_node(8);
            face->set_node(5) = this->get_node(12);

            break;
          }

        case 2:  // connecting to another infinite element
          {
            face.reset(new InfQuad6);

            face->set_node(0) = this->get_node(1);
            face->set_node(1) = this->get_node(2);
            face->set_node(2) = this->get_node(5);
            face->set_node(3) = this->get_node(6);
            face->set_node(4) = this->get_node(9);
            face->set_node(5) = this->get_node(13);

            break;
          }

        case 3:  // connecting to another infinite element
          {
            face.reset(new InfQuad6);

            face->set_node(0) = this->get_node(2);
            face->set_node(1) = this->get_node(3);
            face->set_node(2) = this->get_node(6);
            face->set_node(3) = this->get_node(7);
            face->set_node(4) = this->get_node(10);
            face->set_node(5) = this->get_node(14);

            break;
          }

        case 4:  // connecting to another infinite element
          {
            face.reset(new InfQuad6);

            face->set_node(0) = this->get_node(3);
            face->set_node(1) = this->get_node(0);
            face->set_node(2) = this->get_node(7);
            face->set_node(3) = this->get_node(4);
            face->set_node(4) = this->get_node(11);
            face->set_node(5) = this->get_node(15);

            break;
          }

        default:
          libmesh_error_msg("Invalid side i = " << i);
        }

      face->subdomain_id() = this->subdomain_id();
      return face;
    }

  libmesh_error_msg("We'll never get here!");
  AutoPtr<Elem> ap(NULL);
  return ap;
}
Пример #22
0
void Partitioner::set_parent_processor_ids(MeshBase & mesh)
{
  // Ignore the parameter when !LIBMESH_ENABLE_AMR
  libmesh_ignore(mesh);

  LOG_SCOPE("set_parent_processor_ids()", "Partitioner");

#ifdef LIBMESH_ENABLE_AMR

  // If the mesh is serial we have access to all the elements,
  // in particular all the active ones.  We can therefore set
  // the parent processor ids indirectly through their children, and
  // set the subactive processor ids while examining their active
  // ancestors.
  // By convention a parent is assigned to the minimum processor
  // of all its children, and a subactive is assigned to the processor
  // of its active ancestor.
  if (mesh.is_serial())
    {
      for (auto & child : mesh.active_element_ptr_range())
        {
          // First set descendents
          std::vector<const Elem *> subactive_family;
          child->total_family_tree(subactive_family);
          for (std::size_t i = 0; i != subactive_family.size(); ++i)
            const_cast<Elem *>(subactive_family[i])->processor_id() = child->processor_id();

          // Then set ancestors
          Elem * parent = child->parent();

          while (parent)
            {
              // invalidate the parent id, otherwise the min below
              // will not work if the current parent id is less
              // than all the children!
              parent->invalidate_processor_id();

              for (auto & child : parent->child_ref_range())
                {
                  libmesh_assert(!child.is_remote());
                  libmesh_assert_not_equal_to (child.processor_id(), DofObject::invalid_processor_id);
                  parent->processor_id() = std::min(parent->processor_id(),
                                                    child.processor_id());
                }
              parent = parent->parent();
            }
        }
    }

  // When the mesh is parallel we cannot guarantee that parents have access to
  // all their children.
  else
    {
      // Setting subactive processor ids is easy: we can guarantee
      // that children have access to all their parents.

      // Loop over all the active elements in the mesh
      for (auto & child : mesh.active_element_ptr_range())
        {
          std::vector<const Elem *> subactive_family;
          child->total_family_tree(subactive_family);
          for (std::size_t i = 0; i != subactive_family.size(); ++i)
            const_cast<Elem *>(subactive_family[i])->processor_id() = child->processor_id();
        }

      // When the mesh is parallel we cannot guarantee that parents have access to
      // all their children.

      // We will use a brute-force approach here.  Each processor finds its parent
      // elements and sets the parent pid to the minimum of its
      // semilocal descendants.
      // A global reduction is then performed to make sure the true minimum is found.
      // As noted, this is required because we cannot guarantee that a parent has
      // access to all its children on any single processor.
      libmesh_parallel_only(mesh.comm());
      libmesh_assert(MeshTools::n_elem(mesh.unpartitioned_elements_begin(),
                                       mesh.unpartitioned_elements_end()) == 0);

      const dof_id_type max_elem_id = mesh.max_elem_id();

      std::vector<processor_id_type>
        parent_processor_ids (std::min(communication_blocksize,
                                       max_elem_id));

      for (dof_id_type blk=0, last_elem_id=0; last_elem_id<max_elem_id; blk++)
        {
          last_elem_id =
            std::min(static_cast<dof_id_type>((blk+1)*communication_blocksize),
                     max_elem_id);
          const dof_id_type first_elem_id = blk*communication_blocksize;

          std::fill (parent_processor_ids.begin(),
                     parent_processor_ids.end(),
                     DofObject::invalid_processor_id);

          // first build up local contributions to parent_processor_ids
          MeshBase::element_iterator       not_it  = mesh.ancestor_elements_begin();
          const MeshBase::element_iterator not_end = mesh.ancestor_elements_end();

          bool have_parent_in_block = false;

          for ( ; not_it != not_end; ++not_it)
            {
              Elem * parent = *not_it;

              const dof_id_type parent_idx = parent->id();
              libmesh_assert_less (parent_idx, max_elem_id);

              if ((parent_idx >= first_elem_id) &&
                  (parent_idx <  last_elem_id))
                {
                  have_parent_in_block = true;
                  processor_id_type parent_pid = DofObject::invalid_processor_id;

                  std::vector<const Elem *> active_family;
                  parent->active_family_tree(active_family);
                  for (std::size_t i = 0; i != active_family.size(); ++i)
                    parent_pid = std::min (parent_pid, active_family[i]->processor_id());

                  const dof_id_type packed_idx = parent_idx - first_elem_id;
                  libmesh_assert_less (packed_idx, parent_processor_ids.size());

                  parent_processor_ids[packed_idx] = parent_pid;
                }
            }

          // then find the global minimum
          mesh.comm().min (parent_processor_ids);

          // and assign the ids, if we have a parent in this block.
          if (have_parent_in_block)
            for (not_it = mesh.ancestor_elements_begin();
                 not_it != not_end; ++not_it)
              {
                Elem * parent = *not_it;

                const dof_id_type parent_idx = parent->id();

                if ((parent_idx >= first_elem_id) &&
                    (parent_idx <  last_elem_id))
                  {
                    const dof_id_type packed_idx = parent_idx - first_elem_id;
                    libmesh_assert_less (packed_idx, parent_processor_ids.size());

                    const processor_id_type parent_pid =
                      parent_processor_ids[packed_idx];

                    libmesh_assert_not_equal_to (parent_pid, DofObject::invalid_processor_id);

                    parent->processor_id() = parent_pid;
                  }
              }
        }
    }

#endif // LIBMESH_ENABLE_AMR
}
Пример #23
0
UniquePtr<Elem> InfPrism12::build_side_ptr (const unsigned int i,
                                            bool proxy)
{
  libmesh_assert_less (i, this->n_sides());

  if (proxy)
    {
      switch (i)
        {
          // base
        case 0:
          return UniquePtr<Elem>(new Side<Tri6,InfPrism12>(this,i));

          // ifem sides
        case 1:
        case 2:
        case 3:
          return UniquePtr<Elem>(new Side<InfQuad6,InfPrism12>(this,i));

        default:
          libmesh_error_msg("Invalid side i = " << i);
        }
    }

  else
    {
      // Create NULL pointer to be initialized, returned later.
      Elem * face = libmesh_nullptr;

      switch (i)
        {
        case 0: // the triangular face at z=-1, base face
          {
            face = new Tri6;
            break;
          }

        case 1: // the quad face at y=0
        case 2: // the other quad face
        case 3: // the quad face at x=0
          {
            face = new InfQuad6;
            break;
          }

        default:
          libmesh_error_msg("Invalid side i = " << i);
        }

      face->subdomain_id() = this->subdomain_id();

      // Set the nodes
      for (unsigned n=0; n<face->n_nodes(); ++n)
        face->set_node(n) = this->node_ptr(InfPrism12::side_nodes_map[i][n]);

      return UniquePtr<Elem>(face);
    }

  libmesh_error_msg("We'll never get here!");
  return UniquePtr<Elem>();
}
Пример #24
0
void Partitioner::set_node_processor_ids(MeshBase & mesh)
{
  LOG_SCOPE("set_node_processor_ids()","Partitioner");

  // This function must be run on all processors at once
  libmesh_parallel_only(mesh.comm());

  // If we have any unpartitioned elements at this
  // stage there is a problem
  libmesh_assert (MeshTools::n_elem(mesh.unpartitioned_elements_begin(),
                                    mesh.unpartitioned_elements_end()) == 0);


  //   const dof_id_type orig_n_local_nodes = mesh.n_local_nodes();

  //   libMesh::err << "[" << mesh.processor_id() << "]: orig_n_local_nodes="
  //     << orig_n_local_nodes << std::endl;

  // Build up request sets.  Each node is currently owned by a processor because
  // it is connected to an element owned by that processor.  However, during the
  // repartitioning phase that element may have been assigned a new processor id, but
  // it is still resident on the original processor.  We need to know where to look
  // for new ids before assigning new ids, otherwise we may be asking the wrong processors
  // for the wrong information.
  //
  // The only remaining issue is what to do with unpartitioned nodes.  Since they are required
  // to live on all processors we can simply rely on ourselves to number them properly.
  std::vector<std::vector<dof_id_type>>
    requested_node_ids(mesh.n_processors());

  // Loop over all the nodes, count the ones on each processor.  We can skip ourself
  std::vector<dof_id_type> ghost_nodes_from_proc(mesh.n_processors(), 0);

  for (auto & node : mesh.node_ptr_range())
    {
      libmesh_assert(node);
      const processor_id_type current_pid = node->processor_id();
      if (current_pid != mesh.processor_id() &&
          current_pid != DofObject::invalid_processor_id)
        {
          libmesh_assert_less (current_pid, ghost_nodes_from_proc.size());
          ghost_nodes_from_proc[current_pid]++;
        }
    }

  // We know how many objects live on each processor, so reserve()
  // space for each.
  for (processor_id_type pid=0; pid != mesh.n_processors(); ++pid)
    requested_node_ids[pid].reserve(ghost_nodes_from_proc[pid]);

  // We need to get the new pid for each node from the processor
  // which *currently* owns the node.  We can safely skip ourself
  for (auto & node : mesh.node_ptr_range())
    {
      libmesh_assert(node);
      const processor_id_type current_pid = node->processor_id();
      if (current_pid != mesh.processor_id() &&
          current_pid != DofObject::invalid_processor_id)
        {
          libmesh_assert_less (current_pid, requested_node_ids.size());
          libmesh_assert_less (requested_node_ids[current_pid].size(),
                               ghost_nodes_from_proc[current_pid]);
          requested_node_ids[current_pid].push_back(node->id());
        }

      // Unset any previously-set node processor ids
      node->invalidate_processor_id();
    }

  // Loop over all the active elements
  for (auto & elem : mesh.active_element_ptr_range())
    {
      libmesh_assert(elem);

      libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id);

      // For each node, set the processor ID to the min of
      // its current value and this Element's processor id.
      //
      // TODO: we would probably get better parallel partitioning if
      // we did something like "min for even numbered nodes, max for
      // odd numbered".  We'd need to be careful about how that would
      // affect solution ordering for I/O, though.
      for (unsigned int n=0; n<elem->n_nodes(); ++n)
        elem->node_ptr(n)->processor_id() = std::min(elem->node_ptr(n)->processor_id(),
                                                     elem->processor_id());
    }

  // And loop over the subactive elements, but don't reassign
  // nodes that are already active on another processor.
  MeshBase::element_iterator       sub_it  = mesh.subactive_elements_begin();
  const MeshBase::element_iterator sub_end = mesh.subactive_elements_end();

  for ( ; sub_it != sub_end; ++sub_it)
    {
      Elem * elem = *sub_it;
      libmesh_assert(elem);

      libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id);

      for (unsigned int n=0; n<elem->n_nodes(); ++n)
        if (elem->node_ptr(n)->processor_id() == DofObject::invalid_processor_id)
          elem->node_ptr(n)->processor_id() = elem->processor_id();
    }

  // Same for the inactive elements -- we will have already gotten most of these
  // nodes, *except* for the case of a parent with a subset of children which are
  // ghost elements.  In that case some of the parent nodes will not have been
  // properly handled yet
  MeshBase::element_iterator       not_it  = mesh.not_active_elements_begin();
  const MeshBase::element_iterator not_end = mesh.not_active_elements_end();

  for ( ; not_it != not_end; ++not_it)
    {
      Elem * elem = *not_it;
      libmesh_assert(elem);

      libmesh_assert_not_equal_to (elem->processor_id(), DofObject::invalid_processor_id);

      for (unsigned int n=0; n<elem->n_nodes(); ++n)
        if (elem->node_ptr(n)->processor_id() == DofObject::invalid_processor_id)
          elem->node_ptr(n)->processor_id() = elem->processor_id();
    }

  // We can't assert that all nodes are connected to elements, because
  // a DistributedMesh with NodeConstraints might have pulled in some
  // remote nodes solely for evaluating those constraints.
  // MeshTools::libmesh_assert_connected_nodes(mesh);

  // For such nodes, we'll do a sanity check later when making sure
  // that we successfully reset their processor ids to something
  // valid.

  // Next set node ids from other processors, excluding self
  for (processor_id_type p=1; p != mesh.n_processors(); ++p)
    {
      // Trade my requests with processor procup and procdown
      processor_id_type procup = cast_int<processor_id_type>
        ((mesh.processor_id() + p) % mesh.n_processors());
      processor_id_type procdown = cast_int<processor_id_type>
        ((mesh.n_processors() + mesh.processor_id() - p) %
         mesh.n_processors());
      std::vector<dof_id_type> request_to_fill;
      mesh.comm().send_receive(procup, requested_node_ids[procup],
                               procdown, request_to_fill);

      // Fill those requests in-place
      for (std::size_t i=0; i != request_to_fill.size(); ++i)
        {
          Node & node = mesh.node_ref(request_to_fill[i]);
          const processor_id_type new_pid = node.processor_id();

          // We may have an invalid processor_id() on nodes that have been
          // "detached" from coarsened-away elements but that have not yet
          // themselves been removed.
          // libmesh_assert_not_equal_to (new_pid, DofObject::invalid_processor_id);
          // libmesh_assert_less (new_pid, mesh.n_partitions()); // this is the correct test --
          request_to_fill[i] = new_pid;           //  the number of partitions may
        }                                         //  not equal the number of processors

      // Trade back the results
      std::vector<dof_id_type> filled_request;
      mesh.comm().send_receive(procdown, request_to_fill,
                               procup,   filled_request);
      libmesh_assert_equal_to (filled_request.size(), requested_node_ids[procup].size());

      // And copy the id changes we've now been informed of
      for (std::size_t i=0; i != filled_request.size(); ++i)
        {
          Node & node = mesh.node_ref(requested_node_ids[procup][i]);

          // this is the correct test -- the number of partitions may
          // not equal the number of processors

          // But: we may have an invalid processor_id() on nodes that
          // have been "detached" from coarsened-away elements but
          // that have not yet themselves been removed.
          // libmesh_assert_less (filled_request[i], mesh.n_partitions());

          node.processor_id(cast_int<processor_id_type>(filled_request[i]));
        }
    }

#ifdef DEBUG
  MeshTools::libmesh_assert_valid_procids<Node>(mesh);
#endif
}
Пример #25
0
AutoPtr<Elem> InfPrism12::build_side (const unsigned int i,
				      bool proxy) const
{
  libmesh_assert_less (i, this->n_sides());

  if (proxy)
    {
      switch (i)
	{
	  // base
	case 0:
	  {
	    AutoPtr<Elem> ap(new Side<Tri6,InfPrism12>(this,i));
	    return ap;
	  }
	  // ifem sides
	case 1:
	case 2:
	case 3:
	  {
	    AutoPtr<Elem> ap(new Side<InfQuad6,InfPrism12>(this,i));
	    return ap;
	  }
	default:
	  libmesh_error();
	}
    }

  else
    {
      // Create NULL pointer to be initialized, returned later.
      AutoPtr<Elem> face(NULL);

      switch (i)
	{
	case 0:  // the triangular face at z=-1, base face
	  {
            face.reset(new Tri6);

	    // Note that for this face element, the normal points inward
	    face->set_node(0) = this->get_node(0);
	    face->set_node(1) = this->get_node(1);
	    face->set_node(2) = this->get_node(2);
	    face->set_node(3) = this->get_node(6);
	    face->set_node(4) = this->get_node(7);
	    face->set_node(5) = this->get_node(8);

	    break;
	  }

	case 1:  // the quad face at y=0
	  {
            face.reset(new InfQuad6);

	    face->set_node(0) = this->get_node(0);
	    face->set_node(1) = this->get_node(1);
	    face->set_node(2) = this->get_node(3);
	    face->set_node(3) = this->get_node(4);
	    face->set_node(4) = this->get_node(6);
	    face->set_node(5) = this->get_node(9);

	    break;
	  }

	case 2:  // the other quad face
	  {
            face.reset(new InfQuad6);

	    face->set_node(0) = this->get_node(1);
	    face->set_node(1) = this->get_node(2);
	    face->set_node(2) = this->get_node(4);
	    face->set_node(3) = this->get_node(5);
	    face->set_node(4) = this->get_node(7);
	    face->set_node(5) = this->get_node(10);

	    break;
	  }

	case 3: // the quad face at x=0
	  {
            face.reset(new InfQuad6);

	    face->set_node(0) = this->get_node(2);
	    face->set_node(1) = this->get_node(0);
	    face->set_node(2) = this->get_node(5);
	    face->set_node(3) = this->get_node(3);
	    face->set_node(4) = this->get_node(8);
	    face->set_node(5) = this->get_node(11);

	    break;
	  }

	default:
	  {
	    libmesh_error();
	  }
	}

      face->subdomain_id() = this->subdomain_id();
      return face;
    }


  // We'll never get here.
  libmesh_error();
  AutoPtr<Elem> ap(NULL);  return ap;
}
Пример #26
0
AutoPtr<Elem> Quad4::build_side (const unsigned int i,
				 bool proxy) const
{
  libmesh_assert_less (i, this->n_sides());

  if (proxy)
    {
      AutoPtr<Elem> ap(new Side<Edge2,Quad4>(this,i));
      return ap;
    }

  else
    {

      switch (i)
	{
	case 0:
	  {
	    Edge2* edge = new Edge2;

	    edge->set_node(0) = this->get_node(0);
	    edge->set_node(1) = this->get_node(1);

	    AutoPtr<Elem> ap(edge);  return ap;
	  }
	case 1:
	  {
	    Edge2* edge = new Edge2;

	    edge->set_node(0) = this->get_node(1);
	    edge->set_node(1) = this->get_node(2);

	    AutoPtr<Elem> ap(edge);  return ap;
	  }
	case 2:
	  {
	    Edge2* edge = new Edge2;

	    edge->set_node(0) = this->get_node(2);
	    edge->set_node(1) = this->get_node(3);

	    AutoPtr<Elem> ap(edge);  return ap;
	  }
	case 3:
	  {
	    Edge2* edge = new Edge2;

	    edge->set_node(0) = this->get_node(3);
	    edge->set_node(1) = this->get_node(0);

	    AutoPtr<Elem> ap(edge);  return ap;
	  }
	default:
	  {
	    libmesh_error();
	  }
	}
    }

  // We will never get here...
  AutoPtr<Elem> ap(NULL);  return ap;
}
Пример #27
0
RealGradient FE<2,NEDELEC_ONE>::shape_deriv(const Elem* elem,
					    const Order order,
					    const unsigned int i,
					    const unsigned int j,
					    const Point&)
{
#if LIBMESH_DIM > 1
  libmesh_assert(elem);
  libmesh_assert_less (j, 2);

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

  switch (total_order)
    {
      // linear Lagrange shape functions
    case FIRST:
      {
	switch (elem->type())
	  {
	  case QUAD8:
	  case QUAD9:
	    {
	      libmesh_assert_less (i, 4);

	      switch (j)
		{
		  // d()/dxi
		case 0:
		  {
		    switch(i)
		      {
		      case 0:
		      case 2:
			return RealGradient();
		      case 1:
			{
			  if( elem->point(1) > elem->point(2) )
			    return RealGradient( 0.0, -0.25 );
			  else
			    return RealGradient( 0.0, 0.25 );
			}
		      case 3:
			{
			  if( elem->point(3) > elem->point(0) )
			    return RealGradient( 0.0, -0.25 );
			  else
			    return RealGradient( 0.0, 0.25 );
			}
		      default:
			libmesh_error();
		      }
		  } // j=0

		  // d()/deta
		case 1:
		  {
		    switch(i)
		      {
		      case 1:
		      case 3:
			return RealGradient();
		      case 0:
			{
			  if( elem->point(0) > elem->point(1) )
			    return RealGradient( 0.25 );
			  else
			    return RealGradient( -0.25 );
			}
		      case 2:
			{
			  if( elem->point(2) > elem->point(3) )
			    return RealGradient( 0.25 );
			  else
			    return RealGradient( -0.25 );
			}
		      default:
			libmesh_error();
		      }
		  } // j=1

		default:
		  libmesh_error();
		}

	      return RealGradient();
	    }

	  case TRI6:
	    {
	      libmesh_assert_less (i, 3);

	      // Account for edge flipping
	      Real f = 1.0;

	      switch(i)
		{
		case 0:
		  {
		    if( elem->point(0) > elem->point(1) )
		      f = -1.0;
		    break;
		  }
		case 1:
		  {
		    if( elem->point(1) > elem->point(2) )
		      f = -1.0;
		    break;
		  }
		case 2:
		  {
		    if( elem->point(2) > elem->point(0) )
		      f = -1.0;
		    break;
		  }
		default:
		  libmesh_error();
		}

	      switch (j)
		{
		  // d()/dxi
		case 0:
		  {
		    return RealGradient( 0.0, f*1.0);
		  }
		  // d()/deta
		case 1:
		  {
		    return RealGradient( f*(-1.0) );
		  }
		default:
		  libmesh_error();
		}
	    }

	  default:
	    {
	      libMesh::err << "ERROR: Unsupported 2D element type!: " << elem->type()
			    << std::endl;
	      libmesh_error();
	    }
	  }
      }
      // unsupported order
    default:
      {
	libMesh::err << "ERROR: Unsupported 2D FE order!: " << total_order
		      << std::endl;
	libmesh_error();
      }
    }
#endif // LIBMESH_DIM > 1

  libmesh_error();
  return RealGradient();
}
Пример #28
0
Real FE<2,XYZ>::shape(const Elem* elem,
                      const Order libmesh_dbg_var(order),
                      const unsigned int i,
                      const Point& point_in)
{
#if LIBMESH_DIM > 1

  libmesh_assert(elem);

  // 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 < 2; 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 xc = centroid(0);
  const Real yc = centroid(1);
  const Real distx = max_distance(0);
  const Real disty = max_distance(1);
  const Real dx = (x - xc)/distx;
  const Real dy = (y - yc)/disty;

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


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

      // linear
    case 1:
      return dx;

    case 2:
      return dy;

      // quadratics
    case 3:
      return dx*dx;

    case 4:
      return dx*dy;

    case 5:
      return dy*dy;

      // cubics
    case 6:
      return dx*dx*dx;

    case 7:
      return dx*dx*dy;

    case 8:
      return dx*dy*dy;

    case 9:
      return dy*dy*dy;

      // quartics
    case 10:
      return dx*dx*dx*dx;

    case 11:
      return dx*dx*dx*dy;

    case 12:
      return dx*dx*dy*dy;

    case 13:
      return dx*dy*dy*dy;

    case 14:
      return dy*dy*dy*dy;

    default:
      unsigned int o = 0;
      for (; i >= (o+1)*(o+2)/2; o++) { }
      unsigned int i2 = i - (o*(o+1)/2);
      Real val = 1.;
      for (unsigned int index=i2; index != o; index++)
        val *= dx;
      for (unsigned int index=0; index != i2; index++)
        val *= dy;
      return val;
    }

  libmesh_error();
  return 0.;

#endif
}
Пример #29
0
RealGradient FE<2,NEDELEC_ONE>::shape(const Elem* elem,
				      const Order order,
				      const unsigned int i,
				      const Point& p)
{
#if LIBMESH_DIM > 1
  libmesh_assert(elem);

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

  switch (total_order)
    {
    case FIRST:
      {
	switch (elem->type())
	  {
	  case QUAD8:
	  case QUAD9:
	    {
	      libmesh_assert_less (i, 4);

	      const Real xi  = p(0);
	      const Real eta = p(1);

              // Even with a loose inverse_map tolerance we ought to
              // be nearly on the element interior in master
              // coordinates
	      libmesh_assert_less_equal ( std::fabs(xi), 1.0+10*TOLERANCE );
	      libmesh_assert_less_equal ( std::fabs(eta), 1.0+10*TOLERANCE );

	      switch(i)
		{
		case 0:
		  {
		    if( elem->point(0) > elem->point(1) )
		      return RealGradient( -0.25*(1.0-eta), 0.0 );
		    else
		      return RealGradient( 0.25*(1.0-eta), 0.0 );
		  }
		case 1:
		  {
		    if( elem->point(1) > elem->point(2) )
		      return RealGradient( 0.0, -0.25*(1.0+xi) );
		    else
		      return RealGradient( 0.0, 0.25*(1.0+xi) );
		  }

		case 2:
		  {
		    if( elem->point(2) > elem->point(3) )
		      return RealGradient( 0.25*(1.0+eta), 0.0 );
		    else
		      return RealGradient( -0.25*(1.0+eta), 0.0 );
		  }
		case 3:
		  {
		    if( elem->point(3) > elem->point(0) )
		      return RealGradient( 0.0, -0.25*(xi-1.0) );
		    else
		      return RealGradient( 0.0, 0.25*(xi-1.0) );
		  }

		default:
		  libmesh_error();

		}

	      return RealGradient();
	    }

	  case TRI6:
	    {
	      const Real xi  = p(0);
	      const Real eta = p(1);

	      libmesh_assert_less (i, 3);

	      switch(i)
		{
		case 0:
		  {
		    if( elem->point(0) > elem->point(1) )
		      return RealGradient( -1.0+eta, -xi );
		    else
		      return RealGradient( 1.0-eta, xi );
		  }
		case 1:
		  {
		    if( elem->point(1) > elem->point(2) )
		      return RealGradient( eta, -xi );
		    else
		      return RealGradient( -eta, xi );
		  }

		case 2:
		  {
		    if( elem->point(2) > elem->point(0) )
		      return RealGradient( eta, -xi+1.0 );
		    else
		      return RealGradient( -eta, xi-1.0 );
		  }

		default:
		  libmesh_error();

		}
	    }

	  default:
	    {
	      libMesh::err << "ERROR: Unsupported 2D element type!: " << elem->type()
			    << std::endl;
	      libmesh_error();
	    }
	  }
      }

      // unsupported order
    default:
      {
	libMesh::err << "ERROR: Unsupported 2D FE order!: " << total_order
		      << std::endl;
	libmesh_error();
      }
    }
#endif // LIBMESH_DIM > 1

  libmesh_error();
  return RealGradient();
}
Пример #30
0
bool MeshRefinement::flag_elements_by_nelem_target (const ErrorVector& error_per_cell)
{
  parallel_only();

  // Check for valid fractions..
  // The fraction values must be in [0,1]
  libmesh_assert_greater_equal (_refine_fraction, 0);
  libmesh_assert_less_equal (_refine_fraction, 1);
  libmesh_assert_greater_equal (_coarsen_fraction, 0);
  libmesh_assert_less_equal (_coarsen_fraction, 1);

  // This function is currently only coded to work when coarsening by
  // parents - it's too hard to guess how many coarsenings will be
  // performed otherwise.
  libmesh_assert (_coarsen_by_parents);

  // The number of active elements in the mesh - hopefully less than
  // 2 billion on 32 bit machines
  const unsigned int n_active_elem  = _mesh.n_active_elem();

  // The maximum number of active elements to flag for coarsening
  const unsigned int max_elem_coarsen =
    static_cast<unsigned int>(_coarsen_fraction * n_active_elem) + 1;

  // The maximum number of elements to flag for refinement
  const unsigned int max_elem_refine  =
    static_cast<unsigned int>(_refine_fraction  * n_active_elem) + 1;

  // Clean up the refinement flags.  These could be left
  // over from previous refinement steps.
  this->clean_refinement_flags();

  // The target number of elements to add or remove
  const int n_elem_new = _nelem_target - n_active_elem;

  // Create an vector with active element errors and ids,
  // sorted by highest errors first
  const unsigned int max_elem_id = _mesh.max_elem_id();
  std::vector<std::pair<float, unsigned int> > sorted_error;

  sorted_error.reserve (n_active_elem);

  // On a ParallelMesh, we need to communicate to know which remote ids
  // correspond to active elements.
  {
    std::vector<bool> is_active(max_elem_id, false);

    MeshBase::element_iterator       elem_it  = _mesh.active_local_elements_begin();
    const MeshBase::element_iterator elem_end = _mesh.active_local_elements_end();
    for (; elem_it != elem_end; ++elem_it)
      {
        const unsigned int eid = (*elem_it)->id();
        is_active[eid] = true;
        libmesh_assert_less (eid, error_per_cell.size());
        sorted_error.push_back
          (std::make_pair(error_per_cell[eid], eid));
      }

    CommWorld.max(is_active);

    CommWorld.allgather(sorted_error);
  }

  // Default sort works since pairs are sorted lexicographically
  std::sort (sorted_error.begin(), sorted_error.end());
  std::reverse (sorted_error.begin(), sorted_error.end());

  // Create a sorted error vector with coarsenable parent elements
  // only, sorted by lowest errors first
  ErrorVector error_per_parent;
  std::vector<std::pair<float, unsigned int> > sorted_parent_error;
  Real parent_error_min, parent_error_max;

  create_parent_error_vector(error_per_cell,
                             error_per_parent,
                             parent_error_min,
                             parent_error_max);

  // create_parent_error_vector sets values for non-parents and
  // non-coarsenable parents to -1.  Get rid of them.
  for (unsigned int i=0; i != error_per_parent.size(); ++i)
    if (error_per_parent[i] != -1)
      sorted_parent_error.push_back(std::make_pair(error_per_parent[i], i));

  std::sort (sorted_parent_error.begin(), sorted_parent_error.end());

  // Keep track of how many elements we plan to coarsen & refine
  unsigned int coarsen_count = 0;
  unsigned int refine_count = 0;

  const unsigned int dim = _mesh.mesh_dimension();
  unsigned int twotodim = 1;
  for (unsigned int i=0; i!=dim; ++i)
    twotodim *= 2;

  // First, let's try to get our element count to target_nelem
  if (n_elem_new >= 0)
  {
    // Every element refinement creates at least
    // 2^dim-1 new elements
    refine_count =
      std::min(static_cast<unsigned int>(n_elem_new / (twotodim-1)),
	       max_elem_refine);
  }
  else
  {
    // Every successful element coarsening is likely to destroy
    // 2^dim-1 net elements.
    coarsen_count =
      std::min(static_cast<unsigned int>(-n_elem_new / (twotodim-1)),
	       max_elem_coarsen);
  }

  // Next, let's see if we can trade any refinement for coarsening
  while (coarsen_count < max_elem_coarsen &&
         refine_count < max_elem_refine &&
         coarsen_count < sorted_parent_error.size() &&
         refine_count < sorted_error.size() &&
         sorted_error[refine_count].first >
	 sorted_parent_error[coarsen_count].first * _coarsen_threshold)
  {
    coarsen_count++;
    refine_count++;
  }

  // On a ParallelMesh, we need to communicate to know which remote ids
  // correspond to refinable elements
  unsigned int successful_refine_count = 0;
  {
    std::vector<bool> is_refinable(max_elem_id, false);

    for (unsigned int i=0; i != sorted_error.size(); ++i)
      {
        unsigned int eid = sorted_error[i].second;
        Elem *elem = _mesh.query_elem(eid);
        if (elem && elem->level() < _max_h_level)
	  is_refinable[eid] = true;
      }
    CommWorld.max(is_refinable);

    if (refine_count > max_elem_refine)
      refine_count = max_elem_refine;
    for (unsigned int i=0; i != sorted_error.size(); ++i)
      {
        if (successful_refine_count >= refine_count)
          break;

        unsigned int eid = sorted_error[i].second;
        Elem *elem = _mesh.query_elem(eid);
        if (is_refinable[eid])
          {
            if (elem)
	      elem->set_refinement_flag(Elem::REFINE);
	    successful_refine_count++;
          }
      }
  }

  // If we couldn't refine enough elements, don't coarsen too many
  // either
  if (coarsen_count < (refine_count - successful_refine_count))
    coarsen_count = 0;
  else
    coarsen_count -= (refine_count - successful_refine_count);

  if (coarsen_count > max_elem_coarsen)
    coarsen_count = max_elem_coarsen;

  unsigned int successful_coarsen_count = 0;
  if (coarsen_count)
    {
      for (unsigned int i=0; i != sorted_parent_error.size(); ++i)
        {
          if (successful_coarsen_count >= coarsen_count * twotodim)
            break;

          unsigned int parent_id = sorted_parent_error[i].second;
          Elem *parent = _mesh.query_elem(parent_id);

          // On a ParallelMesh we skip remote elements
          if (!parent)
            continue;

          libmesh_assert(parent->has_children());
          for (unsigned int c=0; c != parent->n_children(); ++c)
            {
              Elem *elem = parent->child(c);
              if (elem && elem != remote_elem)
                {
                  libmesh_assert(elem->active());
                  elem->set_refinement_flag(Elem::COARSEN);
                  successful_coarsen_count++;
                }
            }
        }
    }

  // Return true if we've done all the AMR/C we can
  if (!successful_coarsen_count &&
      !successful_refine_count)
    return true;
  // And false if there may still be more to do.
  return false;
}