// Copyright (c) 2010-2023, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // // This file is part of the MFEM library. For more information and source code // availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the // terms of the BSD-3 license. We welcome feedback and contributions, see file // CONTRIBUTING.md for details. #ifndef MFEM_COMPLEX_BLOCK_STATIC_CONDENSATION #define MFEM_COMPLEX_BLOCK_STATIC_CONDENSATION #include "mfem.hpp" namespace mfem { /** @brief Class that performs static condensation of interior dofs for multiple FE spaces for complex systems (see BlockStaticCondensation). It's used by the class ComplexDPGWeakForm. */ class ComplexBlockStaticCondensation { int height, width; int nblocks; // original number of blocks int rblocks; // reduces number of blocks Mesh * mesh = nullptr; bool parallel = false; // original set of Finite Element Spaces Array fes; // indicates if the original space is already a trace space Array IsTraceSpace; // New set of "reduced" Finite Element Spaces // (after static condensation) Array tr_fes; Array dof_offsets; Array tdof_offsets; Array rdof_offsets; Array rtdof_offsets; // Schur complement matrix // S = A_ii - A_ib (A_bb)^{-1} A_bi. BlockMatrix * S_r = nullptr; BlockMatrix * S_i = nullptr; BlockMatrix * S_e_r = nullptr; BlockMatrix * S_e_i = nullptr; ComplexOperator * S = nullptr; BlockVector * y_r = nullptr; BlockVector * y_i = nullptr; Vector * y = nullptr; Array lmat; Array lvec; Array rdof_edof; // Map from reduced dofs to exposed dofs Array ess_rtdof_list; BlockMatrix * P = nullptr; // Block Prolongation BlockMatrix * R = nullptr; // Block Restriction #ifdef MFEM_USE_MPI BlockOperator * pS_r = nullptr; BlockOperator * pS_e_r = nullptr; BlockOperator * pS_i = nullptr; BlockOperator * pS_e_i = nullptr; // Block HypreParMatrix for Prolongation BlockOperator * pP = nullptr; #endif bool Parallel() const { return parallel; } // tr_idx (trace dofs indices) // int_idx (interior dof indices) void GetReduceElementIndicesAndOffsets(int el, Array & tr_idx, Array & int_idx, Array & offsets) const; void GetReduceElementVDofs(int el, Array & rdofs) const; void GetElementVDofs(int el, Array & vdofs) const; // S = A_ii - A_ib (A_bb)^{-1} A_bi. // y = y_i - A_ib (A_bb)^{-1} y_b ComplexDenseMatrix * GetLocalShurComplement(int el, const Array & tr_idx, const Array & int_idx, const ComplexDenseMatrix & elmat, const Vector & elvect_r, const Vector & elvect_i, Vector & rvect_r, Vector & rvect_i); void ComputeOffsets(); void BuildProlongation(); #ifdef MFEM_USE_MPI void BuildParallelProlongation(); #endif // ess_tdof list for each space Array *> ess_tdofs; void FillEssTdofLists(const Array & ess_tdof_list); void ConformingAssemble(int skip_zeros); /** Restrict a marker Array on the true FE spaces dofs to a marker Array on the reduced/trace true FE spaces dofs. */ void ConvertMarkerToReducedTrueDofs(Array & tdof_marker, Array & rtdof_marker); void SetSpaces(Array & fes_); void Init(); public: ComplexBlockStaticCondensation(Array & fes_); ~ComplexBlockStaticCondensation(); /** Assemble the contribution to the Schur complement from the given element matrix @a elmat. Save the other blocks internally: A_bb_inv, A_bi, and A_bi. */ void AssembleReducedSystem(int el, ComplexDenseMatrix &elmat, Vector & elvect_r, Vector & elvect_i); /// Finalize the construction of the Schur complement matrix. void Finalize(int skip_zeros = 0); /// Determine and save internally essential reduced true dofs. void SetEssentialTrueDofs(const Array &ess_tdof_list); /// Eliminate the given reduced true dofs from the Schur complement matrix S. void EliminateReducedTrueDofs(const Array &ess_rtdof_list, Matrix::DiagonalPolicy dpolicy); bool HasEliminatedBC() const { #ifndef MFEM_USE_MPI return S_e_r; #else return S_e_r || pS_e_r; #endif } /// Return the serial Schur complement matrix. BlockMatrix &GetSchurMatrix_r() { return *S_r; } BlockMatrix &GetSchurMatrix_i() { return *S_i; } ComplexOperator &GetSchurComplexOperator() { if (!S) { #ifndef MFEM_USE_MPI S = new ComplexOperator(S_r,S_i,false,false); #else if (parallel) { S = new ComplexOperator(pS_r,pS_i,false,false); } else { S = new ComplexOperator(S_r,S_i,false,false); } #endif } return *S; } /// Return the eliminated part of the serial Schur complement matrix. BlockMatrix &GetSchurMatrixElim_r() { return *S_e_r; } BlockMatrix &GetSchurMatrixElim_i() { return *S_e_i; } #ifdef MFEM_USE_MPI /// Return the parallel Schur complement matrix. BlockOperator &GetParallelSchurMatrix_r() { return *pS_r; } BlockOperator &GetParallelSchurMatrix_i() { return *pS_i; } /// Return the eliminated part of the parallel Schur complement matrix. BlockOperator &GetParallelSchurMatrixElim_r() { return *pS_e_r; } BlockOperator &GetParallelSchurMatrixElim_i() { return *pS_e_i; } void ParallelAssemble(BlockMatrix *m_r, BlockMatrix*m_i); #endif /** Form the global reduced system matrix using the given @a diag_policy. This method can be called after Assemble() is called. */ void FormSystemMatrix(Operator::DiagonalPolicy diag_policy); /** Restrict a solution vector on the full FE space dofs to a vector on the reduced/trace true FE space dofs. */ void ReduceSolution(const Vector &sol, Vector &sc_sol) const; /** @brief Set the reduced solution `X` and r.h.s `B` vectors from the full linear system solution `x` and r.h.s. `b` vectors. This method should be called after the internal reduced essential dofs have been set using SetEssentialTrueDofs() and both the Schur complement and its eliminated part have been finalized. */ void ReduceSystem(Vector &x, Vector &X, Vector &B, int copy_interior = 0) const; /** Restrict a list of true FE space dofs to a list of reduced/trace true FE space dofs. */ void ConvertListToReducedTrueDofs(const Array &ess_tdof_list, Array &ess_rtdof_list) const; /** Given a solution of the reduced system 'sc_sol' and the RHS 'b' for the full linear system, compute the solution of the full system 'sol'. */ void ComputeSolution(const Vector &sc_sol, Vector &sol) const; }; } #endif