LCOV - code coverage report
Current view: top level - src/kernels - EigenKernel.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 419b9d Lines: 77 99 77.8 %
Date: 2025-08-08 20:01:16 Functions: 6 6 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             : #include "EigenKernel.h"
      11             : 
      12             : // MOOSE includes
      13             : #include "Assembly.h"
      14             : #include "EigenExecutionerBase.h"
      15             : #include "Executioner.h"
      16             : #include "MooseApp.h"
      17             : #include "MooseEigenSystem.h"
      18             : #include "MooseVariableFE.h"
      19             : #include "FEProblemBase.h"
      20             : 
      21             : #include "libmesh/quadrature.h"
      22             : 
      23             : InputParameters
      24       57624 : EigenKernel::validParams()
      25             : {
      26       57624 :   InputParameters params = Kernel::validParams();
      27      172872 :   params.addParam<bool>(
      28      115248 :       "eigen", true, "Use for eigenvalue problem (true) or source problem (false)");
      29      172872 :   params.addParam<PostprocessorName>(
      30      115248 :       "eigen_postprocessor", 1.0, "The name of the postprocessor that provides the eigenvalue.");
      31       57624 :   params.registerBase("EigenKernel");
      32       57624 :   return params;
      33           0 : }
      34             : 
      35         378 : EigenKernel::EigenKernel(const InputParameters & parameters)
      36             :   : Kernel(parameters),
      37         378 :     _eigen(getParam<bool>("eigen")),
      38         378 :     _eigen_sys(
      39         378 :         dynamic_cast<MooseEigenSystem *>(&_fe_problem.getNonlinearSystemBase(_sys.number()))),
      40         378 :     _eigenvalue(NULL)
      41             : {
      42             :   // The name to the postprocessor storing the eigenvalue
      43         378 :   std::string eigen_pp_name;
      44             : 
      45             :   // If the "eigen_postprocessor" is given, use it. The isParamValid does not work here because of
      46             :   // the default value, which
      47             :   // you don't want to use if an EigenExecutioner exists.
      48         378 :   if (!isDefaultPostprocessorValue("eigen_postprocessor"))
      49           0 :     eigen_pp_name = getPostprocessorName("eigen_postprocessor");
      50             : 
      51             :   // Attempt to extract the eigenvalue postprocessor from the Executioner
      52             :   else
      53             :   {
      54         378 :     EigenExecutionerBase * exec = dynamic_cast<EigenExecutionerBase *>(_app.getExecutioner());
      55         378 :     if (exec)
      56         338 :       eigen_pp_name = exec->getParam<PostprocessorName>("bx_norm");
      57             :   }
      58             : 
      59             :   // If the postprocessor name was not provided and an EigenExecutionerBase is not being used,
      60             :   // use the default value from the "eigen_postprocessor" parameter
      61         378 :   if (eigen_pp_name.empty())
      62          40 :     _eigenvalue = &getPostprocessorValue("eigen_postprocessor");
      63             : 
      64             :   // If the name does exist, then use the postprocessor value
      65             :   else
      66             :   {
      67         338 :     if (_is_implicit)
      68         169 :       _eigenvalue = &getPostprocessorValueByName(eigen_pp_name);
      69             :     else
      70             :     {
      71         169 :       EigenExecutionerBase * exec = dynamic_cast<EigenExecutionerBase *>(_app.getExecutioner());
      72         169 :       if (exec)
      73         169 :         _eigenvalue = &exec->eigenvalueOld();
      74             :       else
      75           0 :         _eigenvalue = &getPostprocessorValueOldByName(eigen_pp_name);
      76             :     }
      77             :   }
      78         378 : }
      79             : 
      80             : void
      81      789588 : EigenKernel::computeResidual()
      82             : {
      83      789588 :   prepareVectorTag(_assembly, _var.number());
      84             : 
      85      789588 :   precalculateResidual();
      86             : 
      87             :   mooseAssert(*_eigenvalue != 0.0, "Can't divide by zero eigenvalue in EigenKernel!");
      88      789588 :   Real one_over_eigen = 1.0 / *_eigenvalue;
      89     3947076 :   for (_i = 0; _i < _test.size(); _i++)
      90    15785712 :     for (_qp = 0; _qp < _qrule->n_points(); _qp++)
      91    12628224 :       _local_re(_i) += _JxW[_qp] * _coord[_qp] * one_over_eigen * computeQpResidual();
      92             : 
      93      789588 :   accumulateTaggedLocalResidual();
      94      789588 :   if (_has_save_in)
      95             :   {
      96           0 :     Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
      97           0 :     for (const auto & var : _save_in)
      98           0 :       var->sys().solution().add_vector(_local_re, var->dofIndices());
      99           0 :   }
     100      789588 : }
     101             : 
     102             : void
     103       22408 : EigenKernel::computeJacobian()
     104             : {
     105       22408 :   if (!_is_implicit)
     106           0 :     return;
     107             : 
     108       22408 :   prepareMatrixTag(_assembly, _var.number(), _var.number());
     109             : 
     110       22408 :   precalculateJacobian();
     111             :   mooseAssert(*_eigenvalue != 0.0, "Can't divide by zero eigenvalue in EigenKernel!");
     112       22408 :   Real one_over_eigen = 1.0 / *_eigenvalue;
     113      111752 :   for (_i = 0; _i < _test.size(); _i++)
     114      446144 :     for (_j = 0; _j < _phi.size(); _j++)
     115     1782848 :       for (_qp = 0; _qp < _qrule->n_points(); _qp++)
     116     1426048 :         _local_ke(_i, _j) += _JxW[_qp] * _coord[_qp] * one_over_eigen * computeQpJacobian();
     117             : 
     118       22408 :   accumulateTaggedLocalMatrix();
     119             : 
     120       22408 :   if (_has_diag_save_in && !_sys.computingScalingJacobian())
     121             :   {
     122         750 :     DenseVector<Number> diag = _assembly.getJacobianDiagonal(_local_ke);
     123         750 :     Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
     124        1500 :     for (const auto & var : _diag_save_in)
     125         750 :       var->sys().solution().add_vector(diag, var->dofIndices());
     126         750 :   }
     127             : }
     128             : 
     129             : void
     130       11264 : EigenKernel::computeOffDiagJacobian(const unsigned int jvar_num)
     131             : {
     132       11264 :   if (!_is_implicit)
     133           0 :     return;
     134             : 
     135       11264 :   if (jvar_num == _var.number())
     136        8264 :     computeJacobian();
     137             :   else
     138             :   {
     139        3000 :     const auto & jvar = getVariable(jvar_num);
     140             : 
     141        3000 :     prepareMatrixTag(_assembly, _var.number(), jvar_num);
     142             : 
     143             :     // This (undisplaced) jvar could potentially yield the wrong phi size if this object is acting
     144             :     // on the displaced mesh
     145        3000 :     auto phi_size = jvar.dofIndices().size();
     146             :     mooseAssert(
     147             :         phi_size * jvar.count() == _local_ke.n(),
     148             :         "The size of the phi container does not match the number of local Jacobian columns");
     149             : 
     150        3000 :     if (_local_ke.m() != _test.size())
     151           0 :       return;
     152             : 
     153        3000 :     precalculateOffDiagJacobian(jvar_num);
     154             :     mooseAssert(*_eigenvalue != 0.0, "Can't divide by zero eigenvalue in EigenKernel!");
     155        3000 :     Real one_over_eigen = 1.0 / *_eigenvalue;
     156        3000 :     if (jvar.count() == 1)
     157             :     {
     158       15000 :       for (_i = 0; _i < _test.size(); _i++)
     159       60000 :         for (_j = 0; _j < phi_size; _j++)
     160      240000 :           for (_qp = 0; _qp < _qrule->n_points(); _qp++)
     161      192000 :             _local_ke(_i, _j) +=
     162      192000 :                 _JxW[_qp] * _coord[_qp] * one_over_eigen * computeQpOffDiagJacobian(jvar.number());
     163             :     }
     164             :     else
     165             :     {
     166           0 :       unsigned int n = phi_size;
     167           0 :       for (_i = 0; _i < _test.size(); _i++)
     168           0 :         for (_j = 0; _j < n; _j++)
     169           0 :           for (_qp = 0; _qp < _qrule->n_points(); _qp++)
     170             :           {
     171           0 :             RealEigenVector v = _JxW[_qp] * _coord[_qp] * one_over_eigen *
     172           0 :                                 computeQpOffDiagJacobianArray(static_cast<ArrayMooseVariable &>(
     173           0 :                                     const_cast<MooseVariableFieldBase &>(jvar)));
     174           0 :             for (unsigned int k = 0; k < v.size(); ++k)
     175           0 :               _local_ke(_i, _j + k * n) += v(k);
     176           0 :           }
     177             :     }
     178             : 
     179        3000 :     accumulateTaggedLocalMatrix();
     180             :   }
     181             : }
     182             : 
     183             : bool
     184        3452 : EigenKernel::enabled() const
     185             : {
     186        3452 :   bool flag = MooseObject::enabled();
     187        3452 :   if (_eigen)
     188             :   {
     189        3220 :     if (!_eigen_sys)
     190           0 :       mooseError("Eigen kernel ",
     191           0 :                  name(),
     192             :                  " requires a MooseEigenSystem and was designed to work with old eigenvalue",
     193             :                  " executioners such as 'NonlinearEigen'.  It is suggested to use the new",
     194             :                  " eigenvalue executioner 'Eigenvalue' along with kernel tagging");
     195             : 
     196        3220 :     if (_is_implicit)
     197        1610 :       return flag && (!_eigen_sys->activeOnOld());
     198             :     else
     199        1610 :       return flag && _eigen_sys->activeOnOld();
     200             :   }
     201             :   else
     202         232 :     return flag;
     203             : }

Generated by: LCOV version 1.14