/*First Version of TestBeam tools, developed for the SPS2016 beamtime and the legacy DAQ-chain. *Intended for the F/MS Prototypes. *For usage with Bucharest, modifications of the functions GetChannelMap and GetRowID are neccessary. */ #include "CbmTrdTestBeamTools.h" #include #include #include ClassImp(CbmTrdTestBeamTools) CbmTrdTestBeamTools::CbmTrdTestBeamTools () : TObject(), fDigis(nullptr) { LOG(INFO) << TString("Default Constructor of ")+TString(this->GetName()) << FairLogger::endl; Instance(this); } CbmTrdTestBeamTools* CbmTrdTestBeamTools::Instance(CbmTrdTestBeamTools* NewInstance=nullptr){ static CbmTrdTestBeamTools* CurrentInstance=nullptr; if (!NewInstance&&!CurrentInstance) CurrentInstance = new CbmTrdTestBeamTools(); if (!NewInstance) return CurrentInstance; if (!CurrentInstance) CurrentInstance=NewInstance; if (NewInstance!=CurrentInstance) LOG(FATAL)<<"Preexisting Instance of "<< CurrentInstance->GetName()<GetSourceAddress(); Int_t SpaId = sourceA-GetSpadicBaseAddress(); if (SpaId<0||SpaId>5){ LOG(ERROR) << "Source Address " << sourceA << " not known." << FairLogger::endl; SpaId = -1; } return SpaId; } Int_t CbmTrdTestBeamTools::GetRobID(CbmSpadicRawMessage* raw) { /* * Get the numerical RobId of origin for the given Message. * SPS2016 Case: Numerical id of the syscore on which the spadic was connected. */ Int_t eqID=raw->GetEquipmentID(); Int_t SyscoreID=eqID-GetBaseEquipmentID(); if((SyscoreID<0||SyscoreID>GetNrRobs())){ LOG(ERROR) << "EqID " << eqID << " not known." << FairLogger::endl; SyscoreID=-1; } return SyscoreID; } Int_t CbmTrdTestBeamTools::GetLayerID(CbmSpadicRawMessage* raw) { /* * Get the layer from whic the given message originated. Defined in downstream direction. * Layer 0 is closest to the target. */ return GetModuleID(raw); }; Int_t CbmTrdTestBeamTools::GetRowID(CbmSpadicRawMessage* raw){ /*Get row of the active channel. *Upper row is row 1. */ return 1-GetChannelOnPadPlane(raw)/16; }; Int_t CbmTrdTestBeamTools::GetColumnID(CbmSpadicRawMessage* raw){ /*Get column of the active channel. *With view towards the target, column 0 is on the left side. *Lower numbered colums are towards the left side of the module. */ Int_t ColID=(GetSpadicID(raw)/2)*16+(GetChannelOnPadPlane(raw))%16; return ColID; }; TString CbmTrdTestBeamTools::GetSpadicName(Int_t DpbID,Int_t SpadicID,TString DpbName="SysCore",kSpadicSize SpadicSize=kFullSpadic) { /* Get a String of the Form "Syscore_0_Spadic_0" describing the specific SPADIC corresponding to the input parameters. * The Parameter InputType allows either the Equipment ID/Source Address or the final Syscore/Spadic ID to be used. * kRawData (default) is the parameter that allows the raw EqID/Source Address to be used, kProcessedData takes Syscore/SpadicID. * The Parameter OutputType allows adressing either the corresponding FullSpadic, via kFullSpadic (default), or the original HalfSpadic, * via kHalfSpadic. * */ TString spadicName=""; spadicName=DpbName+"_"+std::to_string(DpbID)+"_"; if(SpadicSize){ spadicName += "Spadic_"; }else{ spadicName += "Half_Spadic_"; } spadicName+=std::to_string(SpadicID); return spadicName; } // virtual Int_t GetCombiID(CbmSpadicRawMessage* raw); Int_t CbmTrdTestBeamTools::GetChannelOnPadPlane(CbmSpadicRawMessage* raw){ /* * The Spadic channels have an indirection layer to the pad on the padplane. * This takes care of the mapping and returns the pad number. */ std::vectorMap=GetChannelMap(raw); Int_t chID=(GetSpadicID(raw)%2)*16+raw->GetChannelID(); return Map.at(chID); }; std::vector CbmTrdTestBeamTools::GetChannelMap(CbmSpadicRawMessage* raw){ /* * Get the channel mapping that is valid for the spadic where raw originated. */ std::vector map = {{31,15,30,14,29,13,28,12,27,11,26,10,25, 9,24, 8, 23, 7,22, 6,21, 5,20, 4,19, 3,18, 2,17, 1,16, 0}}; return map; }; Int_t CbmTrdTestBeamTools::GetBaseline(CbmSpadicRawMessage* raw) { /* * Estimate the signal baseline. Returns the lowest ADC value in the first two samples. */ Int_t Base =*std::min_element(raw->GetSamples(),raw->GetSamples()); //Int_t Basecand=*std::min_element(raw->GetSamples()+raw->GetNrSamples()-3,raw->GetSamples()+raw->GetNrSamples()); return Base;//(BaseGetNrSamples();i++){ if (raw->GetSamples()[i]>MaxADC) MaxADC=raw->GetSamples()[i]; } return MaxADC-Base; }; Float_t CbmTrdTestBeamTools::GetIntegratedCharge(CbmSpadicRawMessage* raw,Double_t Base) { /* * Get the integrated charge of raw, with Base subtracted. * Includes correction for unequal message lengths. */ Float_t* ProcessedSamples=new Float_t[32]; Int_t* Samples=raw->GetSamples(); Int_t NrSamples=raw->GetNrSamples(); Int_t Baseline=GetBaseline(raw); if(Base!=0.0) Baseline = Base; for (int i=0;i(Integral*1.5/(CorrectionFactor*1E3)); } Int_t CbmTrdTestBeamTools::GetModuleID (CbmTrdCluster* Clust) { //Returns ModuleID of the first Digi in the cluster. //This is identical to the ModuleID of the cluster. CbmTrdDigi*digi = static_cast (fDigis->At ( *Clust->GetDigis ().begin ())); return CbmTrdAddress::GetModuleId (digi->GetAddress ()); } // ---- ------------------------------------------------------- Int_t CbmTrdTestBeamTools::GetLayerID (CbmTrdCluster* Clust) { //Returns LayerID of the first Digi in the cluster. //This is identical to the LayerID of the cluster. CbmTrdDigi*digi = static_cast (fDigis->At ( *(Clust->GetDigis ().begin ()))); return CbmTrdAddress::GetLayerId (digi->GetAddress ()); } ; Int_t CbmTrdTestBeamTools::GetCentralRowID (CbmTrdCluster* Clust) { /*Get main row of the cluster. * Only defined for 1 Row Clusters at this time. * The Definition is identical to TestBeamTools::GetRowID. */ //TODO: Implement for 2D-Clusters. /*if (Clust->GetNRows () != 1) //TODO: Find self triggered Digi. return -1;*/ CbmTrdDigi*digi = static_cast (fDigis->At ( *(Clust->GetDigis ().begin ()))); return CbmTrdAddress::GetRowId (digi->GetAddress ()); } ; Int_t CbmTrdTestBeamTools::GetCentralColumnID (CbmTrdCluster* Clust) { /*Get the main column of the cluster. *For clusters of odd size, this is the central column. *For clusters of even size, this is the column to the left of the clusters center. */ std::vector Digis (Clust->GetDigis ()); std::vector columns; // std::vector selfTriggeredDigis; for (auto it = Digis.begin (); it != Digis.end (); it++) { CbmTrdDigi*digi = static_cast (fDigis->At (*it)); if (digi->GetTriggerType () == 1 || digi->GetTriggerType () == 3) columns.push_back (CbmTrdAddress::GetColumnId (digi->GetAddress ())); } if (!columns.size ()) for (auto it = Digis.begin (); it != Digis.end (); it++) { CbmTrdDigi*digi = static_cast (fDigis->At (*it)); columns.push_back (CbmTrdAddress::GetColumnId (digi->GetAddress ())); } Float_t col = 0; for (auto it = columns.begin (); it != columns.end (); it++) col += *it; if (columns.size ()) col /= columns.size (); return static_cast ((col)); } ; Int_t CbmTrdTestBeamTools::GetRowWidth (CbmTrdCluster* Clust) { /* * Return width of the Cluster in terms of rows. */ std::vector Rows, Digis = Clust->GetDigis (); for (auto it = Digis.begin (); it != Digis.end (); it++) { CbmTrdDigi*Digi = static_cast (fDigis->At (*it)); Int_t Row = CbmTrdAddress::GetColumnId (Digi->GetAddress ()); Rows.push_back (Row); } Int_t MinRow = *std::min_element (Rows.begin (), Rows.end ()); Int_t MaxRow = *std::max_element (Rows.begin (), Rows.end ()); return MaxRow - MinRow + 1; } ; Int_t CbmTrdTestBeamTools::GetColumnWidth (CbmTrdCluster* Clust) { /* * Return width of the Cluster in terms of Columns. */ //TODO: Implement this for 2D Clusters std::vector Columns; for (auto it = Clust->GetDigis ().begin (); it != Clust->GetDigis ().end (); it++) { CbmTrdDigi*Digi = static_cast (fDigis->At (*it)); Int_t Col = CbmTrdAddress::GetColumnId (Digi->GetAddress ()); Columns.push_back (Col); } Int_t MinCol = *std::min_element (Columns.begin (), Columns.end ()); Int_t MaxCol = *std::max_element (Columns.begin (), Columns.end ()); return MaxCol - MinCol + 1; } Float_t CbmTrdTestBeamTools::GetCharge (CbmTrdCluster* Clust) { const std::vector Digis = Clust->GetDigis (); Float_t Charge = 0.0; for (auto it = Digis.begin (); it != Digis.end (); it++) { CbmTrdDigi*digi = static_cast (fDigis->At (*it)); Charge += digi->GetCharge () + digi->GetChargeTR (); } return Charge; } ; Float_t CbmTrdTestBeamTools::GetRowDisplacement (CbmTrdCluster* Clust) { //TODO: To be implemented for 2 Row Clusters or Bucharest Data. return 0; } Float_t CbmTrdTestBeamTools::GetColumnDisplacement (CbmTrdCluster* Clust) { /**Calculate Displacement according to charge Distribution along main row. * Experimental:: Give more weight to the outer edges of the Clusters. */ std::vector Digis (Clust->GetDigis ()); // const std::vector Digis=Clust->GetDigis(); auto sortDigis = [&,this](Int_t a,Int_t b) { return static_cast((static_cast(this->fDigis->At(a))->Compare(this->fDigis->At(b)))+1); }; std::sort (Digis.begin (), Digis.end (), sortDigis); Int_t mainRow = GetCentralRowID (Clust); for (auto it = Digis.begin (); it != Digis.end ();) { CbmTrdDigi*digi = static_cast (fDigis->At (*it)); if (CbmTrdAddress::GetRowId (digi->GetAddress ()) != mainRow) { Digis.erase (it); it = Digis.begin (); } else { it++; } } Float_t WeightedColumns; Float_t TotalRowCharge = 0; std::vector Charges; Float_t Offset = GetCentralColumnID(Clust); Float_t Displacement; if (ClassifyCluster (Clust) != CbmTrdClusterClassification::kInvalidCharge) { for (UInt_t i = 0; i < Digis.size (); i++) { CbmTrdDigi*digi = static_cast (fDigis->At (Digis.at (i))); Float_t Charge (digi->GetCharge () + digi->GetChargeTR ()); TotalRowCharge += Charge; WeightedColumns += (Charge * CbmTrdAddress::GetColumnId (digi->GetAddress ())); } if (TotalRowCharge <= 0) TotalRowCharge = 1; Displacement = WeightedColumns / TotalRowCharge; Displacement -= Offset; } else { for (auto p : Digis) { CbmTrdDigi*digi = static_cast (fDigis->At (p)); if (digi==nullptr) continue; Charges.push_back (digi->GetCharge ()); } for (Int_t i = 0; i+2 < Charges.size (); i++) { Offset=i; //std::cout << i << " "<< i+1 << " "<< i+2 << " "< (b) / static_cast (a)) + sqrt ( static_cast (b) / static_cast (c)))); Double_t Offset = a3 / TMath::Pi () * TMath::ATanH ( (sqrt (static_cast (b) / static_cast (a)) - sqrt (static_cast (b) / static_cast (c))) / (2.0 * TMath::SinH (TMath::Pi () * PadWidth / a3))); return Offset; } CbmTrdTestBeamTools::CbmTrdClusterClassification CbmTrdTestBeamTools::ClassifyCluster (CbmTrdCluster*Clust) { std::vector Digis (Clust->GetDigis ()); if (Digis.size () == 0) return kEmpty; //TODO: Fragmentationtest //std::cout << "Cluster debug " <(-1==(static_cast(this->fDigis->At(a))->Compare(this->fDigis->At(b)))); }; std::sort (Digis.begin (), Digis.end (), sortDigis); //Check Triggerpatterns std::vector TriggerTypes, Columns; //Int_t MainRow = GetCentralRowID (Clust); for (auto it = Digis.begin (); it != Digis.end (); it++) { CbmTrdDigi*digi = static_cast (fDigis->At (*it)); /*if (CbmTrdAddress::GetRowId (digi->GetAddress ()) != MainRow) continue;*/ TriggerTypes.push_back (digi->GetTriggerType ()); //std::cout << digi->GetTriggerType()<< " "; Columns.push_back (CbmTrdAddress::GetColumnId (digi->GetAddress ())); } //std::cout << std::endl; //Check for expected Neighbour Trigger Pattern. //Only default FNR Pattern implemented if (std::find (TriggerTypes.begin (), TriggerTypes.end (), 2) != TriggerTypes.begin () || std::find (TriggerTypes.rbegin (), TriggerTypes.rend (), 2) != TriggerTypes.rbegin ()) return kMissingFNR; if (std::find (TriggerTypes.begin (), TriggerTypes.end (), 1) == TriggerTypes.end () && std::find (TriggerTypes.begin (), TriggerTypes.end (), 3) == TriggerTypes.end ()) return kMissingSTR; //Check for Gaps /* Int_t CurrentCol = Columns.at (0); for (Int_t i = 1; i < Columns.size (); i++) { if (++CurrentCol < Columns.at (i)) return kMissingSTR; } */ return kNormal; }