LCOV - code coverage report
Current view: top level - src/loops - ComputeLinearFVLimitedGradientThread.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 98 121 81.0 %
Date: 2026-05-29 20:35:17 Functions: 2 4 50.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 "ComputeLinearFVLimitedGradientThread.h"
      11             : 
      12             : #include "GradientLimiterType.h"
      13             : #include "SystemBase.h"
      14             : #include "PetscVectorReader.h"
      15             : #include "FEProblemBase.h"
      16             : #include "FVUtils.h"
      17             : 
      18             : #include "libmesh/dof_object.h"
      19             : 
      20             : #include <algorithm>
      21             : #include <cmath>
      22             : #include <limits>
      23             : 
      24       11870 : ComputeLinearFVLimitedGradientThread::ComputeLinearFVLimitedGradientThread(
      25             :     FEProblemBase & fe_problem,
      26             :     SystemBase & system,
      27             :     const std::vector<std::unique_ptr<NumericVector<Number>>> & raw_gradient,
      28             :     std::vector<std::unique_ptr<NumericVector<Number>>> & temporary_limited_gradient,
      29             :     const Moose::FV::GradientLimiterType limiter_type,
      30       11870 :     const std::unordered_set<unsigned int> & requested_variables)
      31       11870 :   : _fe_problem(fe_problem),
      32       11870 :     _dim(_fe_problem.mesh().dimension()),
      33       11870 :     _system(system),
      34       11870 :     _libmesh_system(system.system()),
      35       11870 :     _system_number(_libmesh_system.number()),
      36       11870 :     _raw_gradient(raw_gradient),
      37       11870 :     _limiter_type(limiter_type),
      38       11870 :     _requested_variables(requested_variables),
      39       11870 :     _temporary_limited_gradient(temporary_limited_gradient)
      40             : {
      41       11870 : }
      42             : 
      43           0 : ComputeLinearFVLimitedGradientThread::ComputeLinearFVLimitedGradientThread(
      44           0 :     ComputeLinearFVLimitedGradientThread & x, Threads::split /*split*/)
      45           0 :   : _fe_problem(x._fe_problem),
      46           0 :     _dim(x._dim),
      47           0 :     _system(x._system),
      48           0 :     _libmesh_system(x._libmesh_system),
      49           0 :     _system_number(x._system_number),
      50           0 :     _raw_gradient(x._raw_gradient),
      51           0 :     _limiter_type(x._limiter_type),
      52           0 :     _requested_variables(x._requested_variables),
      53           0 :     _temporary_limited_gradient(x._temporary_limited_gradient)
      54             : {
      55           0 : }
      56             : 
      57             : void
      58       11870 : ComputeLinearFVLimitedGradientThread::operator()(const ElemInfoRange & range)
      59             : {
      60       11870 :   ParallelUniqueId puid;
      61       11870 :   _tid = puid.id;
      62             : 
      63       11870 :   const auto & raw_grad_container = _raw_gradient;
      64             : 
      65       11870 :   if (_limiter_type != Moose::FV::GradientLimiterType::Venkatakrishnan)
      66           0 :     mooseError("ComputeLinearFVLimitedGradientThread currently supports only the Venkatakrishnan "
      67             :                "limiter.");
      68             : 
      69       11870 :   unsigned int size = 0;
      70             : 
      71       23740 :   for (const auto & variable : _system.getVariables(_tid))
      72             :   {
      73       11870 :     _current_var = dynamic_cast<MooseLinearVariableFV<Real> *>(variable);
      74       11870 :     if (!_current_var)
      75           0 :       continue;
      76             : 
      77       11870 :     if (!_current_var->needsGradientVectorStorage())
      78           0 :       continue;
      79             : 
      80       11870 :     if (!_requested_variables.count(_current_var->number()))
      81           0 :       continue;
      82             : 
      83       11870 :     if (!size)
      84       11870 :       size = range.size();
      85             : 
      86       11870 :     std::vector<std::vector<Real>> temporary_values(_temporary_limited_gradient.size(),
      87       11870 :                                                     std::vector<Real>(size, 0.0));
      88       11870 :     std::vector<dof_id_type> dof_indices(size, 0);
      89             : 
      90       11870 :     PetscVectorReader solution_reader(*_libmesh_system.current_local_solution);
      91       11870 :     std::vector<PetscVectorReader> grad_reader;
      92       11870 :     grad_reader.reserve(raw_grad_container.size());
      93       32580 :     for (const auto dim_index : index_range(raw_grad_container))
      94       20710 :       grad_reader.emplace_back(*raw_grad_container[dim_index]);
      95             : 
      96             :     mooseAssert(raw_grad_container.size() >= _dim,
      97             :                 "Raw gradient container has fewer components than mesh dimension.");
      98             :     mooseAssert(_temporary_limited_gradient.size() >= _dim,
      99             :                 "Limited gradient container has fewer components than mesh dimension.");
     100             : 
     101       11870 :     auto elem_iterator = range.begin();
     102    16459982 :     for (const auto elem_i : make_range(size))
     103             :     {
     104    16448112 :       const auto & elem_info = *elem_iterator;
     105    16448112 :       elem_iterator++;
     106             : 
     107    16448112 :       if (!_current_var->hasBlocks(elem_info->subdomain_id()))
     108     1010592 :         continue;
     109             : 
     110    16448112 :       const dof_id_type dof = elem_info->dofIndices()[_system_number][_current_var->number()];
     111    16448112 :       if (dof == libMesh::DofObject::invalid_id)
     112           0 :         continue;
     113             : 
     114    16448112 :       dof_indices[elem_i] = dof;
     115             : 
     116    16448112 :       const Real phi_elem = solution_reader(dof);
     117    16448112 :       Real max_value = phi_elem;
     118    16448112 :       Real min_value = phi_elem;
     119             : 
     120             :       // Gather one-ring min/max values.
     121    16448112 :       const Elem * const elem = elem_info->elem();
     122    73216896 :       for (const auto side : make_range(elem->n_sides()))
     123             :       {
     124    56768784 :         const Elem * const neighbor = elem->neighbor_ptr(side);
     125    56768784 :         if (!neighbor)
     126      735804 :           continue;
     127             : 
     128    56032980 :         const auto & neighbor_info = _fe_problem.mesh().elemInfo(neighbor->id());
     129    56032980 :         if (!_current_var->hasBlocks(neighbor_info.subdomain_id()))
     130           0 :           continue;
     131             : 
     132             :         const dof_id_type neighbor_dof =
     133    56032980 :             neighbor_info.dofIndices()[_system_number][_current_var->number()];
     134    56032980 :         if (neighbor_dof == libMesh::DofObject::invalid_id)
     135           0 :           continue;
     136             : 
     137    56032980 :         const Real phi_neighbor = solution_reader(neighbor_dof);
     138    56032980 :         max_value = std::max(max_value, phi_neighbor);
     139    56032980 :         min_value = std::min(min_value, phi_neighbor);
     140             :       }
     141             : 
     142             :       // Read the raw cell gradient.
     143    16448112 :       VectorValue<Real> raw_grad;
     144    16448112 :       raw_grad.zero();
     145    49306764 :       for (const auto dim_index : make_range(_dim))
     146    32858652 :         raw_grad(dim_index) = grad_reader[dim_index](dof);
     147             : 
     148             :       // If the stencil is constant (or nearly constant), don't attempt to limit.
     149    16448112 :       if (std::abs(max_value - min_value) < 1e-14)
     150             :       {
     151     3031590 :         for (const auto dim_index : make_range(_dim))
     152     2020998 :           temporary_values[dim_index][elem_i] = raw_grad(dim_index);
     153     1010592 :         continue;
     154     1010592 :       }
     155             : 
     156    15437520 :       Real alpha = 1.0;
     157    15437520 :       const Point & elem_centroid = elem_info->centroid();
     158             : 
     159    69076382 :       for (const auto side : make_range(elem->n_sides()))
     160             :       {
     161    53638862 :         const Elem * const neighbor = elem->neighbor_ptr(side);
     162    53638862 :         if (!neighbor)
     163      670203 :           continue;
     164             : 
     165    52968659 :         const auto & neighbor_info = _fe_problem.mesh().elemInfo(neighbor->id());
     166    52968659 :         if (!_current_var->hasBlocks(neighbor_info.subdomain_id()))
     167           0 :           continue;
     168             : 
     169             :         const dof_id_type neighbor_dof =
     170    52968659 :             neighbor_info.dofIndices()[_system_number][_current_var->number()];
     171    52968659 :         if (neighbor_dof == libMesh::DofObject::invalid_id)
     172           0 :           continue;
     173             : 
     174    52968659 :         const bool elem_has_face_info = Moose::FV::elemHasFaceInfo(*elem, neighbor);
     175    52968659 :         const Elem * const fi_elem = elem_has_face_info ? elem : neighbor;
     176             :         const unsigned int fi_side =
     177    52968659 :             elem_has_face_info ? side : neighbor->which_neighbor_am_i(elem);
     178    52968659 :         const auto * fi = _fe_problem.mesh().faceInfo(fi_elem, fi_side);
     179             :         mooseAssert(fi,
     180             :                     "Missing FaceInfo for neighboring elements with centroid " +
     181             :                         Moose::stringify(elem_info->centroid()) + " and " +
     182             :                         Moose::stringify(neighbor->vertex_average()) +
     183             :                         " while computing limited gradients.");
     184             : 
     185    52968659 :         const Point face_point = fi->faceCentroid();
     186             : 
     187    52968659 :         const Real delta_face = raw_grad * (face_point - elem_centroid);
     188             : 
     189    52968659 :         Real h = elem->hmin();
     190    52968659 :         Real grad_mag = raw_grad.norm();
     191             : 
     192    52968659 :         Real eps = 0.1 * (grad_mag * h) * (grad_mag * h) + 1e-20;
     193             : 
     194    52968659 :         const Real delta_max = std::abs(max_value - phi_elem) + eps;
     195    52968659 :         const Real delta_min = std::abs(min_value - phi_elem) + eps;
     196             : 
     197    79652239 :         const Real rf = (delta_face >= 0.0) ? std::abs(delta_face) / delta_max
     198    26683580 :                                             : std::abs(delta_face) / delta_min;
     199             : 
     200    52968659 :         const Real beta = (2.0 * rf + 1.0) / (rf * (2.0 * rf + 1.0) + 1.0);
     201    52968659 :         alpha = std::min(alpha, beta);
     202             :       }
     203             : 
     204    15437520 :       const VectorValue<Real> limited_grad = alpha * raw_grad;
     205    46275174 :       for (const auto dim_index : make_range(_dim))
     206    30837654 :         temporary_values[dim_index][elem_i] = limited_grad(dim_index);
     207             :     }
     208             : 
     209       32580 :     for (const auto dim_index : make_range(_dim))
     210             :     {
     211       20710 :       _temporary_limited_gradient[dim_index]->add_vector(temporary_values[dim_index].data(),
     212             :                                                          dof_indices);
     213             :     }
     214       11870 :   }
     215       11870 : }
     216             : 
     217             : void
     218           0 : ComputeLinearFVLimitedGradientThread::join(const ComputeLinearFVLimitedGradientThread & /*y*/)
     219             : {
     220           0 : }

Generated by: LCOV version 1.14