Skip to content
Snippets Groups Projects
CbmDaq.h 7.53 KiB
/* Copyright (C) 2012-2020 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
   SPDX-License-Identifier: GPL-3.0-only
   Authors: Volker Friese [committer] */

/** @file CbmDaq.h
 ** @author Volker Friese <v.friese@gsi.de>
 ** @date 20 July 2012
 **
 **/


#ifndef CBMDAQ_H
#define CBMDAQ_H 1

#include "CbmDefs.h"         // for ECbmModuleId
#include "CbmMCEventList.h"  // for CbmMCEventList

#include <FairTask.h>  // for FairTask, InitStatus

#include <Rtypes.h>      // for THashConsistencyHolder, ClassDef
#include <RtypesCore.h>  // for Int_t, Double_t, Bool_t, kFALSE, ULong64_t
#include <TStopwatch.h>  // for TStopwatch

#include <map>      // for map
#include <string>   // for string
#include <utility>  // for pair
class CbmDigi;
class CbmDigitizeBase;
class CbmTimeSlice;
class TClonesArray;


/** @class CbmDaq
 ** @author Volker Friese <v.friese@gsi.de>
 ** @date 20 July 2012
 ** @brief CBM task class for filling digis into time slices
 **
 ** The CbmDaq collects raw data (digis) from various input sources
 ** (detectors), sorts them w.r.t. time and fills time slices.
 ** The digis in one time slice are written to TCLonesArrays as branches of
 ** the output tree. One tree entry corresponds to one time slice (interval),
 ** the duration of which can be adjusted.
 **/
class CbmDaq : public FairTask {

 public:
  /** @brief Constructor
     ** @param eventMode  If true, run in event-by-event mode
     **
     ** By default, the DAQ will run in time-based mode with flexible
     ** time slices (all data into one time slice). To choose the
     ** event-by-event mode, set the argument to true; then,
     ** data will be grouped into events, one event per time slice.
     ** To select the regular mode with time slices of fixed duration,
     ** use the constructor with Double_t argument.
     **/
  CbmDaq(Bool_t eventMode = kFALSE);


  /** @brief Constructor for regular DAQ mode
     ** @param tslength  Duration of time slices [ns]
     **/
  CbmDaq(Double_t tsLength);


  /** @brief Destructor   **/
  ~CbmDaq();


  /** @brief Task execution **/
  virtual void Exec(Option_t* opt);


  /** @brief Initialisation **/
  virtual InitStatus Init();


  /** @brief Set the DAQ buffer latency
     ** @param time  Buffer latency [ns]
     **
     ** To decide when a time-slice can be closed (no more data in the
     ** time-slice interval will come), the DAQ takes into account
     ** a certain time-disordering of digis. The latency is the
     ** maximal time difference between the current (event) time
     ** and the time-stamp of the digi. It should
     ** at least be the maximum dead time of all detectors plus
     ** some safety margin accounting for the time resolution of the
     ** detectors.
     ** The latency is only changed if the latency passed as argument
     ** is larger than the current value to avoid that a call from
     ** a second digitizer lowers the latency set by a first digitizer.
     ** The current default of 2,000 ns corresponds to the STS with
     ** dead time of 800 ns and time resolution of 5 ns.
     **/
  void SetLatency(Double_t time)
  {
    if (time > fLatency) fLatency = time;
  }


  /** @brief Set the digitizer for a given system
     ** @param system  System Id (ECbmModuleId)
     ** @param digitizer  Pointer to digitizer instance
     **/
  void SetDigitizer(ECbmModuleId system, CbmDigitizeBase* digitizer);


  /** @brief Set the time-slice length
     ** @param length  Length of a time-slice [ns]
     **/
  void SetTimeSliceLength(Double_t length) { fTimeSliceLength = length; }


  /** @brief Store all time-slices
     ** @param choice If kTRUE; also empty slices will be stored.
     **
     ** By default, only time slices containing data are filled into the tree.
     **/
  void StoreAllTimeSlices(Bool_t choice = kTRUE) { fStoreEmptySlices = choice; }


 private:
  Bool_t fIsEventByEvent;       ///< Flag for event-by-event mode
  Double_t fTimeSliceLength;    ///< Time-slice length [ns]
  Double_t fLatency = 5000.;    ///< Maximal time disorder of input data [ns]
  Bool_t fStoreEmptySlices;     ///< Flag to store also empty time slices
  Double_t fTimeEventPrevious;  ///< Time of previous event [ns]

  Int_t fNofEvents;           ///< Number of processed events
  Int_t fNofDigis;            ///< Total number of processed digis
  Int_t fNofDigisIgnored;     ///< Number of ignored digis
  Int_t fNofTimeSlices;       ///< Number of time slices
  Int_t fNofTimeSlicesEmpty;  ///< Number of empty time slices
  Double_t fTimeDigiFirst;    ///< Time of first digi
  Double_t fTimeDigiLast;     ///< Time of last digi
  Double_t fTimeSliceFirst;   ///< Start time of first time slice
  Double_t fTimeSliceLast;    ///< Stop time of last time slice

  TStopwatch fTimer;                                     //! Stop watch
  std::map<ECbmModuleId, TClonesArray*> fDigis;          //! Output arrays (digis)
  std::map<ECbmModuleId, CbmDigitizeBase*> fDigitizers;  //!  Array of registered digitizers
  CbmTimeSlice* fTimeSlice;                              //! Current time slice
  CbmMCEventList fEventList;                             //!  MC event list (all)
  CbmMCEventList* fEventsCurrent;                        //! MC events for current time slice


  /** First and last event in current time slice for each input **/
  std::map<Int_t, std::pair<Int_t, Int_t>> fEventRange;  //!


  /** @brief Check the output arrays for being time-sorted
     ** @return kTRUE if all outputs are time-sorted
     **/
  Bool_t CheckOutput() const;


  /** Close the current time slice
     ** The current slice is filled to the tree. It is then reset
     ** to the next time slice interval.
     */
  void CloseTimeSlice();


  /** Copy the MC events contributing to the current time slice
     ** to the output array.
     **
     ** @return  Number of MC events for this time slice
     **/
  Int_t CopyEventList();


  /** @brief Copy data (digi) from the DaqBuffer into the output array
     ** @param digi  Pointer to digi object
     **/
  void FillData(CbmDigi* digi);
  //TODO: Obsolete, remove


  /** Move data from the buffer into the current time slice
     ** @param checkTime If true, data will be moved up to fillTime.
     ** @param fillTime  Time up to which data are moved
     ** @return Number of digis filled into the time slice
     **/
  ULong64_t FillTimeSlice(Bool_t timeLimit, Double_t fillTime = -1.);


  /** @brief Size of DAQ buffers
     ** @value Sum of number of data in all DAQ buffers
     **/
  ULong64_t GetBufferSize() const;


  /** @brief Debug output of DAQ buffer status
     ** @value String with status of DAQ buffers
     **/
  std::string GetBufferStatus(Bool_t verbose = kFALSE) const;


  /** @brief Time of first datum in DAQ buffers
     ** @value Minimum time stamp in all DAQ buffers
     **/
  Double_t GetBufferTimeFirst() const;


  /** @brief Time of last datum in DAQ buffers
     ** @value Maximum time stamp in all DAQ buffers
     **/
  Double_t GetBufferTimeLast() const;

  /** @brief Check for empty DAQ buffers
     ** @brief value True if all DAQ buffers are empty
     **/
  Bool_t IsDaqBufferEmpty() const;


  /** Screen log of the range of MC events contributing to the
     ** current time slice
     **/
  void PrintCurrentEventRange() const;


  /** @brief Start a new time slice in the output tree **/
  void StartNextTimeSlice();


  /** At end of run: Process the remaining data in the CbmDaqBuffer  **/
  virtual void Finish();


  /** Copy constructor and assignment operator are not allowed. **/
  CbmDaq(const CbmDaq&) = delete;
  CbmDaq& operator=(const CbmDaq&) = delete;

  ClassDef(CbmDaq, 4);
};

#endif /* CBMDAQ_H */