source: XIOS/trunk/extern/remap/src/node.cpp @ 688

Last change on this file since 688 was 688, checked in by mhnguyen, 9 years ago

Integrating remap library into XIOS

+) Change name of some files of remap library to be compatible with XIOS
+) Implement function to fill in automatically boundary longitude and latitude

Test
+) On Curie
+) test_remap correct

File size: 17.4 KB
Line 
1//#include "mpi.h" // some compiler fails if mpi.h is not the first header to be included
2#include <mpi.h>
3#include <cstdlib>
4#include <cmath>
5#include <iostream>
6#include <cassert>
7#include "tree.hpp"
8#include "elt.hpp"
9#include "intersect.hpp"
10#include <vector>
11#include <set>
12#include <algorithm>
13
14#include "node.hpp"
15
16namespace sphereRemap {
17
18
19#define UPDATE_EVERY 1
20
21using namespace std;
22
23//#ifdef DEBUG
24//std::map<void*, struct mem_info> _mem_deb; // reference counter
25//
26//void NodePtr::unlink()
27//{
28//      _mem_deb[ptr].ref_cnt -= 1;
29//      if (_mem_deb[ptr].ref_cnt == 0) // we were last reference
30//      {
31//              if (_mem_deb[ptr].stat == DELETED) // delete has already been called, everything is fine, free memory now
32//              {
33//                      _mem_deb.erase(ptr);
34//                      ::delete [] ((char *) ptr);
35//              }
36//              else // no more pointer, but memory not freed -> memory leak !!
37//              {
38//                      std::cerr << "WARNING: Memory leak created at address " << ptr << ".";
39//                      assert(_mem_deb[ptr].stat == ALLOCATED); // and not BORROWED
40//#ifdef AUTO_LEAK_FIX
41//                      // free automatically, just for fun
42//                      _mem_deb.erase(ptr);
43//                      ptr->~Node(); // call destructor, since `Node::delete` has not been applied it has not been called
44//                      ::delete [] ((char *) ptr);
45//                      std::cerr << " LEAK FIXED.";
46//#endif
47//
48//                      std::cerr << std::endl;
49//              }
50//      }
51//}
52//
53//void memory_report()
54//{
55//      for (std::map<void*, struct mem_info>::iterator it = _mem_deb.begin(); it != _mem_deb.end(); it++)
56//      {
57//              if (it->second.stat == BORROWED) continue;
58//              std::cerr << "Node at " << it->first << " has " << it->second.ref_cnt << " references to it and "
59//                        << ((it->second.stat == DELETED) ? "has" : "has *not*") << " been deleted." << std::endl;
60//#ifdef AUTO_LEAK_FIX
61//              if (it->second.stat == ALLOCATED) // `Node::delete` has not been called
62//                      ((Node *) it->first)->~Node();
63//              delete [] ((char *)  it->first);
64//#endif
65//      }
66//}
67//
68//int ref_cnt(void *ptr)
69//{
70//      return _mem_deb[ptr].ref_cnt;
71//}
72//#endif
73
74int compareDist(NodePtr n1, NodePtr n2)
75{
76        return squaredist(n1->tree->ref->centre, n1->centre)
77             < squaredist(n2->tree->ref->centre, n2->centre);
78}
79
80/* On level `level` find the node in our subtree that is closest to `src` and return through argument `closest`.
81   The return value is just for recursive calling */
82void Node::findClosest(int level, NodePtr src, double& minDist2, NodePtr &closest)
83{
84        double r2;
85
86        r2 = squaredist(src->centre, this->centre);
87        if (level == this->level)
88        {
89                if (r2 < minDist2 || closest == NULL)
90                {
91                        minDist2 = r2;
92                        closest = this;
93                }
94        }
95        else if (r2 < radius*radius)
96        {
97                for(int i = 0; i < child.size(); i++)
98                        child[i]->findClosest(level, src, minDist2, closest);
99        }
100}
101
102NodePtr Node::farthest(vector<NodePtr >& list)
103{
104        assert(this);
105        double dmax = -HUGE_VAL;
106        NodePtr node = NULL;
107        for (size_t i=0; i < list.size(); i++)
108        {
109                double d = ds(this->centre, list[i]->centre);
110                if (d > dmax) {
111                        node = list[i];
112                        dmax = d;
113                }
114        }
115        return node;
116}
117
118/* returns element in `list` cosest to us (`this`) by meassure `ds`.
119   If `n` is negative finds element furthest away instead. */
120NodePtr Node::closest(vector<NodePtr >& list, int n)
121{
122        assert(this);
123        double dmin2 = (n>0) ? HUGE_VAL : -HUGE_VAL;
124        NodePtr node = NULL;
125        for (int i = 0; i < list.size(); i++)
126        {
127                double d2 = squaredist(this->centre, list[i]->centre);
128                if (n * (d2 - dmin2) < 0)
129                {
130                        node = list[i];
131                        dmin2 = d2;
132                }
133        }
134        return node;
135}
136
137// make sure we will be able to accomodate `node`
138void Node::move(const NodePtr node)   // this->leafCount may be 0
139{
140        double w = double(node->leafCount)/double(node->leafCount + this->leafCount);
141        Coord oldCentre = this->centre;
142        this->centre = proj(this->centre * (1-w) + node->centre * w);
143        this->leafCount += node->leafCount;
144        this->radius += arcdist(oldCentre, this->centre) + 1e-9;
145}
146
147void Node::remove(const NodePtr node)
148{
149        if (&node == NULL) return;
150        double w = double(node->leafCount) / this->leafCount;
151        Coord newCentre = proj(this->centre - node->centre * w);
152        this->leafCount -= node->leafCount;
153        this->radius += arcdist(newCentre, this->centre) + 1e-9;
154        this->centre = newCentre;
155        this->updateCount++;
156}
157
158void Node::inflate(const NodePtr node)
159{
160        double d = arcdist(this->centre, node->centre);
161        double r = node->radius;
162        if (this->radius < d + r)
163                this->radius = d + r + 1e-9;
164}
165
166/* recomputes the radius which currently might be much larger than necessary */
167void Node::update()
168{
169        Coord centre = ORIGIN;
170        int n = 0;
171        for (int i = 0; i < this->child.size(); i++) {
172                centre = centre + this->child[i]->centre * this->child[i]->leafCount;
173                n += this->child[i]->leafCount;
174        }
175        this->centre = proj(centre);
176        this->leafCount = n;
177
178        double R = 0;
179        for (int i = 0; i < this->child.size(); i++)
180        {
181                double d = arcdist(this->centre, this->child[i]->centre);
182                double r = this->child[i]->radius;
183                if (R < d + r) R = d + r;
184        }
185        this->radius = R + 1e-9;
186        this->updateCount = 0;
187        if (child.size())
188                level = child[0]->level + 1;
189}
190
191void Node::output(ostream& flux, int level, int color)
192{
193  if (level==this->level)
194  {
195    flux<<centre.x<<" , "<<centre.y<<" , "<<centre.z<<" , "<<radius<<endl ;
196  }
197  else
198  {
199    for (int i = 0; i < this->child.size(); i++) child[i]->output(flux,level,color) ;
200  }
201}
202
203
204/* void Node::append(NodePtr node);
205{
206        if (node->level == this->level -1)
207        {
208                // new node is one level lower (correct level)
209                this->child.append(node);
210                node->parent = this;
211        }
212        else if (node->level < this->level -1)
213        {
214                // if new node is on even lower level, recursively append to closest child
215                node->closest(this->child)->append(node);
216        }
217        else
218        {
219                cerr << "Error: Attempted node insertion with invalid level." << endl;
220                exit(1);
221        }
222}*/
223
224bool find_in_tree1(Node* node)
225{
226        if (node == node->tree->root) return true;
227        if (node->parent == NULL)
228        {
229                cerr << "Cannot find!" << endl;
230                return false;
231        }
232        return find_in_tree1(node->parent);
233}
234
235bool find_in_tree2(NodePtr node, NodePtr ref)
236{
237        for (int i = 0; i < ref->child.size(); i++)
238        {
239                if (node == ref->child[i])
240                {
241                        cerr << "find2: " << ref << " -> " << ref->child[i] << endl;
242                        return true;
243                }
244                else if (find_in_tree2(node, ref->child[i]))
245                {
246                        cerr << "find2: " << ref << " -> " << ref->child[i] << endl;
247                        return true;
248                }
249        }
250        return false;
251}
252
253
254/* This appends `this` to the node `node` */
255NodePtr insert(NodePtr thIs, NodePtr node)
256{
257        int la = thIs->level; // node to be inserted
258        int lb = node->level; // node where insertation
259        assert(la < lb); // node to be inserted must have lower level then parent
260        //if (thIs->parent) assert(find_in_tree1(thIs) == true);
261        NodePtr q = NULL;
262        NodePtr chd = NULL;
263        node->move(thIs);
264        if (la == lb - 1)
265        {
266                node->child.push_back(thIs);
267                thIs->parent = node;
268                if (node->child.size() > MAX_NODE_SZ) // with us as additional child `node` is now too large :(
269                        return (node->reinserted || node->parent == NULL) ?
270                                split(node) : reinsert(node);
271        }
272        else // la < lb - 1
273        {
274                chd = thIs->closest(node->child);
275                q = insert(thIs, chd);
276        }
277        if ((node->updateCount + 1) % UPDATE_EVERY == 0)
278                node->update();
279        else
280        {
281                if (q) node->remove(q);
282                node->inflate(chd);
283        }
284        return q;
285}
286
287typedef NodePtr pNode;
288
289/* move `frac` of our children to a new node which is returned */
290NodePtr reinsert(NodePtr thIs)
291{
292        thIs->tree->ref = thIs;
293        std::sort(thIs->child.begin(), thIs->child.end(), compareDist);
294        int out = (int) (frac*thIs->child.size());
295
296        /* make sure out is only so big that there are still MIN_NODE_SZ children after removing out */
297        if (thIs->child.size() - out < MIN_NODE_SZ) out = thIs->child.size() - MIN_NODE_SZ;
298
299        /* transfere out children from us to a new node q which will be returned */
300        NodePtr q = new Node;
301        q->tree = thIs->tree;
302        q->child.resize(out);
303        for (int i = thIs->child.size() - out; i < thIs->child.size(); i++)
304        {
305                thIs->tree->push_back(thIs->child[i]);
306                int k = i - (thIs->child.size() - out);
307                q->child[k] = thIs->child[i];
308                q->child[k]->parent = q;
309        }
310        thIs->child.resize(thIs->child.size() - out);
311        thIs->update();
312        q->update();
313        thIs->reinserted = true; // avoid infinite loop of reinserting the same node, by marking it as reinserted and stop if same node arrives at same place again
314        thIs->tree->ri = 1;
315        return q;
316}
317
318/* move around nodes that are far away from the centre of their parents in order reduce radia of the circles
319   leading to faster look-up times because of less redundancies between nodes.
320   TODO cite paper for Slim SS-tree */
321void slim2(NodePtr thIs, int level)
322{
323        bool out;
324        double distChild;
325
326#ifdef DEBUG
327//      assert(ref_cnt(thIs) >= thIs->child.size() + 1 /*parent*/ + 1 /*thIs*/);
328#endif
329        if (thIs->level==level)
330        {
331                out = false;
332                while (!out)
333                {
334                        /* remove child which is farthest away from the centre and try to reinsert it into the tree */
335                        double distMax = 0;
336                        int itMax = -1;
337                        for (int i = 0; i < thIs->child.size(); i++)
338                        {
339                                distChild = arcdist(thIs->centre, thIs->child[i]->centre) + thIs->child[i]->radius;
340                                if (distChild > distMax)
341                                {
342                                        distMax = distChild;
343                                        itMax = i;
344                                }
345                        }
346                        if (transferNode(thIs->tree->root, thIs, thIs->child[itMax]))
347                        {
348                                thIs->child.erase(thIs->child.begin()+itMax);
349                                out = false;
350                        }
351                        else
352                                out = true;
353
354                        if (thIs->child.size() < MIN_NODE_SZ) out = true;
355                }
356
357                if (thIs->child.size() < MIN_NODE_SZ  && thIs->level < thIs->tree->root->level)
358                {
359                        thIs->tree->decreaseLevelSize(thIs->level);
360                        for(int i = 0; i < thIs->child.size(); i++)
361                                thIs->tree->push_back(thIs->child[i]);
362                        thIs->child.resize(0);
363                }
364                else thIs->update();
365        }
366        else
367        {
368                int newChildCount = 0;
369                for (int i = 0; i < thIs->child.size(); i++)
370                {
371                        if (thIs == thIs->tree->root)
372                        {
373                                // keep at least one child for root
374                                if (i == thIs->child.size()-1 && newChildCount == 0)
375                                {
376                                        thIs->child[newChildCount] = thIs->child[i];
377                                        newChildCount++;
378                                        break;
379                                }
380                        }
381
382                        slim2(thIs->child[i], level);
383                        if (thIs->child[i]->child.size() != 0) // thIs->child[i] is not a leaf
384                        {
385                                thIs->child[newChildCount] = thIs->child[i];
386                                newChildCount++;
387                        } /* else FIXME sometimes this child must be deleted (otherwise leak) sometimes not (otherwise segfault)
388                                        maybe delete not here but when transfered
389                                delete thIs->child[i]; // if our child does not make any grand-children what good is it? -> remove!
390*/
391
392                }
393                thIs->child.resize(newChildCount);
394
395                if (thIs->child.size() < MIN_NODE_SZ && thIs->level < thIs->tree->root->level)
396                {
397                        thIs->tree->decreaseLevelSize(thIs->level);
398                        for (int i = 0; i < thIs->child.size(); i++)
399                                thIs->tree->push_front(thIs->child[i]);
400                        thIs->child.resize(0);
401                }
402                else thIs->update();
403        }
404}
405
406bool transferNode(NodePtr thIs, NodePtr parent, NodePtr node)
407{
408  if (parent == thIs) return false;
409
410        if (thIs->level == parent->level)
411        {
412                if (thIs->child.size() < MAX_NODE_SZ && thIs->child.size() >= MIN_NODE_SZ)
413                {
414                        insert(node, thIs);
415                        return true;
416                }
417                else
418                        return false;
419        }
420        else
421        {
422                for (int i = 0; i < thIs->child.size(); i++)
423                {
424                        if (arcdist(thIs->child[i]->centre, node->centre) + node->radius < thIs->child[i]->radius)
425                        {
426                                if (transferNode(thIs->child[i], parent, node))
427                                {
428                                        thIs->update();
429                                        return true;
430                                }
431                        }
432                }
433                return false;
434        }
435}
436
437
438
439NodePtr split(NodePtr thIs)
440{
441        thIs->tree->increaseLevelSize(thIs->level);
442        NodePtr p = new Node;
443        NodePtr q = new Node;
444        p->level = q->level = thIs->level;
445        p->reinserted = q->reinserted = false;
446        p->parent = q->parent = thIs->parent;
447        p->tree = q->tree = thIs->tree;
448
449
450        p->child.resize(MAX_NODE_SZ/2);
451        q->child.resize(MAX_NODE_SZ/2 + 1);
452        assert(thIs->child.size() == MAX_NODE_SZ+1);
453        thIs->tree->ref = q->child[0] = thIs->closest(thIs->child, FARTHEST); // farthest from centre
454        std::sort(thIs->child.begin(), thIs->child.end(), compareDist);
455        for (int i = 1; i < MAX_NODE_SZ+1; i++)
456                assert(thIs->child[i]->parent == thIs);
457        for (int i = 1; i < MAX_NODE_SZ/2 + 1; i++)
458                q->child[i] = thIs->child[i];
459        for (int i = MAX_NODE_SZ/2+1; i<MAX_NODE_SZ+1; i++)
460                p->child[i-MAX_NODE_SZ/2-1] = thIs->child[i];
461        for (int i = 0; i < MAX_NODE_SZ/2 + 1; i++)
462                q->child[i]->parent = q;
463        for (int i = MAX_NODE_SZ/2+1; i < MAX_NODE_SZ+1; i++)
464                p->child[i-MAX_NODE_SZ/2-1]->parent = p;
465        p->update();
466        q->update();
467
468        if (squaredist(thIs->centre, q->centre) < squaredist(thIs->centre, p->centre))
469                swap(p, q);
470
471        thIs->child = p->child; // now our children do not know we are their parents and believe p is their parent
472        for (int i = 0; i < thIs->child.size(); i++)
473                thIs->child[i]->parent = thIs;
474        thIs->reinserted = p->reinserted;
475        thIs->update();
476        delete p;
477
478        if (thIs == thIs->tree->root) // root split
479        {
480                // since we currently are root, make new root and make us and q its children
481                thIs->tree->newRoot(thIs->level + 1);
482                thIs->tree->root->child.push_back(thIs);  thIs->parent = thIs->tree->root;
483                thIs->tree->root->child.push_back(q);     q->parent    = thIs->tree->root;
484                thIs->tree->root->update();
485        }
486        else
487        {
488                thIs->tree->push_front(q);
489        }  // push_front?
490        return q;
491}
492
493/* Assuming we are a leaf push all leafs into our list of intersectors
494   that are descendant of node and whoes circle intersects ours.
495*/
496void Node::search(NodePtr node)
497{
498        assert(this->level == 0);
499        int Nchild = node->child.size();
500        if (this->intersects(node)) {
501                if (node->level == 0)
502                        this->intersectors.push_back(node);
503                else
504                        for (int i=0; i<Nchild; i++)
505                                search(node->child[i]);
506        }
507}
508
509/* FIXME this should not be in node.cpp and getNeighbours should not be part of the SS-tree
510   this is mapper specific */
511void findNeighbour(NodePtr thIs, NodePtr node, set<NodePtr >& neighbourList)
512{
513        if (thIs->level==0)
514        {
515                Elt* elt1= (Elt*)(thIs->data);
516                Elt* elt2= (Elt*)(node->data);
517                if (isNeighbour(*elt1, *elt2)) neighbourList.insert(thIs);
518        }
519        else
520        {
521                for(int i=0; i<thIs->child.size(); i++)
522                        if (thIs->child[i]->intersects(node)) findNeighbour(thIs->child[i], node, neighbourList);
523        }
524}
525
526bool Node::intersects(NodePtr node)
527{
528        double d = arcdist(this->centre, node->centre);
529        double r = this->radius;
530        double R = node->radius;
531        return (d < r + R + 1e-9) ? true : false;
532}
533
534bool Node::centreInside(Node &node)
535{
536        double d = arcdist(this->centre, node.centre);
537        double R = node.radius;
538        return (d < R + 1e-9) ? true : false;
539}
540
541bool Node::isInside(Node &node)
542{
543        double d = arcdist(this->centre, node.centre);
544        double r = this->radius;
545        double R = node.radius;
546        return (d + r < R + 1e-9) ? true : false;
547}
548
549int Node::incluCheck()
550{
551        if (this->level == 0) return 0;
552        int nOutside = 0;
553        int n = this->child.size();  // cout << "n = " << n << endl;
554        for (int i=0; i<n; i++)
555        {
556                if (!this->child[i]->isInside(*this))
557                {
558                        cout << "Node of level " << this->level << " does not contain its "
559                                << i << "th child\n";
560                        nOutside++;
561                }
562                nOutside += this->child[i]->incluCheck();
563        }
564        return nOutside;
565}
566
567void Node::printChildren()
568{
569        cout << "level " << this->level << ", centre ";
570        cout << "level " << this->level << ", centre " << this->centre << "\t r = " << this->radius << endl;
571        cout << this << " p: " << this->parent << endl;
572        int n = this->child.size();
573        for (int i=0; i<n; i++)
574        {
575                NodePtr child = this->child[i];
576                cout << "fils " << i << ": centre " << child->centre << "\t r = " << child->radius << endl;
577                cout << "dist to center " << arcdist(this->centre, child->centre) <<
578                        " d + R = " << arcdist(this->centre,child->centre)+child->radius << endl;
579        }
580}
581
582void Node::assignRoute(std::vector<int>::iterator& rank, int level)
583{
584        if (this->level==level)
585        {
586                route = *rank;
587                rank++;
588        }
589        else
590        {
591                for (int i = 0; i < child.size(); i++)
592                        child[i]->assignRoute(rank, level);
593        }
594}
595
596void Node::assignCircleAndPropagateUp(Coord *centres, double *radia, int level)
597{
598        if (this->level == level)
599        {
600                // assign
601                centre = centres[route];
602                radius = radia[route];
603                free_descendants(); // levels of sample tree beyond `level` will not be used any more
604                child.resize(0);
605                this->level = 0;
606        }
607        else
608        {
609                for (int i = 0; i < child.size(); i++)
610                        child[i]->assignCircleAndPropagateUp(centres, radia, level);
611                update(); // propagate up
612        }
613}
614
615/* Route node `node` within the subtree attached to us.
616 `level` is the level one which to assign
617*/
618// Each sample node has a rank randomly assigned to it, assign `node` from full tree
619void Node::routeNode(NodePtr node, int level)
620{
621        NodePtr closest;
622
623        double distMin2 = 0; // squared distance
624        closest = NULL;
625        if (tree->root == this)
626                findClosest(level, node, distMin2, closest);
627
628        if (closest != NULL && tree->root == this)
629                /* When is this point reached?
630                   if the preceeding findClosest was called and succesed to set closest
631                   findClosest sets closest if we are `level` or src is in our circle (=> belongs to child of ours)
632                   => reached if we are not `level` and node is not child of us
633                */
634                node->route = closest->route;
635        else  /* find closest was not successfull or we were not root */
636        {
637                if (this->level == level)
638                        node->route = this->route;
639                else /* not yet right level => go down one more */
640                        node->closest(this->child)->routeNode(node, level);
641        }
642}
643
644void Node::routeIntersection(vector<int>& routes, NodePtr node)
645{
646        if (level == 0)
647        {
648                routes.push_back(this->route);
649        }
650        else
651        {
652                for (int i = 0; i < child.size(); i++) {
653                        if (child[i]->intersects(node))
654                                child[i]->routeIntersection(routes, node);
655                }
656        }
657}
658
659void Node::routingIntersecting(vector<Node> *routingList, NodePtr node)
660{
661        if (level==0)
662        {
663                int rank = route;
664                routingList[rank].push_back(*node);
665        }
666        else
667        {
668                for (int i = 0; i < child.size(); i++) {
669                        if (child[i]->intersects(node))
670                                child[i]->routingIntersecting(routingList, node);
671                }
672        }
673}
674
675void Node::free_descendants()
676{
677        for (int i = 0; i < child.size(); i++)
678        {
679                child[i]->free_descendants();
680                if (child[i]->level) // do not attempt to delete leafs, they are delete through leafs vector
681                        delete child[i];
682        }
683}
684
685}
Note: See TracBrowser for help on using the repository browser.