|
12 | 12 | #ifndef O2_TRD_KRWRITERSPEC_H |
13 | 13 | #define O2_TRD_KRWRITERSPEC_H |
14 | 14 |
|
| 15 | +#include "Framework/DataProcessorSpec.h" |
| 16 | +#include "Framework/DataTakingContext.h" |
| 17 | +#include "DataFormatsTRD/KrCluster.h" |
| 18 | +#include "DataFormatsTRD/KrClusterTriggerRecord.h" |
| 19 | +#include "CommonUtils/MemFileHelper.h" |
| 20 | +#include "DetectorsCommonDataFormats/FileMetaData.h" |
| 21 | + |
| 22 | +#include <TFile.h> |
| 23 | +#include <TTree.h> |
| 24 | +#include <filesystem> |
| 25 | +#include <fmt/format.h> |
| 26 | + |
15 | 27 | namespace o2 |
16 | 28 | { |
17 | | -namespace framework |
| 29 | +namespace trd |
18 | 30 | { |
19 | | -struct DataProcessorSpec; |
20 | | -} |
21 | | -} // namespace o2 |
22 | 31 |
|
23 | | -namespace o2 |
| 32 | +class TRDKrClsWriterTask : public o2::framework::Task |
24 | 33 | { |
25 | | -namespace trd |
| 34 | + public: |
| 35 | + TRDKrClsWriterTask() = default; |
| 36 | + |
| 37 | + void init(o2::framework::InitContext& ic) final |
| 38 | + { |
| 39 | + mOutputDir = o2::utils::Str::rectifyDirectory(ic.options().get<std::string>("output-dir")); |
| 40 | + |
| 41 | + // should we write meta files for epn2eos? |
| 42 | + mMetaFileDir = ic.options().get<std::string>("meta-output-dir"); |
| 43 | + if (mMetaFileDir != "/dev/null") { |
| 44 | + mMetaFileDir = o2::utils::Str::rectifyDirectory(mMetaFileDir); |
| 45 | + mStoreMetaFile = true; |
| 46 | + } |
| 47 | + |
| 48 | + LOGP(info, "Storing output in {}, meta file writing enabled: {}", mOutputDir, mStoreMetaFile); |
| 49 | + mAutoSave = ic.options().get<int>("autosave-interval"); |
| 50 | + |
| 51 | + char hostname[_POSIX_HOST_NAME_MAX]; |
| 52 | + gethostname(hostname, _POSIX_HOST_NAME_MAX); |
| 53 | + mHostName = hostname; |
| 54 | + mHostName = mHostName.substr(0, mHostName.find('.')); |
| 55 | + } |
| 56 | + |
| 57 | + void createOutputFile(int runNumber, o2::framework::ProcessingContext& pc) |
| 58 | + { |
| 59 | + mFileName = fmt::format("o2_trdKrCls_run{}_{}.root", runNumber, mHostName); |
| 60 | + auto fileNameTmp = o2::utils::Str::concat_string(mOutputDir, mFileName, ".part"); |
| 61 | + mFileOut = std::make_unique<TFile>(fileNameTmp.c_str(), "recreate"); |
| 62 | + mTreeOut = std::make_unique<TTree>("krData", "TRD krypton cluster data"); |
| 63 | + mTreeOut->Branch("cluster", &krClusterPtr); |
| 64 | + mTreeOut->Branch("trigRec", &krTrigRecPtr); |
| 65 | + mDataTakingContext = pc.services().get<DataTakingContext>(); |
| 66 | + mOutputFileCreated = true; |
| 67 | + } |
| 68 | + |
| 69 | + void writeToFile() |
| 70 | + { |
| 71 | + if (!mOutputFileCreated) { |
| 72 | + return; |
| 73 | + } |
| 74 | + mFileOut->cd(); |
| 75 | + mTreeOut->Write(); |
| 76 | + } |
| 77 | + |
| 78 | + void closeOutputFile() |
| 79 | + { |
| 80 | + if (!mOutputFileCreated) { |
| 81 | + return; |
| 82 | + } |
| 83 | + writeToFile(); |
| 84 | + mTreeOut.reset(); |
| 85 | + mFileOut->Close(); |
| 86 | + mFileOut.reset(); |
| 87 | + auto fileNameWithPath = mOutputDir + mFileName; |
| 88 | + std::filesystem::rename(o2::utils::Str::concat_string(mOutputDir, mFileName, ".part"), fileNameWithPath); |
| 89 | + if (mStoreMetaFile) { |
| 90 | + o2::dataformats::FileMetaData fileMetaData; // object with information for meta data file |
| 91 | + fileMetaData.fillFileData(fileNameWithPath); |
| 92 | + fileMetaData.setDataTakingContext(mDataTakingContext); |
| 93 | + fileMetaData.type = "calib"; |
| 94 | + fileMetaData.priority = "high"; |
| 95 | + auto metaFileNameTmp = fmt::format("{}{}.tmp", mMetaFileDir, mFileName); |
| 96 | + auto metaFileName = fmt::format("{}{}.done", mMetaFileDir, mFileName); |
| 97 | + try { |
| 98 | + std::ofstream metaFileOut(metaFileNameTmp); |
| 99 | + metaFileOut << fileMetaData; |
| 100 | + metaFileOut.close(); |
| 101 | + std::filesystem::rename(metaFileNameTmp, metaFileName); |
| 102 | + } catch (std::exception const& e) { |
| 103 | + LOG(error) << "Failed to store meta data file " << metaFileName << ", reason: " << e.what(); |
| 104 | + } |
| 105 | + } |
| 106 | + } |
| 107 | + |
| 108 | + void run(o2::framework::ProcessingContext& pc) final |
| 109 | + { |
| 110 | + if (!mOutputFileCreated) { |
| 111 | + auto tInfo = pc.services().get<o2::framework::TimingInfo>(); |
| 112 | + createOutputFile(tInfo.runNumber, pc); |
| 113 | + } |
| 114 | + if (pc.transitionState() == TransitionHandlingState::Requested) { |
| 115 | + LOG(info) << "Run stop requested, closing output file"; |
| 116 | + mRunStopRequested = true; |
| 117 | + closeOutputFile(); |
| 118 | + } |
| 119 | + if (mRunStopRequested) { |
| 120 | + return; |
| 121 | + } |
| 122 | + auto cluster = pc.inputs().get<gsl::span<KrCluster>>("krcluster"); |
| 123 | + auto triggerRecords = pc.inputs().get<gsl::span<KrClusterTriggerRecord>>("krtrigrec"); |
| 124 | + for (const auto& cls : cluster) { |
| 125 | + krCluster.push_back(cls); |
| 126 | + } |
| 127 | + for (const auto& trig : triggerRecords) { |
| 128 | + krTrigRec.push_back(trig); |
| 129 | + } |
| 130 | + mTreeOut->Fill(); |
| 131 | + krCluster.clear(); |
| 132 | + krTrigRec.clear(); |
| 133 | + if (mAutoSave > 0 && ++mTFCounter % mAutoSave == 0) { |
| 134 | + writeToFile(); |
| 135 | + } |
| 136 | + } |
| 137 | + |
| 138 | + void endOfStream(o2::framework::EndOfStreamContext& ec) final |
| 139 | + { |
| 140 | + if (mRunStopRequested) { |
| 141 | + return; |
| 142 | + } |
| 143 | + LOG(info) << "End of stream received, closing output file"; |
| 144 | + closeOutputFile(); |
| 145 | + } |
| 146 | + |
| 147 | + private: |
| 148 | + bool mRunStopRequested{false}; |
| 149 | + bool mStoreMetaFile{false}; |
| 150 | + bool mOutputFileCreated{false}; |
| 151 | + int mAutoSave{0}; |
| 152 | + uint64_t mTFCounter{0}; |
| 153 | + std::string mOutputDir{"none"}; |
| 154 | + std::string mMetaFileDir{"/dev/null"}; |
| 155 | + std::string mHostName{}; |
| 156 | + std::string mFileName{}; |
| 157 | + std::unique_ptr<TFile> mFileOut{}; |
| 158 | + std::unique_ptr<TTree> mTreeOut{}; |
| 159 | + std::vector<KrCluster> krCluster, *krClusterPtr{&krCluster}; |
| 160 | + std::vector<KrClusterTriggerRecord> krTrigRec, *krTrigRecPtr{&krTrigRec}; |
| 161 | + o2::framework::DataTakingContext mDataTakingContext; |
| 162 | +}; |
| 163 | + |
| 164 | +framework::DataProcessorSpec getKrClusterWriterSpec() |
26 | 165 | { |
| 166 | + std::vector<InputSpec> inputs; |
| 167 | + inputs.emplace_back("krcluster", "TRD", "KRCLUSTER"); |
| 168 | + inputs.emplace_back("krtrigrec", "TRD", "TRGKRCLS"); |
27 | 169 |
|
28 | | -o2::framework::DataProcessorSpec getKrClusterWriterSpec(); |
| 170 | + return DataProcessorSpec{"kr-cluster-writer", |
| 171 | + inputs, |
| 172 | + Outputs{}, |
| 173 | + AlgorithmSpec{adaptFromTask<o2::trd::TRDKrClsWriterTask>()}, |
| 174 | + Options{ |
| 175 | + {"output-dir", VariantType::String, "none", {"Output directory for data. Defaults to current working directory"}}, |
| 176 | + {"meta-output-dir", VariantType::String, "/dev/null", {"metadata output directory, must exist (if not /dev/null)"}}, |
| 177 | + {"autosave-interval", VariantType::Int, 0, {"Write output to file for every n-th TF. 0 means this feature is OFF"}}}}; |
| 178 | +} |
29 | 179 |
|
30 | 180 | } // end namespace trd |
31 | 181 | } // end namespace o2 |
|
0 commit comments