Program Listing for File TrackClusterBuilder.cxx

Return to documentation for file (larflow/Reco/TrackClusterBuilder.cxx)

#include "TrackClusterBuilder.h"

#include "TVector3.h"
#include "larflow/Reco/geofuncs.h"

#include "ublarcvapp/ubdllee/dwall.h"

namespace larflow {
namespace reco {

  void TrackClusterBuilder::process( larcv::IOManager& iolcv,
                                     larlite::storage_manager& ioll )
  {

    std::string producer = "trackprojsplit_full";

    larlite::event_larflowcluster* ev_cluster
      = (larlite::event_larflowcluster*)ioll.get_data(larlite::data::kLArFlowCluster, producer);
    larlite::event_pcaxis* ev_pcaxis
      = (larlite::event_pcaxis*)ioll.get_data(larlite::data::kPCAxis,producer);

    loadClusterLibrary( *ev_cluster, *ev_pcaxis );

  }

  void TrackClusterBuilder::clear()
  {
    _segment_v.clear();
    _segedge_m.clear();
    _connect_m.clear();
    _nodepos_v.clear();
    _track_proposal_v.clear();
  }

  void TrackClusterBuilder::loadClusterLibrary( const larlite::event_larflowcluster& cluster_v,
                                                const larlite::event_pcaxis& pcaxis_v )
  {

    for (int i=0; i<cluster_v.size(); i++) {
      const larlite::larflowcluster& cluster = cluster_v.at(i);
      const larlite::pcaxis& pca = pcaxis_v.at(i);

      // create a segment object
      std::vector<float> start(3,0);
      std::vector<float> end(3,0);
      for (int v=0; v<3; v++){
        start[v] = pca.getEigenVectors()[3][v];
        end[v]   = pca.getEigenVectors()[4][v];
      }

      Segment_t seg( start, end );
      seg.cluster = &cluster;
      seg.pca     = &pca;

      if ( seg.len<1.0 )
        continue;

      _segment_v.push_back(seg);
      _segment_v.back().idx = (int)_segment_v.size()-1;

      NodePos_t node1;
      node1.segidx  = _segment_v.back().idx;
      node1.nodeidx = (int)_nodepos_v.size();
      node1.pos     = start;

      NodePos_t node2;
      node2.segidx  = _segment_v.back().idx;
      node2.nodeidx = (int)_nodepos_v.size()+1;
      node2.pos     = end;

      _nodepos_v.push_back( node1 );
      _nodepos_v.push_back( node2 );

      // make segment edges
      Connection_t segedge1to2;
      segedge1to2.node = &_segment_v.back();
      segedge1to2.from_seg_idx = node1.nodeidx;
      segedge1to2.to_seg_idx   = node2.nodeidx;
      segedge1to2.dist         = seg.len;
      segedge1to2.cosine = 0.;
      segedge1to2.cosine_seg = 0.;
      segedge1to2.dir = seg.dir;

      Connection_t segedge2to1;
      segedge2to1.node = &_segment_v.back();
      segedge2to1.from_seg_idx = node2.nodeidx;
      segedge2to1.to_seg_idx   = node1.nodeidx;
      segedge2to1.dist         = seg.len;
      segedge2to1.cosine = 0.;
      segedge2to1.cosine_seg = 0.;
      segedge2to1.dir = seg.dir;
      for (int v=0; v<3; v++) segedge2to1.dir[v] *= -1.0;

      _segedge_m[ std::pair<int,int>( node1.nodeidx, node2.nodeidx ) ] = segedge1to2;
      _segedge_m[ std::pair<int,int>( node2.nodeidx, node1.nodeidx ) ] = segedge2to1;


    }

    LARCV_INFO() << "Stored " << _segment_v.size() << " track segments" << std::endl;
    LARCV_INFO() << "Stored " << _nodepos_v.size() << " segment endpoints as nodes" << std::endl;
  }

  void TrackClusterBuilder::buildNodeConnections()
  {

    for (int inode=0; inode<(int)_nodepos_v.size(); inode++ ) {
      NodePos_t& node_i = _nodepos_v[inode];

      for (int jnode=inode+1; jnode<(int)_nodepos_v.size(); jnode++) {

        // do not connect nodes on the same segment
        auto it_segedge = _segedge_m.find( std::pair<int,int>(inode,jnode) );
        if ( it_segedge!=_segedge_m.end() )
          continue;

        // define a connection in both directions
        NodePos_t& node_j = _nodepos_v[jnode];

        float dist = 0.;
        std::vector<float> dir_ij(3,0);
        for (int v=0; v<3; v++) {
          dir_ij[v] = node_j.pos[v]-node_i.pos[v];
          dist += dir_ij[v]*dir_ij[v];
        }
        dist = sqrt(dist);
        if ( dist>0 ) for (int v=0; v<3; v++) dir_ij[v] /= dist;

        if ( dist>100.0 ) continue;

        // make sure this is the shortest distance
        // between the segments
        int jnode_pair = -1;
        if ( jnode%2==0 ) {
          jnode_pair = jnode+1;
        }
        else
          jnode_pair = jnode-1;

        NodePos_t& node_j_pair = _nodepos_v[jnode_pair];
        float pairdist = 0.;
        for (int v=0; v<3; v++ ) {
          pairdist += ( node_j_pair.pos[v]-node_i.pos[v] )*( node_j_pair.pos[v]-node_i.pos[v] );
        }
        pairdist = sqrt(pairdist);

        if ( pairdist<dist ) {
          // the node's segment pair is closer to node_i, so we do not make this connection
          continue;
        }

        // i->j
        Connection_t con_ij;
        con_ij.node = nullptr;
        con_ij.from_seg_idx = inode;
        con_ij.to_seg_idx   = jnode;
        con_ij.dist = dist;
        con_ij.endidx = 0;
        con_ij.cosine = 0.;
        con_ij.cosine_seg = 0.;
        con_ij.dir = dir_ij;

        Connection_t con_ji;
        con_ji.node = nullptr;
        con_ji.from_seg_idx = jnode;
        con_ji.to_seg_idx   = inode;
        con_ji.dist   = dist;
        con_ij.endidx = 0;
        con_ji.cosine = 0.;
        con_ji.cosine_seg = 0.;
        con_ji.dir = dir_ij;
        for (int v=0; v<3; v++) {
          con_ji.dir[v] *= -1.0;
        }

        _connect_m[ std::pair<int,int>(inode,jnode) ] = con_ij;
        _connect_m[ std::pair<int,int>(jnode,inode) ] = con_ji;

      }
    }

    LARCV_INFO() << "Made " << _connect_m.size() << " nodepos connections" << std::endl;
  }

  void TrackClusterBuilder::buildTracksFromPoint( const std::vector<float>& startpoint )
  {

    // find closest segment
    float mindist = 0.;
    int   min_segidx = -1;

    for ( size_t iseg=0; iseg<_segment_v.size(); iseg++ ) {
      auto const& seg = _segment_v[iseg];
      float dist = pointLineDistance<float>(  seg.start, seg.end, startpoint );
      float proj = pointRayProjection<float>( seg.start, seg.dir, startpoint );

      if ( proj>-3.0 && proj<=seg.len+3.0 ) {
        if ( mindist>dist || min_segidx<0 ) {
          mindist = dist;
          min_segidx = iseg;
        }
      }
    }
    if ( min_segidx<0 ) {
      LARCV_INFO() << "No acceptable segment found for startpoint" << std::endl;
      return;
    }

    if ( mindist>3.0 ) {
      LARCV_INFO() << "No segment is close enough to keypoint" << std::endl;
      return;
    }

    LARCV_DEBUG() << "=== Seed track with point (" << startpoint[0] << "," << startpoint[1] << "," << startpoint[2] << ") ======" << std::endl;
    LARCV_DEBUG() << " segment found idx=[" << min_segidx << "] to build from " << str(_segment_v[min_segidx]) << std::endl;

    // reset the nodes
    for ( auto& node : _nodepos_v )
      node.inpath = false;

    // Nodes from the segment
    NodePos_t& node1 = _nodepos_v[2*min_segidx];
    NodePos_t& node2 = _nodepos_v[2*min_segidx+1];
    node1.inpath = true;
    node2.inpath = true;

    NodePos_t* startnode = nullptr;
    NodePos_t* nextnode  = nullptr;
    float dist1 = 0.;
    float dist2 = 0.;
    for (int v=0; v<3; v++) {
      dist1 += (node1.pos[v]-startpoint[v])*(node1.pos[v]-startpoint[v]);
      dist2 += (node2.pos[v]-startpoint[v])*(node2.pos[v]-startpoint[v]);
    }
    startnode = (dist1<dist2) ? &node1 : &node2;
    nextnode  = (dist1>dist2) ? &node1 : &node2;

    LARCV_DEBUG() << " starting track from: (" << startnode->pos[0] << "," << startnode->pos[1] << "," << startnode->pos[2] << ")" << std::endl;
    LARCV_DEBUG() << " first gap edge from: (" << nextnode->pos[0] << "," << nextnode->pos[1] << "," << nextnode->pos[2] << ")" << std::endl;

    auto it_segedge12 = _segedge_m.find( std::pair<int,int>(startnode->nodeidx,nextnode->nodeidx) );
    auto it_segedge21 = _segedge_m.find( std::pair<int,int>(nextnode->nodeidx,startnode->nodeidx) );
    std::vector<float>& path_dir = it_segedge12->second.dir;

    std::vector< NodePos_t* > path;
    std::vector< const std::vector<float>* > path_dir_v;
    std::vector< std::vector<NodePos_t*> > complete_v;

    // start to nextnode
    if ( !startnode->veto ) {
      path.clear();
      path_dir_v.clear();
      path.push_back( startnode );
      path_dir_v.push_back( &path_dir );
      _recursiveFollowPath( *nextnode, path_dir, path, path_dir_v, complete_v );
      LARCV_DEBUG() << "[after start->next] point generated " << complete_v.size() << " possible tracks" << std::endl;
    }

    // flip things
    if ( !nextnode->veto ) {
      path.clear();
      path_dir_v.clear();
      path.push_back( nextnode );
      path_dir_v.push_back( &it_segedge21->second.dir );
      _recursiveFollowPath( *startnode, path_dir, path, path_dir_v, complete_v );
      LARCV_DEBUG() << "[after next->start] point generated " << complete_v.size() << " possible tracks" << std::endl;
    }


    // this will generate proposals. we must choose among them
    std::vector< std::vector<NodePos_t*> > filtered_v;
    _choose_best_paths( complete_v, filtered_v );

    for ( auto& path : filtered_v )  {
      LARCV_DEBUG() << "storing path nnodes=" << path.size()
                    << " node[" << path.front()->nodeidx << "]->node[" << path.back()->nodeidx << "]"
                    << " seg[" << path.front()->segidx << "]->seg[" << path.back()->segidx << "]"
                    << std::endl;
      _track_proposal_v.push_back( path );
    }

    LARCV_INFO() << "Number of paths now stored: " << _track_proposal_v.size() << std::endl;

  }

  void TrackClusterBuilder::_recursiveFollowPath( NodePos_t& node,
                                                  std::vector<float>& path_dir,
                                                  std::vector<NodePos_t*>& path,
                                                  std::vector< const std::vector<float>* > path_dir_v,
                                                  std::vector< std::vector<NodePos_t*> >& complete )
  {

    // we add ourselves to the current path
    node.inpath = true;
    path.push_back( &node );
    path_dir_v.push_back( &path_dir );

    // oh wow. we loop through possible connections, and descend.
    int nconnections = 0;
    float mindist = 1e9;
    float maxcos = 0;
    for (int inode=0; inode<_nodepos_v.size(); inode++) {

      NodePos_t& nextnode = _nodepos_v[inode];
      if ( nextnode.inpath || nextnode.veto ) continue;

      auto it = _connect_m.find( std::pair<int,int>(node.nodeidx,inode) );
      if ( it==_connect_m.end() ) continue; // no connection

      //std::cout << "  (connect " << seg.idx << "->" << iseg << ") dist=" << it->second.dist << " cos="  << it->second.cosine << std::endl;

      // we connect based on:

      // distance between node (edge length)
      // direction between nodes (edge direction)
      // direction between nextnode and its pair (segment direction)
      int inode_pair = -1;
      if ( inode%2==0 )
        inode_pair = inode+1;
      else
        inode_pair = inode-1;

      auto it_segedge = _segedge_m.find( std::pair<int,int>(inode,inode_pair) );
      float& gaplen = it->second.dist;
      std::vector<float>&  gapdir = it->second.dir; // should have worked ...
      // std::vector<float>  gapdir(3,0);// = it->second.dir;
      // for (int v=0; v<3; v++) {
      //   gapdir[v] = (nextnode.pos[v]-node.pos[v])/gaplen;
      // }
      std::vector<float>& segdir = it_segedge->second.dir;

      float segcos = 0.;  // cosine between last segment and proposed segment
      float concos1 = 0.; // cosine between last segment and gap edge
      float concos2 = 0.; // cosine between gap edge and proposed segment dir
      for ( int v=0; v<3; v++ ) {
        segcos  += path_dir[v]*segdir[v];
        concos1 += path_dir[v]*gapdir[v];
        concos2 += gapdir[v]*segdir[v];
      }

      // add this segment
      // std::cout << "  consider node[" << node.nodeidx << "]->node[" << nextnode.nodeidx << "] "
      //           << " seg[" << node.segidx << "]->seg[" << nextnode.segidx << "] "
      //           << "dist=" << gaplen << " "
      //           << " seg1-seg2=" << segcos
      //           << " seg1-edge=" << concos1
      //           << " edge-seg2=" << concos2
      //           << std::endl;

      // criteria for accepting connection
      // ugh, the heuristics ...
      if ( (gaplen<2.0 && segcos>0 ) // close: only check direction between segments
           || (gaplen>=2.0 && gaplen<10.0 && segcos>0.8 && concos1>0.8 && concos2>0.8 )  // far: everything in the same direction
           || (gaplen>=10.0 && segcos>0.9 && concos1>0.9 && concos2>0.9 ) ) {  // far: everything in the same direction

        // add this segment
        // std::cout << "  ==> connect node[" << node.nodeidx << "]->node[" << node.nodeidx << "] "
        //           << " seg[" << node.segidx << "]->seg[" << nextnode.segidx << "] "
        //           << std::endl;
        //std::cin.get();

        NodePos_t& node_pair = _nodepos_v[inode_pair];
        nextnode.inpath = true;
        path_dir_v.push_back( &segdir );
        path.push_back( &nextnode );
        nconnections++;
        _recursiveFollowPath( node_pair, segdir, path, path_dir_v, complete );

        if ( complete.size()>=1000 ) {
          //cut this off!
          std::cout << "  cut off search. track limit reached: " << complete.size() << std::endl;
          break;
        }
      }
    }

    if ( nconnections==0 && complete.size()<10000 && path.size()>1 ) {
      // was a leaf, so make a complete track.
      // else was a link
      complete.push_back( path );
      LARCV_DEBUG() << "reached a leaf, copy track len=" << path.size() << " to completed list. num of completed tracks: " << complete.size() << std::endl;
    }
    //std::cout << "  mindist=" << mindist << " maxcos=" << maxcos << std::endl;
    // pop  off the last two nodes
    int nnodes = (int)path.size();
    if ( path.size()<2 )
      return;
    path[nnodes-2]->inpath = false;
    path[nnodes-1]->inpath = false;
    path.pop_back();
    path.pop_back();
    path_dir.pop_back();
    path_dir.pop_back();

    return;
  }

  std::string TrackClusterBuilder::str( const TrackClusterBuilder::Segment_t& seg )
  {
    std::stringstream ss;
    ss << "[segment[" << seg.idx << "] len=" << seg.len;
    if ( seg.start.size()==3 )
      ss << " start=(" << seg.start[0] << "," << seg.start[1] << "," << seg.start[2] << ") ";
    if (seg.end.size()==3 )
      ss << " end=(" << seg.end[0] << "," << seg.end[1] << "," << seg.end[2] << ") ";
    if (seg.dir.size()==3 )
      ss << " dir=(" << seg.dir[0] << "," << seg.dir[1] << "," << seg.dir[2] << ") ";
    ss << "]";
    return ss.str();
  }

  void TrackClusterBuilder::_choose_best_paths( std::vector< std::vector<NodePos_t*> >& complete_v,
                                                std::vector< std::vector<NodePos_t*> >& filtered_v )
  {


    typedef std::vector<NodePos_t*> Path_t;

    // phase 1, group paths by leaf index (the index of the last node)
    std::map<int, std::vector< Path_t* > > leaf_groups;
    for ( auto& path : complete_v ) {
      int leafidx = path.back()->nodeidx;
      auto it = leaf_groups.find(leafidx);
      if ( it==leaf_groups.end() ) {
        leaf_groups[leafidx] = std::vector< Path_t* >();
        it = leaf_groups.find(leafidx);
      }
      it->second.push_back( &path );
    }

    // loop over leaf groups, choosing subset close to min
    int nfiltered_before = (int)filtered_v.size();
    std::vector< Path_t* > selected_v;
    std::vector<float> path_dist_ratio_v;
    std::vector<float> selected_pathlen_v;
    std::vector<float> selected_enddist_v;
    float min_pathdist_ratio = 1.0e9;
    path_dist_ratio_v.reserve( leaf_groups.size() );
    for ( auto it=leaf_groups.begin(); it!=leaf_groups.end(); it++ ) {

      //std::cout << "=== Find mindist subgroup in Leaf Group[" << it->first << "] ===" << std::endl;

      std::vector< float > pathlen_v;
      std::vector< float > seglen_v;
      pathlen_v.reserve(it->second.size());
      seglen_v.reserve(it->second.size());

      int minpath_idx = -1;
      float minpathlen = 1e9;

      for ( size_t ipath=0; ipath<it->second.size(); ipath++ ) {
        Path_t* ppath = it->second.at(ipath);
        float pathdist = 0.;
        float totseglen = 0.;
        for ( size_t inode=1; inode<ppath->size(); inode++ ) {

          NodePos_t* pnode = ppath->at(inode);
          NodePos_t* pnode_prev = ppath->at(inode-1);

          float dist = 0.;
          for (int v=0; v<3; v++)
            dist += ( pnode->pos[v]-pnode_prev->pos[v] )*( pnode->pos[v]-pnode_prev->pos[v] );
          dist = sqrt(dist);

          if ( inode%2==1 )
            totseglen += dist;
          pathdist += dist;

        }//end of loop over path segments
        //std::cout << "  Leaf-group[" << it->first << "] path[" << ipath << "] pathlen=" << pathdist << " seglen=" << totseglen << std::endl;
        pathlen_v.push_back(pathdist);
        seglen_v.push_back(totseglen);
        if ( pathdist<minpathlen ) {
          minpath_idx = (int)ipath;
          minpathlen = pathdist;
        }
      }//end of path loop
      //std::cout << " Leaf group minpathlen=" << minpathlen << std::endl;

      // get max seg/path frac out of paths within minimum dist
      int max_segfrac_idx = -1;
      float max_segfrac = 0.;
      for (size_t ipath=0; ipath<pathlen_v.size(); ipath++ ) {
        if ( fabs(pathlen_v[ipath]-minpathlen) < 20.0 ) {
          float segfrac = seglen_v[ipath]/pathlen_v[ipath];
          if ( segfrac>max_segfrac ) {
            max_segfrac = segfrac;
            max_segfrac_idx = ipath;
          }
        }
      }
      //std::cout << " Leaf sub-group maxsegfrac=" << max_segfrac <<" pathidx=" << max_segfrac_idx << std::endl;
      selected_v.push_back( it->second.at(max_segfrac_idx) );
      selected_pathlen_v.push_back( pathlen_v[max_segfrac_idx] );

      // store path/dist ratio
      Path_t* leafpath = it->second.at(max_segfrac_idx);


      float end_dist = 0.;
      for (int v=0; v<3; v++) {
        float dx = leafpath->front()->pos[v] - leafpath->back()->pos[v];
        end_dist += dx*dx;
      }
      end_dist = sqrt(end_dist);
      selected_enddist_v.push_back( end_dist );

      float pathdist_ratio = 0.;
      if ( end_dist>0 ) {
        pathdist_ratio = pathlen_v[max_segfrac_idx]/end_dist;
      }
      path_dist_ratio_v.push_back( pathdist_ratio );


      if ( pathdist_ratio>0 && pathdist_ratio<min_pathdist_ratio ) {
        min_pathdist_ratio = pathdist_ratio;
      }

      //std::cout << "  Leafgroup["  << it->first << "] best path dist between ends: " << end_dist << std::endl;

      //std::cout << "=== End of Leafgroup[" << it->first << "] selection path/dist ratio: " << pathdist_ratio << " len=" << pathlen_v[max_segfrac_idx] << " ===" << std::endl;
    }//end of group loop

    // so far we've chosen best path from seed point to leaf point,
    // now choose among leaf points, if _one_track_per_startpoint is true.

    if ( _one_track_per_startpoint ) {
      // choose among the best of the best?
      // the minimum ratio of path-length to
      float min_track_path_dist_ratio = 1e9;
      float max_track_dist = 0.;
      int min_max_len_idx = -1;
      for ( size_t i=0; i<selected_v.size(); i++ ) {
        if ( path_dist_ratio_v[i]>=1.0 && path_dist_ratio_v[i]<min_pathdist_ratio+0.2 ) {
          // if ( min_track_path_dist_ratio>path_dist_ratio_v[i] ) {
          //   min_max_len_idx = i;
          //   min_track_path_dist_ratio = path_dist_ratio_v[i];
          // }
          if ( max_track_dist<selected_enddist_v[i] ) {
            max_track_dist = selected_enddist_v[i];
            min_max_len_idx = i;
        }
        }
      }

      if ( min_max_len_idx>=0 ) {
        filtered_v.push_back( *selected_v[min_max_len_idx] );
      }
    }
    else {
      // allow us to return a collection of paths from the same start point to many different leaves
      for ( auto& ppath : selected_v )
        filtered_v.push_back ( *ppath );
      std::cout << "Number of leaf-group candidate tracks return: " << (int)filtered_v.size()-nfiltered_before << std::endl;
    }

  }

  void TrackClusterBuilder::fillLarliteTrackContainer( larlite::event_track& evout_track )
  {

    for ( size_t itrack=0; itrack<_track_proposal_v.size(); itrack++ ) {

      auto const& path = _track_proposal_v[itrack];

      if ( path.size()<=1 )
        continue;

      larlite::track lltrack;
      lltrack.reserve(path.size()); // npts = 2*num seg;

      std::vector<float> last_seg_dir(3,0);
      for (int inode=1; inode<path.size(); inode++ ) {

        const NodePos_t* node     = path[inode];
        const NodePos_t* nodeprev = path[inode-1];
        float d = 0.;
        for (int v=0; v<3; v++) {
          last_seg_dir[v] = node->pos[v]-nodeprev->pos[v];
          d += last_seg_dir[v]*last_seg_dir[v];
        }
        d = sqrt(d);
        if ( d>0 ) {
          for (int v=0; v<3; v++)
            last_seg_dir[v] /= d;
        }

        lltrack.add_vertex( TVector3(nodeprev->pos[0],nodeprev->pos[1], nodeprev->pos[2]) );
        lltrack.add_direction( TVector3(last_seg_dir[0],last_seg_dir[1], last_seg_dir[2]) );

        if ( inode+1==(int)path.size() ) {
          lltrack.add_vertex( TVector3(node->pos[0],node->pos[1], node->pos[2]) );
          lltrack.add_direction( TVector3(last_seg_dir[0],last_seg_dir[1], last_seg_dir[2]) );
        }

      }//end of loop over nodes

      evout_track.emplace_back( std::move(lltrack) );
    }//end of loop over tracks

  }

  void TrackClusterBuilder::_buildTracksFromSegments()
  {

    // mark segments used
    int unused = 0;
    std::vector<int> used_v( _segment_v.size(), 0 );
    for ( auto const& path : _track_proposal_v ) {
      for ( auto const& pnode : path ) {
        used_v[ pnode->segidx ] = 1;
      }
    }

    // make seginfo
    struct UnusedSeg_t {
      int segidx;
      float dwall;
      std::vector<float> pos;
      bool operator<( const UnusedSeg_t& rhs ) const {
        if ( dwall<rhs.dwall ) return true;
        return false;
      };
    };

    std::vector< UnusedSeg_t > seglist_v;
    seglist_v.reserve( _segment_v.size() );

    for ( int iseg=0; iseg<(int)used_v.size(); iseg++ ) {
      if ( used_v[iseg]==1 ) continue;
      UnusedSeg_t seginfo;
      seginfo.segidx = iseg;

      int btype1 = 0;
      int btype2 = 0;
      float dwall1 = ublarcvapp::dwall_noAC( _segment_v[iseg].start, btype1 );
      float dwall2 = ublarcvapp::dwall_noAC( _segment_v[iseg].end,   btype2 );

      seginfo.dwall =  ( dwall1<dwall2 ) ? dwall1: dwall2;
      if ( dwall1<dwall2 ) {
        seginfo.pos = _segment_v[iseg].start;
      }
      else {
        seginfo.pos = _segment_v[iseg].end;
      }
      seglist_v.push_back( seginfo );
    }

    std::sort( seglist_v.begin(), seglist_v.end() );
    LARCV_DEBUG() << "number of (sorted) unused segments: " << seglist_v.size() << std::endl;

    bool something2run = true;
    int nsegtracks_made = 0;
    while (something2run) {

      // choose which segment to run
      something2run = false;
      UnusedSeg_t* seg2run = nullptr;

      for ( auto& seginfo : seglist_v ) {
        if ( seginfo.dwall < 30.0 && used_v[seginfo.segidx]==0 ) {
          // unused
          seg2run = &seginfo;
          something2run = true;
          break;
        }
      }

      // nothing to run
      if ( something2run ) {
        // number of tracks already made
        LARCV_DEBUG() << "Make track from segment[" << seg2run->segidx << "] dwall=" << seg2run->dwall
                      << " pos=(" << seg2run->pos[0] << "," << seg2run->pos[1] << "," << seg2run->pos[2] << ")"
                      << std::endl;


        int ntracksmade = _track_proposal_v.size();
        buildTracksFromPoint( seg2run->pos );
        used_v[seg2run->segidx] = 1;

        // number of tracks made
        int nmade = (int)_track_proposal_v.size()-ntracksmade;
        nsegtracks_made += nmade;
        for ( int itrack=ntracksmade; itrack<(int)_track_proposal_v.size(); itrack++ ) {
          auto& path = _track_proposal_v.at(itrack);
          for ( auto &pnode : path ) {
            used_v[pnode->segidx] = 1;
          }
        }
      }
      else {
        LARCV_DEBUG() << "No segment to run" << std::endl;
      }
      LARCV_DEBUG() << "[entry to continue]" << std::endl;
      //std::cin.get();
    }

    LARCV_DEBUG() << "number of tracks made via segment seeds: " << nsegtracks_made << std::endl;

  }

}
}