From 43a465972893ff9a75790b67b80f518584d3172d Mon Sep 17 00:00:00 2001
From: P-A Loizeau <p.-a.loizeau@gsi.de>
Date: Wed, 18 Jan 2023 11:28:22 +0100
Subject: [PATCH] Add task to clone CbmEvent array if in input + rel. mCBM reco
 macro fix

---
 macro/beamtime/mcbm2022/mcbm_reco.C      |  10 +-
 reco/tasks/CMakeLists.txt                |   1 +
 reco/tasks/CbmRecoTasksLinkDef.h         |   1 +
 reco/tasks/CbmTaskEventsCloneInToOut.cxx | 142 +++++++++++++++++++++++
 reco/tasks/CbmTaskEventsCloneInToOut.h   |  72 ++++++++++++
 5 files changed, 223 insertions(+), 3 deletions(-)
 create mode 100644 reco/tasks/CbmTaskEventsCloneInToOut.cxx
 create mode 100644 reco/tasks/CbmTaskEventsCloneInToOut.h

diff --git a/macro/beamtime/mcbm2022/mcbm_reco.C b/macro/beamtime/mcbm2022/mcbm_reco.C
index 4f128847f6..2e68005e6f 100644
--- a/macro/beamtime/mcbm2022/mcbm_reco.C
+++ b/macro/beamtime/mcbm2022/mcbm_reco.C
@@ -61,8 +61,8 @@ Bool_t mcbm_reco(UInt_t uRunId                   = 2391,
   TString cFileId = sRunId;
 
   //TString parFileIn  = sInpDir + "/unp_mcbm_params_" + sRunId;
-  TString parFileOut = sOutDir + "/reco_event_mcbm_test_params_" + sRunId;
-  TString outFile    = sOutDir + "/reco_event_mcbm_test" + sRunId;
+  TString parFileOut = sOutDir + "/reco_" + (bDigiEvtsInput ? "digievent" : "event") + "_mcbm_test_params_" + sRunId;
+  TString outFile    = sOutDir + "/reco_" + (bDigiEvtsInput ? "digievent" : "event") + "_mcbm_test" + sRunId;
 
   // Your folder with the Tof Calibration files;
   TString TofFileFolder = "";
@@ -260,7 +260,7 @@ Bool_t mcbm_reco(UInt_t uRunId                   = 2391,
 
   // -----   DigiEvent compatibility task   ---------------------------------
   if (bDigiEvtsInput) {
-    // ---- This is required if the input is in DigiEvent format
+    // ---- This is required if the input is in DigiEvent format to create CbmEvents + vectors of Digis in memory
     auto makeEvents = std::make_unique<CbmTaskMakeRecoEvents>();
     run->AddTask(makeEvents.release());
     std::cout << "-I- : Added task MakeRecoEvents" << std::endl;
@@ -271,6 +271,10 @@ Bool_t mcbm_reco(UInt_t uRunId                   = 2391,
                  << "\n Exiting";
       return kFALSE;
     }
+    // ---- This is required if the input is in CbmEvent format to create a copy in memory for update (e.g. with hits)
+    auto cloneEventsInToOut = std::make_unique<CbmTaskEventsCloneInToOut>();
+    run->AddTask(cloneEventsInToOut.release());
+    std::cout << "-I- : Added task EventsCloneInToOut" << std::endl;
   }
   // ------------------------------------------------------------------------
 
diff --git a/reco/tasks/CMakeLists.txt b/reco/tasks/CMakeLists.txt
index 80d8698852..49ea82ea73 100644
--- a/reco/tasks/CMakeLists.txt
+++ b/reco/tasks/CMakeLists.txt
@@ -11,6 +11,7 @@ set(SRCS
   CbmSourceTs.cxx
   CbmTaskBuildEvents.cxx
   CbmTaskDigiEventQa.cxx
+  CbmTaskEventsCloneInToOut.cxx
   CbmTaskMakeRecoEvents.cxx
   CbmTaskTriggerDigi.cxx
   CbmTaskUnpack.cxx
diff --git a/reco/tasks/CbmRecoTasksLinkDef.h b/reco/tasks/CbmRecoTasksLinkDef.h
index ac0ef94908..32def2aa29 100644
--- a/reco/tasks/CbmRecoTasksLinkDef.h
+++ b/reco/tasks/CbmRecoTasksLinkDef.h
@@ -16,6 +16,7 @@
 #pragma link C++ class CbmSourceTs + ;
 #pragma link C++ class CbmTaskBuildEvents + ;
 #pragma link C++ class CbmTaskDigiEventQa + ;
+#pragma link C++ class CbmTaskEventsCloneInToOut + ;
 #pragma link C++ class CbmTaskMakeRecoEvents + ;
 #pragma link C++ class CbmTaskTriggerDigi + ;
 #pragma link C++ class CbmTaskUnpack + ;
diff --git a/reco/tasks/CbmTaskEventsCloneInToOut.cxx b/reco/tasks/CbmTaskEventsCloneInToOut.cxx
new file mode 100644
index 0000000000..77df1c7824
--- /dev/null
+++ b/reco/tasks/CbmTaskEventsCloneInToOut.cxx
@@ -0,0 +1,142 @@
+/* Copyright (C) 2022 Facility for Antiproton and Ion Research in Europe, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Pierre-Alain Loizeau [committer] */
+
+
+#include "CbmTaskEventsCloneInToOut.h"
+
+#include "CbmDefs.h"
+#include "CbmEvent.h"
+
+#include <FairFileSource.h>
+#include <FairRootManager.h>
+#include <Logger.h>
+
+#include <TClonesArray.h>
+#include <TStopwatch.h>
+
+#include <algorithm>
+#include <cassert>
+#include <iomanip>
+
+
+using namespace std;
+
+
+// -----   Constructor   -----------------------------------------------------
+CbmTaskEventsCloneInToOut::CbmTaskEventsCloneInToOut() : FairTask("EventsCloneInToOut") {}
+// ---------------------------------------------------------------------------
+
+
+// -----   Destructor   ------------------------------------------------------
+CbmTaskEventsCloneInToOut::~CbmTaskEventsCloneInToOut() {}
+// ---------------------------------------------------------------------------
+
+
+// -----   Execution   -------------------------------------------------------
+void CbmTaskEventsCloneInToOut::Exec(Option_t*)
+{
+  // --- Timer and counters
+  TStopwatch timer;
+  timer.Start();
+
+  // --- No action if no CbmEvents branch is present
+  if (!fRecoEventsIn) return;
+
+  fRecoEventsOut->Delete();  // Bad way to do it according to ROOT docs, but memory leak otherwise
+
+  // --- Copy all entries in input TClonesArray to output one
+  // => Event loop
+  for (Int_t eventNr = 0; eventNr < fRecoEventsIn->GetEntriesFast(); ++eventNr) {
+    const CbmEvent* pEventIn = dynamic_cast<const CbmEvent*>((*fRecoEventsIn)[eventNr]);
+    if (pEventIn) {
+      /// Explicit creation-copy as no ranged Copy method for TClonesArray
+      new ((*fRecoEventsOut)[eventNr]) CbmEvent(*pEventIn);
+    }
+    else {
+      LOG(fatal) << GetName() << ": Failed to get input event " << eventNr << " in TS " << fNumTs;
+    }
+  }
+
+  if (fRecoEventsIn->GetEntriesFast() != fRecoEventsOut->GetEntriesFast()) {
+    LOG(fatal) << GetName() << ": Input size not matching output one: " << fRecoEventsIn->GetEntriesFast() << " VS "
+               << fRecoEventsOut->GetEntriesFast() << " in TS " << fNumTs;
+  }
+
+  // --- Timeslice log
+  timer.Stop();
+  stringstream logOut;
+  logOut << setw(20) << left << GetName() << " [";
+  logOut << fixed << setw(8) << setprecision(1) << right << timer.RealTime() * 1000. << " ms] ";
+  logOut << "TS " << fNumTs << ", events In " << fRecoEventsIn->GetEntriesFast() << ", events Out "
+         << fRecoEventsOut->GetEntriesFast();
+  LOG(info) << logOut.str();
+
+  // --- Run statistics
+  fNumTs++;
+  fTimeTot += timer.RealTime();
+  fNumEvents += fRecoEventsOut->GetEntriesFast();
+}
+// ----------------------------------------------------------------------------
+
+
+// -----   End-of-timeslice action   ------------------------------------------
+void CbmTaskEventsCloneInToOut::Finish()
+{
+  LOG(info) << "=====================================";
+  LOG(info) << GetName() << ": Run summary";
+  LOG(info) << "Timeslices         : " << fNumTs;
+  LOG(info) << "Events             : " << fNumEvents;
+  LOG(info) << "Time  / TS         : " << fixed << setprecision(2) << 1000. * fTimeTot / double(fNumTs) << " ms";
+  LOG(info) << "=====================================";
+  fRecoEventsOut->Delete();
+}
+// ----------------------------------------------------------------------------
+
+
+// -----   Initialisation   ---------------------------------------------------
+InitStatus CbmTaskEventsCloneInToOut::Init()
+{
+
+  LOG(info) << "==================================================";
+  LOG(info) << GetName() << ": Initialising ";
+
+  // --- Get FairRootManager instance
+  FairRootManager* frm = FairRootManager::Instance();
+  if (nullptr == frm) {
+    LOG(error) << GetName() << ": Failed to get FairRootManager! Aborting...";
+    return kFATAL;
+  }
+
+  // --- Try to get input vector (CbmDigiEvent)
+  fpFileIn = dynamic_cast<FairFileSource*>(frm->GetSource());
+  if (nullptr == fpFileIn) {
+    LOG(error) << GetName() << ": Failed to get Fair file interface object! Aborting...";
+    return kFATAL;
+  }
+
+  TTree* pTree = fpFileIn->GetInTree();
+  if (pTree->GetBranch("CbmEvent")) {
+    fRecoEventsIn = new TClonesArray("CbmEvent", 100);
+    pTree->SetBranchAddress("CbmEvent", &fRecoEventsIn);
+    pTree->SetBranchStatus("CbmEvent", 1);
+
+    LOG(info) << GetName() << ": Found branch CbmEvent in input";
+
+    // --- Event
+    fRecoEventsOut = new TClonesArray("CbmEvent", 1);
+    frm->Register("CbmEvent", "Reco events", fRecoEventsOut, kTRUE);
+    LOG(info) << GetName() << ": created branch CbmEvent in output";
+  }
+  else {
+    LOG(error) << GetName() << ": No CbmEvent branch found in file! Aborting...";
+    return kFATAL;
+  }
+
+  LOG(info) << "==================================================";
+
+  return kSUCCESS;
+}
+// ----------------------------------------------------------------------------
+
+ClassImp(CbmTaskEventsCloneInToOut)
diff --git a/reco/tasks/CbmTaskEventsCloneInToOut.h b/reco/tasks/CbmTaskEventsCloneInToOut.h
new file mode 100644
index 0000000000..fbb87a7105
--- /dev/null
+++ b/reco/tasks/CbmTaskEventsCloneInToOut.h
@@ -0,0 +1,72 @@
+/* Copyright (C) 2023 Facility for Antiproton and Ion Research in Europe, Darmstadt
+   SPDX-License-Identifier: GPL-3.0-only
+   Authors: Pierre-Alain Loizeau [committer] */
+
+
+#ifndef CbmTaskEventsCloneInToOut_H
+#define CbmTaskEventsCloneInToOut_H 1
+
+#include <FairTask.h>
+
+class TClonesArray;
+class FairFileSource;
+
+/** @class CbmTaskEventsCloneInToOut
+ ** @brief Task class for clone CbmEvent objects from the Input to the output to allow their update, e.g. due to new
+ **        reconstruction steps.
+ **
+ ** @author Pierre-Alain Loizeau <v.friese@gsi.de>
+ ** @since 17.01.2023
+ **
+ ** This tasks copies the existing CbmEvent from the input file to the memory with the persitency flag set, so that they
+ ** appear in the output file and can be updated (standard inputs are const).
+ **
+ ** The task has to be run prior to any reconstruction task adding more information to the CbmEvent (e.g. hit or track
+ ** reconstruction), but only in case the event building was done in a previous run (thus saving the events to the file
+ ** used as input for this run)
+ **
+ **/
+class CbmTaskEventsCloneInToOut : public FairTask {
+
+
+public:
+  /** @brief Constructor **/
+  CbmTaskEventsCloneInToOut();
+
+
+  /** @brief Copy constructor (disabled) **/
+  CbmTaskEventsCloneInToOut(const CbmTaskEventsCloneInToOut&) = delete;
+
+
+  /** @brief Destructor **/
+  virtual ~CbmTaskEventsCloneInToOut();
+
+
+  /** @brief Task execution **/
+  virtual void Exec(Option_t* opt);
+
+
+  /** @brief Finish timeslice **/
+  virtual void Finish();
+
+
+  /** @brief Assignment operator (disabled) **/
+  CbmTaskEventsCloneInToOut& operator=(const CbmTaskEventsCloneInToOut&) = delete;
+
+
+private:  // methods
+  /** @brief Task initialisation **/
+  virtual InitStatus Init();
+
+private:  // members
+  FairFileSource* fpFileIn          = nullptr;
+  const TClonesArray* fRecoEventsIn = nullptr;
+  TClonesArray* fRecoEventsOut      = nullptr;
+  double fTimeTot                   = 0.;  ///< Execution time
+  size_t fNumTs                     = 0;   ///< Number of processed timeslices
+  size_t fNumEvents                 = 0;   ///< Number of events
+
+  ClassDef(CbmTaskEventsCloneInToOut, 1);
+};
+
+#endif /* CbmTaskEventsCloneInToOut_H */
-- 
GitLab