LCOV - code coverage report
Current view: top level - include/problems - SubChannel1PhaseProblem.h (source / functions) Hit Total Coverage
Test: idaholab/moose subchannel: #31782 (615931) with base 7edd10 Lines: 50 52 96.2 %
Date: 2025-11-11 23:27:16 Functions: 7 7 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             : #pragma once
      11             : #include "ExternalProblem.h"
      12             : #include "PostprocessorInterface.h"
      13             : #include "SubChannelApp.h"
      14             : #include "QuadSubChannelMesh.h"
      15             : #include "SolutionHandle.h"
      16             : #include "SinglePhaseFluidProperties.h"
      17             : #include <petscdm.h>
      18             : #include <petscdmda.h>
      19             : #include <petscksp.h>
      20             : #include <petscsys.h>
      21             : #include <petscvec.h>
      22             : #include <petscsnes.h>
      23             : 
      24             : /**
      25             :  * Base class for the 1-phase steady-state/transient subchannel solver.
      26             :  */
      27             : class SubChannel1PhaseProblem : public ExternalProblem, public PostprocessorInterface
      28             : {
      29             : public:
      30             :   SubChannel1PhaseProblem(const InputParameters & params);
      31             :   virtual ~SubChannel1PhaseProblem();
      32             : 
      33             :   virtual void externalSolve() override;
      34             :   virtual void syncSolutions(Direction direction) override;
      35             :   virtual bool solverSystemConverged(const unsigned int) override;
      36             :   virtual void initialSetup() override;
      37             : 
      38             :   /// Function that computes the added heat coming from the fuel pins, for channel i_ch and cell iz
      39             :   virtual Real computeAddedHeatPin(unsigned int i_ch, unsigned int iz) = 0;
      40             :   /// Function that computes the heat added by the duct, for channel i_ch and cell iz
      41             :   Real computeAddedHeatDuct(unsigned int i_ch, unsigned int iz);
      42             : 
      43             : protected:
      44             :   struct FrictionStruct
      45             :   {
      46             :     int i_ch;
      47             :     Real Re, S, w_perim;
      48             :   } _friction_args;
      49             : 
      50             :   /// Returns friction factor
      51             :   virtual Real computeFrictionFactor(FrictionStruct friction_args) = 0;
      52             : 
      53      424240 :   struct NusseltStruct
      54             :   {
      55             :     Real Re, Pr;
      56             :     unsigned int i_pin, iz, i_ch;
      57             :     MooseEnum htc_correlation;
      58             :     // parameterized constructor
      59             :     NusseltStruct(Real Re_,
      60             :                   Real Pr_,
      61             :                   unsigned int i_pin_,
      62             :                   unsigned int iz_,
      63             :                   unsigned int i_ch_,
      64             :                   const MooseEnum & htc_corr)
      65      424240 :       : Re(Re_), Pr(Pr_), i_pin(i_pin_), iz(iz_), i_ch(i_ch_), htc_correlation(htc_corr)
      66             :     {
      67       17220 :     }
      68             :   };
      69             : 
      70             :   /// The correlation used for computing the heat transfer correlation near the pin
      71             :   const MooseEnum _pin_htc_correlation;
      72             :   /// The correlation used for computing the heat transfer correlation near the duct
      73             :   const MooseEnum _duct_htc_correlation;
      74             :   NusseltStruct _nusselt_args;
      75             : 
      76             :   /// Function that computes the Nusselt number given a heat exchange correlation
      77             :   Real computeNusseltNumber(const NusseltStruct & nusselt_args);
      78             : 
      79             :   /// Computes diversion crossflow per gap for block iblock
      80             :   void computeWijFromSolve(int iblock);
      81             :   /// Computes net diversion crossflow per channel for block iblock
      82             :   void computeSumWij(int iblock);
      83             :   /// Computes mass flow per channel for block iblock
      84             :   void computeMdot(int iblock);
      85             :   /// Computes turbulent crossflow per gap for block iblock
      86             :   void computeWijPrime(int iblock);
      87             :   /// Computes turbulent mixing coefficient
      88             :   virtual Real computeBeta(unsigned int i_gap, unsigned int iz, bool enthalpy) = 0;
      89             :   /// Computes Pressure Drop per channel for block iblock
      90             :   void computeDP(int iblock);
      91             :   /// Computes Pressure per channel for block iblock
      92             :   void computeP(int iblock);
      93             :   /// Computes Enthalpy per channel for block iblock
      94             :   virtual void computeh(int iblock) = 0;
      95             :   /// Computes Temperature per channel for block iblock
      96             :   void computeT(int iblock);
      97             :   /// Computes Density per channel for block iblock
      98             :   void computeRho(int iblock);
      99             :   /// Computes Viscosity per channel for block iblock
     100             :   void computeMu(int iblock);
     101             :   /// Computes Residual Matrix based on the lateral momentum conservation equation for block iblock
     102             :   void computeWijResidual(int iblock);
     103             :   /// Function that computes the width of the duct cell that the peripheral subchannel i_ch sees
     104             :   virtual Real getSubChannelPeripheralDuctWidth(unsigned int i_ch) = 0;
     105             :   /// Computes Residual Vector based on the lateral momentum conservation equation for block iblock & updates flow variables based on current crossflow solution
     106             :   libMesh::DenseVector<Real> residualFunction(int iblock, libMesh::DenseVector<Real> solution);
     107             :   /// Computes solution of nonlinear equation using snes and provided a residual in a formFunction
     108             :   PetscErrorCode petscSnesSolver(int iblock,
     109             :                                  const libMesh::DenseVector<Real> & solution,
     110             :                                  libMesh::DenseVector<Real> & root);
     111             :   /// This is the residual Vector function in a form compatible with the SNES PETC solvers
     112             :   friend PetscErrorCode formFunction(SNES snes, Vec x, Vec f, void * ctx);
     113             : 
     114             :   /// Computes implicit solve using PetSc
     115             :   PetscErrorCode implicitPetscSolve(int iblock);
     116             : 
     117             :   /// Function to initialize the solution & geometry fields
     118             :   virtual void initializeSolution() = 0;
     119             : 
     120             :   /// Functions that computes the interpolation scheme given the Peclet number
     121             :   PetscScalar computeInterpolationCoefficients(PetscScalar Peclet = 0.0);
     122             :   PetscScalar
     123             :   computeInterpolatedValue(PetscScalar topValue, PetscScalar botValue, PetscScalar Peclet = 0.0);
     124             : 
     125             :   /// inline function that is used to define the gravity direction
     126         372 :   Real computeGravityDir(const MooseEnum & dir) const
     127             :   {
     128             :     switch (dir)
     129             :     {
     130             :       case 0: // counter_flow
     131             :         return 1.0;
     132             :       case 1: // co_flow
     133             :         return -1.0;
     134             :       case 2: // none
     135             :         return 0.0;
     136           0 :       default:
     137           0 :         mooseError(name(), ": Invalid gravity direction: expected counter_flow, co_flow, or none");
     138             :     }
     139             :   }
     140             : 
     141             :   /**
     142             :    * Solve a linear system (A * x = rhs) with a simple PCJACOBI KSP and populate the
     143             :    * enthalpy solution into _h_soln for nodes [first_node, last_node].
     144             :    *
     145             :    * Uses member tolerances (_rtol, _atol, _dtol, _maxit), mesh (_subchannel_mesh),
     146             :    * channel count (_n_channels), and error/solution handles (mooseError, _h_soln).
     147             :    *
     148             :    * @param A            PETSc matrix (operators)
     149             :    * @param rhs          PETSc vector (right-hand side)
     150             :    * @param first_node   inclusive start axial node index
     151             :    * @param last_node    inclusive end axial node index
     152             :    * @param ksp_prefix   options prefix for KSP (e.g. "h_sys_"), may be nullptr
     153             :    */
     154             :   PetscErrorCode solveAndPopulateEnthalpy(
     155             :       Mat A, Vec rhs, unsigned int first_node, unsigned int last_node, const char * ksp_prefix);
     156             : 
     157             :   PetscErrorCode cleanUp();
     158             :   SubChannelMesh & _subchannel_mesh;
     159             :   /// number of axial blocks
     160             :   unsigned int _n_blocks;
     161             :   libMesh::DenseMatrix<Real> & _Wij;
     162             :   libMesh::DenseMatrix<Real> _Wij_old;
     163             :   libMesh::DenseMatrix<Real> _WijPrime;
     164             :   libMesh::DenseMatrix<Real> _Wij_residual_matrix;
     165             :   const Real _g_grav;
     166             :   const Real & _kij;
     167             :   unsigned int _n_cells;
     168             :   unsigned int _n_gaps;
     169             :   unsigned int _n_pins;
     170             :   unsigned int _n_channels;
     171             :   unsigned int _block_size;
     172             :   /// axial location of nodes
     173             :   std::vector<Real> _z_grid;
     174             :   Real _one;
     175             :   /// Flag that activates or deactivates the transient parts of the equations we solve by multiplication
     176             :   Real _TR;
     177             :   /// Flag that activates or deactivates the calculation of density
     178             :   const bool _compute_density;
     179             :   /// Flag that activates or deactivates the calculation of viscosity
     180             :   const bool _compute_viscosity;
     181             :   /// Flag that informs if we need to solve the Enthalpy/Temperature equations or not
     182             :   const bool _compute_power;
     183             :   /// Flag that informs if there is a pin mesh or not
     184             :   const bool _pin_mesh_exist;
     185             :   /// Flag that informs if there is a pin mesh or not
     186             :   const bool _duct_mesh_exist;
     187             :   /// Variable that informs whether we exited external solve with a converged solution or not
     188             :   bool _converged;
     189             :   /// Time step
     190             :   Real _dt;
     191             :   /// Outlet Pressure
     192             :   const PostprocessorValue & _P_out;
     193             :   /// Turbulent modeling parameter used in axial momentum equation
     194             :   const Real & _CT;
     195             :   /// Convergence tolerance for the pressure loop in external solve
     196             :   const Real & _P_tol;
     197             :   /// Convergence tolerance for the temperature loop in external solve
     198             :   const Real & _T_tol;
     199             :   /// Maximum iterations for the inner temperature loop
     200             :   const int & _T_maxit;
     201             :   /// The relative convergence tolerance, (relative decrease) for the ksp linear solver
     202             :   const PetscReal & _rtol;
     203             :   /// The absolute convergence tolerance for the ksp linear solver
     204             :   const PetscReal & _atol;
     205             :   /// The divergence tolerance for the ksp linear solver
     206             :   const PetscReal & _dtol;
     207             :   /// The maximum number of iterations to use for the ksp linear solver
     208             :   const PetscInt & _maxit;
     209             :   /// The interpolation method used in constructing the systems
     210             :   const MooseEnum _interpolation_scheme;
     211             :   /// The direction of gravity
     212             :   const MooseEnum _gravity_direction;
     213             :   const Real _dir_grav;
     214             :   /// Flag to define the usage of a implicit or explicit solution
     215             :   const bool _implicit_bool;
     216             :   /// Flag to define the usage of staggered or collocated pressure
     217             :   const bool _staggered_pressure_bool;
     218             :   /// Segregated solve
     219             :   const bool _segregated_bool;
     220             :   /// Boolean to printout information related to subchannel solve
     221             :   const bool _verbose_subchannel;
     222             :   /// Flag that activates the effect of deformation (pin/duct) based on the auxvalues for displacement, Dpin
     223             :   const bool _deformation;
     224             : 
     225             :   /// Solutions handles and link to TH tables properties
     226             :   const SinglePhaseFluidProperties * _fp;
     227             :   std::unique_ptr<SolutionHandle> _mdot_soln;
     228             :   std::unique_ptr<SolutionHandle> _SumWij_soln;
     229             :   std::unique_ptr<SolutionHandle> _P_soln;
     230             :   std::unique_ptr<SolutionHandle> _DP_soln;
     231             :   std::unique_ptr<SolutionHandle> _h_soln;
     232             :   std::unique_ptr<SolutionHandle> _T_soln;
     233             :   std::unique_ptr<SolutionHandle> _Tpin_soln;
     234             :   std::unique_ptr<SolutionHandle> _Dpin_soln;
     235             :   std::unique_ptr<SolutionHandle> _rho_soln;
     236             :   std::unique_ptr<SolutionHandle> _mu_soln;
     237             :   std::unique_ptr<SolutionHandle> _S_flow_soln;
     238             :   std::unique_ptr<SolutionHandle> _w_perim_soln;
     239             :   std::unique_ptr<SolutionHandle> _q_prime_soln;
     240             :   std::unique_ptr<SolutionHandle> _duct_heat_flux_soln; // Only used for ducted assemblies
     241             :   std::unique_ptr<SolutionHandle> _Tduct_soln;          // Only used for ducted assemblies
     242             :   std::unique_ptr<SolutionHandle> _displacement_soln;
     243             : 
     244             :   /// Petsc Functions
     245       55719 :   inline PetscErrorCode createPetscVector(Vec & v, PetscInt n)
     246             :   {
     247             :     PetscFunctionBegin;
     248       55719 :     LibmeshPetscCall(VecCreate(PETSC_COMM_SELF, &v));
     249       55719 :     LibmeshPetscCall(PetscObjectSetName((PetscObject)v, "Solution"));
     250       55719 :     LibmeshPetscCall(VecSetSizes(v, PETSC_DECIDE, n));
     251       55719 :     LibmeshPetscCall(VecSetFromOptions(v));
     252       55719 :     LibmeshPetscCall(VecZeroEntries(v));
     253       55719 :     PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
     254             :   }
     255             : 
     256        7197 :   inline PetscErrorCode createPetscMatrix(Mat & M, PetscInt n, PetscInt m)
     257             :   {
     258             :     PetscFunctionBegin;
     259        7197 :     LibmeshPetscCall(MatCreate(PETSC_COMM_SELF, &M));
     260        7197 :     LibmeshPetscCall(MatSetSizes(M, PETSC_DECIDE, PETSC_DECIDE, n, m));
     261        7197 :     LibmeshPetscCall(MatSetFromOptions(M));
     262        7197 :     LibmeshPetscCall(MatSetUp(M));
     263        7197 :     PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
     264             :   }
     265             : 
     266             :   template <class T>
     267             :   PetscErrorCode populateVectorFromDense(Vec & x,
     268             :                                          const T & solution,
     269             :                                          const unsigned int first_axial_level,
     270             :                                          const unsigned int last_axial_level,
     271             :                                          const unsigned int cross_dimension);
     272             :   template <class T>
     273             :   PetscErrorCode populateDenseFromVector(const Vec & x,
     274             :                                          T & solution,
     275             :                                          const unsigned int first_axial_level,
     276             :                                          const unsigned int last_axial_level,
     277             :                                          const unsigned int cross_dimension);
     278             :   template <class T>
     279             :   PetscErrorCode populateVectorFromHandle(Vec & x,
     280             :                                           const T & solution,
     281             :                                           const unsigned int first_axial_level,
     282             :                                           const unsigned int last_axial_level,
     283             :                                           const unsigned int cross_dimension);
     284             :   template <class T>
     285             :   PetscErrorCode populateSolutionChan(const Vec & x,
     286             :                                       T & solution,
     287             :                                       const unsigned int first_axial_level,
     288             :                                       const unsigned int last_axial_level,
     289             :                                       const unsigned int cross_dimension);
     290             : 
     291             :   //// Matrices and vectors to be used in implicit assembly
     292             :   /// Mass conservation
     293             :   /// Mass conservation - sum of cross fluxes
     294             :   Mat _mc_sumWij_mat;
     295             :   Vec _Wij_vec;
     296             :   Vec _prod;
     297             :   Vec _prodp;
     298             :   /// Mass conservation - axial convection
     299             :   Mat _mc_axial_convection_mat;
     300             :   Vec _mc_axial_convection_rhs;
     301             :   /// Mass conservation - density time derivative
     302             :   /// No implicit matrix
     303             : 
     304             :   /// Axial momentum
     305             :   /// Axial momentum conservation - compute turbulent cross fluxes
     306             :   Mat _amc_turbulent_cross_flows_mat;
     307             :   Vec _amc_turbulent_cross_flows_rhs;
     308             :   /// Axial momentum conservation - time derivative
     309             :   Mat _amc_time_derivative_mat;
     310             :   Vec _amc_time_derivative_rhs;
     311             :   /// Axial momentum conservation - advective (Eulerian) derivative
     312             :   Mat _amc_advective_derivative_mat;
     313             :   Vec _amc_advective_derivative_rhs;
     314             :   /// Axial momentum conservation - cross flux derivative
     315             :   Mat _amc_cross_derivative_mat;
     316             :   Vec _amc_cross_derivative_rhs;
     317             :   /// Axial momentum conservation - friction force
     318             :   Mat _amc_friction_force_mat;
     319             :   Vec _amc_friction_force_rhs;
     320             :   /// Axial momentum conservation - buoyancy force
     321             :   /// No implicit matrix
     322             :   Vec _amc_gravity_rhs;
     323             :   /// Axial momentum conservation - pressure force
     324             :   Mat _amc_pressure_force_mat;
     325             :   Vec _amc_pressure_force_rhs;
     326             :   /// Axial momentum system matrix
     327             :   Mat _amc_sys_mdot_mat;
     328             :   Vec _amc_sys_mdot_rhs;
     329             : 
     330             :   /// Cross momentum
     331             :   /// Cross momentum conservation - time derivative
     332             :   Mat _cmc_time_derivative_mat;
     333             :   Vec _cmc_time_derivative_rhs;
     334             :   /// Cross momentum conservation - advective (Eulerian) derivative
     335             :   Mat _cmc_advective_derivative_mat;
     336             :   Vec _cmc_advective_derivative_rhs;
     337             :   /// Cross momentum conservation - friction force
     338             :   Mat _cmc_friction_force_mat;
     339             :   Vec _cmc_friction_force_rhs;
     340             :   /// Cross momentum conservation - pressure force
     341             :   Mat _cmc_pressure_force_mat;
     342             :   Vec _cmc_pressure_force_rhs;
     343             :   /// Lateral momentum system matrix
     344             :   Mat _cmc_sys_Wij_mat;
     345             :   Vec _cmc_sys_Wij_rhs;
     346             : 
     347             :   /// Enthalpy
     348             :   /// Enthalpy conservation - time derivative
     349             :   Mat _hc_time_derivative_mat;
     350             :   Vec _hc_time_derivative_rhs;
     351             :   /// Enthalpy conservation - advective (Eulerian) derivative;
     352             :   Mat _hc_advective_derivative_mat;
     353             :   Vec _hc_advective_derivative_rhs;
     354             :   /// Enthalpy conservation - cross flux derivative
     355             :   Mat _hc_cross_derivative_mat;
     356             :   Vec _hc_cross_derivative_rhs;
     357             :   /// Enthalpy conservation - source and sink
     358             :   Vec _hc_added_heat_rhs;
     359             :   /// System matrices
     360             :   Mat _hc_sys_h_mat;
     361             :   Vec _hc_sys_h_rhs;
     362             : 
     363             :   /// Added resistances for monolithic convergence
     364             :   PetscScalar _added_K = 0.0;
     365             :   PetscScalar _added_K_old = 1000.0;
     366             :   PetscScalar _max_sumWij;
     367             :   PetscScalar _max_sumWij_new;
     368             :   PetscScalar _correction_factor = 1.0;
     369             : 
     370             : public:
     371             :   static InputParameters validParams();
     372             : };
     373             : 
     374             : template <class T>
     375             : PetscErrorCode
     376       20466 : SubChannel1PhaseProblem::populateDenseFromVector(const Vec & x,
     377             :                                                  T & loc_solution,
     378             :                                                  const unsigned int first_axial_level,
     379             :                                                  const unsigned int last_axial_level,
     380             :                                                  const unsigned int cross_dimension)
     381             : {
     382             :   PetscScalar * xx;
     383             : 
     384             :   PetscFunctionBegin;
     385       20466 :   LibmeshPetscCall(VecGetArray(x, &xx));
     386      344826 :   for (unsigned int iz = first_axial_level; iz < last_axial_level + 1; iz++)
     387             :   {
     388      324360 :     unsigned int iz_ind = iz - first_axial_level;
     389    23383656 :     for (unsigned int i_l = 0; i_l < cross_dimension; i_l++)
     390             :     {
     391    23059296 :       loc_solution(i_l, iz) = xx[iz_ind * cross_dimension + i_l];
     392             :     }
     393             :   }
     394       20466 :   LibmeshPetscCall(VecRestoreArray(x, &xx));
     395             : 
     396       20466 :   PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
     397             : }
     398             : 
     399             : template <class T>
     400             : PetscErrorCode
     401       53262 : SubChannel1PhaseProblem::populateVectorFromHandle(Vec & x,
     402             :                                                   const T & loc_solution,
     403             :                                                   const unsigned int first_axial_level,
     404             :                                                   const unsigned int last_axial_level,
     405             :                                                   const unsigned int cross_dimension)
     406             : {
     407             :   PetscScalar * xx;
     408             : 
     409             :   PetscFunctionBegin;
     410       53262 :   LibmeshPetscCall(VecGetArray(x, &xx));
     411      750582 :   for (unsigned int iz = first_axial_level; iz < last_axial_level + 1; iz++)
     412             :   {
     413      697320 :     unsigned int iz_ind = iz - first_axial_level;
     414    32191200 :     for (unsigned int i_l = 0; i_l < cross_dimension; i_l++)
     415             :     {
     416    31493880 :       auto * loc_node = _subchannel_mesh.getChannelNode(i_l, iz);
     417    31493880 :       xx[iz_ind * cross_dimension + i_l] = loc_solution(loc_node);
     418             :     }
     419             :   }
     420       53262 :   LibmeshPetscCall(VecRestoreArray(x, &xx));
     421             : 
     422       53262 :   PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
     423             : }
     424             : 
     425             : template <class T>
     426             : PetscErrorCode
     427       20466 : SubChannel1PhaseProblem::populateVectorFromDense(Vec & x,
     428             :                                                  const T & loc_solution,
     429             :                                                  const unsigned int first_axial_level,
     430             :                                                  const unsigned int last_axial_level,
     431             :                                                  const unsigned int cross_dimension)
     432             : {
     433             :   PetscScalar * xx;
     434             :   PetscFunctionBegin;
     435       20466 :   LibmeshPetscCall(VecGetArray(x, &xx));
     436      344826 :   for (unsigned int iz = first_axial_level; iz < last_axial_level + 1; iz++)
     437             :   {
     438      324360 :     unsigned int iz_ind = iz - first_axial_level;
     439    23383656 :     for (unsigned int i_l = 0; i_l < cross_dimension; i_l++)
     440             :     {
     441    23059296 :       xx[iz_ind * cross_dimension + i_l] = loc_solution(i_l, iz);
     442             :     }
     443             :   }
     444       20466 :   LibmeshPetscCall(VecRestoreArray(x, &xx));
     445       20466 :   PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
     446             : }
     447             : 
     448             : template <class T>
     449             : PetscErrorCode
     450       32796 : SubChannel1PhaseProblem::populateSolutionChan(const Vec & x,
     451             :                                               T & loc_solution,
     452             :                                               const unsigned int first_axial_level,
     453             :                                               const unsigned int last_axial_level,
     454             :                                               const unsigned int cross_dimension)
     455             : {
     456             :   PetscScalar * xx;
     457             :   PetscFunctionBegin;
     458       32796 :   LibmeshPetscCall(VecGetArray(x, &xx));
     459             :   Node * loc_node;
     460      405756 :   for (unsigned int iz = first_axial_level; iz < last_axial_level + 1; iz++)
     461             :   {
     462      372960 :     unsigned int iz_ind = iz - first_axial_level;
     463    16480944 :     for (unsigned int i_l = 0; i_l < cross_dimension; i_l++)
     464             :     {
     465    16107984 :       loc_node = _subchannel_mesh.getChannelNode(i_l, iz);
     466    16107984 :       loc_solution.set(loc_node, xx[iz_ind * cross_dimension + i_l]);
     467             :     }
     468             :   }
     469       32796 :   PetscFunctionReturn(LIBMESH_PETSC_SUCCESS);
     470             : }

Generated by: LCOV version 1.14