Back to home page

sPhenix code displayed by LXR

 
 

    


File indexing completed on 2025-08-06 08:18:35

0001 #include "PHTruthSiliconAssociation.h"
0002 
0003 #include <fun4all/Fun4AllReturnCodes.h>
0004 
0005 #include <phool/PHCompositeNode.h>
0006 #include <phool/PHRandomSeed.h>
0007 #include <phool/getClass.h>
0008 #include <phool/phool.h>
0009 
0010 /// Tracking includes
0011 #include <globalvertex/SvtxVertexMap.h>
0012 #include <trackbase/ActsGeometry.h>
0013 #include <trackbase/TrkrClusterContainer.h>
0014 #include <trackbase/TrkrClusterCrossingAssoc.h>
0015 #include <trackbase/TrkrClusterHitAssoc.h>
0016 #include <trackbase/TrkrClusterv3.h>
0017 #include <trackbase/TrkrDefs.h>
0018 #include <trackbase/TrkrHitSet.h>
0019 #include <trackbase/TrkrHitTruthAssoc.h>
0020 #include <trackbase_historic/SvtxTrackSeed_v1.h>
0021 #include <trackbase_historic/TrackSeedContainer_v1.h>
0022 #include <trackbase_historic/TrackSeed_FastSim_v2.h>
0023 #include <trackbase_historic/TrackSeed_v2.h>
0024 #include <trackbase_historic/TrackSeedHelper.h>
0025 
0026 #include <g4main/PHG4Hit.h>  // for PHG4Hit
0027 #include <g4main/PHG4HitContainer.h>
0028 #include <g4main/PHG4HitDefs.h>   // for keytype
0029 #include <g4main/PHG4Particle.h>  // for PHG4Particle
0030 #include <g4main/PHG4TruthInfoContainer.h>
0031 #include <g4main/PHG4VtxPoint.h>
0032 
0033 #include <TDatabasePDG.h>
0034 #include <TParticlePDG.h>
0035 
0036 #include <gsl/gsl_randist.h>
0037 #include <gsl/gsl_rng.h>  // for gsl_rng_alloc
0038 
0039 using namespace std;
0040 
0041 namespace
0042 {
0043   template <class T>
0044   inline constexpr T square(const T &x)
0045   {
0046     return x * x;
0047   }
0048 }  // namespace
0049 
0050 //____________________________________________________________________________..
0051 PHTruthSiliconAssociation::PHTruthSiliconAssociation(const std::string &name)
0052   : SubsysReco(name)
0053 {
0054   // initialize random generator
0055   const uint seed = PHRandomSeed();
0056   m_rng.reset(gsl_rng_alloc(gsl_rng_mt19937));
0057   gsl_rng_set(m_rng.get(), seed);
0058 }
0059 
0060 //____________________________________________________________________________..
0061 int PHTruthSiliconAssociation::Init(PHCompositeNode * /*topNode*/)
0062 {
0063   return Fun4AllReturnCodes::EVENT_OK;
0064 }
0065 
0066 //____________________________________________________________________________..
0067 int PHTruthSiliconAssociation::InitRun(PHCompositeNode *topNode)
0068 {
0069   int ret = GetNodes(topNode);
0070 
0071   return ret;
0072 }
0073 
0074 //____________________________________________________________________________..
0075 int PHTruthSiliconAssociation::process_event(PHCompositeNode * /*topNode*/)
0076 {
0077   if (Verbosity() >= 1)
0078   {
0079     cout << "PHTruthSiliconAssociation::process_event(PHCompositeNode *topNode) Processing Event" << endl;
0080   }
0081 
0082   // Reset the silicon seed node
0083   _silicon_track_map->Reset();
0084 
0085   // Loop over all SeedTracks from the CA seeder
0086   // These should contain all TPC clusters already
0087 
0088   for (unsigned int phtrk_iter = 0;
0089        phtrk_iter < _tpc_track_map->size();
0090        ++phtrk_iter)
0091   {
0092     _tracklet = _tpc_track_map->get(phtrk_iter);
0093 
0094     if (!_tracklet)
0095     {
0096       continue;
0097     }
0098 
0099     if (Verbosity() >= 1)
0100     {
0101       std::cout
0102           << __LINE__
0103           << ": Processing seed itrack: " << phtrk_iter
0104           << ": nhits: " << _tracklet->size_cluster_keys()
0105           << ": Total tracks: " << _tpc_track_map->size()
0106           << endl;
0107     }
0108 
0109     // identify the best truth track match(es) for this seed track
0110     std::vector<PHG4Particle *> g4particle_vec = getG4PrimaryParticle(_tracklet);
0111     if (Verbosity() > 0)
0112     {
0113       std::cout << " g4particle_vec.size() " << g4particle_vec.size() << std::endl;
0114     }
0115 
0116     if (g4particle_vec.size() < 1)
0117     {
0118       continue;
0119     }
0120 
0121     if (Verbosity() >= 1)
0122     {
0123       std::cout << "  tpc seed track:" << endl;
0124       _tracklet->identify();
0125     }
0126 
0127     for (auto g4particle : g4particle_vec)
0128     {
0129       // identify the clusters that are associated with this g4particle
0130       std::set<TrkrDefs::cluskey> clusters = getSiliconClustersFromParticle(g4particle);
0131       if (clusters.size() < 3)
0132       {
0133         continue;
0134       }
0135 
0136       // Make a silicon track seed
0137       unsigned int silicon_seed_index = buildTrackSeed(clusters, g4particle, _silicon_track_map);
0138 
0139       // Add this entry to the SvtxTrackSeedContainer
0140       auto seed = std::make_unique<SvtxTrackSeed_v1>();
0141       seed->set_tpc_seed_index(phtrk_iter);
0142       seed->set_silicon_seed_index(silicon_seed_index);
0143       _svtx_seed_map->insert(seed.get());
0144 
0145       unsigned int combined_seed_index = _svtx_seed_map->size() - 1;
0146 
0147       if (Verbosity() >= 1)
0148       {
0149         std::cout << " Created SvtxTrackSeed  " << combined_seed_index
0150                   << " with tpcid " << _svtx_seed_map->get(combined_seed_index)->get_tpc_seed_index()
0151                   << " and silicon ID " << _svtx_seed_map->get(combined_seed_index)->get_silicon_seed_index()
0152                   << std::endl;
0153       }
0154     }
0155   }
0156 
0157   if (Verbosity() > 0)
0158   {
0159     // loop over the assembled tracks
0160     for (unsigned int phtrk_iter = 0;
0161          phtrk_iter < _svtx_seed_map->size();
0162          ++phtrk_iter)
0163     {
0164       auto seed = _svtx_seed_map->get(phtrk_iter);
0165       if (!seed)
0166       {
0167         continue;
0168       }
0169 
0170       auto tpc_index = seed->get_tpc_seed_index();
0171       auto silicon_index = seed->get_silicon_seed_index();
0172 
0173       std::cout << "SvtxSeedTrack: " << phtrk_iter
0174                 << " tpc_index " << tpc_index
0175                 << " silicon_index " << silicon_index
0176                 << std::endl;
0177 
0178       std::cout << " ----------  silicon tracklet " << silicon_index << std::endl;
0179       auto silicon_tracklet = _silicon_track_map->get(silicon_index);
0180       if (!silicon_tracklet)
0181       {
0182         continue;
0183       }
0184       silicon_tracklet->identify();
0185 
0186       std::cout << " ---------- tpc tracklet " << tpc_index << std::endl;
0187       auto tpc_tracklet = _tpc_track_map->get(tpc_index);
0188       if (!tpc_tracklet)
0189       {
0190         continue;
0191       }
0192       tpc_tracklet->identify();
0193     }
0194   }
0195 
0196   if (Verbosity() >= 1)
0197   {
0198     cout << "PHTruthSiliconAssociation::process_event(PHCompositeNode *topNode) Leaving process_event" << endl;
0199   }
0200 
0201   return Fun4AllReturnCodes::EVENT_OK;
0202 }
0203 
0204 //____________________________________________________________________________..
0205 int PHTruthSiliconAssociation::ResetEvent(PHCompositeNode * /*topNode*/)
0206 {
0207   // cout << "PHTruthSiliconAssociation::ResetEvent(PHCompositeNode *topNode) Resetting internal structures, prepare for next event" << endl;
0208   return Fun4AllReturnCodes::EVENT_OK;
0209 }
0210 
0211 //____________________________________________________________________________..
0212 int PHTruthSiliconAssociation::EndRun(const int /*runnumber*/)
0213 {
0214   return Fun4AllReturnCodes::EVENT_OK;
0215 }
0216 
0217 //____________________________________________________________________________..
0218 int PHTruthSiliconAssociation::End(PHCompositeNode * /*topNode*/)
0219 {
0220   return Fun4AllReturnCodes::EVENT_OK;
0221 }
0222 
0223 //____________________________________________________________________________..
0224 int PHTruthSiliconAssociation::Reset(PHCompositeNode * /*topNode*/)
0225 {
0226   return Fun4AllReturnCodes::EVENT_OK;
0227 }
0228 
0229 //____________________________________________________________________________..
0230 void PHTruthSiliconAssociation::Print(const std::string & /*what*/) const
0231 {
0232   // cout << "PHTruthSiliconAssociation::Print(const std::string &what) const Printing info for " << what << endl;
0233 }
0234 
0235 /*
0236 void PHTruthSiliconAssociation::makeSvtxSeedMap()
0237 {
0238   /// The track fitter expects a full svtxtrackseed container, so just
0239   /// convert the tpc+silicon track seeds created into svtxtrack seeds
0240 
0241   for(unsigned int iter = 0; iter < _track_map->size(); ++iter)
0242     {
0243       auto seed = std::make_unique<SvtxTrackSeed_v1>();
0244       seed->set_tpc_seed_index(iter);
0245       _svtx_seed_map->insert(seed.get());
0246     }
0247 
0248 }
0249 */
0250 
0251 int PHTruthSiliconAssociation::GetNodes(PHCompositeNode *topNode)
0252 {
0253   //---------------------------------
0254   // Get Objects off of the Node Tree
0255   //---------------------------------
0256 
0257   _g4truth_container = findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
0258   if (!_g4truth_container)
0259   {
0260     cerr << PHWHERE << " ERROR: Can't find node G4TruthInfo" << endl;
0261     return Fun4AllReturnCodes::ABORTEVENT;
0262   }
0263 
0264   _cluster_crossing_map = findNode::getClass<TrkrClusterCrossingAssoc>(topNode, "TRKR_CLUSTERCROSSINGASSOC");
0265   if (!_cluster_crossing_map)
0266   {
0267     cerr << PHWHERE << " ERROR: Can't find TRKR_CLUSTERCROSSINGASSOC " << endl;
0268     return Fun4AllReturnCodes::ABORTEVENT;
0269   }
0270   /*
0271   _corrected_cluster_map = findNode::getClass<TrkrClusterContainer>(topNode,"CORRECTED_TRKR_CLUSTER");
0272   if(_corrected_cluster_map)
0273     {
0274       std::cout << " Found CORRECTED_TRKR_CLUSTER node " << std::endl;
0275     }
0276   */
0277 
0278   _cluster_map = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
0279   if (!_cluster_map)
0280   {
0281     cerr << PHWHERE << " ERROR: Can't find node TRKR_CLUSTER" << endl;
0282     return Fun4AllReturnCodes::ABORTEVENT;
0283   }
0284 
0285   _hit_truth_map = findNode::getClass<TrkrHitTruthAssoc>(topNode, "TRKR_HITTRUTHASSOC");
0286   if (!_hit_truth_map)
0287   {
0288     cerr << PHWHERE << " ERROR: Can't find TrkrHitTruthAssoc." << endl;
0289     return Fun4AllReturnCodes::ABORTEVENT;
0290   }
0291 
0292   _cluster_hit_map = findNode::getClass<TrkrClusterHitAssoc>(topNode, "TRKR_CLUSTERHITASSOC");
0293   if (!_cluster_hit_map)
0294   {
0295     cerr << PHWHERE << " ERROR: Can't find TrkrClusterHitAssoc." << endl;
0296     return Fun4AllReturnCodes::ABORTEVENT;
0297   }
0298 
0299   _tgeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
0300   if (!_tgeometry)
0301   {
0302     std::cerr << PHWHERE << "ERROR: can't find acts tracking geometry" << std::endl;
0303     return Fun4AllReturnCodes::ABORTEVENT;
0304   }
0305 
0306   /// Get the DST Node
0307   PHNodeIterator iter(topNode);
0308   PHCompositeNode *dstNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "DST"));
0309 
0310   /// Check that it is there
0311   if (!dstNode)
0312   {
0313     std::cerr << "DST Node missing, quitting" << std::endl;
0314     throw std::runtime_error("failed to find DST node in PHTruthSiliconAssociation::createNodes");
0315   }
0316 
0317   /// Get the tracking subnode under DST
0318   PHNodeIterator dstIter(dstNode);
0319   PHCompositeNode *svtxNode = dynamic_cast<PHCompositeNode *>(dstIter.findFirst("PHCompositeNode", "SVTX"));
0320 
0321   /// Check that it is there
0322   if (!svtxNode)
0323   {
0324     svtxNode = new PHCompositeNode("SVTX");
0325     dstNode->addNode(svtxNode);
0326   }
0327 
0328   _silicon_track_map = findNode::getClass<TrackSeedContainer>(topNode, "SiliconTrackSeedContainer");
0329   if (!_silicon_track_map)
0330   {
0331     _silicon_track_map = new TrackSeedContainer_v1;
0332     PHIODataNode<PHObject> *si_tracks_node =
0333         new PHIODataNode<PHObject>(_silicon_track_map, "SiliconTrackSeedContainer", "PHObject");
0334     svtxNode->addNode(si_tracks_node);
0335   }
0336 
0337   _tpc_track_map = findNode::getClass<TrackSeedContainer>(topNode, "TpcTrackSeedContainer");
0338   if (!_tpc_track_map)
0339   {
0340     cerr << PHWHERE << " ERROR: Can't find TpcTrackSeedContainer: " << endl;
0341     return Fun4AllReturnCodes::ABORTEVENT;
0342   }
0343 
0344   _svtx_seed_map = findNode::getClass<TrackSeedContainer>(topNode, "SvtxTrackSeedContainer");
0345   if (!_svtx_seed_map)
0346   {
0347     _svtx_seed_map = new TrackSeedContainer_v1;
0348     PHIODataNode<PHObject> *node2 = new PHIODataNode<PHObject>(_svtx_seed_map, "SvtxTrackSeedContainer", "PHObject");
0349     svtxNode->addNode(node2);
0350   }
0351 
0352   _g4hits_tpc = findNode::getClass<PHG4HitContainer>(topNode, "G4HIT_TPC");
0353   _g4hits_intt = findNode::getClass<PHG4HitContainer>(topNode, "G4HIT_INTT");
0354   _g4hits_mvtx = findNode::getClass<PHG4HitContainer>(topNode, "G4HIT_MVTX");
0355 
0356   return Fun4AllReturnCodes::EVENT_OK;
0357 }
0358 
0359 std::vector<PHG4Particle *> PHTruthSiliconAssociation::getG4PrimaryParticle(TrackSeed *track)
0360 {
0361   // Find the best g4particle match to the clusters associated with this reco track
0362 
0363   std::vector<PHG4Particle *> g4part_vec;
0364   std::set<int> pid;
0365   std::multimap<int, int> pid_count;
0366   int minfound = 200;  // require at least this many hits to be put on the list of contributing particles
0367 
0368   // loop over associated clusters to get hits
0369   for (auto iter = track->begin_cluster_keys();
0370        iter != track->end_cluster_keys();
0371        ++iter)
0372   {
0373     TrkrDefs::cluskey cluster_key = *iter;
0374 
0375     // get all reco hits for this cluster
0376     // TrkrClusterHitAssoc::ConstRange
0377     std::pair<std::multimap<TrkrDefs::cluskey, TrkrDefs::hitkey>::const_iterator, std::multimap<TrkrDefs::cluskey, TrkrDefs::hitkey>::const_iterator>
0378         hitrange = _cluster_hit_map->getHits(cluster_key);  // returns range of pairs {cluster key, hit key} for this cluskey
0379     // for(TrkrClusterHitAssoc::ConstIterator clushititer = hitrange.first; clushititer != hitrange.second; ++clushititer)
0380     for (std::multimap<TrkrDefs::cluskey, TrkrDefs::hitkey>::const_iterator
0381              clushititer = hitrange.first;
0382          clushititer != hitrange.second; ++clushititer)
0383     {
0384       TrkrDefs::hitkey hitkey = clushititer->second;
0385       // TrkrHitTruthAssoc uses a map with (hitsetkey, std::pair(hitkey, g4hitkey)) - get the hitsetkey from the cluskey
0386       TrkrDefs::hitsetkey hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(cluster_key);
0387 
0388       // get all of the g4hits for this hitkey
0389       std::multimap<TrkrDefs::hitsetkey, std::pair<TrkrDefs::hitkey, PHG4HitDefs::keytype> > temp_map;
0390       _hit_truth_map->getG4Hits(hitsetkey, hitkey, temp_map);  // returns pairs (hitsetkey, std::pair(hitkey, g4hitkey)) for this hitkey only
0391       for (auto &htiter : temp_map)
0392       {
0393         // extract the g4 hit key
0394         PHG4HitDefs::keytype g4hitkey = htiter.second.second;
0395         PHG4Hit *g4hit = nullptr;
0396         unsigned int trkrid = TrkrDefs::getTrkrId(hitsetkey);
0397         switch (trkrid)
0398         {
0399         case TrkrDefs::tpcId:
0400           g4hit = _g4hits_tpc->findHit(g4hitkey);
0401           break;
0402         case TrkrDefs::inttId:
0403           g4hit = _g4hits_intt->findHit(g4hitkey);
0404           break;
0405         case TrkrDefs::mvtxId:
0406           g4hit = _g4hits_mvtx->findHit(g4hitkey);
0407           break;
0408         default:
0409           break;
0410         }
0411         if (g4hit)
0412         {
0413           // get the g4particle ID for this g4hit
0414           pid.insert(g4hit->get_trkid());
0415           // this is for counting the number of times this g4particle was associated
0416           int cnt = 1;
0417           pid_count.insert(std::make_pair(g4hit->get_trkid(), cnt));
0418         }
0419       }  // end loop over g4hits associated with hitsetkey and hitkey
0420     }    // end loop over hits associated with cluskey
0421   }      // end loop over clusters associated with this track
0422 
0423   // loop over the particle id's, and count the number for each one
0424   for (int it : pid)
0425   {
0426     if (it < 0)
0427     {
0428       continue;  // ignore secondary particles
0429     }
0430 
0431     int nfound = 0;
0432     std::pair<std::multimap<int, int>::iterator, std::multimap<int, int>::iterator> this_pid = pid_count.equal_range(it);
0433     for (auto cnt_it = this_pid.first; cnt_it != this_pid.second; ++cnt_it)
0434     {
0435       nfound++;
0436     }
0437 
0438     if (Verbosity() >= 1)
0439     {
0440       std::cout << "    pid: " << it << "  nfound " << nfound << std::endl;
0441     }
0442     if (nfound > minfound)
0443     {
0444       g4part_vec.push_back(_g4truth_container->GetParticle(it));
0445     }
0446   }
0447 
0448   return g4part_vec;
0449 }
0450 
0451 std::set<TrkrDefs::cluskey> PHTruthSiliconAssociation::getSiliconClustersFromParticle(PHG4Particle *g4particle)
0452 {
0453   // Find the reco clusters in the silicon layers from this g4particle
0454 
0455   std::set<TrkrDefs::cluskey> clusters;
0456 
0457   // loop over all the clusters
0458   for (const auto &hitsetkey : _cluster_map->getHitSetKeys())
0459   {
0460     const auto layer = TrkrDefs::getLayer(hitsetkey);
0461     if (layer > 6)
0462     {
0463       continue;  // we need the silicon layers only
0464     }
0465 
0466     auto range = _cluster_map->getClusters(hitsetkey);
0467     for (auto clusIter = range.first; clusIter != range.second; ++clusIter)
0468     {
0469       TrkrDefs::cluskey cluster_key = clusIter->first;
0470 
0471       // get all truth hits for this cluster
0472       // TrkrClusterHitAssoc::ConstRange
0473       std::pair<std::multimap<TrkrDefs::cluskey, TrkrDefs::hitkey>::const_iterator, std::multimap<TrkrDefs::cluskey, TrkrDefs::hitkey>::const_iterator>
0474           hitrange = _cluster_hit_map->getHits(cluster_key);  // returns range of pairs {cluster key, hit key} for this cluskey
0475       // for(TrkrClusterHitAssoc::ConstIterator
0476       for (std::multimap<TrkrDefs::cluskey, TrkrDefs::hitkey>::const_iterator
0477                clushititer = hitrange.first;
0478            clushititer != hitrange.second; ++clushititer)
0479       {
0480         TrkrDefs::hitkey hitkey = clushititer->second;
0481         // TrkrHitTruthAssoc uses a map with (hitsetkey, std::pair(hitkey, g4hitkey)) - get the hitsetkey from the cluskey
0482         TrkrDefs::hitsetkey hitsetkey_A = TrkrDefs::getHitSetKeyFromClusKey(cluster_key);
0483 
0484         // get all of the g4hits for this hitkey
0485         std::multimap<TrkrDefs::hitsetkey, std::pair<TrkrDefs::hitkey, PHG4HitDefs::keytype> > temp_map;
0486         _hit_truth_map->getG4Hits(hitsetkey_A, hitkey, temp_map);  // returns pairs (hitsetkey, std::pair(hitkey, g4hitkey)) for this hitkey only
0487         for (auto &htiter : temp_map)
0488         {
0489           // extract the g4 hit key
0490           PHG4HitDefs::keytype g4hitkey = htiter.second.second;
0491           PHG4Hit *g4hit = nullptr;
0492           unsigned int trkrid = TrkrDefs::getTrkrId(hitsetkey_A);
0493           switch (trkrid)
0494           {
0495           case TrkrDefs::mvtxId:
0496             g4hit = _g4hits_mvtx->findHit(g4hitkey);
0497             break;
0498           case TrkrDefs::inttId:
0499             g4hit = _g4hits_intt->findHit(g4hitkey);
0500             break;
0501           default:
0502             break;
0503           }
0504           if (g4hit)
0505           {
0506             // get the g4particle for this g4hit
0507             int trkid = g4hit->get_trkid();
0508             if (trkid == g4particle->get_track_id())
0509             {
0510               clusters.insert(cluster_key);
0511             }
0512           }
0513         }  // end loop over g4hits associated with hitsetkey and hitkey
0514       }    // end loop over hits associated with cluskey
0515     }      // end loop over all cluster keys in silicon layers
0516   }        // end loop over hitsets
0517   return clusters;
0518 }
0519 
0520 std::set<short int> PHTruthSiliconAssociation::getInttCrossings(TrackSeed *si_track) const
0521 {
0522   std::set<short int> intt_crossings;
0523 
0524   // If the Si track contains an INTT hit, use it to get the bunch crossing offset
0525   // loop over associated clusters to get keys for silicon cluster
0526   for (auto iter = si_track->begin_cluster_keys();
0527        iter != si_track->end_cluster_keys();
0528        ++iter)
0529   {
0530     TrkrDefs::cluskey cluster_key = *iter;
0531     const unsigned int trkrid = TrkrDefs::getTrkrId(cluster_key);
0532     if (trkrid == TrkrDefs::inttId)
0533     {
0534       // std::cout << "      INTT cluster key " << cluster_key << std::endl;
0535 
0536       const unsigned int layer = TrkrDefs::getLayer(cluster_key);
0537 
0538       // get the bunch crossings for all hits in this cluster
0539       auto crossings = _cluster_crossing_map->getCrossings(cluster_key);
0540       for (auto iter_A = crossings.first; iter_A != crossings.second; ++iter_A)
0541       {
0542         const auto &[key, crossing] = *iter_A;
0543         if (Verbosity())
0544         {
0545           std::cout << "PHTruthSiliconAssociation::getInttCrossings - si Track cluster " << key << " layer " << layer << " crossing " << crossing << std::endl;
0546         }
0547         intt_crossings.insert(crossing);
0548       }
0549     }
0550   }
0551   //      std::cout << " intt_crossings size is " << intt_crossings.size() << std::endl;
0552 
0553   return intt_crossings;
0554 }
0555 
0556 unsigned int PHTruthSiliconAssociation::buildTrackSeed(const std::set<TrkrDefs::cluskey> &clusters, PHG4Particle *g4particle, TrackSeedContainer *container)
0557 {
0558   auto track = std::make_unique<TrackSeed_FastSim_v2>();
0559   bool silicon = false;
0560   for (const auto &cluskey : clusters)
0561   {
0562     if (TrkrDefs::getTrkrId(cluskey) == TrkrDefs::TrkrId::mvtxId ||
0563         TrkrDefs::getTrkrId(cluskey) == TrkrDefs::TrkrId::inttId)
0564     {
0565       silicon = true;
0566     }
0567     track->insert_cluster_key(cluskey);
0568   }
0569 
0570   const auto particle = TDatabasePDG::Instance()->GetParticle(g4particle->get_pid());
0571   int charge = 1;
0572   if (particle)
0573   {
0574     if (particle->Charge() < 0)
0575     {
0576       charge = -1;
0577     }
0578   }
0579 
0580   auto random1 = gsl_ran_flat(m_rng.get(), 0.95, 1.05);
0581   float px = g4particle->get_px() * random1;
0582   float py = g4particle->get_py() * random1;
0583   float pz = g4particle->get_pz() * random1;
0584 
0585   const auto g4vertex = _g4truth_container->GetVtx(g4particle->get_vtx_id());
0586   auto random2 = gsl_ran_flat(m_rng.get(), -0.002, 0.002);
0587   float x = g4vertex->get_x() + random2;
0588   float y = g4vertex->get_y() + random2;
0589   float z = g4vertex->get_z() + random2;
0590 
0591   float pt = sqrt(px * px + py * py);
0592   float phi = atan2(py, px);
0593   float R = 100 * pt / (0.3 * 1.4);
0594   float theta = atan2(pt, pz);
0595   if (theta < 0)
0596   {
0597     theta += M_PI;
0598   }
0599   if (theta > M_PI)
0600   {
0601     theta -= M_PI;
0602   }
0603 
0604   float eta = -log(tan(theta / 2.));
0605 
0606   // We have two equations, phi = atan2(-(X0-x),y-Y0) and
0607   // R^2 = (x-X0)^2 + (y-Y0)^2. Solve for X0 and Y0 knowing R and phi
0608   float tanphisq = square(tan(phi));
0609   float a = tanphisq + 1;
0610   float b = -2 * y * (tanphisq + 1);
0611   float c = (tanphisq + 1) * square(y) - square(R);
0612 
0613   float Y0_1 = (-b + sqrt(square(b) - 4 * a * c)) / (2. * a);
0614   float Y0_2 = (-b - sqrt(square(b) - 4 * a * c)) / (2. * a);
0615   float X0_1 = sqrt(pow(R, 2) - pow(Y0_1 - y, 2)) + x;
0616   float X0_2 = -sqrt(pow(R, 2) - pow(Y0_2 - y, 2)) + x;
0617   track->set_X0(X0_1);
0618   track->set_Y0(Y0_1);
0619   track->set_qOverR(charge / R);
0620   track->set_slope(1. / tan(theta));
0621   track->set_Z0(z);
0622 
0623   /// Need to find the right one for the bend angle
0624 
0625   float newphi = TrackSeedHelper::get_phi_fastsim( track.get() );
0626   /// We have to pick the right one based on the bend angle, so iterate
0627   /// through until you find the closest phi match
0628   if (fabs(newphi - phi) > 0.03)
0629   {
0630     track->set_X0(X0_2);
0631     newphi = TrackSeedHelper::get_phi_fastsim( track.get() );
0632 
0633     if (fabs(newphi - phi) > 0.03)
0634     {
0635       track->set_Y0(Y0_2);
0636       newphi = TrackSeedHelper::get_phi_fastsim( track.get() );
0637 
0638       if (fabs(newphi - phi) > 0.03)
0639       {
0640         track->set_X0(X0_1);
0641         newphi = TrackSeedHelper::get_phi_fastsim( track.get() );
0642       }
0643     }
0644   }
0645 
0646   // make phi persistent
0647   if (Verbosity() > 2)
0648   {
0649     std::cout << "Charge is " << charge << std::endl;
0650     std::cout << "truth/reco px " << px << ", " << track->get_px() << std::endl;
0651     std::cout << "truth/reco py " << py << ", " << track->get_py() << std::endl;
0652     std::cout << "truth/reco pz " << pz << ", " << track->get_pz() << std::endl;
0653     std::cout << "truth/reco pt " << pt << ", " << track->get_pt() << std::endl;
0654     std::cout << "truth/reco phi " << phi << ", " << track->get_phi() << std::endl;
0655     std::cout << "truth/reco eta " << eta << ", " << track->get_eta() << std::endl;
0656     std::cout << "truth/reco x " << x << ", " << TrackSeedHelper::get_x(track.get()) << std::endl;
0657     std::cout << "truth/reco y " << y << ", " << TrackSeedHelper::get_y(track.get()) << std::endl;
0658     std::cout << "truth/reco z " << z << ", " << TrackSeedHelper::get_z(track.get()) << std::endl;
0659   }
0660 
0661   // set intt crossing
0662   if (silicon)
0663   {
0664     // silicon tracklet
0665     /* inspired from PHtruthSiliconAssociation */
0666     const auto intt_crossings = getInttCrossings(track.get());
0667     if (intt_crossings.empty())
0668     {
0669       if (Verbosity() > 1)
0670       {
0671         std::cout << "PHTruthTrackSeeding::Process - Silicon track " << container->size() - 1 << " has no INTT clusters" << std::endl;
0672       }
0673       return (container->size() - 1);
0674     }
0675     else if (intt_crossings.size() > 1)
0676     {
0677       if (Verbosity() > 1)
0678       {
0679         std::cout << "PHTruthTrackSeeding::Process - INTT crossings not all the same for track " << container->size() - 1 << " crossing_keep - dropping this match " << std::endl;
0680       }
0681     }
0682     else
0683     {
0684       const auto &crossing = *intt_crossings.begin();
0685       track->set_crossing(crossing);
0686       if (Verbosity() > 1)
0687       {
0688         std::cout << "PHTruthTrackSeeding::Process - Combined track " << container->size() - 1 << " bunch crossing " << crossing << std::endl;
0689       }
0690     }
0691   }  // end if _min_layer
0692   else
0693   {
0694     // no INTT layers, crossing is unknown
0695     track->set_crossing(SHRT_MAX);
0696   }
0697 
0698   container->insert(track.get());
0699 
0700   return (container->size() - 1);
0701 }