From 26152126b0286ae5c8cf749ddf8691c4875d25a7 Mon Sep 17 00:00:00 2001 From: Alexandru Bercuci <abercuci@niham.nipne.ro> Date: Fri, 14 Jan 2022 12:27:32 +0200 Subject: [PATCH] rename class TrdModuleRecT TrdModuleRec2D to align to official nomenclature --- reco/detectors/trd/CMakeLists.txt | 2 +- reco/detectors/trd/CbmTrdDigiRec.h | 2 +- reco/detectors/trd/CbmTrdModuleRec2D.cxx | 1748 ++++++++++++++++++++++ reco/detectors/trd/CbmTrdModuleRec2D.h | 235 +++ reco/detectors/trd/CbmTrdRecoLinkDef.h | 2 +- 5 files changed, 1986 insertions(+), 3 deletions(-) create mode 100644 reco/detectors/trd/CbmTrdModuleRec2D.cxx create mode 100644 reco/detectors/trd/CbmTrdModuleRec2D.h diff --git a/reco/detectors/trd/CMakeLists.txt b/reco/detectors/trd/CMakeLists.txt index 0a72467eb2..b822da9fc2 100644 --- a/reco/detectors/trd/CMakeLists.txt +++ b/reco/detectors/trd/CMakeLists.txt @@ -52,7 +52,7 @@ CbmTrdClusterFinder.cxx CbmTrdHitProducer.cxx CbmTrdModuleRec.cxx CbmTrdModuleRecR.cxx -CbmTrdModuleRecT.cxx +CbmTrdModuleRec2D.cxx CbmTrdDigiRec.cxx unpack/CbmTrdUnpackConfig.cxx diff --git a/reco/detectors/trd/CbmTrdDigiRec.h b/reco/detectors/trd/CbmTrdDigiRec.h index 65420d4d80..7f1762a411 100644 --- a/reco/detectors/trd/CbmTrdDigiRec.h +++ b/reco/detectors/trd/CbmTrdDigiRec.h @@ -20,7 +20,7 @@ ** class which is in the end used to calculate the TRD hit parameters. **/ class CbmTrdDigiRec : public CbmTrdDigi { - friend class CbmTrdModuleRecT; + friend class CbmTrdModuleRec2D; public: /** \brief Default constructor*/ diff --git a/reco/detectors/trd/CbmTrdModuleRec2D.cxx b/reco/detectors/trd/CbmTrdModuleRec2D.cxx new file mode 100644 index 0000000000..3ee375f323 --- /dev/null +++ b/reco/detectors/trd/CbmTrdModuleRec2D.cxx @@ -0,0 +1,1748 @@ +/* Copyright (C) 2018-2020 Horia Hulubei National Institute of Physics and Nuclear Engineering, Bucharest + SPDX-License-Identifier: GPL-3.0-only + Authors: Alexandru Bercuci [committer] */ + +#include "CbmTrdModuleRec2D.h" + +#include "CbmDigiManager.h" +#include "CbmTrdCluster.h" +#include "CbmTrdDigi.h" +#include "CbmTrdDigiRec.h" +#include "CbmTrdFASP.h" +#include "CbmTrdHit.h" +#include "CbmTrdParModDigi.h" + +#include <FairLogger.h> + +#include <TClonesArray.h> +#include <TF1.h> +#include <TGeoPhysicalNode.h> +#include <TGraphErrors.h> + +#include <iostream> +#include <vector> + +using std::cout; +using std::endl; +using std::vector; + +Double_t CbmTrdModuleRec2D::fgDT[] = {4.181e-6, 1586, 24}; +TGraphErrors* CbmTrdModuleRec2D::fgEdep = NULL; +TGraphErrors* CbmTrdModuleRec2D::fgT = NULL; +TF1* CbmTrdModuleRec2D::fgPRF = NULL; +//_______________________________________________________________________________ +CbmTrdModuleRec2D::CbmTrdModuleRec2D() + : CbmTrdModuleRec() + , fConfigMap(0) + , fT0(0) + , fBuffer() + , fDigis() + , vt0(0) + , vcM(0) + , vrM(0) + , viM(0) + , vyM(0) + , vs() + , vse() + , vt() + , vx() + , vxe() +{ +} + +//_______________________________________________________________________________ +CbmTrdModuleRec2D::CbmTrdModuleRec2D(Int_t mod, Int_t ly, Int_t rot) + : CbmTrdModuleRec(mod, ly, rot) + , fConfigMap(0) + , fT0(0) + , fBuffer() + , fDigis() + , vt0(0) + , vcM(0) + , vrM(0) + , viM(0) + , vyM(0) + , vs() + , vse() + , vt() + , vx() + , vxe() +{ + printf("AddModuleT @ %d\n", mod); Config(1,0); + SetNameTitle(Form("Trd2dReco%d", mod), "Reconstructor for triangular read-out."); +} + +//_______________________________________________________________________________ +CbmTrdModuleRec2D::~CbmTrdModuleRec2D() {} + +//_______________________________________________________________________________ +Bool_t CbmTrdModuleRec2D::AddDigi(const CbmTrdDigi* d, Int_t id) +{ + /** Add digi to cluster fragments. At first clusters are ordered on pad rows and time. + * No channel ordering is assumed. The time condition for a digi to enter a cluster + * chunk is to have abs(dt)<5 wrt cluster t0 + */ + + if (CWRITE()) cout << "add @" << id << " " << d->ToString(); + + Int_t ch = d->GetAddressChannel(), col, row = GetPadRowCol(ch, col), dtime; + Double_t t, r = d->GetCharge(t, dtime); + Int_t tm = d->GetTimeDAQ() - fT0, terminator(0); + if (dtime < 0) tm += dtime; // correct for the difference between tilt and rect + if (r < 1) terminator = 1; + else if (t < 1) + terminator = -1; + + if (CWRITE()) printf("row[%2d] col[%2d] tm[%2d] terminator[%d]\n", row, col, tm, terminator); + CbmTrdCluster* cl(NULL); + + // get the link to saved clusters + std::map<Int_t, std::list<CbmTrdCluster*>>::iterator it = fBuffer.find(row); + // check for saved + if (it != fBuffer.end()) { + Bool_t kINSERT(kFALSE); + std::list<CbmTrdCluster*>::iterator itc = fBuffer[row].begin(); + for (; itc != fBuffer[row].end(); itc++) { + if (CWRITE()) cout << (*itc)->ToString(); + + UShort_t tc = (*itc)->GetStartTime(); + Int_t dt = tc - tm; + + if (dt < -5) continue; + else if (dt < 5) { + if (CWRITE()) printf("match time dt=%d\n", dt); + if ((*itc)->IsChannelInRange(ch) == 0) { + if (!(*itc)->AddDigi(id, ch, terminator, dt)) break; + kINSERT = kTRUE; + if (CWRITE()) cout << " => Cl (Ad) " << (*itc)->ToString(); + break; + } + } + else { + if (CWRITE()) printf("break for time dt=%d\n", dt); + break; + } + } + + if (!kINSERT) { + if (itc != fBuffer[row].end() && itc != fBuffer[row].begin()) { + itc--; + fBuffer[row].insert(itc, cl = new CbmTrdCluster(fModAddress, id, ch, row, tm)); + if (CWRITE()) cout << " => Cl (I) " << cl->ToString(); + } + else { + fBuffer[row].push_back(cl = new CbmTrdCluster(fModAddress, id, ch, row, tm)); + if (CWRITE()) cout << " => Cl (Pb) " << cl->ToString(); + } + cl->SetTrianglePads(); + if (terminator < 0) cl->SetProfileStart(); + else if (terminator > 0) + cl->SetProfileStop(); + } + } + else { + fBuffer[row].push_back(cl = new CbmTrdCluster(fModAddress, id, ch, row, tm)); + cl->SetTrianglePads(); + if (terminator < 0) cl->SetProfileStart(); + else if (terminator > 0) + cl->SetProfileStop(); + if (CWRITE()) cout << " => Cl (Nw) " << cl->ToString(); + } + + return kTRUE; +} + +//_______________________________________________________________________________ +Int_t CbmTrdModuleRec2D::GetOverThreshold() const +{ + Int_t nch(0); + for (std::map<Int_t, std::list<CbmTrdCluster*>>::const_iterator ir = fBuffer.cbegin(); ir != fBuffer.cend(); ir++) { + for (std::list<CbmTrdCluster*>::const_iterator itc = (*ir).second.cbegin(); itc != (*ir).second.cend(); itc++) + nch += (*itc)->GetNCols(); + } + return nch; +} + +//_______________________________________________________________________________ +Int_t CbmTrdModuleRec2D::FindClusters() +{ + CbmTrdCluster* cl(NULL); + + // get the link to saved clusters + Int_t ncl(0); + std::list<CbmTrdCluster*>::iterator itc0, itc1; + for (std::map<Int_t, std::list<CbmTrdCluster*>>::iterator ir = fBuffer.begin(); ir != fBuffer.end(); ir++) { + itc0 = (*ir).second.begin(); + while ((*ir).second.size() > 1 && itc0 != (*ir).second.end()) { // try merge clusters + itc1 = itc0; + itc1++; + + Bool_t kMERGE = kFALSE; + while (itc1 != (*ir).second.end()) { + if (CWRITE()) cout << " base cl[0] : " << (*itc0)->ToString() << " + cl[1] : " << (*itc1)->ToString(); + if ((*itc0)->Merge((*itc1))) { + if (CWRITE()) cout << " SUM : " << (*itc0)->ToString(); + kMERGE = kTRUE; + delete (*itc1); + itc1 = (*ir).second.erase(itc1); + if (itc1 == (*ir).second.end()) break; + } + else + itc1++; + } + if (!kMERGE) itc0++; + } + + for (itc0 = (*ir).second.begin(); itc0 != (*ir).second.end(); itc0++) { + cl = (*itc0); + cl = new ((*fClusters)[ncl++]) CbmTrdCluster(*cl); + cl->SetTrianglePads(); + delete (*itc0); + } + } + fBuffer.clear(); + + //printf("fClusters[%p] nCl[%d]\n", (void*)fClusters, fClusters->GetEntriesFast()); + //LOG(info) << GetName() << "::FindClusters : " << ncl; + return ncl; +} + +//_______________________________________________________________________________ +Bool_t CbmTrdModuleRec2D::MakeHits() { return kTRUE; } + +//_______________________________________________________________________________ +Bool_t CbmTrdModuleRec2D::PreProcessHits() +{ + /** Steering routine for classifying hits and apply further analysis + * -> hit deconvolution (see Deconvolute) + */ + + Int_t nhits = fHits->GetEntriesFast(); + if (CWRITE()) LOG(info) << "\n" << GetName() << "::PreProcessHits(" << nhits << ")"; + + CbmTrdHit* hit(NULL); + for (Int_t ih(0); ih < nhits; ih++) { + hit = (CbmTrdHit*) ((*fHits)[ih]); + if (!CheckConvolution(hit)) continue; + nhits += Deconvolute(hit); + } + nhits = fHits->GetEntriesFast(); + if (CWRITE()) LOG(info) << "\n" << GetName() << "::Deconvolute(" << nhits << ")"; + return kTRUE; +} + +//_______________________________________________________________________________ +Bool_t CbmTrdModuleRec2D::CheckConvolution(CbmTrdHit* /*h*/) const { return kFALSE; } + +//_______________________________________________________________________________ +Bool_t CbmTrdModuleRec2D::Deconvolute(CbmTrdHit* /*h*/) { return kFALSE; } + +//_______________________________________________________________________________ +Bool_t CbmTrdModuleRec2D::PostProcessHits() +{ + /** Steering routine for classifying hits and apply further analysis + * -> hit merging for row-cross (see RowCross) + */ + + CbmTrdHit *h0(NULL), *h1(NULL); + + Int_t a0, nhits = fHits->GetEntriesFast(); + Float_t Dx(2 * fDigiPar->GetPadSizeX(0)), Dy(2 * fDigiPar->GetPadSizeY(0)); + for (Int_t ih(0); ih < nhits; ih++) { + h0 = (CbmTrdHit*) ((*fHits)[ih]); + if (h0->IsUsed()) continue; + + for (Int_t jh(ih + 1); jh < nhits; jh++) { + h1 = (CbmTrdHit*) ((*fHits)[jh]); + if (h1->IsUsed()) continue; + + // basic check on Row + if (TMath::Abs(h1->GetY() - h0->GetY()) > Dy) continue; + + // basic check on Col + if (TMath::Abs(h1->GetX() - h0->GetX()) > Dx) continue; + + // basic check on Time + if (TMath::Abs(h1->GetTime() - h0->GetTime()) > 4000) continue; // TODO check with preoper time calibration + + // go to topologic checks + if (!(a0 = CheckMerge(h0->GetRefId(), h1->GetRefId()))) continue; + + ProjectDigis(a0 < 0 ? h0->GetRefId() : h1->GetRefId(), a0 < 0 ? h1->GetRefId() : h0->GetRefId()); + + // call the working algorithm + if (MergeHits(h0, a0)) h0->SetRowCross(h1); + if (CWRITE()) { + cout << ih << " : " << h0->ToString(); + cout << jh << " : " << h1->ToString(); + cout << "\n" << endl; + } + } + } + nhits = 0; + for (Int_t ih(0); ih < fHits->GetEntriesFast(); ih++) { + h0 = (CbmTrdHit*) ((*fHits)[ih]); + if (!h0->IsUsed()) continue; + fHits->RemoveAt(ih); //delete h0; + nhits++; + } + fHits->Compress(); + + // clear all calibrated digis + for (map<Int_t, vector<CbmTrdDigiRec*>>::iterator ic = fDigis.begin(); ic != fDigis.end(); ic++) { + for (vector<CbmTrdDigiRec*>::iterator id = ic->second.begin(); id != ic->second.end(); id++) + delete *id; + ic->second.clear(); + } + fDigis.clear(); + + if (CWRITE()) LOG(info) << "\n" << GetName() << "::MergeHits(" << nhits << ")"; + return kTRUE; +} + + +//_______________________________________________________________________________ +Int_t CbmTrdModuleRec2D::CheckMerge(Int_t cid, Int_t cjd) +{ + /** Check topologic conditions if the 2 clusters (in digi representation) can be merged. + * The first pair is always from the bottom row + * return the anode candidate wrt boundary 1, 2, 3 for the first 3 anodes of the upper row; -1, -2, -3 for the bottom row (r0) or 0 if the check fails + */ + + Bool_t on(kFALSE); + Int_t /*row, */ col, rowMax(0), vc[2] = {-1, -1}, vm[2] = {0}, vcid[2] = {cid, cjd}; + Double_t t(0.), r(0.), rtMax(0.), T(0.), m, d, mdMax(0.), M[2] = {-1., -1.}, S[2] = {0.}; + vector<CbmTrdDigiRec*>::iterator id, jd, jp[2]; + for (Int_t rowId(0); rowId < 2; rowId++) { + rtMax = 0.; + mdMax = 0.; + for (id = fDigis[vcid[rowId]].begin(); id != fDigis[vcid[rowId]].end(); id++) { + GetPadRowCol((*id)->GetAddressChannel(), col); + //cout<<(*id)->ToString(); + + // mark max position and type + t = (*id)->GetTiltCharge(on); + if (on && t > rtMax) { + vc[rowId] = col; + vm[rowId] = 0; + rtMax = t; + } + r = (*id)->GetRectCharge(on); + if (on && r > rtMax) { + vc[rowId] = col; + vm[rowId] = 1; + rtMax = r; + } + + m = 0.; + d = 0.; + if (!rowId) { // compute TR pairs on the bottom row + m = 0.5 * (t + r); + d = r - t; + } + else { // compute RT pairs on the upper row + jd = id + 1; + T = 0.; + if (jd != fDigis[vcid[rowId]].end()) T = (*jd)->GetTiltCharge(on); + + m = 0.5 * (r + T); + d = r - T; + } + if (TMath::Abs(m) > 0.) d = 1.e2 * d / m; + if (m > mdMax) { + mdMax = m; + M[rowId] = m; + S[rowId] = d; + jp[rowId] = id; + rowMax = rowId; + } + } + } + rowMax = M[0] > M[1] ? 0 : 1; + + // basic check on col of the max signal + Int_t dc = vc[1] - vc[0]; + if (dc < 0 || dc > 1) return 0; + + // special care for both tilt maxima : the TT case + // recalculate values on the min row on neighbor column + if (!vm[0] && !vm[1]) { + if (rowMax == 0) { // modify r=1 + r = T = 0.; + if (M[1] >= 0) { + if (jp[1] != fDigis[cjd].end()) jp[1]++; + if (jp[1] != fDigis[cjd].end()) { + r = (*jp[1])->GetRectCharge(on); + jp[1]++; + if (jp[1] != fDigis[cjd].end()) T = (*jp[1])->GetTiltCharge(on); + } + } + M[1] = 0.5 * (r + T); + S[1] = r - T; + } + else { // modify r=0 + r = t = 0.; + if (M[0] >= 0) { + if (jp[0] != fDigis[cid].begin()) jp[0]--; + if (jp[0] != fDigis[cid].begin()) { + r = (*jp[0])->GetRectCharge(on); + t = (*jp[0])->GetTiltCharge(on); + } + } + M[0] = 0.5 * (t + r); + S[0] = r - t; + } + } + rowMax = M[0] > M[1] ? 0 : 1; + + // Build the ratio of the charge + Float_t mM = M[rowMax ? 0 : 1] / M[rowMax]; + + // Float_t mM_c[] = {0.03, 0.243, 0.975}, // center of distribution for each anode hypo + // mM_s[] = {0., 1.7e-3, 8.8e-3}, // slope of distribution for each anode hypo + // mM_r[] = {0.03, 0.03, 0.01}; // range of distribution for each anode hypo in proper coordinates + // for(Int_t ia(0); ia<3; ia++) + // if(TMath::Abs(mM_s[ia] * S[rowMax] + mM_c[ia] - mM) < mM_r[ia] ) return (rowMax?1:-1) * (3-ia); + + Float_t mS = TMath::Abs(S[rowMax]), mM_l[3] = {0.15, 0.5, 1}, mM_r[3] = {0, 0.28, 1}, mS_r[3] = {43, 27, 20}, dSdM[2], + S0[2]; + for (Int_t i(0); i < 2; i++) { + dSdM[i] = (mS_r[i + 1] - mS_r[i]) / (mM_r[i + 1] - mM_r[i]); + S0[i] = mS_r[i] - dSdM[i] * mM_r[i]; + } + Int_t irange = mM < mM_r[1] ? 0 : 1; + if (mS > S0[irange] + dSdM[irange] * mM) return 0; + + for (Int_t ia(0); ia < 3; ia++) { + if (mM < mM_l[ia]) return (rowMax ? 1 : -1) * (3 - ia); + } + return 0; +} + + +//_______________________________________________________________________________ +Bool_t CbmTrdModuleRec2D::MergeHits(CbmTrdHit* h, Int_t a0) +{ + Int_t n0(vs.size() - 2); + Double_t dx(0.), dy(0.); + + switch (n0) { + case 1: + if (IsMaxTilt()) { // T + dx = -0.5; + dy = 0; + } + else { // R + dx = 0.5; + dy = 0; + } + break; + case 2: + if (IsOpenLeft() && IsOpenRight()) { // RT + dx = viM == 1 ? 0. : -1; + dy = -0.5; + } + else { // TR + dx = 0.; + dy = 0.5; + } + break; + case 3: + if (IsMaxTilt() && !IsSymmHit()) { // TRT asymm + dx = viM == 1 ? 0. : -1; + dy = GetYoffset(); + } + else if (!IsMaxTilt() && IsSymmHit()) { // TRT symm + dx = 0.; + dy = GetYoffset(); + } + else if (IsMaxTilt() && IsSymmHit()) { // RTR symm + dx = GetXoffset(); + dy = 0.; + } + else if (!IsMaxTilt() && !IsSymmHit()) { // RTR asymm + dx = GetXoffset(); + dy = viM == 1 ? -0.5 : 0.5; + } + break; + default: + dx = GetXoffset(); + dy = GetYoffset(); + break; + } + + RecenterXoffset(dx); + Int_t typ(GetHitClass()); + // get position correction [pw] + Double_t xcorr = GetXcorr(dx, typ, 1) / fDigiPar->GetPadSizeX(0), xcorrBias(xcorr); + if (IsBiasX()) { + typ = GetHitRcClass(a0); + Int_t xmap = vyM & 0xff; + switch (n0) { + case 4: + if (dx < 0) xcorrBias += (IsBiasXleft() ? -0.12 : 0.176); + else + xcorrBias += (xmap == 53 || xmap == 80 || xmap == 113 || xmap == 117 ? -0.176 : 0.12); + break; + case 5: + case 7: + if (typ < 0) break; + if (xmap == 50 || xmap == 58 || xmap == 146 || xmap == 154) { + if (typ == 2) xcorr += 0.0813; + else if (typ == 3) { + xcorr -= 0.0813; + typ = 2; + } + dx -= xcorr; + RecenterXoffset(dx); + xcorrBias = GetXcorr(dx, typ, 2) / fDigiPar->GetPadSizeX(0); + } + else { + dx -= xcorr; + RecenterXoffset(dx); + if (typ < 2) xcorrBias = GetXcorr(dx, typ, 2) / fDigiPar->GetPadSizeX(0); + else if (typ == 2) + xcorrBias = 0.12; + else if (typ == 3) + xcorrBias = -0.12; + } + break; + default: + if (typ < 0) break; + else if (typ == 2) + xcorr += 0.0813; + else if (typ == 3) { + xcorr -= 0.0813; + typ = 2; + } + dx -= xcorr; + RecenterXoffset(dx); + xcorrBias = GetXcorr(dx, typ, 2) / fDigiPar->GetPadSizeX(0); + break; + } + } + else { + if (typ) xcorrBias += (dx < 0 ? 1 : -1) * 0.0293; + } + dx -= xcorrBias; + RecenterXoffset(dx); + dy = dx - dy; + RecenterYoffset(dy); + if (dy < -0.5 || dy > 0.5) printf("!!! dy = %f r[%d]\n", dy, vrM); + + Double_t ycorr = GetYcorr(dy) / fDigiPar->GetPadSizeY(0); + dy += ycorr; + RecenterYoffset(dy); + dx *= fDigiPar->GetPadSizeX(0); + dy *= fDigiPar->GetPadSizeY(0); + + TVector3 local_pad, local_pad_err; + Int_t srow, sector = fDigiPar->GetSectorRow(vrM, srow); + fDigiPar->GetPadPosition(sector, vcM, srow, local_pad, local_pad_err); + + Double_t edx(1), edy(1), edt(60), time(-21), tdrift(100), e(200); + Double_t local[3] = {local_pad[0] + dx, local_pad[1] + dy, local_pad[2]}, global[3]; + // globalErr[3] = {0/*edx*/, 0/*edy*/, 0.}; + LocalToMaster(local, global); + h->SetX(global[0]); + h->SetY(global[1]); + h->SetZ(global[2]); + h->SetDx(edx); + h->SetDy(edy); + h->SetDz(0.); + h->SetDxy(0.); + h->SetTime(CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kFASP) * (vt0 + time) - tdrift + 30.29, edt); + h->SetELoss(e); + // hit->SetClassType(); + // hit->SetMaxType(tM); + // if(ovf) hit->SetOverFlow(); + + if (CWRITE()) { + printf("-> loc[%6.2f %6.2f %6.2f] err[%6.2f %6.2f %6.2f]\n", local_pad[0], local_pad[1], local_pad[2], + local_pad_err[0], local_pad_err[1], local_pad_err[2]); + printf("REC col[%2d] row[%2d] dx[%7.3f(pw) %7.3f(cm)] x[%7.2f] y[%7.2f] dy[%5.2f] t0[%llu]\n", vcM, vrM, + dx / fDigiPar->GetPadSizeX(0), dx, global[0], global[1], dy, vt0); + } + + return kTRUE; +} + +//_______________________________________________________________________________ +Bool_t CbmTrdModuleRec2D::BuildHit(CbmTrdHit* h) +{ + Int_t n0(vs.size() - 2); + Double_t dx(0.), dy(0.); //, da(0.); + + switch (n0) { + case 1: + if (IsMaxTilt()) { // T + dx = -0.5; + dy = 0; + } + else { // R + dx = 0.5; + dy = 0; + } + break; + case 2: + if (IsOpenLeft() && IsOpenRight()) { // RT + dx = viM == 1 ? 0. : -1; + dy = -0.5; + } + else { // TR + dx = 0.; + dy = 0.5; + } + break; + case 3: + if (IsMaxTilt() && !IsSymmHit()) { // TRT asymm + dx = viM == 1 ? 0. : -1; + dy = GetYoffset(); + } + else if (!IsMaxTilt() && IsSymmHit()) { // TRT symm + dx = 0.; + dy = GetYoffset(); + } + else if (IsMaxTilt() && IsSymmHit()) { // RTR symm + dx = GetXoffset(); + dy = 0.; + } + else if (!IsMaxTilt() && !IsSymmHit()) { // RTR asymm + dx = GetXoffset(); + dy = viM == 1 ? -0.5 : 0.5; + } + break; + default: + dx = GetXoffset(); + dy = GetYoffset(); + break; + } + RecenterXoffset(dx); + + // get position correction + Double_t xcorr = GetXcorr(dx, GetHitClass()) / fDigiPar->GetPadSizeX(0); + dx -= xcorr; + RecenterXoffset(dx); + dy = dx - dy; + RecenterYoffset(dy); + if (dy < -0.5 || dy > 0.5) printf("!!! dy = %f r[%d]\n", dy, vrM); + + Double_t ycorr = GetYcorr(dy) / fDigiPar->GetPadSizeY(0); + dy += ycorr; + RecenterYoffset(dy); + dx *= fDigiPar->GetPadSizeX(0); + dy *= fDigiPar->GetPadSizeY(0); + + // get anode wire offset + Int_t ia(0); + Float_t ya(0.); // anode position in local pad coordinates + for (; ia <= NANODE; ia++) { + ya = -1.35 + ia * 0.3; + if (dy > ya + 0.15) continue; + break; + } + // da = dy-ya; + // //correct inside apmlification region + // da*=-0.7; + // if(da<-0.015) da+=0.1; + // else if(da>0.015) da-=0.1; + // dy+=da; + // da = dy - ya; + + // Error parametrization X : parabolic model on cl size + Double_t parX[] = {0.713724, -0.318667, 0.0366036}; + Double_t parY[] = {0.0886413, 0., 0.0435141}; + Int_t nex = TMath::Min(n0, 7); + Double_t edx = parX[0] + parX[1] * nex + parX[2] * nex * nex, edy = parY[0] + parY[2] * dy * dy, + edt = 26.33; // should be parametrized as function of da TODO + // use this trick to force larger roads on CbmLitTrackFinderBranch + // target code from CbmLitTrackFinderBranch::FollowTracks and CbmLitHitData::AddHit + // bool hitInside = (pixelHit->GetX() < (tpar.GetX() + devX)) && (pixelHit->GetX() > (tpar.GetX() - devX)) + if (n0 < 3) { + edx = 1.; + edy = 1.; + edt = 60.; + } + + TVector3 local_pad, local_pad_err; + Int_t srow, sector = fDigiPar->GetSectorRow(vrM, srow); + fDigiPar->GetPadPosition(sector, vcM, srow, local_pad, local_pad_err); + + Double_t local[3] = {local_pad[0] + dx, local_pad[1] + dy, local_pad[2]}, global[3]; + //globalErr[3] = {edx, edy, 0.}; + LocalToMaster(local, global); + + // COMPUTE TIME + for (Int_t idx(1); idx <= n0; idx++) { + Double_t dtFEE = + fgDT[0] * (vs[idx] - fgDT[1]) * (vs[idx] - fgDT[1]) / CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kFASP); + if (vxe[idx] > 0) vx[idx] += dy / fDigiPar->GetPadSizeY(0); + fgT->SetPoint(idx - 1, vx[idx], vt[idx] - dtFEE); + } + Double_t xc = vx[n0 + 2]; + for (Int_t ip(n0); ip < fgT->GetN(); ip++) { + fgT->SetPoint(ip, xc, 0); + xc += 0.5; + } + Double_t time(-21.), tdrift(100); // should depend on Ua + if (n0 > 1 && (fgT->Fit("pol1", "QC", "goff") == 0)) { + TF1* f = fgT->GetFunction("pol1"); + time = f->GetParameter(0) - fgDT[2]; + if (TMath::IsNaN(time)) time = -21; + //dtime += TMath::Abs(f->GetParameter(1)*(vx[n0+1] - vx[1])); + } + + // COMPUTE ENERGY + for (UInt_t idx(0); idx < vs.size(); idx++) { + if (vxe[idx] > 0) { + fgEdep->SetPoint(idx, vx[idx] + dy / fDigiPar->GetPadSizeY(0), vs[idx]); + fgEdep->SetPointError(idx, vxe[idx], vse[idx]); + } + else { + fgEdep->SetPoint(idx, vx[idx], vs[idx]); + fgEdep->SetPointError(idx, vxe[idx], vse[idx]); + } + } + xc = vx[n0 + 2]; + for (Int_t ip(vs.size()); ip < fgEdep->GetN(); ip++) { + //fgEdep->RemovePoint(ip); + xc += 0.5; + fgEdep->SetPoint(ip, xc, 0); + fgEdep->SetPointError(ip, 0., 300); + } + //if(CWRITE()) fgEdep->Print(); + + Double_t e(0.), xlo(*vx.begin()), xhi(*vx.rbegin()); + fgPRF->SetParameter(0, vs[viM]); + fgPRF->FixParameter(1, dx / fDigiPar->GetPadSizeX(0)); + fgPRF->SetParameter(2, 0.65); + fgPRF->SetParLimits(2, 0.45, 10.5); + fgEdep->Fit(fgPRF, "QBN", "goff", xlo - 0.5, xhi + 0.5); + if (!fgPRF->GetNDF()) return NULL; + //chi = fgPRF->GetChisquare()/fgPRF->GetNDF(); + e = fgPRF->Integral(xlo - 0.5, xhi + 0.5); + + // apply MC correction + Float_t gain0 = 210.21387; //(XeCO2 @ 1900V) + // Float_t grel[3] = {1., 0.98547803, 0.93164071}, + // goff[3][3] = { + // {0.05714, -0.09, -0.09}, + // {0., -0.14742, -0.14742}, + // {0., -0.29, -0.393} + // }; + // Int_t ian=0; + // if(TMath::Abs(dy)<=0.3) ian=0; + // else if(TMath::Abs(dy)<=0.6) ian=1; + // else if(TMath::Abs(dy)<=0.9) ian=2; + // Int_t isize=0; + // if(n0<=3) isize=0; + // else if(n0<=4) isize=1; + // else isize=2; + Float_t gain = gain0; //*grel[ian]; + e /= gain; // apply effective gain + //e+=goff[ian][isize]; // apply missing energy offset + + h->SetX(global[0]); + h->SetY(global[1]); + h->SetZ(global[2]); + h->SetDx(edx); + h->SetDy(edy); + h->SetDz(0); + h->SetDxy(0.); + h->SetTime(CbmTrdDigi::Clk(CbmTrdDigi::eCbmTrdAsicType::kFASP) * (vt0 + time) - tdrift + 30.29, edt); + h->SetELoss(e); + // hit->SetClassType(); + // hit->SetMaxType(tM); + // if(ovf) hit->SetOverFlow(); + + if (CWRITE()) { + printf("-> loc[%6.2f %6.2f %6.2f] err[%6.2f %6.2f %6.2f]\n", local_pad[0], local_pad[1], local_pad[2], + local_pad_err[0], local_pad_err[1], local_pad_err[2]); + printf("REC col[%2d] row[%2d] x[%7.2f] dx[%5.2f] y[%7.2f] dy[%5.2f] t0[%llu]\n", vcM, vrM, global[0], dx, global[1], + dy, vt0); + } + + return kTRUE; +} + +#include <TCanvas.h> +#include <TH1.h> +//_______________________________________________________________________________ +CbmTrdHit* CbmTrdModuleRec2D::MakeHit(Int_t ic, const CbmTrdCluster* cl, std::vector<const CbmTrdDigi*>* digis) +{ + if (!fgEdep) { // first use initialization of PRF helppers + LOG(info) << GetName() << "::MakeHit: Init static helpers. "; + fgEdep = new TGraphErrors; + fgEdep->SetLineColor(kBlue); + fgEdep->SetLineWidth(2); + fgT = new TGraphErrors; + fgT->SetLineColor(kBlue); + fgT->SetLineWidth(2); + fgPRF = new TF1("prf", "[0]*exp(-0.5*((x-[1])/[2])**2)", -10, 10); + fgPRF->SetLineColor(kRed); + fgPRF->SetParNames("E", "x", "prf"); + } + TH1* hf(NULL); + TCanvas* cvs(NULL); + if (CDRAW()) { + cvs = new TCanvas("c", "TRD Anode Hypothesis", 10, 600, 1000, 500); + cvs->Divide(2, 1, 1.e-5, 1.e-5); + TVirtualPad* vp = cvs->cd(1); + vp->SetLeftMargin(0.06904908); + vp->SetRightMargin(0.009969325); + vp->SetTopMargin(0.01402806); + vp = cvs->cd(2); + vp->SetLeftMargin(0.06904908); + vp->SetRightMargin(0.009969325); + vp->SetTopMargin(0.01402806); + hf = new TH1I("hf", ";x [pw];s [ADC chs]", 100, -3, 3); + hf->GetYaxis()->SetRangeUser(-50, 4500); + hf->Draw("p"); + } + + if (CWRITE()) cout << cl->ToString(); + if (!LoadDigis(digis, ic)) return NULL; + if (!ProjectDigis(ic)) return NULL; + Int_t nofHits = fHits->GetEntriesFast(); + CbmTrdHit* hit = new ((*fHits)[nofHits]) CbmTrdHit(); + hit->SetAddress(fModAddress); + hit->SetRefId(ic); + //hit->SetMatch(); + BuildHit(hit); + if (CWRITE()) cout << hit->ToString(); + if (CDRAW()) DrawHit(hit); + return hit; +} + +//_______________________________________________________________________________ +Int_t CbmTrdModuleRec2D::GetHitClass() const +{ + /** Incapsulate hit classification criteria based on signal topology + * [0] : center hit type + * [1] : side hit type + */ + + Int_t n0(vs.size() - 2); + if ((n0 == 5 && ((IsMaxTilt() && IsSymmHit()) || (!IsMaxTilt() && !IsSymmHit()))) || // TRTRT symm/asymm + n0 == 4 || (n0 == 3 && ((IsMaxTilt() && IsSymmHit()) || (!IsMaxTilt() && !IsSymmHit())))) + return 1; // RTR symm/asymm + else if (n0 > 5 && HasOvf()) + return 2; + return 0; +} + +//_______________________________________________________________________________ +Int_t CbmTrdModuleRec2D::GetHitRcClass(Int_t a0) const +{ + Int_t a0m = TMath::Abs(a0); + UChar_t xmap = vyM & 0xff; + if (a0m == 2 && IsBiasXleft() && IsBiasXright() && !IsBiasXmid()) return 0; + else if (a0m == 3 && ((IsBiasXleft() && IsBiasXright()) || xmap == 116 || xmap == 149 || xmap == 208)) + return 1; + else if (!IsBiasXleft() + && (a0m == 2 + || (a0m == 3 && ((!IsBiasXright() && IsBiasXmid()) || xmap == 209 || xmap == 212 || xmap == 145)))) + return 2; + else if (!IsBiasXright() + && (a0m == 2 || (a0m == 3 && ((!IsBiasXleft() && IsBiasXmid()) || xmap == 112 || xmap == 117)))) + return 3; + else + return -1; +} + +//_______________________________________________________________________________ +Double_t CbmTrdModuleRec2D::GetXoffset(Int_t n0) const +{ + Double_t dx(0.), R(0.); + Int_t n(n0 ? n0 : vs.size()); + for (Int_t ir(0); ir < n; ir++) { + if (vxe[ir] > 0) continue; // select rectangular coupling + R += vs[ir]; + dx += vs[ir] * vx[ir]; + } + if (TMath::Abs(R) > 0) return dx / R; + LOG(warn) << GetName() << "::GetXoffset : Unexpected null sum."; + return 0.; +} + +//_______________________________________________________________________________ +Double_t CbmTrdModuleRec2D::GetYoffset(Int_t n0) const +{ + Double_t dy(0.), T(0.); + Int_t n(n0 ? n0 : vs.size()); + for (Int_t it(0); it < n; it++) { + if (vxe[it] > 0) { // select tilted coupling + T += vs[it]; + dy += vs[it] * vx[it]; + } + } + if (TMath::Abs(T) > 0) return dy / T; + LOG(warn) << GetName() << "::GetYoffset : Unexpected null sum."; + return 0.; +} + +//_______________________________________________________________________________ +Double_t CbmTrdModuleRec2D::GetXcorr(Double_t dxIn, Int_t typ, Int_t cls) const +{ + /** Give the linear interpolation of SYS correction for current position offset "dx" based + * on LUT calculated wrt MC EbyE data. The position offset is expresed in [pw] units + * while the output is in [cm] + */ + + if (typ < 0 || typ > 2) { + //LOG(error)<< GetName() << "::GetXcorr : type in-param "<<typ<<" out of range."; + return 0; + } + Double_t dx = TMath::Abs(dxIn); + Int_t ii = TMath::Max(0, TMath::Nint(dx / fgCorrXdx) - 1), i0; // i1; + + if (ii < 0 || ii > NBINSCORRX) { + LOG(warn) << GetName() << "::GetXcorr : LUT idx " << ii << " out of range for dx=" << dxIn; + return 0; + } + if (dx < fgCorrXdx * ii) { + i0 = TMath::Max(0, ii - 1); + /*i1=ii;*/ + } + else { + i0 = ii; + /*i1=TMath::Min(NBINSCORRX-1,ii+1);*/ + } + + Float_t* xval = &fgCorrXval[typ][i0]; + if (cls == 1) xval = &fgCorrRcXval[typ][i0]; + else if (cls == 2) + xval = &fgCorrRcXbiasXval[typ][i0]; + Double_t DDx = (xval[1] - xval[0]), a = DDx / fgCorrXdx, b = xval[0] - DDx * (i0 + 0.5); + return (dxIn > 0 ? 1 : -1) * b + a * dxIn; +} + +//_______________________________________________________________________________ +Double_t CbmTrdModuleRec2D::GetYcorr(Double_t dy, Int_t /* cls*/) const +{ + /** Process y offset. Apply systematic correction for y (MC derived). + * The position offset is expresed in [pw] units while the output is in [cm] + */ + Float_t fdy(1.), yoff(0.); + Int_t n0(vs.size() - 2); + switch (n0) { + case 3: + fdy = fgCorrYval[0][0]; + yoff = fgCorrYval[0][1]; + if (IsMaxTilt() && IsSymmHit()) { + fdy = 0.; + yoff = (dy > 0 ? -1 : 1) * 1.56; + } + else if (!IsMaxTilt() && !IsSymmHit()) { + fdy = 0.; + yoff = (dy > 0 ? -1 : 1) * 1.06; + } + else if (!IsMaxTilt() && IsSymmHit()) { + fdy = 2.114532; + yoff = -0.263; + } + else /*if(IsMaxTilt()&&!IsSymmHit())*/ { + fdy = 2.8016010; + yoff = -1.38391; + } + break; + case 4: + fdy = fgCorrYval[1][0]; + yoff = fgCorrYval[1][1]; + if ((!IsMaxTilt() && IsLeftHit()) || (IsMaxTilt() && !IsLeftHit())) yoff *= -1; + break; + case 5: + case 7: + case 9: + case 11: + fdy = fgCorrYval[2][0]; + yoff = fgCorrYval[2][1]; + break; + case 6: + case 8: + case 10: + fdy = fgCorrYval[3][0]; + yoff = fgCorrYval[3][1]; + if ((!IsMaxTilt() && IsLeftHit()) || (IsMaxTilt() && !IsLeftHit())) yoff *= -1; + break; + } + return dy * fdy + yoff; +} + +//_______________________________________________________________________________ +void CbmTrdModuleRec2D::RecenterXoffset(Double_t& dx) +{ + /** Shift graph representation to fit dx[pw] in [-0.5, 0.5] + */ + + if (dx >= -0.5 && dx < 0.5) return; + Int_t ishift = Int_t(dx - 0.5) + (dx > 0.5 ? 1 : 0); + if (vcM + ishift < 0) ishift = -vcM; + else if (vcM + ishift >= GetNcols()) + ishift = GetNcols() - vcM - 1; + LOG(debug) << GetName() << "::RecenterXoffset : shift dx offset by " << ishift << " from dx=" << dx << " to " + << dx - ishift << " center col from " << (Int_t) vcM << " to " << Int_t(vcM + ishift); + dx -= ishift; + vcM += ishift; + for (UInt_t idx(0); idx < vx.size(); idx++) + vx[idx] -= ishift; +} + + +//_______________________________________________________________________________ +void CbmTrdModuleRec2D::RecenterYoffset(Double_t& dy) +{ + /** Shift graph representation to fit dy[ph] in [-0.5, 0.5] + */ + + if (dy >= -0.5 && dy < 0.5) return; + Int_t ishift = Int_t(dy - 0.5) + (dy > 0.5 ? 1 : 0); + // if(vrM+ishift < 0) ishift = - vrM; + // else if(vrM+ishift >= GetNrows()) ishift = GetNrows() - vrM -1; + LOG(debug) << GetName() << "::RecenterYoffset : shift dy offset by " << ishift << " from dy=" << dy << " to " + << dy - ishift; + dy -= ishift; + //vrM+= ishift; + // if(vrM==0 && dy<-0.5) dy=-0.5; + // if(vrM==GetNrows() -1 && dy>0.5) dy=0.5; +} + +//_______________________________________________________________________________ +Int_t CbmTrdModuleRec2D::LoadDigis(vector<const CbmTrdDigi*>* din, Int_t cid) +{ + /** Load RAW digis info in calibration aware strucuture CbmTrdDigiReco + * Do basic sanity checks; also incomplete adjacent digi and if found merge them. + */ + Int_t col(-1), /*row, */ colT(-1), colR(-1); + const CbmTrdDigi *dgT(NULL), *dgR(NULL); + for (vector<const CbmTrdDigi*>::iterator i = din->begin(), j = i + 1; i != din->end(); i++) { + dgT = (*i); + //row = + GetPadRowCol(dgT->GetAddressChannel(), colT); + // check column order for cluster + if (col >= 0 && colT != col + 1) { + LOG(error) << GetName() << "::LoadDigis : digis in cluster " << cid << " not in increasing order !"; + return 0; + } + col = colT; + colR = -1; + dgR = NULL; + if (j != din->end()) { + dgR = (*j); + //row = + GetPadRowCol(dgR->GetAddressChannel(), colR); + } + if (colR == colT) { + fDigis[cid].push_back(new CbmTrdDigiRec(*dgT, *dgR)); + j = din->erase(j); + } + else + fDigis[cid].push_back(new CbmTrdDigiRec(*dgT)); + + if (j != din->end()) j++; + } + return fDigis[cid].size(); +} + +//_______________________________________________________________________________ +Int_t CbmTrdModuleRec2D::ProjectDigis(Int_t cid, Int_t cjd) +{ + /** Load digis information in working vectors Digis are represented in the normal coordinate system of + * (pad width [pw], DAQ time [clk], signal [ADC chs]) with rectangular signals at integer + * positions. + */ + + if (fDigis.find(cid) == fDigis.end()) { + LOG(warn) << GetName() << "::ProjectDigis : Request cl id " << cid << " not found."; + return 0; + } + + vs.clear(); + vse.clear(); + vx.clear(); + vxe.clear(); + vt.clear(); + vt0 = 0; + vrM = 0; + vcM = 0; + vyM = 0; + viM = 0; + + Bool_t on(0); // flag signal transmition + Int_t n0(0), nsr(0), // no of signals in the cluster (all/rect) + NR(0), nr(0), // no of rect signals/channel in case of RC + NT(0), nt(0), // no of tilt signals/channel in case of RC + ovf(1); // over-flow flag for at least one of the digis + //dt; + Char_t ddt, // signal time offset wrt prompt + dt0(0); // cluster time offset wrt arbitrary t0 + Double_t r, re(100.), // rect signal + t, te(100.), // tilt signal + err, // final error parametrization for signal + xc(-0.5), // running signal-pad position + max(0.); // max signal + Int_t j(0), col(-1), col0(0), col1(0), step(0), row1; + + // link second row if needed + vector<CbmTrdDigiRec*>::iterator i1; + if (cjd >= 0) { + if (fDigis.find(cjd) == fDigis.end()) { + LOG(warn) << GetName() << "::ProjectDigis : Request cl id " << cjd << " not found. Skip second row."; + cjd = -1; + } + else + i1 = fDigis[cjd].begin(); + } + + const CbmTrdDigiRec *dg(NULL), *dg0(NULL), *dg1(NULL); + for (vector<CbmTrdDigiRec*>::iterator i = fDigis[cid].begin(); i != fDigis[cid].end(); i++, j++) { + dg = (*i); + dg0 = NULL; + dg1 = NULL; + if (CWRITE()) cout << "dg0 :" << dg->ToString(); + + // initialize + if (col < 0) { + vrM = GetPadRowCol(dg->GetAddressChannel(), col); + vt0 = dg->GetTimeDAQ(); // set arbitrary t0 to avoid double digis loop + } + GetPadRowCol(dg->GetAddressChannel(), col0); + nr = nt = 0; + + // read calibrated signals + t = dg->GetTiltCharge(on); + if (on) nt = 1; + r = dg->GetRectCharge(on); + if (on) nr = 1; + // look for matching neighbor digis in case of pad row cross + if (cjd >= 0) { + if ((dg0 = (i1 != fDigis[cjd].end()) ? (*i1) : NULL)) { + row1 = GetPadRowCol(dg0->GetAddressChannel(), col1); + if (!step) step = vrM - row1; + if (col1 == col0) { + r += dg0->GetRectCharge(on); + if (on) nr++; + } + else + dg0 = NULL; + } + if (step == 1 && i1 != fDigis[cjd].begin()) { + dg1 = (*(i1 - 1)); + GetPadRowCol(dg1->GetAddressChannel(), col1); + if (col1 == col0 - 1) { + t += dg1->GetTiltCharge(on); + if (on) nt++; + } + else + dg1 = NULL; + } + if (step == -1 && i1 != fDigis[cjd].end() && i1 + 1 != fDigis[cjd].end()) { + dg1 = (*(i1 + 1)); + GetPadRowCol(dg1->GetAddressChannel(), col1); + if (col1 == col0 + 1) { + t += dg1->GetTiltCharge(on); + if (on) nt++; + } + else + dg1 = NULL; + } + if (dg0) i1++; + } + if (CWRITE()) { + if (dg0) cout << "dgR :" << dg0->ToString(); + if (dg1) cout << "dgT :" << dg1->ToString(); + cout << "-------------------------------------" << endl; + } + + // process tilt signal/time + ddt = dg->GetTiltTime() - vt0; + if (ddt < dt0) dt0 = ddt; + if (abs(t) > 0) { + if (nt > 1) t *= 0.5; + err = te * (nt > 1 ? 0.707 : 1); + if (dg->HasTiltOvf()) { + ovf = -1; + err = 150.; + } + if (t > max) { + max = t; + vcM = j; + SetMaxTilt(1); + viM = vs.size(); + } + } + else + err = 300.; + vt.push_back(ddt); + vs.push_back(t); + vse.push_back(err); + vx.push_back(xc); + vxe.push_back(0.035); + xc += 0.5; + + // process rect signal/time + ddt = dg->GetRectTime() - vt0; + if (ddt < dt0) dt0 = ddt; + if (abs(r) > 0) { + nsr++; + if (nr > 1) r *= 0.5; + err = re * (nr > 1 ? 0.707 : 1); + if (dg->HasRectOvf()) { + ovf = -1; + err = 150.; + } + if (r > max) { + max = r; + vcM = j; + SetMaxTilt(0); + viM = vs.size(); + } + } + else + err = 300.; + vt.push_back(ddt); + vs.push_back(r); + vse.push_back(err); + vx.push_back(xc); + vxe.push_back(0.); + xc += 0.5; + NR += nr; + NT += nt; + } + + // add front and back anchor points if needed + if (TMath::Abs(vs[0]) > 1.e-3) { + xc = vx[0]; + ddt = vt[0]; + vs.insert(vs.begin(), 0); + vse.insert(vse.begin(), 300); + vt.insert(vt.begin(), ddt); + vx.insert(vx.begin(), xc - 0.5); + vxe.insert(vxe.begin(), 0); + viM++; + } + Int_t n(vs.size() - 1); + if (TMath::Abs(vs[n]) > 1.e-3) { + xc = vx[n] + 0.5; + ddt = vt[n]; + vs.push_back(0); + vse.push_back(300); + vt.push_back(ddt); + vx.push_back(xc); + vxe.push_back(0.035); + } + + n0 = vs.size() - 2; + // compute cluster asymmetry + Int_t nR = n0 + 1 - viM; + if (nR == viM) { + SetSymmHit(1); + if (vs.size() % 2) { + Double_t LS(0.), RS(0.); + for (UChar_t idx(0); idx < viM; idx++) + LS += vs[idx]; + for (UInt_t idx(viM + 1); idx < vx.size(); idx++) + RS += vs[idx]; + SetLeftSgn(LS < RS ? 0 : 1); + } + } + else { + SetSymmHit(0); + if (viM < nR) SetLeftHit(0); + else if (viM > nR) + SetLeftHit(1); + } + // recenter time and space profile + vt0 += dt0; + for (UInt_t idx(0); idx < vx.size(); idx++) { + vt[idx] -= dt0; + vx[idx] -= vcM; + } + vcM += col; + + // check if all signals have same significance + Int_t nmiss = 2 * nsr - NR; //printf("R : nsr[%d] NR[%d] nmiss[%d]\n", nsr, NR, nmiss); + if (cjd >= 0 && nmiss) { + SetBiasX(1); + for (UChar_t idx(1); idx < viM; idx++) { + if (vxe[idx] > 0.) continue; // select rect signals + if (vse[idx] > re * 0.8) SetBiasXleft(1); + } + if (vxe[viM] <= 0. && vse[viM] > re * 0.8) SetBiasXmid(1); + for (UChar_t idx(viM + 1); idx < vs.size() - 1; idx++) { + if (vxe[idx] > 0.) continue; // select rect signals + if (vse[idx] > re * 0.8) SetBiasXright(1); + } + } + else + SetBiasX(0); + nmiss = 2 * n0 - 2 * nsr - NT; //printf("T : n0[%d] nsr[%d] NT[%d] nmiss[%d]\n", n0, nsr, NT, nmiss); + if (cjd >= 0 && nmiss) { + SetBiasY(); + for (UChar_t idx(1); idx < viM; idx++) { + if (vxe[idx] > 0. && vse[idx] > te * 0.8) SetBiasYleft(1); // select tilt signals + } + if (vxe[viM] > 0. && vse[viM] > te * 0.8) SetBiasYmid(1); + for (UChar_t idx(viM + 1); idx < vs.size() - 1; idx++) { + if (vxe[idx] > 0. && vse[idx] > te * 0.8) SetBiasYright(1); // select tilt signals + } + } + else + SetBiasY(0); + + if (CWRITE()) { + printf("t0[clk]=%llu col[%2d] row[%2d] sz[%d] OVF[%c] %c", vt0, vcM, vrM, Int_t(vs.size() - 2), + (ovf < 0 ? 'y' : 'n'), IsOpenLeft() ? '(' : '['); + if (IsSymmHit()) { + if (HasLeftSgn()) printf("<|"); + else + printf("|>"); + } + else + printf("%s", IsLeftHit() ? "<<" : ">>"); + printf("%c bias[%c %c]\n", IsOpenRight() ? ')' : ']', IsBiasX() ? (IsBiasXleft() ? '<' : '>') : 'o', + IsBiasY() ? (IsBiasYleft() ? '<' : '>') : 'o'); + for (UInt_t idx(0); idx < vs.size(); idx++) { + printf("%2d dt[%2d] s[ADC]=%6.1f+-%6.1f x[pw]=%5.2f+-%5.2f ", idx, vt[idx], vs[idx], vse[idx], vx[idx], vxe[idx]); + if (idx == viM) printf("[%s]", (IsMaxTilt() ? "//" : "||")); + printf("\n"); + } + } + + if (ovf < 0) SetOvf(); //printf("SetOvf %d\n", vyM); } + return ovf * (vs.size() - 2); +} + +//_______________________________________________________________________________ +Int_t CbmTrdModuleRec2D::LoadDigis(vector<const CbmTrdDigi*>* digis, vector<CbmTrdDigi*>* vdgM, vector<Bool_t>* vmask, + ULong64_t& t0, Int_t& cM) +{ + /** Load digis information in working vectors. + * The digis as provided by the digitizer are replaced by the merged one + * according to the vmask map. Digis are represented in the normal coordinate system of + * (pad width [pw], DAQ time [clk], signal [ADC chs]) with rectangular signals at integer + * positions. + */ + vs.clear(); + vse.clear(); + vx.clear(); + vxe.clear(); + vt.clear(); + + cM = 0; // relative position of maximum signal + Int_t n0(0), // number of measured signals + ovf(1), // over-flow flag for at least one of the digis + dt; + Char_t ddt, // signal time offset wrt prompt + dt0(0); // cluster time offset wrt arbitrary t0 + Double_t r, re(100.), // rect signal + t, te(100.), // tilt signal + err, // final error parametrization for signal + xc(-0.5), // running signal-pad position + max(0.); // max signal + Int_t j(0), col0(-1), col1(0); + const CbmTrdDigi* dg(NULL); + vector<CbmTrdDigi*>::iterator idgM = vdgM->begin(); + for (vector<const CbmTrdDigi*>::iterator i = digis->begin(); i != digis->end(); i++, j++) { + dg = (*i); + if ((*vmask)[j]) { + dg = (*idgM); + idgM++; + } + if (CWRITE()) cout << dg->ToString(); + r = dg->GetCharge(t, dt); + if (t0 == 0) t0 = dg->GetTimeDAQ(); // set arbitrary t0 to avoid double digis loop + if (col0 < 0) GetPadRowCol(dg->GetAddressChannel(), col0); // initialilze + ddt = dg->GetTimeDAQ() - t0; + if (ddt < dt0) dt0 = ddt; + + // check column wise organization + GetPadRowCol(dg->GetAddressChannel(), col1); + if (col0 + j != col1) { + LOG(error) << GetName() << "::LoadDigis : digis in cluster not in increasing order !"; + return 0; + } + + // process tilt signal + if (t > 0) { + err = te; + if (t > 4094) { + ovf = -1; + err = 150.; + } + t -= CbmTrdFASP::GetBaselineCorr(); + n0++; + if (t > max) { + max = t; + cM = j; + } + } + else + err = 300.; + vt.push_back(ddt); + vs.push_back(t); + vse.push_back(err); + vx.push_back(xc); + vxe.push_back(0.035); + xc += 0.5; + + // process rect signal + ddt += dt; + if (ddt < dt0) dt0 = ddt; + if (r > 0) { + err = re; + if (r > 4094) { + ovf = -1; + err = 150.; + } + r -= CbmTrdFASP::GetBaselineCorr(); + n0++; + if (r > max) { + max = r; + cM = j; + } + } + else + err = 300.; + vt.push_back(ddt); + vs.push_back(r); + vse.push_back(err); + vx.push_back(xc); + vxe.push_back(0.); + xc += 0.5; + } + + // remove merged digis if they were created + if (idgM != vdgM->end()) LOG(warn) << GetName() << "::LoadDigis : not all merged digis have been consumed !"; + for (idgM = vdgM->begin(); idgM != vdgM->end(); idgM++) + delete (*idgM); + + // add front and back anchor points if needed + if (TMath::Abs(vs[0]) > 1.e-3) { + xc = vx[0]; + ddt = vt[0]; + vs.insert(vs.begin(), 0); + vse.insert(vse.begin(), 300); + vt.insert(vt.begin(), ddt); + vx.insert(vx.begin(), xc - 0.5); + vxe.insert(vxe.begin(), 0); + } + Int_t n(vs.size() - 1); + if (TMath::Abs(vs[n]) > 1.e-3) { + xc = vx[n] + 0.5; + ddt = vt[n]; + vs.push_back(0); + vse.push_back(300); + vt.push_back(ddt); + vx.push_back(xc); + vxe.push_back(0.035); + } + // recenter time and space profile + t0 += dt0; + for (UInt_t idx(0); idx < vx.size(); idx++) { + vt[idx] -= dt0; + vx[idx] -= cM; + } + return ovf * n0; +} + + +//_______________________________________________________________________________ +Int_t CbmTrdModuleRec2D::LoadDigisRC(vector<const CbmTrdDigi*>* digis, const Int_t r0, const Int_t a0, + /*vector<CbmTrdDigi*> *vdgM, */ ULong64_t& t0, Int_t& cM) +{ + /** Load digis information for row-cross hits in working vectors. + * The digis as provided by the digitizer are replaced by the merged one (TODO) + * according to the vmask map. Digis are represented in the normal coordinate system of + * (pad width [pw], DAQ time [clk], signal [ADC chs]) with rectangular signals at integer + * positions. + * TODO + * 1. Time information in the secondary row not used. + * 2. Time walk (dependence on charge) not recovered by calibration. + * + */ + vs.clear(); + vse.clear(); + vx.clear(); + vxe.clear(); + vt.clear(); + + cM = 0; // relative position of maximum signal + Int_t step, + n0(0), // number of measured signals + ovf(1), // over-flow flag for at least one of the digis + dt, dT; + Char_t ddt, // signal time offset wrt prompt + dt0(0); // cluster time offset wrt arbitrary t0 + Double_t r, R, re(100.), // rect signal + t, T, te(100.), // tilt signal + err, // final error parametrization for signal + xc(0.), // running signal-pad position + max(0.); // max signal + Int_t j(0), row, col, col0(-1), col1(0); + //vector<CbmTrdDigi*>::iterator idgM=vdgM->begin(); + + vector<const CbmTrdDigi*>::iterator i0, i1, ix0, ix1; + i0 = digis->begin(); + i1 = i0; + do { + row = GetPadRowCol((*i1)->GetAddressChannel(), col1); + if (col0 < 0) col0 = col1; + if (row == r0) i1++; + else + break; + } while (i1 != digis->end()); + ix0 = i1; + ix1 = digis->end(); + col = col0; + step = -1; + if (a0 > 0) { + i0 = i1; + ix0 = digis->end(); + ix1 = i1; + i1 = digis->begin(); + col = col0; + col0 = col1; + col1 = col; + col = col0; + step = 1; + } + if (CWRITE()) printf("col0[%d] col1[%d] step[%2d]\n", col0, col1, step); + const CbmTrdDigi *dg0(NULL), *dg1(NULL), *dg10(NULL); + + // always loop on the largest cluster + for (; i0 != ix0; i0++, j++) { + dg0 = (*i0); + dg1 = NULL; + dg10 = NULL; + if (CWRITE()) cout << "dg0 :" << dg0->ToString(); + + r = dg0->GetCharge(t, dt); + if (t > 0) t -= CbmTrdFASP::GetBaselineCorr(); + if (r > 0) r -= CbmTrdFASP::GetBaselineCorr(); + + if (t0 == 0) t0 = dg0->GetTimeDAQ(); // set arbitrary t0 to avoid double digis loop + ddt = dg0->GetTimeDAQ() - t0; + if (ddt < dt0) dt0 = ddt; + + // check column wise organization + row = GetPadRowCol(dg0->GetAddressChannel(), col0); + if (col + j != col0) { + LOG(error) << GetName() << "::LoadDigisRC : digis in cluster not in increasing order " << col0 << " !"; + return 0; + } + + // look for matching neighbor digis + if ((dg1 = (i1 != ix1) ? (*i1) : NULL)) { + GetPadRowCol(dg1->GetAddressChannel(), col1); + if (col1 == col0) { + R = dg1->GetCharge(T, dT); + if (R > 0.) r += R - CbmTrdFASP::GetBaselineCorr(); + } + else + dg1 = NULL; + } + if (step == 1 && i1 != digis->begin()) { + dg10 = (*(i1 - 1)); + GetPadRowCol(dg10->GetAddressChannel(), col1); + if (col1 == col0 - 1) { + dg10->GetCharge(T, dT); + if (T > 0.) t += T - CbmTrdFASP::GetBaselineCorr(); + } + else + dg10 = NULL; + } + if (step == -1 && i1 != ix1 && i1 + 1 != ix1) { + dg10 = (*(i1 + 1)); + GetPadRowCol(dg10->GetAddressChannel(), col1); + if (col1 == col0 + 1) { + dg10->GetCharge(T, dT); + if (T > 0.) t += T - CbmTrdFASP::GetBaselineCorr(); + } + else + dg10 = NULL; + } + if (dg1) i1++; + + if (CWRITE()) { + if (dg1) cout << "dgR :" << dg1->ToString(); + if (dg10) cout << "dgT :" << dg10->ToString(); + cout << "-------------------------------------" << endl; + } + + // process tilt signal + if (t > 0) { + err = te; + n0++; + if (t > max) { + max = t; + cM = j; + } + } + else + err = 300.; + vt.push_back(ddt); + vs.push_back(t); + vse.push_back(err); + vx.push_back(xc); + vxe.push_back(0.035); + + // process rect signal + ddt += dt; + if (ddt < dt0) dt0 = ddt; + if (r > 0) { + err = re; + n0++; + if (r > max) { + max = r; + cM = j; + } + } + else + err = 300.; + vt.push_back(ddt); + vs.push_back(r); + vse.push_back(err); + vx.push_back(xc); + vxe.push_back(0.); + xc += 1; + } + + // // remove merged digis if they were created + // if(idgM != vdgM->end()) LOG(warn) << GetName() << "::LoadDigis : not all merged digis have been consumed !"; + // for(idgM=vdgM->begin(); idgM!=vdgM->end(); idgM++) delete (*idgM); + // + // add front and back anchor points if needed + if (TMath::Abs(vs[0]) > 1.e-3) { + xc = vx[0]; + ddt = vt[0]; + vs.insert(vs.begin(), 0); + vse.insert(vse.begin(), 300); + vt.insert(vt.begin(), ddt); + vx.insert(vx.begin(), xc - 1); + vxe.insert(vxe.begin(), 0); + } + Int_t n(vs.size() - 1); + if (TMath::Abs(vs[n]) > 1.e-3) { + xc = vx[n] + 1; + ddt = vt[n]; + vs.push_back(0); + vse.push_back(300); + vt.push_back(ddt); + vx.push_back(xc); + vxe.push_back(0.035); + } + + // recenter time and space profile + if (cM + col >= fDigiPar->GetNofColumns()) cM = fDigiPar->GetNofColumns() - col - 1; + else if (cM + col < 0) + cM = -col; + t0 += dt0; + for (UInt_t idx(0); idx < vx.size(); idx++) { + vt[idx] -= dt0; + vx[idx] -= cM; + } + cM += col; + return ovf * n0; +} + +//_______________________________________________________________________________ +Bool_t CbmTrdModuleRec2D::MergeDigis(vector<const CbmTrdDigi*>* digis, vector<CbmTrdDigi*>* vdgM, vector<Bool_t>* vmask) +{ + /* Merge digis in the cluster if their topology within it allows it although cuts in the + * digi merger procedure (CbmTrdFASP::WriteDigi()) were not fulfilled. + * Normally this are boundary signals with large time delays wrt neighbors + */ + + CbmTrdDigi* dgM(NULL); + if (digis->size() < 2) { // sanity check ... just in case + LOG(warn) << GetName() << "::MergeDigis : Bad digi config for cluster :"; + return kFALSE; + } + + Double_t r, t; + Int_t colR, colT, dt, contor(0); + Bool_t kFOUND(0); + for (vector<const CbmTrdDigi*>::iterator idig = digis->begin(), jdig = idig + 1; jdig != digis->end(); + idig++, jdig++, contor++) { + const CbmTrdDigi* dgT((*idig)); // tilt signal digi + const CbmTrdDigi* dgR((*jdig)); // rect signal digi + GetPadRowCol(dgR->GetAddressChannel(), colR); + GetPadRowCol(dgT->GetAddressChannel(), colT); + + if (colR != colT) continue; + + dgM = new CbmTrdDigi(*dgT); + r = dgR->GetCharge(t, dt); + dgT->GetCharge(t, dt); + dt = dgR->GetTimeDAQ() - dgT->GetTimeDAQ(); + dgM->SetCharge(t, r, dt); + Int_t rtrg(dgR->GetTriggerType() & 2), ttrg(dgT->GetTriggerType() & 1); + dgM->SetTriggerType(rtrg | ttrg); //merge the triggers + if (CWRITE()) { + cout << "MERGE" << endl; + cout << dgT->ToString(); + cout << dgR->ToString(); + cout << "TO" << endl; + cout << dgM->ToString(); + cout << "..." << endl; + } + kFOUND = 1; + + vdgM->push_back(dgM); + (*vmask)[contor] = 1; + jdig = digis->erase(jdig); + if (jdig == digis->end()) break; + } + + if (!kFOUND) { + LOG(warn) << GetName() << "::MergeDigis : Digi to pads matching failed for cluster :"; + return kFALSE; + } + return kTRUE; +} + + +Float_t CbmTrdModuleRec2D::fgCorrXdx = 0.01; +Float_t CbmTrdModuleRec2D::fgCorrXval[3][NBINSCORRX] = { + {-0.001, -0.001, -0.002, -0.002, -0.003, -0.003, -0.003, -0.004, -0.004, -0.006, -0.006, -0.006, -0.007, + -0.007, -0.008, -0.008, -0.008, -0.009, -0.009, -0.011, -0.011, -0.011, -0.012, -0.012, -0.012, -0.012, + -0.013, -0.013, -0.013, -0.013, -0.014, -0.014, -0.014, -0.014, -0.014, -0.016, -0.016, -0.016, -0.016, + -0.017, -0.017, -0.017, -0.018, -0.018, -0.018, -0.018, -0.018, 0.000, 0.000, 0.000}, + {0.467, 0.430, 0.396, 0.364, 0.335, 0.312, 0.291, 0.256, 0.234, 0.219, 0.207, 0.191, 0.172, + 0.154, 0.147, 0.134, 0.123, 0.119, 0.109, 0.122, 0.113, 0.104, 0.093, 0.087, 0.079, 0.073, + 0.067, 0.063, 0.058, 0.053, 0.049, 0.046, 0.042, 0.038, 0.036, 0.032, 0.029, 0.027, 0.024, + 0.022, 0.019, 0.017, 0.014, 0.013, 0.011, 0.009, 0.007, 0.004, 0.003, 0.001}, + {0.001, 0.001, 0.001, 0.001, 0.002, 0.002, 0.001, 0.002, 0.004, 0.003, 0.002, 0.002, 0.002, + 0.002, 0.002, 0.002, 0.003, 0.004, 0.003, 0.004, 0.004, 0.007, 0.003, 0.004, 0.002, 0.002, + -0.011, -0.011, -0.012, -0.012, -0.012, -0.013, -0.013, -0.013, -0.014, -0.014, -0.014, -0.016, -0.016, + -0.016, -0.017, -0.017, -0.017, -0.018, -0.018, -0.018, -0.019, 0.029, 0.018, 0.001}}; +Float_t CbmTrdModuleRec2D::fgCorrYval[NBINSCORRY][2] = {{2.421729, 0.}, + {0.629389, -0.215285}, + {0.23958, 0.}, + {0.151913, 0.054404}}; +Float_t CbmTrdModuleRec2D::fgCorrRcXval[2][NBINSCORRX] = { + {-0.00050, -0.00050, -0.00150, -0.00250, -0.00250, -0.00350, -0.00450, -0.00450, -0.00550, -0.00650, + -0.00650, -0.00750, -0.00850, -0.00850, -0.00850, -0.00950, -0.00950, -0.00950, -0.01050, -0.01150, + -0.01150, -0.01150, -0.01250, -0.01250, -0.01250, -0.01250, -0.01350, -0.01350, -0.01350, -0.01350, + -0.01450, -0.01450, -0.01450, -0.01550, -0.01550, -0.01550, -0.01550, -0.01650, -0.01650, -0.01550, + -0.01650, -0.01614, -0.01620, -0.01624, -0.01626, -0.01627, -0.01626, -0.01624, -0.01620, -0.01615}, + {0.36412, 0.34567, 0.32815, 0.31152, 0.29574, 0.28075, 0.26652, 0.25302, 0.24020, 0.22803, 0.21647, 0.21400, 0.19400, + 0.18520, 0.17582, 0.16600, 0.14600, 0.13800, 0.14280, 0.14200, 0.13400, 0.12600, 0.12200, 0.11000, 0.10200, 0.09400, + 0.09000, 0.08600, 0.08200, 0.07400, 0.07000, 0.06600, 0.06600, 0.06200, 0.05800, 0.05400, 0.05400, 0.05000, 0.04600, + 0.04600, 0.04200, 0.03800, 0.03800, 0.03400, 0.03400, 0.03000, 0.03000, 0.02600, 0.02200, 0.02200}}; +Float_t CbmTrdModuleRec2D::fgCorrRcXbiasXval[3][NBINSCORRX] = { + {0.00100, 0.00260, 0.00540, 0.00740, 0.00900, 0.01060, 0.01300, 0.01460, 0.01660, 0.01900, 0.02060, 0.02260, 0.02420, + 0.02700, 0.02860, 0.02980, 0.03220, 0.03340, 0.03540, 0.03620, 0.03820, 0.04020, 0.04180, 0.04340, 0.04460, 0.04620, + 0.04740, 0.04941, 0.05088, 0.05233, 0.05375, 0.05515, 0.05653, 0.05788, 0.05921, 0.06052, 0.06180, 0.06306, 0.06430, + 0.06551, 0.06670, 0.06786, 0.06901, 0.07012, 0.07122, 0.07229, 0.07334, 0.07436, 0.07536, 0.07634}, + {0.00100, 0.00380, 0.00780, 0.00900, 0.01220, 0.01460, 0.01860, 0.01940, 0.02260, 0.02540, 0.02820, 0.03060, 0.03220, + 0.03660, 0.03980, 0.04094, 0.04420, 0.04620, 0.04824, 0.04980, 0.05298, 0.05532, 0.05740, 0.05991, 0.06217, 0.06500, + 0.06540, 0.06900, 0.07096, 0.07310, 0.07380, 0.07729, 0.07935, 0.08139, 0.08340, 0.08538, 0.08734, 0.08928, 0.08900, + 0.09307, 0.09493, 0.09340, 0.09858, 0.09620, 0.09740, 0.10386, 0.09980, 0.10726, 0.10892, 0.11056}, + {0.00011, 0.00140, 0.00340, 0.00420, 0.00500, 0.00620, 0.00820, 0.00860, 0.01060, 0.01100, 0.01220, 0.01340, 0.01500, + 0.01540, 0.01700, 0.01820, 0.01900, 0.02060, 0.02180, 0.02260, 0.02340, 0.02420, 0.02500, 0.02500, 0.02660, 0.02740, + 0.02820, 0.02900, 0.03020, 0.03180, 0.03300, 0.03260, 0.03380, 0.03460, 0.03500, 0.03580, 0.03780, 0.03820, 0.03860, + 0.03900, 0.04100, 0.04180, 0.04060, 0.04300, 0.04340, 0.04340, 0.04380, 0.04460, 0.04580, 0.04540}}; + +ClassImp(CbmTrdModuleRec2D) diff --git a/reco/detectors/trd/CbmTrdModuleRec2D.h b/reco/detectors/trd/CbmTrdModuleRec2D.h new file mode 100644 index 0000000000..aa27610823 --- /dev/null +++ b/reco/detectors/trd/CbmTrdModuleRec2D.h @@ -0,0 +1,235 @@ +/* Copyright (C) 2018-2020 Horia Hulubei National Institute of Physics and Nuclear Engineering, Bucharest + SPDX-License-Identifier: GPL-3.0-only + Authors: Alexandru Bercuci[committer] */ + +#ifndef CBMTRDMODULEREC2D_H +#define CBMTRDMODULEREC2D_H + +#include "CbmTrdModuleRec.h" + +#include <list> +#include <map> +#include <vector> +#define NBINSCORRX 50 //! no of bins in the discretized correction LUT +#define NBINSCORRY 4 //! no of bins in the parametrization correction +#define NANODE 9 + +using std::list; +using std::map; +using std::vector; +class TGraphErrors; +class CbmTrdDigiRec; +class TF1; +/** @class CbmTrdModuleRec2D + ** @brief Cluster finding and hit reconstruction algorithms for the TRD(2D) module. + ** @author Alexandru Bercucic <abercuci@niham.nipne.ro> + ** @since 01.02.2019 + ** @date 01.10.2021 + ** + ** Extend the TRD module reconstructor for the particular case of inner TRD-2D modules. + ** The class is a collection of algorithms to : + ** - identify time and spatially correlated digis and build clusters + ** - identify the type of clusters and apply further merging/deconvolution + ** - apply FEE (channel gain, baseline) and detector (energy gain, maps, etc) calibration + ** - steer the calculation of hit 4D parameters (x, y, t, E) + **/ +class CbmTrdModuleRec2D : public CbmTrdModuleRec { +public: + enum CbmTrdModuleRec2Dconfig + { + kVerbose = 0 // steer verbosity on/off + , + kDraw // steer graphic representation on/off + }; + + /** \brief Default constructor.*/ + CbmTrdModuleRec2D(); + /** \brief Constructor with placement */ + CbmTrdModuleRec2D(Int_t mod, Int_t ly = -1, Int_t rot = 0); + virtual ~CbmTrdModuleRec2D(); + + + /** \brief Add digi to local module **/ + virtual Bool_t AddDigi(const CbmTrdDigi* d, Int_t id); + /** \brief Config task with the following settings + * \param[in] v verbosity toggle + * \param[in] d drawing toggle + */ + virtual inline void Config(Bool_t v, Bool_t d); + virtual void DrawHit(CbmTrdHit*) const { ; } + /** \brief Count RO channels (R or T) with data**/ + virtual Int_t GetOverThreshold() const; + /** \brief Check hit quality (deconvolute pile-ups, etc)**/ + virtual Bool_t PreProcessHits(); + /** \brief Finalize hits (merge RC hits, etc)**/ + virtual Bool_t PostProcessHits(); + /** \brief Finalize clusters **/ + virtual Int_t FindClusters(); + /** \brief Steering routine for building hits **/ + virtual Bool_t MakeHits(); + /** \brief Steering routine for converting cluster to hit **/ + virtual CbmTrdHit* MakeHit(Int_t cId, const CbmTrdCluster* c, std::vector<const CbmTrdDigi*>* digis); + /** \brief Load RAW digis into working array of RECO digis + * \param[in] din list of RAW digis in increasing order of column no + * \param[in] cid cluster index in the cluster array + * \return no of digis loaded + */ + Int_t LoadDigis(vector<const CbmTrdDigi*>* din, Int_t cid); + Int_t ProjectDigis(Int_t cid, Int_t cjd = -1); + /** \brief Implement topologic cuts for hit merging + * \return index of anode wire wrt to boundary or 0 if check fails + */ + Int_t CheckMerge(Int_t cid, Int_t cjd); + /** \brief Algorithm for hit merging + * \param[in] h hit to be modified by addition of hp. + * \param[in] a0 anode hypothesis around boundary (see CheckMerge function). + * \return TRUE if succesful. + */ + Bool_t MergeHits(CbmTrdHit* h, Int_t a0); + Bool_t BuildHit(CbmTrdHit* h); + UShort_t GetHitMap() const { return vyM; } + /** \brief x position correction based on LUT + * \param[in] dx offset computed on charge sharing expressed in [pw] + * \param[in] typ hit type central pad [0] or edge [1] + * \param[in] cls correction class x wrt center [0] row-cross [1] row-cross biassed x [2] + * \return correction expresed in [cm] + */ + Double_t GetXcorr(Double_t dx, Int_t typ, Int_t cls = 0) const; + /** \brief y position correction based on LUT + * \param[in] dy offset computed on charge sharing expressed in [ph] + * \param[in] cls correction class + * \return correction expresed in [cm] + */ + Double_t GetYcorr(Double_t dy, Int_t cls = 0) const; + /** \brief Shift graph representation to [-0.5, 0.5] + * \param[in] dx offset wrt center pad [pw] + */ + void RecenterXoffset(Double_t& dx); + /** \brief Shift graph representation to [-0.5, 0.5] + * \param[in] dy offset wrt center pad [ph] + */ + void RecenterYoffset(Double_t& dy); + /** \brief Hit classification wrt center pad + * \return hit type : center hit [0]; side hit [1] + */ + Int_t GetHitClass() const; + /** \brief Hit classification wrt signal bias + * \return hit type : center hit [0]; side hit [1] + */ + Int_t GetHitRcClass(Int_t a0) const; + +protected: +private: + CbmTrdModuleRec2D(const CbmTrdModuleRec2D& ref); + const CbmTrdModuleRec2D& operator=(const CbmTrdModuleRec2D& ref); + + Bool_t CDRAW() const { return TESTBIT(fConfigMap, kDraw); } + Bool_t CWRITE() const { return TESTBIT(fConfigMap, kVerbose); } + /** \brief Implement cuts for hit convolution definition + * \param[in] h hit to be analysed. + * \return TRUE if double cluster + */ + Bool_t CheckConvolution(CbmTrdHit* h) const; + /** \brief Algorithm for cluster spliting + * \param[in] h hit to be analysed. + * \return TRUE if succesful. The extra cluster is added to the end of the hits array + */ + Bool_t Deconvolute(CbmTrdHit* h); + Double_t GetXoffset(Int_t n0 = 0) const; + Double_t GetYoffset(Int_t n0 = 0) const; + /** \brief Load digis info into local data structures + * \param[in] digis initial digis list shrinked for incomplete digis. + * \param[in] vdgM list of merged digis + * \param[in] vmask position of merged digis in the digis list + * \param[in] t0 prompt time of cluster + * \param[out] cM relative position of maximum + * \return no of signals loaded. if detected overflow negative number + */ + Int_t LoadDigis(std::vector<const CbmTrdDigi*>* digis, std::vector<CbmTrdDigi*>* vdgM, std::vector<Bool_t>* vmask, + ULong64_t& t0, Int_t& cM); + Int_t LoadDigisRC(vector<const CbmTrdDigi*>* digis, const Int_t r0, const Int_t a0, + /*vector<CbmTrdDigi*> *vdgM, */ ULong64_t& t0, Int_t& cM); + + /** \brief Merge R/T signals to digis if topological conditions in cluster are fulfilled + * \param[in] digis initial digis list. + * \param[out] vdgM list of merged digis + * \param[out] vmask position of merged digis in the output digis list + * \return If successful the digis are resized by removing the references to incomplete clusters + */ + Bool_t MergeDigis(std::vector<const CbmTrdDigi*>* digis, std::vector<CbmTrdDigi*>* vdgM, std::vector<Bool_t>* vmask); + + Bool_t HasLeftSgn() const { return TESTBIT(vyM, 3); } + Bool_t HasOvf() const { return TESTBIT(vyM, 12); } + Bool_t IsBiasX() const { return TESTBIT(vyM, 4); } + Bool_t IsBiasXleft() const { return TESTBIT(vyM, 5); } + Bool_t IsBiasXmid() const { return TESTBIT(vyM, 6); } + Bool_t IsBiasXright() const { return TESTBIT(vyM, 7); } + Bool_t IsBiasY() const { return TESTBIT(vyM, 8); } + Bool_t IsBiasYleft() const { return TESTBIT(vyM, 9); } + Bool_t IsLeftHit() const { return TESTBIT(vyM, 2); } + Bool_t IsMaxTilt() const { return TESTBIT(vyM, 0); } + Bool_t IsOpenLeft() const { return (viM % 2 && !IsMaxTilt()) || (!(viM % 2) && IsMaxTilt()); } + inline Bool_t IsOpenRight() const; + Bool_t IsSymmHit() const { return TESTBIT(vyM, 1); } + void SetBiasX(Bool_t set = 1) { set ? SETBIT(vyM, 4) : CLRBIT(vyM, 4); } + void SetBiasXleft(Bool_t set = 1) { set ? SETBIT(vyM, 5) : CLRBIT(vyM, 5); } + void SetBiasXmid(Bool_t set = 1) { set ? SETBIT(vyM, 6) : CLRBIT(vyM, 6); } + void SetBiasXright(Bool_t set = 1) { set ? SETBIT(vyM, 7) : CLRBIT(vyM, 7); } + void SetBiasY(Bool_t set = 1) { set ? SETBIT(vyM, 8) : CLRBIT(vyM, 8); } + void SetBiasYleft(Bool_t set = 1) { set ? SETBIT(vyM, 9) : CLRBIT(vyM, 9); } + void SetBiasYmid(Bool_t set = 1) { set ? SETBIT(vyM, 10) : CLRBIT(vyM, 10); } + void SetBiasYright(Bool_t set = 1) { set ? SETBIT(vyM, 11) : CLRBIT(vyM, 11); } + void SetLeftSgn(Bool_t set = 1) { set ? SETBIT(vyM, 3) : CLRBIT(vyM, 3); } + void SetLeftHit(Bool_t set = 1) { set ? SETBIT(vyM, 2) : CLRBIT(vyM, 2); } + void SetSymmHit(Bool_t set = 1) { set ? SETBIT(vyM, 1) : CLRBIT(vyM, 1); } + void SetMaxTilt(Bool_t set = 1) { set ? SETBIT(vyM, 0) : CLRBIT(vyM, 0); } + void SetOvf(Bool_t set = 1) { set ? SETBIT(vyM, 12) : CLRBIT(vyM, 12); } + + UChar_t fConfigMap; // task configuration settings + ULong64_t fT0; //! start time of event/time slice [clk] + std::map<Int_t, std::list<CbmTrdCluster*>> fBuffer; //row-wise organized clusters + std::map<Int_t, vector<CbmTrdDigiRec*>> fDigis; //!cluster-wise organized calibrated digi + // working representation of a hit on which the reconstruction is performed + ULong64_t vt0; //! start time of current hit [clk] + UChar_t vcM; //! maximum col + UChar_t vrM; //! maximum row + UChar_t viM; //! index of maximum signal in the projection + UShort_t vyM; //! bit map for cluster topology classification + std::vector<Double_t> vs; //! working copy of signals from cluster + std::vector<Double_t> vse; //! working copy of signal errors from cluster + std::vector<Char_t> vt; //! working copy of signal relative timing + std::vector<Double_t> vx; //! working copy of signal relative positions + std::vector<Double_t> vxe; //! working copy of signal relative position errors + + static Float_t fgCorrXdx; //! step of the discretized correction LUT + static Float_t fgCorrXval[3][NBINSCORRX]; //! discretized correction LUT + static Float_t fgCorrYval[NBINSCORRY][2]; //! discretized correction params + static Float_t fgCorrRcXval[2][NBINSCORRX]; //! discretized correction LUT + static Float_t fgCorrRcXbiasXval[3][NBINSCORRX]; //! discretized correction LUT + static Double_t fgDT[3]; //! FASP delay wrt signal + static TGraphErrors* fgEdep; //! data handler for cluster PRF + static TF1* fgPRF; //! fitter for cluster PRF + static TGraphErrors* fgT; //! data handler for cluster TRF + + ClassDef(CbmTrdModuleRec2D, + 2) // Triangular pad module; Cluster finding and hit reconstruction algorithms +}; + +void CbmTrdModuleRec2D::Config(Bool_t v, Bool_t d) +{ + if (v) SETBIT(fConfigMap, kVerbose); + else + CLRBIT(fConfigMap, kVerbose); + printf("CbmTrdModuleRec2D::Verbose[%c]\n", CWRITE() ? 'y' : 'n'); + if (d) SETBIT(fConfigMap, kDraw); + else + CLRBIT(fConfigMap, kDraw); + printf("CbmTrdModuleRec2D::Draw[%c]\n", CDRAW() ? 'y' : 'n'); +} + +Bool_t CbmTrdModuleRec2D::IsOpenRight() const +{ + Int_t nR = vs.size() - 1 - viM; + return (nR % 2 && IsMaxTilt()) || (!(nR % 2) && !IsMaxTilt()); +} +#endif diff --git a/reco/detectors/trd/CbmTrdRecoLinkDef.h b/reco/detectors/trd/CbmTrdRecoLinkDef.h index 92169034ae..31652af862 100644 --- a/reco/detectors/trd/CbmTrdRecoLinkDef.h +++ b/reco/detectors/trd/CbmTrdRecoLinkDef.h @@ -16,7 +16,7 @@ #pragma link C++ class CbmTrdHitProducer + ; #pragma link C++ class CbmTrdModuleRec + ; #pragma link C++ class CbmTrdModuleRecR + ; -#pragma link C++ class CbmTrdModuleRecT + ; +#pragma link C++ class CbmTrdModuleRec2D + ; #pragma link C++ class CbmTrdDigiRec + ; #pragma link C++ class CbmTrdClusterizerFastQa + ; -- GitLab