int PHG4HoughTransformTPC::InitializeGeometry(PHCompositeNode *topNode) {

  //---------------------------------------------------------
  // Grab Run-Dependent Detector Geometry and Configure Hough
  //---------------------------------------------------------

  bool default_geo = false;
  
  PHG4CylinderCellGeomContainer* cellgeos = findNode::getClass<PHG4CylinderCellGeomContainer>(topNode,"CYLINDERCELLGEOM_SVTX");
  PHG4CylinderGeomContainer* laddergeos = findNode::getClass<PHG4CylinderGeomContainer>(topNode,"CYLINDERGEOM_SILICON_TRACKER");
  //PHG4CylinderCellContainer* cells = findNode::getClass<PHG4CylinderCellContainer>(topNode,"G4CELL_SVTX");
  
  if (cellgeos||laddergeos) {
    unsigned int ncelllayers = 0;
    if (cellgeos) ncelllayers += cellgeos->get_NLayers();
    unsigned int nladderlayers = 0;
    if (laddergeos) nladderlayers += laddergeos->get_NLayers();
    _nlayers = ncelllayers + nladderlayers;
    default_geo = false;
  } else {
    cerr << PHWHERE
	 << "Neither CYLINDERCELLGEOM_SVTX nor CYLINDERGEOM_SILICON_TRACKER available, reverting to a default geometry"
	 << std::endl;    
    _nlayers = 6;
    default_geo = true;
  }

  //=================================================//                                                                                                      
  //  Initializing HelixHough objects                //                                                                                                      
  //=================================================//                                                                                            

  _radii.assign(_nlayers, 0.0);
  _smear_xy_layer.assign(_nlayers, 0.0);
  _smear_z_layer.assign(_nlayers, 0.0);
  float sqrt_12 = sqrt(12.);
	
  if (default_geo) {

    // default geometry
    _radii[0] = 2.5;
    _radii[1] = 5.0;
    _radii[2] = 10.0;
    _radii[3] = 14.0;
    _radii[4] = 40.0;
    _radii[5] = 60.0;
    
    _smear_xy_layer[0] = (50.0e-4/sqrt_12);
    _smear_z_layer[0] = (425.0e-4/sqrt_12);
    _smear_xy_layer[1] = (50.0e-4/sqrt_12);
    _smear_z_layer[1] = (425.0e-4/sqrt_12);
    _smear_xy_layer[2] = (80.0e-4/sqrt_12);
    _smear_z_layer[2] = (1000.0e-4/sqrt_12);
    _smear_xy_layer[3] = (80.0e-4/sqrt_12);
    _smear_z_layer[3] = (1000.0e-4/sqrt_12);
    
    for(int il=4; il<_nlayers; ++il) {
      _smear_xy_layer[il] = (80.0e-4/sqrt_12);
      _smear_z_layer[il] = (30000.0e-4/sqrt_12);
    }

    _layer_ilayer_map.clear();
    for (int ilayer = 0; ilayer < _nlayers; ++ilayer) {
      _layer_ilayer_map.insert(make_pair(ilayer,ilayer));
    }
    
  } else {

    // Since the G4 layers don't necessarily correspond to the
    // silicon layers, and don't necessarily start from zero (argh),
    // we create our own layers numbers that are consecutive
    // starting from zero.

    // Now that we have two kinds of layers, I won't know in principle
    // which type is in what order, so I figure that out now...
    
    map<float,int> radius_layer_map;

    if (cellgeos) {
      PHG4CylinderCellGeomContainer::ConstRange layerrange = cellgeos->get_begin_end();
      for(PHG4CylinderCellGeomContainer::ConstIterator layeriter = layerrange.first;
	  layeriter != layerrange.second;
	  ++layeriter) {
	radius_layer_map.insert( make_pair(layeriter->second->get_radius(),
					   layeriter->second->get_layer()) );
      }
    }

    if (laddergeos) {
      PHG4CylinderGeomContainer::ConstRange layerrange = laddergeos->get_begin_end();
      for(PHG4CylinderGeomContainer::ConstIterator layeriter = layerrange.first;
	  layeriter != layerrange.second;
	  ++layeriter) {
	radius_layer_map.insert( make_pair(layeriter->second->get_radius(),
					   layeriter->second->get_layer()) );
      }
    }

    // now that the layer ids are sorted by radius, I can create a storage
    // index, ilayer, that is 0..N-1 and sorted by radius
    
    int ilayer = 0;
    for(map<float,int>::iterator iter = radius_layer_map.begin();
	iter != radius_layer_map.end();
	++iter) {
      _layer_ilayer_map.insert( make_pair(iter->second,ilayer) );
      ++ilayer;
    }   

    // now we extract the information from the cellgeos first
    if (cellgeos) {    
      PHG4CylinderCellGeomContainer::ConstRange begin_end = cellgeos->get_begin_end();
      PHG4CylinderCellGeomContainer::ConstIterator miter = begin_end.first;
      for( ; miter != begin_end.second; miter++) {
	PHG4CylinderCellGeom *cellgeo = miter->second;
      
	if (verbosity > 1) cellgeo->identify();

	_radii[_layer_ilayer_map[cellgeo->get_layer()]] = cellgeo->get_radius();      
	_smear_xy_layer[_layer_ilayer_map[cellgeo->get_layer()]] = cellgeo->get_radius()*cellgeo->get_phistep();
	_smear_z_layer[_layer_ilayer_map[cellgeo->get_layer()]] = cellgeo->get_zstep();     
      }
    }

    if (laddergeos) {    
      PHG4CylinderGeomContainer::ConstRange begin_end = laddergeos->get_begin_end();
      PHG4CylinderGeomContainer::ConstIterator miter = begin_end.first;
      for( ; miter != begin_end.second; miter++) {
	PHG4CylinderGeom *geo = miter->second;
	
	if (verbosity > 1) geo->identify();
	
	_radii[_layer_ilayer_map[geo->get_layer()]] = geo->get_radius();      
	_smear_xy_layer[_layer_ilayer_map[geo->get_layer()]] = geo->get_strip_y_spacing();
	_smear_z_layer[_layer_ilayer_map[geo->get_layer()]] = geo->get_strip_z_spacing();     
      }
    }
  }  

  // set material on each layer
  
  _material.assign(_radii.size(), 0.03);

  map<int, float>::iterator mat_it;
  for (map<int, float>::iterator iter = _user_material.begin();
       iter != _user_material.end();
       ++iter) {
    _material[_layer_ilayer_map[iter->first]] = iter->second;
  }

  float kappa_max = ptToKappa(_min_pT);

  HelixRange top_range( 0.0, 2.*M_PI,
		       -0.2, 0.2,
			0.0, kappa_max,
		       -0.9, 0.9,
		       -1.0*_dcaz_cut, 1.0*_dcaz_cut);
  if (!_use_vertex) {
    top_range.min_z0 = -10.;
    top_range.max_z0 = 10.;
  }
  
  vector<unsigned int> onezoom(5,0);
  vector<vector<unsigned int> > zoomprofile;
  zoomprofile.assign(3,onezoom);
  zoomprofile[0][0] = 16;
  zoomprofile[0][1] = 1;
  zoomprofile[0][2] = 4;
  zoomprofile[0][3] = 8;
  zoomprofile[0][4] = 1;
  
  zoomprofile[1][0] = 16;
  zoomprofile[1][1] = 1;
  zoomprofile[1][2] = 4;
  zoomprofile[1][3] = 4;
  zoomprofile[1][4] = 1;
  
  zoomprofile[2][0] = 4;
  zoomprofile[2][1] = 2;
  zoomprofile[2][2] = 2;
  zoomprofile[2][3] = 2;
  zoomprofile[2][4] = 2;
  
  // for (unsigned int i = 3; i <= 4; ++i) {
  //   zoomprofile[i][0] = 4;
  //   zoomprofile[i][1] = 2;
  //   zoomprofile[i][2] = 2;
  //   zoomprofile[i][3] = 3;
  //   zoomprofile[i][4] = 2;
  // }
    
  _tracker = new sPHENIXTracker(zoomprofile, 1, top_range, _material, _radii, _magField);
  _tracker->setIterateClustering(true);
  _tracker->setNLayers(_seed_layers);
  _tracker->requireLayers(_req_seed);
  _max_hits_init = _seed_layers*4;
  if(_seed_layers >= 10){_max_hits_init = _seed_layers*2;}
  _min_hits_init = _req_seed;
  if(_seed_layers < 10){ _tracker->setClusterStartBin(1); }
  else{ _tracker->setClusterStartBin(10); }
  _tracker->setRejectGhosts(_reject_ghosts);
  _tracker->setFastChi2Cut(_chi2_cut_fast_par0,
			   _chi2_cut_fast_par1,
			   _chi2_cut_fast_max);
  _tracker->setChi2Cut(_chi2_cut_full);
  _tracker->setChi2RemovalCut(_chi2_cut_full*0.5);
  _tracker->setCellularAutomatonChi2Cut(_ca_chi2_cut);
  _tracker->setPrintTimings(false);
  if(verbosity > 3){_tracker->setPrintTimings(true);}
  _tracker->setVerbosity(verbosity);
  _tracker->setCutOnDca(_cut_on_dca);
  _tracker->setDcaCut(_dca_cut);
  _tracker->setSmoothBack(false);
  _tracker->setBinScale(_bin_scale);
  _tracker->setZBinScale(_z_bin_scale);
  _tracker->setRemoveHits(_remove_hits);
  _tracker->setSeparateByHelicity(true);
  _tracker->setMaxHitsPairs(0);
  _tracker->setCosAngleCut(_cos_angle_cut);
  
  
  vector<vector<unsigned int> > zoomprofile_init;
  zoomprofile_init.assign(4,onezoom);
  for(unsigned int i=0;i<=1;++i)
  {
    zoomprofile_init[i][0] = 8;
    zoomprofile_init[i][1] = 1;
    zoomprofile_init[i][2] = 3;
    zoomprofile_init[i][3] = 4;
    zoomprofile_init[i][4] = 4;
  }
  for(unsigned int i=2;i<=3;++i)
  {
    zoomprofile_init[i][0] = 8;
    zoomprofile_init[i][1] = 1;
    zoomprofile_init[i][2] = 2;
    zoomprofile_init[i][3] = 2;
    zoomprofile_init[i][4] = 2;
  }
  vector<HelixRange> top_range_init;
  unsigned int nphi = 1;
  unsigned int nz0 = 5;
  double phimin = 0.;
  double phi_step = 2.0*M_PI/((double)nphi);
  float kappa_max_init = ptToKappa(_min_pT_init);
  for(unsigned int i=0;i<nphi;++i)
  {
    double z0min = -10.;
    double z0_step = 20./((double)nz0);
    for(unsigned int j=0;j<nz0;++j)
    {
      top_range_init.push_back(HelixRange(phimin, phimin+phi_step,   -0.2, 0.2,   0.0, kappa_max_init,   -0.9, 0.9,   z0min, z0min+z0_step));
      _tracker_vertex.push_back( new sPHENIXTracker(zoomprofile_init, 1, top_range_init.back(), _material, _radii, _magField) );
      if(verbosity > 3){(_tracker_vertex.back())->setPrintTimings(true);}
      (_tracker_vertex.back())->setVerbosity(verbosity);
      (_tracker_vertex.back())->setNLayers(_seed_layers);
      (_tracker_vertex.back())->requireLayers(_req_seed);
      (_tracker_vertex.back())->setClusterStartBin(1);
      (_tracker_vertex.back())->setRejectGhosts(true);
      (_tracker_vertex.back())->setFastChi2Cut(_chi2_cut_fast_par0,
					       _chi2_cut_fast_par1,
					       _chi2_cut_fast_max);
      (_tracker_vertex.back())->setChi2Cut(_chi2_cut_init);
      (_tracker_vertex.back())->setChi2RemovalCut(_chi2_cut_init*0.5);
      (_tracker_vertex.back())->setCellularAutomatonChi2Cut(_ca_chi2_cut);
      (_tracker_vertex.back())->setCutOnDca(false);
      (_tracker_vertex.back())->setSmoothBack(true);
      (_tracker_vertex.back())->setBinScale(_bin_scale);
      (_tracker_vertex.back())->setZBinScale(_z_bin_scale);
      (_tracker_vertex.back())->setRemoveHits(false);
      (_tracker_vertex.back())->setSeparateByHelicity(true);
      (_tracker_vertex.back())->setMaxHitsPairs(0);
      (_tracker_vertex.back())->setCosAngleCut(_cos_angle_cut);
      z0min += z0_step;
    }
    phimin += phi_step;
  }
  
  for(unsigned int ilayer = 0; ilayer < _fit_error_scale.size(); ++ilayer) {
    float scale1 = _fit_error_scale[ilayer];
    float scale2 = _vote_error_scale[ilayer];
    float scale = scale1/scale2;
    _tracker->setHitErrorScale(ilayer, scale);
    for(unsigned int j = 0; j < _tracker_vertex.size(); ++j) {
      _tracker_vertex[j]->setHitErrorScale(ilayer, scale);
    }
  }
  
  return Fun4AllReturnCodes::EVENT_OK;
}
void PHG4SvtxClusterizer::ClusterCylinderCells(PHCompositeNode *topNode) {

  //----------
  // Get Nodes
  //----------

  // get the SVX geometry object
  PHG4CylinderCellGeomContainer* geom_container = findNode::getClass<PHG4CylinderCellGeomContainer>(topNode,"CYLINDERCELLGEOM_SVTX");
  if (!geom_container) return;
  
  PHG4HitContainer* g4hits = findNode::getClass<PHG4HitContainer>(topNode,"G4HIT_SVTX");
  if (!g4hits) return;
  
  PHG4CylinderCellContainer* cells = findNode::getClass<PHG4CylinderCellContainer>(topNode,"G4CELL_SVTX");
  if (!cells) return; 
  
  //-----------
  // Clustering
  //-----------

  // sort hits layer by layer
  std::multimap<int,SvtxHit*> layer_hits_mmap;  
  for (SvtxHitMap::Iter iter = _hits->begin();
       iter != _hits->end();
       ++iter) {
    SvtxHit* hit = &iter->second;
    layer_hits_mmap.insert(make_pair(hit->get_layer(),hit));
  }
  
  // loop over cylinder layers
  PHG4CylinderCellGeomContainer::ConstRange layerrange = geom_container->get_begin_end();
  for(PHG4CylinderCellGeomContainer::ConstIterator layeriter = layerrange.first;
      layeriter != layerrange.second;
      ++layeriter) {

    int layer = layeriter->second->get_layer();
    int nphibins = layeriter->second->get_phibins();

    // loop over all hits/cells in this layer
    std::map<PHG4CylinderCell*,SvtxHit*> cell_hit_map;
    std::vector<PHG4CylinderCell*> cell_list;   
    for (std::multimap<int,SvtxHit*>::iterator hiter = layer_hits_mmap.lower_bound(layer);
	 hiter != layer_hits_mmap.upper_bound(layer);
	 ++hiter) {
      SvtxHit* hit = hiter->second;
      PHG4CylinderCell* cell = cells->findCylinderCell(hit->get_cellid());
      cell_list.push_back(cell);
      cell_hit_map.insert(make_pair(cell,hit));
    }

    if (cell_list.size() == 0) continue; // if no cells, go to the next layer
    
    sort(cell_list.begin(), cell_list.end(), PHG4SvtxClusterizer::lessthan);

    typedef adjacency_list <vecS, vecS, undirectedS> Graph;
    typedef graph_traits<Graph>::vertex_descriptor Vertex;
    Graph G;

    for(unsigned int i=0; i<cell_list.size(); i++) {
      for(unsigned int j=i+1; j<cell_list.size(); j++) {
        if( are_adjacent(cell_list[i], cell_list[j], nphibins) )
          add_edge(i,j,G);
      }
      
      add_edge(i,i,G);
    }

    // Find the connections between the vertices of the graph (vertices are the rawhits, 
    // connections are made when they are adjacent to one another)
    vector<int> component(num_vertices(G));
    
    // this is the actual clustering, performed by boost
    connected_components(G, &component[0]); 

    // Loop over the components(hit cells) compiling a list of the
    // unique connected groups (ie. clusters).
    set<int> cluster_ids; // unique components       
    multimap<int, PHG4CylinderCell*> clusters;
    for (unsigned int i=0; i<component.size(); i++) {
      cluster_ids.insert( component[i] );
      clusters.insert( make_pair(component[i], cell_list[i]) );
    }
    
    typedef multimap<int, PHG4CylinderCell*>::iterator mapiterator;
    
    for (set<int>::iterator clusiter = cluster_ids.begin(); 
	 clusiter != cluster_ids.end(); 
	 clusiter++ ) {
      
      int clusid = *clusiter;
      pair<mapiterator,mapiterator> clusrange = clusters.equal_range(clusid);
      
      mapiterator mapiter = clusrange.first;
      
      int layer = mapiter->second->get_layer();
      PHG4CylinderCellGeom* geom = geom_container->GetLayerCellGeom(layer);
      
      SvtxCluster clus;
      clus.set_layer( layer );
      float clus_energy = 0.0;
      unsigned int clus_adc = 0;

      // determine the size of the cluster in phi and z
      // useful for track fitting the cluster

      set<int> phibins;
      set<int> zbins;
      for (mapiter = clusrange.first; mapiter != clusrange.second; mapiter++ ) {
	PHG4CylinderCell* cell = mapiter->second;     
	
	phibins.insert(cell->get_binphi());
	zbins.insert(cell->get_binz());
      }
      
      float pitch = geom->get_phistep()*geom->get_radius();
      float thickness = geom->get_thickness();
      float length = geom->get_zstep();
      float phisize = phibins.size()*pitch;
      float zsize = zbins.size()*length;

      double xsum = 0.0;
      double ysum = 0.0;
      double zsum = 0.0;
      unsigned int nhits = 0;

      for(mapiter = clusrange.first; mapiter != clusrange.second; mapiter++ ) {
        PHG4CylinderCell* cell = mapiter->second;
	SvtxHit* hit = cell_hit_map[cell];
	
	clus.insert_hit(hit->get_id());
	
        clus_energy += hit->get_e();
	clus_adc    += hit->get_adc();

	// compute the hit center
	double r   = geom->get_radius();
        double phi = geom->get_phicenter(cell->get_binphi());

	double x = r*cos(phi);
	double y = r*sin(phi);
        double z = geom->get_zcenter(cell->get_binz());

	if (_make_e_weights[layer]) {
	  xsum += x * hit->get_adc();
	  ysum += y * hit->get_adc();
	  zsum += z * hit->get_adc();  
	} else {
	  xsum += x;
	  ysum += y;
	  zsum += z;
	}
	++nhits;
      }
      
      double clusx = NAN;
      double clusy = NAN;
      double clusz = NAN;

      if (_make_e_weights[layer]) {
	clusx = xsum / clus_adc;
	clusy = ysum / clus_adc;
	clusz = zsum / clus_adc;	
      } else {
	clusx = xsum / nhits;
	clusy = ysum / nhits;
	clusz = zsum / nhits;
      }
      
      double radius  = sqrt(clusx*clusx+clusy*clusy);
      double clusphi = atan2( clusy, clusx);
       
      clus.set_position( 0 , clusx );
      clus.set_position( 1 , clusy );
      clus.set_position( 2 , clusz );

      clus.set_e(clus_energy);
      clus.set_adc(clus_adc);

      float invsqrt12 = 1.0/sqrt(12.);
      
      TMatrixF DIM(3,3);
      DIM[0][0] = pow(0.5*thickness,2);
      DIM[0][1] = 0.0;
      DIM[0][2] = 0.0;
      DIM[1][0] = 0.0;
      DIM[1][1] = pow(0.5*phisize,2);
      DIM[1][2] = 0.0;
      DIM[2][0] = 0.0;
      DIM[2][1] = 0.0;
      DIM[2][2] = pow(0.5*zsize,2);

      TMatrixF ERR(3,3);
      ERR[0][0] = pow(0.5*thickness*invsqrt12,2);
      ERR[0][1] = 0.0;
      ERR[0][2] = 0.0;
      ERR[1][0] = 0.0;
      ERR[1][1] = pow(0.5*phisize*invsqrt12,2);
      ERR[1][2] = 0.0;
      ERR[2][0] = 0.0;
      ERR[2][1] = 0.0;
      ERR[2][2] = pow(0.5*zsize*invsqrt12,2);

      TMatrixF ROT(3,3);
      ROT[0][0] = cos(clusphi);
      ROT[0][1] = -sin(clusphi);
      ROT[0][2] = 0.0;
      ROT[1][0] = sin(clusphi);
      ROT[1][1] = cos(clusphi);
      ROT[1][2] = 0.0;
      ROT[2][0] = 0.0;
      ROT[2][1] = 0.0;
      ROT[2][2] = 1.0;

      TMatrixF ROT_T(3,3);
      ROT_T.Transpose(ROT);
      
      TMatrixF COVAR_DIM(3,3);
      COVAR_DIM = ROT * DIM * ROT_T;
      
      clus.set_size( 0 , 0 , COVAR_DIM[0][0] );
      clus.set_size( 0 , 1 , COVAR_DIM[0][1] );
      clus.set_size( 0 , 2 , COVAR_DIM[0][2] );
      clus.set_size( 1 , 0 , COVAR_DIM[1][0] );
      clus.set_size( 1 , 1 , COVAR_DIM[1][1] );
      clus.set_size( 1 , 2 , COVAR_DIM[1][2] );
      clus.set_size( 2 , 0 , COVAR_DIM[2][0] );
      clus.set_size( 2 , 1 , COVAR_DIM[2][1] );
      clus.set_size( 2 , 2 , COVAR_DIM[2][2] );

      TMatrixF COVAR_ERR(3,3);
      COVAR_ERR = ROT * ERR * ROT_T;

      clus.set_error( 0 , 0 , COVAR_ERR[0][0] );
      clus.set_error( 0 , 1 , COVAR_ERR[0][1] );
      clus.set_error( 0 , 2 , COVAR_ERR[0][2] );
      clus.set_error( 1 , 0 , COVAR_ERR[1][0] );
      clus.set_error( 1 , 1 , COVAR_ERR[1][1] );
      clus.set_error( 1 , 2 , COVAR_ERR[1][2] );
      clus.set_error( 2 , 0 , COVAR_ERR[2][0] );
      clus.set_error( 2 , 1 , COVAR_ERR[2][1] );
      clus.set_error( 2 , 2 , COVAR_ERR[2][2] );
      
      if (clus_energy > get_threshold_by_layer(layer)) {
	SvtxCluster* ptr = _clusterlist->insert(clus);
	if (!ptr->IsValid()) {
	  static bool first = true;
	  if (first) {
	    cout << PHWHERE << "ERROR: Invalid SvtxClusters are being produced" << endl;
	    ptr->identify();
	    first = false;
	  }
	}
	
	if (verbosity>1) {
	  cout << "r=" << radius << " phi=" << clusphi << " z=" << clusz << endl;
	  cout << "pos=(" << clus.get_position(0) << ", " << clus.get_position(1)
	       << ", " << clus.get_position(2) << ")" << endl;
	  cout << endl;
	}
      }	else if (verbosity>1) {
	cout << "removed r=" << radius << " phi=" << clusphi << " z=" << clusz << endl;
	cout << "pos=(" << clus.get_position(0) << ", " << clus.get_position(1)
	     << ", " << clus.get_position(2) << ")" << endl;
	cout << endl;
      } 
    }
  }
  
  return;
}
int PHG4HoughTransform::InitializeGeometry(PHCompositeNode *topNode) {

  //---------------------------------------------------------
  // Grab Run-Dependent Detector Geometry and Configure Hough
  //---------------------------------------------------------

  PHG4CylinderCellGeomContainer* cellgeos =
      findNode::getClass<PHG4CylinderCellGeomContainer>(
          topNode, "CYLINDERCELLGEOM_SVTX");
  PHG4CylinderGeomContainer* laddergeos =
      findNode::getClass<PHG4CylinderGeomContainer>(
          topNode, "CYLINDERGEOM_SILICON_TRACKER");
  PHG4CylinderGeomContainer* mapsladdergeos =
      findNode::getClass<PHG4CylinderGeomContainer>(
          topNode, "CYLINDERGEOM_MAPS");

  if (cellgeos || laddergeos || mapsladdergeos) {
    unsigned int ncelllayers = 0;
    if (cellgeos) ncelllayers += cellgeos->get_NLayers();
    unsigned int nladderlayers = 0;
    if (laddergeos) nladderlayers += laddergeos->get_NLayers();
    unsigned int nmapsladderlayers = 0;
    if (mapsladdergeos) nmapsladderlayers += mapsladdergeos->get_NLayers();
    _nlayers = ncelllayers + nladderlayers + nmapsladderlayers;
  } else {
    cerr << PHWHERE
         << "None of  CYLINDERCELLGEOM_SVTX or CYLINDERGEOM_SILICON_TRACKER or CYLINDERGEOM_MAPS"
            "available, bail"
         << std::endl;
    return Fun4AllReturnCodes::ABORTRUN;
  }

  //=================================================//
  //  Initializing HelixHough objects                //
  //=================================================//
  	
  // Since the G4 layers don't necessarily correspond to the
  // silicon layers, and don't necessarily start from zero (argh),
  // we create our own layers numbers that are consecutive
  // starting from zero.

  // Now that we have two kinds of layers, I won't know in principle
  // which type is in what order, so I figure that out now...

  _radii.assign(_nlayers, 0.0);    
  map<float,int> radius_layer_map;

  if (cellgeos) {
    PHG4CylinderCellGeomContainer::ConstRange layerrange = cellgeos->get_begin_end();
    for(PHG4CylinderCellGeomContainer::ConstIterator layeriter = layerrange.first;
	layeriter != layerrange.second;
	++layeriter) {
      radius_layer_map.insert( make_pair(layeriter->second->get_radius(),
					 layeriter->second->get_layer()) );
    }
  }

  if (laddergeos) {
    PHG4CylinderGeomContainer::ConstRange layerrange = laddergeos->get_begin_end();
    for(PHG4CylinderGeomContainer::ConstIterator layeriter = layerrange.first;
	layeriter != layerrange.second;
	++layeriter) {
      radius_layer_map.insert( make_pair(layeriter->second->get_radius(),
					 layeriter->second->get_layer()) );
    }
  }

  if (mapsladdergeos) {
    PHG4CylinderGeomContainer::ConstRange layerrange = mapsladdergeos->get_begin_end();
    for(PHG4CylinderGeomContainer::ConstIterator layeriter = layerrange.first;
	layeriter != layerrange.second;
	++layeriter) {
      radius_layer_map.insert( make_pair(layeriter->second->get_radius(),
					 layeriter->second->get_layer()) );
    }
  }

  // now that the layer ids are sorted by radius, I can create a storage
  // index, ilayer, that is 0..N-1 and sorted by radius
  
  int ilayer = 0;
  for(map<float,int>::iterator iter = radius_layer_map.begin();
      iter != radius_layer_map.end();
      ++iter) {
    _layer_ilayer_map.insert( make_pair(iter->second,ilayer) );
    ++ilayer;
  }   

  // now we extract the information from the cellgeos first
  if (cellgeos) {    
    PHG4CylinderCellGeomContainer::ConstRange begin_end = cellgeos->get_begin_end();
    PHG4CylinderCellGeomContainer::ConstIterator miter = begin_end.first;
    for( ; miter != begin_end.second; miter++) {
      PHG4CylinderCellGeom *cellgeo = miter->second;
      
      if (verbosity > 1) cellgeo->identify();
      
      _radii[_layer_ilayer_map[cellgeo->get_layer()]] = cellgeo->get_radius();      
    }
  }

  if (laddergeos) {    
    PHG4CylinderGeomContainer::ConstRange begin_end = laddergeos->get_begin_end();
    PHG4CylinderGeomContainer::ConstIterator miter = begin_end.first;
    for( ; miter != begin_end.second; miter++) {
      PHG4CylinderGeom *geo = miter->second;
      
      if (verbosity > 1) geo->identify();
      
      _radii[_layer_ilayer_map[geo->get_layer()]] = geo->get_radius();      
    }
  }

  if (mapsladdergeos) {    
    PHG4CylinderGeomContainer::ConstRange begin_end = mapsladdergeos->get_begin_end();
    PHG4CylinderGeomContainer::ConstIterator miter = begin_end.first;
    for( ; miter != begin_end.second; miter++) {
      PHG4CylinderGeom *geo = miter->second;
      
      if (verbosity > 1) geo->identify();
      
      _radii[_layer_ilayer_map[geo->get_layer()]] = geo->get_radius();      
    }
  }

  // set material on each layer
  
  _material.assign(_radii.size(), 0.03);

  map<int, float>::iterator mat_it;
  for (map<int, float>::iterator iter = _user_material.begin();
       iter != _user_material.end();
       ++iter) {
    _material[_layer_ilayer_map[iter->first]] = iter->second;
  }

  // initialize the pattern recogition tools

  setup_tracker_object();
  setup_initial_tracker_object();
  setup_seed_tracker_objects();
  
  return Fun4AllReturnCodes::EVENT_OK;
}
int PHG4TPCClusterizer::process_event(PHCompositeNode* topNode) {

  PHNodeIterator iter(topNode);

  PHCompositeNode* dstNode =
      static_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "DST"));
  if (!dstNode) {
    cout << PHWHERE << "DST Node missing, doing nothing." << endl;
    return Fun4AllReturnCodes::ABORTRUN;
  }
  PHNodeIterator iter_dst(dstNode);

  SvtxHitMap* hits = findNode::getClass<SvtxHitMap>(dstNode, "SvtxHitMap");
  if (!hits) {
    cout << PHWHERE << "ERROR: Can't find node SvtxHitMap" << endl;
    return Fun4AllReturnCodes::ABORTRUN;
  }

  PHCompositeNode* svxNode =
      dynamic_cast<PHCompositeNode*>(iter_dst.findFirst("PHCompositeNode", "SVTX"));
  if (!svxNode) {
    svxNode = new PHCompositeNode("SVTX");
    dstNode->addNode(svxNode);
  }

  SvtxClusterMap* svxclusters =
      findNode::getClass<SvtxClusterMap>(dstNode, "SvtxClusterMap");
  if (!svxclusters) {
    svxclusters = new SvtxClusterMap_v1();
    PHIODataNode<PHObject>* SvtxClusterMapNode =
        new PHIODataNode<PHObject>(svxclusters, "SvtxClusterMap", "PHObject");
    svxNode->addNode(SvtxClusterMapNode);
  }

  PHG4CylinderCellGeomContainer* geom_container =
    findNode::getClass<PHG4CylinderCellGeomContainer>(topNode,"CYLINDERCELLGEOM_SVTX");
  if (!geom_container) return Fun4AllReturnCodes::ABORTRUN;

  PHG4CylinderCellContainer* cells =  findNode::getClass<PHG4CylinderCellContainer>(dstNode,"G4CELL_SVTX");
  if (!cells) return Fun4AllReturnCodes::ABORTRUN;

  std::vector<std::vector<const SvtxHit*> > layer_sorted;
  PHG4CylinderCellGeomContainer::ConstRange layerrange = geom_container->get_begin_end();
  for (PHG4CylinderCellGeomContainer::ConstIterator layeriter = layerrange.first;
       layeriter != layerrange.second;
       ++layeriter) {
    // We only need TPC layers here, so skip the layers below _min_layer
    // This if statement is needed because although the maps ladder layers are not included in the cylinder cell geom container, 
    // the cylinder Svx layers are, so they have to be dropped here if they are present
    if( (unsigned int) layeriter->second->get_layer() < _min_layer)
      continue;
    layer_sorted.push_back(std::vector<const SvtxHit*>());
  }
  for (SvtxHitMap::Iter iter = hits->begin(); iter != hits->end(); ++iter) {
    SvtxHit* hit = iter->second;
    if( (unsigned int) hit->get_layer() < _min_layer)
      continue;
    layer_sorted[hit->get_layer() - _min_layer].push_back(hit);
  }
  
  for (PHG4CylinderCellGeomContainer::ConstIterator layeriter =
           layerrange.first;
       layeriter != layerrange.second; ++layeriter) {

    unsigned int layer = (unsigned int)layeriter->second->get_layer();
    
    // exit on the MAPS layers...
    // needed in case cylinder svtx layers are present      
    if (layer < _min_layer) continue;
    if (layer > _max_layer) continue;
    
    PHG4CylinderCellGeom* geo = geom_container->GetLayerCellGeom(layer);
    const int nphibins = layeriter->second->get_phibins();
    const int nzbins = layeriter->second->get_zbins();

    nhits.clear();
    nhits.assign(nzbins, 0);
    amps.clear();
    amps.assign(nphibins * nzbins, 0.);
    cellids.clear();
    cellids.assign(nphibins * nzbins, 0);

    for (unsigned int i = 0; i < layer_sorted[layer - _min_layer].size(); ++i) {

      const SvtxHit* hit = layer_sorted[layer - _min_layer][i];
      if (hit->get_e() <= 0.) continue;
      
      PHG4CylinderCell* cell = cells->findCylinderCell(hit->get_cellid());
      int phibin = cell->get_binphi();
      int zbin = cell->get_binz();
      nhits[zbin] += 1;
      amps[zbin * nphibins + phibin] += hit->get_e();
      cellids[zbin * nphibins + phibin] = hit->get_id();
    }

    int nhits_tot = 0;
    for (int zbin = 0; zbin < nzbins; ++zbin) {
      nhits_tot += nhits[zbin];
    }

    while (nhits_tot > 0) {

      for (int zbin = 0; zbin < nzbins; ++zbin) {

        if (nhits[zbin] <= 0) continue;

        for (int phibin = 0; phibin < nphibins; ++phibin) {

          if (is_local_maximum(amps, nphibins, nzbins, phibin, zbin) == false) {
            continue;
          }

          float phi = 0.;
          float z = 0.;
          float e = 0.;

          fit_cluster(amps, nphibins, nzbins, nhits_tot, nhits, phibin, zbin,
                      geo, phi, z, e);

          if ((layer > 2) && (e < energy_cut)) {
            continue;
          }

          SvtxCluster_v1 clus;
          clus.set_layer(layer);
          clus.set_e(e);
          double radius = geo->get_radius() + 0.5*geo->get_thickness();
          clus.set_position(0, radius * cos(phi));
          clus.set_position(1, radius * sin(phi));
          clus.set_position(2, z);
	  
          clus.insert_hit(cellids[zbin * nphibins + phibin]);

	  float invsqrt12 = 1.0/sqrt(12.);
      
	  TMatrixF DIM(3,3);
	  DIM[0][0] = 0.0;//pow(0.0*0.5*thickness,2);
	  DIM[0][1] = 0.0;
	  DIM[0][2] = 0.0;
	  DIM[1][0] = 0.0;
	  DIM[1][1] = pow(0.5*0.011,2);
	  DIM[1][2] = 0.0;
	  DIM[2][0] = 0.0;
	  DIM[2][1] = 0.0;
	  DIM[2][2] = pow(0.5*0.03,2);

	  TMatrixF ERR(3,3);
	  ERR[0][0] = 0.0;//pow(0.0*0.5*thickness*invsqrt12,2);
	  ERR[0][1] = 0.0;
	  ERR[0][2] = 0.0;
	  ERR[1][0] = 0.0;
	  ERR[1][1] = pow(0.5*0.011*invsqrt12,2);
	  ERR[1][2] = 0.0;
	  ERR[2][0] = 0.0;
	  ERR[2][1] = 0.0;
	  ERR[2][2] = pow(0.5*0.03*invsqrt12,2);

	  TMatrixF ROT(3,3);
	  ROT[0][0] = cos(phi);
	  ROT[0][1] = -sin(phi);
	  ROT[0][2] = 0.0;
	  ROT[1][0] = sin(phi);
	  ROT[1][1] = cos(phi);
	  ROT[1][2] = 0.0;
	  ROT[2][0] = 0.0;
	  ROT[2][1] = 0.0;
	  ROT[2][2] = 1.0;

	  TMatrixF ROT_T(3,3);
	  ROT_T.Transpose(ROT);
      
	  TMatrixF COVAR_DIM(3,3);
	  COVAR_DIM = ROT * DIM * ROT_T;
	  
	  clus.set_size( 0 , 0 , COVAR_DIM[0][0] );
	  clus.set_size( 0 , 1 , COVAR_DIM[0][1] );
	  clus.set_size( 0 , 2 , COVAR_DIM[0][2] );
	  clus.set_size( 1 , 0 , COVAR_DIM[1][0] );
	  clus.set_size( 1 , 1 , COVAR_DIM[1][1] );
	  clus.set_size( 1 , 2 , COVAR_DIM[1][2] );
	  clus.set_size( 2 , 0 , COVAR_DIM[2][0] );
	  clus.set_size( 2 , 1 , COVAR_DIM[2][1] );
	  clus.set_size( 2 , 2 , COVAR_DIM[2][2] );

	  TMatrixF COVAR_ERR(3,3);
	  COVAR_ERR = ROT * ERR * ROT_T;
	  
	  clus.set_error( 0 , 0 , COVAR_ERR[0][0] );
	  clus.set_error( 0 , 1 , COVAR_ERR[0][1] );
	  clus.set_error( 0 , 2 , COVAR_ERR[0][2] );
	  clus.set_error( 1 , 0 , COVAR_ERR[1][0] );
	  clus.set_error( 1 , 1 , COVAR_ERR[1][1] );
	  clus.set_error( 1 , 2 , COVAR_ERR[1][2] );
	  clus.set_error( 2 , 0 , COVAR_ERR[2][0] );
	  clus.set_error( 2 , 1 , COVAR_ERR[2][1] );
	  clus.set_error( 2 , 2 , COVAR_ERR[2][2] );
      
          svxclusters->insert(&clus);
        }
      }
    }
  }

  reset();
  return Fun4AllReturnCodes::EVENT_OK;
}