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

Generated by: LCOV version 1.14