2323#include " Framework/ControlService.h"
2424#include " DataFormatsTPC/Defs.h"
2525#include " SpacePoints/TrackResiduals.h"
26+ #include " SpacePoints/TrackInterpolation.h"
2627#include " DetectorsBase/Propagator.h"
2728#include " CommonUtils/StringUtils.h"
2829#include " TPCInterpolationWorkflow/TPCResidualReaderSpec.h"
@@ -38,7 +39,7 @@ namespace tpc
3839class TPCResidualReader : public Task
3940{
4041 public:
41- TPCResidualReader () = default ;
42+ TPCResidualReader (bool doBinning, GID:: mask_t src) : mDoBinning (doBinning), mSources (src) {}
4243 ~TPCResidualReader () override = default ;
4344 void init (InitContext& ic) final ;
4445 void run (ProcessingContext& pc) final ;
@@ -53,10 +54,18 @@ class TPCResidualReader : public Task
5354 std::unique_ptr<TFile> mFile ;
5455 std::unique_ptr<TTree> mTreeResiduals ;
5556 std::unique_ptr<TTree> mTreeStats ;
57+ std::unique_ptr<TTree> mTreeUnbinnedResiduals ;
58+ bool mDoBinning {false };
59+ GID::mask_t mSources ;
5660 TrackResiduals mTrackResiduals ;
5761 std::vector<std::string> mFileNames {" " }; // /< input files
5862 std::string mOutfile {" debugVoxRes.root" }; // /< output file name
59- std::vector<o2::tpc::TrackResiduals::LocalResid> mResiduals , *mResidualsPtr = &mResiduals ;
63+ std::vector<TrackResiduals::LocalResid> mResiduals , *mResidualsPtr = &mResiduals ; // /< binned residuals input
64+ std::array<std::vector<TrackResiduals::LocalResid>, SECTORSPERSIDE * SIDES> mResidualsSector ; // /< binned residuals generated on-the-fly
65+ std::array<std::vector<TrackResiduals::LocalResid>*, SECTORSPERSIDE * SIDES> mResidualsSectorPtr ; // /< for setting branch addresses
66+ std::array<std::vector<TrackResiduals::VoxStats>, SECTORSPERSIDE * SIDES> mVoxStatsSector ; // /< voxel statistics generated on-the-fly
67+ std::vector<UnbinnedResid> mUnbinnedResiduals , *mUnbinnedResidualsPtr = &mUnbinnedResiduals ; // /< unbinned residuals input
68+ std::vector<TrackDataCompact> mTrackData , *mTrackDataPtr = &mTrackData ; // /< the track references for unbinned residuals
6069};
6170
6271void TPCResidualReader::fillResiduals (const int iSec)
@@ -111,15 +120,86 @@ void TPCResidualReader::run(ProcessingContext& pc)
111120{
112121 mTrackResiduals .createOutputFile (mOutfile .data ()); // FIXME remove when map output is handled properly
113122
114- for (int iSec = 0 ; iSec < SECTORSPERSIDE * SIDES; ++iSec) {
123+ if (mDoBinning ) {
124+ // initialize the trees for the binned residuals and the statistics
125+ LOG (info) << " Preparing the binning of residuals" ;
126+ mTreeResiduals = std::make_unique<TTree>(" resid" , " TPC binned residuals" );
127+ for (int iSec = 0 ; iSec < SECTORSPERSIDE * SIDES; ++iSec) {
128+ mResidualsSectorPtr [iSec] = &mResidualsSector [iSec];
129+ mVoxStatsSector [iSec].resize (mTrackResiduals .getNVoxelsPerSector ());
130+ for (int ix = 0 ; ix < mTrackResiduals .getNXBins (); ++ix) {
131+ for (int ip = 0 ; ip < mTrackResiduals .getNY2XBins (); ++ip) {
132+ for (int iz = 0 ; iz < mTrackResiduals .getNZ2XBins (); ++iz) {
133+ auto & statsVoxel = mVoxStatsSector [iSec][mTrackResiduals .getGlbVoxBin (ix, ip, iz)];
134+ // COG estimates are set to the bin center by default
135+ mTrackResiduals .getVoxelCoordinates (iSec, ix, ip, iz, statsVoxel.meanPos [TrackResiduals::VoxX], statsVoxel.meanPos [TrackResiduals::VoxF], statsVoxel.meanPos [TrackResiduals::VoxZ]);
136+ }
137+ }
138+ }
139+ mTreeResiduals ->Branch (Form (" sec%d" , iSec), &mResidualsSectorPtr [iSec]);
140+ }
141+ // now go through all input files, apply the track selection and fill be binned residuals
115142 for (const auto & file : mFileNames ) {
116143 LOGP (info, " Processing residuals from file {}" , file);
117-
118- // set up the tree from the input file
119144 connectTree (file);
145+ for (int iEntry = 0 ; iEntry < mTreeUnbinnedResiduals ->GetEntries (); ++iEntry) {
146+ mTreeUnbinnedResiduals ->GetEntry (iEntry);
147+ for (const auto & trkInfo : mTrackData ) {
148+ if (!GID::includesSource (trkInfo.sourceId , mSources )) {
149+ continue ;
150+ }
151+ for (int i = trkInfo.idxFirstResidual ; i < trkInfo.idxFirstResidual + trkInfo.nResiduals ; ++i) {
152+ const auto & residIn = mUnbinnedResiduals [i];
153+ int sec = residIn.sec ;
154+ auto & residVecOut = mResidualsSector [sec];
155+ auto & statVecOut = mVoxStatsSector [sec];
156+ std::array<unsigned char , TrackResiduals::VoxDim> bvox;
157+ float xPos = param::RowX[residIn.row ];
158+ float yPos = residIn.y * param::MaxY / 0x7fff ;
159+ float zPos = residIn.z * param::MaxZ / 0x7fff ;
160+ if (!mTrackResiduals .findVoxelBin (sec, xPos, yPos, zPos, bvox)) {
161+ // we are not inside any voxel
162+ LOGF (debug, " Dropping residual in sec(%i), x(%f), y(%f), z(%f)" , sec, xPos, yPos, zPos);
163+ continue ;
164+ }
165+ residVecOut.emplace_back (residIn.dy , residIn.dz , residIn.tgSlp , bvox);
166+ auto & stat = statVecOut[mTrackResiduals .getGlbVoxBin (bvox)];
167+ float & binEntries = stat.nEntries ;
168+ float oldEntries = binEntries++;
169+ float norm = 1 .f / binEntries;
170+ // update COG for voxel bvox (update for X only needed in case binning is not per pad row)
171+ float xPosInv = 1 .f / xPos;
172+ stat.meanPos [TrackResiduals::VoxX] = (stat.meanPos [TrackResiduals::VoxX] * oldEntries + xPos) * norm;
173+ stat.meanPos [TrackResiduals::VoxF] = (stat.meanPos [TrackResiduals::VoxF] * oldEntries + yPos * xPosInv) * norm;
174+ stat.meanPos [TrackResiduals::VoxZ] = (stat.meanPos [TrackResiduals::VoxZ] * oldEntries + zPos * xPosInv) * norm;
175+ }
176+ }
177+ }
178+ mTreeResiduals ->Fill ();
179+ for (auto & residuals : mResidualsSector ) {
180+ residuals.clear ();
181+ }
182+ }
183+ }
120184
121- // fill the residuals for one sector
122- fillResiduals (iSec);
185+ for (int iSec = 0 ; iSec < SECTORSPERSIDE * SIDES; ++iSec) {
186+ if (mDoBinning ) {
187+ auto brResid = mTreeResiduals ->GetBranch (Form (" sec%d" , iSec));
188+ brResid->SetAddress (&mResidualsPtr );
189+
190+ for (int iEntry = 0 ; iEntry < brResid->GetEntries (); ++iEntry) {
191+ brResid->GetEntry (iEntry);
192+ mTrackResiduals .getLocalResVec ().insert (mTrackResiduals .getLocalResVec ().end (), mResiduals .begin (), mResiduals .end ());
193+ }
194+ mTrackResiduals .setStats (mVoxStatsSector [iSec], iSec);
195+ } else {
196+ for (const auto & file : mFileNames ) {
197+ LOGP (info, " Processing residuals from file {}" , file);
198+ // set up the tree from the input file
199+ connectTree (file);
200+ // fill the residuals for one sector
201+ fillResiduals (iSec);
202+ }
123203 }
124204
125205 // do processing
@@ -139,19 +219,34 @@ void TPCResidualReader::run(ProcessingContext& pc)
139219
140220void TPCResidualReader::connectTree (const std::string& filename)
141221{
142- mTreeResiduals .reset (nullptr ); // in case it was already loaded
143- mTreeStats .reset (nullptr ); // in case it was already loaded
222+ if (!mDoBinning ) {
223+ // in case we do the binning on-the-fly, we fill these trees manually
224+ // and don't want to delete them in between
225+ mTreeResiduals .reset (nullptr ); // in case it was already loaded
226+ mTreeStats .reset (nullptr ); // in case it was already loaded
227+ }
228+ mTreeUnbinnedResiduals .reset (nullptr ); // in case it was already loaded
144229 mFile .reset (TFile::Open (filename.c_str ()));
145230 assert (mFile && !mFile ->IsZombie ());
146- mTreeResiduals .reset ((TTree*)mFile ->Get (" resid" ));
147- assert (mTreeResiduals );
148- mTreeStats .reset ((TTree*)mFile ->Get (" stats" ));
149- assert (mTreeStats );
150-
151- LOG (info) << " Loaded tree from " << filename << " with " << mTreeResiduals ->GetEntries () << " entries" ;
231+ if (!mDoBinning ) {
232+ // we load the already binned residuals and the voxel statistics
233+ mTreeResiduals .reset ((TTree*)mFile ->Get (" resid" ));
234+ assert (mTreeResiduals );
235+ mTreeStats .reset ((TTree*)mFile ->Get (" stats" ));
236+ assert (mTreeStats );
237+ LOG (info) << " Loaded tree from " << filename << " with " << mTreeResiduals ->GetEntries () << " entries" ;
238+ } else {
239+ // we load the unbinned residuals
240+ LOG (info) << " Loading the binned residuals" ;
241+ mTreeUnbinnedResiduals .reset ((TTree*)mFile ->Get (" unbinnedResid" ));
242+ assert (mTreeUnbinnedResiduals );
243+ mTreeUnbinnedResiduals ->SetBranchAddress (" res" , &mUnbinnedResidualsPtr );
244+ mTreeUnbinnedResiduals ->SetBranchAddress (" trackInfo" , &mTrackDataPtr );
245+ LOG (info) << " Loaded tree from " << filename << " with " << mTreeUnbinnedResiduals ->GetEntries () << " entries" ;
246+ }
152247}
153248
154- DataProcessorSpec getTPCResidualReaderSpec ()
249+ DataProcessorSpec getTPCResidualReaderSpec (bool doBinning, GID:: mask_t src )
155250{
156251 std::vector<InputSpec> inputs;
157252 std::vector<OutputSpec> outputs;
@@ -160,7 +255,7 @@ DataProcessorSpec getTPCResidualReaderSpec()
160255 " tpc-residual-reader" ,
161256 inputs,
162257 outputs,
163- AlgorithmSpec{adaptFromTask<TPCResidualReader>()},
258+ AlgorithmSpec{adaptFromTask<TPCResidualReader>(doBinning, src )},
164259 Options{
165260 {" residuals-infiles" , VariantType::String, " o2tpc_residuals.root" , {" comma-separated list of input files or .txt file containing list of input files" }},
166261 {" input-dir" , VariantType::String, " none" , {" Input directory" }},
0 commit comments