Files
mfem/miniapps/dpg/util/pweakform.cpp
T

223 lines
5.7 KiB
C++

// Copyright (c) 2010-2025, 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 "pweakform.hpp"
#ifdef MFEM_USE_MPI
namespace mfem
{
void ParDPGWeakForm::FillEssTdofLists(const Array<int> & 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 ParDPGWeakForm::Assemble(int skip_zeros)
{
DPGWeakForm::Assemble(skip_zeros);
}
void ParDPGWeakForm::ParallelAssemble(BlockMatrix *m)
{
if (!P) { BuildProlongation(); }
p_mat = new BlockOperator(tdof_offsets);
p_mat_e = new BlockOperator(tdof_offsets);
p_mat->owns_blocks = 1;
p_mat_e->owns_blocks = 1;
HypreParMatrix * A = nullptr;
HypreParMatrix * PtAP = nullptr;
for (int i = 0; i<nblocks; i++)
{
HypreParMatrix * Pi = (HypreParMatrix*)(&P->GetBlock(i,i));
HypreParMatrix * Pit = Pi->Transpose();
for (int j = 0; j<nblocks; j++)
{
if (m->IsZeroBlock(i,j)) { continue; }
if (i == j)
{
// Make block diagonal square hypre matrix
A = new HypreParMatrix(trial_pfes[i]->GetComm(), trial_pfes[i]->GlobalVSize(),
trial_pfes[i]->GetDofOffsets(),&m->GetBlock(i,i));
PtAP = RAP(A,Pi);
delete A;
p_mat_e->SetBlock(i,i,PtAP->EliminateRowsCols(*ess_tdofs[i]));
}
else
{
HypreParMatrix * Pj = (HypreParMatrix*)(&P->GetBlock(j,j));
A = new HypreParMatrix(trial_pfes[i]->GetComm(), trial_pfes[i]->GlobalVSize(),
trial_pfes[j]->GlobalVSize(), trial_pfes[i]->GetDofOffsets(),
trial_pfes[j]->GetDofOffsets(), &m->GetBlock(i,j));
HypreParMatrix * APj = ParMult(A, Pj,true);
delete A;
PtAP = ParMult(Pit,APj,true);
delete APj;
p_mat_e->SetBlock(i,j,PtAP->EliminateCols(*ess_tdofs[j]));
PtAP->EliminateRows(*ess_tdofs[i]);
}
p_mat->SetBlock(i,j,PtAP);
}
delete Pit;
}
}
void ParDPGWeakForm::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<SparseMatrix*>(R_));
}
}
void ParDPGWeakForm::FormLinearSystem(const Array<int>
&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
{
B.SetSize(P->Width());
P->MultTranspose(*y,B);
X.SetSize(R->Height());
R->Mult(x,X);
// eliminate tdof in RHS
// B -= Ae*X
Vector tmp(B.Size());
p_mat_e->Mult(X,tmp);
B-=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(gdof) = X(gdof); // diagonal policy in always one in parallel
}
}
if (!copy_interior) { X.SetSubVectorComplement(ess_tdof_list, 0.0); }
}
}
void ParDPGWeakForm::FormSystemMatrix(const Array<int>
&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->GetParallelSchurMatrix(), false);
}
else
{
FillEssTdofLists(ess_tdof_list);
if (mat)
{
const int remove_zeros = 0;
Finalize(remove_zeros);
ParallelAssemble(mat);
delete mat;
mat = nullptr;
delete mat_e;
mat_e = nullptr;
}
A.Reset(p_mat,false);
}
}
void ParDPGWeakForm::RecoverFEMSolution(const Vector &X,
Vector &x)
{
if (static_cond)
{
static_cond->ComputeSolution(X, x);
}
else
{
x.SetSize(P->Height());
P->Mult(X, x);
}
}
void ParDPGWeakForm::Update()
{
DPGWeakForm::Update();
delete p_mat_e;
p_mat_e = nullptr;
delete p_mat;
p_mat = nullptr;
for (int i = 0; i<nblocks; i++)
{
delete ess_tdofs[i];
ess_tdofs[i] = new Array<int>();
}
delete P;
P = nullptr;
delete R;
R = nullptr;
}
ParDPGWeakForm::~ParDPGWeakForm()
{
delete p_mat_e;
p_mat_e = 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