Commit 2005f7ac authored by Quentin Khan's avatar Quentin Khan

Add possibility to create ghost nodes in the adaptive tree

The ghost nodes are exactly the same as the original ones, a flag is
used to mark the difference.
parent 723a952d
......@@ -211,7 +211,6 @@ public:
/// Node data structure
using data_t = NodeData;
/**
* \brief Node structural data
* Keeps data about the node that may be read by kernels or algorithms.
......@@ -222,12 +221,15 @@ public:
static_assert(models_symbolic_data<symbolic_data_t>::value,
"The symbolic_data_t type does not model the required symbolic data interface.");
/// Level type alias
using level_t = typename std::remove_reference<
decltype(std::declval<symbolic_data_t>().getLevel())>::type;
/// Morton index type alias
using morton_index_t = typename std::remove_reference<
decltype(std::declval<symbolic_data_t>().getMortonIndex())>::type;
constexpr static int not_ghost_tag = ~0;
private:
......@@ -254,6 +256,8 @@ private:
/// Indicates whether node is a leaf
bool _is_leaf = true;
/// Owner process when node is a ghost
int ghost_owner_ = ~0;
/// Node data that may be of use to algorithms and kernels
symbolic_data_t _symbolic_data;
......@@ -408,10 +412,24 @@ public:
}
/// Morton index accessor
std::size_t getIndex() const noexcept {
morton_index_t getIndex() const noexcept {
return _symbolic_data.m_idx;
}
/// Check whether node is a ghost
bool is_ghost() const {
return this->ghost_owner_ != not_ghost_tag;
}
/// Owner process rank
int ghost_owner() const {
return this->ghost_owner_;
}
void set_ghost_owner(int owner_id) {
this->ghost_owner_ = owner_id;
}
/// Tree accessor
tree_t& getTree() noexcept {
return *_tree;
......@@ -560,6 +578,7 @@ public:
std::size_t child_index = box_t::space_filling_curve_t::index(p.position(), getBox().center());
getChild(child_index)->insert(p);
} else {
this->set_ghost_owner(not_ghost_tag);
this->getParticleContainer()->reserve(this->getTree().leaf_max_particle_count());
particle_push(*(this->getParticleContainer()), p);
if(getParticleContainer()->size() > getTree().leaf_max_particle_count()) {
......@@ -599,6 +618,38 @@ public:
return particle_t();
}
/**
* \brief Builds a ghost leaf at specified location
*
* Builds the minimal subtree needed so that the leaf at given level with
* given morton index exists. Nodes created to reach the given leaf are
* marked as owned by given owner.
*
* \param level Leaf level
* \param m_idx Leaf morton index
* \param owner_id Id of process owning the leaf
*/
void build_ghost_leaf(level_t level, morton_index_t m_idx, int owner_id) {
constexpr unsigned mask = ~((~0u) << Dim);
auto* n = this;
while(n->getLevel() != level) {
if(n->is_leaf()) {
n->split();
for(FNode* child : n->_children) {
child->set_ghost_owner(owner_id);
}
}
auto child_idx = (m_idx >> (level - n->getLevel() - 1)) & mask;
n = n->getChild(child_idx);
}
n->set_ghost_owner(owner_id);
}
/**
* \brief Splits or fuses nodes after tree modifications
*
......@@ -1082,6 +1133,14 @@ public:
}
return os;
}
friend morton_index_t morton_index(const FNode& n) {
return n.getIndex();
}
friend level_t level(const FNode& n) {
return n.getLevel();
}
};
......
......@@ -55,6 +55,7 @@ public:
friend node_t;
using level_t = typename node_t::level_t;
using morton_index_t = typename node_t::morton_index_t;
/// Print particles when printing tree or not
bool print_particles = false;
......@@ -240,6 +241,70 @@ public:
return _leaves;
}
/**
* \brief Builds a ghost leaf at specified location
*
* Builds the minimal subtree needed so that the leaf at given level with
* given morton index exists. Nodes created to reach the given leaf are
* marked as owned by given owner.
*
* \param level Leaf level
* \param m_idx Leaf morton index
* \param owner_id Id of process owning the leaf
*/
void build_ghost_leaf(level_t l, morton_index_t m, unsigned owner_id) {
this->root()->build_ghost_leaf(l, m, owner_id);
}
/**
* \brief Builds a ghost leaf at specified location
*
* Builds the minimal subtree needed so that the leaf at given level with
* given morton index exists. Nodes created to reach the given leaf are
* marked as owned by given owner.
*
* \param node_info Node information
* \param owner_id Id of process owning the leaf
*
* \tparam NodeInfo Node information type.
*
* The node_info object must have two free functions defined:
*
* - `level(node_info)`
* - `morton_index(node_info)`
*/
template<class NodeInfo>
void build_ghost_leaf(const NodeInfo& node_info, unsigned owner_id) {
level_t l = static_cast<level_t>(level(node_info));
morton_index_t m = static_cast<morton_index_t>(morton_index(node_info));
this->root()->build_ghost_leaf(l, m, owner_id);
}
/**
* \brief Builds ghost leaves from a range of locations
*
* Builds the minimal subtree needed so that the leaf at given level with
* given morton index exists. Nodes created to reach the given leaf are
* marked as owned by given owner.
*
* \param r Node information range
* \param owner_id Id of process owning the leaf
*
* \tparam NodeInfoRange Range of node information type.
*
* The NodeInfo objects must have two free functions defined:
*
* - `level(node_info)`
* - `morton_index(node_info)`
*/
template<class NodeInfoRange>
void build_ghost_subtree(const NodeInfoRange& r, unsigned owner_id) {
for(const auto& node_info : r) {
this->build_ghost_leaf(node_info, owner_id);
}
}
/**
* \brief In order walk accessor
*/
......
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