File indexing completed on 2025-12-16 09:20:13
0001
0002
0003
0004
0005
0006 #include "MicromegasClusterizer.h"
0007 #include "MicromegasDefs.h"
0008 #include "CylinderGeomMicromegas.h"
0009
0010 #include <g4detectors/PHG4CylinderGeomContainer.h>
0011 #include <g4detectors/PHG4CylinderGeom.h> // for PHG4CylinderGeom
0012
0013 #include <trackbase/ActsGeometry.h>
0014 #include <trackbase/TrkrClusterContainerv4.h> // for TrkrCluster
0015 #include <trackbase/TrkrClusterv5.h>
0016 #include <trackbase/TrkrDefs.h>
0017 #include <trackbase/TrkrHitSet.h>
0018 #include <trackbase/TrkrHit.h>
0019 #include <trackbase/TrkrHitSetContainer.h>
0020 #include <trackbase/TrkrClusterHitAssocv3.h>
0021
0022 #include <Acts/Definitions/Units.hpp>
0023 #include <Acts/Surfaces/Surface.hpp>
0024
0025 #include <fun4all/Fun4AllReturnCodes.h>
0026 #include <fun4all/SubsysReco.h> // for SubsysReco
0027
0028 #include <phool/getClass.h>
0029 #include <phool/PHCompositeNode.h>
0030 #include <phool/PHIODataNode.h> // for PHIODataNode
0031 #include <phool/PHNode.h> // for PHNode
0032 #include <phool/PHNodeIterator.h> // for PHNodeIterator
0033 #include <phool/PHObject.h> // for PHObject
0034
0035 #include <Eigen/Dense>
0036
0037 #include <TVector3.h>
0038
0039 #include <cassert>
0040 #include <cmath>
0041 #include <cstdint> // for uint16_t
0042 #include <iterator> // for distance
0043 #include <map> // for _Rb_tree_const_it...
0044 #include <utility> // for pair, make_pair
0045 #include <vector>
0046
0047
0048 namespace
0049 {
0050
0051 template<class T>
0052 inline constexpr T square( const T& x ) { return x*x; }
0053
0054
0055 [[maybe_unused]] inline std::ostream& operator << (std::ostream& out, const Acts::Vector3& vector )
0056 {
0057 out << "( " << vector[0] << "," << vector[1] << "," << vector[2] << ")";
0058 return out;
0059 }
0060
0061
0062 [[maybe_unused]] inline std::ostream& operator << (std::ostream& out, const Acts::Vector2& vector )
0063 {
0064 out << "( " << vector[0] << "," << vector[1] << ")";
0065 return out;
0066 }
0067
0068
0069 [[maybe_unused]] inline std::ostream& operator << (std::ostream& out, const TVector3& vector )
0070 {
0071 out << "( " << vector.x() << "," << vector.y() << "," << vector.z() << ")";
0072 return out;
0073 }
0074
0075
0076 [[maybe_unused]] inline std::ostream& operator << (std::ostream& out, const TVector2& vector )
0077 {
0078 out << "( " << vector.X() << "," << vector.Y() << ")";
0079 return out;
0080 }
0081
0082 }
0083
0084
0085 MicromegasClusterizer::MicromegasClusterizer(const std::string &name )
0086 : SubsysReco(name)
0087 {}
0088
0089
0090 int MicromegasClusterizer::Init(PHCompositeNode* )
0091 {
0092
0093 std::cout << "MicromegasClusterizer::Init - m_use_default_pedestal: " << m_use_default_pedestal << std::endl;
0094 std::cout << "MicromegasClusterizer::Init - m_default_pedestal: " << m_default_pedestal << std::endl;
0095 std::cout
0096 << "MicromegasClusterizer::Init -"
0097 << " m_calibration_filename: "
0098 << (m_calibration_filename.empty() ? "unspecified":m_calibration_filename )
0099 << std::endl;
0100
0101
0102 if( !m_calibration_filename.empty() )
0103 { m_calibration_data.read( m_calibration_filename ); }
0104
0105 return Fun4AllReturnCodes::EVENT_OK;
0106 }
0107
0108
0109 int MicromegasClusterizer::InitRun(PHCompositeNode *topNode)
0110 {
0111 PHNodeIterator iter(topNode);
0112
0113
0114 auto dstNode = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "DST"));
0115 assert( dstNode );
0116
0117
0118 auto trkrClusterContainer = findNode::getClass<TrkrClusterContainer>(dstNode, "TRKR_CLUSTER");
0119 if (!trkrClusterContainer)
0120 {
0121 PHNodeIterator dstiter(dstNode);
0122 auto trkrNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
0123 if(!trkrNode)
0124 {
0125 trkrNode = new PHCompositeNode("TRKR");
0126 dstNode->addNode(trkrNode);
0127 }
0128
0129 trkrClusterContainer = new TrkrClusterContainerv4;
0130 auto TrkrClusterContainerNode = new PHIODataNode<PHObject>(trkrClusterContainer, "TRKR_CLUSTER", "PHObject");
0131 trkrNode->addNode(TrkrClusterContainerNode);
0132 }
0133
0134
0135 auto trkrClusterHitAssoc = findNode::getClass<TrkrClusterHitAssoc>(topNode,"TRKR_CLUSTERHITASSOC");
0136 if(!trkrClusterHitAssoc)
0137 {
0138 PHNodeIterator dstiter(dstNode);
0139 auto trkrNode = dynamic_cast<PHCompositeNode *>(dstiter.findFirst("PHCompositeNode", "TRKR"));
0140 if(!trkrNode)
0141 {
0142 trkrNode = new PHCompositeNode("TRKR");
0143 dstNode->addNode(trkrNode);
0144 }
0145
0146 trkrClusterHitAssoc = new TrkrClusterHitAssocv3;
0147 PHIODataNode<PHObject> *newNode = new PHIODataNode<PHObject>(trkrClusterHitAssoc, "TRKR_CLUSTERHITASSOC", "PHObject");
0148 trkrNode->addNode(newNode);
0149 }
0150 return Fun4AllReturnCodes::EVENT_OK;
0151 }
0152
0153
0154 int MicromegasClusterizer::process_event(PHCompositeNode *topNode)
0155 {
0156
0157
0158 PHG4CylinderGeomContainer* geonode = nullptr;
0159 for( std::string geonodename: {"CYLINDERGEOM_MICROMEGAS_FULL", "CYLINDERGEOM_MICROMEGAS" } )
0160 { if(( geonode = findNode::getClass<PHG4CylinderGeomContainer>(topNode, geonodename.c_str()) )) { break;
0161 }}
0162 assert(geonode);
0163
0164
0165 auto trkrhitsetcontainer = findNode::getClass<TrkrHitSetContainer>(topNode, "TRKR_HITSET");
0166 assert( trkrhitsetcontainer );
0167
0168
0169 auto trkrClusterContainer = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
0170 assert( trkrClusterContainer );
0171
0172
0173 auto trkrClusterHitAssoc = findNode::getClass<TrkrClusterHitAssoc>(topNode, "TRKR_CLUSTERHITASSOC");
0174 assert( trkrClusterHitAssoc );
0175
0176
0177 auto acts_geometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
0178 assert( acts_geometry );
0179
0180
0181 const auto hitset_range = trkrhitsetcontainer->getHitSets(TrkrDefs::TrkrId::micromegasId);
0182 for( auto hitset_it = hitset_range.first; hitset_it != hitset_range.second; ++hitset_it )
0183 {
0184
0185 TrkrHitSet* hitset = hitset_it->second;
0186 const TrkrDefs::hitsetkey hitsetkey = hitset_it->first;
0187 const auto layer = TrkrDefs::getLayer(hitsetkey);
0188 const auto tileid = MicromegasDefs::getTileId(hitsetkey);
0189
0190
0191 const auto layergeom = dynamic_cast<CylinderGeomMicromegas*>(geonode->GetLayerGeom(layer));
0192 assert(layergeom);
0193
0194
0195 const auto acts_surface = acts_geometry->maps().getMMSurface( hitsetkey);
0196 if( !acts_surface )
0197 {
0198 std::cout
0199 << "MicromegasClusterizer::process_event -"
0200 << " could not find surface for layer " << (int) layer << " tile: " << (int) tileid
0201 << " skipping hitset"
0202 << std::endl;
0203 continue;
0204 }
0205
0206
0207
0208
0209
0210 const auto segmentation_type = layergeom->get_segmentation_type();
0211 const double pitch = layergeom->get_pitch();
0212 const double strip_length = layergeom->get_strip_length( tileid, acts_geometry );
0213
0214
0215 using range_list_t = std::vector<TrkrHitSet::ConstRange>;
0216 range_list_t ranges;
0217
0218
0219 const auto hit_range = hitset->getHits();
0220
0221
0222 auto begin = hit_range.first;
0223
0224
0225 uint16_t previous_strip = 0;
0226 bool first = true;
0227
0228 for( auto hit_it = hit_range.first; hit_it != hit_range.second; ++hit_it )
0229 {
0230
0231
0232 const auto hitkey = hit_it->first;
0233
0234
0235 const auto strip = MicromegasDefs::getStrip( hitkey );
0236
0237 if( first )
0238 {
0239
0240 previous_strip = strip;
0241 first = false;
0242 continue;
0243
0244 } else if( strip - previous_strip > 1 ) {
0245
0246
0247 ranges.push_back( std::make_pair( begin, hit_it ) );
0248
0249
0250 begin = hit_it;
0251
0252 }
0253
0254
0255 previous_strip = strip;
0256
0257 }
0258
0259
0260 if( begin != hit_range.second ) { ranges.push_back( std::make_pair( begin, hit_range.second ) );
0261 }
0262
0263
0264 int cluster_count = 0;
0265
0266
0267 for( const auto& range : ranges )
0268 {
0269
0270 const auto ckey = TrkrDefs::genClusKey( hitsetkey, cluster_count++ );
0271
0272 TVector2 local_coordinates;
0273 double weight_sum = 0;
0274
0275
0276
0277 double coord_sum = 0;
0278 double coordsquare_sum = 0;
0279
0280
0281 unsigned int adc_sum = 0;
0282 unsigned int max_adc = 0;
0283 const unsigned int strip_count = std::distance(range.first,range.second);
0284 if(m_drop_single_strips && strip_count < 2)
0285 { continue; }
0286
0287
0288 for( auto hit_it = range.first; hit_it != range.second; ++hit_it )
0289 {
0290
0291 const auto hitkey = hit_it->first;
0292 const auto hit = hit_it->second;
0293
0294
0295 trkrClusterHitAssoc->addAssoc(ckey, hitkey );
0296
0297
0298 const auto strip = MicromegasDefs::getStrip( hitkey );
0299
0300
0301 const double pedestal = m_use_default_pedestal ?
0302 m_default_pedestal:
0303 m_calibration_data.get_pedestal_mapped(hitsetkey, strip);
0304 const double weight = double(hit->getAdc()) - pedestal;
0305
0306
0307 const auto hit_adc = hit->getAdc();
0308 if( hit_adc > max_adc) { max_adc = hit_adc; }
0309 adc_sum += hit_adc;
0310
0311
0312 const auto strip_local_coordinate = layergeom->get_local_coordinates( tileid, acts_geometry, strip );
0313 local_coordinates += strip_local_coordinate*weight;
0314 switch( segmentation_type )
0315 {
0316 case MicromegasDefs::SegmentationType::SEGMENTATION_PHI:
0317 {
0318
0319 coord_sum += strip_local_coordinate.X()*weight;
0320 coordsquare_sum += square(strip_local_coordinate.X())*weight;
0321 break;
0322 }
0323
0324 case MicromegasDefs::SegmentationType::SEGMENTATION_Z:
0325 {
0326 coord_sum += strip_local_coordinate.Y()*weight;
0327 coordsquare_sum += square(strip_local_coordinate.Y())*weight;
0328 break;
0329 }
0330 }
0331
0332 weight_sum += weight;
0333
0334 }
0335
0336 local_coordinates *= (1./weight_sum);
0337
0338
0339 static const float invsqrt12 = 1./std::sqrt(12);
0340 static constexpr float error_scale_phi = 1.6;
0341 static constexpr float error_scale_z = 0.8;
0342
0343 auto coord_cov = coordsquare_sum/weight_sum - square( coord_sum/weight_sum );
0344 auto coord_error_sq = coord_cov/weight_sum;
0345
0346
0347 double error_sq_x = 0;
0348 double error_sq_y = 0;
0349 switch( segmentation_type )
0350 {
0351 case MicromegasDefs::SegmentationType::SEGMENTATION_PHI:
0352 {
0353 if( coord_error_sq == 0 ) { coord_error_sq = square(pitch)/12;
0354 } else { coord_error_sq *= square(error_scale_phi);
0355 }
0356 error_sq_x = coord_error_sq;
0357 error_sq_y = square(strip_length*invsqrt12);
0358 break;
0359 }
0360
0361 case MicromegasDefs::SegmentationType::SEGMENTATION_Z:
0362 {
0363 if( coord_error_sq == 0 ) { coord_error_sq = square(pitch)/12;
0364 } else { coord_error_sq *= square(error_scale_z);
0365 }
0366 error_sq_x = square(strip_length*invsqrt12);
0367 error_sq_y = coord_error_sq;
0368 break;
0369 }
0370 }
0371
0372 auto cluster = std::make_unique<TrkrClusterv5>();
0373 cluster->setAdc( adc_sum );
0374 cluster->setMaxAdc( max_adc );
0375 cluster->setLocalX(local_coordinates.X());
0376 cluster->setLocalY(local_coordinates.Y());
0377 cluster->setPhiError(sqrt(error_sq_x));
0378 cluster->setZError(sqrt(error_sq_y));
0379
0380
0381 switch( segmentation_type )
0382 {
0383 case MicromegasDefs::SegmentationType::SEGMENTATION_PHI:
0384 {
0385 cluster->setPhiSize(strip_count);
0386 cluster->setZSize(1);
0387 break;
0388 }
0389
0390 case MicromegasDefs::SegmentationType::SEGMENTATION_Z:
0391 {
0392 cluster->setPhiSize(1);
0393 cluster->setZSize(strip_count);
0394 break;
0395 }
0396 }
0397
0398 trkrClusterContainer->addClusterSpecifyKey( ckey, cluster.release() );
0399
0400
0401 ++m_clustercounts[hitsetkey];
0402
0403 }
0404
0405 }
0406
0407 return Fun4AllReturnCodes::EVENT_OK;
0408 }
0409
0410
0411 int MicromegasClusterizer::End(PHCompositeNode* )
0412 {
0413
0414 {
0415 for (const auto& [hitsetkey, count] : m_clustercounts)
0416 {
0417 std::cout << "MicromegasClusterizer::End - hitsetkey: " << hitsetkey << ", cluster count: " << count << std::endl;
0418 }
0419 }
0420
0421 return Fun4AllReturnCodes::EVENT_OK;
0422 }