Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MicromegasClusterizer.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file MicromegasClusterizer.cc
1 
7 #include "MicromegasDefs.h"
9 
11 #include <g4detectors/PHG4CylinderGeom.h> // for PHG4CylinderGeom
12 
13 #include <trackbase/ActsGeometry.h>
14 #include <trackbase/TrkrClusterContainerv4.h> // for TrkrCluster
16 #include <trackbase/TrkrDefs.h>
17 #include <trackbase/TrkrHitSet.h>
18 #include <trackbase/TrkrHit.h>
21 
24 
26 #include <fun4all/SubsysReco.h> // for SubsysReco
27 
28 #include <phool/getClass.h>
29 #include <phool/PHCompositeNode.h>
30 #include <phool/PHIODataNode.h> // for PHIODataNode
31 #include <phool/PHNode.h> // for PHNode
32 #include <phool/PHNodeIterator.h> // for PHNodeIterator
33 #include <phool/PHObject.h> // for PHObject
34 
35 #include <Eigen/Dense>
36 
37 #include <TVector3.h>
38 
39 #include <cassert>
40 #include <cmath>
41 #include <cstdint> // for uint16_t
42 #include <iterator> // for distance
43 #include <map> // for _Rb_tree_const_it...
44 #include <utility> // for pair, make_pair
45 #include <vector>
46 
47 
48 namespace
49 {
51  template<class T>
52  inline constexpr T square( const T& x ) { return x*x; }
53 
54  // streamers
55  [[maybe_unused]] inline std::ostream& operator << (std::ostream& out, const Acts::Vector3& vector )
56  {
57  out << "( " << vector[0] << "," << vector[1] << "," << vector[2] << ")";
58  return out;
59  }
60 
61  // streamers
62  [[maybe_unused]] inline std::ostream& operator << (std::ostream& out, const Acts::Vector2& vector )
63  {
64  out << "( " << vector[0] << "," << vector[1] << ")";
65  return out;
66  }
67 
68  // streamers
69  [[maybe_unused]] inline std::ostream& operator << (std::ostream& out, const TVector3& vector )
70  {
71  out << "( " << vector.x() << "," << vector.y() << "," << vector.z() << ")";
72  return out;
73  }
74 
75  // streamers
76  [[maybe_unused]] inline std::ostream& operator << (std::ostream& out, const TVector2& vector )
77  {
78  out << "( " << vector.X() << "," << vector.Y() << ")";
79  return out;
80  }
81 
82 }
83 
84 //_______________________________________________________________________________
86  : SubsysReco(name)
87 {}
88 
89 //_____________________________________________________________________
91 {
92  // print configuration
93  std::cout << "MicromegasClusterizer::Init - m_use_default_pedestal: " << m_use_default_pedestal << std::endl;
94  std::cout << "MicromegasClusterizer::Init - m_default_pedestal: " << m_default_pedestal << std::endl;
95  std::cout
96  << "MicromegasClusterizer::Init -"
97  << " m_calibration_filename: "
98  << (m_calibration_filename.empty() ? "unspecified":m_calibration_filename )
99  << std::endl;
100 
101  // read calibrations
102  if( !m_calibration_filename.empty() )
104 
106 }
107 
108 //_______________________________________________________________________________
110 {
111  PHNodeIterator iter(topNode);
112 
113  // Looking for the DST node
114  auto dstNode = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "DST"));
115  assert( dstNode );
116 
117  // Create the Cluster node if missing
118  auto trkrClusterContainer = findNode::getClass<TrkrClusterContainer>(dstNode, "TRKR_CLUSTER");
119  if (!trkrClusterContainer)
120  {
121  PHNodeIterator dstiter(dstNode);
122  auto trkrNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
123  if(!trkrNode)
124  {
125  trkrNode = new PHCompositeNode("TRKR");
126  dstNode->addNode(trkrNode);
127  }
128 
129  trkrClusterContainer = new TrkrClusterContainerv4;
130  auto TrkrClusterContainerNode = new PHIODataNode<PHObject>(trkrClusterContainer, "TRKR_CLUSTER", "PHObject");
131  trkrNode->addNode(TrkrClusterContainerNode);
132  }
133 
134  // create cluster to hit association node, if missing
135  auto trkrClusterHitAssoc = findNode::getClass<TrkrClusterHitAssoc>(topNode,"TRKR_CLUSTERHITASSOC");
136  if(!trkrClusterHitAssoc)
137  {
138  PHNodeIterator dstiter(dstNode);
139  auto trkrNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
140  if(!trkrNode)
141  {
142  trkrNode = new PHCompositeNode("TRKR");
143  dstNode->addNode(trkrNode);
144  }
145 
146  trkrClusterHitAssoc = new TrkrClusterHitAssocv3;
147  PHIODataNode<PHObject> *newNode = new PHIODataNode<PHObject>(trkrClusterHitAssoc, "TRKR_CLUSTERHITASSOC", "PHObject");
148  trkrNode->addNode(newNode);
149  }
151 }
152 
153 //_______________________________________________________________________________
155 {
156 
157  // geometry
158  PHG4CylinderGeomContainer* geonode = nullptr;
159  for( std::string geonodename: {"CYLINDERGEOM_MICROMEGAS_FULL", "CYLINDERGEOM_MICROMEGAS" } )
160  { if(( geonode = findNode::getClass<PHG4CylinderGeomContainer>(topNode, geonodename.c_str()) )) break; }
161  assert(geonode);
162 
163  // hitset container
164  auto trkrhitsetcontainer = findNode::getClass<TrkrHitSetContainer>(topNode, "TRKR_HITSET");
165  assert( trkrhitsetcontainer );
166 
167  // cluster container
168  auto trkrClusterContainer = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
169  assert( trkrClusterContainer );
170 
171  // cluster-hit association
172  auto trkrClusterHitAssoc = findNode::getClass<TrkrClusterHitAssoc>(topNode, "TRKR_CLUSTERHITASSOC");
173  assert( trkrClusterHitAssoc );
174 
175  // geometry
176  auto acts_geometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
177  assert( acts_geometry );
178 
179  // loop over micromegas hitsets
180  const auto hitset_range = trkrhitsetcontainer->getHitSets(TrkrDefs::TrkrId::micromegasId);
181  for( auto hitset_it = hitset_range.first; hitset_it != hitset_range.second; ++hitset_it )
182  {
183  // get hitset, key and layer
184  TrkrHitSet* hitset = hitset_it->second;
185  const TrkrDefs::hitsetkey hitsetkey = hitset_it->first;
186  const auto layer = TrkrDefs::getLayer(hitsetkey);
187  const auto tileid = MicromegasDefs::getTileId(hitsetkey);
188 
189  // get micromegas geometry object
190  const auto layergeom = dynamic_cast<CylinderGeomMicromegas*>(geonode->GetLayerGeom(layer));
191  assert(layergeom);
192 
193  // get micromegas acts surface
194  const auto acts_surface = acts_geometry->maps().getMMSurface( hitsetkey);
195  if( !acts_surface )
196  {
197  std::cout
198  << "MicromegasClusterizer::process_event -"
199  << " could not find surface for layer " << (int) layer << " tile: " << (int) tileid
200  << " skipping hitset"
201  << std::endl;
202  continue;
203  }
204 
205  /*
206  * get segmentation type, layer thickness, strip length and pitch.
207  * They are used to calculate cluster errors
208  */
209  const auto segmentation_type = layergeom->get_segmentation_type();
210  const double pitch = layergeom->get_pitch();
211  const double strip_length = layergeom->get_strip_length( tileid, acts_geometry );
212 
213  // keep a list of ranges corresponding to each cluster
214  using range_list_t = std::vector<TrkrHitSet::ConstRange>;
215  range_list_t ranges;
216 
217  // loop over hits
218  const auto hit_range = hitset->getHits();
219 
220  // keep track of first iterator of runing cluster
221  auto begin = hit_range.first;
222 
223  // keep track of previous strip
224  uint16_t previous_strip = 0;
225  bool first = true;
226 
227  for( auto hit_it = hit_range.first; hit_it != hit_range.second; ++hit_it )
228  {
229 
230  // get hit key
231  const auto hitkey = hit_it->first;
232 
233  // get strip number
234  const auto strip = MicromegasDefs::getStrip( hitkey );
235 
236  if( first )
237  {
238 
239  previous_strip = strip;
240  first = false;
241  continue;
242 
243  } else if( strip - previous_strip > 1 ) {
244 
245  // store current cluster range
246  ranges.push_back( std::make_pair( begin, hit_it ) );
247 
248  // reinitialize begin of next cluster range
249  begin = hit_it;
250 
251  }
252 
253  // update previous strip
254  previous_strip = strip;
255 
256  }
257 
258  // store last cluster
259  if( begin != hit_range.second ) ranges.push_back( std::make_pair( begin, hit_range.second ) );
260 
261  // initialize cluster count
262  int cluster_count = 0;
263 
264  // loop over found hit ranges and create clusters
265  for( const auto& range : ranges )
266  {
267  // create cluster key and corresponding cluster
268  const auto ckey = TrkrDefs::genClusKey( hitsetkey, cluster_count++ );
269 
270  TVector2 local_coordinates;
271  double weight_sum = 0;
272 
273  // needed for proper error calculation
274  // it is either the sum over z, or phi, depending on segmentation
275  double coord_sum = 0;
276  double coordsquare_sum = 0;
277 
278  // also store adc value
279  unsigned int adc_sum = 0;
280  unsigned int max_adc = 0;
281  unsigned int strip_count = 0;
282  // loop over constituting hits
283  for( auto hit_it = range.first; hit_it != range.second; ++hit_it )
284  {
285  ++strip_count;
286  // get hit key
287  const auto hitkey = hit_it->first;
288  const auto hit = hit_it->second;
289 
290  // associate cluster key to hit key
291  trkrClusterHitAssoc->addAssoc(ckey, hitkey );
292 
293  // get strip number
294  const auto strip = MicromegasDefs::getStrip( hitkey );
295 
296  // get adc, remove pedestal
297  const double pedestal = m_use_default_pedestal ?
299  m_calibration_data.get_pedestal_mapped(hitsetkey, strip);
300  const double weight = double(hit->getAdc()) - pedestal;
301 
302  // increment cluster adc
303  const auto hit_adc = hit->getAdc();
304  if( hit_adc > max_adc) { max_adc = hit_adc; }
305  adc_sum += hit_adc;
306 
307  // get strip local coordinate and update relevant sums
308  const auto strip_local_coordinate = layergeom->get_local_coordinates( tileid, acts_geometry, strip );
309  local_coordinates += strip_local_coordinate*weight;
310  switch( segmentation_type )
311  {
313  {
314 
315  coord_sum += strip_local_coordinate.X()*weight;
316  coordsquare_sum += square(strip_local_coordinate.X())*weight;
317  break;
318  }
319 
321  {
322  coord_sum += strip_local_coordinate.Y()*weight;
323  coordsquare_sum += square(strip_local_coordinate.Y())*weight;
324  break;
325  }
326  }
327 
328  weight_sum += weight;
329 
330  }
331 
332  local_coordinates *= (1./weight_sum);
333 
334  // dimension and error in r, rphi and z coordinates
335  static const float invsqrt12 = 1./std::sqrt(12);
336  static constexpr float error_scale_phi = 1.6;
337  static constexpr float error_scale_z = 0.8;
338 
339  auto coord_cov = coordsquare_sum/weight_sum - square( coord_sum/weight_sum );
340  auto coord_error_sq = coord_cov/weight_sum;
341 
342  // local errors (x is along rphi, y is along z)
343  double error_sq_x = 0;
344  double error_sq_y = 0;
345  switch( segmentation_type )
346  {
348  {
349  if( coord_error_sq == 0 ) coord_error_sq = square(pitch)/12;
350  else coord_error_sq *= square(error_scale_phi);
351  error_sq_x = coord_error_sq;
352  error_sq_y = square(strip_length*invsqrt12);
353  break;
354  }
355 
357  {
358  if( coord_error_sq == 0 ) coord_error_sq = square(pitch)/12;
359  else coord_error_sq *= square(error_scale_z);
360  error_sq_x = square(strip_length*invsqrt12);
361  error_sq_y = coord_error_sq;
362  break;
363  }
364  }
365 
366 
367  auto cluster = std::make_unique<TrkrClusterv5>();
368  cluster->setAdc( adc_sum );
369  cluster->setMaxAdc( max_adc );
370  cluster->setLocalX(local_coordinates.X());
371  cluster->setLocalY(local_coordinates.Y());
372  cluster->setPhiError(sqrt(error_sq_x));
373  cluster->setZError(sqrt(error_sq_y));
374  // store cluster size
375  switch( segmentation_type )
376  {
378  {
379  cluster->setPhiSize(strip_count);
380  cluster->setZSize(1);
381  break;
382  }
383 
385  {
386  cluster->setPhiSize(1);
387  cluster->setZSize(strip_count);
388  break;
389  }
390  }
391  // add to container
392  trkrClusterContainer->addClusterSpecifyKey( ckey, cluster.release() );
393 
394 
395  }
396 
397  }
398  // done
400 }