207 lines
4.9 KiB
C++
207 lines
4.9 KiB
C++
// Copyright (c) 2010-2020, 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 "multigrid.hpp"
|
|
|
|
namespace mfem
|
|
{
|
|
|
|
Multigrid::Multigrid(const FiniteElementSpaceHierarchy& fespaces_)
|
|
: fespaces(fespaces_), cycleType(CycleType::VCYCLE), preSmoothingSteps(1),
|
|
postSmoothingSteps(1)
|
|
{}
|
|
|
|
Multigrid::~Multigrid()
|
|
{
|
|
for (int i = 0; i < operators.Size(); ++i)
|
|
{
|
|
if (ownedOperators[i])
|
|
{
|
|
delete operators[i];
|
|
}
|
|
if (ownedSmoothers[i])
|
|
{
|
|
delete smoothers[i];
|
|
}
|
|
delete X[i];
|
|
delete Y[i];
|
|
delete R[i];
|
|
delete Z[i];
|
|
}
|
|
|
|
operators.DeleteAll();
|
|
smoothers.DeleteAll();
|
|
X.DeleteAll();
|
|
Y.DeleteAll();
|
|
R.DeleteAll();
|
|
Z.DeleteAll();
|
|
|
|
for (int i = 0; i < bfs.Size(); ++i)
|
|
{
|
|
delete bfs[i];
|
|
}
|
|
|
|
bfs.DeleteAll();
|
|
|
|
for (int i = 0; i < essentialTrueDofs.Size(); ++i)
|
|
{
|
|
delete essentialTrueDofs[i];
|
|
}
|
|
|
|
essentialTrueDofs.DeleteAll();
|
|
}
|
|
|
|
void Multigrid::AddLevel(Operator* opr, Solver* smoother, bool ownOperator,
|
|
bool ownSmoother)
|
|
{
|
|
operators.Append(opr);
|
|
smoothers.Append(smoother);
|
|
ownedOperators.Append(ownOperator);
|
|
ownedSmoothers.Append(ownSmoother);
|
|
width = opr->Width();
|
|
height = opr->Height();
|
|
|
|
X.Append(new Vector(height));
|
|
*X.Last() = 0.0;
|
|
Y.Append(new Vector(height));
|
|
*Y.Last() = 0.0;
|
|
R.Append(new Vector(height));
|
|
*R.Last() = 0.0;
|
|
Z.Append(new Vector(height));
|
|
*Z.Last() = 0.0;
|
|
}
|
|
|
|
int Multigrid::NumLevels() const { return operators.Size(); }
|
|
|
|
int Multigrid::GetFinestLevelIndex() const { return NumLevels() - 1; }
|
|
|
|
const Operator* Multigrid::GetOperatorAtLevel(int level) const
|
|
{
|
|
return operators[level];
|
|
}
|
|
|
|
Operator* Multigrid::GetOperatorAtLevel(int level)
|
|
{
|
|
return operators[level];
|
|
}
|
|
|
|
const Operator* Multigrid::GetOperatorAtFinestLevel() const
|
|
{
|
|
return GetOperatorAtLevel(operators.Size() - 1);
|
|
}
|
|
|
|
Operator* Multigrid::GetOperatorAtFinestLevel()
|
|
{
|
|
return GetOperatorAtLevel(operators.Size() - 1);
|
|
}
|
|
|
|
Solver* Multigrid::GetSmootherAtLevel(int level) const
|
|
{
|
|
return smoothers[level];
|
|
}
|
|
|
|
Solver* Multigrid::GetSmootherAtLevel(int level)
|
|
{
|
|
return smoothers[level];
|
|
}
|
|
|
|
void Multigrid::SetCycleType(CycleType cycleType_, int preSmoothingSteps_,
|
|
int postSmoothingSteps_)
|
|
{
|
|
cycleType = cycleType_;
|
|
preSmoothingSteps = preSmoothingSteps_;
|
|
postSmoothingSteps = postSmoothingSteps_;
|
|
}
|
|
|
|
void Multigrid::Mult(const Vector& x, Vector& y) const
|
|
{
|
|
MFEM_ASSERT(NumLevels() > 0, "");
|
|
*X.Last() = x;
|
|
*Y.Last() = 0.0;
|
|
Cycle(GetFinestLevelIndex());
|
|
y = *Y.Last();
|
|
}
|
|
|
|
void Multigrid::SetOperator(const Operator& op)
|
|
{
|
|
MFEM_ABORT("SetOperator not supported in Multigrid");
|
|
}
|
|
|
|
void Multigrid::SmoothingStep(int level) const
|
|
{
|
|
GetOperatorAtLevel(level)->Mult(*Y[level], *R[level]); // r = A x
|
|
subtract(*X[level], *R[level], *R[level]); // r = b - A x
|
|
GetSmootherAtLevel(level)->Mult(*R[level], *Z[level]); // z = S r
|
|
add(*Y[level], 1.0, *Z[level], *Y[level]); // x = x + S (b - A x)
|
|
}
|
|
|
|
void Multigrid::Cycle(int level) const
|
|
{
|
|
if (level == 0)
|
|
{
|
|
GetSmootherAtLevel(level)->Mult(*X[level], *Y[level]);
|
|
return;
|
|
}
|
|
|
|
for (int i = 0; i < preSmoothingSteps; i++)
|
|
{
|
|
SmoothingStep(level);
|
|
}
|
|
|
|
// Compute residual
|
|
GetOperatorAtLevel(level)->Mult(*Y[level], *R[level]);
|
|
subtract(*X[level], *R[level], *R[level]);
|
|
|
|
// Restrict residual
|
|
fespaces.GetProlongationAtLevel(level - 1)->MultTranspose(*R[level],
|
|
*X[level - 1]);
|
|
|
|
// Init zeros
|
|
*Y[level - 1] = 0.0;
|
|
|
|
// Corrections
|
|
int corrections = 1;
|
|
if (cycleType == CycleType::WCYCLE)
|
|
{
|
|
corrections = 2;
|
|
}
|
|
for (int correction = 0; correction < corrections; ++correction)
|
|
{
|
|
Cycle(level - 1);
|
|
}
|
|
|
|
// Prolongate
|
|
fespaces.GetProlongationAtLevel(level - 1)->Mult(*Y[level - 1], *R[level]);
|
|
|
|
// Add update
|
|
*Y[level] += *R[level];
|
|
|
|
// Post-smooth
|
|
for (int i = 0; i < postSmoothingSteps; i++)
|
|
{
|
|
SmoothingStep(level);
|
|
}
|
|
}
|
|
|
|
void Multigrid::FormFineLinearSystem(Vector& x, Vector& b, OperatorHandle& A,
|
|
Vector& X, Vector& B)
|
|
{
|
|
bfs.Last()->FormLinearSystem(*essentialTrueDofs.Last(), x, b, A, X, B);
|
|
}
|
|
|
|
void Multigrid::RecoverFineFEMSolution(const Vector& X, const Vector& b,
|
|
Vector& x)
|
|
{
|
|
bfs.Last()->RecoverFEMSolution(X, b, x);
|
|
}
|
|
|
|
} // namespace mfem
|