-
Administrator authored
Unify user names in the license header authors list. Remove duplicate users in the authors list. Cleanupo of some other inor issues.
Administrator authoredUnify user names in the license header authors list. Remove duplicate users in the authors list. Cleanupo of some other inor issues.
CbmReadoutBuffer.h 14.79 KiB
/* Copyright (C) 2015-2020 GSI Helmholtzzentrum fuer Schwerionenforschung, Darmstadt
SPDX-License-Identifier: GPL-3.0-only
Authors: Volker Friese [committer], Florian Uhlig */
/*
* CbmReadoutBuffer.h
*
* Created on: 26.05.2015
* Author: vfriese
*/
#ifndef CBMREADOUTBUFFER_H
#define CBMREADOUTBUFFER_H 1
#include <FairRootManager.h>
#include <FairWriteoutBuffer.h>
#include <Logger.h>
#include <TClonesArray.h>
#include <TObject.h>
#include <cassert>
#include <map>
#include <vector>
// The data class must implement the methods Double_t GetTimeStart(),
// Double_t GetTimeStop(), and void SetTimeStop(Double_t),
// as well as a copy constructor (default one is fine).
// Data must inherit from TObject.
template<class Data>
class CbmReadoutBuffer : public FairWriteoutBuffer {
public:
// ---------------------------------------------------------------------
/** Default constructor
**
** No output TClonesArray will be present. The buffered data have to
** be fetched through ReadOutData.
**/
CbmReadoutBuffer() : FairWriteoutBuffer(), fBuffer(), fBufferIt(), fOldIt(), fArray(nullptr), fWriteToArray(kFALSE) {}
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
/** Constructor with branch and folder name
** @param branchName Name of branch in output tree
** @param folderName No idea what this is good for
** @param persistence If kTRUE (default), the branch will appear in the output file.
**
** If this constructor is used, a branch with a TClonesArray will be created. Data
** from the buffer will be copied to this array. Note that in this case,
** ReadOutData will deliver no data (for the same readout time), since the
** buffered data are deleted after being copied to the array.
**/
CbmReadoutBuffer(TString branchName, TString folderName, Bool_t persistence = kTRUE)
: FairWriteoutBuffer()
, fBuffer()
, fBufferIt()
, fOldIt()
, fArray(nullptr)
, fWriteToArray(kTRUE)
{
if (FairRootManager::Instance()) {
Data* data = new Data();
const char* className = data->ClassName();
delete data;
LOG(info) << "Class name is " << className;
fArray = FairRootManager::Instance()->Register(branchName, className, folderName, persistence);
}
}
// ---------------------------------------------------------------------
CbmReadoutBuffer(const CbmReadoutBuffer&) = delete;
CbmReadoutBuffer& operator=(const CbmReadoutBuffer&) = delete;
// ---------------------------------------------------------------------
/** Destructor
**
** Cleans up remaining data in the buffer, if present, which should not
** be the case if used properly.
**/
virtual ~CbmReadoutBuffer()
{
if (fBuffer.size()) LOG(warn) << "Destroying non-empty readout buffer! Number of data: " << fBuffer.size();
for (fBufferIt = fBuffer.begin(); fBufferIt != fBuffer.end(); fBufferIt++)
if (fBufferIt->second) delete fBufferIt->second;
}
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
/** Adding data to the TClonesArray
** Abstract method from FairWriteoutBuffer; not needed in this
** template implementation.
**/
virtual void AddNewDataToTClonesArray(FairTimeStamp* /*data*/) {}
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
/** Check data for consistency
** (stop time should be larger than start time)
** @param data Data object
** @value kTRUE is stop time is later than start time.
**/
Bool_t CheckData(Data* data) { return (data->GetTimeStop() >= data->GetTimeStart()); }
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
/** Check interference of two data objects
** @param data1,data2 Data objects
** @value kTRUE if objects interfere
**
** Interference is present if the temporal extension of the objects
** overlap.
**/
Bool_t CheckInterference(Data* data1, Data* data2)
{
if (data1->GetTimeStop() < data2->GetTimeStart()) return kFALSE;
if (data2->GetTimeStop() < data1->GetTimeStart()) return kFALSE;
return kTRUE;
}
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
/** Clear the output TClonesArray
** Called at the end of the event from FairRootManager
**/
virtual void DeleteOldData()
{
if (fArray) fArray->Delete();
}
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
/** Erase data from data map
** Abstract method from FairWriteoutBuffer; not needed in this
** template implementation.
**/
virtual void EraseDataFromDataMap(FairTimeStamp*) {}
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
/** Fill data into the buffer
** @param address Unique address
** @param data Pointer to data object
**
** If, for the same address, other data are present in the buffer,
** the time intervals of old and new data will be compared.
** If there is no time overlap with already present data, the new data will
** be inserted into the buffer. Otherwise, the method Modify is called
** and the resulting, modified data are inserted into the buffer.
**/
void Fill(UInt_t address, Data* data)
{
LOG(debug4) << "RO: Filling data at t = " << data->GetTimeStart() << " in address " << address;
// --- Check data for consistency (start/stop time)
if (!CheckData(data)) {
LOG(fatal) << GetName() << ": inconsistent data input to Fill(). "
<< "Start time is " << data->GetTimeStart() << " stop time is " << data->GetTimeStop();
}
// --- Loop over all present data with same address
// --- Pick the first to which the interference criterion applies.
Bool_t dataFound = kFALSE;
for (fBufferIt = fBuffer.lower_bound(address); fBufferIt != fBuffer.upper_bound(address); fBufferIt++) {
// --- Check interference of buffer data with old data. If so, jump
// --- out of loop
if (CheckInterference(data, fBufferIt->second)) {
dataFound = kTRUE;
break;
} //? Interference
} //# Data at same address
// --- Action of interfering data found in the buffer
if (dataFound) {
// --- Call Modify method
std::vector<Data*> newDataList;
Merge(fBufferIt->second, data, newDataList);
// --- Check return data list for non-interference
// --- Modify has to be implemented in such as way as to return a
// --- list (vector) of non-interfering data objects. This is
// --- checked here to prevent unwanted behaviour
// --- (e.g., endless loops).
Int_t nData = newDataList.size();
for (Int_t iData1 = 0; iData1 < nData; iData1++) {
for (Int_t iData2 = iData1 + 1; iData2 < nData; iData2++) {
if (CheckInterference(newDataList[iData1], newDataList[iData2]))
LOG(fatal) << GetName() << ": Interfering data in return from Modify! "
<< "Data 1: t(start) = " << newDataList[iData1]->GetTimeStart()
<< " ns, t(stop) = " << newDataList[iData1]->GetTimeStop()
<< ", Data 2: t(start) = " << newDataList[iData2]->GetTimeStart()
<< " ns, t(stop) = " << newDataList[iData2]->GetTimeStop();
} //# data in vector (second loop)
} //# data in vector (first loop)
// --- Remove old data from buffer and delete added data object
if (fBufferIt->second) delete fBufferIt->second;
fBuffer.erase(fBufferIt);
delete data;
// --- Fill new data to buffer, still checking for existing ones
for (UInt_t iData = 0; iData < newDataList.size(); iData++) {
LOG(debug4) << "RO: Filling modified data at address " << address
<< ", t = " << newDataList[iData]->GetTimeStart() << " to " << newDataList[iData]->GetTimeStop();
Fill(address, newDataList[iData]);
} //# result data of Modify
} //? Interfering data
// --- No interference; just insert data into buffer
else {
fBuffer.insert(std::pair<UInt_t, Data*>(address, data));
LOG(debug4) << "RO: Insert data at address " << address << ", t = " << data->GetTimeStart() << " to "
<< data->GetTimeStop();
} //? No interference
}
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
/** Fill data map
** Abstract method from FairWriteoutBuffer; not needed in this
** template implementation.
**/
virtual void FillDataMap(FairTimeStamp*, double /*activeTime*/) {}
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
/** Active time for a given data object
** Abstract method from FairWriteoutBuffer; not needed in this
** template implementation.
**/
virtual double FindTimeForData(FairTimeStamp*) { return -1.; }
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
/** Number of data in the buffer
** @return Number of data objects in buffer
**/
virtual Int_t GetNData() { return fBuffer.size(); }
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
virtual Int_t Merge(Data* oldData1, Data* oldData2, std::vector<Data*>& newDataList)
{
// Default prescription: return earlier data, skip the later one,
// but set the stop time of the result to the maximum of the
// two stop times
Data* firstData = (oldData1->GetTimeStart() < oldData2->GetTimeStart() ? oldData1 : oldData2);
Double_t stopTime = std::max(oldData1->GetTimeStop(), oldData2->GetTimeStop());
// Create new data object
Data* newData = new Data(*firstData);
newData->SetTimeStop(stopTime);
// Add new data object to the result list
newDataList.push_back(newData);
return 1; // Number of return data objects
}
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
/** Write out all data in the buffer to the TClonesArray
**
** All buffer data, irrespective of time, will be copied
** to the output array and deleted from the buffer.
** Called from Framework (FairRootManager)
*/
virtual void WriteOutAllData() { WriteOutData(-1.); }
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
/** Read out data from the buffer
** @param[in] time Readout time. If < 0, all data will be read out.
** @param[out] dataList Vector with pointers to data objects
** @value Number of data objects read out
**
** Data interface alternative to the TClonesArray. Data from the buffer
** with stop time before the specified readout time will be delivered
** and removed from the buffer.
** The object ownership is passed to the consumer, who is responsible
** for destroying the data objects in the data vector.
**/
Int_t ReadOutData(Double_t time, std::vector<Data*>& dataList)
{
LOG(debug) << "RO Buffer: read out at t = " << time << ", buffer size " << fBuffer.size();
if (!dataList.empty()) dataList.clear();
Int_t nData = 0;
fBufferIt = fBuffer.begin();
while (fBufferIt != fBuffer.end()) {
UInt_t address = fBufferIt->first;
Data* data = fBufferIt->second;
LOG(debug4) << "Buffer entry: " << address << " " << data->GetTimeStart();
// --- Assert valid data object
assert(data);
// --- Skip if stop time after readout time
if (time >= 0. && data->GetTimeStop() > time) {
fBufferIt++;
continue;
}
// --- Fill output vector with data pointers
LOG(debug4) << "RO: read out data at t = " << data->GetTimeStart();
dataList.push_back(data);
// --- Remove element from buffer
fOldIt = fBufferIt;
fBufferIt++;
fBuffer.erase(fOldIt);
nData++;
} //# elements in buffer
return nData;
}
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
/** Write out data to the TClonesArray
** @param time Readout time. If < 0, all data will be written out.
**
** All data with stop time before the readout time will be copied
** to the output array and deleted from the buffer.
** Called from Framework (FairRootManager).
** Note that this method has no effect if fWriteToArray is kFALSE,
** which is the default.
**/
virtual void WriteOutData(Double_t time)
{
if (!fWriteToArray) return;
LOG(info) << "RO Buffer: write out at t = " << time << ", buffer size " << fBuffer.size() << ", array size "
<< fArray->GetEntriesFast();
Int_t nDataWritten = 0;
fBufferIt = fBuffer.begin();
while (fBufferIt != fBuffer.end()) {
UInt_t address = fBufferIt->first;
Data* data = fBufferIt->second;
LOG(debug4) << "Buffer entry: " << address << " " << data->GetTimeStart();
// --- Assert valid data object
assert(data);
// --- Skip if stop time after readout time
if (time >= 0. && data->GetTimeStop() > time) {
fBufferIt++;
continue;
}
// --- Copy data to TClonesArray
if (fArray) {
LOG(debug4) << "RO: Writing to array: t = " << data->GetTimeStart();
new ((*fArray)[fArray->GetEntriesFast()]) Data(*data);
}
// --- Delete data and remove element from buffer
delete data;
fOldIt = fBufferIt;
fBufferIt++;
fBuffer.erase(fOldIt);
nDataWritten++;
} //# buffer elements
LOG(info) << "RO Buffer: wrote " << nDataWritten << " data, buffer size " << fBuffer.size() << ", array size "
<< fArray->GetEntriesFast();
}
// ---------------------------------------------------------------------
protected:
std::multimap<UInt_t, Data*> fBuffer; //!
typename std::multimap<UInt_t, Data*>::iterator fBufferIt; //!
typename std::multimap<UInt_t, Data*>::iterator fOldIt; //!
TClonesArray* fArray; //!
Bool_t fWriteToArray;
};
#endif /* CBMREADOUTBUFFER_H_ */