|
54 | 54 | #include "Framework/TableBuilder.h" |
55 | 55 | #include "Framework/CCDBParamSpec.h" |
56 | 56 | #include "CommonUtils/TreeStreamRedirector.h" |
| 57 | +#include "CommonUtils/KeyValParam.h" |
| 58 | +#include "CommonUtils/NameConf.h" |
57 | 59 | #include "FT0Base/Geometry.h" |
58 | 60 | #include "GlobalTracking/MatchTOF.h" |
59 | 61 | #include "ReconstructionDataFormats/Cascade.h" |
|
88 | 90 | #include "MathUtils/Utils.h" |
89 | 91 | #include "Math/SMatrix.h" |
90 | 92 | #include "TString.h" |
| 93 | +#include <fnmatch.h> |
91 | 94 | #include <limits> |
92 | 95 | #include <map> |
93 | 96 | #include <numeric> |
@@ -1902,6 +1905,8 @@ void AODProducerWorkflowDPL::init(InitContext& ic) |
1902 | 1905 |
|
1903 | 1906 | mUseSigFiltMC = ic.options().get<bool>("mc-signal-filt"); |
1904 | 1907 |
|
| 1908 | + mCollectConfigFiles = ic.options().get<bool>("collect-config-files"); |
| 1909 | + |
1905 | 1910 | // set no truncation if selected by user |
1906 | 1911 | if (mTruncate != 1) { |
1907 | 1912 | LOG(info) << "Truncation is not used!"; |
@@ -2670,6 +2675,10 @@ void AODProducerWorkflowDPL::run(ProcessingContext& pc) |
2670 | 2675 | mMetaDataVals = {dataType, "3", O2Version, ROOTVersion, mRecoPass, mAnchorProd, mAnchorPass, mLPMProdTag, mUser}; |
2671 | 2676 | add_additional_meta_info(mMetaDataKeys, mMetaDataVals); |
2672 | 2677 |
|
| 2678 | + if (mCollectConfigFiles) { |
| 2679 | + collectConfigFiles(mMetaDataKeys, mMetaDataVals); |
| 2680 | + } |
| 2681 | + |
2673 | 2682 | pc.outputs().snapshot(Output{"AMD", "AODMetadataKeys", 0}, mMetaDataKeys); |
2674 | 2683 | pc.outputs().snapshot(Output{"AMD", "AODMetadataVals", 0}, mMetaDataVals); |
2675 | 2684 |
|
@@ -3405,6 +3414,102 @@ std::vector<uint8_t> AODProducerWorkflowDPL::fillBCFlags(const o2::globaltrackin |
3405 | 3414 | return flags; |
3406 | 3415 | } |
3407 | 3416 |
|
| 3417 | +bool AODProducerWorkflowDPL::collectConfigFiles(std::vector<TString>& keys, std::vector<TString>& values, int indent) |
| 3418 | +{ |
| 3419 | + // collect JSON-files of ConfigParams dumped by different upstream processors and add to medata |
| 3420 | + static std::string pattern, directory; |
| 3421 | + static size_t cachedNumberOfFiles = 0, cachedTotalFileSize = 0; |
| 3422 | + static bool first = true, discard = false; |
| 3423 | + if (discard) { |
| 3424 | + return false; |
| 3425 | + } |
| 3426 | + std::error_code ec; |
| 3427 | + if (first) { |
| 3428 | + first = false; |
| 3429 | + pattern = o2::base::NameConf::Instance().getConfigOutputFileName("*"); |
| 3430 | + auto dir = o2::conf::KeyValParam::Instance().getOutputDir(); |
| 3431 | + if (dir == "/dev/null") { |
| 3432 | + LOGP(warn, "ConfigParams output is disabled, abandoning {} files collection for metadata", pattern); |
| 3433 | + discard = true; |
| 3434 | + return false; |
| 3435 | + } |
| 3436 | + directory = (dir.empty() || dir == "none") ? "." : dir; |
| 3437 | + if (!std::filesystem::is_directory(directory, ec)) { |
| 3438 | + LOGP(error, R"(No directory "{}" is found to look for {} configuration files)", directory, pattern); |
| 3439 | + discard = true; |
| 3440 | + return false; |
| 3441 | + } |
| 3442 | + } |
| 3443 | + static std::unordered_map<std::string, std::string> cachedMap; |
| 3444 | + std::vector<std::filesystem::path> files; |
| 3445 | + size_t currentTotalFileSize = 0; |
| 3446 | + |
| 3447 | + for (const auto& entry : std::filesystem::directory_iterator(directory)) { |
| 3448 | + if (!entry.is_regular_file()) { |
| 3449 | + continue; |
| 3450 | + } |
| 3451 | + const std::string fileName = entry.path().filename().string(); |
| 3452 | + if (fnmatch(pattern.c_str(), fileName.c_str(), 0) != 0) { |
| 3453 | + continue; |
| 3454 | + } |
| 3455 | + const auto fileSize = entry.file_size(ec); |
| 3456 | + if (ec) { |
| 3457 | + LOGP(error, "Cannot determine size of file {}, reason: {}", entry.path().string(), ec.message()); |
| 3458 | + } |
| 3459 | + files.push_back(entry.path()); |
| 3460 | + currentTotalFileSize += static_cast<size_t>(fileSize); |
| 3461 | + } |
| 3462 | + |
| 3463 | + if (files.size() != cachedNumberOfFiles || currentTotalFileSize != cachedTotalFileSize) { // need to create a new map |
| 3464 | + cachedNumberOfFiles = files.size(); |
| 3465 | + cachedTotalFileSize = currentTotalFileSize; |
| 3466 | + cachedMap.clear(); |
| 3467 | + } |
| 3468 | + |
| 3469 | + if (!files.empty() && cachedMap.empty()) { |
| 3470 | + for (const auto& fname : files) { |
| 3471 | + std::ifstream input(fname); |
| 3472 | + if (!input) { |
| 3473 | + LOGP(error, "Cannot open JSON file {}", fname.string()); |
| 3474 | + cachedTotalFileSize = 0; // will trigger a new trial next time |
| 3475 | + continue; |
| 3476 | + } |
| 3477 | + nlohmann::json document; |
| 3478 | + try { |
| 3479 | + input >> document; |
| 3480 | + } catch (const nlohmann::json::parse_error& e) { |
| 3481 | + LOGP(error, "Cannot parse JSON file {}, reason: {}", fname.string(), e.what()); |
| 3482 | + cachedTotalFileSize = 0; // will trigger a new trial next time |
| 3483 | + continue; |
| 3484 | + } |
| 3485 | + |
| 3486 | + if (!document.is_object()) { |
| 3487 | + LOGP(error, "Top-level JSON value is not an object in file: {}", fname.string()); |
| 3488 | + cachedTotalFileSize = 0; // will trigger a new trial next time |
| 3489 | + continue; |
| 3490 | + } |
| 3491 | + |
| 3492 | + for (auto it = document.begin(); it != document.end(); ++it) { |
| 3493 | + const std::string& key = it.key(); |
| 3494 | + if (cachedMap.find(key) != cachedMap.end()) { |
| 3495 | + LOGP(error, "Duplicate top-level key {} in file {}", key, fname.string()); |
| 3496 | + continue; |
| 3497 | + } |
| 3498 | + LOGP(info, "Adding json config {} from file {} to AOD metadata", key, fname.string()); |
| 3499 | + nlohmann::json valueDocument = nlohmann::json::object(); |
| 3500 | + valueDocument[key] = it.value(); |
| 3501 | + cachedMap[key] = valueDocument.dump(indent); |
| 3502 | + } |
| 3503 | + } |
| 3504 | + } |
| 3505 | + |
| 3506 | + for (const auto& kv : cachedMap) { |
| 3507 | + keys.push_back(kv.first.c_str()); |
| 3508 | + values.push_back(kv.second.c_str()); |
| 3509 | + } |
| 3510 | + return true; |
| 3511 | +} |
| 3512 | + |
3408 | 3513 | void AODProducerWorkflowDPL::endOfStream(EndOfStreamContext& /*ec*/) |
3409 | 3514 | { |
3410 | 3515 | LOGF(info, "aod producer dpl total timing: Cpu: %.3e Real: %.3e s in %d slots", |
@@ -3565,7 +3670,9 @@ DataProcessorSpec getAODProducerWorkflowSpec(GID::mask_t src, bool enableSV, boo |
3565 | 3670 | ConfigParamSpec{"trackqc-tpc-pt", VariantType::Float, 0.2f, {"Keep TPC standalone track with this pt"}}, |
3566 | 3671 | ConfigParamSpec{"with-streamers", VariantType::String, "", {"Bit-mask to steer writing of intermediate streamer files"}}, |
3567 | 3672 | ConfigParamSpec{"seed", VariantType::Int, 0, {"Set seed for random generator used for sampling (0 (default) means using a random_device)"}}, |
3568 | | - ConfigParamSpec{"mc-signal-filt", VariantType::Bool, false, {"Enable usage of signal filtering (only for MC with embedding)"}}}}; |
| 3673 | + ConfigParamSpec{"mc-signal-filt", VariantType::Bool, false, {"Enable usage of signal filtering (only for MC with embedding)"}}, |
| 3674 | + ConfigParamSpec{"collect-config-files", VariantType::Bool, false, {"Collect ConfigParams json files written by upsteam processors"}}, |
| 3675 | + }}; |
3569 | 3676 | } |
3570 | 3677 |
|
3571 | 3678 | } // namespace o2::aodproducer |
0 commit comments