// 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. #include "pcomplexweakform.hpp" #ifdef MFEM_USE_MPI namespace mfem { void ParComplexDPGWeakForm::FillEssTdofLists(const Array & ess_tdof_list) { int j; for (int i = 0; i < ess_tdof_list.Size(); i++) { int tdof = ess_tdof_list[i]; for (j = 0; j < nblocks; j++) { if (tdof_offsets[j+1] > tdof) { break; } } ess_tdofs[j]->Append(tdof-tdof_offsets[j]); } } void ParComplexDPGWeakForm::Assemble(int skip_zeros) { ComplexDPGWeakForm::Assemble(skip_zeros); } void ParComplexDPGWeakForm::ParallelAssemble(BlockMatrix *m_r, BlockMatrix *m_i) { if (!P) { BuildProlongation(); } p_mat_r = new BlockOperator(tdof_offsets); p_mat_i = new BlockOperator(tdof_offsets); p_mat_e_r = new BlockOperator(tdof_offsets); p_mat_e_i = new BlockOperator(tdof_offsets); p_mat_r->owns_blocks = 1; p_mat_i->owns_blocks = 1; p_mat_e_r->owns_blocks = 1; p_mat_e_i->owns_blocks = 1; HypreParMatrix * A_r = nullptr; HypreParMatrix * A_i = nullptr; HypreParMatrix * PtAP_r = nullptr; HypreParMatrix * PtAP_i = nullptr; for (int i = 0; i < nblocks; i++) { HypreParMatrix * Pi = (HypreParMatrix*)(&P->GetBlock(i,i)); for (int j = 0; jIsZeroBlock(i,j)) { continue; } if (i == j) { // Make block diagonal square hypre matrix A_r = new HypreParMatrix(trial_pfes[i]->GetComm(), trial_pfes[i]->GlobalVSize(), trial_pfes[i]->GetDofOffsets(), &m_r->GetBlock(i,i)); PtAP_r = RAP(A_r,Pi); delete A_r; p_mat_e_r->SetBlock(i, i, PtAP_r->EliminateRowsCols(*ess_tdofs[i])); A_i = new HypreParMatrix(trial_pfes[i]->GetComm(), trial_pfes[i]->GlobalVSize(), trial_pfes[i]->GetDofOffsets(), &m_i->GetBlock(i,i)); PtAP_i = RAP(A_i,Pi); delete A_i; p_mat_e_i->SetBlock(i, i, PtAP_i->EliminateCols(*ess_tdofs[i])); PtAP_i->EliminateRows(*ess_tdofs[i]); } else { HypreParMatrix * Pj = (HypreParMatrix*)(&P->GetBlock(j,j)); A_r = new HypreParMatrix(trial_pfes[i]->GetComm(), trial_pfes[i]->GlobalVSize(), trial_pfes[j]->GlobalVSize(), trial_pfes[i]->GetDofOffsets(), trial_pfes[j]->GetDofOffsets(), &m_r->GetBlock(i,j)); PtAP_r = RAP(Pi,A_r,Pj); delete A_r; p_mat_e_r->SetBlock(i, j, PtAP_r->EliminateCols(*ess_tdofs[j])); PtAP_r->EliminateRows(*ess_tdofs[i]); A_i = new HypreParMatrix(trial_pfes[i]->GetComm(), trial_pfes[i]->GlobalVSize(), trial_pfes[j]->GlobalVSize(), trial_pfes[i]->GetDofOffsets(), trial_pfes[j]->GetDofOffsets(), &m_i->GetBlock(i,j)); PtAP_i = RAP(Pi,A_i,Pj); delete A_i; p_mat_e_i->SetBlock(i, j, PtAP_i->EliminateCols(*ess_tdofs[j])); PtAP_i->EliminateRows(*ess_tdofs[i]); } p_mat_r->SetBlock(i, j, PtAP_r); p_mat_i->SetBlock(i, j, PtAP_i); } } } void ParComplexDPGWeakForm::BuildProlongation() { P = new BlockOperator(dof_offsets, tdof_offsets); R = new BlockMatrix(tdof_offsets, dof_offsets); P->owns_blocks = 0; R->owns_blocks = 0; for (int i = 0; i < nblocks; i++) { HypreParMatrix * P_ = trial_pfes[i]->Dof_TrueDof_Matrix(); P->SetBlock(i,i,P_); const SparseMatrix * R_ = trial_pfes[i]->GetRestrictionMatrix(); R->SetBlock(i, i, const_cast(R_)); } } void ParComplexDPGWeakForm::FormLinearSystem(const Array &ess_tdof_list, Vector &x, OperatorHandle &A, Vector &X, Vector &B, int copy_interior) { FormSystemMatrix(ess_tdof_list, A); if (static_cond) { static_cond->ReduceSystem(x, X, B, copy_interior); } else { int n = P->Width(); B.SetSize(2*n); Vector B_r(B, 0, n); Vector B_i(B, n, n); P->MultTranspose(*y_r, B_r); P->MultTranspose(*y_i, B_i); int m = R->Height(); X.SetSize(2*m); Vector X_r(X, 0, m); Vector X_i(X, m, m); Vector x_r(x, 0, x.Size()/2); Vector x_i(x, x.Size()/2, x.Size()/2); R->Mult(x_r, X_r); R->Mult(x_i, X_i); // eliminate tdof is RHS // B_r -= Ae_r*X_r + Ae_i X_i // B_i -= Ae_i*X_r + Ae_r X_i Vector tmp(B_r.Size()); p_mat_e_r->Mult(X_r, tmp); B_r-=tmp; p_mat_e_i->Mult(X_i, tmp); B_r+=tmp; p_mat_e_i->Mult(X_r, tmp); B_i-=tmp; p_mat_e_r->Mult(X_i, tmp); B_i-=tmp; for (int j = 0; j < nblocks; j++) { if (!ess_tdofs[j]->Size()) { continue; } for (int i = 0; i < ess_tdofs[j]->Size(); i++) { int tdof = (*ess_tdofs[j])[i]; int gdof = tdof + tdof_offsets[j]; B_r(gdof) = X_r(gdof); // diagonal policy is always one in parallel B_i(gdof) = X_i(gdof); // diagonal policy is always one in parallel } } if (!copy_interior) { X_r.SetSubVectorComplement(ess_tdof_list, 0.0); X_i.SetSubVectorComplement(ess_tdof_list, 0.0); } } } void ParComplexDPGWeakForm::FormSystemMatrix(const Array &ess_tdof_list, OperatorHandle &A) { if (static_cond) { if (!static_cond->HasEliminatedBC()) { static_cond->SetEssentialTrueDofs(ess_tdof_list); static_cond->FormSystemMatrix(Operator::DiagonalPolicy::DIAG_ONE); } A.Reset(&static_cond->GetSchurComplexOperator(), false); } else { FillEssTdofLists(ess_tdof_list); if (mat_r) { const int remove_zeros = 0; Finalize(remove_zeros); ParallelAssemble(mat_r, mat_i); delete mat_r; delete mat_i; mat_r = nullptr; mat_i = nullptr; delete mat_e_r; delete mat_e_i; mat_e_r = nullptr; mat_e_i = nullptr; } p_mat = new ComplexOperator(p_mat_r, p_mat_i, false, false); A.Reset(p_mat, false); } } void ParComplexDPGWeakForm::RecoverFEMSolution(const Vector &X, Vector &x) { if (static_cond) { static_cond->ComputeSolution(X, x); } else { int n = P->Height(); int m = P->Width(); x.SetSize(2*n); Vector x_r(x,0,n); Vector x_i(x,n,n); Vector X_r(const_cast(X), 0, m); Vector X_i(const_cast(X), m, m); P->Mult(X_r, x_r); P->Mult(X_i, x_i); } } void ParComplexDPGWeakForm::Update() { ComplexDPGWeakForm::Update(); delete p_mat_e_r; delete p_mat_e_i; p_mat_e_r = nullptr; p_mat_e_i = nullptr; delete p_mat_r; delete p_mat_i; p_mat_r = nullptr; p_mat_i = nullptr; delete p_mat; p_mat = nullptr; for (int i = 0; i < nblocks; i++) { delete ess_tdofs[i]; ess_tdofs[i] = new Array(); } delete P; P = nullptr; delete R; R = nullptr; } ParComplexDPGWeakForm::~ParComplexDPGWeakForm() { delete p_mat_e_r; delete p_mat_e_i; p_mat_e_r = nullptr; p_mat_e_i = nullptr; delete p_mat_r; delete p_mat_i; p_mat_r = nullptr; p_mat_i = nullptr; delete p_mat; p_mat = nullptr; for (int i = 0; i < nblocks; i++) { delete ess_tdofs[i]; } delete P; delete R; } } // namespace mfem #endif