18#include "libmesh/enum_parallel_type.h"
19#include "libmesh/static_condensation.h"
21#if defined(LIBMESH_HAVE_EIGEN) && defined(LIBMESH_HAVE_PETSC)
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"
35#include <unordered_set>
41 const DofMap & full_dof_map,
46 _full_dof_map(full_dof_map),
47 _reduced_dof_map(reduced_dof_map),
49 _sc_is_initialized(false),
50 _have_cached_values(false),
52 _uncondensed_dofs_only(false)
55 _scp = std::make_unique<StaticCondensationPreconditioner>(*
this);
62 libmesh_not_implemented();
67 libmesh_not_implemented();
72 libmesh_not_implemented();
138 const auto condensed_dof_size = dof_data.condensed_global_to_local_map.size();
139 const auto uncondensed_dof_size = dof_data.uncondensed_global_to_local_map.size();
141 matrix_data.Acc.setZero(condensed_dof_size, condensed_dof_size);
142 matrix_data.Acu.setZero(condensed_dof_size, uncondensed_dof_size);
143 matrix_data.Auc.setZero(uncondensed_dof_size, condensed_dof_size);
144 matrix_data.Auu.setZero(uncondensed_dof_size, uncondensed_dof_size);
173 const auto nz = nnz.empty() ?
dof_id_type(0) : *std::max_element(nnz.begin(), nnz.end());
174 const auto oz = noz.empty() ?
dof_id_type(0) : *std::max_element(noz.begin(), noz.end());
199 std::vector<dof_id_type> reduced_space_indices;
203 reduced_space_indices.clear();
210 matrix_data.AccFactor = matrix_data.Acc.partialPivLu();
211 result -= matrix_data.Auc * matrix_data.AccFactor.solve(matrix_data.Acu);
213 shim.
resize(result.rows(), result.cols());
214 for (
const auto i :
make_range(result.rows()))
215 for (
const auto j :
make_range(result.cols()))
216 shim(i, j) = result(i, j);
217 for (
const auto & var_reduced_space_indices : dof_data.reduced_space_indices)
218 reduced_space_indices.insert(reduced_space_indices.end(),
219 var_reduced_space_indices.begin(),
220 var_reduced_space_indices.end());
240 matrix_data.Acc.setZero();
241 matrix_data.Acu.setZero();
242 matrix_data.Auc.setZero();
243 matrix_data.Auu.setZero();
279 const std::vector<numeric_index_type> & rows,
280 const std::vector<numeric_index_type> & cols)
282 if (rows.empty() || cols.empty())
290 auto info_from_index = [&dof_data](
const auto global_index) {
291 auto index_it = dof_data.condensed_global_to_local_map.find(global_index);
292 const bool index_is_condensed = index_it != dof_data.condensed_global_to_local_map.end();
293 if (!index_is_condensed)
295 index_it = dof_data.uncondensed_global_to_local_map.find(global_index);
296 if (index_it == dof_data.uncondensed_global_to_local_map.end())
297 libmesh_error_msg(
"Failed to find the 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");
306 libmesh_assert(dof_data.uncondensed_global_to_local_map.find(global_index) ==
307 dof_data.uncondensed_global_to_local_map.end());
309 return std::make_pair(index_is_condensed, index_it->second);
315 const auto global_i = rows[i];
316 const auto global_j = cols[j];
317 const auto [i_is_condensed, local_i] = info_from_index(global_i);
318 const auto [j_is_condensed, local_j] = info_from_index(global_j);
322 mat = &matrix_data.Acc;
324 mat = &matrix_data.Acu;
329 mat = &matrix_data.Auc;
331 mat = &matrix_data.Auu;
333 (*mat)(local_i, local_j) += dm(i, j);
340 const std::vector<numeric_index_type> & dof_indices)
342 this->
add_matrix(dm, dof_indices, dof_indices);
347 libmesh_not_implemented();
352 libmesh_not_implemented();
366 std::vector<numeric_index_type> &,
367 std::vector<Number> &)
const
369 libmesh_not_implemented();
373 const std::vector<dof_id_type> & elem_dof_indices,
374 std::vector<Number> & elem_dof_values_vec,
377 global_vector.
get(elem_dof_indices, elem_dof_values_vec);
378 elem_dof_values.resize(elem_dof_indices.size());
380 elem_dof_values(i) = elem_dof_values_vec[i];
385 std::vector<dof_id_type> elem_condensed_dofs;
386 std::vector<Number> elem_condensed_rhs_vec;
387 EigenVector elem_condensed_rhs, elem_uncondensed_rhs;
392 std::vector<dof_id_type> reduced_space_indices;
393 for (
auto elem :
_mesh.active_local_element_ptr_range())
396 reduced_space_indices.clear();
398 for (
const auto & var_reduced_space_indices : dof_data.reduced_space_indices)
399 reduced_space_indices.insert(reduced_space_indices.end(),
400 var_reduced_space_indices.begin(),
401 var_reduced_space_indices.end());
402 elem_condensed_dofs.resize(dof_data.condensed_global_to_local_map.size());
403 for (
const auto & [global_dof, local_dof] : dof_data.condensed_global_to_local_map)
406 elem_condensed_dofs[local_dof] = global_dof;
409 set_local_vectors(full_rhs, elem_condensed_dofs, elem_condensed_rhs_vec, elem_condensed_rhs);
410 elem_uncondensed_rhs = -matrix_data.Auc * matrix_data.AccFactor.solve(elem_condensed_rhs);
412 libmesh_assert(cast_int<std::size_t>(elem_uncondensed_rhs.size()) ==
413 reduced_space_indices.size());
414 _reduced_rhs->add_vector(elem_uncondensed_rhs.data(), reduced_space_indices);
422 std::vector<dof_id_type> elem_condensed_dofs, elem_uncondensed_dofs;
423 std::vector<Number> elem_condensed_rhs_vec, elem_uncondensed_sol_vec;
424 EigenVector elem_condensed_rhs, elem_uncondensed_sol, elem_condensed_sol;
426 for (
auto elem :
_mesh.active_local_element_ptr_range())
430 elem_condensed_dofs.resize(dof_data.condensed_global_to_local_map.size());
431 elem_uncondensed_dofs.resize(dof_data.uncondensed_global_to_local_map.size());
432 for (
const auto & [global_dof, local_dof] : dof_data.condensed_global_to_local_map)
435 elem_condensed_dofs[local_dof] = global_dof;
437 for (
const auto & [global_dof, local_dof] : dof_data.uncondensed_global_to_local_map)
440 elem_uncondensed_dofs[local_dof] = global_dof;
443 set_local_vectors(full_rhs, elem_condensed_dofs, elem_condensed_rhs_vec, elem_condensed_rhs);
445 elem_uncondensed_dofs,
446 elem_uncondensed_sol_vec,
447 elem_uncondensed_sol);
450 matrix_data.AccFactor.solve(elem_condensed_rhs - matrix_data.Acu * elem_uncondensed_sol);
451 full_sol.
insert(elem_condensed_sol.data(), elem_condensed_dofs);
464 full_parallel_sol.
zero();
485#include "libmesh/dof_map.h"
491 const DofMap & full_dof_map,
496 "Static condensation requires configuring libMesh with PETSc and Eigen support");
void max(const T &r, T &o, Request &req) const
void min(const T &r, T &o, Request &req) const
Defines a dense matrix for use in Finite Element-type computations.
void resize(const unsigned int new_m, const unsigned int new_n)
Resizes the matrix to the specified size and calls zero().
dof_id_type n_dofs() const
dof_id_type first_dof(const processor_id_type proc) const
dof_id_type end_dof(const processor_id_type proc) const
dof_id_type n_local_dofs() const
This class handles the numbering of degrees of freedom on a mesh.
dof_id_type n_dofs(const unsigned int vn) const
The DofObject defines an abstract base class for objects that have degrees of freedom associated with...
static constexpr dof_id_type invalid_id
An invalid id to distinguish an uninitialized DofObject.
This is the base class from which all geometric element types are derived.
static std::unique_ptr< LinearSolver< T > > build(const libMesh::Parallel::Communicator &comm_in, const SolverPackage solver_package=libMesh::default_solver_package())
Builds a LinearSolver using the linear solver package specified by solver_package.
This is the MeshBase class.
Provides a uniform interface to vector storage schemes for different linear algebra libraries.
virtual std::unique_ptr< NumericVector< T > > get_subvector(const std::vector< numeric_index_type > &)
Creates a view into this vector using the indices in rows.
virtual void get(const std::vector< numeric_index_type > &index, T *values) const
Access multiple components at once.
virtual void create_subvector(NumericVector< T > &, const std::vector< numeric_index_type > &, bool=true) const
Fills in subvector from this vector using the indices in rows.
virtual void close()=0
Calls the NumericVector's internal assembly routines, ensuring that the values are consistent across ...
virtual void insert(const T *v, const std::vector< numeric_index_type > &dof_indices)
Inserts the entries of v in *this at the locations specified by v.
static std::unique_ptr< NumericVector< T > > build(const Parallel::Communicator &comm, SolverPackage solver_package=libMesh::default_solver_package(), ParallelType parallel_type=AUTOMATIC)
Builds a NumericVector on the processors in communicator comm using the linear solver package specifi...
virtual void zero()=0
Set all entries to zero.
virtual void restore_subvector(std::unique_ptr< NumericVector< T > >, const std::vector< numeric_index_type > &)
Restores a view into this vector using the indices in rows.
const Parallel::Communicator & _communicator
const Parallel::Communicator & comm() const
processor_id_type n_processors() const
virtual void clear() noexcept override
clear() is called from the destructor, so it should not throw.
This class allows to use a PETSc shell matrix as a PetscMatrix.
virtual void init(const numeric_index_type m, const numeric_index_type n, const numeric_index_type m_l, const numeric_index_type n_l, const numeric_index_type=30, const numeric_index_type=10, const numeric_index_type blocksize=1) override
Initialize SparseMatrix with the specified sizes.
This class provides a nice interface to the PETSc C-based AIJ data structures for parallel,...
static std::unique_ptr< SparseMatrix< T > > build(const Parallel::Communicator &comm, const SolverPackage solver_package=libMesh::default_solver_package(), const MatrixBuildType matrix_build_type=MatrixBuildType::AUTOMATIC)
Builds a SparseMatrix<T> using the linear solver package specified by solver_package.
virtual bool initialized() const
SparsityPattern::Build const * _sp
The sparsity pattern associated with this object.
const std::vector< dof_id_type > & get_n_oz() const
The number of off-processor nonzeros in my portion of the global matrix.
const std::vector< dof_id_type > & get_n_nz() const
The number of on-processor nonzeros in my portion of the global matrix.
A class holding degree of freedom information pertinent to static condensation.
void dont_condense_vars(const std::unordered_set< unsigned int > &vars)
Add vars to the list of variables not to condense.
dof_id_type get_reduced_from_global_constraint_dof(dof_id_type full_dof) const
Retrieve the dof index in the reduced system corresponding to the provided dof index in the full syst...
std::vector< dof_id_type > _local_uncondensed_dofs
All the uncondensed degrees of freedom (numbered in the "full" uncondensed + condensed space).
std::unique_ptr< SparsityPattern::Build > _reduced_sp
Owned storage of the reduced system sparsity pattern.
std::unordered_map< dof_id_type, DofData > _elem_to_dof_data
A map from element ID to Schur complement data.
std::vector< dof_id_type > _reduced_noz
Number of off-diagonal nonzeros per row in the reduced system.
std::vector< dof_id_type > _reduced_nnz
Number of on-diagonal nonzeros per row in the reduced system.
bool initialized() const
Whether we are initialized.
virtual numeric_index_type row_start() const override
virtual void set(const numeric_index_type i, const numeric_index_type j, const Number value) override
Set the element (i,j) to value.
StaticCondensation(const MeshBase &mesh, System &system, const DofMap &full_dof_map, StaticCondensationDofMap &reduced_dof_map)
virtual void get_diagonal(NumericVector< Number > &dest) const override
Copies the diagonal part of the matrix into dest.
static void set_local_vectors(const NumericVector< Number > &global_vector, const std::vector< dof_id_type > &elem_dof_indices, std::vector< Number > &elem_dof_values_vec, EigenVector &elem_dof_values)
Retrieves the degree of freedom values from global_vector corresponding to elem_dof_indices,...
DenseMatrix< Number > _size_one_mat
Helper data member for adding individual matrix elements.
void backwards_substitution(const NumericVector< Number > &full_rhs, NumericVector< Number > &full_sol)
After performing the solve with the _reduced_rhs and Schur complement matrix (_reduced_sys_mat) to de...
void set_current_elem(const Elem &elem)
Set the current element.
dof_id_type _current_elem_id
The current element ID.
virtual numeric_index_type n() const override
std::unique_ptr< LinearSolver< Number > > _reduced_solver
The solver for the uncondensed degrees of freedom.
virtual void clear() noexcept override
clear() is called from the destructor, so it should not throw.
virtual bool initialized() const override
ParallelType _parallel_type
The parallel type to use for the reduced matrix.
virtual numeric_index_type row_stop() const override
virtual void print_personal(std::ostream &os=libMesh::out) const override
Print the contents of the matrix to the screen in a package-personalized style, if available.
virtual SparseMatrix< Number > & operator=(const SparseMatrix< Number > &) override
This looks like a copy assignment operator, but note that, unlike normal copy assignment operators,...
virtual Real l1_norm() const override
virtual SolverPackage solver_package() override
std::unique_ptr< NumericVector< Number > > _ghosted_full_sol
This is a ghosted representation of the full (uncondensed + condensed) solution. Note that.
virtual void get_row(numeric_index_type i, std::vector< numeric_index_type > &indices, std::vector< Number > &values) const override
Get a row from the matrix.
virtual numeric_index_type m() const override
virtual Real linfty_norm() const override
virtual bool closed() const override
virtual std::unique_ptr< SparseMatrix< Number > > clone() const override
StaticCondensationDofMap & _reduced_dof_map
bool _uncondensed_dofs_only
whether this matrix represents uncondensed dofs only.
virtual std::unique_ptr< SparseMatrix< Number > > zero_clone() const override
std::unique_ptr< NumericVector< Number > > _reduced_rhs
RHS corresponding to the uncondensed degrees of freedom.
std::unordered_map< dof_id_type, MatrixData > _elem_to_matrix_data
A map from element ID to Schur complement data.
virtual void add_matrix(const DenseMatrix< Number > &dm, const std::vector< numeric_index_type > &rows, const std::vector< numeric_index_type > &cols) override
Add the full matrix dm to the SparseMatrix.
std::unique_ptr< SparseMatrix< Number > > _reduced_sys_mat
global sparse matrix for the uncondensed degrees of freedom
void dont_condense_vars(const std::unordered_set< unsigned int > &vars)
Add vars to the list of variables not to condense.
std::unique_ptr< NumericVector< Number > > _reduced_sol
solution for the uncondensed degrees of freedom
virtual void get_transpose(SparseMatrix< Number > &dest) const override
Copies the transpose of the matrix into dest, which may be *this.
bool _have_cached_values
Whether we have cached values via add_XXX()
void init()
Size the element matrices.
std::unique_ptr< StaticCondensationPreconditioner > _scp
Preconditioner object which will call back to us for the preconditioning action.
void apply(const NumericVector< Number > &full_rhs, NumericVector< Number > &full_sol)
Perform our three stages, forward_elimination(), a solve() on the condensed system,...
virtual void close() override
Calls the SparseMatrix's internal assembly routines, ensuring that the values are consistent across p...
const DofMap & _full_dof_map
virtual void add(const numeric_index_type i, const numeric_index_type j, const Number value) override
Add value to the element (i,j).
bool _sc_is_initialized
Whether our object has been initialized.
void forward_elimination(const NumericVector< Number > &full_rhs)
Takes an incoming "full" RHS from the solver, where full means the union of uncondensed and condennse...
virtual ~StaticCondensation()
virtual void zero() override
Set all entries to 0.
virtual Number operator()(const numeric_index_type i, const numeric_index_type j) const override
void setup()
A no-op to be consistent with shimming from the StaticCondenstionPreconditioner.
Manages consistently variables, degrees of freedom, and coefficient vectors.
const std::string & name() const
std::unique_ptr< NumericVector< Number > > current_local_solution
All the values I need to compute my contribution to the simulation at hand.
bool in_threads
A boolean which is true iff we are in a Threads:: function It may be useful to assert(!...
The libMesh namespace provides an interface to certain functionality in the library.
Eigen::Matrix< Number, Eigen::Dynamic, Eigen::Dynamic > EigenMatrix
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
ParallelType
Defines an enum for parallel data structure types.
@ INVALID_PARALLELIZATION
void libmesh_ignore(const Args &...)
SolverPackage default_solver_package()
dof_id_type numeric_index_type
SolverPackage
Defines an enum for various linear solver packages.
Eigen::Matrix< Number, Eigen::Dynamic, 1 > EigenVector
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...