LCOV - code coverage report
Current view: top level - src/reporters - MeshInfo.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 227 227 100.0 %
Date: 2025-07-17 01:28:37 Functions: 17 17 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : 
      16             : registerMooseObject("MooseApp", MeshInfo);
      17             : 
      18             : InputParameters
      19       14993 : MeshInfo::validParams()
      20             : {
      21       14993 :   InputParameters params = GeneralReporter::validParams();
      22       14993 :   params.addClassDescription(
      23             :       "Report mesh information, such as the number of elements, nodes, and degrees of freedom.");
      24             : 
      25             :   MultiMooseEnum items(
      26             :       "num_dofs num_dofs_nonlinear num_dofs_auxiliary num_elements num_nodes num_local_dofs "
      27             :       "num_local_dofs_nonlinear num_local_dofs_auxiliary num_local_elements num_local_nodes "
      28             :       "local_sidesets local_sideset_elems sidesets sideset_elems local_subdomains "
      29       14993 :       "local_subdomain_elems subdomains subdomain_elems");
      30       14993 :   params.addParam<MultiMooseEnum>(
      31             :       "items",
      32             :       items,
      33             :       "The iteration information to output, if nothing is provided everything will be output.");
      34             : 
      35       29986 :   return params;
      36       14993 : }
      37             : 
      38         340 : MeshInfo::MeshInfo(const InputParameters & parameters)
      39             :   : GeneralReporter(parameters),
      40         340 :     _items(getParam<MultiMooseEnum>("items")),
      41         340 :     _num_dofs(declareHelper<unsigned int>("num_dofs", REPORTER_MODE_REPLICATED)),
      42         340 :     _num_dofs_nl(declareHelper<unsigned int>("num_dofs_nonlinear", REPORTER_MODE_REPLICATED)),
      43         340 :     _num_dofs_aux(declareHelper<unsigned int>("num_dofs_auxiliary", REPORTER_MODE_REPLICATED)),
      44         340 :     _num_dofs_constrained(
      45         340 :         declareHelper<unsigned int>("num_dofs_constrained", REPORTER_MODE_REPLICATED)),
      46         340 :     _num_elem(declareHelper<unsigned int>("num_elements", REPORTER_MODE_REPLICATED)),
      47         340 :     _num_node(declareHelper<unsigned int>("num_nodes", REPORTER_MODE_REPLICATED)),
      48         340 :     _num_local_dofs(declareHelper<unsigned int>("num_local_dofs", REPORTER_MODE_DISTRIBUTED)),
      49         340 :     _num_local_dofs_nl(
      50         340 :         declareHelper<unsigned int>("num_dofs_local_nonlinear", REPORTER_MODE_DISTRIBUTED)),
      51         340 :     _num_local_dofs_aux(
      52         340 :         declareHelper<unsigned int>("num_dofs_local_auxiliary", REPORTER_MODE_DISTRIBUTED)),
      53         340 :     _num_local_elem(declareHelper<unsigned int>("num_local_elements", REPORTER_MODE_DISTRIBUTED)),
      54         340 :     _num_local_node(declareHelper<unsigned int>("num_local_nodes", REPORTER_MODE_DISTRIBUTED)),
      55             : 
      56         340 :     _local_sidesets(declareHelper<std::map<BoundaryID, SidesetInfo>>("local_sidesets",
      57             :                                                                      REPORTER_MODE_DISTRIBUTED)),
      58         340 :     _local_sideset_elems(declareHelper<std::map<BoundaryID, SidesetInfo>>(
      59             :         "local_sideset_elems", REPORTER_MODE_DISTRIBUTED)),
      60         340 :     _sidesets(declareHelper<std::map<BoundaryID, SidesetInfo>>("sidesets", REPORTER_MODE_ROOT)),
      61         340 :     _sideset_elems(
      62         340 :         declareHelper<std::map<BoundaryID, SidesetInfo>>("sideset_elems", REPORTER_MODE_ROOT)),
      63             : 
      64         340 :     _local_subdomains(declareHelper<std::map<SubdomainID, SubdomainInfo>>(
      65             :         "local_subdomains", REPORTER_MODE_DISTRIBUTED)),
      66         340 :     _local_subdomain_elems(declareHelper<std::map<SubdomainID, SubdomainInfo>>(
      67             :         "local_subdomain_elems", REPORTER_MODE_DISTRIBUTED)),
      68         340 :     _subdomains(
      69         340 :         declareHelper<std::map<SubdomainID, SubdomainInfo>>("subdomains", REPORTER_MODE_ROOT)),
      70         340 :     _subdomain_elems(
      71         340 :         declareHelper<std::map<SubdomainID, SubdomainInfo>>("subdomain_elems", REPORTER_MODE_ROOT)),
      72             : 
      73         340 :     _equation_systems(_fe_problem.es()),
      74         340 :     _nonlinear_system(_fe_problem.es().get_system("nl0")),
      75         340 :     _aux_system(_fe_problem.es().get_system("aux0")),
      76         680 :     _mesh(_fe_problem.mesh().getMesh())
      77             : {
      78         340 : }
      79             : 
      80             : void
      81         313 : MeshInfo::execute()
      82             : {
      83         313 :   _num_dofs_nl = _nonlinear_system.n_dofs();
      84         313 :   _num_dofs_aux = _aux_system.n_dofs();
      85         313 :   _num_dofs = _equation_systems.n_dofs();
      86         313 :   _num_dofs_constrained = 0;
      87         939 :   for (auto s : make_range(_equation_systems.n_systems()))
      88         626 :     _num_dofs_constrained += _equation_systems.get_system(s).n_constrained_dofs();
      89             : 
      90         313 :   _num_node = _mesh.n_nodes();
      91         313 :   _num_elem = _mesh.n_elem();
      92         313 :   _num_local_dofs_nl = _nonlinear_system.n_local_dofs();
      93         313 :   _num_local_dofs_aux = _aux_system.n_local_dofs();
      94         313 :   _num_local_dofs = _num_local_dofs_nl + _num_local_dofs_aux;
      95         313 :   _num_local_node = _mesh.n_local_nodes();
      96         313 :   _num_local_elem = _mesh.n_local_elem();
      97             : 
      98         313 :   possiblyAddSidesetInfo();
      99         313 :   possiblyAddSubdomainInfo();
     100         313 : }
     101             : 
     102             : void
     103         313 : MeshInfo::possiblyAddSidesetInfo()
     104             : {
     105             :   // Helper for adding the sideset names to a given map of sidesets
     106         281 :   auto add_sideset_names = [&](std::map<BoundaryID, SidesetInfo> & sidesets)
     107             :   {
     108        1061 :     for (auto & pair : sidesets)
     109         780 :       pair.second.name = _mesh.get_boundary_info().get_sideset_name(pair.second.id);
     110         281 :   };
     111             : 
     112             :   // Helper for sorting all of the sides in each sideset
     113         202 :   auto sort_sides = [](std::map<BoundaryID, SidesetInfo> & sidesets)
     114             :   {
     115         714 :     for (auto & pair : sidesets)
     116         512 :       std::sort(pair.second.sides.begin(), pair.second.sides.end());
     117         202 :   };
     118             : 
     119         313 :   const bool include_all = !_items.isValid();
     120             : 
     121         578 :   if (include_all || _items.isValueSet("local_sidesets") ||
     122         578 :       _items.isValueSet("local_sideset_elems") || _items.isValueSet("sideset_elems"))
     123             :   {
     124         154 :     _local_sidesets.clear();
     125         154 :     _local_sideset_elems.clear();
     126         154 :     _sideset_elems.clear();
     127             : 
     128             :     // Fill the local sideset information; all cases need it
     129         154 :     std::map<BoundaryID, SidesetInfo> sidesets;
     130         154 :     for (const auto & bnd_elem :
     131        5036 :          as_range(_fe_problem.mesh().bndElemsBegin(), _fe_problem.mesh().bndElemsEnd()))
     132        2364 :       if (bnd_elem->_elem->processor_id() == processor_id())
     133             :       {
     134        1548 :         auto & entry = sidesets[bnd_elem->_bnd_id];
     135        1548 :         entry.id = bnd_elem->_bnd_id;
     136        1548 :         entry.sides.emplace_back(bnd_elem->_elem->id(), bnd_elem->_side);
     137         154 :       }
     138             : 
     139             :     // For local sidesets: copy over the local info, remove the sides, and add the names
     140         154 :     if (include_all || _items.isValueSet("local_sidesets"))
     141             :     {
     142             :       // Copy over the local sideset info, remove the sides, and add the names
     143          48 :       _local_sidesets = sidesets;
     144         192 :       for (auto & pair : _local_sidesets)
     145         144 :         pair.second.sides.clear();
     146          48 :       add_sideset_names(_local_sidesets);
     147             :     }
     148             : 
     149             :     // For local sideset elems: copy over the local info, and add the names
     150         154 :     if (include_all || _items.isValueSet("local_sideset_elems"))
     151             :     {
     152          48 :       _local_sideset_elems = sidesets;
     153          48 :       sort_sides(_local_sideset_elems);
     154          48 :       add_sideset_names(_local_sideset_elems);
     155             :     }
     156             : 
     157             :     // For the global sideset elems, we need to communicate all of the elems
     158         154 :     if (include_all || _items.isValueSet("sideset_elems"))
     159             :     {
     160             :       // Set up a structure for sending each (id, elem id, side) tuple to root
     161             :       std::map<processor_id_type,
     162             :                std::vector<std::tuple<boundary_id_type, dof_id_type, unsigned int>>>
     163         154 :           send_info;
     164         154 :       auto & root_info = send_info[0];
     165         622 :       for (const auto & pair : sidesets)
     166        2016 :         for (const auto & side : pair.second.sides)
     167        1548 :           root_info.emplace_back(pair.second.id, side.first, side.second);
     168             : 
     169             :       // Take the received information and insert it into _sideset_elems
     170             :       auto accumulate_info =
     171         154 :           [this](processor_id_type,
     172        1548 :                  const std::vector<std::tuple<boundary_id_type, dof_id_type, unsigned int>> & info)
     173             :       {
     174        1702 :         for (const auto & tuple : info)
     175             :         {
     176        1548 :           const auto id = std::get<0>(tuple);
     177        1548 :           auto & entry = _sideset_elems[id];
     178        1548 :           entry.id = id;
     179        1548 :           entry.sides.emplace_back(std::get<1>(tuple), std::get<2>(tuple));
     180             :         }
     181         154 :       };
     182             : 
     183             :       // Push the information and insert it into _sideset_elems on root
     184         154 :       Parallel::push_parallel_vector_data(comm(), send_info, accumulate_info);
     185             : 
     186         154 :       sort_sides(_sideset_elems);
     187         154 :       add_sideset_names(_sideset_elems);
     188         154 :     }
     189         154 :   }
     190             : 
     191             :   // For global sideset information without elements, we can simplify communication.
     192             :   // All we need are the boundary IDs from libMesh (may not be reduced, so take the union)
     193             :   // and then add the names (global)
     194         313 :   if (include_all || _items.isValueSet("sidesets"))
     195             :   {
     196          57 :     _sidesets.clear();
     197             : 
     198          57 :     auto boundary_ids = _mesh.get_boundary_info().get_boundary_ids();
     199          57 :     comm().set_union(boundary_ids, 0);
     200          57 :     if (processor_id() == 0)
     201             :     {
     202         155 :       for (const auto id : boundary_ids)
     203         124 :         _sidesets[id].id = id;
     204          31 :       add_sideset_names(_sidesets);
     205             :     }
     206          57 :   }
     207         313 : }
     208             : 
     209             : void
     210         424 : to_json(nlohmann::json & json, const std::map<BoundaryID, MeshInfo::SidesetInfo> & sidesets)
     211             : {
     212        1156 :   for (const auto & pair : sidesets)
     213             :   {
     214         732 :     const MeshInfo::SidesetInfo & sideset_info = pair.second;
     215             : 
     216         732 :     nlohmann::json sideset_json;
     217         732 :     sideset_json["id"] = sideset_info.id;
     218         732 :     if (sideset_info.name.size())
     219         732 :       sideset_json["name"] = sideset_info.name;
     220         732 :     if (sideset_info.sides.size())
     221             :     {
     222         488 :       auto & sides_json = sideset_json["sides"];
     223             : 
     224        2836 :       for (const std::pair<dof_id_type, unsigned int> & pair : sideset_info.sides)
     225             :       {
     226        2348 :         nlohmann::json side_json;
     227        2348 :         side_json["elem_id"] = pair.first;
     228        2348 :         side_json["side"] = pair.second;
     229        2348 :         sides_json.push_back(side_json);
     230        2348 :       }
     231             :     }
     232             : 
     233         732 :     json.push_back(sideset_json);
     234         732 :   }
     235         424 : }
     236             : 
     237             : void
     238          95 : dataStore(std::ostream & stream, MeshInfo::SidesetInfo & sideset_info, void * context)
     239             : {
     240          95 :   storeHelper(stream, sideset_info.id, context);
     241          95 :   storeHelper(stream, sideset_info.name, context);
     242          95 :   storeHelper(stream, sideset_info.sides, context);
     243          95 : }
     244             : 
     245             : void
     246          95 : dataLoad(std::istream & stream, MeshInfo::SidesetInfo & sideset_info, void * context)
     247             : {
     248          95 :   loadHelper(stream, sideset_info.id, context);
     249          95 :   loadHelper(stream, sideset_info.name, context);
     250          95 :   loadHelper(stream, sideset_info.sides, context);
     251          95 : }
     252             : 
     253             : void
     254         313 : MeshInfo::possiblyAddSubdomainInfo()
     255             : {
     256             :   // Helper for adding the subdomain names to a given map of subdomains
     257         215 :   auto add_subdomain_names = [&](std::map<SubdomainID, SubdomainInfo> & subdomains)
     258             :   {
     259         613 :     for (auto & pair : subdomains)
     260         398 :       pair.second.name = _mesh.subdomain_name(pair.second.id);
     261         215 :   };
     262             : 
     263             :   // Helper for sorting all of the elems in each subdomain
     264         136 :   auto sort_elems = [](std::map<SubdomainID, SubdomainInfo> & subdomains)
     265             :   {
     266         448 :     for (auto & pair : subdomains)
     267         312 :       std::sort(pair.second.elems.begin(), pair.second.elems.end());
     268         136 :   };
     269             : 
     270         313 :   const bool include_all = !_items.isValid();
     271             : 
     272         578 :   if (include_all || _items.isValueSet("local_subdomains") ||
     273         578 :       _items.isValueSet("local_subdomain_elems") || _items.isValueSet("subdomain_elems"))
     274             :   {
     275         136 :     _local_subdomains.clear();
     276         136 :     _local_subdomain_elems.clear();
     277         136 :     _subdomain_elems.clear();
     278             : 
     279             :     // Fill the local subdomain information; all cases need it
     280         136 :     std::map<SubdomainID, SubdomainInfo> subdomains;
     281        3560 :     for (const auto & elem : *_fe_problem.mesh().getActiveLocalElementRange())
     282             :     {
     283        3424 :       auto & entry = subdomains[elem->subdomain_id()];
     284        3424 :       entry.id = elem->subdomain_id();
     285        3424 :       entry.elems.push_back(elem->id());
     286             :     }
     287             : 
     288             :     // For local subdomains: copy over the local info, remove the elems, and add the names
     289         136 :     if (include_all || _items.isValueSet("local_subdomains"))
     290             :     {
     291          48 :       _local_subdomains = subdomains;
     292          96 :       for (auto & pair : _local_subdomains)
     293          48 :         pair.second.elems.clear();
     294          48 :       add_subdomain_names(_local_subdomains);
     295             :     }
     296             : 
     297             :     // For local subdomain elems: copy over the local info, and add the names
     298         136 :     if (include_all || _items.isValueSet("local_subdomain_elems"))
     299             :     {
     300          48 :       _local_subdomain_elems = subdomains;
     301          48 :       sort_elems(_local_subdomain_elems);
     302          48 :       add_subdomain_names(_local_subdomain_elems);
     303             :     }
     304             : 
     305             :     // For the global subdomain elems, we need to communicate all of the elems
     306         136 :     if (include_all || _items.isValueSet("subdomain_elems"))
     307             :     {
     308             :       // Set up a structure for sending each (id, elem id) to root
     309         136 :       std::map<processor_id_type, std::vector<std::pair<subdomain_id_type, dof_id_type>>> send_info;
     310         136 :       auto & root_info = send_info[0];
     311         430 :       for (const auto & pair : subdomains)
     312        3718 :         for (const auto elem_id : pair.second.elems)
     313        3424 :           root_info.emplace_back(pair.second.id, elem_id);
     314             : 
     315             :       // Take the received information and insert it into _subdomain_elems
     316             :       auto accumulate_info =
     317         136 :           [this](processor_id_type,
     318        3424 :                  const std::vector<std::pair<subdomain_id_type, dof_id_type>> & info)
     319             :       {
     320        3560 :         for (const auto & subdomain_elem_pair : info)
     321             :         {
     322        3424 :           auto & entry = _subdomain_elems[subdomain_elem_pair.first];
     323        3424 :           entry.id = subdomain_elem_pair.first;
     324        3424 :           entry.elems.emplace_back(subdomain_elem_pair.second);
     325             :         }
     326         136 :       };
     327             : 
     328             :       // Push the information and insert it into _subdomain_elems on root
     329         136 :       Parallel::push_parallel_vector_data(comm(), send_info, accumulate_info);
     330             : 
     331         136 :       if (processor_id() == 0)
     332             :       {
     333          88 :         sort_elems(_subdomain_elems);
     334          88 :         add_subdomain_names(_subdomain_elems);
     335             :       }
     336         136 :     }
     337         136 :   }
     338             : 
     339             :   // For global subdomain information without elements, we can simplify communication.
     340             :   // All we need are the subdomain IDs from libMesh and then add the names (global)
     341         313 :   if (include_all || _items.isValueSet("subdomains"))
     342             :   {
     343          57 :     _subdomains.clear();
     344             : 
     345          57 :     std::set<subdomain_id_type> subdomain_ids;
     346          57 :     _mesh.subdomain_ids(subdomain_ids);
     347             : 
     348          57 :     if (processor_id() == 0)
     349             :     {
     350          69 :       for (const auto id : subdomain_ids)
     351          38 :         _subdomains[id].id = id;
     352          31 :       add_subdomain_names(_subdomains);
     353             :     }
     354          57 :   }
     355         313 : }
     356             : 
     357             : void
     358         398 : to_json(nlohmann::json & json, const std::map<SubdomainID, MeshInfo::SubdomainInfo> & subdomains)
     359             : {
     360         780 :   for (const auto & pair : subdomains)
     361             :   {
     362         382 :     const MeshInfo::SubdomainInfo & subdomain_info = pair.second;
     363             : 
     364         382 :     nlohmann::json subdomain_json;
     365         382 :     subdomain_json["id"] = subdomain_info.id;
     366         382 :     if (subdomain_info.name.size())
     367         254 :       subdomain_json["name"] = subdomain_info.name;
     368         382 :     if (subdomain_info.elems.size())
     369             :     {
     370         304 :       auto & sides_json = subdomain_json["elems"];
     371        5728 :       for (const auto & id : subdomain_info.elems)
     372        5424 :         sides_json.push_back(id);
     373             :     }
     374             : 
     375         382 :     json.push_back(subdomain_json);
     376         382 :   }
     377         398 : }
     378             : 
     379             : void
     380          50 : dataStore(std::ostream & stream, MeshInfo::SubdomainInfo & subdomain_info, void * context)
     381             : {
     382          50 :   storeHelper(stream, subdomain_info.id, context);
     383          50 :   storeHelper(stream, subdomain_info.name, context);
     384          50 :   storeHelper(stream, subdomain_info.elems, context);
     385          50 : }
     386             : 
     387             : void
     388          50 : dataLoad(std::istream & stream, MeshInfo::SubdomainInfo & subdomain_info, void * context)
     389             : {
     390          50 :   loadHelper(stream, subdomain_info.id, context);
     391          50 :   loadHelper(stream, subdomain_info.name, context);
     392          50 :   loadHelper(stream, subdomain_info.elems, context);
     393          50 : }

Generated by: LCOV version 1.14