Skip to content

Commit

Permalink
Merge pull request #272 from awslabs/sjg/eigen-error-estimator-memory
Browse files Browse the repository at this point in the history
Release memory associated with libCEED operator assembly
  • Loading branch information
hughcars authored Dec 2, 2024
2 parents 57c9c9a + b95a8cd commit 7b4f4b2
Show file tree
Hide file tree
Showing 7 changed files with 41 additions and 20 deletions.
12 changes: 7 additions & 5 deletions palace/drivers/eigensolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,13 @@ EigenSolver::Solve(const std::vector<std::unique_ptr<Mesh>> &mesh) const
ksp->SetOperators(*A, *P);
eigen->SetLinearSolver(*ksp);

// Initialize structures for storing and reducing the results of error estimation.
TimeDependentFluxErrorEstimator<ComplexVector> estimator(
space_op.GetMaterialOp(), space_op.GetNDSpaces(), space_op.GetRTSpaces(),
iodata.solver.linear.estimator_tol, iodata.solver.linear.estimator_max_it, 0,
iodata.solver.linear.estimator_mg);
ErrorIndicator indicator;

// Eigenvalue problem solve.
BlockTimer bt1(Timer::EPS);
Mpi::Print("\n");
Expand All @@ -267,11 +274,6 @@ EigenSolver::Solve(const std::vector<std::unique_ptr<Mesh>> &mesh) const

// Calculate and record the error indicators, and postprocess the results.
Mpi::Print("\nComputing solution error estimates and performing postprocessing\n");
TimeDependentFluxErrorEstimator<ComplexVector> estimator(
space_op.GetMaterialOp(), space_op.GetNDSpaces(), space_op.GetRTSpaces(),
iodata.solver.linear.estimator_tol, iodata.solver.linear.estimator_max_it, 0,
iodata.solver.linear.estimator_mg);
ErrorIndicator indicator;
if (!KM)
{
// Normalize the finalized eigenvectors with respect to mass matrix (unit electric field
Expand Down
13 changes: 7 additions & 6 deletions palace/fem/bilinearform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ BilinearForm::PartialAssemble(const FiniteElementSpace &trial_fespace,
integ->SetMapTypes(trial_map_type, test_map_type);
integ->Assemble(ceed, trial_restr, test_restr, trial_basis, test_basis,
data.geom_data, data.geom_data_restr, &sub_op);
op->AddOper(sub_op); // Sub-operator owned by ceed::Operator
op->AddSubOperator(sub_op); // Sub-operator owned by ceed::Operator
}
}
else if (mfem::Geometry::Dimension[geom] == mesh.Dimension() - 1 &&
Expand All @@ -95,7 +95,7 @@ BilinearForm::PartialAssemble(const FiniteElementSpace &trial_fespace,
integ->SetMapTypes(trial_map_type, test_map_type);
integ->Assemble(ceed, trial_restr, test_restr, trial_basis, test_basis,
data.geom_data, data.geom_data_restr, &sub_op);
op->AddOper(sub_op); // Sub-operator owned by ceed::Operator
op->AddSubOperator(sub_op); // Sub-operator owned by ceed::Operator
}
}
}
Expand Down Expand Up @@ -181,13 +181,14 @@ BilinearForm::Assemble(const FiniteElementSpaceHierarchy &fespaces, bool skip_ze
}
}

// Construct the final operators using full or partial assemble as needed. Force the
// coarse-level operator to be fully assembled always.
// Construct the final operators using full or partial assemble as needed. We do not
// force the coarse-level operator to be fully assembled always, it will be only assembled
// as needed for parallel assembly.
std::vector<std::unique_ptr<Operator>> ops;
ops.reserve(fespaces.GetNumLevels() - l0);
for (std::size_t l = l0; l < fespaces.GetNumLevels(); l++)
{
if (l == 0 || UseFullAssembly(fespaces.GetFESpaceAtLevel(l), pa_order_threshold))
if (UseFullAssembly(fespaces.GetFESpaceAtLevel(l), pa_order_threshold))
{
ops.push_back(FullAssemble(*pa_ops[l - l0], skip_zeros));
}
Expand Down Expand Up @@ -242,7 +243,7 @@ std::unique_ptr<ceed::Operator> DiscreteLinearOperator::PartialAssemble() const
{
CeedOperator sub_op, sub_op_t;
interp->Assemble(ceed, trial_restr, test_restr, interp_basis, &sub_op, &sub_op_t);
op->AddOper(sub_op, sub_op_t); // Sub-operator owned by ceed::Operator
op->AddSubOperator(sub_op, sub_op_t); // Sub-operator owned by ceed::Operator
}

// Basis is owned by the operator.
Expand Down
20 changes: 18 additions & 2 deletions palace/fem/libceed/operator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ Operator::~Operator()
}
}

void Operator::AddOper(CeedOperator sub_op, CeedOperator sub_op_t)
void Operator::AddSubOperator(CeedOperator sub_op, CeedOperator sub_op_t)
{
// This should be called from within a OpenMP parallel region.
const int id = utils::GetThreadNum();
Expand Down Expand Up @@ -100,6 +100,19 @@ void Operator::Finalize()
}
}

void Operator::DestroyAssemblyData() const
{
PalacePragmaOmp(parallel if (op.size() > 1))
{
const int id = utils::GetThreadNum();
MFEM_ASSERT(static_cast<std::size_t>(id) < op.size(),
"Out of bounds access for thread number " << id << "!");
Ceed ceed;
PalaceCeedCallBackend(CeedOperatorGetCeed(op[id], &ceed));
PalaceCeedCall(ceed, CeedOperatorAssemblyDataStrip(op[id]));
}
}

void Operator::AssembleDiagonal(Vector &diag) const
{
Ceed ceed;
Expand All @@ -125,6 +138,7 @@ void Operator::AssembleDiagonal(Vector &diag) const
PalaceCeedCall(
ceed, CeedOperatorLinearAssembleAddDiagonal(op[id], v[id], CEED_REQUEST_IMMEDIATE));
PalaceCeedCall(ceed, CeedVectorTakeArray(v[id], mem, nullptr));
PalaceCeedCall(ceed, CeedOperatorAssemblyDataStrip(op[id]));
}
}

Expand Down Expand Up @@ -467,6 +481,7 @@ std::unique_ptr<hypre::HypreCSRMatrix> CeedOperatorFullAssemble(const Operator &
CeedVector vals;
CeedMemType mem;
CeedOperatorAssembleCOO(ceed, op[id], skip_zeros, &nnz, &rows, &cols, &vals, &mem);
PalaceCeedCall(ceed, CeedOperatorAssemblyDataStrip(op[id]));

// Convert COO to CSR (on each thread). The COO memory is free'd internally.
loc_mat[id] =
Expand Down Expand Up @@ -527,6 +542,7 @@ std::unique_ptr<Operator> CeedOperatorCoarsen(const Operator &op_fine,
PalaceCeedCall(ceed, CeedOperatorMultigridLevelCreate(op_fine, nullptr, restr_coarse,
basis_coarse, op_coarse, nullptr,
nullptr));
PalaceCeedCall(ceed, CeedOperatorAssemblyDataStrip(*op_coarse));
};

// Initialize the coarse operator.
Expand Down Expand Up @@ -558,7 +574,7 @@ std::unique_ptr<Operator> CeedOperatorCoarsen(const Operator &op_fine,
{
CeedOperator sub_op_coarse;
SingleOperatorCoarsen(ceed, sub_ops_fine[k], &sub_op_coarse);
op_coarse->AddOper(sub_op_coarse); // Sub-operator owned by ceed::Operator
op_coarse->AddSubOperator(sub_op_coarse); // Sub-operator owned by ceed::Operator
}
}

Expand Down
4 changes: 3 additions & 1 deletion palace/fem/libceed/operator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@ class Operator : public palace::Operator
CeedOperator operator[](std::size_t i) const { return op[i]; }
auto Size() const { return op.size(); }

void AddOper(CeedOperator sub_op, CeedOperator sub_op_t = nullptr);
void AddSubOperator(CeedOperator sub_op, CeedOperator sub_op_t = nullptr);

void Finalize();

void DestroyAssemblyData() const;

void SetDofMultiplicity(Vector &&mult) { dof_multiplicity = std::move(mult); }

void AssembleDiagonal(Vector &diag) const override;
Expand Down
4 changes: 2 additions & 2 deletions palace/linalg/errorestimator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ GradFluxErrorEstimator<VecType>::GradFluxErrorEstimator(
info, (void *)ctx.data(), ctx.size() * sizeof(CeedIntScalar), ceed, E_gf_vec,
D_gf_vec, nd_restr, rt_restr, nd_basis, rt_basis, mesh_elem_restr, data.geom_data,
data.geom_data_restr, &sub_op);
integ_op.AddOper(sub_op); // Sub-operator owned by ceed::Operator
integ_op.AddSubOperator(sub_op); // Sub-operator owned by ceed::Operator

// Element restriction and passive input vectors are owned by the operator.
PalaceCeedCall(ceed, CeedElemRestrictionDestroy(&mesh_elem_restr));
Expand Down Expand Up @@ -458,7 +458,7 @@ CurlFluxErrorEstimator<VecType>::CurlFluxErrorEstimator(
info, (void *)ctx.data(), ctx.size() * sizeof(CeedIntScalar), ceed, B_gf_vec,
H_gf_vec, rt_restr, nd_restr, rt_basis, nd_basis, mesh_elem_restr, data.geom_data,
data.geom_data_restr, &sub_op);
integ_op.AddOper(sub_op); // Sub-operator owned by ceed::Operator
integ_op.AddSubOperator(sub_op); // Sub-operator owned by ceed::Operator

// Element restriction and passive input vectors are owned by the operator.
PalaceCeedCall(ceed, CeedElemRestrictionDestroy(&mesh_elem_restr));
Expand Down
4 changes: 2 additions & 2 deletions palace/linalg/operator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
namespace palace
{

using Operator = mfem::Operator;

//
// Functionality extending mfem::Operator from MFEM.
//

using Operator = mfem::Operator;

// Abstract base class for complex-valued operators.
class ComplexOperator
{
Expand Down
4 changes: 2 additions & 2 deletions palace/linalg/vector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
namespace palace
{

using Vector = mfem::Vector;

//
// Functionality extending mfem::Vector from MFEM, including basic functions for parallel
// vectors distributed across MPI processes.
//

using Vector = mfem::Vector;

// A complex-valued vector represented as two real vectors, one for each component.
class ComplexVector
{
Expand Down

0 comments on commit 7b4f4b2

Please sign in to comment.