Commit 054d8705 authored by GILLES Sebastien's avatar GILLES Sebastien
Browse files

#772 Implement a FromVertexMatching class which handles the data required to...

#772 Implement a FromVertexMatching class which handles the data required to make the VertexMatching operator work as expected in parallel.
parent b375c33d
......@@ -1283,6 +1283,12 @@
BEE8CAA91C2452D20006C9C8 /* InitVertexMatching.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEE8CAA61C2452D20006C9C8 /* InitVertexMatching.cpp */; };
BEE8CAAA1C2452D20006C9C8 /* InitVertexMatching.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BEE8CAA71C2452D20006C9C8 /* InitVertexMatching.hpp */; };
BEE8CAAD1C24530B0006C9C8 /* InitVertexMatching.hxx in Headers */ = {isa = PBXBuildFile; fileRef = BEE8CAAC1C24530B0006C9C8 /* InitVertexMatching.hxx */; };
BEE8CAB51C2464A10006C9C8 /* InitVertexMatchingManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEE8CAB21C2464A10006C9C8 /* InitVertexMatchingManager.cpp */; };
BEE8CAB61C2464A10006C9C8 /* InitVertexMatchingManager.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BEE8CAB31C2464A10006C9C8 /* InitVertexMatchingManager.hpp */; };
BEE8CAB71C2464A10006C9C8 /* InitVertexMatchingManager.hxx in Headers */ = {isa = PBXBuildFile; fileRef = BEE8CAB41C2464A10006C9C8 /* InitVertexMatchingManager.hxx */; };
BEE8CABB1C2465E00006C9C8 /* InitVertexMatching.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEE8CAB81C2465E00006C9C8 /* InitVertexMatching.cpp */; };
BEE8CABC1C2465E00006C9C8 /* InitVertexMatching.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BEE8CAB91C2465E00006C9C8 /* InitVertexMatching.hpp */; };
BEE8CABD1C2465E00006C9C8 /* InitVertexMatching.hxx in Headers */ = {isa = PBXBuildFile; fileRef = BEE8CABA1C2465E00006C9C8 /* InitVertexMatching.hxx */; };
BEEABA4E1A49BC8700A875C6 /* Ensight6.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BEEABA4B1A49BC8700A875C6 /* Ensight6.cpp */; };
BEEABA4F1A49BC8700A875C6 /* Ensight6.hpp in Headers */ = {isa = PBXBuildFile; fileRef = BEEABA4C1A49BC8700A875C6 /* Ensight6.hpp */; };
BEEABA501A49BC8700A875C6 /* Ensight6.hxx in Headers */ = {isa = PBXBuildFile; fileRef = BEEABA4D1A49BC8700A875C6 /* Ensight6.hxx */; };
......@@ -4907,6 +4913,12 @@
BEE8CAA61C2452D20006C9C8 /* InitVertexMatching.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = InitVertexMatching.cpp; path = Interpolator/Private/InitVertexMatching.cpp; sourceTree = "<group>"; };
BEE8CAA71C2452D20006C9C8 /* InitVertexMatching.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = InitVertexMatching.hpp; path = Interpolator/Private/InitVertexMatching.hpp; sourceTree = "<group>"; };
BEE8CAAC1C24530B0006C9C8 /* InitVertexMatching.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = InitVertexMatching.hxx; path = Interpolator/InitVertexMatching.hxx; sourceTree = "<group>"; };
BEE8CAB21C2464A10006C9C8 /* InitVertexMatchingManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InitVertexMatchingManager.cpp; sourceTree = "<group>"; };
BEE8CAB31C2464A10006C9C8 /* InitVertexMatchingManager.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = InitVertexMatchingManager.hpp; sourceTree = "<group>"; };
BEE8CAB41C2464A10006C9C8 /* InitVertexMatchingManager.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = InitVertexMatchingManager.hxx; sourceTree = "<group>"; };
BEE8CAB81C2465E00006C9C8 /* InitVertexMatching.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InitVertexMatching.cpp; sourceTree = "<group>"; };
BEE8CAB91C2465E00006C9C8 /* InitVertexMatching.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = InitVertexMatching.hpp; sourceTree = "<group>"; };
BEE8CABA1C2465E00006C9C8 /* InitVertexMatching.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = InitVertexMatching.hxx; sourceTree = "<group>"; };
BEEABA4B1A49BC8700A875C6 /* Ensight6.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Ensight6.cpp; sourceTree = "<group>"; };
BEEABA4C1A49BC8700A875C6 /* Ensight6.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Ensight6.hpp; sourceTree = "<group>"; };
BEEABA4D1A49BC8700A875C6 /* Ensight6.hxx */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Ensight6.hxx; sourceTree = "<group>"; };
......@@ -7908,6 +7920,12 @@
BE646CCE1B32987C008BD37C /* QuadratureRuleTracker.cpp */,
BE646CCF1B32987C008BD37C /* QuadratureRuleTracker.hpp */,
BE646CD01B32987C008BD37C /* QuadratureRuleTracker.hxx */,
BEE8CAB81C2465E00006C9C8 /* InitVertexMatching.cpp */,
BEE8CAB91C2465E00006C9C8 /* InitVertexMatching.hpp */,
BEE8CABA1C2465E00006C9C8 /* InitVertexMatching.hxx */,
BEE8CAB21C2464A10006C9C8 /* InitVertexMatchingManager.cpp */,
BEE8CAB31C2464A10006C9C8 /* InitVertexMatchingManager.hpp */,
BEE8CAB41C2464A10006C9C8 /* InitVertexMatchingManager.hxx */,
BEBEB21D19C849C200E4EA1D /* Impl */,
);
path = Private;
......@@ -9048,6 +9066,7 @@
BEB7B1051BB4168F005E5D18 /* DirichletBoundaryConditionManager.hxx in Headers */,
BE2B663D1A2778C700E80864 /* GeometryBasedBasicRefFElt.hpp in Headers */,
BE5CA7C11ADBC5BD00758CD2 /* MatrixPattern.hpp in Headers */,
BEE8CABC1C2465E00006C9C8 /* InitVertexMatching.hpp in Headers */,
BE90E0771A2491AE00CCAFDE /* AttributeProcessorHelper.hxx in Headers */,
BE90E1511A2491AE00CCAFDE /* Comp23.hpp in Headers */,
BE90E0FD1A2491AE00CCAFDE /* QuadraturePoint.hpp in Headers */,
......@@ -9103,10 +9122,13 @@
BE63C14D1B2186ED00978D05 /* PointP0.hpp in Headers */,
BE90E10C1A2491AE00CCAFDE /* Triangle.hpp in Headers */,
BE86A9EF1A385C9B003B211D /* SegmentP2.hpp in Headers */,
BEE8CAB71C2464A10006C9C8 /* InitVertexMatchingManager.hxx in Headers */,
BEE8CABD1C2465E00006C9C8 /* InitVertexMatching.hxx in Headers */,
BE2B66641A2778C700E80864 /* RefFEltSpace.hxx in Headers */,
BE90E1251A2491AE00CCAFDE /* NodeBearer.hpp in Headers */,
BE44ECC41AC9463D00561634 /* GodOfDofManager.hpp in Headers */,
BE90E1361A2491AE00CCAFDE /* ComponentManager.hpp in Headers */,
BEE8CAB61C2464A10006C9C8 /* InitVertexMatchingManager.hpp in Headers */,
BE90E07C1A2491AE00CCAFDE /* ComputeDofIndexes.hxx in Headers */,
13EDDEC91AB03E1B00A1E8F9 /* PointP1.hpp in Headers */,
BE90E14D1A2491AE00CCAFDE /* Comp13.hpp in Headers */,
......@@ -11012,6 +11034,7 @@
BE90E10F1A2491AE00CCAFDE /* Quadrangle.cpp in Sources */,
BE19AB531A37354100EAF725 /* SegmentP1.cpp in Sources */,
BE90E0781A2491AE00CCAFDE /* InterfaceSpecialization.cpp in Sources */,
BEE8CABB1C2465E00006C9C8 /* InitVertexMatching.cpp in Sources */,
BE90E1241A2491AE00CCAFDE /* NodeBearer.cpp in Sources */,
BE5CA7C01ADBC5BD00758CD2 /* MatrixPattern.cpp in Sources */,
BE90E0691A2491AE00CCAFDE /* FEltSpaceStorage.cpp in Sources */,
......@@ -11043,6 +11066,7 @@
BE3221891B4686B100F27D6C /* Local2GlobalStorage.cpp in Sources */,
BE90E0FF1A2491AE00CCAFDE /* QuadratureRule.cpp in Sources */,
BE90E10D1A2491AE00CCAFDE /* Tetrahedron.cpp in Sources */,
BEE8CAB51C2464A10006C9C8 /* InitVertexMatchingManager.cpp in Sources */,
BE90E1131A2491AE00CCAFDE /* QuadratureRuleList.cpp in Sources */,
BE90E14A1A2491AE00CCAFDE /* Comp123.cpp in Sources */,
BE43DC9C1BCCFF980093EB01 /* AllocateGlobalLinearAlgebra.cpp in Sources */,
......
......@@ -57,7 +57,7 @@
</MacroExpansion>
<CommandLineArguments>
<CommandLineArgument
argument = "-np 4"
argument = "-np 2"
isEnabled = "YES">
</CommandLineArgument>
<CommandLineArgument
......
......@@ -406,4 +406,27 @@ namespace HappyHeart
}
Dof::vector_shared_ptr FEltSpace::GetProcessorWiseDofList(const NumberingSubset& numbering_subset) const
{
decltype(auto) complete_list = GetProcessorWiseDofList();
Dof::vector_shared_ptr ret;
ret.reserve(complete_list.size());
const auto end = complete_list.cend();
std::copy_if(complete_list.cbegin(),
end,
std::back_inserter(ret),
[&numbering_subset](const auto& dof_ptr)
{
assert(!(!dof_ptr));
return dof_ptr->IsInNumberingSubset(numbering_subset);
});
ret.shrink_to_fit();
return ret;
}
} // namespace HappyHeart
......@@ -283,6 +283,17 @@ namespace HappyHeart
*/
const Dof::vector_shared_ptr& GetProcessorWiseDofList() const noexcept;
/*!
* \brief Get the list of processor-wise dofs covered by the finite element space and inside given
* numbering subset.
*
* \attention The list doesn't exist and is returned by value; in most cases filtering on the nemesake above will be
* much more efficient.
*
*/
Dof::vector_shared_ptr GetProcessorWiseDofList(const NumberingSubset& numbering_subset) const;
/*!
* \brief Get the list of ghosted dofs covered by the finite element space.
*
......
......@@ -33,7 +33,6 @@ namespace HappyHeart
}
inline unsigned int FEltSpace::GetDimension() const noexcept
{
return dimension_;
......
......@@ -19,6 +19,7 @@
#include "FiniteElement/FiniteElementSpace/Private/Partition.hpp"
#include "FiniteElement/FiniteElementSpace/Private/Connectivity.hpp"
#include "FiniteElement/FiniteElementSpace/Private/ReduceToProcessorWise.hpp"
#include "FiniteElement/FiniteElementSpace/Private/InitVertexMatchingManager.hpp"
#include "FiniteElement/FiniteElementSpace/GodOfDof.hpp"
......@@ -133,6 +134,21 @@ namespace HappyHeart
// Compute the number of program- and processor- wise dofs.
Ndof_holder_ = std::make_unique<Private::NdofHolder>(node_bearer_list, numbering_subset_list, rank);
// Init the relevant data for FromVertexMatching interpolator. \todo 772!
{
auto& init_vertex_matching_manager = Private::InitVertexMatchingManager::CreateOrGetInstance();
if (IsFEltSpace(7))
init_vertex_matching_manager.Create(1,
GetFEltSpace(7),
GetNumberingSubset(7));
if (IsFEltSpace(3))
init_vertex_matching_manager.Create(2,
GetFEltSpace(3),
GetNumberingSubset(6));
}
// Reduce the list of node bearers.
Private::ReduceNodeBearerList(rank, GetNonCstNodeBearerList());
......@@ -653,28 +669,35 @@ namespace HappyHeart
}
const FEltSpace& GodOfDof::GetFEltSpace(unsigned int fe_space_index) const
auto GodOfDof::GetIteratorFEltSpace(unsigned int felt_space_index) const
{
// Lookup is done by std::find. Not a performance issue: a GodOfDof is not expect to contain more than
// an handful of finite element spaces.
const auto& felt_space_list = GetFEltSpaceList();
auto it = std::find_if(felt_space_list.cbegin(),
return std::find_if(felt_space_list.cbegin(),
felt_space_list.cend(),
[fe_space_index](const auto& felt_space_ptr)
[felt_space_index](const auto& felt_space_ptr)
{
assert(!(!felt_space_ptr));
return felt_space_ptr->GetUniqueId() == fe_space_index;
return felt_space_ptr->GetUniqueId() == felt_space_index;
});
}
bool GodOfDof::IsFEltSpace(unsigned int felt_space_index) const
{
return GetIteratorFEltSpace(felt_space_index) != GetFEltSpaceList().cend();
}
const FEltSpace& GodOfDof::GetFEltSpace(unsigned int felt_space_index) const
{
auto it = GetIteratorFEltSpace(felt_space_index);
assert(it != felt_space_list.cend() && "If not something went awry in GodOfDof initialization!");
assert(it != GetFEltSpaceList().cend() && "If not something went awry in GodOfDof initialization!");
return *(*it);
}
void GodOfDof::ComputeNumberingSubsetList()
{
......@@ -694,9 +717,7 @@ namespace HappyHeart
Utilities::EliminateDuplicate(numbering_subset_list_);
assert(!numbering_subset_list_.empty() && "There must be at least one...");
}
const Wrappers::Petsc::MatrixPattern& GodOfDof::GetMatrixPattern(const NumberingSubset& row_numbering_subset,
const NumberingSubset& column_numbering_subset) const
......
......@@ -119,9 +119,16 @@ namespace HappyHeart
//! Get the geometric mesh region object.
const GeometricMeshRegion& GetGeometricMeshRegion() const;
//! Get access to the \a index -th finite element space.
/*!
* \brief Get access to the \a index -th finite element space.
*
* It assumes the finite element space does exist in the GodOfDof; this can be checked beforehand with
* IsFEltSpace(index).
*/
const FEltSpace& GetFEltSpace(unsigned int index) const;
//! Whether the finite element space \a felt_space_index is in the GodOfDof.
bool IsFEltSpace(unsigned int felt_space_index) const;
//! Get the list of FEltSpace.
const FEltSpace::vector_unique_ptr& GetFEltSpaceList() const;
......@@ -307,6 +314,14 @@ namespace HappyHeart
DirichletBoundaryCondition::vector_shared_ptr& GetNonCstDirichletBoundaryConditionList();
/*!
* \brief Iterator to the finite element space which index is \a index.
*
* Iterator might be the end of the list; this method is only for internal purposes.
*/
auto GetIteratorFEltSpace(unsigned int index) const;
private:
//! Init the nodes.
......
......@@ -99,7 +99,6 @@ namespace HappyHeart
//! Clear temporary data for each god of dof.
void ClearGodOfDofTemporaryData();
} // namespace HappyHeart
......
......@@ -44,7 +44,7 @@ namespace HappyHeart
/*!
* \brief Compute the dof indexesdepending on the numbering subset.
* \brief Compute the dof indexes depending on the numbering subset.
*
* \tparam MpiScaleT Whether we are computing program_wise or processor (or ghost)-wise indexes.
*
......
//
// InitVertexMatching.cpp
// HappyHeart
//
// Created by Sebastien Gilles on 18/12/15.
// Copyright © 2015 Inria. All rights reserved.
//
#include "Core/NumberingSubset.hpp"
#include "FiniteElement/FiniteElementSpace/Private/InitVertexMatching.hpp"
#include "FiniteElement/FiniteElementSpace/FEltSpace.hpp"
#include "FiniteElement/FiniteElementSpace/GodOfDof.hpp"
namespace HappyHeart
{
namespace Private
{
InitVertexMatching::InitVertexMatching(const unsigned int unique_id,
const FEltSpace& felt_space,
const NumberingSubset& numbering_subset)
: unique_id_parent(unique_id),
felt_space_(felt_space),
numbering_subset_(numbering_subset)
{
const auto& local_felt_space_storage = felt_space.GetLocalFEltSpacePerRefFEltSpace();
auto& Ndof = Nprogram_wise_dof_;
auto& dof_list_per_coord_list = GetNonCstDofProgramWiseIndexPerCoordIndex();
for (const auto& pair : local_felt_space_storage)
{
const auto& local_felt_space_list = pair.second;
for (const auto& local_felt_space_per_geom_elt : local_felt_space_list)
{
const auto& local_felt_space_ptr = local_felt_space_per_geom_elt.second;
assert(!(!local_felt_space_ptr));
const auto& local_felt_space = *local_felt_space_ptr;
const auto& node_bearer_list = local_felt_space.GetNodeBearerList();
for (const auto& node_bearer_ptr : node_bearer_list)
{
assert(!(!node_bearer_ptr));
const auto& node_bearer = *node_bearer_ptr;
if (node_bearer.GetNature() != InterfaceNS::Nature::vertex)
continue;
// Determine the index of the coords. Check whether it is in the matching list and whether it
// has already been handled.
const auto& vertex_coords_list = node_bearer_ptr->GetInterface().GetVertexCoordsList();
assert(vertex_coords_list.size() == 1 && "Interface considered here should be vertex...");
assert(!(!vertex_coords_list.back()));
const auto coord_index = vertex_coords_list.back()->GetIndex();
{
const auto it_coord = dof_list_per_coord_list.find(coord_index);
if (it_coord != dof_list_per_coord_list.cend())
continue;
}
// Fill the list of related dof.
std::vector<unsigned int> index_list;
const auto& node_list = node_bearer.GetNodeList();
for (const auto& node_ptr : node_list)
{
assert(!(!node_ptr));
const auto& node = *node_ptr;
if (!node.DoBelongToNumberingSubset(numbering_subset))
continue;
const auto& dof_list = node.GetDofList();
for (const auto& dof_ptr : dof_list)
{
assert(!(!dof_ptr));
const auto& dof = *dof_ptr;
index_list.push_back(dof.GetProgramWiseIndex(numbering_subset));
++Ndof;
}
}
dof_list_per_coord_list.insert({ coord_index, std::move(index_list) });
}
}
}
std::ofstream out("/Users/sebastien/Desktop/init_vertex_matching_" + std::to_string(unique_id) + "_" + std::to_string(felt_space.MpiHappyHeart().GetRank<int>()));
for (const auto& pair : dof_list_per_coord_list)
{
out << pair.first << " -> ";
Utilities::PrintContainer(pair.second, out);
}
std::cout << "IVM DONE " << dof_list_per_coord_list.size() << std::endl;
}
const std::string& InitVertexMatching::ClassName()
{
static std::string ret("InitVertexMatching");
return ret;
}
void InitVertexMatching::ReduceToProcessorWise()
{
#ifndef NDEBUG
assert(!is_reduced_to_processor_wise_);
is_reduced_to_processor_wise_ = true;
#endif // NDEBUG
const auto& felt_space = GetFEltSpace();
const auto god_of_dof_ptr = felt_space.GetGodOfDofPtr();
const auto& mesh = god_of_dof_ptr->GetGeometricMeshRegion();
const auto& coords_list = mesh.GetCoordsList();
storage_type reduced_storage;
auto& storage = GetNonCstDofProgramWiseIndexPerCoordIndex();
const auto end_storage = storage.cend();
std::cout << "Possibilities: ";
Utilities::PrintKeys(storage);
// auto& Nprocessor_wise_dof = Nprocessor_wise_dof_;
std::cout << "Check " << storage.size() << " ";
for (const auto& coords_ptr : coords_list)
{
assert(!(!coords_ptr));
const auto& coords = *coords_ptr;
const auto coords_index = coords.GetIndex();
auto it = storage.find(coords_index);
if (it != end_storage)
{
reduced_storage.insert(*it);
// Nprocessor_wise_dof += it->second.size();
}
}
std::cout << "\n" << felt_space.MpiHappyHeart().GetRankPreffix() << " STORAGE before/after for " << felt_space.GetUniqueId() << " = " << storage.size() << "\t" << reduced_storage.size() << std::endl;
std::swap(storage, reduced_storage);
}
unsigned int InitVertexMatching::ComputeNprocessorWisedof()
{
const auto& felt_space = GetFEltSpace();
decltype(auto) complete_dof_list = felt_space.GetProcessorWiseDofList();
decltype(auto) numbering_subset = GetNumberingSubset();
unsigned int ret = 0u;
for (const auto& dof_ptr : complete_dof_list)
{
assert(!(!dof_ptr));
const auto& dof = *dof_ptr;
if (dof.IsInNumberingSubset(numbering_subset))
++ret;
}
return ret;
}
} // namespace Private
} // namespace HappyHeart
//
// InitVertexMatching.hpp
// HappyHeart
//
// Created by Sebastien Gilles on 18/12/15.
// Copyright © 2015 Inria. All rights reserved.
//
#ifndef HAPPY_HEART_x_FINITE_ELEMENT_x_FINITE_ELEMENT_SPACE_x_PRIVATE_x_INIT_VERTEX_MATCHING_HPP_
# define HAPPY_HEART_x_FINITE_ELEMENT_x_FINITE_ELEMENT_SPACE_x_PRIVATE_x_INIT_VERTEX_MATCHING_HPP_
# include <memory>
# include <vector>
# include <map>
# include "Utilities/UniqueId/UniqueId.hpp"
namespace HappyHeart
{
// ============================
// Forward declarations.
// ============================
class FEltSpace;
class NumberingSubset;
// ============================
// End of forward declarations.
// ============================
namespace Private
{
// ============================
// Forward declarations.
// ============================
class InitVertexMatchingManager;
// ============================
// End of forward declarations.
// ============================
class InitVertexMatching : public Crtp::UniqueId<InitVertexMatching, UniqueIdNS::AssignationMode::manual>
{
public:
//! Alias to self.
using self = InitVertexMatching;
//! Alias to unique pointer.
using unique_ptr = std::unique_ptr<self>;
//! Friendship to manager.
friend InitVertexMatchingManager;
//! Convenient alias to parent.
using unique_id_parent = Crtp::UniqueId<InitVertexMatching, UniqueIdNS::AssignationMode::manual>;
//! Returns the name of the class.
static const std::string& ClassName();
//! Convenient alias for storage;
using storage_type = std::map<unsigned int, std::vector<unsigned int>>;
public:
/// \name Special members.
///@{
//! Constructor.
explicit InitVertexMatching(unsigned int unique_id,
const FEltSpace& felt_space,
const NumberingSubset& numbering_subset);
//! Destructor.
~InitVertexMatching() = default;
//! Copy constructor.
InitVertexMatching(const InitVertexMatching&) = delete;
//! Move constructor.
InitVertexMatching(InitVertexMatching&&) = delete;
//! Copy affectation.
InitVertexMatching& operator=(const InitVertexMatching&) = delete;
//! Move affectation.
InitVertexMatching& operator=(InitVertexMatching&&) = delete;
///@}
public:
const FEltSpace& GetFEltSpace() const noexcept;
const NumberingSubset& GetNumberingSubset() const noexcept;