936 lines
24 KiB
C++
936 lines
24 KiB
C++
// Copyright (c) 2010-2024, 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 "darcyform.hpp"
|
|
|
|
namespace mfem
|
|
{
|
|
|
|
DarcyForm::DarcyForm(FiniteElementSpace *fes_u_, FiniteElementSpace *fes_p_,
|
|
bool bsymmetrize)
|
|
: fes_u(fes_u_), fes_p(fes_p_), bsym(bsymmetrize)
|
|
{
|
|
offsets.SetSize(3);
|
|
offsets[0] = 0;
|
|
offsets[1] = fes_u->GetVSize();
|
|
offsets[2] = fes_p->GetVSize();
|
|
offsets.PartialSum();
|
|
|
|
width = height = offsets.Last();
|
|
|
|
M_u = NULL;
|
|
M_p = NULL;
|
|
Mnl_u = NULL;
|
|
Mnl_p = NULL;
|
|
B = NULL;
|
|
Mnl = NULL;
|
|
|
|
assembly = AssemblyLevel::LEGACY;
|
|
|
|
block_op = NULL;
|
|
|
|
reduction = NULL;
|
|
hybridization = NULL;
|
|
}
|
|
|
|
BilinearForm* DarcyForm::GetFluxMassForm()
|
|
{
|
|
if (!M_u) { M_u = new BilinearForm(fes_u); }
|
|
return M_u;
|
|
}
|
|
|
|
const BilinearForm* DarcyForm::GetFluxMassForm() const
|
|
{
|
|
//MFEM_ASSERT(M_u, "Flux mass form not allocated!");
|
|
return M_u;
|
|
}
|
|
|
|
BilinearForm* DarcyForm::GetPotentialMassForm()
|
|
{
|
|
if (!M_p) { M_p = new BilinearForm(fes_p); }
|
|
return M_p;
|
|
}
|
|
|
|
const BilinearForm* DarcyForm::GetPotentialMassForm() const
|
|
{
|
|
//MFEM_ASSERT(M_p, "Potential mass form not allocated!");
|
|
return M_p;
|
|
}
|
|
|
|
NonlinearForm *DarcyForm::GetFluxMassNonlinearForm()
|
|
{
|
|
if (!Mnl_u) { Mnl_u = new NonlinearForm(fes_u); }
|
|
return Mnl_u;
|
|
}
|
|
|
|
const NonlinearForm *DarcyForm::GetFluxMassNonlinearForm() const
|
|
{
|
|
//MFEM_ASSERT(Mnl_u, "Flux mass nonlinear form not allocated!");
|
|
return Mnl_u;
|
|
}
|
|
|
|
NonlinearForm* DarcyForm::GetPotentialMassNonlinearForm()
|
|
{
|
|
if (!Mnl_p) { Mnl_p = new NonlinearForm(fes_p); }
|
|
return Mnl_p;
|
|
}
|
|
|
|
const NonlinearForm* DarcyForm::GetPotentialMassNonlinearForm() const
|
|
{
|
|
//MFEM_ASSERT(Mnl_p, "Potential mass nonlinear form not allocated!");
|
|
return Mnl_p;
|
|
}
|
|
|
|
MixedBilinearForm* DarcyForm::GetFluxDivForm()
|
|
{
|
|
if (!B) { B = new MixedBilinearForm(fes_u, fes_p); }
|
|
return B;
|
|
}
|
|
|
|
const MixedBilinearForm* DarcyForm::GetFluxDivForm() const
|
|
{
|
|
//MFEM_ASSERT(B, "Flux div form not allocated!");
|
|
return B;
|
|
}
|
|
|
|
BlockNonlinearForm *DarcyForm::GetBlockNonlinearForm()
|
|
{
|
|
if (!Mnl)
|
|
{
|
|
Array<FiniteElementSpace*> fes({fes_u, fes_p});
|
|
Mnl = new BlockNonlinearForm(fes);
|
|
}
|
|
return Mnl;
|
|
}
|
|
|
|
const BlockNonlinearForm *DarcyForm::GetBlockNonlinearForm() const
|
|
{
|
|
//MFEM_ASSERT(Mnl, "Block nonlinear form not allocated!");
|
|
return Mnl;
|
|
}
|
|
|
|
void DarcyForm::SetAssemblyLevel(AssemblyLevel assembly_level)
|
|
{
|
|
assembly = assembly_level;
|
|
|
|
if (M_u) { M_u->SetAssemblyLevel(assembly); }
|
|
if (M_p) { M_p->SetAssemblyLevel(assembly); }
|
|
if (Mnl_u) { Mnl_u->SetAssemblyLevel(assembly); }
|
|
if (Mnl_p) { Mnl_p->SetAssemblyLevel(assembly); }
|
|
if (B) { B->SetAssemblyLevel(assembly); }
|
|
}
|
|
|
|
void DarcyForm::EnableReduction(const Array<int> &ess_flux_tdof_list,
|
|
DarcyReduction *reduction_)
|
|
{
|
|
MFEM_ASSERT(!Mnl, "Reduction cannot be used with block nonlinear forms");
|
|
MFEM_ASSERT((M_u || Mnl_u) && (M_p || Mnl_p),
|
|
"Mass forms for the fluxes and potentials must be set prior to this call!");
|
|
|
|
delete reduction;
|
|
if (assembly != AssemblyLevel::LEGACY)
|
|
{
|
|
reduction = NULL;
|
|
MFEM_WARNING("Reduction not supported for this assembly level");
|
|
return;
|
|
}
|
|
reduction = reduction_;
|
|
|
|
// Automatically load the flux mass integrators
|
|
if (Mnl_u)
|
|
{
|
|
NonlinearFormIntegrator *flux_integ = NULL;
|
|
auto dnlfi = Mnl_u->GetDNFI();
|
|
if (dnlfi->Size())
|
|
{
|
|
SumNLFIntegrator *snlfi = new SumNLFIntegrator(false);
|
|
for (NonlinearFormIntegrator *nlfi : *dnlfi)
|
|
{
|
|
snlfi->AddIntegrator(nlfi);
|
|
}
|
|
flux_integ = snlfi;
|
|
}
|
|
reduction->SetFluxMassNonlinearIntegrator(flux_integ);
|
|
}
|
|
|
|
// Automatically load the potential mass integrators
|
|
if (Mnl_p)
|
|
{
|
|
NonlinearFormIntegrator *pot_integ = NULL;
|
|
auto dnlfi = Mnl_p->GetDNFI();
|
|
if (dnlfi->Size())
|
|
{
|
|
SumNLFIntegrator *snlfi = new SumNLFIntegrator(false);
|
|
for (NonlinearFormIntegrator *nlfi : *dnlfi)
|
|
{
|
|
snlfi->AddIntegrator(nlfi);
|
|
}
|
|
pot_integ = snlfi;
|
|
}
|
|
reduction->SetPotMassNonlinearIntegrator(pot_integ);
|
|
}
|
|
|
|
reduction->Init(ess_flux_tdof_list);
|
|
}
|
|
|
|
void DarcyForm::EnableHybridization(FiniteElementSpace *constr_space,
|
|
BilinearFormIntegrator *constr_flux_integ,
|
|
const Array<int> &ess_flux_tdof_list)
|
|
{
|
|
MFEM_ASSERT(M_u || Mnl_u || Mnl,
|
|
"Mass form for the fluxes must be set prior to this call!");
|
|
delete hybridization;
|
|
if (assembly != AssemblyLevel::LEGACY)
|
|
{
|
|
delete constr_flux_integ;
|
|
hybridization = NULL;
|
|
MFEM_WARNING("Hybridization not supported for this assembly level");
|
|
return;
|
|
}
|
|
hybridization = new DarcyHybridization(fes_u, fes_p, constr_space, bsym);
|
|
|
|
// Automatically load the potential constraint operator from the face integrators
|
|
if (M_p)
|
|
{
|
|
BilinearFormIntegrator *constr_pot_integ = NULL;
|
|
auto fbfi = M_p->GetFBFI();
|
|
if (fbfi->Size())
|
|
{
|
|
SumIntegrator *sbfi = new SumIntegrator(false);
|
|
for (BilinearFormIntegrator *bfi : *fbfi)
|
|
{
|
|
sbfi->AddIntegrator(bfi);
|
|
}
|
|
constr_pot_integ = sbfi;
|
|
}
|
|
hybridization->SetConstraintIntegrators(constr_flux_integ, constr_pot_integ);
|
|
}
|
|
else if (Mnl_p)
|
|
{
|
|
NonlinearFormIntegrator *constr_pot_integ = NULL;
|
|
auto fnlfi = Mnl_p->GetInteriorFaceIntegrators();
|
|
if (fnlfi.Size())
|
|
{
|
|
SumNLFIntegrator *snlfi = new SumNLFIntegrator(false);
|
|
for (NonlinearFormIntegrator *nlfi : fnlfi)
|
|
{
|
|
snlfi->AddIntegrator(nlfi);
|
|
}
|
|
constr_pot_integ = snlfi;
|
|
}
|
|
hybridization->SetConstraintIntegrators(constr_flux_integ, constr_pot_integ);
|
|
}
|
|
else
|
|
{
|
|
hybridization->SetConstraintIntegrators(constr_flux_integ,
|
|
(BilinearFormIntegrator*)NULL);
|
|
}
|
|
|
|
// Automatically load the flux mass integrators
|
|
if (Mnl_u)
|
|
{
|
|
NonlinearFormIntegrator *flux_integ = NULL;
|
|
auto dnlfi = Mnl_u->GetDNFI();
|
|
if (dnlfi->Size())
|
|
{
|
|
SumNLFIntegrator *snlfi = new SumNLFIntegrator(false);
|
|
for (NonlinearFormIntegrator *nlfi : *dnlfi)
|
|
{
|
|
snlfi->AddIntegrator(nlfi);
|
|
}
|
|
flux_integ = snlfi;
|
|
}
|
|
hybridization->SetFluxMassNonlinearIntegrator(flux_integ);
|
|
}
|
|
|
|
// Automatically load the potential mass integrators
|
|
if (Mnl_p)
|
|
{
|
|
NonlinearFormIntegrator *pot_integ = NULL;
|
|
auto dnlfi = Mnl_p->GetDNFI();
|
|
if (dnlfi->Size())
|
|
{
|
|
SumNLFIntegrator *snlfi = new SumNLFIntegrator(false);
|
|
for (NonlinearFormIntegrator *nlfi : *dnlfi)
|
|
{
|
|
snlfi->AddIntegrator(nlfi);
|
|
}
|
|
pot_integ = snlfi;
|
|
}
|
|
hybridization->SetPotMassNonlinearIntegrator(pot_integ);
|
|
}
|
|
|
|
// Automatically load the block integrators
|
|
if (Mnl)
|
|
{
|
|
BlockNonlinearFormIntegrator *block_integ = NULL;
|
|
auto &dnlfi = Mnl->GetDomainIntegrators();
|
|
block_integ = dnlfi[0];
|
|
hybridization->SetBlockNonlinearIntegrator(block_integ, false);
|
|
}
|
|
|
|
// Automatically add the boundary flux constraint integrators
|
|
if (B)
|
|
{
|
|
auto bfbfi_marker = B->GetBFBFI_Marker();
|
|
hybridization->UseExternalBdrFluxConstraintIntegrators();
|
|
|
|
for (Array<int> *bfi_marker : *bfbfi_marker)
|
|
{
|
|
if (bfi_marker)
|
|
{
|
|
hybridization->AddBdrFluxConstraintIntegrator(constr_flux_integ, *bfi_marker);
|
|
}
|
|
else
|
|
{
|
|
hybridization->AddBdrFluxConstraintIntegrator(constr_flux_integ);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Automatically add the boundary potential constraint integrators
|
|
if (M_p)
|
|
{
|
|
auto bfbfi = M_p->GetBFBFI();
|
|
auto bfbfi_marker = M_p->GetBFBFI_Marker();
|
|
hybridization->UseExternalBdrPotConstraintIntegrators();
|
|
|
|
for (int i = 0; i < bfbfi->Size(); i++)
|
|
{
|
|
BilinearFormIntegrator *bfi = (*bfbfi)[i];
|
|
Array<int> *bfi_marker = (*bfbfi_marker)[i];
|
|
if (bfi_marker)
|
|
{
|
|
hybridization->AddBdrPotConstraintIntegrator(bfi, *bfi_marker);
|
|
}
|
|
else
|
|
{
|
|
hybridization->AddBdrPotConstraintIntegrator(bfi);
|
|
}
|
|
}
|
|
}
|
|
else if (Mnl_p)
|
|
{
|
|
auto bfnlfi = Mnl_p->GetBdrFaceIntegrators();
|
|
auto bfnlfi_marker = Mnl_p->GetBdrFaceIntegratorsMarkers();
|
|
hybridization->UseExternalBdrPotConstraintIntegrators();
|
|
|
|
for (int i = 0; i < bfnlfi.Size(); i++)
|
|
{
|
|
NonlinearFormIntegrator *nlfi = bfnlfi[i];
|
|
Array<int> *nlfi_marker = bfnlfi_marker[i];
|
|
if (nlfi_marker)
|
|
{
|
|
hybridization->AddBdrPotConstraintIntegrator(nlfi, *nlfi_marker);
|
|
}
|
|
else
|
|
{
|
|
hybridization->AddBdrPotConstraintIntegrator(nlfi);
|
|
}
|
|
}
|
|
}
|
|
|
|
hybridization->Init(ess_flux_tdof_list);
|
|
}
|
|
|
|
void DarcyForm::Assemble(int skip_zeros)
|
|
{
|
|
if (M_u)
|
|
{
|
|
if (hybridization)
|
|
{
|
|
DenseMatrix elmat;
|
|
|
|
// Element-wise integration
|
|
for (int i = 0; i < fes_u -> GetNE(); i++)
|
|
{
|
|
M_u->ComputeElementMatrix(i, elmat);
|
|
#ifndef MFEM_DARCY_HYBRIDIZATION_ELIM_BCS
|
|
M_u->AssembleElementMatrix(i, elmat, skip_zeros);
|
|
#endif //!MFEM_DARCY_HYBRIDIZATION_ELIM_BCS
|
|
hybridization->AssembleFluxMassMatrix(i, elmat);
|
|
}
|
|
}
|
|
else if (reduction)
|
|
{
|
|
DenseMatrix elmat;
|
|
|
|
// Element-wise integration
|
|
for (int i = 0; i < fes_u -> GetNE(); i++)
|
|
{
|
|
M_u->ComputeElementMatrix(i, elmat);
|
|
#ifndef MFEM_DARCY_REDUCTION_ELIM_BCS
|
|
M_u->AssembleElementMatrix(i, elmat, skip_zeros);
|
|
#endif //!MFEM_DARCY_REDUCTION_ELIM_BCS
|
|
reduction->AssembleFluxMassMatrix(i, elmat);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
M_u->Assemble(skip_zeros);
|
|
}
|
|
}
|
|
else if (Mnl_u)
|
|
{
|
|
Mnl_u->Setup();
|
|
}
|
|
|
|
if (B)
|
|
{
|
|
if (hybridization)
|
|
{
|
|
DenseMatrix elmat;
|
|
|
|
// Element-wise integration
|
|
for (int i = 0; i < fes_u -> GetNE(); i++)
|
|
{
|
|
B->ComputeElementMatrix(i, elmat);
|
|
#ifndef MFEM_DARCY_HYBRIDIZATION_ELIM_BCS
|
|
B->AssembleElementMatrix(i, elmat, skip_zeros);
|
|
#endif //!MFEM_DARCY_HYBRIDIZATION_ELIM_BCS
|
|
hybridization->AssembleDivMatrix(i, elmat);
|
|
}
|
|
}
|
|
else if (reduction)
|
|
{
|
|
DenseMatrix elmat;
|
|
|
|
// Element-wise integration
|
|
for (int i = 0; i < fes_u -> GetNE(); i++)
|
|
{
|
|
B->ComputeElementMatrix(i, elmat);
|
|
#ifndef MFEM_DARCY_REDUCTION_ELIM_BCS
|
|
B->AssembleElementMatrix(i, elmat, skip_zeros);
|
|
#endif //!MFEM_DARCY_REDUCTION_ELIM_BCS
|
|
reduction->AssembleDivMatrix(i, elmat);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
B->Assemble(skip_zeros);
|
|
}
|
|
}
|
|
|
|
if (M_p)
|
|
{
|
|
if (hybridization)
|
|
{
|
|
DenseMatrix elmat;
|
|
|
|
// Element-wise integration
|
|
for (int i = 0; i < fes_p -> GetNE(); i++)
|
|
{
|
|
M_p->ComputeElementMatrix(i, elmat);
|
|
#ifndef MFEM_DARCY_HYBRIDIZATION_ELIM_BCS
|
|
M_p->AssembleElementMatrix(i, elmat, skip_zeros);
|
|
#endif //!MFEM_DARCY_HYBRIDIZATION_ELIM_BCS
|
|
hybridization->AssemblePotMassMatrix(i, elmat);
|
|
}
|
|
|
|
AssemblePotHDGFaces(skip_zeros);
|
|
}
|
|
else if (reduction)
|
|
{
|
|
DenseMatrix elmat;
|
|
|
|
// Element-wise integration
|
|
for (int i = 0; i < fes_p -> GetNE(); i++)
|
|
{
|
|
M_p->ComputeElementMatrix(i, elmat);
|
|
#ifndef MFEM_DARCY_REDUCTION_ELIM_BCS
|
|
M_p->AssembleElementMatrix(i, elmat, skip_zeros);
|
|
#endif //!MFEM_DARCY_REDUCTION_ELIM_BCS
|
|
reduction->AssemblePotMassMatrix(i, elmat);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
M_p->Assemble(skip_zeros);
|
|
}
|
|
}
|
|
else if (Mnl_p)
|
|
{
|
|
Mnl_p->Setup();
|
|
}
|
|
}
|
|
|
|
void DarcyForm::Finalize(int skip_zeros)
|
|
{
|
|
AllocBlockOp();
|
|
|
|
if (block_op)
|
|
{
|
|
if (M_u)
|
|
{
|
|
M_u->Finalize(skip_zeros);
|
|
block_op->SetDiagonalBlock(0, M_u);
|
|
}
|
|
else if (Mnl_u)
|
|
{
|
|
block_op->SetDiagonalBlock(0, Mnl_u);
|
|
}
|
|
else if (Mnl)
|
|
{
|
|
pM.Reset(Mnl, false);
|
|
}
|
|
|
|
if (M_p)
|
|
{
|
|
M_p->Finalize(skip_zeros);
|
|
block_op->SetDiagonalBlock(1, M_p, (bsym)?(-1.):(+1.));
|
|
}
|
|
else if (Mnl_p)
|
|
{
|
|
block_op->SetDiagonalBlock(1, Mnl_p, (bsym)?(-1.):(+1.));
|
|
}
|
|
|
|
if (B)
|
|
{
|
|
B->Finalize(skip_zeros);
|
|
|
|
if (!pBt.Ptr()) { ConstructBT(B); }
|
|
|
|
block_op->SetBlock(0, 1, pBt.Ptr(), (bsym)?(-1.):(+1.));
|
|
block_op->SetBlock(1, 0, B, (bsym)?(-1.):(+1.));
|
|
}
|
|
}
|
|
|
|
if (hybridization)
|
|
{
|
|
hybridization->Finalize();
|
|
}
|
|
else if (reduction)
|
|
{
|
|
reduction->Finalize();
|
|
}
|
|
}
|
|
|
|
void DarcyForm::FormLinearSystem(const Array<int> &ess_flux_tdof_list,
|
|
BlockVector &x, BlockVector &b, OperatorHandle &A, Vector &X_, Vector &B_,
|
|
int copy_interior)
|
|
{
|
|
if (assembly != AssemblyLevel::LEGACY)
|
|
{
|
|
Array<int> ess_pot_tdof_list;//empty for discontinuous potentials
|
|
|
|
//conforming
|
|
|
|
if (M_u)
|
|
{
|
|
M_u->FormLinearSystem(ess_flux_tdof_list, x.GetBlock(0), b.GetBlock(0), pM_u,
|
|
X_, B_, copy_interior);
|
|
block_op->SetDiagonalBlock(0, pM_u.Ptr());
|
|
}
|
|
else if (Mnl_u)
|
|
{
|
|
Operator *opM;
|
|
Mnl_u->FormLinearSystem(ess_flux_tdof_list, x.GetBlock(0), b.GetBlock(0), opM,
|
|
X_, B_, copy_interior);
|
|
pM_u.Reset(opM);
|
|
block_op->SetDiagonalBlock(0, pM_u.Ptr());
|
|
}
|
|
else if (Mnl)
|
|
{
|
|
Operator *opM;
|
|
Mnl->FormLinearSystem(ess_flux_tdof_list, x, b, opM, X_, B_, copy_interior);
|
|
pM.Reset(opM);
|
|
}
|
|
|
|
if (M_p)
|
|
{
|
|
M_p->FormLinearSystem(ess_pot_tdof_list, x.GetBlock(1), b.GetBlock(1), pM_p, X_,
|
|
B_, copy_interior);
|
|
block_op->SetDiagonalBlock(1, pM_p.Ptr(), (bsym)?(-1.):(+1.));
|
|
}
|
|
else if (Mnl_p)
|
|
{
|
|
block_op->SetDiagonalBlock(1, Mnl_p, (bsym)?(-1.):(+1.));
|
|
}
|
|
|
|
if (B)
|
|
{
|
|
if (bsym)
|
|
{
|
|
//In the case of the symmetrized system, the sign is oppposite!
|
|
Vector b_(fes_p->GetVSize());
|
|
b_ = 0.;
|
|
B->FormRectangularLinearSystem(ess_flux_tdof_list, ess_pot_tdof_list,
|
|
x.GetBlock(0), b_, pB, X_, B_);
|
|
b.GetBlock(1) -= b_;
|
|
}
|
|
else
|
|
{
|
|
B->FormRectangularLinearSystem(ess_flux_tdof_list, ess_pot_tdof_list,
|
|
x.GetBlock(0), b.GetBlock(1), pB, X_, B_);
|
|
}
|
|
|
|
ConstructBT(pB.Ptr());
|
|
|
|
block_op->SetBlock(0, 1, pBt.Ptr(), (bsym)?(-1.):(+1.));
|
|
block_op->SetBlock(1, 0, pB.Ptr(), (bsym)?(-1.):(+1.));
|
|
}
|
|
|
|
if (Mnl && pM.Ptr())
|
|
{
|
|
A.Reset(new SumOperator(block_op, 1., pM.Ptr(), 1., false, false));
|
|
}
|
|
else
|
|
{
|
|
A.Reset(block_op, false);
|
|
}
|
|
|
|
X_.MakeRef(x, 0, x.Size());
|
|
B_.MakeRef(b, 0, b.Size());
|
|
|
|
return;
|
|
}
|
|
|
|
FormSystemMatrix(ess_flux_tdof_list, A);
|
|
|
|
//conforming
|
|
|
|
if (hybridization)
|
|
{
|
|
// Reduction to the Lagrange multipliers system
|
|
EliminateVDofsInRHS(ess_flux_tdof_list, x, b);
|
|
hybridization->ReduceRHS(b, B_);
|
|
X_.SetSize(B_.Size());
|
|
X_ = 0.0;
|
|
}
|
|
else if (reduction)
|
|
{
|
|
// Reduction to the Lagrange multipliers system
|
|
EliminateVDofsInRHS(ess_flux_tdof_list, x, b);
|
|
reduction->ReduceRHS(b, B_);
|
|
X_.SetSize(B_.Size());
|
|
X_ = 0.0;
|
|
}
|
|
else
|
|
{
|
|
// A, X and B point to the same data as mat, x and b
|
|
EliminateVDofsInRHS(ess_flux_tdof_list, x, b);
|
|
X_.MakeRef(x, 0, x.Size());
|
|
B_.MakeRef(b, 0, b.Size());
|
|
if (!copy_interior)
|
|
{
|
|
x.GetBlock(0).SetSubVectorComplement(ess_flux_tdof_list, 0.0);
|
|
x.GetBlock(1) = 0.;
|
|
}
|
|
}
|
|
}
|
|
|
|
void DarcyForm::FormSystemMatrix(const Array<int> &ess_flux_tdof_list,
|
|
OperatorHandle &A)
|
|
{
|
|
AllocBlockOp();
|
|
|
|
if (block_op)
|
|
{
|
|
Array<int> ess_pot_tdof_list;//empty for discontinuous potentials
|
|
|
|
if (M_u)
|
|
{
|
|
M_u->FormSystemMatrix(ess_flux_tdof_list, pM_u);
|
|
block_op->SetDiagonalBlock(0, pM_u.Ptr());
|
|
}
|
|
else if (Mnl_u)
|
|
{
|
|
Operator *opM;
|
|
Mnl_u->FormSystemOperator(ess_flux_tdof_list, opM);
|
|
pM_u.Reset(opM);
|
|
block_op->SetDiagonalBlock(0, pM_u.Ptr());
|
|
}
|
|
else if (Mnl)
|
|
{
|
|
Operator *opM;
|
|
Mnl->FormSystemOperator(ess_flux_tdof_list, opM);
|
|
pM.Reset(opM);
|
|
}
|
|
|
|
if (M_p)
|
|
{
|
|
M_p->FormSystemMatrix(ess_pot_tdof_list, pM_p);
|
|
block_op->SetDiagonalBlock(1, pM_p.Ptr(), (bsym)?(-1.):(+1.));
|
|
}
|
|
else if (Mnl_p)
|
|
{
|
|
block_op->SetDiagonalBlock(1, Mnl_p, (bsym)?(-1.):(+1.));
|
|
}
|
|
|
|
if (B)
|
|
{
|
|
B->FormRectangularSystemMatrix(ess_flux_tdof_list, ess_pot_tdof_list, pB);
|
|
|
|
ConstructBT(pB.Ptr());
|
|
|
|
block_op->SetBlock(0, 1, pBt.Ptr(), (bsym)?(-1.):(+1.));
|
|
block_op->SetBlock(1, 0, pB.Ptr(), (bsym)?(-1.):(+1.));
|
|
}
|
|
}
|
|
|
|
if (hybridization)
|
|
{
|
|
hybridization->Finalize();
|
|
if (!Mnl_u && !Mnl_p && !Mnl)
|
|
{
|
|
A.Reset(&hybridization->GetMatrix(), false);
|
|
}
|
|
else
|
|
{
|
|
A.Reset(hybridization, false);
|
|
}
|
|
}
|
|
else if (reduction)
|
|
{
|
|
reduction->Finalize();
|
|
if (!Mnl_u && !Mnl_p && !Mnl)
|
|
{
|
|
A.Reset(&reduction->GetMatrix(), false);
|
|
}
|
|
else
|
|
{
|
|
A.Reset(reduction, false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Mnl && pM.Ptr())
|
|
{
|
|
A.Reset(new SumOperator(block_op, 1., pM.Ptr(), 1., false, false));
|
|
}
|
|
else
|
|
{
|
|
A.Reset(block_op, false);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DarcyForm::RecoverFEMSolution(const Vector &X, const BlockVector &b,
|
|
BlockVector &x)
|
|
{
|
|
if (hybridization)
|
|
{
|
|
//conforming
|
|
hybridization->ComputeSolution(b, X, x);
|
|
}
|
|
else if (reduction)
|
|
{
|
|
//conforming
|
|
reduction->ComputeSolution(b, X, x);
|
|
}
|
|
else
|
|
{
|
|
BlockVector X_b(const_cast<Vector&>(X), offsets);
|
|
if (M_u)
|
|
{
|
|
M_u->RecoverFEMSolution(X_b.GetBlock(0), b.GetBlock(0), x.GetBlock(0));
|
|
}
|
|
if (M_p)
|
|
{
|
|
M_p->RecoverFEMSolution(X_b.GetBlock(1), b.GetBlock(1), x.GetBlock(1));
|
|
}
|
|
}
|
|
}
|
|
|
|
void DarcyForm::EliminateVDofsInRHS(const Array<int> &vdofs_flux,
|
|
const BlockVector &x, BlockVector &b)
|
|
{
|
|
#ifdef MFEM_DARCY_HYBRIDIZATION_ELIM_BCS
|
|
if (hybridization)
|
|
{
|
|
hybridization->EliminateVDofsInRHS(vdofs_flux, x, b);
|
|
return;
|
|
}
|
|
#endif //MFEM_DARCY_HYBRIDIZATION_ELIM_BCS
|
|
#ifdef MFEM_DARCY_REDUCTION_ELIM_BCS
|
|
if (reduction)
|
|
{
|
|
reduction->EliminateVDofsInRHS(vdofs_flux, x, b);
|
|
return;
|
|
}
|
|
#endif //MFEM_DARCY_REDUCTION_ELIM_BCS
|
|
if (B)
|
|
{
|
|
if (bsym)
|
|
{
|
|
//In the case of the symmetrized system, the sign is oppposite!
|
|
Vector b_(fes_p->GetVSize());
|
|
b_ = 0.;
|
|
B->EliminateTrialVDofsInRHS(vdofs_flux, x.GetBlock(0), b_);
|
|
b.GetBlock(1) -= b_;
|
|
}
|
|
else
|
|
{
|
|
B->EliminateTrialVDofsInRHS(vdofs_flux, x.GetBlock(0), b.GetBlock(1));
|
|
}
|
|
}
|
|
if (M_u)
|
|
{
|
|
M_u->EliminateVDofsInRHS(vdofs_flux, x.GetBlock(0), b.GetBlock(0));
|
|
}
|
|
else if (Mnl_u && pM_u.Ptr())
|
|
{
|
|
pM_u.As<ConstrainedOperator>()->EliminateRHS(x.GetBlock(0), b.GetBlock(0));
|
|
}
|
|
else if (Mnl && pM.Ptr())
|
|
{
|
|
pM.As<ConstrainedOperator>()->EliminateRHS(x, b);
|
|
}
|
|
|
|
}
|
|
|
|
void DarcyForm::Mult(const Vector &x, Vector &y) const
|
|
{
|
|
block_op->Mult(x, y);
|
|
if (pM.Ptr()) { pM->AddMult(x, y); }
|
|
}
|
|
|
|
void DarcyForm::MultTranspose(const Vector &x, Vector &y) const
|
|
{
|
|
block_op->MultTranspose(x, y);
|
|
if (pM.Ptr()) { pM->AddMultTranspose(x, y); }
|
|
}
|
|
|
|
Operator &DarcyForm::GetGradient(const Vector &x) const
|
|
{
|
|
if (!Mnl) { return *block_op; }
|
|
|
|
pG.Reset(new SumOperator(block_op, 1., &Mnl->GetGradient(x), 1., false, false));
|
|
return *pG.Ptr();
|
|
}
|
|
|
|
void DarcyForm::Update()
|
|
{
|
|
if (M_u) { M_u->Update(); }
|
|
if (M_p) { M_p->Update(); }
|
|
if (Mnl_u) { Mnl_u->Update(); }
|
|
if (Mnl_p) { Mnl_p->Update(); }
|
|
if (B) { B->Update(); }
|
|
if (Mnl) { Mnl->Update(); }
|
|
|
|
pBt.Clear();
|
|
|
|
if (reduction) { reduction->Reset(); }
|
|
if (hybridization) { hybridization->Reset(); }
|
|
}
|
|
|
|
DarcyForm::~DarcyForm()
|
|
{
|
|
if (M_u) { delete M_u; }
|
|
if (M_p) { delete M_p; }
|
|
if (Mnl_u) { delete Mnl_u; }
|
|
if (Mnl_p) { delete Mnl_p; }
|
|
if (B) { delete B; }
|
|
if (Mnl) { delete Mnl; }
|
|
|
|
delete block_op;
|
|
|
|
delete reduction;
|
|
delete hybridization;
|
|
}
|
|
|
|
void DarcyForm::AssemblePotHDGFaces(int skip_zeros)
|
|
{
|
|
Mesh *mesh = fes_p->GetMesh();
|
|
FaceElementTransformations *tr;
|
|
DenseMatrix elmat1, elmat2;
|
|
Array<int> vdofs1, vdofs2;
|
|
|
|
if (hybridization->GetPotConstraintIntegrator())
|
|
{
|
|
int nfaces = mesh->GetNumFaces();
|
|
for (int i = 0; i < nfaces; i++)
|
|
{
|
|
tr = mesh -> GetInteriorFaceTransformations (i);
|
|
if (tr == NULL) { continue; }
|
|
|
|
hybridization->ComputeAndAssemblePotFaceMatrix(i, elmat1, elmat2, vdofs1,
|
|
vdofs2);
|
|
#ifndef MFEM_DARCY_HYBRIDIZATION_ELIM_BCS
|
|
M_p->SpMat().AddSubMatrix(vdofs1, vdofs1, elmat1, skip_zeros);
|
|
M_p->SpMat().AddSubMatrix(vdofs2, vdofs2, elmat2, skip_zeros);
|
|
#endif //MFEM_DARCY_HYBRIDIZATION_ELIM_BCS
|
|
}
|
|
}
|
|
|
|
auto &boundary_face_integs_marker = *hybridization->GetPotBCBFI_Marker();
|
|
|
|
if (boundary_face_integs_marker.Size())
|
|
{
|
|
// Which boundary attributes need to be processed?
|
|
Array<int> bdr_attr_marker(mesh->bdr_attributes.Size() ?
|
|
mesh->bdr_attributes.Max() : 0);
|
|
bdr_attr_marker = 0;
|
|
for (int k = 0; k < boundary_face_integs_marker.Size(); k++)
|
|
{
|
|
if (boundary_face_integs_marker[k] == NULL)
|
|
{
|
|
bdr_attr_marker = 1;
|
|
break;
|
|
}
|
|
Array<int> &bdr_marker = *boundary_face_integs_marker[k];
|
|
MFEM_ASSERT(bdr_marker.Size() == bdr_attr_marker.Size(),
|
|
"invalid boundary marker for boundary face integrator #"
|
|
<< k << ", counting from zero");
|
|
for (int i = 0; i < bdr_attr_marker.Size(); i++)
|
|
{
|
|
bdr_attr_marker[i] |= bdr_marker[i];
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < fes_p -> GetNBE(); i++)
|
|
{
|
|
const int bdr_attr = mesh->GetBdrAttribute(i);
|
|
if (bdr_attr_marker[bdr_attr-1] == 0) { continue; }
|
|
|
|
tr = mesh -> GetBdrFaceTransformations (i);
|
|
if (tr != NULL)
|
|
{
|
|
hybridization->ComputeAndAssemblePotBdrFaceMatrix(i, elmat1, vdofs1);
|
|
#ifndef MFEM_DARCY_HYBRIDIZATION_ELIM_BCS
|
|
M_p->SpMat().AddSubMatrix(vdofs1, vdofs1, elmat1, skip_zeros);
|
|
#endif //MFEM_DARCY_HYBRIDIZATION_ELIM_BCS
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DarcyForm::AllocBlockOp()
|
|
{
|
|
bool noblock = false;
|
|
#ifdef MFEM_DARCY_REDUCTION_ELIM_BCS
|
|
noblock = noblock || reduction;
|
|
#endif //MFEM_DARCY_REDUCTION_ELIM_BCS
|
|
#ifdef MFEM_DARCY_HYBRIDIZATION_ELIM_BCS
|
|
noblock = noblock || hybridization;
|
|
#endif //MFEM_DARCY_HYBRIDIZATION_ELIM_BCS
|
|
|
|
if (!noblock)
|
|
{
|
|
delete block_op;
|
|
block_op = new BlockOperator(offsets);
|
|
}
|
|
}
|
|
|
|
const Operator *DarcyForm::ConstructBT(const MixedBilinearForm *B)
|
|
{
|
|
pBt.Reset(Transpose(B->SpMat()));
|
|
return pBt.Ptr();
|
|
}
|
|
|
|
const Operator* DarcyForm::ConstructBT(const Operator *opB)
|
|
{
|
|
pBt.Reset(new TransposeOperator(opB));
|
|
return pBt.Ptr();
|
|
}
|
|
|
|
}
|