| 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% |
codecodecode+
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() |
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(); |
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); |
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; |
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 |
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 |
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 |