LCOV - code coverage report
Current view: top level - src/numerics - static_condensation.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 202 251 80.5 %
Date: 2025-08-19 19:27:09 Functions: 25 49 51.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : #include "libmesh/enum_parallel_type.h"
      19             : #include "libmesh/static_condensation.h"
      20             : 
      21             : #if defined(LIBMESH_HAVE_EIGEN) && defined(LIBMESH_HAVE_PETSC)
      22             : 
      23             : #include "libmesh/mesh_base.h"
      24             : #include "libmesh/dof_map.h"
      25             : #include "libmesh/elem.h"
      26             : #include "libmesh/int_range.h"
      27             : #include "libmesh/numeric_vector.h"
      28             : #include "libmesh/linear_solver.h"
      29             : #include "libmesh/static_condensation_preconditioner.h"
      30             : #include "libmesh/system.h"
      31             : #include "libmesh/petsc_matrix.h"
      32             : #include "libmesh/equation_systems.h"
      33             : #include "libmesh/static_condensation_dof_map.h"
      34             : #include "timpi/parallel_sync.h"
      35             : #include <unordered_set>
      36             : 
      37             : namespace libMesh
      38             : {
      39         350 : StaticCondensation::StaticCondensation(const MeshBase & mesh,
      40             :                                        System & system,
      41             :                                        const DofMap & full_dof_map,
      42         350 :                                        StaticCondensationDofMap & reduced_dof_map)
      43             :   : PetscMatrixShellMatrix<Number>(full_dof_map.comm()),
      44         330 :     _mesh(mesh),
      45         330 :     _system(system),
      46         330 :     _full_dof_map(full_dof_map),
      47         330 :     _reduced_dof_map(reduced_dof_map),
      48         330 :     _current_elem_id(DofObject::invalid_id),
      49         330 :     _sc_is_initialized(false),
      50         330 :     _have_cached_values(false),
      51         330 :     _parallel_type(INVALID_PARALLELIZATION),
      52         350 :     _uncondensed_dofs_only(false)
      53             : {
      54         340 :   _size_one_mat.resize(1, 1);
      55         680 :   _scp = std::make_unique<StaticCondensationPreconditioner>(*this);
      56         350 : }
      57             : 
      58         660 : StaticCondensation::~StaticCondensation() = default;
      59             : 
      60           0 : SparseMatrix<Number> & StaticCondensation::operator=(const SparseMatrix<Number> &)
      61             : {
      62           0 :   libmesh_not_implemented();
      63             : }
      64             : 
      65           0 : std::unique_ptr<SparseMatrix<Number>> StaticCondensation::zero_clone() const
      66             : {
      67           0 :   libmesh_not_implemented();
      68             : }
      69             : 
      70           0 : std::unique_ptr<SparseMatrix<Number>> StaticCondensation::clone() const
      71             : {
      72           0 :   libmesh_not_implemented();
      73             : }
      74             : 
      75         490 : void StaticCondensation::clear() noexcept
      76             : {
      77         490 :   PetscMatrixShellMatrix<Number>::clear();
      78             : 
      79          14 :   _elem_to_matrix_data.clear();
      80          14 :   _reduced_sys_mat.reset();
      81          14 :   _reduced_sol.reset();
      82          14 :   _reduced_rhs.reset();
      83          14 :   _reduced_solver.reset();
      84         490 :   _current_elem_id = DofObject::invalid_id;
      85         490 :   _have_cached_values = false;
      86         490 :   _sc_is_initialized = false;
      87         490 : }
      88             : 
      89           0 : void StaticCondensation::init(const numeric_index_type m,
      90             :                               const numeric_index_type n,
      91             :                               const numeric_index_type m_l,
      92             :                               const numeric_index_type n_l,
      93             :                               const numeric_index_type nnz,
      94             :                               const numeric_index_type noz,
      95             :                               const numeric_index_type blocksize)
      96             : {
      97           0 :   if (!this->initialized())
      98             :     {
      99           0 :       PetscMatrixShellMatrix<Number>::init(m, n, m_l, n_l, nnz, noz, blocksize);
     100           0 :       _parallel_type = ((m == m_l) && (this->n_processors() > 1)) ? SERIAL : PARALLEL;
     101           0 :       this->init();
     102             :     }
     103           0 : }
     104             : 
     105         490 : void StaticCondensation::init(const ParallelType type)
     106             : {
     107         490 :   if (!this->initialized())
     108             :     {
     109         490 :       PetscMatrixShellMatrix<Number>::init(type);
     110         490 :       _parallel_type = type;
     111         490 :       this->init();
     112             :     }
     113         490 : }
     114             : 
     115        3800 : bool StaticCondensation::initialized() const
     116             : {
     117        3800 :   return PetscMatrixShellMatrix<Number>::initialized() && _sc_is_initialized;
     118             : }
     119             : 
     120        1470 : void StaticCondensation::init()
     121             : {
     122        1470 :   if (this->initialized())
     123          28 :     return;
     124             : 
     125          14 :   libmesh_assert(_reduced_dof_map.initialized());
     126             : 
     127             :   // This API is public, so it can be called without going through the other init overloads which
     128             :   // would give us an indication of what kind of parallel type the user wants. If we've gotten no
     129             :   // indication so far, we will default to parallel
     130         490 :   if (_parallel_type == INVALID_PARALLELIZATION)
     131           0 :     _parallel_type = PARALLEL;
     132          14 :   libmesh_assert(_parallel_type != SERIAL);
     133             : 
     134        3240 :   for (const auto & [elem_id, dof_data] : _reduced_dof_map._elem_to_dof_data)
     135             :     {
     136         250 :       auto & matrix_data = _elem_to_matrix_data[elem_id];
     137             : 
     138         250 :       const auto condensed_dof_size = dof_data.condensed_global_to_local_map.size();
     139         250 :       const auto uncondensed_dof_size = dof_data.uncondensed_global_to_local_map.size();
     140             : 
     141        2750 :       matrix_data.Acc.setZero(condensed_dof_size, condensed_dof_size);
     142        2750 :       matrix_data.Acu.setZero(condensed_dof_size, uncondensed_dof_size);
     143        2750 :       matrix_data.Auc.setZero(uncondensed_dof_size, condensed_dof_size);
     144        2750 :       matrix_data.Auu.setZero(uncondensed_dof_size, uncondensed_dof_size);
     145             :     }
     146             : 
     147             :   //
     148             :   // Build the reduced system data
     149             :   //
     150         490 :   const auto n = _reduced_dof_map.n_dofs();
     151             :   const auto n_local =
     152         490 :       (_parallel_type == SERIAL) ? _reduced_dof_map.n_dofs() : _reduced_dof_map.n_local_dofs();
     153         966 :   _reduced_solver = LinearSolver<Number>::build(this->comm());
     154         504 :   _reduced_solver->init((_system.name() + "_condensed_").c_str());
     155         966 :   _reduced_rhs = NumericVector<Number>::build(this->comm());
     156             :   // Init the RHS vector so we can conveniently get processor row offsets
     157         490 :   _reduced_rhs->init(n, n_local);
     158             : 
     159             :   // Initialize the reduced system matrix
     160         490 :   _sp = _reduced_dof_map._reduced_sp.get();
     161         966 :   _reduced_sys_mat = SparseMatrix<Number>::build(this->comm());
     162         490 :   if (auto * const petsc_mat = dynamic_cast<PetscMatrix<Number> *>(_reduced_sys_mat.get()))
     163             :     {
     164             :       // Optimization for PETSc. This is critical for problems in which there are SCALAR dofs that
     165             :       // introduce dense rows to avoid allocating a dense matrix
     166         490 :       petsc_mat->init(
     167         490 :           n, n, n_local, n_local, _reduced_dof_map._reduced_nnz, _reduced_dof_map._reduced_noz);
     168             :     }
     169             :   else
     170             :     {
     171           0 :       const auto & nnz = _sp->get_n_nz();
     172           0 :       const auto & noz = _sp->get_n_oz();
     173           0 :       const auto nz = nnz.empty() ? dof_id_type(0) : *std::max_element(nnz.begin(), nnz.end());
     174           0 :       const auto oz = noz.empty() ? dof_id_type(0) : *std::max_element(noz.begin(), noz.end());
     175           0 :       _reduced_sys_mat->init(n, n, n_local, n_local, nz, oz);
     176             :     }
     177             : 
     178             :   // Build ghosted full solution vector. Note that this is, in general, *not equal* to the system
     179             :   // solution, e.g. this may correspond to the solution for the Newton *update*
     180         966 :   _ghosted_full_sol = _system.current_local_solution->clone();
     181             : 
     182         490 :   _sc_is_initialized = true;
     183             : }
     184             : 
     185        3780 : void StaticCondensation::close()
     186             : {
     187        3780 :   _communicator.max(_have_cached_values);
     188        3780 :   if (!_have_cached_values)
     189             :     {
     190        2450 :       bool closed = _reduced_sys_mat->closed();
     191             :       // closed is not collective
     192        2450 :       _communicator.min(closed);
     193        2450 :       if (!closed)
     194           0 :         _reduced_sys_mat->close();
     195          70 :       return;
     196             :     }
     197             : 
     198        1406 :   DenseMatrix<Number> shim;
     199          38 :   std::vector<dof_id_type> reduced_space_indices;
     200        6192 :   for (auto & [elem_id, matrix_data] : _elem_to_matrix_data)
     201             :     {
     202        4862 :       const auto & dof_data = libmesh_map_find(_reduced_dof_map._elem_to_dof_data, elem_id);
     203         442 :       reduced_space_indices.clear();
     204             : 
     205             :       // The result matrix is either a Schur complement or it's simply the result of summing element
     206             :       // matrices of the uncondensed degrees of freedom
     207         884 :       EigenMatrix result = matrix_data.Auu;
     208        4862 :       if (!_uncondensed_dofs_only)
     209             :         {
     210        4862 :           matrix_data.AccFactor = matrix_data.Acc.partialPivLu();
     211        4862 :           result -= matrix_data.Auc * matrix_data.AccFactor.solve(matrix_data.Acu);
     212             :         }
     213        5304 :       shim.resize(result.rows(), result.cols());
     214       65450 :       for (const auto i : make_range(result.rows()))
     215      869264 :         for (const auto j : make_range(result.cols()))
     216      882192 :           shim(i, j) = result(i, j);
     217       16060 :       for (const auto & var_reduced_space_indices : dof_data.reduced_space_indices)
     218       10180 :         reduced_space_indices.insert(reduced_space_indices.end(),
     219             :                                      var_reduced_space_indices.begin(),
     220        4072 :                                      var_reduced_space_indices.end());
     221        4862 :       _reduced_sys_mat->add_matrix(shim, reduced_space_indices);
     222             :     }
     223             : 
     224        1330 :   _reduced_sys_mat->close();
     225             : 
     226        1330 :   _have_cached_values = false;
     227        1254 : }
     228             : 
     229          14 : bool StaticCondensation::closed() const
     230             : {
     231          14 :   return _reduced_sys_mat->closed() && !_have_cached_values;
     232             : }
     233             : 
     234        1820 : void StaticCondensation::zero()
     235             : {
     236        1820 :   _reduced_sys_mat->zero();
     237        9432 :   for (auto & [elem_id, matrix_data] : _elem_to_matrix_data)
     238             :     {
     239         692 :       libmesh_ignore(elem_id);
     240        6920 :       matrix_data.Acc.setZero();
     241        6920 :       matrix_data.Acu.setZero();
     242        6920 :       matrix_data.Auc.setZero();
     243        6920 :       matrix_data.Auu.setZero();
     244             :     }
     245        1820 : }
     246             : 
     247         490 : void StaticCondensation::setup() { libmesh_assert(this->closed()); }
     248             : 
     249           0 : numeric_index_type StaticCondensation::m() const { return _full_dof_map.n_dofs(); }
     250             : 
     251           0 : numeric_index_type StaticCondensation::row_start() const { return _full_dof_map.first_dof(); }
     252             : 
     253           0 : numeric_index_type StaticCondensation::row_stop() const { return _full_dof_map.end_dof(); }
     254             : 
     255           0 : void StaticCondensation::set(const numeric_index_type full_i,
     256             :                              const numeric_index_type full_j,
     257             :                              const Number val)
     258             : {
     259           0 :   const auto reduced_i = _reduced_dof_map.get_reduced_from_global_constraint_dof(full_i);
     260           0 :   const auto reduced_j = _reduced_dof_map.get_reduced_from_global_constraint_dof(full_j);
     261           0 :   _reduced_sys_mat->set(reduced_i, reduced_j, val);
     262           0 : }
     263             : 
     264        4862 : void StaticCondensation::set_current_elem(const Elem & elem)
     265             : {
     266         442 :   libmesh_assert(!Threads::in_threads || libMesh::n_threads() == 1);
     267        4862 :   _current_elem_id = elem.id();
     268        4862 : }
     269             : 
     270           0 : void StaticCondensation::add(const numeric_index_type i,
     271             :                              const numeric_index_type j,
     272             :                              const Number value)
     273             : {
     274           0 :   _size_one_mat(0, 0) = value;
     275           0 :   this->add_matrix(_size_one_mat, {i}, {j});
     276           0 : }
     277             : 
     278       93566 : void StaticCondensation::add_matrix(const DenseMatrix<Number> & dm,
     279             :                                     const std::vector<numeric_index_type> & rows,
     280             :                                     const std::vector<numeric_index_type> & cols)
     281             : {
     282       93566 :   if (rows.empty() || cols.empty())
     283           0 :     return;
     284             : 
     285        8506 :   libmesh_assert(_current_elem_id != DofObject::invalid_id);
     286       93566 :   auto & matrix_data = libmesh_map_find(_elem_to_matrix_data, _current_elem_id);
     287       93566 :   const auto & dof_data = libmesh_map_find(_reduced_dof_map._elem_to_dof_data, _current_elem_id);
     288             :   EigenMatrix * mat;
     289             : 
     290     5398792 :   auto info_from_index = [&dof_data](const auto global_index) {
     291      385628 :     auto index_it = dof_data.condensed_global_to_local_map.find(global_index);
     292      385628 :     const bool index_is_condensed = index_it != dof_data.condensed_global_to_local_map.end();
     293     4241908 :     if (!index_is_condensed)
     294             :       {
     295      216160 :         index_it = dof_data.uncondensed_global_to_local_map.find(global_index);
     296     2377760 :         if (index_it == dof_data.uncondensed_global_to_local_map.end())
     297           0 :           libmesh_error_msg("Failed to find the global index "
     298             :                             << global_index
     299             :                             << " in our current element's degree of freedom information. One way "
     300             :                                "this can happen is when using a discontinuous Galerkin method, "
     301             :                                "adding element matrices to both + and - sides of a face");
     302             :       }
     303             :     else
     304             :       // We found the dof in the condensed container. Let's assert that it's not also in the
     305             :       // uncondensed container
     306      169468 :       libmesh_assert(dof_data.uncondensed_global_to_local_map.find(global_index) ==
     307             :                      dof_data.uncondensed_global_to_local_map.end());
     308             : 
     309     5013164 :     return std::make_pair(index_is_condensed, index_it->second);
     310       85060 :   };
     311             : 
     312      521576 :   for (const auto i : make_range(dm.m()))
     313     2548964 :     for (const auto j : make_range(dm.n()))
     314             :       {
     315     2120954 :         const auto global_i = rows[i];
     316     2120954 :         const auto global_j = cols[j];
     317     2120954 :         const auto [i_is_condensed, local_i] = info_from_index(global_i);
     318     2120954 :         const auto [j_is_condensed, local_j] = info_from_index(global_j);
     319     2120954 :         if (i_is_condensed)
     320             :           {
     321      982762 :             if (j_is_condensed)
     322      508926 :               mat = &matrix_data.Acc;
     323             :             else
     324      473836 :               mat = &matrix_data.Acu;
     325             :           }
     326             :         else
     327             :           {
     328     1138192 :             if (j_is_condensed)
     329      372460 :               mat = &matrix_data.Auc;
     330             :             else
     331      765732 :               mat = &matrix_data.Auu;
     332             :           }
     333     2313768 :         (*mat)(local_i, local_j) += dm(i, j);
     334             :       }
     335             : 
     336       93566 :   _have_cached_values = true;
     337             : }
     338             : 
     339        2046 : void StaticCondensation::add_matrix(const DenseMatrix<Number> & dm,
     340             :                                     const std::vector<numeric_index_type> & dof_indices)
     341             : {
     342        2046 :   this->add_matrix(dm, dof_indices, dof_indices);
     343        2046 : }
     344             : 
     345           0 : void StaticCondensation::add(const Number, const SparseMatrix<Number> &)
     346             : {
     347           0 :   libmesh_not_implemented();
     348             : }
     349             : 
     350           0 : Number StaticCondensation::operator()(const numeric_index_type, const numeric_index_type) const
     351             : {
     352           0 :   libmesh_not_implemented();
     353             : }
     354             : 
     355           0 : Real StaticCondensation::l1_norm() const { libmesh_not_implemented(); }
     356             : 
     357           0 : Real StaticCondensation::linfty_norm() const { libmesh_not_implemented(); }
     358             : 
     359           0 : void StaticCondensation::print_personal(std::ostream &) const { libmesh_not_implemented(); }
     360             : 
     361           0 : void StaticCondensation::get_diagonal(NumericVector<Number> &) const { libmesh_not_implemented(); }
     362             : 
     363           0 : void StaticCondensation::get_transpose(SparseMatrix<Number> &) const { libmesh_not_implemented(); }
     364             : 
     365           0 : void StaticCondensation::get_row(numeric_index_type,
     366             :                                  std::vector<numeric_index_type> &,
     367             :                                  std::vector<Number> &) const
     368             : {
     369           0 :   libmesh_not_implemented();
     370             : }
     371             : 
     372       14586 : void StaticCondensation::set_local_vectors(const NumericVector<Number> & global_vector,
     373             :                                            const std::vector<dof_id_type> & elem_dof_indices,
     374             :                                            std::vector<Number> & elem_dof_values_vec,
     375             :                                            EigenVector & elem_dof_values)
     376             : {
     377       14586 :   global_vector.get(elem_dof_indices, elem_dof_values_vec);
     378        2652 :   elem_dof_values.resize(elem_dof_indices.size());
     379      180642 :   for (const auto i : index_range(elem_dof_indices))
     380      196248 :     elem_dof_values(i) = elem_dof_values_vec[i];
     381       14586 : }
     382             : 
     383        1330 : void StaticCondensation::forward_elimination(const NumericVector<Number> & full_rhs)
     384             : {
     385          76 :   std::vector<dof_id_type> elem_condensed_dofs;
     386          76 :   std::vector<Number> elem_condensed_rhs_vec;
     387          76 :   EigenVector elem_condensed_rhs, elem_uncondensed_rhs;
     388             : 
     389        1330 :   full_rhs.create_subvector(
     390        1330 :       *_reduced_rhs, _reduced_dof_map._local_uncondensed_dofs, /*all_global_entries=*/false);
     391             : 
     392          76 :   std::vector<dof_id_type> reduced_space_indices;
     393       15440 :   for (auto elem : _mesh.active_local_element_ptr_range())
     394             :     {
     395        4862 :       auto & matrix_data = libmesh_map_find(_elem_to_matrix_data, elem->id());
     396         442 :       reduced_space_indices.clear();
     397        4862 :       const auto & dof_data = libmesh_map_find(_reduced_dof_map._elem_to_dof_data, elem->id());
     398       16060 :       for (const auto & var_reduced_space_indices : dof_data.reduced_space_indices)
     399       10180 :         reduced_space_indices.insert(reduced_space_indices.end(),
     400             :                                      var_reduced_space_indices.begin(),
     401        4072 :                                      var_reduced_space_indices.end());
     402        4862 :       elem_condensed_dofs.resize(dof_data.condensed_global_to_local_map.size());
     403       57596 :       for (const auto & [global_dof, local_dof] : dof_data.condensed_global_to_local_map)
     404             :         {
     405        4794 :           libmesh_assert(local_dof < elem_condensed_dofs.size());
     406       57528 :           elem_condensed_dofs[local_dof] = global_dof;
     407             :         }
     408             : 
     409        4862 :       set_local_vectors(full_rhs, elem_condensed_dofs, elem_condensed_rhs_vec, elem_condensed_rhs);
     410        4862 :       elem_uncondensed_rhs = -matrix_data.Auc * matrix_data.AccFactor.solve(elem_condensed_rhs);
     411             : 
     412         442 :       libmesh_assert(cast_int<std::size_t>(elem_uncondensed_rhs.size()) ==
     413             :                      reduced_space_indices.size());
     414        5304 :       _reduced_rhs->add_vector(elem_uncondensed_rhs.data(), reduced_space_indices);
     415        1254 :     }
     416        1330 :   _reduced_rhs->close();
     417        1330 : }
     418             : 
     419        1330 : void StaticCondensation::backwards_substitution(const NumericVector<Number> & full_rhs,
     420             :                                                 NumericVector<Number> & full_sol)
     421             : {
     422          76 :   std::vector<dof_id_type> elem_condensed_dofs, elem_uncondensed_dofs;
     423          76 :   std::vector<Number> elem_condensed_rhs_vec, elem_uncondensed_sol_vec;
     424          76 :   EigenVector elem_condensed_rhs, elem_uncondensed_sol, elem_condensed_sol;
     425             : 
     426       15440 :   for (auto elem : _mesh.active_local_element_ptr_range())
     427             :     {
     428        4862 :       auto & matrix_data = libmesh_map_find(_elem_to_matrix_data, elem->id());
     429        4862 :       const auto & dof_data = libmesh_map_find(_reduced_dof_map._elem_to_dof_data, elem->id());
     430        4862 :       elem_condensed_dofs.resize(dof_data.condensed_global_to_local_map.size());
     431        4862 :       elem_uncondensed_dofs.resize(dof_data.uncondensed_global_to_local_map.size());
     432       57596 :       for (const auto & [global_dof, local_dof] : dof_data.condensed_global_to_local_map)
     433             :         {
     434        4794 :           libmesh_assert(local_dof < elem_condensed_dofs.size());
     435       57528 :           elem_condensed_dofs[local_dof] = global_dof;
     436             :         }
     437       65450 :       for (const auto & [global_dof, local_dof] : dof_data.uncondensed_global_to_local_map)
     438             :         {
     439        5508 :           libmesh_assert(local_dof < elem_uncondensed_dofs.size());
     440       66096 :           elem_uncondensed_dofs[local_dof] = global_dof;
     441             :         }
     442             : 
     443        4862 :       set_local_vectors(full_rhs, elem_condensed_dofs, elem_condensed_rhs_vec, elem_condensed_rhs);
     444        4862 :       set_local_vectors(*_ghosted_full_sol,
     445             :                         elem_uncondensed_dofs,
     446             :                         elem_uncondensed_sol_vec,
     447             :                         elem_uncondensed_sol);
     448             : 
     449             :       elem_condensed_sol =
     450        5304 :           matrix_data.AccFactor.solve(elem_condensed_rhs - matrix_data.Acu * elem_uncondensed_sol);
     451        5304 :       full_sol.insert(elem_condensed_sol.data(), elem_condensed_dofs);
     452        1254 :     }
     453             : 
     454        1330 :   full_sol.close();
     455        1330 : }
     456             : 
     457        1330 : void StaticCondensation::apply(const NumericVector<Number> & full_rhs,
     458             :                                NumericVector<Number> & full_parallel_sol)
     459             : {
     460        1330 :   forward_elimination(full_rhs);
     461             :   // Apparently PETSc will send us the yvec without zeroing it ahead of time. This can be a poor
     462             :   // initial guess for the Krylov solve as well as lead to bewildered users who expect their initial
     463             :   // residual norm to equal the norm of the RHS
     464        1330 :   full_parallel_sol.zero();
     465        2622 :   _reduced_sol = full_parallel_sol.get_subvector(_reduced_dof_map._local_uncondensed_dofs);
     466        1368 :   _reduced_solver->solve(*_reduced_sys_mat, *_reduced_sol, *_reduced_rhs, 1e-5, 300);
     467             :   // Must restore to the full solution because during backwards substitution we will need to be able
     468             :   // to read ghosted dofs and we don't support ghosting of subvectors
     469        1368 :   full_parallel_sol.restore_subvector(std::move(_reduced_sol),
     470        1330 :                                       _reduced_dof_map._local_uncondensed_dofs);
     471        1330 :   *_ghosted_full_sol = full_parallel_sol;
     472        1330 :   backwards_substitution(full_rhs, full_parallel_sol);
     473        1330 : }
     474             : 
     475           0 : SolverPackage StaticCondensation::solver_package() { return libMesh::default_solver_package(); }
     476             : 
     477         280 : void StaticCondensation::dont_condense_vars(const std::unordered_set<unsigned int> & vars)
     478             : {
     479         280 :   _reduced_dof_map.dont_condense_vars(vars);
     480         280 : }
     481             : 
     482             : }
     483             : #else
     484             : 
     485             : #include "libmesh/dof_map.h"
     486             : 
     487             : namespace libMesh
     488             : {
     489           0 : StaticCondensation::StaticCondensation(const MeshBase &,
     490             :                                        const System &,
     491             :                                        const DofMap & full_dof_map,
     492           0 :                                        StaticCondensationDofMap &)
     493           0 :   : SparseMatrix<Number>(full_dof_map.comm())
     494             : {
     495           0 :   libmesh_error_msg(
     496             :       "Static condensation requires configuring libMesh with PETSc and Eigen support");
     497             : }
     498             : }
     499             : 
     500             : #endif // LIBMESH_HAVE_EIGEN && LIBMESH_HAVE_PETSC

Generated by: LCOV version 1.14