OpenWalnut  1.5.0dev
WHtree.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 //---------------------------------------------------------------------------
26 //
27 // Project: hClustering
28 //
29 // Whole-Brain Connectivity-Based Hierarchical Parcellation Project
30 // David Moreno-Dominguez
31 // d.mor.dom@gmail.com
32 // moreno@cbs.mpg.de
33 // www.cbs.mpg.de/~moreno//
34 // This file is also part of OpenWalnut ( http://www.openwalnut.org ).
35 //
36 // For more reference on the underlying algorithm and research they have been used for refer to:
37 // - Moreno-Dominguez, D., Anwander, A., & Knoesche, T. R. (2014).
38 // A hierarchical method for whole-brain connectivity-based parcellation.
39 // Human Brain Mapping, 35(10), 5000-5025. doi: http://dx.doi.org/10.1002/hbm.22528
40 // - Moreno-Dominguez, D. (2014).
41 // Whole-brain cortical parcellation: A hierarchical method based on dMRI tractography.
42 // PhD Thesis, Max Planck Institute for Human Cognitive and Brain Sciences, Leipzig.
43 // ISBN 978-3-941504-45-5
44 //
45 // hClustering is free software: you can redistribute it and/or modify
46 // it under the terms of the GNU Lesser General Public License as published by
47 // the Free Software Foundation, either version 3 of the License, or
48 // (at your option) any later version.
49 // http://creativecommons.org/licenses/by-nc/3.0
50 //
51 // hClustering is distributed in the hope that it will be useful,
52 // but WITHOUT ANY WARRANTY; without even the implied warranty of
53 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
54 // GNU Lesser General Public License for more details.
55 //
56 //---------------------------------------------------------------------------
57 
58 // std library
59 #include <utility>
60 #include <vector>
61 #include <list>
62 #include <algorithm>
63 #include <string>
64 #include <fstream>
65 
66 #include "core/common/WStringUtils.h"
67 #include "core/common/exceptions/WFileOpenFailed.h"
68 #include "core/common/WLogger.h"
69 #include "WHtree.h"
70 
71 
72 
73 WHtree::WHtree(): m_loadStatus( false ), m_cpcc( 0 )
74 {
75 }
76 
77 WHtree::WHtree( std::string filename ): m_loadStatus( false ), m_cpcc( 0 )
78 {
79  readTree( filename );
80 }
81 
82 WHtree::WHtree( std::string treeName, HC_GRID datasetGridInit, WHcoord datasetSizeInit, size_t numStreamlinesInit, float logFactorInit,
83  std::vector< WHnode > leavesInit, std::vector< WHnode > nodesInit, std::vector< size_t > trackidInit,
84  std::vector< WHcoord > coordInit, std::list< WHcoord > discardInit, float cpccInit )
85  : m_loadStatus( false ),
86  m_datasetSize( datasetSizeInit ),
87  m_datasetGrid( datasetGridInit ),
88  m_numStreamlines( numStreamlinesInit ),
89  m_logFactor( logFactorInit ),
90  m_cpcc( cpccInit ),
91  m_treeName( treeName ),
92  m_leaves( leavesInit ),
93  m_nodes( nodesInit ),
94  m_coordinates( coordInit ),
95  m_trackids( trackidInit ),
96  m_discarded( discardInit )
97 {
98  if( check() )
99  {
100  m_loadStatus = true;
101  }
102 }
103 
104 WHtree::WHtree( const WHtree &object )
105  : m_loadStatus( object.m_loadStatus ),
106  m_datasetSize( object.m_datasetSize ),
107  m_datasetGrid( object.m_datasetGrid ),
108  m_numStreamlines( object.m_numStreamlines ),
109  m_logFactor( object.m_logFactor ),
110  m_cpcc( object.m_cpcc ),
111  m_treeName( object.m_treeName ),
112  m_leaves( object.m_leaves ),
113  m_nodes( object.m_nodes ),
114  m_coordinates( object.m_coordinates ),
115  m_trackids( object.m_trackids ),
116  m_discarded( object.m_discarded ),
117  m_containedLeaves( object.m_containedLeaves )
118 {
119 }
120 
122 {
123  //Cleanup
124 }
125 
126 
127 
128 // === PUBLIC MEMBER FUNCTIONS ===
129 
130 
131 
132 std::string WHtree::getReport( bool longMsg ) const
133 {
134  if( !m_loadStatus )
135  {
136  return "tree not loaded";
137  }
138  std::string reportMessage( "Tree has " + string_utils::toString( m_leaves.size() ) + " leaves and " +
139  string_utils::toString( m_nodes.size() ) + " nodes" );
140  if( longMsg )
141  {
142  reportMessage += "\nDataset size is: " + m_datasetSize.getNameString() + " in " + getGridString( m_datasetGrid ) + " format";
143  if( m_cpcc != 0 )
144  {
145  reportMessage += ". CPCC: " + string_utils::toString( m_cpcc );
146  }
147  }
148  return reportMessage;
149 } // end getReport() -------------------------------------------------------------------------------------
150 
151 
152 bool WHtree::check() const
153 {
154  if( m_nodes.empty() || m_leaves.size() < 2 )
155  {
156  wlog::error( "WHtree" ) << "ERROR @ WHtree::check(): only 0-1 leaf / no nodes";
157  return false;
158  }
159  if( m_coordinates.size() != m_leaves.size() )
160  {
161  wlog::error( "WHtree" ) << "ERROR @ WHtree::check(): leaves(" << m_leaves.size() << ") and coordinates(" \
162  << m_coordinates.size() << ") vector sizes do not match";
163  return false;
164  }
165  if( m_coordinates.size() != m_trackids.size() )
166  {
167  wlog::error( "WHtree" ) << "WARNING @ WHtree::writeTree(): trackids(" << m_trackids.size() << ") and coordinates(" \
168  << m_coordinates.size() << ") vector sizes do not match. track ids will be invalid";
169  }
170  if( m_nodes.size() >= m_leaves.size() )
171  {
172  wlog::error( "WHtree" ) << "ERROR @ WHtree::check(): same number of nodes as leaves";
173  return false;
174  }
175 
176  std::vector<size_t> sumLeafParents( m_leaves.size(), 0 );
177  std::vector<size_t> sumNodeParents( m_nodes.size(), 0 );
178  std::vector<size_t> sumNodeKids( m_nodes.size(), 0 );
179 
180  // loop through leaves
181  for( std::vector<WHnode>::const_iterator leafIter( m_leaves.begin() ); leafIter != m_leaves.end(); ++leafIter )
182  {
183  nodeID_t parentID( leafIter->getParent() );
184  if( !parentID.first )
185  {
186  wlog::error( "WHtree" ) << "ERROR @ WHtree::check(): leaf has a leaf as parent";
187  return false;
188  }
189  std::vector<nodeID_t> kids = getNode( parentID ).getChildren();
190  if( find( kids.begin(), kids.end(), leafIter->getFullID() ) == kids.end() )
191  {
192  wlog::error( "WHtree" ) << "ERROR @ WHtree::check(): leaf parent doesnt have leaf ID among its children";
193  return false;
194  }
195  if( leafIter->getSize() != 1 )
196  {
197  wlog::error( "WHtree" ) << "ERROR @ WHtree::check(): leaf has a size other than 1";
198  return false;
199  }
200  if( leafIter->getHLevel() != 0 )
201  {
202  wlog::error( "WHtree" ) << "ERROR @ WHtree::check(): leaf has hLevel other than 0";
203  return false;
204  }
205  ++sumNodeKids[parentID.second];
206  }
207 
208  // loop through nodes
209  for( std::vector<WHnode>::const_iterator nodeIter( m_nodes.begin() ); nodeIter != m_nodes.end(); ++nodeIter )
210  {
211  std::vector<nodeID_t> kids = nodeIter->getChildren();
212  size_t currentHLevel( 0 ), currentSize( 0 );
213 
214  for( std::vector<nodeID_t>::const_iterator kidIter( kids.begin() ); kidIter != kids.end(); ++kidIter )
215  {
216  currentHLevel = std::max( currentHLevel, getNode( *kidIter ).getHLevel()+1 );
217  currentSize += getNode( *kidIter ).getSize();
218  nodeID_t kidParent = getNode( *kidIter ).getParent();
219  if( kidParent != nodeIter->getFullID() )
220  {
221  wlog::error( "WHtree" ) << "ERROR @ WHtree::check(): node child (" << kidIter->first << "-" << kidIter->second
222  << ") doesnt have node ID (" << nodeIter->isNode() << "-" << nodeIter->getID()
223  << ") as its parent but instead has (" << kidParent.first << "-" << kidParent.second << ")";
224  return false;
225  }
226  if( kidIter->first )
227  {
228  ++sumNodeParents[kidIter->second];
229  }
230  else
231  {
232  ++sumLeafParents[kidIter->second];
233  }
234  }
235 
236  nodeID_t parentID( nodeIter->getParent() );
237  if( ( !parentID.first ) && ( ( nodeIter+1 ) != m_nodes.end() ) )
238  {
239  wlog::error( "WHtree" ) << "ERROR @ WHtree::check(): node has a leaf as parent";
240  return false;
241  }
242  if( ( !nodeIter->isRoot() ) && ( ( nodeIter+1 ) == m_nodes.end() ) )
243  {
244  wlog::error( "WHtree" ) << "ERROR @ WHtree::check(): last node does not have 0-0 as parent";
245  return false;
246  }
247  if( !nodeIter->isRoot() )
248  {
249  std::vector<nodeID_t> kids = getNode( parentID ).getChildren();
250  if( find( kids.begin(), kids.end(), nodeIter->getFullID() ) == kids.end() )
251  {
252  wlog::error( "WHtree" ) << "ERROR @ WHtree::check(): node parent doesnt have node ID among its children";
253  return false;
254  }
255  ++sumNodeKids[parentID.second];
256  }
257  if( nodeIter->getSize() != currentSize )
258  {
259  wlog::error( "WHtree" ) << "ERROR @ WHtree::check(): node " << nodeIter->getID() << " size (" << nodeIter->getSize()
260  << ") is not sum of its children sizes (" << currentSize << ")";
261  return false;
262  }
263  if( nodeIter->getHLevel() != currentHLevel )
264  {
265  wlog::error( "WHtree" ) << "ERROR @ WHtree::check(): node hLevel is not one more than its highest child";
266  return false;
267  }
268  }
269 
270  //check consistency of counters
271  for( std::vector<size_t>::const_iterator iter( sumLeafParents.begin() ); iter != sumLeafParents.end(); ++iter )
272  {
273  if( *iter != 1 )
274  {
275  wlog::error( "WHtree" ) << "ERROR @ WHtree::check(): more than one node has the same leaf as child";
276  return false;
277  }
278  }
279  for( std::vector<size_t>::const_iterator iter( sumNodeParents.begin() ); iter != sumNodeParents.end()-1; ++iter )
280  {
281  if( *iter != 1 )
282  {
283  wlog::error( "WHtree" ) << "ERROR @ WHtree::check(): more than one node has the same node as child";
284  return false;
285  }
286  }
287  if( sumNodeParents.back() != 0 )
288  {
289  wlog::error( "WHtree" ) << "ERROR @ WHtree::check(): at least one node has the root node as child";
290  return false;
291  }
292  for( std::vector<WHnode>::const_iterator nodeIter( m_nodes.begin() ); nodeIter != m_nodes.end(); ++nodeIter )
293  {
294  std::vector<nodeID_t> kids = nodeIter->getChildren();
295  if( kids.size() != sumNodeKids[nodeIter->getID()] )
296  {
297  wlog::error( "WHtree" )
298  << "ERROR @ WHtree::check(): node children vector size does not match the number of nodes/leafs that have it as parent" << std::endl
299  << nodeIter->printAllData();
300  return false;
301  }
302  }
303  return true; // everything checked out fine
304 } // end check() -------------------------------------------------------------------------------------
305 
306 
307 const WHnode& WHtree::getNode( const nodeID_t &thisNode ) const
308 {
309  if( thisNode.first )
310  {
311  return getNode( thisNode.second );
312  }
313  else
314  {
315  return getLeaf( thisNode.second );
316  }
317 } // end getNode() -------------------------------------------------------------------------------------
318 const WHnode& WHtree::getNode( const size_t thisNode ) const
319 {
320  if( thisNode >= m_nodes.size() )
321  {
322  wlog::error( "WHtree" ) << "ERROR @ WHtree::getNode: index is out of boundaries(" << thisNode << ". total nodes: "
323  << m_nodes.size() << "), returning first node";
324  return m_nodes.front();
325  }
326  else
327  {
328  return ( m_nodes[thisNode] );
329  }
330 } // end getNode() -------------------------------------------------------------------------------------
331 
332 
333 const WHnode& WHtree::getLeaf( const size_t thisLeaf ) const
334 {
335  if( thisLeaf >= m_leaves.size() )
336  {
337  wlog::error( "WHtree" ) << "ERROR @ WHtree::getLeaf: index is out of boundaries (" << thisLeaf << ". total leaves: "
338  << m_leaves.size() << "), returning first leaf";
339  return m_leaves.front();
340  }
341  else
342  {
343  return ( m_leaves[thisLeaf] );
344  }
345 } // end getLeaf() -------------------------------------------------------------------------------------
346 
347 
348 const WHnode& WHtree::getRoot() const
349 {
350  return ( m_nodes.back() );
351 } // end getRoot() -------------------------------------------------------------------------------------
352 
353 
354 size_t WHtree::getLeafID( const WHcoord &thisCoord ) const
355 {
356  std::vector<WHcoord>::const_iterator findIter( std::find( m_coordinates.begin(), m_coordinates.end(), thisCoord ) );
357  if( findIter == m_coordinates.end() )
358  {
359  throw std::runtime_error( "ERROR @ WHtree::getLeafID(): coordinate is not in the tree" );
360  }
361  else
362  {
363  return( findIter-m_coordinates.begin() );
364  }
365 } // end getLeafID() -------------------------------------------------------------------------------------
366 
367 size_t WHtree::getTrackID( const size_t &leafID ) const
368 {
369  if( leafID >= m_trackids.size() )
370  {
371  throw std::runtime_error( "ERROR @ WHtree::getTrackID(): leafID is out of boundaries" );
372  }
373  else
374  {
375  return m_trackids[leafID];
376  }
377 } // end getTrackID() -------------------------------------------------------------------------------------
378 
379 
380 std::vector<size_t> WHtree::getLeaves4node( const size_t nodeID ) const
381 {
382  std::vector<size_t> returnVector;
383 
384  if( nodeID >= m_nodes.size() )
385  {
386  wlog::error( "WHtree" ) << "ERROR @ WHtree::getLeaves4node(): nodeID is out of boundaries";
387  return returnVector;
388  }
389  else
390  {
391  if( !m_containedLeaves.empty() ) // if contained leaves for each node have already been calculated, just return them
392  {
393  return m_containedLeaves[nodeID];
394  }
395  else // if not, calculate them for this node
396  {
397  std::list<size_t> worklist;
398  worklist.push_back( nodeID );
399  while( !worklist.empty() )
400  {
401  size_t currentNode( worklist.front() );
402  worklist.pop_front();
403  std::vector<nodeID_t> kids( getNode( currentNode ).getChildren() );
404  for( std::vector<nodeID_t>::const_iterator iter( kids.begin() ); iter != kids.end(); ++iter )
405  {
406  if( iter->first ) // is node
407  {
408  worklist.push_back( iter->second );
409  }
410  else // is leaf
411  {
412  returnVector.push_back( iter->second );
413  }
414  }
415  }
416  std::sort( returnVector.begin(), returnVector.end() );
417  return returnVector;
418  }
419  }
420 } // end getLeaves4node() -------------------------------------------------------------------------------------
421 std::vector<size_t> WHtree::getLeaves4node( const nodeID_t &nodeID ) const
422 {
423  if( nodeID.first )
424  {
425  return getLeaves4node( nodeID.second );
426  }
427  else
428  {
429  return std::vector<size_t>( 1, nodeID.second );
430  }
431 } // end getLeaves4node() -------------------------------------------------------------------------------------
432 
433 
434 std::vector<size_t> WHtree::getBranchNodes( const size_t nodeID ) const
435 {
436  std::vector<size_t> returnVector;
437  if( nodeID >= getNumNodes() )
438  {
439  wlog::error( "WHtree" ) << "ERROR @ WHtree::getBranchNodes(): nodeID is out of boundaries";
440  return returnVector;
441  }
442  else
443  {
444  std::list<size_t> worklist;
445  worklist.push_back( nodeID );
446  while( !worklist.empty() )
447  {
448  size_t currentNode( worklist.front() );
449  worklist.pop_front();
450  returnVector.push_back( currentNode );
451  std::vector<nodeID_t> kids( getNode( currentNode ).getChildren() );
452  for( std::vector<nodeID_t>::const_iterator iter( kids.begin() ); iter != kids.end(); ++iter )
453  {
454  if( iter->first )
455  {
456  worklist.push_back( iter->second ); // is node
457  }
458  }
459  }
460  std::sort( returnVector.begin(), returnVector.end() );
461  return returnVector;
462  }
463 } // end getBranchNodes() -------------------------------------------------------------------------------------
464 
465 
466 WHcoord WHtree::getCoordinate4leaf( const size_t leafID ) const
467 {
468  if( leafID >= m_coordinates.size() )
469  {
470  wlog::error( "WHtree" ) << "ERROR @ WHtree::coordinate4leaf(): leafID is out of boundaries";
471  return WHcoord( 0, 0, 0 );
472  }
473  else
474  {
475  return m_coordinates[leafID];
476  }
477 } // end getCoordinate4leaf() -------------------------------------------------------------------------------------
478 
479 
480 std::vector<WHcoord> WHtree::getCoordinates4node( const size_t nodeID ) const
481 {
482  std::vector<WHcoord> returnVector;
483  std::vector<size_t> containedLeaves( getLeaves4node( nodeID ) );
484 
485  for( std::vector<size_t>::const_iterator iter( containedLeaves.begin() ); iter != containedLeaves.end(); ++iter )
486  {
487  returnVector.push_back( getCoordinate4leaf( *iter ) );
488  }
489  return returnVector;
490 } // end getCoordinates4node() -------------------------------------------------------------------------------------
491 std::vector<WHcoord> WHtree::getCoordinates4node( const nodeID_t &nodeID ) const
492 {
493  if( nodeID.first )
494  {
495  return getCoordinates4node( nodeID.second );
496  }
497  else
498  {
499  return std::vector<WHcoord>( 1, getCoordinate4leaf( nodeID.second ) );
500  }
501 } // end getCoordinates4node() -------------------------------------------------------------------------------------
502 
503 
504 WHcoord WHtree::getMeanCoordinate4node( const size_t nodeID ) const
505 {
506  WHcoord baseCoord;
507  {
508  std::vector<WHcoord> bnCoords( getCoordinates4node( nodeID ) );
509  size_t sumX( 0 ), sumY( 0 ), sumZ( 0 );
510  for( std::vector<WHcoord>::const_iterator coordIter( bnCoords.begin() ); coordIter != bnCoords.end(); ++coordIter )
511  {
512  sumX += coordIter->m_x;
513  sumY += coordIter->m_y;
514  sumZ += coordIter->m_z;
515  }
516  baseCoord.m_x = sumX/bnCoords.size();
517  baseCoord.m_y = sumY/bnCoords.size();
518  baseCoord.m_z = sumZ/bnCoords.size();
519  }
520  return baseCoord;
521 } // end getMeanCoordinate4node() -------------------------------------------------------------------------------------
522 WHcoord WHtree::getMeanCoordinate4node( const nodeID_t &nodeID ) const
523 {
524  if( nodeID.first )
525  {
526  return getMeanCoordinate4node( nodeID.second );
527  }
528  else
529  {
530  return getCoordinate4leaf( nodeID.second );
531  }
532 } // end getMeanCoordinate4node() -------------------------------------------------------------------------------------
533 
534 
535 size_t WHtree::getCommonAncestor( const size_t nodeID1, const size_t nodeID2 ) const
536 {
537  if( nodeID1 == nodeID2 )
538  {
539  return nodeID1;
540  }
541  else
542  {
543  size_t tempID1( getNode( nodeID1 ).getID() ), tempID2( getNode( nodeID2 ).getID() );
544  while( tempID1 != tempID2 )
545  {
546  if( tempID1 < tempID2 ) // node 1 is lower in the hierarchy
547  {
548  tempID1 = ( getNode( tempID1 ).getParent() ).second;
549  }
550  else // seed 2 is is lower in the hierarchy
551  {
552  tempID2 = ( getNode( tempID2 ).getParent() ).second;
553  }
554  }
555  return tempID1;
556  }
557 } // end hTree::getCommonAncestor() -------------------------------------------------------------------------------------
558 nodeID_t WHtree::getCommonAncestor( const nodeID_t &nodeID1, const nodeID_t &nodeID2 ) const
559 {
560  if( nodeID1 == nodeID2 )
561  {
562  return nodeID1;
563  }
564  else
565  {
566  size_t node1, node2;
567  if( !nodeID1.first ) // its a leaf
568  {
569  node1 = ( getLeaf( nodeID1.second ).getParent() ).second;
570  }
571  else
572  {
573  node1 = ( nodeID1.second );
574  }
575 
576  if( !nodeID2.first ) // its a leaf
577  {
578  node2 = ( getLeaf( nodeID2.second ).getParent() ).second;
579  }
580  else
581  {
582  node2 = ( nodeID2.second );
583  }
584  return std::make_pair( true, getCommonAncestor( node1, node2 ) );
585  }
586 } // end hTree::getCommonAncestor() -------------------------------------------------------------------------------------
587 
588 
589 std::vector<nodeID_t> WHtree::getRoute2Root( const nodeID_t &nodeID ) const
590 {
591  std::vector<nodeID_t> returnVector;
592  if( ( nodeID.first ) && ( nodeID.second >= m_nodes.size() ) )
593  {
594  wlog::error( "WHtree" ) << "ERROR @ WHtree::route2Root(): leafID is out of boundaries";
595  return returnVector;
596  }
597  const WHnode& root( getRoot() );
598  const WHnode* current( &getNode( nodeID ) );
599  returnVector.reserve( root.getHLevel() - current->getHLevel() );
600  returnVector.push_back( nodeID );
601 
602  while( !current->isRoot() )
603  {
604  current = &getNode( current->getParent() );
605  returnVector.push_back( current->getFullID() );
606  }
607 
608  return returnVector;
609 } // end hTree::getRoute2Root() -------------------------------------------------------------------------------------
610 
611 
612 unsigned int WHtree::getTripletOrder( const nodeID_t &nodeIDa, const nodeID_t &nodeIDb, const nodeID_t &nodeIDc ) const
613 {
614  //0="non resolved" (a,b,c join same parent), 1="ab before c", 2="ac before b", 3="bc before a"
615 
616  nodeID_t ancestorAB( getCommonAncestor( nodeIDa, nodeIDb ) );
617  nodeID_t ancestorAC( getCommonAncestor( nodeIDa, nodeIDc ) );
618  nodeID_t ancestorBC( getCommonAncestor( nodeIDb, nodeIDc ) );
619 
620  if( ancestorAB == ancestorAC )
621  {
622  if( ancestorAB == ancestorBC )
623  {
624  return 0; // all join toghether
625  }
626  else
627  {
628  return 3; // a is the last to join
629  }
630  }
631  else if( ancestorAB == ancestorBC )
632  {
633  return 2; // b is the last to join
634  }
635  else
636  {
637  return 1; // c is the last to join
638  }
639 } // end hTree::getTripletOrder() -------------------------------------------------------------------------------------
640 
641 
642 std::vector<size_t> WHtree::getBaseNodes( const size_t root ) const
643 {
644  if( root > getRoot().getID() )
645  {
646  wlog::error( "WHtree" ) << "ERROR @ WHtree::getBaseNodes(): branch root ID is out of boundaries (ID: "
647  << root << ", # nodes: " << getNumNodes() << ").";
648  return std::vector<size_t> ();
649  }
650 
651  std::list<size_t> baseList;
652  for( std::vector<WHnode>::const_iterator leafIter( m_leaves.begin() ); leafIter != m_leaves.end(); ++leafIter )
653  {
654  baseList.push_back( ( leafIter->getParent() ).second );
655  }
656 
657  baseList.sort();
658  baseList.unique();
659  std::vector<size_t> returnVector;
660 
661  if( root != getRoot().getID() )
662  {
663  for( std::list<size_t>::iterator listIter( baseList.begin() ); listIter != baseList.end(); ++listIter )
664  {
665  const WHnode* current( &getNode( *listIter ) );
666  while( !current->isRoot() )
667  {
668  if( current->getID() ==root )
669  {
670  returnVector.push_back( getNode( *listIter ).getID() );
671  break;
672  }
673  current = &getNode( current->getParent() );
674  }
675  }
676  }
677  else
678  {
679  for( std::list<size_t>::const_iterator baseIter( baseList.begin() ); baseIter != baseList.end(); ++baseIter )
680  {
681  returnVector.push_back( *baseIter );
682  }
683  }
684  return returnVector;
685 } // end getBaseNodes() -------------------------------------------------------------------------------------
686 std::vector<nodeID_t> WHtree::getBaseNodes( const nodeID_t &root ) const
687 {
688  std::vector<nodeID_t> returnVector;
689 
690  if( !root.first ) // if its a leaf
691  {
692  return std::vector<nodeID_t>();
693  }
694  else
695  {
696  std::vector<size_t> bases( getBaseNodes( root.second ) );
697  for( size_t i = 0; i < bases.size(); ++i )
698  {
699  returnVector.push_back( std::make_pair( true, bases[i] ) );
700  }
701  return returnVector;
702  }
703 } // end getBaseNodes() -------------------------------------------------------------------------------------
704 
705 
706 std::vector<size_t> WHtree::getRootBaseNodes() const
707 {
708  return getBaseNodes( getRoot().getID() );
709 } // end getRootBaseNodes() -------------------------------------------------------------------------------------
710 
711 
713 {
714  std::vector<size_t> bases( getRootBaseNodes() );
715  if( bases.empty() )
716  {
717  return false;
718  }
719  for( size_t i = 0; i < bases.size(); ++i )
720  {
721  if( getNode( bases[i] ).getHLevel() > 1 )
722  {
723  return false;
724  }
725  }
726  return true;
727 } // end testRootBaseNodes() -------------------------------------------------------------------------------------
728 
729 
730 dist_t WHtree::getDistance( const size_t nodeID1, const size_t nodeID2 ) const
731 {
732  size_t ancestor( getCommonAncestor( nodeID1, nodeID2 ) );
733  return getNode( ancestor ).getDistLevel();
734 } // end hTree::getNodeDistance() -------------------------------------------------------------------------------------
735 dist_t WHtree::getDistance( const nodeID_t &nodeID1, const nodeID_t &nodeID2 ) const
736 {
737  nodeID_t ancestor( getCommonAncestor( nodeID1, nodeID2 ) );
738  return getNode( ancestor ).getDistLevel();
739 } // end hTree::getDistance() -------------------------------------------------------------------------------------
740 dist_t WHtree::getDistance( const WHcoord &coord1, const WHcoord &coord2 ) const
741 {
742  nodeID_t nodeID1( std::make_pair( false, getLeafID( coord1 ) ) );
743  nodeID_t nodeID2( std::make_pair( false, getLeafID( coord2 ) ) );
744  return getDistance( nodeID1, nodeID2 );
745 } // end hTree::distance() -------------------------------------------------------------------------------------
746 
747 
748 dist_t WHtree::getLeafDistance( const size_t leafID1, const size_t leafID2 ) const
749 {
750  nodeID_t ancestor( getCommonAncestor( std::make_pair( false, leafID1 ), std::make_pair( false, leafID2 ) ) );
751  return getNode( ancestor ).getDistLevel();
752 } // end hTree::getLeafDistance() -------------------------------------------------------------------------------------
753 
754 
755 void WHtree::sortBySize( std::vector<size_t>* nodeVector ) const
756 {
757  std::vector<size_t> &nodeVectorRef( *nodeVector );
758  for( size_t i = 0; i < nodeVectorRef.size(); ++i )
759  {
760  if( nodeVectorRef[i] >= getNumNodes() )
761  {
762  wlog::error( "WHtree" ) << "ERROR @ WHtree::sortBySize(): indices out of bounds (" << nodeVectorRef[i]
763  << ". total nodes: " << getNumNodes() << ")";
764  return;
765  }
766  }
767  std::sort( nodeVectorRef.begin(), nodeVectorRef.end(), compSize( this ) );
768  return;
769 } // end sortBySize() -------------------------------------------------------------------------------------
770 void WHtree::sortBySize( std::list<size_t>* nodeList ) const
771 {
772  std::list<size_t> &nodeListRef( *nodeList );
773  for( std::list<size_t>::const_iterator iter = nodeListRef.begin(); iter != nodeListRef.end(); ++iter )
774  {
775  if( *iter >= getNumNodes() )
776  {
777  wlog::error( "WHtree" ) << "ERROR @ WHtree::sortBySize(): indices out of bounds (" << *iter << ". total nodes: " << getNumNodes() << ")";
778  return;
779  }
780  }
781  nodeListRef.sort( compSize( this ) );
782  return;
783 } // end sortBySize() -------------------------------------------------------------------------------------
784 void WHtree::sortBySize( std::vector<nodeID_t>* nodeVector ) const
785 {
786  std::vector<nodeID_t> &nodeVectorRef( *nodeVector );
787  for( size_t i = 0; i < nodeVectorRef.size(); ++i )
788  {
789  if( ( nodeVectorRef[i].first && nodeVectorRef[i].second >= getNumNodes() ) ||
790  ( !nodeVectorRef[i].first && nodeVectorRef[i].second >= getNumLeaves() ) )
791  {
792  wlog::error( "WHtree" ) << "ERROR @ WHtree::sortBySize(): indices out of bounds(" << nodeVectorRef[ i ].first << "-"
793  << nodeVectorRef[ i ].second << ". total leaves: " << getNumLeaves() << ". total nodes: " << getNumNodes() << ")";
794  return;
795  }
796  }
797  std::sort( nodeVectorRef.begin(), nodeVectorRef.end(), compSize( this ) );
798  return;
799 } // end sortBySize() -------------------------------------------------------------------------------------
800 void WHtree::sortBySize( std::list<nodeID_t>* nodeList ) const
801 {
802  std::list<nodeID_t> &nodeListRef( *nodeList );
803  for( std::list<nodeID_t>::const_iterator iter = nodeListRef.begin(); iter != nodeListRef.end(); ++iter )
804  {
805  if( ( iter->first && iter->second >= getNumNodes() ) ||
806  ( !iter->first && iter->second >= getNumLeaves() ) )
807  {
808  wlog::error( "WHtree" ) << "ERROR @ WHtree::sortBySize(): indices out of bounds(" << iter->first << "-" << iter->second
809  << ". total leaves: " << getNumLeaves() << ". total nodes: " << getNumNodes() << ")";
810  return;
811  }
812  }
813  nodeListRef.sort( compSize( this ) );
814  return;
815 } // end sortBySize() -------------------------------------------------------------------------------------
816 
817 void WHtree::sortByHLevel( std::vector<size_t>* nodeVector ) const
818 {
819  std::sort( nodeVector->begin(), nodeVector->end(), compHLevel( this ) );
820  return;
821 } // end sortByHLevel() -------------------------------------------------------------------------------------
822 void WHtree::sortByHLevel( std::vector<nodeID_t>* nodeVector ) const
823 {
824  std::sort( nodeVector->begin(), nodeVector->end(), compHLevel( this ) );
825  return;
826 } // end sortByHLevel() -------------------------------------------------------------------------------------
827 void WHtree::sortByHLevel( std::list<size_t>* nodeList ) const
828 {
829  nodeList->sort( compHLevel( this ) );
830  return;
831 } // end sortByHLevel() -------------------------------------------------------------------------------------
832 void WHtree::sortByHLevel( std::list<nodeID_t>* nodeList ) const
833 {
834  nodeList->sort( compHLevel( this ) );
835  return;
836 } // end sortByHLevel() -------------------------------------------------------------------------------------
837 
839 {
840  std::vector<size_t> emptyVect;
841  m_containedLeaves.resize( m_nodes.size(), emptyVect );
842 
843  for( std::vector<WHnode>::const_iterator leafIter( m_leaves.begin() ); leafIter != m_leaves.end(); ++leafIter )
844  {
845  nodeID_t thisParent( leafIter->getParent() );
846  m_containedLeaves[thisParent.second].push_back( leafIter->getID() );
847  }
848  for( std::vector<WHnode>::const_iterator nodeIter( m_nodes.begin() ); nodeIter != m_nodes.end(); ++nodeIter )
849  {
850  std::sort( m_containedLeaves[nodeIter->getID()].begin(), m_containedLeaves[nodeIter->getID()].end() );
851  if( !nodeIter->isRoot() )
852  {
853  m_containedLeaves[nodeIter->getParent().second].insert( m_containedLeaves[nodeIter->getParent().second].end(),
854  m_containedLeaves[nodeIter->getID()].begin(),
855  m_containedLeaves[nodeIter->getID()].end() );
856  }
857  }
858 } // end loadContainedLeaves() -------------------------------------------------------------------------------------
859 
861 {
862  std::vector<std::vector<size_t> > emptyThing;
863  m_containedLeaves.swap( emptyThing );
864 } // end clearContainedLeaves() -------------------------------------------------------------------------------------
865 
866 
867 bool WHtree::convert2grid( const HC_GRID newGrid )
868 {
869  if( m_datasetGrid == newGrid )
870  {
871  return false;
872  }
873  else if( m_datasetGrid == HC_VISTA && newGrid == HC_NIFTI )
874  {
875  for( std::vector<WHcoord>::iterator iter( m_coordinates.begin() ); iter != m_coordinates.end(); ++iter )
876  {
877  WHcoord tempCoord = *iter;
878  *iter = tempCoord.vista2nifti( m_datasetSize );
879  }
880  for( std::list<WHcoord>::iterator iter( m_discarded.begin() ); iter != m_discarded.end(); ++iter )
881  {
882  WHcoord tempCoord = *iter;
883  *iter = tempCoord.vista2nifti( m_datasetSize );
884  }
885  m_datasetGrid = HC_NIFTI;
886  return true;
887  }
888  else if( m_datasetGrid == HC_NIFTI && newGrid == HC_VISTA )
889  {
890  for( std::vector<WHcoord>::iterator iter( m_coordinates.begin() ); iter != m_coordinates.end(); ++iter )
891  {
892  WHcoord tempCoord = *iter;
893  *iter = tempCoord.nifti2vista( m_datasetSize );
894  }
895  for( std::list<WHcoord>::iterator iter( m_discarded.begin() ); iter != m_discarded.end(); ++iter )
896  {
897  WHcoord tempCoord=*iter;
898  *iter = tempCoord.nifti2vista( m_datasetSize );
899  }
900  m_datasetGrid = HC_VISTA;
901  return true;
902  }
903  else
904  {
905  wlog::error( "WHtree" ) << "ERROR @ WHtree::convert2grid(): coordinate grid not recognized";
906  return false;
907  }
908 } // end convert2grid() -------------------------------------------------------------------------------------
909 
910 
911 bool WHtree::readTree( const std::string &filename )
912 {
913  m_nodes.clear();
914  m_leaves.clear();
915  m_coordinates.clear();
916  m_trackids.clear();
917  m_discarded.clear();
918 
919  WFileParser parser( filename );
920  if( !parser.readFile() )
921  {
922  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree(): Parser error";
923  return false;
924  }
925 
926  std::vector<std::string> lines = parser.getRawLines();
927  if( lines.size() == 0 )
928  {
929  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree(): File is empty";
930  return false;
931  }
932 
933  {
934  std::vector< std::vector< std::string> >datasetStrings = parser.getLinesForTagSeparated( "imagesize" );
935  if( datasetStrings.size() == 0 )
936  {
937  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree(): Dataset size was not found in tree file";
938  return false;
939  }
940  if( datasetStrings.size() > 1 )
941  {
942  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree(): Dataset attribute had multiple lines";
943  return false;
944  }
945  WHcoord datasetSize( string_utils::fromString<coord_t>( datasetStrings[0][0] ),
946  string_utils::fromString<coord_t>( datasetStrings[0][1] ),
947  string_utils::fromString<coord_t>( datasetStrings[0][2] ) );
948  std::string gridString( datasetStrings[0][3] );
949  if( gridString == getGridString( HC_VISTA ) )
950  {
951  m_datasetGrid = HC_VISTA;
952  }
953  else if( gridString == getGridString( HC_NIFTI ) )
954  {
955  m_datasetGrid = HC_NIFTI;
956  }
957  else
958  {
959  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree(): Dataset grid type string \"" << gridString << "\" could not be identified";
960  return false;
961  }
962  m_datasetSize = datasetSize;
963  }
964 
965  {
966  std::vector< std::vector< std::string > > streamNumberStrings = parser.getLinesForTagSeparated( "streams" );
967  if( streamNumberStrings.size() == 0 )
968  {
969  wlog::error( "WHtree" ) << "WARNING @ WHtree::readTree(): tracking streams number was not found in tree file,"
970  << " assuming streams=0 for compatibility";
971  m_numStreamlines = 0;
972  }
973  if( streamNumberStrings.size() > 1 )
974  {
975  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree(): tracking streams number attribute has multiple lines";
976  return false;
977  }
978  if( streamNumberStrings[0].size() > 1 )
979  {
980  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree(): tracking streams number attribute has multiple elements";
981  return false;
982  }
983  m_numStreamlines = string_utils::fromString< size_t >( streamNumberStrings[0][0] );
984  }
985 
986  {
987  std::vector< std::vector< std::string > >logFactorStrings = parser.getLinesForTagSeparated( "logfactor" );
988  if( logFactorStrings.size() == 0 )
989  {
990  wlog::error( "WHtree" ) << "WARNING @ WHtree::readTree(): logarithmic normalization factor was not found in tree file,"
991  << " assuming logFactor=0 for compatibility";
992  m_logFactor = 0;
993  }
994  if( logFactorStrings.size() > 1 )
995  {
996  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree():"
997  << "logarithmic normalization factor attribute has multiple lines";
998  return false;
999  }
1000  if( logFactorStrings[0].size() > 1 )
1001  {
1002  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree(): logarithmic normalization factor attribute has multiple elements";
1003  return false;
1004  }
1005  m_logFactor = string_utils::fromString< float >( logFactorStrings[0][0] );
1006 
1007  if( m_logFactor != 0 && m_numStreamlines != 0 && std::fabs( m_logFactor - log10( m_numStreamlines ) ) > 0.00001 )
1008  {
1009  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree(): tracking streams number ("
1010  << m_numStreamlines << ") and logarithmic normalization factor ("
1011  << m_logFactor << ") are a missmatch . Log factor should be: "<< log10( m_numStreamlines );
1012  return false;
1013  }
1014  }
1015 
1016  {
1017  std::vector< std::vector< std::string> >coordStrings = parser.getLinesForTagSeparated( "coordinates" );
1018  m_coordinates.reserve( coordStrings.size() );
1019  m_leaves.reserve( coordStrings.size() );
1020  size_t leafCount( 0 );
1021  for( size_t i = 0; i < coordStrings.size(); ++i )
1022  {
1023  WHcoord tempCoord( string_utils::fromString<coord_t>( coordStrings[i][0] ),
1024  string_utils::fromString<coord_t>( coordStrings[i][1] ),
1025  string_utils::fromString<coord_t>( coordStrings[i][2] ) );
1026  WHnode tempNode( std::make_pair( 0, leafCount ) );
1027  m_leaves.push_back( tempNode );
1028  m_coordinates.push_back( tempCoord );
1029  ++leafCount;
1030  }
1031  }
1032  {
1033  std::vector< std::vector< std::string > > indexStrings = parser.getLinesForTagSeparated( "trackindex" );
1034  if( indexStrings.empty() )
1035  {
1036  if( m_datasetGrid == HC_NIFTI )
1037  {
1038  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree(): no tract ids in roi file, necessary to work on nifti mode";
1039  return false;
1040  }
1041  else
1042  {
1043  m_trackids.reserve( m_coordinates.size() );
1044  for( size_t i = 0; i < m_coordinates.size(); ++i )
1045  {
1046  m_trackids.push_back( i );
1047  }
1048  }
1049  }
1050  else
1051  {
1052  m_trackids.reserve( indexStrings.size() );
1053  for( size_t i = 0; i < indexStrings.size(); ++i )
1054  {
1055  size_t tempIndex( string_utils::fromString< size_t >( indexStrings[i][0] ) );
1056  m_trackids.push_back( tempIndex );
1057  }
1058  }
1059  }
1060  {
1061  std::vector< std::vector< std::string> >clusterStrings = parser.getLinesForTagSeparated( "clusters" );
1062  m_nodes.reserve( clusterStrings.size() );
1063  size_t nodeCount( 0 );
1064  for( size_t i = 0; i < clusterStrings.size(); ++i )
1065  {
1066  dist_t distance( string_utils::fromString< dist_t > ( clusterStrings[i][0] ) );
1067  std::vector<nodeID_t>joiningNodes;
1068  for( size_t j = 1; j < clusterStrings[i].size(); j += 2 )
1069  {
1070  joiningNodes.push_back( std::make_pair( string_utils::fromString<bool>( clusterStrings[i][j] ),
1071  string_utils::fromString<size_t>( clusterStrings[i][j+1] ) ) );
1072  }
1073 
1074  size_t tempSize( 0 ), tempHLevel( 0 );
1075  nodeID_t tempID( std::make_pair( 1, nodeCount ) );
1076  for( std::vector<nodeID_t>::const_iterator iter( joiningNodes.begin() ); iter != joiningNodes.end(); ++iter )
1077  {
1078  WHnode* kid( fetchNode( *iter ) );
1079  if( kid == 0 )
1080  {
1081  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree(): kid id (" << iter->first << "-" << iter->second
1082  << ") was out of boundaries. Nodes: " << m_nodes.size();
1083  return false;
1084  }
1085  tempSize += kid->getSize();
1086  tempHLevel = std::max( tempHLevel, kid->getHLevel() );
1087  kid->setParent( tempID );
1088  }
1089  ++tempHLevel;
1090 
1091  WHnode tempNode( tempID, joiningNodes, tempSize, distance, tempHLevel );
1092  //std::cout << tempNode.printAllData() << std::endl;
1093  m_nodes.push_back( tempNode );
1094  ++nodeCount;
1095  }
1096  }
1097 
1098  {
1099  std::vector< std::vector< std::string> >discardedStrings = parser.getLinesForTagSeparated( "discarded" );
1100  for( size_t i = 0; i < discardedStrings.size(); ++i )
1101  {
1102  WHcoord tempCoord( string_utils::fromString<coord_t>( discardedStrings[i][0] ),
1103  string_utils::fromString<coord_t>( discardedStrings[i][1] ),
1104  string_utils::fromString<coord_t>( discardedStrings[i][2] ) );
1105  m_discarded.push_back( tempCoord );
1106  }
1107  m_discarded.sort();
1108  }
1109 
1110  {
1111  std::vector< std::vector< std::string> >cpccStrings = parser.getLinesForTagSeparated( "cpcc" );
1112  if( !cpccStrings.empty() )
1113  {
1114  if( cpccStrings.size() > 1 || cpccStrings[0].size() > 1 )
1115  {
1116  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree(): multiple objects on cpcc attribute";
1117  return false;
1118  }
1119  m_cpcc = string_utils::fromString<float>( cpccStrings[0][0] );
1120  }
1121  }
1122 
1123  {
1124  m_selectedValues.clear();
1125  m_selectedPartitions.clear();
1126  std::vector< std::vector< std::string> >partValueStrings = parser.getLinesForTagSeparated( "partvalues" );
1127  if( !partValueStrings.empty() )
1128  {
1129  m_selectedValues.reserve( partValueStrings.size() );
1130  for( size_t i = 0; i < partValueStrings.size(); ++i )
1131  {
1132  float value( string_utils::fromString< float > ( partValueStrings[i][0] ) );
1133  m_selectedValues.push_back( value );
1134  }
1135  }
1136 
1137  std::vector< std::vector< std::string> >partitionStrings = parser.getLinesForTagSeparated( "partitions" );
1138  if( !partitionStrings.empty() )
1139  {
1140  m_selectedPartitions.reserve( partitionStrings.size() );
1141  for( size_t i = 0; i < partitionStrings.size(); ++i )
1142  {
1143  std::vector< size_t > thisPartition;
1144  thisPartition.reserve( partitionStrings[i].size() );
1145  for( size_t j = 0; j < partitionStrings[i].size(); ++j )
1146  {
1147  size_t partCluster( string_utils::fromString< size_t > ( partitionStrings[i][j] ) );
1148  thisPartition.push_back( partCluster );
1149  }
1150  m_selectedPartitions.push_back( thisPartition );
1151  }
1152  }
1153 
1154  std::vector< std::vector< std::string > >partcolorStrings = parser.getLinesForTagSeparated( "partcolors" );
1155  if( !partcolorStrings.empty() )
1156  {
1157  m_selectedColors.reserve( partcolorStrings.size() );
1158  for( size_t i = 0; i < partcolorStrings.size(); ++i )
1159  {
1160  std::vector< WHcoord > thisPartColors;
1161  thisPartColors.reserve( partcolorStrings[i].size() );
1162 
1163  for( size_t j = 0; j < partcolorStrings[i].size(); ++j )
1164  {
1165  std::string thisCoordstring( partcolorStrings[i][j] );
1166  if( thisCoordstring.size() != 11 )
1167  {
1168  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree(): partition colors have wrong size (" << thisCoordstring.size()
1169  << ") while it should be 11. string: " << thisCoordstring;
1170  m_selectedColors.clear();
1171  break;
1172  }
1173 
1174  std::string colorR( thisCoordstring.substr( 0, 3 ) );
1175  std::string colorG( thisCoordstring.substr( 4, 3 ) );
1176  std::string colorB( thisCoordstring.substr( 8, 3 ) );
1177 
1178 
1179  WHcoord thisColor( string_utils::fromString< coord_t > ( colorR ),
1180  string_utils::fromString< coord_t > ( colorG ),
1181  string_utils::fromString< coord_t > ( colorB ) );
1182  thisPartColors.push_back( thisColor );
1183  }
1184  m_selectedColors.push_back( thisPartColors );
1185  }
1186  }
1187 
1188  if( m_selectedColors.size() != 0 )
1189  {
1190  if( m_selectedColors.size() != m_selectedPartitions.size() )
1191  {
1192  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree(): partition and colors dimensions dont match. Color field will be left empty";
1193  m_selectedColors.clear();
1194  }
1195  else
1196  {
1197  for( size_t i = 0; i < m_selectedColors.size(); ++i )
1198  {
1199  if( m_selectedColors[i].size() != m_selectedPartitions[i].size() )
1200  {
1201  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree(): partition and colors dimensions dont match."
1202  << " Color field will be left empty";
1203  m_selectedColors.clear();
1204  break;
1205  }
1206  }
1207  }
1208  }
1209  if( m_selectedPartitions.size() != m_selectedValues.size() )
1210  {
1211  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree(): partition and value dimensions dont match. Fields will be left empty";
1212  clearPartitions();
1213  }
1214  }
1215 
1216 
1217 
1218  if( !check() )
1219  {
1220  wlog::error( "WHtree" ) << "ERROR @ WHtree::readTree(): loaded tree is not consistent";
1221  return false;
1222  }
1223 
1224  m_treeName = boost::filesystem::path( filename ).stem().string();
1225 
1226 
1227  m_loadStatus = true;
1228  return true;
1229 } // end readTree() -------------------------------------------------------------------------------------
1230 
1231 
1232 
1233 bool WHtree::writeTree( const std::string &filename, const bool niftiMode ) const
1234 {
1235  std::ofstream outFile( filename.c_str() );
1236  if( !outFile )
1237  {
1238  throw WFileOpenFailed( "ERROR: unable to open out file: \"" + filename + "." );
1239  }
1240 
1241 
1242 
1243  std::string gridString;
1244  if( niftiMode )
1245  {
1246  gridString = getGridString( HC_NIFTI );
1247  }
1248  else
1249  {
1250  gridString = getGridString( HC_VISTA );
1251  }
1252 
1253  outFile << "#imagesize" << std::endl << m_datasetSize << " " << gridString << std::endl << "#endimagesize" << std::endl;
1254  outFile << std::endl;
1255  if( m_cpcc != 0 )
1256  {
1257  outFile << "#cpcc" << std::endl << string_utils::toString( m_cpcc ) << std::endl << "#endcpcc" << std::endl << std::endl;
1258  }
1259 
1260  outFile << "#streams" << std::endl << m_numStreamlines << std::endl << "#endstreams" << std::endl;
1261 
1262  outFile << "#logfactor" << std::endl << m_logFactor << std::endl << "#endlogfactor" << std::endl;
1263 
1264  outFile << "#coordinates" << std::endl;
1265  for( std::vector<WHcoord>::const_iterator coordIter( m_coordinates.begin() ) ; coordIter != m_coordinates.end() ; ++coordIter )
1266  {
1267  WHcoord currentCoord( *coordIter );
1268  if( niftiMode )
1269  {
1270  if( m_datasetGrid == HC_VISTA )
1271  {
1272  currentCoord = currentCoord.vista2nifti( m_datasetSize );
1273  }
1274  }
1275  else
1276  {
1277  if( m_datasetGrid == HC_NIFTI )
1278  {
1279  currentCoord = currentCoord.nifti2vista( m_datasetSize );
1280  }
1281  }
1282  outFile << currentCoord << std::endl;
1283  }
1284  outFile << "#endcoordinates" << std::endl << std::endl;
1285 
1286  if( niftiMode )
1287  {
1288  if( m_coordinates.size() != m_trackids.size() )
1289  {
1290  wlog::error( "WHtree" ) << "WARNING @ WHtree::writeTree(): trackids(" << m_trackids.size() << ") and coordinates("
1291  << m_coordinates.size() << ") vector sizes do not match. track ids will note written to file";
1292  }
1293  else
1294  {
1295  outFile << "#trackindex" << std::endl;
1296 
1297  for( std::vector<size_t>::const_iterator indexIter( m_trackids.begin() ) ; indexIter != m_trackids.end() ; ++indexIter )
1298  {
1299  outFile << *indexIter << std::endl;
1300  }
1301  outFile << "#endtrackindex" << std::endl << std::endl;
1302  }
1303  }
1304 
1305  outFile << "#clusters" << std::endl;
1306  for( std::vector<WHnode>::const_iterator nodeIter( m_nodes.begin() ) ; nodeIter != m_nodes.end() ; ++nodeIter )
1307  {
1308  outFile << *nodeIter << std::endl;
1309  }
1310  outFile << "#endclusters" << std::endl << std::endl;
1311 
1312  outFile << "#discarded" << std::endl;
1313  for( std::list<WHcoord>::const_iterator coordIter( m_discarded.begin() ) ; coordIter != m_discarded.end() ; ++coordIter )
1314  {
1315  WHcoord currentCoord( *coordIter );
1316  if( niftiMode )
1317  {
1318  if( m_datasetGrid == HC_VISTA )
1319  {
1320  currentCoord = currentCoord.vista2nifti( m_datasetSize );
1321  }
1322  }
1323  else
1324  {
1325  if( m_datasetGrid == HC_NIFTI )
1326  {
1327  currentCoord = currentCoord.nifti2vista( m_datasetSize );
1328  }
1329  }
1330  outFile << currentCoord << std::endl;
1331  }
1332  outFile << "#enddiscarded" << std::endl;
1333 
1334  if( m_selectedValues.size() !=0 )
1335  {
1336  outFile << std::endl << "#partvalues" << std::endl;
1337  for( size_t i = 0; i < m_selectedValues.size(); ++i )
1338  {
1339  outFile << m_selectedValues[i] << std::endl;
1340  }
1341  outFile << "#endpartvalues" << std::endl;
1342 
1343  outFile << std::endl << "#partitions" << std::endl;
1344  for( size_t i = 0; i < m_selectedPartitions.size(); ++i )
1345  {
1346  for( size_t j = 0; j < m_selectedPartitions[i].size(); ++j )
1347  {
1348  outFile <<m_selectedPartitions[i][j]<< " ";
1349  }
1350  outFile << std::endl;
1351  }
1352  outFile << "#endpartitions" << std::endl;
1353 
1354  if( m_selectedColors.size() !=0 )
1355  {
1356  outFile << std::endl << "#partcolors" << std::endl;
1357  for( size_t i = 0; i < m_selectedColors.size(); ++i )
1358  {
1359  for( size_t j = 0; j < m_selectedColors[i].size(); ++j )
1360  {
1361  WHcoord thisColor( m_selectedColors[i][j] );
1362  size_t xcolor( thisColor.m_x );
1363  size_t ycolor( thisColor.m_y );
1364  size_t zcolor( thisColor.m_z );
1365 
1366  outFile << boost::format( "%03d;%03d;%03d " ) % xcolor % ycolor % zcolor;
1367  }
1368  outFile << std::endl;
1369  }
1370  outFile << "#endpartcolors" << std::endl;
1371  }
1372  }
1373 
1374 
1375 
1376  return true;
1377 } // end writeTree() -------------------------------------------------------------------------------------
1378 
1379 
1380 bool WHtree::writeTreeDebug( const std::string &filename ) const
1381 {
1382  std::ofstream outFile( filename.c_str() );
1383  if( !outFile )
1384  {
1385  throw WFileOpenFailed( "ERROR: unable to open out file: \"" + filename + "." );
1386  }
1387 
1388  outFile << "Dataset size: " << m_datasetSize << " " << getGridString( m_datasetGrid ) << std::endl;
1389 
1390  if( m_cpcc != 0 )
1391  {
1392  outFile << "CPCC: " << string_utils::toString( m_cpcc ) << std::endl << std::endl;
1393  }
1394 
1395  outFile << "Streamlines per seed voxel: " << m_numStreamlines << std::endl;
1396 
1397  outFile << "Logarithmic normalization factor: " << m_logFactor << std::endl << std::endl;
1398 
1399  outFile << "============LEAVES============" << std::endl << std::endl;
1400  for( std::vector<WHnode>::const_iterator leafIter( m_leaves.begin() ); leafIter != m_leaves.end(); ++leafIter )
1401  {
1402  WHcoord currentCoord( getCoordinate4leaf( leafIter->getID() ) );
1403  outFile << "ID: " << leafIter->getID() << ". Track: " << getTrackID( leafIter->getID() );
1404  outFile << "Coord: " << currentCoord << " " << leafIter->printAllData() << std::endl;
1405  }
1406  outFile << std::endl << std::endl << "============NODES============" << std::endl << std::endl;
1407  for( std::vector<WHnode>::const_iterator nodeIter( m_nodes.begin() ) ; nodeIter != m_nodes.end() ; ++nodeIter )
1408  {
1409  outFile << nodeIter->printAllData() << std::endl;
1410  }
1411 
1412  return true;
1413 } // end writeTreeDebug() -------------------------------------------------------------------------------------
1414 
1415 
1416 bool WHtree::writeTreeOldWalnut( const std::string &filename ) const
1417 {
1418  std::ofstream outFile( filename.c_str() );
1419  if( !outFile )
1420  {
1421  throw WFileOpenFailed( "ERROR: unable to open out file: \"" + filename + "." );
1422  }
1423 
1424 
1425  outFile << "#coordinates" << std::endl;
1426  for( std::vector<WHcoord>::const_iterator coordIter( m_coordinates.begin() ) ; coordIter != m_coordinates.end() ; ++coordIter )
1427  {
1428  WHcoord currentCoord( *coordIter );
1429  if( m_datasetGrid == HC_VISTA )
1430  {
1431  currentCoord = currentCoord.vista2nifti( m_datasetSize );
1432  }
1433  outFile << boost::format( "%03d,%03d,%03d\n" ) % currentCoord.m_x % currentCoord.m_y % currentCoord.m_z;
1434  }
1435  outFile << "#endcoordinates" << std::endl << std::endl;
1436 
1437  outFile << "#clusters" << std::endl;
1438  for( std::vector<WHnode>::const_iterator nodeIter( m_nodes.begin() ); nodeIter != m_nodes.end(); ++nodeIter )
1439  {
1440  std::vector<nodeID_t> currentKids( nodeIter->getChildren() );
1441  for( size_t i = 0; i < currentKids.size(); ++i )
1442  {
1443  size_t currentID( currentKids[i].second );
1444  if( currentKids[i].first )
1445  {
1446  currentID += getNumLeaves();
1447  }
1448  outFile << boost::format( "%06d" ) % currentID << "," << std::flush;
1449  }
1450  outFile << string_utils::toString( nodeIter->getDistLevel() ) << std::endl;
1451  }
1452  outFile << "#endclusters" << std::endl << std::endl;
1453 
1454 return true;
1455 } // end writeTreeOldWalnut() -------------------------------------------------------------------------------------
1456 
1457 bool WHtree::writeTreeSimple( const std::string &filename ) const
1458 {
1459  std::ofstream outFile( filename.c_str() );
1460  if( !outFile )
1461  {
1462  throw WFileOpenFailed( "ERROR: unable to open out file: \"" + filename + "." );
1463  }
1464 
1465  outFile << getNumLeaves() << std::endl;
1466  for( std::vector<WHnode>::const_iterator nodeIter( m_nodes.begin() ) ; nodeIter != m_nodes.end() ; ++nodeIter )
1467  {
1468  outFile << *nodeIter << std::endl;
1469  }
1470  return true;
1471 } // end writeTreeSimple() -------------------------------------------------------------------------------------
1472 
1473 void WHtree::insertPartitions( const std::vector<std::vector<size_t> > &selectedPartitions, const std::vector< float > &selectedValues,
1474  const std::vector<std::vector<WHcoord> > &selectedColors )
1475 {
1476  clearPartitions();
1477  if( selectedPartitions.size() != selectedValues.size() )
1478  {
1479  wlog::error( "WHtree" ) << "ERROR @ WHtree::insertPartitions(): inserted partition set and partition value vector have different dimensions";
1480  }
1481  else
1482  {
1483  m_selectedPartitions = selectedPartitions;
1484  m_selectedValues = selectedValues;
1485  }
1486 
1487  if( !selectedColors.empty() )
1488  {
1489  if( selectedColors.size() != selectedPartitions.size() )
1490  {
1491  wlog::error( "WHtree" ) << "ERROR @ WHtree::insertPartitions(): inserted partition color set and partition set have different dimensions";
1492  }
1493  else
1494  {
1495  for( size_t i = 0; i < selectedColors.size(); ++i )
1496  {
1497  if( selectedColors[i].size() != selectedPartitions[i].size() )
1498  {
1499  wlog::error( "WHtree" ) << "ERROR @ WHtree::insertPartitions(): partition and colors dimensions dont match"
1500  << " (" << selectedPartitions[i].size() << "-" << selectedColors[i].size()
1501  << ") Color field will be left empty";
1502  return;
1503  }
1504  }
1505  m_selectedColors = selectedColors;
1506  }
1507  }
1508  return;
1509 } // end insertPartitions() -------------------------------------------------------------------------------------
1510 
1511 void WHtree::insertPartColors( const std::vector<std::vector<WHcoord> > &selectedColors )
1512 {
1513  if( selectedColors.size() != m_selectedPartitions.size() )
1514  {
1515  wlog::error( "WHtree" ) << "ERROR @ WHtree::insertPartColors(): inserted partition color set and partition set have different dimensions";
1516  }
1517  else
1518  {
1519  for( size_t i = 0; i < selectedColors.size(); ++i )
1520  {
1521  if( selectedColors[i].size() != m_selectedPartitions[i].size() )
1522  {
1523  wlog::error( "WHtree" ) << "ERROR @ WHtree::insertPartColors(): partition and colors dimensions dont match."
1524  << " Color field will be left empty";
1525  clearPartColors();
1526  return;
1527  }
1528  }
1529  m_selectedColors = selectedColors;
1530  }
1531  return;
1532 } // end insertPartColors() -------------------------------------------------------------------------------------
1533 
1535 {
1536  std::vector<std::vector<size_t> > empty1;
1537  std::vector< float > empty2;
1538  std::vector<std::vector<WHcoord> > empty3;
1539  m_selectedPartitions.swap( empty1 );
1540  m_selectedValues.swap( empty2 );
1541  m_selectedColors.swap( empty3 );
1542  return;
1543 } // end clearPartitions() -------------------------------------------------------------------------------------
1544 
1546 {
1547  std::vector<std::vector<WHcoord> > empty;
1548  m_selectedColors.swap( empty );
1549  return;
1550 } // end clearPartColors() -------------------------------------------------------------------------------------
1551 
1552 std::vector< std::vector< unsigned int > > WHtree::getBranching( const std::vector < nodeID_t > &thisPartition,
1553  size_t depthLevel,
1554  std::vector< std::vector < nodeID_t > > *partitionSet,
1555  const bool excludeLeaves )
1556 {
1557  if( depthLevel == 0 )
1558  {
1559  return std::vector< std::vector< unsigned int > >();
1560  }
1561 
1562  std::vector< std::vector < nodeID_t > > addedPartitionSet;
1563  std::vector< std::vector< unsigned int > > addedIndexTable;
1564  addedIndexTable.reserve( thisPartition.size() );
1565  addedPartitionSet.reserve( thisPartition.size() );
1566 
1567  for( size_t i = 0; i < thisPartition.size(); ++i )
1568  {
1569  // if its a base node and flag is set not to divide them, skip
1570  if( getNode( thisPartition[i] ).getHLevel() == 1 && excludeLeaves )
1571  {
1572  continue;
1573  }
1574  // get branched sub/partition for every cluster
1575  std::vector<nodeID_t> branch;
1576  {
1577  std::vector<nodeID_t> kids( getNode( thisPartition[i] ).getChildren() );
1578  branch.reserve( kids.size() );
1579  for( size_t j = 0; j < kids.size(); ++j )
1580  {
1581  branch.push_back( kids[j] );
1582  }
1583  }
1584  // insert branched partition
1585  {
1586  std::vector < nodeID_t > newPartition( thisPartition );
1587  newPartition.erase( newPartition.begin()+i );
1588  newPartition.insert( newPartition.begin()+i, branch.begin(), branch.end() );
1589 
1590  addedPartitionSet.push_back( newPartition );
1591  addedIndexTable.push_back( std::vector<unsigned int>( 1, i ) );
1592  }
1593  // obtain further sub-partitions if depth level continues
1594  if( depthLevel > 1 )
1595  {
1596  std::vector< std::vector < nodeID_t > > subPartitionSet;
1597  std::vector< std::vector< unsigned int > > subIndexTable( getBranching( branch, depthLevel-1, &subPartitionSet, excludeLeaves ) );
1598 
1599  addedPartitionSet.reserve( addedPartitionSet.size() + subPartitionSet.size() );
1600  addedIndexTable.reserve( addedPartitionSet.size() + subPartitionSet.size() );
1601 
1602  if( subPartitionSet.size() != subIndexTable.size() )
1603  {
1604  throw std::runtime_error( "ERROR @ WHtree::getBranching(): dimension error on obtained vectors" );
1605  }
1606 
1607  for( size_t j = 0; j < subIndexTable.size(); ++j )
1608  {
1609  std::vector < nodeID_t > newPartition( thisPartition );
1610  newPartition.erase( newPartition.begin()+i );
1611  newPartition.insert( newPartition.begin()+i, subPartitionSet[j].begin(), subPartitionSet[j].end() );
1612  addedPartitionSet.push_back( newPartition );
1613 
1614  std::vector< unsigned int > newIndexEntry( 1, i );
1615  newIndexEntry.insert( newIndexEntry.end(), subIndexTable[j].begin(), subIndexTable[j].end() );
1616  addedIndexTable.push_back( newIndexEntry );
1617  }
1618  }
1619  } //end for loop
1620 
1621  // add the obtained partitions to the vector
1622  partitionSet->insert( partitionSet->end(), addedPartitionSet.begin(), addedPartitionSet.end() );
1623 
1624  return addedIndexTable;
1625 } // end getBranching() -------------------------------------------------------------------------------------
1626 
1627 std::vector< std::vector< unsigned int > > WHtree::getBranching( const std::vector < size_t > &thisPartition,
1628  size_t depthLevel,
1629  std::vector< std::vector < size_t > > *partitionSet )
1630 {
1631  if( !partitionSet->empty() )
1632  {
1633  throw std::runtime_error( "ERROR @ WHtree::getBranching(): partition set wasnt empty" );
1634  }
1635 
1636  std::vector<nodeID_t> partFullId;
1637  std::vector< std::vector < nodeID_t > > partitionFullIdSet;
1638 
1639  partFullId.reserve( thisPartition.size() );
1640  for( size_t i = 0; i < thisPartition.size(); ++i )
1641  {
1642  partFullId.push_back( std::make_pair( true, thisPartition[i] ) );
1643  }
1644 
1645  std::vector< std::vector< unsigned int > > indexTable( getBranching( partFullId, depthLevel, &partitionFullIdSet, true ) );
1646 
1647  partitionSet->reserve( partitionFullIdSet.size() );
1648  for( size_t i = 0; i < partitionFullIdSet.size(); ++i )
1649  {
1650  std::vector<size_t> thisSet;
1651  thisSet.reserve( partitionFullIdSet[i].size() );
1652  for( size_t j = 0; j < partitionFullIdSet[i].size(); ++j )
1653  {
1654  if( partitionFullIdSet[i][j].first )
1655  {
1656  thisSet.push_back( partitionFullIdSet[i][j].second );
1657  }
1658  else
1659  {
1660  wlog::error( "WHtree" ) << "WARNING @ WHtree::getBranching(), leaves were returned";
1661  }
1662  }
1663  partitionSet->push_back( thisSet );
1664  }
1665 
1666  return indexTable;
1667 }
1668 
1669 // === PRIVATE MEMBER FUNCTIONS ===
1670 
1671 
1672 
1673 WHnode* WHtree::fetchNode( const size_t thisNode )
1674 {
1675  if( thisNode >= m_nodes.size() )
1676  {
1677  return 0;
1678  }
1679  else
1680  {
1681  return &( m_nodes[thisNode] );
1682  }
1683 } // end fetchNode() -------------------------------------------------------------------------------------
1684 WHnode* WHtree::fetchNode( const nodeID_t &thisNode )
1685 {
1686  if( thisNode.first )
1687  {
1688  return fetchNode( thisNode.second );
1689  }
1690  else
1691  {
1692  return fetchLeaf( thisNode.second );
1693  }
1694 } // end fetchNode() -------------------------------------------------------------------------------------
1695 
1696 
1697 WHnode* WHtree::fetchLeaf( const size_t thisLeaf )
1698 {
1699  if( thisLeaf >= m_leaves.size() )
1700  {
1701  return 0;
1702  }
1703  else
1704  {
1705  return &( m_leaves[thisLeaf] );
1706  }
1707 } // end fetchLeaf() -------------------------------------------------------------------------------------
1708 
1709 
1711 {
1712  return fetchNode( getNumNodes()-1 );
1713 } // end fetchRoot() -------------------------------------------------------------------------------------
1714 
1715 
1716 std::pair<size_t, size_t> WHtree::cleanup( std::vector<size_t> *outLookup )
1717 {
1718  //finish setting pruning flags on unnecessary nodes
1719 
1720  //reset nodes size and
1721  for( std::vector<WHnode>::iterator nodesIter( m_nodes.begin() ); nodesIter != m_nodes.end(); ++nodesIter )
1722  {
1723  nodesIter->setSize( 0 );
1724  nodesIter->setHLevel( 0 );
1725  }
1726  //initialize base nodes size
1727  for( std::vector<WHnode>::const_iterator leavesIter( m_leaves.begin() ); leavesIter != m_leaves.end(); ++leavesIter )
1728  {
1729  WHnode *parentNode( fetchNode( leavesIter->getParent() ) );
1730  size_t currentSize( parentNode->getSize() );
1731  if( !( leavesIter->isFlagged() ) )
1732  {
1733  // leaf will not be pruned
1734  parentNode->setSize( currentSize+1 );
1735  parentNode->setHLevel( 1 );
1736  }
1737  }
1738  //initialize remaining nodes
1739  for( std::vector<WHnode>::iterator nodesIter( m_nodes.begin() ); nodesIter != m_nodes.end()-1; ++nodesIter )
1740  {
1741  WHnode *parentNode( fetchNode( nodesIter->getParent() ) );
1742  size_t currentNodeSize( nodesIter->getSize() );
1743  size_t currentPapaSize( parentNode->getSize() );
1744  parentNode->setSize( currentPapaSize + currentNodeSize );
1745  if( currentNodeSize < 2 )
1746  {
1747  // if a node has less than 2 leaves it is unnecesary in a hierarchical tree, so in that case the prune bit must be set too
1748  nodesIter->setFlag( true );
1749  if( currentNodeSize > 0 )
1750  {
1751  parentNode->setHLevel( nodesIter->getHLevel() );
1752  }
1753  }
1754  else
1755  {
1756  parentNode->setHLevel( std::max( parentNode->getHLevel(), nodesIter->getHLevel()+1 ) );
1757  }
1758  }
1759  // loop through nodes and check that there are no hanging nodes ( nodes with one or no children) without structural function
1760  for( std::vector<WHnode>::iterator nodesIter( m_nodes.begin() ); nodesIter != m_nodes.end(); ++nodesIter )
1761  {
1762  size_t numNewKids( 0 );
1763  std::vector<nodeID_t> kids( nodesIter->getChildren() );
1764 
1765  for( std::vector<nodeID_t>::iterator kidsIter( kids.begin() ); kidsIter != kids.end(); ++kidsIter )
1766  {
1767  if( fetchNode( *kidsIter )->isLeaf() )
1768  {
1769  if( !( getNode( *kidsIter ).isFlagged() ) )
1770  {
1771  ++numNewKids;
1772  }
1773  }
1774  else
1775  {
1776  if( ( getNode( *kidsIter ).getHLevel() ) != 0 )
1777  {
1778  ++numNewKids;
1779  }
1780  }
1781  }
1782 
1783  if( numNewKids <= 1 )
1784  {
1785  nodesIter->setFlag( true );
1786  }
1787  }
1788 
1789  // create new IDs lookup tables
1790  const size_t INVALID( getNumLeaves()+1 );
1791  std::vector<size_t> lookupLeafID( getNumLeaves(), INVALID ), lookupNodeID( getNumNodes(), INVALID ), lookupParentID( getNumNodes(), INVALID );
1792  size_t leafCounter( 0 ), nodeCounter( 0 ); // new ID counters
1793  // loop through leaves and create lookup table for new leaves IDs
1794  for( size_t i = 0; i < m_leaves.size(); ++i )
1795  {
1796  if( !m_leaves[i].isFlagged() )
1797  {
1798  lookupLeafID[i] = leafCounter++;
1799  }
1800  }
1801  // loop through nodes and create lookup table for new nodes IDs
1802  for( size_t i = 0; i < m_nodes.size(); ++i )
1803  {
1804  if( !m_nodes[i].isFlagged() )
1805  {
1806  lookupNodeID[i] = nodeCounter++;
1807  }
1808  }
1809  // loop through nodes and create lookup table for new nodes parent_IDs
1810  for( size_t i = 0; i < m_nodes.size(); ++i )
1811  {
1812  if( m_nodes[i].isFlagged() )
1813  {
1814  const WHnode* searchNode( &getNode( i ) );
1815  while( searchNode->isFlagged() ) // while parents are set to prune, keep going up the tree until a valid node is reached
1816  {
1817  if( searchNode->isRoot() )
1818  {
1819  break; // this was the top node of the tree
1820  }
1821  searchNode = &getNode( searchNode->getParent() );
1822  }
1823  if( searchNode->isRoot() && searchNode->isFlagged() )
1824  {
1825  lookupParentID[i] = 0;
1826  }
1827  else
1828  {
1829  lookupParentID[i] = lookupNodeID[searchNode->getID()];
1830  }
1831 
1832  if( lookupParentID[i] == INVALID )
1833  {
1834  throw std::runtime_error( "ERROR @ WHtree::cleanup(): error filling new parent ID lookup table" );
1835  }
1836  }
1837  else
1838  {
1839  lookupParentID[i] = lookupNodeID[m_nodes[i].getID()];
1840  }
1841  }
1842 
1843  // delete discarded elements from containers
1844  // eliminate discarded leaves from the leaves vector and the coordinates vector
1845  size_t discardedLeaves( 0 ), discardedNodes( 0 );
1846  std::vector<WHnode>::iterator leavesDelIter( m_leaves.begin() );
1847  std::vector<WHcoord>::iterator coordDelIter( m_coordinates.begin() );
1848  std::vector< size_t >::iterator trackidIter( m_trackids.begin() );
1849 
1850  while( leavesDelIter != m_leaves.end() )
1851  {
1852  if( leavesDelIter->isFlagged() )
1853  {
1854  ++discardedLeaves;
1855  m_discarded.push_back( *coordDelIter );
1856  leavesDelIter = m_leaves.erase( leavesDelIter );
1857  coordDelIter = m_coordinates.erase( coordDelIter );
1858  trackidIter = m_trackids.erase( trackidIter );
1859  }
1860  else
1861  {
1862  ++leavesDelIter;
1863  ++coordDelIter;
1864  ++trackidIter;
1865  }
1866  }
1867  // eliminate discarded nodes from the vector
1868  std::vector<WHnode>::iterator nodesDelIter( m_nodes.begin() );
1869  while( nodesDelIter != m_nodes.end() )
1870  {
1871  if( nodesDelIter->isFlagged() )
1872  {
1873  ++discardedNodes;
1874  nodesDelIter = m_nodes.erase( nodesDelIter );
1875  }
1876  else
1877  {
1878  ++nodesDelIter;
1879  }
1880  }
1881 
1882  // update names of non-discarded elements
1883  // loop through leaves and change leaves IDs and Parents IDs
1884  for( std::vector<WHnode>::iterator leavesIter( m_leaves.begin() ); leavesIter != m_leaves.end(); ++leavesIter )
1885  {
1886  size_t newID( lookupLeafID[leavesIter->getID()] );
1887  size_t newParentID( lookupParentID[leavesIter->getParent().second] );
1888 
1889  if( ( newID == INVALID ) || ( newParentID == INVALID ) )
1890  {
1891  wlog::error( "WHtree" ) << "Discarded " << discardedLeaves<< " and " << discardedNodes<< " nodes" << std::endl
1892  << "Old ID: " << leavesIter->getID() << ". New ID: " << newID<< ". Old parent ID: " << leavesIter->getParent().second
1893  << ". New parent ID: " << newParentID;
1894 
1895  throw std::runtime_error( "ERROR @ WHtree::cleanup(): error updating leaf IDs, invalid lookup table value" );
1896  }
1897 
1898  leavesIter->setID( std::make_pair( false, newID ) );
1899  leavesIter->setParent( std::make_pair( true, newParentID ) );
1900  }
1901  // loop through nodes and change names of nodes IDs and parents
1902  for( std::vector<WHnode>::iterator nodesIter( m_nodes.begin() ); nodesIter != m_nodes.end(); ++nodesIter )
1903  {
1904  size_t newID( lookupNodeID[nodesIter->getID()] );
1905 
1906  size_t newParentID( 0 );
1907  if( ( nodesIter+1 ) != m_nodes.end() )
1908  {
1909  newParentID = ( lookupParentID[nodesIter->getParent().second] );
1910  }
1911 
1912  std::vector<nodeID_t> emptyKids;
1913 
1914  if( ( newID == INVALID ) || ( newParentID == INVALID ) )
1915  {
1916  throw std::runtime_error( "ERROR @ WHtree::cleanup(): error updating node IDs, invalid lookup table value" );
1917  }
1918 
1919  if( newParentID == 0 ) // if node is top of the tree parent must be set to 0-0
1920  {
1921  if( ( nodesIter+1 ) != m_nodes.end() ) // this should only happen at the last node
1922  {
1923  wlog::error( "WHtree" ) << std::endl << "Node says its root: " << nodesIter->printAllData() << std::endl
1924  << "New ID: " << newID << ". New parent ID: " << newParentID << std::endl
1925  << "But last node is: " << ( m_nodes.end()-1 )->printAllData() << std::endl
1926  << "New ID: " << lookupNodeID[( m_nodes.end()-1 )->getID()] << std::endl;
1927  throw std::runtime_error( "ERROR @ WHtree::cleanup(): pruning failed, top of tree is not last node in vector" );
1928  }
1929  nodesIter->setParent( std::make_pair( false, 0 ) );
1930  }
1931  else
1932  {
1933  nodesIter->setParent( std::make_pair( true, newParentID ) );
1934  }
1935 
1936  nodesIter->setID( std::make_pair( true, newID ) );
1937  nodesIter->setChildren( emptyKids );
1938  nodesIter->setHLevel( 0 );
1939  }
1940 
1941  // fill up children and hierarchical level data
1942  for( std::vector<WHnode>::iterator leavesIter( m_leaves.begin() ); leavesIter != m_leaves.end(); ++leavesIter )
1943  {
1944  WHnode *parentNode( fetchNode( leavesIter->getParent() ) );
1945  std::vector<nodeID_t> currentKids( parentNode->getChildren() );
1946  currentKids.push_back( leavesIter->getFullID() );
1947  parentNode->setChildren( currentKids );
1948  parentNode->setHLevel( 1 );
1949  }
1950  for( std::vector<WHnode>::iterator nodesIter( m_nodes.begin() ); nodesIter != m_nodes.end(); ++nodesIter )
1951  {
1952  if( nodesIter->isRoot() )
1953  {
1954  continue;
1955  }
1956  WHnode *parentNode( fetchNode( nodesIter->getParent() ) );
1957  std::vector<nodeID_t> currentKids( parentNode->getChildren() );
1958  currentKids.push_back( nodesIter->getFullID() );
1959  parentNode->setChildren( currentKids );
1960  parentNode->setHLevel( std::max( parentNode->getHLevel(), ( nodesIter->getHLevel() )+1 ) );
1961  }
1962 
1963  // check if final tree is consistent
1964  if( !check() )
1965  {
1966  throw std::runtime_error( "ERROR @ WHtree::cleanup(): resulting tree is not consistent" );
1967  }
1968  if( discardedLeaves != 0 || discardedNodes != 0 )
1969  {
1970  m_cpcc = 0;
1971  clearPartitions();
1972  }
1973 
1974  if( outLookup != 0 ) // if a pointer was passed as argument
1975  {
1976  *outLookup = lookupNodeID;
1977  }
1978 
1979  clearPartitions();
1980  clearPartColors();
1981  return std::make_pair( discardedLeaves, discardedNodes );
1982 } // end cleanup() -------------------------------------------------------------------------------------
1983 
1984 
1985 size_t WHtree::debinarize( bool keepBaseNodes )
1986 {
1987  if( keepBaseNodes && !testRootBaseNodes() )
1988  {
1989  wlog::error( "WHtree" ) << "WARNING@ Debinarize: base nodes have mixed nodes and leaves, debinarize will be standard ";
1990  keepBaseNodes = false;
1991  }
1992  const size_t origNumNodes( getNumNodes() );
1993 
1994  std::vector<bool> validNode( getNumNodes(), true );
1995  std::vector<std::vector<nodeID_t> > realChildren;
1996  realChildren.resize( getNumNodes() );
1997  std::vector<size_t> realParentsforLeaves( getNumLeaves(), 0 );
1998  std::vector<size_t> realParentsforNodes( getNumNodes(), 0 );
1999 
2000 
2001  if( !keepBaseNodes )
2002  {
2003  // first loop through leaves
2004  for( unsigned int id = 0; id < getNumLeaves(); ++id )
2005  {
2006  size_t currentNode( fetchLeaf( id )->getParent().second );
2007  dist_t currentDist( fetchNode( currentNode )->getDistLevel() );
2008 
2009  if( fetchNode( currentNode )->isRoot() ) // its parent is the last node
2010  {
2011  realParentsforLeaves[id] = currentNode;
2012  realChildren[currentNode].push_back( std::make_pair( false, id ) );
2013  continue;
2014  }
2015  size_t nextParent( fetchNode( currentNode )->getParent().second );
2016  dist_t nextDist( fetchNode( nextParent )->getDistLevel() );
2017 
2018  while( currentDist == nextDist )
2019  {
2020  validNode[currentNode] = false;
2021  currentNode = nextParent;
2022  currentDist = nextDist;
2023 
2024  if( fetchNode( nextParent )->isRoot() ) // if we reach the last node we stop
2025  {
2026  break;
2027  }
2028 
2029  nextParent = fetchNode( currentNode )->getParent().second;
2030  nextDist = fetchNode( nextParent )->getDistLevel();
2031  }
2032  realParentsforLeaves[id] = currentNode;
2033  realChildren[currentNode].push_back( std::make_pair( false, id ) );
2034  }
2035  }
2036  else
2037  {
2038  for( unsigned int id = 0; id < getNumLeaves(); ++id )
2039  {
2040  size_t currentNode( fetchLeaf( id )->getParent().second );
2041 
2042  if( fetchNode( currentNode )->isRoot() ) // its parent is the last node
2043  {
2044  realParentsforLeaves[id] = currentNode;
2045  realChildren[currentNode].push_back( std::make_pair( false, id ) );
2046  continue;
2047  }
2048 
2049  realParentsforLeaves[id] = currentNode;
2050  realChildren[currentNode].push_back( std::make_pair( false, id ) );
2051  }
2052  }
2053 
2054  // then loop through nodes
2055  for( unsigned int id = 0; id < getNumNodes()-1; ++id ) //we never process the last node (has no parent)
2056  {
2057  size_t currentNode( fetchNode( id )->getParent().second );
2058  dist_t currentDist( fetchNode( currentNode )->getDistLevel() );
2059 
2060  if( fetchNode( currentNode )->isRoot() ) // its parent is the last node
2061  {
2062  realParentsforNodes[id] = currentNode;
2063  if( validNode[id] )
2064  {
2065  realChildren[currentNode].push_back( std::make_pair( true, id ) );
2066  }
2067  continue;
2068  }
2069  size_t nextParent( fetchNode( currentNode )->getParent().second );
2070  dist_t nextDist( fetchNode( nextParent )->getDistLevel() );
2071 
2072  while( currentDist == nextDist )
2073  {
2074  validNode[currentNode] = false;
2075 
2076  currentNode = nextParent;
2077  currentDist = nextDist;
2078 
2079  if( fetchNode( nextParent )->isRoot() ) // its parent is the last node
2080  {
2081  break;
2082  }
2083 
2084  nextParent = fetchNode( currentNode )->getParent().second;
2085  nextDist = fetchNode( nextParent )->getDistLevel();
2086  }
2087  realParentsforNodes[id] = currentNode;
2088  if( validNode[id] )
2089  realChildren[currentNode].push_back( std::make_pair( true, id ) );
2090  }
2091  realParentsforNodes[getNumNodes()-1 ]= 0; // parent of root node
2092 
2093 
2094  // check validity
2095  for( unsigned int i = 0; i < getNumNodes(); ++i ) //we never process the last node (has no parent)
2096  {
2097  if( validNode[i] && ( realChildren[i].empty() ) )
2098  {
2099  wlog::error( "WHtree" ) << "node (1-" << i << ") has no real children";
2100  throw std::runtime_error( "ERROR @ WHtree::debinarize(): node has no real children" );
2101  }
2102  }
2103 
2104  // lookuptable to account for id change due to invalid nodes
2105  size_t nbCount( 0 );
2106  const size_t invalid( validNode.size()+1 );
2107  std::vector<size_t> changeLookup( validNode.size(), invalid );
2108  for( size_t i = 0; i < validNode.size(); ++i )
2109  {
2110  if( validNode[i] )
2111  {
2112  changeLookup[i] = nbCount;
2113  ++nbCount;
2114  }
2115  }
2116 
2117  //rename real children
2118  for( size_t i = 0; i < realChildren.size(); ++i )
2119  {
2120  for( size_t j = 0; j < realChildren[i].size(); ++j )
2121  {
2122  if( realChildren[i][j].first )
2123  {
2124  size_t newName( changeLookup[realChildren[i][j].second] );
2125  if( newName == invalid )
2126  {
2127  throw std::runtime_error( "ERROR @ WHtree::debinarize(): error renaming node children" );
2128  }
2129  realChildren[i][j].second = newName;
2130  }
2131  }
2132  }
2133 
2134  // change leaves info
2135  for( unsigned int id = 0; id < getNumLeaves(); ++id )
2136  {
2137  size_t realDad( changeLookup[realParentsforLeaves[id]] );
2138  if( realDad == invalid )
2139  {
2140  throw std::runtime_error( "ERROR @ WHtree::debinarize(): error renaming nb leaf parents" );
2141  }
2142  fetchLeaf( id )->setParent( std::make_pair( true, realDad ) );
2143  }
2144 
2145  {
2146  // create new nodes vector
2147  std::vector<WHnode> nbNodes;
2148  nbNodes.reserve( getNumNodes() );
2149  for( unsigned int id = 0; id < getNumNodes()-1; ++id )
2150  {
2151  if( validNode[id] )
2152  {
2153  size_t realDad( changeLookup[realParentsforNodes[id]] );
2154  if( realDad == invalid )
2155  {
2156  wlog::error( "WHtree" ) << "node (1-" << id << ") is valid but has invalid dad, ( preDad was 1-" << realParentsforNodes[ id ]
2157  << ")";
2158  throw std::runtime_error( "ERROR @ WHtree::debinarize(): error renaming nb node parents" );
2159  }
2160  WHnode thisnode( std::make_pair( true, changeLookup[id] ), realChildren[id],
2161  fetchNode( id )->getSize(), fetchNode( id )->getDistLevel(), 0 );
2162  thisnode.setParent( std::make_pair( true, realDad ) );
2163  nbNodes.push_back( thisnode );
2164  }
2165  }
2166  WHnode rootnode( std::make_pair( true, changeLookup[getNumNodes()-1] ), realChildren[getNumNodes()-1],
2167  fetchNode( getNumNodes()-1 )->getSize(), fetchNode( getNumNodes()-1 )->getDistLevel(), 0 );
2168  nbNodes.push_back( rootnode );
2169 
2170 
2171  // replace old node vector with new one
2172  m_nodes = nbNodes;
2173  }
2175  clearPartitions();
2176  // refill hLevel data
2177  for( unsigned int id = 0; id < getNumNodes(); ++id )
2178  {
2179  WHnode* currentNode( fetchNode( id ) );
2180  std::vector<nodeID_t> currentKids( currentNode->getChildren() );
2181  size_t currentHLevel( 0 );
2182  for( size_t j = 0; j < currentKids.size(); ++j )
2183  {
2184  currentHLevel = std::max( currentHLevel, fetchNode( currentKids[j] )->getHLevel()+1 );
2185  }
2186  currentNode->setHLevel( currentHLevel );
2187  }
2188 
2189  if( !check() )
2190  {
2191  throw std::runtime_error( "ERROR @ WHtree::debinarize(): resutling tree is not consistent" );
2192  }
2193 
2194  size_t discardedNodes( origNumNodes - getNumNodes() );
2195 
2196  if( discardedNodes != 0 )
2197  {
2198  m_cpcc = 0;
2199  clearPartitions();
2200  }
2201 
2202  return discardedNodes;
2203 } // end debinarize() -------------------------------------------------------------------------------------
2204 
2206 {
2207  // loop through nodes and force monotonicity
2208  for( std::vector<WHnode>::iterator nodesIter( m_nodes.begin() ); nodesIter != m_nodes.end(); ++nodesIter )
2209  {
2210  WHnode* currentNode( fetchNode( nodesIter->getID() ) );
2211  std::vector<nodeID_t> currentKids( currentNode->getChildren() );
2212 
2213  for( size_t j = 0; j < currentKids.size(); ++j )
2214  {
2215  WHnode* kid( fetchNode( currentKids[j] ) );
2216  // if its kid has a higher level than the node, there was a non-monotonic step, and the highest level is kept
2217  if( kid->getDistLevel() > currentNode->getDistLevel() )
2218  {
2219  currentNode->setDistLevel( kid->getDistLevel() );
2220  }
2221  }
2222  }
2223  return;
2224 } // end forceMonotonicityUp() -------------------------------------------------------------------------------------
2225 
2227 {
2228  // loop through nodes and force monotonicity
2229  for( std::vector<WHnode>::reverse_iterator nodesIter( m_nodes.rbegin() ); nodesIter != m_nodes.rend(); ++nodesIter )
2230  {
2231  WHnode* currentNode( fetchNode( nodesIter->getID() ) );
2232  std::vector<nodeID_t> currentKids( currentNode->getChildren() );
2233 
2234  for( size_t j = 0; j < currentKids.size(); ++j )
2235  {
2236  WHnode* kid( fetchNode( currentKids[j] ) );
2237  // if its kid has a higher level than the node, there was a non-monotonic step, and the lowest level is kept
2238  if( kid->getDistLevel() > currentNode->getDistLevel() )
2239  {
2240  kid->setDistLevel( currentNode->getDistLevel() );
2241  }
2242  }
2243  }
2244  return;
2245 } // end forceMonotonicityDown() -------------------------------------------------------------------------------------
2246 
2247 void WHtree::forceMonotonicity( double errorMult )
2248 {
2249  if( errorMult > 100 || errorMult <= 0 )
2250  {
2251  errorMult = 1;
2252  }
2253  double errorMargin( errorMult * 1E-5 );
2254 
2255  for( int64_t i = m_nodes.size()-1; i >= 0; )
2256  {
2257  WHnode* currentNode( fetchNode( m_nodes[i].getID() ) );
2258  size_t currentSize( currentNode->getSize() );
2259  dist_t currentLevel( currentNode->getDistLevel() );
2260 
2261  std::vector<nodeID_t> currentKids( currentNode->getChildren() );
2262 
2263  double newLevelSum( 0 );
2264  size_t remainingSize( currentSize );
2265  bool doCorrect( false );
2266 
2267  for( size_t j = 0; j < currentKids.size(); ++j )
2268  {
2269  WHnode* kid( fetchNode( currentKids[j] ) );
2270  // if its kid has a higher level than the node, there was a non-monotonic step
2271  if( kid->getDistLevel() > currentLevel + errorMargin )
2272  {
2273  newLevelSum += kid->getDistLevel() * kid->getSize();
2274  remainingSize -= kid->getSize();
2275  doCorrect = true;
2276  }
2277  }
2278  if( doCorrect )
2279  {
2280 // std::cout << i << " -> " << std::flush;
2281 
2282  double correctedLevel( ( newLevelSum + ( remainingSize * currentLevel ) ) / currentSize );
2283  // correct level of current node
2284  currentNode->setDistLevel( correctedLevel );
2285  // correct level of non-monotonic children nodes
2286  for( size_t j = 0; j < currentKids.size(); ++j )
2287  {
2288  WHnode* kid( fetchNode( currentKids[j] ) );
2289  // if its kid has a higher level than the node, there was a non-monotonic step, and the highest level must be kept to avoid info loss
2290  if( kid->getDistLevel() > correctedLevel )
2291  {
2292  kid->setDistLevel( correctedLevel );
2293  }
2294  }
2295 
2296  // if node is not root check if corrected level is higher than parent node
2297  if( currentNode->isRoot() )
2298  {
2299  --i;
2300  }
2301  else
2302  {
2303  WHnode* parentNode( fetchNode( currentNode->getParent() ) );
2304  double parentLevel( parentNode->getDistLevel() );
2305  // if new level is higher than parent level, go back to parent node id and continue from there
2306  if( correctedLevel > parentLevel + errorMargin )
2307  {
2308  i = parentNode->getID();
2309  }
2310  else
2311  {
2312  --i;
2313  }
2314  }
2315 //DEBUG std::cout << i << " : " <<currentLevel<< " -> " << correctedLevel << std::endl;
2316  }
2317  else
2318  {
2319  --i;
2320  }
2321  }
2322 
2324 
2325  return;
2326 } // end forceMonotonicity() -------------------------------------------------------------------------------------
2327 
2328 
2329 
Thrown whenever a file could not be opened.
class implements text file loading and several convinience methods to access
std::vector< std::vector< std::string > > getLinesForTagSeparated(std::string tag)
getter
std::vector< std::string > getRawLines()
getter
bool readFile()
helper function to read a text file
this class to contain a seed voxel coordinate.
Definition: WHcoord.h:76
WHcoord nifti2vista(const WHcoord dataSize) const
transform coordinates to vista format
Definition: WHcoord.cpp:215
coord_t m_z
z coordinate
Definition: WHcoord.h:156
std::string getNameString() const
returns a string with the coordinates of the voxel in the form "xxx_yyy_zzz"
Definition: WHcoord.cpp:205
coord_t m_y
y coordinate
Definition: WHcoord.h:155
WHcoord vista2nifti(const WHcoord dataSize) const
transform coordinates to vista format
Definition: WHcoord.cpp:233
coord_t m_x
x coordinate
Definition: WHcoord.h:154
this class implements a hierarchical tree node with several relevant attributes
Definition: WHnode.h:69
size_t getSize() const
returns number of elements contained by the node
Definition: WHnode.h:257
void setParent(const nodeID_t newDad)
sets the parent id field to the specified value
Definition: WHnode.cpp:87
bool isFlagged() const
returns true if object is flagged for pruning
Definition: WHnode.h:237
void setChildren(std::vector< nodeID_t > newKids)
sets the children vector to the input values
Definition: WHnode.cpp:107
void setHLevel(const size_t newLevel)
sets the hierarchical level field to the specified value
Definition: WHnode.cpp:97
bool isLeaf() const
returns true if object is a leaf
Definition: WHnode.h:232
size_t getHLevel() const
returns maximum number of nodes between the node and a leaf element
Definition: WHnode.h:267
void setSize(const size_t newSize)
sets the size field to the specified value
Definition: WHnode.cpp:92
bool isRoot() const
returns true if object is the root of the tree
Definition: WHnode.cpp:77
size_t getID() const
returns node/leaf ID
Definition: WHnode.h:242
dist_t getDistLevel() const
returns distance level at which the element was formed
Definition: WHnode.h:262
void setDistLevel(const dist_t newLevel)
sets the distance level field to the specified value
Definition: WHnode.cpp:102
nodeID_t getFullID() const
returns full ID
Definition: WHnode.h:247
nodeID_t getParent() const
returns parent ID
Definition: WHnode.h:252
std::vector< nodeID_t > getChildren() const
returns a vector with the ids of the children of that node
Definition: WHnode.h:272
this class implements a hierarchical tree and provides functions for creation, partitioning,...
Definition: WHtree.h:81
WHtree()
Constructor.
Definition: WHtree.cpp:73
void loadContainedLeaves()
stores the contained leaves for each node
Definition: WHtree.cpp:838
std::vector< size_t > getRootBaseNodes() const
returns a vector with all the nodes that have direct link to leaves from the main root
Definition: WHtree.cpp:706
const WHnode & getRoot() const
returns a const reference to the root node
Definition: WHtree.cpp:348
size_t getCommonAncestor(const size_t nodeID1, const size_t nodeID2) const
retrieves the the first common ancestor node of two given nodes
Definition: WHtree.cpp:535
float m_cpcc
Stores the cpcc value of the tree.
Definition: WHtree.h:637
std::vector< std::vector< WHcoord > > m_selectedColors
Stores the colors of the selected partitions.
Definition: WHtree.h:667
bool writeTreeDebug(const std::string &filename) const
writes all redundant tree data for debugging purposes
Definition: WHtree.cpp:1380
std::vector< std::vector< size_t > > m_containedLeaves
Stores the contained leafs of each node.
Definition: WHtree.h:658
std::vector< size_t > getBaseNodes(const size_t root) const
returns a vector with all the nodes that have direct link to leaves fro the indicated subtree
Definition: WHtree.cpp:642
size_t getNumNodes() const
Returns the number of nodes of the tree.
Definition: WHtree.h:836
dist_t getDistance(const size_t nodeID1, const size_t nodeID2) const
computes the cophenetic distance between 2 nodes
Definition: WHtree.cpp:730
std::vector< WHcoord > m_coordinates
Stores the coordinates of the leaf voxels.
Definition: WHtree.h:649
std::vector< WHcoord > getCoordinates4node(const size_t nodeID) const
Returns a vector with all the seed voxel coordinates contained in that cluster.
Definition: WHtree.cpp:480
std::vector< size_t > getLeaves4node(const size_t nodeID) const
Returns a vector with all the leaf IDs contained in that cluster.
Definition: WHtree.cpp:380
WHcoord m_datasetSize
Stores the size of the dataset this tree was built from.
Definition: WHtree.h:625
std::vector< WHnode > m_nodes
Stores all the nodes (non-leaves) of the tree.
Definition: WHtree.h:646
void insertPartitions(const std::vector< std::vector< size_t > > &selectedPartitions, const std::vector< float > &selectedValues, const std::vector< std::vector< WHcoord > > &selectedColors=std::vector< std::vector< WHcoord > >())
insert a set of partitions into the tree data
Definition: WHtree.cpp:1473
const WHnode & getNode(const nodeID_t &thisNode) const
returns a const pointer to the node indicated by the ID
Definition: WHtree.cpp:307
size_t getLeafID(const WHcoord &thisCoord) const
returns the leaf ID of a coordinate in the tree
Definition: WHtree.cpp:354
bool m_loadStatus
Stores all the leaves of the tree (represents a single voxel, for several purposes a leaf also counts...
Definition: WHtree.h:622
void clearPartitions()
delete all data related to saved partitions
Definition: WHtree.cpp:1534
void clearPartColors()
delete only color data of the saved partitions
Definition: WHtree.cpp:1545
bool writeTreeOldWalnut(const std::string &filename) const
writes dta for working with the old walnut module
Definition: WHtree.cpp:1416
void forceMonotonicityDown()
eliminates non monotonic steps in the tree top-down, raising the level of parents involved in the non...
Definition: WHtree.cpp:2226
dist_t getLeafDistance(const size_t leafID1, const size_t leafID2) const
computes the cophenetic distance between 2 leaves
Definition: WHtree.cpp:748
std::vector< std::vector< size_t > > m_selectedPartitions
Stores a set of selected partitions.
Definition: WHtree.h:661
unsigned int getTripletOrder(const nodeID_t &nodeIDa, const nodeID_t &nodeIDb, const nodeID_t &nodeIDc) const
checks the joining order of a given triplet
Definition: WHtree.cpp:612
size_t debinarize(const bool keepBaseNodes=false)
merges nodes joining binary at the same level into non-binary structures
Definition: WHtree.cpp:1985
const WHnode & getLeaf(const size_t thisLeaf) const
returns a const pointer to the leaf indicated by the ID
Definition: WHtree.cpp:333
std::vector< WHnode > m_leaves
Stores all the leaves of the tree (represents a single voxel, for several purposes a leaf also counts...
Definition: WHtree.h:643
bool writeTreeSimple(const std::string &filename) const
writes only join data without coordinates or reading labels
Definition: WHtree.cpp:1457
void clearContainedLeaves()
frees the memory of m_containedLeaves
Definition: WHtree.cpp:860
WHnode * fetchNode(const nodeID_t &thisNode)
returns a pointer to the node indicated by the ID
Definition: WHtree.cpp:1684
std::string getReport(bool longMsg=true) const
writes out a small report status of the tree
Definition: WHtree.cpp:132
std::pair< size_t, size_t > cleanup(std::vector< size_t > *outLookup=0)
cleans leaves/nodes set to be pruned
Definition: WHtree.cpp:1716
void sortByHLevel(std::vector< size_t > *const nodeVector) const
Reorders the nodes in the vector according to their hierarchical level.
Definition: WHtree.cpp:817
size_t getTrackID(const size_t &leafID) const
returns the corresponding track ID to a leaf ID on the tree
Definition: WHtree.cpp:367
void insertPartColors(const std::vector< std::vector< WHcoord > > &selectedColors)
insert a set of partitions colors into the tree data in case a set of saved partitions is already pre...
Definition: WHtree.cpp:1511
WHcoord getMeanCoordinate4node(const size_t nodeID) const
Returns the mean coordinate of all the seed voxel coordinates contained in that cluster.
Definition: WHtree.cpp:504
WHnode * fetchRoot()
returns a pointer to the root node
Definition: WHtree.cpp:1710
void sortBySize(std::vector< size_t > *const nodeVector) const
Reorders the nodes in the vector according to their size.
Definition: WHtree.cpp:755
float m_logFactor
logarithmic normalization factor used in the tractograms when building the tree
Definition: WHtree.h:634
size_t m_numStreamlines
number of streamlines generated form each seed voxel in the tractograms used to build the tree
Definition: WHtree.h:631
void forceMonotonicity(double errorMult=1)
eliminates non monotonic steps in the tree while keeping as much information as possible.
Definition: WHtree.cpp:2247
std::string m_treeName
Stores the name of the tree file.
Definition: WHtree.h:640
bool testRootBaseNodes() const
tests if all base nodes have only leaf children
Definition: WHtree.cpp:712
bool writeTree(const std::string &filename, const bool isNifti=true) const
writes the current tree data
Definition: WHtree.cpp:1233
std::vector< nodeID_t > getRoute2Root(const nodeID_t &nodeID) const
node route to root node
Definition: WHtree.cpp:589
bool check() const
checks tree integrity
Definition: WHtree.cpp:152
HC_GRID m_datasetGrid
Stores the the type of coordinate grid of the dataset.
Definition: WHtree.h:628
std::vector< size_t > m_trackids
Stores the ids of the seed tracts correesponding to each leaf.
Definition: WHtree.h:652
bool convert2grid(const HC_GRID newGrid)
converts all the coordinates to the grid format indicated
Definition: WHtree.cpp:867
std::vector< size_t > getBranchNodes(const size_t nodeID) const
Returns a vector with all the node IDs contained in that branch.
Definition: WHtree.cpp:434
WHcoord getCoordinate4leaf(const size_t leafID) const
the coordinates of a particular leaf
Definition: WHtree.cpp:466
bool readTree(const std::string &filename)
Reads the the tree data from a file and creates the structure, containing it in the leaves,...
Definition: WHtree.cpp:911
WHnode * fetchLeaf(const size_t thisLeaf)
returns a pointer to the leaf indicated by the ID
Definition: WHtree.cpp:1697
std::vector< float > m_selectedValues
Stores the quality values of the selected partitions.
Definition: WHtree.h:664
~WHtree()
Destructor.
Definition: WHtree.cpp:121
size_t getNumLeaves() const
Returns the number of leaves of the tree.
Definition: WHtree.h:831
std::list< WHcoord > m_discarded
Stores the coordinates of the voxels that were discarded during the process of building the tree.
Definition: WHtree.h:655
std::vector< std::vector< unsigned int > > getBranching(const std::vector< nodeID_t > &thisPartition, size_t depthLevel, std::vector< std::vector< nodeID_t > > *partitionSet, const bool excludeLeaves)
gets all possble sets of sub-partitions in a tree given an initial partition and a depth level (where...
Definition: WHtree.cpp:1552
void forceMonotonicityUp()
eliminates non monotonic steps in the tree bottom-up, lowering the level of children involved in the ...
Definition: WHtree.cpp:2205
std::string toString(const T &value)
Convert a given value to a string.
Definition: WStringUtils.h:120
WStreamedLogger error(const std::string &source)
Logging an error message.
Definition: WLogger.h:298
implements a compare operator for nodes, depending on the hierarchical level
Definition: WHtree.h:770
implements a compare operator for nodes inside a tree structure, depending on the Size
Definition: WHtree.h:734