https://mooseframework.inl.gov
Loading...
Searching...
No Matches
MeshInfo.C
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#include "MeshInfo.h"
11#include "SubProblem.h"
12#include "libmesh/system.h"
13#include "libmesh/equation_systems.h"
14#include "libmesh/parallel_sync.h"
15#include "libmesh/parallel_algebra.h"
16#include "libmesh/elem_side_builder.h"
17#include "libmesh/enum_elem_quality.h"
18#include "libmesh/enum_to_string.h"
19
21
23const std::vector<MeshInfo::DomainElemQuality> MeshInfo::domain_elem_qualities{
24 {libMesh::ElemQuality::MIN_ANGLE, MeshInfo::BoundType::MIN},
25 {libMesh::ElemQuality::MAX_ANGLE, MeshInfo::BoundType::MAX},
26 {libMesh::ElemQuality::JACOBIAN, MeshInfo::BoundType::MIN},
27 {libMesh::ElemQuality::JACOBIAN, MeshInfo::BoundType::MAX}};
29const std::vector<libMesh::ElemQuality> MeshInfo::elem_qualities{libMesh::ElemQuality::MIN_ANGLE,
30 libMesh::ElemQuality::MAX_ANGLE,
31 libMesh::ElemQuality::JACOBIAN};
32
33std::string
38
41{
44 "Report mesh information, such as the number of elements, nodes, and degrees of freedom.");
45
46 MultiMooseEnum items("elems num_dofs num_dofs_nonlinear num_dofs_auxiliary num_dofs_constrained "
47 "num_elements num_nodes num_local_dofs num_local_dofs_nonlinear "
48 "num_local_dofs_auxiliary num_local_elements num_local_nodes local_elems "
49 "local_sidesets local_subdomains sidesets subdomains");
51 "items",
52 items,
53 "The iteration information to output; if not provided, everything will be output.");
54
55 // Elem parameters
56 {
57 {
58 MultiMooseEnum items("all bounding_box dim elem_mapping_type elem_type hmax hmin "
59 "neighbor_ids node_ids num_sides points processor_id unique_id volume");
61 "elem_items", items, "Items to include when outputting element information");
62 }
63
64 {
65 std::vector<std::string> elem_qualities;
67 std::transform(MeshInfo::elem_qualities.begin(),
69 std::back_inserter(elem_qualities),
70 [](const auto v) { return elemQualityToString(v); });
71 std::sort(elem_qualities.begin(), elem_qualities.end());
74 "elem_qualities",
75 items,
76 "Element quality metrics to include when outputting element information");
77 }
78 }
79
80 // Domain parameters (sidesets, subdomains)
81 {
82 static const std::array<std::string, 2> domain_names{"sideset", "subdomain"};
83
84 // [sideset,subdomain]_items
85 {
86 MultiMooseEnum items(
87 "all bounding_box elems elem_types min_volume max_volume num_elems processor_ids volume");
88 for (const auto & name : domain_names)
90 name + "_items", items, "Items to include when outputting " + name + " information");
91 }
92 // [sideset,subdomain]_elem_qualities
93 {
94 // Convert each entry in MeshInfo::domain_elem_qualities to a human string, like:
95 // {libMesh::ElemQuality::MIN_ANGLE, MeshInfo::BoundType::MIN} -> "min_min_angle"
96 std::vector<std::string> domain_elem_qualities;
98 std::transform(MeshInfo::domain_elem_qualities.begin(),
100 std::back_inserter(domain_elem_qualities),
101 [](const auto & v) { return v.itemName(); });
102 std::sort(domain_elem_qualities.begin(), domain_elem_qualities.end());
103
105 for (const auto & name : domain_names)
106 params.addParam<MultiMooseEnum>(
107 name + "_elem_qualities",
108 items,
109 "Bounded (min or max) element quality metrics to include when outputting " + name +
110 " information");
111 }
112 }
113
114 return params;
115}
116
118 : GeneralReporter(parameters),
119 _items(getParam<MultiMooseEnum>("items")),
120 _elem_items(getParam<MultiMooseEnum>("elem_items")),
121 _sideset_items(getParam<MultiMooseEnum>("sideset_items")),
122 _subdomain_items(getParam<MultiMooseEnum>("subdomain_items")),
123 _elem_qualities(getParam<MultiMooseEnum>("elem_qualities")),
124 _sideset_elem_qualities(getParam<MultiMooseEnum>("sideset_elem_qualities")),
125 _subdomain_elem_qualities(getParam<MultiMooseEnum>("subdomain_elem_qualities")),
126
127 _num_dofs(declareHelper<unsigned int>("num_dofs", REPORTER_MODE_REPLICATED)),
128 _num_dofs_nl(declareHelper<unsigned int>("num_dofs_nonlinear", REPORTER_MODE_REPLICATED)),
129 _num_dofs_aux(declareHelper<unsigned int>("num_dofs_auxiliary", REPORTER_MODE_REPLICATED)),
130 _num_dofs_constrained(
131 declareHelper<unsigned int>("num_dofs_constrained", REPORTER_MODE_REPLICATED)),
132 _num_elem(declareHelper<unsigned int>("num_elements", REPORTER_MODE_REPLICATED)),
133 _num_node(declareHelper<unsigned int>("num_nodes", REPORTER_MODE_REPLICATED)),
134 _num_local_dofs(declareHelper<unsigned int>("num_local_dofs", REPORTER_MODE_DISTRIBUTED)),
135 _num_local_dofs_nl(
136 declareHelper<unsigned int>("num_local_dofs_nonlinear", REPORTER_MODE_DISTRIBUTED)),
137 _num_local_dofs_aux(
138 declareHelper<unsigned int>("num_local_dofs_auxiliary", REPORTER_MODE_DISTRIBUTED)),
139 _num_local_elem(declareHelper<unsigned int>("num_local_elements", REPORTER_MODE_DISTRIBUTED)),
140 _num_local_node(declareHelper<unsigned int>("num_local_nodes", REPORTER_MODE_DISTRIBUTED)),
141
142 _elem_infos(initCombinedInfos<ElemInfos>("elems", _elem_items, _elem_qualities)),
143 _sideset_infos(
144 initCombinedInfos<SidesetInfos>("sidesets", _sideset_items, _sideset_elem_qualities)),
145 _subdomain_infos(initCombinedInfos<SubdomainInfos>(
146 "subdomains", _subdomain_items, _subdomain_elem_qualities)),
147
148 _equation_systems(_fe_problem.es()),
149 _nonlinear_system(_fe_problem.es().get_system("nl0")),
150 _aux_system(_fe_problem.es().get_system("aux0")),
151 _mesh(_fe_problem.mesh().getMesh())
152{
153 if (_elem_items.isValid() && !hasItem("elems", _items) && !hasItem("local_elems", _items))
154 paramError("elem_items", "Should not be provided without an elems item enabled");
155 if (_elem_qualities.isValid() && !hasItem("elems", _items) && !hasItem("local_elems", _items))
156 paramError("elem_qualities", "Should not be provided without an elems item enabled");
157 if (_sideset_items.isValid() && !hasItem("sidesets", _items) &&
158 !hasItem("local_sidesets", _items))
159 paramError("sideset_items", "Should not be provided without a sidesets item enabled");
160 if (_sideset_elem_qualities.isValid() && !hasItem("sidesets", _items) &&
161 !hasItem("local_sidesets", _items))
162 paramError("sideset_elem_qualities", "Should not be provided without a sidesets item enabled");
163 if (_subdomain_items.isValid() && !hasItem("subdomains", _items) &&
164 !hasItem("local_subdomains", _items))
165 paramError("subdomain_items", "Should not be provided without a subdomains item enabled");
166 if (_subdomain_elem_qualities.isValid() && !hasItem("subdomains", _items) &&
167 !hasItem("local_subdomains", _items))
168 paramError("subdomain_elem_qualities",
169 "Should not be provided without a subdomains item enabled");
170}
171
173 const BoundType bound_type)
174 : std::pair<libMesh::ElemQuality, BoundType>(elem_quality, bound_type)
175{
176}
177
178std::string
180{
181 return (boundType() == BoundType::MAX ? std::string("max") : std::string("min")) + "_" +
182 elemQualityToString(elemQuality());
183}
184
185void
186MeshInfo::DomainElemQuality::updateValue(std::map<DomainElemQuality, Real> & quality_map,
187 const Real value) const
188{
189 static const Real default_max = 0;
190 static const Real default_min = std::numeric_limits<Real>::max();
191 const bool is_max = boundType() == BoundType::MAX;
192 auto & entry = quality_map.try_emplace(*this, (is_max ? default_max : default_min)).first->second;
193 if (is_max)
194 entry = std::max(entry, value);
195 else
196 entry = std::min(entry, value);
197}
198
200 : bounding_box(MeshInfo::hasItem("bounding_box", items)),
201 volume(MeshInfo::hasItem("volume", items))
202{
203}
204
208 elems(MeshInfo::hasItem("elems", items)),
209 elem_types(MeshInfo::hasItem("elem_types", items)),
210 max_volume(MeshInfo::hasItem("max_volume", items)),
211 min_volume(MeshInfo::hasItem("min_volume", items)),
212 num_elems(MeshInfo::hasItem("num_elems", items)),
213 processor_ids(MeshInfo::hasItem("processor_ids", items))
214{
215 std::copy_if(MeshInfo::domain_elem_qualities.begin(),
217 std::back_inserter(this->elem_qualities),
218 [&](const auto & v) { return MeshInfo::hasItem(v.itemName(), elem_qualities); });
219}
220
224 dim(MeshInfo::hasItem("dim", items)),
225 elem_mapping_type(MeshInfo::hasItem("elem_mapping_type", items)),
226 elem_type(MeshInfo::hasItem("elem_type", items)),
227 hmax(MeshInfo::hasItem("hmax", items)),
228 hmin(MeshInfo::hasItem("hmin", items)),
229 neighbor_ids(MeshInfo::hasItem("neighbor_ids", items)),
230 node_ids(MeshInfo::hasItem("node_ids", items)),
231 num_sides(MeshInfo::hasItem("num_sides", items)),
232 points(MeshInfo::hasItem("points", items)),
233 processor_id(MeshInfo::hasItem("processor_id", items)),
234 unique_id(MeshInfo::hasItem("unique_id", items))
235{
236 std::copy_if(MeshInfo::elem_qualities.begin(),
238 std::back_inserter(this->elem_qualities),
239 [&](const auto v)
241}
242
243template <typename InfoMapType, class InfoItemsType>
245 InfoMapType * global,
246 const InfoItemsType & items)
247 : local(local), global(global), items(items)
248{
249}
250
251template <class CombinedInfosType>
252CombinedInfosType
254 const MultiMooseEnum & items,
255 const MultiMooseEnum & qualities)
256{
257 using info_map_type = typename CombinedInfosType::info_map_type;
258 const typename CombinedInfosType::items_type dii(items, qualities);
259 return CombinedInfosType(
260 declareHelper<info_map_type>("local_" + name, REPORTER_MODE_DISTRIBUTED, dii),
261 declareHelper<info_map_type>(name, REPORTER_MODE_ROOT, dii),
262 dii);
263}
264
265void
267{
268 auto local_ptr = _elem_infos.local;
269 auto global_ptr = _elem_infos.global;
270
271 // Nothing to do
272 if (!local_ptr && !global_ptr)
273 return;
274
275 // Clear all entries first
276 for (auto value_ptr : {local_ptr, global_ptr})
277 if (value_ptr)
278 value_ptr->map.clear();
279
281 const auto map_insert = [](auto & map, const auto id, const auto subdomain_id) -> ElemInfo &
282 {
283 mooseAssert(!map.count(id), "Should not exist in map");
284 return map
285 .emplace(std::piecewise_construct,
286 std::forward_as_tuple(id),
287 std::forward_as_tuple(id, subdomain_id))
288 .first->second;
289 };
291 const auto & items = _elem_infos.items;
292
293#define set_simple(name, elem_function_name) \
294 if (items.name) \
295 entry.name = elem.elem_function_name()
296
297 // Fill the local information
298 std::map<dof_id_type, ElemInfo> local_info;
299 for (const auto elem_ptr : *_fe_problem.mesh().getActiveLocalElementRange())
300 {
301 auto & elem = *elem_ptr;
302 auto & entry = map_insert(local_info, elem.id(), elem.subdomain_id());
303
304 entry.elem_qualities.reserve(items.elem_qualities.size());
305 for (const auto quality : items.elem_qualities)
306 entry.elem_qualities.emplace_back(quality, elem.quality(quality));
307
308 set_simple(bounding_box, loose_bounding_box);
309 set_simple(volume, volume);
310 set_simple(dim, dim);
311 set_simple(elem_mapping_type, mapping_type);
312 set_simple(elem_type, type);
313 set_simple(hmax, hmax);
314 set_simple(hmin, hmin);
315 if (items.neighbor_ids)
316 {
317 entry.neighbor_ids.reserve(elem.n_neighbors());
318 for (const auto neighbor_ptr : elem.neighbor_ptr_range())
319 entry.neighbor_ids.push_back(neighbor_ptr ? neighbor_ptr->id()
321 }
322 if (items.node_ids)
323 {
324 entry.node_ids.reserve(elem.n_nodes());
325 for (const auto & node : elem.node_ref_range())
326 entry.node_ids.push_back(node.id());
327 }
328 set_simple(num_sides, n_sides);
329 if (items.points)
330 {
331 entry.points.reserve(elem.n_nodes());
332 for (const auto & node : elem.node_ref_range())
333 entry.points.emplace_back(node);
334 }
335 set_simple(processor_id, processor_id);
336 if (items.unique_id)
337 entry.unique_id =
338 elem.valid_unique_id() ? elem.unique_id() : libMesh::DofObject::invalid_unique_id;
339 }
340#undef set_simple
341
342 // For local, copy over everything we have. It's just local information.
343 if (local_ptr)
344 local_ptr->map = local_info;
345
346 // For global entries, need to accumulate data
347 if (global_ptr)
348 {
349 // initialize with ID and subdomain_id
350 {
351 std::vector<std::pair<dof_id_type, subdomain_id_type>> data;
352 data.reserve(local_info.size());
353 for (auto & [id, info] : local_info)
354 data.emplace_back(id, info.subdomain_id);
355 comm().gather(0, data);
356 for (const auto & [id, subdomain_id] : data)
357 map_insert(global_ptr->map, id, subdomain_id);
358 }
359
360 const auto gather = [&](const auto && get_value, const auto && set_value)
361 {
362 using T = std::remove_reference_t<std::invoke_result_t<decltype(get_value), ElemInfo &>>;
363 std::vector<std::pair<dof_id_type, T>> data;
364 data.reserve(local_info.size());
365 for (auto & [id, info] : local_info)
366 data.emplace_back(id, get_value(info));
367 comm().gather(0, data);
368 for (const auto & [id, value] : data)
369 set_value(global_ptr->map.at(id), value);
370 };
371
372 // elem_qualities
373 if (items.elem_qualities.size())
374 gather(
375 [](const auto & info)
376 {
377 std::vector<std::pair<std::underlying_type_t<libMesh::ElemQuality>, Real>> values;
378 values.reserve(info.elem_qualities.size());
379 values.insert(values.end(), info.elem_qualities.begin(), info.elem_qualities.end());
380 return values;
381 },
382 [](auto & info, const auto & value)
383 {
384 info.elem_qualities.reserve(value.size());
385 for (const auto & [elem_quality, quality_value] : value)
386 info.elem_qualities.emplace_back(static_cast<libMesh::ElemQuality>(elem_quality),
387 quality_value);
388 });
389 // bounding_box
390 if (items.bounding_box)
391 gather([](const auto & info)
392 { return static_cast<const std::pair<Point, Point> &>(info.bounding_box); },
393 [](auto & info, const auto & value)
394 { static_cast<std::pair<Point, Point> &>(info.bounding_box) = value; });
395
396#define gather_simple(name) \
397 if (items.name) \
398 gather([](const auto & info) { return info.name; }, \
399 [](auto & info, const auto & value) { info.name = value; })
400#define gather_enum(name) \
401 if (items.name) \
402 gather([](const auto & info) \
403 { return static_cast<std::underlying_type_t<decltype(ElemInfo::name)>>(info.name); }, \
404 [](auto & info, const auto & value) \
405 { info.name = static_cast<decltype(ElemInfo::name)>(value); })
406
407 // volume
408 gather_simple(volume);
409 // dim
410 gather_simple(dim);
411 // elem_mapping_type
412 gather_enum(elem_mapping_type);
413 // elem_type
414 gather_enum(elem_type);
415 // hmax
416 gather_simple(hmax);
417 // hmin
418 gather_simple(hmin);
419 // neighbor_ids
420 gather_simple(neighbor_ids);
421 // node_ids
422 gather_simple(node_ids);
423 // num_sides
424 gather_simple(num_sides);
425 // points
426 gather_simple(points);
427 // processor_id
428 gather_simple(processor_id);
429 // unique_id
430 gather_simple(unique_id);
431
432#undef gather_simple
433#undef gather_enum
434 }
435}
436
437template <class CombinedInfosType>
438void
439MeshInfo::possiblyAddDomainInfo(CombinedInfosType & infos)
440{
441 constexpr bool is_sidesets = std::is_same_v<CombinedInfosType, SidesetInfos>;
442 using id_type = typename CombinedInfosType::id_type;
443 using info_type = typename CombinedInfosType::info_type;
444 using map_type = typename CombinedInfosType::map_type;
445
446 auto & local = infos.local;
447 auto & global = infos.global;
448
449 // Nothing to do
450 if (!local && !global)
451 return;
452
453 // Helper for either getting an entry from one of the maps or inserting if it doesn't exist
454 const auto get_or_insert_info = [](map_type & map, const id_type id) -> info_type &
455 { return map.try_emplace(id, id).first->second; };
456
457 // Clear all entries first
458 for (auto value_ptr : {local, global})
459 if (value_ptr)
460 value_ptr->map.clear();
461
462 const auto & items = infos.items;
463
464 // Fill the local information
465 map_type local_info;
466 {
467 const auto compute_volume = items.max_volume || items.min_volume || items.volume;
468
469 // Helper for adding an element to the info
470 const auto add = [&](const auto id, const libMesh::Elem & elem, auto && elems_entry)
471 {
472 auto & entry = get_or_insert_info(local_info, id);
473 const Real volume = compute_volume ? elem.volume() : 0;
474 if (items.bounding_box)
475 entry.bounding_box.union_with(elem.loose_bounding_box());
476 if (items.volume)
477 entry.volume += volume;
478 for (const auto & quality : items.elem_qualities)
479 quality.updateValue(entry.elem_qualities, elem.quality(quality.elemQuality()));
480 if (items.elems)
481 entry.elems.emplace_back(std::move(elems_entry));
482 if (items.elem_types)
483 entry.elem_types.insert(elem.type());
484 if (items.min_volume)
485 entry.min_volume = std::min(entry.min_volume, volume);
486 if (items.max_volume)
487 entry.max_volume = std::max(entry.max_volume, volume);
488 if (items.num_elems)
489 ++entry.num_elems;
490 if (items.processor_ids)
491 entry.processor_ids.insert(elem.processor_id());
492 };
493
494 // Add elements for subdomains and sidesets
495 auto & mesh = _fe_problem.mesh();
496 if constexpr (is_sidesets)
497 {
498 libMesh::ElemSideBuilder side_builder;
499 for (const auto & bnd_elem : as_range(mesh.bndElemsBegin(), mesh.bndElemsEnd()))
500 {
501 const auto & elem = *bnd_elem->_elem;
502 if (elem.processor_id() == processor_id())
503 {
504 const auto side = bnd_elem->_side;
505 add(bnd_elem->_bnd_id, side_builder(elem, side), std::make_pair(elem.id(), side));
506 }
507 }
508 }
509 else
510 {
511 for (const auto & elem : *mesh.getActiveLocalElementRange())
512 add(elem->subdomain_id(), *elem, elem->id());
513 }
514 }
515
516 // For local, copy over everything we have. It's just local information.
517 if (local)
518 local->map = local_info;
519
520 // For global entries, need to accumulate data
521 if (global)
522 {
523 bool did_gather = false;
524 const auto gather = [&](const auto && get_value, const auto && set_value)
525 {
526 using T = std::remove_reference_t<std::invoke_result_t<decltype(get_value), info_type &>>;
527 std::vector<std::pair<id_type, T>> data;
528 data.reserve(local_info.size());
529 for (auto & [id, info] : local_info)
530 data.emplace_back(id, get_value(info));
531 comm().gather(0, data);
532 for (const auto & [id, value] : data)
533 set_value(get_or_insert_info(global->map, id), value);
534 did_gather = true;
535 };
536
537 // bounding_box
538 if (items.bounding_box)
539 gather([](const auto & info)
540 { return std::make_pair(info.bounding_box.min(), info.bounding_box.max()); },
541 [](auto & info, const auto & value)
542 { info.bounding_box.union_with(BoundingBox(value.first, value.second)); });
543 // volume
544 if (items.volume)
545 gather([](const auto & info) { return info.volume; },
546 [](auto & info, const auto & value) { info.volume += value; });
547 // elem_qualities
548 if (items.elem_qualities.size())
549 gather(
550 [](const auto & info)
551 {
552 std::vector<std::tuple<std::underlying_type_t<decltype(DomainElemQuality::first)>,
553 std::underlying_type_t<decltype(DomainElemQuality::second)>,
554 Real>>
555 values;
556 values.reserve(info.elem_qualities.size());
557 for (const auto & [bounded_quality, value] : info.elem_qualities)
558 values.emplace_back(
559 bounded_quality.elemQuality(), bounded_quality.boundType(), value);
560 return values;
561 },
562 [](auto & info, const auto & value)
563 {
564 for (const auto & [elem_quality, bound_type, quality_value] : value)
565 {
566 const DomainElemQuality dq(static_cast<libMesh::ElemQuality>(elem_quality),
567 static_cast<BoundType>(bound_type));
568 dq.updateValue(info.elem_qualities, quality_value);
569 }
570 });
571 // elems
572 if (items.elems)
573 gather([](const auto & info) { return info.elems; },
574 [](auto & info, const auto & value)
575 { info.elems.insert(info.elems.end(), value.begin(), value.end()); });
576 // elem_types
577 if (items.elem_types)
578 gather(
579 [](const auto & info)
580 {
581 std::vector<int> values;
582 values.reserve(info.elem_types.size());
583 std::transform(info.elem_types.begin(),
584 info.elem_types.end(),
585 std::back_inserter(values),
586 [](const auto v) { return static_cast<int>(v); });
587 return values;
588 },
589 [](auto & info, const auto & value)
590 {
591 std::transform(value.begin(),
592 value.end(),
593 std::inserter(info.elem_types, info.elem_types.end()),
594 [](const auto v) { return static_cast<libMesh::ElemType>(v); });
595 });
596 // max_volume
597 if (items.max_volume)
598 gather([](const auto & info) { return info.max_volume; },
599 [](auto & info, const auto & value)
600 { info.max_volume = std::max(info.max_volume, value); });
601 // min_volume
602 if (items.min_volume)
603 gather([](const auto & info) { return info.min_volume; },
604 [](auto & info, const auto & value)
605 { info.min_volume = std::min(info.min_volume, value); });
606 // num_elems
607 if (items.num_elems)
608 gather([](const auto & info) { return info.num_elems; },
609 [](auto & info, const auto & value) { info.num_elems += value; });
610 // processor_ids
611 if (items.processor_ids)
612 gather(
613 [](const auto & info)
614 {
615 mooseAssert(info.processor_ids.size() == 1, "Should have exactly one pid");
616 return *info.processor_ids.begin();
617 },
618 [](auto & info, const auto & value) { info.processor_ids.insert(value); });
619
620 // If we haven't gathered anything at all (no items), we didn't insert
621 // any IDs so we need to do that now
622 if (!did_gather)
623 {
624 std::vector<id_type> data;
625 data.reserve(local_info.size());
626 std::transform(local_info.begin(),
627 local_info.end(),
628 std::back_inserter(data),
629 [](const auto v) { return v.first; });
630 comm().gather(0, data);
631 for (const auto id : data)
632 get_or_insert_info(global->map, id);
633 }
634
635 // For global sidesets, we could technically have sidesets that contain no
636 // sides, which we wouldn't have picked up in the local build above. In
637 // a previous implementation of MeshInfo, we still reported these. So, keep
638 // reporting them.
639 if constexpr (is_sidesets)
640 {
641 auto sideset_ids = _mesh.get_boundary_info().get_side_boundary_ids();
642 comm().set_union(sideset_ids);
643 for (const auto id : sideset_ids)
644 get_or_insert_info(global->map, id);
645 }
646 }
647
648 for (auto to : {local, global})
649 if (to)
650 {
651 // Add sideset/subdomain names
652 for (auto & [id, info] : to->map)
653 if constexpr (is_sidesets)
654 info.name = _mesh.get_boundary_info().get_sideset_name(id);
655 else
656 info.name = _mesh.subdomain_name(id);
657
658 // Sort "elems" if elems requested
659 if (items.elems)
660 for (auto & id_info_pair : to->map)
661 std::sort(id_info_pair.second.elems.begin(), id_info_pair.second.elems.end());
662 }
663}
664
665void
667{
668#define set_value(variable, value) \
669 if (variable) \
670 *variable = value
671
672 set_value(_num_dofs, _equation_systems.n_dofs());
674 set_value(_num_dofs_aux, _aux_system.n_dofs());
676 {
678 for (auto s : make_range(_equation_systems.n_systems()))
679 *_num_dofs_constrained += _equation_systems.get_system(s).n_constrained_dofs();
680 }
681
682 set_value(_num_elem, _mesh.n_elem());
683 set_value(_num_node, _mesh.n_nodes());
687 set_value(_num_local_elem, _mesh.n_local_elem());
688 set_value(_num_local_node, _mesh.n_local_nodes());
689
690#undef set_value
691
695}
696
697bool
698MeshInfo::hasItem(const std::string & name, const MultiMooseEnum & items)
699{
700 mooseAssert(items.find(name) != items.items().end(), "Invalid item: " << name);
701 if (items.isValid())
702 return items.isValueSet(name) || items.isValueSet("all");
703 return items.find("all") == items.items().end();
704}
705
707#define info_json_simple(name) \
708 if (items.name) \
709 info_json[#name] = info.name
710#define info_json_enum(name) \
711 if (items.name) \
712 info_json[#name] = libMesh::Utility::enum_to_string(info.name)
713#define info_json_id(name, invalid_value) \
714 if (items.name) \
715 { \
716 if (info.name == invalid_value) \
717 info_json[#name] = nullptr; \
718 else \
719 info_json[#name] = info.name; \
720 }
721#define info_json_ids(name, invalid_value) \
722 if (items.name) \
723 for (const auto id : info.name) \
724 { \
725 if (id == invalid_value) \
726 info_json[#name].push_back(nullptr); \
727 else \
728 info_json[#name].push_back(id); \
729 }
730template <class InfoType>
731void
732toJSONInfoBase(nlohmann::json & json, const InfoType & info)
733{
734 json["id"] = info.id;
735}
736template <class InfoType, class InfoItemsType>
737void
738toJSONElemContainingInfo(nlohmann::json & info_json,
739 const InfoType & info,
740 const InfoItemsType & items)
741{
742 toJSONInfoBase(info_json, info);
743 info_json_simple(bounding_box);
744 info_json_simple(volume);
745}
746void
747to_json(nlohmann::json & json, const MeshInfo::ElemInfoMap & info_map)
748{
749 const auto & items = info_map.items;
750 for (const auto & [id, info] : info_map.map)
751 {
752 mooseAssert(id == info.id, "Inconsistent id");
753
754 nlohmann::json info_json;
755 toJSONElemContainingInfo(info_json, info, items);
756 info_json["subdomain_id"] = info.subdomain_id;
757
758 // elem_qualities
759 if (info.elem_qualities.size())
760 for (const auto & [quality, value] : info.elem_qualities)
761 info_json["elem_qualities"][elemQualityToString(quality)] = value;
762 // dim
763 info_json_simple(dim);
764 // elem_mapping_type
765 info_json_enum(elem_mapping_type);
766 // elem_type
767 info_json_enum(elem_type);
768 // hmax
769 info_json_simple(hmax);
770 // hmin
771 info_json_simple(hmin);
772 // neighbor_ids
773 info_json_ids(neighbor_ids, libMesh::DofObject::invalid_id);
774 // node_ids
775 info_json_ids(node_ids, libMesh::DofObject::invalid_id);
776 // num_sides
777 info_json_simple(num_sides);
778 // points
779 info_json_simple(points);
780 // processor_id
781 info_json_simple(processor_id);
782 // unique_id
783 info_json_id(unique_id, libMesh::DofObject::invalid_unique_id);
784
785 json.push_back(std::move(info_json));
786 }
787}
788template <class DomainInfoMapType>
789void
790toJSONDomainInfoMap(nlohmann::json & json, const DomainInfoMapType & info_map)
791{
792 constexpr bool is_sideset = std::is_same_v<DomainInfoMapType, MeshInfo::SidesetInfoMap>;
793 const auto & items = info_map.items;
794
795 for (const auto & [id, info] : info_map.map)
796 {
797 mooseAssert(id == info.id, "Inconsistent id");
798
799 nlohmann::json info_json;
800 toJSONElemContainingInfo(info_json, info, items);
801
802 if (info.name.size())
803 info_json["name"] = info.name;
804 // elem_qualities
805 if (items.elem_qualities.size())
806 for (const auto & [bounded_quality, value] : info.elem_qualities)
807 info_json["elem_qualities"][bounded_quality.itemName()] = value;
808 // elems
809 if (items.elems)
810 {
811 auto & elems_json = info_json["elems"];
812 if constexpr (is_sideset)
813 {
814 for (const auto & elem_entry : info.elems)
815 elems_json.push_back({{"elem_id", elem_entry.first}, {"side", elem_entry.second}});
816 }
817 else
818 elems_json = info.elems;
819 }
820 // elem_types
821 if (items.elem_types)
822 {
823 std::vector<std::string> elem_types;
824 elem_types.reserve(info.elem_types.size());
825 std::transform(info.elem_types.begin(),
826 info.elem_types.end(),
827 std::back_inserter(elem_types),
828 [](const auto v) { return libMesh::Utility::enum_to_string(v); });
829 std::sort(elem_types.begin(), elem_types.end());
830 info_json["elem_types"] = elem_types;
831 }
832 // max_volume
833 info_json_simple(max_volume);
834 // min_volume
835 info_json_simple(min_volume);
836 // min_volume
837 info_json_simple(num_elems);
838 // processor_ids
839 info_json_simple(processor_ids);
840
841 json.push_back(std::move(info_json));
842 }
843}
844#undef info_json_simple
845#undef info_json_enum
846#undef info_json_id
847#undef info_json_ids
848void
849to_json(nlohmann::json & json, const MeshInfo::SidesetInfoMap & info_map)
850{
851 toJSONDomainInfoMap(json, info_map);
852}
853void
854to_json(nlohmann::json & json, const MeshInfo::SubdomainInfoMap & info_map)
855{
856 toJSONDomainInfoMap(json, info_map);
857}
858
860void
861dataStore(std::ostream & stream, MeshInfo::DomainElemQuality & beq, void *)
862{
863 int value;
864
865 value = static_cast<int>(beq.elemQuality());
866 dataStore(stream, value, nullptr);
867
868 value = static_cast<int>(beq.boundType());
869 dataStore(stream, value, nullptr);
870}
871void
872dataLoad(std::istream & stream, MeshInfo::DomainElemQuality & beq, void *)
873{
874 int value;
875
876 dataLoad(stream, value, nullptr);
877 beq.elemQuality() = static_cast<libMesh::ElemQuality>(value);
878
879 dataLoad(stream, value, nullptr);
880 beq.boundType() = static_cast<MeshInfo::BoundType>(value);
881}
882
884template <typename T>
885void
886dataStoreInfoBase(std::ostream & stream, T & info)
887{
888 dataStore(stream, info.id, nullptr);
889}
890template <typename T>
891void
892dataStoreElemContainingInfo(std::ostream & stream, T & info)
893{
894 dataStoreInfoBase(stream, info);
895 dataStore(stream, info.bounding_box, nullptr);
896 dataStore(stream, info.volume, nullptr);
897}
898void
899dataStore(std::ostream & stream, MeshInfo::ElemInfo & info, void *)
900{
901 dataStoreElemContainingInfo(stream, info);
902 dataStore(stream, info.elem_qualities, nullptr);
903 dataStore(stream, info.dim, nullptr);
904 dataStore(stream, info.elem_mapping_type, nullptr);
905 dataStore(stream, info.elem_type, nullptr);
906 dataStore(stream, info.hmax, nullptr);
907 dataStore(stream, info.hmin, nullptr);
908 dataStore(stream, info.neighbor_ids, nullptr);
909 dataStore(stream, info.node_ids, nullptr);
910 dataStore(stream, info.num_sides, nullptr);
911 dataStore(stream, info.points, nullptr);
912 dataStore(stream, info.processor_id, nullptr);
913 dataStore(stream, info.subdomain_id, nullptr);
914 dataStore(stream, info.unique_id, nullptr);
915}
916template <typename T>
917void
918dataStoreDomainInfo(std::ostream & stream, T & info)
919{
920 dataStoreElemContainingInfo(stream, info);
921 dataStore(stream, info.name, nullptr);
922 dataStore(stream, info.elem_qualities, nullptr);
923 dataStore(stream, info.elems, nullptr);
924 dataStore(stream, info.elem_types, nullptr);
925 dataStore(stream, info.min_volume, nullptr);
926 dataStore(stream, info.max_volume, nullptr);
927 dataStore(stream, info.num_elems, nullptr);
928 dataStore(stream, info.processor_ids, nullptr);
929}
930void
931dataStore(std::ostream & stream, MeshInfo::SidesetInfo & info, void *)
932{
933 dataStoreDomainInfo(stream, info);
934}
935void
936dataStore(std::ostream & stream, MeshInfo::SubdomainInfo & info, void *)
937{
938 dataStoreDomainInfo(stream, info);
939}
940template <typename T>
941void
942dataLoadInfoBase(std::istream & stream, T & info)
943{
944 dataLoad(stream, info.id, nullptr);
945}
946template <typename T>
947void
948dataLoadElemContainingInfo(std::istream & stream, T & info)
949{
950 dataLoadInfoBase(stream, info);
951 dataLoad(stream, info.bounding_box, nullptr);
952 dataLoad(stream, info.volume, nullptr);
953}
954void
955dataLoad(std::istream & stream, MeshInfo::ElemInfo & info, void *)
956{
957 dataLoadElemContainingInfo(stream, info);
958 dataLoad(stream, info.elem_qualities, nullptr);
959 dataLoad(stream, info.dim, nullptr);
960 dataLoad(stream, info.elem_mapping_type, nullptr);
961 dataLoad(stream, info.elem_type, nullptr);
962 dataLoad(stream, info.hmax, nullptr);
963 dataLoad(stream, info.hmin, nullptr);
964 dataLoad(stream, info.neighbor_ids, nullptr);
965 dataLoad(stream, info.node_ids, nullptr);
966 dataLoad(stream, info.num_sides, nullptr);
967 dataLoad(stream, info.points, nullptr);
968 dataLoad(stream, info.processor_id, nullptr);
969 dataLoad(stream, info.subdomain_id, nullptr);
970 dataLoad(stream, info.unique_id, nullptr);
971}
972template <typename T>
973void
974dataLoadDomainInfo(std::istream & stream, T & info)
975{
976 dataLoadElemContainingInfo(stream, info);
977 dataLoad(stream, info.name, nullptr);
978 dataLoad(stream, info.elem_qualities, nullptr);
979 dataLoad(stream, info.elems, nullptr);
980 dataLoad(stream, info.elem_types, nullptr);
981 dataLoad(stream, info.min_volume, nullptr);
982 dataLoad(stream, info.max_volume, nullptr);
983 dataLoad(stream, info.num_elems, nullptr);
984 dataLoad(stream, info.processor_ids, nullptr);
985}
986void
987dataLoad(std::istream & stream, MeshInfo::SidesetInfo & info, void *)
988{
989 dataLoadDomainInfo(stream, info);
990}
991void
992dataLoad(std::istream & stream, MeshInfo::SubdomainInfo & info, void *)
993{
994 dataLoadDomainInfo(stream, info);
995}
996
998void
999dataStore(std::ostream & stream, MeshInfo::ElemInfoMap & info_map, void *)
1000{
1001 dataStore(stream, info_map.map, nullptr);
1002}
1003void
1004dataStore(std::ostream & stream, MeshInfo::SidesetInfoMap & info_map, void *)
1005{
1006 dataStore(stream, info_map.map, nullptr);
1007}
1008void
1009dataStore(std::ostream & stream, MeshInfo::SubdomainInfoMap & info_map, void *)
1010{
1011 dataStore(stream, info_map.map, nullptr);
1012}
1013void
1014dataLoad(std::istream & stream, MeshInfo::ElemInfoMap & info_map, void *)
1015{
1016 dataLoad(stream, info_map.map, nullptr);
1017}
1018void
1019dataLoad(std::istream & stream, MeshInfo::SidesetInfoMap & info_map, void *)
1020{
1021 dataLoad(stream, info_map.map, nullptr);
1022}
1023void
1024dataLoad(std::istream & stream, MeshInfo::SubdomainInfoMap & info_map, void *)
1025{
1026 dataLoad(stream, info_map.map, nullptr);
1027}
1028
1029template MeshInfo::SidesetInfos MeshInfo::initCombinedInfos<MeshInfo::SidesetInfos>(
1030 const std::string &, const MultiMooseEnum &, const MultiMooseEnum &);
1031template MeshInfo::SubdomainInfos MeshInfo::initCombinedInfos<MeshInfo::SubdomainInfos>(
1032 const std::string &, const MultiMooseEnum &, const MultiMooseEnum &);
1033template void MeshInfo::possiblyAddDomainInfo<MeshInfo::SidesetInfos>(MeshInfo::SidesetInfos &);
1034template void MeshInfo::possiblyAddDomainInfo<MeshInfo::SubdomainInfos>(MeshInfo::SubdomainInfos &);
void dataLoadElemContainingInfo(std::istream &stream, T &info)
Definition MeshInfo.C:948
void toJSONInfoBase(nlohmann::json &json, const InfoType &info)
Definition MeshInfo.C:732
void toJSONElemContainingInfo(nlohmann::json &info_json, const InfoType &info, const InfoItemsType &items)
Definition MeshInfo.C:738
std::string elemQualityToString(const libMesh::ElemQuality eq)
Definition MeshInfo.C:34
void dataStoreInfoBase(std::ostream &stream, T &info)
Data store and load for node, elem, sideset, subdomain info entries.
Definition MeshInfo.C:886
void dataLoadDomainInfo(std::istream &stream, T &info)
Definition MeshInfo.C:974
registerMooseObject("MooseApp", MeshInfo)
void dataStoreDomainInfo(std::ostream &stream, T &info)
Definition MeshInfo.C:918
void dataStoreElemContainingInfo(std::ostream &stream, T &info)
Definition MeshInfo.C:892
void dataLoadInfoBase(std::istream &stream, T &info)
Definition MeshInfo.C:942
void toJSONDomainInfoMap(nlohmann::json &json, const DomainInfoMapType &info_map)
Definition MeshInfo.C:790
void dataStore(std::ostream &, MeshInfo::DomainElemQuality &, void *)
Data store and load for DomainElemQuality.
Definition MeshInfo.C:861
void to_json(nlohmann::json &, const MeshInfo::ElemInfoMap &)
JSON serialization for info maps.
Definition MeshInfo.C:747
void dataLoad(std::istream &, MeshInfo::DomainElemQuality &, void *)
Definition MeshInfo.C:872
std::array< Real, 2 > values
Definition MortarUtils.C:52
const ReporterMode REPORTER_MODE_REPLICATED
const ReporterMode REPORTER_MODE_DISTRIBUTED
const ReporterMode REPORTER_MODE_ROOT
unsigned int dim
void ErrorVector unsigned int
Class used for caching additional information for elements such as the volume and centroid.
Definition ElemInfo.h:26
virtual MooseMesh & mesh() override
Reporter object that has a single execution of the "execute" method for each execute flag.
static InputParameters validParams()
The main MOOSE class responsible for handling user-defined parameters in almost every MOOSE system.
void addParam(const std::string &name, const S &value, const std::string &doc_string)
These methods add an optional parameter and a documentation string to the InputParameters object.
void addClassDescription(const std::string &doc_string)
This method adds a description of the class that will be displayed in the input file syntax dump.
Report mesh information, such as the number of elements, nodes, and degrees of freedom.
Definition MeshInfo.h:28
unsigned int *const _num_dofs_constrained
Definition MeshInfo.h:358
static bool hasItem(const std::string &name, const MultiMooseEnum &items)
Definition MeshInfo.C:698
unsigned int *const _num_local_dofs_aux
Definition MeshInfo.h:363
SidesetInfos _sideset_infos
Combined sideset information (reporter values and requested items)
Definition MeshInfo.h:371
unsigned int *const _num_dofs_aux
Definition MeshInfo.h:357
const libMesh::System & _aux_system
Definition MeshInfo.h:377
static InputParameters validParams()
Definition MeshInfo.C:40
MeshInfo(const InputParameters &parameters)
Definition MeshInfo.C:117
const MultiMooseEnum & _sideset_elem_qualities
The requested element quality metrics, bounded over sidesets.
Definition MeshInfo.h:324
const MultiMooseEnum & _elem_qualities
The requested element quality metrics.
Definition MeshInfo.h:322
unsigned int *const _num_local_node
Definition MeshInfo.h:365
BoundType
Type of a bound for DomainElemQuality (min or max).
Definition MeshInfo.h:38
const MultiMooseEnum & _sideset_items
The requested sideset items.
Definition MeshInfo.h:318
ElemInfos _elem_infos
Combined element information (reporter values and requested items)
Definition MeshInfo.h:369
static const std::vector< libMesh::ElemQuality > elem_qualities
The qualities to include for elems.
Definition MeshInfo.h:29
CombinedInfosType initCombinedInfos(const std::string &name, const MultiMooseEnum &items, const MultiMooseEnum &qualities)
Initializer for SidesetInfos and SubdomainInfos.
Definition MeshInfo.C:253
const MultiMooseEnum & _subdomain_elem_qualities
The requested element quality metrics, bounded over subdomains.
Definition MeshInfo.h:326
unsigned int *const _num_dofs
Reporter values to declare.
Definition MeshInfo.h:355
const libMesh::MeshBase & _mesh
Definition MeshInfo.h:378
const MultiMooseEnum & _items
The requested items.
Definition MeshInfo.h:314
unsigned int *const _num_local_dofs_nl
Definition MeshInfo.h:362
const MultiMooseEnum & _subdomain_items
The requested subdomain items.
Definition MeshInfo.h:320
const libMesh::EquationSystems & _equation_systems
Definition MeshInfo.h:375
virtual void execute() override
Execute method.
Definition MeshInfo.C:666
unsigned int *const _num_node
Definition MeshInfo.h:360
const libMesh::System & _nonlinear_system
Definition MeshInfo.h:376
unsigned int *const _num_elem
Definition MeshInfo.h:359
void possiblyAddElemInfo()
Add elem information if requested.
Definition MeshInfo.C:266
unsigned int *const _num_local_dofs
Definition MeshInfo.h:361
void possiblyAddDomainInfo(CombinedInfosType &infos)
Add domain information (sidesets and subdomains) if requested.
Definition MeshInfo.C:439
static const std::vector< DomainElemQuality > domain_elem_qualities
The qualities (ElemQuality and bound type) to include for domain quantities (subdomains and sidesets)
Definition MeshInfo.h:23
SubdomainInfos _subdomain_infos
Combined subdomain information (reporter values and requested items)
Definition MeshInfo.h:373
const MultiMooseEnum & _elem_items
The requested elem items.
Definition MeshInfo.h:316
unsigned int *const _num_local_elem
Definition MeshInfo.h:364
unsigned int *const _num_dofs_nl
Definition MeshInfo.h:356
const std::string & type() const
Get the type of this class.
Definition MooseBase.h:93
const std::string & name() const
Get the name of the class.
Definition MooseBase.h:103
void paramError(const std::string &param, Args... args) const
Emits an error prefixed with the file and line number of the given param (from the input file) along ...
Definition MooseBase.h:457
std::set< MooseEnumItem >::const_iterator find(const MooseEnumItem &other) const
Locate an item.
const std::set< MooseEnumItem > & items() const
Return the complete set of available flags.
This is a "smart" enum class intended to replace many of the shortcomings in the C++ enum type.
bool isValueSet(const std::string &value) const
Methods for seeing if a value is set in the MultiMooseEnum.
virtual bool isValid() const override
IsValid.
void set_union(T &data, const unsigned int root_id) const
void gather(const unsigned int root_id, const T &send_data, std::vector< T, A > &recv) const
FEProblemBase & _fe_problem
Reference to the FEProblemBase for this user object.
const std::string & get_sideset_name(boundary_id_type id) const
const std::set< boundary_id_type > & get_side_boundary_ids() const
static constexpr dof_id_type invalid_id
static constexpr unique_id_type invalid_unique_id
unsigned int n_systems() const
const T_sys & get_system(std::string_view name) const
std::size_t n_dofs() const
const BoundaryInfo & get_boundary_info() const
virtual dof_id_type n_elem() const=0
virtual dof_id_type n_nodes() const=0
dof_id_type n_local_elem() const
dof_id_type n_local_nodes() const
std::string & subdomain_name(subdomain_id_type id)
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
dof_id_type n_dofs() const
dof_id_type n_local_dofs() const
MeshBase & mesh
std::string toLower(std::string name)
Convert supplied string to lower case.
std::string stringJoin(const std::vector< std::string > &values, const std::string &separator=" ")
Concatenates value into a single string separated by separator.
MPI_Info info
Real value(unsigned n, unsigned alpha, unsigned beta, Real x)
void elem_types(const MeshBase &mesh, std::vector< ElemType > &et)
std::string enum_to_string(const T e)
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const ItemsType items
Which entries are to be output.
Definition MeshInfo.h:297
CombinedInfos(info_map_type *local, info_map_type *global, const ItemsType &items)
Definition MeshInfo.C:244
InfoMapType *const global
Global information.
Definition MeshInfo.h:295
InfoMapType *const local
Local information.
Definition MeshInfo.h:293
Key for a libMesh::ElemQuality quality type with a bound (min or max) to be used over an entire domai...
Definition MeshInfo.h:48
void updateValue(std::map< DomainElemQuality, Real > &quality_map, const Real value) const
Update the value in the quality map.
Definition MeshInfo.C:186
libMesh::ElemQuality & elemQuality()
Get the libMesh::ElemQuality entry.
Definition MeshInfo.h:54
BoundType & boundType()
Get the type of the bound (min or max)
Definition MeshInfo.h:60
std::string itemName() const
Get the name for this quality ([min,max]_[quality])
Definition MeshInfo.C:179
std::vector< DomainElemQuality > elem_qualities
Bounded (min, max) element quality metrics that should be output.
Definition MeshInfo.h:218
Structure for a single domain entry (sideset or subdomain).
Definition MeshInfo.h:118
Base struct for defining which items are to be output for a domain that contains elements (elems,...
Definition MeshInfo.h:188
std::vector< libMesh::ElemQuality > elem_qualities
Element qualities that should be output.
Definition MeshInfo.h:241
Structure for a single elem entry.
Definition MeshInfo.h:148
Struct that defines a domain (sideset or subdomain) map (id -> entities) and the items that should be...
Definition MeshInfo.h:253
ItemsType items
Which items are to be output.
Definition MeshInfo.h:264
map_type map
The underlying data.
Definition MeshInfo.h:262