4141#include "TRandom.h"
4242
4343// O2 includes
44- #include "DataFormatsTPC/TrackTPC.h"
4544#include "TPCBase/Mapper.h"
4645#include "TPCBase/ParameterDetector.h"
4746#include "TPCBase/ParameterElectronics.h"
5554#include "CommonUtils/TreeStreamRedirector.h"
5655#include "CommonUtils/ConfigurableParam.h"
5756#include "TPCBase/ParameterGas.h"
58- #include "TPCSpaceCharge/PoissonSolverHelpers.h"
5957#include "TPCReconstruction/HwClusterer.h"
6058#include "TPCSimulation/GEMAmplification.h"
6159#endif
@@ -66,7 +64,8 @@ GlobalPosition3D getPointFromPhi(float phi, float theta, GlobalPosition3D global
6664GlobalPosition3D getPosBTrack (const GlobalPosition3D & posA , const GlobalPosition3D & posB );
6765GlobalPosition3D getGlobalPositionTrk (float lambda , const GlobalPosition3D & refA , const GlobalPosition3D & refB );
6866
69- const int mSector = 4 ; ///< consider only this mSector
67+ const int mSector = 4 ; ///< consider only this mSector
68+ const float mMaxDrift = 270 ; ///< maximum drift length in cm
7069
7170/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
7271/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -81,7 +80,7 @@ const int mSector = 4; ///< consider only this mSector
8180/// \param dedxMax maximum dE/dx of the tracks (primary ionization: number of electrons per cm)
8281/// \param maxSinPhi maximum sin(phi) of the tracks
8382/// \param maxTanTheta maximum tan(theta) of the tracks
84- void simulateTracks (const int maxEvents = 1 , const char * outputFolder = "./" , const float dedxMin = 14 , const float dedxMax = 50 , const float maxSinPhi = 1.f , const float maxTanTheta = 1.6 )
83+ void simulateTracks (const int maxEvents = 1 , const char * outputFolder = "./" , const int dedxMin = 14 , const int dedxMax = 50 , const float maxSinPhi = 1.f , const float maxTanTheta = 1.6f )
8584{
8685 // output file / tree
8786 TFile fOut (fmt ::format ("{}/o2sim_HitsTPC.root" , outputFolder ).data (), "RECREATE" );
@@ -101,14 +100,17 @@ void simulateTracks(const int maxEvents = 1, const char* outputFolder = "./", co
101100 // set random seed
102101 gRandom -> SetSeed (0 );
103102
103+ // bias dedx to lower values
104+ TF1 fdEdx ("fdEdx" , "-log(x) + 10" , 1 , dedxMax );
105+
104106 // loop over events (tracks)
105107 for (int iEvent = 0 ; iEvent < maxEvents ; ++ iEvent ) {
106108 hitGroupSector .clear ();
107109
108110 // draw random track parameters
109111 phi = std ::asin (gRandom -> Uniform (0 , maxSinPhi ));
110112 theta = std ::atan (gRandom -> Uniform (0 , maxTanTheta ));
111- dedx = gRandom -> Uniform (dedxMin , dedxMax );
113+ dedx = (dedxMin == dedxMax ) ? dedxMin : fdEdx . GetRandom ( );
112114
113115 // fill the tree (simulate the primary electrons along the track)
114116 fillTPCHits (theta , phi , dedx , hitGroupSector , trackInfo );
@@ -132,12 +134,16 @@ void fillTPCHits(const float theta, const float phi, const float dedx, std::vect
132134 const float xPos = gRandom -> Uniform (-2 , 2 ); // x starting position of track
133135 const int ireg = gRandom -> Integer (Mapper ::NREGIONS ); // region where the track starts
134136 static auto& detParam = ParameterDetector ::Instance ();
135- const float zCoordinate = gRandom -> Uniform (0 , detParam .TPClength - 1 ); // draw flat z position
137+ const float minZ = detParam .TPClength - mMaxDrift ;
138+ static TF1 fz ("fz" , "tanh(x/60 - 3.5) * 0.6 + 1.6" , minZ , detParam .TPClength );
139+ const float zCoordinate = fz .GetRandom (); // draw z position
140+
136141 const float flightTime = 0 ; // flight time of the particle. This value is not needed and set therefor to 0.
137142 const float radiusStart = mapper .getPadRegionInfo (ireg ).getRadiusFirstRow (); // region start
138143 const auto padLength = mapper .getPadRegionInfo (ireg ).getPadHeight ();
139144 const float radius = radiusStart + Mapper ::ROWSPERREGION [ireg ] / 2 * padLength ; // start in the center of the region
140145 HitGroup hitGroup {}; // create HitGroup and push_back to TPCHitsShiftedSector
146+ const float radiusEnd = radiusStart + Mapper ::ROWSPERREGION [ireg ] * padLength ;
141147
142148 // first point of the track
143149 const GlobalPosition3D posATrack (xPos , radius , zCoordinate );
@@ -160,10 +166,10 @@ void fillTPCHits(const float theta, const float phi, const float dedx, std::vect
160166 const float radiusCurr = std ::sqrt (xTmp * xTmp + yTmp * yTmp );
161167
162168 // check if the track is in the TPC
163- const float rMinTPC = TPCParameters < float > :: IFCRADIUS ;
164- const float rMaxTPC = TPCParameters < float > :: OFCRADIUS ;
165- static auto & detParam = ParameterDetector :: Instance ();
166- if (std ::abs (zTmp ) > detParam .TPClength || radiusCurr > rMaxTPC || yTmp < rMinTPC || zTmp < 0 || mapper .isOutOfSector (posTrk , Sector (mSector )) || radiusCurr < rMinTPC ) {
169+ const float rMinTPC = radiusStart ;
170+ const float rMaxTPC = radiusEnd ;
171+
172+ if (std ::abs (zTmp ) > detParam .TPClength || radiusCurr > rMaxTPC || yTmp < rMinTPC || zTmp < minZ || mapper .isOutOfSector (posTrk , Sector (mSector )) || radiusCurr < rMinTPC ) {
167173 continue ;
168174 }
169175
@@ -259,6 +265,26 @@ void setZBinWidth(const int facZWidth = 1)
259265 LOG (info ) << "zbinWidth: " << zbinWidth ;
260266}
261267
268+ GlobalPosition3D getElectronDrift (const GlobalPosition3D & posEle )
269+ {
270+ static o2 ::math_utils ::RandomRing < > randomGaus ;
271+
272+ const auto& detParam = ParameterDetector ::Instance ();
273+ const auto& gasParam = ParameterGas ::Instance ();
274+ float driftl = detParam .TPClength - posEle .Z ();
275+ if (driftl < 0.01 ) {
276+ driftl = 0.01 ;
277+ }
278+ driftl = std ::sqrt (driftl );
279+ const float sigT = driftl * gasParam .DiffT ;
280+ const float sigL = driftl * gasParam .DiffL ;
281+
282+ /// The position is smeared by a Gaussian with mean around the actual position and a width according to the diffusion
283+ /// coefficient times sqrt(drift length)
284+ GlobalPosition3D posEleDiffusion ((randomGaus .getNextValue () * sigT ) + posEle .X (), (randomGaus .getNextValue () * sigT ) + posEle .Y (), (randomGaus .getNextValue () * sigL ) + posEle .Z ());
285+ return posEleDiffusion ;
286+ }
287+
262288/// creating the digits from the simulated hits (similar to the digitizer in O2)
263289/// \param inpFileSim input sim file
264290/// \param outName output path
@@ -269,6 +295,9 @@ void setZBinWidth(const int facZWidth = 1)
269295/// \param disableNoise do not simulate any noise, commonMode and pedestal
270296void createDigitsFromSim (const char * inpFileSim = "o2sim_HitsTPC.root" , const std ::string outName = "digits.root" , const float eleAttachmentFac = 1 , const int facZWidth = 1 , const int maxSecondaries = 3 , const int nEleGEM = -1 , const bool disableNoise = false)
271297{
298+ // set random seed
299+ gRandom -> SetSeed (0 );
300+
272301 auto& cdb = CDBInterface ::instance ();
273302 cdb .setUseDefaults ();
274303
@@ -288,8 +317,8 @@ void createDigitsFromSim(const char* inpFileSim = "o2sim_HitsTPC.root", const st
288317 auto& detParam = ParameterDetector ::Instance ();
289318 auto& eleParam = ParameterElectronics ::Instance ();
290319 const float zbinWidth = eleParam .ZbinWidth ;
291- auto& gemParam = ParameterGEM ::Instance ();
292320 static GEMAmplification & gemAmplification = GEMAmplification ::instance ();
321+ const auto& gasParam = ParameterGas ::Instance ();
293322
294323 ElectronTransport & electronTransport = ElectronTransport ::instance ();
295324 electronTransport .updateParameters ();
@@ -326,10 +355,9 @@ void createDigitsFromSim(const char* inpFileSim = "o2sim_HitsTPC.root", const st
326355 // loop over hits
327356 const int nEvents = hitTree -> GetEntries (); // number of simulated events per hit file
328357 for (int iev = 0 ; iev < nEvents ; ++ iev ) {
329- const double eventTime = 100 + iev * 10 ; // some random time
358+ const double eventTime = 0 ;
330359 if (iev % 50 == false) {
331360 LOG (info ) << "event: " << iev + 1 << " from " << nEvents << " events" ;
332- LOG (info ) << "TPC: Event time " << eventTime << " us" ;
333361 }
334362 hitTree -> GetEntry (iev );
335363
@@ -347,17 +375,16 @@ void createDigitsFromSim(const char* inpFileSim = "o2sim_HitsTPC.root", const st
347375 GlobalPosition3D posEle (eh .GetX (), eh .GetY (), eh .GetZ ());
348376
349377 const int nPrimaryElectrons = static_cast < int > (eh .GetEnergyLoss ());
350- const float hitTime = eh .GetTime () * 0.001 ;
378+ const float hitTime = eh .GetTime () * 0.001f ;
351379 if (nPrimaryElectrons <= 0 ) {
352380 continue ;
353381 }
354382
355- float driftTime = 0.f ;
356383 for (int iele = 0 ; iele < nPrimaryElectrons ; iele ++ ) {
357- const GlobalPosition3D posEleDiff = electronTransport . getElectronDrift (posEle , driftTime );
384+ const GlobalPosition3D posEleDiff = getElectronDrift (posEle );
358385
359386 // add secondaries
360- int nSecondaries = maxSecondaries == 0 ? 0 : getNsec ();
387+ int nSecondaries = ( maxSecondaries == 0 ) ? 0 : getNsec ();
361388
362389 // restrict secondaries to avoid clusters with high charge (tail in the qMax qTot distributions)
363390 if (nSecondaries > maxSecondaries ) {
@@ -374,24 +401,20 @@ void createDigitsFromSim(const char* inpFileSim = "o2sim_HitsTPC.root", const st
374401 // electrons are created randomly
375402 const double x = gRandom -> Gaus (0 , std ::abs (posEle .X () - posEleDiff .X ())) + posEle .X ();
376403 const double y = gRandom -> Gaus (0 , std ::abs (posEle .Y () - posEleDiff .Y ())) + posEle .Y ();
377- double z = gRandom -> Gaus (0 , std ::abs (posEle .Z () - posEleDiff .Z ())) + posEle .Z ();
378- if (z < 0 ) {
379- z = 0.01 ;
380- }
404+ const double z = gRandom -> Gaus (0 , std ::abs (posEle .Z () - posEleDiff .Z ())) + posEle .Z ();
381405 posTotElectrons .emplace_back (GlobalPosition3D (x , y , z ));
382406 }
383407
384408 // loop over all electrons
385409 for (unsigned int j = 0 ; j < posTotElectrons .size (); ++ j ) {
386410 auto posEleTmp = posTotElectrons [j ];
387- driftTime = electronTransport . getDriftTime ( posEleTmp .Z ());
411+ const float driftTime = ( detParam . TPClength - posEleTmp .Z ()) / gasParam . DriftV ;
388412
389413 const float eleTime = driftTime + hitTime ; /// in us
390414 if (eleTime > maxEleTime ) {
391415 LOG (warning ) << "Skipping electron with driftTime " << driftTime << " from hit at time " << hitTime ;
392416 continue ;
393417 }
394- const float absoluteTime = eleTime + eventTime ; /// in us
395418
396419 // Attachment
397420 if (electronTransport .isElectronAttachment (driftTime )) {
@@ -404,11 +427,14 @@ void createDigitsFromSim(const char* inpFileSim = "o2sim_HitsTPC.root", const st
404427 }
405428
406429 // When the electron is not in the mSector we're processing, abandon
407- if (mapper .isOutOfSector (posEleTmp , mSector )) {
430+ // create dummy pos at A-Side
431+ auto posEleTmpTmp = posEleTmp ;
432+ posEleTmpTmp .SetZ (1 );
433+ if (mapper .isOutOfSector (posEleTmpTmp , mSector )) {
408434 continue ;
409435 }
410436
411- const DigitPos digiPadPos = mapper .findDigitPosFromGlobalPosition (posEleTmp , mSector );
437+ const DigitPos digiPadPos = mapper .findDigitPosFromGlobalPosition (posEleTmpTmp , mSector );
412438 if (!digiPadPos .isValid ()) {
413439 continue ;
414440 }
@@ -432,11 +458,9 @@ void createDigitsFromSim(const char* inpFileSim = "o2sim_HitsTPC.root", const st
432458 const int sourceID = 0 ; // TPC
433459 const o2 ::MCCompLabel label (MCTrackID , eventID , sourceID , false );
434460
435- for (float i = 0 ; i < nShapedPoints ; ++ i ) {
436- const float time = absoluteTime + i * zbinWidth ;
437- const auto timebin = sampaProcessing .getTimeBinFromTime (time );
438- float fillCharge = signalArray [i ];
439- digitContainer .addDigit (label , cru , timebin , globalPad , fillCharge );
461+ for (int i = 0 ; i < nShapedPoints ; ++ i ) {
462+ const float timebin = driftTime / eleParam .ZbinWidth + i ;
463+ digitContainer .addDigit (label , cru , timebin , globalPad , signalArray [i ]);
440464 }
441465 }
442466 } // electron loop
@@ -501,10 +525,13 @@ void createCluster(const char* inpHits = "o2sim_HitsTPC.root", const char* outFi
501525{
502526 gRandom -> SetSeed (0 );
503527
504- static auto& detParam = ParameterDetector ::Instance ();
505528 auto& eleParam = ParameterElectronics ::Instance ();
506529 auto& gasParam = ParameterGas ::Instance ();
530+ auto& cdb = CDBInterface ::instance ();
531+ cdb .setUseDefaults ();
532+
507533 const static Mapper & mapper = Mapper ::instance ();
534+ SAMPAProcessing & sampaProcessing = SAMPAProcessing ::instance ();
508535
509536 // load the theta, phi and dE/dx angles from the simulation
510537 TFile fTrackInf (inpHits , "READ ");
@@ -539,13 +566,6 @@ void createCluster(const char* inpHits = "o2sim_HitsTPC.root", const char* outFi
539566 std ::vector < o2 ::tpc ::Digit > * digits = new std ::vector < o2 ::tpc ::Digit > ;
540567 tDigi -> SetBranchAddress (fmt ::format ("TPCDigit_ {}", mSector ).data (), & digits );
541568
542- // cut on the sigmaTime (extracted from plotting sigmaTime vs tan(theta))
543- TF1 fSigmaTimeCut ("sigmaTimeCut ", "pol3 ", 0 , 3 );
544- fSigmaTimeCut .SetParameter (0 , 0.194862 );
545- fSigmaTimeCut .SetParameter (1 , 0.818718 );
546- fSigmaTimeCut .SetParameter (2 , -0.213279 );
547- fSigmaTimeCut .SetParameter (3 , 0.0181574 );
548-
549569 std ::vector < float > vdedx ;
550570 std ::vector < float > vrelTime ;
551571 std ::vector < float > vpad ;
@@ -619,27 +639,25 @@ void createCluster(const char* inpHits = "o2sim_HitsTPC.root", const char* outFi
619639 for (auto cont : clusterOutput ) {
620640 auto container = cont .getContainer ();
621641 const CRU cru (container - > CRU );
622- const PadRegionInfo & region = mapper .getPadRegionInfo (cru .region ());
623- const int rowOffset = region .getGlobalRowOffset ();
642+ const int rowOffset = mapper .getPadRegionInfo (cru .region ()).getGlobalRowOffset ();
624643
625644 for (int clusterCount = 0 ; clusterCount < container -> numberOfClusters ; ++ clusterCount ) {
626645 const auto timeBinOffset = container -> timeBinOffset ;
627646 auto& cluster = container -> clusters [clusterCount ];
628647 const int qTot = cluster .getQTot ();
629648 const int qMax = cluster .getQMax ();
630- const float pad = cluster .getPad () + 0.5 ;
649+ const float pad = cluster .getPad () + 0.5f ;
631650 const float time = cluster .getTimeLocal () + timeBinOffset ;
632651 const int padrow = rowOffset + cluster .getRow ();
633652 const int region = cru .region ();
634653 const float sigmaPad = std ::sqrt (cluster .getSigmaPad2 ());
635654 const float sigmaTime = std ::sqrt (cluster .getSigmaTime2 ());
636- const float zPos = std ::abs (time * eleParam .ZbinWidth * gasParam .DriftV - 0.6 - detParam .TPClength ); // factor 0.6? see distToTrackZ
637- const float relPad = pad - static_cast < int > (pad );
638- const float relTime = time - static_cast < int > (time + 0.5 );
639- const auto tanTheta = std ::tan (theta );
655+ const float zPos = sampaProcessing .getZfromTimeBin (time , Side ::A ) + eleParam .ZbinWidth * gasParam .DriftV ;
656+ const float relPad = cluster .getPad () - static_cast < int > (pad );
657+ const float relTime = time - static_cast < int > (time + 0.5f );
640658
641659 // check for mSector edge pad
642- const int off = 1 ;
660+ const int off = 2 ;
643661 const int offPad = 2 ;
644662 const int localPadRow = Mapper ::getLocalRowFromGlobalRow (padrow );
645663 bool isEdge = false;
@@ -687,8 +705,7 @@ void createCluster(const char* inpHits = "o2sim_HitsTPC.root", const char* outFi
687705 const float distXT = (globX * xTrkF + globY * yTrkF ) / (xTrkF * xTrkF + yTrkF * yTrkF );
688706 const float distanceToTrackXY = std ::sqrt (std ::pow (globX - distXT * xTrkF , 2 ) + std ::pow (globY - distXT * yTrkF , 2 ));
689707
690- const float distZ = (globZ * zTrkF ) / (zTrkF * zTrkF );
691- const float distanceToTrackZ = std ::sqrt (std ::pow (globZ - dist * zTrkF , 2 ));
708+ const float distanceToTrackZ = globZ - dist * zTrkF ;
692709
693710 vLargestqTotinRow .emplace_back (largestqTot );
694711 vdedx .emplace_back (dedx );
@@ -711,8 +728,6 @@ void createCluster(const char* inpHits = "o2sim_HitsTPC.root", const char* outFi
711728 vsinglePadOrTime .emplace_back (singlePadOrTime );
712729 vLocalRow .emplace_back (localPadRow );
713730 zeroSuppOut .emplace_back (zeroSuppression );
714- const bool lowTimeCut = sigmaTime < fSigmaTimeCut .Eval (tanTheta );
715- vSigmaTimeCut .emplace_back (lowTimeCut );
716731 }
717732 }
718733
@@ -735,7 +750,6 @@ void createCluster(const char* inpHits = "o2sim_HitsTPC.root", const char* outFi
735750 << "z=" << vzPos // z of the cluster
736751 << "isEdge=" << visEdge // true if the cluster is edge pad
737752 << "singlePadOrTime=" << vsinglePadOrTime // true if the cluster is single pad or single time cluster
738- << "sigmaTimeCut=" << vSigmaTimeCut // cut on the sigma time
739753 << "eleAttFac=" << eleAttFac // electron attachement factor
740754 << "zeroSupp=" << zeroSuppOut // absolute zero supression value in ADC counts
741755 << "isLargestqTot=" << vLargestqTotinRow // is true cluster has the highest qTot from all clusters in the same pad row (cluster with lower charge are noise)
@@ -746,7 +760,7 @@ void createCluster(const char* inpHits = "o2sim_HitsTPC.root", const char* outFi
746760 }
747761
748762 TTree * tree = (TTree * )(pcstream .GetFile ()-> Get ("cl" )) ;
749- tree -> SetAlias ("cut" , "isLargestqTot==1 && singlePadOrTime==0 && isEdge==0 && sigmaTimeCut==0 && sigmaTime>0.5 " ); // cut to filter clusters
763+ tree -> SetAlias ("cut" , "isLargestqTot==1 && singlePadOrTime==0 && isEdge==0" ); // cut to filter clusters
750764 pcstream .Close ();
751765 fTrackInf .Close ();
752766}
0 commit comments