LCOV - code coverage report
Current view: top level - src/partitioning - sfc_partitioner.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 49 59 83.1 %
Date: 2025-08-19 19:27:09 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : 
      19             : 
      20             : // Local Includes
      21             : #include "libmesh/libmesh_config.h"
      22             : #include "libmesh/elem.h"
      23             : #include "libmesh/enum_partitioner_type.h"
      24             : #include "libmesh/libmesh_logging.h"
      25             : #include "libmesh/mesh_base.h"
      26             : #include "libmesh/sfc_partitioner.h"
      27             : 
      28             : #ifdef LIBMESH_HAVE_SFCURVES
      29             : namespace Sfc {
      30             : extern "C" {
      31             : #     include "sfcurves.h"
      32             : }
      33             : }
      34             : #else
      35             : #  include "libmesh/linear_partitioner.h"
      36             : #endif
      37             : 
      38             : namespace libMesh
      39             : {
      40             : 
      41             : 
      42         142 : PartitionerType SFCPartitioner::type() const
      43             : {
      44         142 :   return SFC_PARTITIONER;
      45             : }
      46             : 
      47             : 
      48         813 : void SFCPartitioner::partition_range(MeshBase & mesh,
      49             :                                      MeshBase::element_iterator beg,
      50             :                                      MeshBase::element_iterator end,
      51             :                                      unsigned int n)
      52             : {
      53             :   // Check for easy returns
      54         813 :   if (beg == end)
      55         213 :     return;
      56             : 
      57         600 :   if (n == 1)
      58             :     {
      59           0 :       this->single_partition_range (beg, end);
      60           0 :       return;
      61             :     }
      62             : 
      63         102 :   libmesh_assert_greater (n, 0);
      64             : 
      65             :   // What to do if the sfcurves library IS NOT present
      66             : #ifndef LIBMESH_HAVE_SFCURVES
      67             : 
      68         396 :   libmesh_do_once(
      69             :     libMesh::out << "ERROR: The library has been built without"    << std::endl
      70             :                  << "Space Filling Curve support.  Using a linear" << std::endl
      71             :                  << "partitioner instead!" << std::endl;);
      72             : 
      73             :   LinearPartitioner lp;
      74         792 :   lp.partition_range (mesh, beg, end, n);
      75             : 
      76             :   // What to do if the sfcurves library IS present
      77             : #else
      78             : 
      79         204 :   LOG_SCOPE("partition_range()", "SFCPartitioner");
      80             : 
      81             :   // We don't yet support distributed meshes with this Partitioner
      82         204 :   if (!mesh.is_serial())
      83           0 :     libmesh_not_implemented();
      84             : 
      85         204 :   const dof_id_type n_range_elem = std::distance(beg, end);
      86         204 :   const dof_id_type max_elem_id = mesh.max_elem_id();
      87             : 
      88             :   // The forward_map maps the range's element ids into a contiguous
      89             :   // block of indices.
      90         306 :   std::vector<dof_id_type> forward_map (max_elem_id, DofObject::invalid_id);
      91             : 
      92             :   // the reverse_map maps the contiguous ids back
      93             :   // to active elements
      94         306 :   std::vector<Elem *> reverse_map (n_range_elem, nullptr);
      95             : 
      96         306 :   std::vector<double> x      (n_range_elem);
      97         306 :   std::vector<double> y      (n_range_elem);
      98         306 :   std::vector<double> z      (n_range_elem);
      99         306 :   std::vector<int>    table  (n_range_elem);
     100             : 
     101             :   // Map the range's element ids into a contiguous range.
     102         102 :   dof_id_type el_num = 0;
     103             : 
     104       11070 :   for (auto & elem : as_range(beg, end))
     105             :     {
     106        5382 :       libmesh_assert_less (elem->id(), forward_map.size());
     107        5382 :       libmesh_assert_less (el_num, reverse_map.size());
     108             : 
     109       10764 :       forward_map[elem->id()] = el_num;
     110       10764 :       reverse_map[el_num] = elem;
     111       10764 :       el_num++;
     112             :     }
     113         102 :   libmesh_assert_equal_to (el_num, n_range_elem);
     114             : 
     115             :   // Get the vertex average for each range element.
     116       11070 :   for (const auto & elem : as_range(beg, end))
     117             :     {
     118        5382 :       libmesh_assert_less (elem->id(), forward_map.size());
     119             : 
     120       10764 :       const Point p = elem->vertex_average();
     121             : 
     122       16146 :       x[forward_map[elem->id()]] = double(p(0));
     123       10764 :       y[forward_map[elem->id()]] = double(p(1));
     124       16146 :       z[forward_map[elem->id()]] = double(p(2));
     125             :     }
     126             : 
     127             :   // We need an integer reference to pass to the Sfc interface.
     128         204 :   int size = static_cast<int>(n_range_elem);
     129             : 
     130             :   // build the space-filling curve
     131         204 :   if (_sfc_type == "Hilbert")
     132         136 :     Sfc::hilbert (x.data(),
     133             :                   y.data(),
     134             :                   z.data(),
     135             :                   &size,
     136             :                   table.data());
     137             : 
     138          68 :   else if (_sfc_type == "Morton")
     139          68 :     Sfc::morton  (x.data(),
     140             :                   y.data(),
     141             :                   z.data(),
     142             :                   &size,
     143             :                   table.data());
     144             : 
     145             :   else
     146             :     {
     147           0 :       libMesh::out << "ERROR: Unknown type: " << _sfc_type << std::endl
     148           0 :                    << " Valid types are"                   << std::endl
     149           0 :                    << "  \"Hilbert\""                      << std::endl
     150           0 :                    << "  \"Morton\""                       << std::endl
     151           0 :                    << " "                                  << std::endl
     152           0 :                    << "Partitioning with a Hilbert curve." << std::endl;
     153             : 
     154           0 :       Sfc::hilbert (x.data(),
     155             :                     y.data(),
     156             :                     z.data(),
     157             :                     &size,
     158             :                     table.data());
     159             :     }
     160             : 
     161             : 
     162             :   // Assign the partitioning to the range elements
     163             :   {
     164             :     // {
     165             :     //   std::ofstream out ("sfc.dat");
     166             :     //   out << "variables=x,y,z" << std::endl;
     167             :     //   out << "zone f=point" << std::endl;
     168             :     //   for (unsigned int i=0; i<n_range_elem; i++)
     169             :     //     out << x[i] << " " << y[i] << " " << z[i] << std::endl;
     170             :     // }
     171             : 
     172         204 :     const dof_id_type blksize = (n_range_elem + n - 1) / n;
     173             : 
     174       10968 :     for (dof_id_type i=0; i<n_range_elem; i++)
     175             :       {
     176        5382 :         libmesh_assert_less (table[i] - 1, reverse_map.size());
     177             : 
     178       16146 :         Elem * elem = reverse_map[table[i] - 1];
     179             : 
     180       10764 :         elem->processor_id() = cast_int<processor_id_type>(i/blksize);
     181             :       }
     182             :   }
     183             : 
     184             : #endif
     185             : }
     186             : 
     187             : 
     188             : 
     189         813 : void SFCPartitioner::_do_partition (MeshBase & mesh,
     190             :                                     const unsigned int n)
     191             : {
     192         813 :   this->partition_range(mesh,
     193        1626 :                         mesh.active_elements_begin(),
     194         921 :                         mesh.active_elements_end(),
     195         216 :                         n);
     196         813 : }
     197             : 
     198             : } // namespace libMesh

Generated by: LCOV version 1.14