LCOV - code coverage report
Current view: top level - src/systems - LinearSystem.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #33416 (b10b36) with base 9fbd27 Lines: 144 160 90.0 %
Date: 2026-07-23 16:15:30 Functions: 12 16 75.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 "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 "ComputeLinearFVElementalThread.h"
      18             : #include "ComputeLinearFVFaceThread.h"
      19             : #include "DisplacedProblem.h"
      20             : #include "Parser.h"
      21             : #include "MooseMesh.h"
      22             : #include "MooseUtils.h"
      23             : #include "MooseApp.h"
      24             : #include "TimeIntegrator.h"
      25             : #include "Assembly.h"
      26             : #include "FloatingPointExceptionGuard.h"
      27             : #include "Moose.h"
      28             : #include "ConsoleStream.h"
      29             : #include "MooseError.h"
      30             : #include "LinearFVElementalKernel.h"
      31             : #include "LinearFVFluxKernel.h"
      32             : #include "UserObject.h"
      33             : #include "SolutionInvalidity.h"
      34             : #include "MooseLinearVariableFV.h"
      35             : #include "LinearFVTimeDerivative.h"
      36             : #include "LinearFVFluxKernel.h"
      37             : #include "LinearFVElementalKernel.h"
      38             : #include "LinearFVBoundaryCondition.h"
      39             : #include "GradientLimiterType.h"
      40             : 
      41             : // libMesh
      42             : #include "libmesh/linear_solver.h"
      43             : #include "libmesh/quadrature_gauss.h"
      44             : #include "libmesh/dense_vector.h"
      45             : #include "libmesh/boundary_info.h"
      46             : #include "libmesh/petsc_matrix.h"
      47             : #include "libmesh/petsc_vector.h"
      48             : #include "libmesh/petsc_nonlinear_solver.h"
      49             : #include "libmesh/numeric_vector.h"
      50             : #include "libmesh/mesh.h"
      51             : #include "libmesh/dense_subvector.h"
      52             : #include "libmesh/dense_submatrix.h"
      53             : #include "libmesh/dof_map.h"
      54             : #include "libmesh/sparse_matrix.h"
      55             : #include "libmesh/petsc_matrix.h"
      56             : #include "libmesh/default_coupling.h"
      57             : #include "libmesh/diagonal_matrix.h"
      58             : #include "libmesh/petsc_solver_exception.h"
      59             : 
      60             : #include <ios>
      61             : 
      62             : using namespace libMesh;
      63             : 
      64             : namespace Moose
      65             : {
      66             : void
      67       25708 : compute_linear_system(libMesh::EquationSystems & es, const std::string & system_name)
      68             : {
      69       25708 :   FEProblemBase * p = es.parameters.get<FEProblemBase *>("_fe_problem_base");
      70       25708 :   auto & sys = p->getLinearSystem(p->linearSysNum(system_name));
      71       25708 :   auto & lin_sys = sys.linearImplicitSystem();
      72       25708 :   auto & matrix = *(sys.linearImplicitSystem().matrix);
      73       25708 :   auto & rhs = *(sys.linearImplicitSystem().rhs);
      74       25708 :   p->computeLinearSystemSys(lin_sys, matrix, rhs);
      75       25708 : }
      76             : }
      77             : 
      78        1264 : LinearSystem::LinearSystem(FEProblemBase & fe_problem, const std::string & name)
      79             :   : SolverSystem(fe_problem, fe_problem, name, Moose::VAR_SOLVER),
      80        1264 :     PerfGraphInterface(fe_problem.getMooseApp().perfGraph(), "LinearSystem"),
      81             :     LinearFVGradientInterface(static_cast<SystemBase &>(*this)),
      82        1264 :     _sys(fe_problem.es().add_system<LinearImplicitSystem>(name)),
      83        1264 :     _rhs_time_tag(-1),
      84        1264 :     _rhs_time(NULL),
      85        1264 :     _rhs_non_time_tag(-1),
      86        1264 :     _rhs_non_time(NULL),
      87        1264 :     _n_linear_iters(0),
      88        1264 :     _converged(false),
      89        6320 :     _linear_implicit_system(fe_problem.es().get_system<LinearImplicitSystem>(name))
      90             : {
      91        1264 :   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        1264 :   _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        1264 :   _rhs_tag = _fe_problem.addVectorTag("RHS");
      99        1264 :   associateVectorToTag(*_linear_implicit_system.rhs, _rhs_tag);
     100             : 
     101        1264 :   _linear_implicit_system.attach_assemble_function(Moose::compute_linear_system);
     102        1264 : }
     103             : 
     104        1262 : LinearSystem::~LinearSystem() = default;
     105             : 
     106             : void
     107        1228 : LinearSystem::preInit()
     108             : {
     109        1228 :   SolverSystem::preInit();
     110             : 
     111             : #ifdef MOOSE_KOKKOS_ENABLED
     112         899 :   if (_fe_problem.hasKokkosResidualObjects())
     113         181 :     _sys.get_dof_map().full_sparsity_pattern_needed();
     114             : #endif
     115        1228 : }
     116             : 
     117             : void
     118        1226 : LinearSystem::initialSetup()
     119             : {
     120        1226 :   SystemBase::initialSetup();
     121        1226 :   _current_solution = system().current_local_solution.get();
     122             :   // Checking if somebody accidentally assigned nonlinear variables to this system
     123        1226 :   const auto & var_names = _vars[0].names();
     124        2472 :   for (const auto & name : var_names)
     125        1246 :     if (!dynamic_cast<MooseLinearVariableFVReal *>(_vars[0].getVariable(name)))
     126           0 :       mooseError("You are trying to add a nonlinear variable to a linear system! The variable "
     127             :                  "which is assigned to the wrong system: ",
     128             :                  name);
     129             : 
     130        1226 :   LinearFVGradientInterface::rebuildLinearFVGradientStorage();
     131             : 
     132             :   // Calling initial setup for the linear kernels
     133        2452 :   for (THREAD_ID tid = 0; tid < libMesh::n_threads(); tid++)
     134             :   {
     135        1226 :     std::vector<LinearFVElementalKernel *> fv_elemental_kernels;
     136        1226 :     _fe_problem.theWarehouse()
     137        1226 :         .query()
     138        1226 :         .template condition<AttribSysNum>(number())
     139        1226 :         .template condition<AttribSystem>("LinearFVElementalKernel")
     140        2452 :         .template condition<AttribKokkos>(false)
     141        1226 :         .template condition<AttribThread>(tid)
     142        1226 :         .queryInto(fv_elemental_kernels);
     143             : 
     144        2265 :     for (auto * fv_kernel : fv_elemental_kernels)
     145        1039 :       fv_kernel->initialSetup();
     146             : 
     147        1226 :     std::vector<LinearFVFluxKernel *> fv_flux_kernels;
     148        1226 :     _fe_problem.theWarehouse()
     149        1226 :         .query()
     150        1226 :         .template condition<AttribSysNum>(number())
     151        1226 :         .template condition<AttribSystem>("LinearFVFluxKernel")
     152        2452 :         .template condition<AttribKokkos>(false)
     153        1226 :         .template condition<AttribThread>(tid)
     154        1226 :         .queryInto(fv_flux_kernels);
     155             : 
     156        2383 :     for (auto * fv_kernel : fv_flux_kernels)
     157        1157 :       fv_kernel->initialSetup();
     158             : 
     159        1226 :     std::vector<LinearFVBoundaryCondition *> fv_bcs;
     160        1226 :     _fe_problem.theWarehouse()
     161        1226 :         .query()
     162        1226 :         .template condition<AttribSysNum>(number())
     163        1226 :         .template condition<AttribSystem>("LinearFVBoundaryCondition")
     164        2452 :         .template condition<AttribKokkos>(false)
     165        1226 :         .template condition<AttribThread>(tid)
     166        1226 :         .queryInto(fv_bcs);
     167             : 
     168        3290 :     for (auto * fv_bc : fv_bcs)
     169        2064 :       fv_bc->initialSetup();
     170        1226 :   }
     171             : 
     172             : #ifdef MOOSE_KOKKOS_ENABLED
     173         898 :   initialSetupKokkosLinearFV();
     174             : #endif
     175        1226 : }
     176             : 
     177             : void
     178          10 : LinearSystem::reinit()
     179             : {
     180          10 :   _current_solution = system().current_local_solution.get();
     181          10 :   LinearFVGradientInterface::rebuildLinearFVGradientStorage();
     182          10 : }
     183             : 
     184             : void
     185       25792 : LinearSystem::computeLinearSystemTags(const std::set<TagID> & vector_tags,
     186             :                                       const std::set<TagID> & matrix_tags,
     187             :                                       const bool compute_gradients)
     188             : {
     189             :   parallel_object_only();
     190             : 
     191       77376 :   TIME_SECTION("LinearSystem::computeLinearSystemTags", 5);
     192             : 
     193       25792 :   _fe_problem.setCurrentLinearSystem(_fe_problem.linearSysNum(name()));
     194             : 
     195       25792 :   FloatingPointExceptionGuard fpe_guard(_app);
     196             : 
     197             :   try
     198             :   {
     199       25792 :     computeLinearSystemInternal(vector_tags, matrix_tags, compute_gradients);
     200             :   }
     201           0 :   catch (MooseException & e)
     202             :   {
     203           0 :     _console << "Exception detected " << e.what() << std::endl;
     204             :     // The buck stops here, we have already handled the exception by
     205             :     // calling stopSolve(), it is now up to PETSc to return a
     206             :     // "diverged" reason during the next solve.
     207           0 :   }
     208       25792 : }
     209             : 
     210             : void
     211       25792 : LinearSystem::computeLinearSystemInternal(const std::set<TagID> & vector_tags,
     212             :                                           const std::set<TagID> & matrix_tags,
     213             :                                           const bool compute_gradients)
     214             : {
     215       77376 :   TIME_SECTION("computeLinearSystemInternal", 3);
     216             : 
     217             :   // Before we assemble we clear up the matrix and the vector
     218       25792 :   _linear_implicit_system.matrix->zero();
     219       25792 :   _linear_implicit_system.rhs->zero();
     220             : 
     221             :   // Make matrix ready to use
     222       25792 :   activateAllMatrixTags();
     223             : 
     224       51604 :   for (auto tag : matrix_tags)
     225             :   {
     226       25812 :     auto & matrix = getMatrix(tag);
     227             :     // Necessary for speed
     228       25812 :     if (auto petsc_matrix = dynamic_cast<PetscMatrix<Number> *>(&matrix))
     229             :     {
     230       25812 :       LibmeshPetscCall(MatSetOption(petsc_matrix->mat(),
     231             :                                     MAT_KEEP_NONZERO_PATTERN, // This is changed in 3.1
     232             :                                     PETSC_TRUE));
     233       25812 :       if (!_fe_problem.errorOnJacobianNonzeroReallocation())
     234           0 :         LibmeshPetscCall(
     235             :             MatSetOption(petsc_matrix->mat(), MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
     236             :     }
     237             :   }
     238             : 
     239       25792 :   if (compute_gradients)
     240       25792 :     computeGradients();
     241             : 
     242             : #ifdef MOOSE_KOKKOS_ENABLED
     243             :   // Kokkos assembly runs first: it accumulates via device-side atomics and syncs
     244             :   // back to PETSc before the CPU path writes. The CPU queries below filter out
     245             :   // Kokkos objects via AttribKokkos(false) so there is no double-counting.
     246       17842 :   if (_fe_problem.hasKokkosResidualObjects())
     247         292 :     computeKokkosLinearSystem(vector_tags, matrix_tags);
     248             : #endif
     249             : 
     250             :   // linear contributions from the domain
     251             :   PARALLEL_TRY
     252             :   {
     253       77376 :     TIME_SECTION("LinearFVKernels_FullSystem", 3 /*, "Computing LinearFVKernels"*/);
     254             : 
     255             :     using ElemInfoRange = StoredRange<MooseMesh::const_elem_info_iterator, const ElemInfo *>;
     256       51584 :     ElemInfoRange elem_info_range(_fe_problem.mesh().ownedElemInfoBegin(),
     257       77376 :                                   _fe_problem.mesh().ownedElemInfoEnd());
     258             : 
     259             :     using FaceInfoRange = StoredRange<MooseMesh::const_face_info_iterator, const FaceInfo *>;
     260       51584 :     FaceInfoRange face_info_range(_fe_problem.mesh().ownedFaceInfoBegin(),
     261       77376 :                                   _fe_problem.mesh().ownedFaceInfoEnd());
     262             : 
     263             :     ComputeLinearFVElementalThread elem_thread(
     264       25792 :         _fe_problem, this->number(), vector_tags, matrix_tags);
     265       25792 :     Threads::parallel_reduce(elem_info_range, elem_thread);
     266             : 
     267             :     ComputeLinearFVFaceThread face_thread(_fe_problem,
     268             :                                           this->number(),
     269             :                                           Moose::FV::LinearFVComputationMode::FullSystem,
     270             :                                           vector_tags,
     271       25792 :                                           matrix_tags);
     272       25792 :     Threads::parallel_reduce(face_info_range, face_thread);
     273       25792 :   }
     274       25792 :   PARALLEL_CATCH;
     275             : 
     276       25792 :   closeTaggedMatrices(matrix_tags);
     277             : 
     278       25792 :   _linear_implicit_system.matrix->close();
     279       25792 :   _linear_implicit_system.rhs->close();
     280             : 
     281             :   // Accumulate the occurrence of solution invalid warnings for the current iteration cumulative
     282             :   // counters
     283       25792 :   _app.solutionInvalidity().syncIteration();
     284       25792 :   _app.solutionInvalidity().accumulateIterationIntoTimeStepOccurences();
     285       25792 : }
     286             : 
     287             : NumericVector<Number> &
     288           0 : LinearSystem::getRightHandSideTimeVector()
     289             : {
     290           0 :   return *_rhs_time;
     291             : }
     292             : 
     293             : NumericVector<Number> &
     294        1264 : LinearSystem::getRightHandSideNonTimeVector()
     295             : {
     296        1264 :   return *_rhs_non_time;
     297             : }
     298             : 
     299             : void
     300           0 : LinearSystem::augmentSparsity(SparsityPattern::Graph & /*sparsity*/,
     301             :                               std::vector<dof_id_type> & /*n_nz*/,
     302             :                               std::vector<dof_id_type> & /*n_oz*/)
     303             : {
     304           0 :   mooseError("LinearSystem does not support AugmentSparsity!");
     305             : }
     306             : 
     307             : void
     308       25708 : LinearSystem::solve()
     309             : {
     310      128540 :   TIME_SECTION("LinearSystem::solve", 2, "Solving linear system");
     311             : 
     312             :   // Clear the iteration counters
     313       25708 :   _current_l_its = 0;
     314             : 
     315       25708 :   system().solve();
     316             : 
     317             :   // store info about the solve
     318       25708 :   _n_linear_iters = _linear_implicit_system.n_linear_iterations();
     319             : 
     320             :   auto & linear_solver =
     321       25708 :       libMesh::cast_ref<PetscLinearSolver<Real> &>(*_linear_implicit_system.get_linear_solver());
     322       25708 :   _initial_linear_residual = linear_solver.get_initial_residual();
     323       25708 :   _final_linear_residual = _linear_implicit_system.final_linear_residual();
     324       25708 :   _converged = linear_solver.get_converged_reason() > 0;
     325             : 
     326       25708 :   _console << "System: " << this->name() << " Initial residual: " << _initial_linear_residual
     327       25708 :            << " Final residual: " << _final_linear_residual << " Num. of Iter. " << _n_linear_iters
     328       25708 :            << std::endl;
     329             : 
     330             :   // determine whether solution invalid occurs in the converged solution
     331       25708 :   checkInvalidSolution();
     332       25708 : }
     333             : 
     334             : void
     335           0 : LinearSystem::stopSolve(const ExecFlagType & /*exec_flag*/,
     336             :                         const std::set<TagID> & vector_tags_to_close)
     337             : {
     338             :   // We close the containers in case the solve restarts from a failed iteration
     339           0 :   closeTaggedVectors(vector_tags_to_close);
     340           0 :   _linear_implicit_system.matrix->close();
     341           0 : }
     342             : 
     343             : bool
     344        1197 : LinearSystem::containsTimeKernel()
     345             : {
     346             :   // Right now, FV kernels are in TheWarehouse so we have to use that.
     347        1197 :   std::vector<LinearFVKernel *> kernels;
     348        1197 :   auto base_query = _fe_problem.theWarehouse()
     349        1197 :                         .query()
     350        2394 :                         .template condition<AttribSysNum>(this->number())
     351        1197 :                         .template condition<AttribSystem>("LinearFVKernel")
     352        1197 :                         .queryInto(kernels);
     353             : 
     354        1197 :   bool contains_time_kernel = false;
     355        1197 :   for (const auto kernel : kernels)
     356             :   {
     357           0 :     contains_time_kernel = dynamic_cast<LinearFVTimeDerivative *>(kernel);
     358           0 :     if (contains_time_kernel)
     359           0 :       break;
     360             :   }
     361             : 
     362        1197 :   return contains_time_kernel;
     363        1197 : }
     364             : 
     365             : void
     366       67031 : LinearSystem::compute(const ExecFlagType type)
     367             : {
     368             :   // - Linear system assembly is associated with EXEC_NONLINEAR
     369             :   // - Avoid division by 0 dt
     370       67031 :   if (type == EXEC_NONLINEAR && _fe_problem.dt() > 0.)
     371         390 :     for (auto & ti : _time_integrators)
     372             :       // Do things like compute integration weights
     373         195 :       ti->preStep();
     374       67031 : }

Generated by: LCOV version 1.14