Exemplo n.º 1
0
void EigenSystem::attach_sensitivity_assemble_object (EigenproblemSensitivityAssembly& assemble)
{
  if (_eigenproblem_sensitivity_assemble_system_function != NULL)
  {
    libmesh_here();
    libMesh::out << "WARNING:  Cannot specify both assembly object and function!"
    << std::endl;
    
    _eigenproblem_sensitivity_assemble_system_function = NULL;
  }
  
  _eigenproblem_sensitivity_assemble_system_object = &assemble;
}
Exemplo n.º 2
0
void Patch::build_around_element (const Elem* e0,
                                  const unsigned int target_patch_size,
                                  PMF patchtype)
{

  // Make sure we are building a patch for an active element.
  libmesh_assert(e0);
  libmesh_assert (e0->active());
  // Make sure we are either starting with a local element or
  // requesting a nonlocal patch
  libmesh_assert ((patchtype != &Patch::add_local_face_neighbors &&
                   patchtype != &Patch::add_local_point_neighbors) ||
                  e0->processor_id() == _my_procid);

  // First clear the current set, then add the element of interest.
  this->clear();
  this->insert (e0);

  // Repeatedly add the neighbors of the elements in the patch until
  // the target patch size is met
  while (this->size() < target_patch_size)
    {
      // It is possible that the target patch size is larger than the number
      // of elements that can be added to the patch.  Since we don't
      // have access to the Mesh object here, the only way we can
      // detect this case is by detecting a "stagnant patch," i.e. a
      // patch whose size does not increase after adding face neighbors
      const std::size_t old_patch_size = this->size();

      // We profile the patch-extending functions separately
      (this->*patchtype)();

      // Check for a "stagnant" patch
      if (this->size() == old_patch_size)
        {
          libmesh_do_once(libMesh::err <<
                          "WARNING: stagnant patch of " << this->size() << " elements."
                          << std::endl <<
                          "Does the target patch size exceed the number of local elements?"
                          << std::endl;
                          libmesh_here(););
          break;
        }
Exemplo n.º 3
0
void EigenSystem::attach_sensitivity_assemble_function (bool fptr(EquationSystems& es,
                                                                  const std::string& name,
                                                                  const ParameterVector& parameters,
                                                                  const unsigned int i,
                                                                  SparseMatrix<Number>* sensitivity_A,
                                                                  SparseMatrix<Number>* sensitivity_B))
{
  libmesh_assert(fptr);
  
  if (_eigenproblem_sensitivity_assemble_system_object != NULL)
  {
    libmesh_here();
    libMesh::out << "WARNING:  Cannot specify both assembly sensitivity function and object!"
    << std::endl;
    
    _eigenproblem_sensitivity_assemble_system_object = NULL;
  }
  
  _eigenproblem_sensitivity_assemble_system_function = fptr;
}
Exemplo n.º 4
0
void FEInterface::inverse_map (const unsigned int dim,
                               const FEType& fe_t,
                               const Elem* elem,
                               const std::vector<Point>& physical_points,
                               std::vector<Point>&       reference_points,
                               const Real tolerance,
                               const bool secure)
{
  const std::size_t n_pts = physical_points.size();

  // Resize the vector
  reference_points.resize(n_pts);

  if (n_pts == 0)
    {
      libMesh::err << "WARNING: empty vector physical_points!"
                   << std::endl;
      libmesh_here();
      return;
    }

#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS

  if ( is_InfFE_elem(elem->type()) )
    {
      ifem_inverse_map(dim, fe_t, elem, physical_points, reference_points, tolerance, secure);
      return;

      //       libMesh::err << "ERROR: Not implemented!"
      // << std::endl;
      //       libmesh_error();
    }

#endif

  void_fe_with_vec_switch(inverse_map(elem, physical_points, reference_points, tolerance, secure));

  libmesh_error();
  return;
}
Exemplo n.º 5
0
// ------------------------------------------------------------
// SFCPartitioner implementation
void SFCPartitioner::_do_partition (MeshBase & mesh,
                                    const unsigned int n)
{

  libmesh_assert_greater (n, 0);

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

  // What to do if the sfcurves library IS NOT present
#ifndef LIBMESH_HAVE_SFCURVES

  libmesh_here();
  libMesh::err << "ERROR: The library has been built without"    << std::endl
               << "Space Filling Curve support.  Using a linear" << std::endl
               << "partitioner instead!" << std::endl;

  LinearPartitioner lp;

  lp.partition (mesh, n);

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

  LOG_SCOPE("sfc_partition()", "SFCPartitioner");

  const dof_id_type n_active_elem = mesh.n_active_elem();
  const dof_id_type n_elem        = mesh.n_elem();

  // the forward_map maps the active element id
  // into a contiguous block of indices
  std::vector<dof_id_type>
    forward_map (n_elem, DofObject::invalid_id);

  // the reverse_map maps the contiguous ids back
  // to active elements
  std::vector<Elem *> reverse_map (n_active_elem, libmesh_nullptr);

  int size = static_cast<int>(n_active_elem);
  std::vector<double> x      (size);
  std::vector<double> y      (size);
  std::vector<double> z      (size);
  std::vector<int>    table  (size);


  // We need to map the active element ids into a
  // contiguous range.
  {
    MeshBase::element_iterator       elem_it  = mesh.active_elements_begin();
    const MeshBase::element_iterator elem_end = mesh.active_elements_end();

    dof_id_type el_num = 0;

    for (; elem_it != elem_end; ++elem_it)
      {
        libmesh_assert_less ((*elem_it)->id(), forward_map.size());
        libmesh_assert_less (el_num, reverse_map.size());

        forward_map[(*elem_it)->id()] = el_num;
        reverse_map[el_num]           = *elem_it;
        el_num++;
      }
    libmesh_assert_equal_to (el_num, n_active_elem);
  }


  // Get the centroid for each active element
  {
    //     const_active_elem_iterator       elem_it (mesh.const_elements_begin());
    //     const const_active_elem_iterator elem_end(mesh.const_elements_end());

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

        libmesh_assert_less (elem->id(), forward_map.size());

        const Point p = elem->centroid();

        x[forward_map[elem->id()]] = p(0);
        y[forward_map[elem->id()]] = p(1);
        z[forward_map[elem->id()]] = p(2);
      }
  }

  // build the space-filling curve
  if (_sfc_type == "Hilbert")
    Sfc::hilbert (&x[0], &y[0], &z[0], &size, &table[0]);

  else if (_sfc_type == "Morton")
    Sfc::morton  (&x[0], &y[0], &z[0], &size, &table[0]);

  else
    {
      libmesh_here();
      libMesh::err << "ERROR: Unknown type: " << _sfc_type << std::endl
                   << " Valid types are"                   << std::endl
                   << "  \"Hilbert\""                      << std::endl
                   << "  \"Morton\""                       << std::endl
                   << " "                                  << std::endl
                   << "Proceeding with a Hilbert curve."   << std::endl;

      Sfc::hilbert (&x[0], &y[0], &z[0], &size, &table[0]);
    }


  // Assign the partitioning to the active elements
  {
    //      {
    //        std::ofstream out ("sfc.dat");
    //        out << "variables=x,y,z" << std::endl;
    //        out << "zone f=point" << std::endl;

    //        for (unsigned int i=0; i<n_active_elem; i++)
    //  out << x[i] << " "
    //      << y[i] << " "
    //      << z[i] << std::endl;
    //      }

    const dof_id_type blksize = (n_active_elem+n-1)/n;

    for (dof_id_type i=0; i<n_active_elem; i++)
      {
        libmesh_assert_less (static_cast<unsigned int>(table[i]-1), reverse_map.size());

        Elem * elem = reverse_map[table[i]-1];

        elem->processor_id() = cast_int<processor_id_type>
          (i/blksize);
      }
  }

#endif

}
Exemplo n.º 6
0
void ParmetisPartitioner::_do_repartition (MeshBase & mesh,
                                           const unsigned int n_sbdmns)
{
  libmesh_assert_greater (n_sbdmns, 0);

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

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

  // What to do if the Parmetis library IS NOT present
#ifndef LIBMESH_HAVE_PARMETIS

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

  MetisPartitioner mp;

  mp.partition (mesh, n_sbdmns);

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

  // Revert to METIS on one processor.
  if (mesh.n_processors() == 1)
    {
      MetisPartitioner mp;
      mp.partition (mesh, n_sbdmns);
      return;
    }

  LOG_SCOPE("repartition()", "ParmetisPartitioner");

  // Initialize the data structures required by ParMETIS
  this->initialize (mesh, n_sbdmns);

  // Make sure all processors have enough active local elements.
  // Parmetis tends to crash when it's given only a couple elements
  // per partition.
  {
    bool all_have_enough_elements = true;
    for (processor_id_type pid=0; pid<_n_active_elem_on_proc.size(); pid++)
      if (_n_active_elem_on_proc[pid] < MIN_ELEM_PER_PROC)
        all_have_enough_elements = false;

    // Parmetis will not work unless each processor has some
    // elements. Specifically, it will abort when passed a NULL
    // partition array on *any* of the processors.
    if (!all_have_enough_elements)
      {
        // FIXME: revert to METIS, although this requires a serial mesh
        MeshSerializer serialize(mesh);
        MetisPartitioner mp;
        mp.partition (mesh, n_sbdmns);
        return;
      }
  }

  // build the graph corresponding to the mesh
  this->build_graph (mesh);


  // Partition the graph
  std::vector<Parmetis::idx_t> vsize(_pmetis->vwgt.size(), 1);
  Parmetis::real_t itr = 1000000.0;
  MPI_Comm mpi_comm = mesh.comm().get();

  // Call the ParMETIS adaptive repartitioning method.  This respects the
  // original partitioning when computing the new partitioning so as to
  // minimize the required data redistribution.
  Parmetis::ParMETIS_V3_AdaptiveRepart(_pmetis->vtxdist.empty() ? libmesh_nullptr : &_pmetis->vtxdist[0],
                                       _pmetis->xadj.empty()    ? libmesh_nullptr : &_pmetis->xadj[0],
                                       _pmetis->adjncy.empty()  ? libmesh_nullptr : &_pmetis->adjncy[0],
                                       _pmetis->vwgt.empty()    ? libmesh_nullptr : &_pmetis->vwgt[0],
                                       vsize.empty()            ? libmesh_nullptr : &vsize[0],
                                       libmesh_nullptr,
                                       &_pmetis->wgtflag,
                                       &_pmetis->numflag,
                                       &_pmetis->ncon,
                                       &_pmetis->nparts,
                                       _pmetis->tpwgts.empty()  ? libmesh_nullptr : &_pmetis->tpwgts[0],
                                       _pmetis->ubvec.empty()   ? libmesh_nullptr : &_pmetis->ubvec[0],
                                       &itr,
                                       &_pmetis->options[0],
                                       &_pmetis->edgecut,
                                       _pmetis->part.empty()    ? libmesh_nullptr : &_pmetis->part[0],
                                       &mpi_comm);

  // Assign the returned processor ids
  this->assign_partitioning (mesh);

#endif // #ifndef LIBMESH_HAVE_PARMETIS ... else ...

}
Exemplo n.º 7
0
void MetisPartitioner::partition_range(MeshBase & mesh,
                                       MeshBase::element_iterator beg,
                                       MeshBase::element_iterator end,
                                       unsigned int n_pieces)
{
  libmesh_assert_greater (n_pieces, 0);

  // We don't yet support distributed meshes with this Partitioner
  if (!mesh.is_serial())
    libmesh_not_implemented();

  // Check for an easy return
  if (n_pieces == 1)
    {
      this->single_partition_range (beg, end);
      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_range (mesh, beg, end, n_pieces);

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

  LOG_SCOPE("partition_range()", "MetisPartitioner");

  const dof_id_type n_range_elem = std::distance(beg, end);

  // Metis will only consider the elements in the range.
  // We need to map the range 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_range_elem);

  {
    std::vector<dof_id_type> global_index;

    MeshCommunication().find_global_indices (mesh.comm(),
                                             MeshTools::create_bounding_box(mesh),
                                             beg, end, global_index);

    libmesh_assert_equal_to (global_index.size(), n_range_elem);

    MeshBase::element_iterator it = beg;
    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_range_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 std::unordered_multimap<const Elem *, const Elem *> map_type;
  map_type interior_to_boundary_map;

  {
    MeshBase::element_iterator it = beg;
    for (; it != end; ++it)
      {
        const 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 std::set<const Elem
            // *> returning 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
          }
      }
  }

  // Data structure that Metis will fill up on processor 0 and broadcast.
  std::vector<Metis::idx_t> part(n_range_elem);

  // Invoke METIS, but only on processor 0.
  // Then broadcast the resulting decomposition
  if (mesh.processor_id() == 0)
    {
      // Data structures and parameters needed only on processor 0 by Metis.
      // std::vector<Metis::idx_t> options(5);
      std::vector<Metis::idx_t> vwgt(n_range_elem);

      Metis::idx_t
        n = static_cast<Metis::idx_t>(n_range_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

      // build the graph
      METIS_CSR_Graph<Metis::idx_t> csr_graph;

      csr_graph.offsets.resize(n_range_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

#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
        MeshBase::element_iterator it = beg;
        for (; it != end; ++it)
          {
            const 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 (auto neighbor : elem->neighbor_ptr_range())
              {
                if (neighbor != libmesh_nullptr)
                  {
                    // If the neighbor is active, but is not in the
                    // range of elements being partitioned, treat it
                    // as a NULL neighbor.
                    if (neighbor->active() && !global_index_map.count(neighbor->id()))
                      continue;

                    // 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 (std::size_t nc=0; nc<neighbors_offspring.size(); nc++)
                          {
                            const Elem * child =
                              neighbors_offspring[nc];

                            // Skip neighbor offspring which are not in the range of elements being partitioned.
                            if (!global_index_map.count(child->id()))
                              continue;

                            // 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_ptr(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
        it = beg;

        for (; it != end; ++it)
          {
            const 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 (auto neighbor : elem->neighbor_ptr_range())
              {
                if (neighbor != libmesh_nullptr)
                  {
                    // If the neighbor is active, but is not in the
                    // range of elements being partitioned, treat it
                    // as a NULL neighbor.
                    if (neighbor->active() && !global_index_map.count(neighbor->id()))
                      continue;

                    // 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 (std::size_t nc=0; nc<neighbors_offspring.size(); nc++)
                          {
                            const Elem * child =
                              neighbors_offspring[nc];

                            // Skip neighbor offspring which are not in the range of elements being partitioned.
                            if (!global_index_map.count(child->id()))
                              continue;

                            // 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_ptr(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)
                  {
                    const Elem * neighbor = *n_it;

                    // Not all interior neighbors are necessarily in
                    // the same Mesh (hence not in the global_index_map).
                    // This will be the case when partitioning a
                    // BoundaryMesh, whose elements all have
                    // interior_parents() that belong to some other
                    // Mesh.
                    const Elem * queried_elem = mesh.query_elem_ptr(neighbor->id());

                    // Compare the neighbor and the queried_elem
                    // pointers, make sure they are the same.
                    if (queried_elem && queried_elem == neighbor)
                      {
                        vectormap<dof_id_type, dof_id_type>::iterator global_index_map_it =
                          global_index_map.find(neighbor->id());

                        // If the interior_neighbor is in the Mesh but
                        // not in the global_index_map, we have other issues.
                        if (global_index_map_it == global_index_map.end())
                          libmesh_error_msg("Interior neighbor with id " << neighbor->id() << " not found in global_index_map.");

                        else
                          csr_graph(elem_global_index, connection++) = global_index_map_it->second;
                      }
                  }
              }

            // Check for any boundary neighbors
            for (const auto & pr : as_range(interior_to_boundary_map.equal_range(elem)))
              {
                const Elem * neighbor = pr.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

  // Broadcast the resulting 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 = beg;
    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
}
Exemplo n.º 8
0
void ErrorVector::plot_error(const std::string& filename,
                             const MeshBase& oldmesh) const
{
  AutoPtr<MeshBase> meshptr = oldmesh.clone();
  MeshBase &mesh = *meshptr;
  mesh.all_first_order();
  EquationSystems temp_es (mesh);
  ExplicitSystem& error_system
    = temp_es.add_system<ExplicitSystem> ("Error");
  error_system.add_variable("error", CONSTANT, MONOMIAL);
  temp_es.init();

  const DofMap& error_dof_map = error_system.get_dof_map();

  MeshBase::const_element_iterator       el     =
    mesh.active_local_elements_begin();
  const MeshBase::const_element_iterator end_el =
    mesh.active_local_elements_end();
  std::vector<unsigned int> dof_indices;

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

    error_dof_map.dof_indices(elem, dof_indices);

    const unsigned int elem_id = elem->id();

    //0 for the monomial basis
    const unsigned int solution_index = dof_indices[0];

    // libMesh::out << "elem_number=" << elem_number << std::endl;
    libmesh_assert_less (elem_id, (*this).size());

    // We may have zero error values in special circumstances
    // libmesh_assert_greater ((*this)[elem_id], 0.);
    error_system.solution->set(solution_index, (*this)[elem_id]);
  }

  // We may have to renumber if the original numbering was not
  // contiguous.  Since this is just a temporary mesh, that's probably
  // fine.
  if (mesh.max_elem_id() != mesh.n_elem() ||
      mesh.max_node_id() != mesh.n_nodes())
    {
      mesh.allow_renumbering(true);
      mesh.renumber_nodes_and_elements();
    }

  if (filename.rfind(".gmv") < filename.size())
    {
      GMVIO(mesh).write_discontinuous_gmv(filename,
                                          temp_es, false);
    }
  else if (filename.rfind(".plt") < filename.size())
    {
      TecplotIO (mesh).write_equation_systems
        (filename, temp_es);
    }
#ifdef LIBMESH_HAVE_EXODUS_API
  else if( (filename.rfind(".exo") < filename.size()) ||
	   (filename.rfind(".e") < filename.size()) )
    {
      ExodusII_IO io(mesh);
      io.write(filename);
      io.write_element_data(temp_es);
    }
#endif
  else
    {
      libmesh_here();
      libMesh::err << "Warning: ErrorVector::plot_error currently only"
                    << " supports .gmv and .plt and .exo/.e (if enabled) output;" << std::endl;
      libMesh::err << "Could not recognize filename: " << filename
                    << std::endl;
    }
}
Exemplo n.º 9
0
void DivaIO::write_stream (std::ostream & out_file)
{
  /*
    From Kelly: ([email protected])

    Ok, the following is the format:

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

  */

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

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

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



  BoundaryMesh boundary_mesh
    (the_mesh.comm(),
     cast_int<unsigned char>(the_mesh.mesh_dimension()-1));
  the_mesh.get_boundary_info().sync(boundary_mesh);


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

  boundary_mesh.clear();


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


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

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

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

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

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


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

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

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

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

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



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

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

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


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

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

                out_file << the_mesh.get_boundary_info().boundary_id(the_mesh.elem(e), s);
            }
  }



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

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

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

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

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

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

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

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


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



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


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

              out_file << conn[0] << ' '
                       << conn[1] << ' '
                       << conn[2] << ' '
                       << conn[3] << ' '
                       << conn[4] << ' '
                       << conn[5] << ' '
                       << conn[6] << ' '
                       << conn[7] << '\n';
            }
        }
}
Exemplo n.º 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

  START_LOG("partition()", "MetisPartitioner");

  const dof_id_type n_active_elem = mesh.n_active_elem();

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

  int
    n = static_cast<int>(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<int>(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
  // independednt of the element ordering, otherwise a circular dependency
  // can result in which the partitioning depends on the ordering which
  // depends on the partitioning...
  std::map<const Elem*, dof_id_type> global_index_map;
  {
    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 (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;
	libmesh_assert (!global_index_map.count(elem));

	global_index_map[elem]  = global_index[cnt++];
      }
    libmesh_assert_equal_to (global_index_map.size(), n_active_elem);
  }


  // build the graph in CSR format.  Note that
  // the edges in the graph will correspond to
  // face neighbors
  std::vector<int> xadj, adjncy;
  {
    std::vector<const Elem*> neighbors_offspring;

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

    // This will be exact when there is no refinement and all the
    // elements are of the same type.
    std::size_t graph_size=0;
    std::vector<std::vector<dof_id_type> > graph(n_active_elem);

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

	libmesh_assert (global_index_map.count(elem));

	const dof_id_type elem_global_index =
	  global_index_map[elem];

	libmesh_assert_less (elem_global_index, vwgt.size());
	libmesh_assert_less (elem_global_index, graph.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<int>((*_weights)[elem->id()]);

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

	    if (neighbor != NULL)
	      {
		// If the neighbor is active treat it
		// as a connection
		if (neighbor->active())
		  {
		    libmesh_assert (global_index_map.count(neighbor));

		    const dof_id_type neighbor_global_index =
		      global_index_map[neighbor];

		    graph[elem_global_index].push_back(neighbor_global_index);
		    graph_size++;
		  }

#ifdef LIBMESH_ENABLE_AMR

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

		    // Get all the active children (& grandchildren, etc...)
		    // of the neighbor.
		    neighbor->active_family_tree (neighbors_offspring);

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

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

			    const dof_id_type child_global_index =
			      global_index_map[child];

			    graph[elem_global_index].push_back(child_global_index);
			    graph_size++;
			  }
		      }
		  }

#endif /* ifdef LIBMESH_ENABLE_AMR */

	      }
	  }
      }

    // Convert the graph into the format Metis wants
    xadj.reserve(n_active_elem+1);
    adjncy.reserve(graph_size);

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

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

    libmesh_assert_equal_to (adjncy.size(), graph_size);
    libmesh_assert_equal_to (xadj.size(), n_active_elem+1);
  } // done building the graph


  if (adjncy.empty())
    adjncy.push_back(0);

  int 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, &xadj[0], &adjncy[0], &vwgt[0], NULL,
				    NULL, &nparts, NULL, NULL, NULL,
				    &edgecut, &part[0]);

  // Otherwise  use kway
  else
    Metis::METIS_PartGraphKway(&n, &ncon, &xadj[0], &adjncy[0], &vwgt[0], NULL,
			       NULL, &nparts, NULL, NULL, NULL,
			       &edgecut, &part[0]);


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

	const dof_id_type elem_global_index =
	  global_index_map[elem];

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

  STOP_LOG("partition()", "MetisPartitioner");
#endif
}
Exemplo n.º 11
0
Point FE<Dim,T>::inverse_map (const Elem* elem,
			      const Point& physical_point,
			      const Real tolerance,
			      const bool secure)
{
  libmesh_assert(elem);
  libmesh_assert_greater_equal (tolerance, 0.);


  // Start logging the map inversion.
  START_LOG("inverse_map()", "FE");

  // How much did the point on the reference
  // element change by in this Newton step?
  Real inverse_map_error = 0.;

  //  The point on the reference element.  This is
  //  the "initial guess" for Newton's method.  The
  //  centroid seems like a good idea, but computing
  //  it is a little more intensive than, say taking
  //  the zero point.
  //
  //  Convergence should be insensitive of this choice
  //  for "good" elements.
  Point p; // the zero point.  No computation required

  //  The number of iterations in the map inversion process.
  unsigned int cnt = 0;

  //  The number of iterations after which we give up and declare
  //  divergence
  const unsigned int max_cnt = 10;

  //  The distance (in master element space) beyond which we give up
  //  and declare divergence.  This is no longer used...
  // Real max_step_length = 4.;



  //  Newton iteration loop.
  do
    {
      //  Where our current iterate \p p maps to.
      const Point physical_guess = FE<Dim,T>::map (elem, p);

      //  How far our current iterate is from the actual point.
      const Point delta = physical_point - physical_guess;

      //  Increment in current iterate \p p, will be computed.
      Point dp;


      //  The form of the map and how we invert it depends
      //  on the dimension that we are in.
      switch (Dim)
	{
	  // ------------------------------------------------------------------
	  //  0D map inversion is trivial
        case 0:
          {
            break;
          }

	  // ------------------------------------------------------------------
	  //  1D map inversion
	  //
	  //  Here we find the point on a 1D reference element that maps to
	  //  the point \p physical_point in the domain.  This is a bit tricky
	  //  since we do not want to assume that the point \p physical_point
	  //  is also in a 1D domain.  In particular, this method might get
	  //  called on the edge of a 3D element, in which case
	  //  \p physical_point actually lives in 3D.
	case 1:
	  {
	    const Point dxi = FE<Dim,T>::map_xi (elem, p);

	    //  Newton's method in this case looks like
	    //
	    //  {X} - {X_n} = [J]*dp
	    //
	    //  Where {X}, {X_n} are 3x1 vectors, [J] is a 3x1 matrix
	    //  d(x,y,z)/dxi, and we seek dp, a scalar.  Since the above
	    //  system is either overdetermined or rank-deficient, we will
	    //  solve the normal equations for this system
	    //
	    //  [J]^T ({X} - {X_n}) = [J]^T [J] {dp}
	    //
	    //  which involves the trivial inversion of the scalar
	    //  G = [J]^T [J]
	    const Real G = dxi*dxi;

	    if (secure)
	      libmesh_assert_greater (G, 0.);

	    const Real Ginv = 1./G;

	    const Real  dxidelta = dxi*delta;

	    dp(0) = Ginv*dxidelta;

            // No master elements have radius > 4, but sometimes we
            // can take a step that big while still converging
	    // if (secure)
	      // libmesh_assert_less (dp.size(), max_step_length);

	    break;
	  }



	  // ------------------------------------------------------------------
	  //  2D map inversion
	  //
	  //  Here we find the point on a 2D reference element that maps to
	  //  the point \p physical_point in the domain.  This is a bit tricky
	  //  since we do not want to assume that the point \p physical_point
	  //  is also in a 2D domain.  In particular, this method might get
	  //  called on the face of a 3D element, in which case
	  //  \p physical_point actually lives in 3D.
	case 2:
	  {
	    const Point dxi  = FE<Dim,T>::map_xi  (elem, p);
	    const Point deta = FE<Dim,T>::map_eta (elem, p);

	    //  Newton's method in this case looks like
	    //
	    //  {X} - {X_n} = [J]*{dp}
	    //
	    //  Where {X}, {X_n} are 3x1 vectors, [J] is a 3x2 matrix
	    //  d(x,y,z)/d(xi,eta), and we seek {dp}, a 2x1 vector.  Since
	    //  the above system is either overdermined or rank-deficient,
	    //  we will solve the normal equations for this system
	    //
	    //  [J]^T ({X} - {X_n}) = [J]^T [J] {dp}
	    //
	    //  which involves the inversion of the 2x2 matrix
	    //  [G] = [J]^T [J]
	    const Real
	      G11 = dxi*dxi,  G12 = dxi*deta,
	      G21 = dxi*deta, G22 = deta*deta;


	    const Real det = (G11*G22 - G12*G21);

	    if (secure)
	      libmesh_assert_not_equal_to (det, 0.);

	    const Real inv_det = 1./det;

	    const Real
	      Ginv11 =  G22*inv_det,
	      Ginv12 = -G12*inv_det,

	      Ginv21 = -G21*inv_det,
	      Ginv22 =  G11*inv_det;


	    const Real  dxidelta  = dxi*delta;
	    const Real  detadelta = deta*delta;

	    dp(0) = (Ginv11*dxidelta + Ginv12*detadelta);
	    dp(1) = (Ginv21*dxidelta + Ginv22*detadelta);

            // No master elements have radius > 4, but sometimes we
            // can take a step that big while still converging
	    // if (secure)
	      // libmesh_assert_less (dp.size(), max_step_length);

	    break;
	  }



	  // ------------------------------------------------------------------
	  //  3D map inversion
	  //
	  //  Here we find the point in a 3D reference element that maps to
	  //  the point \p physical_point in a 3D domain. Nothing special
	  //  has to happen here, since (unless the map is singular because
	  //  you have a BAD element) the map will be invertable and we can
	  //  apply Newton's method directly.
	case 3:
	  {
       	    const Point dxi   = FE<Dim,T>::map_xi   (elem, p);
	    const Point deta  = FE<Dim,T>::map_eta  (elem, p);
	    const Point dzeta = FE<Dim,T>::map_zeta (elem, p);

	    //  Newton's method in this case looks like
	    //
	    //  {X} = {X_n} + [J]*{dp}
	    //
	    //  Where {X}, {X_n} are 3x1 vectors, [J] is a 3x3 matrix
	    //  d(x,y,z)/d(xi,eta,zeta), and we seek {dp}, a 3x1 vector.
	    //  Since the above system is nonsingular for invertable maps
	    //  we will solve
	    //
	    //  {dp} = [J]^-1 ({X} - {X_n})
	    //
	    //  which involves the inversion of the 3x3 matrix [J]
	    const Real
	      J11 = dxi(0), J12 = deta(0), J13 = dzeta(0),
	      J21 = dxi(1), J22 = deta(1), J23 = dzeta(1),
	      J31 = dxi(2), J32 = deta(2), J33 = dzeta(2);

	    const Real det = (J11*(J22*J33 - J23*J32) +
			      J12*(J23*J31 - J21*J33) +
			      J13*(J21*J32 - J22*J31));

	    if (secure)
	      libmesh_assert_not_equal_to (det, 0.);

	    const Real inv_det = 1./det;

	    const Real
	      Jinv11 =  (J22*J33 - J23*J32)*inv_det,
	      Jinv12 = -(J12*J33 - J13*J32)*inv_det,
	      Jinv13 =  (J12*J23 - J13*J22)*inv_det,

	      Jinv21 = -(J21*J33 - J23*J31)*inv_det,
	      Jinv22 =  (J11*J33 - J13*J31)*inv_det,
	      Jinv23 = -(J11*J23 - J13*J21)*inv_det,

	      Jinv31 =  (J21*J32 - J22*J31)*inv_det,
	      Jinv32 = -(J11*J32 - J12*J31)*inv_det,
	      Jinv33 =  (J11*J22 - J12*J21)*inv_det;

	    dp(0) = (Jinv11*delta(0) +
		     Jinv12*delta(1) +
		     Jinv13*delta(2));

	    dp(1) = (Jinv21*delta(0) +
		     Jinv22*delta(1) +
		     Jinv23*delta(2));

	    dp(2) = (Jinv31*delta(0) +
		     Jinv32*delta(1) +
		     Jinv33*delta(2));

            // No master elements have radius > 4, but sometimes we
            // can take a step that big while still converging
	    // if (secure)
	      // libmesh_assert_less (dp.size(), max_step_length);

	    break;
	  }


	  //  Some other dimension?
	default:
	  libmesh_error();
	} // end switch(Dim), dp now computed



      //  ||P_n+1 - P_n||
      inverse_map_error = dp.size();

      //  P_n+1 = P_n + dp
      p.add (dp);

      //  Increment the iteration count.
      cnt++;

      //  Watch for divergence of Newton's
      //  method.  Here's how it goes:
      //  (1) For good elements, we expect convergence in 10
      //      iterations, with no too-large steps.
      //      - If called with (secure == true) and we have not yet converged
      //        print out a warning message.
      //      - If called with (secure == true) and we have not converged in
      //        20 iterations abort
      //  (2) This method may be called in cases when the target point is not
      //      inside the element and we have no business expecting convergence.
      //      For these cases if we have not converged in 10 iterations forget
      //      about it.
      if (cnt > max_cnt)
	{
	  //  Warn about divergence when secure is true - this
	  //  shouldn't happen
	  if (secure)
	    {
	      // Print every time in devel/dbg modes
#ifndef NDEBUG
	      libmesh_here();
	      libMesh::err << "WARNING: Newton scheme has not converged in "
			    << cnt << " iterations:" << std::endl
			    << "   physical_point="
			    << physical_point
			    << "   physical_guess="
			    << physical_guess
			    << "   dp="
			    << dp
			    << "   p="
			    << p
			    << "   error=" << inverse_map_error
                            << "   in element " << elem->id()
			    << std::endl;

              elem->print_info(libMesh::err);
#else
	      // In optimized mode, just print once that an inverse_map() call
	      // had trouble converging its Newton iteration.
	      libmesh_do_once(libMesh::err << "WARNING: At least one element took more than "
			      << max_cnt
			      << " iterations to converge in inverse_map()...\n"
			      << "Rerun in devel/dbg mode for more details."
			      << std::endl;);

#endif // NDEBUG

	      if (cnt > 2*max_cnt)
		{
		  libMesh::err << "ERROR: Newton scheme FAILED to converge in "
			        << cnt
			        << " iterations!"
                                << " in element " << elem->id()
			        << std::endl;

                  elem->print_info(libMesh::err);

		  libmesh_error();
		}
	    }
	  //  Return a far off point when secure is false - this
	  //  should only happen when we're trying to map a point
	  //  that's outside the element
	  else
	    {
	      for (unsigned int i=0; i != Dim; ++i)
		p(i) = 1e6;

	      STOP_LOG("inverse_map()", "FE");
	      return p;
	    }
	}
Exemplo n.º 12
0
void ErrorVector::plot_error(const std::string & filename,
                             const MeshBase & oldmesh) const
{
  std::unique_ptr<MeshBase> meshptr = oldmesh.clone();
  MeshBase & mesh = *meshptr;

  // The all_first_order routine will prepare_for_use(), which would
  // break our ordering if elements get changed.
  mesh.allow_renumbering(false);
  mesh.all_first_order();

#ifdef LIBMESH_ENABLE_AMR
  // We don't want p elevation when plotting a single constant value
  // per element
  for (auto & elem : mesh.element_ptr_range())
    {
      elem->set_p_refinement_flag(Elem::DO_NOTHING);
      elem->set_p_level(0);
    }
#endif // LIBMESH_ENABLE_AMR

  EquationSystems temp_es (mesh);
  ExplicitSystem & error_system
    = temp_es.add_system<ExplicitSystem> ("Error");
  error_system.add_variable("error", CONSTANT, MONOMIAL);
  temp_es.init();

  const DofMap & error_dof_map = error_system.get_dof_map();
  std::vector<dof_id_type> dof_indices;

  for (const auto & elem : mesh.active_local_element_ptr_range())
    {
      error_dof_map.dof_indices(elem, dof_indices);

      const dof_id_type elem_id = elem->id();

      //0 for the monomial basis
      const dof_id_type solution_index = dof_indices[0];

      // libMesh::out << "elem_number=" << elem_number << std::endl;
      libmesh_assert_less (elem_id, (*this).size());

      // We may have zero error values in special circumstances
      // libmesh_assert_greater ((*this)[elem_id], 0.);
      error_system.solution->set(solution_index, (*this)[elem_id]);
    }

  error_system.solution->close();

  // We may have to renumber if the original numbering was not
  // contiguous.  Since this is just a temporary mesh, that's probably
  // fine.
  if (mesh.max_elem_id() != mesh.n_elem() ||
      mesh.max_node_id() != mesh.n_nodes())
    {
      mesh.allow_renumbering(true);
      mesh.renumber_nodes_and_elements();
    }

  if (filename.rfind(".gmv") < filename.size())
    {
      GMVIO(mesh).write_discontinuous_gmv(filename,
                                          temp_es, false);
    }
  else if (filename.rfind(".plt") < filename.size())
    {
      TecplotIO (mesh).write_equation_systems
        (filename, temp_es);
    }
#ifdef LIBMESH_HAVE_EXODUS_API
  else if ((filename.rfind(".exo") < filename.size()) ||
           (filename.rfind(".e") < filename.size()))
    {
      ExodusII_IO io(mesh);
      io.write(filename);
      io.write_element_data(temp_es);
    }
#endif
  else if (filename.rfind(".xda") < filename.size())
    {
      XdrIO(mesh).write("mesh-"+filename);
      temp_es.write("soln-"+filename,WRITE,
                    EquationSystems::WRITE_DATA |
                    EquationSystems::WRITE_ADDITIONAL_DATA);
    }
  else if (filename.rfind(".xdr") < filename.size())
    {
      XdrIO(mesh,true).write("mesh-"+filename);
      temp_es.write("soln-"+filename,ENCODE,
                    EquationSystems::WRITE_DATA |
                    EquationSystems::WRITE_ADDITIONAL_DATA);
    }
  else
    {
      libmesh_here();
      libMesh::err << "Warning: ErrorVector::plot_error currently only"
                   << " supports .gmv, .plt, .xdr/.xda, and .exo/.e (if enabled) output;" << std::endl;
      libMesh::err << "Could not recognize filename: " << filename
                   << std::endl;
    }
}