libMesh/libmesh: coverage diff

Base 8c3130 Head #4557 f07a27
Total Total +/- New
Rate 66.47% 66.49% +0.02% 100.00%
Hits 80271 80330 +59 86
Misses 40494 40491 -3 0
Filename Stmts Miss Cover
include/mesh/exodusII_io_helper.h 0 +2 -5.26%
src/mesh/distributed_mesh.C 0 -3 +0.37%
src/mesh/exodusII_io_helper.C +56 +1 +0.20%
src/mesh/mesh_base.C 0 -1 +0.07%
src/mesh/mesh_triangle_holes.C 0 +1 -0.28%
src/mesh/replicated_mesh.C 0 -1 +0.22%
src/parallel/parallel_elem.C 0 -2 +0.49%
TOTAL +56 -3 +0.02%
code
coverage unchanged
code
coverage increased
code
coverage decreased
+
line added or modified

include/mesh/exodusII_io_helper.h

1359  
1360  
1361  
1362  
1363  
1364  
1365  
1366  
1367  
1368  
};


inline void ExodusII_IO_Helper::set_add_sides(bool add_sides)
{
  _add_sides = add_sides;
}


inline bool ExodusII_IO_Helper::get_add_sides()

src/mesh/distributed_mesh.C

853  
854  
855  
856  
857  
858  
859  
860  
861  
862  

  if (old_n)
    {
      *old_n = p;
      old_n->processor_id() = proc_id;

      return old_n;
    }

  Node * n = Node::build(p, id).release();

src/mesh/exodusII_io_helper.C

208  
209  
210  
211 +
212 +
213 +
214  
215  
216  
217 +
218  
219 +
220 +
221 +
222  
223 +
224 +
225 +
226  
227  
228  
  {
    // Without a reduction across ranks, the subdomain map is only
    // complete if the whole mesh is available here.
    libmesh_assert(reduce || mesh.is_serial_on_zero());
    if (reduce)
      libmesh_parallel_only(mesh.comm());

    // When reducing, each rank only contributes its local elements, so
    // that no element is counted twice on a replicated mesh.
    auto for_each_elem = [&mesh, reduce](auto && f)
      {
        if (reduce)
          for (const auto & elem : mesh.active_local_element_ptr_range())
            f(*elem);
        else
          for (const auto & elem : mesh.active_element_ptr_range())
            f(*elem);
      };

    // Exodus requires every element block to contain a single element
    // type.  Group elements first by subdomain id and then by element
230  
231  
232  
233 +
234  
235  
236  
237  
238 +
239  
240 +
241 +
242 +
243 +
244  
245 +
246 +
247 +
248 +
249 +
250  
251  
252  
253  
254 +
255 +
256 +
257  
258 +
259 +
260 +
261  
262  
263  
264 +
265  
266 +
267 +
268  
269 +
270 +
271  
272  
273  
274  
275 +
276  
277 +
278 +
279 +
280  
281  
282  
    // (for example a mix of C0POLYHEDRON and HEX8 cells) is split across
    // multiple blocks rather than written as a single, invalid block.
    std::map<subdomain_id_type,
             std::map<ElemType, std::vector<unsigned int>>> elems_by_subdomain_type;

    // We skip writing infinite elements to the Exodus file, so don't
    // put them in the map. That way the number of blocks should be
    // correct.
    if (reduce)
      {
        std::vector<dof_id_type> elem_ids;
        std::vector<subdomain_id_type> elem_sbd_ids;
        std::vector<int> elem_types;
        for_each_elem([&](const Elem & elem)
          {
            if (elem.infinite())
              return;
            elem_ids.push_back(elem.id());
            elem_sbd_ids.push_back(elem.subdomain_id());
            elem_types.push_back(elem.type());
          });

        // Every rank contributes the same number of entries to each
        // vector, so the gathered vectors stay aligned.
        mesh.comm().allgather(elem_ids);
        mesh.comm().allgather(elem_sbd_ids);
        mesh.comm().allgather(elem_types);

        for (auto i : index_range(elem_ids))
          elems_by_subdomain_type[elem_sbd_ids[i]][static_cast<ElemType>(elem_types[i])]
            .push_back(cast_int<unsigned int>(elem_ids[i]));

        // Gathered ids arrive grouped by rank; sort them to match the
        // id ordering of a serial traversal.
        for (auto & [sbd_id, type_map] : elems_by_subdomain_type)
          {
            libmesh_ignore(sbd_id);
            for (auto & [elem_t, ids] : type_map)
              {
                libmesh_ignore(elem_t);
                std::sort(ids.begin(), ids.end());
              }
          }
      }
    else
      for_each_elem([&](const Elem & elem)
        {
          if (elem.infinite())
            return;
          elems_by_subdomain_type[elem.subdomain_id()][elem.type()].push_back(elem.id());
        });

    // Assign a block id to each (subdomain, element type) group.  The
286  
287  
288  
289 +
290 +
291  
292 +
293  
294 +
295 +
296  
297 +
298  
299 +
300  
301 +
302 +
303  
304  
305  
306  
307  
308 +
309 +
310  
311  
312  
    // subdomain get synthesized block ids allocated above all existing
    // subdomain ids.
    std::map<subdomain_id_type, std::vector<unsigned int>> subdomain_map;
    subdomain_id_type next_synth_block_id = elems_by_subdomain_type.empty() ?
      0 : elems_by_subdomain_type.rbegin()->first + 1;

    for (auto & [sbd_id, type_map] : elems_by_subdomain_type)
      {
        bool first_type = true;
        for (auto & [elem_t, elem_ids] : type_map)
          {
            libmesh_ignore(elem_t);
            const subdomain_id_type block_id =
              first_type ? sbd_id : next_synth_block_id++;

            first_type = false;
            subdomain_map[block_id] = std::move(elem_ids);
          }
      }

    // Real element blocks occupy the ids below subdomain_id_end; any
    // blocks synthesized for visualization sides are numbered after them.
    if (!subdomain_map.empty())
      subdomain_id_end = subdomain_map.rbegin()->first + 1;

    // If we've been asked to add side elements, those go in their own
    // blocks.  We don't have any ids to list for elements that don't
314  
315  
316  
317 +
318 +
319  
320 +
321 +
322  
323 +
324  
325 +
326 +
327  
328  
329 +
330  
331  
332  
333  
334 +
335  
336 +
337  
338  
339  
340 +
341 +
342  
343 +
344 +
345  
346  
347  
    // the number of elements we'll add in each new block.
    if (add_sides)
      {
        std::map<subdomain_id_type, unsigned int> side_block_counts;
        for_each_elem([&](const Elem & elem)
          {
            if (elem.infinite())
              return;

            for (auto s : elem.side_index_range())
              {
                if (EquationSystems::redundant_added_side(elem,s))
                  continue;

                const subdomain_id_type side_block_id =
                  cast_int<subdomain_id_type>(subdomain_id_end + elem.side_type(s));

                // Guard the invariant above (also catches subdomain_id_type
                // overflow wrapping a side block id back down onto an
                // element block id).
                libmesh_assert_greater_equal(side_block_id, subdomain_id_end);

                ++side_block_counts[side_block_id];
              }
          });

        if (reduce)
          mesh.comm().sum(side_block_counts);

        for (const auto & [side_block_id, count] : side_block_counts)
          subdomain_map[side_block_id] = {count};
      }

    return subdomain_map;
2765  
2766  
2767  
2768 +
2769  
2770 +
2771 +
2772 +
2773  
2774  
2775  
    return;

  // We need to know about all processors' subdomains
  subdomain_id_type subdomain_id_end = 0;
  auto subdomain_map = build_subdomain_map(mesh,
                                           _add_sides,
                                           /*reduce=*/!_run_only_on_proc0,
                                           subdomain_id_end);

  if (!use_discontinuous)
    {
3047  
3048  
3049  
3050 +
3051 +
3052  
3053  
3054  
3055  
3056  
3057  
3058 +
3059 +
3060  
3061  
3062  
3063 +
3064 +
3065  
3066  
3067  
{
  LOG_SCOPE("write_elements()", "ExodusII_IO_Helper");

  if ((_run_only_on_proc0) && (this->processor_id() != 0))
    return;

  // Map from block ID to a vector of element IDs in that block.  Element
  // IDs are now of type dof_id_type, subdomain IDs are of type subdomain_id_type.
  subdomain_id_type subdomain_id_end = 0;
  auto subdomain_map = build_subdomain_map(mesh,
                                           _add_sides,
                                           /*reduce=*/!_run_only_on_proc0,
                                           subdomain_id_end);

  // Allocate the polyhedron face block ID after both mesh subdomains and
  // any blocks synthesized for visualization sides.
  const int c0polyhedron_face_block_id = subdomain_map.empty() ? 0 :
    cast_int<int>(subdomain_map.rbegin()->first) + 1;

  // element map vector
  num_elem_blk = cast_int<int>(subdomain_map.size());
3120  
3121  
3122  
3123 +
3124 +
3125  
3126 +
3127  
3128 +
3129  
3130  
3131  
3132  
3133  
3134  
3135 +
3136 +
3137 +
3138 +
3139  
3140  
3141  
3142  
3143 +
3144 +
3145 +
3146 +
3147 +
3148 +
3149 +
3150  
3151  
3152  
          // detect such synthesized blocks from the mismatch between the
          // block id and the actual subdomain of the elements it holds.
          const subdomain_id_type elem_subdomain_id =
            mesh.elem_ref(element_id_vec[0]).subdomain_id();
          const bool is_synthesized_block = (subdomain_id != elem_subdomain_id);

          std::string block_name = mesh.subdomain_name(elem_subdomain_id);

          if (is_synthesized_block)
            {
              // Suffix the (original) subdomain's name with the element
              // type, so the synthesized block is identifiable and its
              // name stays distinct from the block that kept the
              // subdomain id.  This block becomes its own subdomain when
              // the file is read back in.
              const std::string type_suffix = Utility::enum_to_string<ElemType>(elem_t);
              block_name = block_name.empty()
                ? (std::to_string(elem_subdomain_id) + "_" + type_suffix)
                : (block_name + "_" + type_suffix);

              // Informational: keep it to one rank so parallel (Nemesis)
              // writes will not repeat it once per processor.
              // NOTE this might miss logs if only occurs on other ranks
              if (this->processor_id() == 0)
                libMesh::out << "ExodusII_IO: subdomain " << elem_subdomain_id
                             << " contains more than one element type; writing its "
                             << type_suffix << " elements to a new block \"" << block_name
                             << "\" (block id " << subdomain_id
                             << ")"
                             << std::endl;
            }

          if (block_name.empty() && elem_t == C0POLYGON)
3672  
3673  
3674  
3675  
3676  
3677  
3678  
                  continue;

                if (elem->side_type(s) != elem_t)
                  continue;

                const std::vector<unsigned int> side_nodes =
                  elem->nodes_on_side(s);

src/mesh/mesh_base.C

1931  
1932  
1933  
1934  
1935  
1936  
1937  
                                  const bool synchronous)
{
  if (synchronous)
    parallel_object_only();
  else
    this->unset_has_synched_subdomain_name_map();
  _block_id_to_name[id] =  name;

src/mesh/mesh_triangle_holes.C

276  
277  
278  
279  
280  
281  
282  
    {
      ray_target = inside - Point(1);
      intersection_distances =
        this->find_ray_intersections(inside, ray_target);
    }

  // I'd make this an assert, but I'm not 100% confident we can't

src/mesh/replicated_mesh.C

483  
484  
485  
486  
487  
488  
489  

  // if the node already exists, then assign new (x,y,z) values
  if (n)
    *n = p;
  // otherwise build a new node, put it in the right spot, and return
  // a valid pointer.
  else

src/parallel/parallel_elem.C

653  
654  
655  
656  
657  
658  
659  
660  

#ifndef NDEBUG
      if (elem->runtime_topology() && elem->dim() == 3)
        for (auto s : elem->side_index_range())
          libmesh_assert(elem->nodes_on_side(s) ==
                         polyhedron_side_nodes[s]);
#endif