LCOV - code coverage report
Current view: top level - src/postprocessors - BoundaryLinearFVFluxIntegral.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 61 77 79.2 %
Date: 2026-05-29 20:35:17 Functions: 4 5 80.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 "BoundaryLinearFVFluxIntegral.h"
      11             : #include "LinearFVBoundaryCondition.h"
      12             : #include "LinearFVFluxKernel.h"
      13             : #include <set>
      14             : 
      15             : registerMooseObject("MooseApp", BoundaryLinearFVFluxIntegral);
      16             : 
      17             : InputParameters
      18        3217 : BoundaryLinearFVFluxIntegral::validParams()
      19             : {
      20        3217 :   InputParameters params = SideIntegralPostprocessor::validParams();
      21       12868 :   params.addRequiredParam<std::vector<std::string>>(
      22             :       "linearfvkernels", "List of LinearFVFluxKernels whose boundary fluxes are integrated.");
      23        3217 :   params.addClassDescription(
      24             :       "Computes the side integral of selected LinearFVFluxKernel boundary flux contributions.");
      25        3217 :   return params;
      26           0 : }
      27             : 
      28          78 : BoundaryLinearFVFluxIntegral::BoundaryLinearFVFluxIntegral(const InputParameters & parameters)
      29             :   : SideIntegralPostprocessor(parameters),
      30          78 :     _kernel_names(getParam<std::vector<std::string>>("linearfvkernels")),
      31          78 :     _variable_number(0),
      32         156 :     _system_number(0)
      33             : {
      34          78 :   _qp_integration = false;
      35             : 
      36          78 :   if (_kernel_names.empty())
      37           0 :     paramError("linearfvkernels", "At least one kernel must be provided.");
      38          78 : }
      39             : 
      40             : void
      41          72 : BoundaryLinearFVFluxIntegral::initialSetup()
      42             : {
      43          72 :   SideIntegralPostprocessor::initialSetup();
      44             : 
      45             :   // Kernels are constructed after postprocessors, so we fetch them here.
      46          72 :   auto base_query = _fe_problem.theWarehouse()
      47         144 :                         .query()
      48          72 :                         .condition<AttribSystem>("LinearFVFluxKernel")
      49          72 :                         .condition<AttribThread>(_tid);
      50             : 
      51          72 :   _kernel_objects.clear();
      52         164 :   for (const auto & name : _kernel_names)
      53             :   {
      54          94 :     std::vector<LinearFVFluxKernel *> kernels;
      55          94 :     auto query = base_query.clone();
      56          94 :     query.condition<AttribName>(name).queryInto(kernels);
      57          94 :     if (kernels.empty())
      58           4 :       paramError("linearfvkernels",
      59             :                  "The given LinearFVFluxKernel with name '",
      60             :                  name,
      61             :                  "' was not found! This can be due to the kernel not existing in the "
      62             :                  "'LinearFVKernels' block or the kernel not inheriting from LinearFVFluxKernel.");
      63             : 
      64          92 :     _kernel_objects.push_back(kernels[0]);
      65          92 :   }
      66             : 
      67             :   // Cache shared variable metadata and verify all kernels act on that same variable.
      68          70 :   const auto & first_variable = _kernel_objects.front()->variable();
      69          70 :   _variable_name = first_variable.name();
      70          70 :   _variable_number = first_variable.number();
      71          70 :   _system_number = first_variable.sys().number();
      72             : 
      73         162 :   for (const auto kernel_ptr : _kernel_objects)
      74          92 :     if (kernel_ptr->variable().name() != _variable_name)
      75           0 :       paramError("linearfvkernels",
      76             :                  "All kernels in 'linearfvkernels' must act on the same variable name. The "
      77             :                  "kernel '",
      78           0 :                  kernel_ptr->name(),
      79             :                  "' acts on variable '",
      80           0 :                  kernel_ptr->variable().name(),
      81             :                  "', while the first kernel acts on variable '",
      82           0 :                  _variable_name,
      83             :                  "'.");
      84             : 
      85             :   // Postprocessors run initialSetup before variable-side BC caches are guaranteed ready,
      86             :   // so we resolve BCs directly from the warehouse.
      87          70 :   auto bc_query = _fe_problem.theWarehouse()
      88         140 :                       .query()
      89          70 :                       .condition<AttribSystem>("LinearFVBoundaryCondition")
      90          70 :                       .condition<AttribThread>(_tid)
      91          70 :                       .condition<AttribVar>(_variable_number)
      92          70 :                       .condition<AttribSysNum>(_system_number);
      93             : 
      94          70 :   _boundary_bcs.clear();
      95         140 :   for (const auto boundary_id : boundaryIDs())
      96             :   {
      97          70 :     std::vector<LinearFVBoundaryCondition *> bcs;
      98          70 :     auto bc_query_copy = bc_query;
      99          70 :     bc_query_copy.condition<AttribBoundaries>(std::set<BoundaryID>({boundary_id})).queryInto(bcs);
     100             : 
     101          70 :     if (bcs.empty())
     102           0 :       paramError("linearfvkernels",
     103             :                  "Variable '",
     104           0 :                  _variable_name,
     105             :                  "' does not have a LinearFVBoundaryCondition on boundary '",
     106           0 :                  _mesh.getBoundaryName(boundary_id),
     107             :                  "'.");
     108             : 
     109          70 :     if (bcs.size() > 1)
     110           0 :       paramError("linearfvkernels",
     111             :                  "Variable '",
     112           0 :                  _variable_name,
     113             :                  "' has multiple LinearFVBoundaryCondition objects on boundary '",
     114           0 :                  _mesh.getBoundaryName(boundary_id),
     115             :                  "', which is not currently supported.");
     116             : 
     117          70 :     _boundary_bcs.emplace(boundary_id, bcs[0]);
     118          70 :   }
     119          70 : }
     120             : 
     121             : Real
     122          42 : BoundaryLinearFVFluxIntegral::computeFaceInfoIntegral(const FaceInfo * const fi)
     123             : {
     124             :   mooseAssert(fi, "FaceInfo should not be null.");
     125             :   mooseAssert(fi->boundaryIDs().size() == 1, "Expected exactly one boundary per face.");
     126             : 
     127          42 :   const auto boundary_id = *fi->boundaryIDs().begin();
     128          42 :   const auto face_type = fi->faceType(std::make_pair(_variable_number, _system_number));
     129          42 :   if (face_type != FaceInfo::VarFaceNeighbors::ELEM &&
     130             :       face_type != FaceInfo::VarFaceNeighbors::NEIGHBOR)
     131           0 :     mooseError("Cannot compute boundary flux on boundary '",
     132           0 :                _mesh.getBoundaryName(boundary_id),
     133             :                "' because the variable face type is not boundary-only.");
     134             : 
     135          42 :   auto * const bc = libmesh_map_find(_boundary_bcs, boundary_id);
     136          42 :   bc->setupFaceData(fi, face_type);
     137             : 
     138          42 :   Real flux_value = 0.0;
     139          98 :   for (const auto kernel_ptr : _kernel_objects)
     140             :   {
     141          56 :     kernel_ptr->setupFaceData(fi);
     142             :     // SideIntegralPostprocessor multiplies by geometric factors, so we just do 1 here.
     143          56 :     kernel_ptr->setCurrentFaceArea(1.0);
     144          56 :     flux_value += kernel_ptr->computeBoundaryFlux(*bc);
     145             :   }
     146             : 
     147          42 :   return flux_value;
     148             : }
     149             : 
     150             : Real
     151           0 : BoundaryLinearFVFluxIntegral::computeQpIntegral()
     152             : {
     153           0 :   mooseError("We should never call this function.");
     154             : }

Generated by: LCOV version 1.14