int
LeptoquarksReco::AddTrackInformation( type_map_tcan& tauCandidateMap, SvtxTrackMap* trackmap, SvtxVertexMap* vertexmap, SvtxEvalStack *svtxevalstack, double R_max )
{
  
  // Pointers for tracks //
  SvtxTrackEval* trackeval = svtxevalstack->get_track_eval();
  SvtxTruthEval* trutheval = svtxevalstack->get_truth_eval();

  /* Loop over tau candidates */
  for (type_map_tcan::iterator iter = tauCandidateMap.begin();
       iter != tauCandidateMap.end();
       ++iter)
    {
      uint tracks_count_r02 = 0;
      int tracks_chargesum_r02 = 0;
      float tracks_rmax_r02 = 0;

      uint tracks_count_r04 = 0;
      int tracks_chargesum_r04 = 0;
      float tracks_rmax_r04 = 0;

      uint tracks_count_R = 0;
      int tracks_chargesum_R = 0;
      float tracks_rmax_R = 0;

      vector<float> tracks_vertex;
      vector<float> temp_vertex;

      float jet_eta = (iter->second)->get_property_float( PidCandidate::jet_eta );
      float jet_phi = (iter->second)->get_property_float( PidCandidate::jet_phi );
      
      /* Loop over tracks
       * (float) track->get_eta(),     //eta of the track
       * (float) track->get_phi(),     //phi of the track
       * (float) track->get_pt(),      //transverse momentum of track
       * (float) track->get_p(),       //total momentum of track
       * (float) track->get_charge(),  //electric charge of track
       * (float) track->get_quality()  //track quality */
  
      //Loop over tracks in event //
    for (SvtxTrackMap::ConstIter track_itr = trackmap->begin();
           track_itr != trackmap->end(); track_itr++) {

        SvtxTrack* track = dynamic_cast<SvtxTrack*>(track_itr->second);

	// Get track variables //
        float track_eta = track->get_eta();
        float track_phi = track->get_phi();
        int track_charge = track->get_charge();
	double gvx,gvy,gvz;
	  
        float delta_R = CalculateDeltaR( track_eta, track_phi, jet_eta, jet_phi );

	PHG4Particle* g4particle = trackeval->max_truth_particle_by_nclusters(track);

	// Get true vertex distances //	  
	PHG4VtxPoint* vtx = trutheval->get_vertex(g4particle);
	gvx = vtx->get_x();
	gvy = vtx->get_y();
	gvz = vtx->get_z();
	

	
	// If charged track is within jet then use its vertex //
	if(delta_R < 0.5 && trutheval->is_primary(g4particle)) tracks_vertex.push_back(sqrt(pow(gvx,2)+pow(gvy,2)+pow(gvz,2)));
	
	/* if save_tracks set true: add track to tree */
        if ( _save_tracks )
          {
            float track_data[17] = {(float) _ievent,
                                    (float) (iter->second)->get_property_uint( PidCandidate::jet_id ),
                                    (float) (iter->second)->get_property_int( PidCandidate::evtgen_pid ),
                                    (float) (iter->second)->get_property_float( PidCandidate::evtgen_etotal ),
                                    (float) (iter->second)->get_property_float( PidCandidate::evtgen_eta ),
                                    (float) (iter->second)->get_property_float( PidCandidate::evtgen_phi ),
                                    (float) (iter->second)->get_property_uint( PidCandidate::evtgen_decay_prong ),
                                    (float) (iter->second)->get_property_uint( PidCandidate::evtgen_decay_hcharged ),
                                    (float) (iter->second)->get_property_uint( PidCandidate::evtgen_decay_lcharged ),
                                    (float) (iter->second)->get_property_float( PidCandidate::jet_eta ),
                                    (float) (iter->second)->get_property_float( PidCandidate::jet_phi ),
                                    (float) (iter->second)->get_property_float( PidCandidate::jet_etotal ),
                                    (float) track->get_quality(),
                                    (float) track_eta,
                                    (float) track_phi,
                                    (float) delta_R,
                                    (float) track->get_p()
            };

            _ntp_track->Fill(track_data);
          }

        /* If track within search cone, update track information for tau candidate */
        if ( delta_R < 0.2 )
          {
            tracks_count_r02++;
            tracks_chargesum_r02 += track_charge;

            if ( delta_R > tracks_rmax_r02 )
              tracks_rmax_r02 = delta_R;
          }

        if ( delta_R < 0.4 )
          {
            tracks_count_r04++;
            tracks_chargesum_r04 += track_charge;

            if ( delta_R > tracks_rmax_r04 )
              tracks_rmax_r04 = delta_R;
          }

	if ( delta_R < R_max )
          {
            tracks_count_R++;
            tracks_chargesum_R += track_charge;

            if ( delta_R > tracks_rmax_R )
              tracks_rmax_R = delta_R;
          }

    } // end loop over reco tracks //
    // sort vertex array in increasing order //
    std::sort(tracks_vertex.begin(),tracks_vertex.end());
    
    // Compute average vertex distance of tracks in jet //
    float avg = Average(tracks_vertex);

    /* Set track-based properties for tau candidate */
      (iter->second)->set_property( PidCandidate::tracks_count_r02, tracks_count_r02 );
      (iter->second)->set_property( PidCandidate::tracks_chargesum_r02, tracks_chargesum_r02 );
      (iter->second)->set_property( PidCandidate::tracks_rmax_r02, tracks_rmax_r02 );
      (iter->second)->set_property( PidCandidate::tracks_count_r04, tracks_count_r04 );
      (iter->second)->set_property( PidCandidate::tracks_chargesum_r04, tracks_chargesum_r04 );
      (iter->second)->set_property( PidCandidate::tracks_rmax_r04, tracks_rmax_r04 );
      (iter->second)->set_property( PidCandidate::tracks_count_R, tracks_count_R );
      (iter->second)->set_property( PidCandidate::tracks_chargesum_R, tracks_chargesum_R );
      (iter->second)->set_property( PidCandidate::tracks_rmax_R, tracks_rmax_R );
      if(avg == avg) (iter->second)->set_property( PidCandidate::tracks_vertex, avg);

    } // end loop over tau  candidates

  return 0;
}
int SimpleTrackingAnalysis::process_event(PHCompositeNode *topNode)
{

  // --- This is the class process_event method
  // --- This is where the bulk of the analysis is done
  // --- Here we get the various data nodes we need to do the analysis
  // --- Then we use variables (accessed through class methods) to perform calculations

  if ( verbosity > -1 )
    {
      cout << endl;
      cout << "------------------------------------------------------------------------------------" << endl;
      cout << "Now processing event number " << nevents << endl; // would be good to add verbosity switch
    }

  ++nevents; // You may as youtself, why ++nevents (pre-increment) rather
  // than nevents++ (post-increment)?  The short answer is performance.
  // For simple types it probably doesn't matter, but it can really help
  // for complex types (like the iterators below).


  // --- Truth level information
  PHG4TruthInfoContainer* truthinfo = findNode::getClass<PHG4TruthInfoContainer>(topNode,"G4TruthInfo");
  if ( !truthinfo )
    {
      cerr << PHWHERE << " ERROR: Can't find G4TruthInfo" << endl;
      exit(-1);
    }

  // --- SvtxTrackMap
  SvtxTrackMap* trackmap = findNode::getClass<SvtxTrackMap>(topNode,"SvtxTrackMap");
  if ( !trackmap )
    {
      cerr << PHWHERE << " ERROR: Can't find SvtxTrackMap" << endl;
      exit(-1);
    }

  // --- SvtxVertexMap
  SvtxVertexMap* vertexmap = findNode::getClass<SvtxVertexMap>(topNode,"SvtxVertexMap");
  if ( !vertexmap )
    {
      cerr << PHWHERE << " ERROR: Can't find SvtxVertexMap" << endl;
      exit(-1);
    }



  // --- Create SVTX eval stack
  SvtxEvalStack svtxevalstack(topNode);
  // --- Get evaluator objects from the eval stack
  SvtxVertexEval*   vertexeval = svtxevalstack.get_vertex_eval();
  SvtxTrackEval*     trackeval = svtxevalstack.get_track_eval();
  SvtxTruthEval*     trutheval = svtxevalstack.get_truth_eval();



  if ( verbosity > 0 ) cout << "Now going to loop over truth partcles..." << endl; // need verbosity switch

  // --- Loop over all truth particles
  PHG4TruthInfoContainer::Range range = truthinfo->GetPrimaryParticleRange();
  for ( PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter )
    {
      PHG4Particle* g4particle = iter->second; // You may ask yourself, why second?
      // In C++ the iterator is a map, which has two members
      // first is the key (analogous the index of an arry),
      // second is the value (analogous to the value stored for the array index)
      int particleID = g4particle->get_pid();

      if ( trutheval->get_embed(g4particle) <= 0 && fabs(particleID) == 11 && verbosity > 0 )
        {
          cout << "NON EMBEDDED ELECTRON!!!  WHEE!!! " << particleID << " " << iter->first << endl;
        }

      if ( trutheval->get_embed(g4particle) <= 0 ) continue; // only look at embedded particles // no good for hits files
      bool iselectron = fabs(particleID) == 11;
      bool ispion = fabs(particleID) == 211;
      if ( verbosity > 0 ) cout << "embedded particle ID is " << particleID << " ispion " << ispion << " iselectron " << iselectron << " " << iter->first << endl;

      set<PHG4Hit*> g4hits = trutheval->all_truth_hits(g4particle);
      float ng4hits = g4hits.size();

      float truept = sqrt(pow(g4particle->get_px(),2)+pow(g4particle->get_py(),2));
      float true_energy = g4particle->get_e();

      // --- Get the reconsructed SvtxTrack based on the best candidate from the truth info
      SvtxTrack* track = trackeval->best_track_from(g4particle);
      if (!track) continue;
      float recopt = track->get_pt();
      float recop = track->get_p();

      if ( verbosity > 0 )
	{
	  cout << "truept is " << truept << endl;
	  cout << "recopt is " << recopt << endl;
	  cout << "true energy is " << true_energy << endl;
	}

      // --- energy variables directly from the track object
      float emc_energy_track = track->get_cal_energy_3x3(SvtxTrack::CEMC);
      float hci_energy_track = track->get_cal_energy_3x3(SvtxTrack::HCALIN);
      float hco_energy_track = track->get_cal_energy_3x3(SvtxTrack::HCALOUT);

      if ( verbosity > 0 )
	{
	  cout << "emc_energy_track is " << emc_energy_track << endl;
	  cout << "hci_energy_track is " << hci_energy_track << endl;
	  cout << "hco_energy_track is " << hco_energy_track << endl;
	}

      // -------------------------------------------------------------------------------------
      // --- IMPORTANT NOTE: according to Jin, dphi and deta will not work correctly in HIJING

      float emc_dphi_track = track->get_cal_dphi(SvtxTrack::CEMC);
      float hci_dphi_track = track->get_cal_dphi(SvtxTrack::HCALIN);
      float hco_dphi_track = track->get_cal_dphi(SvtxTrack::HCALOUT);

      float emc_deta_track = track->get_cal_deta(SvtxTrack::CEMC);
      float hci_deta_track = track->get_cal_deta(SvtxTrack::HCALIN);
      float hco_deta_track = track->get_cal_deta(SvtxTrack::HCALOUT);

      float assoc_dphi = 0.1; // adjust as needed, consider class set method
      float assoc_deta = 0.1; // adjust as needed, consider class set method
      bool good_emc_assoc = fabs(emc_dphi_track) < assoc_dphi && fabs(emc_deta_track) < assoc_deta;
      bool good_hci_assoc = fabs(hci_dphi_track) < assoc_dphi && fabs(hci_deta_track) < assoc_deta;
      bool good_hco_assoc = fabs(hco_dphi_track) < assoc_dphi && fabs(hco_deta_track) < assoc_deta;

      // ------------------------------------------------------------------------------------------


      float hct_energy_track = 0;
      if ( hci_energy_track >= 0 ) hct_energy_track += hci_energy_track;
      if ( hco_energy_track >= 0 ) hct_energy_track += hco_energy_track;

      float total_energy_dumb = 0;
      if ( emc_energy_track >= 0 ) total_energy_dumb += emc_energy_track;
      if ( hci_energy_track >= 0 ) total_energy_dumb += hci_energy_track;
      if ( hco_energy_track >= 0 ) total_energy_dumb += hco_energy_track;

      float total_energy_smart = 0;
      if ( good_emc_assoc ) total_energy_smart += emc_energy_track;
      if ( good_hci_assoc ) total_energy_smart += hci_energy_track;
      if ( good_hco_assoc ) total_energy_smart += hco_energy_track;



      // ----------------------------------------------------------------------
      // ----------------------------------------------------------------------
      // ----------------------------------------------------------------------

      //cout << "starting the main part of the truth analysis" << endl;

      // examine truth particles that leave all (7 or 8 depending on design) detector hits
      if ( ng4hits == nlayers )
	{
	  _truept_particles_leavingAllHits->Fill(truept);

	  unsigned int nfromtruth = trackeval->get_nclusters_contribution(track,g4particle);

	  unsigned int ndiff = abs((int)nfromtruth-(int)nlayers);
	  if ( ndiff <= 2 ) _truept_particles_recoWithin2Hits->Fill(truept);
	  if ( ndiff <= 1 ) _truept_particles_recoWithin1Hit->Fill(truept);
	  if ( ndiff == 0 ) _truept_particles_recoWithExactHits->Fill(truept);

	  float diff = fabs(recopt-truept)/truept;
	  if ( diff < 0.05 ) _truept_particles_recoWithin5Percent->Fill(truept);
	  if ( diff < 0.04 )
	    {
	      _truept_particles_recoWithin4Percent->Fill(truept);
	      _truept_quality_particles_recoWithin4Percent->Fill(truept,track->get_quality());
	    }
	  if ( diff < 0.03 ) _truept_particles_recoWithin3Percent->Fill(truept);

          double good_energy = total_energy_dumb - 3.14;


          double eoverp = good_energy/recop;
          double sigmapt = 0.011 + 0.0008*recopt;
          th2d_truept_particles_withcalocuts_leavingAllHits->Fill(truept,eoverp);
          if ( ndiff <= 2 ) th2d_truept_particles_withcalocuts_recoWithin2Hits->Fill(truept,eoverp);
          if ( ndiff <= 1 ) th2d_truept_particles_withcalocuts_recoWithin1Hit->Fill(truept,eoverp);
          if ( ndiff == 0 ) th2d_truept_particles_withcalocuts_recoWithExactHits->Fill(truept,eoverp);
          if ( diff < 0.05 ) th2d_truept_particles_withcalocuts_recoWithin5Percent->Fill(truept,eoverp);
          if ( diff < 0.04 ) th2d_truept_particles_withcalocuts_recoWithin4Percent->Fill(truept,eoverp);
          if ( diff < 0.03 ) th2d_truept_particles_withcalocuts_recoWithin3Percent->Fill(truept,eoverp);
          if ( diff < 1.0*sigmapt ) th2d_truept_particles_withcalocuts_recoWithin1Sigma->Fill(recopt,eoverp);
          if ( diff < 2.0*sigmapt ) th2d_truept_particles_withcalocuts_recoWithin2Sigma->Fill(recopt,eoverp);
          if ( diff < 3.0*sigmapt ) th2d_truept_particles_withcalocuts_recoWithin3Sigma->Fill(recopt,eoverp);


	} // end of requirement of ng4hits == nlayers

    } // end of loop over truth particles



  // loop over all reco particles
  int ntracks = 0;
  for ( SvtxTrackMap::Iter iter = trackmap->begin(); iter != trackmap->end(); ++iter )
    {

      // --- Get the StxTrack object (from the iterator)
      SvtxTrack* track = iter->second;
      float recopt = track->get_pt();
      float recop = track->get_p();

      // --- Get the truth particle from the evaluator
      PHG4Particle* g4particle = trackeval->max_truth_particle_by_nclusters(track);
      float truept = sqrt(pow(g4particle->get_px(),2)+pow(g4particle->get_py(),2));
      int particleID = g4particle->get_pid();
      if ( verbosity > 5 ) cout << "particle ID is " << particleID << endl;
      bool iselectron = fabs(particleID) == 11;
      bool ispion = fabs(particleID) == 211;

      // ---------------------
      // --- calorimeter stuff
      // ---------------------

      // --- get the energy values directly from the track
      float emc_energy_track = track->get_cal_energy_3x3(SvtxTrack::CEMC);
      float hci_energy_track = track->get_cal_energy_3x3(SvtxTrack::HCALIN);
      float hco_energy_track = track->get_cal_energy_3x3(SvtxTrack::HCALOUT);

      float total_energy = 0;
      if ( emc_energy_track > 0 ) total_energy += emc_energy_track;
      if ( hci_energy_track > 0 ) total_energy += hci_energy_track;
      if ( hco_energy_track > 0 ) total_energy += hco_energy_track;

      if ( verbosity > 2 ) cout << "total calo energy is " << total_energy << endl;

      if (trutheval->get_embed(g4particle) > 0)
	{
	  // embedded results (quality or performance measures)
	  _truept_dptoverpt->Fill(truept,(recopt-truept)/truept);
	  _truept_dca->Fill(truept,track->get_dca2d());
	  _recopt_quality->Fill(recopt,track->get_quality());
          if ( verbosity > 0 ) cout << "embedded particle ID is " << particleID << " ispion " << ispion << " iselectron " << iselectron << endl;
          // ---
	} // end if (embedded results)
      else
	{
          // electron and pion (hadron) id

	  // non-embedded results (purity measures)
	  _recopt_tracks_all->Fill(recopt);
	  _recopt_quality_tracks_all->Fill(recopt,track->get_quality());

	  unsigned int nfromtruth = trackeval->get_nclusters_contribution(track,g4particle);

	  unsigned int ndiff = abs((int)nfromtruth-(int)nlayers);
	  if ( ndiff <= 2 ) _recopt_tracks_recoWithin2Hits->Fill(recopt);
	  if ( ndiff <= 1 ) _recopt_tracks_recoWithin1Hit->Fill(recopt);
	  if ( ndiff == 0 ) _recopt_tracks_recoWithExactHits->Fill(recopt);

	  float diff = fabs(recopt-truept)/truept;
	  if ( diff < 0.05 ) _recopt_tracks_recoWithin5Percent->Fill(recopt);
	  if ( diff < 0.04 )
	    {
	      _recopt_tracks_recoWithin4Percent->Fill(recopt);
	      _recopt_quality_tracks_recoWithin4Percent->Fill(recopt,track->get_quality());
	    }
	  if ( diff < 0.03 ) _recopt_tracks_recoWithin3Percent->Fill(recopt);


	  // --------------------------------------
	  // --- same but now with calorimeter cuts
	  // --------------------------------------

          double good_energy = total_energy - 3.14;

          double eoverp = good_energy/recop;
          double sigmapt = 0.011 + 0.0008*recopt;
          th2d_recopt_tracks_withcalocuts_all->Fill(recopt,eoverp);
          if ( ndiff <= 2 ) th2d_recopt_tracks_withcalocuts_recoWithin2Hits->Fill(recopt,eoverp);
          if ( ndiff <= 1 ) th2d_recopt_tracks_withcalocuts_recoWithin1Hit->Fill(recopt,eoverp);
          if ( ndiff == 0 ) th2d_recopt_tracks_withcalocuts_recoWithExactHits->Fill(recopt,eoverp);
          if ( diff < 0.05 ) th2d_recopt_tracks_withcalocuts_recoWithin5Percent->Fill(recopt,eoverp);
          if ( diff < 0.04 ) th2d_recopt_tracks_withcalocuts_recoWithin4Percent->Fill(recopt,eoverp);
          if ( diff < 0.03 ) th2d_recopt_tracks_withcalocuts_recoWithin3Percent->Fill(recopt,eoverp);
          if ( diff < 1.0*sigmapt ) th2d_recopt_tracks_withcalocuts_recoWithin1Sigma->Fill(recopt,eoverp);
          if ( diff < 2.0*sigmapt ) th2d_recopt_tracks_withcalocuts_recoWithin2Sigma->Fill(recopt,eoverp);
          if ( diff < 3.0*sigmapt ) th2d_recopt_tracks_withcalocuts_recoWithin3Sigma->Fill(recopt,eoverp);

	  // --- done with reco tracks

	} // else (non-embedded results)

      ++ntracks;
    } // loop over reco tracks


  hmult->Fill(ntracks);

  // --- Get the leading vertex
  SvtxVertex* maxvertex = NULL;
  unsigned int maxtracks = 0;
  for ( SvtxVertexMap::Iter iter = vertexmap->begin(); iter != vertexmap->end(); ++iter )
    {
      SvtxVertex* vertex = iter->second;
      if ( vertex->size_tracks() > maxtracks )
	{
	  maxvertex = vertex;
	  maxtracks = vertex->size_tracks();
	}
    }
  if ( !maxvertex )
    {
      cerr << PHWHERE << " ERROR: cannot get reconstructed vertex (event number " << nevents << ")" << endl;
      ++nerrors;
      return Fun4AllReturnCodes::DISCARDEVENT;
    }

  // --- Get the coordinates for the vertex from the evaluator
  PHG4VtxPoint* point = vertexeval->max_truth_point_by_ntracks(maxvertex);
  if ( !point )
    {
      cerr << PHWHERE << " ERROR: cannot get truth vertex (event number " << nevents << ")" << endl;
      ++nerrors;
      return Fun4AllReturnCodes::DISCARDEVENT;
    }
  _dx_vertex->Fill(maxvertex->get_x() - point->get_x());
  _dy_vertex->Fill(maxvertex->get_y() - point->get_y());
  _dz_vertex->Fill(maxvertex->get_z() - point->get_z());

  hmult_vertex->Fill(ntracks);



  return Fun4AllReturnCodes::EVENT_OK;

}