3 #include <EVENT/LCCollection.h>
4 #include <EVENT/SimCalorimeterHit.h>
5 #include <IMPL/CalorimeterHitImpl.h>
6 #include <IMPL/LCCollectionVec.h>
7 #include <EVENT/MCParticle.h>
8 #include <IMPL/LCFlagImpl.h>
9 #include <IMPL/LCRelationImpl.h>
10 #include <marlin/Global.h>
11 #include <marlin/Exceptions.h>
13 #include <EVENT/LCParameters.h>
14 #include <UTIL/CellIDDecoder.h>
15 #include <UTIL/CellIDEncoder.h>
22 #include "marlin/VerbosityLevels.h"
23 #include "CalorimeterHitType.h"
25 #include <marlin/AIDAProcessor.h>
26 #include <AIDA/ITupleFactory.h>
27 #include <AIDA/ITuple.h>
29 #include <DDSegmentation/BitField64.h>
30 #include <DDRec/CellIDPositionConverter.h>
31 #include <DD4hep/DetectorSelector.h>
33 using namespace lcio ;
34 using namespace marlin ;
42 : Processor(
"SimDigital") ,
43 chargeSpreaderParameters()
45 _description =
"This processor creates SDHCAL digitized CalorimeterHits from SDHCAL SimCalorimeterHits" ;
48 std::vector<std::string> hcalCollections = {
"HcalBarrelCollection" ,
"HcalEndCapRingsCollection" ,
"HcalEndCapsCollection" } ;
49 registerInputCollections( LCIO::SIMCALORIMETERHIT,
50 "inputHitCollections" ,
51 "Sim Calorimeter Hit Collections" ,
56 std::vector<std::string> outputHcalCollections = {
"HCALBarrelDigi" ,
"HCALEndcapDigi" ,
"HCALOtherDigi" } ;
57 registerProcessorParameter(
"outputHitCollections",
58 "output hit collection names",
60 outputHcalCollections) ;
62 std::vector<std::string> outputRelCollections = {} ;
63 registerProcessorParameter(
"outputRelationCollections",
64 "output hit relation Collection Names" ,
66 outputRelCollections ) ;
69 std::vector<float> hcalThresholds = {0.1f} ;
70 registerProcessorParameter(
"HCALThreshold" ,
71 "Threshold for HCAL Hits in pC" ,
75 registerProcessorParameter(
"HCALCellSize" ,
76 "Cell size (mm) of HCAL, if it is equal or less than zero then the value is taken from dd4hep" ,
81 registerProcessorParameter(
"EffMapOption" ,
82 "Step efficiency correction method : should be Uniform" ,
84 std::string(
"Uniform") ) ;
86 registerProcessorParameter(
"EffMapConstantValue",
87 "Value of the constant term for efficiency correction if EffMapOption==Uniform",
91 registerProcessorParameter(
"EffMapFile" ,
92 "Efficiency map file" ,
98 registerProcessorParameter(
"SpreaderMapFile",
99 "Charge spreader map file",
103 registerProcessorParameter(
"functionRange" ,
104 "maximal distance (in mm) at which a step can induce charge using the 2D function defined with functionFormula or when using ChargeSplitterOption==Erf",
109 registerProcessorParameter(
"RPC_PadSeparation",
110 "distance in mm between two RPC pads : used if ChargeSplitterOption==Function or Erf",
114 std::vector<float> erfWidth = {2} ;
115 registerProcessorParameter(
"erfWidth",
116 "Width values for the different Erf functions",
120 std::vector<float> erfWeigth = {1} ;
121 registerProcessorParameter(
"erfWeigth",
122 "Weigth for the different Erf functions",
127 registerProcessorParameter(
"ChargeSplitterd",
128 "d parameter for exact splitter",
132 registerProcessorParameter(
"ChargeSplitterOption",
133 "Define the charge splitter method. Possible option : Erf , Exact",
135 std::string(
"Erf") ) ;
140 registerProcessorParameter(
"CellIDEncodingStringType",
141 "The type of the encoding, LCGEO or PROTO",
143 std::string(
"LCGEO")) ;
147 registerProcessorParameter(
"doThresholds",
148 "Replace analog hit energy by value given in CalibrHCAL according to thresholds given in HCALThreshold",
153 registerProcessorParameter(
"PolyaOption" ,
154 "Uniform polya or different polya per Asic",
156 std::string(
"Uniform") ) ;
158 registerProcessorParameter(
"PolyaMapFile" ,
163 registerProcessorParameter(
"PolyaRandomSeed",
164 "The seed of the polya function",
168 registerProcessorParameter(
"PolyaAverageCharge" ,
169 "Parameter for the Polya distribution used to simulate the induced charge distribution : mean of the distribution",
173 registerProcessorParameter(
"PolyaWidthParameter" ,
174 "Parameter for the Polya distribution used to simulate the induced charge distribution : related to the distribution width ",
179 registerProcessorParameter(
"GasGapWidth" ,
180 "Width of the RPC gas gap",
186 registerProcessorParameter(
"LinkSteps" ,
187 "Parameter for angle correction",
192 registerProcessorParameter(
"AngleCorrectionPower" ,
193 "Parameter for angle correction",
197 registerProcessorParameter(
"TimeCut" ,
200 std::numeric_limits<double>::max() ) ;
202 registerProcessorParameter(
"StepLengthCut" ,
211 registerProcessorParameter(
"StepCellCenterMaxDistanceLayerDirection",
212 "Maximum distance (mm) between the Geant4 step position and the cell center, in the RPC width direction, to keep a step for digitization",
216 registerProcessorParameter(
"StepsMinDistanceRPCplaneDirection",
217 "Minimum distance (mm) between 2 Geant4 steps, in the RPC plane, to keep the 2 steps",
221 registerProcessorParameter(
"KeepAtLeastOneStep",
222 "if true, ensure that each hit will keep at least one step for digitisation independatly of filtering conditions (StepCellCenterMaxDistanceLayerDirection)",
241 throw ParseException(
chargeSpreaderOption + std::string(
" option for charge inducing is not available ") ) ;
255 throw ParseException(
chargeSpreaderOption + std::string(
" option for charge splitting is not available ") ) ;
267 throw ParseException(
efficiencyOption + std::string(
" option for efficiency correction is not available") ) ;
276 "SimDigital_StepDebug",
277 "int filterlevel, float stepTime,deltaI,deltaJ,deltaLayer,minIJdist,length,charge");
278 streamlog_out(DEBUG) <<
"Tuple for step debug has been initialized to " << _debugTupleStepFilter << std::endl;
279 streamlog_out(DEBUG) <<
"it has " << _debugTupleStepFilter->columns() <<
" columns" <<std::endl;
282 _tupleStepFilter = AIDAProcessor::tupleFactory(
this )->create(
"SimDigitalStepStat",
283 "SimDigital_StepStat",
284 "int allsteps, absZfiltered, IJdistancefiltered");
285 streamlog_out(DEBUG) <<
"Tuple for step stat has been initialized to " <<
_tupleStepFilter << std::endl;
286 streamlog_out(DEBUG) <<
"it has " <<
_tupleStepFilter->columns() <<
" columns" <<std::endl;
289 _tupleCollection = AIDAProcessor::tupleFactory(
this )->create(
"CollectionStat",
290 "Collection_statistics",
291 "int NsimHit, NrecoHit, N1, N2, N3");
292 streamlog_out(DEBUG) <<
"Tuple for collection stat has been initialized to " <<
_tupleCollection << std::endl;
293 streamlog_out(DEBUG) <<
"it has " <<
_tupleCollection->columns() <<
" columns" <<std::endl;
295 _histoCellCharge = AIDAProcessor::histogramFactory(
this )->createHistogram1D(
"CellCharge",
"CellCharge",10000,0,100) ;
298 flag.setBit(LCIO::CHBIT_LONG) ;
299 flag.setBit(LCIO::RCHBIT_TIME) ;
300 flagRel.setBit(LCIO::LCREL_WEIGHTED) ;
305 if ( vec.size() == 0 )
307 std::vector<StepAndCharge>::iterator first = vec.begin() ;
308 std::vector<StepAndCharge>::iterator lasttobekept = vec.end() ;
311 while (
int(first-lasttobekept)<0)
313 std::vector<StepAndCharge>::iterator second=first;
315 while (
int(second-lasttobekept) < 0)
321 std::iter_swap(second,lasttobekept);
329 std::vector<StepAndCharge>::iterator firstToremove=lasttobekept;
333 vec.erase(firstToremove,vec.end());
340 for (std::vector<StepAndCharge>::const_iterator it=vec.begin(); it != vec.end(); it++)
348 for (std::vector<StepAndCharge>::const_iterator itB=vec.begin(); itB != vec.end(); itB++)
352 float dist = ( (it->step)-(itB->step) ).perp() ;
368 int numElements = col->getNumberOfElements() ;
370 for (
int j = 0 ; j < numElements ; ++j )
372 SimCalorimeterHit* hit =
dynamic_cast<SimCalorimeterHit*
>( col->getElementAt( j ) ) ;
374 std::vector<StepAndCharge> steps ;
384 auto timeGreaterThan = [&](
const StepAndCharge& v) ->
bool {
return std::fabs( v.time ) >
timeCut ; } ;
385 std::vector<StepAndCharge>::iterator remPos = std::remove_if(steps.begin() , steps.end() , timeGreaterThan ) ;
386 steps.erase( remPos , steps.end() ) ;
391 remPos = std::remove_if( steps.begin() , steps.end() , stepSmallerThan ) ;
392 steps.erase( remPos , steps.end() ) ;
398 remPos = std::remove_if(steps.begin() , steps.end() , absZGreaterThan ) ;
402 steps.erase( remPos , steps.end() ) ;
405 auto randomGreater = [eff](
const StepAndCharge&) ->
bool {
return static_cast<double>(rand())/RAND_MAX > eff ; } ;
406 steps.erase( std::remove_if(steps.begin() , steps.end() , randomGreater ) , steps.end() ) ;
411 for (
auto& itstep : steps )
413 float angleCorr = 1 ;
414 if ( itstep.stepLength*invGasGapWidth > 1 )
415 angleCorr = std::pow( itstep.stepLength*invGasGapWidth ,
_angleCorrPow ) ;
419 streamlog_out( DEBUG ) <<
"step at : " << itstep.step <<
"\t with a charge of : " << itstep.charge << std::endl ;
424 std::sort(steps.begin(), steps.end(), sortStepWithCharge ) ;
426 streamlog_out( DEBUG ) <<
"sim hit at " << hit << std::endl ;
427 if (streamlog_level(DEBUG) )
429 for(std::vector<StepAndCharge>::iterator it=steps.begin(); it!=steps.end(); ++it)
430 streamlog_out( DEBUG ) <<
"step at : " << (*it).step <<
"\t with a charge of : " << (*it).charge << std::endl;
438 float time = std::numeric_limits<float>::max() ;
439 for (
const auto& step : steps )
440 time = std::min(time , step.time) ;
444 chargeSpreader->
addCharge( itstep.charge , static_cast<float>(itstep.step.x()) , static_cast<float>(itstep.step.y()) , aGeomCellId ) ;
451 std::unique_ptr<CalorimeterHitImpl> tmp = aGeomCellId->
encode(it.first.first , it.first.second) ;
456 dd4hep::long64 index = tmp->getCellID1() ;
457 index = index << 32 ;
458 index += tmp->getCellID0() ;
460 if ( myHitMap.find(index) == myHitMap.end() )
463 toto.
ahit = std::move(tmp) ;
464 toto.
ahit->setEnergy(0) ;
465 toto.
ahit->setTime(time) ;
468 hitMemory& calhitMem = myHitMap.at(index) ;
476 calhitMem.
ahit->setEnergy( calhitMem.
ahit->getEnergy() + it.second ) ;
481 streamlog_out(ERROR) <<
"BUG in charge splitter, got a non positive charge : " << it.second << std::endl ;
487 for(
const auto& it : myHitMap )
488 _hitCharge.push_back( it.second.ahit->getEnergy() ) ;
496 for (
auto it = myHitMap.cbegin() ; it != myHitMap.cend() ; )
498 if ( (it->second).ahit->getEnergy() < threshold )
499 it = myHitMap.erase(it) ;
508 for (cellIDHitMap::iterator it = myHitMap.begin() ; it != myHitMap.end() ; it++)
511 float hitCharge = currentHitMem.
ahit->getEnergy() ;
513 unsigned int iThr = 0 ;
527 currentHitMem.
ahit->setEnergy( static_cast<float>( iThr+1 ) ) ;
536 outputCol->setFlag(
flag.getFlag()) ;
538 outputRelCol->setFlag(
flagRel.getFlag()) ;
539 outputRelCol->parameters().setValue(
"FromType" , LCIO::CALORIMETERHIT ) ;
540 outputRelCol->parameters().setValue(
"ToType" , LCIO::SIMCALORIMETERHIT ) ;
560 for (cellIDHitMap::iterator it = myHitMap.begin() ; it != myHitMap.end() ; it++)
563 if (currentHitMem.
rawHit != -1)
565 streamlog_out(DEBUG) <<
" rawHit= " << currentHitMem.
rawHit << std::endl ;
566 SimCalorimeterHit* hitraw =
dynamic_cast<SimCalorimeterHit*
>( inputCol->getElementAt( currentHitMem.
rawHit ) ) ;
567 currentHitMem.
ahit->setRawHit(hitraw) ;
570 auto caloHit = currentHitMem.
ahit.release() ;
571 outputCol->addElement(caloHit) ;
574 SimCalorimeterHit* hit =
dynamic_cast<SimCalorimeterHit*
>( inputCol->getElementAt( currentHitMem.
rawHit ) ) ;
575 LCRelationImpl* rel =
new LCRelationImpl(caloHit , hit , 1.0) ;
576 outputRelCol->addElement( rel ) ;
606 LCCollection* inputCol = evt->getCollection( inputColName.c_str() ) ;
607 _counters[
"NSim"] += inputCol->getNumberOfElements() ;
608 CHT::Layout layout = layoutFromString( inputColName ) ;
615 _counters[
"NReco"] += outputCol->getNumberOfElements() ;
617 evt->addCollection(outputCol , outputColName.c_str()) ;
618 evt->addCollection(outputRelCol , outputRelColName.c_str()) ;
620 catch(DataNotAvailableException& )
635 streamlog_out(MESSAGE) <<
"have processed " <<
_counters[
"|ALL"] <<
" events" << std::endl;
static void bookTuples(const marlin::Processor *proc)
virtual void addCharge(float charge, float posI, float posJ, SimDigitalGeomCellId *)
std::string efficiencyOption
AIDA::ITuple * _tupleCollection
void processCollection(LCCollection *inputCol, LCCollectionVec *&outputCol, LCCollectionVec *&outputRelCol, CHT::Layout layout)
std::vector< float > _thresholdHcal
AIDA::ITuple * _tupleStepFilter
virtual void init()
Called at the begin of the job before anything is read.
virtual float getCellSize()=0
std::string chargeSpreaderOption
AIDA::IHistogram1D * _histoCellCharge
std::unique_ptr< CalorimeterHitImpl > ahit
std::vector< float > erfWeigth
virtual float getEfficiency(SimDigitalGeomCellId *cellID)=0
void removeHitsBelowThreshold(cellIDHitMap &myHitMap, float threshold)
std::map< std::string, int > _counters
std::set< int > relatedHits
cellIDHitMap createPotentialOutputHits(LCCollection *col, SimDigitalGeomCellId *aGeomCellId)
std::vector< StepAndCharge > decode(SimCalorimeterHit *hit, bool link)
std::string spreaderMapFile
std::vector< double > _hitCharge
ChargeInducer * chargeInducer
std::map< dd4hep::long64, hitMemory > cellIDHitMap
std::vector< float > erfWidth
EfficiencyManager * efficiency
void applyThresholds(cellIDHitMap &myHitMap)
ChargeSpreader * chargeSpreader
AIDA::ITuple * _debugTupleStepFilter
void newHit(float cellSize_)
std::vector< std::string > _outputCollections
void setSeed(unsigned int value)
virtual void setLayerLayout(CHT::Layout layout)=0
std::vector< LCCollection * > LCCollectionVec
virtual std::unique_ptr< CalorimeterHitImpl > encode(int delta_I, int delta_J)=0
std::map< dd4hep::long64, std::vector< LCGenericObject * > > geneMap
std::string _encodingType
std::vector< std::string > _outputRelCollections
float _minXYdistanceBetweenStep
virtual void processEvent(LCEvent *evt)
Called for every event - the working horse.
virtual void setParameters(ChargeSpreaderParameters param)
const std::map< I_J_Coordinates, float > & getChargeMap() const
void setCellSize(float size)
ChargeSpreaderParameters chargeSpreaderParameters
std::vector< std::string > _inputCollections
void fillTupleStep(const std::vector< StepAndCharge > &vec, int level)
virtual float getCharge(SimDigitalGeomCellId *cellID)=0
void removeAdjacentStep(std::vector< StepAndCharge > &vec)