text: // $Id$
  //**************************************************************************
  //* This file is property of and copyright by the ALICE HLT Project        *
  //* ALICE Experiment at CERN, All rights reserved.                         *
  //*                                                                        *
  //* Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
  //*                  Jochen Thaeder <jochen@thaeder.de>                    *
  //*                  for The ALICE HLT Project.                            *
  //*                                                                        *
  //* Permission to use, copy, modify and distribute this software and its   *
  //* documentation strictly for non-commercial purposes is hereby granted   *
  //* without fee, provided that the above copyright notice appears in all   *
  //* copies and that both the copyright notice and this permission notice   *
  //* appear in the supporting documentation. The authors make no claims     *
  //* about the suitability of this software for any purpose. It is          *
  //* provided "as is" without express or implied warranty.                  *
  //**************************************************************************
  
  /// @file   AliHLTTRDTriggerComponent.cxx
  /// @author Felix Rettig, Stefan Kirsch
  /// @date   2012-08-16
  /// @brief
  
  #include <cstdlib>
  #include "TSystem.h"
  #include "TObjArray.h"
  #include "TObjString.h"
  #include "TFile.h"
  #include "TH1I.h"
  #include "TH2I.h"
  #include "AliESDtrack.h"
  #include "AliESDEvent.h"
  #include "AliHLTTRDDefinitions.h"
  #include "AliHLTTriggerDecision.h"
  #include "AliHLTDomainEntry.h"
  #include "AliHLTLogging.h"
  #include "AliHLTErrorGuard.h"
  #include "AliHLTGlobalBarrelTrack.h"
  #include "AliESDtrackCuts.h"
  //#include "AliHLTESDTrackCuts.h"
  #include "AliGeomManager.h"
  #include "AliHLTComponentBenchmark.h"
  #include "AliHLTTRDTriggerComponent.h"
  #include "AliTRDonlineTrackingDataContainer.h"
  #include "AliTRDpadPlane.h"
  
  ClassImp(AliHLTTRDTriggerComponent)
  
  #define LogError( ... ) { HLTError(__VA_ARGS__); if (fDebugLevel >= 1) { DbgLog("ERROR", __VA_ARGS__); } }
  #define LogInfo( ... ) { HLTInfo(__VA_ARGS__); if (fDebugLevel >= 1) { DbgLog("INFO", __VA_ARGS__); } }
  #define LogInspect( ... ) { HLTDebug(__VA_ARGS__); if (fDebugLevel >= 1) { DbgLog("INSPECT", __VA_ARGS__); } }
  #define LogDebug( ... ) { if (fDebugLevel >= 1) { HLTInfo(__VA_ARGS__); DbgLog("DEBUG", __VA_ARGS__); } }
  
  AliHLTTRDTriggerComponent::AliHLTTRDTriggerComponent() :
    AliHLTTrigger(),
    fName(),
    fRefTrackSelectionEtaLimit(0.9),
    fRefTrackSelectionVertexXYLimit(20.),
    fRefTrackSelectionVertexZLimit(30.),
    fRefTrackSelectionPtThreshold(0.7),
    fMatchRatingThreshold(0.25),
    fElectronTriggerPtThresholdHSE(3.),
    fElectronTriggerPIDThresholdHSE(144),
    fElectronTriggerPtThresholdHQU(2.),
    fElectronTriggerPIDThresholdHQU(164),
    fApplyRefTrackCuts(kFALSE),
    fElectronTriggerOnL1TrgOnly(kFALSE),
    fHistoMode(1),
    fDebugLevel(0),
    fExtendedHistos(kFALSE),
    fEventRendering(kFALSE),
    fPushHistos(kFALSE),
    fWriteHistos(kFALSE),
    fEventId(fgkInvalidEventId),
    fRunNumber(-1),
    fChunkId(NULL),
    fSectorsWithData(0),
    fIsMinBiasEvent(kFALSE),
    fIsTRDElectronEvent(kFALSE),
    fESDtracksPresent(kFALSE),
    fHLTtracksPresent(kFALSE),
    fTRDGeometry(NULL),
    fEsdEvent(NULL),
    fTrackingData(NULL),
    fHLTTracks(NULL),
    fRefTrackCuts(NULL),
  #ifdef __TRDHLTDEBUG
    fEventDisplay(NULL),
    fBenchmark(NULL),
  #endif
    fHistArray(NULL),
    fHistMatchRating(NULL),
    fHistMatchRatingByPt(NULL),
    fHistMatchRatingByPid(NULL),
    fHistTrackPt(NULL),
    fHistTrackPtMatched(NULL),
    fHistTrackPtCorr(NULL),
    fHistTrackPid(NULL),
    fHistTrackPidMatched(NULL),
    fHistElectronCandidatePt(NULL),
    fHistElectronCandidateMatchedPt(NULL),
    fHistElectronCandidatePid(NULL),
    fHistElectronCandidateMatchedPid(NULL),
    fHistRefTrackPid(NULL),
    fHistMatchedRefTrackPid(NULL),
    fHistPIDvsTruncPID(NULL),
    fHistElectronFalsePIDvsTruncPID(NULL),
    fHistElectronConfirmedPIDvsTruncPID(NULL),
    fHistTrackMatchingCombinations(NULL),
    fHistElectronTriggerBaseMinBias(NULL),
    fHistElectronTriggerBaseTrdL1(NULL)
  {
  }
  
  const char* AliHLTTRDTriggerComponent::fgkDefaultOCDBEntry = "HLT/ConfigHLT/TRDTrigger";
  const char* AliHLTTRDTriggerComponent::fgkTriggerDecisionElectronHSE = "TRD-ELECTRON-HSE";
  const char* AliHLTTRDTriggerComponent::fgkTriggerDecisionElectronHQU = "TRD-ELECTRON-HQU";
  
  AliHLTTRDTriggerComponent::~AliHLTTRDTriggerComponent()
  {
  }
  
  const char* AliHLTTRDTriggerComponent::GetTriggerName() const
  {
    if (!fName.IsNull())
      return fName.Data();
    else
      return "TRDTriggerComponent";
  }
  
  AliHLTComponent* AliHLTTRDTriggerComponent::Spawn()
  {
    return new AliHLTTRDTriggerComponent;
  }
  
  int AliHLTTRDTriggerComponent::DoInit(int argc, const char** argv)
  {
    int iResult = 0;
  
    do {
  
      fChunkId = new TString("XXXXX");
  #ifdef __TRDHLTDEBUG
      if (fChunkId){
        // chunk identification for debug output
        *fChunkId = gSystem->WorkingDirectory();
        fChunkId->Remove(0, fChunkId->Last('/') + 1);
        if (fChunkId->Contains("hlt_trd_comp"))
  	*fChunkId = "L";
      } else {
        iResult = -ENOMEM;
        break;
      }
  #endif
  
      AliGeomManager::LoadGeometry();
  
      fTRDGeometry = new AliTRDgeometry();
      if (!fTRDGeometry) {
        iResult = -ENOMEM;
        break;
      }
  
      fTrackingData = new AliTRDonlineTrackingDataContainer();
      if (!fTrackingData) {
        iResult = -ENOMEM;
        break;
      }
  
      fHLTTracks = new vector<AliHLTGlobalBarrelTrack>;
      if (!fHLTTracks) {
        iResult = -ENOMEM;
        break;
      }
  
      fRefTrackCuts = new AliESDtrackCuts("AliESDtrackCuts", "No track cuts");
      if (fRefTrackCuts){
        // fRefTrackCuts = AliESDtrackCuts::GetStandardITSTPCTrackCuts2011(kTRUE, 0);
        fRefTrackCuts = AliESDtrackCuts::GetStandardTPCOnlyTrackCuts();
        fRefTrackCuts->SetEtaRange(-0.8, 0.8);
      } else {
        iResult = -ENOMEM;
        break;
      }
  
      fHistArray = new TObjArray(25);
      if(!fHistArray)
        return -ENOMEM;
      fHistArray->SetOwner(kTRUE);
  
      fHistMatchRating = new TH1I("trdtrg_match_rating", "Match rating distribution HLT tracks vs. GTU track;match rating;abundance;",
  				1./0.02, 0., 1.);
      fHistArray->AddLast(fHistMatchRating);
  
      fHistMatchRatingByPt = new TH2I("trdtrg_match_rating_pt", "Match rating distribution HLT tracks vs. GTU track by p_{T};match rating m;p_{T}^{TRD,online} (GeV/c)",
  				    1./0.02, 0., 1., 20./0.02, 0., 20.);
      fHistArray->AddLast(fHistMatchRatingByPt);
  
      fHistMatchRatingByPid = new TH2I("trdtrg_match_rating_pid", "Match rating distribution HLT tracks vs. GTU track by PID;match rating m;PID (a.u.)",
  				     1./0.02, 0., 1., 256, 0, 256);
      fHistArray->AddLast(fHistMatchRatingByPid);
  
      fHistTrackPt = new TH1I("trdtrg_track_pt", "GTU track p_{T};GTU track p_{T} (GeV/c);abundance", 200, -20, 20.);
      fHistArray->AddLast(fHistTrackPt);
  
      fHistTrackPtMatched = new TH1I("trdtrg_matched_track_pt", "matched GTU track p_{T};GTU track p_{T} (GeV/c);abundance", 200, -20, 20.);
      fHistArray->AddLast(fHistTrackPtMatched);
  
      fHistTrackPtCorr = new TH2I("trdtrg_track_pt_corr", "HLT vs. GTU track p_{T};p_{T}^{HLT} (GeV/c);p_{T}^{GTU} (GeV/c)",
  	       400, -40., 40., 400, -40., 40.);
      fHistArray->AddLast(fHistTrackPtCorr);
  
      fHistTrackPid = new TH1I("trdtrg_track_pid", "GTU track PID;GTU track PID (a.u.);abundance", 256, 0, 256);
      fHistArray->AddLast(fHistTrackPid);
  
      fHistTrackPidMatched = new TH1I("trdtrg_matched_track_pid", "matched GTU track PID;GTU track PID (a.u.);abundance", 256, 0, 256);
      fHistArray->AddLast(fHistTrackPidMatched);
  
      fHistTrackMatchingCombinations = new TH2I("trdtrg_matching_combinations", "HLT-GTU track matching combinations;set;combinations to check;",
  					      10, 0, 10, 2000, 0, 10000);
      fHistArray->AddLast(fHistTrackMatchingCombinations);
  
      fHistElectronTriggerBaseMinBias = new TH1I("trdtrg_electron_trigger_base_mb", "min. bias base numbers for electron trigger analysis;set;abundance;",
  					      10, 0, 10);
      fHistElectronTriggerBaseMinBias->GetXaxis()->SetBinLabel(1, "min. bias events");
      fHistElectronTriggerBaseMinBias->GetXaxis()->SetBinLabel(2, "TRD L1 electron triggered");
      fHistElectronTriggerBaseMinBias->GetXaxis()->SetBinLabel(3, "TRD HLT electron triggered");
      fHistArray->AddLast(fHistElectronTriggerBaseMinBias);
  
      fHistElectronTriggerBaseTrdL1 = new TH1I("trdtrg_electron_trigger_base_l1", "TRD L1 base numbers for electron trigger analysis;set;abundance;",
  					      10, 0, 10);
      fHistElectronTriggerBaseTrdL1->GetXaxis()->SetBinLabel(1, "TRD L1 electron triggered");
      fHistElectronTriggerBaseTrdL1->GetXaxis()->SetBinLabel(2, "TRD HLT electron triggered");
      fHistArray->AddLast(fHistElectronTriggerBaseTrdL1);
  
      fHistElectronCandidatePt = new TH1I("trdtrg_electron_candidate_pt", "GTU electron candidate p_{T};GTU track p_{T} (GeV/c);abundance", 200, -20, 20.);
      fHistArray->AddLast(fHistElectronCandidatePt);
  
      fHistElectronCandidateMatchedPt = new TH1I("trdtrg_electron_candidate_matched_pt", "matching GTU electron candidate p_{T};GTU track p_{T} (GeV/c);abundance", 200, -20, 20.);
      fHistArray->AddLast(fHistElectronCandidateMatchedPt);
  
      fHistElectronCandidatePid = new TH1I("trdtrg_electron_candidate_pid", "GTU electron candidate PID;GTU track PID (a.u.);abundance", 256, 0, 256);
      fHistArray->AddLast(fHistElectronCandidatePid);
  
      fHistElectronCandidateMatchedPid = new TH1I("trdtrg_electron_candidate_matched_pid", "matching GTU electron candidate PID;GTU track PID (a.u.);abundance", 256, 0, 256);
      fHistArray->AddLast(fHistElectronCandidateMatchedPid);
  
    } while (0);
  
    if (iResult < 0){
  
      if (fHistArray) delete fHistArray;
      fHistArray = NULL;
  
      if (fTRDGeometry) delete fTRDGeometry;
      fTRDGeometry = NULL;
  
      if (fRefTrackCuts) delete fRefTrackCuts;
      fRefTrackCuts = NULL;
  
      if (fHLTTracks) delete fHLTTracks;
      fHLTTracks = NULL;
  
      if (fTrackingData) delete fTrackingData;
      fTrackingData = NULL;
  
      if (fChunkId) delete fChunkId;
      fChunkId = NULL;
  
    }
  
    // check if the -triggername argument is used, the trigger name determines the following initialization
    vector<const char*> remainingArgs;
    for (int i = 0; i < argc; ++i) {
      if (strcmp(argv[i], "-triggername") == 0) {
        if (++i < argc){
  	fName = argv[i];
        } else {
  	LogError("invalid parameter for argument '-triggername', string expected");
  	return -EINVAL;
        }
        continue;
      }
      remainingArgs.push_back(argv[i]);
    }
  
    TString cdbPath;
    if (!fName.IsNull()) {
      cdbPath = "HLT/ConfigHLT/";
      cdbPath += fName;
    } else {
      cdbPath = fgkDefaultOCDBEntry;
    }
  
    LogInfo("cdbPath = <%s>", cdbPath.Data());
    iResult = ConfigureFromCDBObject(cdbPath);
  
    if (iResult >= 0 && argc > 0)
      iResult = ConfigureFromArgumentString(remainingArgs.size(), &(remainingArgs[0]));
  
    return iResult;
  }
  
  int AliHLTTRDTriggerComponent::DoDeinit()
  {
  
  #ifdef __TRDHLTDEBUG
    if (fEventDisplay) delete fEventDisplay;
    fEventDisplay = NULL;
  #endif
  
    if ((fHistoMode == 1) && (fWriteHistos)){
      TFile out("trg_out/trg_hists.root", "RECREATE");
      if (!out.IsZombie()) {
        out.cd();
        UInt_t numHists = fHistArray->GetEntries();
        for (UInt_t iHist = 0; iHist < numHists; ++iHist)
  	if (fHistArray->At(iHist))
  	  fHistArray->At(iHist)->Write();
        out.Close();
      }
    }
  
    if (fHistArray) delete fHistArray;
    fHistArray = NULL;
  
    if (fRefTrackCuts) delete fRefTrackCuts;
    fRefTrackCuts = NULL;
  
    if (!fHLTTracks) delete fHLTTracks;
    fHLTTracks = NULL;
  
    if (fTrackingData) delete fTrackingData;
    fTrackingData = NULL;
  
    if (fTRDGeometry) delete fTRDGeometry;
    fTRDGeometry = NULL;
  
    if (fChunkId) delete fChunkId;
    fChunkId = NULL;
  
    return 0;
  }
  
  int AliHLTTRDTriggerComponent::Reconfigure(const char* cdbEntry, const char* /*chainId*/)
  {
    TString cdbPath;
    if (!cdbEntry || cdbEntry[0] == 0) {
      if (!fName.IsNull()) {
        cdbPath = "HLT/ConfigHLT/";
        cdbPath += fName;
      } else {
        cdbPath = fgkDefaultOCDBEntry;
      }
    } else
      cdbPath = cdbEntry;
  
    return ConfigureFromCDBObject(cdbPath);
  }
  
  int AliHLTTRDTriggerComponent::ReadPreprocessorValues(const char* /*modules*/)
  {
    return 0;
  }
  
  Int_t AliHLTTRDTriggerComponent::ConfigureFromCDBObject(TString /*cdbPath*/)
  {
    return 0;
  }
  
  int AliHLTTRDTriggerComponent::ScanConfigurationArgument(int argc, const char** argv)
  {
  
    if (argc <= 0)
      return 0;
  
    UShort_t iArg = 0;
    TString argument(argv[iArg]);
  
    if (!argument.CompareTo("-match-sel-eta")){
      if (++iArg >= argc) return -EPROTO;
      argument = argv[iArg];
      fRefTrackSelectionEtaLimit = argument.Atof();
      LogInfo("ref track selection eta limit set to %.1f.", fRefTrackSelectionEtaLimit);
      return 2;
    }
  
    if (!argument.CompareTo("-match-sel-vxy")){
      if (++iArg >= argc) return -EPROTO;
      argument = argv[iArg];
      fRefTrackSelectionVertexXYLimit = argument.Atof();
      LogInfo("ref track selection vertex xy limit set to %.1f.", fRefTrackSelectionVertexXYLimit);
      return 2;
    }
  
    if (!argument.CompareTo("-match-sel-vz")){
      if (++iArg >= argc) return -EPROTO;
      argument = argv[iArg];
      fRefTrackSelectionVertexZLimit = argument.Atof();
      LogInfo("ref track selection vertex z limit set to %.1f.", fRefTrackSelectionVertexZLimit);
      return 2;
    }
  
    if (!argument.CompareTo("-match-sel-pt")){
      if (++iArg >= argc) return -EPROTO;
      argument = argv[iArg];
      fRefTrackSelectionPtThreshold = argument.Atof();
      LogInfo("ref track selection pt threshold set to %.1f GeV/c.", fRefTrackSelectionPtThreshold);
      return 2;
    }
  
    if (!argument.CompareTo("-match-rating")){
      if (++iArg >= argc) return -EPROTO;
      argument = argv[iArg];
      fMatchRatingThreshold = argument.Atof();
      LogInfo("match rating threshold set to %.2f GeV/c.", fMatchRatingThreshold);
      return 2;
    }
  
    if (!argument.CompareTo("-histo-mode")){
      if (++iArg >= argc) return -EPROTO;
      argument = argv[iArg];
      fHistoMode = argument.Atoi();
      LogInfo("histo mode set to %d", fHistoMode);
      return 2;
    }
  
    if (!argument.CompareTo("-trghse")){
      LogInfo("TRD HLT electron trigger HSE enabled.");
      return 1;
    }
  
    if (!argument.CompareTo("-hse-pt")){
      if (++iArg >= argc) return -EPROTO;
      argument = argv[iArg];
      fElectronTriggerPtThresholdHSE = argument.Atof();
      LogInfo("pt threshold for HSE trigger set to %.1f GeV/c.", fElectronTriggerPtThresholdHSE);
      return 2;
    }
  
    if (!argument.CompareTo("-hse-pid")){
      if (++iArg >= argc) return -EPROTO;
      argument = argv[iArg];
      fElectronTriggerPIDThresholdHSE = argument.Atof();
      LogInfo("PID threshold for HSE trigger set to %d.", fElectronTriggerPIDThresholdHSE);
      return 2;
    }
  
    if (!argument.CompareTo("-trghqu")){
      LogInfo("TRD HLT electron trigger HQU enabled.");
      return 1;
    }
  
    if (!argument.CompareTo("-hqu-pt")){
      if (++iArg >= argc) return -EPROTO;
      argument = argv[iArg];
      fElectronTriggerPtThresholdHQU = argument.Atof();
      LogInfo("pt threshold for HQU trigger set to %.1f GeV/c.", fElectronTriggerPtThresholdHQU);
      return 2;
    }
  
    if (!argument.CompareTo("-hqu-pid")){
      if (++iArg >= argc) return -EPROTO;
      argument = argv[iArg];
      fElectronTriggerPIDThresholdHQU = argument.Atof();
      LogInfo("PID threshold for HQU trigger set to %.1f GeV/c.", fElectronTriggerPIDThresholdHQU);
      return 2;
    }
  
    if (!argument.CompareTo("-l1-only")){
      LogInfo("evaluation of electron trigger only for events with TRD L1 electron trigger enabled.");
      fElectronTriggerOnL1TrgOnly = kTRUE;
      return 1;
    }
  
    if (!argument.CompareTo("-histo-ext")){
      LogInfo("extended histogramming enabled.");
      fExtendedHistos = kTRUE; // enable extended histogramming, for debugging/tuning only!
  
      if (!fHistRefTrackPid){
        fHistRefTrackPid = new TH2I("trdtrg_reftrack_pid", "TPC dE/dx by p_{T} for matching GTU tracks;p_{T} (GeV/c);dE/dx (a. u.)",
  				  500, 0., 10., 500, 0., 500);
        fHistArray->AddLast(fHistRefTrackPid);
      }
  
      if (!fHistMatchedRefTrackPid){
        fHistMatchedRefTrackPid = new TH2I("trdtrg_matched_reftrack_pid", "TPC dE/dx by p_{T} for matching GTU tracks;p_{T} (GeV/c);dE/dx (a. u.)",
  					 500, 0., 10., 500, 0., 500);
        fHistArray->AddLast(fHistMatchedRefTrackPid);
      }
  
      if (!fHistPIDvsTruncPID){
        fHistPIDvsTruncPID = new TH2I("trdtrg_pid_trunc_pid", "GTU track PID vs. truncated PID;PID (a.u.);truncated PID (a. u.)",
  				    256, 0., 256., 256, 0., 256.);
        fHistArray->AddLast(fHistPIDvsTruncPID);
      }
  
      if (!fHistElectronFalsePIDvsTruncPID){
        fHistElectronFalsePIDvsTruncPID = new TH2I("trdtrg_electron_false_pid_trunc_pid", "false electron PID vs. truncated PID;PID (a.u.);truncated PID (a. u.)",
  						 256, 0., 256., 256, 0., 256.);
        fHistArray->AddLast(fHistElectronFalsePIDvsTruncPID);
      }
  
      if (!fHistElectronConfirmedPIDvsTruncPID){
        fHistElectronConfirmedPIDvsTruncPID = new TH2I("trdtrg_electron_confirmed_pid_trunc_pid", "confirmed electron PID vs. truncated PID;PID (a.u.);truncated PID (a. u.)",
  						     256, 0., 256., 256, 0., 256.);
        fHistArray->AddLast(fHistElectronConfirmedPIDvsTruncPID);
      }
  
      return 1;
    }
  
    if (!argument.CompareTo("-ref-cuts")){
      LogInfo("ref track cuts for matching enabled.");
      fApplyRefTrackCuts = kTRUE;
      return 1;
    }
  
    if (!argument.CompareTo("-push-histograms")){
      LogInfo("pushing of histograms enabled.");
      fPushHistos = kTRUE; // enable histogram pushing, for debugging/tuning only!
      return 1;
    }
  
    if (!argument.CompareTo("-write-histograms")){
      LogInfo("writing of histograms enabled.");
      fWriteHistos = kTRUE; // enable histogram writing, for debugging/tuning only!
      return 1;
    }
  
    if (!argument.CompareTo("-render")){
  #ifdef __TRDHLTDEBUG
      LogInfo("rendering of interesting events enabled.");
      if (!fEventDisplay)
        fEventDisplay = new AliTRDtrackingEventDisplay();
        LogInfo("event rendering activated. this is for debugging only!");
      fEventRendering = kTRUE; // enable event rendering, for debugging/tuning only!
  #endif
      return 1;
    }
  
    if (!argument.CompareTo("-debug")){
      if (++iArg >= argc) return -EPROTO;
      argument = argv[iArg];
      fDebugLevel = argument.Atoi();
      LogInfo("debug level set to %d.", fDebugLevel);
      return 2;
    }
  
    if (!argument.CompareTo("-ref-pt")){
      if (++iArg >= argc) return -EPROTO;
      argument = argv[iArg];
      Float_t minPt, maxPt;
      fRefTrackCuts->GetPtRange(minPt, maxPt);
      maxPt = argument.Atof();
      fRefTrackCuts->SetPtRange(minPt, maxPt);
      LogInfo("ref track pt range set to %.1f .. %.1f GeV/c.", minPt, maxPt);
      return 2;
    }
  
    if (!argument.CompareTo("-ref-tdca")){
      if (++iArg >= argc) return -EPROTO;
      argument = argv[iArg];
      fRefTrackCuts->SetMaxDCAToVertexXY(argument.Atof());
      LogInfo("ref track DCA transverse threshold set to %.3f", argument.Atof());
      return 2;
    }
  
    if (!argument.CompareTo("-ref-ldca")){
      if (++iArg >= argc) return -EPROTO;
      argument = argv[iArg];
      fRefTrackCuts->SetMaxDCAToVertexZ(argument.Atof());
      LogInfo("ref track longitudinal DCA threshold set to %.3f", argument.Atof());
      return 2;
    }
  
    return 1;
  }
  
  void AliHLTTRDTriggerComponent::ScanTriggerClasses(const char* firedTriggerClasses) {
  
    fIsMinBiasEvent = kFALSE;
  
    TString trg(firedTriggerClasses);
    if (trg.Index("CINT7WU-S-NOPF-ALL") >= 0)
      fIsMinBiasEvent = kTRUE;
  
    if (trg.Index("CINT8WU-S-NOPF-ALL") >= 0)
      fIsMinBiasEvent = kTRUE;
  
  }
  
  Bool_t AliHLTTRDTriggerComponent::CheckRefTrackCuts(AliESDtrack* track){
  
    // cuts by cut class
    if (fApplyRefTrackCuts)
      return fRefTrackCuts->AcceptTrack(track) ? kTRUE : kFALSE;
  
    // simple custom cuts
    Float_t dcaToVertexXY, dcaToVertexZ;
    track->GetImpactParametersTPC(dcaToVertexXY, dcaToVertexZ);
    // LogDebug("IMPACT TPC %.4f  %.4f", dcaToVertexXY, dcaToVertexZ);
  
    if ((dcaToVertexXY > fRefTrackSelectionVertexXYLimit) || (dcaToVertexZ >= fRefTrackSelectionVertexZLimit))
      return kFALSE;
  
    if (TMath::Abs(track->Eta()) > fRefTrackSelectionEtaLimit)
      return kFALSE;
  
    return kTRUE;
  }
  
  
  void AliHLTTRDTriggerComponent::DbgLog(const char* prefix, ...){
  #ifdef __TRDHLTDEBUG
    AliHLTEventID_t eventNumber = fEventId;
    printf("TRDHLTGM %s-%s-%s: [TRG] %s",
   	 (fRunNumber >= 0) ? Form("%06d", fRunNumber) : "XXXXXX",
   	 fChunkId->Data(),
   	 (eventNumber != fgkInvalidEventId) ? Form("%05llu", eventNumber) : "XXXXX",
   	 (strlen(prefix) > 0) ? Form("<%s> ", prefix) : "");
  #endif
    va_list args;
    va_start(args, prefix);
    char* fmt = va_arg(args, char*);
    vprintf(fmt, args);
    printf("\n");
    va_end(args);
  }
  
  int AliHLTTRDTriggerComponent::PrepareESDData(){
  
    int result = 0;
    fESDtracksPresent = kFALSE;
  
    // check access to ESD event data
    const TObject* obj = GetFirstInputObject(kAliHLTAllDataTypes, "AliESDEvent");
    fEsdEvent = dynamic_cast<AliESDEvent*>(const_cast<TObject*>(obj));
  
    if (fEsdEvent) {
      fEsdEvent->GetStdContent();
      fRunNumber = fEsdEvent->GetRunNumber();
      fESDtracksPresent = kTRUE;
      unsigned int numTracks = fEsdEvent->GetNumberOfTracks();
  
      // process trigger classes
      ScanTriggerClasses(fEsdEvent->GetFiredTriggerClasses().Data());
  
      LogDebug("ESD event data: %d ESD tracks [event num: %d] [minbias: %d (fired:%s)]",
  		    numTracks, fEsdEvent->GetEventNumberInFile(), fIsMinBiasEvent, fEsdEvent->GetFiredTriggerClasses().Data());
  
      // process ESD tracks
      if ((fDebugLevel >= 2) || fExtendedHistos){
        AliESDtrack* esdTrack;
        TString paramStr("");
        for (unsigned int iTrack = 0; iTrack < numTracks; ++iTrack) {
  	esdTrack = fEsdEvent->GetTrack(iTrack);
  
  	if (fExtendedHistos){
  	  fHistRefTrackPid->Fill(esdTrack->Pt(), esdTrack->GetTPCsignal());
  	}
  
  	if (fDebugLevel >= 2){
  	  paramStr = "";
  	  if (esdTrack){
  
  	    if (esdTrack->GetInnerParam())
  	      paramStr += "I";
  
  	    if (esdTrack->GetOuterParam())
  	      paramStr += "O";
  
  	    LogDebug("ESD track %4d - pt: %+.2fGeV/c  [params: S%s]", iTrack, esdTrack->GetSignedPt(), paramStr.Data());
  	  } else
  	    LogError("ESD data for track %d invalid", iTrack);
  	}
  
        } // loop over ESD tracks
      }
  
      fTrackingData->SetGtuPtMultiplierFromMagField(fEsdEvent->GetMagneticField()); // used for sign correction
  
      result = 1;
  
    }
  
    return result;
  
  }
  
  int AliHLTTRDTriggerComponent::PrepareHLTData(){
  
    int iResult = 0;
    UInt_t numHLTTracks = 0;
    fHLTtracksPresent = kFALSE;
  
    if (!fHLTTracks){
      LogError("HLT track vector instance not available.");
      return 0;
    }
  
    fHLTTracks->clear();
  
    for (const AliHLTComponentBlockData *pBlock = GetFirstInputBlock(kAliHLTDataTypeTrack | kAliHLTDataOriginTPC);
         pBlock != NULL; pBlock = GetNextInputBlock()) {
      LogDebug("#hlttrk - data block with HLT raw tracks received");
      fHLTtracksPresent = kTRUE;
  
      // vector<AliHLTGlobalBarrelTrack> hltTracks;
      if ((iResult = AliHLTGlobalBarrelTrack::ConvertTrackDataArray(reinterpret_cast<const AliHLTTracksData*>(pBlock->fPtr), pBlock->fSize, *fHLTTracks)) >= 0) {
        for (vector<AliHLTGlobalBarrelTrack>::iterator element = fHLTTracks->begin();
  	   element != fHLTTracks->end(); element++) {
  
  	numHLTTracks++;
  	//## AliHLTGlobalBarrelTrack -> AliKalmanTrack -> AliExternalTrackParam
  
        } // loop over HLT tracks
      }
    } // loop over data blocks
  
    LogDebug("#hlttrk - %d HLT raw tracks found", numHLTTracks);
  
    return iResult;
  
  }
  
  int AliHLTTRDTriggerComponent::PrepareTRDData() {
  
    int result = 1;
  
    fSectorsWithData = 0;
    fTrackingData->Clear();
    for (const AliHLTComponentBlockData* datablock = GetFirstInputBlock(AliHLTTRDDefinitions::fgkOnlineDataType);
         datablock != NULL;
         datablock = GetNextInputBlock())
      {
        fSectorsWithData |= datablock->fSpecification;
        fTrackingData->Decompress(datablock->fPtr, datablock->fSize, kTRUE);
      }
  
    fTrackingData->SetGtuPtMultiplierFromMagField(GetBz()); // used for sign correction
  
    fTrackingData->PrintSummary("trigger component");
  
    return result;
  
  }
  
  int AliHLTTRDTriggerComponent::MatchTRDTracksESD(){
  
    if (!fEsdEvent) {
      LogError("ESD event data not available in MatchTRDTracks().");
      return 0;
    }
  
    if (fHistoMode == 0){
      UInt_t numHists = fHistArray->GetEntries();
      for (UInt_t iHist = 0; iHist < numHists; ++iHist)
        if (fHistArray->At(iHist))
  	((TH1*) (fHistArray->At(iHist)))->Reset();
    }
  
    int result = 1;
    unsigned int numRefTracks = fEsdEvent->GetNumberOfTracks();
    unsigned int numGtuTracks;
    Int_t refTrackIndices[fkMaxRefTracksPerStack];
    UInt_t refTrackCount = 0;
    Bool_t isRelevant;
    Double_t distY, distZ;
    Double_t matchRating;
    Double_t bestMatchRating;
    Int_t bestMatchRefIndex;
    AliESDtrack* refTrack = NULL;
    UInt_t numComparisonsDone = 0;
    UInt_t numUnmatchedTracks = 0;
    UInt_t numMatchedTracks = 0;
    Double_t magField = fEsdEvent->GetMagneticField();
  
    for (UShort_t iStack = 0; iStack < fkTRDStacks; ++iStack) {
      numGtuTracks = fTrackingData->GetNumTracks(iStack);
      refTrackCount = 0;
  
      // preselect ESD relevant ESD tracks
      for (UInt_t iRefTrack = 0; iRefTrack < numRefTracks; ++iRefTrack) {
        refTrack = fEsdEvent->GetTrack(iRefTrack);
        isRelevant = (refTrack->Pt() >= fRefTrackSelectionPtThreshold); //## implement properly
        if (isRelevant){
  	if (refTrackCount < fkMaxRefTracksPerStack)
  	  refTrackIndices[refTrackCount++] = iRefTrack;
  	else {
  	  LogError("number of HLT tracks exceeding limit of %d. Skipping some tracks.", fkMaxRefTracksPerStack);
  	  break;
  	}
        }
      }
  
      // try to match GTU track with ref tracks
      for (UInt_t iGtuTrack = 0; iGtuTrack < numGtuTracks; ++iGtuTrack) {
        bestMatchRating = 0.;
        bestMatchRefIndex = -1;
        Double_t gpt = fTrackingData->GetTrackPt(iStack, iGtuTrack);
        UShort_t gpid = fTrackingData->GetTrackPID(iStack, iGtuTrack);
        UShort_t layerMask = fTrackingData->GetTrackLayerMask(iStack, iGtuTrack);
  
        Float_t trklLocalY[fkTRDLayers];
        Int_t trklBinZ[fkTRDLayers];
        for (UShort_t iLayer = 0; iLayer < fkTRDLayers; ++iLayer){
  	if ((layerMask >> iLayer) & 1){
  	  trklLocalY[iLayer] = fTrackingData->GetTrackTrackletLocalY(iStack, iGtuTrack, iLayer);
  	  trklBinZ[iLayer] = fTrackingData->GetTrackTrackletBinZ(iStack, iGtuTrack, iLayer);
  	}
        }
  
        for (UInt_t iRefTrack = 0; iRefTrack < refTrackCount; ++iRefTrack) {
  	refTrack = fEsdEvent->GetTrack(refTrackIndices[iRefTrack]);
  
  // 	if (!CheckRefTrackCuts(refTrack))
  // 	  continue;
  
  	numComparisonsDone++;
  
  // 	if ((!refTrack->GetOuterParam()) && (!refTrack->GetInnerParam()))  // use tracks with TPC outer param only (all HLT tracks have it anyways)
  // 	  continue;
  
  	Int_t distRes = EstimateTrackDistance(refTrack, iStack, layerMask, trklLocalY, trklBinZ,
  					      magField, &distY, &distZ);
  
  	if (fDebugLevel >= 3){
  	  printf("CHECKMATCH = %i   distY %.2f   distZ %.2f   pt: %.2f   %.2f\n",
  		distRes, distY, distZ, gpt, refTrack->GetSignedPt());
  	}
  
  	if (distRes == 0){
  	  matchRating = RateTrackMatch(distY, distZ, gpt, refTrack->GetSignedPt());
  	} else {
  	  matchRating = 0.;
  	}
  
  	if ((matchRating >= fMatchRatingThreshold) && (matchRating > bestMatchRating)) {
  	  bestMatchRefIndex = refTrackIndices[iRefTrack];
  	  bestMatchRating = matchRating;
  	} else if (matchRating > bestMatchRating)
  	  bestMatchRating = matchRating;
  
  // 	DbgLog("", Form("#match - comparing GTU track %d in S%02d-%d with ref track %d: [gpt: %+5.2f rpt: %+5.2f] dy: %.1f dz: %.1f rating: %.1f",
  // 			iGtuTrack, iStack/5, iStack%5, refTrackIndices[iRefTrack],
  // 			fTrackingData->GetTrackPt(iStack, iGtuTrack), refTrack->GetSignedPt(),
  // 			distY, distZ, matchRating));
  
        } // loop over ref tracks in stack
  
        fHistMatchRating->Fill(bestMatchRating);
        fHistMatchRatingByPt->Fill(bestMatchRating, TMath::Abs(gpt));
        fHistMatchRatingByPid->Fill(bestMatchRating, gpid);
        fHistTrackPt->Fill(gpt);
        fHistTrackPid->Fill(gpid);
  
        if (fExtendedHistos){
  	fHistMatchedRefTrackPid->Fill(refTrack->Pt(), refTrack->GetTPCsignal());
        }
  
        if (bestMatchRefIndex >= 0){
  	// GTU track has matching reference track
  	refTrack = fEsdEvent->GetTrack(bestMatchRefIndex);
  	Double_t rpt = refTrack->GetSignedPt();
  	LogDebug("#match - match found: rating %.2f, gpt: %+5.2f, rpt: %+5.2f (%i) -> diff: %.2f%%",
  			    bestMatchRating,gpt, rpt, bestMatchRefIndex, (gpt - rpt)/rpt*100.);
  	fTrackingData->SetTrackAddInfo(iStack, iGtuTrack, bestMatchRefIndex);
  	if (fDebugLevel >= 3){
  	  LogDebug("#match-info rating: %.2f gpt: %+.2f  matchref: %d  rpt: %+.2f	gpid: %d  S%02d-%d %d	rpid: %.3f",
  			  bestMatchRating, gpt, bestMatchRefIndex, rpt, gpid,
  			  iStack/5, iStack%5, iGtuTrack, refTrack->GetTPCsignal());
  	}
  	numMatchedTracks++;
  
  	fHistTrackPtMatched->Fill(gpt);
  	fHistTrackPtCorr->Fill(rpt, gpt);
  	fHistTrackPidMatched->Fill(gpid);
  
        } else {
  	if (fDebugLevel >= 3){
  	  LogDebug("#match-info rating: %.2f gpt: %+.2f  no ref matching  gpid: %d  S%02d-%d %d",
  			  bestMatchRating, gpt, gpid,
  			  iStack/5, iStack%5, iGtuTrack);
  	}
  	numUnmatchedTracks++;
        }
  
      } // loop over gtu tracks in stack
  
    } // loop over stacks
  
    LogInfo("#match - %d matched GTU tracks, %d unmatched",
  		      numMatchedTracks, numUnmatchedTracks);
  
    fHistTrackMatchingCombinations->Fill(0., (Double_t)(numRefTracks * fTrackingData->GetNumTracks()));  // index 0: full combinatorics
    fHistTrackMatchingCombinations->Fill(1., numComparisonsDone);  // index 1: track matching comparisons actually done
  
    return result;
  
  }
  
  int AliHLTTRDTriggerComponent::MatchTRDTracksHLT(){
  
    if (!fHLTTracks){
      LogError("HLT track data available.");
      return 0;
    }
  
    Double_t magField = GetBz();
    unsigned int numGtuTracks;
    unsigned int numHLTTracks = 0;
    Bool_t isRelevant;
    Double_t distY, distZ;
    Double_t matchRating;
    Double_t bestMatchRating;
    Int_t bestMatchRefIndex;
    UInt_t numComparisonsDone = 0;
    UInt_t numUnmatchedTracks = 0;
    UInt_t numMatchedTracks = 0;
  
    Bool_t hltTrackPreSel[fkMaxRefTracks];
    UInt_t iHltTrack;
  
    for (UShort_t iStack = 0; iStack < fkTRDStacks; ++iStack) {
      numGtuTracks = fTrackingData->GetNumTracks(iStack);
  
      // preselect relevant HLT tracks
      iHltTrack = 0;
      for (vector<AliHLTGlobalBarrelTrack>::iterator element = fHLTTracks->begin();
  	 element != fHLTTracks->end(); element++) {
        numHLTTracks++;
        isRelevant = (element->Pt() >= fRefTrackSelectionPtThreshold); //## implement properly
  
        //## use cuts here
        hltTrackPreSel[iHltTrack++] = isRelevant;
        if (iHltTrack >= fkMaxRefTracks) {
  	LogError("maximum number of HLT tracks exceeded.");
  	break;
        }
      } // loop over HLT tracks;
  
      // search for matching HLT track for each GTU track
      for (UInt_t iGtuTrack = 0; iGtuTrack < numGtuTracks; ++iGtuTrack) {
        bestMatchRating = 0.;
        bestMatchRefIndex = -1;
        Double_t gpt = fTrackingData->GetTrackPt(iStack, iGtuTrack);
        UShort_t gpid = fTrackingData->GetTrackPID(iStack, iGtuTrack);
        UShort_t layerMask = fTrackingData->GetTrackLayerMask(iStack, iGtuTrack);
  
        Float_t trklLocalY[fkTRDLayers];
        Int_t trklBinZ[fkTRDLayers];
        for (UShort_t iLayer = 0; iLayer < fkTRDLayers; ++iLayer){
  	if ((layerMask >> iLayer) & 1){
  	  trklLocalY[iLayer] = fTrackingData->GetTrackTrackletLocalY(iStack, iGtuTrack, iLayer);
  	  trklBinZ[iLayer] = fTrackingData->GetTrackTrackletBinZ(iStack, iGtuTrack, iLayer);
  	}
        }
  
        iHltTrack = 0;
        for (vector<AliHLTGlobalBarrelTrack>::iterator element = fHLTTracks->begin();
  	   element != fHLTTracks->end(); element++) {
  	if (!hltTrackPreSel[iHltTrack]){
  	  iHltTrack++;
  	  continue;
  	}
  
  	// compare GTU track and relevant HLT track
  	numComparisonsDone++;
  
  	AliHLTGlobalBarrelTrack hltPar(*element);
  	Int_t distRes = EstimateTrackDistance(&hltPar, iStack, layerMask, trklLocalY, trklBinZ,
  					       magField, &distY, &distZ);
  
  	if (fDebugLevel >= 3){
  	  printf("CHECKMATCH = %i   distY %.2f   distZ %.2f   pt: %.2f   %.2f\n",
  		 distRes, distY, distZ, gpt, element->GetSignedPt());
  	}
  
  	if (distRes == 0){
  	  matchRating = RateTrackMatch(distY, distZ, gpt, element->GetSignedPt());
  	} else {
  	  matchRating = 0.;
  	}
  
  	if ((matchRating >= fMatchRatingThreshold) && (matchRating > bestMatchRating)) {
  	  bestMatchRefIndex = iHltTrack;
  	  bestMatchRating = matchRating;
  	} else if (matchRating > bestMatchRating)
  	  bestMatchRating = matchRating;
  
  
  	iHltTrack++;
        } // loop over HLT tracks;
  
        fHistMatchRating->Fill(bestMatchRating);
        fHistMatchRatingByPt->Fill(bestMatchRating, TMath::Abs(gpt));
        fHistMatchRatingByPid->Fill(bestMatchRating, gpid);
        fHistTrackPt->Fill(gpt);
        fHistTrackPid->Fill(gpid);
  
        if (bestMatchRefIndex >= 0){
  	// GTU track has matching reference track
   	Double_t rpt = fHLTTracks->at(bestMatchRefIndex).GetSignedPt();
   	LogDebug("#match - match found: rating %.2f, gpt: %+5.2f, rpt: %+5.2f (%i) -> diff: %.2f%%",
   			    bestMatchRating,gpt, rpt, bestMatchRefIndex, (gpt - rpt)/rpt*100.);
  	fTrackingData->SetTrackAddInfo(iStack, iGtuTrack, bestMatchRefIndex);
  
  // 	if (fExtendedHistos){
  // 	  fHistMatchedRefTrackPid->Fill(element->Pt(), element->GetTPCsignal());
  // 	}
  //
  // 	if (fDebugLevel >= 3){
  // 	  LogDebug("#match-info rating: %.2f gpt: %+.2f  matchref: %d  rpt: %+.2f	gpid: %d  S%02d-%d %d	rpid: %.3f",
  // 			  bestMatchRating, gpt, bestMatchRefIndex, rpt, gpid,
  // 			  iStack/5, iStack%5, iGtuTrack, refTrack->GetTPCsignal());
  // 	}
  	numMatchedTracks++;
  
  	fHistTrackPtMatched->Fill(gpt);
  	fHistTrackPtCorr->Fill(rpt, gpt);
  	fHistTrackPidMatched->Fill(gpid);
  
        } else {
  	if (fDebugLevel >= 3){
  	  LogDebug("#match-info rating: %.2f gpt: %+.2f  no ref matching  gpid: %d  S%02d-%d %d",
  			  bestMatchRating, gpt, gpid,
  			  iStack/5, iStack%5, iGtuTrack);
  	}
  	numUnmatchedTracks++;
        }
  
      } // loop over gtu tracks
    } // loop over stacks
  
    LogInfo("#match - %d matched GTU tracks, %d unmatched (%d comparisons)",
  	  numMatchedTracks, numUnmatchedTracks, numComparisonsDone);
  
    fHistTrackMatchingCombinations->Fill(0., (Double_t)(numHLTTracks * fTrackingData->GetNumTracks()));  // index 0: full combinatorics
    fHistTrackMatchingCombinations->Fill(1., numComparisonsDone);  // index 1: track matching comparisons actually done
  
    return kTRUE;
  }
  
  int AliHLTTRDTriggerComponent::MatchTRDTracks(){
  
    if (!fEsdEvent) {
      LogError("ESD event data not available in MatchTRDTracks().");
      return 0;
    }
  
    if (fHistoMode == 0){
      UInt_t numHists = fHistArray->GetEntries();
      for (UInt_t iHist = 0; iHist < numHists; ++iHist)
        if (fHistArray->At(iHist))
  	((TH1*) (fHistArray->At(iHist)))->Reset();
    }
  
    int result = 1;
    unsigned int numRefTracks = fEsdEvent->GetNumberOfTracks();
    unsigned int numGtuTracks;
    Int_t refTrackIndices[fkMaxRefTracksPerStack];
    UInt_t refTrackCount = 0;
    Bool_t isRelevant;
    Double_t distY, distZ;
    Double_t matchRating;
    Double_t bestMatchRating;
    Int_t bestMatchRefIndex;
    AliESDtrack* refTrack;
    UInt_t numComparisonsDone = 0;
    UInt_t numUnmatchedTracks = 0;
    UInt_t numMatchedTracks = 0;
  
    for (UShort_t iStack = 0; iStack < fkTRDStacks; ++iStack) {
      numGtuTracks = fTrackingData->GetNumTracks(iStack);
      refTrackCount = 0;
  
      // preselect ESD relevant ESD tracks
      for (UInt_t iRefTrack = 0; iRefTrack < numRefTracks; ++iRefTrack) {
        refTrack = fEsdEvent->GetTrack(iRefTrack);
        isRelevant = (refTrack->Pt() >= fRefTrackSelectionPtThreshold);
        if (isRelevant){
  	if (refTrackCount < fkMaxRefTracksPerStack)
  	  refTrackIndices[refTrackCount++] = iRefTrack;
  	else {
  	  LogError("number of HLT tracks exceeding limit of %d. Skipping some tracks.", fkMaxRefTracksPerStack);
  	  break;
  	}
        }
      }
  
      // try to match GTU track with ref tracks
      for (UInt_t iGtuTrack = 0; iGtuTrack < numGtuTracks; ++iGtuTrack) {
        bestMatchRating = 0.;
        bestMatchRefIndex = -1;
        Double_t gpt = fTrackingData->GetTrackPt(iStack, iGtuTrack);
        UShort_t gpid = fTrackingData->GetTrackPID(iStack, iGtuTrack);
        UShort_t layerMask = fTrackingData->GetTrackLayerMask(iStack, iGtuTrack);
  
        for (UInt_t iRefTrack = 0; iRefTrack < refTrackCount; ++iRefTrack) {
  	refTrack = fEsdEvent->GetTrack(refTrackIndices[iRefTrack]);
  
  	if (!CheckRefTrackCuts(refTrack))
  	  continue;
  
  	numComparisonsDone++;
  
  // 	if ((!refTrack->GetOuterParam()) && (!refTrack->GetInnerParam()))  // use tracks with TPC outer param only (all HLT tracks have it anyways)
  // 	  continue;
  
  	Float_t trklLocalY[fkTRDLayers];
  	Int_t trklBinZ[fkTRDLayers];
  	for (UShort_t iLayer = 0; iLayer < fkTRDLayers; ++iLayer){
  	  if ((layerMask >> iLayer) & 1){
  	    trklLocalY[iLayer] = fTrackingData->GetTrackTrackletLocalY(iStack, iGtuTrack, iLayer);
  	    trklBinZ[iLayer] = fTrackingData->GetTrackTrackletBinZ(iStack, iGtuTrack, iLayer);
  	  }
  	}
  
  	Int_t distRes = EstimateTrackDistance(refTrack, iStack, layerMask, trklLocalY, trklBinZ,
  					      fEsdEvent->GetMagneticField(), &distY, &distZ);
  
  	if (distRes == 0){
  	  matchRating = RateTrackMatch(distY, distZ, gpt, refTrack->GetSignedPt());
  	} else {
  	  matchRating = 0.;
  	}
  
  	if ((matchRating >= fMatchRatingThreshold) && (matchRating > bestMatchRating)) {
  	  bestMatchRefIndex = refTrackIndices[iRefTrack];
  	  bestMatchRating = matchRating;
  	} else if (matchRating > bestMatchRating)
  	  bestMatchRating = matchRating;
  
  // 	DbgLog("", Form("#match - comparing GTU track %d in S%02d-%d with ref track %d: [gpt: %+5.2f rpt: %+5.2f] dy: %.1f dz: %.1f rating: %.1f",
  // 			iGtuTrack, iStack/5, iStack%5, refTrackIndices[iRefTrack],
  // 			fTrackingData->GetTrackPt(iStack, iGtuTrack), refTrack->GetSignedPt(),
  // 			distY, distZ, matchRating));
  
        } // loop over ref tracks in stack
  
        fHistMatchRating->Fill(bestMatchRating);
        fHistMatchRatingByPt->Fill(bestMatchRating, TMath::Abs(gpt));
        fHistMatchRatingByPid->Fill(bestMatchRating, gpid);
        fHistTrackPt->Fill(gpt);
        fHistTrackPid->Fill(gpid);
  
        if (bestMatchRefIndex >= 0){
  	// GTU track has matching reference track
  	refTrack = fEsdEvent->GetTrack(bestMatchRefIndex);
  	Double_t rpt = refTrack->GetSignedPt();
  	LogDebug("#match - match found: rating %.2f, gpt: %+5.2f, rpt: %+5.2f (%i) -> diff: %.2f%%",
  			    bestMatchRating,gpt, rpt, bestMatchRefIndex, (gpt - rpt)/rpt*100.);
  	fTrackingData->SetTrackAddInfo(iStack, iGtuTrack, bestMatchRefIndex);
  
  	if (fExtendedHistos){
  	  fHistMatchedRefTrackPid->Fill(refTrack->Pt(), refTrack->GetTPCsignal());
  	}
  
  	if (fDebugLevel >= 3){
  	  LogDebug("#match-info rating: %.2f gpt: %+.2f  matchref: %d  rpt: %+.2f	gpid: %d  S%02d-%d %d	rpid: %.3f",
  			  bestMatchRating, gpt, bestMatchRefIndex, rpt, gpid,
  			  iStack/5, iStack%5, iGtuTrack, refTrack->GetTPCsignal());
  	}
  	numMatchedTracks++;
  
  	fHistTrackPtMatched->Fill(gpt);
  	fHistTrackPtCorr->Fill(rpt, gpt);
  	fHistTrackPidMatched->Fill(gpid);
  
        } else {
  	if (fDebugLevel >= 3){
  	  LogDebug("#match-info rating: %.2f gpt: %+.2f  no ref matching  gpid: %d  S%02d-%d %d",
  			  bestMatchRating, gpt, gpid,
  			  iStack/5, iStack%5, iGtuTrack);
  	}
  	numUnmatchedTracks++;
        }
  
      } // loop over gtu tracks in stack
  
    } // loop over stacks
  
    LogInfo("#match - %d matched GTU tracks, %d unmatched",
  		      numMatchedTracks, numUnmatchedTracks);
  
    fHistTrackMatchingCombinations->Fill(0., (Double_t)(numRefTracks * fTrackingData->GetNumTracks()));  // index 0: full combinatorics
    fHistTrackMatchingCombinations->Fill(1., numComparisonsDone);  // index 1: track matching comparisons actually done
  
    return result;
  }
  
  void AliHLTTRDTriggerComponent::DumpTrackingData(){
  
    if (fTrackingData->GetNumTracklets() + fTrackingData->GetNumTracks() == 0)
      return;
  
    TString trklStr("");
    TString matchStr("");
    UShort_t layerMask;
  
  //  for (UShort_t iSector = 0; iSector < 18; ++iSector){
  //    if (fTrackingData->GetSectorTrgWord(iSector) != ((UInt_t)0x2345352 ^ ((UInt_t)iSector + 34)))
  //      LogError("invalid sector trigger word in sector %02d: trg word is 0x%08x, should be 0x%08x",
  // 	       iSector, fTrackingData->GetSectorTrgWord(iSector), ((UInt_t)0x2345352 ^ ((UInt_t)iSector + 34)));
  //    for (UShort_t iStack = 0; iStack < 5; ++iStack){
  //      ULong64_t dwl = ((ULong64_t)0xaffe << 16) | (ULong64_t)iSector << 8 | iStack;
  //      ULong64_t dw = (((ULong64_t)0xbead << 16) | (ULong64_t)iSector << 8 | iStack) | ((ULong64_t)dwl << 32);
  //      if (fTrackingData->GetStackTrgWord(iSector, iStack) != dw)
  // 	LogError("stack %02d-%d trg word is 0x%016llx, should be 0x%016llx",
  // 		 iSector, iStack, fTrackingData->GetStackTrgWord(iSector, iStack), dw);
  //    }
  //  }
  
    for (UShort_t iStack = 0; iStack < fkTRDStacks; ++iStack){
      for (Int_t iTrk = 0; iTrk < fTrackingData->GetNumTracks(iStack); ++iTrk){
  
        layerMask = fTrackingData->GetTrackLayerMask(iStack, iTrk);
  
        trklStr = Form("trkl: ");
        for (Short_t iLayer = 5; iLayer >= 0; --iLayer){
  	if ((layerMask >> iLayer) & 1)
  	  trklStr += Form("0x%08x (%+8.3f)  ",
  			  fTrackingData->GetTrackTrackletWord(iStack, iTrk, iLayer),
  			  fTrackingData->GetTrackTrackletLocalY(iStack, iTrk, iLayer));
  	else
  	  trklStr += "---------------------  ";
        } // loop over layers
        trklStr.Remove(trklStr.Length() - 2, 2);
  
        if (fTrackingData->GetTrackAddInfo(iStack, iTrk) >= 0){
  	Double_t rpt = (fESDtracksPresent) ?  fEsdEvent->GetTrack(fTrackingData->GetTrackAddInfo(iStack, iTrk))->GetSignedPt() :
  	  fHLTTracks->at(fTrackingData->GetTrackAddInfo(iStack, iTrk)).GetSignedPt();
  	matchStr = Form("mpt: %+7.2f", rpt);
        } else
  	matchStr = "unmatched";
  
        if (fDebugLevel >= 3){
  
  	printf("###DOTDA EV%04llu  GTU TRACK - S%02d-%d	 pt: %+7.2f  pid: %3d  lm: 0x%02x %s  %s\n",
  	       fEventId,
  	       iStack/5, iStack%5, fTrackingData->GetTrackPt(iStack, iTrk), fTrackingData->GetTrackPID(iStack, iTrk),
  	       layerMask, trklStr.Data(),
  	       matchStr.Data());
  
  	printf("###DOTDB EV%04llu  GTU TRACK - S%02d-%d	 pt: %+7.2f  pid: %3d  lm: 0x%02x %s\n",
  	       fEventId,
  	       iStack/5, iStack%5, fTrackingData->GetTrackPt(iStack, iTrk), fTrackingData->GetTrackPID(iStack, iTrk),
  	       layerMask, trklStr.Data());
        }
  
  
        // paranoia checks
        for (Short_t iLayer = 5; iLayer >= 0; --iLayer){
  	if (((layerMask >> iLayer) & 1) && (fTrackingData->GetTrackTrackletWord(iStack, iTrk, iLayer) == 0x10001000))
  	  LogError("invalid layer mask / tracklet value combination A");
  
  	if ((((layerMask >> iLayer) & 1) == 0) && (fTrackingData->GetTrackTrackletWord(iStack, iTrk, iLayer) != 0x10001000))
  	  LogError("invalid layer mask / tracklet value combination B");
        }
  
      } // loop over tracks in stack
    } // loop over stacks
  
  }
  
  void AliHLTTRDTriggerComponent::AssignTrackInfo(TString* infoStr, const UInt_t stack, const UInt_t trackIndex, const char* flagStr) {
  
    TString flags(flagStr);
    Bool_t appendRefData = kFALSE;
  
    if (fTrackingData->GetTrackAddInfo(stack, trackIndex) >= 0){
      appendRefData = kTRUE;
      if (flags.First('M') < 0)
        flags += "M";
    }
  
    *infoStr = Form("EXCH-TRK-INFO DS<%s> CH<%s> EV%05llu SEC%02d-%d-%d  gpt: %+6.1f  gpid: %3d  flags: %s",
  		  "TRDHLTTRG",
  		  fChunkId->Data(), fEventId,
  		  stack/5, stack%5, trackIndex,
  		  fTrackingData->GetTrackPt(stack, trackIndex),
  		  fTrackingData->GetTrackPID(stack, trackIndex), flags.Data());
  
    if (appendRefData){
      Double_t rpt = (fESDtracksPresent) ? fEsdEvent->GetTrack(fTrackingData->GetTrackAddInfo(stack, trackIndex))->GetSignedPt() :
        fHLTTracks->at(fTrackingData->GetTrackAddInfo(stack, trackIndex)).GetSignedPt();
      *infoStr += Form("  rpt: %+6.1f", rpt);
    }
  
  }
  
  #ifdef __TRDHLTDEBUG
  void AliHLTTRDTriggerComponent::RenderEvent(const Bool_t showGtuTracks, const Bool_t showTracklets, const Bool_t showRefTracks) {
  
    if ((!fEventDisplay) || (!fEsdEvent))
      return;
  
    LogDebug("rendering event");
  
    const Float_t refTrackPtDisplayThreshold = 0.7;
    const Float_t trackPtEmphasizeThreshold = 1.8;
  
    fEventDisplay->Reset();
    fEventDisplay->SetMagField(fEsdEvent->GetMagneticField());
    for (UInt_t iDet = 0; iDet < fkTRDStacks*fkTRDLayers; ++iDet)
      fEventDisplay->SetChamberState(iDet/fkTRDLayers, iDet%6, ((fSectorsWithData >> (iDet/30)) & 1) );
  
    if (showTracklets){
      for (UShort_t iDet = 0; iDet < fkTRDStacks*fkTRDLayers; ++iDet){
        UInt_t numTrkl = fTrackingData->GetNumTracklets(iDet);
        for (UInt_t iTrkl = 0; iTrkl < numTrkl; ++iTrkl){
  	fEventDisplay->AddTracklet(fTrackingData->GetTracklet(iDet, iTrkl));
        }
      }
    }
  
    if (showGtuTracks){
      for (UShort_t iStack = 0; iStack < fkTRDStacks; ++iStack){
        for (Int_t iTrk = 0; iTrk < fTrackingData->GetNumTracks(iStack); ++iTrk){
  	AliESDTrdTrack* track = fTrackingData->GetTrack(iStack, iTrk);
  	Int_t trkIndex = fEventDisplay->AddTrack(track, (TMath::Abs(track->Pt()) >= trackPtEmphasizeThreshold) ? (kMagenta + 2) : kMagenta, 1, 1);
  	if (fTrackingData->GetTrackAddInfo(iStack, iTrk) >= 0)
  	  fEventDisplay->SetTrackTrackletStyle(trkIndex, kRed, 12);
  	else
  	  fEventDisplay->SetTrackTrackletStyle(trkIndex, kViolet - 5, 12);
        }
      }
    }
  
    unsigned int numRefTracks = fEsdEvent->GetNumberOfTracks();
    unsigned int numRefTracksRendered = 0;
    if (showRefTracks){
      // check for some marks for rendering
      UShort_t marks[40000];
      memset(marks, 0, sizeof(UShort_t)*40000);
      for (UShort_t iStack = 0; iStack < fkTRDStacks; ++iStack){
        for (Int_t iTrk = 0; iTrk < fTrackingData->GetNumTracks(iStack); ++iTrk){
  	if (fTrackingData->GetTrackAddInfo(iStack, iTrk) >= 0){
  	  marks[fTrackingData->GetTrackAddInfo(iStack, iTrk)] |= 1;
  	  if (
  	      (fTrackingData->GetTrackPID(iStack, iTrk) >= fElectronTriggerPIDThresholdHQU) &&
  	      (TMath::Abs(fTrackingData->GetTrackPt(iStack, iTrk)) >= fElectronTriggerPtThresholdHQU))
  	    marks[fTrackingData->GetTrackAddInfo(iStack, iTrk)] |= 2;
  	}
        }
      }
  
      // add to rendering
      for (unsigned int iTrack = 0; iTrack < numRefTracks; ++iTrack){
        AliESDtrack* track = fEsdEvent->GetTrack(iTrack);
        if ((track->Pt() >= refTrackPtDisplayThreshold) || (marks[iTrack] != 0)){
  	Color_t color = (track->Pt() >= trackPtEmphasizeThreshold) ? (kGray + 2) : kGray;
  	UShort_t width = 1;
  	UShort_t style = 1;
  	if (marks[iTrack] & 0x2){
  	  color = kRed + 1;
  	  width = 6;
  	}
  	if (!CheckRefTrackCuts(track))
  	  style = 2;
  
  	fEventDisplay->AddTrack(track, color, width, style);
  	numRefTracksRendered++;
        }
      }
    }
  
    if (!fEventDisplay->IsEmpty()){
      fEventDisplay->SetTitle("");
      fEventDisplay->SetSetupText("HLT", Form("%.1f#scale[0.5]{ }/#scale[0.5]{ }%.1f",
  					  refTrackPtDisplayThreshold, trackPtEmphasizeThreshold));
      fEventDisplay->SetBottomText(Form("%05i-%s-%05llu",
  				      fRunNumber, fChunkId->Data(), fEventId));
      fEventDisplay->SetBottomTextRight(Form("%d (%d) HLT tracks, %d tracklets, %d GTU tracks",
  					   numRefTracks,
  					   numRefTracksRendered,
  					   fTrackingData->GetNumTracklets(),
  					   fTrackingData->GetNumTracks()));
      fEventDisplay->SetLook(AliTRDtrackingEventDisplay::dmMediumLight);
      fEventDisplay->SetDisplayMode(AliTRDtrackingEventDisplay::dmFullXY);
      fEventDisplay->SaveToFile(Form("display/event-%s-%05llu.eps",
  				   fChunkId->Data(), fEventId));
    }
  
  }
  #endif
  
  Bool_t AliHLTTRDTriggerComponent::TRDElectronTrigger(const char *ident, const Double_t minPt, const UShort_t minPID){
  
    LogDebug("Electron trigger processing (%s: pt>=%.1f, pid>=%d)...", ident, minPt, minPID);
  
    UInt_t numTracks;
    Bool_t highPtElectronSeenGTU = kFALSE;
    Bool_t highPtElectronSeen = kFALSE;
    UInt_t truncMeanPID = 0;
    TString trackExchangeInfo("");
    TString flags("");
  
    UInt_t trdSectorTrgContribs = 0;
    for (UShort_t iSector = 0; iSector < fkTRDSectors; ++iSector)
      trdSectorTrgContribs |= fTrackingData->GetSectorTrgContribs(iSector);
    if ((trdSectorTrgContribs >> 5) & 0x3)
      fIsTRDElectronEvent = kTRUE;
    else
      fIsTRDElectronEvent = kFALSE;
  
    if (fIsMinBiasEvent)
      fHistElectronTriggerBaseMinBias->Fill(0.);
  
    if (fIsTRDElectronEvent)
      fHistElectronTriggerBaseTrdL1->Fill(0.);
  
    if ((fElectronTriggerOnL1TrgOnly) && (!fIsTRDElectronEvent)){
      // evaluate trigger for events with TRD L1 electron trigger fired
      DbgLog("skipping %s electron trigger evaluation for event, because no TRD trigger flag set (ctbs: 0x%02x)",
  	   ident, trdSectorTrgContribs);
      return 0;
    }
  
    for (UShort_t iStack = 0; iStack < fkTRDStacks; ++iStack){
      numTracks = fTrackingData->GetNumTracks(iStack);
      for (UInt_t iTrk = 0; iTrk < numTracks; ++iTrk){
        Double_t gpt = fTrackingData->GetTrackPt(iStack, iTrk);
        Bool_t trdElectronCandidate = kFALSE;
        Bool_t hltElectronCandidate = kFALSE;
  
        // re-evaluate GTU only decision for comparison
        if (
  	  (TMath::Abs(gpt) >= minPt) &&
  	  (fTrackingData->GetTrackPID(iStack, iTrk) >= minPID)
  	  ) {
  	trdElectronCandidate = kTRUE;
  	highPtElectronSeenGTU = kTRUE;
  	fHistElectronCandidatePt->Fill(gpt);
  	fHistElectronCandidatePid->Fill(fTrackingData->GetTrackPID(iStack, iTrk));
  
  	if (fExtendedHistos){
  
  	  // idea to be checked
  	  truncMeanPID = 0;
  	  Short_t minLyr = -1;
  	  UShort_t minValue = 255;
  	  Short_t maxLyr = -1;
  	  UShort_t maxValue = 0;
  	  UShort_t lyrCount = 0;
  	  UInt_t layerMask = fTrackingData->GetTrackLayerMask(iStack, iTrk);
  
  	  // scan for min & max values
  	  for (UShort_t iLayer = 0; iLayer < fkTRDLayers; ++iLayer){
  	    if ((layerMask >> iLayer) & 1){
  	      if (fTrackingData->GetTrackTrackletPID(iStack, iTrk, iLayer) < minValue){
  		minValue = fTrackingData->GetTrackTrackletPID(iStack, iTrk, iLayer);
  		minLyr = iLayer;
  	      }
  	      if (fTrackingData->GetTrackTrackletPID(iStack, iTrk, iLayer) > maxValue){
  		maxValue = fTrackingData->GetTrackTrackletPID(iStack, iTrk, iLayer);
  		maxLyr = iLayer;
  	      }
  	    }
  	  } // loop over layers
  
  	  // calculate trunc mean
  	  for (UShort_t iLayer = 0; iLayer < fkTRDLayers; ++iLayer){
  	    if (((layerMask >> iLayer) & 1) && (iLayer != minLyr) && (iLayer != maxLyr)){
  	      truncMeanPID += fTrackingData->GetTrackTrackletPID(iStack, iTrk, iLayer);
  	      lyrCount++;
  	    }
  	  } // loop over layers
  	  truncMeanPID = TMath::Nint((Double_t)(truncMeanPID)/(Double_t)(lyrCount));
  
  	  fHistPIDvsTruncPID->Fill(fTrackingData->GetTrackPID(iStack, iTrk), truncMeanPID);
  	  if (fTrackingData->GetTrackAddInfo(iStack, iTrk) < 0)
  	    fHistElectronFalsePIDvsTruncPID->Fill(fTrackingData->GetTrackPID(iStack, iTrk), truncMeanPID);
  
  	}
  
  	LogInspect("#hlt-trd-trg - GTU flagged %s %s high-pt electron seen in S%02d-%d: pt: %+6.1f  pid: %d  [id: S%02d-%d-%d] [trunc-pid: %d]",
  		   (fTrackingData->GetTrackAddInfo(iStack, iTrk) < 0) ? "unmatched" : "matched", ident,
  		   iStack/5, iStack%5,
  		   gpt, fTrackingData->GetTrackPID(iStack, iTrk),
  		   iStack/5, iStack%5, iTrk,
  		   truncMeanPID);
        }
  
        // evaluate HLT-level trigger decision using match information
        if (
  	  (fTrackingData->GetTrackAddInfo(iStack, iTrk) >= 0) &&
  	  (TMath::Abs(gpt) >= minPt) &&
  	  (fTrackingData->GetTrackPID(iStack, iTrk) >= minPID)
  	  ) {
  	hltElectronCandidate = kTRUE;
  	highPtElectronSeen = kTRUE;
  
  	fHistElectronCandidateMatchedPt->Fill(gpt);
  	fHistElectronCandidateMatchedPid->Fill(fTrackingData->GetTrackPID(iStack, iTrk));
  
  	if (fExtendedHistos){
  	  fHistElectronConfirmedPIDvsTruncPID->Fill(fTrackingData->GetTrackPID(iStack, iTrk), truncMeanPID);
  	}
  
  	Double_t rpt = (fESDtracksPresent) ? fEsdEvent->GetTrack(fTrackingData->GetTrackAddInfo(iStack, iTrk))->GetSignedPt() :
  	  fHLTTracks->at(fTrackingData->GetTrackAddInfo(iStack, iTrk)).GetSignedPt();
  	LogInspect("#hlt-trd-trg - HLT matched %s high-pt electron seen in S%02d-%d: gpt: %+6.1f  gpid: %d   rpt: %+6.1f  [id: S%02d-%d-%d]",
  		   ident, iStack/5, iStack%5, fTrackingData->GetTrackPt(iStack, iTrk), fTrackingData->GetTrackPID(iStack, iTrk),
  		   rpt, iStack/5, iStack%5, iTrk);
        }
  
        // log output for subsequent offline analysis
        if ((fDebugLevel >= 3) && (trdElectronCandidate || hltElectronCandidate)){
  	trackExchangeInfo = "";
  	flags = "";
  	if (trdElectronCandidate)
  	  flags += "G";
  	if (hltElectronCandidate)
  	  flags += "H";
  	AssignTrackInfo(&trackExchangeInfo, iStack, iTrk, flags.Data());
  	LogDebug("%s\n", trackExchangeInfo.Data());
        }
  
      } // loop over tracks in stack
    } // loop over stacks
  
    if (highPtElectronSeenGTU || highPtElectronSeen){
      LogInspect("#hlt-trd-trg - event triggered by %s electron trigger (TRD L1: %d, TRD HLT: %d)",
  	       ident, highPtElectronSeenGTU, highPtElectronSeen);
    }
  
    if (highPtElectronSeenGTU){
      if (fIsMinBiasEvent)
        fHistElectronTriggerBaseMinBias->Fill(1.);
    }
  
    if (highPtElectronSeen){
      if (fIsMinBiasEvent)
        fHistElectronTriggerBaseMinBias->Fill(2.);
      if (fIsTRDElectronEvent)
        fHistElectronTriggerBaseTrdL1->Fill(1.);
    }
  
    return (highPtElectronSeen) ? kTRUE : kFALSE;
  }
  
  
  int AliHLTTRDTriggerComponent::DoTrigger()
  {
  
    fEsdEvent = NULL;
    fRunNumber = -1;
    int iResult = 0;
    UShort_t firedTriggers = 0;
  
    const AliHLTComponentEventData* hltEventData = GetEventData();
    fEventId = hltEventData->fEventID;
    LogDebug("### START DoTrigger [event id: %llu, %d blocks, size: %d]",
  		      fEventId, hltEventData->fBlockCnt, hltEventData->fStructSize);
  
  //  LogDebug("### START DoTrigger [event id: %llu, %d blocks, size: %d]",
  // 		      fEventId, hltEventData->fBlockCnt, hltEventData->fStructSize);
  
    if (!IsDataEvent()) {  // process data events only
      IgnoreEvent();
      LogDebug("### END   DoTrigger [event id: %llu, %d blocks, size: %d] (skipped: no data event)",
  	     fEventId, hltEventData->fBlockCnt, hltEventData->fStructSize);
      return iResult;
    }
  
    fTrackingData->SetLogPrefix(Form("TRDHLTGM XXXXXX-%05llu: [TRG] {TrkDat} ", fEventId));
  
    do {
  
      // access to TRD specific data from AliHLTTRDPreprocessorComponent
      if (!PrepareTRDData()){
        LogError("access to TRD data failed. Skipping event...");
        break;
      }
  
      if (fTrackingData->GetNumTracks() + fTrackingData->GetNumTracklets() == 0) {
        LogDebug("no trigger-relevant TRD information, skipping further event processing");
        break;
      }
  
      // access to ESD data
      if (!PrepareESDData()){
        LogInfo("access to ESD event data failed.");
      }
  
      // access to alternative HLT data
      if (!fESDtracksPresent){
        if (!PrepareHLTData()){
  	LogError("access to HLT event data failed.");
        }
      }
  
      // match TRD and HLT tracks
      if (fESDtracksPresent){
        if (!MatchTRDTracksESD()){
  	LogError("matching TRD tracks to ESD tracks failed. Skipping event...");
  	break;
        }
      } else if (fHLTtracksPresent){
        if (!MatchTRDTracksHLT()){
  	LogError("matching TRD tracks to HLT tracks failed. Skipping event...");
  	break;
        }
      } else {
        LogError("No HLT track information available. Skipping event...");
        break;
      }
  
  //    if (!MatchTRDTracks()){
  //      LogError("matching TRD tracks to TPC tracks failed. Skipping event...");
  //      break;
  //    }
  
      if (fDebugLevel >= 1)
        DumpTrackingData();
  
      // evaluate electron trigger conditions
      if (TRDElectronTrigger("HSE", fElectronTriggerPtThresholdHSE, fElectronTriggerPIDThresholdHSE))
        firedTriggers |= fkElectronTriggerHSE;
  
      if (TRDElectronTrigger("HQU", fElectronTriggerPtThresholdHQU, fElectronTriggerPIDThresholdHQU))
        firedTriggers |= fkElectronTriggerHQU;
  
      break;
  
    } while (1);
  
  
    // trigger decision
    TString description("");
    if (firedTriggers & fkElectronTriggerHSE){
      if (description.Length() > 0)
        description += " ";
      description += fgkTriggerDecisionElectronHSE;
    }
  
    if (firedTriggers & fkElectronTriggerHQU){
      if (description.Length() > 0)
        description += " ";
      description += fgkTriggerDecisionElectronHQU;
    }
  
    SetDescription(description.Data());
    AliHLTTriggerDecision decision((firedTriggers) ? kTRUE : kFALSE,
  				 GetTriggerName(),
  				 GetReadoutList(),
  				 GetDescription()
  				 );
    TriggerEvent(&decision, kAliHLTDataTypeTObject | kAliHLTDataOriginOut);
  
    if (firedTriggers){
      LogInspect("TRD HLT trigger fired for event: description: >%s<, flags: 0x%04x",
  	       description.Data(), firedTriggers);
  #ifdef __TRDHLTDEBUG
      if (fEventRendering)
        RenderEvent();
  #endif
    } else {
      LogDebug("TRD HLT trigger did not fire for event");
    }
  
    if (fPushHistos){
      PushBack(fHistArray, (kAliHLTDataTypeTObjArray | kAliHLTDataOriginTRD), 0x3fffff);
    }
  
    LogDebug("### END   DoTrigger [event id: %llu, %d blocks, size: %d]",
  		      fEventId, hltEventData->fBlockCnt, hltEventData->fStructSize);
  
    return iResult;
  }
  
  Bool_t AliHLTTRDTriggerComponent::TrackPlaneIntersect(AliExternalTrackParam *trk, Double_t pnt[3], Double_t norm[3], Double_t mag){
  
    UInt_t its = 0;
    Double_t r = 290.;
    Double_t dist = 99999, dist_prev = 99999;
    Double_t x[3] = {0., 0., 0.};
    Bool_t ret = kTRUE;
  
    dist = (x[0] - pnt[0]) * norm[0] + (x[1] - pnt[1]) *norm[1] + (x[2] - pnt[2]) * norm[2];
  
    while(TMath::Abs(dist) > 0.1) {
  
      trk->GetXYZAt(r, mag, x);
  
      if ((x[0] * x[0] + x[1] * x[1]) < 100.) {  // extrapolation to radius failed
        ret = kFALSE;
        break;
      }
  
      //distance between current track position and plane
      dist_prev = TMath::Abs(dist);
      dist = (x[0] - pnt[0]) * norm[0] + (x[1] - pnt[1]) * norm[1];
      r -= dist;
      its++;
      if(TMath::Abs(dist) >= dist_prev ||
         (r > 380.) || (r < 100.)){
        ret = kFALSE;
        break;
      }
    }
  
    for (Int_t i=0; i<3; i++){
      if(ret)
        pnt[i] = x[i];
      else
        pnt[i] = 0.;
    }
  
    return kTRUE;
  }
  
  
  Double_t AliHLTTRDTriggerComponent::RateTrackMatch(Double_t distY, Double_t distZ, Double_t rpt, Double_t gpt){
  
    // maximum limits for spatial distance
    if ((distY > 5.) || (distZ > 20.))
      return 0.;
  
    // same pt sign required
    if ((rpt * gpt) < 0.)
      return 0.;
  
    Double_t rating_distY = -0.1 * distY + 1.;
    Double_t rating_distZ = -0.025 * distZ + 1.;
    Double_t rating_ptDiff = 1. - TMath::Abs((TMath::Abs(rpt) > 0.000001) ? ((gpt-rpt)/rpt) : 0.);
  
    if (rating_ptDiff <  0.)
      rating_ptDiff = 0.2;
  
    Double_t total = rating_distY * rating_distZ * rating_ptDiff;
  
  //  DbgLog("", Form("#matching: rating:   dy: %.3f   dz: %.3f   dpt: %.3f     -> total: %.3f",
  // 		    rating_distY, rating_distZ, rating_ptDiff, total));
  
    if (total > 1.)
      LogError("track match rating exceeds limit of 1.0: %.3f", total);
  
    return total;
  }
  
  Int_t AliHLTTRDTriggerComponent::EstimateTrackDistance(AliESDtrack *esd_track,
  							const UShort_t stack,
  							const UShort_t layerMask,
  							const Float_t trklLocalY[6], const Int_t trklBinZ[6],
  							Double_t mag, Double_t *ydist, Double_t *zdist){
    if (!esd_track)
      return -3;
  
    AliExternalTrackParam* refParam = NULL;
    if (esd_track->GetOuterParam())
      refParam = new AliExternalTrackParam(*(esd_track->GetOuterParam()));
    if (!refParam)
      refParam = new AliExternalTrackParam(*(esd_track));
  
    Int_t res = EstimateTrackDistance(refParam, stack, layerMask, trklLocalY, trklBinZ, mag, ydist, zdist);
  
    if (refParam)
      delete refParam;
  
    return res;
  
  }
  
  Int_t AliHLTTRDTriggerComponent::EstimateTrackDistance(AliExternalTrackParam *refParam,
  							const UShort_t stack,
  							const UShort_t layerMask,
  							const Float_t trklLocalY[6], const Int_t trklBinZ[6],
  							Double_t mag, Double_t *ydist, Double_t *zdist){
  
    Float_t diff_y = 0;
    Float_t diff_z = 0;
    Int_t nLayers = 0;
    Double_t xtrkl[3];
    Double_t ptrkl[3];
    Double_t ptrkl2[3];
    UInt_t trklDet;
    UShort_t trklLayer;
    // UInt_t stack_gtu;
    UShort_t stackInSector;
  
    AliTRDpadPlane* padPlane;
  
    for (UShort_t iLayer = 0; iLayer < 6; iLayer++){
      if ((layerMask >> iLayer) & 1){
        trklDet = stack*6 + iLayer;
        trklLayer = iLayer;
        // stack_gtu = stack;
        stackInSector = stack % 5;
  
        // local coordinates of the outer end point of the tracklet
        xtrkl[0] = AliTRDgeometry::AnodePos();
        xtrkl[1] = trklLocalY[iLayer];
  
        padPlane = fTRDGeometry->GetPadPlane(trklLayer, stackInSector);
        if(stackInSector == 2){ // corrected version by Felix Muecke
  	xtrkl[2] = padPlane->GetRowPos(trklBinZ[iLayer]) - (padPlane->GetRowSize(trklBinZ[iLayer]))/2. - padPlane->GetRowPos(6);
        } else {
  	xtrkl[2] = padPlane->GetRowPos(trklBinZ[iLayer]) - (padPlane->GetRowSize(trklBinZ[iLayer]))/2. - padPlane->GetRowPos(8);
        }
  
        // transform to global coordinates
        TGeoHMatrix *matrix = fTRDGeometry->GetClusterMatrix(trklDet);
        if (!matrix){
  	LogError("invalid TRD cluster matrix in EstimateTrackDistance for detector %i", trklDet);
  	return -5;
        }
        matrix->LocalToMaster(xtrkl, ptrkl);
        fTRDGeometry->RotateBack((stack/5) * 30, ptrkl, ptrkl2);  // ptrkl2 now contains the global position of the outer end point of the tracklet
  
        // calculate parameterization of plane representing the tracklets layer
        Double_t layer_zero_local[3] = {0., 0.,	0.};
        Double_t layer_zero_global[3], layer_zero_global2[3];
  
        matrix->LocalToMaster(layer_zero_local, layer_zero_global);
        fTRDGeometry->RotateBack(trklDet, layer_zero_global, layer_zero_global2); // layer_zero_global2 points to chamber origin in global coords
  
        Double_t layer_ref_local[3] = {AliTRDgeometry::AnodePos(), 0.,  0.};
        Double_t layer_ref_global[3], layer_ref_global2[3];
  
        matrix->LocalToMaster(layer_ref_local, layer_ref_global);
        fTRDGeometry->RotateBack(trklDet, layer_ref_global, layer_ref_global2); // layer_ref_global2 points to center anode pos within plane in global coords
  
        Double_t n0[3] = {layer_ref_global2[0]-layer_zero_global2[0],
  			layer_ref_global2[1]-layer_zero_global2[1],
  			layer_ref_global2[2]-layer_zero_global2[2]};
  
        Double_t n_len = TMath::Sqrt(n0[0]*n0[0] + n0[1]*n0[1] + n0[2]*n0[2]);
        if (n_len == 0.){ // This should never happen
  	//printf("<ERROR> divison by zero in estimate_track_distance!");
  	n_len = 1.;
        }
        Double_t n[3] = {n0[0]/n_len, n0[1]/n_len, n0[2]/n_len}; // normal vector of plane
  
        Bool_t isects = TrackPlaneIntersect(refParam, layer_ref_global2, n, mag); // find intersection point between track and TRD layer
  
        if (isects == kFALSE){ // extrapolation fails, because track never reaches the TRD radius
  	return -1;
        }
  
        Double_t m[2] = {ptrkl2[0] - layer_ref_global2[0], ptrkl2[1] - layer_ref_global2[1]};
        Double_t len_m = TMath::Sqrt(m[0]*m[0] + m[1]*m[1]);
        diff_y += len_m;
        diff_z += TMath::Abs(ptrkl2[2] - layer_ref_global2[2]);
        nLayers++;
      }
    }
  
    if (nLayers > 0){
      *ydist = diff_y / nLayers;
      *zdist = diff_z / nLayers;
      return 0;
    } else {
      LogError("invalid number of contributing layers (%d) in EstimateTrackDistance()", nLayers);
      return -4;
    }
  }
  