View on GitHub

Vistle

Distributed Data-parallel Scientific Visualization in VR

celltree_impl.h
Go to the documentation of this file.
1#ifndef CELLTREE_IMPL_H
2#define CELLTREE_IMPL_H
3
4namespace vistle {
5
6//#define CT_DEBUG
7//#define CT_DEBUG_VERBOSE
8
9//const Scalar Epsilon = std::numeric_limits<Scalar>::epsilon();
10
11const unsigned MaxLeafSize = 8;
12
13template<typename Scalar, typename Index, int NumDimensions>
15{
16 return (Object::Type)(Object::CELLTREE1 + NumDimensions - 1);
17}
18
19template<typename Scalar, typename Index, int NumDimensions>
20V_COREEXPORT void Celltree<Scalar, Index, NumDimensions>::refreshImpl() const
21{}
22
23template<typename Scalar, typename Index, int NumDimensions>
25 const Vector &gmax)
26{
27 assert(nodes().size() == 1);
28 for (int i = 0; i < NumDimensions; ++i)
29 this->min()[i] = gmin[i];
30 for (int i = 0; i < NumDimensions; ++i)
31 this->max()[i] = gmax[i];
32#ifdef CT_DEBUG
33 struct MinMaxBoundsFunctor: public Celltree::CellBoundsFunctor {
34 const Vector *m_min, *m_max;
35
36 MinMaxBoundsFunctor(const Vector *min, const Vector *max): m_min(min), m_max(max) {}
37
38 bool operator()(Index elem, Vector *min, Vector *max) const
39 {
40 auto vmin = m_min[elem], vmax = m_max[elem];
41 *min = vmin;
42 *max = vmax;
43
44 return true;
45 }
46 };
47 MinMaxBoundsFunctor boundFunc(min, max);
48 this->validateTree(boundFunc);
49#endif
50 refine(min, max, 0, gmin, gmax);
51#ifdef CT_DEBUG
52 std::cerr << "created celltree: " << nodes().size() << " nodes, " << cells().size() << " cells" << std::endl;
53 validateTree(boundFunc);
54#endif
55}
56
57template<typename Scalar, typename Index, int NumDimensions>
59 const Vector &gmin, const Vector &gmax)
60{
61 const Scalar smax = std::numeric_limits<Scalar>::max();
62
63 const int NumBuckets = 5;
64
65 Node *node = &(nodes()[curNode]);
66
67 // only split node if necessary
68 if (node->size <= MaxLeafSize)
69 return;
70
71 // cell index array, contains runs of cells belonging to nodes
72 Index *cells = d()->m_cells->data();
73
74 // sort cells into buckets for each possible split dimension
75
76 // initialize min/max extents of buckets
77 Index bucket[NumDimensions][NumBuckets];
78 Vector bmin[NumBuckets], bmax[NumBuckets];
79 for (int i = 0; i < NumBuckets; ++i) {
80 for (int d = 0; d < NumDimensions; ++d)
81 bucket[d][i] = 0;
82 bmin[i].fill(smax);
83 bmax[i].fill(-smax);
84 }
85
86 auto center = [min, max](Index c) -> Vector {
87 return Scalar(0.5) * (min[c] + max[c]);
88 };
89
90 // find min/max extents of cell centers
91 Vector cmin, cmax;
92 cmin.fill(smax);
93 cmax.fill(-smax);
94 for (Index i = node->start; i < node->start + node->size; ++i) {
95 const Index cell = cells[i];
96 Vector cent = center(cell);
97 for (int d = 0; d < NumDimensions; ++d) {
98 if (cmin[d] > cent[d])
99 cmin[d] = cent[d];
100 if (cmax[d] < cent[d])
101 cmax[d] = cent[d];
102 }
103 }
104
105 // sort cells into buckets
106 const Vector crange = cmax - cmin;
107
108 auto getBucket = [cmin, cmax, crange, NumBuckets](Vector center, int d) -> int {
109 return crange[d] == 0 ? 0 : std::min(int((center[d] - cmin[d]) / crange[d] * NumBuckets), NumBuckets - 1);
110 };
111
112 for (Index i = node->start; i < node->start + node->size; ++i) {
113 const Index cell = cells[i];
114 const Vector cent = center(cell);
115 for (int d = 0; d < NumDimensions; ++d) {
116 const int b = getBucket(cent, d);
117 assert(b >= 0);
118 assert(b < NumBuckets);
119 ++bucket[d][b];
120 bmin[b][d] = std::min(bmin[b][d], min[cell][d]);
121 bmax[b][d] = std::max(bmax[b][d], max[cell][d]);
122 }
123 }
124
125 // adjust bucket bounds for empty buckets
126 for (int d = 0; d < NumDimensions; ++d) {
127 for (int b = NumBuckets - 2; b >= 0; --b) {
128 if (bmin[b][d] > bmin[b + 1][d])
129 bmin[b][d] = bmin[b + 1][d];
130 }
131 for (int b = 1; b < NumBuckets; ++b) {
132 if (bmax[b][d] < bmax[b - 1][d])
133 bmax[b][d] = bmax[b - 1][d];
134 }
135 }
136
137 // find best split dimension and plane
138 Scalar min_weight(smax);
139 int best_dim = -1, best_bucket = -1;
140 for (int d = 0; d < NumDimensions; ++d) {
141 Index nleft = 0;
142 for (int split_b = 0; split_b < NumBuckets - 1; ++split_b) {
143 nleft += bucket[d][split_b];
144 assert(node->size >= nleft);
145 const Index nright = node->size - nleft;
146 Scalar weight =
147 nleft * (bmax[split_b][d] - bmin[0][d]) + nright * (bmax[NumBuckets - 1][d] - bmin[split_b + 1][d]);
148 if (crange[d] > 0)
149 weight /= node->size * crange[d];
150 else
151 weight = smax;
152 //std::cerr << "d="<<d<< ", b=" << split_b<< ", weight=" << weight << std::endl;
153 if (nleft > 0 && nright > 0 && weight < min_weight) {
154 min_weight = weight;
155 best_dim = d;
156 best_bucket = split_b;
157 }
158 }
159 assert(nleft + bucket[d][NumBuckets - 1] == node->size);
160 }
161 if (best_dim == -1) {
162 std::cerr << "abandoning split with " << node->size << " children" << std::endl;
163 return;
164 }
165
166 // split index lists...
167 const Index size = node->size;
168 const Index start = node->start;
169
170 // record children into node being split
171 const Scalar Lmax = bmax[best_bucket][best_dim];
172 const Scalar Rmin = bmin[best_bucket + 1][best_dim];
173 *node = Node(best_dim, Lmax, Rmin, nodes().size());
174 const Index D = best_dim;
175
176 auto centerD = [min, max, D](Index c) -> Scalar {
177 return Scalar(0.5) * (min[c][D] + max[c][D]);
178 };
179 auto getBucketD = [cmin, cmax, crange, D, NumBuckets](Scalar center) -> int {
180 return crange[D] == 0 ? 0 : std::min(int((center - cmin[D]) / crange[D] * NumBuckets), NumBuckets - 1);
181 };
182
183#ifdef CT_DEBUG
184 const Scalar split = cmin[D] + crange[D] / NumBuckets * (best_bucket + 1);
185#ifdef CT_DEBUG_VERBOSE
186 std::cerr << "split: dim=" << best_dim << ", bucket=" << best_bucket;
187 std::cerr << " (";
188 for (int i = 0; i < NumBuckets; ++i) {
189 std::cerr << bucket[best_dim][i];
190 if (i == best_bucket)
191 std::cerr << "|";
192 else if (i < NumBuckets - 1)
193 std::cerr << " ";
194 }
195 std::cerr << ")";
196 std::cerr << " split: " << split;
197 std::cerr << " (" << cmin[D] << " - " << cmax[D] << ")";
198 std::cerr << std::endl;
199#endif
200#endif
201
202 Index nleft = 0;
203 Index *top = &cells[start + size];
204 for (Index *c = &cells[start]; c < top; ++c) {
205 const Scalar cent = centerD(*c);
206 const int b = getBucketD(cent);
207 if (b > best_bucket) {
208 for (Scalar other;;) {
209 --top;
210 other = centerD(*top);
211 const int bo = getBucketD(other);
212 if (bo < best_bucket + 1) {
213 if (c < top) {
214 std::swap(*c, *top);
215 ++nleft;
216 }
217 break;
218 }
219 }
220 } else {
221 ++nleft;
222 }
223 }
224
225#ifdef CT_DEBUG
226 for (Index i = nleft; i < size; ++i) {
227 Index c = cells[start + i];
228 Vector cent = center(c);
229 assert(cent[D] >= split);
230 assert(min[c][D] >= Rmin);
231 for (int i = 0; i < 3; ++i) {
232 assert(min[c][i] >= gmin[i]);
233 assert(max[c][i] <= gmax[i]);
234 }
235 }
236 for (Index i = 0; i < nleft; ++i) {
237 Index c = cells[start + i];
238 Vector cent = center(c);
239 assert(cent[D] <= split);
240 assert(max[c][D] <= Lmax);
241 for (int i = 0; i < 3; ++i) {
242 assert(min[c][i] >= gmin[i]);
243 assert(max[c][i] <= gmax[i]);
244 }
245 }
246#endif
247
248 Index l = nodes().size();
249 nodes().push_back(Node(start, nleft));
250
251 Index r = nodes().size();
252 nodes().push_back(Node(start + nleft, size - nleft));
253
254 assert(nodes()[l].size < size);
255 assert(nodes()[r].size < size);
256 assert(nodes()[l].size + nodes()[r].size == size);
257
258 Vector nmin = gmin;
259 Vector nmax = gmax;
260
261 // further refinement for left...
262 nmin[best_dim] = bmin[0][best_dim];
263 nmax[best_dim] = bmax[best_bucket][best_dim];
264 refine(min, max, l, nmin, nmax);
265
266 // ...and right subnodes
267 nmin[best_dim] = bmin[best_bucket + 1][best_dim];
268 nmax[best_dim] = bmax[NumBuckets - 1][best_dim];
269 refine(min, max, r, nmin, nmax);
270}
271
272template<typename Scalar, typename Index, int NumDimensions>
273template<class BoundsFunctor>
275{
276 Vector mmin, mmax;
277 for (int c = 0; c < NumDimensions; ++c) {
278 mmin[c] = min()[c];
279 mmax[c] = max()[c];
280 }
281#ifdef CT_DEBUG
282 std::cerr << "validateCelltree: min=" << mmin << ", max=" << mmax << std::endl;
283#endif
284 return validateNode(boundFunc, 0, mmin, mmax);
285}
286
287template<typename Scalar, typename Index, int NumDimensions>
288template<class BoundsFunctor>
289bool Celltree<Scalar, Index, NumDimensions>::validateNode(BoundsFunctor &boundFunc, Index nodenum, const Vector &min,
290 const Vector &max) const
291{
292 bool valid = true;
293 const Index *cells = d()->m_cells->data();
294 const Node *node = &(nodes()[nodenum]);
295 if (node->isLeaf()) {
296 for (Index i = node->start; i < node->start + node->size; ++i) {
297 const Index elem = cells[i];
298 Vector emin, emax;
299 boundFunc(elem, &emin, &emax);
300 for (int d = 0; d < NumDimensions; ++d) {
301 if (emin[d] < min[d]) {
302 std::cerr << "celltree node " << nodenum << " @" << i - node->start << " of " << node->size
303 << ": min[" << d << "] violation on elem " << elem << ": is " << emin << ", should "
304 << min << std::endl;
305 valid = false;
306 }
307 if (emax[d] > max[d]) {
308 std::cerr << "celltree node " << nodenum << " @" << i - node->start << " of " << node->size
309 << ": max[" << d << "] violation on elem " << elem << ": is " << emax << ", should "
310 << max << std::endl;
311 valid = false;
312 }
313 }
314 }
315 return valid;
316 }
317
318 if (node->Lmax < min[node->dim]) {
319 std::cerr << "celltree: Lmax=" << node->Lmax << " too small for dim=" << node->dim
320 << ", should >= " << min[node->dim] << std::endl;
321 valid = false;
322 }
323 if (node->Rmin < min[node->dim]) {
324 std::cerr << "celltree: Rmin=" << node->Rmin << " too small for dim=" << node->dim
325 << ", should >= " << min[node->dim] << std::endl;
326 valid = false;
327 }
328 if (node->Lmax > max[node->dim]) {
329 std::cerr << "celltree: Lmax=" << node->Lmax << " too large for dim=" << node->dim
330 << ", should <= " << max[node->dim] << std::endl;
331 valid = false;
332 }
333 if (node->Rmin > max[node->dim]) {
334 std::cerr << "celltree: Rmin=" << node->Rmin << " too large for dim=" << node->dim
335 << ", should <= " << max[node->dim] << std::endl;
336 valid = false;
337 }
338
339 Vector lmax(max), rmin(min);
340 lmax[node->dim] = node->Lmax;
341 rmin[node->dim] = node->Rmin;
342
343 if (!validateNode(boundFunc, node->left(), min, lmax))
344 valid = false;
345 if (!validateNode(boundFunc, node->right(), rmin, max))
346 valid = false;
347 return valid;
348}
349
350template<class Scalar, class Index, int NumDimensions>
351template<class Archive>
353{
354 assert("serialization of Celltree::Node not implemented" == 0);
355}
356
357template<typename Scalar, typename Index, int NumDimensions>
359: Celltree::Base(Celltree::Data::create("", numCells, meta))
360{
361 refreshImpl();
362}
363
364template<typename Scalar, typename Index, int NumDimensions>
366{
367 refreshImpl();
368}
369
370template<typename Scalar, typename Index, int NumDimensions>
371Celltree<Scalar, Index, NumDimensions>::Celltree(Data *data): Celltree::Base(data)
372{
373 refreshImpl();
374}
375
376template<typename Scalar, typename Index, int NumDimensions>
378{
379 return d()->m_nodes->empty() || d()->m_cells->empty();
380}
381
382template<typename Scalar, typename Index, int NumDimensions>
384{
385 return d()->m_nodes->empty() || d()->m_cells->empty();
386}
387
388template<typename Scalar, typename Index, int NumDimensions>
389bool Celltree<Scalar, Index, NumDimensions>::checkImpl() const
390{
391 V_CHECK(d()->m_nodes->size() >= 1);
392 V_CHECK(d()->m_nodes->size() <= d()->m_cells->size());
393 if ((*d()->m_nodes)[0].isLeaf()) {
394 V_CHECK((*d()->m_nodes)[0].size <= d()->m_cells->size());
395 } else {
396 V_CHECK((*d()->m_nodes)[0].Lmax >= (*d()->m_nodes)[0].Rmin);
397 }
398 return true;
399}
400
401template<typename Scalar, typename Index, int NumDimensions>
402void Celltree<Scalar, Index, NumDimensions>::Data::initData()
403{
404 const Scalar smax = std::numeric_limits<Scalar>::max();
405 for (int d = 0; d < NumDimensions; ++d) {
406 m_bounds[d] = smax;
407 m_bounds[NumDimensions + d] = -smax;
408 }
409
410 m_nodes.construct(1);
411 (*m_nodes)[0] = Node(0, 0);
412}
413
414template<typename Scalar, typename Index, int NumDimensions>
415Celltree<Scalar, Index, NumDimensions>::Data::Data(const Data &o, const std::string &n)
416: Celltree::Base::Data(o, n), m_cells(o.m_cells), m_nodes(o.m_nodes)
417{
418 memcpy(m_bounds, o.m_bounds, sizeof(m_bounds));
419}
420
421template<typename Scalar, typename Index, int NumDimensions>
422Celltree<Scalar, Index, NumDimensions>::Data::Data(const std::string &name, const Index numCells, const Meta &meta)
423: Base::Data(Object::Type(Object::CELLTREE1 - 1 + NumDimensions), name, meta)
424{
425 initData();
426
427 m_cells.construct(numCells);
428
429 Index *cells = m_cells->data();
430 for (Index i = 0; i < numCells; ++i) {
431 cells[i] = i;
432 }
433
434 (*m_nodes)[0] = Node(0, numCells);
435}
436
437template<typename Scalar, typename Index, int NumDimensions>
439Celltree<Scalar, Index, NumDimensions>::Data::create(const std::string &objId, const Index numCells, const Meta &meta)
440{
441 const std::string name = Shm::the().createObjectId(objId);
442 Data *ct = shm<Data>::construct(name)(name, numCells, meta);
443 publish(ct);
444
445 return ct;
446}
447
448#if 0
449V_OBJECT_CREATE_NAMED(Celltree<Scalar, Index, NumDimensions>)
450#else
451template<typename Scalar, typename Index, int NumDimensions>
452Celltree<Scalar, Index, NumDimensions>::Data::Data(Object::Type id, const std::string &name, const Meta &meta)
453: Base::Data(id, name, meta)
454{
455 initData();
456}
457
458template<typename Scalar, typename Index, int NumDimensions>
460Celltree<Scalar, Index, NumDimensions>::Data::createNamed(Object::Type id, const std::string &name)
461{
462 Data *t = shm<Data>::construct(name)(id, name, Meta());
463 publish(t);
464 return t;
465}
466#endif
467
468} // namespace vistle
469#endif
compute bounding box of a cell
Definition: celltree.h:78
Definition: celltree.h:31
void refine(const Vector *min, const Vector *max, Index nodeIdx, const Vector &gmin, const Vector &gmax)
Definition: celltree_impl.h:58
shm< Index >::array & cells()
Definition: celltree.h:99
VistleScalarVector< NumDimensions >::type Vector
Definition: celltree.h:37
CelltreeNode< sizeof(Index), NumDimensions > Node
Definition: celltree.h:38
bool validateTree(BoundsFunctor &func) const
Definition: celltree_impl.h:274
void init(const Vector *min, const Vector *max, const Vector &gmin, const Vector &gmax)
Definition: celltree_impl.h:24
Celltree(const Index numCells, const Meta &meta=Meta())
Definition: celltree_impl.h:358
Definition: objectmeta.h:16
Definition: object.h:58
virtual bool isEmpty() const
Definition: object.cpp:349
ObjectData Data
Definition: object.h:69
Type
Definition: object.h:84
@ CELLTREE1
Definition: object.h:109
std::string createObjectId(const std::string &name="")
Definition: shm.cpp:435
static Shm & the()
Definition: shm.cpp:315
#define V_COREEXPORT
Definition: export.h:9
void serialize(Archive &ar, vistle::Vector1 &v, const unsigned int version)
Definition: vector.h:105
static T min(T a, T b)
Definition: messages.cpp:28
Definition: allobjects.cpp:30
const unsigned MaxLeafSize
Definition: celltree_impl.h:11
Vector3 Vector
Definition: vector.h:36
float Scalar
Definition: scalar.h:14
uint32_t Index
Definition: index.h:13
Definition: celltree.h:20
#define V_OBJECT_CREATE_NAMED(ObjType)
Definition: object.h:542
#define V_CHECK(true_expr)
use in checkImpl
Definition: object.h:368
Definition: object.h:233
Meta meta
Definition: object.h:238
static ObjectData * create(Object::Type id, const std::string &name, const Meta &m)
Definition: object.cpp:244
const shm_name_t name
Definition: shmdata.h:41
static managed_shm::segment_manager::template construct_proxy< T >::type construct(const std::string &name)
Definition: shm_impl.h:87