From 8b959084cc5ce564422d3285d19f506751f89884 Mon Sep 17 00:00:00 2001
From: Florian Uhlig <f.uhlig@gsi.de>
Date: Thu, 17 Feb 2022 18:41:31 +0100
Subject: [PATCH] Don't transport more events as available in input

In #2421 a crash was reported when the number of events requested to be
transported is larger than the number of events in the input.
Add protection against such a crash in the transport class. The number of
events to be transported is set to the minimum number of events in any of the
connected inputs.
---
 .../generators/CbmPlutoGenerator.cxx          | 34 +++---------------
 sim/transport/generators/CbmPlutoGenerator.h  | 31 +++++++++-------
 .../generators/CbmUnigenGenerator.cxx         | 24 ++-----------
 sim/transport/generators/CbmUnigenGenerator.h | 36 +++++++++++--------
 sim/transport/steer/CMakeLists.txt            |  2 ++
 sim/transport/steer/CbmTransport.cxx          | 31 +++++++++++++++-
 6 files changed, 78 insertions(+), 80 deletions(-)

diff --git a/sim/transport/generators/CbmPlutoGenerator.cxx b/sim/transport/generators/CbmPlutoGenerator.cxx
index f3d944df0c..4e92dbbff9 100644
--- a/sim/transport/generators/CbmPlutoGenerator.cxx
+++ b/sim/transport/generators/CbmPlutoGenerator.cxx
@@ -34,29 +34,11 @@
 #include <sys/stat.h>
 
 // -----   Default constructor   ------------------------------------------
-CbmPlutoGenerator::CbmPlutoGenerator()
-  : FairGenerator()
-  , fdata(makeStaticData())
-  , fbase(makeDataBase())
-  , iEvent(0)
-  , fFileName(nullptr)
-  , fInputChain(nullptr)
-  , fParticles(nullptr)
-  , fPDGmanual(0)
-{
-}
+CbmPlutoGenerator::CbmPlutoGenerator() : FairGenerator() {}
 // ------------------------------------------------------------------------
 
 // -----   Standard constructor   -----------------------------------------
-CbmPlutoGenerator::CbmPlutoGenerator(const Char_t* fileName)
-  : FairGenerator()
-  , fdata(makeStaticData())
-  , fbase(makeDataBase())
-  , iEvent(0)
-  , fFileName(fileName)
-  , fInputChain(nullptr)
-  , fParticles(new TClonesArray("PParticle", 100))
-  , fPDGmanual(0)
+CbmPlutoGenerator::CbmPlutoGenerator(const Char_t* fileName) : FairGenerator(), fFileName(fileName)
 {
   fInputChain = new TChain("data");
 
@@ -68,19 +50,12 @@ CbmPlutoGenerator::CbmPlutoGenerator(const Char_t* fileName)
   else {
     LOG(fatal) << "Problem opening file " << fileName;
   }
+  fAvailableEvents = fInputChain->GetEntries();
 }
 // ------------------------------------------------------------------------
 
 // -----  Constructor with file list   -----------------------------------------
-CbmPlutoGenerator::CbmPlutoGenerator(std::vector<std::string> fileNames)
-  : FairGenerator()
-  , fdata(makeStaticData())
-  , fbase(makeDataBase())
-  , iEvent(0)
-  , fFileName()
-  , fInputChain(nullptr)
-  , fParticles(new TClonesArray("PParticle", 100))
-  , fPDGmanual(0)
+CbmPlutoGenerator::CbmPlutoGenerator(std::vector<std::string> fileNames) : FairGenerator()
 {
   fInputChain = new TChain("data");
   for (const auto& name : fileNames) {
@@ -94,6 +69,7 @@ CbmPlutoGenerator::CbmPlutoGenerator(std::vector<std::string> fileNames)
   }
 
   fInputChain->SetBranchAddress("Particles", &fParticles);
+  fAvailableEvents = fInputChain->GetEntries();
 }
 
 
diff --git a/sim/transport/generators/CbmPlutoGenerator.h b/sim/transport/generators/CbmPlutoGenerator.h
index c8585c4c15..5650523e4b 100644
--- a/sim/transport/generators/CbmPlutoGenerator.h
+++ b/sim/transport/generators/CbmPlutoGenerator.h
@@ -22,19 +22,19 @@
 
 #include "FairGenerator.h"  // for FairGenerator
 
-#include "Rtypes.h"  // for Char_t, etc
+#include "Rtypes.h"        // for Char_t, etc
+#include "TClonesArray.h"  // for TClonesArray
 
 #include <string>
 #include <vector>
 
+#include "PParticle.h"    // for PParticle
+#include "PStaticData.h"  // for PStaticData
+
 class FairPrimaryGenerator;
 
-class TClonesArray;
 class TChain;
 
-class PStaticData;
-class PDataBase;
-
 class CbmPlutoGenerator : public FairGenerator {
 
 public:
@@ -66,22 +66,27 @@ public:
   virtual Bool_t ReadEvent(FairPrimaryGenerator* primGen);
   void SetManualPDG(Int_t pdg) { fPDGmanual = pdg; }
 
+  /** @brief Get the maximum number of events available in the input file
+    ** @return number of available ebvents
+    */
+  Int_t GetNumAvailableEvents() { return fAvailableEvents; }
 
 private:
-  PStaticData* fdata;  //! pluto static data
-  PDataBase* fbase;    //! pluto data base
+  PStaticData* fdata {makeStaticData()};  //! pluto static data
+  PDataBase* fbase {makeDataBase()};      //! pluto data base
 
-  Int_t iEvent;              //! Event number
-  const Char_t* fFileName;   //! Input file name
-  TChain* fInputChain;       //! Pointer to input file
-  TClonesArray* fParticles;  //! Particle array from PLUTO
-  Int_t fPDGmanual;          //! forced pdg value for undefined pluto codes
+  Int_t iEvent {0};                                               //! Event number
+  const Char_t* fFileName {""};                                   //! Input file name
+  TChain* fInputChain {nullptr};                                  //! Pointer to input file
+  TClonesArray* fParticles {new TClonesArray("PParticle", 100)};  //! Particle array from PLUTO
+  Int_t fPDGmanual {0};                                           //! forced pdg value for undefined pluto codes
+  Int_t fAvailableEvents {0};                                     //! Maximum number of events in the input file
 
   /** Private method CloseInput. Just for convenience. Closes the
      ** input file properly. Called from destructor and from ReadEvent. **/
   void CloseInput();
 
-  ClassDef(CbmPlutoGenerator, 4);
+  ClassDef(CbmPlutoGenerator, 5);
 };
 
 #endif
diff --git a/sim/transport/generators/CbmUnigenGenerator.cxx b/sim/transport/generators/CbmUnigenGenerator.cxx
index 3a4be378ea..212d618263 100644
--- a/sim/transport/generators/CbmUnigenGenerator.cxx
+++ b/sim/transport/generators/CbmUnigenGenerator.cxx
@@ -35,17 +35,6 @@ CbmUnigenGenerator::CbmUnigenGenerator(const char* fileName, EMode mode)
   : FairGenerator("UnigenGenerator", "CBM generator")
   , fFileName(fileName)
   , fMode(mode)
-  , fPhi(0.)
-  , fIsInit(kFALSE)
-  , fFile(nullptr)
-  , fTree(nullptr)
-  , fCurrentEntry(-1)
-  , fEvent(new UEvent())
-  , fNofPrimaries(0)
-  , fNofEvents(0)
-  , fBetaCM(0.)
-  , fGammaCM(1.)
-  , fIonMap()
 {
   LOG(debug) << GetName() << ": Constructor";
   if (mode == kRotateFixed)
@@ -63,16 +52,6 @@ CbmUnigenGenerator::CbmUnigenGenerator(const char* fileName, EMode mode, Double_
   , fFileName(fileName)
   , fMode(mode)
   , fPhi(phi)
-  , fIsInit(kFALSE)
-  , fFile(nullptr)
-  , fTree(nullptr)
-  , fCurrentEntry(-1)
-  , fEvent(new UEvent())
-  , fNofPrimaries(0)
-  , fNofEvents(0)
-  , fBetaCM(0.)
-  , fGammaCM(1.)
-  , fIonMap()
 {
   LOG(debug) << GetName() << ": Constructor";
   if (fileName[0] == '\0') return;
@@ -207,7 +186,8 @@ Bool_t CbmUnigenGenerator::Init()
     return kFALSE;
   }
   fTree->SetBranchAddress("event", &fEvent);
-  LOG(info) << GetName() << ": " << fTree->GetEntries() << " events in input tree";
+  fAvailableEvents = fTree->GetEntriesFast();
+  LOG(info) << GetName() << ": " << fAvailableEvents << " events in input tree";
 
   // --- Register ions found in the input file
   Int_t nIons = RegisterIons();
diff --git a/sim/transport/generators/CbmUnigenGenerator.h b/sim/transport/generators/CbmUnigenGenerator.h
index 8af033e84a..bd34df29df 100644
--- a/sim/transport/generators/CbmUnigenGenerator.h
+++ b/sim/transport/generators/CbmUnigenGenerator.h
@@ -19,9 +19,10 @@
 
 #include <map>
 
+#include "UEvent.h"
+
 class TFile;
 class TTree;
-class UEvent;
 class UParticle;
 class FairIon;
 class FairPrimaryGenerator;
@@ -93,21 +94,26 @@ public:
      **/
   virtual Bool_t ReadEvent(FairPrimaryGenerator* primGen);
 
+  /** @brief Get the maximum number of events available in the input file
+    ** @return number of available ebvents
+    */
+  Int_t GetNumAvailableEvents() { return fAvailableEvents; }
 
 private:
-  TString fFileName;                    ///< Input file name
-  EMode fMode;                          ///< Rotation mode
-  Double_t fPhi;                        ///< Event plane rotation angle
-  Bool_t fIsInit;                       ///< Flag whether generator is initialised
-  TFile* fFile;                         //!< Input ROOT file
-  TTree* fTree;                         //!< Input ROOT tree
-  Int_t fCurrentEntry;                  ///< Current entry number
-  UEvent* fEvent;                       //!< Current input event
-  Int_t fNofPrimaries;                  //!< Number of primaries registered in current event
-  Int_t fNofEvents;                     ///< Number of processed events
-  Double_t fBetaCM;                     ///< CM velocity in the lab frame
-  Double_t fGammaCM;                    ///< Gamma factor of CM in lab frame
-  std::map<TString, FairIon*> fIonMap;  //!< Map from ion name to FairIon
+  TString fFileName      = "";             ///< Input file name
+  EMode fMode            = kStandard;      ///< Rotation mode
+  Double_t fPhi          = 0.;             ///< Event plane rotation angle
+  Bool_t fIsInit         = kFALSE;         ///< Flag whether generator is initialised
+  TFile* fFile           = nullptr;        //!< Input ROOT file
+  TTree* fTree           = nullptr;        //!< Input ROOT tree
+  Int_t fCurrentEntry    = -1;             ///< Current entry number
+  UEvent* fEvent         = new UEvent();   //!< Current input event
+  Int_t fNofPrimaries    = 0;              //!< Number of primaries registered in current event
+  Int_t fNofEvents       = 0;              ///< Number of processed events
+  Double_t fBetaCM       = 0;              ///< CM velocity in the lab frame
+  Double_t fGammaCM      = 0;              ///< Gamma factor of CM in lab frame
+  Int_t fAvailableEvents = 0;              ///< Maximum number of events in the input file
+  std::map<TString, FairIon*> fIonMap {};  //!< Map from ion name to FairIon
 
   // Constants for decimal decomposition of ion PDG.
   // For ions the PDG code is +-10LZZZAAAI, with L = number of Lambdas,
@@ -204,7 +210,7 @@ private:
   CbmUnigenGenerator& operator=(const CbmUnigenGenerator&) = delete;
 
 
-  ClassDef(CbmUnigenGenerator, 4);
+  ClassDef(CbmUnigenGenerator, 5);
 };
 
 #endif
diff --git a/sim/transport/steer/CMakeLists.txt b/sim/transport/steer/CMakeLists.txt
index d119b821f1..2b4e797c65 100644
--- a/sim/transport/steer/CMakeLists.txt
+++ b/sim/transport/steer/CMakeLists.txt
@@ -31,6 +31,8 @@ ${CBMROOT_SOURCE_DIR}/sim
 ${CBMROOT_SOURCE_DIR}/sim/transport
 ${CBMROOT_SOURCE_DIR}/sim/transport/base
 ${CBMROOT_SOURCE_DIR}/sim/transport/generators
+${CBMROOT_SOURCE_DIR}/sim/transport/generators/unigen
+${CBMROOT_SOURCE_DIR}/sim/transport/generators/pluto
 ${CBMROOT_SOURCE_DIR}/sim/transport/steer
 ${CBMROOT_SOURCE_DIR}/sim/transport/geosetup
 ${CBMDATA_DIR}
diff --git a/sim/transport/steer/CbmTransport.cxx b/sim/transport/steer/CbmTransport.cxx
index 87676b0b8c..cb7bee6ab6 100644
--- a/sim/transport/steer/CbmTransport.cxx
+++ b/sim/transport/steer/CbmTransport.cxx
@@ -49,6 +49,7 @@
 
 #include <array>
 #include <cassert>
+#include <climits>
 #include <iostream>
 #include <sstream>
 #include <string>
@@ -468,6 +469,35 @@ void CbmTransport::PiAndEtaDecay(TVirtualMC* vmc)
 void CbmTransport::Run(Int_t nEvents)
 {
 
+  // Get the minimum number of events from all file based generators
+  // Set the number of events to process to this minimum number of events
+  Int_t numAvailEvents {0};
+  Int_t numMinAvailEvents {INT_MAX};
+  TObjArray* genList = fEventGen->GetListOfGenerators();
+  for (Int_t i = 0; i < genList->GetEntries(); i++) {
+    CbmUnigenGenerator* gen = dynamic_cast<CbmUnigenGenerator*>(genList->At(i));
+    if (gen) {
+      numAvailEvents = gen->GetNumAvailableEvents();
+      if (nEvents > numAvailEvents) {
+        if (numAvailEvents < numMinAvailEvents) { numMinAvailEvents = numAvailEvents; }
+      }
+    }
+    CbmPlutoGenerator* pgen = dynamic_cast<CbmPlutoGenerator*>(genList->At(i));
+    if (pgen) {
+      numAvailEvents = pgen->GetNumAvailableEvents();
+      if (nEvents > numAvailEvents) {
+        if (numAvailEvents < numMinAvailEvents) { numMinAvailEvents = numAvailEvents; }
+      }
+    }
+  }
+  if (nEvents > numMinAvailEvents) {
+    LOG(warning) << "";
+    LOG(warning) << "The number of requested events (" << nEvents << ") is larger than the number of available events ("
+                 << numMinAvailEvents << ")";
+    LOG(warning) << "Set the number of events to process to " << numMinAvailEvents;
+    LOG(warning) << "";
+  }
+
   // --- Timer
   TStopwatch timer;
 
@@ -525,7 +555,6 @@ void CbmTransport::Run(Int_t nEvents)
   // --- Initialise the event generator
   InitEventGenerator();
 
-
   // --- Trigger generation of run info
   fRun->SetGenerateRunInfo(fGenerateRunInfo);
 
-- 
GitLab