Garfield++ 4.0
A toolkit for the detailed simulation of particle detectors based on ionisation measurement in gases and semiconductors
Loading...
Searching...
No Matches
TetrahedralTree.cc
Go to the documentation of this file.
2#include <iostream>
3
4namespace Garfield {
5
6/**
7TetrahedralTree.cc
8This class stores the mesh nodes and elements in an Octree data
9structure to optimize the element search operations
10
11Author: Ali Sheharyar
12Organization: Texas A&M University at Qatar
13*/
14TetrahedralTree::TetrahedralTree(const Vec3& origin, const Vec3& halfDimension)
15 : m_origin(origin), m_halfDimension(halfDimension) {
16 m_min.x = origin.x - halfDimension.x;
17 m_min.y = origin.y - halfDimension.y;
18 m_min.z = origin.z - halfDimension.z;
19 m_max.x = origin.x + halfDimension.x;
20 m_max.y = origin.y + halfDimension.y;
21 m_max.z = origin.z + halfDimension.z;
22
23 // Initially, there are no children
24 for (int i = 0; i < 8; ++i) children[i] = nullptr;
25}
26
28 // Recursively destroy octants
29 for (int i = 0; i < 8; ++i) delete children[i];
30}
31
32// Check if a box overlaps with this node
33bool TetrahedralTree::DoesBoxOverlap(const double bb[6]) const {
34 if (m_max.x < bb[0] || m_max.y < bb[1] || m_max.z < bb[2]) return false;
35 if (m_min.x > bb[3] || m_min.y > bb[4] || m_min.z > bb[5]) return false;
36 return true;
37}
38
39// Determine which octant of the tree would contain 'point'
40int TetrahedralTree::GetOctantContainingPoint(const Vec3& point) const {
41 int oct = 0;
42 if (point.x >= m_origin.x) oct |= 4;
43 if (point.y >= m_origin.y) oct |= 2;
44 if (point.z >= m_origin.z) oct |= 1;
45 return oct;
46}
47
48bool TetrahedralTree::IsLeafNode() const {
49 // We are a leaf if we have no children. Since we either have none, or
50 // all eight, it is sufficient to just check the first.
51 return children[0] == nullptr;
52}
53
54void TetrahedralTree::InsertMeshNode(Vec3 point, const int index) {
55 // Check if it is a leaf node.
56 if (!IsLeafNode()) {
57 // We are at an interior node. Insert recursively into the
58 // appropriate child octant.
59 int octant = GetOctantContainingPoint(point);
60 children[octant]->InsertMeshNode(point, index);
61 return;
62 }
63
64 // Add the new point if the block is not full.
65 if (nodes.size() < BlockCapacity) {
66 nodes.push_back(std::make_pair(point, index));
67 return;
68 }
69 // Block is full, so we need to partition it.
70 // Split the current node and create new empty trees for each child octant.
71 for (int i = 0; i < 8; ++i) {
72 // Compute new bounding box for this child
73 Vec3 newOrigin = m_origin;
74 newOrigin.x += m_halfDimension.x * (i & 4 ? .5f : -.5f);
75 newOrigin.y += m_halfDimension.y * (i & 2 ? .5f : -.5f);
76 newOrigin.z += m_halfDimension.z * (i & 1 ? .5f : -.5f);
77 children[i] = new TetrahedralTree(newOrigin, m_halfDimension * .5f);
78 }
79
80 // Move the mesh nodes from the partitioned node (now marked as interior) to
81 // its children.
82 while (!nodes.empty()) {
83 auto node = nodes.back();
84 nodes.pop_back();
85 const int oct = GetOctantContainingPoint(node.first);
86 children[oct]->InsertMeshNode(node.first, node.second);
87 }
88 // Insert the new point in the appropriate octant.
89 children[GetOctantContainingPoint(point)]->InsertMeshNode(point, index);
90}
91
92void TetrahedralTree::InsertMeshElement(const double bb[6], const int index) {
93 if (IsLeafNode()) {
94 // Add the element to the list of this octant.
95 elements.push_back(index);
96 return;
97 }
98 // Check which children overlap with the element's bounding box.
99 for (int i = 0; i < 8; i++) {
100 if (!children[i]->DoesBoxOverlap(bb)) continue;
101 children[i]->InsertMeshElement(bb, index);
102 }
103}
104
105// It returns the list of tetrahedrons that intersects in a bounding box (Octree
106// block) that contains the
107// point passed as input.
108std::vector<int> TetrahedralTree::GetElementsInBlock(const Vec3& point) const {
109 const TetrahedralTree* octreeNode = GetBlockFromPoint(point);
110
111 if (octreeNode) {
112 return octreeNode->elements;
113 }
114
115 return std::vector<int>();
116}
117
118// check if the point is inside the domain.
119// This function is only executed at root to ensure that input point is inside
120// the mesh's bounding box
121// If we don't check this, the case when root is leaf node itself will return
122// wrong block
123const TetrahedralTree* TetrahedralTree::GetBlockFromPoint(
124 const Vec3& point) const {
125 if (!(m_min.x <= point.x && point.x <= m_max.x &&
126 m_min.y <= point.y && point.y <= m_max.y &&
127 m_min.z <= point.z && point.z <= m_max.z))
128 return nullptr;
129
130 return GetBlockFromPointHelper(point);
131}
132
133const TetrahedralTree* TetrahedralTree::GetBlockFromPointHelper(
134 const Vec3& point) const {
135 // If we're at a leaf node, it means, the point is inside this block
136 if (IsLeafNode()) return this;
137 // We are at the interior node, so check which child octant contains the
138 // point
139 int octant = GetOctantContainingPoint(point);
140 return children[octant]->GetBlockFromPointHelper(point);
141}
142}
Helper class for searches in field maps.
void InsertMeshElement(const double bb[6], const int index)
Insert a mesh element with given bounding box and index to the tree.
TetrahedralTree(const Vec3 &origin, const Vec3 &halfDimension)
Constructor.
std::vector< int > GetElementsInBlock(const Vec3 &point) const
Get all elements linked to a block corresponding to the given point.
void InsertMeshNode(Vec3 point, const int index)
Insert a mesh node (a vertex/point) to the tree.