LCOV - code coverage report
Current view: top level - src/systems - LinearSystem.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 419b9d Lines: 136 152 89.5 %
Date: 2025-08-08 20:01:16 Functions: 11 15 73.3 %
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 "LinearSystem.h"
      11             : #include "AuxiliarySystem.h"
      12             : #include "Problem.h"
      13             : #include "FEProblem.h"
      14             : #include "PetscSupport.h"
      15             : #include "Factory.h"
      16             : #include "ParallelUniqueId.h"
      17             : #include "ComputeLinearFVGreenGaussGradientFaceThread.h"
      18             : #include "ComputeLinearFVGreenGaussGradientVolumeThread.h"
      19             : #include "ComputeLinearFVElementalThread.h"
      20             : #include "ComputeLinearFVFaceThread.h"
      21             : #include "DisplacedProblem.h"
      22             : #include "Parser.h"
      23             : #include "MooseMesh.h"
      24             : #include "MooseUtils.h"
      25             : #include "MooseApp.h"
      26             : #include "TimeIntegrator.h"
      27             : #include "Assembly.h"
      28             : #include "FloatingPointExceptionGuard.h"
      29             : #include "Moose.h"
      30             : #include "ConsoleStream.h"
      31             : #include "MooseError.h"
      32             : #include "LinearFVElementalKernel.h"
      33             : #include "LinearFVFluxKernel.h"
      34             : #include "UserObject.h"
      35             : #include "SolutionInvalidity.h"
      36             : #include "MooseLinearVariableFV.h"
      37             : #include "LinearFVTimeDerivative.h"
      38             : 
      39             : // libMesh
      40             : #include "libmesh/linear_solver.h"
      41             : #include "libmesh/quadrature_gauss.h"
      42             : #include "libmesh/dense_vector.h"
      43             : #include "libmesh/boundary_info.h"
      44             : #include "libmesh/petsc_matrix.h"
      45             : #include "libmesh/petsc_vector.h"
      46             : #include "libmesh/petsc_nonlinear_solver.h"
      47             : #include "libmesh/numeric_vector.h"
      48             : #include "libmesh/mesh.h"
      49             : #include "libmesh/dense_subvector.h"
      50             : #include "libmesh/dense_submatrix.h"
      51             : #include "libmesh/dof_map.h"
      52             : #include "libmesh/sparse_matrix.h"
      53             : #include "libmesh/petsc_matrix.h"
      54             : #include "libmesh/default_coupling.h"
      55             : #include "libmesh/diagonal_matrix.h"
      56             : #include "libmesh/petsc_solver_exception.h"
      57             : 
      58             : #include <ios>
      59             : 
      60             : using namespace libMesh;
      61             : 
      62             : namespace Moose
      63             : {
      64             : void
      65        5300 : compute_linear_system(libMesh::EquationSystems & es, const std::string & system_name)
      66             : {
      67        5300 :   FEProblemBase * p = es.parameters.get<FEProblemBase *>("_fe_problem_base");
      68        5300 :   auto & sys = p->getLinearSystem(p->linearSysNum(system_name));
      69        5300 :   auto & lin_sys = sys.linearImplicitSystem();
      70        5300 :   auto & matrix = *(sys.linearImplicitSystem().matrix);
      71        5300 :   auto & rhs = *(sys.linearImplicitSystem().rhs);
      72        5300 :   p->computeLinearSystemSys(lin_sys, matrix, rhs);
      73        5300 : }
      74             : }
      75             : 
      76        1314 : LinearSystem::LinearSystem(FEProblemBase & fe_problem, const std::string & name)
      77             :   : SolverSystem(fe_problem, fe_problem, name, Moose::VAR_SOLVER),
      78        1314 :     PerfGraphInterface(fe_problem.getMooseApp().perfGraph(), "LinearSystem"),
      79        1314 :     _sys(fe_problem.es().add_system<LinearImplicitSystem>(name)),
      80        1314 :     _rhs_time_tag(-1),
      81        1314 :     _rhs_time(NULL),
      82        1314 :     _rhs_non_time_tag(-1),
      83        1314 :     _rhs_non_time(NULL),
      84        1314 :     _n_linear_iters(0),
      85        1314 :     _converged(false),
      86        3942 :     _linear_implicit_system(fe_problem.es().get_system<LinearImplicitSystem>(name))
      87             : {
      88        1314 :   getRightHandSideNonTimeVector();
      89             :   // Don't need to add the matrix - it already exists. Well, technically it will exist
      90             :   // after the initialization. Right now it is just a nullpointer. We will just make sure
      91             :   // we associate the tag with the system matrix for now.
      92        1314 :   _system_matrix_tag = _fe_problem.addMatrixTag("SYSTEM");
      93             : 
      94             :   // We create a tag for the right hand side, the vector is already in the libmesh system
      95        1314 :   _rhs_tag = _fe_problem.addVectorTag("RHS");
      96        1314 :   associateVectorToTag(*_linear_implicit_system.rhs, _rhs_tag);
      97             : 
      98        1314 :   _linear_implicit_system.attach_assemble_function(Moose::compute_linear_system);
      99        1314 : }
     100             : 
     101        1314 : LinearSystem::~LinearSystem() = default;
     102             : 
     103             : void
     104        1314 : LinearSystem::initialSetup()
     105             : {
     106        1314 :   SystemBase::initialSetup();
     107             :   // Checking if somebody accidentally assigned nonlinear variables to this system
     108        1314 :   const auto & var_names = _vars[0].names();
     109        2628 :   for (const auto & name : var_names)
     110        1314 :     if (!dynamic_cast<MooseLinearVariableFVReal *>(_vars[0].getVariable(name)))
     111           0 :       mooseError("You are trying to add a nonlinear variable to a linear system! The variable "
     112             :                  "which is assigned to the wrong system: ",
     113             :                  name);
     114             : 
     115             :   // Calling initial setup for the linear kernels
     116        2628 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
     117             :   {
     118        1314 :     std::vector<LinearFVElementalKernel *> fv_elemental_kernels;
     119        1314 :     _fe_problem.theWarehouse()
     120        2628 :         .query()
     121        1314 :         .template condition<AttribSystem>("LinearFVElementalKernel")
     122        1314 :         .template condition<AttribThread>(tid)
     123        1314 :         .queryInto(fv_elemental_kernels);
     124             : 
     125        3034 :     for (auto * fv_kernel : fv_elemental_kernels)
     126        1720 :       fv_kernel->initialSetup();
     127             : 
     128        1314 :     std::vector<LinearFVFluxKernel *> fv_flux_kernels;
     129        1314 :     _fe_problem.theWarehouse()
     130        2628 :         .query()
     131        1314 :         .template condition<AttribSystem>("LinearFVFluxKernel")
     132        1314 :         .template condition<AttribThread>(tid)
     133        1314 :         .queryInto(fv_flux_kernels);
     134             : 
     135        2915 :     for (auto * fv_kernel : fv_flux_kernels)
     136        1601 :       fv_kernel->initialSetup();
     137        1314 :   }
     138        1314 : }
     139             : 
     140             : void
     141        5366 : LinearSystem::computeLinearSystemTags(const std::set<TagID> & vector_tags,
     142             :                                       const std::set<TagID> & matrix_tags,
     143             :                                       const bool compute_gradients)
     144             : {
     145             :   parallel_object_only();
     146             : 
     147        5366 :   TIME_SECTION("LinearSystem::computeLinearSystemTags", 5);
     148             : 
     149        5366 :   _fe_problem.setCurrentLinearSystem(_fe_problem.linearSysNum(name()));
     150             : 
     151        5366 :   FloatingPointExceptionGuard fpe_guard(_app);
     152             : 
     153             :   try
     154             :   {
     155        5366 :     computeLinearSystemInternal(vector_tags, matrix_tags, compute_gradients);
     156             :   }
     157           0 :   catch (MooseException & e)
     158             :   {
     159           0 :     _console << "Exception detected " << e.what() << std::endl;
     160             :     // The buck stops here, we have already handled the exception by
     161             :     // calling stopSolve(), it is now up to PETSc to return a
     162             :     // "diverged" reason during the next solve.
     163           0 :   }
     164        5366 : }
     165             : 
     166             : void
     167       10678 : LinearSystem::computeGradients()
     168             : {
     169       10678 :   _new_gradient.clear();
     170       26788 :   for (auto & vec : _raw_grad_container)
     171       16110 :     _new_gradient.push_back(vec->zero_clone());
     172             : 
     173       10678 :   TIME_SECTION("LinearVariableFV_Gradients", 3 /*, "Computing Linear FV variable gradients"*/);
     174             : 
     175             :   PARALLEL_TRY
     176             :   {
     177             :     using FaceInfoRange = StoredRange<MooseMesh::const_face_info_iterator, const FaceInfo *>;
     178       21356 :     FaceInfoRange face_info_range(_fe_problem.mesh().ownedFaceInfoBegin(),
     179       32034 :                                   _fe_problem.mesh().ownedFaceInfoEnd());
     180             : 
     181             :     ComputeLinearFVGreenGaussGradientFaceThread gradient_face_thread(
     182       10678 :         _fe_problem, _fe_problem.linearSysNum(name()));
     183       10678 :     Threads::parallel_reduce(face_info_range, gradient_face_thread);
     184       10678 :   }
     185       10678 :   PARALLEL_CATCH;
     186             : 
     187       26788 :   for (auto & vec : _new_gradient)
     188       16110 :     vec->close();
     189             : 
     190             :   PARALLEL_TRY
     191             :   {
     192             :     using ElemInfoRange = StoredRange<MooseMesh::const_elem_info_iterator, const ElemInfo *>;
     193       21356 :     ElemInfoRange elem_info_range(_fe_problem.mesh().ownedElemInfoBegin(),
     194       32034 :                                   _fe_problem.mesh().ownedElemInfoEnd());
     195             : 
     196             :     ComputeLinearFVGreenGaussGradientVolumeThread gradient_volume_thread(
     197       10678 :         _fe_problem, _fe_problem.linearSysNum(name()));
     198       10678 :     Threads::parallel_reduce(elem_info_range, gradient_volume_thread);
     199       10678 :   }
     200       10678 :   PARALLEL_CATCH;
     201             : 
     202       26788 :   for (const auto i : index_range(_raw_grad_container))
     203             :   {
     204       16110 :     _new_gradient[i]->close();
     205       16110 :     _raw_grad_container[i] = std::move(_new_gradient[i]);
     206             :   }
     207       10678 : }
     208             : 
     209             : void
     210        5366 : LinearSystem::computeLinearSystemInternal(const std::set<TagID> & vector_tags,
     211             :                                           const std::set<TagID> & matrix_tags,
     212             :                                           const bool compute_gradients)
     213             : {
     214        5366 :   TIME_SECTION("computeLinearSystemInternal", 3);
     215             : 
     216             :   // Before we assemble we clear up the matrix and the vector
     217        5366 :   _linear_implicit_system.matrix->zero();
     218        5366 :   _linear_implicit_system.rhs->zero();
     219             : 
     220             :   // Make matrix ready to use
     221        5366 :   activeAllMatrixTags();
     222             : 
     223       10756 :   for (auto tag : matrix_tags)
     224             :   {
     225        5390 :     auto & matrix = getMatrix(tag);
     226             :     // Necessary for speed
     227        5390 :     if (auto petsc_matrix = dynamic_cast<PetscMatrix<Number> *>(&matrix))
     228             :     {
     229        5390 :       LibmeshPetscCall(MatSetOption(petsc_matrix->mat(),
     230             :                                     MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
     231             :                                     PETSC_TRUE));
     232        5390 :       if (!_fe_problem.errorOnJacobianNonzeroReallocation())
     233           0 :         LibmeshPetscCall(
     234             :             MatSetOption(petsc_matrix->mat(), MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
     235             :     }
     236             :   }
     237             : 
     238        5366 :   if (compute_gradients)
     239        5366 :     computeGradients();
     240             : 
     241             :   // linear contributions from the domain
     242             :   PARALLEL_TRY
     243             :   {
     244        5366 :     TIME_SECTION("LinearFVKernels_FullSystem", 3 /*, "Computing LinearFVKernels"*/);
     245             : 
     246             :     using ElemInfoRange = StoredRange<MooseMesh::const_elem_info_iterator, const ElemInfo *>;
     247       10732 :     ElemInfoRange elem_info_range(_fe_problem.mesh().ownedElemInfoBegin(),
     248       16098 :                                   _fe_problem.mesh().ownedElemInfoEnd());
     249             : 
     250             :     using FaceInfoRange = StoredRange<MooseMesh::const_face_info_iterator, const FaceInfo *>;
     251       10732 :     FaceInfoRange face_info_range(_fe_problem.mesh().ownedFaceInfoBegin(),
     252       16098 :                                   _fe_problem.mesh().ownedFaceInfoEnd());
     253             : 
     254             :     ComputeLinearFVElementalThread elem_thread(
     255        5366 :         _fe_problem, this->number(), vector_tags, matrix_tags);
     256        5366 :     Threads::parallel_reduce(elem_info_range, elem_thread);
     257             : 
     258             :     ComputeLinearFVFaceThread face_thread(_fe_problem,
     259             :                                           this->number(),
     260             :                                           Moose::FV::LinearFVComputationMode::FullSystem,
     261             :                                           vector_tags,
     262        5366 :                                           matrix_tags);
     263        5366 :     Threads::parallel_reduce(face_info_range, face_thread);
     264        5366 :   }
     265        5366 :   PARALLEL_CATCH;
     266             : 
     267        5366 :   closeTaggedMatrices(matrix_tags);
     268             : 
     269        5366 :   _linear_implicit_system.matrix->close();
     270        5366 :   _linear_implicit_system.rhs->close();
     271             : 
     272             :   // Accumulate the occurrence of solution invalid warnings for the current iteration cumulative
     273             :   // counters
     274        5366 :   _app.solutionInvalidity().syncIteration();
     275        5366 :   _app.solutionInvalidity().solutionInvalidAccumulation();
     276        5366 : }
     277             : 
     278             : NumericVector<Number> &
     279           0 : LinearSystem::getRightHandSideTimeVector()
     280             : {
     281           0 :   return *_rhs_time;
     282             : }
     283             : 
     284             : NumericVector<Number> &
     285        1314 : LinearSystem::getRightHandSideNonTimeVector()
     286             : {
     287        1314 :   return *_rhs_non_time;
     288             : }
     289             : 
     290             : void
     291           0 : LinearSystem::augmentSparsity(SparsityPattern::Graph & /*sparsity*/,
     292             :                               std::vector<dof_id_type> & /*n_nz*/,
     293             :                               std::vector<dof_id_type> & /*n_oz*/)
     294             : {
     295           0 :   mooseError("LinearSystem does not support AugmentSparsity!");
     296             : }
     297             : 
     298             : void
     299        5300 : LinearSystem::solve()
     300             : {
     301        5300 :   TIME_SECTION("LinearSystem::solve", 2, "Solving linear system");
     302             : 
     303             :   // Clear the iteration counters
     304        5300 :   _current_l_its = 0;
     305             : 
     306        5300 :   system().solve();
     307             : 
     308             :   // store info about the solve
     309        5300 :   _n_linear_iters = _linear_implicit_system.n_linear_iterations();
     310             : 
     311             :   auto & linear_solver =
     312        5300 :       libMesh::cast_ref<PetscLinearSolver<Real> &>(*_linear_implicit_system.get_linear_solver());
     313        5300 :   _initial_linear_residual = linear_solver.get_initial_residual();
     314        5300 :   _final_linear_residual = _linear_implicit_system.final_linear_residual();
     315        5300 :   _converged = linear_solver.get_converged_reason() > 0;
     316             : 
     317        5300 :   _console << "System: " << this->name() << " Initial residual: " << _initial_linear_residual
     318        5300 :            << " Final residual: " << _final_linear_residual << " Num. of Iter. " << _n_linear_iters
     319        5300 :            << std::endl;
     320             : 
     321             :   // determine whether solution invalid occurs in the converged solution
     322        5300 :   checkInvalidSolution();
     323        5300 : }
     324             : 
     325             : void
     326           0 : LinearSystem::stopSolve(const ExecFlagType & /*exec_flag*/,
     327             :                         const std::set<TagID> & vector_tags_to_close)
     328             : {
     329             :   // We close the containers in case the solve restarts from a failed iteration
     330           0 :   closeTaggedVectors(vector_tags_to_close);
     331           0 :   _linear_implicit_system.matrix->close();
     332           0 : }
     333             : 
     334             : bool
     335        1288 : LinearSystem::containsTimeKernel()
     336             : {
     337             :   // Right now, FV kernels are in TheWarehouse so we have to use that.
     338        1288 :   std::vector<LinearFVKernel *> kernels;
     339        1288 :   auto base_query = _fe_problem.theWarehouse()
     340        1288 :                         .query()
     341        2576 :                         .template condition<AttribSysNum>(this->number())
     342        1288 :                         .template condition<AttribSystem>("LinearFVKernel")
     343        1288 :                         .queryInto(kernels);
     344             : 
     345        1288 :   bool contains_time_kernel = false;
     346        1288 :   for (const auto kernel : kernels)
     347             :   {
     348           0 :     contains_time_kernel = dynamic_cast<LinearFVTimeDerivative *>(kernel);
     349           0 :     if (contains_time_kernel)
     350           0 :       break;
     351             :   }
     352             : 
     353        1288 :   return contains_time_kernel;
     354        1288 : }
     355             : 
     356             : void
     357       18688 : LinearSystem::compute(ExecFlagType)
     358             : {
     359             :   // Linear systems have their own time derivative computation machinery
     360       18688 : }

Generated by: LCOV version 1.14