Skip to content

Commit f90ac54

Browse files
mfasDashahor02
authored andcommitted
[EMCAL-610] Implementation of the raw encoder for EMCAL
1 parent 27a0e00 commit f90ac54

4 files changed

Lines changed: 333 additions & 2 deletions

File tree

Detectors/EMCAL/simulation/CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@
1111
o2_add_library(EMCALSimulation
1212
SOURCES src/Detector.cxx src/Digitizer.cxx src/DigitizerTask.cxx
1313
src/SpaceFrame.cxx src/SimParam.cxx src/LabeledDigit.cxx
14-
src/DMAOutputStream.cxx
15-
PUBLIC_LINK_LIBRARIES O2::EMCALBase O2::DetectorsBase O2::SimConfig O2::SimulationDataFormat)
14+
src/RawWriter.cxx src/DMAOutputStream.cxx
15+
PUBLIC_LINK_LIBRARIES O2::EMCALBase O2::DetectorsBase O2::SimConfig O2::SimulationDataFormat O2::Headers)
1616

1717
o2_target_root_dictionary(EMCALSimulation
1818
HEADERS include/EMCALSimulation/Detector.h
1919
include/EMCALSimulation/Digitizer.h
2020
include/EMCALSimulation/DigitizerTask.h
21+
include/EMCALSimulation/RawWriter.h
2122
include/EMCALSimulation/DMAOutputStream.h
2223
include/EMCALSimulation/SpaceFrame.h
2324
include/EMCALSimulation/SimParam.h
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Copyright CERN and copyright holders of ALICE O2. This software is
2+
// distributed under the terms of the GNU General Public License v3 (GPL
3+
// Version 3), copied verbatim in the file "COPYING".
4+
//
5+
// See http://alice-o2.web.cern.ch/license for full licensing information.
6+
//
7+
// In applying this license CERN does not waive the privileges and immunities
8+
// granted to it by virtue of its status as an Intergovernmental Organization
9+
// or submit itself to any jurisdiction.
10+
11+
#ifndef ALICEO2_EMCAL_RAWWRITER_H
12+
#define ALICEO2_EMCAL_RAWWRITER_H
13+
14+
#include <array>
15+
#include <fstream>
16+
#include <memory>
17+
#include <string>
18+
#include <map>
19+
#include <vector>
20+
21+
#include "Rtypes.h"
22+
23+
#include "EMCALBase/Mapper.h"
24+
#include "EMCALSimulation/DMAOutputStream.h"
25+
#include "DataFormatsEMCAL/Digit.h"
26+
#include "DataFormatsEMCAL/TriggerRecord.h"
27+
28+
namespace o2
29+
{
30+
31+
namespace emcal
32+
{
33+
34+
class Geometry;
35+
36+
struct AltroBunch {
37+
int mStarttime;
38+
std::vector<int> mADCs;
39+
};
40+
41+
struct ChannelData {
42+
int mRow;
43+
int mCol;
44+
std::vector<o2::emcal::Digit*> mDigits;
45+
};
46+
47+
struct SRUDigitContainer {
48+
int mSRUid;
49+
std::map<int, ChannelData> mChannels;
50+
};
51+
52+
union ChannelHeader {
53+
uint32_t mDataWord;
54+
struct {
55+
uint32_t mHardwareAddress : 16; ///< Bits 0 - 15: Hardware address
56+
uint32_t mPayloadSize : 10; ///< Bits 16 - 25: Payload size
57+
uint32_t mZero1 : 3; ///< Bits 26 - 28: zeroed
58+
uint32_t mBadChannel : 1; ///< Bit 29: Bad channel status
59+
uint32_t mZero2 : 2; ///< Bits 30 - 31: zeroed
60+
};
61+
};
62+
63+
union CaloBunchWord {
64+
uint32_t mDataWord;
65+
struct {
66+
uint32_t mWord2 : 10; ///< Bits 0 - 9 : Word 2
67+
uint32_t mWord1 : 10; ///< Bits 10 - 19 : Word 1
68+
uint32_t mWord0 : 10; ///< Bits 20 - 29 : Word 0
69+
uint32_t mZero : 2; ///< Bits 30 - 31 : zeroed
70+
};
71+
};
72+
73+
class RawWriter
74+
{
75+
public:
76+
RawWriter() = default;
77+
RawWriter(const char* rawfilename) { setRawFileName(rawfilename); }
78+
~RawWriter() = default;
79+
80+
void setRawFileName(const char* filename) { mOutputStream.setOutputFilename(filename); }
81+
void setDigits(std::vector<o2::emcal::Digit>* digits) { mDigits = digits; }
82+
void setTriggerRecords(std::vector<o2::emcal::TriggerRecord>* triggers);
83+
void setNumberOfADCSamples(int nsamples) { mNADCSamples = nsamples; }
84+
void setPedestal(int pedestal) { mPedestal = pedestal; }
85+
void setGeometry(o2::emcal::Geometry* geo) { mGeometry = geo; }
86+
87+
bool hasNextTrigger() const { return mCurrentTrigger != mTriggers->end(); }
88+
89+
void init();
90+
void process();
91+
void processNextTrigger();
92+
93+
protected:
94+
std::vector<AltroBunch> findBunches(const std::vector<o2::emcal::Digit*>& channelDigits);
95+
std::tuple<int, int, int> getOnlineID(int towerID);
96+
97+
ChannelHeader createChannelHeader(int hardwareAddress, int payloadSize, bool isBadChannel);
98+
std::vector<char> createRCUTrailer();
99+
std::vector<int> encodeBunchData(const std::vector<int>& data);
100+
101+
private:
102+
DMAOutputStream mOutputStream; ///< DMA output stream
103+
int mNADCSamples = 15; ///< Number of time samples
104+
int mPedestal = 0; ///< Pedestal
105+
o2::emcal::Geometry* mGeometry = nullptr; ///< EMCAL geometry
106+
std::array<o2::emcal::Mapper, 4> mMappers; ///< EMCAL mappers
107+
std::vector<o2::emcal::Digit>* mDigits; ///< Digits input vector - must be in digitized format including the time response
108+
std::vector<o2::emcal::TriggerRecord>* mTriggers; ///< Trigger records, separating the data from different triggers
109+
std::vector<SRUDigitContainer> mSRUdata; ///< Internal helper of digits assigned to SRUs
110+
std::vector<o2::emcal::TriggerRecord>::iterator mCurrentTrigger; ///< Current trigger in the trigger records
111+
112+
ClassDefNV(RawWriter, 1);
113+
};
114+
115+
} // namespace emcal
116+
117+
} // namespace o2
118+
119+
#endif

Detectors/EMCAL/simulation/src/EMCALSimulationLinkDef.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
#pragma link C++ class o2::emcal::DMAOutputStream + ;
2222
#pragma link C++ class o2::emcal::SimParam + ;
2323
#pragma link C++ class o2::emcal::LabeledDigit + ;
24+
#pragma link C++ class o2::emcal::RawWriter + ;
25+
#pragma link C++ class o2::emcal::DMAOutputStream + ;
2426

2527
#pragma link C++ class std::list < o2::emcal::LabeledDigit > +;
2628

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
// Copyright CERN and copyright holders of ALICE O2. This software is
2+
// distributed under the terms of the GNU General Public License v3 (GPL
3+
// Version 3), copied verbatim in the file "COPYING".
4+
//
5+
// See http://alice-o2.web.cern.ch/license for full licensing information.
6+
//
7+
// In applying this license CERN does not waive the privileges and immunities
8+
// granted to it by virtue of its status as an Intergovernmental Organization
9+
// or submit itself to any jurisdiction.
10+
11+
#include <gsl/span>
12+
#include <TSystem.h>
13+
#include "DataFormatsEMCAL/Constants.h"
14+
#include "EMCALBase/Geometry.h"
15+
#include "EMCALSimulation/RawWriter.h"
16+
#include "Headers/RAWDataHeader.h"
17+
18+
using namespace o2::emcal;
19+
20+
void RawWriter::setTriggerRecords(std::vector<o2::emcal::TriggerRecord>* triggers)
21+
{
22+
mTriggers = triggers;
23+
mCurrentTrigger = triggers->begin();
24+
}
25+
26+
void RawWriter::init()
27+
{
28+
mOutputStream.open();
29+
30+
// initialize mappers
31+
std::array<char, 4> sides = {{'A', 'C'}};
32+
for (auto iside = 0; iside < sides.size(); iside++) {
33+
for (auto isru = 0; isru < 20; isru++) {
34+
mMappers[iside * 2 + isru].setMapping(Form("%s/share/Detectors/EMC/file/RCU%d%c.data", gSystem->Getenv("O2_ROOT"), isru, sides[iside]));
35+
}
36+
}
37+
38+
// initialize containers for SRU
39+
for (auto isru = 0; isru < 40; isru++) {
40+
SRUDigitContainer srucont;
41+
srucont.mSRUid = isru;
42+
mSRUdata.push_back(srucont);
43+
}
44+
}
45+
46+
void RawWriter::processNextTrigger()
47+
{
48+
for (auto srucont : mSRUdata)
49+
srucont.mChannels.clear();
50+
std::vector<o2::emcal::Digit*>* bunchDigits;
51+
int lasttower = -1;
52+
for (auto& dig : gsl::span(&mDigits->data()[mCurrentTrigger->getFirstEntry()], mCurrentTrigger->getNumberOfObjects())) {
53+
auto tower = dig.getTower();
54+
if (tower != lasttower) {
55+
lasttower = tower;
56+
auto onlineindices = getOnlineID(tower);
57+
int sruID = std::get<0>(onlineindices);
58+
auto towerdata = mSRUdata[sruID].mChannels.find(tower);
59+
if (towerdata == mSRUdata[sruID].mChannels.end()) {
60+
mSRUdata[sruID].mChannels[tower] = {std::get<1>(onlineindices), std::get<2>(onlineindices), std::vector<o2::emcal::Digit*>(mNADCSamples)};
61+
bunchDigits = &(mSRUdata[sruID].mChannels[tower].mDigits);
62+
memset(bunchDigits->data(), 0, sizeof(o2::emcal::Digit*) * mNADCSamples);
63+
} else {
64+
bunchDigits = &(towerdata->second.mDigits);
65+
}
66+
(*bunchDigits)[int(dig.getTimeStamp())] = &dig;
67+
}
68+
}
69+
70+
// Create and fill DMA pages for each channel
71+
std::vector<char> payload;
72+
for (auto srucont : mSRUdata) {
73+
o2::header::RAWDataHeaderV4 rawheader;
74+
rawheader.triggerBC = mCurrentTrigger->getBCData().bc;
75+
rawheader.triggerOrbit = mCurrentTrigger->getBCData().orbit;
76+
// @TODO: Set trigger type
77+
rawheader.feeId = srucont.mSRUid;
78+
79+
for (const auto& [tower, channel] : srucont.mChannels) {
80+
// Find out hardware address of the channel
81+
auto hwaddress = mMappers[srucont.mSRUid].getHardwareAddress(channel.mRow, channel.mCol, ChannelType_t::HIGH_GAIN); // @TODO distinguish between high- and low-gain cells
82+
83+
std::vector<int> rawbunches;
84+
for (auto& bunch : findBunches(channel.mDigits)) {
85+
rawbunches.push_back(bunch.mStarttime);
86+
rawbunches.push_back(bunch.mADCs.size());
87+
for (auto adc : bunch.mADCs) {
88+
rawbunches.push_back(adc);
89+
}
90+
}
91+
auto encodedbunches = encodeBunchData(rawbunches);
92+
auto chanhead = createChannelHeader(hwaddress, encodedbunches.size() * 3 - 2, false); /// bad channel status eventually to be added later
93+
char* chanheadwords = reinterpret_cast<char*>(&chanhead);
94+
for (int iword = 0; iword < sizeof(ChannelHeader) / sizeof(char); iword++) {
95+
payload.emplace_back(chanheadwords[iword]);
96+
}
97+
char* channelwords = reinterpret_cast<char*>(encodedbunches.data());
98+
for (auto iword = 0; iword < encodedbunches.size() * sizeof(int) / sizeof(char); iword++) {
99+
payload.emplace_back(channelwords[iword]);
100+
}
101+
}
102+
103+
// Create RCU trailer
104+
auto trailerwords = createRCUTrailer();
105+
for (auto word : trailerwords)
106+
payload.emplace_back(word);
107+
108+
// write DMA page to stream
109+
mOutputStream.writeData(rawheader, payload);
110+
}
111+
}
112+
113+
std::vector<AltroBunch> RawWriter::findBunches(const std::vector<o2::emcal::Digit*>& channelDigits)
114+
{
115+
std::vector<AltroBunch> result;
116+
AltroBunch* currentBunch = nullptr;
117+
int starttime = 0;
118+
for (auto ien = channelDigits.size() - 1;; ien--) {
119+
auto dig = channelDigits[ien];
120+
if (!dig) {
121+
starttime++;
122+
continue;
123+
}
124+
int adc = dig->getEnergy() / constants::EMCAL_ADCENERGY; /// conversion Energy <-> ADC := 16 MeV/ADC
125+
if (adc < mPedestal) {
126+
// Stop bunch
127+
currentBunch = nullptr;
128+
starttime++;
129+
continue;
130+
}
131+
if (!currentBunch) {
132+
// start new bunch
133+
AltroBunch bunch;
134+
bunch.mStarttime = starttime;
135+
result.push_back(bunch);
136+
currentBunch = &(result.back());
137+
}
138+
currentBunch->mADCs.emplace_back(adc);
139+
starttime++;
140+
}
141+
return result;
142+
}
143+
144+
std::tuple<int, int, int> RawWriter::getOnlineID(int towerID)
145+
{
146+
auto cellindex = mGeometry->GetCellIndex(towerID);
147+
auto supermoduleID = std::get<0>(cellindex);
148+
auto etaphi = mGeometry->GetCellPhiEtaIndexInSModule(supermoduleID, std::get<1>(cellindex), std::get<2>(cellindex), std::get<3>(cellindex));
149+
auto etaphishift = mGeometry->ShiftOfflineToOnlineCellIndexes(supermoduleID, std::get<0>(etaphi), std::get<1>(etaphi));
150+
int row = std::get<0>(etaphishift), col = std::get<1>(etaphishift);
151+
152+
int sruID = -1;
153+
if (0 <= row && row < 8)
154+
sruID = 0; // first cable row
155+
else if (8 <= row && row < 16 && 0 <= col && col < 24)
156+
sruID = 0; // first half;
157+
else if (8 <= row && row < 16 && 24 <= col && col < 48)
158+
sruID = 1; // second half;
159+
else if (16 <= row && row < 24)
160+
sruID = 1; // third cable row
161+
if (supermoduleID % 2 == 1)
162+
sruID = 1 - sruID; // swap for odd=C side, to allow us to cable both sides the same
163+
164+
return std::make_tuple(sruID, row, col);
165+
}
166+
167+
std::vector<int> RawWriter::encodeBunchData(const std::vector<int>& data)
168+
{
169+
std::vector<int> encoded;
170+
CaloBunchWord currentword;
171+
int wordnumber = 0;
172+
for (auto adc : data) {
173+
switch (wordnumber) {
174+
case 0:
175+
currentword.mWord0 = adc;
176+
break;
177+
case 1:
178+
currentword.mWord1 = adc;
179+
break;
180+
case 2:
181+
currentword.mWord2 = adc;
182+
break;
183+
};
184+
if (wordnumber == 2) {
185+
// start new word;
186+
encoded.push_back(currentword.mDataWord);
187+
currentword.mDataWord = 0;
188+
wordnumber = 0;
189+
} else {
190+
wordnumber++;
191+
}
192+
}
193+
return encoded;
194+
}
195+
196+
ChannelHeader RawWriter::createChannelHeader(int hardwareAddress, int payloadSize, bool isBadChannel)
197+
{
198+
ChannelHeader header;
199+
header.mHardwareAddress = hardwareAddress;
200+
header.mPayloadSize = payloadSize;
201+
header.mBadChannel = isBadChannel ? 1 : 0;
202+
return header;
203+
}
204+
205+
std::vector<char> RawWriter::createRCUTrailer()
206+
{
207+
std::vector<char> trailerwords;
208+
return trailerwords;
209+
}

0 commit comments

Comments
 (0)