LCOV - code coverage report
Current view: top level - src/userobjects - BooleanComboClusteringUserObject.C (source / functions) Hit Total Coverage
Test: neams-th-coe/cardinal: ddd5f2 Lines: 75 84 89.3 %
Date: 2026-06-07 19:35:24 Functions: 8 9 88.9 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #include "BooleanComboClusteringUserObject.h"
       2             : #include "ClusteringUserObjectBase.h"
       3             : 
       4             : registerMooseObject("CardinalApp", BooleanComboClusteringUserObject);
       5             : 
       6             : std::unordered_map<std::string, int> BooleanComboClusteringUserObject::_precedence{
       7             :     {"not", 3}, {"!", 3}, {"and", 2}, {"&&", 2}, {"or", 1}, {"||", 1}};
       8             : 
       9             : InputParameters
      10          33 : BooleanComboClusteringUserObject::validParams()
      11             : {
      12          33 :   InputParameters params = GeneralUserObject::validParams();
      13          66 :   params.addRequiredParam<ExtraElementIDName>("id_name", "extra_element_integer_id name");
      14          66 :   params.addRequiredParam<std::vector<std::string>>("expression",
      15             :                                                     "boolean logic operation expression");
      16          33 :   params.addClassDescription("Takes various heuristic user objects and applies a user defined "
      17             :                              "boolean logic operation on them.");
      18          33 :   return params;
      19           0 : }
      20             : 
      21          15 : BooleanComboClusteringUserObject::BooleanComboClusteringUserObject(
      22          15 :     const InputParameters & parameters)
      23             :   : GeneralUserObject(parameters),
      24          15 :     _id_name(getParam<ExtraElementIDName>("id_name")),
      25          30 :     _mesh(_fe_problem.mesh().getMesh())
      26             : {
      27          15 :   if (!_mesh.has_elem_integer(_id_name))
      28             :   {
      29           3 :     mooseWarning(_id_name,
      30             :                  " extra element integer is missing in the mesh."
      31             :                  " Adding extra element integer ",
      32             :                  _id_name);
      33           0 :     _mesh.add_elem_integer(_id_name);
      34             :   }
      35             : 
      36          12 :   _extra_integer_index = _mesh.get_elem_integer_index(_id_name);
      37          24 :   reversePolishNotation(getParam<std::vector<std::string>>("expression"));
      38          12 :   initializeUserObjects();
      39          12 : }
      40             : 
      41             : void
      42          12 : BooleanComboClusteringUserObject::initializeUserObjects()
      43             : {
      44             :   _clustering_user_objects.clear();
      45          36 :   for (const auto & token : _output_stack)
      46             :   {
      47           6 :     if (_precedence.count(token))
      48             :       // separate the user object names. If true that means token is an operator
      49           6 :       continue;
      50          36 :     const auto & uo = getUserObjectByName<ClusteringUserObjectBase>(token);
      51          18 :     _clustering_user_objects.insert(std::make_pair(token, &uo));
      52             :   }
      53          12 : }
      54             : 
      55             : bool
      56        8142 : BooleanComboClusteringUserObject::belongsToCluster(libMesh::Elem * base_element,
      57             :                                                    libMesh::Elem * neighbor_elem)
      58             : {
      59             :   // follow the reverse polish notation
      60        8142 :   std::stack<bool> result_stack;
      61             : 
      62       24300 :   for (const auto token : _output_stack)
      63             :   {
      64             :     // if token is an operator
      65       16158 :     if (token == "and" || token == "&&")
      66             :     {
      67        2160 :       bool rhs = result_stack.top();
      68             :       result_stack.pop();
      69        2160 :       bool lhs = result_stack.top();
      70             :       result_stack.pop();
      71        4320 :       result_stack.push(lhs && rhs);
      72             :     }
      73       13998 :     else if (token == "or" || token == "||")
      74             :     {
      75        1848 :       bool rhs = result_stack.top();
      76             :       result_stack.pop();
      77        1848 :       bool lhs = result_stack.top();
      78             :       result_stack.pop();
      79        3696 :       result_stack.push(lhs || rhs);
      80             :     }
      81       12150 :     else if (token == "not" || token == "!")
      82             :     {
      83           0 :       bool val = result_stack.top();
      84             :       result_stack.pop();
      85           0 :       result_stack.push(!val);
      86             :     }
      87             :     else
      88       24300 :       result_stack.push(_clustering_user_objects[token]->evaluate(base_element, neighbor_elem));
      89             :   }
      90        8142 :   return result_stack.top();
      91             : }
      92             : 
      93             : void
      94          24 : BooleanComboClusteringUserObject::findCluster()
      95             : {
      96          24 :   std::stack<libMesh::Elem *> neighbor_stack;
      97             : 
      98        4848 :   for (auto & elem : _mesh.active_element_ptr_range())
      99             :   {
     100        2400 :     if (elem->get_extra_integer(_extra_integer_index) != NOT_VISITED)
     101         192 :       continue;
     102             : 
     103        2208 :     int cluster_id = elem->id();
     104             :     neighbor_stack.push(elem);
     105             : 
     106        4608 :     while (!neighbor_stack.empty())
     107             :     {
     108        2400 :       libMesh::Elem * current_elem = neighbor_stack.top();
     109             :       neighbor_stack.pop();
     110             : 
     111       12000 :       for (unsigned int s = 0; s < current_elem->n_sides(); s++)
     112             :       {
     113        9600 :         libMesh::Elem * neighbor_elem = current_elem->neighbor_ptr(s);
     114        9600 :         if (neighbor_elem && neighbor_elem->active() &&
     115        8640 :             neighbor_elem->get_extra_integer(_extra_integer_index) == NOT_VISITED)
     116             :         {
     117        8142 :           if (belongsToCluster(current_elem, neighbor_elem))
     118             :           {
     119         192 :             elem->set_extra_integer(_extra_integer_index, cluster_id);
     120         192 :             neighbor_elem->set_extra_integer(_extra_integer_index, cluster_id);
     121             :             neighbor_stack.push(neighbor_elem);
     122             :           }
     123             :         }
     124             :       }
     125             :     }
     126          24 :   }
     127          24 : }
     128             : 
     129             : void
     130          24 : BooleanComboClusteringUserObject::resetExtraInteger()
     131             : {
     132        4848 :   for (auto & elem : _mesh.active_element_ptr_range())
     133        2424 :     elem->set_extra_integer(_extra_integer_index, NOT_VISITED);
     134          24 : }
     135             : 
     136             : void
     137          24 : BooleanComboClusteringUserObject::execute()
     138             : {
     139          24 :   resetExtraInteger();
     140          24 :   findCluster();
     141          24 : }
     142             : 
     143             : int
     144           0 : BooleanComboClusteringUserObject::getExtraIntegerScore(libMesh::Elem * elem) const
     145             : {
     146           0 :   return elem->get_extra_integer(_extra_integer_index);
     147             : }
     148             : 
     149             : void
     150          12 : BooleanComboClusteringUserObject::reversePolishNotation(const std::vector<std::string> & expression)
     151             : {
     152          12 :   std::stack<std::string> op_stack;
     153             : 
     154          48 :   for (const auto & token : expression)
     155             :   {
     156          36 :     if (token == _left_parenthesis)
     157             :       op_stack.push(token);
     158          30 :     else if (token == _right_parenthesis)
     159             :     {
     160          12 :       while (!op_stack.empty() && op_stack.top() != _left_parenthesis)
     161             :       {
     162           6 :         _output_stack.push_back(op_stack.top());
     163             :         op_stack.pop();
     164             :       }
     165           6 :       if (!op_stack.empty() && op_stack.top() == _left_parenthesis)
     166             :         op_stack.pop();
     167             :     }
     168             :     // operator handling based on _precedence
     169          24 :     else if (_precedence.find(token) != _precedence.end())
     170             :     {
     171             :       // if operation hasn't the least precedence
     172             :       // push back to the output stack
     173          12 :       while (!op_stack.empty() && _precedence.find(op_stack.top()) != _precedence.end() &&
     174           0 :              _precedence[op_stack.top()] >= _precedence[token])
     175             :       {
     176           0 :         _output_stack.push_back(op_stack.top());
     177             :         op_stack.pop();
     178             :       }
     179             :       op_stack.push(token);
     180             :     }
     181             :     else
     182          18 :       _output_stack.push_back(token);
     183             :   }
     184          12 :   while (!op_stack.empty())
     185             :   {
     186           0 :     _output_stack.push_back(op_stack.top());
     187             :     op_stack.pop();
     188             :   }
     189          12 : }

Generated by: LCOV version 1.14