+
+ return pads.GetEntries();
+}
+
+
+//_____________________________________________________________________________
+Bool_t AliMUONTrackHitPattern::IsCloseToAccEdge(TObjArray& pads, Int_t detElemId, Float_t coor[2]) const
+{
+ AliMpArea* deArea = fkTransformer.GetDEArea(detElemId);
+ Float_t dpx = ((AliMpPad*)pads.At(1))->GetDimensionX();
+ Float_t dpy = ((AliMpPad*)pads.At(0))->GetDimensionY();
+ Float_t resolution[2] = { 0.75*dpx, 0.75*dpy };
+ Float_t sign[3] = {0., 1., -1.};
+ for ( Int_t ineighx=0; ineighx<3; ineighx++ ) {
+ for ( Int_t ineighy=0; ineighy<3; ineighy++ ) {
+ AliMpArea pointArea(coor[0]+sign[ineighx]*resolution[0],
+ coor[1]+sign[ineighy]*resolution[1],
+ 2.*AliMpConstants::LengthTolerance(),
+ 2.*AliMpConstants::LengthTolerance());
+ if ( ! deArea->Contains(pointArea) ) return kTRUE;
+ } // loop on y neighbours
+ } // loop on x neighbours
+ return kFALSE;
+}
+
+
+//_____________________________________________________________________________
+Bool_t AliMUONTrackHitPattern::IsMasked(const AliMpPad& pad, Int_t detElemId, Int_t cathode, const TVector3& vec11, const TVector3& vec21) const
+{
+ //
+ /// Check if pad or its neighbours are masked
+ //
+
+ Int_t nMasked = 0;
+
+ if ( fkTriggerUtilities->IsMasked(pad, detElemId, cathode) ) ++nMasked;
+
+ // Check closest neighbour
+
+ TVector3 localCoor;
+ PosInDetElemIdLocal(localCoor, vec11, vec21, detElemId);
+
+ Float_t padPos[2] = { pad.GetPositionX(), pad.GetPositionY()};
+ Float_t padDim[2] = { pad.GetDimensionX(), pad.GetDimensionY()};
+ Float_t inpactPos[2] = { localCoor.X(), localCoor.Y()};
+ Float_t sign[2] = {-1., 1.};
+ Int_t icoor = 1-cathode;
+ Int_t addSlatSign[3] = {0,1,-1};
+ Int_t inputCh = AliMpDEManager::GetChamberId(detElemId)+1;
+ Int_t inputSlat = detElemId%100;
+
+ Float_t newPos[2];
+ for ( Int_t ineigh=0; ineigh<2; ineigh++ ) {
+ newPos[1-icoor] = inpactPos[1-icoor];
+ newPos[icoor] = inpactPos[icoor] + 1.05 * sign[ineigh] * padDim[icoor];
+ if ( TMath::Abs(newPos[icoor] - padPos[icoor]) < padDim[icoor] ) continue;
+ const AliMpVSegmentation* seg =
+ AliMpSegmentation::Instance()->GetMpSegmentation(detElemId,AliMp::GetCathodType(cathode));
+ AliMpPad neighPad = seg->PadByPosition(newPos[0],newPos[1],kFALSE);
+ if ( neighPad.IsValid() ) {
+ if ( fkTriggerUtilities->IsMasked(neighPad, detElemId, cathode) ) ++nMasked;
+ }
+ else {
+ TVector3 deltaVec(newPos[0]-inpactPos[0],newPos[1]-inpactPos[1],0.);
+ TVector3 transVec11 = vec11+deltaVec;
+ TVector3 transVec21 = vec21+deltaVec;
+ TObjArray padsFromPos;
+ padsFromPos.SetOwner();
+ for ( Int_t iAddSlat=0; iAddSlat<2; iAddSlat++ ) {
+ Int_t currSlat = (inputSlat + addSlatSign[iAddSlat])%18;
+ Int_t currDetElemId = 100 * inputCh + currSlat;
+ PadsFromPos(transVec11,transVec21,currDetElemId,padsFromPos);
+ AliMpPad* currPad = (AliMpPad*)padsFromPos.UncheckedAt(cathode);
+ Bool_t isMasked = ( currPad ) ? fkTriggerUtilities->IsMasked(*currPad, currDetElemId, cathode) : kFALSE;
+ padsFromPos.Delete();
+ if ( isMasked ) ++nMasked;
+ }
+ } // loop on slats
+ } // loop on neigbours
+
+ Double_t maskedProb = ((Double_t)nMasked)/3.;
+ if ( gRandom->Rndm() < maskedProb ) return kTRUE;
+
+ return kFALSE;
+}
+
+
+//_____________________________________________________________________________
+Bool_t AliMUONTrackHitPattern::PerformTrigTrackMatch(UInt_t &pattern,
+ const AliMUONTriggerTrack* matchedTrigTrack) const
+{
+ //
+ /// It searches for matching digits around the trigger track.
+ //
+
+ AliCodeTimerAuto("",0);
+
+ enum {kBending, kNonBending};
+
+ TArrayF zMeanChamber(AliMUONConstants::NTriggerCh());
+ zMeanChamber[0] = matchedTrigTrack->GetZ11();
+ zMeanChamber[1] = matchedTrigTrack->GetZ11() + AliMUONConstants::DefaultChamberZ(11) - AliMUONConstants::DefaultChamberZ(10);
+ zMeanChamber[2] = matchedTrigTrack->GetZ21();
+ zMeanChamber[3] = matchedTrigTrack->GetZ21() + AliMUONConstants::DefaultChamberZ(13) - AliMUONConstants::DefaultChamberZ(12);
+
+ TArrayI digitPerTrack(2);
+ digitPerTrack.Reset();
+
+ Float_t trackIntersectCh[2];
+
+ Float_t slopeX = matchedTrigTrack->GetSlopeX();
+ Float_t slopeY = matchedTrigTrack->GetSlopeY();
+
+ Float_t z11 = matchedTrigTrack->GetZ11();
+ Float_t x11 = slopeX * z11;
+ Float_t y11 = matchedTrigTrack->GetY11();
+ Float_t z21 = matchedTrigTrack->GetZ21();
+ Float_t x21 = slopeX * z21;
+ Float_t y21 = y11 + slopeY * (z21-z11);
+ TVector3 vec11(x11, y11, z11), vec21(x21, y21, z21);
+
+ Int_t firstSlat = -1, firstBoard = -1;
+ AliESDMuonTrack::EAliTriggerChPatternFlag goodForEff = AliESDMuonTrack::kBoardEff;
+ TObjArray matchedPads(2), padsFromPos(2), validPads(2);
+ matchedPads.SetOwner(); padsFromPos.SetOwner();
+ Int_t matchedDetElemId[2], detElemIdFromTrack[2];
+
+ for(Int_t ich=0; ich<AliMUONConstants::NTriggerCh(); ich++) { // chamber loop
+
+ // searching track intersection with chambers (first approximation)
+ Float_t deltaZ = zMeanChamber[ich] - zMeanChamber[0];
+ trackIntersectCh[0] = zMeanChamber[ich] * slopeX;
+ trackIntersectCh[1] = y11 + deltaZ * slopeY;
+ Int_t nFound = DetElemIdFromPos(trackIntersectCh[0], trackIntersectCh[1], 11+ich, detElemIdFromTrack);
+ if ( nFound == 0 ) {
+ // track is rejected since the extrapolated track
+ // does not match a slat (border effects)
+ AliESDMuonTrack::AddEffInfo(pattern, AliESDMuonTrack::kTrackOutsideGeometry);
+ goodForEff = AliESDMuonTrack::kNoEff;
+ AliDebug(10, "Warning: trigger track outside trigger chamber\n");
+ continue;
+ }
+
+ matchedDetElemId[0] = matchedDetElemId[1] = detElemIdFromTrack[0];
+
+ if ( ! FindPadMatchingTrig(vec11, vec21, matchedDetElemId, matchedPads) ) {
+ // if ! FindPadMatchingTrig => too many digits matching pad =>
+ // => Event not clear => Do not use for efficiency calculation
+ AliESDMuonTrack::AddEffInfo(pattern, AliESDMuonTrack::kTrackMatchesManyPads);
+ goodForEff = AliESDMuonTrack::kNoEff;
+ AliDebug(10, Form("Warning: track = %p (%i) matches many pads. Rejected!\n",(void *)matchedTrigTrack, matchedDetElemId[0]));
+ }
+
+ Int_t nMatched = 0;
+
+ Int_t mostProbDEmatched = detElemIdFromTrack[0];
+ for ( Int_t icath=0; icath<2; icath++ ) {
+ if ( matchedPads.UncheckedAt(icath) ) {
+ nMatched++;
+ // Fill pattern anyway
+ AliESDMuonTrack::SetFiredChamber(pattern, icath, ich);
+ digitPerTrack[icath]++;
+ mostProbDEmatched = matchedDetElemId[icath];
+ }
+ }
+ Int_t mostProbDEfromTrack = detElemIdFromTrack[0];
+ for ( Int_t ifound=0; ifound<nFound; ifound++ ) {
+ if ( detElemIdFromTrack[ifound] == mostProbDEmatched ) {
+ mostProbDEfromTrack = mostProbDEmatched;
+ break;
+ }
+ }
+
+ if ( goodForEff == AliESDMuonTrack::kNoEff ) continue;
+
+ if ( nMatched < 2 ) PadsFromPos(vec11, vec21, mostProbDEfromTrack, padsFromPos);
+
+ for ( Int_t cath=0; cath<2; cath++ ) {
+ if ( matchedPads.UncheckedAt(cath) ) validPads.AddAt(matchedPads.UncheckedAt(cath),cath);
+ else if ( padsFromPos.UncheckedAt(cath) ) {
+ AliMpPad* currPad = (AliMpPad*)padsFromPos.UncheckedAt(cath);
+ validPads.AddAt(currPad,cath);
+ if ( IsMasked(*currPad, mostProbDEfromTrack, cath, vec11, vec21) ) {
+ // Check if strip was masked (if inefficient strip is found)
+ AliESDMuonTrack::AddEffInfo(pattern,AliESDMuonTrack::kTrackMatchesMasks); // pad is masked
+ AliDebug(10,Form("DetElemId %i cath %i board %i strip %i is masked: effFlag 0", mostProbDEfromTrack, cath, currPad->GetLocalBoardId(0), currPad->GetLocalBoardChannel(0)));
+ goodForEff = AliESDMuonTrack::kNoEff;
+ }
+ }
+ else goodForEff = AliESDMuonTrack::kNoEff;
+ } // loop on cathodes
+
+ if ( goodForEff != AliESDMuonTrack::kNoEff ) {
+
+ if ( nMatched == 0 && IsCloseToAccEdge(padsFromPos, mostProbDEfromTrack, trackIntersectCh) ) {
+ // Non of cathodes is fired.
+ // If we are close to the edge of the RPC
+ // it could be a problem of acceptance
+ AliESDMuonTrack::AddEffInfo(pattern, AliESDMuonTrack::kTrackOutsideGeometry);
+ goodForEff = AliESDMuonTrack::kNoEff;
+ AliDebug(10, "Warning: trigger track at the edge of the chamber\n");
+ }
+
+ Int_t currSlat = mostProbDEmatched%100;
+ if ( firstSlat < 0 ) firstSlat = currSlat;
+ else if ( currSlat != firstSlat ) {
+ goodForEff = AliESDMuonTrack::kChEff;
+ firstSlat = AliESDMuonTrack::kCrossDifferentSlats;
+ }
+
+ if ( firstBoard < 0 ) firstBoard = ((AliMpPad*)validPads[kBending])->GetLocalBoardId(0);
+
+ for ( Int_t cath=0; cath<2; cath++ ){
+
+ if ( goodForEff == AliESDMuonTrack::kBoardEff) {
+ Bool_t atLeastOneLoc = kFALSE;
+ AliMpPad* currPad = (AliMpPad*)validPads.UncheckedAt(cath);
+ for ( Int_t iloc=0; iloc<currPad->GetNofLocations(); iloc++) {
+ if ( currPad->GetLocalBoardId(iloc) == firstBoard ) {
+ atLeastOneLoc = kTRUE;
+ break;
+ }
+ } // loop on locations
+ if ( ! atLeastOneLoc ) goodForEff = AliESDMuonTrack::kSlatEff;
+ }
+ } // loop on cathodes
+ } // if track good for efficiency
+ matchedPads.Delete();
+ padsFromPos.Delete();
+ } // end chamber loop
+
+ if ( goodForEff == AliESDMuonTrack::kNoEff ) return kFALSE;
+
+ for(Int_t cath=0; cath<2; cath++){
+ if(digitPerTrack[cath]<3) {
+ // track is rejected since the number of associated
+ // digits found is less than 3.
+ AliESDMuonTrack::AddEffInfo(pattern, AliESDMuonTrack::kTrackMatchesFewPads);
+ goodForEff = AliESDMuonTrack::kNoEff;
+ AliDebug(10, Form("Warning: found %i digits for trigger track cathode %i.\nRejecting event\n", digitPerTrack[cath],cath));
+ }
+ } // loop on cathodes
+
+ if ( goodForEff == AliESDMuonTrack::kNoEff ) return kFALSE;
+
+ AliESDMuonTrack::AddEffInfo(pattern, firstSlat, firstBoard, goodForEff);