diff --git a/offline/QA/Calorimeters/CaloValid.cc b/offline/QA/Calorimeters/CaloValid.cc index 2451672807..86272eb0ba 100644 --- a/offline/QA/Calorimeters/CaloValid.cc +++ b/offline/QA/Calorimeters/CaloValid.cc @@ -142,6 +142,23 @@ int CaloValid::process_event(PHCompositeNode* topNode) return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Process tower, trigger, MBD, and cluster information for a single event and fill QA histograms. + * + * Processes calibrated and raw towers for CEMC, HCALIN, and HCALOUT plus MBD PMTs; decodes GL1 trigger bits; + * accumulates per-calorimeter totals; fills per-channel, eta/phi, timing, status, and QA histograms; builds + * cluster pairs to produce pi0 candidates and fills related mass/IB histograms; and fills trigger-aligned + * distributions and livetime/rejection profiles. + * + * The function reads multiple nodes from the provided top-level node tree (EventHeader, GlobalVertexMap, + * Gl1Packet, TowerInfoContainer for several collections, MbdPmtContainer, RawClusterContainer, RawTowerGeomContainer) + * and relies on an available TriggerAnalyzer if set. If the required cluster node ("CLUSTERINFO_CEMC") is missing + * the function logs an error and returns 0. Histograms updated by this method include correlations between EMCal/MBD/HCAL, + * per-channel pedestal/energy/timing, eta-phi maps, cluster QA, pi0/IB mass distributions, and trigger-related profiles. + * + * @param topNode Top-level node providing event data containers accessed by name. + * @return int Fun4All return code; `Fun4AllReturnCodes::EVENT_OK` on normal completion, or `0` if the CEMC cluster node is missing. + */ int CaloValid::process_towers(PHCompositeNode* topNode) { //---------------------------Event header--------------------------------// @@ -335,7 +352,10 @@ int CaloValid::process_towers(PHCompositeNode* topNode) status = status >> 1U; // clang-tidy mark 1 as unsigned } - totalcemc += offlineenergy; + if (isGood) + { + totalcemc += offlineenergy; + } h_emcaltime->Fill(_timef); if (offlineenergy > emcal_hit_threshold) { @@ -407,7 +427,10 @@ int CaloValid::process_towers(PHCompositeNode* topNode) status = status >> 1U; // clang-tidy mark 1 as unsigned } - totalihcal += offlineenergy; + if (isGood) + { + totalihcal += offlineenergy; + } h_ihcaltime->Fill(_timef); if (offlineenergy > ihcal_hit_threshold) @@ -472,7 +495,10 @@ int CaloValid::process_towers(PHCompositeNode* topNode) status = status >> 1U; // clang-tidy mark 1 as unsigned } - totalohcal += offlineenergy; + if (isGood) + { + totalohcal += offlineenergy; + } h_ohcaltime->Fill(_timef); if (offlineenergy > ohcal_hit_threshold) @@ -1292,4 +1318,4 @@ void CaloValid::createHistos() } hm->registerHisto(h_triggerVec); hm->registerHisto(pr_ldClus_trig); -} +} \ No newline at end of file diff --git a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc index 78b3e3a365..f312c19565 100644 --- a/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc +++ b/offline/framework/fun4allraw/Fun4AllStreamingInputManager.cc @@ -642,6 +642,19 @@ int Fun4AllStreamingInputManager::FillGl1() return 0; } +/** + * @brief Populate the INTT raw-hit container from buffered streaming inputs. + * + * Calls FillInttPool() to ensure INTT input pools are populated, determines a BCO + * selection window relative to the manager's reference BCO, and appends all INTT + * raw hits whose BCO is within that window into the InttRawHitContainer found + * under the top node. While doing so, the method may set m_RefBCO if it was + * unset, drop buffered entries earlier than the configured negative offset, and + * fill QA histograms that describe per-packet and per-FEE tagging and BCO + * differences. + * + * @return int 0 on success; non-zero error code returned from FillInttPool() on failure. + */ int Fun4AllStreamingInputManager::FillIntt() { int iret = FillInttPool(); @@ -776,9 +789,15 @@ int Fun4AllStreamingInputManager::FillIntt() { h_taggedAllFee_intt->Fill(refbcobitshift); } - while (m_InttRawHitMap.begin()->first <= select_crossings - m_intt_negative_bco) + + for (auto& [bco, hitinfo] : m_InttRawHitMap) { - for (auto *intthititer : m_InttRawHitMap.begin()->second.InttRawHitVector) + if (bco > select_crossings) + { + break; + } + + for (auto *intthititer : hitinfo.InttRawHitVector) { if (Verbosity() > 1) { @@ -788,25 +807,24 @@ int Fun4AllStreamingInputManager::FillIntt() } inttcont->AddHit(intthititer); } - for (auto *iter : m_InttInputVector) - { - iter->CleanupUsedPackets(m_InttRawHitMap.begin()->first); - if (m_intt_negative_bco < 2) // triggered mode - { - iter->clearPacketBClkStackMap(m_InttRawHitMap.begin()->first); - iter->clearFeeGTML1BCOMap(m_InttRawHitMap.begin()->first); - } - } - m_InttRawHitMap.begin()->second.InttRawHitVector.clear(); - m_InttRawHitMap.erase(m_InttRawHitMap.begin()); - if (m_InttRawHitMap.empty()) - { - break; - } - } + } return 0; } - +/** + * @brief Collects MVTX streaming data for the current reference BCO and fills MVTX event/header containers and QA histograms. + * + * Processes MVTX input pools, prunes MVTX BCO entries older than the configured negative window, updates the internal reference BCO if unset, evaluates packet/FEE tagging and fills QA histograms, and transfers MVTX fee information, L1 trigger BCOs, and raw hits into the MVTX event header and hit container for BCOS inside the configured selection window. + * + * Side effects: + * - May set m_RefBCO when it was zero. + * - Adds fee ID info entries and L1 trigger BCOs to the MVTX raw event header node. + * - Adds MVTX raw hits to the MVTX raw hit container node. + * - Updates internal per-input packet bookkeeping via CleanupUsedPackets/clearFeeGTML1BCOMap during pruning. + * - Fills multiple MVTX QA histograms used for tag and BCO-difference monitoring. + * - Terminates the process with exit(1) if required MVTX nodes are missing. + * + * @return int `0` on successful fill; non-zero return values are propagated from FillMvtxPool when pool filling fails. + */ int Fun4AllStreamingInputManager::FillMvtx() { int iret = FillMvtxPool(); @@ -846,7 +864,7 @@ int Fun4AllStreamingInputManager::FillMvtx() } select_crossings += m_RefBCO; - uint64_t ref_bco_minus_range = m_RefBCO < m_mvtx_bco_range ? 0 : m_RefBCO - m_mvtx_bco_range; + uint64_t ref_bco_minus_range = m_RefBCO < m_mvtx_negative_bco ? 0 : m_RefBCO - m_mvtx_negative_bco; if (Verbosity() > 2) { std::cout << "select MVTX crossings" @@ -981,90 +999,42 @@ int Fun4AllStreamingInputManager::FillMvtx() } taggedPacketsFEEs.clear(); - if (m_mvtx_is_triggered) + uint64_t lower_limit = m_mvtx_is_triggered ? select_crossings : select_crossings - m_mvtx_bco_range - m_mvtx_negative_bco; + uint64_t upper_limit = m_mvtx_is_triggered ? select_crossings + m_mvtx_bco_range : select_crossings; + + for (auto& [bco, hitinfo] : m_MvtxRawHitMap) { - while (select_crossings <= m_MvtxRawHitMap.begin()->first && m_MvtxRawHitMap.begin()->first <= select_crossings + m_mvtx_bco_range) // triggered + if (bco < lower_limit) { - if (Verbosity() > 2) - { - std::cout << "Adding 0x" << std::hex << m_MvtxRawHitMap.begin()->first - << " ref: 0x" << select_crossings << std::dec << std::endl; - } - for (auto *mvtxFeeIdInfo : m_MvtxRawHitMap.begin()->second.MvtxFeeIdInfoVector) - { - if (Verbosity() > 1) - { - mvtxFeeIdInfo->identify(); - } - mvtxEvtHeader->AddFeeIdInfo(mvtxFeeIdInfo); - delete mvtxFeeIdInfo; - } - m_MvtxRawHitMap.begin()->second.MvtxFeeIdInfoVector.clear(); - mvtxEvtHeader->AddL1Trg(m_MvtxRawHitMap.begin()->second.MvtxL1TrgBco); + continue; + } + if (bco > upper_limit) + { + break; + } - for (auto *mvtxhititer : m_MvtxRawHitMap.begin()->second.MvtxRawHitVector) - { - if (Verbosity() > 1) - { - mvtxhititer->identify(); - } - mvtxcont->AddHit(mvtxhititer); - } - for (auto *iter : m_MvtxInputVector) - { - iter->CleanupUsedPackets(m_MvtxRawHitMap.begin()->first); - } - m_MvtxRawHitMap.begin()->second.MvtxRawHitVector.clear(); - m_MvtxRawHitMap.begin()->second.MvtxL1TrgBco.clear(); - m_MvtxRawHitMap.erase(m_MvtxRawHitMap.begin()); - // m_MvtxRawHitMap.empty() need to be checked here since we do not call FillPoolMvtx() - if (m_MvtxRawHitMap.empty()) - { - break; - } + if (Verbosity() > 2) + { + std::cout << "Adding 0x" << std::hex << bco + << " ref: 0x" << select_crossings << std::dec << std::endl; } - } - else - { - while (select_crossings - m_mvtx_bco_range - m_mvtx_negative_bco <= m_MvtxRawHitMap.begin()->first && m_MvtxRawHitMap.begin()->first <= select_crossings) // streamed + for (auto *mvtxFeeIdInfo : hitinfo.MvtxFeeIdInfoVector) { - if (Verbosity() > 2) - { - std::cout << "Adding 0x" << std::hex << m_MvtxRawHitMap.begin()->first - << " ref: 0x" << select_crossings << std::dec << std::endl; - } - for (auto *mvtxFeeIdInfo : m_MvtxRawHitMap.begin()->second.MvtxFeeIdInfoVector) + if (Verbosity() > 1) { - if (Verbosity() > 1) - { - mvtxFeeIdInfo->identify(); - } - mvtxEvtHeader->AddFeeIdInfo(mvtxFeeIdInfo); - delete mvtxFeeIdInfo; + mvtxFeeIdInfo->identify(); } - m_MvtxRawHitMap.begin()->second.MvtxFeeIdInfoVector.clear(); - mvtxEvtHeader->AddL1Trg(m_MvtxRawHitMap.begin()->second.MvtxL1TrgBco); + mvtxEvtHeader->AddFeeIdInfo(mvtxFeeIdInfo); + } + mvtxEvtHeader->AddL1Trg(hitinfo.MvtxL1TrgBco); - for (auto *mvtxhititer : m_MvtxRawHitMap.begin()->second.MvtxRawHitVector) - { - if (Verbosity() > 1) - { - mvtxhititer->identify(); - } - mvtxcont->AddHit(mvtxhititer); - } - for (auto *iter : m_MvtxInputVector) - { - iter->CleanupUsedPackets(m_MvtxRawHitMap.begin()->first); - } - m_MvtxRawHitMap.begin()->second.MvtxRawHitVector.clear(); - m_MvtxRawHitMap.begin()->second.MvtxL1TrgBco.clear(); - m_MvtxRawHitMap.erase(m_MvtxRawHitMap.begin()); - // m_MvtxRawHitMap.empty() need to be checked here since we do not call FillPoolMvtx() - if (m_MvtxRawHitMap.empty()) + for (auto *mvtxhititer : hitinfo.MvtxRawHitVector) + { + if (Verbosity() > 1) { - break; + mvtxhititer->identify(); } + mvtxcont->AddHit(mvtxhititer); } } @@ -1420,9 +1390,20 @@ int Fun4AllStreamingInputManager::FillMicromegasPool() return 0; } +/** + * @brief Fill MVTX input pools and ensure run-number consistency. + * + * Calls FillPool(ref_bco_minus_range) on each registered MVTX input, updates the manager's run number + * from the first input, and validates that all inputs share the same run number. + * + * @return int `0` on success, `-1` if no MVTX hits were collected (MvtxRawHitMap is empty). + * + * @note This function may terminate the process (exit with code 1) if a run-number mismatch is detected + * between MVTX inputs. + */ int Fun4AllStreamingInputManager::FillMvtxPool() { - uint64_t ref_bco_minus_range = m_RefBCO < m_mvtx_bco_range ? m_mvtx_bco_range : m_RefBCO - m_mvtx_bco_range; + uint64_t ref_bco_minus_range = m_RefBCO < m_mvtx_negative_bco ? m_mvtx_negative_bco : m_RefBCO - m_mvtx_negative_bco; for (auto *iter : m_MvtxInputVector) { if (Verbosity() > 3) @@ -1569,4 +1550,4 @@ void Fun4AllStreamingInputManager::createQAHistos() h_tagBcoFelix_mvtx[i] = dynamic_cast(hm->getHisto((boost::format("h_MvtxPoolQA_TagBCO_felix%i") % i).str())); h_tagBcoFelixAllFees_mvtx[i] = dynamic_cast(hm->getHisto((boost::format("h_MvtxPoolQA_TagBCOAllFees_Felix%i") % i).str())); } -} +} \ No newline at end of file diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc index 7500e3badf..4c81356675 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.cc @@ -524,7 +524,22 @@ void SingleMicromegasPoolInput_v2::FillBcoQA(uint64_t gtm_bco) // how many waveforms found for this BCO h_waveform->Fill(n_waveforms); } -//_______________________________________________________ +/** + * @brief Create and register QA histograms and optional evaluation trees for Micromegas BCO/packet monitoring. + * + * This initializes per-event and per-packet QA histograms used to track: + * - packet and waveform counts per GTM BCO, + * - per-packet matching statistics, + * - heartbeat counts per SAMPA, + * - total and dropped waveform counts per packet and per FEE. + * + * Histograms are registered with the global QA histogram manager and have axis labels and fill styling configured. + * + * When evaluation mode is enabled, opens the configured evaluation TFile and creates a TTree ("T") with branches: + * - is_heartbeat, matched, packet_id, fee_id, channel, + * - gtm_bco_first, gtm_bco, gtm_bco_matched, + * - fee_bco_first, fee_bco, fee_bco_predicted, fee_bco_predicted_matched. + */ void SingleMicromegasPoolInput_v2::createQAHistos() { auto* hm = QAHistManagerDef::getHistoManager(); @@ -607,6 +622,7 @@ void SingleMicromegasPoolInput_v2::createQAHistos() m_evaluation_file.reset(new TFile(m_evaluation_filename.c_str(), "RECREATE")); m_evaluation_tree = new TTree("T", "T"); m_evaluation_tree->Branch("is_heartbeat", &m_waveform.is_heartbeat); + m_evaluation_tree->Branch("matched", &m_waveform.matched); m_evaluation_tree->Branch("packet_id", &m_waveform.packet_id); m_evaluation_tree->Branch("fee_id", &m_waveform.fee_id); m_evaluation_tree->Branch("channel", &m_waveform.channel); @@ -788,7 +804,20 @@ void SingleMicromegasPoolInput_v2::decode_gtm_data(int packet_id, const SingleMi } } -//____________________________________________________________________ +/** + * @brief Process and decode FEE data packets for a given packet and FEE, producing raw hits and QA updates. + * + * Parses buffered FEE words, validates packet headers and lengths, extracts payload fields and waveform samples, + * performs BCO matching, updates heartbeat and waveform counters/histograms, records evaluation entries when enabled, + * and on successful matches creates and stores MicromegasRawHitv3 objects associated with the resolved GTM BCO. + * + * Invalid or unmatchable packets (bad magic keys, insufficient length, or failed BCO matching) are dropped and + * increment the corresponding drop counters and QA histograms. Heartbeat-only payloads update heartbeat statistics + * but are not converted into raw hits. + * + * @param packet_id Identifier of the incoming packet being processed. + * @param fee_id Identifier of the front-end electronics (FEE) board whose buffer is being consumed. + */ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int fee_id) { // get bco information @@ -912,6 +941,13 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int // try get gtm bco matching fee const auto& fee_bco = payload.bx_timestamp; + if( m_do_evaluation ) + { + m_waveform.is_heartbeat = is_heartbeat; + m_waveform.fee_id = fee_id; + m_waveform.channel = payload.channel; + m_waveform.fee_bco = fee_bco; + } // find matching gtm bco uint64_t gtm_bco = 0; @@ -920,9 +956,20 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int { // assign gtm bco gtm_bco = result.value(); - } - else - { + if( m_do_evaluation ) + { + m_waveform.matched = true; + m_waveform.gtm_bco_matched = gtm_bco; + { + const auto predicted = bco_matching_information.get_predicted_fee_bco(gtm_bco);; + if( predicted ) + { + m_waveform.fee_bco_predicted_matched = predicted.value(); + } + } + m_evaluation_tree->Fill(); + } + } else { // increment counter and histogram ++m_waveform_counters[packet_id].dropped_bco; ++m_fee_waveform_counters[fee_id].dropped_bco; @@ -935,28 +982,16 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int ++m_fee_heartbeat_counters[fee_id].dropped_bco; } - // skip the waverform - continue; - } - - if (m_do_evaluation) - { - m_waveform.is_heartbeat = (payload.type == HEARTBEAT_T); - m_waveform.fee_id = fee_id; - m_waveform.channel = payload.channel; - m_waveform.fee_bco = fee_bco; - - m_waveform.gtm_bco_matched = gtm_bco; + if( m_do_evaluation ) { - const auto predicted = bco_matching_information.get_predicted_fee_bco(gtm_bco); - ; - if (predicted) - { - m_waveform.fee_bco_predicted_matched = predicted.value(); - } + m_waveform.matched = false; + m_waveform.gtm_bco_matched = 0; + m_waveform.fee_bco_predicted_matched = 0; + m_evaluation_tree->Fill(); } - m_evaluation_tree->Fill(); + // skip the waverform + continue; } // ignore heartbeat waveforms @@ -1024,4 +1059,4 @@ void SingleMicromegasPoolInput_v2::process_fee_data(int packet_id, unsigned int m_MicromegasRawHitMap[gtm_bco].push_back(newhit.release()); } -} +} \ No newline at end of file diff --git a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h index d8c3c1da62..a4f7aa4b6d 100644 --- a/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h +++ b/offline/framework/fun4allraw/SingleMicromegasPoolInput_v2.h @@ -212,8 +212,20 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput std::unique_ptr m_evaluation_file; /** - * waveform is similar to sample except that there is only one of which per waveform, - * and that it stores the max adc and corresponding sample_id + * Represents a single Micromegas waveform summarizing its peak ADC sample and associated timing and matching metadata. + * + * @var packet_id Index of the source packet containing this waveform. + * @var fee_id Identifier of the FEE (front-end electronics) that produced the waveform. + * @var channel Channel number on the FEE where the waveform was recorded. + * @var is_heartbeat True when the waveform is a heartbeat measurement. + * @var matched True when the waveform has been matched to a corresponding BCO/track during alignment. + * @var gtm_bco_first LL1 (GTM) beam clock value observed at the start of the waveform. + * @var gtm_bco LL1 (GTM) beam clock value associated with the waveform. + * @var gtm_bco_matched LL1 (GTM) beam clock value used after successful matching. + * @var fee_bco_first FEE-level beam clock value observed at the start of the waveform. + * @var fee_bco FEE-level beam clock value associated with the waveform. + * @var fee_bco_predicted FEE-level BCO predicted from GTM timing for this waveform. + * @var fee_bco_predicted_matched Predicted FEE-level BCO after matching/validation. */ class Waveform { @@ -230,7 +242,15 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput /// true if measurement is hearbeat bool is_heartbeat = false; - /// ll1 bco + /// true if matched + bool matched = false; + + /** + * @brief LL1 beam clock (BCO) from the first GTM word observed for this waveform. + * + * Holds the LL1 BCO value captured from the first GTM record associated with the waveform. + * A value of 0 indicates it has not been set. + */ uint64_t gtm_bco_first {0}; /// ll1 bco @@ -260,4 +280,4 @@ class SingleMicromegasPoolInput_v2 : public SingleStreamingInput //*} }; -#endif +#endif \ No newline at end of file diff --git a/offline/framework/fun4allraw/SingleMvtxPoolInput.cc b/offline/framework/fun4allraw/SingleMvtxPoolInput.cc index de98a9936e..187556b28f 100644 --- a/offline/framework/fun4allraw/SingleMvtxPoolInput.cc +++ b/offline/framework/fun4allraw/SingleMvtxPoolInput.cc @@ -1,7 +1,7 @@ #include "SingleMvtxPoolInput.h" -#include "MvtxRawDefs.h" #include "Fun4AllStreamingInputManager.h" +#include "MvtxRawDefs.h" #include "mvtx_pool.h" #include @@ -28,8 +28,18 @@ #include #include +/** + * @brief Constructs a SingleMvtxPoolInput and initializes streaming input state. + * + * Initializes the base SingleStreamingInput with the provided name, allocates + * internal packet-list storage, and sets the default raw hit container name + * to "MVTXRAWHIT". + * + * @param name Identifier used to name/register this streaming input instance. + */ SingleMvtxPoolInput::SingleMvtxPoolInput(const std::string &name) - : SingleStreamingInput(name), plist(new Packet *[2]) + : SingleStreamingInput(name) + , plist(new Packet *[2]) { m_rawHitContainerName = "MVTXRAWHIT"; @@ -48,6 +58,17 @@ SingleMvtxPoolInput::~SingleMvtxPoolInput() } } +/** + * @brief Read raw MVTX packets from input, aggregate them into pools, and populate MVTX data structures. + * + * Processes available events until the input window is satisfied or no more events are available: + * - opens input files as needed and marks AllDone if files are exhausted, + * - collects packets into per-packet pools and extracts per-FEE strobes, hits, and L1 trigger BCOs, + * - inserts strobe BCOs into m_BclkStack, records per-FEE latest strobe in m_FEEBclkMap, accumulates strobe counts in m_FeeStrobeMap, and stores per-FEE L1 BCOs in m_FeeGTML1BCOMap, + * - creates MvtxRawHitv1 objects for each hit and stores them in m_MvtxRawHitMap (and forwards them, along with fee/strobe info and L1→strobe associations, to StreamingInputManager if present). + * + * @param minBCO Minimum strobe BCO to accept; strobes with BCO less than this value are skipped. + */ void SingleMvtxPoolInput::FillPool(const uint64_t minBCO) { if (AllDone()) // no more files and all events read @@ -161,7 +182,7 @@ void SingleMvtxPoolInput::FillPool(const uint64_t minBCO) m_BclkStack.insert(strb_bco); m_FEEBclkMap[feeId] = strb_bco; - if (strb_bco < minBCO - m_NegativeBco) + if (strb_bco < minBCO) { continue; } @@ -206,7 +227,7 @@ void SingleMvtxPoolInput::FillPool(const uint64_t minBCO) auto it = m_BclkStack.lower_bound(lv1Bco); // auto const strb_it = (it == m_BclkStack.begin()) ? (*it == lv1Bco ? it : m_BclkStack.cend()) : --it; // this is equivalent but human readable for the above: - auto strb_it = m_BclkStack.cend(); + auto strb_it = m_BclkStack.cend(); if (it == m_BclkStack.begin()) { @@ -435,6 +456,13 @@ void SingleMvtxPoolInput::CreateDSTNode(PHCompositeNode *topNode) } } +/** + * @brief Configure MVTX timing and BCO window parameters and propagate them to the streaming manager. + * + * Reads the strobe width from the database when enabled, computes m_BcoRange and m_NegativeBco according to the strobe width and operating mode, and forwards these values to the StreamingInputManager. In triggered mode, signals the StreamingInputManager to run MVTX in triggered mode. + * + * @note If configured to read the strobe width from the database and no value is found, the function prints a warning and exits the process. + */ void SingleMvtxPoolInput::ConfigureStreamingInputManager() { auto [runnumber, segment] = Fun4AllUtils::GetRunSegment(*(GetFileList().begin())); @@ -462,7 +490,7 @@ void SingleMvtxPoolInput::ConfigureStreamingInputManager() else if (m_strobeWidth > 9 && m_strobeWidth < 11) { m_BcoRange = 500; - m_NegativeBco = 500; + m_NegativeBco = 120; } else if (m_strobeWidth < 1) // triggered mode { @@ -492,4 +520,4 @@ void SingleMvtxPoolInput::ConfigureStreamingInputManager() StreamingInputManager()->SetMvtxNegativeBco(m_NegativeBco); } return; -} +} \ No newline at end of file diff --git a/offline/packages/trackreco/PHActsTrkFitter.cc b/offline/packages/trackreco/PHActsTrkFitter.cc index a26ee1fa0a..2dd04d1662 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.cc +++ b/offline/packages/trackreco/PHActsTrkFitter.cc @@ -5,7 +5,6 @@ * \author Tony Frawley */ - #include "PHActsTrkFitter.h" #include "ActsPropagator.h" @@ -25,7 +24,7 @@ #include #include #include -//#include +// #include #include #include #include @@ -86,6 +85,19 @@ PHActsTrkFitter::PHActsTrkFitter(const std::string& name) { } +/** + * @brief Prepare runtime nodes, configuration, and fitting tools before event processing. + * + * Initializes and attaches required nodes, configures alignment and magnetic-field handling, + * constructs Kalman fitter function objects, configures the outlier finder and timing + * histograms, and initializes the Acts evaluator and TPC geometry references using the + * provided top-level node. + * + * @param topNode Root of the Fun4All node tree used to create and retrieve required nodes. + * @return int Fun4AllReturnCodes::EVENT_OK on success; + * Fun4AllReturnCodes::ABORTEVENT if node creation or retrieval fails; + * Fun4AllReturnCodes::ABORTRUN if required DST geometry (TPCGEOMCONTAINER) is missing. + */ int PHActsTrkFitter::InitRun(PHCompositeNode* topNode) { if (Verbosity() > 1) @@ -134,8 +146,8 @@ int PHActsTrkFitter::InitRun(PHCompositeNode* topNode) MaterialSurfaceSelector selector; if (m_fitSiliconMMs || m_directNavigation) { - m_tGeometry->geometry().tGeometry->visitSurfaces(selector,false); - //std::cout<<"selector.surfaces.size() "<geometry().tGeometry->visitSurfaces(selector, false); + // std::cout<<"selector.surfaces.size() "<(m_evalname); m_evaluator->Init(topNode); - if(m_actsEvaluator && !m_simActsEvaluator) + if (m_actsEvaluator && !m_simActsEvaluator) { m_evaluator->isData(); } @@ -182,10 +194,10 @@ int PHActsTrkFitter::InitRun(PHCompositeNode* topNode) _tpccellgeo = findNode::getClass(topNode, "TPCGEOMCONTAINER"); if (!_tpccellgeo) - { - std::cout << PHWHERE << " unable to find DST node TPCGEOMCONTAINER" << std::endl; - return Fun4AllReturnCodes::ABORTRUN; - } + { + std::cout << PHWHERE << " unable to find DST node TPCGEOMCONTAINER" << std::endl; + return Fun4AllReturnCodes::ABORTRUN; + } if (Verbosity() > 1) { @@ -269,6 +281,16 @@ int PHActsTrkFitter::ResetEvent(PHCompositeNode* /*topNode*/) return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Finalize the fitter, write outputs, and clean up analysis resources. + * + * If timing analysis is enabled, writes timing histograms and closes the timing file. + * If an Acts evaluator is configured, calls its End() method. + * If an outlier finder is in use, writes its data. + * Prints a completion message when verbosity is greater than zero. + * + * @return int Fun4AllReturnCodes::EVENT_OK on successful completion. + */ int PHActsTrkFitter::End(PHCompositeNode* /*topNode*/) { if (m_timeAnalysis) @@ -287,7 +309,7 @@ int PHActsTrkFitter::End(PHCompositeNode* /*topNode*/) { m_evaluator->End(); } - if(m_useOutlierFinder) + if (m_useOutlierFinder) { m_outlierFinder.Write(); } @@ -298,6 +320,26 @@ int PHActsTrkFitter::End(PHCompositeNode* /*topNode*/) return Fun4AllReturnCodes::EVENT_OK; } +/** + * @brief Iterate over input track seeds and fit each using the Acts track fitter. + * + * For each seed in m_seedMap, prepares measurements and source links, optionally + * scans candidate interaction-crossing values when a crossing estimate is enabled, + * runs the Acts fitter, and converts successful fit results into SvtxTrack objects + * inserted into the appropriate output map. + * + * Behavior details: + * - Uses silicon and TPC seeds (when available) to build per-track measurement sets. + * - When crossing estimation is enabled, performs trial fits over a range of crossing + * values and selects the result with the best chi2/ndf. + * - Inserts successful fits into m_trackMap or m_directedTrackMap depending on the + * configuration (normal vs. directed/micromegas fitting). + * - Increments m_nBadFits for fits that fail (when not in silicon/MM calibration mode). + * - Respects configuration flags for pp mode, crossing-estimate handling, silicon/TPC + * inclusion, directed navigation, and ignored layers. + * + * @param logLevel Controls the Acts logger verbosity used during fitting and related operations. + */ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) { auto logger = Acts::getDefaultLogger("PHActsTrkFitter", logLevel); @@ -314,47 +356,46 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) // capture the input crossing value, and set crossing parameters //============================== - short silicon_crossing = SHRT_MAX; - auto siseed = m_siliconSeeds->get(siid); - if(siseed) - { - silicon_crossing = siseed->get_crossing(); - } + short silicon_crossing = SHRT_MAX; + auto *siseed = m_siliconSeeds->get(siid); + if (siseed) + { + silicon_crossing = siseed->get_crossing(); + } short crossing = silicon_crossing; short int crossing_estimate = crossing; - if(m_enable_crossing_estimate) - { - crossing_estimate = track->get_crossing_estimate(); // geometric crossing estimate from matcher - } + if (m_enable_crossing_estimate) + { + crossing_estimate = track->get_crossing_estimate(); // geometric crossing estimate from matcher + } //=============================== - // must have silicon seed with valid crossing if we are doing a SC calibration fit if (m_fitSiliconMMs) + { + if ((siid == std::numeric_limits::max()) || (silicon_crossing == SHRT_MAX)) { - if( (siid == std::numeric_limits::max()) || (silicon_crossing == SHRT_MAX)) - { - continue; - } + continue; } + } // do not skip TPC only tracks, just set crossing to the nominal zero - if(!siseed) - { - crossing = 0; - } + if (!siseed) + { + crossing = 0; + } if (Verbosity() > 1) { - if(siseed) - { - std::cout << "tpc and si id " << tpcid << ", " << siid << " silicon_crossing " << silicon_crossing - << " crossing " << crossing << " crossing estimate " << crossing_estimate << std::endl; - } + if (siseed) + { + std::cout << "tpc and si id " << tpcid << ", " << siid << " silicon_crossing " << silicon_crossing + << " crossing " << crossing << " crossing estimate " << crossing_estimate << std::endl; + } } - auto tpcseed = m_tpcSeeds->get(tpcid); + auto *tpcseed = m_tpcSeeds->get(tpcid); /// Need to also check that the tpc seed wasn't removed by the ghost finder if (!tpcseed) @@ -381,7 +422,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) if (Verbosity() > 1 && siseed) { std::cout << " m_pp_mode " << m_pp_mode << " m_enable_crossing_estimate " << m_enable_crossing_estimate - << " INTT crossing " << crossing << " crossing_estimate " << crossing_estimate << std::endl; + << " INTT crossing " << crossing << " crossing_estimate " << crossing_estimate << std::endl; } short int this_crossing = crossing; @@ -390,35 +431,35 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) std::vector chisq_ndf; std::vector svtx_vec; - if(m_pp_mode) + if (m_pp_mode) + { + if (m_enable_crossing_estimate && crossing == SHRT_MAX) + { + // this only happens if there is a silicon seed but no assigned INTT crossing, and only in pp_mode + // If there is no INTT crossing, start with the crossing_estimate value, vary up and down, fit, and choose the best chisq/ndf + use_estimate = true; + nvary = max_bunch_search; + if (Verbosity() > 1) + { + std::cout << " No INTT crossing: use crossing_estimate " << crossing_estimate << " with nvary " << nvary << std::endl; + } + } + else { - if (m_enable_crossing_estimate && crossing == SHRT_MAX) - { - // this only happens if there is a silicon seed but no assigned INTT crossing, and only in pp_mode - // If there is no INTT crossing, start with the crossing_estimate value, vary up and down, fit, and choose the best chisq/ndf - use_estimate = true; - nvary = max_bunch_search; - if (Verbosity() > 1) - { - std::cout << " No INTT crossing: use crossing_estimate " << crossing_estimate << " with nvary " << nvary << std::endl; - } - } - else - { - // use INTT crossing - crossing_estimate = crossing; - } + // use INTT crossing + crossing_estimate = crossing; } + } else + { + // non pp mode, we want only crossing zero, veto others + if (siseed && silicon_crossing != 0) { - // non pp mode, we want only crossing zero, veto others - if(siseed && silicon_crossing != 0) - { - crossing = 0; - //continue; - } - crossing_estimate = crossing; + crossing = 0; + // continue; } + crossing_estimate = crossing; + } // Fit this track assuming either: // crossing = INTT value, if it exists (uses nvary = 0) @@ -441,16 +482,16 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) makeSourceLinks.initialize(_tpccellgeo); makeSourceLinks.setVerbosity(Verbosity()); makeSourceLinks.set_pp_mode(m_pp_mode); - for(const auto& layer : m_ignoreLayer) + for (const auto& layer : m_ignoreLayer) { makeSourceLinks.ignoreLayer(layer); } // loop over modifiedTransformSet and replace transient elements modified for the previous track with the default transforms // does nothing if m_transient_id_set is empty makeSourceLinks.resetTransientTransformMap( - m_alignmentTransformationMapTransient, - m_transient_id_set, - m_tGeometry); + m_alignmentTransformationMapTransient, + m_transient_id_set, + m_tGeometry); if (m_use_clustermover) { @@ -459,37 +500,56 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) { // silicon source links sourceLinks = makeSourceLinks.getSourceLinksClusterMover( - siseed, + siseed, + measurements, + m_clusterContainer, + m_tGeometry, + m_globalPositionWrapper, + this_crossing); + } + + // tpc source links + const auto tpcSourceLinks = makeSourceLinks.getSourceLinksClusterMover( + tpcseed, measurements, m_clusterContainer, m_tGeometry, m_globalPositionWrapper, this_crossing); - } - - // tpc source links - const auto tpcSourceLinks = makeSourceLinks.getSourceLinksClusterMover( - tpcseed, - measurements, - m_clusterContainer, - m_tGeometry, - m_globalPositionWrapper, - this_crossing); // add tpc sourcelinks to silicon source links sourceLinks.insert(sourceLinks.end(), tpcSourceLinks.begin(), tpcSourceLinks.end()); - - } else { - + } + else + { // make source links using transient transforms for distortion corrections - if(Verbosity() > 1) - { std::cout << "Calling getSourceLinks for si seed, siid " << siid << " and tpcid " << tpcid << std::endl; } + if (Verbosity() > 1) + { + std::cout << "Calling getSourceLinks for si seed, siid " << siid << " and tpcid " << tpcid << std::endl; + } if (siseed && !m_ignoreSilicon) { // silicon source links sourceLinks = makeSourceLinks.getSourceLinks( - siseed, + siseed, + measurements, + m_clusterContainer, + m_tGeometry, + m_globalPositionWrapper, + m_alignmentTransformationMapTransient, + m_transient_id_set, + this_crossing); + } + + if (Verbosity() > 1) + { + std::cout << "Calling getSourceLinks for tpc seed, siid " << siid << " and tpcid " << tpcid << std::endl; + } + + // tpc source links + const auto tpcSourceLinks = makeSourceLinks.getSourceLinks( + tpcseed, measurements, m_clusterContainer, m_tGeometry, @@ -497,21 +557,6 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) m_alignmentTransformationMapTransient, m_transient_id_set, this_crossing); - } - - if(Verbosity() > 1) - { std::cout << "Calling getSourceLinks for tpc seed, siid " << siid << " and tpcid " << tpcid << std::endl; } - - // tpc source links - const auto tpcSourceLinks = makeSourceLinks.getSourceLinks( - tpcseed, - measurements, - m_clusterContainer, - m_tGeometry, - m_globalPositionWrapper, - m_alignmentTransformationMapTransient, - m_transient_id_set, - this_crossing); // add tpc sourcelinks to silicon source links sourceLinks.insert(sourceLinks.end(), tpcSourceLinks.begin(), tpcSourceLinks.end()); @@ -524,15 +569,15 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) Acts::Vector3 position(0, 0, 0); if (siseed) { - position = TrackSeedHelper::get_xyz(siseed)*Acts::UnitConstants::cm; + position = TrackSeedHelper::get_xyz(siseed) * Acts::UnitConstants::cm; } - if(!siseed || !is_valid(position) || m_ignoreSilicon) + if (!siseed || !is_valid(position) || m_ignoreSilicon) { - position = TrackSeedHelper::get_xyz(tpcseed)*Acts::UnitConstants::cm; + position = TrackSeedHelper::get_xyz(tpcseed) * Acts::UnitConstants::cm; } if (!is_valid(position)) { - if(Verbosity() > 4) + if (Verbosity() > 4) { std::cout << "Invalid position of " << position.transpose() << std::endl; } @@ -559,26 +604,26 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) for (const auto& surface_apr : m_materialSurfaces) { - if(m_forceSiOnlyFit) + if (m_forceSiOnlyFit) { - if(surface_apr->geometryId().volume() >12) + if (surface_apr->geometryId().volume() > 12) { continue; } } bool pop_flag = false; - if(surface_apr->geometryId().approach() == 1) + if (surface_apr->geometryId().approach() == 1) { surfaces.push_back(surface_apr); } else { pop_flag = true; - for (const auto& surface_sns: surfaces_tmp) + for (const auto& surface_sns : surfaces_tmp) { if (surface_apr->geometryId().volume() == surface_sns->geometryId().volume()) { - if ( surface_apr->geometryId().layer()==surface_sns->geometryId().layer()) + if (surface_apr->geometryId().layer() == surface_sns->geometryId().layer()) { pop_flag = false; surfaces.push_back(surface_sns); @@ -594,9 +639,9 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) surfaces.pop_back(); pop_flag = false; } - if (surface_apr->geometryId().volume() == 12&& surface_apr->geometryId().layer()==8) + if (surface_apr->geometryId().volume() == 12 && surface_apr->geometryId().layer() == 8) { - for (const auto& surface_sns: surfaces_tmp) + for (const auto& surface_sns : surfaces_tmp) { if (14 == surface_sns->geometryId().volume()) { @@ -619,13 +664,13 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) { // make sure micromegas are in the tracks, if required if (m_useMicromegas && - std::none_of(surfaces.begin(), surfaces.end(), [this](const auto& surface) - { return m_tGeometry->maps().isMicromegasSurface(surface); })) - { - continue; + std::none_of(surfaces.begin(), surfaces.end(), [this](const auto& surface) + { return m_tGeometry->maps().isMicromegasSurface(surface); })) + { + continue; + } } } - } float px = std::numeric_limits::quiet_NaN(); float py = std::numeric_limits::quiet_NaN(); @@ -635,7 +680,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) float seedphi = 0; float seedtheta = 0; float seedeta = 0; - if(siseed) + if (siseed) { seedphi = siseed->get_phi(); seedtheta = siseed->get_theta(); @@ -659,7 +704,9 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) px = pt * std::cos(phi); py = pt * std::sin(phi); pz = pt * std::cosh(eta) * std::cos(theta); - } else { + } + else + { px = seedpt * std::cos(seedphi); py = seedpt * std::sin(seedphi); pz = seedpt * std::cosh(seedeta) * std::cos(seedtheta); @@ -668,14 +715,14 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) Acts::Vector3 momentum(px, py, pz); if (!is_valid(momentum)) { - if(Verbosity() > 4) + if (Verbosity() > 4) { std::cout << "Invalid momentum of " << momentum.transpose() << std::endl; } continue; } - auto pSurface = Acts::Surface::makeShared( position); + auto pSurface = Acts::Surface::makeShared(position); Acts::Vector4 actsFourPos(position(0), position(1), position(2), 10 * Acts::UnitConstants::ns); Acts::BoundSquareMatrix cov = setDefaultCovariance(); @@ -723,8 +770,10 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) auto trackStateContainer = std::make_shared(); ActsTrackFittingAlgorithm::TrackContainer tracks(trackContainer, trackStateContainer); - if(Verbosity() > 1) - { std::cout << "Calling fitTrack for track with siid " << siid << " tpcid " << tpcid << " crossing " << crossing << std::endl; } + if (Verbosity() > 1) + { + std::cout << "Calling fitTrack for track with siid " << siid << " tpcid " << tpcid << " crossing " << crossing << std::endl; + } auto result = fitTrack(sourceLinks, seed, kfOptions, surfaces, calibrator, tracks); fitTimer.stop(); @@ -761,7 +810,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) if (ivary != nvary) { - if(Verbosity() > 3) + if (Verbosity() > 3) { std::cout << "Skipping track fit for trial variation" << std::endl; } @@ -806,7 +855,6 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) if (getTrackFitResult(result, track, &newTrack, tracks, measurements)) { - // insert in dedicated map m_directedTrackMap->insertWithKey(&newTrack, trid); } @@ -822,11 +870,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) m_trackMap->insertWithKey(&newTrack, trid); } } // end insert track for normal fit - } // end case where INTT crossing is known - - - - + } // end case where INTT crossing is known } else if (!m_fitSiliconMMs) { @@ -840,7 +884,7 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) << std::endl; } } // end fit failed case - } // end ivary loop + } // end ivary loop trackTimer.stop(); auto trackTime = trackTimer.get_accumulated_time(); @@ -854,11 +898,25 @@ void PHActsTrkFitter::loopTracks(Acts::Logging::Level logLevel) return; } +/** + * @brief Convert an Acts fit result into an SvtxTrack and record auxiliary analysis state. + * + * If the Acts fit result contains a valid reference surface, update the provided SvtxTrack + * with fitted parameters and covariance derived from the Acts trajectory, build a Trajectory + * object for the fit states, and optionally record alignment state and evaluator information. + * + * @param fitOutput The Acts fit result containing the fitted track/trajectory. + * @param seed The input TrackSeed associated with this fit (used by the evaluator). + * @param track The SvtxTrack to update in place with fitted parameters and covariance. + * @param tracks The Acts track container holding trajectory states from the fit. + * @param measurements The measurement container used when filling alignment state information. + * @return `true` if the Acts result had a reference surface and the SvtxTrack was updated, `false` otherwise. + */ bool PHActsTrkFitter::getTrackFitResult( - const FitResult& fitOutput, - TrackSeed* seed, SvtxTrack* track, - const ActsTrackFittingAlgorithm::TrackContainer& tracks, - const ActsTrackFittingAlgorithm::MeasurementContainer& measurements) + const FitResult& fitOutput, + TrackSeed* seed, SvtxTrack* track, + const ActsTrackFittingAlgorithm::TrackContainer& tracks, + const ActsTrackFittingAlgorithm::MeasurementContainer& measurements) { /// Make a trajectory state for storage, which conforms to Acts track fit /// analysis tool @@ -872,12 +930,12 @@ bool PHActsTrkFitter::getTrackFitResult( // retrieve track parameters from fit result Acts::BoundTrackParameters parameters = ActsExamples::TrackParameters(outtrack.referenceSurface().getSharedPtr(), - outtrack.parameters(), outtrack.covariance(), outtrack.particleHypothesis()); + outtrack.parameters(), outtrack.covariance(), outtrack.particleHypothesis()); indexedParams.emplace( - outtrack.tipIndex(), - ActsExamples::TrackParameters{outtrack.referenceSurface().getSharedPtr(), - outtrack.parameters(), outtrack.covariance(), outtrack.particleHypothesis()}); + outtrack.tipIndex(), + ActsExamples::TrackParameters{outtrack.referenceSurface().getSharedPtr(), + outtrack.parameters(), outtrack.covariance(), outtrack.particleHypothesis()}); if (Verbosity() > 2) { @@ -937,7 +995,20 @@ bool PHActsTrkFitter::getTrackFitResult( return false; } -//__________________________________________________________________________________ +/** + * @brief Dispatches a track fit to the configured Acts fitter and returns the result. + * + * Chooses the direct (directed) fitter when silicon micromegas fitting is enabled or when + * direct navigation is active; otherwise uses the full Kalman fitter. + * + * @param sourceLinks Ordered measurement source links used as input to the fitter. + * @param seed Initial track parameters for the fit. + * @param kfOptions General fitter options and context (field, geometry, calibration flags). + * @param surfSequence Ordered surface sequence used by the directed fitter (may be unused by the full fitter). + * @param calibrator Calibration adapter applied during fitting (material/measurement calibrations). + * @param tracks Output container that will be populated with fitted track(s) and trajectory states. + * @return ActsTrackFittingAlgorithm::TrackFitterResult Result object describing fit success, diagnostics, and fitted trajectory data. + */ ActsTrackFittingAlgorithm::TrackFitterResult PHActsTrkFitter::fitTrack( const std::vector& sourceLinks, const ActsTrackFittingAlgorithm::TrackParameters& seed, @@ -948,13 +1019,26 @@ ActsTrackFittingAlgorithm::TrackFitterResult PHActsTrkFitter::fitTrack( { // use direct fit for silicon MM gits or direct navigation if (m_fitSiliconMMs || m_directNavigation) - { return (*m_fitCfg.dFit)(sourceLinks, seed, kfOptions, surfSequence, calibrator, tracks); } + { + return (*m_fitCfg.dFit)(sourceLinks, seed, kfOptions, surfSequence, calibrator, tracks); + } // use full fit in all other cases return (*m_fitCfg.fit)(sourceLinks, seed, kfOptions, calibrator, tracks); } -//__________________________________________________________________________________ +/** + * @brief Extracts source links that belong to silicon/micromegas surfaces and populates a matching surface list. + * + * Iterates over the provided source links, finds each link's detector surface, applies configured filters + * (exclude TPC surfaces when silicon/MM fitting is enabled; exclude micromegas if m_useMicromegas is false; + * when m_forceSiOnlyFit is set, exclude both micromegas and TPC surfaces), appends accepted surfaces to + * `surfaces` in the same order, and returns the corresponding subset of source links. + * + * @param sourceLinks Input source links to filter. + * @param surfaces Output vector that will be appended with the surfaces corresponding to accepted source links. + * @return SourceLinkVec The subset of `sourceLinks` that passed the surface filters (order preserved). + */ SourceLinkVec PHActsTrkFitter::getSurfaceVector(const SourceLinkVec& sourceLinks, SurfacePtrVec& surfaces) const { SourceLinkVec siliconMMSls; @@ -986,9 +1070,9 @@ SourceLinkVec PHActsTrkFitter::getSurfaceVector(const SourceLinkVec& sourceLinks } } - if(m_forceSiOnlyFit) + if (m_forceSiOnlyFit) { - if(m_tGeometry->maps().isMicromegasSurface(surf)||m_tGeometry->maps().isTpcSurface(surf)) + if (m_tGeometry->maps().isMicromegasSurface(surf) || m_tGeometry->maps().isTpcSurface(surf)) { continue; } @@ -1010,6 +1094,16 @@ SourceLinkVec PHActsTrkFitter::getSurfaceVector(const SourceLinkVec& sourceLinks return siliconMMSls; } +/** + * @brief Ensure surfaces are in ascending (volume, layer) order by removing out-of-order entries. + * + * Scans the provided surface vector in-place and removes any surface that breaks the + * ascending order when comparing geometryId().volume() then geometryId().layer(). + * The function mutates the input vector to preserve only surfaces sorted by + * (volume, layer) with increasing volume primary and increasing layer secondary. + * + * @param surfaces Vector of surface pointers to validate and modify in place. + */ void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const { for (unsigned int i = 0; i < surfaces.size() - 1; i++) @@ -1058,11 +1152,27 @@ void PHActsTrkFitter::checkSurfaceVec(SurfacePtrVec& surfaces) const } } +/** + * @brief Update a SvtxTrack with fitted Acts trajectory parameters and states. + * + * Updates the provided SvtxTrack's reference position, momentum, charge, fit chi2 and NDF, + * covariance (if present, rotated into the SvtxTrack frame), and associated SvtxTrackStates + * derived from the Acts trajectory. When configured to fit silicon Micromegas (m_fitSiliconMMs) + * and the track has a TPC seed, additionally extrapolates the fitted parameters to TPC cluster + * surfaces and appends corresponding track states. Position values taken from Acts (mm) are + * converted to the SvtxTrack convention (cm). + * + * @param tips Ordered list of trajectory tip indices; the first element is used as the track tip. + * @param paramsMap Map of indexed fitted parameters keyed by trajectory index (contains position, + * momentum, charge and optional covariance). + * @param tracks Container holding the Acts trajectory and its track states used to populate SvtxTrackStates. + * @param track Mutable SvtxTrack object to be updated in-place with fit results and states. + */ void PHActsTrkFitter::updateSvtxTrack( - const std::vector& tips, - const Trajectory::IndexedParameters& paramsMap, - const ActsTrackFittingAlgorithm::TrackContainer& tracks, - SvtxTrack* track) + const std::vector& tips, + const Trajectory::IndexedParameters& paramsMap, + const ActsTrackFittingAlgorithm::TrackContainer& tracks, + SvtxTrack* track) { const auto& mj = tracks.trackStateContainer(); @@ -1133,31 +1243,37 @@ void PHActsTrkFitter::updateSvtxTrack( trackStateTimer.restart(); if (m_fillSvtxTrackStates) - { transformer.fillSvtxTrackStates(mj, trackTip, track, m_transient_geocontext); } + { + transformer.fillSvtxTrackStates(mj, trackTip, track, m_transient_geocontext); + } // in using silicon mm fit also extrapolate track parameters to all TPC surfaces with clusters // get all tpc clusters auto* seed = track->get_tpc_seed(); - if( m_fitSiliconMMs && seed ) + if (m_fitSiliconMMs && seed) { - // acts propagator ActsPropagator propagator(m_tGeometry); // loop over cluster keys associated to TPC seed - for( auto key_iter = seed->begin_cluster_keys(); key_iter != seed->end_cluster_keys(); ++key_iter ) + for (auto key_iter = seed->begin_cluster_keys(); key_iter != seed->end_cluster_keys(); ++key_iter) { const auto& cluskey = *key_iter; // make sure cluster is from TPC const auto detId = TrkrDefs::getTrkrId(cluskey); if (detId != TrkrDefs::tpcId) - { continue; } + { + continue; + } // get layer, propagate const auto layer = TrkrDefs::getLayer(cluskey); auto result = propagator.propagateTrack(params, layer); - if( !result.ok() ) { continue; } + if (!result.ok()) + { + continue; + } // get path length and extrapolated parameters auto& [pathLength, trackStateParams] = result.value(); @@ -1380,4 +1496,4 @@ int PHActsTrkFitter::getNodes(PHCompositeNode* topNode) m_globalPositionWrapper.set_suppressCrossing(true); return Fun4AllReturnCodes::EVENT_OK; -} +} \ No newline at end of file diff --git a/offline/packages/trackreco/PHActsTrkFitter.h b/offline/packages/trackreco/PHActsTrkFitter.h index c6e0afec35..f4812b669e 100644 --- a/offline/packages/trackreco/PHActsTrkFitter.h +++ b/offline/packages/trackreco/PHActsTrkFitter.h @@ -21,8 +21,8 @@ #include #include #include -#include #include +#include #include @@ -49,7 +49,188 @@ using Measurement = Acts::Measurement; using SurfacePtrVec = std::vector; using SourceLinkVec = std::vector; -class PHActsTrkFitter : public SubsysReco +/** + * Construct a PHActsTrkFitter instance. + * @param name Instance name used for messaging and node registration. + */ + /** + * Finalize module work, write and close any open files, and perform cleanup. + * @param topNode Top-level node of the current event/node tree. + * @returns 0 on success, non-zero on failure. + */ + /** + * Acquire required nodes and create any missing nodes needed for the run. + * @param topNode Top-level node of the current event/node tree. + * @returns 0 on success, non-zero on failure. + */ + /** + * Process a single event by running the track refit workflow. + * @param topNode Top-level node of the current event/node tree. + * @returns 0 on success, non-zero on failure. + */ + /** + * Reset per-event internal state. + * @param topNode Top-level node of the current event/node tree. + * @returns 0 on success, non-zero on failure. + */ + /** + * Enable or disable internal timing instrumentation. + * @param timeAnalysis If true, enable timing analysis; if false, disable it. + */ + /** + * Enable or disable use of the directed navigator to fit tracks containing silicon and Micromegas hits. + * @param fitSiliconMMs If true, use direct navigation for silicon+MM fits. + */ + /** + * When using direct navigation, force fitting to use only silicon surfaces (ignore MM surfaces). + * @param forceSiOnlyFit If true, restrict direct-navigation fits to silicon surfaces only. + */ + /** + * Require Micromegas hits to be present when performing Silicon+MM direct-navigation fits. + * @param value If true, require Micromegas presence for SiliconMM fits. + */ + /** + * Mark silicon clusters to be ignored during fitting. + */ + /** + * Control whether SvtxTrackState entries are updated from Acts fit results. + * @param fillSvtxTrackStates If true, update SvtxTrackState information on tracks. + */ + /** + * Enable or disable the Acts-based evaluator. + * @param actsEvaluator If true, enable evaluator output. + */ + /** + * Enable or disable the Acts-based evaluator in simulation mode; also enables the evaluator flag. + * @param actsEvaluator If true, enable simulation-mode evaluator and set evaluator enabled. + */ + /** + * Set the evaluator output filename. + * @param name Output filename for the evaluator. + */ + /** + * Configure an external magnetic field map by path/name. + * @param fieldMap Identifier or path to the field map to use. + */ + /** + * Set the absolute PDG hypothesis used as the particle assumption for fitting. + * @param pHypothesis PDG code to assume (absolute value). + */ + /** + * Toggle commissioning mode which may alter fitter behavior or tolerances. + * @param com If true, enable commissioning mode. + */ + /** + * Enable or disable the chi^2-based outlier finder inside the fitter. + * @param outlier If true, enable outlier finding. + */ + /** + * Specify an output file for the outlier finder results. + * @param outfilename Path to the outlier finder output file. + */ + /** + * Set the number of fitter iterations to perform. + * @param iter Number of iterations. + */ + /** + * Set the output Svtx track map name. + * @param map_name Name to use for the track map. + */ + /** + * Set the Svtx seed map name. + * @param map_name Name to use for the seed map. + */ + /** + * Set the Svtx alignment state map name and configure alignment state handling. + * @param map_name Name to use for the SvtxAlignmentStateMap. + */ + /** + * Configure running mode for pp collisions. + * @param ispp If true, enable pp running mode. + */ + /** + * Enable or disable geometric crossing estimate usage. + * @param flag If true, enable geometric crossing estimate. + */ + /** + * Enable or disable use of the cluster mover facility. + * @param use If true, enable cluster mover. + */ + /** + * Mark a detector layer to be ignored during fits. + * @param layer Integer identifier of the layer to ignore. + */ + /** + * Set the name of the TRKR_CLUSTER container to read clusters from. + * @param name Name of the TRKR_CLUSTER container. + */ + /** + * Enable or disable direct navigation mode. + * @param flag If true, use direct navigation when available. + */ + /** + * Retrieve required nodes from the node tree and cache pointers to them. + * @param topNode Top-level node of the current event/node tree. + * @returns 0 on success, non-zero on failure. + */ + /** + * Create module-specific nodes under the provided top node when absent. + * @param topNode Top-level node of the current event/node tree. + * @returns 0 on success, non-zero on failure. + */ + /** + * Iterate over tracks and perform fitting actions at the given Acts logging level. + * @param logLevel Logging threshold passed to Acts components during fitting. + */ + /** + * Translate Acts trajectory output into SvtxTrack fields and SvtxTrackState entries. + * @param tips Indices of trajectory tips to consider for state extraction. + * @param paramsMap Map of indexed trajectory parameters. + * @param tracks Container of Acts fit track objects produced by the fitter. + * @param track SvtxTrack to be updated with fit results. + */ + /** + * Fit a single track using either regular navigation or direct navigation based on configuration. + * @param sourceLinks Source links (measurements) that compose the track to be fitted. + * @param seed Initial seed parameters for the fitter. + * @param kfOptions General fitter options and algorithm configuration. + * @param surfSequence Ordered sequence of surface pointers for direct navigation (may be empty for regular navigation). + * @param calibrator Calibrator adapter used to convert measurements for fitting. + * @param tracks Output container that will be populated with resulting Acts tracks. + * @returns Result object describing fit success, status, and produced measurements. + */ + /** + * Build a sorted vector of surface pointers corresponding to the provided source links for direct navigation. + * @param sourceLinks Input source links. + * @param surfaces Output vector populated with corresponding surface pointers in navigation order. + * @returns A possibly filtered vector of source links corresponding to the constructed surfaces. + */ + /** + * Validate the integrity and ordering of a surface vector prepared for direct navigation. + * @param surfaces Surface pointer vector to validate. + */ + /** + * Convert a fit result into SvtxTrack updates and determine fit acceptance. + * @param fitOutput Fit result produced by the Acts fitter. + * @param seed Original TrackSeed corresponding to the fit. + * @param track SvtxTrack to update with the fit results. + * @param tracks Container of Acts track objects produced during fitting. + * @param measurements Container of measurements produced by the fit. + * @returns `true` if the fit result was successfully converted and accepted, `false` otherwise. + */ + /** + * Provide a default covariance matrix to be used when a seed lacks covariance information. + * @returns Default bound covariance matrix sized for the track parameterization used by the fitter. + */ + /** + * Print diagnostic information for a track seed to the configured logger. + * @param seed Seed parameters to be logged. + */ + /** + * Collect surfaces that contain material into an internal list if they are not already present. + * @param surface Test surface to inspect and possibly add to the selector's list. + */ + class PHActsTrkFitter : public SubsysReco { public: /// Default constructor @@ -130,18 +311,19 @@ class PHActsTrkFitter : public SubsysReco void set_track_map_name(const std::string& map_name) { _track_map_name = map_name; } void set_svtx_seed_map_name(const std::string& map_name) { _svtx_seed_map_name = map_name; } - void set_svtx_alignment_state_map_name(const std::string& map_name) { - _svtx_alignment_state_map_name = map_name; - m_alignStates.alignmentStateMap(map_name); + void set_svtx_alignment_state_map_name(const std::string& map_name) + { + _svtx_alignment_state_map_name = map_name; + m_alignStates.alignmentStateMap(map_name); } /// Set flag for pp running void set_pp_mode(bool ispp) { m_pp_mode = ispp; } - void set_enable_geometric_crossing_estimate(bool flag) { m_enable_crossing_estimate = flag ; } + void set_enable_geometric_crossing_estimate(bool flag) { m_enable_crossing_estimate = flag; } void set_use_clustermover(bool use) { m_use_clustermover = use; } void ignoreLayer(int layer) { m_ignoreLayer.insert(layer); } - void setTrkrClusterContainerName(std::string &name){ m_clusterContainerName = name; } + void setTrkrClusterContainerName(std::string& name) { m_clusterContainerName = name; } void setDirectNavigation(bool flag) { m_directNavigation = flag; } private: @@ -155,10 +337,10 @@ class PHActsTrkFitter : public SubsysReco /// Convert the acts track fit result to an svtx track void updateSvtxTrack( - const std::vector& tips, - const Trajectory::IndexedParameters& paramsMap, - const ActsTrackFittingAlgorithm::TrackContainer& tracks, - SvtxTrack* track); + const std::vector& tips, + const Trajectory::IndexedParameters& paramsMap, + const ActsTrackFittingAlgorithm::TrackContainer& tracks, + SvtxTrack* track); /// Helper function to call either the regular navigation or direct /// navigation, depending on m_fitSiliconMMs @@ -240,7 +422,7 @@ class PHActsTrkFitter : public SubsysReco // max variation of bunch crossing away from crossing_estimate short int max_bunch_search = 2; - //name of TRKR_CLUSTER container + // name of TRKR_CLUSTER container std::string m_clusterContainerName = "TRKR_CLUSTER"; //!@name evaluator @@ -253,7 +435,7 @@ class PHActsTrkFitter : public SubsysReco //@} //! tracks -// SvtxTrackMap* m_seedTracks = nullptr; + // SvtxTrackMap* m_seedTracks = nullptr; //! tpc global position wrapper TpcGlobalPositionWrapper m_globalPositionWrapper; @@ -268,7 +450,7 @@ class PHActsTrkFitter : public SubsysReco int _n_iteration = 0; std::string _track_map_name = "SvtxTrackMap"; std::string _svtx_seed_map_name = "SvtxTrackSeedContainer"; - std::string _svtx_alignment_state_map_name = "SvtxAlignmentStateMap"; + std::string _svtx_alignment_state_map_name = "SvtxAlignmentStateMap"; /// Default particle assumption to pion unsigned int m_pHypothesis = 211; @@ -292,14 +474,18 @@ class PHActsTrkFitter : public SubsysReco std::vector m_materialSurfaces = {}; - struct MaterialSurfaceSelector { + struct MaterialSurfaceSelector + { std::vector surfaces = {}; /// @param surface is the test surface - void operator()(const Acts::Surface* surface) { - if (surface->surfaceMaterial() != nullptr) { + void operator()(const Acts::Surface* surface) + { + if (surface->surfaceMaterial() != nullptr) + { if (std::find(surfaces.begin(), surfaces.end(), surface) == - surfaces.end()) { + surfaces.end()) + { surfaces.push_back(surface); } } @@ -307,4 +493,4 @@ class PHActsTrkFitter : public SubsysReco }; }; -#endif +#endif \ No newline at end of file