Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Detectors/EMCAL/workflow/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@ o2_add_library(EMCALWorkflow
src/RawToCellConverterSpec.cxx
src/EntropyEncoderSpec.cxx
src/EntropyDecoderSpec.cxx
src/StandaloneAODProducerSpec.cxx
PUBLIC_LINK_LIBRARIES O2::Framework O2::DataFormatsEMCAL O2::EMCALSimulation O2::Steer
O2::DPLUtils O2::EMCALBase O2::EMCALReconstruction O2::Algorithm)
O2::DPLUtils O2::EMCALBase O2::EMCALReconstruction O2::Algorithm O2::MathUtils)

o2_add_executable(reco-workflow
COMPONENT_NAME emcal
Expand Down Expand Up @@ -51,3 +52,7 @@ o2_add_executable(cell-writer-workflow
COMPONENT_NAME emcal
SOURCES src/cell-writer-workflow.cxx
PUBLIC_LINK_LIBRARIES O2::EMCALWorkflow)
o2_add_executable(standalone-aod-producer-workflow
COMPONENT_NAME emcal
SOURCES src/standalone-aod-producer-workflow.cxx
PUBLIC_LINK_LIBRARIES O2::EMCALWorkflow)
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

/// @file StandaloneAODProducerSpec.h
/// @brief Convert CTF (EncodedBlocks) to AO2D EMCal standalone

#ifndef O2_EMCAL_STANDALONEAODPRODUCERSPEC_SPEC
#define O2_EMCAL_STANDALONEAODPRODUCERSPEC_SPEC

#include "Framework/AnalysisDataModel.h"
#include "Framework/AnalysisHelpers.h"
#include "Framework/DataProcessorSpec.h"
#include "Framework/Task.h"
#include "DataFormatsEMCAL/EventHandler.h"
#include <TStopwatch.h>

namespace o2
{
namespace emcal
{

class StandaloneAODProducerSpec : public o2::framework::Task
{
public:
StandaloneAODProducerSpec();
~StandaloneAODProducerSpec() override = default;
void run(o2::framework::ProcessingContext& pc) final;
void init(o2::framework::InitContext& ic) final;
void endOfStream(o2::framework::EndOfStreamContext& ec) final;

static const char* getCellBinding() { return "EMCCells"; }
static const char* getCellTriggerRecordBinding() { return "EMCCellsTrgR"; }

private:
int64_t mTFNumber = -1; // Timeframe ID
int mRunNumber = -1; // Run number
uint32_t mCaloAmp = 0xFFFFFF00; // 15 bits
uint32_t mCaloTime = 0xFFFFFF00; // 15 bits
o2::emcal::EventHandler<o2::emcal::Cell>* mCaloEventHandler = nullptr; ///< Pointer to the event builder for emcal cells
TStopwatch mTimer;

static const char* BININGCELLS;
static const char* BINDINGCELLSTRG;
Comment on lines +50 to +51
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer needed.

};

/// create a processor spec
framework::DataProcessorSpec getStandaloneAODProducerSpec();

} // namespace emcal
} // namespace o2

#endif
171 changes: 171 additions & 0 deletions Detectors/EMCAL/workflow/src/StandaloneAODProducerSpec.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

#include "EMCALWorkflow/StandaloneAODProducerSpec.h"
#include "Framework/TableBuilder.h"
#include "Framework/AnalysisDataModel.h"
#include "Framework/ConfigParamRegistry.h"
#include "Framework/DataTypes.h"
#include "Framework/InputRecordWalker.h"
#include "Framework/Logger.h"
#include "Framework/TableBuilder.h"
#include "Framework/TableTreeHelpers.h"
#include "MathUtils/Utils.h"

using namespace o2::framework;

namespace o2
{
namespace emcal
{

StandaloneAODProducerSpec::StandaloneAODProducerSpec()
{
mTimer.Stop();
mTimer.Reset();
}

void StandaloneAODProducerSpec::init(o2::framework::InitContext& ic)
{
mCaloEventHandler = new o2::emcal::EventHandler<o2::emcal::Cell>();
mCaloAmp = 0xFFFFFFFF;
mCaloTime = 0xFFFFFFFF;

mTFNumber = ic.options().get<int64_t>("aod-timeframe-id");
mRunNumber = ic.options().get<int>("run-number");
}

void StandaloneAODProducerSpec::run(ProcessingContext& pc)
{
auto cput = mTimer.CpuTime();
mTimer.Start(false);

const auto* dh = o2::header::get<o2::header::DataHeader*>(pc.inputs().getFirstValid(true).header);
uint64_t tfNumber;
if (mTFNumber == -1L) {
// TODO has to be made globally unique (by using absolute time of TF). For now is unique within the run
tfNumber = uint64_t(dh->firstTForbit) + (uint64_t(dh->runNumber) << 32); // getTFNumber(mStartIR, runNumber);
} else {
tfNumber = mTFNumber;
}
const int runNumber = (mRunNumber == -1) ? int(dh->runNumber) : mRunNumber;

auto cellsIn = pc.inputs().get<gsl::span<o2::emcal::Cell>>(getCellBinding());
auto triggersIn = pc.inputs().get<gsl::span<o2::emcal::TriggerRecord>>(getCellTriggerRecordBinding());

LOG(INFO) << "FOUND " << cellsIn.size() << " EMC cells in CTF";
LOG(INFO) << "FOUND " << triggersIn.size() << " EMC tiggers in CTF";

auto& bcBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "BC"});
auto& collisionsBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "COLLISION"});
auto& caloCellsBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "CALO"});
auto& caloCellsTRGTableBuilder = pc.outputs().make<TableBuilder>(Output{"AOD", "CALOTRIGGER"});

auto bcCursor = bcBuilder.cursor<o2::aod::BCs>();
auto collisionsCursor = collisionsBuilder.cursor<o2::aod::Collisions>();
auto caloCellsCursor = caloCellsBuilder.cursor<o2::aod::Calos>();
auto caloCellsTRGTableCursor = caloCellsTRGTableBuilder.cursor<o2::aod::CaloTriggers>();

// build event for easier handling
mCaloEventHandler->reset();
mCaloEventHandler->setCellData(cellsIn, triggersIn);

uint64_t triggerMask = 1;
// loop over events
for (int iev = 0; iev < mCaloEventHandler->getNumberOfEvents(); iev++) {
o2::emcal::EventData inputEvent = mCaloEventHandler->buildEvent(iev);
auto cellsInEvent = inputEvent.mCells; // get cells belonging to current event
auto interactionRecord = inputEvent.mInteractionRecord; // get interaction records belonging to current event

LOG(INFO) << "Found " << cellsInEvent.size() << " cells in event";

auto bcID = interactionRecord.toLong();
Copy link
Collaborator

@jgrosseo jgrosseo Nov 18, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wrong. You have to fill into the tables the tree entry of the BC entry in the BC tree. You get this with bcCursor.lastIndex() after filling the respective BC entry.
So you need a loop over BCs, you cannot fill first one, then the other (unless you know which ones you fill and you do not reorder as you do below)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bcCursor is a lambda function, lastIndex() doesn't exist. Can't we just take a running index (i.e. iev) that we increment per event/bc in the loop?

bcCursor(0,
runNumber,
bcID,
triggerMask);
auto indexBC = iev;

for (auto& cell : cellsInEvent) {

// fill table
caloCellsCursor(0,
indexBC,
cell.getTower(),
o2::math_utils::detail::truncateFloatFraction(cell.getAmplitude(), mCaloAmp),
o2::math_utils::detail::truncateFloatFraction(cell.getTimeStamp(), mCaloTime),
cell.getType(),
1); // hard coded for emcal (-1 would be undefined, 0 phos)
} // end of cell loop

// filled only with BCID, rest dummy for no2
caloCellsTRGTableCursor(0,
indexBC,
0, // fastOrAbsId (dummy value)
0., // lnAmplitude (dummy value)
0, // triggerBits (dummy value)
1); // caloType (dummy value)

// fill collision cursor
collisionsCursor(0,
indexBC,
0., // X-Pos dummy value
0., // Y Pos
0., // Z Pos
0, // cov 0
0, // cov 1
0, // cov 2
0, // cov 3
0, // cov 4
0, // cov 5
0, // vertex bit field for flags
0, // chi2
0, // ncontributors
0, // rel interaction time
0); // vertex time stamp

} // end of event loop
// std::cout << "Finished cell loop" << std::endl;

pc.outputs().snapshot(Output{"TFN", "TFNumber", 0, Lifetime::Timeframe}, tfNumber);

mTimer.Stop();
}

void StandaloneAODProducerSpec::endOfStream(EndOfStreamContext& ec)
{
LOGF(INFO, "EMCAL Standalone AOD Producer total timing: Cpu: %.3e Real: %.3e s in %d slots",
mTimer.CpuTime(), mTimer.RealTime(), mTimer.Counter() - 1);
}

DataProcessorSpec getStandaloneAODProducerSpec()
{
std::vector<OutputSpec> outputs;
outputs.emplace_back(OutputLabel{"O2bc"}, "AOD", "BC", 0, Lifetime::Timeframe);
outputs.emplace_back(OutputLabel{"O2collision"}, "AOD", "COLLISION", 0, Lifetime::Timeframe);
outputs.emplace_back(OutputLabel{"O2caloCell"}, "AOD", "CALO", 0, Lifetime::Timeframe);
outputs.emplace_back(OutputLabel{"O2caloCellTRGR"}, "AOD", "CALOTRIGGER", 0, Lifetime::Timeframe);
outputs.emplace_back(OutputSpec{"TFN", "TFNumber"});

return DataProcessorSpec{
"standalone-aod-producer-workflow",
Inputs{
InputSpec{StandaloneAODProducerSpec::getCellTriggerRecordBinding(), "EMC", "CELLSTRGR", 0, Lifetime::Timeframe},
InputSpec{StandaloneAODProducerSpec::getCellBinding(), "EMC", "CELLS", 0, Lifetime::Timeframe}},
outputs,
AlgorithmSpec{adaptFromTask<StandaloneAODProducerSpec>()},
Options{
ConfigParamSpec{"run-number", VariantType::Int64, -1L, {"The run-number. If left default we try to get it from DPL header."}},
ConfigParamSpec{"aod-timeframe-id", VariantType::Int64, -1L, {"Set timeframe number"}}}};
}

} // namespace emcal
} // namespace o2
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

/// @file standalone-aod-producer-workflow.cxx
/// @author Florian Jonas
/// @since 2021-11-09
/// @brief Conversion from CTF data -> AO2D standalone for EMCal (does not require other detectors like AODProducerWorklfow)

#include "EMCALWorkflow/StandaloneAODProducerSpec.h"
#include "CommonUtils/ConfigurableParam.h"
#include "Framework/ConfigParamSpec.h"

using namespace o2::framework;

// ------------------------------------------------------------------

// we need to add workflow options before including Framework/runDataProcessing
void customize(std::vector<o2::framework::ConfigParamSpec>& workflowOptions)
{
// option allowing to set parameters
std::vector<ConfigParamSpec> options{ConfigParamSpec{"configKeyValues", VariantType::String, "", {"Semicolon separated key=value strings"}}};

std::swap(workflowOptions, options);
}

// ------------------------------------------------------------------

#include "Framework/runDataProcessing.h"

WorkflowSpec defineDataProcessing(ConfigContext const& cfgc)
{
WorkflowSpec wf;
// Update the (declared) parameters if changed from the command line
o2::conf::ConfigurableParam::updateFromString(cfgc.options().get<std::string>("configKeyValues"));
wf.emplace_back(o2::emcal::getStandaloneAODProducerSpec());
return wf;
}