]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - PWG2/RESONANCES/AliRsnMiniAnalysisTask.cxx
introduce the option to analyze with PROOF, plus cosmetics
[u/mrichter/AliRoot.git] / PWG2 / RESONANCES / AliRsnMiniAnalysisTask.cxx
index 3db1437739c3d3e397ff6d0ca297d27c9e097997..cd3a39d29ddec65ab5986c2d489b9b15c823e750 100644 (file)
 
 #include <Riostream.h>
 
-#include <TList.h>
 #include <TH1.h>
-#include <TH2.h>
-#include <TH3.h>
-#include <THnSparse.h>
+#include <TList.h>
+#include <TTree.h>
+#include <TStopwatch.h>
 
 #include "AliLog.h"
+#include "AliEventplane.h"
+#include "AliMultiplicity.h"
+#include "AliTriggerAnalysis.h"
 #include "AliAnalysisManager.h"
+#include "AliInputEventHandler.h"
+
 #include "AliESDtrackCuts.h"
 #include "AliESDUtils.h"
-#include "AliMultiplicity.h"
-#include "AliInputEventHandler.h"
-#include "AliTriggerAnalysis.h"
-#include "AliMCEvent.h"
+
 #include "AliAODEvent.h"
-#include "AliMCParticle.h"
 #include "AliAODMCParticle.h"
-#include "AliEventplane.h"
 
 #include "AliRsnCutSet.h"
+#include "AliRsnMiniPair.h"
 #include "AliRsnMiniEvent.h"
 #include "AliRsnMiniParticle.h"
-#include "AliRsnMiniPair.h"
 
 #include "AliRsnMiniAnalysisTask.h"
 
+
 ClassImp(AliRsnMiniAnalysisTask)
 
 //__________________________________________________________________________________________________
@@ -47,6 +47,7 @@ AliRsnMiniAnalysisTask::AliRsnMiniAnalysisTask() :
    fEvNum(0),
    fUseCentrality(kFALSE),
    fCentralityType("QUALITY"),
+   fContinuousMix(kTRUE),
    fNMix(0),
    fMaxDiffMult(10),
    fMaxDiffVz(1.0),
@@ -59,9 +60,10 @@ AliRsnMiniAnalysisTask::AliRsnMiniAnalysisTask() :
    fTrackCuts(0),
    fRsnEvent(),
    fEvBuffer(0x0),
-   fNMixed(0),
    fTriggerAna(0x0),
-   fESDtrackCuts(0x0)
+   fESDtrackCuts(0x0),
+   fMiniEvent(0x0),
+   fBigOutput(kFALSE)
 {
 //
 // Dummy constructor ALWAYS needed for I/O.
@@ -75,6 +77,7 @@ AliRsnMiniAnalysisTask::AliRsnMiniAnalysisTask(const char *name, Bool_t useMC) :
    fEvNum(0),
    fUseCentrality(kFALSE),
    fCentralityType("QUALITY"),
+   fContinuousMix(kTRUE),
    fNMix(0),
    fMaxDiffMult(10),
    fMaxDiffVz(1.0),
@@ -87,9 +90,10 @@ AliRsnMiniAnalysisTask::AliRsnMiniAnalysisTask(const char *name, Bool_t useMC) :
    fTrackCuts(0),
    fRsnEvent(),
    fEvBuffer(0x0),
-   fNMixed(0),
    fTriggerAna(0x0),
-   fESDtrackCuts(0x0)
+   fESDtrackCuts(0x0),
+   fMiniEvent(0x0),
+   fBigOutput(kFALSE)
 {
 //
 // Default constructor.
@@ -102,12 +106,13 @@ AliRsnMiniAnalysisTask::AliRsnMiniAnalysisTask(const char *name, Bool_t useMC) :
 }
 
 //__________________________________________________________________________________________________
-AliRsnMiniAnalysisTask::AliRsnMiniAnalysisTask(const AliRsnMiniAnalysisTaskcopy) :
+AliRsnMiniAnalysisTask::AliRsnMiniAnalysisTask(const AliRsnMiniAnalysisTask &copy) :
    AliAnalysisTaskSE(copy),
    fUseMC(copy.fUseMC),
    fEvNum(0),
    fUseCentrality(copy.fUseCentrality),
    fCentralityType(copy.fCentralityType),
+   fContinuousMix(copy.fContinuousMix),
    fNMix(copy.fNMix),
    fMaxDiffMult(copy.fMaxDiffMult),
    fMaxDiffVz(copy.fMaxDiffVz),
@@ -120,9 +125,10 @@ AliRsnMiniAnalysisTask::AliRsnMiniAnalysisTask(const AliRsnMiniAnalysisTask& cop
    fTrackCuts(copy.fTrackCuts),
    fRsnEvent(),
    fEvBuffer(0x0),
-   fNMixed(0),
    fTriggerAna(copy.fTriggerAna),
-   fESDtrackCuts(copy.fESDtrackCuts)
+   fESDtrackCuts(copy.fESDtrackCuts),
+   fMiniEvent(0x0),
+   fBigOutput(copy.fBigOutput)
 {
 //
 // Copy constructor.
@@ -132,7 +138,7 @@ AliRsnMiniAnalysisTask::AliRsnMiniAnalysisTask(const AliRsnMiniAnalysisTask& cop
 }
 
 //__________________________________________________________________________________________________
-AliRsnMiniAnalysisTask& AliRsnMiniAnalysisTask::operator=(const AliRsnMiniAnalysisTask& copy)
+AliRsnMiniAnalysisTask &AliRsnMiniAnalysisTask::operator=(const AliRsnMiniAnalysisTask &copy)
 {
 //
 // Assignment operator.
@@ -141,10 +147,11 @@ AliRsnMiniAnalysisTask& AliRsnMiniAnalysisTask::operator=(const AliRsnMiniAnalys
 //
 
    AliAnalysisTaskSE::operator=(copy);
-   
+
    fUseMC = copy.fUseMC;
    fUseCentrality = copy.fUseCentrality;
    fCentralityType = copy.fCentralityType;
+   fContinuousMix = copy.fContinuousMix;
    fNMix = copy.fNMix;
    fMaxDiffMult = copy.fMaxDiffMult;
    fMaxDiffVz = copy.fMaxDiffVz;
@@ -155,7 +162,8 @@ AliRsnMiniAnalysisTask& AliRsnMiniAnalysisTask::operator=(const AliRsnMiniAnalys
    fTrackCuts = copy.fTrackCuts;
    fTriggerAna = copy.fTriggerAna;
    fESDtrackCuts = copy.fESDtrackCuts;
-   
+   fBigOutput = copy.fBigOutput;
+
    return (*this);
 }
 
@@ -163,13 +171,15 @@ AliRsnMiniAnalysisTask& AliRsnMiniAnalysisTask::operator=(const AliRsnMiniAnalys
 AliRsnMiniAnalysisTask::~AliRsnMiniAnalysisTask()
 {
 //
-// Destructor. 
+// Destructor.
 // Clean-up the output list, but not the histograms that are put inside
 // (the list is owner and will clean-up these histograms). Protect in PROOF case.
 //
 
+
    if (fOutput && !AliAnalysisManager::GetAnalysisManager()->IsProofMode()) {
       delete fOutput;
+      delete fEvBuffer;
    }
 }
 
@@ -186,7 +196,7 @@ Int_t AliRsnMiniAnalysisTask::AddTrackCuts(AliRsnCutSet *cuts)
 //
 
    TObject *obj = fTrackCuts.FindObject(cuts->GetName());
-   
+
    if (obj) {
       AliInfo(Form("A cut set named '%s' already exists", cuts->GetName()));
       return fTrackCuts.IndexOf(obj);
@@ -205,20 +215,24 @@ void AliRsnMiniAnalysisTask::UserCreateOutputObjects()
 //
 
    // reset counter
-   fEvNum = 0;
+   fEvNum = -1;
+
+   // message
+   AliInfo(Form("Selected event characterization: %s (%s)", (fUseCentrality ? "centrality" : "multiplicity"), fCentralityType.Data()));
 
    // initialize trigger analysis
    if (fTriggerAna) delete fTriggerAna;
    fTriggerAna = new AliTriggerAnalysis;
-   
+
    // initialize ESD quality cuts
    if (fESDtrackCuts) delete fESDtrackCuts;
    fESDtrackCuts = AliESDtrackCuts::GetStandardITSTPCTrackCuts2010();
 
    // create list and set it as owner of its content (MANDATORY)
+   if (fBigOutput) OpenFile(1);
    fOutput = new TList();
    fOutput->SetOwner();
-   
+
    // initialize event statistics counter
    fHEventStat = new TH1F("hEventStat", "Event statistics", 4, 0.0, 4.0);
    fHEventStat->GetXaxis()->SetBinLabel(1, "CINT1B");
@@ -226,29 +240,24 @@ void AliRsnMiniAnalysisTask::UserCreateOutputObjects()
    fHEventStat->GetXaxis()->SetBinLabel(3, "Candle");
    fHEventStat->GetXaxis()->SetBinLabel(4, "Accepted");
    fOutput->Add(fHEventStat);
-   
+
    // create temporary tree for filtered events
-   AliRsnMiniEvent *mini = 0x0;
+   if (fMiniEvent) delete fMiniEvent;
    fEvBuffer = new TTree("EventBuffer", "Temporary buffer for mini events");
-   fEvBuffer->Branch("events", "AliRsnMiniEvent", &mini);
-   
+   fEvBuffer->Branch("events", "AliRsnMiniEvent", &fMiniEvent);
+
    // create one histogram per each stored definition (event histograms)
    Int_t i, ndef = fHistograms.GetEntries();
    AliRsnMiniOutput *def = 0x0;
    for (i = 0; i < ndef; i++) {
-      def = (AliRsnMiniOutput*)fHistograms[i];
+      def = (AliRsnMiniOutput *)fHistograms[i];
       if (!def) continue;
       if (!def->Init(GetName(), fOutput)) {
          AliError(Form("Def '%s': failed initialization", def->GetName()));
          continue;
       }
    }
-   
-   // setup PID response
-   AliAnalysisManager *man = AliAnalysisManager::GetAnalysisManager(); 
-       AliInputEventHandler *inputHandler = (AliInputEventHandler*)man->GetInputEventHandler(); 
-       fRsnEvent.SetPIDResponse(inputHandler->GetPIDResponse());
-   
+
    // post data for ALL output slots >0 here, to get at least an empty histogram
    PostData(1, fOutput);
 }
@@ -257,78 +266,48 @@ void AliRsnMiniAnalysisTask::UserCreateOutputObjects()
 void AliRsnMiniAnalysisTask::UserExec(Option_t *)
 {
 //
-// Main computation loop.
-// To be precise, this loop only checks if events are OK and eventually
-// stores them in the temporary tree used for the analysis.
-// The computation of correlations is done only at the end,
-// in the automatic function which is called every time
+// Computation loop.
+// In this case, it checks if the event is acceptable, and eventually
+// creates the corresponding mini-event and stores it in the buffer.
+// The real histogram filling is done at the end, in "FinishTaskOutput".
 //
 
-   // event counter
+   // increment event counter
    fEvNum++;
-   
+
    // check current event
    Char_t check = CheckCurrentEvent();
    if (!check) return;
-      
-   // if the check is successful, the mini-event is created and stored
-   AliRsnMiniEvent *miniEvent = 0x0;
-   fEvBuffer->SetBranchAddress("events", &miniEvent);
-   
-   // assign event-related values
-   miniEvent = new AliRsnMiniEvent;
-   miniEvent->Vz() = fInputEvent->GetPrimaryVertex()->GetZ();
-   miniEvent->Angle() = ComputeAngle();
-   miniEvent->Mult() = ComputeCentrality((check == 'E'));
-   AliDebugClass(1, Form("Event %d: vz = %f -- mult = %f -- angle = %f", fEvNum, miniEvent->Vz(), miniEvent->Mult(), miniEvent->Angle()));
-   
-   // fill all histograms for events only
-   Int_t id, ndef = fHistograms.GetEntries();
-   AliRsnMiniOutput *def = 0x0;
-   for (id = 0; id < ndef; id++) {
-      def = (AliRsnMiniOutput*)fHistograms[id];
-      if (!def) continue;
-      if (!def->IsEventOnly()) continue;
-      def->Fill(miniEvent, &fValues);
-   }
-   
-   // fill all histograms for mother only (if MC is present)
+
+   // setup PID response
+   AliAnalysisManager *man = AliAnalysisManager::GetAnalysisManager();
+   AliInputEventHandler *inputHandler = (AliInputEventHandler *)man->GetInputEventHandler();
+   fRsnEvent.SetPIDResponse(inputHandler->GetPIDResponse());
+
+   // fill a mini-event from current
+   // and skip this event if no tracks were accepted
+   FillMiniEvent(check);
+
+   // fill MC based histograms on mothers,
+   // which do need the original event
    if (fUseMC) {
       if (fRsnEvent.IsESD() && fMCEvent)
-         FillTrueMotherESD(miniEvent);
+         FillTrueMotherESD(fMiniEvent);
       else if (fRsnEvent.IsAOD() && fRsnEvent.GetAODList())
-         FillTrueMotherAOD(miniEvent);
+         FillTrueMotherAOD(fMiniEvent);
    }
-   
-   // loop on daughters
-   // and store only those that pass at least one cut
-   Int_t it, ic, ncuts = fTrackCuts.GetEntries(), ntot = fRsnEvent.GetAbsoluteSum();
-   AliRsnDaughter cursor;
-   AliRsnMiniParticle miniParticle;
-   for (it = 0; it < ntot; it++) {
-      fRsnEvent.SetDaughter(cursor, it);
-      miniParticle.CopyDaughter(&cursor);
-      for (ic = 0; ic < ncuts; ic++) {
-         AliRsnCutSet *cuts = (AliRsnCutSet*)fTrackCuts[ic];
-         if (cuts->IsSelected(&cursor)) miniParticle.SetCutBit(ic);
-      }
-      AliDebugClass(3, Form("-- Track %d: REC px = %f -- py = %f -- pz = %f", it, miniParticle.Px(0), miniParticle.Py(0), miniParticle.Pz(0)));
-      AliDebugClass(3, Form("-- Track %d: SIM px = %f -- py = %f -- pz = %f", it, miniParticle.Px(1), miniParticle.Py(1), miniParticle.Pz(1)));
-      AliDebugClass(3, Form("-- Track %d: Charge = %c -- PDG = %d -- mother = %d -- motherPDG = %d", it, miniParticle.Charge(), miniParticle.PDG(), miniParticle.Mother(), miniParticle.MotherPDG()));
-      AliDebugClass(2, Form("-- Track %d: Cutbit = %u", it, miniParticle.CutBits()));
-      if (miniParticle.CutBits()) {
-         miniEvent->AddParticle(miniParticle);
-      }
+
+   // if the event is not empty, store it
+   if (fMiniEvent->IsEmpty()) {
+      AliDebugClass(2, Form("Rejecting empty event #%d", fEvNum));
+   } else {
+      Int_t id = fEvBuffer->GetEntries();
+      AliDebugClass(2, Form("Adding event #%d with ID = %d", fEvNum, id));
+      fMiniEvent->ID() = id;
+      fEvBuffer->Fill();
    }
-   AliDebugClass(1, Form("Event %d: selected tracks = %d", fEvNum, miniEvent->Particles().GetEntriesFast()));
-   
-   // store event
-   fEvBuffer->Fill();
-   
-   // process single event
-   ProcessEvents(miniEvent);
-   
-   // post outputs
+
+   // post data for computed stuff
    PostData(1, fOutput);
 }
 
@@ -336,47 +315,197 @@ void AliRsnMiniAnalysisTask::UserExec(Option_t *)
 void AliRsnMiniAnalysisTask::FinishTaskOutput()
 {
 //
-// At the end of execution, when the temporary tree is filled,
-// perform mixing with all found events
+// This function is called at the end of the loop on available events,
+// and then the buffer will be full with all the corresponding mini-events,
+// each one containing all tracks selected by each of the available track cuts.
+// Here a loop is done on each of these events, and both single-event and mixing are computed
 //
 
-   Int_t i1, i2, imix, nEvents = fEvBuffer->GetEntries();
-   AliRsnMiniEvent *evMix = 0x0, evMain;
-   fEvBuffer->SetBranchAddress("events", &evMix);
+   // security code: reassign the buffer to the mini-event cursor
+   fEvBuffer->SetBranchAddress("events", &fMiniEvent);
+   TStopwatch timer;
+   // prepare variables
+   Int_t ievt, nEvents = (Int_t)fEvBuffer->GetEntries();
+   Int_t idef, nDefs   = fHistograms.GetEntries();
+   Int_t imix, iloop, ifill;
+   AliRsnMiniOutput *def = 0x0;
+   AliRsnMiniOutput::EComputation compType;
+
+   Int_t printNum = 0;
+   if (nEvents>1e5) printNum=nEvents/100;
+   if (nEvents>1e4) printNum=nEvents/10;
    
+   // loop on events, and for each one fill all outputs
+   // using the appropriate procedure depending on its type
+   // only mother-related histograms are filled in UserExec,
+   // since they require direct access to MC event
+   timer.Start();
+   for (ievt = 0; ievt < nEvents; ievt++) {
+      // get next entry
+      fEvBuffer->GetEntry(ievt);
+      if (printNum&&(ievt%printNum==0)) {
+         AliInfo(Form("[%s] Std.Event %d/%d",GetName(), ievt,nEvents));
+         timer.Stop(); timer.Print();fflush(stdout); timer.Start(kFALSE);
+      }
+      // fill
+      for (idef = 0; idef < nDefs; idef++) {
+         def = (AliRsnMiniOutput *)fHistograms[idef];
+         if (!def) continue;
+         compType = def->GetComputation();
+         // execute computation in the appropriate way
+         switch (compType) {
+            case AliRsnMiniOutput::kEventOnly:
+               //AliDebugClass(1, Form("Event %d, def '%s': event-value histogram filling", ievt, def->GetName()));
+               ifill = 1;
+               def->FillEvent(fMiniEvent, &fValues);
+               break;
+            case AliRsnMiniOutput::kTruePair:
+               //AliDebugClass(1, Form("Event %d, def '%s': true-pair histogram filling", ievt, def->GetName()));
+               ifill = def->FillPair(fMiniEvent, fMiniEvent, &fValues);
+               break;
+            case AliRsnMiniOutput::kTrackPair:
+               //AliDebugClass(1, Form("Event %d, def '%s': pair-value histogram filling", ievt, def->GetName()));
+               ifill = def->FillPair(fMiniEvent, fMiniEvent, &fValues);
+               break;
+            case AliRsnMiniOutput::kTrackPairRotated1:
+               //AliDebugClass(1, Form("Event %d, def '%s': rotated (1) background histogram filling", ievt, def->GetName()));
+               ifill = def->FillPair(fMiniEvent, fMiniEvent, &fValues);
+               break;
+            case AliRsnMiniOutput::kTrackPairRotated2:
+               //AliDebugClass(1, Form("Event %d, def '%s': rotated (2) background histogram filling", ievt, def->GetName()));
+               ifill = def->FillPair(fMiniEvent, fMiniEvent, &fValues);
+               break;
+            default:
+               // other kinds are processed elsewhere
+               ifill = 0;
+               AliDebugClass(2, Form("Computation = %d", (Int_t)compType));
+         }
+         // message
+         AliDebugClass(1, Form("Event %6d: def = '%15s' -- fills = %5d", ievt, def->GetName(), ifill));
+      }
+   }
+
+   // if no mixing is required, stop here and post the output
+   if (fNMix < 1) {
+      AliDebugClass(2, "Stopping here, since no mixing is required");
+      PostData(1, fOutput);
+      return;
+   }
+
    // initialize mixing counter
-   fNMixed.Set(nEvents);
-   TString msg();
+   Int_t    nmatched[nEvents];
+   TString *smatched = new TString[nEvents];
+   for (ievt = 0; ievt < nEvents; ievt++) {
+      smatched[ievt] = "|";
+      nmatched[ievt] = 0;
+   }
    
-   // loop on events
-   for (i1 = 0; i1 < nEvents; i1++) {
-      if (fNMixed[i1] >= fNMix) continue;
-      fEvBuffer->GetEntry(i1);
-      evMain = (*evMix);
-      for (i2 = 1; i2 < nEvents; i2++) {
-         imix = i1 + i2;
+   
+   AliInfo(Form("[%s] Std.Event %d/%d",GetName(), nEvents,nEvents));
+   timer.Stop(); timer.Print(); timer.Start();fflush(stdout);
+
+   // search for good matchings
+   for (ievt = 0; ievt < nEvents; ievt++) {
+      if (printNum&&(ievt%printNum==0)) {
+         AliInfo(Form("[%s] EventMixing searching %d/%d",GetName(),ievt,nEvents));
+         timer.Stop(); timer.Print(); timer.Start(kFALSE); fflush(stdout);
+      }
+      if (nmatched[ievt] >= fNMix) continue;
+      fEvBuffer->GetEntry(ievt);
+      AliRsnMiniEvent evMain(*fMiniEvent);
+      for (iloop = 1; iloop < nEvents; iloop++) {
+         imix = ievt + iloop;
          if (imix >= nEvents) imix -= nEvents;
-         if (imix == i1) continue;
-         if (fNMixed[i1] >= fNMix) break;
-         if (fNMixed[imix] >= fNMix) continue;
+         if (imix == ievt) continue;
+         // text next entry
          fEvBuffer->GetEntry(imix);
-         // exit if events are not matched
-         if (TMath::Abs(evMain.Vz() - evMix->Vz()) > fMaxDiffVz) continue;
-         if (TMath::Abs(evMain.Mult() - evMix->Mult()) > fMaxDiffMult) continue;
-         if (TMath::Abs(evMain.Angle() - evMix->Angle()) > fMaxDiffAngle) continue;
-         // found a match: increment counter for both events
-         fNMixed[i1]++;
-         fNMixed[imix]++;
-         //cout << "Mixed " << i1 << " with " << imix << endl;
-         ProcessEvents(&evMain, evMix);
-         // if mixed enough times, stop
+         // skip if events are not matched
+         if (!EventsMatch(&evMain, fMiniEvent)) continue;
+         // check that the array of good matches for mixed does not already contain main event
+         if (smatched[imix].Contains(Form("|%d|", ievt))) continue;
+         // check that the found good events has not enough matches already
+         if (nmatched[imix] >= fNMix) continue;
+         // add new mixing candidate
+         smatched[ievt].Append(Form("%d|", imix));
+         nmatched[ievt]++;
+         nmatched[imix]++;
+         if (nmatched[ievt] >= fNMix) break;
       }
+      AliDebugClass(1, Form("Matches for event %5d = %d [%s] (missing are declared above)", evMain.ID(), nmatched[ievt], smatched[ievt].Data()));
    }
    
-   // message
-   for (Int_t ii = 0; ii < nEvents; ii++) cout << Form("Event #%6d mixed %3d times", ii, fNMixed[ii]) << endl;
-   
-   // post outputs
+   AliInfo(Form("[%s] EventMixing searching %d/%d",GetName(),nEvents,nEvents));
+   timer.Stop(); timer.Print();fflush(stdout); timer.Start();
+
+   // perform mixing
+   TObjArray *list = 0x0;
+   TObjString *os = 0x0;
+   for (ievt = 0; ievt < nEvents; ievt++) {
+      if (printNum&&(ievt%printNum==0)) {
+         AliInfo(Form("[%s] EventMixing %d/%d",GetName(),ievt,nEvents));
+         timer.Stop(); timer.Print(); timer.Start(kFALSE); fflush(stdout);
+      }
+      ifill = 0;
+      fEvBuffer->GetEntry(ievt);
+      AliRsnMiniEvent evMain(*fMiniEvent);
+      list = smatched[ievt].Tokenize("|");
+      TObjArrayIter next(list);
+      while ( (os = (TObjString *)next()) ) {
+         imix = os->GetString().Atoi();
+         fEvBuffer->GetEntry(imix);
+         for (idef = 0; idef < nDefs; idef++) {
+            def = (AliRsnMiniOutput *)fHistograms[idef];
+            if (!def) continue;
+            if (!def->IsTrackPairMix()) continue;
+            ifill += def->FillPair(&evMain, fMiniEvent, &fValues, kTRUE);
+            if (!def->IsSymmetric()) {
+               AliDebugClass(2, "Reflecting non symmetric pair");
+               ifill += def->FillPair(fMiniEvent, &evMain, &fValues, kFALSE);
+            }
+         }
+      }
+      delete list;
+   }
+
+   delete [] smatched;
+
+   AliInfo(Form("[%s] EventMixing %d/%d",GetName(),nEvents,nEvents));
+   timer.Stop();timer.Print();fflush(stdout);
+
+   /*
+   OLD
+   ifill = 0;
+   for (iloop = 1; iloop < nEvents; iloop++) {
+      imix = ievt + iloop;
+      // restart from beginning if reached last event
+      if (imix >= nEvents) imix -= nEvents;
+      // avoid to mix an event with itself
+      if (imix == ievt) continue;
+      // skip all events already mixed enough times
+      if (fNMixed[ievt] >= fNMix) break;
+      if (fNMixed[imix] >= fNMix) continue;
+      fEvBuffer->GetEntry(imix);
+      // skip if events are not matched
+      if (TMath::Abs(evMain.Vz()    - fMiniEvent->Vz()   ) > fMaxDiffVz   ) continue;
+      if (TMath::Abs(evMain.Mult()  - fMiniEvent->Mult() ) > fMaxDiffMult ) continue;
+      if (TMath::Abs(evMain.Angle() - fMiniEvent->Angle()) > fMaxDiffAngle) continue;
+      // found a match: increment counter for both events
+      AliDebugClass(1, Form("Event %d, def '%s': event mixing (%d with %d)", ievt, def->GetName(), ievt, imix));
+      fNMixed[ievt]++;
+      fNMixed[imix]++;
+      // process mixing
+      ifill += def->FillPair(&evMain, fMiniEvent, &fValues);
+      // stop if mixed enough times
+      if (fNMixed[ievt] >= fNMix) break;
+   }
+   break;
+   // print number of mixings done with each event
+   for (ievt = 0; ievt < nEvents; ievt++) {
+      AliDebugClass(2, Form("Event %6d: mixed %2d times", ievt, fNMixed[ievt]));
+   }
+   */
+
+   // post computed data
    PostData(1, fOutput);
 }
 
@@ -388,10 +517,10 @@ void AliRsnMiniAnalysisTask::Terminate(Option_t *)
 // Called once at the end of the query
 //
 
-   fOutput = dynamic_cast<TList*>(GetOutputData(1));
-   if (!fOutput) { 
-      AliError("Could not retrieve TList fOutput"); 
-      return; 
+   fOutput = dynamic_cast<TList *>(GetOutputData(1));
+   if (!fOutput) {
+      AliError("Could not retrieve TList fOutput");
+      return;
    }
 }
 
@@ -417,7 +546,7 @@ Char_t AliRsnMiniAnalysisTask::CheckCurrentEvent()
 
    // string to sum messages
    TString msg("");
-   
+
    // check input type
    // exit points are provided in all cases an event is bad
    // if this block is passed, an event can be rejected only
@@ -429,9 +558,9 @@ Char_t AliRsnMiniAnalysisTask::CheckCurrentEvent()
       output = 'E';
       // ESD specific check: Physics Selection
       // --> if this is failed, the event is rejected
-      isSelected = (((AliInputEventHandler*)(AliAnalysisManager::GetAnalysisManager()->GetInputEventHandler()))->IsEventSelected() & AliVEvent::kMB);
+      isSelected = (((AliInputEventHandler *)(AliAnalysisManager::GetAnalysisManager()->GetInputEventHandler()))->IsEventSelected() & AliVEvent::kMB);
       if (!isSelected) {
-         AliDebugClass(1, "Event does not pass physics selections");
+         AliDebugClass(2, "Event does not pass physics selections");
          fRsnEvent.SetRef(0x0);
          fRsnEvent.SetRefMC(0x0);
          return 0;
@@ -440,7 +569,7 @@ Char_t AliRsnMiniAnalysisTask::CheckCurrentEvent()
       fRsnEvent.SetRef(fInputEvent);
       // add MC if requested and available
       if (fUseMC) {
-         if (fMCEvent) 
+         if (fMCEvent)
             fRsnEvent.SetRefMC(fMCEvent);
          else {
             AliWarning("MC event requested but not available");
@@ -467,29 +596,29 @@ Char_t AliRsnMiniAnalysisTask::CheckCurrentEvent()
       fRsnEvent.SetRefMC(0x0);
       return 0;
    }
-   
+
    // fill counter of accepted events
    fHEventStat->Fill(0.1);
-   
+
    // check if it is V0AND
    // --> uses a cast to AliESDEvent even if the input is an AliAODEvent
-   Bool_t v0A = fTriggerAna->IsOfflineTriggerFired((AliESDEvent*)fInputEvent, AliTriggerAnalysis::kV0A);
-   Bool_t v0C = fTriggerAna->IsOfflineTriggerFired((AliESDEvent*)fInputEvent, AliTriggerAnalysis::kV0C);
+   Bool_t v0A = fTriggerAna->IsOfflineTriggerFired((AliESDEvent *)fInputEvent, AliTriggerAnalysis::kV0A);
+   Bool_t v0C = fTriggerAna->IsOfflineTriggerFired((AliESDEvent *)fInputEvent, AliTriggerAnalysis::kV0C);
    if (v0A && v0C) {
       msg += " -- VOAND = YES";
       fHEventStat->Fill(1.1);
    } else {
       msg += " -- VOAND = NO ";
    }
-   
+
    // check candle
    // --> requires at least one good quality track with Pt > 0.5 and |eta| <= 0.8
    Int_t iTrack, ntracksLoop = fInputEvent->GetNumberOfTracks();
    Bool_t candle = kFALSE;
-   for (iTrack = 0; iTrack < ntracksLoop; iTrack++) {    
-      AliVTrack   *track = (AliVTrack*)fInputEvent->GetTrack(iTrack);
-      AliESDtrack *esdt  = dynamic_cast<AliESDtrack*>(track);
-      AliAODTrack *aodt  = dynamic_cast<AliAODTrack*>(track);
+   for (iTrack = 0; iTrack < ntracksLoop; iTrack++) {
+      AliVTrack   *track = (AliVTrack *)fInputEvent->GetTrack(iTrack);
+      AliESDtrack *esdt  = dynamic_cast<AliESDtrack *>(track);
+      AliAODTrack *aodt  = dynamic_cast<AliAODTrack *>(track);
       if (track->Pt() < 0.5) continue;
       if(TMath::Abs(track->Eta()) > 0.8) continue;
       if (esdt) if (!fESDtrackCuts->AcceptTrack(esdt)) continue;
@@ -498,12 +627,12 @@ Char_t AliRsnMiniAnalysisTask::CheckCurrentEvent()
       break;
    }
    if (candle) {
-      msg += " -- CANDLE = YES"; 
+      msg += " -- CANDLE = YES";
       fHEventStat->Fill(2.1);
    } else {
-      msg += " -- CANDLE = NO "; 
+      msg += " -- CANDLE = NO ";
    }
-   
+
    // if event cuts are defined, they are checked here
    // final decision on the event depends on this
    isSelected = kTRUE;
@@ -519,9 +648,9 @@ Char_t AliRsnMiniAnalysisTask::CheckCurrentEvent()
       msg += " -- Local cuts = NONE";
       isSelected = kTRUE;
    }
-   
+
    // if the above exit point is not taken, the event is accepted
-   AliDebugClass(1, Form("Stats for event %d: %s", fEvNum, msg.Data()));
+   AliDebugClass(2, Form("Stats: %s", msg.Data()));
    if (isSelected) {
       fHEventStat->Fill(3.1);
       return output;
@@ -530,6 +659,52 @@ Char_t AliRsnMiniAnalysisTask::CheckCurrentEvent()
    }
 }
 
+//__________________________________________________________________________________________________
+void AliRsnMiniAnalysisTask::FillMiniEvent(Char_t evType)
+{
+//
+// Refresh cursor mini-event data member to fill with current event.
+// Returns the total number of tracks selected.
+//
+
+   // assign event-related values
+   if (fMiniEvent) delete fMiniEvent;
+   fMiniEvent = new AliRsnMiniEvent;
+   fMiniEvent->Vz()    = fInputEvent->GetPrimaryVertex()->GetZ();
+   fMiniEvent->Angle() = ComputeAngle();
+   fMiniEvent->Mult()  = ComputeCentrality((evType == 'E'));
+   AliDebugClass(2, Form("Event %d: type = %c -- vz = %f -- mult = %f -- angle = %f", fEvNum, evType, fMiniEvent->Vz(), fMiniEvent->Mult(), fMiniEvent->Angle()));
+
+   // loop on daughters and assign track-related values
+   Int_t ic, ncuts = fTrackCuts.GetEntries();
+   Int_t ip, npart = fRsnEvent.GetAbsoluteSum();
+   Int_t npos = 0, nneg = 0, nneu = 0;
+   AliRsnDaughter cursor;
+   AliRsnMiniParticle miniParticle;
+   for (ip = 0; ip < npart; ip++) {
+      // point cursor to next particle
+      fRsnEvent.SetDaughter(cursor, ip);
+      // copy momentum and MC info if present
+      miniParticle.CopyDaughter(&cursor);
+      miniParticle.Index() = ip;
+      // switch on the bits corresponding to passed cuts
+      for (ic = 0; ic < ncuts; ic++) {
+         AliRsnCutSet *cuts = (AliRsnCutSet *)fTrackCuts[ic];
+         if (cuts->IsSelected(&cursor)) miniParticle.SetCutBit(ic);
+      }
+      // if a track passes at least one track cut, it is added to the pool
+      if (miniParticle.CutBits()) {
+         fMiniEvent->AddParticle(miniParticle);
+         if (miniParticle.Charge() == '+') npos++;
+         else if (miniParticle.Charge() == '-') nneg++;
+         else nneu++;
+      }
+   }
+
+   // get number of accepted tracks
+   AliDebugClass(1, Form("Event %6d: total = %5d, accepted = %4d (pos %4d, neg %4d, neu %4d)", fEvNum, npart, (Int_t)fMiniEvent->Particles().GetEntriesFast(), npos, nneg, nneu));
+}
+
 //__________________________________________________________________________________________________
 Double_t AliRsnMiniAnalysisTask::ComputeAngle()
 {
@@ -537,8 +712,16 @@ Double_t AliRsnMiniAnalysisTask::ComputeAngle()
 // Get the plane angle
 //
 
-   AliEventplane *plane = fInputEvent->GetEventplane();
-   if (plane) 
+   AliEventplane *plane = 0x0;
+
+   if (fInputEvent->InheritsFrom(AliESDEvent::Class()))
+      plane = fInputEvent->GetEventplane();
+   else if (fInputEvent->InheritsFrom(AliAODEvent::Class())) {
+      AliAODEvent *aodEvent = (AliAODEvent *)fInputEvent;
+      plane = aodEvent->GetHeader()->GetEventplaneP();
+   }
+
+   if (plane)
       return plane->GetEventplane("Q");
    else {
       AliWarning("No event plane defined");
@@ -567,13 +750,13 @@ Double_t AliRsnMiniAnalysisTask::ComputeCentrality(Bool_t isESD)
          return fInputEvent->GetNumberOfTracks();
       else if (!fCentralityType.CompareTo("QUALITY"))
          if (isESD)
-            return AliESDtrackCuts::GetReferenceMultiplicity((AliESDEvent*)fInputEvent, kTRUE);
+            return AliESDtrackCuts::GetReferenceMultiplicity((AliESDEvent *)fInputEvent, kTRUE);
          else {
             Double_t count = 0.;
             Int_t iTrack, ntracksLoop = fInputEvent->GetNumberOfTracks();
-            for (iTrack = 0; iTrack < ntracksLoop; iTrack++) {    
-               AliVTrack   *track = (AliVTrack*)fInputEvent->GetTrack(iTrack);
-               AliAODTrack *aodt  = dynamic_cast<AliAODTrack*>(track);
+            for (iTrack = 0; iTrack < ntracksLoop; iTrack++) {
+               AliVTrack   *track = (AliVTrack *)fInputEvent->GetTrack(iTrack);
+               AliAODTrack *aodt  = dynamic_cast<AliAODTrack *>(track);
                if (!aodt) continue;
                if (!aodt->TestFilterBit(5)) continue;
                count++;
@@ -582,7 +765,7 @@ Double_t AliRsnMiniAnalysisTask::ComputeCentrality(Bool_t isESD)
          }
       else if (!fCentralityType.CompareTo("TRACKLETS")) {
          if (isESD) {
-            const AliMultiplicity *mult = ((AliESDEvent*)fInputEvent)->GetMultiplicity();
+            const AliMultiplicity *mult = ((AliESDEvent *)fInputEvent)->GetMultiplicity();
             Float_t nClusters[6] = {0.0,0.0,0.0,0.0,0.0,0.0};
             for(Int_t ilay = 0; ilay < 6; ilay++) nClusters[ilay] = (Float_t)mult->GetNumberOfITSClusters(ilay);
             return AliESDUtils::GetCorrSPD2(nClusters[1], fInputEvent->GetPrimaryVertex()->GetZ());
@@ -611,20 +794,20 @@ void AliRsnMiniAnalysisTask::FillTrueMotherESD(AliRsnMiniEvent *miniEvent)
    AliMCParticle *daughter1, *daughter2;
    TLorentzVector p1, p2;
    AliRsnMiniOutput *def = 0x0;
-   
+
    for (id = 0; id < ndef; id++) {
-      def = (AliRsnMiniOutput*)fHistograms[id];
+      def = (AliRsnMiniOutput *)fHistograms[id];
       if (!def) continue;
       if (!def->IsMother()) continue;
       for (ip = 0; ip < npart; ip++) {
-         AliMCParticle *part = (AliMCParticle*)fMCEvent->GetTrack(ip);
-         if (TMath::Abs(part->Particle()->GetPdgCode()) != def->GetMotherPDG()) continue;
+         AliMCParticle *part = (AliMCParticle *)fMCEvent->GetTrack(ip);
+         if (part->Particle()->GetPdgCode() != def->GetMotherPDG()) continue;
          // check that daughters match expected species
          if (part->Particle()->GetNDaughters() < 2) continue;
          label1 = part->Particle()->GetDaughter(0);
          label2 = part->Particle()->GetDaughter(1);
-         daughter1 = (AliMCParticle*)fMCEvent->GetTrack(label1);
-         daughter2 = (AliMCParticle*)fMCEvent->GetTrack(label2);
+         daughter1 = (AliMCParticle *)fMCEvent->GetTrack(label1);
+         daughter2 = (AliMCParticle *)fMCEvent->GetTrack(label2);
          okMatch = kFALSE;
          if (TMath::Abs(daughter1->Particle()->GetPdgCode()) == def->GetPDG(0) && TMath::Abs(daughter2->Particle()->GetPdgCode()) == def->GetPDG(1)) {
             okMatch = kTRUE;
@@ -640,7 +823,7 @@ void AliRsnMiniAnalysisTask::FillTrueMotherESD(AliRsnMiniEvent *miniEvent)
          miniPair.Sum(0) = miniPair.Sum(1) = (p1 + p2);
          miniPair.FillRef(def->GetMotherMass());
          // do computations
-         def->Fill(&miniPair, miniEvent, &fValues);
+         def->FillMother(&miniPair, miniEvent, &fValues);
       }
    }
 }
@@ -660,20 +843,20 @@ void AliRsnMiniAnalysisTask::FillTrueMotherAOD(AliRsnMiniEvent *miniEvent)
    AliAODMCParticle *daughter1, *daughter2;
    TLorentzVector p1, p2;
    AliRsnMiniOutput *def = 0x0;
-   
+
    for (id = 0; id < ndef; id++) {
-      def = (AliRsnMiniOutput*)fHistograms[id];
+      def = (AliRsnMiniOutput *)fHistograms[id];
       if (!def) continue;
       if (!def->IsMother()) continue;
       for (ip = 0; ip < npart; ip++) {
-         AliAODMCParticle *part = (AliAODMCParticle*)list->At(ip);
-         if (TMath::Abs(part->GetPdgCode()) != def->GetMotherPDG()) continue;
+         AliAODMCParticle *part = (AliAODMCParticle *)list->At(ip);
+         if (part->GetPdgCode() != def->GetMotherPDG()) continue;
          // check that daughters match expected species
          if (part->GetNDaughters() < 2) continue;
          label1 = part->GetDaughter(0);
          label2 = part->GetDaughter(1);
-         daughter1 = (AliAODMCParticle*)list->At(label1);
-         daughter2 = (AliAODMCParticle*)list->At(label2);
+         daughter1 = (AliAODMCParticle *)list->At(label1);
+         daughter2 = (AliAODMCParticle *)list->At(label2);
          okMatch = kFALSE;
          if (TMath::Abs(daughter1->GetPdgCode()) == def->GetPDG(0) && TMath::Abs(daughter2->GetPdgCode()) == def->GetPDG(1)) {
             okMatch = kTRUE;
@@ -689,56 +872,54 @@ void AliRsnMiniAnalysisTask::FillTrueMotherAOD(AliRsnMiniEvent *miniEvent)
          miniPair.Sum(0) = miniPair.Sum(1) = (p1 + p2);
          miniPair.FillRef(def->GetMotherMass());
          // do computations
-         def->Fill(&miniPair, miniEvent, &fValues);
+         def->FillMother(&miniPair, miniEvent, &fValues);
       }
    }
 }
 
-//________________________________________________________________________
-void AliRsnMiniAnalysisTask::ProcessEvents(AliRsnMiniEvent *evMain, AliRsnMiniEvent *evMix)
+//__________________________________________________________________________________________________
+Bool_t AliRsnMiniAnalysisTask::EventsMatch(AliRsnMiniEvent *event1, AliRsnMiniEvent *event2)
 {
 //
-// This function processes all single tracks.
-// Loops on the daughters defined in current event
-// and on all of them which pass the single-track cuts defined, computes what needed
+// Check if two events are compatible.
+// If the mixing is continuous, this is true if differences in vz, mult and angle are smaller than
+// the specified values.
+// If the mixing is binned, this is true if the events are in the same bin.
 //
 
-   // check if it is mixed
-   Bool_t isMix;
-   if (evMix) {
-      isMix = kTRUE;
+   if (!event1 || !event2) return kFALSE;
+   Int_t ivz1, ivz2, imult1, imult2, iangle1, iangle2;
+   Double_t dv, dm, da;
+
+   if (fContinuousMix) {
+      dv = TMath::Abs(event1->Vz()    - event2->Vz()   );
+      dm = TMath::Abs(event1->Mult()  - event2->Mult() );
+      da = TMath::Abs(event1->Angle() - event2->Angle());
+      if (dv > fMaxDiffVz) {
+         //AliDebugClass(2, Form("Events #%4d and #%4d don't match due to a too large diff in Vz = %f", event1->ID(), event2->ID(), dv));
+         return kFALSE;
+      }
+      if (dm > fMaxDiffMult ) {
+         //AliDebugClass(2, Form("Events #%4d and #%4d don't match due to a too large diff in Mult = %f", event1->ID(), event2->ID(), dm));
+         return kFALSE;
+      }
+      if (da > fMaxDiffAngle) {
+         //AliDebugClass(2, Form("Events #%4d and #%4d don't match due to a too large diff in Angle = %f", event1->ID(), event2->ID(), da));
+         return kFALSE;
+      }
+      return kTRUE;
    } else {
-      evMix = evMain;
-      isMix = kFALSE;
+      ivz1 = (Int_t)(event1->Vz() / fMaxDiffVz);
+      ivz2 = (Int_t)(event2->Vz() / fMaxDiffVz);
+      imult1 = (Int_t)(event1->Mult() / fMaxDiffMult);
+      imult2 = (Int_t)(event2->Mult() / fMaxDiffMult);
+      iangle1 = (Int_t)(event1->Angle() / fMaxDiffAngle);
+      iangle2 = (Int_t)(event2->Angle() / fMaxDiffAngle);
+      if (ivz1 != ivz2) return kFALSE;
+      if (imult1 != imult2) return kFALSE;
+      if (iangle1 != iangle2) return kFALSE;
+      return kTRUE;
    }
-   AliDebugClass(1, Form("Event %d: processing %s", fEvNum, (isMix ? "mixing" : "single event")));
-   
-   // 2 nested loops on tracks
-   // inner starts from next track or from first, depending if is mixing or not
-   Int_t i1, i2, idef, start;
-   Int_t n1 = evMain->Particles().GetEntries();
-   Int_t n2 = evMix ->Particles().GetEntries();
-   Int_t ndef = fHistograms.GetEntries();
-   AliRsnMiniParticle *daughter1 = 0x0, *daughter2 = 0x0;
-   AliRsnMiniOutput *def = 0x0;
-   for (i1 = 0; i1 < n1; i1++) {
-      daughter1 = (AliRsnMiniParticle*)evMain->Particles()[i1];
-      if (!daughter1) continue;
-      if (isMix) start = 0; else start = i1 + 1;
-      for (i2 = start; i2 < n2; i2++) {
-         daughter2 = (AliRsnMiniParticle*)evMix->Particles()[i2];
-         if (!daughter2) continue;
-         // loop on definitions
-         for (idef = 0; idef < ndef; idef++) {
-            def = (AliRsnMiniOutput*)fHistograms[idef];
-            if (!def) continue;
-            if (def->IsEventOnly()) continue;
-            if (def->IsMother()) continue;
-            if (isMix && !def->IsTrackPairMix()) continue;
-            if (!isMix && def->IsTrackPairMix()) continue;
-            // check if definitions here match the current pair
-            def->Fill(daughter1, daughter2, evMain, &fValues);
-         } // end loop on definitions
-      } // end loop on daughter #2
-   } // end loop on daughter #1
 }
+
+