Files
mfem/fem/multigrid.cpp
T
2020-04-18 18:07:43 -07:00

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