Commit c27e1175 authored by GILLES Sebastien's avatar GILLES Sebastien
Browse files

#1443 Improve safety and design of Dof/Node/NodeBearer classes:

- Now Dof holds a weak_ptr toward its Node, which itself gets one toward its NodeBearer.
- Whether a Dof belongs to a NumberingSubset is now handled by a test upon its Node.
- Dof program-wise index by numbering subset are now mandatory to fill processor-wise index by numbering subset - this is to avoid invalid state of the object, which is quite complicated to build (part of it before partitioning, and part
of it after).
parent 7022e0cb
......@@ -16,6 +16,7 @@
#include <iostream> // TMP #1443
#include "FiniteElement/Nodes_and_dofs/Dof.hpp"
#include "FiniteElement/Nodes_and_dofs/Node.hpp"
#include "Core/NumberingSubset/NumberingSubset.hpp"
......@@ -47,8 +48,8 @@ namespace MoReFEM
} // namespace anonymous
Dof::Dof(const std::shared_ptr<const NodeBearer>& node_bearer_ptr)
: node_bearer_(node_bearer_ptr)
Dof::Dof(const std::shared_ptr<const Node>& node_ptr)
: node_(node_ptr)
{ }
......@@ -98,17 +99,11 @@ namespace MoReFEM
bool Dof::IsInNumberingSubset(const NumberingSubset& numbering_subset) const
{
const auto& program_wise_index_per_numbering_subset = GetProgramWiseIndexPerNumberingSubset();
// This shouldn't happen (a Dof should be related to at least one NumberingSubset) but it help some tests to
// allow it in this function call (it leads to error messages easier to use to debug).
if (program_wise_index_per_numbering_subset.empty())
return false;
return Iterator(program_wise_index_per_numbering_subset, numbering_subset)
!= program_wise_index_per_numbering_subset.cend();
const auto node_ptr = GetNodeFromWeakPtr();
assert(!(!node_ptr));
return node_ptr->DoBelongToNumberingSubset(numbering_subset);
}
namespace // anonymous
{
......
......@@ -36,6 +36,7 @@ namespace MoReFEM
class NumberingSubset;
class Node;
class NodeBearer;
namespace Internal::FEltSpaceNS
......@@ -105,9 +106,9 @@ namespace MoReFEM
/*!
* \brief Constructor.
*
* \param[in] node_bearer_ptr Pointer to the \a NodeBearer onto which the dof will be created.
* \param[in] node_bearer_ptr Pointer to the \a Node onto which the dof will be created.
*/
explicit Dof(const std::shared_ptr<const NodeBearer>& node_bearer_ptr);
explicit Dof(const std::shared_ptr<const Node>& node_ptr);
//! Destructor.
~Dof();
......@@ -185,15 +186,15 @@ namespace MoReFEM
bool IsInNumberingSubset(const NumberingSubset& numbering_subset) const;
/*!
* \brief Return a pointer to the node bearer to which the current dof belongs to.
* \brief Return a pointer to the \a Node to which the current dof belongs to.
*
* \internal <b><tt>[internal]</tt></b> No reference on purpose here: node_bearer_ is stored as a weak_ptr not
* \internal <b><tt>[internal]</tt></b> No reference on purpose here: node_ is stored as a weak_ptr not
* to introduce circular dependancy.
* \endinternal
*
* \return Shared pointer to the enclosing \a NodeBearer.
* \return Shared pointer to the enclosing \a Node.
*/
std::shared_ptr<const NodeBearer> GetNodeBearerFromWeakPtr() const;
std::shared_ptr<const Node> GetNodeFromWeakPtr() const;
private:
......@@ -278,7 +279,7 @@ namespace MoReFEM
# endif // NDEBUG
//! Weak pointer to NodeBearer.
std::weak_ptr<const NodeBearer> node_bearer_;
std::weak_ptr<const Node> node_;
};
......
......@@ -51,14 +51,13 @@ namespace MoReFEM
}
inline std::shared_ptr<const NodeBearer> Dof::GetNodeBearerFromWeakPtr() const
inline std::shared_ptr<const Node> Dof::GetNodeFromWeakPtr() const
{
assert(!node_bearer_.expired());
return node_bearer_.lock();
assert(!node_.expired());
return node_.lock();
}
} // namespace MoReFEM
......
......@@ -25,19 +25,27 @@ namespace MoReFEM
Node::Node(const std::shared_ptr<const NodeBearer>& node_bearer_ptr,
const ExtendedUnknown& extended_unknown,
unsigned int Ndof)
const ExtendedUnknown& extended_unknown)
: unknown_(extended_unknown.GetUnknown()),
shape_function_label_(extended_unknown.GetShapeFunctionLabel())
shape_function_label_(extended_unknown.GetShapeFunctionLabel()),
node_bearer_(node_bearer_ptr)
{
assert(Ndof > 0);
for (unsigned int i = 0u; i < Ndof; ++i)
dof_list_.push_back(std::make_shared<Dof>(node_bearer_ptr));
const auto& numbering_subset_ptr = extended_unknown.GetNumberingSubsetPtr();
const auto numbering_subset_ptr = extended_unknown.GetNumberingSubsetPtr();
assert(!(!numbering_subset_ptr));
RegisterNumberingSubset(numbering_subset_ptr);
}
void Node::Init(unsigned int Ndof)
{
assert(Ndof > 0);
for (unsigned int i = 0u; i < Ndof; ++i)
dof_list_.push_back(std::make_shared<Dof>(shared_from_this()));
# ifndef NDEBUG
init_called_ = true;
# endif // NDEBUG
}
bool operator<(const Node& lhs, const Node& rhs)
......
......@@ -55,7 +55,7 @@ namespace MoReFEM
* are obvious, a same \a Node might be registered in several \a FEltSpace for different \a NumberingSubset.
* \endinternal
*/
class Node final
class Node final : public std::enable_shared_from_this<Node>
{
public:
......@@ -65,7 +65,10 @@ namespace MoReFEM
//! Vector of shared pointers.
using vector_shared_ptr = std::vector<shared_ptr>;
public:
//! Friendship to \a NodeBearer (the only class allowed to create \a Node object).
friend class NodeBearer;
private:
/// \name Special members.
///@{
......@@ -73,20 +76,24 @@ namespace MoReFEM
/*!
* \brief Constructor.
*
* It is private as it shoud be called only by \a NodeBearer.
*
* \param[in] extended_unknown Unknown addressed by all the dofs in the Node
* (e.g. 'displacement', 'pressure'). It is here an extended unknown because when it is created it is
* within a given numbering subset, however it's important to remember a given Node might be related to many
* numbering subsets in the end (some may be added through \a RegisterNumberingSubset()).
* \param[in] node_bearer_ptr Pointer to the node bearer onto which the \a Node is created.
* \param[in] Ndof Number of dofs to create.
*/
explicit Node(const std::shared_ptr<const NodeBearer>& node_bearer_ptr,
const ExtendedUnknown& extended_unknown,
unsigned int Ndof);
const ExtendedUnknown& extended_unknown);
public:
//! Destructor.
~Node() = default;
private:
//! \copydoc doxygen_hide_copy_constructor
Node(const Node& rhs) = delete;
......@@ -102,6 +109,18 @@ namespace MoReFEM
///@}
/*!
* \brief This method must be called to fulfill construction of the objet.
*
* \internal The \a Dof are built there as they need weak pointer to current object - which the constructor can't give directly.
*
* \param[in] Ndof Number of dofs to create.
* */
void Init(unsigned int Ndof);
public:
//! Get the unknown.
const Unknown& GetUnknown() const noexcept;
......@@ -136,6 +155,16 @@ namespace MoReFEM
//! Return the list of numbering subset.
const NumberingSubset::vector_const_shared_ptr& GetNumberingSubsetList() const noexcept;
/* \brief Return a pointer to the \a NodeBearer to which the current \a Node belongs to.
*
* \internal <b><tt>[internal]</tt></b> No reference on purpose here: node_bearer_ is stored as a weak_ptr not
* to introduce circular dependancy.
* \endinternal
*
* \return Shared pointer to the enclosing \a NodeBearer.
*/
std::shared_ptr<const NodeBearer> GetNodeBearerFromWeakPtr() const;
private:
//! Unknown.
......@@ -149,6 +178,13 @@ namespace MoReFEM
//! List of dofs.
Dof::vector_shared_ptr dof_list_;
//! Weak pointer to NodeBearer.
std::weak_ptr<const NodeBearer> node_bearer_;
# ifndef NDEBUG
bool init_called_ = false;
# endif // NDEBUG
};
......
......@@ -22,18 +22,21 @@ namespace MoReFEM
inline const Unknown& Node::GetUnknown() const noexcept
{
assert(init_called_ && "Init() should be called!");
return unknown_;
}
inline const Dof::vector_shared_ptr& Node::GetDofList() const noexcept
{
assert(init_called_ && "Init() should be called!");
return dof_list_;
}
inline const Dof::shared_ptr& Node::GetDofPtr(unsigned int i) const
{
assert(init_called_ && "Init() should be called!");
const auto& dof_list = GetDofList();
assert(i < static_cast<unsigned int>(dof_list.size()));
assert(!(!dof_list[i]));
......@@ -43,28 +46,38 @@ namespace MoReFEM
inline const Dof& Node::GetDof(unsigned int i) const
{
assert(init_called_ && "Init() should be called!");
return *GetDofPtr(i);
}
inline const std::string& Node::GetShapeFunctionLabel() const noexcept
{
assert(init_called_ && "Init() should be called!");
return shape_function_label_;
}
inline unsigned int Node::Ndof() const noexcept
{
assert(init_called_ && "Init() should be called!");
return static_cast<unsigned int>(dof_list_.size());
}
inline const NumberingSubset::vector_const_shared_ptr& Node::GetNumberingSubsetList() const noexcept
{
assert(init_called_ && "Init() should be called!");
return numbering_subset_list_;
}
inline std::shared_ptr<const NodeBearer> Node::GetNodeBearerFromWeakPtr() const
{
assert(!node_bearer_.expired());
return node_bearer_.lock();
}
} // namespace MoReFEM
......
......@@ -14,6 +14,7 @@
#include <algorithm>
#include "FiniteElement/Nodes_and_dofs/Node.hpp"
#include "FiniteElement/Nodes_and_dofs/NodeBearer.hpp"
#include "FiniteElement/FiniteElementSpace/FEltSpace.hpp"
......@@ -59,13 +60,14 @@ namespace MoReFEM
{
assert(Ndof > 0);
auto node_ptr = std::make_shared<Node>(shared_from_this(),
extended_unknown,
Ndof);
node_list_.push_back(node_ptr);
auto node_ptr = new Node(shared_from_this(), extended_unknown);
node_ptr->Init(Ndof);
auto shared_ptr = std::shared_ptr<Node>(node_ptr);
node_list_.push_back(shared_ptr);
return node_ptr;
return shared_ptr;
}
......
......@@ -43,9 +43,12 @@ namespace MoReFEM
if (dof.IsInNumberingSubset(numbering_subset))
{
const auto node_bearer = dof.GetNodeBearerFromWeakPtr();
const auto node_ptr = dof.GetNodeFromWeakPtr();
assert(!(!node_ptr));
const auto node_bearer_ptr = node_ptr->GetNodeBearerFromWeakPtr();
const auto& interface = node_bearer->GetInterface();
const auto& interface = node_bearer_ptr->GetInterface();
assert(interface.GetNature() == InterfaceNS::Nature::vertex && "At the moment this function works only for P1 dofs...");
decltype(auto) coords_list = interface.GetVertexCoordsList();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment