Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PHTpcClusterMover.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file PHTpcClusterMover.cc
1 #include "PHTpcClusterMover.h"
2 
3 #include "PHTpcClusterMover.h"
4 
6 
8 #include <trackbase/TrkrClusterv3.h> // for TrkrCluster
9 #include <trackbase/TrkrDefs.h> // for cluskey, getLayer, TrkrId
11 #include <trackbase_historic/SvtxTrack.h> // for SvtxTrack, SvtxTrack::C...
14 
17 
19 
20 #include <phool/getClass.h>
21 #include <phool/phool.h>
22 #include <phool/PHCompositeNode.h>
23 
24 #include <TF1.h>
25 
26 #include <cmath> // for sqrt, fabs, atan2, cos
27 #include <iostream> // for operator<<, basic_ostream
28 #include <map> // for map
29 #include <set> // for _Rb_tree_const_iterator
30 #include <utility> // for pair, make_pair
31 
32 //____________________________________________________________________________..
34  : SubsysReco(name)
35 {}
36 
37 //____________________________________________________________________________..
39 {
40  int ret = GetNodes(topNode);
41  if (ret != Fun4AllReturnCodes::EVENT_OK) return ret;
42  for (int layer=7; layer<7+48; layer++){
44  std::cout << "PHTpcClusterMover:: layer = " << layer << " layer_radius " << GeoLayer->get_radius() << std::endl;
45  layer_radius[layer-7] = GeoLayer->get_radius();
46  }
47 
49  //inner_tpc_spacing = (mid_tpc_min_radius - inner_tpc_min_radius) / 16.0;
50  //mid_tpc_spacing = (outer_tpc_min_radius - mid_tpc_min_radius) / 16.0;
51  //outer_tpc_spacing = (outer_tpc_max_radius - outer_tpc_min_radius) / 16.0;
52  //for(int i=0; i < 16; ++i)
53  // {
54  // layer_radius[i] = inner_tpc_min_radius + (double) i * inner_tpc_spacing + 0.5 * inner_tpc_spacing;
55  // if(Verbosity() > 4) std::cout << " i " << i << " layer_radius " << layer_radius[i] << std::endl;
56  // }
57  //for(int i=0; i < 16; ++i)
58  // {
59  // layer_radius[i+16] = mid_tpc_min_radius + (double) i * mid_tpc_spacing + 0.5 * mid_tpc_spacing;
60  // if(Verbosity() > 4) std::cout << " i " << i << " layer_radius " << layer_radius[i+16] << std::endl;
61  // }
62  //for(int i=0; i < 16; ++i)
63  // {
64  // layer_radius[i+32] = outer_tpc_min_radius + (double) i * outer_tpc_spacing + 0.5 * outer_tpc_spacing;
65  // if(Verbosity() > 4) std::cout << " i " << i << " layer_radius " << layer_radius[i+32] << std::endl;
66  // }
67 
68  return ret;
69 }
70 
71 //____________________________________________________________________________..
73 {
74 
75  if(Verbosity() > 0)
76  std::cout << PHWHERE << " track map size " << _track_map->size() << std::endl;
77 
78  // loop over the tracks
79  for (auto phtrk_iter = _track_map->begin();
80  phtrk_iter != _track_map->end();
81  ++phtrk_iter)
82  {
83  _track = phtrk_iter->second;
84 
85  if (Verbosity() >= 1)
86  {
87  std::cout << std::endl
88  << __LINE__
89  << ": Processing track itrack: " << phtrk_iter->first
90  << ": nhits: " << _track-> size_cluster_keys()
91  << ": Total tracks: " << _track_map->size()
92  << ": phi: " << _track->get_phi()
93  << std::endl;
94  }
95 
96  // Get the TPC clusters for this track and correct them for distortions
97  std::vector<Acts::Vector3> globalClusterPositions;
98  std::map<TrkrDefs::cluskey, Acts::Vector3> tpc_clusters;
99 
100  for (auto key_iter = _track->begin_cluster_keys();
101  key_iter != _track->end_cluster_keys();
102  ++key_iter)
103  {
104  TrkrDefs::cluskey cluster_key = *key_iter;
105  unsigned int trkrId = TrkrDefs::getTrkrId(cluster_key);
106  unsigned int layer = TrkrDefs::getLayer(cluster_key);
107 
108  // non Tpc clusters are copied unchanged to the new map if they are present
109  // This is needed for truth seeding case, where the tracks already have silicon clusters
110  if(trkrId != TrkrDefs::tpcId)
111  {
112 
113  // check if clusters has not been inserted already
114  if( _corrected_cluster_map->findCluster(cluster_key) ) continue;
115 
116  // get cluster from original map
117  auto cluster = _cluster_map->findCluster(cluster_key);
118  if( !cluster ) continue;
119 
120  // create a copy
121  auto newclus = new TrkrClusterv3;
122  newclus->CopyFrom( cluster );
123 
124  // insert in corrected map
125  _corrected_cluster_map->addClusterSpecifyKey(cluster_key, newclus);
126  continue;
127  }
128 
129  // get the cluster in 3D coordinates
130  auto tpc_clus = _cluster_map->findCluster(cluster_key);
131  auto global = _tGeometry->getGlobalPosition(cluster_key, tpc_clus);
132 
133  // check if TPC distortion correction are in place and apply
134  if(Verbosity() > 2) std::cout << " layer " << layer << " distorted cluster position: " << global[0] << " " << global[1] << " " << global[2];
135  if( _dcc ) global = _distortionCorrection.get_corrected_position( global, _dcc );
136  if(Verbosity() > 2) std::cout << " corrected cluster position: " << global[0] << " " << global[1] << " " << global[2] << std::endl;
137 
138  // Store the corrected 3D cluster positions
139  globalClusterPositions.push_back(global);
140  tpc_clusters.insert(std::make_pair(cluster_key, global));
141 
142  }
143 
144  // need at least 3 clusters to fit a circle
145  if(globalClusterPositions.size() < 3)
146  {
147  if(Verbosity() > 3) std::cout << PHWHERE << " -- skip this tpc track, not enough clusters: " << globalClusterPositions.size() << std::endl;
148  continue; // skip to the next TPC track
149  }
150 
151  // fit a circle to the clusters
152  const auto [R, X0, Y0] = TrackFitUtils::circle_fit_by_taubin( globalClusterPositions );
153  if(Verbosity() > 10)
154  { std::cout << " Fitted circle has R " << R << " X0 " << X0 << " Y0 " << Y0 << std::endl; }
155 
156  // toss tracks for which the fitted circle could not have come from the vertex
157  //if(R < 30.0) continue;
158 
159  // get the straight line representing the z trajectory in the form of z vs radius
160  const auto [A, B] = TrackFitUtils::line_fit( globalClusterPositions );
161  if(Verbosity() > 10)
162  { std::cout << " Fitted line has A " << A << " B " << B << std::endl; }
163 
164  // Now we need to move each cluster associated with this track to the readout layer radius
165  for( const auto& [cluskey, global]:tpc_clusters )
166  {
167  const unsigned int layer = TrkrDefs::getLayer(cluskey);
168 
169  // get circle position at target surface radius
170  double target_radius = layer_radius[layer-7];
171  int ret = get_circle_circle_intersection(target_radius, R, X0, Y0, global[0], global[1], _x_proj, _y_proj);
172  if(ret == Fun4AllReturnCodes::ABORTEVENT) continue; // skip to next cluster
173  // z projection is unique
174  _z_proj = B + A * target_radius;
175 
176  // get circle position at cluster radius
177  double cluster_radius = sqrt(global[0] * global[0] + global[1] * global[1]);
178  ret = get_circle_circle_intersection(cluster_radius, R, X0, Y0, global[0], global[1], _x_start, _y_start);
179  if(ret == Fun4AllReturnCodes::ABORTEVENT) continue; // skip to next cluster
180  // z projection is unique
181  _z_start = B + A * cluster_radius;
182 
183  // calculate dx, dy, dz along circle trajectory from cluster radius to surface radius
184  double xnew = global[0] - (_x_start - _x_proj);
185  double ynew = global[1] - (_y_start - _y_proj);
186  double znew = global[2] - (_z_start - _z_proj);
187 
188  // now move the cluster to the surface radius
189  // we keep the cluster key fixed, change the surface if necessary
190  // write the new cluster position local coordinates on the surface
191 
192  Acts::Vector3 global_new(xnew, ynew, znew);
193 
197  tpcHitSetKey,
198  global_new,
199  subsurfkey);
200 
201  if(!surface)
202  {
205  std::cout << PHWHERE << "Failed to find surface for cluster " << cluskey << std::endl;
206  continue;
207  }
208 
209  // get the original cluster
211 
212  // put the corrected cluster in the new cluster map
213 
214  // ghost tracks can have repeat clusters, so check if cluster already moved
216 
217  // create new cluster
218  auto newclus = new TrkrClusterv3;
219 
220  // copy from source
221  newclus->CopyFrom( cluster );
222 
223  // assign subsurface key
224  newclus->setSubSurfKey(subsurfkey);
225 
226  // get local coordinates
227  Acts::Vector3 normal = surface->normal(_tGeometry->geometry().getGeoContext());
228  auto local = surface->globalToLocal(_tGeometry->geometry().getGeoContext(),
229  global * Acts::UnitConstants::cm,
230  normal);
231 
232  Acts::Vector2 localPos;
233  if(local.ok())
234  {
235  localPos = local.value() / Acts::UnitConstants::cm;
236  }
237  else
238  {
240  Acts::Vector3 center = surface->center(_tGeometry->geometry().getGeoContext())/Acts::UnitConstants::cm;
241  double clusRadius = sqrt(xnew * xnew + ynew * ynew);
242  double clusphi = atan2(ynew, xnew);
243  double rClusPhi = clusRadius * clusphi;
244  double surfRadius = sqrt(center(0)*center(0) + center(1)*center(1));
245  double surfPhiCenter = atan2(center[1], center[0]);
246  double surfRphiCenter = surfPhiCenter * surfRadius;
247  double surfZCenter = center[2];
248 
249  localPos(0) = rClusPhi - surfRphiCenter;
250  localPos(1) = znew - surfZCenter;
251  }
252 
253  if(Verbosity() > 4)
254  {
255  std::cout << "*** cluster_radius " << cluster_radius << " cluster x,y,z: " << global[0] << " " << global[1] << " " << global[2] << std::endl;
256  std::cout << " projection_radius " << target_radius << " proj x,y,z: " << _x_proj << " " << _y_proj << " " << _z_proj << std::endl;
257  std::cout << " traj_start_radius " << cluster_radius << " start x,y,z: "<< _x_start << " " << _y_start << " " << _z_start << std::endl;
258  std::cout << " moved_clus_radius " << target_radius << " final x,y,z: "<< xnew << " " << ynew << " " << znew << std::endl;
259  }
260 
261  // assign to new cluster
262  newclus->setLocalX(localPos(0));
263  newclus->setLocalY(localPos(1));
264 
265  // insert in map
267  }
268 
269  // For normal reconstruction, the silicon clusters for this track will be copied over after the matching is done
270  }
271 
273 }
274 
276 {
278 }
279 
281 {
282  _tpc_geom_container = findNode::getClass<PHG4TpcCylinderGeomContainer>(topNode, "CYLINDERCELLGEOM_SVTX");
283  if (!_tpc_geom_container)
284  {
285  std::cout << PHWHERE << " ERROR: Can't find node CYLINDERCELLGEOM_SVTX" << std::endl;
287  }
288 
289  _cluster_map = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
290  if (!_cluster_map)
291  {
292  std::cout << PHWHERE << " ERROR: Can't find node TRKR_CLUSTER" << std::endl;
294  }
295 
296  _track_map = findNode::getClass<SvtxTrackMap>(topNode, "SvtxTrackMap");
297  if (!_track_map)
298  {
299  std::cout << PHWHERE << " ERROR: Can't find SvtxTrackMap: " << std::endl;
301  }
302 
303  _tGeometry = findNode::getClass<ActsGeometry>(topNode,"ActsGeometry");
304  if(!_tGeometry)
305  {
306  std::cout << PHWHERE << "Error, can't find acts tracking geometry" << std::endl;
308  }
309 
310  // tpc distortion correction
311  _dcc = findNode::getClass<TpcDistortionCorrectionContainer>(topNode,"TpcDistortionCorrectionContainerStatic");
312  if( _dcc )
313  {
314  std::cout << "PHTpcClusterMover: found TPC distortion correction container" << std::endl;
315  }
316 
317  // create the node for distortion corrected clusters, if it does not already exist
318  _corrected_cluster_map = findNode::getClass<TrkrClusterContainer>(topNode, "CORRECTED_TRKR_CLUSTER");
320  {
321  std::cout << "Creating node CORRECTED_TRKR_CLUSTER" << std::endl;
322 
323  PHNodeIterator iter(topNode);
324 
325  // Looking for the DST node
326  PHCompositeNode *dstNode = dynamic_cast<PHCompositeNode *>(iter.findFirst("PHCompositeNode", "DST"));
327  if (!dstNode)
328  {
329  std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl;
331  }
332  PHNodeIterator dstiter(dstNode);
333  PHCompositeNode *DetNode =
334  dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
335  if (!DetNode)
336  {
337  DetNode = new PHCompositeNode("TRKR");
338  dstNode->addNode(DetNode);
339  }
340 
342  PHIODataNode<PHObject> *TrkrClusterContainerNode =
343  new PHIODataNode<PHObject>(_corrected_cluster_map, "CORRECTED_TRKR_CLUSTER", "PHObject");
344  DetNode->addNode(TrkrClusterContainerNode);
345  }
346  else
347  {
349  }
350 
351 
352 
354 }
355 
356 int PHTpcClusterMover::get_circle_circle_intersection(double target_radius, double R, double X0, double Y0, double xclus, double yclus, double &x, double &y)
357 {
358  // finds the intersection of the fitted circle with the cylinder having radius = target_radius
359  const auto [xplus, yplus, xminus, yminus] = TrackFitUtils::circle_circle_intersection(target_radius, R, X0, Y0 );
360 
361  // We only need to check xplus for failure, skip this TPC cluster in that case
362  if(std::isnan(xplus))
363  {
364  if(Verbosity() > 0)
365  {
366  std::cout << " circle/circle intersection calculation failed, skip this cluster" << std::endl;
367  std::cout << " target_radius " << target_radius << " fitted R " << R << " fitted X0 " << X0 << " fitted Y0 " << Y0 << std::endl;
368  }
369  return Fun4AllReturnCodes::ABORTEVENT; // skip to next cluster
370  }
371 
372  // we can figure out which solution is correct based on the cluster position in the TPC
373  if(fabs(xclus - xplus) < 5.0 && fabs(yclus - yplus) < 5.0) // 5 cm, large and arbitrary
374  {
375  x = xplus;
376  y = yplus;
377  }
378  else
379  {
380  x = xminus;
381  y = yminus;
382  }
384  }