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

Generated by: LCOV version 1.14